[PATCH] Changing folder paths on disk to support fast-rename

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a very small patch for a very big change (and incomplete,
it doesn't alter rehash, dohash, etc)

Anyway...

Considering the fast-rename and extending it to delete, we have
the following problem:

folders:

user.brong
user.brong.foo
user.brong.foo.bar

Delete/rename user.brong.foo WITHOUT affecting user.brong.foo.bar.

On disk these are:

BASEDIR/b/user/brong/
BASEDIR/b/user/brong/foo/
BASEDIR/b/user/brong/foo/bar/

So you either have to:

a) move every single non "bar" file to the new location, or

b) move user/brong/foo to the new location, then create a new
   user/brong/foo and move bar back into it.

I realised there was:

c) change folder layout on disk such that sub folders in the
   IMAP world aren't sub-folders in the on-disk world.


(c) started looking more attractive all the time, especially
since I've seen it at work with my Maildir copy which
offlineimap keeps up to date for me.


The following patch creates:

BASEDIR/user/b/brong/user.brong/
BASEDIR/user/b/brong/user.brong.foo/
BASEDIR/user/b/brong/user.brong.foo.bar/

and handles shared namespace, etc as:

BASEDIR/shared/shared
BASEDIR/shared/shared.foo
BASEDIR/shared/shared.foo.bar

Basically, if mboxlist_isusermailbox(name, 0) is true then
it gets hashed the first way, otherwise the second.

This has the nice property with our rename/delete patch
(also attached) and required for this patch you get:

BASEDIR/user/b/brong/DELETED.user.brong.foo.TIMESTAMP/

keeping the user's stuff all together on disk.


I really do prefer the "each IMAP folder is a different
folder" and "hashing based on realistic use patterns" (at
least for us... and I'm a believer in Hans Reiser's attitude
that if your filesystem can't handle a folder with thousands
of items then your filesystem needs fixing)


I'll be working on fast-rename in this new universe next,
but I thought I should throw this out there for comments.
So, what do you think (and yes, I'll be making rehash at
least work happily with this, because we'll need to do it
ourselves.  Current plan - down the replica, rehash it,
change the config, bring it back up.  Failover, rinse,
repeat)

Bron.

P.S. I'm using quilt now to work on these patches.  It's an
order of magnitude nicer than working on each patch in
isolation and using diff/patch by hand, but it means that
patches are now in a series that apply one after the other
rather than all against the raw upstream source.  I hope to
post my entire quilt series once I fix the one thing that
has a FastMail specific key encoded in it to use a config
option instead.
-- 
  Bron Gondwana
  brong@xxxxxxxxxxx

Index: cyrus-imapd-2.3.9/imap/mailbox.c
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/mailbox.c	2007-08-21 01:28:56.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/mailbox.c	2007-08-21 01:36:23.000000000 -0400
@@ -3362,6 +3362,7 @@
 {
     const char *idx;
     char c, *p;
+    char itemname[MAX_MAILBOX_PATH+1];
 
     snprintf(buf, buf_len, "%s", root);
     buf_len -= strlen(buf);
@@ -3369,7 +3370,7 @@
 
     if (config_virtdomains && (p = strchr(name, '!'))) {
 	*p = '\0';  /* split domain!user */
-	if (config_hashimapspool) {
+	if (config_hashimapspool != IMAP_ENUM_HASHIMAPSPOOL_OFF) {
 	    c = (char) dir_hash_c(name, config_fulldirhash);
 	    snprintf(buf, buf_len, "%s%c/%s", FNAME_DOMAINDIR, c, name);
 	}
@@ -3382,7 +3383,7 @@
 	buf += strlen(buf);
     }
 
-    if (config_hashimapspool) {
+    if (config_hashimapspool == IMAP_ENUM_HASHIMAPSPOOL_ON) {
 	idx = strchr(name, '.');
 	if (idx == NULL) {
 	    idx = name;
@@ -3392,13 +3393,30 @@
 	c = (char) dir_hash_c(idx, config_fulldirhash);
 	
 	snprintf(buf, buf_len, "/%c/%s", c, name);
+
+	/* change all '.'s to '/' */
+	for (p = buf; *p; p++) {
+	    if (*p == '.') *p = '/';
+	}
+    } else if (config_hashimapspool == IMAP_ENUM_HASHIMAPSPOOL_USERID) {
+	if (idx = mboxname_isusermailbox(name, 0)) {
+	    c = (char) dir_hash_c(idx, config_fulldirhash);
+	    strncpy(itemname, idx, MAX_MAILBOX_PATH);
+	    if (p = strchr(itemname, '.')) *p = '\0'; /* trim to username */
+	    snprintf(buf, buf_len, "/user/%c/%s/%s", c, itemname, name);
+	} else {
+	    strncpy(itemname, name, MAX_MAILBOX_PATH);
+	    if (p = strchr(itemname, '.')) *p = '\0'; /* trim to first part */
+	    snprintf(buf, buf_len, "/%s/%s", itemname, name);
+	}
     } else {
 	/* standard mailbox placement */
 	snprintf(buf, buf_len, "/%s", name);
-    }
 
-    /* change all '.'s to '/' */
-    for (p = buf; *p; p++) {
-	if (*p == '.') *p = '/';
+	/* change all '.'s to '/' */
+	for (p = buf; *p; p++) {
+	    if (*p == '.') *p = '/';
+	}
     }
+
 }
Index: cyrus-imapd-2.3.9/lib/imapoptions
===================================================================
--- cyrus-imapd-2.3.9.orig/lib/imapoptions	2007-08-21 01:28:56.000000000 -0400
+++ cyrus-imapd-2.3.9/lib/imapoptions	2007-08-21 01:28:59.000000000 -0400
@@ -266,10 +266,14 @@
    server must be quiesced and then the directories moved with the
    \fBrehash\fR utility. */
 
-{ "hashimapspool", 0, SWITCH }
+{ "hashimapspool", "off", ENUM("off", "userid", "on") }
 /* If enabled, the partitions will also be hashed, in addition to the
    hashing done on configuration directories.  This is recommended if
-   one partition has a very bushy mailbox tree. */
+   one partition has a very bushy mailbox tree.
+.PP
+   If set to "userid" then the second item will be stripped out as
+   the directory path and the other dots won't be converted:
+   e.g. /b/brong/user.brong.Trash/ */
 
 # Commented out - there's no such thing as "hostname_mechs", but we need
 # this for the man page
Index: cyrus-imapd-2.3.9/lib/libconfig.c
===================================================================
--- cyrus-imapd-2.3.9.orig/lib/libconfig.c	2007-08-21 01:28:56.000000000 -0400
+++ cyrus-imapd-2.3.9/lib/libconfig.c	2007-08-21 01:28:59.000000000 -0400
@@ -74,7 +74,7 @@
 const char *config_mupdate_server = NULL;/* NULL */
 const char *config_defdomain = NULL;     /* NULL */
 const char *config_ident = NULL;         /* the service name */
-int config_hashimapspool;	  /* f */
+enum enum_value config_hashimapspool;	  /* f */
 enum enum_value config_virtdomains;	          /* f */
 enum enum_value config_mupdate_config;	/* IMAP_ENUM_MUPDATE_CONFIG_STANDARD */
 
@@ -274,7 +274,7 @@
     }
 
     /* look up mailbox hashing */
-    config_hashimapspool = config_getswitch(IMAPOPT_HASHIMAPSPOOL);
+    config_hashimapspool = config_getenum(IMAPOPT_HASHIMAPSPOOL);
 
     /* are we supporting virtual domains?  */
     config_virtdomains = config_getenum(IMAPOPT_VIRTDOMAINS);
Index: cyrus-imapd-2.3.9/lib/libconfig.h
===================================================================
--- cyrus-imapd-2.3.9.orig/lib/libconfig.h	2007-08-21 01:28:56.000000000 -0400
+++ cyrus-imapd-2.3.9/lib/libconfig.h	2007-08-21 01:28:59.000000000 -0400
@@ -71,7 +71,7 @@
 extern const char *config_mupdate_server;
 extern const char *config_defdomain;
 extern const char *config_ident;
-extern int config_hashimapspool;
+extern enum enum_value config_hashimapspool;
 extern int config_implicitrights;
 extern enum enum_value config_virtdomains;
 extern enum enum_value config_mupdate_config;
Index: cyrus-imapd-2.3.9/imap/cyr_expire.c
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/cyr_expire.c	2007-08-16 21:42:14.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/cyr_expire.c	2007-08-16 21:46:47.000000000 -0400
@@ -91,6 +91,20 @@
     int skip_annotate;
 };
 
+struct delete_node {
+    struct delete_node *next;
+    char *name;
+};
+
+struct delete_rock {
+    char prefix[100];
+    int prefixlen;
+    time_t delete_mark;
+    struct delete_node *head;
+    struct delete_node *tail;
+    int verbose;
+};
+
 /*
  * mailbox_expunge() callback to expunge expired articles.
  */
@@ -273,14 +287,72 @@
     return 0;
 }
 
+int delete(char *name, int matchlen, int maycreate __attribute__((unused)),
+	 void *rock)
+{
+    struct delete_rock *drock = (struct delete_rock *) rock;
+    char fnamebuf[MAX_MAILBOX_PATH+1];
+    struct stat sbuf;
+    char *p;
+    int i, r, domainlen = 0;
+    struct delete_node *node;
+    int mbtype;
+    char *path, *mpath;
+
+    if (config_virtdomains && (p = strchr(name, '!')))
+	domainlen = p - name + 1;
+
+    /* check if this is a mailbox we want to examine */
+    if (strncmp(name+domainlen, drock->prefix, drock->prefixlen))
+	return 0;
+
+    /* Skip remote mailboxes */
+    r = mboxlist_detail(name, &mbtype, &path, &mpath, NULL, NULL, NULL);
+    if (r) {
+	if (drock->verbose) {
+	    printf("error looking up %s: %s\n", name, error_message(r));
+	}
+	return 1;
+    }
+    if (mbtype & MBTYPE_REMOTE) return 0;
+
+    /* check that the header is older than the number of days we care about */
+    if (mpath &&
+       (config_metapartition_files &
+	  IMAP_ENUM_METAPARTITION_FILES_HEADER)) {
+	strlcpy(fnamebuf, mpath, sizeof(fnamebuf));
+    } else {
+	strlcpy(fnamebuf, path, sizeof(fnamebuf));
+    }
+    strlcat(fnamebuf, FNAME_HEADER, sizeof(fnamebuf));
+    if (stat(fnamebuf, &sbuf)) return 0;
+    if ((sbuf.st_mtime == 0) || (sbuf.st_mtime > drock->delete_mark))
+	return(0);
+
+    /* Add this mailbox to list of mailboxes to delete */
+    node = xmalloc(sizeof(struct delete_node));
+    node->next = NULL;
+    node->name = xstrdup(name);
+
+    if (drock->tail) {
+	drock->tail->next = node;
+	drock->tail = node;
+    } else {
+	drock->head = drock->tail = node;
+    }
+    return(0);
+}
+
 int main(int argc, char *argv[])
 {
     extern char *optarg;
-    int opt, r = 0, expire_days = 0, expunge_days = 0;
+    int opt, r = 0, expire_days = 0, expunge_days = 0, delete_days = 0;
     char *alt_config = NULL;
     char buf[100];
     struct hash_table expire_table;
     struct expire_rock erock;
+    struct delete_rock drock;
+    const char *deleteprefix;
 
     if ((geteuid()) == 0 && (become_cyrus() != 0)) {
 	fatal("must run as the Cyrus user", EC_USAGE);
@@ -288,13 +360,19 @@
 
     /* zero the expire_rock */
     memset(&erock, 0, sizeof(erock));
+    memset(&drock, 0, sizeof(drock));
 
-    while ((opt = getopt(argc, argv, "C:E:X:va")) != EOF) {
+    while ((opt = getopt(argc, argv, "C:D:E:X:va")) != EOF) {
 	switch (opt) {
 	case 'C': /* alt config file */
 	    alt_config = optarg;
 	    break;
 
+	case 'D':
+	    if (delete_days) usage();
+	    delete_days = atoi(optarg);
+	    break;
+
 	case 'E':
 	    if (expire_days) usage();
 	    expire_days = atoi(optarg);
@@ -307,6 +385,7 @@
 
 	case 'v':
 	    erock.verbose++;
+	    drock.verbose++;
 	    break;
 
 	case 'a':
@@ -367,6 +446,44 @@
 		erock.deleted, erock.messages, erock.mailboxes);
     }
 
+    if (mboxlist_delayed_delete_isenabled() &&
+        (deleteprefix = config_getstring(IMAPOPT_DELETEPREFIX))) {
+        struct delete_node *node;
+        int count = 0;
+        
+        if (drock.verbose) {
+            fprintf(stderr,
+                    "Removing deleted mailboxes older than %d days\n",
+                    delete_days);
+        }
+
+        strlcpy(drock.prefix, deleteprefix, sizeof(drock.prefix));
+        strlcat(drock.prefix, ".", sizeof(drock.prefix));
+        drock.prefixlen = strlen(drock.prefix);
+        drock.delete_mark = time(0) - (delete_days * 60 * 60 * 24);
+        drock.head = NULL;
+        drock.tail = NULL;
+
+        mboxlist_findall(NULL, buf, 1, 0, 0, &delete, &drock);
+
+        for (node = drock.head ; node ; node = node->next) {
+            if (drock.verbose) {
+                fprintf(stderr, "Removing: %s\n", node->name);
+            }
+            r = mboxlist_deletemailbox(node->name, 1, NULL, NULL, 0, 0, 0);
+            count++;
+        }
+
+        if (drock.verbose) {
+            if (count != 1) {
+                fprintf(stderr, "Removed %d deleted mailboxes\n", count);
+            } else {
+                fprintf(stderr, "Removed 1 deleted mailbox\n");
+            }
+        }
+        syslog(LOG_NOTICE, "Removed %d deleted mailboxes", count);
+    }
+
     /* purge deliver.db entries of expired messages */
     r = duplicate_prune(expire_days, &expire_table);
 
Index: cyrus-imapd-2.3.9/imap/imapd.c
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/imapd.c	2007-08-16 21:42:58.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/imapd.c	2007-08-16 21:45:58.000000000 -0400
@@ -5016,9 +5016,19 @@
 {
     int r;
 
-    r = mboxlist_deletemailbox(name, imapd_userisadmin,
-			       imapd_userid, imapd_authstate,
-			       0, 0, 0);
+    if (!mboxlist_delayed_delete_isenabled()) {
+        r = mboxlist_deletemailbox(name, imapd_userisadmin,
+                                   imapd_userid, imapd_authstate,
+                                   0, 0, 0);
+    } else if (imapd_userisadmin && mboxlist_in_deleteprefix(name)) {
+        r = mboxlist_deletemailbox(name, imapd_userisadmin,
+                                   imapd_userid, imapd_authstate,
+                                   0, 0, 0);
+    } else {
+        r = mboxlist_delayed_deletemailbox(name, imapd_userisadmin,
+                                           imapd_userid, imapd_authstate,
+                                           0, 0, 0);
+    }
     
     if (!r) sync_log_mailbox(name);
 
@@ -5098,9 +5108,20 @@
 	if (config_virtdomains && (p = strchr(mailboxname, '!')))
 	    domainlen = p - mailboxname + 1;
 
-	r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
-				   imapd_userid, imapd_authstate, 1-force,
-				   localonly, 0);
+        if (localonly || !mboxlist_delayed_delete_isenabled()) {
+            r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
+                                       imapd_userid, imapd_authstate, 
+                                       1-force, localonly, 0);
+        } else if (imapd_userisadmin &&
+                   mboxlist_in_deleteprefix(mailboxname)) {
+            r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
+                                       imapd_userid, imapd_authstate,
+                                       0 /* checkacl */, localonly, 0);
+        } else {
+            r = mboxlist_delayed_deletemailbox(mailboxname, imapd_userisadmin,
+                                               imapd_userid, imapd_authstate,
+                                               1-force, localonly, 0);
+        }
     }
 
     /* was it a top-level user mailbox? */
@@ -9323,6 +9344,12 @@
     else
 	strlcpy(mboxname, lastname, sizeof(mboxname));
 
+    /* Suppress DELETED hierachy unless admin */
+    if (!imapd_userisadmin &&
+        mboxlist_delayed_delete_isenabled() &&
+        mboxlist_in_deleteprefix(mboxname))
+        return;
+
     /* Look it up */
     nonexistent = mboxlist_detail(mboxname, &mbtype,
 				  NULL, NULL, NULL, NULL, NULL);
Index: cyrus-imapd-2.3.9/imap/mboxlist.c
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/mboxlist.c	2007-08-16 21:42:14.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/mboxlist.c	2007-08-16 21:46:47.000000000 -0400
@@ -82,6 +82,7 @@
 
 #include "mboxlist.h"
 #include "quota.h"
+#include "sync_log.h"
 
 #define DB config_mboxlist_db
 #define SUBDB config_subscription_db
@@ -875,6 +876,103 @@
 }
 	
 /*
+ * Delayed Delete a mailbox: translate delete into rename
+ *
+ * XXX local_only?
+ */
+int
+mboxlist_delayed_deletemailbox(const char *name, int isadmin, char *userid, 
+                               struct auth_state *auth_state, int checkacl,
+                               int local_only, int force)
+{
+    char newname[MAX_MAILBOX_PATH+1];
+    char *path, *mpath;
+    char *acl;
+    char *partition;
+    int r;
+    long access;
+    struct mailbox mailbox;
+    int deletequotaroot = 0;
+    struct txn *tid = NULL;
+    int isremote = 0;
+    int mbtype;
+    const char *p;
+    const char *deleteprefix = config_getstring(IMAPOPT_DELETEPREFIX);
+    int domainlen = 0;
+    struct timeval tv;
+
+    if(!isadmin && force) return IMAP_PERMISSION_DENIED;
+
+    /* Check for request to delete a user:
+       user.<x> with no dots after it */
+    if ((p = mboxname_isusermailbox(name, 1))) {
+	/* Can't DELETE INBOX (your own inbox) */
+	if (userid) {
+	    int len = config_virtdomains ?
+                strcspn(userid, "@") : strlen(userid);
+	    if ((len == strlen(p)) && !strncmp(p, userid, len)) {
+		return(IMAP_MAILBOX_NOTSUPPORTED);
+	    }
+	}
+
+	/* Only admins may delete user */
+	if (!isadmin) return(IMAP_PERMISSION_DENIED);
+    }
+
+    do {
+        r = mboxlist_mylookup(name, &mbtype,
+                              &path, &mpath, &partition, &acl, NULL, 1);
+    } while (r == IMAP_AGAIN);
+
+    if (r) return(r);
+
+    isremote = mbtype & MBTYPE_REMOTE;
+
+    /* are we reserved? (but for remote mailboxes this is okay, since
+     * we don't touch their data files at all) */
+    if(!isremote && (mbtype & MBTYPE_RESERVE) && !force) {
+	return(IMAP_MAILBOX_RESERVED);
+    }
+
+    /* check if user has Delete right (we've already excluded non-admins
+     * from deleting a user mailbox) */
+    if (checkacl) {
+	access = cyrus_acl_myrights(auth_state, acl);
+	if(!(access & ACL_DELETEMBOX)) {
+	    /* User has admin rights over their own mailbox namespace */
+	    if (mboxname_userownsmailbox(userid, name) &&
+		(config_implicitrights & ACL_ADMIN)) {
+		isadmin = 1;
+	    }
+	    
+	    /* Lie about error if privacy demands */
+	    r = (isadmin || (access & ACL_LOOKUP)) ?
+		IMAP_PERMISSION_DENIED : IMAP_MAILBOX_NONEXISTENT;
+	    return(r);
+	}
+    }
+
+    if (config_virtdomains && (p = strchr(name, '!')))
+        domainlen = p - name + 1;    
+
+    gettimeofday( &tv, NULL );
+
+    if (domainlen && domainlen < sizeof(newname))
+	strncpy(newname, name, domainlen);
+    snprintf(newname+domainlen, sizeof(newname)-domainlen, "%s.%s.%X",
+             deleteprefix, name+domainlen, tv.tv_sec);
+
+    /* Get mboxlist_renamemailbox to do the hard work. No ACL checks needed */
+    r = mboxlist_renamemailbox((char *)name, newname, partition,
+                               1 /* isadmin */, userid,
+                               auth_state, force);
+
+    /* don't forget to log the rename! */
+    sync_log_mailbox_double((char *)name, newname);
+    return r;
+}
+
+/*
  * Delete a mailbox.
  * Deleting the mailbox user.FOO may only be performed by an admin.
  *
@@ -3261,3 +3359,42 @@
 
     return DB->abort(mbdb, tid);
 }
+
+int
+mboxlist_delayed_delete_isenabled(void)
+{
+    static int defined = 0;
+    static enum enum_value config_delete_mode;
+
+    if (!defined) {
+        defined = 1;
+        config_delete_mode = config_getenum(IMAPOPT_DELETE_MODE);
+    }
+
+    return(config_delete_mode == IMAP_ENUM_DELETE_MODE_DELAYED);
+}
+
+int mboxlist_in_deleteprefix(const char *mailboxname)
+{
+    static int defined = 0;
+    static const char *deleteprefix = NULL;
+    static int deleteprefix_len = 0;
+    int domainlen = 0;
+    char *p;
+
+    if (!defined) {
+        defined = 1;
+        deleteprefix = config_getstring(IMAPOPT_DELETEPREFIX);
+        if (deleteprefix)
+            deleteprefix_len = strlen(deleteprefix);
+    }
+
+    if (!deleteprefix || !mboxlist_delayed_delete_isenabled())
+        return(0);
+
+    if (config_virtdomains && (p = strchr(mailboxname, '!')))
+        domainlen = p - mailboxname + 1;    
+
+    return ((!strncmp(mailboxname + domainlen, deleteprefix, deleteprefix_len) &&
+             mailboxname[domainlen + deleteprefix_len] == '.') ? 1 : 0);
+}
Index: cyrus-imapd-2.3.9/imap/mboxlist.h
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/mboxlist.h	2007-08-16 21:42:14.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/mboxlist.h	2007-08-16 21:45:58.000000000 -0400
@@ -118,6 +118,12 @@
 			   struct auth_state *auth_state,
 			   int localonly, int forceuser, int dbonly);
 
+/* delated delete */
+/* Translate delete into rename */
+int
+mboxlist_delayed_deletemailbox(const char *name, int isadmin, char *userid, 
+                               struct auth_state *auth_state, int checkacl,
+                               int local_only, int force);
 /* Delete a mailbox. */
 /* setting local_only disables any communication with the mupdate server
  * and deletes the mailbox from the filesystem regardless of if it is
@@ -204,4 +210,6 @@
 int mboxlist_commit(struct txn *tid);
 int mboxlist_abort(struct txn *tid);
 
+int mboxlist_delayed_delete_isenabled(void);
+int mboxlist_in_deleteprefix(const char *mailboxname);
 #endif
Index: cyrus-imapd-2.3.9/imap/mboxname.c
===================================================================
--- cyrus-imapd-2.3.9.orig/imap/mboxname.c	2007-08-16 21:42:14.000000000 -0400
+++ cyrus-imapd-2.3.9/imap/mboxname.c	2007-08-16 21:46:47.000000000 -0400
@@ -599,11 +599,25 @@
 char *mboxname_isusermailbox(const char *name, int isinbox)
 {
     const char *p;
+    const char *start = name;
+    const char *deleteprefix = config_getstring(IMAPOPT_DELETEPREFIX);
+    const char sep = config_getswitch(IMAPOPT_UNIXHIERARCHYSEP) ? '/' : '.';
+    int len = strlen(deleteprefix);
+    int isdel = 0;
+
+    /* step past the domain part */
+    if (config_virtdomains && (p = strchr(start, '!')))
+	start = p + 1;
+
+    /* step past any deleted bit */
+    if (mboxlist_delayed_delete_isenabled() && strlen(start) > len && !strncmp(start, deleteprefix, len) && start[len] == sep)  {
+	start += len + 1;
+	isdel = 1; /* there's an additional sep + hextimestamp on isdel folders */
+    }
 
-    if (((!strncmp(name, "user.", 5) && (p = name+5)) ||
-	 ((p = strstr(name, "!user.")) && (p += 6))) &&
-	(!isinbox || !strchr(p, '.')))
-	return (char*) p;
+    if (strlen(start) > 5 && !strncmp(start, "user", 4) && start[4] == sep && 
+      (!isinbox || !strchr(start+5, sep)) || (isdel && (p = strchr(start+5, sep)) && !strchr(p+1, sep)))
+	return (char*) start+5;
     else
 	return NULL;
 }
Index: cyrus-imapd-2.3.9/lib/imapoptions
===================================================================
--- cyrus-imapd-2.3.9.orig/lib/imapoptions	2007-08-16 21:42:58.000000000 -0400
+++ cyrus-imapd-2.3.9/lib/imapoptions	2007-08-16 21:47:21.000000000 -0400
@@ -201,6 +201,16 @@
 { "defaultpartition", "default", STRING }
 /* The partition name used by default for new mailboxes. */
 
+{ "deleteprefix", "DELETED", STRING }
+/* Location for deleted mailboxes, if "delete_mode" set to be "delayed" */
+
+{ "delete_mode", "immediate", ENUM("immediate", "delayed") }
+/*  The manner in which mailboxes are deleted. "Immediate" mode is the
+    default behavior in which mailboxes are removed immediately. In
+    "Delayed" mode, mailboxes are renamed to a special hiearchy defined
+    by the "deleteprefix" option to be removed later by cyr_expire.
+*/
+
 { "deleteright", "c", STRING }
 /* Deprecated - only used for backwards compatibility with existing
    installations.  Lists the old RFC 2086 right which was used to
Index: cyrus-imapd-2.3.9/man/cyr_expire.8
===================================================================
--- cyrus-imapd-2.3.9.orig/man/cyr_expire.8	2007-08-16 21:42:14.000000000 -0400
+++ cyrus-imapd-2.3.9/man/cyr_expire.8	2007-08-16 21:44:30.000000000 -0400
@@ -48,6 +48,9 @@
 .B \-C
 .I config-file
 ]
+[
+.BI \-D " delete-days"
+]
 .BI \-E " expire-days"
 [
 .BI \-X " expunge-days"
@@ -84,6 +87,11 @@
 .BI \-C " config-file"
 Read configuration options from \fIconfig-file\fR.
 .TP
+\fB\-D \fIdelete-days\fR
+Remove previously deleted mailboxes older than \fIdelete-days\fR
+(when using the "delayed" delete mode).  The default is 0 (zero)
+days, which will delete \fBall\fR previously deleted mailboxes.
+.TP
 \fB\-E \fIexpire-days\fR
 Prune the duplicate database of entries older than \fIexpire-days\fR.  This
 value is only used for entries which do not have a corresponding
----
Cyrus Home Page: http://cyrusimap.web.cmu.edu/
Cyrus Wiki/FAQ: http://cyrusimap.web.cmu.edu/twiki
List Archives/Info: http://asg.web.cmu.edu/cyrus/mailing-list.html

[Index of Archives]     [Cyrus SASL]     [Squirrel Mail]     [Asterisk PBX]     [Video For Linux]     [Photo]     [Yosemite News]     [gtk]     [KDE]     [Gimp on Windows]     [Steve's Art]

  Powered by Linux