/* * Parse a seqset from the given string and append it to the chain * of seqsets at `*l'. */ HIDDEN void seqset_append(struct seqset **l, char *sequence, unsigned maxval) { struct seqset **tail = l; while (*tail) { if (!maxval) maxval = (*tail)->maxval; tail = &(*tail)->nextseq; } *tail = seqset_parse(sequence, NULL, maxval); }
/* * Performs a STATUS command - note: state MAY be NULL here. */ int status_lookup(const char *mboxname, const char *userid, unsigned statusitems, struct statusdata *sdata) { struct mailbox *mailbox = NULL; unsigned numrecent = 0; unsigned numunseen = 0; unsigned c_statusitems; int r; /* Check status cache if possible */ if (config_getswitch(IMAPOPT_STATUSCACHE)) { /* Do actual lookup of cache item. */ r = statuscache_lookup(mboxname, userid, statusitems, sdata); /* Seen/recent status uses "push" invalidation events from * seen_db.c. This avoids needing to open cyrus.header to get * the mailbox uniqueid to open the seen db and get the * unseen_mtime and recentuid. */ if (!r) { syslog(LOG_DEBUG, "statuscache, '%s', '%s', '0x%02x', 'yes'", mboxname, userid, statusitems); return 0; } syslog(LOG_DEBUG, "statuscache, '%s', '%s', '0x%02x', 'no'", mboxname, userid, statusitems); } /* Missing or invalid cache entry */ r = mailbox_open_irl(mboxname, &mailbox); if (r) return r; /* We always have message count, uidnext, uidvalidity, and highestmodseq for cache */ c_statusitems = STATUS_MESSAGES | STATUS_UIDNEXT | STATUS_UIDVALIDITY | STATUS_HIGHESTMODSEQ; if (!mailbox->i.exists) { /* no messages, so these two must also be zero */ c_statusitems |= STATUS_RECENT | STATUS_UNSEEN; } else if (statusitems & (STATUS_RECENT | STATUS_UNSEEN)) { /* Read \Seen state */ struct seqset *seq = NULL; uint32_t recno; struct index_record record; int internalseen = mailbox_internal_seen(mailbox, userid); unsigned recentuid; if (internalseen) { recentuid = mailbox->i.recentuid; } else { struct seen *seendb = NULL; struct seendata sd = SEENDATA_INITIALIZER; r = seen_open(userid, SEEN_CREATE, &seendb); if (!r) r = seen_read(seendb, mailbox->uniqueid, &sd); seen_close(&seendb); if (r) goto done; recentuid = sd.lastuid; seq = seqset_parse(sd.seenuids, NULL, recentuid); seen_freedata(&sd); } for (recno = 1; recno <= mailbox->i.num_records; recno++) { if (mailbox_read_index_record(mailbox, recno, &record)) continue; if (record.system_flags & FLAG_EXPUNGED) continue; if (record.uid > recentuid) numrecent++; if (internalseen) { if (!(record.system_flags & FLAG_SEEN)) numunseen++; } else { if (!seqset_ismember(seq, record.uid)) numunseen++; } } /* we've calculated the correct values for both */ c_statusitems |= STATUS_RECENT | STATUS_UNSEEN; } statuscache_fill(sdata, userid, mailbox, c_statusitems, numrecent, numunseen); /* cache the new value while unlocking */ mailbox_unlock_index(mailbox, sdata); done: mailbox_close(&mailbox); return r; }
int main(int argc, char *argv[]) { const char *alt_config = NULL; unsigned maxval = 0; int flags = SEQ_MERGE; struct seqset *seq = NULL; int opt; unsigned num; char *res; const char *origlist = NULL; while ((opt = getopt(argc, argv, "C:m:o:s")) != EOF) { switch (opt) { case 'C': /* alt config file */ alt_config = optarg; break; case 'm': /* maxval */ parseuint32(optarg, NULL, &maxval); break; case 'o': origlist = optarg; break; case 's': flags = SEQ_SPARSE; } } if ((argc - optind) < 1) usage(argv[0]); cyrus_init(alt_config, "cyr_sequence", 0); /* special case */ if (!strcmp(argv[optind], "create")) { int i; seq = seqset_init(maxval, flags); for (i = optind + 1; i < argc; i++) { char *ptr = argv[i]; int isadd = 1; if (*ptr == '~') { isadd = 0; ptr++; } if (parseuint32(ptr, NULL, &num)) printf("%s NAN\n", argv[i]); else seqset_add(seq, num, isadd); } if (origlist) { unsigned oldmax = seq_lastnum(origlist, NULL); if (oldmax > maxval) { struct seqset *origseq = seqset_parse(origlist, NULL, oldmax); unsigned val; for (val = maxval + 1; val <= oldmax; val++) seqset_add(seq, val, seqset_ismember(origseq, val)); seqset_free(origseq); } } res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "parsed")) { unsigned i; seq = seqset_parse(argv[optind+1], NULL, maxval); printf("Sections: " SIZE_T_FMT "\n", seq->len); for (i = 0; i < seq->len; i++) { if (seq->set[i].high == UINT_MAX) printf(" [%u, *]\n", seq->set[i].low); else printf(" [%u, %u]\n", seq->set[i].low, seq->set[i].high); } } else if (!strcmp(argv[optind], "compress")) { seq = seqset_parse(argv[optind+1], NULL, maxval); res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "members")) { seq = seqset_parse(argv[optind+1], NULL, maxval); while ((num = seqset_getnext(seq))) { printf("%u\n", num); } } else if (!strcmp(argv[optind], "join")) { struct seqset *seq2; seq = seqset_parse(argv[optind+1], NULL, maxval); seq2 = seqset_parse(argv[optind+2], NULL, maxval); seqset_join(seq, seq2); res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "ismember")) { int i; seq = seqset_parse(argv[optind+1], NULL, maxval); for (i = optind + 2; i < argc; i++) { if (parseuint32(argv[i], NULL, &num)) printf("%s NAN\n", argv[i]); else printf("%d %s\n", num, seqset_ismember(seq, num) ? "Yes" : "No"); } } else { printf("Unknown command %s", argv[optind]); } seqset_free(seq); cyrus_done(); return 0; }