pop3-migration-plugin.c revision 06fda713b84e857dbc3e80f401a54085c9b0ed16
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik/* Copyright (c) 2007-2016 Dovecot authors, see the included COPYING file */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "lib.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "array.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "istream.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "istream-header-filter.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "str.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "sha1.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "message-size.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "message-header-hash.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "message-header-parser.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "mail-cache.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "mail-namespace.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "mail-search-build.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "index-storage.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "index-mail.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#include "pop3-migration-plugin.h"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#define POP3_MIGRATION_CONTEXT(obj) \
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik MODULE_CONTEXT(obj, pop3_migration_storage_module)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik#define POP3_MIGRATION_MAIL_CONTEXT(obj) \
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik MODULE_CONTEXT(obj, pop3_migration_mail_module)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct msg_map_common {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* sha1(header) - set only when needed */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned char hdr_sha1[SHA1_RESULTLEN];
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int hdr_sha1_set:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct pop3_uidl_map {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct msg_map_common common;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uint32_t pop3_seq;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uint32_t imap_uid;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* UIDL */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const char *pop3_uidl;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* LIST size */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uoff_t size;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct imap_msg_map {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct msg_map_common common;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uint32_t uid, pop3_seq;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uoff_t psize;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const char *pop3_uidl;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct pop3_migration_mail_storage {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik union mail_storage_module_context module_ctx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const char *pop3_box_vname;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ARRAY(struct pop3_uidl_map) pop3_uidl_map;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int all_mailboxes:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int pop3_all_hdr_sha1_set:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int ignore_missing_uidls:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int skip_size_check:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct pop3_migration_mailbox {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik union mailbox_module_context module_ctx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ARRAY(struct imap_msg_map) imap_msg_map;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int first_unfound_idx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_cache_field cache_field;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int cache_field_registered:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int uidl_synced:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int uidl_sync_failed:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned int uidl_ordered:1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik/* NOTE: these headers must be sorted */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic const char *hdr_hash_skip_headers[] = {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "Content-Length",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "Return-Path", /* Yahoo IMAP has Return-Path, Yahoo POP3 doesn't */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "Status",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-IMAP",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-IMAPbase",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-Keywords",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-Message-Flag",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-Status",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-UID",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-UIDL",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik "X-Yahoo-Newman-Property"
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik};
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikconst char *pop3_migration_plugin_version = DOVECOT_ABI_VERSION;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic MODULE_CONTEXT_DEFINE_INIT(pop3_migration_storage_module,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik &mail_storage_module_register);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic MODULE_CONTEXT_DEFINE_INIT(pop3_migration_mail_module,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik &mail_module_register);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int imap_msg_map_uid_cmp(const struct imap_msg_map *map1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const struct imap_msg_map *map2)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (map1->uid < map2->uid)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (map1->uid > map2->uid)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int pop3_uidl_map_pop3_seq_cmp(const struct pop3_uidl_map *map1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const struct pop3_uidl_map *map2)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (map1->pop3_seq < map2->pop3_seq)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik return -1;
a190e39ea4f2c084091be1cd37a3c6e3b603540eNikolai Kondrashov if (map1->pop3_seq > map2->pop3_seq)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int pop3_uidl_map_hdr_cmp(const struct pop3_uidl_map *map1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const struct pop3_uidl_map *map2)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return memcmp(map1->common.hdr_sha1, map2->common.hdr_sha1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sizeof(map1->common.hdr_sha1));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int imap_msg_map_hdr_cmp(const struct imap_msg_map *map1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const struct imap_msg_map *map2)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return memcmp(map1->common.hdr_sha1, map2->common.hdr_sha1,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sizeof(map1->common.hdr_sha1));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstruct pop3_hdr_context {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik bool have_eoh;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik bool stop;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik};
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikstatic bool header_name_is_valid(const char *name)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik unsigned int i;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik for (i = 0; name[i] != '\0'; i++) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if ((uint8_t)name[i] <= 0x20 || name[i] >= 0x7f)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik return FALSE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik return TRUE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik}
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikstatic void
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikpop3_header_filter_callback(struct header_filter_istream *input ATTR_UNUSED,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct message_header_line *hdr,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik bool *matched, struct pop3_hdr_context *ctx)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (hdr == NULL)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik return;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (hdr->eoh) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik ctx->have_eoh = TRUE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (ctx->stop) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik /* matched is handled differently for eoh by
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik istream-header-filter. a design bug I guess.. */
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik *matched = FALSE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik } else {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (strspn(hdr->name, "\r") == hdr->name_len) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* CR+CR+LF - some servers stop the header processing
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik here while others don't. To make sure they can be
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik matched correctly we want to stop here entirely. */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ctx->stop = TRUE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (ctx->stop)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik *matched = TRUE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik else if (!header_name_is_valid(hdr->name)) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* Yahoo IMAP drops headers with invalid names, while
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik Yahoo POP3 preserves them. Drop them all. */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik *matched = TRUE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikint pop3_migration_get_hdr_sha1(uint32_t mail_seq, struct istream *input,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik uoff_t hdr_size,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik unsigned char sha1_r[SHA1_RESULTLEN],
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik bool *have_eoh_r)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct istream *input2;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik const unsigned char *data;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik size_t size;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct sha1_ctxt sha1_ctx;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct pop3_hdr_context hdr_ctx;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik memset(&hdr_ctx, 0, sizeof(hdr_ctx));
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik input2 = i_stream_create_limit(input, hdr_size);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik /* hide headers that might change or be different in IMAP vs. POP3 */
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik input = i_stream_create_header_filter(input2,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik hdr_hash_skip_headers,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik N_ELEMENTS(hdr_hash_skip_headers),
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik pop3_header_filter_callback, &hdr_ctx);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik i_stream_unref(&input2);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik sha1_init(&sha1_ctx);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik while (i_stream_read_data(input, &data, &size, 0) > 0) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik message_header_hash_more(&hash_method_sha1, &sha1_ctx, 2,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik data, size);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik i_stream_skip(input, size);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (input->stream_errno != 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to read header for msg %u: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail_seq, i_stream_get_error(input));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_stream_unref(&input);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sha1_result(&sha1_ctx, sha1_r);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_stream_unref(&input);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik *have_eoh_r = hdr_ctx.have_eoh;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic unsigned int get_cache_idx(struct mail *mail)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(mail->box);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mbox->cache_field_registered)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return mbox->cache_field.idx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mbox->cache_field.name = "pop3-migration.hdr";
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mbox->cache_field.type = MAIL_CACHE_FIELD_FIXED_SIZE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mbox->cache_field.field_size = SHA1_RESULTLEN;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail_cache_register_fields(mail->box->cache, &mbox->cache_field, 1);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mbox->cache_field_registered = TRUE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return mbox->cache_field.idx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikget_hdr_sha1(struct mail *mail, unsigned char sha1_r[SHA1_RESULTLEN])
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct istream *input;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct message_size hdr_size;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik bool have_eoh;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mail_get_hdr_stream(mail, &hdr_size, &input) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to get header for msg %u: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->seq, mailbox_get_last_error(mail->box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (pop3_migration_get_hdr_sha1(mail->seq, input,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik hdr_size.physical_size,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sha1_r, &have_eoh) < 0)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (have_eoh) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct index_mail *imail = (struct index_mail *)mail;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik index_mail_cache_add_idx(imail, get_cache_idx(mail),
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sha1_r, SHA1_RESULTLEN);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* The empty "end of headers" line is missing. Either this means that
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik the headers ended unexpectedly (which is ok) or that the remote
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik server is buggy. Some servers have problems with
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik 1) header line continuations that contain only whitespace and
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik 2) headers that have no ":". The header gets truncated when such
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik line is reached.
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik At least Oracle IMS IMAP FETCH BODY[HEADER] handles 1) by not
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik returning the whitespace line and 2) by returning the line but
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik truncating the rest. POP3 TOP instead returns the entire header.
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik This causes the IMAP and POP3 hashes not to match.
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik If there's LF+CR+CR+LF in the middle of headers, Courier IMAP's
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik FETCH BODY[HEADER] stops after that, but Courier POP3's TOP doesn't.
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik So we'll try to avoid this by falling back to full FETCH BODY[]
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik (and/or RETR) and we'll parse the header ourself from it. This
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik should work around any similar bugs in all IMAP/POP3 servers. */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mail_get_stream(mail, &hdr_size, NULL, &input) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to get body for msg %u: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->seq, mailbox_get_last_error(mail->box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return pop3_migration_get_hdr_sha1(mail->seq, input,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik hdr_size.physical_size,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik sha1_r, &have_eoh);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic bool
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikget_cached_hdr_sha1(struct mail *mail, buffer_t *cache_buf,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik unsigned char sha1_r[SHA1_RESULTLEN])
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct index_mail *imail = (struct index_mail *)mail;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik buffer_set_used_size(cache_buf, 0);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (index_mail_cache_lookup_field(imail, cache_buf,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik get_cache_idx(mail)) > 0 &&
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik cache_buf->used == SHA1_RESULTLEN) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik memcpy(sha1_r, cache_buf->data, cache_buf->used);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return TRUE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return FALSE;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic struct mailbox *pop3_mailbox_alloc(struct mail_storage *storage)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct pop3_migration_mail_storage *mstorage =
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik POP3_MIGRATION_CONTEXT(storage);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_namespace *ns;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ns = mail_namespace_find(storage->user->namespaces,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mstorage->pop3_box_vname);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_assert(ns != NULL);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return mailbox_alloc(ns->list, mstorage->pop3_box_vname,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik MAILBOX_FLAG_READONLY | MAILBOX_FLAG_POP3_SESSION);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic int pop3_map_read(struct mail_storage *storage, struct mailbox *pop3_box)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct pop3_migration_mail_storage *mstorage =
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik POP3_MIGRATION_CONTEXT(storage);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mailbox_transaction_context *t;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_search_args *search_args;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_search_context *ctx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail *mail;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct pop3_uidl_map *map;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik const char *uidl;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik uoff_t size = (uoff_t)-1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik int ret = 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (array_is_created(&mstorage->pop3_uidl_map)) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* already read these, just reset the imap_uids */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik array_foreach_modifiable(&mstorage->pop3_uidl_map, map)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik map->imap_uid = 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return 0;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_array_init(&mstorage->pop3_uidl_map, 128);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mailbox_sync(pop3_box, 0) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Couldn't sync mailbox %s: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik pop3_box->vname, mailbox_get_last_error(pop3_box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik t = mailbox_transaction_begin(pop3_box, 0);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik search_args = mail_search_build_init();
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail_search_build_add_all(search_args);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ctx = mailbox_search_init(t, search_args, NULL,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mstorage->skip_size_check ? 0 :
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik MAIL_FETCH_PHYSICAL_SIZE, NULL);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail_search_args_unref(&search_args);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik while (mailbox_search_next(ctx, &mail)) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik /* get the size with LIST instead of RETR */
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mstorage->skip_size_check)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik else if (mail_get_physical_size(mail, &size) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to get size for msg %u: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->seq,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mailbox_get_last_error(pop3_box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ret = -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik break;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &uidl) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to get UIDL for msg %u: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->seq,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mailbox_get_last_error(pop3_box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ret = -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik break;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (*uidl == '\0') {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_warning("pop3_migration: UIDL for msg %u is empty",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mail->seq);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik continue;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik map = array_append_space(&mstorage->pop3_uidl_map);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik map->pop3_seq = mail->seq;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik map->pop3_uidl = p_strdup(storage->pool, uidl);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik map->size = size;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik if (mailbox_search_deinit(&ctx) < 0) {
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik i_error("pop3_migration: Failed to search all POP3 mails: %s",
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik mailbox_get_last_error(pop3_box, NULL));
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ret = -1;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik }
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik (void)mailbox_transaction_commit(&t);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik return ret;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik}
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikstatic void
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnikpop3_map_read_cached_hdr_hashes(struct mailbox_transaction_context *t,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_search_args *search_args,
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct array *msg_map)
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik{
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail_search_context *ctx;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct mail *mail;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik struct msg_map_common *map;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik buffer_t *cache_buf;
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik cache_buf = buffer_create_dynamic(pool_datastack_create(), SHA1_RESULTLEN);
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik
a2c10cf31d14bac598f5cd008973375c3f9575a6Lukas Slebodnik while (mailbox_search_next(ctx, &mail)) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map = array_idx_modifiable_i(msg_map, mail->seq-1);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (get_cached_hdr_sha1(mail, cache_buf, map->hdr_sha1))
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map->hdr_sha1_set = TRUE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (mailbox_search_deinit(&ctx) < 0) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik i_warning("pop3_migration: Failed to search all cached POP3 header hashes: %s - ignoring",
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik mailbox_get_last_error(t->box, NULL));
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik}
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikstatic void map_remove_found_seqs(struct mail_search_arg *search_arg,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct array *msg_map, uint32_t seq1)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik const struct msg_map_common *map;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik uint32_t seq, count = array_count_i(msg_map);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik i_assert(search_arg->type == SEARCH_SEQSET);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik for (seq = seq1; seq <= count; seq++) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map = array_idx_i(msg_map, seq-1);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (map->hdr_sha1_set)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik seq_range_array_remove(&search_arg->value.seqset, seq);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik}
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikstatic int
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikmap_read_hdr_hashes(struct mailbox *box, struct array *msg_map, uint32_t seq1)
137d5dd0dba48f647e5f8b3976ddb78d65dc77a5Lukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct mailbox_transaction_context *t;
137d5dd0dba48f647e5f8b3976ddb78d65dc77a5Lukas Slebodnik struct mail_search_args *search_args;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct mail_search_context *ctx;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct mail *mail;
137d5dd0dba48f647e5f8b3976ddb78d65dc77a5Lukas Slebodnik struct msg_map_common *map;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik int ret = 0;
137d5dd0dba48f647e5f8b3976ddb78d65dc77a5Lukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik t = mailbox_transaction_begin(box, 0);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik /* get all the cached hashes */
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik search_args = mail_search_build_init();
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik mail_search_build_add_seqset(search_args, seq1, array_count_i(msg_map));
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik pop3_map_read_cached_hdr_hashes(t, search_args, msg_map);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik /* read all the non-cached hashes. doing this in two passes allows
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik us to set wanted_fields=MAIL_FETCH_STREAM_HEADER, which allows
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik prefetching to work without downloading all the headers even
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik for mails that already are cached. */
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map_remove_found_seqs(search_args->args, msg_map, seq1);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik ctx = mailbox_search_init(t, search_args, NULL,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik MAIL_FETCH_STREAM_HEADER, NULL);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik mail_search_args_unref(&search_args);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik while (mailbox_search_next(ctx, &mail)) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map = array_idx_modifiable_i(msg_map, mail->seq-1);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (get_hdr_sha1(mail, map->hdr_sha1) < 0) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik ret = -1;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik break;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik map->hdr_sha1_set = TRUE;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik if (mailbox_search_deinit(&ctx) < 0) {
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik i_error("pop3_migration: Failed to search all mail headers: %s",
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik mailbox_get_last_error(box, NULL));
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik ret = -1;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik }
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik (void)mailbox_transaction_commit(&t);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik return ret;
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik}
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikstatic int
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnikpop3_map_read_hdr_hashes(struct mail_storage *storage, struct mailbox *pop3_box,
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik unsigned first_seq)
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik{
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik struct pop3_migration_mail_storage *mstorage =
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik POP3_MIGRATION_CONTEXT(storage);
cb8c24707275c5bda7310d67e7f46c75d3ac36eaLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (mstorage->pop3_all_hdr_sha1_set)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return 0;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (mstorage->all_mailboxes) {
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik /* we may be matching against multiple mailboxes.
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik read all the hashes only once. */
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik first_seq = 1;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik }
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (map_read_hdr_hashes(pop3_box, &mstorage->pop3_uidl_map.arr,
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik first_seq) < 0)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return -1;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (first_seq == 1)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mstorage->pop3_all_hdr_sha1_set = TRUE;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return 0;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik}
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnikstatic int imap_map_read(struct mailbox *box)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik{
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_migration_mail_storage *mstorage =
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik POP3_MIGRATION_CONTEXT(box->storage);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct mailbox_status status;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct mailbox_transaction_context *t;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct mail_search_args *search_args;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct mail_search_context *ctx;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct mail *mail;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct imap_msg_map *map;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik uoff_t psize = (uoff_t)-1;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik int ret = 0;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mailbox_get_open_status(box, STATUS_MESSAGES, &status);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik i_assert(!array_is_created(&mbox->imap_msg_map));
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik p_array_init(&mbox->imap_msg_map, box->pool, status.messages);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik t = mailbox_transaction_begin(box, 0);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik search_args = mail_search_build_init();
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mail_search_build_add_all(search_args);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik ctx = mailbox_search_init(t, search_args, NULL,
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mstorage->skip_size_check ? 0 :
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik MAIL_FETCH_PHYSICAL_SIZE, NULL);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mail_search_args_unref(&search_args);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik while (mailbox_search_next(ctx, &mail)) {
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (mstorage->skip_size_check)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik ;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik else if (mail_get_physical_size(mail, &psize) < 0) {
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik i_error("pop3_migration: Failed to get psize for imap uid %u: %s",
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mail->uid,
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mailbox_get_last_error(box, NULL));
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik ret = -1;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik break;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik }
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik map = array_append_space(&mbox->imap_msg_map);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik map->uid = mail->uid;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik map->psize = psize;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik }
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (mailbox_search_deinit(&ctx) < 0) {
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik i_error("pop3_migration: Failed to search all IMAP mails: %s",
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mailbox_get_last_error(box, NULL));
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik ret = -1;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik }
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik (void)mailbox_transaction_commit(&t);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return ret;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik}
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnikstatic int imap_map_read_hdr_hashes(struct mailbox *box)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik{
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return map_read_hdr_hashes(box, &mbox->imap_msg_map.arr,
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik mbox->first_unfound_idx+1);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik}
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnikstatic bool pop3_uidl_assign_by_size(struct mailbox *box)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik{
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_migration_mail_storage *mstorage =
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik POP3_MIGRATION_CONTEXT(box->storage);
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct pop3_uidl_map *pop3_map;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik struct imap_msg_map *imap_map;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik unsigned int i, pop3_count, imap_count, count;
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik if (mstorage->skip_size_check)
c3baf4d7c0cbd139d96fd04f6b3c175d2f99de6cLukas Slebodnik return FALSE;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map = array_get_modifiable(&mstorage->pop3_uidl_map, &pop3_count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map = array_get_modifiable(&mbox->imap_msg_map, &imap_count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik count = I_MIN(pop3_count, imap_count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik /* see if we can match the messages using sizes */
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik for (i = 0; i < count; i++) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (pop3_map[i].size != imap_map[i].psize)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik break;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (i+1 < count && pop3_map[i].size == pop3_map[i+1].size) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik /* two messages with same size, don't trust them */
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik break;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map[i].imap_uid = imap_map[i].uid;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[i].pop3_uidl = pop3_map[i].pop3_uidl;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[i].pop3_seq = pop3_map[i].pop3_seq;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mbox->first_unfound_idx = i;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (box->storage->user->mail_debug)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik i_debug("pop3_migration: %u/%u mails matched by size", i, count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return i == count;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik}
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnikstatic int
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnikpop3_uidl_assign_by_hdr_hash(struct mailbox *box, struct mailbox *pop3_box)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik{
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_migration_mail_storage *mstorage =
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik POP3_MIGRATION_CONTEXT(box->storage);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_uidl_map *pop3_map;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct imap_msg_map *imap_map;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik unsigned int pop3_idx, imap_idx, pop3_count, imap_count;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik unsigned int first_seq, missing_uids_count;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik uint32_t first_missing_idx = (uint32_t)-1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik int ret;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik first_seq = mbox->first_unfound_idx+1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (pop3_map_read_hdr_hashes(box->storage, pop3_box, first_seq) < 0 ||
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map_read_hdr_hashes(box) < 0)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return -1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik array_sort(&mstorage->pop3_uidl_map, pop3_uidl_map_hdr_cmp);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik array_sort(&mbox->imap_msg_map, imap_msg_map_hdr_cmp);
137d5dd0dba48f647e5f8b3976ddb78d65dc77a5Lukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map = array_get_modifiable(&mstorage->pop3_uidl_map, &pop3_count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map = array_get_modifiable(&mbox->imap_msg_map, &imap_count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_idx = imap_idx = 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik while (pop3_idx < pop3_count && imap_idx < imap_count) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (!pop3_map[pop3_idx].common.hdr_sha1_set ||
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl pop3_map[pop3_idx].imap_uid != 0) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_idx++;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik continue;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (!imap_map[imap_idx].common.hdr_sha1_set ||
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[imap_idx].pop3_uidl != NULL) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_idx++;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik continue;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik ret = memcmp(pop3_map[pop3_idx].common.hdr_sha1,
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[imap_idx].common.hdr_sha1,
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik sizeof(pop3_map[pop3_idx].common.hdr_sha1));
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (ret < 0)
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl pop3_idx++;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik else if (ret > 0)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_idx++;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik else {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map[pop3_idx].imap_uid = imap_map[imap_idx].uid;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[imap_idx].pop3_uidl =
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map[pop3_idx].pop3_uidl;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik imap_map[imap_idx].pop3_seq =
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map[pop3_idx].pop3_seq;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik missing_uids_count = 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik for (pop3_idx = 0; pop3_idx < pop3_count; pop3_idx++) {
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl if (pop3_map[pop3_idx].imap_uid == 0) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (first_missing_idx == (uint32_t)-1)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik first_missing_idx = pop3_idx;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik missing_uids_count++;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (missing_uids_count > 0 && !mstorage->all_mailboxes) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik string_t *str = t_str_new(128);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik str_printfa(str, "pop3_migration: %u POP3 messages have no "
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik "matching IMAP messages (first POP3 msg %u UIDL %s)",
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik missing_uids_count,
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map[first_missing_idx].pop3_seq,
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl pop3_map[first_missing_idx].pop3_uidl);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (imap_count + missing_uids_count == pop3_count) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik str_append(str, " - all IMAP messages were found "
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik "(POP3 contains more than IMAP INBOX - you may want to set pop3_migration_all_mailboxes=yes)");
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (!mstorage->ignore_missing_uidls) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik i_error("%s - set pop3_migration_ignore_missing_uidls=yes to continue anyway",
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik str_c(str));
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return -1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik i_warning("%s", str_c(str));
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik } else if (box->storage->user->mail_debug) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik i_debug("pop3_migration: %u mails matched by headers", pop3_count);
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik array_sort(&mstorage->pop3_uidl_map, pop3_uidl_map_pop3_seq_cmp);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik array_sort(&mbox->imap_msg_map, imap_msg_map_uid_cmp);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik}
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnikstatic int pop3_migration_uidl_sync(struct mailbox *box)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik{
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_migration_mail_storage *mstorage =
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik POP3_MIGRATION_CONTEXT(box->storage);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct mailbox *pop3_box;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik const struct pop3_uidl_map *pop3_map;
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl unsigned int i, count;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik uint32_t prev_uid;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_box = pop3_mailbox_alloc(box->storage);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik /* the POP3 server isn't connected to yet. handle all IMAP traffic
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik first before connecting, so POP3 server won't disconnect us due to
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik idling. */
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (imap_map_read(box) < 0 ||
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map_read(box->storage, pop3_box) < 0) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mailbox_free(&pop3_box);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return -1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl if (!pop3_uidl_assign_by_size(box)) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik /* everything wasn't assigned, figure out the rest with
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik header hashes */
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (pop3_uidl_assign_by_hdr_hash(box, pop3_box) < 0) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mailbox_free(&pop3_box);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return -1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik /* see if the POP3 UIDL order is the same as IMAP UID order */
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mbox->uidl_ordered = TRUE;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_map = array_get(&mstorage->pop3_uidl_map, &count);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik prev_uid = 0;
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl for (i = 0; i < count; i++) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (pop3_map[i].imap_uid == 0)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik continue;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (prev_uid > pop3_map[i].imap_uid) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mbox->uidl_ordered = FALSE;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik break;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik prev_uid = pop3_map[i].imap_uid;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mbox->uidl_synced = TRUE;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mailbox_free(&pop3_box);
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl return 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik}
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnikstatic int pop3_migration_uidl_sync_if_needed(struct mailbox *box)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik{
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (mbox->uidl_synced)
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik if (mbox->uidl_sync_failed ||
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik pop3_migration_uidl_sync(box) < 0) {
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik mbox->uidl_sync_failed = TRUE;
1584db9c0b15ee239bd4e163c4ecaf6909b1b11bPavel Reichl mail_storage_set_error(box->storage, MAIL_ERROR_TEMP,
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik "POP3 UIDLs couldn't be synced");
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return -1;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik }
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik return 0;
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik}
089db891b8a7a94b5666e8cffb1d7b359d6aeb6eLukas Slebodnik
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnikstatic int
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnikpop3_migration_get_special(struct mail *_mail, enum mail_fetch_field field,
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik const char **value_r)
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik{
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct mail_private *mail = (struct mail_private *)_mail;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik union mail_module_context *mmail = POP3_MIGRATION_MAIL_CONTEXT(mail);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(_mail->box);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct imap_msg_map map_key, *map;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik if (field == MAIL_FETCH_UIDL_BACKEND ||
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik field == MAIL_FETCH_POP3_ORDER) {
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik if (pop3_migration_uidl_sync_if_needed(_mail->box) < 0)
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik return -1;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik memset(&map_key, 0, sizeof(map_key));
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik map_key.uid = _mail->uid;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik map = array_bsearch(&mbox->imap_msg_map, &map_key,
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik imap_msg_map_uid_cmp);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik if (map != NULL && map->pop3_uidl != NULL) {
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik if (field == MAIL_FETCH_UIDL_BACKEND)
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik *value_r = map->pop3_uidl;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik else
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik *value_r = t_strdup_printf("%u", map->pop3_seq);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik return 0;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik }
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik /* not found from POP3 server, fallback to default */
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik }
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik return mmail->super.get_special(_mail, field, value_r);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik}
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnikstatic void pop3_migration_mail_allocated(struct mail *_mail)
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik{
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct pop3_migration_mail_storage *mstorage =
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik POP3_MIGRATION_CONTEXT(_mail->box->storage);
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct mail_private *mail = (struct mail_private *)_mail;
b28f5fb097e06a97a45e0ae348e506d9d1432cc8Lukas Slebodnik struct mail_vfuncs *v = mail->vlast;
union mail_module_context *mmail;
struct mail_namespace *ns;
if (mstorage == NULL ||
(!mstorage->all_mailboxes && !_mail->box->inbox_user)) {
/* assigns UIDLs only for INBOX */
return;
}
ns = mail_namespace_find(_mail->box->storage->user->namespaces,
mstorage->pop3_box_vname);
if (ns == mailbox_get_namespace(_mail->box)) {
/* we're accessing the pop3-migration namespace itself */
return;
}
mmail = p_new(mail->pool, union mail_module_context, 1);
mmail->super = *v;
mail->vlast = &mmail->super;
v->get_special = pop3_migration_get_special;
MODULE_CONTEXT_SET_SELF(mail, pop3_migration_mail_module, mmail);
}
static struct mail_search_context *
pop3_migration_mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program,
enum mail_fetch_field wanted_fields,
struct mailbox_header_lookup_ctx *wanted_headers)
{
struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(t->box);
struct pop3_migration_mail_storage *mstorage =
POP3_MIGRATION_CONTEXT(t->box->storage);
if ((wanted_fields & (MAIL_FETCH_UIDL_BACKEND |
MAIL_FETCH_POP3_ORDER)) != 0 &&
(mstorage->all_mailboxes || t->box->inbox_user)) {
/* Start POP3 UIDL syncing before the search, so we'll do it
before we start sending any FETCH BODY[]s to IMAP. It
shouldn't matter much, except this works around a bug in
Yahoo IMAP where it sometimes breaks its state when doing
a FETCH BODY[] followed by FETCH BODY[HEADER].. */
(void)pop3_migration_uidl_sync_if_needed(t->box);
}
return mbox->module_ctx.super.search_init(t, args, sort_program,
wanted_fields, wanted_headers);
}
static void pop3_migration_mailbox_allocated(struct mailbox *box)
{
struct mailbox_vfuncs *v = box->vlast;
struct pop3_migration_mailbox *mbox;
mbox = p_new(box->pool, struct pop3_migration_mailbox, 1);
mbox->module_ctx.super = *v;
box->vlast = &mbox->module_ctx.super;
v->search_init = pop3_migration_mailbox_search_init;
MODULE_CONTEXT_SET(box, pop3_migration_storage_module, mbox);
}
static void pop3_migration_mail_storage_destroy(struct mail_storage *storage)
{
struct pop3_migration_mail_storage *mstorage =
POP3_MIGRATION_CONTEXT(storage);
if (array_is_created(&mstorage->pop3_uidl_map))
array_free(&mstorage->pop3_uidl_map);
mstorage->module_ctx.super.destroy(storage);
}
static void pop3_migration_mail_storage_created(struct mail_storage *storage)
{
struct pop3_migration_mail_storage *mstorage;
struct mail_storage_vfuncs *v = storage->vlast;
const char *pop3_box_vname;
pop3_box_vname = mail_user_plugin_getenv(storage->user,
"pop3_migration_mailbox");
if (pop3_box_vname == NULL) {
if (storage->user->mail_debug)
i_debug("pop3_migration: No pop3_migration_mailbox setting - disabled");
return;
}
mstorage = p_new(storage->pool, struct pop3_migration_mail_storage, 1);
mstorage->module_ctx.super = *v;
storage->vlast = &mstorage->module_ctx.super;
v->destroy = pop3_migration_mail_storage_destroy;
mstorage->pop3_box_vname = p_strdup(storage->pool, pop3_box_vname);
mstorage->all_mailboxes =
mail_user_plugin_getenv(storage->user,
"pop3_migration_all_mailboxes") != NULL;
mstorage->ignore_missing_uidls =
mail_user_plugin_getenv(storage->user,
"pop3_migration_ignore_missing_uidls") != NULL;
mstorage->skip_size_check =
mail_user_plugin_getenv(storage->user,
"pop3_migration_skip_size_check") != NULL;
MODULE_CONTEXT_SET(storage, pop3_migration_storage_module, mstorage);
}
static struct mail_storage_hooks pop3_migration_mail_storage_hooks = {
.mail_allocated = pop3_migration_mail_allocated,
.mailbox_allocated = pop3_migration_mailbox_allocated,
.mail_storage_created = pop3_migration_mail_storage_created
};
void pop3_migration_plugin_init(struct module *module)
{
mail_storage_hooks_add(module, &pop3_migration_mail_storage_hooks);
}
void pop3_migration_plugin_deinit(void)
{
mail_storage_hooks_remove(&pop3_migration_mail_storage_hooks);
}