1 diff -Naur cyrus-imapd-2.2.12.orig/imap/ctl_cyrusdb.c cyrus-imapd-2.2.12/imap/ctl_cyrusdb.c
2 --- cyrus-imapd-2.2.12.orig/imap/ctl_cyrusdb.c Tue Jul 13 04:34:20 2004
3 +++ cyrus-imapd-2.2.12/imap/ctl_cyrusdb.c Mon Mar 7 11:30:58 2005
5 /* if it is MBTYPE_RESERVED, unset it & call mboxlist_delete */
6 if(!r && (mbtype & MBTYPE_RESERVE)) {
8 - r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1);
9 + r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1, 1);
13 diff -Naur cyrus-imapd-2.2.12.orig/imap/ctl_mboxlist.c cyrus-imapd-2.2.12/imap/ctl_mboxlist.c
14 --- cyrus-imapd-2.2.12.orig/imap/ctl_mboxlist.c Sat May 22 05:45:48 2004
15 +++ cyrus-imapd-2.2.12/imap/ctl_mboxlist.c Mon Mar 7 11:30:58 2005
18 wipe_head = wipe_head->next;
20 - ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1);
21 + ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1, 1);
23 fprintf(stderr, "couldn't delete defunct mailbox %s\n",
25 diff -Naur cyrus-imapd-2.2.12.orig/imap/imapd.c cyrus-imapd-2.2.12/imap/imapd.c
26 --- cyrus-imapd-2.2.12.orig/imap/imapd.c Mon Feb 14 07:39:55 2005
27 +++ cyrus-imapd-2.2.12/imap/imapd.c Mon Mar 7 11:30:58 2005
30 r = mboxlist_deletemailbox(name, imapd_userisadmin,
31 imapd_userid, imapd_authstate,
36 prot_printf(imapd_out, "* NO delete %s: %s\r\n",
37 @@ -3743,6 +3743,12 @@
38 char mailboxname[MAX_MAILBOX_NAME+1];
43 + if(name && *name == '+') {
48 r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
49 imapd_userid, mailboxname);
52 r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
53 imapd_userid, imapd_authstate, 1,
55 + localonly, 0, keepQuota);
58 /* was it a top-level user mailbox? */
66 static struct buf arg;
68 if (c != ')' || arg.s[0] != '\0') {
70 if (c != ' ') goto badlist;
71 - if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
72 + if (strcasecmp(arg.s, "remove") == 0) rmquota = 1;
73 + else if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
74 c = getword(imapd_in, &arg);
75 if (c != ' ' && c != ')') goto badlist;
76 if (arg.s[0] == '\0') goto badlist;
77 @@ -4769,7 +4777,10 @@
78 imapd_userid, mailboxname);
81 - r = mboxlist_setquota(mailboxname, newquota, force);
83 + r = mboxlist_setquota(mailboxname, newquota, force);
85 + r = mboxlist_unsetquota(mailboxname);
90 /* note also that we need to remember to let proxyadmins do this */
91 r = mboxlist_deletemailbox(mailboxname,
92 imapd_userisadmin || imapd_userisproxyadmin,
93 - imapd_userid, imapd_authstate, 0, 1, 0);
94 + imapd_userid, imapd_authstate, 0, 1, 0, 1);
96 "Could not delete local mailbox during move of %s",
98 diff -Naur cyrus-imapd-2.2.12.orig/imap/mailbox.c cyrus-imapd-2.2.12/imap/mailbox.c
99 --- cyrus-imapd-2.2.12.orig/imap/mailbox.c Mon Feb 14 07:39:57 2005
100 +++ cyrus-imapd-2.2.12/imap/mailbox.c Mon Mar 7 11:30:58 2005
101 @@ -2117,27 +2117,7 @@
103 seen_delete_mailbox(mailbox);
105 - if (delete_quota_root && !rquota) {
106 - quota_delete(&mailbox->quota, &tid);
107 - free(mailbox->quota.root);
108 - mailbox->quota.root = NULL;
109 - } else if (!rquota) {
110 - /* Free any quota being used by this mailbox */
111 - if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
112 - mailbox->quota.used -= mailbox->quota_mailbox_used;
115 - mailbox->quota.used = 0;
117 - r = quota_write(&mailbox->quota, &tid);
120 - "LOSTQUOTA: unable to record free of %lu bytes in quota %s",
121 - mailbox->quota_mailbox_used, mailbox->quota.root);
124 - quota_commit(&tid);
126 + mailbox_updatequota(mailbox,NULL);
128 /* remove all files in directory */
129 strlcpy(buf, mailbox->path, sizeof(buf));
130 @@ -2751,3 +2731,49 @@
131 if (*p == '.') *p = '/';
136 +/* This function is used to update the quota. Can be used to replace
137 + * identical parts of the code, and can be quite handy some times
138 + * The tid is used in order to make possible to make the quota update
139 + * being a part of a bigger transaction to the quota db */
140 +int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid)
142 + int r = 0, havetid = 0;
143 + struct txn **ltid = NULL;
149 + /* Ensure that we are locked */
150 + if(!mailbox->header_lock_count) return IMAP_INTERNAL;
153 + if(mailbox->quota.root) {
154 + r = quota_read(&mailbox->quota, ltid, 1);
156 + if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
157 + mailbox->quota.used -= mailbox->quota_mailbox_used;
160 + mailbox->quota.used = 0;
162 + r = quota_write(&mailbox->quota, ltid);
165 + "LOSTQUOTA: unable to record free of %lu bytes in quota %s",
166 + mailbox->quota_mailbox_used, mailbox->quota.root);
171 + /* It is not a big mistake not to have quota .. just remove from the mailbox */
172 + else if ( r == IMAP_QUOTAROOT_NONEXISTENT) {
173 + free(mailbox->quota.root);
180 diff -Naur cyrus-imapd-2.2.12.orig/imap/mailbox.h cyrus-imapd-2.2.12/imap/mailbox.h
181 --- cyrus-imapd-2.2.12.orig/imap/mailbox.h Thu Jan 22 22:17:09 2004
182 +++ cyrus-imapd-2.2.12/imap/mailbox.h Mon Mar 7 11:30:58 2005
184 struct mailbox *mailboxp);
185 extern int mailbox_delete(struct mailbox *mailbox, int delete_quota_root);
187 +extern int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid);
189 extern int mailbox_rename_copy(struct mailbox *oldmailbox,
190 const char *newname, char *newpath,
191 bit32 *olduidvalidityp, bit32 *newuidvalidityp,
192 diff -Naur cyrus-imapd-2.2.12.orig/imap/mboxlist.c cyrus-imapd-2.2.12/imap/mboxlist.c
193 --- cyrus-imapd-2.2.12.orig/imap/mboxlist.c Mon Jul 26 20:08:03 2004
194 +++ cyrus-imapd-2.2.12/imap/mboxlist.c Mon Mar 7 11:30:58 2005
196 static int mboxlist_opensubs();
197 static void mboxlist_closesubs();
199 +static int child_cb(char *name,
200 + int matchlen __attribute__((unused)),
201 + int maycreate __attribute__((unused)),
204 static int mboxlist_rmquota(const char *name, int matchlen, int maycreate,
206 static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
211 + struct quota *oldquota;
217 int mboxlist_deletemailbox(const char *name, int isadmin, char *userid,
218 struct auth_state *auth_state, int checkacl,
219 - int local_only, int force)
220 + int local_only, int force, int keepQuota)
223 + int r, has_children = 0;
226 struct mailbox mailbox;
228 int deleteright = get_deleteright();
230 mupdate_handle *mupdate_h = NULL;
231 + char *quotaroot = NULL;
233 if(!isadmin && force) return IMAP_PERMISSION_DENIED;
235 @@ -1018,13 +1025,44 @@
237 if ((r && !force) || isremote) goto done;
239 - if (!r || force) r = mailbox_delete(&mailbox, deletequotaroot);
241 + /* first we have to keep the previous quota root in order to delete it */
242 + if(mailbox.quota.root)
243 + quotaroot = xstrdup(mailbox.quota.root);
244 + r = mailbox_delete(&mailbox, deletequotaroot);
248 * See if we have to remove mailbox's quota root
250 - if (!r && mailbox.quota.root != NULL) {
251 + if (!r && quotaroot != NULL) {
252 /* xxx look for any other mailboxes in this quotaroot */
253 + /* If we have not asked to remove the quota (default behaviour), we check
254 + * whether there are any subfolders beneeth the quota root. If there aren't
255 + * any subfolders the reasonable thing is to delete the quota */
257 + char pattern[MAX_MAILBOX_PATH+1];
258 + strlcpy(pattern, quotaroot, sizeof(pattern));
259 + if (config_virtdomains && name[strlen(name)-1] == '!') {
260 + strlcat(pattern, "*", sizeof(pattern));
263 + strlcat(pattern, ".*", sizeof(pattern));
265 + /* find if there are subfolders. Then we want to
266 + * keep the existing quota */
267 + mboxlist_findall(NULL, pattern, isadmin, userid,
268 + auth_state, child_cb, (void *) &has_children);
271 + if(!mboxlist_mylookup(quotaroot, NULL, NULL, NULL, NULL, NULL, 0 ))
274 + /* If we want to remove the quota explicitely or the quota root folder has no subfolders
275 + * we execute the rmquota patch */
276 + if(!keepQuota || !has_children )
277 + mboxlist_unsetquota(quotaroot);
282 @@ -2357,6 +2395,7 @@
285 crock.quota = "a;
286 + crock.oldquota = NULL;
288 /* top level mailbox */
290 @@ -2375,17 +2414,21 @@
292 int mboxlist_unsetquota(const char *root)
294 + char newquota[MAX_MAILBOX_PATH+1];
295 char pattern[MAX_MAILBOX_PATH+1];
298 + struct change_rock crock;
301 if (!root[0] || root[0] == '.' || strchr(root, '/')
302 || strchr(root, '*') || strchr(root, '%') || strchr(root, '?')) {
303 return IMAP_MAILBOX_BADNAME;
308 quota.root = (char *) root;
309 - r = quota_read("a, NULL, 0);
310 + r = quota_read("a, crock.tid, 0);
311 if (r == IMAP_QUOTAROOT_NONEXISTENT) {
314 @@ -2402,13 +2445,45 @@
317 strlcat(pattern, ".*", sizeof(pattern));
319 - /* top level mailbox */
320 - mboxlist_rmquota(root, 0, 0, (void *)root);
321 - /* submailboxes - we're using internal names here */
322 - mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
324 - r = quota_delete("a, NULL);
325 + r = quota_delete("a, crock.tid);
327 + /* If we cannot delete the quota then abort the operation */
329 + /* quota_findroot performs several checks that we can
330 + * assume that are already done, and don't have to perform
331 + * them again. One of them is that it returns 1 only if
332 + * quotaroot exists.
334 + if(quota_findroot(newquota, sizeof(newquota), root)) {
335 + struct quota rootquota;
336 + rootquota.root = newquota;
337 + k = quota_read(&rootquota, crock.tid, 0);
339 + crock.quota = &rootquota;
340 + crock.oldquota = "a;
341 + /* top level mailbox */
342 + k = mboxlist_changequota(root, 0, 0, &crock);
344 + /* submailboxes - we're using internal names here */
346 + k = mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_changequota, &crock);
348 + k = quota_write(&rootquota, crock.tid);
352 + /* top level mailbox */
353 + mboxlist_rmquota(root, 0, 0, (void *)root);
354 + /* submailboxes - we're using internal names here */
355 + mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
360 + quota_commit(crock.tid);
362 + quota_abort(crock.tid);
366 @@ -2506,6 +2581,7 @@
367 struct mailbox mailbox;
368 struct change_rock *crock = (struct change_rock *) rock;
369 struct quota *mboxlist_newquota = crock->quota;
370 + struct quota *mboxlist_oldquota = crock->oldquota;
371 struct txn **tid = crock->tid;
373 assert(rock != NULL);
374 @@ -2523,27 +2599,24 @@
377 if (mailbox.quota.root) {
378 - if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
379 - /* Part of a child quota root */
380 - mailbox_close(&mailbox);
384 - r = quota_read(&mailbox.quota, tid, 1);
386 - if (mailbox.quota.used >= mailbox.quota_mailbox_used) {
387 - mailbox.quota.used -= mailbox.quota_mailbox_used;
390 - mailbox.quota.used = 0;
392 - r = quota_write(&mailbox.quota, tid);
395 - "LOSTQUOTA: unable to record free of %lu bytes in quota %s",
396 - mailbox.quota_mailbox_used, mailbox.quota.root);
398 - free(mailbox.quota.root);
399 + if(mboxlist_oldquota) {
400 + if (strlen(mailbox.quota.root) > strlen(mboxlist_oldquota->root)) {
401 + /* Part of a child quota root */
402 + mailbox_close(&mailbox);
407 + if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
408 + /* Part of a child quota root */
409 + mailbox_close(&mailbox);
414 + r = mailbox_updatequota(&mailbox,tid);
419 mailbox.quota.root = xstrdup(mboxlist_newquota->root);
420 @@ -2553,18 +2626,24 @@
421 mboxlist_newquota->used += mailbox.quota_mailbox_used;
422 mailbox_close(&mailbox);
427 mailbox_close(&mailbox);
428 + syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s. \
429 + Command aborted. Run reconstruct to make sure mailboxes \
430 + are in consistent state",
431 + name, mboxlist_newquota->root, error_message(r));
434 syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s",
435 - name, mboxlist_newquota->root, error_message(r));
436 + name, mboxlist_newquota->root, error_message(r));
438 /* Note, we're a callback, and it's not a huge tragedy if we
439 * fail, so we don't ever return a failure */
444 /* must be called after cyrus_init */
445 void mboxlist_init(int myflags)
447 diff -Naur cyrus-imapd-2.2.12.orig/imap/mboxlist.h cyrus-imapd-2.2.12/imap/mboxlist.h
448 --- cyrus-imapd-2.2.12.orig/imap/mboxlist.h Wed Mar 17 19:07:49 2004
449 +++ cyrus-imapd-2.2.12/imap/mboxlist.h Mon Mar 7 11:30:58 2005
452 int mboxlist_deletemailbox(const char *name, int isadmin, char *userid,
453 struct auth_state *auth_state, int checkacl,
454 - int local_only, int force);
455 + int local_only, int force, int keepQuota);
457 /* Rename/move a mailbox (hierarchical) */
458 int mboxlist_renamemailbox(char *oldname, char *newname, char *partition,
459 diff -Naur cyrus-imapd-2.2.12.orig/imap/mupdate.c cyrus-imapd-2.2.12/imap/mupdate.c
460 --- cyrus-imapd-2.2.12.orig/imap/mupdate.c Fri Dec 17 17:32:16 2004
461 +++ cyrus-imapd-2.2.12/imap/mupdate.c Mon Mar 7 11:30:58 2005
462 @@ -2190,7 +2190,7 @@
463 remote_boxes.head = r->next;
464 } else if (ret < 0) {
465 /* Local without corresponding remote, delete it */
466 - mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0);
467 + mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0, 1);
468 local_boxes.head = l->next;
469 } else /* (ret > 0) */ {
470 /* Remote without corresponding local, insert it */
471 @@ -2205,7 +2205,7 @@
473 /* we have more deletes to do */
475 - mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0);
476 + mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0, 1);
477 local_boxes.head = l->next;
478 l = local_boxes.head;
480 diff -Naur cyrus-imapd-2.2.12.orig/imap/nntpd.c cyrus-imapd-2.2.12/imap/nntpd.c
481 --- cyrus-imapd-2.2.12.orig/imap/nntpd.c Fri Jan 7 21:59:04 2005
482 +++ cyrus-imapd-2.2.12/imap/nntpd.c Mon Mar 7 11:30:58 2005
483 @@ -3298,7 +3298,7 @@
484 /* XXX should we delete right away, or wait until empty? */
486 r = mboxlist_deletemailbox(mailboxname, 0,
487 - newsmaster, newsmaster_authstate, 1, 0, 0);
488 + newsmaster, newsmaster_authstate, 1, 0, 0, 1);