cyrus-imapd/cyrus-imapd-2.3.1-rmquota+deletemailbox-0.2-1.diff
2006-02-28 20:04:01 +00:00

549 lines
19 KiB
Diff

diff -Naur cyrus-imapd-2.3.1.orig/imap/ctl_cyrusdb.c cyrus-imapd-2.3.1/imap/ctl_cyrusdb.c
--- cyrus-imapd-2.3.1.orig/imap/ctl_cyrusdb.c 2005-02-16 22:06:18.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/ctl_cyrusdb.c 2006-01-16 11:10:56.000000000 +0100
@@ -133,7 +133,7 @@
/* if it is MBTYPE_RESERVED, unset it & call mboxlist_delete */
if(!r && (mbtype & MBTYPE_RESERVE)) {
if(!r) {
- r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1);
+ r = mboxlist_deletemailbox(name, 1, NULL, NULL, 0, 0, 1, 1);
if(r) {
/* log the error */
syslog(LOG_ERR,
diff -Naur cyrus-imapd-2.3.1.orig/imap/ctl_mboxlist.c cyrus-imapd-2.3.1/imap/ctl_mboxlist.c
--- cyrus-imapd-2.3.1.orig/imap/ctl_mboxlist.c 2005-11-23 14:41:24.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/ctl_mboxlist.c 2006-01-16 11:10:56.000000000 +0100
@@ -457,7 +457,7 @@
wipe_head = wipe_head->next;
- ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1);
+ ret = mboxlist_deletemailbox(me->mailbox, 1, "", NULL, 0, 1, 1, 1);
if(ret) {
fprintf(stderr, "couldn't delete defunct mailbox %s\n",
me->mailbox);
diff -Naur cyrus-imapd-2.3.1.orig/imap/imapd.c cyrus-imapd-2.3.1/imap/imapd.c
--- cyrus-imapd-2.3.1.orig/imap/imapd.c 2005-12-13 20:35:50.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/imapd.c 2006-01-16 11:10:56.000000000 +0100
@@ -4707,7 +4707,7 @@
r = mboxlist_deletemailbox(name, imapd_userisadmin,
imapd_userid, imapd_authstate,
- 0, 0, 0);
+ 0, 0, 0, 1);
if (!r) sync_log_mailbox(name);
@@ -4731,6 +4731,12 @@
char *p;
int domainlen = 0;
int sync_lockfd = (-1);
+ int keepQuota = 1;
+
+ if(name && *name == '+') {
+ keepQuota = 0;
+ name++;
+ }
r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
imapd_userid, mailboxname);
@@ -4789,7 +4795,7 @@
r = mboxlist_deletemailbox(mailboxname, imapd_userisadmin,
imapd_userid, imapd_authstate, 1-force,
- localonly, 0);
+ localonly, 0, keepQuota);
}
/* was it a top-level user mailbox? */
@@ -6149,6 +6155,7 @@
{
int newquota = -1;
int badresource = 0;
+ int rmquota = 0;
int c;
int force = 0;
static struct buf arg;
@@ -6165,7 +6172,8 @@
if (c != ')' || arg.s[0] != '\0') {
for (;;) {
if (c != ' ') goto badlist;
- if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
+ if (strcasecmp(arg.s, "remove") == 0) rmquota = 1;
+ else if (strcasecmp(arg.s, "storage") != 0) badresource = 1;
c = getword(imapd_in, &arg);
if (c != ' ' && c != ')') goto badlist;
if (arg.s[0] == '\0') goto badlist;
@@ -6234,7 +6242,10 @@
quotaroot++;
}
- r = mboxlist_setquota(mailboxname, newquota, force);
+ if(!rmquota)
+ r = mboxlist_setquota(mailboxname, newquota, force);
+ else
+ r = mboxlist_unsetquota(mailboxname);
}
imapd_check(NULL, 0, 0);
@@ -7931,7 +7942,7 @@
/* note also that we need to remember to let proxyadmins do this */
r = mboxlist_deletemailbox(mailboxname,
imapd_userisadmin || imapd_userisproxyadmin,
- imapd_userid, imapd_authstate, 0, 1, 0);
+ imapd_userid, imapd_authstate, 0, 1, 0, 1);
if(r) syslog(LOG_ERR,
"Could not delete local mailbox during move of %s",
mailboxname);
diff -Naur cyrus-imapd-2.3.1.orig/imap/mailbox.c cyrus-imapd-2.3.1/imap/mailbox.c
--- cyrus-imapd-2.3.1.orig/imap/mailbox.c 2005-11-10 07:04:55.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/mailbox.c 2006-01-16 11:10:56.000000000 +0100
@@ -2622,27 +2622,7 @@
seen_delete_mailbox(mailbox);
- if (delete_quota_root && !rquota) {
- quota_delete(&mailbox->quota, &tid);
- free(mailbox->quota.root);
- mailbox->quota.root = NULL;
- } else if (!rquota) {
- /* Free any quota being used by this mailbox */
- if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
- mailbox->quota.used -= mailbox->quota_mailbox_used;
- }
- else {
- mailbox->quota.used = 0;
- }
- r = quota_write(&mailbox->quota, &tid);
- if (r) {
- syslog(LOG_ERR,
- "LOSTQUOTA: unable to record free of " UQUOTA_T_FMT " bytes in quota %s",
- mailbox->quota_mailbox_used, mailbox->quota.root);
- }
- else
- quota_commit(&tid);
- }
+ mailbox_updatequota(mailbox,NULL);
/* remove data (message file) directory */
path = mailbox->path;
@@ -3263,3 +3243,49 @@
if (*p == '.') *p = '/';
}
}
+
+
+/* This function is used to update the quota. Can be used to replace
+ * identical parts of the code, and can be quite handy some times
+ * The tid is used in order to make possible to make the quota update
+ * being a part of a bigger transaction to the quota db */
+int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid)
+{
+ int r = 0, havetid = 0;
+ struct txn **ltid = NULL;
+
+ if(tid) {
+ ltid = tid;
+ havetid = 1;
+ }
+ /* Ensure that we are locked */
+ if(!mailbox->header_lock_count) return IMAP_INTERNAL;
+
+
+ if(mailbox->quota.root) {
+ r = quota_read(&mailbox->quota, ltid, 1);
+ if( r == 0 ) {
+ if (mailbox->quota.used >= mailbox->quota_mailbox_used) {
+ mailbox->quota.used -= mailbox->quota_mailbox_used;
+ }
+ else {
+ mailbox->quota.used = 0;
+ }
+ r = quota_write(&mailbox->quota, ltid);
+ if (r) {
+ syslog(LOG_ERR,
+ "LOSTQUOTA: unable to record free of %lu bytes in quota %s",
+ mailbox->quota_mailbox_used, mailbox->quota.root);
+ }
+ else if(!havetid)
+ quota_commit(tid);
+ }
+ /* It is not a big mistake not to have quota .. just remove from the mailbox */
+ else if ( r == IMAP_QUOTAROOT_NONEXISTENT) {
+ free(mailbox->quota.root);
+ r = 0;
+ }
+ }
+ return r;
+}
+
diff -Naur cyrus-imapd-2.3.1.orig/imap/mailbox.h cyrus-imapd-2.3.1/imap/mailbox.h
--- cyrus-imapd-2.3.1.orig/imap/mailbox.h 2005-05-27 19:40:54.000000000 +0200
+++ cyrus-imapd-2.3.1/imap/mailbox.h 2006-01-16 11:10:56.000000000 +0100
@@ -329,6 +329,8 @@
struct mailbox *mailboxp);
extern int mailbox_delete(struct mailbox *mailbox, int delete_quota_root);
+extern int mailbox_updatequota(struct mailbox *mailbox, struct txn **tid);
+
extern int mailbox_rename_copy(struct mailbox *oldmailbox,
const char *newname, char *newpartition,
bit32 *olduidvalidityp, bit32 *newuidvalidityp,
diff -Naur cyrus-imapd-2.3.1.orig/imap/mboxlist.c cyrus-imapd-2.3.1/imap/mboxlist.c
--- cyrus-imapd-2.3.1.orig/imap/mboxlist.c 2005-12-13 20:36:03.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/mboxlist.c 2006-01-16 11:10:56.000000000 +0100
@@ -93,6 +93,11 @@
static int mboxlist_opensubs();
static void mboxlist_closesubs();
+static int child_cb(char *name,
+ int matchlen __attribute__((unused)),
+ int maycreate __attribute__((unused)),
+ void *rock);
+
static int mboxlist_rmquota(const char *name, int matchlen, int maycreate,
void *rock);
static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
@@ -100,6 +105,7 @@
struct change_rock {
struct quota *quota;
+ struct quota *oldquota;
struct txn **tid;
};
@@ -891,9 +897,9 @@
*/
int mboxlist_deletemailbox(const char *name, int isadmin, char *userid,
struct auth_state *auth_state, int checkacl,
- int local_only, int force)
+ int local_only, int force, int keepQuota)
{
- int r;
+ int r, has_children = 0;
char *acl;
long access;
struct mailbox mailbox;
@@ -904,6 +910,7 @@
int mbtype;
const char *p;
mupdate_handle *mupdate_h = NULL;
+ char *quotaroot = NULL;
if(!isadmin && force) return IMAP_PERMISSION_DENIED;
@@ -1016,13 +1023,44 @@
if ((r && !force) || isremote) goto done;
- if (!r || force) r = mailbox_delete(&mailbox, deletequotaroot);
+ if (!r || force) {
+ /* first we have to keep the previous quota root in order to delete it */
+ if(mailbox.quota.root)
+ quotaroot = xstrdup(mailbox.quota.root);
+ r = mailbox_delete(&mailbox, deletequotaroot);
+ }
/*
* See if we have to remove mailbox's quota root
*/
- if (!r && mailbox.quota.root != NULL) {
+ if (!r && quotaroot != NULL) {
/* xxx look for any other mailboxes in this quotaroot */
+ /* If we have not asked to remove the quota (default behaviour), we check
+ * whether there are any subfolders beneeth the quota root. If there aren't
+ * any subfolders the reasonable thing is to delete the quota */
+ if(keepQuota) {
+ char pattern[MAX_MAILBOX_PATH+1];
+ strlcpy(pattern, quotaroot, sizeof(pattern));
+ if (config_virtdomains && name[strlen(name)-1] == '!') {
+ strlcat(pattern, "*", sizeof(pattern));
+ }
+ else {
+ strlcat(pattern, ".*", sizeof(pattern));
+ }
+ /* find if there are subfolders. Then we want to
+ * keep the existing quota */
+ mboxlist_findall(NULL, pattern, isadmin, userid,
+ auth_state, child_cb, (void *) &has_children);
+
+ if(!has_children)
+ if(!mboxlist_mylookup(quotaroot, NULL, NULL, NULL, NULL, NULL, NULL, 0 ))
+ has_children = 1;
+ }
+ /* If we want to remove the quota explicitely or the quota root folder has no subfolders
+ * we execute the rmquota patch */
+ if(!keepQuota || !has_children )
+ mboxlist_unsetquota(quotaroot);
+ free(quotaroot);
}
done:
@@ -2478,6 +2516,7 @@
if (r) return r;
crock.quota = &quota;
+ crock.oldquota = NULL;
crock.tid = &tid;
/* top level mailbox */
if(have_mailbox)
@@ -2496,17 +2535,21 @@
*/
int mboxlist_unsetquota(const char *root)
{
+ char newquota[MAX_MAILBOX_PATH+1];
char pattern[MAX_MAILBOX_PATH+1];
struct quota quota;
- int r=0;
+ struct change_rock crock;
+ int r=0, k=0;
if (!root[0] || root[0] == '.' || strchr(root, '/')
|| strchr(root, '*') || strchr(root, '%') || strchr(root, '?')) {
return IMAP_MAILBOX_BADNAME;
}
+
+ crock.tid=NULL;
quota.root = (char *) root;
- r = quota_read(&quota, NULL, 0);
+ r = quota_read(&quota, crock.tid, 0);
if (r == IMAP_QUOTAROOT_NONEXISTENT) {
/* already unset */
return 0;
@@ -2523,13 +2566,45 @@
}
else
strlcat(pattern, ".*", sizeof(pattern));
-
- /* top level mailbox */
- mboxlist_rmquota(root, 0, 0, (void *)root);
- /* submailboxes - we're using internal names here */
- mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
- r = quota_delete(&quota, NULL);
+ r = quota_delete(&quota, crock.tid);
+
+ /* If we cannot delete the quota then abort the operation */
+ if(!r) {
+ /* quota_findroot performs several checks that we can
+ * assume that are already done, and don't have to perform
+ * them again. One of them is that it returns 1 only if
+ * quotaroot exists.
+ */
+ if(quota_findroot(newquota, sizeof(newquota), root)) {
+ struct quota rootquota;
+ rootquota.root = newquota;
+ k = quota_read(&rootquota, crock.tid, 0);
+ if (!k) {
+ crock.quota = &rootquota;
+ crock.oldquota = &quota;
+ /* top level mailbox */
+ k = mboxlist_changequota(root, 0, 0, &crock);
+ }
+ /* submailboxes - we're using internal names here */
+ if (!k)
+ k = mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_changequota, &crock);
+ if(!k)
+ k = quota_write(&rootquota, crock.tid);
+
+ }
+ else {
+ /* top level mailbox */
+ mboxlist_rmquota(root, 0, 0, (void *)root);
+ /* submailboxes - we're using internal names here */
+ mboxlist_findall(NULL, pattern, 1, 0, 0, mboxlist_rmquota, (void *)root);
+ }
+ }
+
+ if(!r && !k)
+ quota_commit(crock.tid);
+ else
+ quota_abort(crock.tid);
return r;
}
@@ -2627,6 +2702,7 @@
struct mailbox mailbox;
struct change_rock *crock = (struct change_rock *) rock;
struct quota *mboxlist_newquota = crock->quota;
+ struct quota *mboxlist_oldquota = crock->oldquota;
struct txn **tid = crock->tid;
assert(rock != NULL);
@@ -2644,27 +2720,24 @@
if (r) goto error;
if (mailbox.quota.root) {
- if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
- /* Part of a child quota root */
- mailbox_close(&mailbox);
- return 0;
- }
-
- r = quota_read(&mailbox.quota, tid, 1);
- if (r) goto error;
- if (mailbox.quota.used >= mailbox.quota_mailbox_used) {
- mailbox.quota.used -= mailbox.quota_mailbox_used;
+ if(mboxlist_oldquota) {
+ if (strlen(mailbox.quota.root) > strlen(mboxlist_oldquota->root)) {
+ /* Part of a child quota root */
+ mailbox_close(&mailbox);
+ return 0;
+ }
}
else {
- mailbox.quota.used = 0;
- }
- r = quota_write(&mailbox.quota, tid);
- if (r) {
- syslog(LOG_ERR,
- "LOSTQUOTA: unable to record free of " UQUOTA_T_FMT " bytes in quota %s",
- mailbox.quota_mailbox_used, mailbox.quota.root);
+ if (strlen(mailbox.quota.root) >= strlen(mboxlist_newquota->root)) {
+ /* Part of a child quota root */
+ mailbox_close(&mailbox);
+ return 0;
+ }
}
- free(mailbox.quota.root);
+
+ r = mailbox_updatequota(&mailbox,tid);
+ if (r)
+ goto error;
}
mailbox.quota.root = xstrdup(mboxlist_newquota->root);
@@ -2674,18 +2747,24 @@
mboxlist_newquota->used += mailbox.quota_mailbox_used;
mailbox_close(&mailbox);
return 0;
-
+
error:
mailbox_close(&mailbox);
+ syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s. \
+ Command aborted. Run reconstruct to make sure mailboxes \
+ are in consistent state",
+ name, mboxlist_newquota->root, error_message(r));
+ return 1;
error_noclose:
syslog(LOG_ERR, "LOSTQUOTA: unable to change quota root for %s to %s: %s",
- name, mboxlist_newquota->root, error_message(r));
+ name, mboxlist_newquota->root, error_message(r));
/* Note, we're a callback, and it's not a huge tragedy if we
* fail, so we don't ever return a failure */
return 0;
}
+
/* must be called after cyrus_init */
void mboxlist_init(int myflags)
{
diff -Naur cyrus-imapd-2.3.1.orig/imap/mboxlist.h cyrus-imapd-2.3.1/imap/mboxlist.h
--- cyrus-imapd-2.3.1.orig/imap/mboxlist.h 2005-02-21 20:25:40.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/mboxlist.h 2006-01-16 11:10:56.000000000 +0100
@@ -125,7 +125,7 @@
* the planet */
int mboxlist_deletemailbox(const char *name, int isadmin, char *userid,
struct auth_state *auth_state, int checkacl,
- int local_only, int force);
+ int local_only, int force, int keepQuota);
/* Rename/move a mailbox (hierarchical) */
int mboxlist_renamemailbox(char *oldname, char *newname, char *partition,
diff -Naur cyrus-imapd-2.3.1.orig/imap/mupdate.c cyrus-imapd-2.3.1/imap/mupdate.c
--- cyrus-imapd-2.3.1.orig/imap/mupdate.c 2005-11-04 14:34:23.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/mupdate.c 2006-01-16 11:10:56.000000000 +0100
@@ -2297,7 +2297,7 @@
remote_boxes.head = r->next;
} else if (ret < 0) {
/* Local without corresponding remote, delete it */
- mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0);
+ mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0, 1);
local_boxes.head = l->next;
} else /* (ret > 0) */ {
/* Remote without corresponding local, insert it */
@@ -2312,7 +2312,7 @@
if(l && !r) {
/* we have more deletes to do */
while(l) {
- mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0);
+ mboxlist_deletemailbox(l->mailbox, 1, "", NULL, 0, 0, 0, 1);
local_boxes.head = l->next;
l = local_boxes.head;
}
diff -Naur cyrus-imapd-2.3.1.orig/imap/nntpd.c cyrus-imapd-2.3.1/imap/nntpd.c
--- cyrus-imapd-2.3.1.orig/imap/nntpd.c 2005-12-13 20:36:06.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/nntpd.c 2006-01-16 11:10:56.000000000 +0100
@@ -3342,7 +3342,7 @@
/* XXX should we delete right away, or wait until empty? */
r = mboxlist_deletemailbox(mailboxname, 0,
- newsmaster, newsmaster_authstate, 1, 0, 0);
+ newsmaster, newsmaster_authstate, 1, 0, 0, 1);
if (!r) sync_log_mailbox(mailboxname);
diff -Naur cyrus-imapd-2.3.1.orig/imap/sync_reset.c cyrus-imapd-2.3.1/imap/sync_reset.c
--- cyrus-imapd-2.3.1.orig/imap/sync_reset.c 2005-12-13 16:31:10.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/sync_reset.c 2006-01-16 11:12:34.000000000 +0100
@@ -254,7 +254,7 @@
if (r) goto fail;
for (item = list->head ; item ; item = item->next) {
- r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0);
+ r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0, 1);
if (r) goto fail;
}
@@ -270,7 +270,7 @@
if (r) goto fail;
for (item = list->head ; item ; item = item->next) {
- r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0);
+ r=mboxlist_deletemailbox(item->name, 1, NULL, sync_authstate, 1, 0, 0, 1);
if (r) goto fail;
}
@@ -278,7 +278,7 @@
/* Nuke inbox (recursive nuke possible?) */
snprintf(buf, sizeof(buf)-1, "user.%s", user);
- r = mboxlist_deletemailbox(buf, 1, "cyrus", sync_authstate, 1, 0, 0);
+ r = mboxlist_deletemailbox(buf, 1, "cyrus", sync_authstate, 1, 0, 0, 1);
if (r && (r != IMAP_MAILBOX_NONEXISTENT)) goto fail;
if ((r=user_deletedata(user, sync_userid, sync_authstate, 1)))
diff -Naur cyrus-imapd-2.3.1.orig/imap/sync_server.c cyrus-imapd-2.3.1/imap/sync_server.c
--- cyrus-imapd-2.3.1.orig/imap/sync_server.c 2005-12-20 16:54:43.000000000 +0100
+++ cyrus-imapd-2.3.1/imap/sync_server.c 2006-01-16 11:13:02.000000000 +0100
@@ -1569,7 +1569,7 @@
for (item = list->head ; item ; item = item->next) {
r=mboxlist_deletemailbox(item->name, sync_userisadmin, sync_userid,
- sync_authstate, 0, 0, 1);
+ sync_authstate, 0, 0, 1, 1);
if (r) goto fail;
}
@@ -1579,7 +1579,7 @@
(sync_namespacep->mboxname_tointernal)(sync_namespacep, "INBOX",
user, buf);
r = mboxlist_deletemailbox(buf, sync_userisadmin, sync_userid,
- sync_authstate, 0, 0, 1);
+ sync_authstate, 0, 0, 1, 1);
if (r && (r != IMAP_MAILBOX_NONEXISTENT)) goto fail;
if ((r=user_deletedata(user, sync_userid, sync_authstate, 1)))
@@ -2501,7 +2501,7 @@
/* Delete with admin priveleges */
r = mboxlist_deletemailbox(name, sync_userisadmin, sync_userid,
- sync_authstate, 0, 0, 1);
+ sync_authstate, 0, 0, 1, 1);
if (r)
prot_printf(sync_out, "NO Failed to delete %s: %s\r\n",