static int do_sync_mailboxes(struct sync_name_list *mboxname_list, struct sync_action_list *user_list, const char **channelp, unsigned flags) { struct sync_name *mbox; int r = 0; if (mboxname_list->count) { r = sync_do_mailboxes(mboxname_list, NULL, sync_backend, flags); if (channelp && r == IMAP_MAILBOX_LOCKED) { for (mbox = mboxname_list->head; mbox; mbox = mbox->next) { if (mbox->mark) continue; sync_log_channel_mailbox(*channelp, mbox->name); report_verbose(" Deferred: MAILBOX %s\n", mbox->name); } r = 0; } else if (r) { /* promote failed personal mailboxes to USER */ int nonuser = 0; for (mbox = mboxname_list->head; mbox; mbox = mbox->next) { /* done OK? Good :) */ if (mbox->mark) continue; char *userid = mboxname_to_userid(mbox->name); if (userid) { mbox->mark = 1; sync_action_list_add(user_list, NULL, userid); report_verbose(" Promoting: MAILBOX %s -> USER %s\n", mbox->name, userid); free(userid); } else nonuser = 1; /* there was a non-user mailbox */ } if (!nonuser) r = 0; } } return r; }
static int do_sync_mailboxes(struct sync_name_list *mboxname_list, struct sync_action_list *user_list, unsigned flags) { int r = 0; if (mboxname_list->count) { r = sync_do_mailboxes(mboxname_list, sync_backend, flags); if (r) { /* promote failed personal mailboxes to USER */ int nonuser = 0; struct sync_name *mbox; for (mbox = mboxname_list->head; mbox; mbox = mbox->next) { /* done OK? Good :) */ if (mbox->mark) continue; char *userid = mboxname_to_userid(mbox->name); if (userid) { mbox->mark = 1; sync_action_list_add(user_list, NULL, userid); if (verbose) { printf(" Promoting: MAILBOX %s -> USER %s\n", mbox->name, userid); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: MAILBOX %s -> USER %s", mbox->name, userid); } free(userid); } else nonuser = 1; /* there was a non-user mailbox */ } if (!nonuser) r = 0; } } return r; }
static int do_sync(sync_log_reader_t *slr) { struct sync_action_list *user_list = sync_action_list_create(); struct sync_action_list *unuser_list = sync_action_list_create(); struct sync_action_list *meta_list = sync_action_list_create(); struct sync_action_list *mailbox_list = sync_action_list_create(); struct sync_action_list *unmailbox_list = sync_action_list_create(); struct sync_action_list *quota_list = sync_action_list_create(); struct sync_action_list *annot_list = sync_action_list_create(); struct sync_action_list *seen_list = sync_action_list_create(); struct sync_action_list *sub_list = sync_action_list_create(); struct sync_name_list *mboxname_list = sync_name_list_create(); const char *args[3]; struct sync_action *action; int r = 0; while (1) { r = sync_log_reader_getitem(slr, args); if (r == EOF) break; if (!strcmp(args[0], "USER")) sync_action_list_add(user_list, NULL, args[1]); else if (!strcmp(args[0], "UNUSER")) sync_action_list_add(unuser_list, NULL, args[1]); else if (!strcmp(args[0], "META")) sync_action_list_add(meta_list, NULL, args[1]); else if (!strcmp(args[0], "SIEVE")) sync_action_list_add(meta_list, NULL, args[1]); else if (!strcmp(args[0], "APPEND")) /* just a mailbox event */ sync_action_list_add(mailbox_list, args[1], NULL); else if (!strcmp(args[0], "MAILBOX")) sync_action_list_add(mailbox_list, args[1], NULL); else if (!strcmp(args[0], "UNMAILBOX")) sync_action_list_add(unmailbox_list, args[1], NULL); else if (!strcmp(args[0], "QUOTA")) sync_action_list_add(quota_list, args[1], NULL); else if (!strcmp(args[0], "ANNOTATION")) sync_action_list_add(annot_list, args[1], NULL); else if (!strcmp(args[0], "SEEN")) sync_action_list_add(seen_list, args[2], args[1]); else if (!strcmp(args[0], "SUB")) sync_action_list_add(sub_list, args[2], args[1]); else if (!strcmp(args[0], "UNSUB")) sync_action_list_add(sub_list, args[2], args[1]); else syslog(LOG_ERR, "Unknown action type: %s", args[0]); } /* Optimise out redundant clauses */ for (action = user_list->head; action; action = action->next) { /* remove per-user items */ remove_meta(action->user, meta_list); remove_meta(action->user, seen_list); remove_meta(action->user, sub_list); } /* duplicate removal for unuser - we also strip all the user events */ for (action = unuser_list->head; action; action = action->next) { /* remove per-user items */ remove_meta(action->user, meta_list); remove_meta(action->user, seen_list); remove_meta(action->user, sub_list); /* unuser trumps user */ remove_meta(action->user, user_list); } for (action = meta_list->head; action; action = action->next) { /* META action overrides any user SEEN or SUB/UNSUB action for same user */ remove_meta(action->user, seen_list); remove_meta(action->user, sub_list); } /* And then run tasks. */ for (action = quota_list->head; action; action = action->next) { if (!action->active) continue; if (sync_do_quota(action->name, sync_backend, flags)) { /* XXX - bogus handling, should be user */ sync_action_list_add(mailbox_list, action->name, NULL); if (verbose) { printf(" Promoting: QUOTA %s -> MAILBOX %s\n", action->name, action->name); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: QUOTA %s -> MAILBOX %s", action->name, action->name); } } } for (action = annot_list->head; action; action = action->next) { if (!action->active) continue; /* NOTE: ANNOTATION "" is a special case - it's a server * annotation, hence the check for a character at the * start of the name */ if (sync_do_annotation(action->name, sync_backend, flags) && *action->name) { /* XXX - bogus handling, should be ... er, something */ sync_action_list_add(mailbox_list, action->name, NULL); if (verbose) { printf(" Promoting: ANNOTATION %s -> MAILBOX %s\n", action->name, action->name); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: ANNOTATION %s -> MAILBOX %s", action->name, action->name); } } } for (action = seen_list->head; action; action = action->next) { if (!action->active) continue; if (sync_do_seen(action->user, action->name, sync_backend, flags)) { char *userid = mboxname_to_userid(action->name); if (userid && mboxname_isusermailbox(action->name, 1) && !strcmp(userid, action->user)) { sync_action_list_add(user_list, NULL, action->user); if (verbose) { printf(" Promoting: SEEN %s %s -> USER %s\n", action->user, action->name, action->user); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: SEEN %s %s -> USER %s", action->user, action->name, action->user); } } else { sync_action_list_add(meta_list, NULL, action->user); if (verbose) { printf(" Promoting: SEEN %s %s -> META %s\n", action->user, action->name, action->user); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: SEEN %s %s -> META %s", action->user, action->name, action->user); } } free(userid); } } for (action = sub_list->head; action; action = action->next) { if (!action->active) continue; if (user_sub(action->user, action->name)) { sync_action_list_add(meta_list, NULL, action->user); if (verbose) { printf(" Promoting: SUB %s %s -> META %s\n", action->user, action->name, action->user); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: SUB %s %s -> META %s", action->user, action->name, action->name); } } } for (action = mailbox_list->head; action; action = action->next) { if (!action->active) continue; sync_name_list_add(mboxname_list, action->name); /* only do up to 1000 mailboxes at a time */ if (mboxname_list->count > 1000) { syslog(LOG_NOTICE, "sync_mailboxes: doing 1000"); r = do_sync_mailboxes(mboxname_list, user_list, flags); if (r) goto cleanup; r = do_restart(); if (r) goto cleanup; sync_name_list_free(&mboxname_list); mboxname_list = sync_name_list_create(); } } r = do_sync_mailboxes(mboxname_list, user_list, flags); if (r) goto cleanup; r = do_restart(); if (r) goto cleanup; for (action = unmailbox_list->head; action; action = action->next) { if (!action->active) continue; r = do_unmailbox(action->name, sync_backend, flags); if (r) goto cleanup; } for (action = meta_list->head; action; action = action->next) { if (!action->active) continue; r = sync_do_meta(action->user, sync_backend, flags); if (r) { if (r == IMAP_INVALID_USER) goto cleanup; sync_action_list_add(user_list, NULL, action->user); if (verbose) { printf(" Promoting: META %s -> USER %s\n", action->user, action->user); } if (verbose_logging) { syslog(LOG_INFO, " Promoting: META %s -> USER %s", action->user, action->user); } } } for (action = user_list->head; action; action = action->next) { if (!action->active) continue; r = sync_do_user(action->user, sync_backend, flags); if (r) goto cleanup; r = do_restart(); if (r) goto cleanup; } for (action = unuser_list->head; action; action = action->next) { if (!action->active) continue; r = do_unuser(action->user); if (r) goto cleanup; } cleanup: if (r) { if (verbose) fprintf(stderr, "Error in do_sync(): bailing out! %s\n", error_message(r)); syslog(LOG_ERR, "Error in do_sync(): bailing out! %s", error_message(r)); } sync_action_list_free(&user_list); sync_action_list_free(&unuser_list); sync_action_list_free(&meta_list); sync_action_list_free(&mailbox_list); sync_action_list_free(&unmailbox_list); sync_action_list_free("a_list); sync_action_list_free(&annot_list); sync_action_list_free(&seen_list); sync_action_list_free(&sub_list); sync_name_list_free(&mboxname_list); return r; }