dsync-mail.c revision d9b9687bf8cae9cfb070b1b7aadefa683220269f
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 "hex-binary.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "md5.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "istream.h"
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen#include "istream-crlf.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "message-size.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-storage.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-mail.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen/* These should be good enough to identify all normal mails. Received: header
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen would make it even better, but those can be somewhat large. Also these
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen fields can be looked up using IMAP ENVELOPE, which is more efficient in
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen some IMAP servers. */
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainenstatic const char *hashed_headers[] = {
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen "Date", "Message-ID", NULL
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen};
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint dsync_mail_get_hdr_hash(struct mail *mail, const char **hdr_hash_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen struct istream *hdr_input, *input;
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen struct mailbox_header_lookup_ctx *hdr_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct md5_context md5_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char md5_result[MD5_RESULTLEN];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const unsigned char *data;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen size_t size;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret = 0;
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen hdr_ctx = mailbox_header_lookup_init(mail->box, hashed_headers);
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen ret = mail_get_header_stream(mail, hdr_ctx, &hdr_input);
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen mailbox_header_lookup_unref(&hdr_ctx);
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen if (ret < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen input = i_stream_create_lf(hdr_input);
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen md5_init(&md5_ctx);
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen while (!i_stream_is_eof(input)) {
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen if (i_stream_read_data(input, &data, &size, 0) == -1)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (size == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen md5_update(&md5_ctx, data, size);
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen i_stream_skip(input, size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
271ba0b2a103e8040021597a3922f27b40d5b5dcTimo Sirainen if (input->stream_errno != 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
ccaaf1874bb0c569ca2589444717fde155e1becaTimo Sirainen i_stream_unref(&input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen md5_final(&md5_ctx, md5_result);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *hdr_hash_r = binary_to_hex(md5_result, sizeof(md5_result));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainenint dsync_mail_fill(struct mail *mail, struct dsync_mail *dmail_r,
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen const char **error_field_r)
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen{
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen const char *guid, *str;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen memset(dmail_r, 0, sizeof(*dmail_r));
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0) {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen *error_field_r = "GUID";
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return -1;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen dmail_r->guid = guid;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen dmail_r->uid = mail->uid;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen dmail_r->input_mail = mail;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen dmail_r->input_mail_uid = mail->uid;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (mail_get_stream(mail, NULL, NULL, &dmail_r->input) < 0) {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen *error_field_r = "body";
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return -1;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &dmail_r->pop3_uidl) < 0) {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen *error_field_r = "pop3-uidl";
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return -1;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0) {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen *error_field_r = "pop3-order";
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return -1;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (*str != '\0') {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (str_to_uint(str, &dmail_r->pop3_order) < 0)
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen i_unreached();
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen if (mail_get_received_date(mail, &dmail_r->received_date) < 0) {
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen *error_field_r = "received-date";
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return -1;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen return 0;
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen}
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenconst_string_array_dup(pool_t pool, const ARRAY_TYPE(const_string) *src,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) *dest)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *strings, *str;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!array_is_created(src))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen strings = array_get(src, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (count == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(dest, pool, count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen str = p_strdup(pool, strings[i]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(dest, &str, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_mail_change_dup(pool_t pool, const struct dsync_mail_change *src,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *dest_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->type = src->type;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->uid = src->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (src->guid != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->guid = *src->guid == '\0' ? "" :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_strdup(pool, src->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->hdr_hash = p_strdup(pool, src->hdr_hash);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->modseq = src->modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen dest_r->pvt_modseq = src->pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->save_timestamp = src->save_timestamp;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->add_flags = src->add_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->remove_flags = src->remove_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->final_flags = src->final_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dest_r->keywords_reset = src->keywords_reset;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const_string_array_dup(pool, &src->keyword_changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &dest_r->keyword_changes);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}