1 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "str.h"
6 #include "mail-copy.h"
7 #include "mail-user.h"
8 #include "mailbox-list-private.h"
9 #include "index-mail.h"
10 #include "pop3c-client.h"
11 #include "pop3c-sync.h"
12 #include "pop3c-storage.h"
13 
14 #define DNS_CLIENT_SOCKET_NAME "dns-client"
15 
16 extern struct mail_storage pop3c_storage;
17 extern struct mailbox pop3c_mailbox;
18 
19 static struct event_category event_category_pop3c = {
20 	.name = "pop3c",
21 	.parent = &event_category_storage,
22 };
23 
pop3c_storage_alloc(void)24 static struct mail_storage *pop3c_storage_alloc(void)
25 {
26 	struct pop3c_storage *storage;
27 	pool_t pool;
28 
29 	pool = pool_alloconly_create("pop3c storage", 512+256);
30 	storage = p_new(pool, struct pop3c_storage, 1);
31 	storage->storage = pop3c_storage;
32 	storage->storage.pool = pool;
33 	return &storage->storage;
34 }
35 
36 static int
pop3c_storage_create(struct mail_storage * _storage,struct mail_namespace * ns,const char ** error_r)37 pop3c_storage_create(struct mail_storage *_storage,
38 		     struct mail_namespace *ns,
39 		     const char **error_r)
40 {
41 	struct pop3c_storage *storage = POP3C_STORAGE(_storage);
42 
43 	storage->set = mail_namespace_get_driver_settings(ns, _storage);
44 	if (storage->set->pop3c_host[0] == '\0') {
45 		*error_r = "missing pop3c_host";
46 		return -1;
47 	}
48 	if (storage->set->pop3c_password[0] == '\0') {
49 		*error_r = "missing pop3c_password";
50 		return -1;
51 	}
52 
53 	return 0;
54 }
55 
56 static struct pop3c_client *
pop3c_client_create_from_set(struct mail_storage * storage,const struct pop3c_settings * set)57 pop3c_client_create_from_set(struct mail_storage *storage,
58 			     const struct pop3c_settings *set)
59 {
60 	struct pop3c_client_settings client_set;
61 	string_t *str;
62 
63 	i_zero(&client_set);
64 	client_set.host = set->pop3c_host;
65 	client_set.port = set->pop3c_port;
66 	client_set.username = set->pop3c_user;
67 	client_set.master_user = set->pop3c_master_user;
68 	client_set.password = set->pop3c_password;
69 	client_set.dns_client_socket_path =
70 		storage->user->set->base_dir[0] == '\0' ? "" :
71 		t_strconcat(storage->user->set->base_dir, "/",
72 			    DNS_CLIENT_SOCKET_NAME, NULL);
73 	str = t_str_new(128);
74 	mail_user_set_get_temp_prefix(str, storage->user->set);
75 	client_set.temp_path_prefix = str_c(str);
76 
77 	client_set.debug = storage->user->mail_debug;
78 	client_set.rawlog_dir =
79 		mail_user_home_expand(storage->user, set->pop3c_rawlog_dir);
80 
81 	mail_user_init_ssl_client_settings(storage->user, &client_set.ssl_set);
82 
83 	if (!set->pop3c_ssl_verify)
84 		client_set.ssl_set.allow_invalid_cert = TRUE;
85 
86 	if (strcmp(set->pop3c_ssl, "pop3s") == 0)
87 		client_set.ssl_mode = POP3C_CLIENT_SSL_MODE_IMMEDIATE;
88 	else if (strcmp(set->pop3c_ssl, "starttls") == 0)
89 		client_set.ssl_mode = POP3C_CLIENT_SSL_MODE_STARTTLS;
90 	else
91 		client_set.ssl_mode = POP3C_CLIENT_SSL_MODE_NONE;
92 	return pop3c_client_init(&client_set, storage->event);
93 }
94 
95 static void
pop3c_storage_get_list_settings(const struct mail_namespace * ns ATTR_UNUSED,struct mailbox_list_settings * set)96 pop3c_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
97 				struct mailbox_list_settings *set)
98 {
99 	set->layout = MAILBOX_LIST_NAME_FS;
100 	if (set->root_dir != NULL && *set->root_dir != '\0' &&
101 	    set->index_dir == NULL) {
102 	       /* we don't really care about root_dir, but we
103 		  just need to get index_dir autocreated. */
104 		set->index_dir = set->root_dir;
105 	}
106 }
107 
108 static struct mailbox *
pop3c_mailbox_alloc(struct mail_storage * storage,struct mailbox_list * list,const char * vname,enum mailbox_flags flags)109 pop3c_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
110 		    const char *vname, enum mailbox_flags flags)
111 {
112 	struct pop3c_mailbox *mbox;
113 	pool_t pool;
114 
115 	pool = pool_alloconly_create("pop3c mailbox", 1024*3);
116 	mbox = p_new(pool, struct pop3c_mailbox, 1);
117 	mbox->box = pop3c_mailbox;
118 	mbox->box.pool = pool;
119 	mbox->box.storage = storage;
120 	mbox->box.list = list;
121 	mbox->box.list->props |= MAILBOX_LIST_PROP_AUTOCREATE_DIRS;
122 	mbox->box.mail_vfuncs = &pop3c_mail_vfuncs;
123 	mbox->storage = POP3C_STORAGE(storage);
124 
125 	index_storage_mailbox_alloc(&mbox->box, vname, flags, MAIL_INDEX_PREFIX);
126 	return &mbox->box;
127 }
128 
129 static int
pop3c_mailbox_exists(struct mailbox * box,bool auto_boxes,enum mailbox_existence * existence_r)130 pop3c_mailbox_exists(struct mailbox *box, bool auto_boxes,
131 		     enum mailbox_existence *existence_r)
132 {
133 	if ((auto_boxes && mailbox_is_autocreated(box)) || box->inbox_any)
134 		*existence_r = MAILBOX_EXISTENCE_SELECT;
135 	else
136 		*existence_r = MAILBOX_EXISTENCE_NONE;
137 	return 0;
138 }
139 
pop3c_login_callback(enum pop3c_command_state state,const char * reply,void * context)140 static void pop3c_login_callback(enum pop3c_command_state state,
141 				 const char *reply, void *context)
142 {
143 	struct pop3c_mailbox *mbox = context;
144 
145 	switch (state) {
146 	case POP3C_COMMAND_STATE_OK:
147 		mbox->logged_in = TRUE;
148 		break;
149 	case POP3C_COMMAND_STATE_ERR:
150 		if (str_begins(reply, "[IN-USE] ")) {
151 			mail_storage_set_error(mbox->box.storage,
152 					       MAIL_ERROR_INUSE, reply + 9);
153 		} else {
154 			/* authentication failure probably */
155 			mail_storage_set_error(mbox->box.storage,
156 					       MAIL_ERROR_PARAMS, reply);
157 		}
158 		break;
159 	case POP3C_COMMAND_STATE_DISCONNECTED:
160 		mailbox_set_critical(&mbox->box,
161 			"pop3c: Disconnected from remote server");
162 		break;
163 	}
164 }
165 
pop3c_mailbox_open(struct mailbox * box)166 static int pop3c_mailbox_open(struct mailbox *box)
167 {
168 	struct pop3c_mailbox *mbox = POP3C_MAILBOX(box);
169 
170 	if (strcmp(box->name, "INBOX") != 0) {
171 		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
172 				       T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
173 		return -1;
174 	}
175 
176 	if (index_storage_mailbox_open(box, FALSE) < 0)
177 		return -1;
178 
179 	mbox->client = pop3c_client_create_from_set(box->storage,
180 						    mbox->storage->set);
181 	pop3c_client_login(mbox->client, pop3c_login_callback, mbox);
182 	pop3c_client_wait_one(mbox->client);
183 	return mbox->logged_in ? 0 : -1;
184 }
185 
pop3c_mailbox_close(struct mailbox * box)186 static void pop3c_mailbox_close(struct mailbox *box)
187 {
188 	struct pop3c_mailbox *mbox = POP3C_MAILBOX(box);
189 
190 	pool_unref(&mbox->uidl_pool);
191 	i_free_and_null(mbox->msg_uids);
192 	i_free_and_null(mbox->msg_sizes);
193 	pop3c_client_deinit(&mbox->client);
194 	index_storage_mailbox_close(box);
195 }
196 
197 static int
pop3c_mailbox_create(struct mailbox * box,const struct mailbox_update * update ATTR_UNUSED,bool directory ATTR_UNUSED)198 pop3c_mailbox_create(struct mailbox *box,
199 		     const struct mailbox_update *update ATTR_UNUSED,
200 		     bool directory ATTR_UNUSED)
201 {
202 	mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
203 			       "POP3 mailbox creation isn't supported");
204 	return -1;
205 }
206 
207 static int
pop3c_mailbox_update(struct mailbox * box,const struct mailbox_update * update ATTR_UNUSED)208 pop3c_mailbox_update(struct mailbox *box,
209 		     const struct mailbox_update *update ATTR_UNUSED)
210 {
211 	if (!guid_128_is_empty(update->mailbox_guid) ||
212 	    update->uid_validity != 0 || update->min_next_uid != 0 ||
213 	    update->min_first_recent_uid != 0) {
214 		mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
215 				       "POP3 mailbox update isn't supported");
216 	}
217 	return index_storage_mailbox_update(box, update);
218 }
219 
pop3c_mailbox_get_status(struct mailbox * box,enum mailbox_status_items items,struct mailbox_status * status_r)220 static int pop3c_mailbox_get_status(struct mailbox *box,
221 				    enum mailbox_status_items items,
222 				    struct mailbox_status *status_r)
223 {
224 	struct pop3c_mailbox *mbox = POP3C_MAILBOX(box);
225 
226 	if (index_storage_get_status(box, items, status_r) < 0)
227 		return -1;
228 
229 	if ((pop3c_client_get_capabilities(mbox->client) &
230 	     POP3C_CAPABILITY_UIDL) == 0)
231 		status_r->have_guids = FALSE;
232 	return 0;
233 }
234 
pop3c_mailbox_get_metadata(struct mailbox * box,enum mailbox_metadata_items items,struct mailbox_metadata * metadata_r)235 static int pop3c_mailbox_get_metadata(struct mailbox *box,
236 				      enum mailbox_metadata_items items,
237 				      struct mailbox_metadata *metadata_r)
238 {
239 	if ((items & MAILBOX_METADATA_GUID) != 0) {
240 		/* a bit ugly way to do this, but better than nothing for now.
241 		   FIXME: if indexes are enabled, keep this there. */
242 		mail_generate_guid_128_hash(box->name, metadata_r->guid);
243 		items &= ENUM_NEGATE(MAILBOX_METADATA_GUID);
244 	}
245 	if (items != 0) {
246 		if (index_mailbox_get_metadata(box, items, metadata_r) < 0)
247 			return -1;
248 	}
249 	return 0;
250 }
251 
pop3c_notify_changes(struct mailbox * box ATTR_UNUSED)252 static void pop3c_notify_changes(struct mailbox *box ATTR_UNUSED)
253 {
254 }
255 
256 static struct mail_save_context *
pop3c_save_alloc(struct mailbox_transaction_context * t)257 pop3c_save_alloc(struct mailbox_transaction_context *t)
258 {
259 	struct mail_save_context *ctx;
260 
261 	ctx = i_new(struct mail_save_context, 1);
262 	ctx->transaction = t;
263 	return ctx;
264 }
265 
266 static int
pop3c_save_begin(struct mail_save_context * ctx,struct istream * input ATTR_UNUSED)267 pop3c_save_begin(struct mail_save_context *ctx,
268 		 struct istream *input ATTR_UNUSED)
269 {
270 	mail_storage_set_error(ctx->transaction->box->storage,
271 		MAIL_ERROR_NOTPOSSIBLE, "POP3 doesn't support saving mails");
272 	return -1;
273 }
274 
pop3c_save_continue(struct mail_save_context * ctx ATTR_UNUSED)275 static int pop3c_save_continue(struct mail_save_context *ctx ATTR_UNUSED)
276 {
277 	return -1;
278 }
279 
pop3c_save_finish(struct mail_save_context * ctx)280 static int pop3c_save_finish(struct mail_save_context *ctx)
281 {
282 	index_save_context_free(ctx);
283 	return -1;
284 }
285 
286 static void
pop3c_save_cancel(struct mail_save_context * ctx)287 pop3c_save_cancel(struct mail_save_context *ctx)
288 {
289 	index_save_context_free(ctx);
290 }
291 
pop3c_storage_is_inconsistent(struct mailbox * box)292 static bool pop3c_storage_is_inconsistent(struct mailbox *box)
293 {
294 	struct pop3c_mailbox *mbox = POP3C_MAILBOX(box);
295 
296 	return index_storage_is_inconsistent(box) ||
297 		!pop3c_client_is_connected(mbox->client);
298 }
299 
300 struct mail_storage pop3c_storage = {
301 	.name = POP3C_STORAGE_NAME,
302 	.class_flags = MAIL_STORAGE_CLASS_FLAG_NO_ROOT |
303 		MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS,
304 	.event_category = &event_category_pop3c,
305 
306 	.v = {
307 		pop3c_get_setting_parser_info,
308 		pop3c_storage_alloc,
309 		pop3c_storage_create,
310 		index_storage_destroy,
311 		NULL,
312 		pop3c_storage_get_list_settings,
313 		NULL,
314 		pop3c_mailbox_alloc,
315 		NULL,
316 		NULL,
317 	}
318 };
319 
320 struct mailbox pop3c_mailbox = {
321 	.v = {
322 		index_storage_is_readonly,
323 		index_storage_mailbox_enable,
324 		pop3c_mailbox_exists,
325 		pop3c_mailbox_open,
326 		pop3c_mailbox_close,
327 		index_storage_mailbox_free,
328 		pop3c_mailbox_create,
329 		pop3c_mailbox_update,
330 		index_storage_mailbox_delete,
331 		index_storage_mailbox_rename,
332 		pop3c_mailbox_get_status,
333 		pop3c_mailbox_get_metadata,
334 		index_storage_set_subscribed,
335 		index_storage_attribute_set,
336 		index_storage_attribute_get,
337 		index_storage_attribute_iter_init,
338 		index_storage_attribute_iter_next,
339 		index_storage_attribute_iter_deinit,
340 		index_storage_list_index_has_changed,
341 		index_storage_list_index_update_sync,
342 		pop3c_storage_sync_init,
343 		index_mailbox_sync_next,
344 		index_mailbox_sync_deinit,
345 		NULL,
346 		pop3c_notify_changes,
347 		index_transaction_begin,
348 		index_transaction_commit,
349 		index_transaction_rollback,
350 		NULL,
351 		pop3c_mail_alloc,
352 		index_storage_search_init,
353 		index_storage_search_deinit,
354 		index_storage_search_next_nonblock,
355 		index_storage_search_next_update_seq,
356 		pop3c_save_alloc,
357 		pop3c_save_begin,
358 		pop3c_save_continue,
359 		pop3c_save_finish,
360 		pop3c_save_cancel,
361 		mail_storage_copy,
362 		NULL,
363 		NULL,
364 		NULL,
365 		pop3c_storage_is_inconsistent
366 	}
367 };
368