1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "hex-binary.h"
6 #include "md5.h"
7 #include "istream.h"
8 #include "istream-crlf.h"
9 #include "message-header-hash.h"
10 #include "message-size.h"
11 #include "mail-storage.h"
12 #include "dsync-mail.h"
13 
14 struct mailbox_header_lookup_ctx *
dsync_mail_get_hash_headers(struct mailbox * box,const char * const * hashed_headers)15 dsync_mail_get_hash_headers(struct mailbox *box, const char *const *hashed_headers)
16 {
17 	return mailbox_header_lookup_init(box, hashed_headers);
18 }
19 
dsync_mail_get_hdr_hash(struct mail * mail,unsigned int version,const char * const * hashed_headers,const char ** hdr_hash_r)20 int dsync_mail_get_hdr_hash(struct mail *mail, unsigned int version,
21 			    const char *const *hashed_headers, const char **hdr_hash_r)
22 {
23 	struct istream *hdr_input, *input;
24 	struct mailbox_header_lookup_ctx *hdr_ctx;
25 	struct message_header_hash_context hash_ctx;
26 	struct md5_context md5_ctx;
27 	unsigned char md5_result[MD5_RESULTLEN];
28 	const unsigned char *data;
29 	size_t size;
30 	ssize_t sret;
31 	int ret = 0;
32 
33 	hdr_ctx = mailbox_header_lookup_init(mail->box, hashed_headers);
34 	ret = mail_get_header_stream(mail, hdr_ctx, &hdr_input);
35 	mailbox_header_lookup_unref(&hdr_ctx);
36 	if (ret < 0)
37 		return -1;
38 
39 	input = i_stream_create_lf(hdr_input);
40 
41 	md5_init(&md5_ctx);
42 	i_zero(&hash_ctx);
43 	while ((sret = i_stream_read_more(input, &data, &size)) > 0) {
44 		message_header_hash_more(&hash_ctx, &hash_method_md5, &md5_ctx,
45 					 version, data, size);
46 		i_stream_skip(input, size);
47 	}
48 	i_assert(sret == -1);
49 	if (input->stream_errno != 0)
50 		ret = -1;
51 	i_stream_unref(&input);
52 
53 	md5_final(&md5_ctx, md5_result);
54 	*hdr_hash_r = binary_to_hex(md5_result, sizeof(md5_result));
55 	return ret;
56 }
57 
dsync_mail_fill(struct mail * mail,bool minimal_fill,struct dsync_mail * dmail_r,const char ** error_field_r)58 int dsync_mail_fill(struct mail *mail, bool minimal_fill,
59 		    struct dsync_mail *dmail_r, const char **error_field_r)
60 {
61 	const char *guid;
62 
63 	i_zero(dmail_r);
64 
65 	if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0) {
66 		*error_field_r = "GUID";
67 		return -1;
68 	}
69 	dmail_r->guid = guid;
70 	dmail_r->uid = mail->uid;
71 
72 	dmail_r->input_mail = mail;
73 	dmail_r->input_mail_uid = mail->uid;
74 
75 	if (mail_get_save_date(mail, &dmail_r->saved_date) < 0) {
76 		*error_field_r = "saved-date";
77 		return -1;
78 	}
79 	if (!minimal_fill)
80 		return dsync_mail_fill_nonminimal(mail, dmail_r, error_field_r);
81 	dmail_r->minimal_fields = TRUE;
82 	return 0;
83 }
84 
dsync_mail_fill_nonminimal(struct mail * mail,struct dsync_mail * dmail_r,const char ** error_field_r)85 int dsync_mail_fill_nonminimal(struct mail *mail, struct dsync_mail *dmail_r,
86 			       const char **error_field_r)
87 {
88 	const char *str;
89 
90 	if (mail_get_stream(mail, NULL, NULL, &dmail_r->input) < 0) {
91 		*error_field_r = "body";
92 		return -1;
93 	}
94 
95 	if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &dmail_r->pop3_uidl) < 0) {
96 		*error_field_r = "pop3-uidl";
97 		return -1;
98 	}
99 	if (mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str) < 0) {
100 		*error_field_r = "pop3-order";
101 		return -1;
102 	}
103 	if (*str != '\0') {
104 		if (str_to_uint32(str, &dmail_r->pop3_order) < 0)
105 			i_unreached();
106 	}
107 	if (mail_get_received_date(mail, &dmail_r->received_date) < 0) {
108 		*error_field_r = "received-date";
109 		return -1;
110 	}
111 	return 0;
112 }
113 
114 static void
const_string_array_dup(pool_t pool,const ARRAY_TYPE (const_string)* src,ARRAY_TYPE (const_string)* dest)115 const_string_array_dup(pool_t pool, const ARRAY_TYPE(const_string) *src,
116 		       ARRAY_TYPE(const_string) *dest)
117 {
118 	const char *const *strings, *str;
119 	unsigned int i, count;
120 
121 	if (!array_is_created(src))
122 		return;
123 
124 	strings = array_get(src, &count);
125 	if (count == 0)
126 		return;
127 
128 	p_array_init(dest, pool, count);
129 	for (i = 0; i < count; i++) {
130 		str = p_strdup(pool, strings[i]);
131 		array_push_back(dest, &str);
132 	}
133 }
134 
dsync_mail_change_dup(pool_t pool,const struct dsync_mail_change * src,struct dsync_mail_change * dest_r)135 void dsync_mail_change_dup(pool_t pool, const struct dsync_mail_change *src,
136 			   struct dsync_mail_change *dest_r)
137 {
138 	dest_r->type = src->type;
139 	dest_r->uid = src->uid;
140 	if (src->guid != NULL) {
141 		dest_r->guid = *src->guid == '\0' ? "" :
142 			p_strdup(pool, src->guid);
143 	}
144 	dest_r->hdr_hash = p_strdup(pool, src->hdr_hash);
145 	dest_r->modseq = src->modseq;
146 	dest_r->pvt_modseq = src->pvt_modseq;
147 
148 	dest_r->add_flags = src->add_flags;
149 	dest_r->remove_flags = src->remove_flags;
150 	dest_r->final_flags = src->final_flags;
151 	dest_r->keywords_reset = src->keywords_reset;
152 	const_string_array_dup(pool, &src->keyword_changes,
153 			       &dest_r->keyword_changes);
154 	dest_r->received_timestamp = src->received_timestamp;
155 	dest_r->virtual_size = src->virtual_size;
156 }
157