1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		Srinivasa Ragavan <sragavan@gnome.org>
17  *
18  *
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <time.h>
27 
28 #include <glib/gstdio.h>
29 
30 #ifdef G_OS_WIN32
31 /* Work around namespace clobbage in <windows.h> */
32 #define DATADIR windows_DATADIR
33 #include <windows.h>
34 #undef DATADIR
35 #undef interface
36 #endif
37 
38 #include <glib/gi18n.h>
39 #include <libebook/libebook.h>
40 #include <libedataserver/libedataserver.h>
41 
42 #include <libemail-engine/mail-mt.h>
43 
44 #include "e-mail-folder-utils.h"
45 #include "e-mail-session.h"
46 #include "e-mail-utils.h"
47 #include "mail-tools.h"
48 
49 #define d(x)
50 
51 static gboolean
e_mail_utils_folder_uri_is_drafts(ESourceRegistry * registry,CamelSession * session,const gchar * folder_uri)52 e_mail_utils_folder_uri_is_drafts (ESourceRegistry *registry,
53 				   CamelSession *session,
54 				   const gchar *folder_uri)
55 {
56 	GList *sources, *link;
57 	gboolean is_drafts = FALSE;
58 
59 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
60 	g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE);
61 	g_return_val_if_fail (folder_uri != NULL, FALSE);
62 
63 	sources = e_source_registry_list_sources (registry, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
64 
65 	for (link = sources; link; link = g_list_next (link)) {
66 		ESource *source = E_SOURCE (link->data);
67 		ESourceMailComposition *extension;
68 		const gchar *drafts_folder_uri;
69 
70 		extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
71 
72 		drafts_folder_uri = e_source_mail_composition_get_drafts_folder (extension);
73 
74 		if (drafts_folder_uri != NULL)
75 			is_drafts = e_mail_folder_uri_equal (session, folder_uri, drafts_folder_uri);
76 
77 		if (is_drafts)
78 			break;
79 	}
80 
81 	g_list_free_full (sources, g_object_unref);
82 
83 	return is_drafts;
84 }
85 
86 /**
87  * em_utils_folder_is_drafts:
88  * @registry: an #ESourceRegistry
89  * @folder: a #CamelFolder
90  *
91  * Decides if @folder is a Drafts folder.
92  *
93  * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
94  **/
95 gboolean
em_utils_folder_is_drafts(ESourceRegistry * registry,CamelFolder * folder)96 em_utils_folder_is_drafts (ESourceRegistry *registry,
97                            CamelFolder *folder)
98 {
99 	CamelFolder *local_drafts_folder;
100 	CamelSession *session;
101 	CamelStore *store;
102 	gchar *folder_uri;
103 	gboolean is_drafts = FALSE;
104 
105 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
106 
107 	store = camel_folder_get_parent_store (folder);
108 	session = camel_service_ref_session (CAMEL_SERVICE (store));
109 
110 	local_drafts_folder =
111 		e_mail_session_get_local_folder (
112 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS);
113 
114 	if (folder == local_drafts_folder) {
115 		is_drafts = TRUE;
116 		goto exit;
117 	}
118 
119 	folder_uri = e_mail_folder_uri_from_folder (folder);
120 
121 	is_drafts = e_mail_utils_folder_uri_is_drafts (registry, session, folder_uri);
122 
123 	g_free (folder_uri);
124 
125 exit:
126 	g_object_unref (session);
127 
128 	return is_drafts;
129 }
130 
131 /**
132  * em_utils_folder_name_is_drafts:
133  * @registry: an #ESourceRegistry
134  * @store: a #CamelStore
135  * @folder_name: a folder name
136  *
137  * Decides if @folder_name of the @store is a Drafts folder.
138  *
139  * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
140  *
141  * Since: 3.24
142  **/
143 gboolean
em_utils_folder_name_is_drafts(ESourceRegistry * registry,CamelStore * store,const gchar * folder_name)144 em_utils_folder_name_is_drafts (ESourceRegistry *registry,
145 				CamelStore *store,
146 				const gchar *folder_name)
147 {
148 	CamelSession *session;
149 	CamelFolder *local_drafts_folder;
150 	gchar *folder_uri, *local_drafts_uri;
151 	gboolean is_drafts;
152 
153 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
154 	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
155 	g_return_val_if_fail (folder_name != NULL, FALSE);
156 
157 	folder_uri = e_mail_folder_uri_build (store, folder_name);
158 	g_return_val_if_fail (folder_uri != NULL, FALSE);
159 
160 	session = camel_service_ref_session (CAMEL_SERVICE (store));
161 
162 	local_drafts_folder =
163 		e_mail_session_get_local_folder (
164 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS);
165 
166 	local_drafts_uri = e_mail_folder_uri_from_folder (local_drafts_folder);
167 
168 	is_drafts = g_strcmp0 (local_drafts_uri, folder_uri) == 0 ||
169 		e_mail_utils_folder_uri_is_drafts (registry, session, folder_uri);
170 
171 	g_clear_object (&session);
172 	g_free (local_drafts_uri);
173 	g_free (folder_uri);
174 
175 	return is_drafts;
176 }
177 
178 /**
179  * em_utils_folder_is_templates:
180  * @registry: an #ESourceRegistry
181  * @folder: a #CamelFolder
182  *
183  * Decides if @folder is a Templates folder.
184  *
185  * Returns %TRUE if this is a Templates folder or %FALSE otherwise.
186  **/
187 
188 gboolean
em_utils_folder_is_templates(ESourceRegistry * registry,CamelFolder * folder)189 em_utils_folder_is_templates (ESourceRegistry *registry,
190                               CamelFolder *folder)
191 {
192 	CamelFolder *local_templates_folder;
193 	CamelSession *session;
194 	CamelStore *store;
195 	GList *list, *iter;
196 	gchar *folder_uri;
197 	gboolean is_templates = FALSE;
198 	const gchar *extension_name;
199 
200 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
201 
202 	store = camel_folder_get_parent_store (folder);
203 	session = camel_service_ref_session (CAMEL_SERVICE (store));
204 
205 	local_templates_folder =
206 		e_mail_session_get_local_folder (
207 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES);
208 
209 	if (folder == local_templates_folder) {
210 		is_templates = TRUE;
211 		goto exit;
212 	}
213 
214 	folder_uri = e_mail_folder_uri_from_folder (folder);
215 
216 	extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
217 	list = e_source_registry_list_sources (registry, extension_name);
218 
219 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
220 		ESource *source = E_SOURCE (iter->data);
221 		ESourceExtension *extension;
222 		const gchar *templates_folder_uri;
223 
224 		extension = e_source_get_extension (source, extension_name);
225 
226 		templates_folder_uri =
227 			e_source_mail_composition_get_templates_folder (
228 			E_SOURCE_MAIL_COMPOSITION (extension));
229 
230 		if (templates_folder_uri != NULL)
231 			is_templates = e_mail_folder_uri_equal (
232 				session, folder_uri, templates_folder_uri);
233 
234 		if (is_templates)
235 			break;
236 	}
237 
238 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
239 	g_free (folder_uri);
240 
241 exit:
242 	g_object_unref (session);
243 
244 	return is_templates;
245 }
246 
247 /**
248  * em_utils_folder_is_sent:
249  * @registry: an #ESourceRegistry
250  * @folder: a #CamelFolder
251  *
252  * Decides if @folder is a Sent folder.
253  *
254  * Returns %TRUE if this is a Sent folder or %FALSE otherwise.
255  **/
256 gboolean
em_utils_folder_is_sent(ESourceRegistry * registry,CamelFolder * folder)257 em_utils_folder_is_sent (ESourceRegistry *registry,
258                          CamelFolder *folder)
259 {
260 	CamelFolder *local_sent_folder;
261 	CamelSession *session;
262 	CamelStore *store;
263 	GList *list, *iter;
264 	gchar *folder_uri;
265 	gboolean is_sent = FALSE;
266 	const gchar *extension_name;
267 
268 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
269 
270 	store = camel_folder_get_parent_store (folder);
271 	session = camel_service_ref_session (CAMEL_SERVICE (store));
272 
273 	local_sent_folder =
274 		e_mail_session_get_local_folder (
275 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT);
276 
277 	if (folder == local_sent_folder) {
278 		is_sent = TRUE;
279 		goto exit;
280 	}
281 
282 	folder_uri = e_mail_folder_uri_from_folder (folder);
283 
284 	extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
285 	list = e_source_registry_list_sources (registry, extension_name);
286 
287 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
288 		ESource *source = E_SOURCE (iter->data);
289 		ESourceMailSubmission *extension;
290 		const gchar *sent_folder_uri;
291 
292 		extension = e_source_get_extension (source, extension_name);
293 
294 		if (!e_source_mail_submission_get_use_sent_folder (extension))
295 			continue;
296 
297 		sent_folder_uri = e_source_mail_submission_get_sent_folder (extension);
298 
299 		if (sent_folder_uri != NULL)
300 			is_sent = e_mail_folder_uri_equal (
301 				session, folder_uri, sent_folder_uri);
302 
303 		if (is_sent)
304 			break;
305 	}
306 
307 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
308 	g_free (folder_uri);
309 
310 exit:
311 	g_object_unref (session);
312 
313 	return is_sent;
314 }
315 
316 /**
317  * em_utils_folder_is_outbox:
318  * @registry: an #ESourceRegistry
319  * @folder: a #CamelFolder
320  *
321  * Decides if @folder is an Outbox folder.
322  *
323  * Returns %TRUE if this is an Outbox folder or %FALSE otherwise.
324  **/
325 gboolean
em_utils_folder_is_outbox(ESourceRegistry * registry,CamelFolder * folder)326 em_utils_folder_is_outbox (ESourceRegistry *registry,
327                            CamelFolder *folder)
328 {
329 	CamelStore *store;
330 	CamelSession *session;
331 	CamelFolder *local_outbox_folder;
332 	gboolean is_outbox;
333 
334 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
335 
336 	store = camel_folder_get_parent_store (folder);
337 	session = camel_service_ref_session (CAMEL_SERVICE (store));
338 
339 	local_outbox_folder =
340 		e_mail_session_get_local_folder (
341 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX);
342 
343 	is_outbox = (folder == local_outbox_folder);
344 
345 	g_object_unref (session);
346 
347 	return is_outbox;
348 }
349 
350 static ESource *
guess_mail_account_from_folder(ESourceRegistry * registry,CamelFolder * folder,const gchar * message_uid)351 guess_mail_account_from_folder (ESourceRegistry *registry,
352                                 CamelFolder *folder,
353                                 const gchar *message_uid)
354 {
355 	ESource *source;
356 	CamelStore *store;
357 	const gchar *uid;
358 
359 	/* Lookup an ESource by CamelStore UID. */
360 	store = camel_folder_get_parent_store (folder);
361 	if (message_uid && folder && CAMEL_IS_VEE_STORE (store)) {
362 		CamelMessageInfo *mi = camel_folder_get_message_info (folder, message_uid);
363 		if (mi) {
364 			CamelFolder *location;
365 
366 			location = camel_vee_folder_get_location (CAMEL_VEE_FOLDER (folder), (CamelVeeMessageInfo *) mi, NULL);
367 			if (location)
368 				store = camel_folder_get_parent_store (location);
369 			g_clear_object (&mi);
370 		}
371 	}
372 
373 	uid = camel_service_get_uid (CAMEL_SERVICE (store));
374 	source = e_source_registry_ref_source (registry, uid);
375 
376 	/* If we found an ESource, make sure it's a mail account. */
377 	if (source != NULL) {
378 		const gchar *extension_name;
379 
380 		extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
381 		if (!e_source_has_extension (source, extension_name)) {
382 			g_object_unref (source);
383 			source = NULL;
384 		}
385 	}
386 
387 	return source;
388 }
389 
390 static ESource *
guess_mail_account_from_message(ESourceRegistry * registry,CamelMimeMessage * message)391 guess_mail_account_from_message (ESourceRegistry *registry,
392                                  CamelMimeMessage *message)
393 {
394 	ESource *source = NULL;
395 	const gchar *uid;
396 
397 	/* Lookup an ESource by 'X-Evolution-Source' header. */
398 	uid = camel_mime_message_get_source (message);
399 	if (uid != NULL)
400 		source = e_source_registry_ref_source (registry, uid);
401 
402 	/* If we found an ESource, make sure it's a mail account. */
403 	if (source != NULL) {
404 		const gchar *extension_name;
405 
406 		extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
407 		if (!e_source_has_extension (source, extension_name)) {
408 			g_object_unref (source);
409 			source = NULL;
410 		}
411 	}
412 
413 	return source;
414 }
415 
416 ESource *
em_utils_guess_mail_account(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid)417 em_utils_guess_mail_account (ESourceRegistry *registry,
418                              CamelMimeMessage *message,
419                              CamelFolder *folder,
420                              const gchar *message_uid)
421 {
422 	ESource *source = NULL;
423 	const gchar *newsgroups;
424 
425 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
426 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
427 
428 	if (folder != NULL)
429 		g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
430 
431 	/* check for newsgroup header */
432 	newsgroups = camel_medium_get_header (
433 		CAMEL_MEDIUM (message), "Newsgroups");
434 	if (folder != NULL && newsgroups != NULL)
435 		source = guess_mail_account_from_folder (registry, folder, message_uid);
436 
437 	/* check for source folder */
438 	if (source == NULL && folder != NULL)
439 		source = guess_mail_account_from_folder (registry, folder, message_uid);
440 
441 	/* then message source */
442 	if (source == NULL)
443 		source = guess_mail_account_from_message (registry, message);
444 
445 	return source;
446 }
447 
448 ESource *
em_utils_guess_mail_identity(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid)449 em_utils_guess_mail_identity (ESourceRegistry *registry,
450                               CamelMimeMessage *message,
451                               CamelFolder *folder,
452                               const gchar *message_uid)
453 {
454 	ESource *source;
455 	ESourceExtension *extension;
456 	const gchar *extension_name;
457 	const gchar *uid;
458 
459 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
460 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
461 
462 	if (folder != NULL)
463 		g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
464 
465 	source = em_utils_guess_mail_account (registry, message, folder, message_uid);
466 
467 	if (source == NULL)
468 		return NULL;
469 
470 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
471 	extension = e_source_get_extension (source, extension_name);
472 
473 	uid = e_source_mail_account_get_identity_uid (
474 		E_SOURCE_MAIL_ACCOUNT (extension));
475 	if (uid == NULL)
476 		return NULL;
477 
478 	source = e_source_registry_ref_source (registry, uid);
479 	if (source == NULL)
480 		return NULL;
481 
482 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
483 	if (!e_source_has_extension (source, extension_name)) {
484 		g_object_unref (source);
485 		return NULL;
486 	}
487 
488 	return source;
489 }
490 
491 static gboolean
mail_account_in_recipients(ESourceRegistry * registry,ESource * source,GHashTable * recipients,gchar ** identity_name,gchar ** identity_address)492 mail_account_in_recipients (ESourceRegistry *registry,
493                             ESource *source,
494                             GHashTable *recipients,
495 			    gchar **identity_name,
496 			    gchar **identity_address)
497 {
498 	ESourceExtension *extension;
499 	const gchar *extension_name;
500 	const gchar *uid;
501 	gboolean match = FALSE;
502 	gchar *address;
503 
504 	/* Disregard disabled mail accounts. */
505 	if (!e_source_registry_check_enabled (registry, source))
506 		return FALSE;
507 
508 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
509 	extension = e_source_get_extension (source, extension_name);
510 
511 	uid = e_source_mail_account_get_identity_uid (
512 		E_SOURCE_MAIL_ACCOUNT (extension));
513 	if (uid == NULL)
514 		return FALSE;
515 
516 	source = e_source_registry_ref_source (registry, uid);
517 	if (source == NULL)
518 		return FALSE;
519 
520 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
521 	if (!e_source_has_extension (source, extension_name)) {
522 		g_object_unref (source);
523 		return FALSE;
524 	}
525 
526 	extension = e_source_get_extension (source, extension_name);
527 
528 	address = e_source_mail_identity_dup_address (
529 		E_SOURCE_MAIL_IDENTITY (extension));
530 
531 	if (address != NULL) {
532 		match = g_hash_table_contains (recipients, address);
533 		g_free (address);
534 	}
535 
536 	if (!match) {
537 		gchar *aliases;
538 
539 		aliases = e_source_mail_identity_dup_aliases (E_SOURCE_MAIL_IDENTITY (extension));
540 		if (aliases) {
541 			CamelInternetAddress *inet_address;
542 			gint ii, len;
543 
544 			inet_address = camel_internet_address_new ();
545 			len = camel_address_decode (CAMEL_ADDRESS (inet_address), aliases);
546 
547 			for (ii = 0; ii < len && !match; ii++) {
548 				const gchar *name = NULL, *email = NULL;
549 
550 				if (camel_internet_address_get (inet_address, ii, &name, &email) && email && *email) {
551 					match = g_hash_table_contains (recipients, email);
552 					if (match) {
553 						if (identity_name)
554 							*identity_name = g_strdup (name);
555 						if (identity_address)
556 							*identity_address = g_strdup (email);
557 					}
558 				}
559 			}
560 
561 			g_clear_object (&inet_address);
562 			g_free (aliases);
563 		}
564 	}
565 
566 	g_object_unref (source);
567 
568 	return match;
569 }
570 
571 static ESource *
guess_mail_account_with_recipients_and_sort(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid,gchar ** identity_name,gchar ** identity_address,EMailUtilsSortSourcesFunc sort_func,gpointer sort_func_data)572 guess_mail_account_with_recipients_and_sort (ESourceRegistry *registry,
573 					     CamelMimeMessage *message,
574 					     CamelFolder *folder,
575 					     const gchar *message_uid,
576 					     gchar **identity_name,
577 					     gchar **identity_address,
578 					     EMailUtilsSortSourcesFunc sort_func,
579 					     gpointer sort_func_data)
580 {
581 	const gchar *recipt_types[] = {
582 		CAMEL_RECIPIENT_TYPE_TO,
583 		CAMEL_RECIPIENT_TYPE_CC,
584 		CAMEL_RECIPIENT_TYPE_BCC,
585 		NULL
586 	};
587 	ESource *source = NULL;
588 	GHashTable *recipients;
589 	CamelInternetAddress *addr;
590 	GList *list, *iter;
591 	const gchar *extension_name;
592 	const gchar *key;
593 	gint ii;
594 
595 	/* This policy is subject to debate and tweaking,
596 	 * but please also document the rational here. */
597 
598 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
599 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
600 
601 	/* Build a set of email addresses in which to test for membership.
602 	 * Only the keys matter here; the values just need to be non-NULL. */
603 	recipients = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
604 
605 	for (ii = 0; recipt_types[ii]; ii++) {
606 		addr = camel_mime_message_get_recipients (message, recipt_types[ii]);
607 		if (addr != NULL) {
608 			gint index = 0;
609 
610 			while (camel_internet_address_get (addr, index++, NULL, &key))
611 				g_hash_table_add (recipients, (gpointer) key);
612 		}
613 	}
614 
615 	/* First Preference: We were given a folder that maps to an
616 	 * enabled mail account, and that account's address appears
617 	 * in the list of To: or Cc: recipients. */
618 
619 	if (folder != NULL)
620 		source = guess_mail_account_from_folder (
621 			registry, folder, message_uid);
622 
623 	if (source == NULL)
624 		goto second_preference;
625 
626 	if (mail_account_in_recipients (registry, source, recipients, identity_name, identity_address))
627 		goto exit;
628 
629 second_preference:
630 
631 	/* Second Preference: Choose any enabled mail account whose
632 	 * address appears in the list to To: or Cc: recipients. */
633 
634 	g_clear_object (&source);
635 
636 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
637 	list = e_source_registry_list_enabled (registry, extension_name);
638 
639 	if (sort_func)
640 		sort_func (&list, sort_func_data);
641 
642 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
643 		ESource *temp = E_SOURCE (iter->data);
644 
645 		if (mail_account_in_recipients (registry, temp, recipients, identity_name, identity_address)) {
646 			source = g_object_ref (temp);
647 			break;
648 		}
649 	}
650 
651 	/* Third Preference: Try with the From address (like in Outbox/Sent folders) */
652 	if (!source && message) {
653 		CamelInternetAddress *from;
654 		const gchar *email = NULL;
655 
656 		from = camel_mime_message_get_from (message);
657 		if (from && camel_internet_address_get (from, 0, NULL, &email) && email) {
658 			g_hash_table_remove_all (recipients);
659 			g_hash_table_add (recipients, (gpointer) email);
660 
661 			for (iter = list; iter != NULL; iter = g_list_next (iter)) {
662 				ESource *temp = E_SOURCE (iter->data);
663 
664 				if (mail_account_in_recipients (registry, temp, recipients, identity_name, identity_address)) {
665 					source = g_object_ref (temp);
666 					break;
667 				}
668 			}
669 		}
670 	}
671 
672 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
673 
674 	if (source != NULL)
675 		goto exit;
676 
677 	/* Last Preference: Defer to em_utils_guess_mail_account(). */
678 	source = em_utils_guess_mail_account (
679 		registry, message, folder, message_uid);
680 
681 exit:
682 	g_hash_table_destroy (recipients);
683 
684 	return source;
685 }
686 
687 ESource *
em_utils_guess_mail_account_with_recipients_and_sort(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid,EMailUtilsSortSourcesFunc sort_func,gpointer sort_func_data)688 em_utils_guess_mail_account_with_recipients_and_sort (ESourceRegistry *registry,
689 						      CamelMimeMessage *message,
690 						      CamelFolder *folder,
691 						      const gchar *message_uid,
692 						      EMailUtilsSortSourcesFunc sort_func,
693 						      gpointer sort_func_data)
694 {
695 	return guess_mail_account_with_recipients_and_sort (registry, message, folder, message_uid, NULL, NULL, sort_func, sort_func_data);
696 }
697 
698 ESource *
em_utils_guess_mail_identity_with_recipients_and_sort(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid,gchar ** identity_name,gchar ** identity_address,EMailUtilsSortSourcesFunc sort_func,gpointer sort_func_data)699 em_utils_guess_mail_identity_with_recipients_and_sort (ESourceRegistry *registry,
700                                                        CamelMimeMessage *message,
701                                                        CamelFolder *folder,
702                                                        const gchar *message_uid,
703 						       gchar **identity_name,
704 						       gchar **identity_address,
705                                                        EMailUtilsSortSourcesFunc sort_func,
706                                                        gpointer sort_func_data)
707 {
708 	ESource *source;
709 	ESourceExtension *extension;
710 	const gchar *extension_name;
711 	const gchar *uid;
712 
713 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
714 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
715 
716 	source = guess_mail_account_with_recipients_and_sort (
717 		registry, message, folder, message_uid, identity_name, identity_address, sort_func, sort_func_data);
718 
719 	if (source == NULL)
720 		return NULL;
721 
722 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
723 	extension = e_source_get_extension (source, extension_name);
724 
725 	uid = e_source_mail_account_get_identity_uid (
726 		E_SOURCE_MAIL_ACCOUNT (extension));
727 	if (uid == NULL)
728 		return NULL;
729 
730 	source = e_source_registry_ref_source (registry, uid);
731 	if (source == NULL)
732 		return NULL;
733 
734 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
735 	if (!e_source_has_extension (source, extension_name)) {
736 		g_object_unref (source);
737 		return NULL;
738 	}
739 
740 	return source;
741 }
742 
743 ESource *
em_utils_guess_mail_account_with_recipients(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid)744 em_utils_guess_mail_account_with_recipients (ESourceRegistry *registry,
745                                              CamelMimeMessage *message,
746                                              CamelFolder *folder,
747                                              const gchar *message_uid)
748 {
749 	return em_utils_guess_mail_account_with_recipients_and_sort (registry, message, folder, message_uid, NULL, NULL);
750 }
751 
752 ESource *
em_utils_guess_mail_identity_with_recipients(ESourceRegistry * registry,CamelMimeMessage * message,CamelFolder * folder,const gchar * message_uid,gchar ** identity_name,gchar ** identity_address)753 em_utils_guess_mail_identity_with_recipients (ESourceRegistry *registry,
754                                               CamelMimeMessage *message,
755                                               CamelFolder *folder,
756                                               const gchar *message_uid,
757 					      gchar **identity_name,
758 					      gchar **identity_address)
759 {
760 	return em_utils_guess_mail_identity_with_recipients_and_sort (registry, message, folder, message_uid, identity_name, identity_address, NULL, NULL);
761 }
762 
763 ESource *
em_utils_ref_mail_identity_for_store(ESourceRegistry * registry,CamelStore * store)764 em_utils_ref_mail_identity_for_store (ESourceRegistry *registry,
765                                       CamelStore *store)
766 {
767 	ESourceMailAccount *extension;
768 	ESource *source;
769 	const gchar *extension_name;
770 	const gchar *store_uid;
771 	gchar *identity_uid;
772 
773 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
774 	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
775 
776 	store_uid = camel_service_get_uid (CAMEL_SERVICE (store));
777 	g_return_val_if_fail (store_uid != NULL, NULL);
778 
779 	source = e_source_registry_ref_source (registry, store_uid);
780 	g_return_val_if_fail (source != NULL, NULL);
781 
782 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
783 	extension = e_source_get_extension (source, extension_name);
784 	identity_uid = e_source_mail_account_dup_identity_uid (extension);
785 
786 	g_object_unref (source);
787 	source = NULL;
788 
789 	if (identity_uid != NULL) {
790 		source = e_source_registry_ref_source (registry, identity_uid);
791 		g_free (identity_uid);
792 	}
793 
794 	return source;
795 }
796 
797 /**
798  * em_utils_is_local_delivery_mbox_file:
799  * @service: a #CamelService
800  *
801  * Returns whether @service refers to a local mbox file where new mail
802  * is delivered by some external software.
803  *
804  * Specifically that means @service's #CamelProvider protocol is "mbox"
805  * and its #CamelLocalSettings:path setting points to an existing file,
806  * not a directory.
807  *
808  * Returns: whether @service is for local mbox delivery
809  **/
810 gboolean
em_utils_is_local_delivery_mbox_file(CamelService * service)811 em_utils_is_local_delivery_mbox_file (CamelService *service)
812 {
813 	CamelProvider *provider;
814 	CamelSettings *settings;
815 	gchar *mbox_path = NULL;
816 	gboolean is_local_delivery_mbox_file;
817 
818 	g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
819 
820 	provider = camel_service_get_provider (service);
821 	g_return_val_if_fail (provider != NULL, FALSE);
822 	g_return_val_if_fail (provider->protocol != NULL, FALSE);
823 
824 	if (!g_str_equal (provider->protocol, "mbox"))
825 		return FALSE;
826 
827 	settings = camel_service_ref_settings (service);
828 
829 	if (CAMEL_IS_LOCAL_SETTINGS (settings)) {
830 		CamelLocalSettings *local_settings;
831 
832 		local_settings = CAMEL_LOCAL_SETTINGS (settings);
833 		mbox_path = camel_local_settings_dup_path (local_settings);
834 	}
835 
836 	is_local_delivery_mbox_file =
837 		(mbox_path != NULL) &&
838 		g_file_test (mbox_path, G_FILE_TEST_EXISTS) &&
839 		!g_file_test (mbox_path, G_FILE_TEST_IS_DIR);
840 
841 	g_free (mbox_path);
842 	g_clear_object (&settings);
843 
844 	return is_local_delivery_mbox_file;
845 }
846 
847 /* Expands groups to individual addresses, or removes empty groups completely.
848  * Usual email addresses are left untouched.
849 */
850 void
em_utils_expand_groups(CamelInternetAddress * addresses)851 em_utils_expand_groups (CamelInternetAddress *addresses)
852 {
853 	gint ii, len;
854 	const gchar *addr;
855 	CamelAddress *addrs;
856 
857 	g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (addresses));
858 
859 	addrs = CAMEL_ADDRESS (addresses);
860 	len = camel_address_length (addrs);
861 	for (ii = len - 1; ii >= 0; ii--) {
862 		addr = NULL;
863 
864 		if (!camel_internet_address_get (addresses, ii, NULL, &addr)) {
865 			camel_address_remove (addrs, ii);
866 		} else if (addr) {
867 			gchar *encoded = camel_internet_address_encode_address (NULL, NULL, addr);
868 
869 			if (encoded) {
870 				CamelInternetAddress *iaddr = camel_internet_address_new ();
871 				gint decoded;
872 
873 				/* decode expands respective groups */
874 				decoded = camel_address_decode (CAMEL_ADDRESS (iaddr), encoded);
875 				if (decoded <= 0 || decoded > 1) {
876 					camel_address_remove (addrs, ii);
877 
878 					if (decoded > 1)
879 						camel_address_cat (addrs, CAMEL_ADDRESS (iaddr));
880 				}
881 
882 				g_object_unref (iaddr);
883 				g_free (encoded);
884 			}
885 		}
886 	}
887 }
888 
889 void
em_utils_get_real_folder_and_message_uid(CamelFolder * folder,const gchar * uid,CamelFolder ** out_real_folder,gchar ** folder_uri,gchar ** message_uid)890 em_utils_get_real_folder_and_message_uid (CamelFolder *folder,
891 					  const gchar *uid,
892 					  CamelFolder **out_real_folder,
893 					  gchar **folder_uri,
894 					  gchar **message_uid)
895 {
896 	g_return_if_fail (folder != NULL);
897 	g_return_if_fail (uid != NULL);
898 
899 	if (out_real_folder)
900 		*out_real_folder = NULL;
901 
902 	if (CAMEL_IS_VEE_FOLDER (folder)) {
903 		CamelMessageInfo *mi;
904 
905 		mi = camel_folder_get_message_info (folder, uid);
906 		if (mi) {
907 			CamelFolder *real_folder;
908 			gchar *real_uid = NULL;
909 
910 			real_folder = camel_vee_folder_get_location (
911 				CAMEL_VEE_FOLDER (folder),
912 				(CamelVeeMessageInfo *) mi,
913 				&real_uid);
914 
915 			if (real_folder) {
916 				if (folder_uri)
917 					*folder_uri = e_mail_folder_uri_from_folder (real_folder);
918 				if (message_uid)
919 					*message_uid = real_uid;
920 				else
921 					g_free (real_uid);
922 
923 				if (out_real_folder)
924 					*out_real_folder = g_object_ref (real_folder);
925 
926 				g_clear_object (&mi);
927 
928 				return;
929 			}
930 
931 			g_clear_object (&mi);
932 		}
933 	}
934 
935 	if (folder_uri)
936 		*folder_uri = e_mail_folder_uri_from_folder (folder);
937 	if (message_uid)
938 		*message_uid = g_strdup (uid);
939 }
940 
941 gboolean
em_utils_address_is_user(ESourceRegistry * registry,const gchar * address,gboolean only_enabled_accounts)942 em_utils_address_is_user (ESourceRegistry *registry,
943 			  const gchar *address,
944 			  gboolean only_enabled_accounts)
945 {
946 	GList *list, *iter;
947 	const gchar *extension_name;
948 	gboolean match = FALSE;
949 
950 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
951 	g_return_val_if_fail (address != NULL, FALSE);
952 
953 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
954 
955 	if (only_enabled_accounts)
956 		list = e_source_registry_list_enabled (registry, extension_name);
957 	else
958 		list = e_source_registry_list_sources (registry, extension_name);
959 
960 	for (iter = list; iter && !match; iter = g_list_next (iter)) {
961 		ESource *source = E_SOURCE (iter->data);
962 		ESourceMailIdentity *extension;
963 		GHashTable *aliases;
964 		const gchar *id_address;
965 
966 		extension = e_source_get_extension (source, extension_name);
967 		id_address = e_source_mail_identity_get_address (extension);
968 
969 		if (id_address && g_ascii_strcasecmp (address, id_address) == 0) {
970 			match = TRUE;
971 			break;
972 		}
973 
974 		aliases = e_source_mail_identity_get_aliases_as_hash_table (extension);
975 		if (aliases) {
976 			match = g_hash_table_contains (aliases, address);
977 			g_hash_table_destroy (aliases);
978 		}
979 	}
980 
981 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
982 
983 	return match;
984 }
985 
986 gboolean
em_utils_sender_is_user(ESourceRegistry * registry,CamelMimeMessage * message,gboolean only_enabled_accounts)987 em_utils_sender_is_user (ESourceRegistry *registry,
988 			 CamelMimeMessage *message,
989 			 gboolean only_enabled_accounts)
990 {
991 	CamelInternetAddress *from;
992 	const gchar *addr = NULL;
993 
994 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
995 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
996 
997 	from = camel_mime_message_get_from (message);
998 
999 	if (!from)
1000 		return FALSE;
1001 
1002 	if (!camel_internet_address_get (from, 0, NULL, &addr) || !addr || !*addr)
1003 		return FALSE;
1004 
1005 	return em_utils_address_is_user (registry, addr, only_enabled_accounts);
1006 }
1007