dsync-mailbox-import.c revision 08e9fec5ba9e1a26e658c4224207d666b6ced27d
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce const char *guid;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* linked list of mails for this GUID */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* if non-NULL, this mail exists in both local and remote. this link
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce points to the other side. */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce const char *guid;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo SorceHASH_TABLE_DEFINE_TYPE(guid_new_mail, const char *, struct importer_new_mail *);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo SorceHASH_TABLE_DEFINE_TYPE(uid_new_mail, void *, struct importer_new_mail *);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct mailbox_transaction_context *trans, *ext_trans;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* UID => struct dsync_mail_change */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce HASH_TABLE_TYPE(dsync_uid_mail_change) local_changes;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* GUID => struct importer_new_mail */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* UID => struct importer_new_mail */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce uint32_t prev_uid, next_local_seq, local_uid_next;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcedsync_mailbox_import_search_init(struct dsync_mailbox_importer *importer)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce sarg = mail_search_build_add(search_args, SEARCH_UIDSET);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce p_array_init(&sarg->value.seqset, search_args->pool, 128);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce mailbox_search_init(importer->trans, search_args, NULL,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if (mailbox_search_next(importer->search_ctx, &importer->cur_mail))
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->next_local_seq = importer->cur_mail->seq;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* this flag causes cur_guid to be looked up later */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce const enum mailbox_transaction_flags ext_trans_flags =
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce pool = pool_alloconly_create(MEMPOOL_GROWING"dsync mailbox importer",
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer = p_new(pool, struct dsync_mailbox_importer, 1);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->last_common_modseq = last_common_modseq;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->remote_first_recent_uid = remote_first_recent_uid;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->remote_highest_modseq = remote_highest_modseq;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce hash_table_create(&importer->import_guids, pool, 0, str_hash, strcmp);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce hash_table_create_direct(&importer->import_uids, pool, 0);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->trans = mailbox_transaction_begin(importer->box,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->ext_trans = mailbox_transaction_begin(box, ext_trans_flags);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->mail = mail_alloc(importer->trans, 0, NULL);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->ext_mail = mail_alloc(importer->ext_trans, 0, NULL);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if ((flags & DSYNC_MAILBOX_IMPORT_FLAG_WANT_MAIL_REQUESTS) != 0) {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce (flags & DSYNC_MAILBOX_IMPORT_FLAG_MAILS_HAVE_GUIDS) != 0;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce (flags & DSYNC_MAILBOX_IMPORT_FLAG_MASTER_BRAIN) != 0;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->local_initial_highestmodseq = status.highest_modseq;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->local_changes = dsync_transaction_log_scan_get_hash(log_scan);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic void dsync_mail_error(struct dsync_mailbox_importer *importer,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce const char *errstr;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce errstr = mailbox_get_last_error(importer->box, &error);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce i_error("Can't lookup %s for UID=%u: %s", field, mail->uid, errstr);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorceimporter_next_mail(struct dsync_mailbox_importer *importer, uint32_t wanted_uid)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* end of search */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce while (importer->cur_mail->seq < importer->next_local_seq ||
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* this message exists locally, but remote didn't send
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce expunge-change for it. if the message's
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce uid <= last-common-uid, it should be deleted */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce seq_range_array_add(&importer->maybe_expunge_uids,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->cur_uid_has_change = importer->cur_mail != NULL &&
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if (mail_get_special(importer->cur_mail, MAIL_FETCH_GUID,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce dsync_mail_error(importer, importer->cur_mail, "GUID");
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* make sure next_local_seq gets updated in case we came here
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce because of min_uid */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce importer->next_local_seq = importer->cur_mail->seq;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic void importer_mail_request(struct dsync_mailbox_importer *importer,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if (importer->want_mail_requests && !newmail->uid_in_local) {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce request = array_append_space(&importer->mail_requests);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic void newmail_link(struct dsync_mailbox_importer *importer,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct importer_new_mail *first_mail, **last, *mail, *link = NULL;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce first_mail = hash_table_lookup(importer->import_guids,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* first mail for this GUID */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* FIXME: ? */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce first_mail = hash_table_lookup(importer->import_uids,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* first mail for this UID */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* 1) add the newmail to the end of the linked list
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce 2) find our link */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce for (mail = first_mail; mail != NULL; mail = mail->next) {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic bool dsync_mailbox_try_save_cur(struct dsync_mailbox_importer *importer,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce newmail = p_new(importer->pool, struct importer_new_mail, 1);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* add a record for local mail */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce newmail->guid = p_strdup(importer->pool, importer->cur_guid);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce } else if (diff > 0) {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* identical */
return remote_saved;
return FALSE;
const char *guid;
return FALSE;
return TRUE;
return TRUE;
return FALSE;
return FALSE;
return TRUE;
bool prefer_remote,
if (conflict_flags != 0) {
if (prefer_remote)
if (conflict_flags != 0) {
if (prefer_remote)
if (conflict_flags != 0) {
if (prefer_remote)
unsigned int *idx_r)
const char *const *names;
unsigned int i, count;
for (i = 0; i < count; i++) {
*idx_r = i;
return TRUE;
return FALSE;
const char *const *namep;
bool prefer_remote)
count = 0;
if (array_size == 0) {
for (i = 0; i < count; i++) {
switch (changes[i][0]) {
case KEYWORD_CHANGE_ADD:
case KEYWORD_CHANGE_FINAL:
case KEYWORD_CHANGE_REMOVE:
count = 0;
for (i = 0; i < count; i++) {
switch (changes[i][0]) {
case KEYWORD_CHANGE_ADD:
case KEYWORD_CHANGE_REMOVE:
case KEYWORD_CHANGE_FINAL:
i_unreached();
for (i = 0; i < array_size; i++) {
if (change_add[i] != 0) {
if (change_remove[i] != 0) {
bool prefer_remote;
if (change_add != 0)
if (change_remove != 0)
unsigned int n, i, count;
for (i = 0; i < count; i++) {
const char *hdr_hash;
int ret;
if (ret == 0) {
i_unreached();
const struct dsync_mail_request *
unsigned int count;
return NULL;
const char *const *changes;
unsigned int i, count;
return NULL;
for (i = 0; i < count; i++) {
return NULL;
const char *const *keyword_names;
static struct mail_save_context *
return save_ctx;
if (ret > 0) {
} else if (save_failed) {
T_BEGIN {
allmails);
} T_END;
int ret = 0;
return ret;
bool *changes_during_sync_r)
unsigned int i, n, wanted_count;
int ret = 0;
if (highest_unwanted_uid == 0 && i > 0 &&
if (highest_unwanted_uid == 0)
if (seq1 > 0) {
return ret;
bool *changes_during_sync_r)
int ret = 0;
&changes) < 0) {
changes_during_sync_r) < 0)
return ret;
const char *key;
unsigned int msgs_left = 0;
msgs_left++;
return msgs_left;
void *key;
unsigned int msgs_left = 0;
msgs_left++;
return msgs_left;
bool *changes_during_sync_r)
unsigned int msgs_left;
int ret;
if (!*changes_during_sync_r)
return ret;