Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/ctl_cyrusdb.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/ctl_cyrusdb.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/ctl_cyrusdb.c	2007-03-30 21:40:20.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/ctl_cyrusdb.c	2007-08-21 16:49:06.000000000 +0300
cf58a5c
@@ -133,7 +133,7 @@
d0d307a
     /* if it is MBTYPE_RESERVED, unset it & call mboxlist_delete */
d0d307a
     if(!r && (mbtype & MBTYPE_RESERVE)) {
d0d307a
 	if(!r) {
d0d307a
-	    r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1);
d0d307a
+	    r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1, 1);
d0d307a
 	    if(r) {
d0d307a
 		/* log the error */
d0d307a
 		syslog(LOG_ERR,
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/ctl_mboxlist.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/ctl_mboxlist.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/ctl_mboxlist.c	2007-07-18 21:56:11.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/ctl_mboxlist.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 14dc340
@@ -484,7 +484,7 @@
d0d307a
 	    
d0d307a
 	    wipe_head = wipe_head->next;
d0d307a
 	    
d0d307a
-	    ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1);
d0d307a
+	    ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1, 1);
Tomas Janousek 915c4a4
 	    if(!ret) sync_log_mailbox(me->mailbox);
d0d307a
 	    if(ret) {
d0d307a
 		fprintf(stderr, "couldn't delete defunct mailbox %s\n",
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/imapd.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/imapd.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/imapd.c	2007-08-02 17:18:51.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/imapd.c	2007-08-21 16:49:28.000000000 +0300
Tomas Janousek 14dc340
@@ -4994,7 +4994,7 @@
d0d307a
 
d0d307a
     r = mboxlist_deletemailbox(name, imapd_userisadmin,
d0d307a
 			       imapd_userid, imapd_authstate,
d0d307a
-			       0, 0, 0);
d0d307a
+			       0, 0, 0, 1);
d0d307a
     
cf58a5c
     if (!r) sync_log_mailbox(name);
cf58a5c
 
Tomas Janousek 14dc340
@@ -5018,6 +5018,12 @@
d0d307a
     char *p;
d0d307a
     int domainlen = 0;
cf58a5c
     int sync_lockfd = (-1);
d0d307a
+    int keepQuota = 1;
d0d307a
+
d0d307a
+    if(name && *name == '+') {
Tomas Janousek 915c4a4
+        keepQuota = 0;
Tomas Janousek 915c4a4
+        name++;
d0d307a
+    }
d0d307a
 
d0d307a
     r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
d0d307a
 					       imapd_userid, mailboxname);
Tomas Janousek 14dc340
@@ -5076,7 +5082,7 @@
d0d307a
 
d0d307a
 	r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
cf58a5c
 				   imapd_userid, imapd_authstate, 1-force,
d0d307a
-				   localonly, 0);
d0d307a
+				   localonly, 0, keepQuota);
d0d307a
     }
d0d307a
 
d0d307a
     /* was it a top-level user mailbox? */
Tomas Janousek 14dc340
@@ -6434,6 +6440,7 @@
d0d307a
 {
d0d307a
     int newquota = -1;
d0d307a
     int badresource = 0;
d0d307a
+    int rmquota = 0;
d0d307a
     int c;
d0d307a
     int force = 0;
d0d307a
     static struct buf arg;
Tomas Janousek 14dc340
@@ -6450,7 +6457,8 @@
d0d307a
     if (c != ')' || arg.s[0] != '\0') {
d0d307a
 	for (;;) {
d0d307a
 	    if (c != ' ') goto badlist;
d0d307a
-	    if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
d0d307a
+	    if (strcasecmp(arg.s, "remove") == 0) rmquota = 1;
d0d307a
+	    else if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
d0d307a
 	    c = getword(imapd_in, &arg;;
d0d307a
 	    if (c != ' ' && c != ')') goto badlist;
d0d307a
 	    if (arg.s[0] == '\0') goto badlist;
Tomas Janousek 14dc340
@@ -6519,7 +6527,10 @@
Tomas Janousek 915c4a4
 
Tomas Janousek 915c4a4
     /* local mailbox */
Tomas Janousek 915c4a4
     if (!r || (r == IMAP_MAILBOX_NONEXISTENT)) {
cf58a5c
-	r = mboxlist_setquota(mailboxname, newquota, force);
Tomas Janousek 915c4a4
+        if(!rmquota) 
cf58a5c
+	    r = mboxlist_setquota(mailboxname, newquota, force);
Tomas Janousek 915c4a4
+	else 
cf58a5c
+	    r = mboxlist_unsetquota(mailboxname);
d0d307a
     }
d0d307a
 
cf58a5c
     imapd_check(NULL, 0, 0);
Tomas Janousek 14dc340
@@ -8237,7 +8248,7 @@
Tomas Janousek 14dc340
 	    /* note also that we need to remember to let proxyadmins do this */
Tomas Janousek 14dc340
 	    r = mboxlist_deletemailbox(mailboxname,
Tomas Janousek 14dc340
 				       imapd_userisadmin || imapd_userisproxyadmin,
Tomas Janousek 14dc340
-				       imapd_userid, imapd_authstate, 0, 1, 0);
Tomas Janousek 14dc340
+				       imapd_userid, imapd_authstate, 0, 1, 0, 1);
Tomas Janousek 14dc340
 	    if(r) syslog(LOG_ERR,
Tomas Janousek 14dc340
 			 "Could not delete local mailbox during move of %s",
Tomas Janousek 14dc340
 			 mailboxname);
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/mailbox.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mailbox.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/mailbox.c	2007-07-20 17:21:57.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mailbox.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -2745,27 +2745,7 @@
d0d307a
 
d0d307a
     seen_delete_mailbox(mailbox);
d0d307a
 
d0d307a
-    if (delete_quota_root && !rquota) {
d0d307a
-	quota_delete(&mailbox->quota, &tid;;
d0d307a
-	free(mailbox->quota.root);
d0d307a
-	mailbox->quota.root = NULL;
d0d307a
-    } else if (!rquota) {
d0d307a
-	/* Free any quota being used by this mailbox */
d0d307a
-	if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
d0d307a
-	    mailbox->quota.used -= mailbox->quota_mailbox_used;
d0d307a
-	}
d0d307a
-	else {
d0d307a
-	    mailbox->quota.used = 0;
d0d307a
-	}
d0d307a
-	r = quota_write(&mailbox->quota, &tid;;
d0d307a
-	if (r) {
d0d307a
-	    syslog(LOG_ERR,
cf58a5c
-		   "LOSTQUOTA: unable to record free of " UQUOTA_T_FMT " bytes in quota %s",
d0d307a
-		   mailbox->quota_mailbox_used, mailbox->quota.root);
d0d307a
-	}
d0d307a
-	else
d0d307a
-	    quota_commit(&tid;;
d0d307a
-    }
d0d307a
+    mailbox_updatequota(mailbox,NULL);
d0d307a
 
Tomas Janousek 915c4a4
     /* Flush data (message file) directory */
Tomas Janousek 915c4a4
     mailbox_delete_files(mailbox->path);
Tomas Janousek 14dc340
@@ -3394,3 +3374,48 @@
d0d307a
 	if (*p == '.') *p = '/';
d0d307a
     }
d0d307a
 }
d0d307a
+
d0d307a
+/* This function is used to update the quota. Can be used to replace
Tomas Janousek 915c4a4
+ * identical parts of the code, and can be quite handy some times
d0d307a
+ * The tid is used in order to make possible to make the quota update
d0d307a
+ * being a part of a bigger transaction to the quota db */
d0d307a
+int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid)
d0d307a
+{
d0d307a
+    int r = 0, havetid = 0;
d0d307a
+    struct txn **ltid = NULL;
d0d307a
+
d0d307a
+    if(tid) {
d0d307a
+        ltid = tid;
d0d307a
+        havetid = 1;
d0d307a
+    }
d0d307a
+    /* Ensure that we are locked */
d0d307a
+    if(!mailbox->header_lock_count) return IMAP_INTERNAL;
d0d307a
+
d0d307a
+
d0d307a
+    if(mailbox->quota.root) {
d0d307a
+        r = quota_read(&mailbox->quota, ltid, 1);
d0d307a
+        if( r == 0 ) {
d0d307a
+            if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
d0d307a
+                mailbox->quota.used -= mailbox->quota_mailbox_used;
d0d307a
+            }
d0d307a
+            else {
d0d307a
+                mailbox->quota.used = 0;
d0d307a
+            }
d0d307a
+            r = quota_write(&mailbox->quota, ltid);
d0d307a
+            if (r) {
d0d307a
+                syslog(LOG_ERR,
d0d307a
+                   "LOSTQUOTA: unable to record free of %lu bytes in quota %s",
d0d307a
+                   mailbox->quota_mailbox_used, mailbox->quota.root);
d0d307a
+            }
d0d307a
+            else if(!havetid)
cf58a5c
+                quota_commit(tid);
d0d307a
+        }
d0d307a
+        /* It is not a big mistake not to have quota .. just remove from the mailbox */
d0d307a
+        else if ( r == IMAP_QUOTAROOT_NONEXISTENT) {
d0d307a
+                free(mailbox->quota.root);
d0d307a
+                r = 0;
d0d307a
+        }
d0d307a
+    }
d0d307a
+    return r;
d0d307a
+}
d0d307a
+
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/mailbox.h cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mailbox.h
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/mailbox.h	2006-11-30 19:11:19.000000000 +0200
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mailbox.h	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -364,6 +364,8 @@
d0d307a
 			  struct mailbox *mailboxp);
d0d307a
 extern int mailbox_delete(struct mailbox *mailbox, int delete_quota_root);
d0d307a
 
d0d307a
+extern int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid);
d0d307a
+
d0d307a
 extern int mailbox_rename_copy(struct mailbox *oldmailbox, 
cf58a5c
 			       const char *newname, char *newpartition,
d0d307a
 			       bit32 *olduidvalidityp, bit32 *newuidvalidityp,
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/mboxlist.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mboxlist.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/mboxlist.c	2007-08-15 20:20:55.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mboxlist.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -95,6 +95,12 @@
d0d307a
 static int mboxlist_opensubs();
d0d307a
 static void mboxlist_closesubs();
d0d307a
 
d0d307a
+static int child_cb(char *name,
d0d307a
+                    int matchlen __attribute__((unused)),
d0d307a
+                    int maycreate __attribute__((unused)),
d0d307a
+                    void *rock);
d0d307a
+
Tomas Janousek 915c4a4
+
d0d307a
 static int mboxlist_rmquota(const char *name, int matchlen, int maycreate,
d0d307a
 			    void *rock);
d0d307a
 static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
Tomas Janousek 915c4a4
@@ -102,6 +108,7 @@
d0d307a
 
d0d307a
 struct change_rock {
d0d307a
     struct quota *quota;
d0d307a
+    struct quota *oldquota;
d0d307a
     struct txn **tid;
d0d307a
 };
d0d307a
 
Tomas Janousek 915c4a4
@@ -889,9 +896,9 @@
d0d307a
  */
d0d307a
 int mboxlist_deletemailbox(const char *name, int isadmin, char *userid, 
d0d307a
 			   struct auth_state *auth_state, int checkacl,
d0d307a
-			   int local_only, int force)
d0d307a
+			   int local_only, int force, int keepQuota)
d0d307a
 {
d0d307a
-    int r;
d0d307a
+    int r, has_children = 0;
d0d307a
     char *acl;
d0d307a
     long access;
d0d307a
     struct mailbox mailbox;
Tomas Janousek 915c4a4
@@ -902,6 +909,7 @@
cf58a5c
     int mbtype;
d0d307a
     const char *p;
d0d307a
     mupdate_handle *mupdate_h = NULL;
d0d307a
+    char *quotaroot = NULL;
d0d307a
 
d0d307a
     if(!isadmin && force) return IMAP_PERMISSION_DENIED;
d0d307a
 
Tomas Janousek 915c4a4
@@ -1014,15 +1022,47 @@
d0d307a
 
d0d307a
     if ((r && !force) || isremote) goto done;
d0d307a
 
d0d307a
-    if (!r || force) r = mailbox_delete(&mailbox, deletequotaroot);
d0d307a
+    if (!r || force) {
d0d307a
+        /* first we have to keep the previous quota root in order to delete it */
d0d307a
+        if(mailbox.quota.root)
d0d307a
+                quotaroot = xstrdup(mailbox.quota.root);
Tomas Janousek 915c4a4
+        r = mailbox_delete(&mailbox, deletequotaroot);
d0d307a
+    }
Tomas Janousek 915c4a4
+
d0d307a
 
d0d307a
     /*
d0d307a
      * See if we have to remove mailbox's quota root
d0d307a
      */
d0d307a
-    if (!r && mailbox.quota.root != NULL) {
Tomas Janousek 915c4a4
-	/* xxx look for any other mailboxes in this quotaroot */
d0d307a
+    if (!r && quotaroot != NULL) {
Tomas Janousek 915c4a4
+        /* xxx look for any other mailboxes in this quotaroot */
Tomas Janousek 915c4a4
+        /* If we have not asked to remove the quota (default behaviour), we check
d0d307a
+         * whether there are any subfolders beneeth the quota root. If there aren't
d0d307a
+         * any subfolders the reasonable thing is to delete the quota */
d0d307a
+        if(keepQuota) {
d0d307a
+            char pattern[MAX_MAILBOX_PATH+1];
d0d307a
+            strlcpy(pattern, quotaroot, sizeof(pattern));
d0d307a
+            if (config_virtdomains && name[strlen(name)-1] == '!') {
d0d307a
+                strlcat(pattern, "*", sizeof(pattern));
d0d307a
+            }
d0d307a
+            else {
d0d307a
+                strlcat(pattern, ".*", sizeof(pattern));
Tomas Janousek 915c4a4
+            }   
Tomas Janousek 915c4a4
+                /* find if there are subfolders. Then we want to
Tomas Janousek 915c4a4
+                 * keep the existing quota */
d0d307a
+            mboxlist_findall(NULL, pattern, isadmin, userid,
d0d307a
+                    auth_state, child_cb, (void *) &has_children);
d0d307a
+
Tomas Janousek 915c4a4
+            if(!has_children)
Tomas Janousek 915c4a4
+                if(!mboxlist_mylookup(quotaroot, NULL, NULL, NULL, NULL, NULL, 0, 1))
Tomas Janousek 915c4a4
+                    has_children = 1;
d0d307a
+        }
d0d307a
+        /* If we want to remove the quota explicitely or the quota root folder has no subfolders
d0d307a
+         * we execute the rmquota patch */
d0d307a
+        if(!keepQuota || !has_children )
d0d307a
+            mboxlist_unsetquota(quotaroot);
d0d307a
+        free(quotaroot);
d0d307a
     }
Tomas Janousek 915c4a4
-
Tomas Janousek 915c4a4
+    
d0d307a
  done:
Tomas Janousek 915c4a4
     if(r && tid && !force) {
Tomas Janousek 915c4a4
 	/* Abort the transaction if it is still in progress */
Tomas Janousek 915c4a4
@@ -2483,6 +2523,7 @@
d0d307a
     if (r) return r;
d0d307a
 
d0d307a
     crock.quota = "a;
d0d307a
+    crock.oldquota = NULL;
d0d307a
     crock.tid = &tid;
d0d307a
     /* top level mailbox */
d0d307a
     if(have_mailbox)
Tomas Janousek 915c4a4
@@ -2501,15 +2542,19 @@
d0d307a
  */
d0d307a
 int mboxlist_unsetquota(const char *root)
d0d307a
 {
d0d307a
+    char newquota[MAX_MAILBOX_PATH+1];
d0d307a
     char pattern[MAX_MAILBOX_PATH+1];
d0d307a
     struct quota quota;
d0d307a
-    int r=0;
d0d307a
+    struct change_rock crock;
d0d307a
+    int r=0, k=0;
d0d307a
 
d0d307a
     if (!root[0] || root[0] == '.' || strchr(root, '/')
d0d307a
 	|| strchr(root, '*') || strchr(root, '%') || strchr(root, '?')) {
d0d307a
 	return IMAP_MAILBOX_BADNAME;
d0d307a
     }
d0d307a
     
Tomas Janousek 915c4a4
+    crock.tid=NULL;
Tomas Janousek 915c4a4
+    
d0d307a
     quota.root = (char *) root;
Tomas Janousek 915c4a4
     r = quota_read(&quota, NULL, 0);
d0d307a
     if (r == IMAP_QUOTAROOT_NONEXISTENT) {
Tomas Janousek 915c4a4
@@ -2534,9 +2579,47 @@
Tomas Janousek 915c4a4
     /* submailboxes - we're using internal names here */
Tomas Janousek 915c4a4
     mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
d0d307a
 
d0d307a
-    r = quota_delete(&quota, NULL);
d0d307a
+    r = quota_delete(&quota, crock.tid);
d0d307a
+
d0d307a
+    /* If we cannot delete the quota then abort the operation */
d0d307a
+    if(!r) {
d0d307a
+       /* quota_findroot performs several checks that we can
d0d307a
+        * assume that are already done, and don't have to perform
d0d307a
+        * them again. One of them is that it returns 1 only if
d0d307a
+        * quotaroot exists.
d0d307a
+        */
d0d307a
+        if(quota_findroot(newquota, sizeof(newquota), root)) {
d0d307a
+            struct quota rootquota;
d0d307a
+            rootquota.root = newquota;
d0d307a
+            k = quota_read(&rootquota, crock.tid, 0);
d0d307a
+            if (!k) {
d0d307a
+                crock.quota = &rootquota;
d0d307a
+                crock.oldquota = "a;
d0d307a
+                /* top level mailbox */
d0d307a
+                k = mboxlist_changequota(root, 0, 0, &crock);
d0d307a
+            }
d0d307a
+            /* submailboxes - we're using internal names here */
d0d307a
+            if (!k)
d0d307a
+                k = mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_changequota, &crock);
d0d307a
+            if(!k)
d0d307a
+                k = quota_write(&rootquota, crock.tid);
d0d307a
+
d0d307a
+         }
d0d307a
+         else {
d0d307a
+           /* top level mailbox */
d0d307a
+           mboxlist_rmquota(root, 0, 0, (void *)root);
d0d307a
+           /* submailboxes - we're using internal names here */
d0d307a
+           mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
d0d307a
+       }
d0d307a
+    }
d0d307a
+
d0d307a
+    if(!r && !k)
d0d307a
+        quota_commit(crock.tid);
d0d307a
+    else
d0d307a
+        quota_abort(crock.tid);
d0d307a
 
d0d307a
     return r;
Tomas Janousek 915c4a4
+
d0d307a
 }
Tomas Janousek 915c4a4
 
Tomas Janousek 915c4a4
 /*
Tomas Janousek 915c4a4
@@ -2632,6 +2715,7 @@
d0d307a
     struct mailbox mailbox;
d0d307a
     struct change_rock *crock = (struct change_rock *) rock;
d0d307a
     struct quota *mboxlist_newquota = crock->quota;
d0d307a
+    struct quota *mboxlist_oldquota = crock->oldquota;
d0d307a
     struct txn **tid = crock->tid;
d0d307a
 
d0d307a
     assert(rock != NULL);
Tomas Janousek 915c4a4
@@ -2649,27 +2733,24 @@
d0d307a
     if (r) goto error;
d0d307a
 
d0d307a
     if (mailbox.quota.root) {
d0d307a
-	if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
d0d307a
-	    /* Part of a child quota root */
d0d307a
-	    mailbox_close(&mailbox);
d0d307a
-	    return 0;
d0d307a
-	}
d0d307a
-
d0d307a
-	r = quota_read(&mailbox.quota, tid, 1);
d0d307a
-	if (r) goto error;
d0d307a
-	if (mailbox.quota.used >= mailbox.quota_mailbox_used) {
d0d307a
-	    mailbox.quota.used -= mailbox.quota_mailbox_used;
Tomas Janousek 915c4a4
-	}
Tomas Janousek 915c4a4
-	else {
d0d307a
-	    mailbox.quota.used = 0;
d0d307a
-	}
d0d307a
-	r = quota_write(&mailbox.quota, tid);
d0d307a
-	if (r) {
d0d307a
-	    syslog(LOG_ERR,
cf58a5c
-		   "LOSTQUOTA: unable to record free of " UQUOTA_T_FMT " bytes in quota %s",
d0d307a
-		   mailbox.quota_mailbox_used, mailbox.quota.root);
Tomas Janousek 915c4a4
-	}
d0d307a
-	free(mailbox.quota.root);
Tomas Janousek 915c4a4
+        if(mboxlist_oldquota) {
Tomas Janousek 915c4a4
+            if (strlen(mailbox.quota.root) > strlen(mboxlist_oldquota->root)) {
Tomas Janousek 915c4a4
+                /* Part of a child quota root */
Tomas Janousek 915c4a4
+                mailbox_close(&mailbox);
Tomas Janousek 915c4a4
+                return 0;
Tomas Janousek 915c4a4
+            }
Tomas Janousek 915c4a4
+        }
Tomas Janousek 915c4a4
+        else {
Tomas Janousek 915c4a4
+            if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
Tomas Janousek 915c4a4
+                /* Part of a child quota root */
Tomas Janousek 915c4a4
+                mailbox_close(&mailbox);
Tomas Janousek 915c4a4
+                return 0;
Tomas Janousek 915c4a4
+            }
Tomas Janousek 915c4a4
+        }
d0d307a
+
Tomas Janousek 915c4a4
+        r = mailbox_updatequota(&mailbox,tid);
Tomas Janousek 915c4a4
+        if (r)
Tomas Janousek 915c4a4
+            goto error;
d0d307a
     }
d0d307a
 
d0d307a
     mailbox.quota.root = xstrdup(mboxlist_newquota->root);
Tomas Janousek 915c4a4
@@ -2682,6 +2763,11 @@
Tomas Janousek 915c4a4
 
d0d307a
  error:
d0d307a
     mailbox_close(&mailbox);
d0d307a
+    syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s. \
d0d307a
+                        Command aborted. Run reconstruct to make sure mailboxes \
d0d307a
+                         are in consistent state",
d0d307a
+           name, mboxlist_newquota->root, error_message(r));
d0d307a
+    return 1;
d0d307a
  error_noclose:
d0d307a
     syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s",
Tomas Janousek 915c4a4
 	   name, mboxlist_newquota->root, error_message(r));
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/mboxlist.h cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mboxlist.h
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/mboxlist.h	2006-11-30 19:11:19.000000000 +0200
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/mboxlist.h	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -126,7 +126,7 @@
d0d307a
  * the planet */
d0d307a
 int mboxlist_deletemailbox(const char *name, int isadmin, char *userid, 
d0d307a
 			   struct auth_state *auth_state, int checkacl,
d0d307a
-			   int local_only, int force);
d0d307a
+			   int local_only, int force, int keepQuota);
d0d307a
 
d0d307a
 /* Rename/move a mailbox (hierarchical) */
d0d307a
 int mboxlist_renamemailbox(char *oldname, char *newname, char *partition, 
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/nntpd.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/nntpd.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/nntpd.c	2007-03-30 21:51:01.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/nntpd.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -3358,7 +3358,7 @@
d0d307a
     /* XXX should we delete right away, or wait until empty? */
d0d307a
 
d0d307a
     r = mboxlist_deletemailbox(mailboxname, 0,
d0d307a
-			       newsmaster, newsmaster_authstate, 1, 0, 0);
d0d307a
+			       newsmaster, newsmaster_authstate, 1, 0, 0, 1);
d0d307a
 
cf58a5c
     if (!r) sync_log_mailbox(mailboxname);
cf58a5c
 
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/sync_reset.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/sync_reset.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/sync_reset.c	2007-03-30 21:40:21.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/sync_reset.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 915c4a4
@@ -258,7 +258,7 @@
cf58a5c
     if (r) goto fail;
cf58a5c
 
cf58a5c
     for (item = list->head ; item ; item = item->next) {
cf58a5c
-        r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0);
cf58a5c
+        r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0, 1);
cf58a5c
 
cf58a5c
         if (r) goto fail;
cf58a5c
     }
Tomas Janousek 915c4a4
@@ -274,7 +274,7 @@
cf58a5c
     if (r) goto fail;
cf58a5c
 
cf58a5c
     for (item = list->head ; item ; item = item->next) {
cf58a5c
-        r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0);
cf58a5c
+        r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0, 1);
cf58a5c
 
cf58a5c
         if (r) goto fail;
cf58a5c
     }
Tomas Janousek 915c4a4
@@ -282,7 +282,7 @@
cf58a5c
 
cf58a5c
     /* Nuke inbox (recursive nuke possible?) */
cf58a5c
     snprintf(buf, sizeof(buf)-1, "user.%s", user);
cf58a5c
-    r = mboxlist_deletemailbox(buf, 1, "cyrus", sync_authstate, 1, 0, 0);
cf58a5c
+    r = mboxlist_deletemailbox(buf, 1, "cyrus", sync_authstate, 1, 0, 0, 1);
cf58a5c
     if (r && (r != IMAP_MAILBOX_NONEXISTENT)) goto fail;
cf58a5c
 
cf58a5c
     if ((r=user_deletedata(user, sync_userid, sync_authstate, 1)))
Tomas Janousek 14dc340
diff -Naur cyrus-imapd-2.3.9/imap/sync_server.c cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/sync_server.c
Tomas Janousek 14dc340
--- cyrus-imapd-2.3.9/imap/sync_server.c	2007-08-01 22:19:03.000000000 +0300
Tomas Janousek 14dc340
+++ cyrus-imapd-2.3.9-rmquota+deletemailbox.uncompiled/imap/sync_server.c	2007-08-21 16:49:06.000000000 +0300
Tomas Janousek 14dc340
@@ -1590,7 +1590,7 @@
cf58a5c
 
cf58a5c
     for (item = list->head ; item ; item = item->next) {
cf58a5c
         r=mboxlist_deletemailbox(item->name, sync_userisadmin, sync_userid,
cf58a5c
-				 sync_authstate, 0, 0, 1);
cf58a5c
+				 sync_authstate, 0, 0, 1, 1);
cf58a5c
 
cf58a5c
         if (r) goto fail;
cf58a5c
     }
Tomas Janousek 14dc340
@@ -1600,7 +1600,7 @@
cf58a5c
     (sync_namespacep->mboxname_tointernal)(sync_namespacep, "INBOX",
cf58a5c
 					   user, buf);
cf58a5c
     r = mboxlist_deletemailbox(buf, sync_userisadmin, sync_userid,
cf58a5c
-			       sync_authstate, 0, 0, 1);
cf58a5c
+			       sync_authstate, 0, 0, 1, 1);
cf58a5c
     if (r && (r != IMAP_MAILBOX_NONEXISTENT)) goto fail;
cf58a5c
 
cf58a5c
     if ((r=user_deletedata(user, sync_userid, sync_authstate, 1)))
Tomas Janousek 14dc340
@@ -2546,7 +2546,7 @@
cf58a5c
 
cf58a5c
     /* Delete with admin priveleges */
cf58a5c
     r = mboxlist_deletemailbox(name, sync_userisadmin, sync_userid,
cf58a5c
-			       sync_authstate, 0, 0, 1);
cf58a5c
+			       sync_authstate, 0, 0, 1, 1);
cf58a5c
 
cf58a5c
     if (r)
cf58a5c
         prot_printf(sync_out, "NO Failed to delete %s: %s\r\n",