Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mboxlist root mailboxid #3571

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 102 additions & 1 deletion imap/ctl_mboxlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum mboxop { DUMP,
CHECKPOINT,
UNDUMP,
VERIFY,
ADD_ROOTS,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really does feel like what we need is a $V key or something in mailboxes.db, rather than using the AS key as the upgrade indicator, and then we can confirm that roots have been added.

NONE };

struct dumprock {
Expand Down Expand Up @@ -882,6 +883,91 @@ static void do_verify(void)
mboxlist_allmbox("", &verify_cb, &found, MBOXTREE_TOMBSTONES);
}

struct root_rock {
mbname_t *mbname;
char *mboxid;
};

static int addroots_cb(const mbentry_t *mbentry, void *rockp)
{
mbname_t *mbname = mbname_from_intname(mbentry->name);
struct root_rock *rrock = rockp;
int is_root = 0, is_child = 0;

/* Skip DELETED.* mailboxes */
if (mbname_isdeleted(mbname)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe we do want to add the INBOX root_mailboxid to DELETED.user.foo mailboxes as well, so we know to consider them in the same userid, since they're findable with mboxlist_usermboxtree and flags.

mbname_free(&mbname);
return 0;
}

const char *userid = mbname_userid(mbname);

if (userid) {
if (strarray_size(mbname_boxes(mbname)) == 0) {
/* INBOX */
is_root = 1;
}
else if (rrock->mbname &&
!strcmpnull(userid, mbname_userid(rrock->mbname))) {
/* Same user */
is_child = 1;
}
}
else {
/* Shared mailbox */
const strarray_t *boxes = mbname_boxes(mbname);

if (strarray_size(boxes) == 1) {
/* Toplevel mailbox */
is_root = 1;
}
else if (rrock->mbname &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this also need && !mbname_userid(rock->mbname) for maximum safety?

!strcmpnull(strarray_nth(boxes, 0),
strarray_nth(mbname_boxes(rrock->mbname), 0))) {
/* Same root */
is_child = 1;
}
}

if (is_root) {
/* Switch to new root */
mbname_free(&rrock->mbname);
free(rrock->mboxid);

rrock->mbname = mbname;
rrock->mboxid = xstrdup(mbentry->uniqueid);
}
else if (is_child) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should also be setting root_mailboxid on the INBOX or top-level folder, so we can just use that field rather than having to interpret the lack of one as "this is the root".

Particularly since that's what we do further down when we maintain this field in the mailbox creation code.

/* Add root mailboxid to child */
mbentry_t *newentry = mboxlist_entry_copy(mbentry);

newentry->root_mailboxid = xstrdup(rrock->mboxid);
mboxlist_update(newentry, 1 /* localonly */);
mboxlist_entry_free(&newentry);

mbname_free(&mbname);
}
else {
/* Orphaned mailbox */
mbname_free(&mbname);
}

return 0;
}

static void do_addroots(int intermediary)
{
struct root_rock rrock = { NULL, NULL };
int flags = MBOXTREE_TOMBSTONES;

if (intermediary) flags |= MBOXTREE_INTERMEDIATES;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be always doing INTERMEDIATES here, while they still exist. We don't want to leave them rootless.


mboxlist_allmbox("", &addroots_cb, &rrock, flags);

mbname_free(&rrock.mbname);
free(rrock.mboxid);
}

static void usage(void)
{
fprintf(stderr, "DUMP:\n");
Expand All @@ -907,7 +993,7 @@ int main(int argc, char *argv[])
char *alt_config = NULL;
int dointermediary = 0;

while ((opt = getopt(argc, argv, "C:awmdurcxf:p:viy")) != EOF) {
while ((opt = getopt(argc, argv, "C:awmdurcxf:p:vsiy")) != EOF) {
switch (opt) {
case 'C': /* alt config file */
alt_config = optarg;
Expand Down Expand Up @@ -977,6 +1063,11 @@ int main(int argc, char *argv[])
else usage();
break;

case 's':
if (op == NONE) op = ADD_ROOTS;
else usage();
break;

case 'i':
interactive = 1;
break;
Expand Down Expand Up @@ -1058,6 +1149,16 @@ int main(int argc, char *argv[])
mboxlist_done();
break;

case ADD_ROOTS:
mboxlist_init(0);
mboxlist_open(mboxdb_fname);

do_addroots(dointermediary);

mboxlist_close();
mboxlist_done();
break;

default:
usage();
cyrus_done();
Expand Down
9 changes: 9 additions & 0 deletions imap/mboxlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ static struct dlist *mboxlist_entry_dlist(const char *dbname,
if (mbentry->uniqueid)
dlist_setatom(dl, "I", mbentry->uniqueid);

if (mbentry->root_mailboxid)
dlist_setatom(dl, "R", mbentry->root_mailboxid);

if (mbentry->partition)
dlist_setatom(dl, "P", mbentry->partition);

Expand Down Expand Up @@ -539,6 +542,9 @@ static int parseentry_cb(int type, struct dlistsax_data *d)
else if (!strcmp(key, "P")) {
rock->mbentry->partition = xstrdupnull(d->data);
}
else if (!strcmp(key, "R")) {
rock->mbentry->root_mailboxid = xstrdupnull(d->data);
}
else if (!strcmp(key, "S")) {
rock->mbentry->server = xstrdupnull(d->data);
}
Expand Down Expand Up @@ -566,6 +572,7 @@ static int parseentry_cb(int type, struct dlistsax_data *d)
* M: _m_time
* N: _n_ame
* P: _p_artition
* R: _r_oot_mailboxid
* S: _s_erver
* T: _t_ype
* V: uid_v_alidity
Expand Down Expand Up @@ -1717,6 +1724,8 @@ static int mboxlist_createmailbox_full(const char *mboxname, int mbtype,
newmbentry->uidvalidity = newmailbox->i.uidvalidity;
newmbentry->createdmodseq = newmailbox->i.createdmodseq;
newmbentry->foldermodseq = foldermodseq ? foldermodseq : newmailbox->i.highestmodseq;
newmbentry->root_mailboxid =
xstrdupnull(parent ? parent->root_mailboxid : newmbentry->uniqueid);
}
r = mboxlist_update_entry(mboxname, newmbentry, NULL);

Expand Down
1 change: 1 addition & 0 deletions imap/mboxlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct mboxlist_entry {
char *acl;
/* extra fields */
char *uniqueid;
char *root_mailboxid;
/* legacy upgrade support */
char *legacy_specialuse;
/* replication support */
Expand Down