dsync-mailbox-export.c revision 791fb70b3255a11a91ce0c2dc3ae1460d4cf8459
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "lib.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "array.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "hash.h"
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen#include "istream.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-index-modseq.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-storage-private.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-search-build.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-transaction-log-scan.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-mail.h"
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen#include "dsync-mailbox.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-mailbox-export.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct dsync_mail_guid_instances {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(seq_range) seqs;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool requested;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool searched;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct dsync_mailbox_exporter {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_t pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox *box;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_transaction_log_scan *log_scan;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t last_common_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox_transaction_context *trans;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_context *search_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUID => instances */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct dsync_mail_guid_instances *) export_guids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(seq_range) requested_uids;
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen ARRAY_TYPE(seq_range) search_uids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(seq_range) expunged_seqs;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) expunged_guids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int expunged_guid_idx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen /* uint32_t UID => struct dsync_mail_change */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(void *, struct dsync_mail_change *) changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* changes sorted by UID */
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dsync_mail_change *) sorted_changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int change_idx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t highest_changed_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct mailbox_attribute_iter *attr_iter;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct hash_iterate_context *attr_change_iter;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen enum mail_attribute_type attr_type;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct dsync_mailbox_attribute attr;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail dsync_mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *error;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int body_search_initialized:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int auto_export_mails:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int mails_have_guids:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int return_all_mails:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int dsync_mail_error(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail, const char *field)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *errstr;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum mail_error error;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen errstr = mailbox_get_last_error(exporter->box, &error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (error == MAIL_ERROR_EXPUNGED)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "Can't lookup %s for UID=%u: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen field, mail->uid, errstr);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainenfinal_keyword_check(struct dsync_mail_change *change, const char *name,
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen char *type_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
5446576156fbe26e07a5cb964a900281d283f387Timo Sirainen *type_r = KEYWORD_CHANGE_FINAL;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = array_get(&change->keyword_changes, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen if (strcmp(changes[i]+1, name) != 0)
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen continue;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen switch (changes[i][0]) {
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen case KEYWORD_CHANGE_ADD:
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen /* replace with ADD_AND_FINAL */
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen array_delete(&change->keyword_changes, i, 1);
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen *type_r = KEYWORD_CHANGE_ADD_AND_FINAL;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen return FALSE;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen case KEYWORD_CHANGE_REMOVE:
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen /* a final keyword is marked as removed.
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen this shouldn't normally happen. */
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen array_delete(&change->keyword_changes, i, 1);
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen return FALSE;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen case KEYWORD_CHANGE_ADD_AND_FINAL:
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen case KEYWORD_CHANGE_FINAL:
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen /* no change */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainensearch_update_flag_changes(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail, struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *keywords;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i;
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen char type;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert((change->add_flags & change->remove_flags) == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->modseq = mail_get_modseq(mail);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen change->pvt_modseq = mail_get_pvt_modseq(mail);
113ad88e9506a02dfa6fc7f4927c47272cf1b461Timo Sirainen change->final_flags = mail_get_flags(mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keywords = mail_get_keywords(mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!array_is_created(&change->keyword_changes) &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keywords[0] != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&change->keyword_changes, exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str_array_length(keywords));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; keywords[i] != NULL; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* add the final keyword if it's not already there
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen as +keyword */
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen if (!final_keyword_check(change, keywords[i], &type)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *keyword_change =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_strdup_printf(exporter->pool, "%c%s",
252f5c6a63878e7a8a7ffb5847eecbad7f8737e8Timo Sirainen type, keywords[i]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&change->keyword_changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &keyword_change, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenexporter_get_guids(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail, const char **guid_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char **hdr_hash_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *guid_r = "";
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *hdr_hash_r = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* always try to get GUID, even if we're also getting header hash */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_get_special(mail, MAIL_FETCH_GUID, guid_r) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dsync_mail_error(exporter, mail, "GUID");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!exporter->mails_have_guids) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get header hash also */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dsync_mail_get_hdr_hash(mail, hdr_hash_r) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dsync_mail_error(exporter, mail, "hdr-stream");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (**guid_r == '\0') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = "Backend doesn't support GUIDs, "
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "sync with header hashes instead";
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUIDs are required, we don't need header hash */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainensearch_update_flag_change_guid(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *change, *log_change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *guid, *hdr_hash;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen change = hash_table_lookup(exporter->changes, POINTER_CAST(mail->uid));
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen if (change != NULL) {
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen } else {
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen i_assert(exporter->return_all_mails);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen change = p_new(exporter->pool, struct dsync_mail_change, 1);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen change->uid = mail->uid;
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen change->type = DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE;
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen hash_table_insert(exporter->changes,
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen POINTER_CAST(mail->uid), change);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = exporter_get_guids(exporter, mail, &guid, &hdr_hash)) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* the message was expunged during export */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memset(change, 0, sizeof(*change));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->type = DSYNC_MAIL_CHANGE_TYPE_EXPUNGE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->uid = mail->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* find its GUID from log if possible */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen log_change = dsync_transaction_log_scan_find_new_expunge(
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->log_scan, mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (log_change != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->guid = log_change->guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->guid = *guid == '\0' ? "" :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_strdup(exporter->pool, guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->hdr_hash = p_strdup(exporter->pool, hdr_hash);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_update_flag_changes(exporter, mail, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic struct dsync_mail_change *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenexport_save_change_get(struct dsync_mailbox_exporter *exporter, uint32_t uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen change = hash_table_lookup(exporter->changes, POINTER_CAST(uid));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change = p_new(exporter->pool, struct dsync_mail_change, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->uid = uid;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(exporter->changes, POINTER_CAST(uid), change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* move flag changes into a save. this happens only when
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last_common_uid isn't known */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(exporter->last_common_uid == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->type = DSYNC_MAIL_CHANGE_TYPE_SAVE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenexport_add_mail_instance(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *change, uint32_t seq)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_guid_instances *instances;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->auto_export_mails && !exporter->mails_have_guids) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUIDs not supported, mail is requested by UIDs */
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&exporter->requested_uids, change->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*change->guid == '\0') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* mail UIDs are manually requested */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(!exporter->mails_have_guids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances = hash_table_lookup(exporter->export_guids, change->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (instances == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances = p_new(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_guid_instances, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&instances->seqs, exporter->pool, 2);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_insert(exporter->export_guids,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_strdup(exporter->pool, change->guid),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->auto_export_mails)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances->requested = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&instances->seqs, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainensearch_add_save(struct dsync_mailbox_exporter *exporter, struct mail *mail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *guid, *hdr_hash;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen time_t save_timestamp;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* If message is already expunged here, just skip it */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = exporter_get_guids(exporter, mail, &guid, &hdr_hash)) <= 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_get_save_date(mail, &save_timestamp) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dsync_mail_error(exporter, mail, "save-date");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change = export_save_change_get(exporter, mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->save_timestamp = save_timestamp;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->guid = *guid == '\0' ? "" :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_strdup(exporter->pool, guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->hdr_hash = p_strdup(exporter->pool, hdr_hash);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_update_flag_changes(exporter, mail, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen export_add_mail_instance(exporter, change, mail->seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_add_flagchange_uids(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(seq_range) *uids)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = hash_table_iterate_init(exporter->changes);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, exporter->changes, &key, &change)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE)
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(uids, change->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_drop_expunged_flag_changes(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* any flag changes for UIDs above last_common_uid weren't found by
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox search, which means they were already expunged. for some
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen reason the log scanner found flag changes for the message, but not
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen the expunge. just remove these. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = hash_table_iterate_init(exporter->changes);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, exporter->changes, &key, &change)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->uid > exporter->last_common_uid)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_remove(exporter->changes, key);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_search(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_context *search_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_args *search_args;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_arg *sarg;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_args = mail_search_build_init();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sarg = mail_search_build_add(search_args, SEARCH_UIDSET);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&sarg->value.seqset, search_args->pool, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen if (exporter->return_all_mails || exporter->last_common_uid == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we want to know about all mails */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_add_range(&sarg->value.seqset, 1, (uint32_t)-1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* lookup GUIDs for messages with flag changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_add_flagchange_uids(exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &sarg->value.seqset);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* lookup new messages */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_add_range(&sarg->value.seqset,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->last_common_uid + 1,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (uint32_t)-1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->trans = mailbox_transaction_begin(exporter->box, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_ctx = mailbox_search_init(exporter->trans, search_args, NULL,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 0, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_search_args_unref(&search_args);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail->uid <= exporter->last_common_uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = search_update_flag_change_guid(exporter, mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = search_add_save(exporter, mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_drop_expunged_flag_changes(exporter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_search_deinit(&search_ctx) < 0 &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "Mail search failed: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(exporter->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int dsync_mail_change_p_uid_cmp(struct dsync_mail_change *const *c1,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *const *c2)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((*c1)->uid < (*c2)->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((*c1)->uid > (*c2)->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_sort_changes(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&exporter->sorted_changes, exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_count(exporter->changes));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = hash_table_iterate_init(exporter->changes);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, exporter->changes, &key, &change))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&exporter->sorted_changes, &change, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_sort(&exporter->sorted_changes, dsync_mail_change_p_uid_cmp);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainenstatic void
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainendsync_mailbox_export_attr_init(struct dsync_mailbox_exporter *exporter,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen enum mail_attribute_type type)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen{
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->attr_iter =
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen mailbox_attribute_iter_init(exporter->box, type, "");
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->attr_type = type;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen}
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_log_scan(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_transaction_log_scan *log_scan)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(dsync_uid_mail_change) log_changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct dsync_mail_change *change, *dup_change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
08e9fec5ba9e1a26e658c4224207d666b6ced27dTimo Sirainen log_changes = dsync_transaction_log_scan_get_hash(log_scan);
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen if (dsync_transaction_log_scan_has_all_changes(log_scan)) {
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen /* we tried to access too old/invalid modseqs. to make sure
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen no changes get lost, we need to send all of the messages */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->return_all_mails = TRUE;
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* clone the hash table, since we're changing it. */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&exporter->changes, exporter->pool,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_count(log_changes));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = hash_table_iterate_init(log_changes);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, log_changes, &key, &change)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dup_change = p_new(exporter->pool, struct dsync_mail_change, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *dup_change = *change;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(exporter->changes, key, dup_change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->highest_changed_uid < change->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->highest_changed_uid = change->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct dsync_mailbox_exporter *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_init(struct mailbox *box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_transaction_log_scan *log_scan,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t last_common_uid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum dsync_mailbox_exporter_flags flags)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mailbox_exporter *exporter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_t pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"dsync mailbox export",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 4096);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter = p_new(pool, struct dsync_mailbox_exporter, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->pool = pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->box = box;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->log_scan = log_scan;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->last_common_uid = last_common_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->auto_export_mails =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (flags & DSYNC_MAILBOX_EXPORTER_FLAG_AUTO_EXPORT_MAILS) != 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->mails_have_guids =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (flags & DSYNC_MAILBOX_EXPORTER_FLAG_MAILS_HAVE_GUIDS) != 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&exporter->requested_uids, pool, 16);
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen p_array_init(&exporter->search_uids, pool, 16);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&exporter->export_guids, pool, 0, str_hash, strcmp);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&exporter->expunged_seqs, pool, 16);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&exporter->expunged_guids, pool, 16);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* first scan transaction log and save any expunges and flag changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_log_scan(exporter, log_scan);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get saves and also find GUIDs for flag changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_search(exporter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get the changes sorted by UID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_sort_changes(exporter);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen dsync_mailbox_export_attr_init(exporter, MAIL_ATTRIBUTE_TYPE_PRIVATE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return exporter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainenstatic int
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainendsync_mailbox_export_iter_next_nonexistent_attr(struct dsync_mailbox_exporter *exporter)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen{
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct dsync_mailbox_attribute *attr;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct mail_attribute_value value;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen while (hash_table_iterate(exporter->attr_change_iter,
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen dsync_transaction_log_scan_get_attr_hash(exporter->log_scan),
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen &attr, &attr)) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (attr->exported || !attr->deleted)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen continue;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* lookup the value mainly to get its last_change value. */
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (mailbox_attribute_get_stream(exporter->trans, attr->type,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->key, &value) < 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen "Mailbox attribute %s lookup failed: %s", attr->key,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen mailbox_get_last_error(exporter->box, NULL));
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen break;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if ((value.flags & MAIL_ATTRIBUTE_VALUE_FLAG_READONLY) != 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (value.value_stream != NULL)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_unref(&value.value_stream);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen continue;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->last_change = value.last_change;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (value.value != NULL || value.value_stream != NULL) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->value = p_strdup(exporter->pool, value.value);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->value_stream = value.value_stream;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->deleted = FALSE;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->exported = TRUE;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->attr = *attr;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return 1;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen hash_table_iterate_deinit(&exporter->attr_change_iter);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return 0;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen}
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainenstatic int
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainendsync_mailbox_export_iter_next_attr(struct dsync_mailbox_exporter *exporter)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen{
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen HASH_TABLE_TYPE(dsync_attr_change) attr_changes;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct dsync_mailbox_attribute lookup_attr, *attr;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct dsync_mailbox_attribute *attr_change;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen const char *key;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen struct mail_attribute_value value;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen bool export_all_attrs;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen export_all_attrs = exporter->return_all_mails ||
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->last_common_uid == 0;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr_changes = dsync_transaction_log_scan_get_attr_hash(exporter->log_scan);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen lookup_attr.type = exporter->attr_type;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* note that the order of processing may be important for some
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attributes. for example sieve can't set a script active until it's
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen first been created */
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen while ((key = mailbox_attribute_iter_next(exporter->attr_iter)) != NULL) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen lookup_attr.key = key;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr_change = hash_table_lookup(attr_changes, &lookup_attr);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (attr_change == NULL && !export_all_attrs)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen continue;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (mailbox_attribute_get_stream(exporter->trans,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->attr_type, key,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen &value) < 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen "Mailbox attribute %s lookup failed: %s", key,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen mailbox_get_last_error(exporter->box, NULL));
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return -1;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if ((value.flags & MAIL_ATTRIBUTE_VALUE_FLAG_READONLY) != 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* readonly attributes can't be changed,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen no point in exporting them */
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (value.value_stream != NULL)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_unref(&value.value_stream);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen continue;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (value.value == NULL && value.value_stream == NULL &&
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen (attr_change == NULL || !attr_change->deleted)) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* the attribute was just deleted?
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen skip for this sync. */
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen continue;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr = &exporter->attr;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen memset(attr, 0, sizeof(*attr));
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->type = exporter->attr_type;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->value = p_strdup(exporter->pool, value.value);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->value_stream = value.value_stream;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->last_change = value.last_change;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (attr_change != NULL) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_assert(!attr_change->exported);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr_change->exported = TRUE;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->key = attr_change->key;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->deleted = attr_change->deleted &&
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen !DSYNC_ATTR_HAS_VALUE(attr);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->modseq = attr_change->modseq;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen } else {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen attr->key = p_strdup(exporter->pool, key);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return 1;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (mailbox_attribute_iter_deinit(&exporter->attr_iter) < 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen "Mailbox attribute iteration failed: %s",
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen mailbox_get_last_error(exporter->box, NULL));
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return -1;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (exporter->attr_type == MAIL_ATTRIBUTE_TYPE_PRIVATE) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* export shared attributes */
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen dsync_mailbox_export_attr_init(exporter,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen MAIL_ATTRIBUTE_TYPE_SHARED);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return dsync_mailbox_export_iter_next_attr(exporter);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen exporter->attr_change_iter = hash_table_iterate_init(attr_changes);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return dsync_mailbox_export_iter_next_nonexistent_attr(exporter);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen}
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainenconst struct dsync_mailbox_attribute *
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainendsync_mailbox_export_next_attr(struct dsync_mailbox_exporter *exporter)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen{
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (exporter->error != NULL)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen return NULL;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (exporter->attr.value_stream != NULL)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_unref(&exporter->attr.value_stream);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (exporter->attr_iter != NULL) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (dsync_mailbox_export_iter_next_attr(exporter) <= 0)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return NULL;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen } else {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (dsync_mailbox_export_iter_next_nonexistent_attr(exporter) <= 0)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return NULL;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return &exporter->attr;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen}
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenconst struct dsync_mail_change *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_next(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *const *changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->error != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = array_get(&exporter->sorted_changes, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->change_idx == count)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return changes[exporter->change_idx++];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_body_search_init(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_args *search_args;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_arg *sarg;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct seq_range *uids;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen char *guid;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen const char *const_guid;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct dsync_mail_guid_instances *instances;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct seq_range *range;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t seq, seq1, seq2;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(exporter->search_ctx == NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_args = mail_search_build_init();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sarg = mail_search_build_add(search_args, SEARCH_SEQSET);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&sarg->value.seqset, search_args->pool, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get a list of messages we want to fetch. if there are more than one
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instance for a GUID, use the first one. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen iter = hash_table_iterate_init(exporter->export_guids);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, exporter->export_guids,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen &guid, &instances)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!instances->requested ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_count(&instances->seqs) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uids = array_idx(&instances->seqs, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq = uids[0].seq1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!instances->searched) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances->searched = TRUE;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&sarg->value.seqset, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (seq_range_exists(&exporter->expunged_seqs, seq)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we're on a second round, refetching expunged
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen messages */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_remove(&instances->seqs, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_remove(&exporter->expunged_seqs, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_count(&instances->seqs) == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* no instances left */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen const_guid = guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&exporter->expunged_guids,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen &const_guid, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uids = array_idx(&instances->seqs, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq = uids[0].seq1;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&sarg->value.seqset, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* add requested UIDs */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen range = array_get(&exporter->requested_uids, &count);
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_seq_range(exporter->box,
789cb161ef9cb3126e6370c87a21a5a844d7dd0bTimo Sirainen range[i].seq1, range[i].seq2,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &seq1, &seq2);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_add_range(&sarg->value.seqset,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq1, seq2);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen array_clear(&exporter->search_uids);
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen array_append_array(&exporter->search_uids, &exporter->requested_uids);
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen array_clear(&exporter->requested_uids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->search_ctx =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_search_init(exporter->trans, search_args, NULL,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAIL_FETCH_GUID |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAIL_FETCH_UIDL_BACKEND |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAIL_FETCH_POP3_ORDER |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAIL_FETCH_RECEIVED_DATE, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_search_args_unref(&search_args);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return array_count(&sarg->value.seqset) > 0 ? 1 : 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_body_search_deinit(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->search_ctx == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_search_deinit(&exporter->search_ctx) < 0 &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "Mail search failed: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(exporter->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int dsync_mailbox_export_mail(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_guid_instances *instances;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen const char *error_field;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (dsync_mail_fill(mail, &exporter->dsync_mail, &error_field) < 0)
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return dsync_mail_error(exporter, mail, error_field);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen instances = *exporter->dsync_mail.guid == '\0' ? NULL :
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen hash_table_lookup(exporter->export_guids,
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen exporter->dsync_mail.guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (instances != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUID found */
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen } else if (exporter->dsync_mail.uid != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* mail requested by UID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "GUID unexpectedly changed for UID=%u GUID=%s",
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen mail->uid, exporter->dsync_mail.guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
3d651cf1a2171471bf6f0a41dcf7388d43206636Timo Sirainen if (!seq_range_exists(&exporter->search_uids, mail->uid))
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen exporter->dsync_mail.uid = 0;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen else
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen exporter->dsync_mail.guid = "";
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* this message was successfully returned, don't try retrying it */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (instances != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_clear(&instances->seqs);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_mailbox_export_want_mail(struct dsync_mailbox_exporter *exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_request *request)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_guid_instances *instances;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(!exporter->auto_export_mails);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
d8bdf558c7ba173fc47a194633d9bd97af1b9c74Timo Sirainen if (request->guid == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(request->uid > 0);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&exporter->requested_uids, request->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances = hash_table_lookup(exporter->export_guids, request->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (instances == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->error = p_strdup_printf(exporter->pool,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "Remote requested unexpected GUID %s", request->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen instances->requested = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenconst struct dsync_mail *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *guids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->error != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!exporter->body_search_initialized) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->body_search_initialized = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dsync_mailbox_export_body_search_init(exporter) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(exporter->error != NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (mailbox_search_next(exporter->search_ctx, &mail)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = dsync_mailbox_export_mail(exporter, mail)) > 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return &exporter->dsync_mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(exporter->error != NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* the message was expunged. if the GUID has another instance,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen try sending it later. */
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&exporter->expunged_seqs, mail->seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* if some instances of messages were expunged, retry fetching them
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen with other instances */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_body_search_deinit(exporter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = dsync_mailbox_export_body_search_init(exporter)) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(exporter->error != NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret > 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* not finished yet */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dsync_mailbox_export_next_mail(exporter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* finished with messages. if there are any expunged messages,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return them */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen guids = array_get(&exporter->expunged_guids, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (exporter->expunged_guid_idx < count) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memset(&exporter->dsync_mail, 0, sizeof(exporter->dsync_mail));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen exporter->dsync_mail.guid =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen guids[exporter->expunged_guid_idx++];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return &exporter->dsync_mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint dsync_mailbox_export_deinit(struct dsync_mailbox_exporter **_exporter,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char **error_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mailbox_exporter *exporter = *_exporter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *_exporter = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_export_body_search_deinit(exporter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (void)mailbox_transaction_commit(&exporter->trans);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (exporter->attr.value_stream != NULL)
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_unref(&exporter->attr.value_stream);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_destroy(&exporter->export_guids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *error_r = t_strdup(exporter->error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_unref(&exporter->pool);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return *error_r != NULL ? -1 : 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}