Projects
Kolab:3.4
cyrus-imapd
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 141
View file
cyrus-imapd.spec
Changed
@@ -38,13 +38,13 @@ Name: cyrus-imapd Summary: A high-performance mail server with IMAP, POP3, NNTP and SIEVE support Version: 2.5 -Release: 0.2.dev20141209.gitf0131008%{?dist} +Release: 0.2.dev20150213.gite9158f38%{?dist} License: BSD Group: System Environment/Daemons URL: http://www.cyrusimap.org # Upstream sources -# From f01310085cbf58958412deda9c61ecfd7c82a19b +# From e9158f38630b553a4f62b883f61193cf1b169fc3 Source0: ftp://ftp.andrew.cmu.edu/pub/cyrus/%{_name}-%{real_version}%{?dot_snapshot_version}.tar.gz Source1: cyrus-imapd.imap-2.3.x-conf Source2: cyrus-imapd.cvt_cyrusdb_all @@ -68,7 +68,6 @@ ## Patch0001: cyrus-imapd-2.5-ctl_mboxlist-mbtype.patch -Patch0002: cyrus-imapd-2.5-revert-safe-skiplist.patch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -265,7 +264,6 @@ %setup -q -n %{_name}-%{real_version}%{?dot_snapshot_version} %patch0001 -p1 -%patch0002 -p1 %if 0%{?with_bdb} < 1 sed -i -e 's/,berkeley//g' cunit/db.testc @@ -618,7 +616,7 @@ %{_bindir}/pop3test %{_bindir}/sieveshell %{_bindir}/sivtest -%{_bindir}/smpttest +%{_bindir}/smtptest %{_bindir}/synctest %{_sysconfdir}/cron.daily/%{_name} %dir %{_cyrexecdir} @@ -750,6 +748,9 @@ %{_libdir}/*.la %changelog +* Fri Feb 13 2015 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 2.5-12.git +- New snapshot + * Tue Dec 9 2014 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 2.5-11.git - Fix Murder topologies not handling null ACLs at all
View file
cyrus-imapd-2.5-openssl-stack.patch
Deleted
@@ -1,16 +0,0 @@ -diff --git a/imap/tls.c b/imap/tls.c -index 6e6ba63..39361f2 100644 ---- a/imap/tls.c -+++ b/imap/tls.c -@@ -860,7 +860,11 @@ EXPORTED int tls_init_serverengine(const char *ident, - } else { - STACK_OF(X509_NAME) *CAnames = SSL_load_client_CA_file(client_ca_file); - -+#if (OPENSSL_VERSION_NUMBER >= 0x1000000fL) - if (!CAnames || sk_num((_STACK *)CAnames) < 1) { -+#else // (OPENSSL_VERSION_NUMBER >= 0x1000000fL) -+ if (!CAnames) { -+#endif - syslog( - LOG_ERR, - "TLS server engine: No client CA certs specified. Client side certs may not work"
View file
cyrus-imapd-2.5-revert-safe-skiplist.patch
Deleted
@@ -1,520 +0,0 @@ -diff --git a/lib/cyrusdb_skiplist.c b/lib/cyrusdb_skiplist.c -index 18d3ca3..fc540e0 100644 ---- a/lib/cyrusdb_skiplist.c -+++ b/lib/cyrusdb_skiplist.c -@@ -399,7 +399,7 @@ static unsigned RECSIZE_safe(struct dbengine *db, const char *ptr) - case ADD: - level = LEVEL_safe(db, ptr); - if (!level) { -- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", -+ syslog(LOG_ERR, "IOERROR: skiplist2 RECSIZE_safe not safe %s, offset %u", - db->fname, (unsigned)(ptr - db->map_base)); - return 0; - } -@@ -413,20 +413,50 @@ static unsigned RECSIZE_safe(struct dbengine *db, const char *ptr) - break; - - case DELETE: -- if (!is_safe(db, ptr+8)) { -- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", -- db->fname, (unsigned)(ptr - db->map_base)); -- return 0; -- } - ret += 8; - break; - - case COMMIT: -- if (!is_safe(db, ptr+4)) { -- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", -- db->fname, (unsigned)(ptr - db->map_base)); -- return 0; -- } -+ ret += 4; -+ break; -+ } -+ -+ return ret; -+} -+ -+/* how many levels does this record have? */ -+static unsigned LEVEL(const char *ptr) -+{ -+ const uint32_t *p, *q; -+ -+ assert(TYPE(ptr) == DUMMY || TYPE(ptr) == INORDER || TYPE(ptr) == ADD); -+ p = q = (uint32_t *) FIRSTPTR(ptr); -+ while (*p != (uint32_t)-1) p++; -+ return (p - q); -+} -+ -+/* how big is this record? */ -+static unsigned RECSIZE(const char *ptr) -+{ -+ int ret = 0; -+ switch (TYPE(ptr)) { -+ case DUMMY: -+ case INORDER: -+ case ADD: -+ ret += 4; /* tag */ -+ ret += 4; /* keylen */ -+ ret += ROUNDUP(KEYLEN(ptr)); /* key */ -+ ret += 4; /* datalen */ -+ ret += ROUNDUP(DATALEN(ptr)); /* data */ -+ ret += 4 * LEVEL(ptr); /* pointers */ -+ ret += 4; /* padding */ -+ break; -+ -+ case DELETE: -+ ret += 8; -+ break; -+ -+ case COMMIT: - ret += 4; - break; - } -@@ -494,12 +524,7 @@ static int newtxn(struct dbengine *db, struct txn **tidptr) - } - - --static unsigned PADDING_safe(struct dbengine *db, const char *ptr) --{ -- unsigned size = RECSIZE_safe(db, ptr); -- if (!size) return 0; -- return ntohl(*((uint32_t *)((ptr) + size - 4))); --} -+#define PADDING(ptr) (ntohl(*((uint32_t *)((ptr) + RECSIZE(ptr) - 4)))) - - /* given an open, mapped db, read in the header information */ - static int read_header(struct dbengine *db) -@@ -570,9 +595,9 @@ static int read_header(struct dbengine *db) - db->fname); - r = CYRUSDB_IOERROR; - } -- if (!r && LEVEL_safe(db, dptr) != db->maxlevel) { -+ if (!r && LEVEL(dptr) != db->maxlevel) { - syslog(LOG_ERR, "DBERROR: %s: DUMMY level(%d) != db->maxlevel(%d)", -- db->fname, LEVEL_safe(db, dptr), db->maxlevel); -+ db->fname, LEVEL(dptr), db->maxlevel); - r = CYRUSDB_IOERROR; - } - -@@ -1281,7 +1306,7 @@ static int mystore(struct dbengine *db, - return CYRUSDB_EXISTS; - } else { - /* replace with an equal height node */ -- lvl = LEVEL_safe(db, ptr); -+ lvl = LEVEL(ptr); - - /* log a removal */ - WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) &delrectype, 4); -@@ -1575,8 +1600,8 @@ static int myabort(struct dbengine *db, struct txn *tid) - - /* find the last log entry */ - for (offset = tid->logstart, ptr = db->map_base + offset; -- offset + RECSIZE_safe(db, ptr) != (uint32_t) tid->logend; -- offset += RECSIZE_safe(db, ptr), ptr = db->map_base + offset) ; -+ offset + RECSIZE(ptr) != (uint32_t) tid->logend; -+ offset += RECSIZE(ptr), ptr = db->map_base + offset) ; - - offset = ptr - db->map_base; - -@@ -1613,7 +1638,7 @@ static int myabort(struct dbengine *db, struct txn *tid) - /* re-add this record. it can't exist right now. */ - netnewoffset = *((uint32_t *)(ptr + 4)); - q = db->map_base + ntohl(netnewoffset); -- lvl = LEVEL_safe(db, q); -+ lvl = LEVEL(q); - (void) find_node(db, KEY(q), KEYLEN(q), updateoffsets); - for (i = 0; i < lvl; i++) { - /* the current pointers FROM this node are correct, -@@ -1628,7 +1653,7 @@ static int myabort(struct dbengine *db, struct txn *tid) - } - - /* remove looking at this */ -- tid->logend -= RECSIZE_safe(db, ptr); -+ tid->logend -= RECSIZE(ptr); - } - - /* truncate the file to remove log entries */ -@@ -1742,13 +1767,13 @@ static int mycheckpoint(struct dbengine *db) - uint32_t netnewoffset; - - ptr = db->map_base + offset; -- lvl = LEVEL_safe(db, ptr); -+ lvl = LEVEL(ptr); - db->listsize++; - - num_iov = 0; - WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) &iorectype, 4); - /* copy all but the rectype from the record */ -- WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) ptr + 4, RECSIZE_safe(db, ptr) - 4); -+ WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) ptr + 4, RECSIZE(ptr) - 4); - - newoffset = lseek(db->fd, 0, SEEK_END); - netnewoffset = htonl(newoffset); -@@ -1915,9 +1940,9 @@ static int dump(struct dbengine *db, int detail __attribute__((unused))) - case INORDER: - case ADD: - printf("kl=%d dl=%d lvl=%d\n", -- KEYLEN(ptr), DATALEN(ptr), LEVEL_safe(db, ptr)); -+ KEYLEN(ptr), DATALEN(ptr), LEVEL(ptr)); - printf("\t"); -- for (i = 0; i < LEVEL_safe(db, ptr); i++) { -+ for (i = 0; i < LEVEL(ptr); i++) { - printf("%04X ", FORWARD(ptr, i)); - } - printf("\n"); -@@ -1932,7 +1957,7 @@ static int dump(struct dbengine *db, int detail __attribute__((unused))) - break; - } - -- ptr += RECSIZE_safe(db, ptr); -+ ptr += RECSIZE(ptr); - } - - unlock(db); -@@ -1961,7 +1986,7 @@ static int myconsistent(struct dbengine *db, struct txn *tid, int locked) - - ptr = db->map_base + offset; - -- for (i = 0; i < LEVEL_safe(db, ptr); i++) { -+ for (i = 0; i < LEVEL(ptr); i++) { - offset = FORWARD(ptr, i); - - if (offset > db->map_size) { -@@ -2005,11 +2030,9 @@ static int myconsistent(struct dbengine *db, struct txn *tid, int locked) - static int recovery(struct dbengine *db, int flags) - { - const char *ptr, *keyptr; -- unsigned filesize = db->map_size; - unsigned updateoffsets[SKIPLIST_MAXLEVEL+1]; - uint32_t offset, offsetnet, myoff = 0; -- int r = 0; -- int need_checkpoint = libcyrus_config_getswitch(CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT); -+ int r = 0, need_checkpoint = 0; - time_t start = time(NULL); - unsigned i; - -@@ -2063,11 +2086,11 @@ static int recovery(struct dbengine *db, int flags) - } - - /* pointers for db->maxlevel */ -- if (!r && LEVEL_safe(db, ptr) != db->maxlevel) { -+ if (!r && LEVEL(ptr) != db->maxlevel) { - r = CYRUSDB_IOERROR; - syslog(LOG_ERR, - "DBERROR: skiplist recovery %s: dummy node level: %d != %d", -- db->fname, LEVEL_safe(db, ptr), db->maxlevel); -+ db->fname, LEVEL(ptr), db->maxlevel); - } - - for (i = 0; i < db->maxlevel; i++) { -@@ -2078,7 +2101,7 @@ static int recovery(struct dbengine *db, int flags) - - /* reset the data that was written INORDER by the last checkpoint */ - offset = DUMMY_OFFSET(db) + DUMMY_SIZE(db); -- while (!r && (offset < filesize) -+ while (!r && (offset < db->map_size) - && TYPE(db->map_base + offset) == INORDER) { - ptr = db->map_base + offset; - offsetnet = htonl(offset); -@@ -2088,9 +2111,9 @@ static int recovery(struct dbengine *db, int flags) - /* xxx check \0 fill on key */ - - /* xxx check \0 fill on data */ -- -+ - /* update previous pointers, record these for updating */ -- for (i = 0; !r && i < LEVEL_safe(db, ptr); i++) { -+ for (i = 0; !r && i < LEVEL(ptr); i++) { - r = lseek(db->fd, updateoffsets[i], SEEK_SET); - if (r < 0) { - syslog(LOG_ERR, "DBERROR: lseek %s: %m", db->fname); -@@ -2113,23 +2136,15 @@ static int recovery(struct dbengine *db, int flags) - updateoffsets[i] = offset + (PTR(ptr, i) - ptr); - } - -- if (!r) { -- unsigned size = RECSIZE_safe(db, ptr); -- if (!size) { -- syslog(LOG_ERR, "skiplist recovery %s: damaged record at %u, truncating here", -- db->fname, offset); -- filesize = offset; -- break; -- } -- -- if (PADDING_safe(db, ptr) != (uint32_t) -1) { -- syslog(LOG_ERR, "DBERROR: %s: offset %04X padding not -1", -- db->fname, offset); -- filesize = offset; -- break; -- } -+ /* check padding */ -+ if (!r && PADDING(ptr) != (uint32_t) -1) { -+ syslog(LOG_ERR, "DBERROR: %s: offset %04X padding not -1", -+ db->fname, offset); -+ r = CYRUSDB_IOERROR; -+ } - -- offset += size; -+ if (!r) { -+ offset += RECSIZE(ptr); - } - } - -@@ -2164,7 +2179,7 @@ static int recovery(struct dbengine *db, int flags) - } - - /* replay the log */ -- while (!r && offset < filesize) { -+ while (!r && offset < db->map_size) { - const char *p, *q; - - /* refresh map, so we see the writes we've just done */ -@@ -2176,7 +2191,7 @@ static int recovery(struct dbengine *db, int flags) - /* bugs in recovery truncates could have left some bogus zeros here */ - if (TYPE(ptr) == 0) { - int orig = offset; -- while (TYPE(ptr) == 0 && offset < filesize) { -+ while (TYPE(ptr) == 0 && offset < db->map_size) { - offset += 4; - ptr = db->map_base + offset; - } -@@ -2189,7 +2204,7 @@ static int recovery(struct dbengine *db, int flags) - - /* if this is a commit, we've processed everything in this txn */ - if (TYPE(ptr) == COMMIT) { -- offset += RECSIZE_safe(db, ptr); -+ offset += RECSIZE(ptr); - continue; - } - -@@ -2203,7 +2218,7 @@ static int recovery(struct dbengine *db, int flags) - } - - /* look ahead for a commit */ -- q = db->map_base + filesize; -+ q = db->map_base + db->map_size; - p = ptr; - for (;;) { - if (RECSIZE_safe(db, p) <= 0) { -@@ -2215,7 +2230,7 @@ static int recovery(struct dbengine *db, int flags) - p = q; - break; - } -- p += RECSIZE_safe(db, p); -+ p += RECSIZE(p); - if (p >= q) break; - if (TYPE(p) == COMMIT) break; - } -@@ -2224,7 +2239,16 @@ static int recovery(struct dbengine *db, int flags) - "skiplist recovery %s: found partial txn, not replaying", - db->fname); - -- filesize = offset; -+ /* no commit, we should truncate */ -+ if (ftruncate(db->fd, offset) < 0) { -+ syslog(LOG_ERR, -+ "DBERROR: skiplist recovery %s: ftruncate: %m", -+ db->fname); -+ r = CYRUSDB_IOERROR; -+ } -+ -+ /* set the map size back as well */ -+ db->map_size = offset; - - break; - } -@@ -2290,7 +2314,7 @@ static int recovery(struct dbengine *db, int flags) - } - offsetnet = htonl(offset); - -- lvl = LEVEL_safe(db, ptr); -+ lvl = LEVEL(ptr); - if (lvl > SKIPLIST_MAXLEVEL) { - syslog(LOG_ERR, - "DBERROR: skiplist recovery %s: node claims level %d (greater than max %d)", -@@ -2299,15 +2323,15 @@ static int recovery(struct dbengine *db, int flags) - } else { - /* NOTE - in the bogus case where a record with the same key already - * exists, there are three possible cases: -- * lvl == LEVEL_safe(db, keyptr) -+ * lvl == LEVEL(keyptr) - * * trivial: all to me, all mine to keyptr's FORWARD -- * lvl > LEVEL_safe(db, keyptr) - -+ * lvl > LEVEL(keyptr) - - * * all updateoffsets values should point to me -- * * up until LEVEL_safe(db, keyptr) set to keyptr's next values -+ * * up until LEVEL(keyptr) set to keyptr's next values - * (updateoffsets[i] should be keyptr in these cases) - * then point all my higher pointers are updateoffsets[i]'s - * FORWARD instead. -- * lvl < LEVEL_safe(db, keyptr) -+ * lvl < LEVEL(keyptr) - * * updateoffsets values up to lvl should point to me - * * all mine should point to keyptr's next values - * * from lvl up, all updateoffsets[i] should point to -@@ -2319,7 +2343,7 @@ static int recovery(struct dbengine *db, int flags) - */ - for (i = 0; i < lvl; i++) { - /* set our next pointers */ -- if (keyptr && i < LEVEL_safe(db, keyptr)) { -+ if (keyptr && i < LEVEL(keyptr)) { - /* need to replace the matching record key */ - newoffsets[i] = - htonl(FORWARD(keyptr, i)); -@@ -2338,9 +2362,9 @@ static int recovery(struct dbengine *db, int flags) - lseek(db->fd, FIRSTPTR(ptr) - db->map_base, SEEK_SET); - retry_write(db->fd, (char *) newoffsets, 4 * lvl); - -- if (keyptr && lvl < LEVEL_safe(db, keyptr)) { -+ if (keyptr && lvl < LEVEL(keyptr)) { - uint32_t newoffsetnet; -- for (i = lvl; i < LEVEL_safe(db, keyptr); i++) { -+ for (i = lvl; i < LEVEL(keyptr); i++) { - newoffsetnet = htonl(FORWARD(keyptr, i)); - /* replace 'updateoffsets' to point onwards */ - lseek(db->fd, -@@ -2356,22 +2380,21 @@ static int recovery(struct dbengine *db, int flags) - } - - /* move to next record */ -- unsigned size = RECSIZE_safe(db, ptr); -- if (!size) break; -- offset += size; -+ offset += RECSIZE(ptr); - } - -- /* didn't read the exact end? We should truncate */ -- if (offset < db->map_size) { -- if (ftruncate(db->fd, offset) < 0) { -- syslog(LOG_ERR, -- "DBERROR: skiplist recovery %s: ftruncate: %m", -- db->fname); -- r = CYRUSDB_IOERROR; -- } -+ if (libcyrus_config_getswitch(CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT)) { -+ /* refresh map, so we see the writes we've just done */ -+ map_refresh(db->fd, 0, &db->map_base, &db->map_len, db->map_size, -+ db->fname, 0); - -- /* set the map size back as well */ -- db->map_size = offset; -+ r = mycheckpoint(db); -+ -+ if (r || !(flags & RECOVERY_CALLER_LOCKED)) { -+ unlock(db); -+ } -+ -+ return r; - } - - /* fsync the recovered database */ -@@ -2404,16 +2427,13 @@ static int recovery(struct dbengine *db, int flags) - } - - if (!r && need_checkpoint) { -- /* refresh map, so we see the writes we've just done */ -- map_refresh(db->fd, 0, &db->map_base, &db->map_len, db->map_size, -- db->fname, 0); - r = mycheckpoint(db); - } - -- if (r || !(flags & RECOVERY_CALLER_LOCKED)) { -+ if(r || !(flags & RECOVERY_CALLER_LOCKED)) { - unlock(db); - } -- -+ - return r; - } - -diff --git a/lib/imapoptions b/lib/imapoptions -index fedc695..597e1c4 100644 ---- a/lib/imapoptions -+++ b/lib/imapoptions -@@ -169,7 +169,7 @@ are listed with ``<none>''. - affect LMTP delivery of messages directly to mailboxes via - plus-addressing. */ - --{ "annotation_db", "twoskip", STRINGLIST("berkeley", "berkeley-hash", "skiplist", "twoskip")} -+{ "annotation_db", "skiplist", STRINGLIST("berkeley", "berkeley-hash", "skiplist", "twoskip")} - /* The cyrusdb backend to use for mailbox annotations. */ - - { "annotation_db_path", NULL, STRING } -@@ -508,7 +508,7 @@ Blank lines and lines beginning with ``#'' are ignored. - specifies the actual key used for iSchedule DKIM signing within the - domain. */ - --{ "duplicate_db", "twoskip", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip")} -+{ "duplicate_db", "skiplist", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip")} - /* The cyrusdb backend to use for the duplicate delivery suppression - and sieve. */ - -@@ -1013,10 +1013,10 @@ Blank lines and lines beginning with ``#'' are ignored. - { "maxword", 131072, INT } - /* Maximum size of a single word for the parser. Default 128k */ - --{ "mboxkey_db", "twoskip", STRINGLIST("berkeley", "skiplist", "twoskip") } -+{ "mboxkey_db", "skiplist", STRINGLIST("berkeley", "skiplist", "twoskip") } - /* The cyrusdb backend to use for mailbox keys. */ - --{ "mboxlist_db", "twoskip", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "twoskip")} -+{ "mboxlist_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "twoskip")} - /* The cyrusdb backend to use for the mailbox list. */ - - { "mboxlist_db_path", NULL, STRING } -@@ -1376,7 +1376,7 @@ If all partitions are over that limit, this feature is not used anymore. - /* Unix domain socket that ptloader listens on. - (defaults to configdir/ptclient/ptsock) */ - --{ "ptscache_db", "twoskip", STRINGLIST("berkeley", "berkeley-hash", "skiplist", "twoskip")} -+{ "ptscache_db", "skiplist", STRINGLIST("berkeley", "berkeley-hash", "skiplist", "twoskip")} - /* The cyrusdb backend to use for the pts cache. */ - - { "ptscache_db_path", NULL, STRING } -@@ -1401,7 +1401,7 @@ If all partitions are over that limit, this feature is not used anymore. - /* This specifies the Class Selector or Differentiated Services Code Point - designation on IP headers (in the ToS field). */ - --{ "quota_db", "twoskip", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "quotalegacy", "twoskip")} -+{ "quota_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "quotalegacy", "twoskip")} - /* The cyrusdb backend to use for quotas. */ - - { "quota_db_path", NULL, STRING } -@@ -1521,7 +1521,7 @@ If all partitions are over that limit, this feature is not used anymore. - recommended for most cases - it's a good compromise which - keeps words separate. */ - --{ "seenstate_db", "twoskip", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "twoskip")} -+{ "seenstate_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "twoskip")} - /* The cyrusdb backend to use for the seen state. */ - - { "sendmail", "/usr/lib/sendmail", STRING } -@@ -1715,7 +1715,7 @@ product version in the capabilities */ - { "statuscache", 0, SWITCH } - /* Enable/disable the imap status cache. */ - --{ "statuscache_db", "twoskip", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip") } -+{ "statuscache_db", "skiplist", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip") } - /* The cyrusdb backend to use for the imap status cache. */ - - { "statuscache_db_path", NULL, STRING } -@@ -1880,7 +1880,7 @@ product version in the capabilities */ - /* File containing the private key belonging to the certificate in - tls_server_cert. */ - --{ "tls_sessions_db", "twoskip", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip")} -+{ "tls_sessions_db", "skiplist", STRINGLIST("berkeley", "berkeley-nosync", "berkeley-hash", "berkeley-hash-nosync", "skiplist", "sql", "twoskip")} - /* The cyrusdb backend to use for the TLS cache. */ - - { "tls_sessions_db_path", NULL, STRING } -@@ -1944,7 +1944,7 @@ product version in the capabilities */ - this user. NOTE: This must be an existing local user name with an - INBOX, NOT an email address! */ - --{ "zoneinfo_db", "twoskip", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "twoskip")} -+{ "zoneinfo_db", "skiplist", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "twoskip")} - /* The cyrusdb backend to use for zoneinfo. */ - - { "zoneinfo_db_path", NULL, STRING }
View file
cyrus-imapd-2.5.tar.gz/Makefile.am
Changed
@@ -629,6 +629,7 @@ lib/sysexits.h \ lib/times.h \ lib/tok.h \ + lib/vparse.h \ lib/wildmat.h \ lib/xmalloc.h nobase_include_HEADERS = sieve/sieve_interface.h @@ -1099,6 +1100,7 @@ lib/strarray.c \ lib/strhash.c \ lib/util.c \ + lib/vparse.c \ lib/xmalloc.c \ lib/xstrlcat.c \ lib/xstrlcpy.c @@ -1465,7 +1467,7 @@ $(LN_S) -f imtest nntptest && \ $(LN_S) -f imtest pop3test && \ $(LN_S) -f imtest sivtest && \ - $(LN_S) -f imtest smpttest && \ + $(LN_S) -f imtest smtptest && \ $(LN_S) -f imtest synctest SUFFIXES = .fig.png
View file
cyrus-imapd-2.5.tar.gz/doc/internal/unit-tests.html
Changed
@@ -562,7 +562,9 @@ Functions with this signature are automatically discovered in the source code by the Cyrus unit test infrastructure, so all you have to do is write the function. Later, a CUnit test named "whatever" will be -created automatically for your <tt>test_whatever</tt> function. +created automatically for your <tt>test_whatever</tt> function. Note that the +opening curly brace must be on the next line or the unit test infrastructure +will not find the function. </dd> <dt><span class="note">(b)</span></dt>
View file
cyrus-imapd-2.5.tar.gz/imap/carddav_db.c
Changed
@@ -635,3 +635,39 @@ return 0; } + +EXPORTED void carddav_make_entry(struct vparse_card *vcard, struct carddav_data *cdata) +{ + struct vparse_entry *ventry; + + for (ventry = vcard->properties; ventry; ventry = ventry->next) { + const char *name = ventry->name; + const char *propval = ventry->v.value; + + if (!name) continue; + if (!propval) continue; + + if (!strcmp(name, "uid")) { + cdata->vcard_uid = propval; + } + else if (!strcmp(name, "n")) { + cdata->name = propval; + } + else if (!strcmp(name, "fn")) { + cdata->fullname = propval; + } + else if (!strcmp(name, "nickname")) { + cdata->nickname = propval; + } + else if (!strcmp(name, "email")) { + /* XXX - insert if primary */ + strarray_append(&cdata->emails, propval); + } + else if (!strcmp(name, "x-addressbookserver-member")) { + const char *item = propval; + if (!strncmp(item, "urn:uuid:", 9)) + strarray_append(&cdata->member_uids, item+9); + } + } + +}
View file
cyrus-imapd-2.5.tar.gz/imap/carddav_db.h
Changed
@@ -48,6 +48,7 @@ #include "dav_db.h" #include "strarray.h" +#include "vparse.h" struct carddav_db; @@ -118,4 +119,7 @@ /* abort transaction */ int carddav_abort(struct carddav_db *carddavdb); +/* create carddav_data from vparse_card */ +void carddav_make_entry(struct vparse_card *vcard, struct carddav_data *cdata); + #endif /* CARDDAV_DB_H */
View file
cyrus-imapd-2.5.tar.gz/imap/dlist.c
Changed
@@ -383,7 +383,7 @@ dl->type = DL_NIL; } -void dlist_makemap(struct dlist *dl, const char *val, size_t len) +EXPORTED void dlist_makemap(struct dlist *dl, const char *val, size_t len) { if (!dl) return; _dlist_clean(dl); @@ -416,7 +416,7 @@ return dl; } -struct dlist *dlist_newpklist(struct dlist *parent, const char *name) +EXPORTED struct dlist *dlist_newpklist(struct dlist *parent, const char *name) { struct dlist *dl = dlist_child(parent, name); dl->type = DL_ATOMLIST; @@ -459,7 +459,7 @@ return dl; } -struct dlist *dlist_sethex64(struct dlist *parent, const char *name, bit64 val) +EXPORTED struct dlist *dlist_sethex64(struct dlist *parent, const char *name, bit64 val) { struct dlist *dl = dlist_child(parent, name); dlist_makehex64(dl, val); @@ -938,7 +938,7 @@ return EOF; } -char dlist_parse_asatomlist(struct dlist **dlp, int parsekey, +EXPORTED char dlist_parse_asatomlist(struct dlist **dlp, int parsekey, struct protstream *in) { char c = dlist_parse(dlp, parsekey, in); @@ -1280,7 +1280,7 @@ return 1; } -int dlist_isatomlist(const struct dlist *dl) +EXPORTED int dlist_isatomlist(const struct dlist *dl) { if (!dl) return 0; return (dl->type == DL_ATOMLIST); @@ -1314,7 +1314,7 @@ /* XXX - these ones aren't const, because they can change * things... */ -int dlist_ishex64(struct dlist *dl) +EXPORTED int dlist_ishex64(struct dlist *dl) { bit64 tmp; @@ -1386,7 +1386,7 @@ return dlist_todate(child, valp); } -int dlist_gethex64(struct dlist *parent, const char *name, bit64 *valp) +EXPORTED int dlist_gethex64(struct dlist *parent, const char *name, bit64 *valp) { struct dlist *child = dlist_getchild(parent, name); return dlist_tohex64(child, valp);
View file
cyrus-imapd-2.5.tar.gz/imap/http_caldav.c
Changed
@@ -3346,6 +3346,10 @@ node = xml_add_prop(HTTP_OK, fctx->ns[NS_DAV], &propstat[PROPSTAT_OK], name, ns, NULL, 0); + /* named calendars are only used for scheduling */ + if (cal && !(namespace_calendar.allow & ALLOW_CAL_SCHED)) + return HTTP_NOT_FOUND; + buf_reset(&fctx->buf); buf_printf(&fctx->buf, "%s/user/%.*s/%s", namespace_calendar.prefix, (int) fctx->req_tgt->userlen, fctx->req_tgt->user, @@ -5265,27 +5269,17 @@ int caladdress_lookup(const char *addr, struct sched_param *param) { - char *p; + const char *userid = addr; int islocal = 1, found = 1; - static char userid[MAX_MAILBOX_BUFFER]; memset(param, 0, sizeof(struct sched_param)); if (!addr) return HTTP_NOT_FOUND; - p = (char *) addr; - if (!strncasecmp(addr, "mailto:", 7)) p += 7; + if (!strncasecmp(userid, "mailto:", 7)) userid += 7; /* XXX Do LDAP/DB/socket lookup to see if user is local */ /* XXX Hack until real lookup stuff is written */ - strlcpy(userid, p, sizeof(userid)); - if ((p = strchr(userid, '@')) && !(*p = '\0') && *++p) { - struct strlist *domains = cua_domains; - - for (; domains && strcmp(p, domains->s); domains = domains->next); - - if (!domains) islocal = 0; - } if (islocal) { /* User is in a local domain */ @@ -5295,7 +5289,7 @@ struct mboxname_parts parts; if (!found) return HTTP_NOT_FOUND; - else param->userid = userid; + else param->userid = xstrdupnull(userid); /* XXX - memleak */ /* Lookup user's cal-home-set to see if its on this server */ @@ -5305,6 +5299,7 @@ mboxname_free_parts(&parts); r = http_mlookup(mailboxname, &mbentry, NULL); + if (!r) { param->server = xstrdupnull(mbentry->server); /* XXX - memory leak */ mboxlist_entry_free(&mbentry);
View file
cyrus-imapd-2.5.tar.gz/imap/http_carddav.c
Changed
@@ -50,7 +50,6 @@ #include <syslog.h> -#include <libical/vcc.h> #include <libxml/tree.h> #include <libxml/uri.h> #include <sys/types.h> @@ -79,6 +78,7 @@ #include "times.h" #include "util.h" #include "version.h" +#include "vparse.h" #include "xmalloc.h" #include "xstrlcat.h" #include "xstrlcpy.h" @@ -105,10 +105,6 @@ struct mailbox *mailbox, struct carddav_db *carddavdb, unsigned flags); -static VObject *vcard_string_as_vobject(const char *str) -{ - return Parse_MIME(str, strlen(str)); -} static int propfind_getcontenttype(const xmlChar *name, xmlNsPtr ns, struct propfind_ctx *fctx, xmlNodePtr resp, @@ -128,16 +124,33 @@ static int report_card_multiget(struct transaction_t *txn, xmlNodePtr inroot, struct propfind_ctx *fctx); -static int store_resource(struct transaction_t *txn, VObject *vcard, +static int store_resource(struct transaction_t *txn, struct vparse_card *vcard, struct mailbox *mailbox, const char *resource, struct carddav_db *carddavdb, int overwrite, unsigned flags); +static struct vparse_state *vcard_string_as_vparser(const char *str) { + struct vparse_state *vparser; + int vr; + + vparser = (struct vparse_state *) xzmalloc(sizeof(struct vparse_state)); + vparser->base = str; + vr = vparse_parse(vparser, 0); + if (vr) return NULL; // XXX report error + + return vparser; +} + +static void free_vparser(void *vparser) { + vparse_free((struct vparse_state *) vparser); + free(vparser); +} + static struct mime_type_t carddav_mime_types[] = { /* First item MUST be the default type and storage format */ { "text/vcard; charset=utf-8", "3.0", NULL, "vcf", NULL, - (void * (*)(const char*)) &vcard_string_as_vobject, - (void (*)(void *)) &cleanVObject, NULL, NULL + (void * (*)(const char*)) &vcard_string_as_vparser, + (void (*)(void *)) &free_vparser, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -564,16 +577,15 @@ { int r; struct buf msg_buf = BUF_INITIALIZER; - VObject *vcard; + struct vparse_state *vparser; /* Load message containing the resource and parse vCard data */ r = mailbox_map_record(src_mbox, src_rec, &msg_buf); if (r) return r; - vcard = Parse_MIME(buf_base(&msg_buf) + src_rec->header_size, - src_rec->size - src_rec->header_size); + vparser = vcard_string_as_vparser(buf_base(&msg_buf) + src_rec->header_size); buf_free(&msg_buf); - if (!vcard) { + if (!vparser || !vparser->card || !vparser->card->objects) { txn->error.precond = CARDDAV_VALID_DATA; return HTTP_FORBIDDEN; } @@ -582,11 +594,10 @@ mailbox_unlock_index(src_mbox, NULL); /* Store source resource at destination */ - r = store_resource(txn, vcard, dest_mbox, dest_rsrc, dest_davdb, + r = store_resource(txn, vparser->card->objects, dest_mbox, dest_rsrc, dest_davdb, overwrite, flags); - cleanVObject(vcard); - cleanStrTbl(); + free_vparser(vparser); return r; } @@ -606,18 +617,22 @@ unsigned flags) { int ret; - VObject *vcard = NULL; + struct vparse_state *vparser = NULL; /* Parse and validate the vCard data */ - vcard = mime->from_string(buf_cstring(&txn->req_body.payload)); - if (!vcard || strcmp(vObjectName(vcard), "VCARD")) { + vparser = mime->from_string(buf_cstring(&txn->req_body.payload)); + if (!vparser || + !vparser->card || + !vparser->card->objects || + !vparser->card->objects->type || + strcmp(vparser->card->objects->type, "vcard")) { txn->error.precond = CARDDAV_VALID_DATA; ret = HTTP_FORBIDDEN; goto done; } /* Store resource at target */ - ret = store_resource(txn, vcard, mailbox, txn->req_tgt.resource, + ret = store_resource(txn, vparser->card->objects, mailbox, txn->req_tgt.resource, davdb, OVERWRITE_CHECK, flags); if (flags & PREFER_REP) { @@ -657,10 +672,8 @@ } done: - if (vcard) { - cleanVObject(vcard); - cleanStrTbl(); - } + if (vparser) + free_vparser(vparser); return ret; } @@ -932,19 +945,19 @@ /* Store the vCard data in the specified addressbook/resource */ -static int store_resource(struct transaction_t *txn, VObject *vcard, +static int store_resource(struct transaction_t *txn, struct vparse_card *vcard, struct mailbox *mailbox, const char *resource, struct carddav_db *carddavdb, int overwrite, unsigned flags) { int ret = HTTP_CREATED, r; - VObjectIterator i; + struct vparse_entry *ventry; struct carddav_data *cdata; FILE *f = NULL; struct index_record oldrecord; struct stagemsg *stage; char *header; - char *version = NULL, *uid = NULL, *fullname = NULL; + const char *version = NULL, *uid = NULL, *fullname = NULL; quota_t qdiffs[QUOTA_NUMRESOURCES] = QUOTA_DIFFS_DONTCARE_INITIALIZER; uint32_t expunge_uid = 0; time_t now = time(NULL); @@ -952,33 +965,27 @@ struct appendstate as; /* Fetch some important properties */ - initPropIterator(&i, vcard); - while (moreIteration(&i)) { - VObject *prop = nextVObject(&i); - const char *name = vObjectName(prop); - const wchar_t *value = NULL; - - if (!strcmp(name, "VERSION")) { - value = vObjectUStringZValue(prop); - if (value) { - version = fakeCString(value); - if (strcmp(version, "3.0")) { - txn->error.precond = CARDDAV_SUPP_DATA; - ret = HTTP_FORBIDDEN; - goto done; - } + for (ventry = vcard->properties; ventry; ventry = ventry->next) { + const char *name = ventry->name; + const char *propval = ventry->v.value; + + if (!name) continue; + if (!propval) continue; + + if (!strcmp(name, "version")) { + version = propval; + if (strcmp(version, "3.0")) { + txn->error.precond = CARDDAV_SUPP_DATA; + ret = HTTP_FORBIDDEN; + goto done; } } - else if (!strcmp(name, "UID")) { - value = vObjectUStringZValue(prop); - if (value) - uid = fakeCString(value); - } - else if (!strcmp(name, "FN")) { - value = vObjectUStringZValue(prop); - if (value) - fullname = fakeCString(value); - } + + else if (!strcmp(name, "uid")) + uid = propval; + + else if (!strcmp(name, "fn")) + fullname = propval; } /* Sanity check data */ @@ -1145,9 +1152,5 @@ append_removestage(stage); done: - free(version); - free(uid); - free(fullname); - return ret; }
View file
cyrus-imapd-2.5.tar.gz/imap/http_dav.c
Changed
@@ -861,8 +861,6 @@ } } - fctx->record = NULL; - return 0; } @@ -1815,6 +1813,9 @@ if (!fctx->req_tgt->collection || /* until we support sync on cal-home */ !fctx->mailbox || fctx->record) return HTTP_NOT_FOUND; + /* not defined on the top-level collection either (aka #calendars) */ + if (!fctx->req_tgt->collection) return HTTP_NOT_FOUND; + buf_reset(&fctx->buf); buf_printf(&fctx->buf, SYNC_TOKEN_URL_SCHEME "%u-" MODSEQ_FMT, fctx->mailbox->i.uidvalidity, @@ -2533,14 +2534,15 @@ } } - if (!mboxname_userownsmailbox(httpd_userid, txn->req_tgt.mboxname)) { + if (!mboxname_userownsmailbox(httpd_userid, mbentry->name)) { /* Check ACL for current user */ - rights = mbentry ? cyrus_acl_myrights(httpd_authstate, mbentry->acl) : 0; + rights = mbentry->acl ? cyrus_acl_myrights(httpd_authstate, mbentry->acl) : 0; if (!(rights & DACL_ADMIN)) { /* DAV:need-privileges */ txn->error.precond = DAV_NEED_PRIVS; txn->error.resource = txn->req_tgt.path; txn->error.rights = DACL_ADMIN; + mboxlist_entry_free(&mbentry); return HTTP_NO_PRIVS; } } @@ -2561,16 +2563,6 @@ /* Local Mailbox */ - /* Open mailbox for writing */ - r = mailbox_open_iwl(txn->req_tgt.mboxname, &mailbox); - if (r) { - syslog(LOG_ERR, "http_mailbox_open(%s) failed: %s", - txn->req_tgt.mboxname, error_message(r)); - txn->error.desc = error_message(r); - ret = HTTP_SERVER_ERROR; - goto done; - } - /* Parse the ACL body */ ret = parse_xml_body(txn, &root); if (!ret && !root) { @@ -2707,6 +2699,9 @@ BAD_CAST "read")) rights |= DACL_READ; else if (!xmlStrcmp(priv->name, + BAD_CAST "read-free-busy")) + rights |= DACL_READFB; + else if (!xmlStrcmp(priv->name, BAD_CAST "write")) rights |= DACL_WRITE; else if (!xmlStrcmp(priv->name, @@ -2716,6 +2711,12 @@ BAD_CAST "write-properties")) rights |= DACL_WRITEPROPS; else if (!xmlStrcmp(priv->name, + BAD_CAST "remove-resource")) + rights |= DACL_RMRSRC; + else if (!xmlStrcmp(priv->name, + BAD_CAST "remove-collection")) + rights |= DACL_RMCOL; + else if (!xmlStrcmp(priv->name, BAD_CAST "bind")) rights |= DACL_BIND; else if (!xmlStrcmp(priv->name, @@ -2775,27 +2776,30 @@ } } - cyrus_acl_masktostr(rights, rightstr); - buf_printf(&acl, "%s%s\t%s\t", - deny ? "-" : "", userid, rightstr); + /* gotta have something to do! */ + if (rights) { + cyrus_acl_masktostr(rights, rightstr); + buf_reset(&acl); + buf_printf(&acl, "%s%s", deny ? "-" : "+", rightstr); + + r = mboxlist_setacl(&httpd_namespace, txn->req_tgt.mboxname, userid, buf_cstring(&acl), + /*isadmin*/1, httpd_userid, httpd_authstate); + if (r) { + syslog(LOG_ERR, "mboxlist_setacl(%s) failed: %s", + txn->req_tgt.mboxname, error_message(r)); + txn->error.desc = error_message(r); + ret = HTTP_SERVER_ERROR; + goto done; + } + } } } - if ((r = mboxlist_sync_setacls(txn->req_tgt.mboxname, buf_cstring(&acl)))) { - syslog(LOG_ERR, "mboxlist_sync_setacls(%s) failed: %s", - txn->req_tgt.mboxname, error_message(r)); - txn->error.desc = error_message(r); - ret = HTTP_SERVER_ERROR; - goto done; - } - mailbox_set_acl(mailbox, buf_cstring(&acl), 0); - response_header(HTTP_OK, txn); done: buf_free(&acl); if (indoc) xmlFreeDoc(indoc); - mailbox_close(&mailbox); return ret; } @@ -3298,6 +3302,7 @@ mboxevent_extract_record(mboxevent, mailbox, &record); mboxevent_extract_mailbox(mboxevent, mailbox); mboxevent_set_numunseen(mboxevent, mailbox, -1); + mboxevent_set_access(mboxevent, NULL, NULL, httpd_userid, txn->req_tgt.mboxname, 0); } /* Do any special processing */ @@ -4124,19 +4129,27 @@ memset(&fctx, 0, sizeof(struct propfind_ctx)); /* Parse the path */ - if (fparams->parse_path && - (r = fparams->parse_path(txn->req_uri->path, - &txn->req_tgt, &txn->error.desc))) return r; + if (fparams->parse_path) { + r = fparams->parse_path(txn->req_uri->path, &txn->req_tgt, &txn->error.desc); + if (r) return r; + } /* Make sure method is allowed */ - if (!(txn->req_tgt.allow & ALLOW_DAV)) return HTTP_NOT_ALLOWED; + if (!(txn->req_tgt.allow & ALLOW_DAV)) + return HTTP_NOT_ALLOWED; /* Check Depth */ hdr = spool_getheader(txn->req_hdrs, "Depth"); if (!hdr || !strcmp(hdr[0], "infinity")) { depth = 2; } - else if (hdr && ((sscanf(hdr[0], "%u", &depth) != 1) || (depth > 1))) { + else if (!strcmp(hdr[0], "1")) { + depth = 1; + } + else if (!strcmp(hdr[0], "0")) { + depth = 0; + } + else { txn->error.desc = "Illegal Depth value\r\n"; return HTTP_BAD_REQUEST; } @@ -4209,7 +4222,7 @@ /* Make sure its a propfind element */ if (xmlStrcmp(root->name, BAD_CAST "propfind")) { - txn->error.desc = "Missing propfind element in PROFIND request\r\n"; + txn->error.desc = "Missing propfind element in PROPFIND request\r\n"; ret = HTTP_BAD_REQUEST; goto done; } @@ -4218,16 +4231,18 @@ for (cur = root->children; cur && cur->type != XML_ELEMENT_NODE; cur = cur->next); + if (!cur) { + txn->error.desc = "Missing child node element in PROPFIND request\r\n"; + ret = HTTP_BAD_REQUEST; + goto done; + } + /* Add propfind type to our header cache */ spool_cache_header(xstrdup(":type"), xstrdup((const char *) cur->name), txn->req_hdrs); /* Make sure its a known element */ - if (!cur) { - ret = HTTP_BAD_REQUEST; - goto done; - } - else if (!xmlStrcmp(cur->name, BAD_CAST "allprop")) { + if (!xmlStrcmp(cur->name, BAD_CAST "allprop")) { fctx.mode = PROPFIND_ALL; } else if (!xmlStrcmp(cur->name, BAD_CAST "propname")) { @@ -4260,7 +4275,8 @@ } /* Start construction of our multistatus response */ - if (!(root = init_xml_response("multistatus", NS_DAV, root, ns))) { + root = init_xml_response("multistatus", NS_DAV, root, ns); + if (!root) { ret = HTTP_SERVER_ERROR; txn->error.desc = "Unable to create XML response\r\n"; goto done; @@ -4301,23 +4317,20 @@ if (!txn->req_tgt.collection && (!depth || !(fctx.prefer & PREFER_NOROOT))) { /* Add response for principal or home-set collection */ - struct mailbox *mailbox = NULL; - if (*txn->req_tgt.mboxname) { /* Open mailbox for reading */ - if ((r = mailbox_open_irl(txn->req_tgt.mboxname, &mailbox))) { + if ((r = mailbox_open_irl(txn->req_tgt.mboxname, &fctx.mailbox))) { syslog(LOG_INFO, "mailbox_open_irl(%s) failed: %s", txn->req_tgt.mboxname, error_message(r)); txn->error.desc = error_message(r); ret = HTTP_SERVER_ERROR; goto done; } - fctx.mailbox = mailbox; } xml_add_response(&fctx, 0, 0); - mailbox_close(&mailbox); + mailbox_close(&fctx.mailbox); } if (depth > 0) { @@ -4827,6 +4840,7 @@ /* XXX Handle Depth (cal-home-set at toplevel) */ + memset(&istate, 0, sizeof(struct index_state)); istate.map = NULL; /* Open mailbox for reading */
View file
cyrus-imapd-2.5.tar.gz/imap/imapd.c
Changed
@@ -318,6 +318,7 @@ { "METADATA", 2 }, { "LIST-EXTENDED", 2 }, { "LIST-STATUS", 2 }, + { "LIST-MYRIGHTS", 2 }, /* not standard */ { "WITHIN", 2 }, { "QRESYNC", 2 }, { "SCAN", 2 }, @@ -1603,10 +1604,12 @@ prot_printf(imapd_out, "%s OK %s\r\n", tag.s, error_message(IMAP_OK_COMPLETED)); - // Translate the name to external - mboxname_hiersep_toexternal(&imapd_namespace, imapd_userid, config_virtdomains ? strcspn(imapd_userid, "@") : 0); - telemetry_rusage(imapd_userid); - mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid, config_virtdomains ? strcspn(imapd_userid, "@") : 0); + if (imapd_userid && *imapd_userid) { + // Translate the name to external + mboxname_hiersep_toexternal(&imapd_namespace, imapd_userid, config_virtdomains ? strcspn(imapd_userid, "@") : 0); + telemetry_rusage(imapd_userid); + mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid, config_virtdomains ? strcspn(imapd_userid, "@") : 0); + } return; } @@ -5677,15 +5680,13 @@ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r)); goto done; - } else { // (r) - prot_printf(imapd_out, "%s OK %s\r\n", tag, error_message(IMAP_OK_COMPLETED)); - goto done; - } // (r) #endif // USE_AUTOCREATE if (specialuse.len) { - r = annotatemore_write(mailboxname, "/specialuse", imapd_userid, &specialuse); + const char *userid = mboxname_to_userid(mailboxname); + if (!userid) userid = imapd_userid; + r = annotatemore_write(mailboxname, "/specialuse", userid, &specialuse); if (r) { /* XXX - failure here SHOULD cause a cleanup of the created mailbox */ syslog( @@ -6913,39 +6914,50 @@ error_message(IMAP_OK_COMPLETED)); } +static int printmyrights(const char *extname, mbentry_t *mbentry) +{ + int rights = 0; + char str[ACL_MAXSTR]; + + rights = cyrus_acl_myrights(imapd_authstate, mbentry->acl); + + /* Add in implicit rights */ + if (imapd_userisadmin) { + rights |= ACL_LOOKUP|ACL_ADMIN; + } + else if (mboxname_userownsmailbox(imapd_userid, mbentry->name)) { + rights |= config_implicitrights; + } + + if (!(rights & (ACL_LOOKUP|ACL_READ|ACL_INSERT|ACL_CREATE|ACL_DELETEMBOX|ACL_ADMIN))) { + return IMAP_MAILBOX_NONEXISTENT; + } + + prot_printf(imapd_out, "* MYRIGHTS "); + prot_printastring(imapd_out, extname); + prot_printf(imapd_out, " "); + prot_printastring(imapd_out, cyrus_acl_masktostr(rights, str)); + prot_printf(imapd_out, "\r\n"); + + return 0; +} + /* * Perform a MYRIGHTS command */ static void cmd_myrights(const char *tag, const char *name) { char mailboxname[MAX_MAILBOX_BUFFER]; - int r, rights = 0; - char str[ACL_MAXSTR]; mbentry_t *mbentry = NULL; + int r; r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name, imapd_userid, mailboxname); - if (!r) { - r = mlookup(tag, name, mailboxname, &mbentry); - } + if (!r) r = mlookup(tag, name, mailboxname, &mbentry); if (r == IMAP_MAILBOX_MOVED) return; - if (!r) { - rights = cyrus_acl_myrights(imapd_authstate, mbentry->acl); - - /* Add in implicit rights */ - if (imapd_userisadmin) { - rights |= ACL_LOOKUP|ACL_ADMIN; - } - else if (mboxname_userownsmailbox(imapd_userid, mailboxname)) { - rights |= config_implicitrights; - } - - if (!(rights & (ACL_LOOKUP|ACL_READ|ACL_INSERT|ACL_CREATE|ACL_DELETEMBOX|ACL_ADMIN))) { - r = IMAP_MAILBOX_NONEXISTENT; - } - } + if (!r) r = printmyrights(name, mbentry); mboxlist_entry_free(&mbentry); @@ -6955,12 +6967,8 @@ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r)); return; } - - prot_printf(imapd_out, "* MYRIGHTS "); - prot_printastring(imapd_out, name); - prot_printf(imapd_out, " "); - prot_printastring(imapd_out, cyrus_acl_masktostr(rights, str)); - prot_printf(imapd_out, "\r\n%s OK %s\r\n", tag, + + prot_printf(imapd_out, "%s OK %s\r\n", tag, error_message(IMAP_OK_COMPLETED)); } @@ -7070,7 +7078,7 @@ prot_putc('(', o); for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++) { if (q->limits[res] >= 0) { - prot_printf(o, "%s%s " QUOTA_T_FMT " %d", + prot_printf(o, "%s%s " QUOTA_T_FMT " " QUOTA_T_FMT, sep, quota_names[res], q->useds[res]/quota_units[res], q->limits[res]); @@ -7088,7 +7096,7 @@ prot_putc('(', o); for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++) { if (q->limits[res] >= 0) { - prot_printf(o, "%s%s %d", + prot_printf(o, "%s%s " QUOTA_T_FMT, sep, quota_names[res], q->limits[res]); sep = " "; @@ -7308,7 +7316,7 @@ */ void cmd_setquota(const char *tag, const char *quotaroot) { - int newquotas[QUOTA_NUMRESOURCES]; + quota_t newquotas[QUOTA_NUMRESOURCES]; int res; int c; int force = 0; @@ -7425,7 +7433,7 @@ prot_printf(imapd_out, "%s NO %s\r\n", tag, error_message(r)); return; } - + prot_printf(imapd_out, "%s OK %s\r\n", tag, error_message(IMAP_OK_COMPLETED)); return; @@ -10986,6 +10994,8 @@ args->ret |= LIST_RET_SUBSCRIBED; else if (!strcmp(buf.s, "children")) args->ret |= LIST_RET_CHILDREN; + else if (!strcmp(buf.s, "myrights")) + args->ret |= LIST_RET_MYRIGHTS; else if (!strcmp(buf.s, "special-use")) args->ret |= LIST_RET_SPECIALUSE; else if (!strcmp(buf.s, "status")) { @@ -11463,6 +11473,11 @@ print_statusline(mboxname, listargs->statusitems, &sdata); } + if ((listargs->ret & LIST_RET_MYRIGHTS) && + !(attributes & MBOX_ATTRIBUTE_NOSELECT)) { + /*ignore result*/printmyrights(mboxname, mbentry); + } + done: mboxlist_entry_free(&mbentry); }
View file
cyrus-imapd-2.5.tar.gz/imap/imapd.h
Changed
@@ -312,7 +312,8 @@ LIST_RET_SUBSCRIBED = (1<<0), LIST_RET_CHILDREN = (1<<1), LIST_RET_SPECIALUSE = (1<<2), - LIST_RET_STATUS = (1<<3) + LIST_RET_STATUS = (1<<3), + LIST_RET_MYRIGHTS = (1<<4) }; /* Bitmask for List name attributes */ @@ -335,7 +336,7 @@ /* Bitmask for client capabilities */ enum { CAPA_CONDSTORE = (1<<0), - CAPA_QRESYNC = (1<<1) + CAPA_QRESYNC = (1<<1) }; /* Bitmask for urlfetch params */
View file
cyrus-imapd-2.5.tar.gz/imap/index.c
Changed
@@ -329,6 +329,11 @@ if (r) goto fail; } + if (state->mailbox->mbtype & MBTYPES_NONIMAP) { + r = IMAP_MAILBOX_BADTYPE; + goto fail; + } + /* initialise the index_state */ index_refresh(state); @@ -344,6 +349,7 @@ return 0; fail: + mailbox_close(&state->mailbox); free(state->mboxname); free(state->userid); free(state); @@ -2785,10 +2791,6 @@ for (msgno = 1; msgno <= state->exists; msgno++) { im = &state->map[msgno-1]; - /* we don't report flag updates if it's been expunged */ - if (im->system_flags & FLAG_EXPUNGED) - continue; - /* report if it's changed since last told */ if (im->modseq > im->told_modseq) index_printflags(state, msgno, printuid, printmodseq); @@ -3208,6 +3210,14 @@ unsigned long start_octet, unsigned long octet_count, struct protstream *pout, unsigned long *outsize) { + /* dumbass eM_Client sends this: + * A4 APPEND "INBOX.Junk Mail" () "14-Jul-2013 17:01:02 +0000" + * CATENATE (URL "/INBOX/;uid=83118/;section=TEXT.MIME" + * URL "/INBOX/;uid=83118/;section=TEXT") + * + * genius. I can sort of see how TEXT.MIME kinda == "HEADER", + * so there we go */ + static char text_mime[] = "HEADER"; const char *data, *msg_base = 0; size_t msg_size = 0; const char *cacheitem; @@ -3219,6 +3229,9 @@ struct mailbox *mailbox = state->mailbox; struct index_record record; + if (!strcasecmp(section, "TEXT.MIME")) + section = text_mime; + if (outsize) *outsize = 0; r = index_reload_record(state, msgno, &record);
View file
cyrus-imapd-2.5.tar.gz/imap/mailbox.c
Changed
@@ -51,9 +51,6 @@ #elif defined(HAVE_STDINT_H) # include <stdint.h> #endif -#ifdef WITH_DAV -#include <libical/vcc.h> -#endif #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -107,6 +104,7 @@ #include "statuscache.h" #include "strarray.h" #include "sync_log.h" +#include "vparse.h" #include "xmalloc.h" #include "xstrlcpy.h" @@ -270,14 +268,9 @@ /* for efficient FastMail interface display */ { "x-spam-score", 3 }, - { "x-spam-hits", 3 }, - { "x-spam-source", 3 }, { "x-resolved-to", 3 }, { "x-delivered-to", 3 }, { "x-mail-from", 3 }, - { "x-truedomain", 3 }, - { "x-truedomain-dkim", 3 }, - { "x-truedomain-spf", 3 }, { "x-truedomain-domain", 3 }, /* things to never cache */ @@ -2670,10 +2663,9 @@ r = carddav_delete(carddavdb, cdata->dav.rowid, 0); } else { - const char *uid = NULL, *fullname = NULL, *nickname = NULL; struct buf msg_buf = BUF_INITIALIZER; - VObjectIterator i; - VObject *vcard; + struct vparse_state vparser; + int vr; /* already seen this message, so do we update it? No */ if (old) goto done; @@ -2682,42 +2674,35 @@ r = mailbox_map_record(mailbox, new, &msg_buf); if (r) goto done; - vcard = Parse_MIME(buf_cstring(&msg_buf) + new->header_size, - new->size - new->header_size); + memset(&vparser, 0, sizeof(struct vparse_state)); + vparser.base = buf_cstring(&msg_buf) + new->header_size; + vr = vparse_parse(&vparser, 0); buf_free(&msg_buf); - if (!vcard) goto done; - - initPropIterator(&i, vcard); - while (moreIteration(&i)) { - VObject *prop = nextVObject(&i); - const char *name = vObjectName(prop); - - if (!strcmp(name, "UID")) { - uid = fakeCString(vObjectUStringZValue(prop)); - } - else if (!strcmp(name, "FN")) { - fullname = fakeCString(vObjectUStringZValue(prop)); - } - if (!strcmp(name, "NICKNAME")) { - nickname = fakeCString(vObjectUStringZValue(prop)); - } + if (vr) goto done; // XXX report error + if (!vparser.card || !vparser.card->objects) { + vparse_free(&vparser); + goto done; } /* Create mapping entry from resource name to UID */ cdata->dav.mailbox = mailbox->name; cdata->dav.resource = resource; cdata->dav.imap_uid = new->uid; - cdata->vcard_uid = uid; - cdata->fullname = fullname; - cdata->nickname = nickname; if (!cdata->dav.creationdate) cdata->dav.creationdate = new->internaldate; + carddav_make_entry(vparser.card->objects, cdata); + r = carddav_write(carddavdb, cdata, 0); + + vparse_free(&vparser); } done: + message_free_body(body); + free(body); + if (carddavdb) { carddav_commit(carddavdb); carddav_close(carddavdb);
View file
cyrus-imapd-2.5.tar.gz/imap/mbdump.c
Changed
@@ -505,7 +505,7 @@ r = quota_read(&q, NULL, 0); if (!r) { - prot_printf(pout, "%d", q.limits[QUOTA_STORAGE]); + prot_printf(pout, QUOTA_T_FMT, q.limits[QUOTA_STORAGE]); } else { prot_printf(pout, "NIL"); if (r == IMAP_QUOTAROOT_NONEXISTENT) r = 0; @@ -717,7 +717,7 @@ } prot_printliteral(pout, quota_names[res], strlen(quota_names[res])); prot_putc(' ', pout); - prot_printf(pout, "%d", q.limits[res]); + prot_printf(pout, QUOTA_T_FMT, q.limits[res]); } prot_putc(')', pout); } @@ -828,8 +828,8 @@ char *mboxkey_file = NULL; quota_t old_quota_usage[QUOTA_NUMRESOURCES]; int res; - int newquotas[QUOTA_NUMRESOURCES]; - int quotalimit = -1; + quota_t newquotas[QUOTA_NUMRESOURCES]; + quota_t quotalimit = -1; annotate_state_t *astate = NULL; memset(&file, 0, sizeof(file)); @@ -856,7 +856,7 @@ if (!strcmp(data.s, "NIL")) { /* Remove any existing quotaroot */ mboxlist_unsetquota(mbname); - } else if (sscanf(data.s, "%d", "alimit) == 1) { + } else if (sscanf(data.s, QUOTA_T_FMT, "alimit) == 1) { /* Set a Quota (may be -1 for "unlimited") */ for (res = 0; res < QUOTA_NUMRESOURCES; res++) { newquotas[res] = QUOTA_UNLIMITED;
View file
cyrus-imapd-2.5.tar.gz/imap/mboxevent.c
Changed
@@ -1220,18 +1220,12 @@ if (mboxevent_expected_param(type, param) && !event->params[param].filled) { switch (event->params[param].id) { - case EVENT_DISK_QUOTA: - return event->params[EVENT_MAX_MESSAGES].filled; - case EVENT_DISK_USED: - return event->params[EVENT_MESSAGES].filled; case EVENT_FLAG_NAMES: /* flagNames may be included with MessageAppend and MessageNew * also we don't expect it here. */ if (!(type & (EVENT_MESSAGE_APPEND|EVENT_MESSAGE_NEW))) buf_appendcstr(&missing, " flagNames"); break; - case EVENT_MAX_MESSAGES: - return event->params[EVENT_DISK_QUOTA].filled; case EVENT_MESSAGE_CONTENT: /* messageContent is not included in standard mode if the size * of the message exceed the limit */ @@ -1239,8 +1233,6 @@ IMAP_ENUM_EVENT_CONTENT_INCLUSION_MODE_STANDARD) buf_appendcstr(&missing, " messageContent"); break; - case EVENT_MESSAGES: - return event->params[EVENT_DISK_USED].filled; case EVENT_MODSEQ: /* modseq is not included if notification refers to several * messages */
View file
cyrus-imapd-2.5.tar.gz/imap/mboxlist.c
Changed
@@ -356,8 +356,8 @@ * V: uid_v_alidity */ EXPORTED int mboxlist_parse_entry(mbentry_t **mbentryptr, - const char *name, size_t namelen, - const char *data, size_t datalen) + const char *name, size_t namelen, + const char *data, size_t datalen) { static struct buf aclbuf; int r = IMAP_MAILBOX_BADFORMAT; @@ -2809,7 +2809,7 @@ * Set all the resource quotas on, or create a quota root. */ EXPORTED int mboxlist_setquotas(const char *root, - int newquotas[QUOTA_NUMRESOURCES], int force) + quota_t newquotas[QUOTA_NUMRESOURCES], int force) { char pattern[MAX_MAILBOX_PATH+1]; struct quota q;
View file
cyrus-imapd-2.5.tar.gz/imap/mboxlist.h
Changed
@@ -99,6 +99,10 @@ mbentry_t *mboxlist_entry_create(); +EXPORTED int mboxlist_parse_entry(mbentry_t **mbentryptr, + const char *name, size_t namelen, + const char *data, size_t datalen); + void mboxlist_entry_free(mbentry_t **mbentryptr); /* formats a cstring from a mboxlist_entry. Caller must free @@ -240,7 +244,7 @@ /* set or create quota root */ int mboxlist_setquotas(const char *root, - int newquotas[QUOTA_NUMRESOURCES], int force); + quota_t newquotas[QUOTA_NUMRESOURCES], int force); int mboxlist_unsetquota(const char *root); /* open the mailboxes db */
View file
cyrus-imapd-2.5.tar.gz/imap/pop3d.c
Changed
@@ -878,6 +878,7 @@ /* send the MessageExpunge event notification */ mboxevent_extract_mailbox(mboxevent, popd_mailbox); mboxevent_set_numunseen(mboxevent, popd_mailbox, -1); + mboxevent_set_access(mboxevent, NULL, NULL, popd_userid, NULL, 0); mboxevent_notify(mboxevent); mboxevent_free(&mboxevent);
View file
cyrus-imapd-2.5.tar.gz/imap/quota.c
Changed
@@ -669,8 +669,8 @@ static void reportquota_resource(struct quota * quota, const char *root, int res) { if (quota->limits[res] > 0) { - printf(" %7" PRIdMAX " %8" PRIdMAX, (intmax_t)quota->limits[res], - (intmax_t)((((intmax_t)quota->useds[res] / quota_units[res]) + printf(" %7lld %8lld", quota->limits[res], + (quota_t)((quota_t)((quota->useds[res] / quota_units[res]) * 100) / quota->limits[res])); } else if (quota->limits[res] == 0) { @@ -679,8 +679,8 @@ else { printf(" "); } - printf(" %8" PRIdMAX " %20s %s\n", - (intmax_t)((intmax_t)quota->useds[res] / quota_units[res]), + printf(" %8lld %20s %s\n", + (quota_t)(quota->useds[res] / quota_units[res]), quota_names[res], root); }
View file
cyrus-imapd-2.5.tar.gz/imap/quota.h
Changed
@@ -78,7 +78,7 @@ /* Information in quota entry */ quota_t useds[QUOTA_NUMRESOURCES]; - int limits[QUOTA_NUMRESOURCES]; /* in QUOTA_UNITS */ + quota_t limits[QUOTA_NUMRESOURCES]; /* in QUOTA_UNITS */ /* information for scanning */ char *scanmbox; @@ -89,7 +89,7 @@ #define QUOTA_UNLIMITED (-1) extern const char * const quota_names[QUOTA_NUMRESOURCES]; -extern const int quota_units[QUOTA_NUMRESOURCES]; +extern const quota_t quota_units[QUOTA_NUMRESOURCES]; int quota_name_to_resource(const char *str); typedef int quotaproc_t(struct quota *quota, void *rock); @@ -140,5 +140,5 @@ void quotadb_done(void); int quota_is_overquota(const struct quota *quota, enum quota_resource res, - int newquotas[QUOTA_NUMRESOURCES]); + quota_t newquotas[QUOTA_NUMRESOURCES]); #endif /* INCLUDED_QUOTA_H */
View file
cyrus-imapd-2.5.tar.gz/imap/quota_db.c
Changed
@@ -90,7 +90,7 @@ "X-NUM-FOLDERS" /* QUOTA_NUMFOLDERS */ }; -EXPORTED const int quota_units[QUOTA_NUMRESOURCES] = { +EXPORTED const quota_t quota_units[QUOTA_NUMRESOURCES] = { 1024, /* QUOTA_STORAGE -- RFC2087 */ 1, /* QUOTA_MESSAGE -- RFC2087 */ 1024, /* QUOTA_ANNOTSTORAGE */ @@ -194,7 +194,7 @@ goto out; /* need at least 2 more fields */ if (sscanf(fields->data[i++], QUOTA_T_FMT, "a->useds[res]) != 1) goto out; - if (sscanf(fields->data[i++], "%d", "a->limits[res]) != 1) + if (sscanf(fields->data[i++], QUOTA_T_FMT, "a->limits[res]) != 1) goto out; /* skip over temporary extra used data from failed quota -f runs */ if (i < fields->count && @@ -665,7 +665,7 @@ } EXPORTED int quota_is_overquota(const struct quota *quota, enum quota_resource res, - int newquotas[QUOTA_NUMRESOURCES]) + quota_t newquotas[QUOTA_NUMRESOURCES]) { int limit = newquotas ? newquotas[res] : quota->limits[res];
View file
cyrus-imapd-2.5.tar.gz/imap/sync_client.c
Changed
@@ -1926,6 +1926,8 @@ char *name = xstrndup(key, keylen); int r = 0; + /* XXX - check for deleted? */ + r = mailbox_open_irl(name, &mailbox); /* doesn't exist? Probably not finished creating or removing yet */ if (r == IMAP_MAILBOX_NONEXISTENT) { @@ -1986,7 +1988,6 @@ struct sync_folder_list *replica_folders, struct sync_quota_list *replica_quota) { - char buf[MAX_MAILBOX_BUFFER]; int r = 0; struct sync_name_list *mboxname_list = sync_name_list_create(); struct sync_name_list *master_quotaroots = sync_name_list_create(); @@ -1995,24 +1996,7 @@ info.mboxlist = mboxname_list; info.quotalist = master_quotaroots; - /* XXX - convert all this to an allusermbox */ - - /* Generate full list of folders on client side */ - (sync_namespace.mboxname_tointernal)(&sync_namespace, "INBOX", - user, buf); - do_mailbox_info(&info, buf, strlen(buf), NULL, 0); - - /* deleted namespace items if enabled */ - if (mboxlist_delayed_delete_isenabled()) { - char deletedname[MAX_MAILBOX_BUFFER]; - mboxname_todeleted(buf, deletedname, 0); - r = mboxlist_allmbox(deletedname, do_mailbox_info, &info, /*incdel*/1); - } - - /* subfolders */ - if (!r) { - r = mboxlist_allmbox(buf, do_mailbox_info, &info, /*incdel*/0); - } + r = mboxlist_allusermbox(user, do_mailbox_info, &info, /*incdel*/1); /* we know all the folders present on the master, so it's safe to delete * anything not mentioned here on the replica - at least until we get
View file
cyrus-imapd-2.5.tar.gz/imap/sync_server.c
Changed
@@ -1217,7 +1217,7 @@ static int do_quota(struct dlist *kin) { const char *root; - int limits[QUOTA_NUMRESOURCES]; + quota_t limits[QUOTA_NUMRESOURCES]; if (!dlist_getatom(kin, "ROOT", &root)) return IMAP_PROTOCOL_BAD_PARAMETERS;
View file
cyrus-imapd-2.5.tar.gz/imap/sync_support.c
Changed
@@ -643,7 +643,7 @@ *lp = NULL; } -void sync_encode_quota_limits(struct dlist *kl, const int limits[QUOTA_NUMRESOURCES]) +void sync_encode_quota_limits(struct dlist *kl, const quota_t limits[QUOTA_NUMRESOURCES]) { int res; @@ -662,7 +662,7 @@ } } -void sync_decode_quota_limits(/*const*/ struct dlist *kl, int limits[QUOTA_NUMRESOURCES]) +void sync_decode_quota_limits(/*const*/ struct dlist *kl, quota_t limits[QUOTA_NUMRESOURCES]) { uint32_t limit = 0; int res;
View file
cyrus-imapd-2.5.tar.gz/imap/sync_support.h
Changed
@@ -221,7 +221,7 @@ struct sync_quota { struct sync_quota *next; char *root; - int limits[QUOTA_NUMRESOURCES]; + quota_t limits[QUOTA_NUMRESOURCES]; int done; }; @@ -241,8 +241,8 @@ void sync_quota_list_free(struct sync_quota_list **lp); -void sync_encode_quota_limits(struct dlist *kl, const int limits[QUOTA_NUMRESOURCES]); -void sync_decode_quota_limits(/*const*/ struct dlist *kl, int limits[QUOTA_NUMRESOURCES]); +void sync_encode_quota_limits(struct dlist *kl, const quota_t limits[QUOTA_NUMRESOURCES]); +void sync_decode_quota_limits(/*const*/ struct dlist *kl, quota_t limits[QUOTA_NUMRESOURCES]); /* ====================================================================== */
View file
cyrus-imapd-2.5.tar.gz/imap/tls.c
Changed
@@ -860,7 +860,7 @@ } else { STACK_OF(X509_NAME) *CAnames = SSL_load_client_CA_file(client_ca_file); - if (!CAnames || sk_num((_STACK *)CAnames) < 1) { + if (!CAnames || sk_X509_NAME_num(CAnames) < 1) { syslog( LOG_ERR, "TLS server engine: No client CA certs specified. Client side certs may not work"
View file
cyrus-imapd-2.5.tar.gz/lib/acl_afs.c
Changed
@@ -180,8 +180,18 @@ } if (access == 0L) { - /* Remove any existing entry for 'identifier' */ - strcpy(thisid, nextid); + /* Remove any existing entry for 'identifier'. + Special case: When we try to delete an invalid/non-existent identifier, + both 'thisid' and 'nextid' point to the end of *acl. */ + newacl = xmalloc(strlen(*acl) + strlen(nextid) - strlen(thisid) + 1); + /* Copy existing ACLs without the current identifier. + Note: The buffer will not be zero terminated. */ + strncpy(newacl, *acl, (thisid - *acl)); + /* Append the remaining ACL string. Zero-terminates the string. */ + strcpy(newacl + (thisid - *acl), nextid); + + free(*acl); + *acl = newacl; } else { /* Replace any existing entry for 'identifier' */
View file
cyrus-imapd-2.5.tar.gz/lib/cyrusdb_skiplist.c
Changed
@@ -362,7 +362,7 @@ { if (ptr < db->map_base) return 0; - if (ptr >= db->map_base + db->map_size) + if (ptr > db->map_base + db->map_size) return 0; return 1; @@ -2189,7 +2189,9 @@ /* if this is a commit, we've processed everything in this txn */ if (TYPE(ptr) == COMMIT) { - offset += RECSIZE_safe(db, ptr); + unsigned size = RECSIZE_safe(db, ptr); + if (!size) break; + offset += size; continue; } @@ -2206,7 +2208,8 @@ q = db->map_base + filesize; p = ptr; for (;;) { - if (RECSIZE_safe(db, p) <= 0) { + unsigned size = RECSIZE_safe(db, p); + if (!size) { /* hmm, we can't trust this transaction */ syslog(LOG_ERR, "DBERROR: skiplist recovery %s: found a RECSIZE of 0, " @@ -2215,7 +2218,7 @@ p = q; break; } - p += RECSIZE_safe(db, p); + p += size; if (p >= q) break; if (TYPE(p) == COMMIT) break; }
View file
cyrus-imapd-2.5.tar.gz/lib/imapoptions
Changed
@@ -1401,7 +1401,7 @@ /* This specifies the Class Selector or Differentiated Services Code Point designation on IP headers (in the ToS field). */ -{ "quota_db", "twoskip", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "quotalegacy", "twoskip")} +{ "quota_db", "quotalegacy", STRINGLIST("flat", "berkeley", "berkeley-hash", "skiplist", "sql", "quotalegacy", "twoskip")} /* The cyrusdb backend to use for quotas. */ { "quota_db_path", NULL, STRING }
View file
cyrus-imapd-2.5.tar.gz/lib/util.c
Changed
@@ -950,9 +950,13 @@ buf->flags = 0; } -EXPORTED void buf_truncate(struct buf *buf, size_t len) +EXPORTED void buf_truncate(struct buf *buf, ssize_t len) { - if (len > buf->alloc) { + if (len < 0) { + len = buf->len + len; + if (len < 0) len = 0; + } + if ((size_t)len > buf->alloc) { /* grow the buffer and zero-fill the new bytes */ size_t more = len - buf->len; buf_ensure(buf, more);
View file
cyrus-imapd-2.5.tar.gz/lib/util.h
Changed
@@ -247,7 +247,7 @@ size_t buf_len(const struct buf *buf); const char *buf_base(const struct buf *buf); void buf_reset(struct buf *buf); -void buf_truncate(struct buf *buf, size_t len); +void buf_truncate(struct buf *buf, ssize_t len); void buf_setcstr(struct buf *buf, const char *str); void buf_setmap(struct buf *buf, const char *base, size_t len); void buf_copy(struct buf *dst, const struct buf *src);
View file
cyrus-imapd-2.5.tar.gz/lib/vparse.c
Added
@@ -0,0 +1,768 @@ +/* vparse.c : fast vcard parser */ + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> + +#include "vparse.h" + +#define LC(s) do { char *p; for (p = s; *p; p++) if (*p >= 'A' && *p <= 'Z') *p += ('a' - 'A'); } while (0) + +static char *buf_dup_cstring(struct buf *buf) +{ + char *ret = strndup(buf->s, buf->len); + /* more space efficient than returning overlength buffers, and + * you would just wind up mallocing another buffer anyway */ + buf->len = 0; + return ret; +} + +static char *buf_dup_lcstring(struct buf *buf) +{ + char *ret = buf_dup_cstring(buf); + LC(ret); + return ret; +} + +#define NOTESTART() state->itemstart = state->p +#define MAKE(X, Y) X = malloc(sizeof(struct Y)); memset(X, 0, sizeof(struct Y)) +#define PUTC(C) buf_putc(&state->buf, C) +#define INC(I) state->p += I + +/* just leaves it on the buffer */ +static int _parse_param_quoted(struct vparse_state *state, int multiparam) +{ + NOTESTART(); + + while (*state->p) { + switch (*state->p) { + case '"': + INC(1); + return 0; + + /* normal backslash quoting - NOTE, not strictly RFC complient, + * but I figure anyone who generates one PROBABLY meant to escape + * the next character because it's so common, and LABEL definitely + * allows \n, so we have to handle that anyway */ + case '\\': + /* seen in the wild - \n split by line wrapping */ + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_QSTRING_EOL; + INC(2); + } + if (!state->p[1]) + return PE_BACKQUOTE_EOF; + if (state->p[1] == 'n' || state->p[1] == 'N') + PUTC('\n'); + else + PUTC(state->p[1]); + INC(2); + break; + + /* special value quoting for doublequote and endline (RFC 6868) */ + case '^': + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_QSTRING_EOL; + INC(2); + } + if (state->p[1] == '\'') { + PUTC('"'); + INC(2); + } + else if (state->p[1] == 'n') { /* only lower case per the RFC */ + PUTC('\n'); + INC(2); + } + else if (state->p[1] == '^') { + PUTC('^'); + INC(2); + } + else { + PUTC('^'); + INC(1); /* treat next char normally */ + } + break; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] != ' ' && state->p[1] != '\t') + return PE_QSTRING_EOL; + INC(2); + break; + + case ',': + if (multiparam) + return PE_QSTRING_COMMA; + /* or fall through, comma isn't special */ + + default: + PUTC(*state->p); + INC(1); + break; + } + } + + return PE_QSTRING_EOF; +} + +static int _parse_param_key(struct vparse_state *state, int *haseq) +{ + *haseq = 0; + + while (*state->p) { + switch (*state->p) { + case '=': + state->param->name = buf_dup_lcstring(&state->buf); + *haseq = 1; + INC(1); + return 0; + + case ';': /* vcard 2.1 parameter with no value */ + case ':': + if (state->barekeys) { + state->param->name = buf_dup_lcstring(&state->buf); + } + else { + state->param->name = strdup("type"); + state->param->value = buf_dup_cstring(&state->buf); + } + /* no INC - we need to see this char up a layer */ + return 0; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] != ' ' && state->p[1] != '\t') + return PE_KEY_EOL; + INC(2); + break; + + /* XXX - check exact legal set? */ + default: + PUTC(*state->p); + INC(1); + break; + } + } + + return PE_KEY_EOF; +} + +static int _parse_entry_params(struct vparse_state *state) +{ + struct vparse_param **paramp = &state->entry->params; + struct vparse_list *item; + int multiparam = 0; + int haseq = 0; + int r; + +repeat: + multiparam = 0; + haseq = 0; + MAKE(state->param, vparse_param); + + NOTESTART(); + + r = _parse_param_key(state, &haseq); + if (r) return r; + + for (item = state->multiparam; item; item = item->next) { + if (!strcmp(state->param->name, item->s)) { + multiparam = 1; + break; + } + } + + /* now get the value */ + while (*state->p) { + switch (*state->p) { + case '\\': /* normal backslash quoting */ + /* seen in the wild - \n split by line wrapping */ + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_PARAMVALUE_EOL; + INC(2); + } + if (!state->p[1]) + return PE_BACKQUOTE_EOF; + if (state->p[1] == 'n' || state->p[1] == 'N') + PUTC('\n'); + else + PUTC(state->p[1]); + INC(2); + break; + + case '^': /* special value quoting for doublequote (RFC 6868) */ + /* seen in the wild - \n split by line wrapping */ + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_PARAMVALUE_EOL; + INC(2); + } + if (state->p[1] == '\'') { + PUTC('"'); + INC(2); + } + else if (state->p[1] == 'n') { + PUTC('\n'); + INC(2); + } + else if (state->p[1] == '^') { + PUTC('^'); + INC(2); + } + else { + PUTC('^'); + INC(1); /* treat next char normally */ + } + break; + + case '"': + INC(1); + loop: + r = _parse_param_quoted(state, multiparam); + if (r == PE_QSTRING_COMMA) { + char *name = strdup(state->param->name); + state->param->value = buf_dup_cstring(&state->buf); + *paramp = state->param; + paramp = &state->param->next; + MAKE(state->param, vparse_param); + state->param->name = name; + INC(1); + goto loop; + } + if (r) return r; + break; + + case ':': + /* done - all parameters parsed */ + if (haseq) + state->param->value = buf_dup_cstring(&state->buf); + *paramp = state->param; + state->param = NULL; + INC(1); + return 0; + + case ';': + /* another parameter to parse */ + if (haseq) + state->param->value = buf_dup_cstring(&state->buf); + *paramp = state->param; + paramp = &state->param->next; + INC(1); + goto repeat; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] != ' ' && state->p[1] != '\t') + return PE_PARAMVALUE_EOL; + INC(2); + break; + + case ',': + if (multiparam) { + char *name = strdup(state->param->name); + if (haseq) + state->param->value = buf_dup_cstring(&state->buf); + *paramp = state->param; + paramp = &state->param->next; + MAKE(state->param, vparse_param); + state->param->name = name; + INC(1); + break; + } + /* or fall through, comma isn't special */ + + default: + PUTC(*state->p); + INC(1); + break; + } + } + + return PE_PARAMVALUE_EOF; +} + +static int _parse_entry_key(struct vparse_state *state) +{ + NOTESTART(); + + while (*state->p) { + switch (*state->p) { + case ':': + state->entry->name = buf_dup_lcstring(&state->buf); + INC(1); + return 0; + + case ';': + state->entry->name = buf_dup_lcstring(&state->buf); + INC(1); + return _parse_entry_params(state); + + case '.': + if (state->entry->group) + return PE_ENTRY_MULTIGROUP; + state->entry->group = buf_dup_lcstring(&state->buf); + INC(1); + break; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] == ' ' || state->p[1] == '\t') /* wrapped line */ + INC(2); + else if (!state->buf.len) /* no key yet? blank intermediate lines are OK */ + INC(1); + else + return PE_NAME_EOL; + break; + + default: + PUTC(*state->p); + INC(1); + break; + } + } + + return PE_NAME_EOF; +} + +static int _parse_entry_multivalue(struct vparse_state *state) +{ + struct vparse_list **valp = &state->entry->v.values; + + state->entry->multivalue = 1; + + NOTESTART(); + +repeat: + MAKE(state->value, vparse_list); + + while (*state->p) { + switch (*state->p) { + /* only one type of quoting */ + case '\\': + /* seen in the wild - \n split by line wrapping */ + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_BACKQUOTE_EOF; + INC(2); + } + if (!state->p[1]) + return PE_BACKQUOTE_EOF; + if (state->p[1] == 'n' || state->p[1] == 'N') + PUTC('\n'); + else + PUTC(state->p[1]); + INC(2); + break; + + case ';': + state->value->s = buf_dup_cstring(&state->buf); + *valp = state->value; + valp = &state->value->next; + INC(1); + goto repeat; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] == ' ' || state->p[1] == '\t') {/* wrapped line */ + INC(2); + break; + } + /* otherwise it's the end of the value */ + INC(1); + goto out; + + default: + PUTC(*state->p); + INC(1); + break; + } + } + +out: + /* reaching the end of the file isn't a failure here, + * it's just another type of end-of-value */ + state->value->s = buf_dup_cstring(&state->buf); + *valp = state->value; + state->value = NULL; + return 0; +} + +static int _parse_entry_value(struct vparse_state *state) +{ + struct vparse_list *item; + + for (item = state->multival; item; item = item->next) + if (!strcmp(state->entry->name, item->s)) + return _parse_entry_multivalue(state); + + NOTESTART(); + + while (*state->p) { + switch (*state->p) { + /* only one type of quoting */ + case '\\': + /* seen in the wild - \n split by line wrapping */ + if (state->p[1] == '\r') INC(1); + if (state->p[1] == '\n') { + if (state->p[2] != ' ' && state->p[2] != '\t') + return PE_BACKQUOTE_EOF; + INC(2); + } + if (!state->p[1]) + return PE_BACKQUOTE_EOF; + + if (state->p[1] == 'n' || state->p[1] == 'N') + PUTC('\n'); + else + PUTC(state->p[1]); + INC(2); + break; + + case '\r': + INC(1); + break; /* just skip */ + case '\n': + if (state->p[1] == ' ' || state->p[1] == '\t') {/* wrapped line */ + INC(2); + break; + } + /* otherwise it's the end of the value */ + INC(1); + goto out; + + default: + PUTC(*state->p); + INC(1); + break; + } + } + +out: + /* reaching the end of the file isn't a failure here, + * it's just another type of end-of-value */ + state->entry->v.value = buf_dup_cstring(&state->buf); + return 0; +} + +/* FREE MEMORY */ + +static void _free_list(struct vparse_list *list) +{ + struct vparse_list *listnext; + + for (; list; list = listnext) { + listnext = list->next; + free(list->s); + free(list); + } +} + +static void _free_param(struct vparse_param *param) +{ + struct vparse_param *paramnext; + + for (; param; param = paramnext) { + paramnext = param->next; + free(param->name); + free(param->value); + free(param); + } +} + +static void _free_entry(struct vparse_entry *entry) +{ + struct vparse_entry *entrynext; + + for (; entry; entry = entrynext) { + entrynext = entry->next; + free(entry->name); + free(entry->group); + if (entry->multivalue) + _free_list(entry->v.values); + else + free(entry->v.value); + _free_param(entry->params); + free(entry); + } +} + +static void _free_card(struct vparse_card *card) +{ + struct vparse_card *cardnext; + + for (; card; card = cardnext) { + cardnext = card->next; + free(card->type); + _free_entry(card->properties); + _free_card(card->objects); + free(card); + } +} + +static void _free_state(struct vparse_state *state) +{ + buf_free(&state->buf); + _free_card(state->card); + _free_list(state->value); + _free_entry(state->entry); + _free_param(state->param); + + memset(state, 0, sizeof(struct vparse_state)); +} + +static int _parse_entry(struct vparse_state *state) +{ + int r = _parse_entry_key(state); + if (r) return r; + return _parse_entry_value(state); +} + +static int _parse_vcard(struct vparse_state *state, struct vparse_card *card, int only_one) +{ + struct vparse_card **subp = &card->objects; + struct vparse_entry **entryp = &card->properties; + struct vparse_card *sub; + const char *cardstart = state->p; + const char *entrystart; + int r; + + while (*state->p) { + /* whitespace is very skippable before AND afterwards */ + if (*state->p == '\r' || *state->p == '\n' || *state->p == ' ' || *state->p == '\t') { + INC(1); + continue; + } + + entrystart = state->p; + + MAKE(state->entry, vparse_entry); + + r = _parse_entry(state); + if (r) return r; + + if (!strcmp(state->entry->name, "begin")) { + /* shouldn't be any params */ + if (state->entry->params) { + state->itemstart = entrystart; + return PE_BEGIN_PARAMS; + } + /* only possible if some idiot passes 'begin' as + * multivalue field name */ + if (state->entry->multivalue) { + state->itemstart = entrystart; + return PE_BEGIN_PARAMS; + } + + MAKE(sub, vparse_card); + sub->type = strdup(state->entry->v.value); + LC(sub->type); + _free_entry(state->entry); + state->entry = NULL; + /* we must stitch it in first, because state won't hold it */ + *subp = sub; + subp = &sub->next; + r = _parse_vcard(state, sub, /*only_one*/0); + if (r) return r; + if (only_one) return 0; + } + else if (!strcmp(state->entry->name, "end")) { + /* shouldn't be any params */ + if (state->entry->params) { + state->itemstart = entrystart; + return PE_BEGIN_PARAMS; + } + /* only possible if some idiot passes 'end' as + * multivalue field name */ + if (state->entry->multivalue) { + state->itemstart = entrystart; + return PE_BEGIN_PARAMS; + } + + if (strcasecmp(state->entry->v.value, card->type)) { + /* special case mismatched card, the "start" was the start of + * the card */ + state->itemstart = cardstart; + return PE_MISMATCHED_CARD; + } + + _free_entry(state->entry); + state->entry = NULL; + + return 0; + } + else { + /* it's a parameter on this one */ + *entryp = state->entry; + entryp = &state->entry->next; + state->entry = NULL; + } + } + + if (card->type) + return PE_FINISHED_EARLY; + + return 0; +} + +/* PUBLIC API */ + +EXPORTED int vparse_parse(struct vparse_state *state, int only_one) +{ + MAKE(state->card, vparse_card); + + state->p = state->base; + + /* don't parse trailing non-whitespace */ + return _parse_vcard(state, state->card, only_one); +} + +EXPORTED void vparse_free(struct vparse_state *state) +{ + _free_state(state); +} + +EXPORTED void vparse_fillpos(struct vparse_state *state, struct vparse_errorpos *pos) +{ + int l = 1; + int c = 0; + const char *p; + + memset(pos, 0, sizeof(struct vparse_errorpos)); + + pos->errorpos = state->p - state->base; + pos->startpos = state->itemstart - state->base; + + for (p = state->base; p < state->p; p++) { + if (*p == '\n') { + l++; + c = 0; + } + else { + c++; + } + if (p == state->itemstart) { + pos->startline = l; + pos->startchar = c; + } + } + + pos->errorline = l; + pos->errorchar = c; +} + +EXPORTED const char *vparse_errstr(int err) +{ + switch(err) { + case PE_BACKQUOTE_EOF: + return "EOF after backslash"; + case PE_BEGIN_PARAMS: + return "Params on BEGIN field"; + case PE_ENTRY_MULTIGROUP: + return "Multiple group levels in property name"; + case PE_FINISHED_EARLY: + return "VCard not completed"; + case PE_KEY_EOF: + return "End of data while parsing parameter key"; + case PE_KEY_EOL: + return "End of line while parsing parameter key"; + case PE_MISMATCHED_CARD: + return "Closed a different card name than opened"; + case PE_NAME_EOF: + return "End of data while parsing entry name"; + case PE_NAME_EOL: + return "End of line while parsing entry name"; + case PE_PARAMVALUE_EOF: + return "End of data while parsing parameter value"; + case PE_PARAMVALUE_EOL: + return "End of line while parsing parameter value"; + case PE_QSTRING_EOF: + return "End of data while parsing quoted value"; + case PE_QSTRING_EOL: + return "End of line while parsing quoted value"; + } + return "Unknown error"; +} + +#ifdef DEBUG +static int _dump_card(struct vparse_card *card) +{ + struct vparse_entry *entry; + struct vparse_param *param; + struct vparse_card *sub; + + printf("begin:%s\n", card->type); + for (entry = card->properties; entry; entry = entry->next) { + printf("%s", entry->name); + for (param = entry->params; param; param = param->next) + printf(";%s=%s", param->name, param->value); + if (entry->multivalue) + printf(":multivalue\n"); + else + printf(":%s\n", entry->v.value); + } + for (sub = card->objects; sub; sub = sub->next) + _dump_card(sub); + printf("end:%s\n", card->type); +} + +static int _dump(struct vparse_card *card) +{ + _dump_card(card->objects); +} + +int main(int argv, const char **argc) +{ + const char *fname = argc[1]; + struct stat sbuf; + int fd = open(fname, O_RDONLY); + struct vparse_state parser; + char *data; + int r; + + memset(&parser, 0, sizeof(struct vparse_state)); + + fstat(fd, &sbuf); + data = malloc(sbuf.st_size+1); + + read(fd, data, sbuf.st_size); + data[sbuf.st_size] = '\0'; + + parser.base = data; + r = vparse_parse(&parser); + if (r) { + struct vparse_errorpos pos; + vparse_fillpos(&parser, &pos); + printf("error %s at line %d char %d: %.*s ... %.*s <--- (started at line %d char %d)\n", + vparse_errstr(r), pos.errorline, pos.errorchar, + 20, parser.base + pos.startpos, + 20, parser.base + pos.errorpos - 20, + pos.startline, pos.startchar); + return 1; + } + + _dump(parser.card); + + vparse_free(&parser); + + return 0; +} +#endif
View file
cyrus-imapd-2.5.tar.gz/lib/vparse.h
Added
@@ -0,0 +1,87 @@ +#ifndef VCARDFAST_H +#define VCARDFAST_H + +#include <stdlib.h> +#include "util.h" + +enum parse_error { +PE_OK = 0, +PE_BACKQUOTE_EOF, +PE_BEGIN_PARAMS, +PE_ENTRY_MULTIGROUP, +PE_FINISHED_EARLY, +PE_KEY_EOF, +PE_KEY_EOL, +PE_MISMATCHED_CARD, +PE_NAME_EOF, +PE_NAME_EOL, +PE_PARAMVALUE_EOF, +PE_PARAMVALUE_EOL, +PE_QSTRING_EOF, +PE_QSTRING_EOL, +PE_QSTRING_COMMA, +PE_NUMERR /* last */ +}; + +struct vparse_list { + char *s; + struct vparse_list *next; +}; + +struct vparse_state { + struct buf buf; + const char *base; + const char *itemstart; + const char *p; + struct vparse_list *multival; + struct vparse_list *multiparam; + int barekeys; + + /* current items */ + struct vparse_card *card; + struct vparse_param *param; + struct vparse_entry *entry; + struct vparse_list *value; +}; + +struct vparse_param { + char *name; + char *value; + struct vparse_param *next; +}; + +struct vparse_entry { + char *group; + char *name; + int multivalue; + union { + char *value; + struct vparse_list *values; + } v; + struct vparse_param *params; + struct vparse_entry *next; +}; + +struct vparse_card { + char *type; + struct vparse_entry *properties; + struct vparse_card *objects; + struct vparse_card *next; +}; + +struct vparse_errorpos { + int startpos; + int startline; + int startchar; + int errorpos; + int errorline; + int errorchar; +}; + +extern int vparse_parse(struct vparse_state *state, int only_one); +extern void vparse_free(struct vparse_state *state); +extern void vparse_fillpos(struct vparse_state *state, struct vparse_errorpos *pos); +extern const char *vparse_errstr(int err); + +#endif /* VCARDFAST_H */ +
View file
cyrus-imapd.dsc
Changed
@@ -2,7 +2,7 @@ Source: cyrus-imapd Binary: cyrus-imapd Architecture: any -Version: 2.5~dev2014120901-0~kolab1 +Version: 2.5~dev2015021301-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.cyrusimap.org/
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +cyrus-imapd (2.5~dev2015021301-0~kolab1) unstable; urgency=low + + * New snapshot at e9158f38630b553a4f62b883f61193cf1b169fc3 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Fri, 13 Feb 2015 11:30:13 +0100 + cyrus-imapd (2.5~dev2014120901-0~kolab1) unstable; urgency=low * New snapshot at f01310085cbf58958412deda9c61ecfd7c82a19b
View file
debian.series
Changed
@@ -1,3 +1,1 @@ cyrus-imapd-2.5-ctl_mboxlist-mbtype.patch -p1 -cyrus-imapd-2.5-openssl-stack.patch -p1 -cyrus-imapd-2.5-revert-safe-skiplist.patch -p1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.