From 1d713fb596664fc93b75cedbaf2358be6b47c346 Mon Sep 17 00:00:00 2001 From: Bron Gondwana Date: Wed, 8 May 2024 16:36:34 +1000 Subject: [PATCH] sync_support: replica USERGROUPs with inboxes on RACLMODSEQ bump --- backup/restore.c | 6 ++--- imap/imapd.c | 1 + imap/sync_support.c | 60 ++++++++++++++++++++++++++++++++++++++------- imap/sync_support.h | 2 ++ 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/backup/restore.c b/backup/restore.c index 27fcff00f43..51161c4b15b 100644 --- a/backup/restore.c +++ b/backup/restore.c @@ -602,7 +602,7 @@ static struct sync_folder_list *restore_make_reserve_folder_list( /* we only care about mboxname here */ sync_folder_list_add(folder_list, NULL, iter->mboxname, 0, NULL, NULL, 0, 0, 0, 0, synccrcs, - 0, 0, 0, 0, NULL, 0, 0, 0, 0); + 0, 0, 0, 0, NULL, 0, 0, 0, NULL, 0); } backup_mailbox_list_empty(mailboxes); @@ -751,7 +751,7 @@ static int restore_add_mailbox(const struct backup_mailbox *mailbox, const struct synccrcs synccrcs = {0, 0}; sync_folder_list_add(reserve_folder_list, NULL, clone->mboxname, 0, NULL, NULL, 0, 0, 0, 0, synccrcs, - 0, 0, 0, 0, NULL, 0, 0, 0, 0); + 0, 0, 0, 0, NULL, 0, 0, 0, NULL, 0); } /* populate mailbox list */ @@ -795,7 +795,7 @@ static int restore_add_message(const struct backup_message *message, const struct synccrcs synccrcs = {0, 0}; sync_folder_list_add(reserve_folder_list, NULL, mailbox->mboxname, 0, NULL, NULL, 0, 0, 0, 0, synccrcs, - 0, 0, 0, 0, NULL, 0, 0, 0, 0); + 0, 0, 0, 0, NULL, 0, 0, 0, NULL, 0); /* add to mailbox list */ my_mailbox_list_add(mailbox_list, mailbox); diff --git a/imap/imapd.c b/imap/imapd.c index 52dcdc30a80..1fd2fa51ae5 100644 --- a/imap/imapd.c +++ b/imap/imapd.c @@ -12711,6 +12711,7 @@ static int sync_mailbox(struct xfer_header *xfer, xconvmodseq, raclmodseq, mailbox_foldermodseq(mailbox), + /* groups */ NULL, /* ispartial */0); annots = NULL; /* list took ownership */ diff --git a/imap/sync_support.c b/imap/sync_support.c index 9b025cda20c..b4f5aeba2fc 100644 --- a/imap/sync_support.c +++ b/imap/sync_support.c @@ -605,6 +605,7 @@ struct sync_folder *sync_folder_list_add(struct sync_folder_list *l, modseq_t xconvmodseq, modseq_t raclmodseq, modseq_t foldermodseq, + const char *groups, int ispartial) { struct sync_folder *result = xzmalloc(sizeof(struct sync_folder)); @@ -637,6 +638,7 @@ struct sync_folder *sync_folder_list_add(struct sync_folder_list *l, result->xconvmodseq = xconvmodseq; result->raclmodseq = raclmodseq; result->foldermodseq = foldermodseq; + result->groups = xstrdupnull(groups); result->ispartial = ispartial; result->mark = 0; @@ -1966,10 +1968,6 @@ static int sync_prepare_dlists(struct mailbox *mailbox, dlist_setdate(kl, "LAST_APPENDDATE", 0); dlist_setdate(kl, "POP3_LAST_LOGIN", remote ? remote->pop3_last_login : 0); dlist_setdate(kl, "POP3_SHOW_AFTER", remote ? remote->pop3_show_after : 0); - if (remote && remote->xconvmodseq) - dlist_setnum64(kl, "XCONVMODSEQ", remote->xconvmodseq); - if (remote && remote->raclmodseq) - dlist_setnum64(kl, "RACLMODSEQ", remote->raclmodseq); } else { struct synccrcs synccrcs = mailbox_synccrcs(mailbox, /*force*/0); @@ -1988,8 +1986,20 @@ static int sync_prepare_dlists(struct mailbox *mailbox, dlist_setnum64(kl, "XCONVMODSEQ", xconvmodseq); } modseq_t raclmodseq = mboxname_readraclmodseq(mailbox_name(mailbox)); - if (raclmodseq) + if (raclmodseq && (!remote || remote->raclmodseq != raclmodseq)) { + // only send if different dlist_setnum64(kl, "RACLMODSEQ", raclmodseq); + char *userid = mboxname_to_userid(mailbox_name(mailbox)); + strarray_t groups = STRARRAY_INITIALIZER; + int r = mboxlist_lookup_usergroups(userid, &groups); + if (!r && strarray_size(&groups)) { + char *groupstxt = strarray_join(&groups, "\t"); + dlist_setatom(kl, "USERGROUPS", groupstxt); + free(groupstxt); + } + strarray_fini(&groups); + free(userid); + } } dlist_setnum32(kl, "UIDVALIDITY", mailbox->i.uidvalidity); dlist_setatom(kl, "PARTITION", topart); @@ -2714,6 +2724,7 @@ int sync_apply_mailbox(struct dlist *kin, modseq_t xconvmodseq = 0; modseq_t raclmodseq = 0; modseq_t createdmodseq = 0; + const char *groups = NULL; /* previous state markers */ modseq_t since_modseq = 0; @@ -2795,6 +2806,7 @@ int sync_apply_mailbox(struct dlist *kin, dlist_getnum64(kin, "XCONVMODSEQ", &xconvmodseq); dlist_getnum64(kin, "RACLMODSEQ", &raclmodseq); dlist_getnum64(kin, "FOLDERMODSEQ", &foldermodseq); + dlist_getatom(kin, "USERGROUPS", &groups); /* Get the CRCs */ dlist_getnum32(kin, "SYNC_CRC", &synccrcs.basic); @@ -3044,6 +3056,32 @@ int sync_apply_mailbox(struct dlist *kin, } } + if (groups) { + strarray_t mygroups = STRARRAY_INITIALIZER; + char *userid = mboxname_to_userid(mboxname); + r = mboxlist_lookup_usergroups(userid, &mygroups); + if (r) goto done; + strarray_t *usergroups = strarray_split(groups, "\t", 0); + int i; + // add any new + for (i = 0; i < strarray_size(usergroups); i++) { + const char *group = strarray_nth(usergroups, i); + if (strarray_find(&mygroups, group, 0) >= 0) continue; + r = mboxlist_set_usergroup(userid, group, /*add*/1, /*silent*/1); + if (r) goto done; + } + // remove any old + for (i = 0; i < strarray_size(&mygroups); i++) { + const char *group = strarray_nth(&mygroups, i); + if (strarray_find(usergroups, group, 0) >= 0) continue; + r = mboxlist_set_usergroup(userid, group, /*add*/0, /*silent*/1); + if (r) goto done; + } + strarray_free(usergroups); + free(userid); + strarray_fini(&mygroups); + } + r = sync_mailbox_compare_update(mailbox, kr, 0, part_list); if (r) goto done; @@ -3107,7 +3145,7 @@ int sync_apply_mailbox(struct dlist *kin, mailbox->i.uidvalidity = mboxname_setuidvalidity(mailbox_name(mailbox), uidvalidity); } - if (mailbox_has_conversations(mailbox)) { + if (mailbox_has_conversations(mailbox) && xconvmodseq) { r = mailbox_update_xconvmodseq(mailbox, xconvmodseq, opt_force); } @@ -4644,7 +4682,7 @@ static int find_reserve_all(struct sync_name_list *mboxname_list, 0, 0, 0, 0, NULL, 0, - 0, mbentry->foldermodseq, 0); + 0, mbentry->foldermodseq, NULL, 0); mboxlist_entry_free(&mbentry); continue; } @@ -4688,6 +4726,8 @@ static int find_reserve_all(struct sync_name_list *mboxname_list, modseq_t tomodseq = mailbox->i.highestmodseq; int ispartial = 0; + char *groups = NULL; + if (batchsize && touid - fromuid > batchsize) { /* see if we actually need to calculate an intermediate state */ modseq_t frommodseq = rfolder ? rfolder->highestmodseq : 0; @@ -4709,7 +4749,7 @@ static int find_reserve_all(struct sync_name_list *mboxname_list, mailbox->i.recentuid, mailbox->i.recenttime, mailbox->i.pop3_last_login, mailbox->i.pop3_show_after, NULL, xconvmodseq, - raclmodseq, mailbox_foldermodseq(mailbox), ispartial); + raclmodseq, mailbox_foldermodseq(mailbox), groups, ispartial); part_list = sync_reserve_partlist(reserve_list, topart ? topart : mailbox_partition(mailbox)); @@ -4994,6 +5034,7 @@ static int sync_kl_parse(struct dlist *kin, modseq_t xconvmodseq = 0; modseq_t raclmodseq = 0; modseq_t foldermodseq = 0; + const char *groups = NULL; if (!folder_list) return IMAP_PROTOCOL_BAD_PARAMETERS; if (!dlist_getatom(kl, "UNIQUEID", &uniqueid)) return IMAP_PROTOCOL_BAD_PARAMETERS; @@ -5015,6 +5056,7 @@ static int sync_kl_parse(struct dlist *kin, dlist_getnum64(kl, "XCONVMODSEQ", &xconvmodseq); dlist_getnum64(kl, "RACLMODSEQ", &raclmodseq); dlist_getnum64(kl, "FOLDERMODSEQ", &foldermodseq); + dlist_getatom(kl, "USERGROUPS", &groups); if (dlist_getlist(kl, "ANNOTATIONS", &al)) decode_annotations(al, &annots, NULL, NULL); @@ -5029,7 +5071,7 @@ static int sync_kl_parse(struct dlist *kin, pop3_last_login, pop3_show_after, annots, xconvmodseq, raclmodseq, - foldermodseq, /*ispartial*/0); + foldermodseq, groups, /*ispartial*/0); } else { diff --git a/imap/sync_support.h b/imap/sync_support.h index 01fc5867867..743d5f24198 100644 --- a/imap/sync_support.h +++ b/imap/sync_support.h @@ -149,6 +149,7 @@ struct sync_folder { modseq_t xconvmodseq; modseq_t raclmodseq; modseq_t foldermodseq; + char *groups; int ispartial; struct quota quota; int mark; @@ -179,6 +180,7 @@ struct sync_folder *sync_folder_list_add(struct sync_folder_list *l, modseq_t xconvmodseq, modseq_t raclmodseq, modseq_t foldermodseq, + const char *groups, int ispartial); struct sync_folder *sync_folder_lookup(struct sync_folder_list *l,