pop3-migration-plugin.c revision 615b4468c088b674aad109c9420d7d5c14eebf43
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MODULE_CONTEXT(obj, pop3_migration_storage_module)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MODULE_CONTEXT_REQUIRE(obj, pop3_migration_storage_module)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MODULE_CONTEXT_REQUIRE(obj, pop3_migration_mail_module)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* sha1(header) - set only when needed */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* LIST size */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen/* NOTE: these headers must be sorted */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic const char *hdr_hash_skip_headers[] = {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "Content-Length",
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "Return-Path", /* Yahoo IMAP has Return-Path, Yahoo POP3 doesn't */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "X-IMAPbase",
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen "X-Keywords",
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen "X-Message-Flag",
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "X-Yahoo-Newman-Property"
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenconst char *pop3_migration_plugin_version = DOVECOT_ABI_VERSION;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(pop3_migration_storage_module,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(pop3_migration_mail_module,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int imap_msg_map_uid_cmp(const struct imap_msg_map *map1,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int pop3_uidl_map_pop3_seq_cmp(const struct pop3_uidl_map *map1,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int pop3_uidl_map_uidl_cmp(const struct pop3_uidl_map *map1,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return strcmp(map1->pop3_uidl, map2->pop3_uidl);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int imap_msg_map_uidl_cmp(const struct imap_msg_map *map1,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return null_strcmp(map1->pop3_uidl, map2->pop3_uidl);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int pop3_uidl_map_hdr_cmp(const struct pop3_uidl_map *map1,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return memcmp(map1->common.hdr_sha1, map2->common.hdr_sha1,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int imap_msg_map_hdr_cmp(const struct imap_msg_map *map1,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return memcmp(map1->common.hdr_sha1, map2->common.hdr_sha1,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic bool header_name_is_valid(const char *name)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen unsigned int i;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if ((uint8_t)name[i] <= 0x20 || name[i] >= 0x7f)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenstatic bool header_value_want_skip(const struct message_header_line *hdr)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (hdr->value[i] != ' ' && hdr->value[i] != '\t')
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* "header: \r\n \r\n" - Zimbra's BODY[HEADER] strips this line away. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenpop3_header_filter_callback(struct header_filter_istream *input ATTR_UNUSED,
a1808be0774cbcb28fec45341aabf803ec44bae5Timo Sirainen if (strspn(hdr->name, "\r") == hdr->name_len) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* CR+CR+LF - some servers stop the header processing
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen here while others don't. To make sure they can be
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen matched correctly we want to stop here entirely. */
c74ea62a27878910e3ca1614ca055d7e2b3b00d5Timo Sirainen } else if (!hdr->continued && hdr->middle_len == 0) {
c74ea62a27878910e3ca1614ca055d7e2b3b00d5Timo Sirainen /* not a valid "key: value" header -
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen Zimbra's BODY[HEADER] strips this line away. */
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen } else if (hdr->continued && header_value_want_skip(hdr)) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* Yahoo IMAP drops headers with invalid names, while
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen Yahoo POP3 preserves them. Drop them all. */
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainenint pop3_migration_get_hdr_sha1(uint32_t mail_seq, struct istream *input,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen unsigned char sha1_r[STATIC_ARRAY SHA1_RESULTLEN],
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const unsigned char *data;
185ed0142fbbfb86e7a98519e7c6f11ec00723cdTimo Sirainen /* hide headers that might change or be different in IMAP vs. POP3 */
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen input = i_stream_create_header_filter(input, HEADER_FILTER_HIDE_BODY |
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen while (i_stream_read_more(input, &data, &size) > 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen message_header_hash_more(&hash_ctx, &hash_method_sha1, &sha1_ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_error("pop3_migration: Failed to read header for msg %u: %s",
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic unsigned int get_cache_idx(struct mail *mail)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT_REQUIRE(mail->box);
const char *errstr;
bool have_eoh;
int ret;
if (have_eoh) {
if (ret == 0) {
if (!have_eoh)
return TRUE;
return FALSE;
return box;
struct mailbox_transaction_context *t;
const char *uidl;
int ret = 0;
(void)mailbox_transaction_commit(&t);
return ret;
struct mailbox_transaction_context *t;
int ret = 0;
if (ret > 0)
(void)mailbox_transaction_commit(&t);
unsigned first_seq)
first_seq) < 0)
const unsigned int uidl_cache_idx =
struct mailbox_transaction_context *t;
int ret = 0;
(void)mailbox_transaction_commit(&t);
return ret;
int ret;
if (ret >= 0)
if (ret == 0) {
for (i = 0; i < count; i++) {
uidl_match++;
size_match++;
int ret;
pop3_idx++;
imap_idx++;
if (ret < 0)
pop3_idx++;
else if (ret > 0)
imap_idx++;
missing_uids_count = 0;
if (all_imap_mails_found)
struct mailbox_transaction_context *t;
unsigned int i, count;
unsigned int field_idx;
for (i = 0; i < count; i++) {
i_unreached();
(void)mailbox_transaction_commit(&t);
const char **value_r)
static struct mail_search_context *
MAIL_FETCH_POP3_ORDER)) != 0 &&
const char *pop3_box_vname;
void pop3_migration_plugin_deinit(void)