evolution-3.6.4/libemail-engine/e-mail-utils.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-utils.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-utils.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Srinivasa Ragavan <sragavan@gnome.org>
  18  *
  19  *
  20  */
  21 
  22 #include <stdio.h>
  23 #include <string.h>
  24 #include <sys/types.h>
  25 #include <sys/stat.h>
  26 #include <errno.h>
  27 #include <time.h>
  28 
  29 #include <glib/gstdio.h>
  30 
  31 #ifdef G_OS_WIN32
  32 /* Work around namespace clobbage in <windows.h> */
  33 #define DATADIR windows_DATADIR
  34 #include <windows.h>
  35 #undef DATADIR
  36 #undef interface
  37 #endif
  38 
  39 #include <glib/gi18n.h>
  40 #include <libebook/libebook.h>
  41 
  42 #include <libemail-utils/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 /**
  52  * em_utils_folder_is_drafts:
  53  * @registry: an #ESourceRegistry
  54  * @folder: a #CamelFolder
  55  *
  56  * Decides if @folder is a Drafts folder.
  57  *
  58  * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
  59  **/
  60 gboolean
  61 em_utils_folder_is_drafts (ESourceRegistry *registry,
  62                            CamelFolder *folder)
  63 {
  64 	CamelFolder *local_drafts_folder;
  65 	CamelSession *session;
  66 	CamelStore *store;
  67 	GList *list, *iter;
  68 	gchar *folder_uri;
  69 	gboolean is_drafts = FALSE;
  70 	const gchar *extension_name;
  71 
  72 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
  73 
  74 	store = camel_folder_get_parent_store (folder);
  75 	session = camel_service_get_session (CAMEL_SERVICE (store));
  76 
  77 	local_drafts_folder =
  78 		e_mail_session_get_local_folder (
  79 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS);
  80 
  81 	if (folder == local_drafts_folder)
  82 		return TRUE;
  83 
  84 	folder_uri = e_mail_folder_uri_from_folder (folder);
  85 
  86 	store = camel_folder_get_parent_store (folder);
  87 	session = camel_service_get_session (CAMEL_SERVICE (store));
  88 
  89 	extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
  90 	list = e_source_registry_list_sources (registry, extension_name);
  91 
  92 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
  93 		ESource *source = E_SOURCE (iter->data);
  94 		ESourceExtension *extension;
  95 		const gchar *drafts_folder_uri;
  96 
  97 		extension = e_source_get_extension (source, extension_name);
  98 
  99 		drafts_folder_uri =
 100 			e_source_mail_composition_get_drafts_folder (
 101 			E_SOURCE_MAIL_COMPOSITION (extension));
 102 
 103 		if (drafts_folder_uri != NULL)
 104 			is_drafts = e_mail_folder_uri_equal (
 105 				session, folder_uri, drafts_folder_uri);
 106 
 107 		if (is_drafts)
 108 			break;
 109 	}
 110 
 111 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 112 	g_free (folder_uri);
 113 
 114 	return is_drafts;
 115 }
 116 
 117 /**
 118  * em_utils_folder_is_templates:
 119  * @registry: an #ESourceRegistry
 120  * @folder: a #CamelFolder
 121  *
 122  * Decides if @folder is a Templates folder.
 123  *
 124  * Returns %TRUE if this is a Templates folder or %FALSE otherwise.
 125  **/
 126 
 127 gboolean
 128 em_utils_folder_is_templates (ESourceRegistry *registry,
 129                               CamelFolder *folder)
 130 {
 131 	CamelFolder *local_templates_folder;
 132 	CamelSession *session;
 133 	CamelStore *store;
 134 	GList *list, *iter;
 135 	gchar *folder_uri;
 136 	gboolean is_templates = FALSE;
 137 	const gchar *extension_name;
 138 
 139 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
 140 
 141 	store = camel_folder_get_parent_store (folder);
 142 	session = camel_service_get_session (CAMEL_SERVICE (store));
 143 
 144 	local_templates_folder =
 145 		e_mail_session_get_local_folder (
 146 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES);
 147 
 148 	if (folder == local_templates_folder)
 149 		return TRUE;
 150 
 151 	folder_uri = e_mail_folder_uri_from_folder (folder);
 152 
 153 	store = camel_folder_get_parent_store (folder);
 154 	session = camel_service_get_session (CAMEL_SERVICE (store));
 155 
 156 	extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
 157 	list = e_source_registry_list_sources (registry, extension_name);
 158 
 159 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
 160 		ESource *source = E_SOURCE (iter->data);
 161 		ESourceExtension *extension;
 162 		const gchar *templates_folder_uri;
 163 
 164 		extension = e_source_get_extension (source, extension_name);
 165 
 166 		templates_folder_uri =
 167 			e_source_mail_composition_get_templates_folder (
 168 			E_SOURCE_MAIL_COMPOSITION (extension));
 169 
 170 		if (templates_folder_uri != NULL)
 171 			is_templates = e_mail_folder_uri_equal (
 172 				session, folder_uri, templates_folder_uri);
 173 
 174 		if (is_templates)
 175 			break;
 176 	}
 177 
 178 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 179 	g_free (folder_uri);
 180 
 181 	return is_templates;
 182 }
 183 
 184 /**
 185  * em_utils_folder_is_sent:
 186  * @registry: an #ESourceRegistry
 187  * @folder: a #CamelFolder
 188  *
 189  * Decides if @folder is a Sent folder.
 190  *
 191  * Returns %TRUE if this is a Sent folder or %FALSE otherwise.
 192  **/
 193 gboolean
 194 em_utils_folder_is_sent (ESourceRegistry *registry,
 195                          CamelFolder *folder)
 196 {
 197 	CamelFolder *local_sent_folder;
 198 	CamelSession *session;
 199 	CamelStore *store;
 200 	GList *list, *iter;
 201 	gchar *folder_uri;
 202 	gboolean is_sent = FALSE;
 203 	const gchar *extension_name;
 204 
 205 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
 206 
 207 	store = camel_folder_get_parent_store (folder);
 208 	session = camel_service_get_session (CAMEL_SERVICE (store));
 209 
 210 	local_sent_folder =
 211 		e_mail_session_get_local_folder (
 212 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT);
 213 
 214 	if (folder == local_sent_folder)
 215 		return TRUE;
 216 
 217 	folder_uri = e_mail_folder_uri_from_folder (folder);
 218 
 219 	store = camel_folder_get_parent_store (folder);
 220 	session = camel_service_get_session (CAMEL_SERVICE (store));
 221 
 222 	extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
 223 	list = e_source_registry_list_sources (registry, extension_name);
 224 
 225 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
 226 		ESource *source = E_SOURCE (iter->data);
 227 		ESourceExtension *extension;
 228 		const gchar *sent_folder_uri;
 229 
 230 		extension = e_source_get_extension (source, extension_name);
 231 
 232 		sent_folder_uri =
 233 			e_source_mail_submission_get_sent_folder (
 234 			E_SOURCE_MAIL_SUBMISSION (extension));
 235 
 236 		if (sent_folder_uri != NULL)
 237 			is_sent = e_mail_folder_uri_equal (
 238 				session, folder_uri, sent_folder_uri);
 239 
 240 		if (is_sent)
 241 			break;
 242 	}
 243 
 244 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 245 	g_free (folder_uri);
 246 
 247 	return is_sent;
 248 }
 249 
 250 /**
 251  * em_utils_folder_is_outbox:
 252  * @registry: an #ESourceRegistry
 253  * @folder: a #CamelFolder
 254  *
 255  * Decides if @folder is an Outbox folder.
 256  *
 257  * Returns %TRUE if this is an Outbox folder or %FALSE otherwise.
 258  **/
 259 gboolean
 260 em_utils_folder_is_outbox (ESourceRegistry *registry,
 261                            CamelFolder *folder)
 262 {
 263 	CamelStore *store;
 264 	CamelSession *session;
 265 	CamelFolder *local_outbox_folder;
 266 
 267 	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
 268 
 269 	store = camel_folder_get_parent_store (folder);
 270 	session = camel_service_get_session (CAMEL_SERVICE (store));
 271 
 272 	local_outbox_folder =
 273 		e_mail_session_get_local_folder (
 274 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX);
 275 
 276 	return (folder == local_outbox_folder);
 277 }
 278 
 279 /* ********************************************************************** */
 280 
 281 struct TryOpenEBookStruct {
 282 	GError **error;
 283 	EFlag *flag;
 284 	gboolean result;
 285 };
 286 
 287 static void
 288 try_open_book_client_cb (GObject *source_object,
 289                          GAsyncResult *result,
 290                          gpointer closure)
 291 {
 292 	EBookClient *book_client = E_BOOK_CLIENT (source_object);
 293 	struct TryOpenEBookStruct *data = (struct TryOpenEBookStruct *) closure;
 294 	GError *error = NULL;
 295 
 296 	if (!data)
 297 		return;
 298 
 299 	e_client_open_finish (E_CLIENT (book_client), result, &error);
 300 
 301 	data->result = error == NULL;
 302 
 303 	if (!data->result) {
 304 		g_clear_error (data->error);
 305 		g_propagate_error (data->error, error);
 306 	}
 307 
 308 	e_flag_set (data->flag);
 309 }
 310 
 311 /*
 312  * try_open_book_client:
 313  * Tries to open address book asynchronously, but acts as synchronous.
 314  * The advantage is it checks periodically whether the camel_operation
 315  * has been canceled or not, and if so, then stops immediately, with
 316  * result FALSE. Otherwise returns same as e_client_open()
 317  */
 318 static gboolean
 319 try_open_book_client (EBookClient *book_client,
 320                       gboolean only_if_exists,
 321                       GCancellable *cancellable,
 322                       GError **error)
 323 {
 324 	struct TryOpenEBookStruct data;
 325 	gboolean canceled = FALSE;
 326 	EFlag *flag = e_flag_new ();
 327 
 328 	data.error = error;
 329 	data.flag = flag;
 330 	data.result = FALSE;
 331 
 332 	e_client_open (
 333 		E_CLIENT (book_client), only_if_exists,
 334 		cancellable, try_open_book_client_cb, &data);
 335 
 336 	while (canceled = g_cancellable_is_cancelled (cancellable),
 337 			!canceled && !e_flag_is_set (flag)) {
 338 		GTimeVal wait;
 339 
 340 		g_get_current_time (&wait);
 341 		g_time_val_add (&wait, 250000); /* waits 250ms */
 342 
 343 		e_flag_timed_wait (flag, &wait);
 344 	}
 345 
 346 	if (canceled) {
 347 		g_cancellable_cancel (cancellable);
 348 
 349 		g_clear_error (error);
 350 		g_propagate_error (
 351 			error, e_client_error_create (
 352 			E_CLIENT_ERROR_CANCELLED, NULL));
 353 	}
 354 
 355 	e_flag_wait (flag);
 356 	e_flag_free (flag);
 357 
 358 	return data.result && (!error || !*error);
 359 }
 360 
 361 extern gint camel_application_is_exiting;
 362 
 363 #define NOT_FOUND_BOOK (GINT_TO_POINTER (1))
 364 
 365 /* to be able to cancel pending requests on exit; this lock
 366  * should not be held while contact_cache lock is held */
 367 G_LOCK_DEFINE_STATIC (search_addressbook_cancellables);
 368 static GSList *search_addressbook_cancellables = NULL;
 369 
 370 G_LOCK_DEFINE_STATIC (contact_cache);
 371 
 372 /* key is lowercased contact email; value is EBook pointer
 373  * (just for comparison) where it comes from */
 374 static GHashTable *contact_cache = NULL;
 375 
 376 /* key is source ID; value is pointer to EBook */
 377 static GHashTable *emu_books_hash = NULL;
 378 
 379 /* key is source ID; value is same pointer as key; this is hash of
 380  * broken books, which failed to open for some reason */
 381 static GHashTable *emu_broken_books_hash = NULL;
 382 
 383 static gboolean
 384 search_address_in_addressbooks (ESourceRegistry *registry,
 385                                 const gchar *address,
 386                                 gboolean local_only,
 387                                 gboolean (*check_contact) (EContact *contact,
 388                                                            gpointer user_data),
 389                                 gpointer user_data,
 390                                 GCancellable *cancellable)
 391 {
 392 	GList *list, *link;
 393 	GList *addr_sources = NULL;
 394 	gboolean found = FALSE, stop = FALSE, found_any = FALSE;
 395 	gchar *lowercase_addr;
 396 	gpointer ptr;
 397 	EBookQuery *book_query;
 398 	gchar *query;
 399 	const gchar *extension_name;
 400 
 401 	if (!address || !*address || g_cancellable_is_cancelled (cancellable) || camel_application_is_exiting)
 402 		return FALSE;
 403 
 404 	G_LOCK (search_addressbook_cancellables);
 405 	if (cancellable)
 406 		g_object_ref (cancellable);
 407 	else
 408 		cancellable = g_cancellable_new ();
 409 	search_addressbook_cancellables = g_slist_prepend (search_addressbook_cancellables, cancellable);
 410 	G_UNLOCK (search_addressbook_cancellables);
 411 
 412 	G_LOCK (contact_cache);
 413 
 414 	if (camel_application_is_exiting || g_cancellable_is_cancelled (cancellable)) {
 415 		G_UNLOCK (contact_cache);
 416 
 417 		G_LOCK (search_addressbook_cancellables);
 418 		search_addressbook_cancellables = g_slist_remove (search_addressbook_cancellables, cancellable);
 419 		g_object_unref (cancellable);
 420 		G_UNLOCK (search_addressbook_cancellables);
 421 
 422 		return FALSE;
 423 	}
 424 
 425 	if (emu_books_hash == NULL) {
 426 		emu_books_hash = g_hash_table_new_full (
 427 			g_str_hash, g_str_equal, g_free, g_object_unref);
 428 		emu_broken_books_hash = g_hash_table_new_full (
 429 			g_str_hash, g_str_equal, g_free, NULL);
 430 		contact_cache = g_hash_table_new_full (
 431 			g_str_hash, g_str_equal, g_free, NULL);
 432 	}
 433 
 434 	lowercase_addr = g_utf8_strdown (address, -1);
 435 	ptr = g_hash_table_lookup (contact_cache, lowercase_addr);
 436 	if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) {
 437 		g_free (lowercase_addr);
 438 		G_UNLOCK (contact_cache);
 439 
 440 		G_LOCK (search_addressbook_cancellables);
 441 		search_addressbook_cancellables = g_slist_remove (search_addressbook_cancellables, cancellable);
 442 		g_object_unref (cancellable);
 443 		G_UNLOCK (search_addressbook_cancellables);
 444 
 445 		return ptr != NOT_FOUND_BOOK;
 446 	}
 447 
 448 	book_query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_IS, address);
 449 	query = e_book_query_to_string (book_query);
 450 	e_book_query_unref (book_query);
 451 
 452 	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
 453 	list = e_source_registry_list_sources (registry, extension_name);
 454 
 455 	for (link = list; link != NULL && !g_cancellable_is_cancelled (cancellable); link = g_list_next (link)) {
 456 		ESource *source = E_SOURCE (link->data);
 457 		ESourceExtension *extension;
 458 		const gchar *backend_name;
 459 		gboolean source_is_local;
 460 		gboolean autocomplete;
 461 
 462 		extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
 463 		extension = e_source_get_extension (source, extension_name);
 464 
 465 		backend_name = e_source_backend_get_backend_name (
 466 			E_SOURCE_BACKEND (extension));
 467 
 468 		source_is_local = (g_strcmp0 (backend_name, "local") == 0);
 469 
 470 		if (local_only && !source_is_local)
 471 			continue;
 472 
 473 		extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
 474 		extension = e_source_get_extension (source, extension_name);
 475 
 476 		autocomplete = e_source_autocomplete_get_include_me (
 477 			E_SOURCE_AUTOCOMPLETE (extension));
 478 
 479 		if (!autocomplete)
 480 			continue;
 481 
 482 		addr_sources = g_list_prepend (
 483 			addr_sources, g_object_ref (source));
 484 	}
 485 
 486 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 487 
 488 	stop = g_cancellable_is_cancelled (cancellable);
 489 
 490 	for (link = addr_sources; !stop && !found && link != NULL
 491 	     && !g_cancellable_is_cancelled (cancellable);
 492 	     link = g_list_next (link)) {
 493 		ESource *source = E_SOURCE (link->data);
 494 		GSList *contacts;
 495 		EBookClient *book_client = NULL;
 496 		gboolean cached_book = FALSE;
 497 		const gchar *display_name;
 498 		const gchar *uid;
 499 		GError *err = NULL;
 500 
 501 		uid = e_source_get_uid (source);
 502 		display_name = e_source_get_display_name (source);
 503 
 504 		/* failed to load this book last time, skip it now */
 505 		if (g_hash_table_lookup (emu_broken_books_hash, uid) != NULL)
 506 			continue;
 507 
 508 		d (printf (" checking '%s'\n", e_source_get_uri (source)));
 509 
 510 		book_client = g_hash_table_lookup (emu_books_hash, uid);
 511 		if (!book_client) {
 512 			book_client = e_book_client_new (source, &err);
 513 
 514 			if (book_client == NULL) {
 515 				if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 516 				    g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
 517 					stop = TRUE;
 518 				} else if (err) {
 519 					gchar *source_uid;
 520 
 521 					source_uid = g_strdup (uid);
 522 
 523 					g_hash_table_insert (
 524 						emu_broken_books_hash,
 525 						source_uid, source_uid);
 526 
 527 					g_warning (
 528 						"%s: Unable to create addressbook '%s': %s",
 529 						G_STRFUNC,
 530 						display_name,
 531 						err->message);
 532 				}
 533 				g_clear_error (&err);
 534 			} else if (!stop && !try_open_book_client (book_client, TRUE, cancellable, &err)) {
 535 				g_object_unref (book_client);
 536 				book_client = NULL;
 537 
 538 				if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 539 				    g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
 540 					stop = TRUE;
 541 				} else if (err) {
 542 					gchar *source_uid;
 543 
 544 					source_uid = g_strdup (uid);
 545 
 546 					g_hash_table_insert (
 547 						emu_broken_books_hash,
 548 						source_uid, source_uid);
 549 
 550 					g_warning (
 551 						"%s: Unable to open addressbook '%s': %s",
 552 						G_STRFUNC,
 553 						display_name,
 554 						err->message);
 555 				}
 556 				g_clear_error (&err);
 557 			}
 558 		} else {
 559 			cached_book = TRUE;
 560 		}
 561 
 562 		if (book_client && !stop &&
 563 		    e_book_client_get_contacts_sync (
 564 		    book_client, query, &contacts, cancellable, &err)) {
 565 			if (contacts != NULL) {
 566 				if (!found_any) {
 567 					g_hash_table_insert (
 568 						contact_cache,
 569 						g_strdup (lowercase_addr),
 570 						book_client);
 571 				}
 572 				found_any = TRUE;
 573 
 574 				if (check_contact) {
 575 					GSList *l;
 576 
 577 					for (l = contacts; l && !found; l = l->next) {
 578 						EContact *contact = l->data;
 579 
 580 						found = check_contact (contact, user_data);
 581 					}
 582 				} else {
 583 					found = TRUE;
 584 				}
 585 
 586 				g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
 587 				g_slist_free (contacts);
 588 			}
 589 		} else if (book_client) {
 590 			stop = stop || (err &&
 591 			    (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 592 			     g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)));
 593 			if (err && !stop) {
 594 				gchar *source_uid = g_strdup (uid);
 595 
 596 				g_hash_table_insert (
 597 					emu_broken_books_hash,
 598 					source_uid, source_uid);
 599 
 600 				g_warning (
 601 					"%s: Can't get contacts from '%s': %s",
 602 					G_STRFUNC,
 603 					display_name,
 604 					err->message);
 605 			}
 606 			g_clear_error (&err);
 607 		}
 608 
 609 		if (stop && !cached_book && book_client) {
 610 			g_object_unref (book_client);
 611 		} else if (!stop && book_client && !cached_book) {
 612 			g_hash_table_insert (
 613 				emu_books_hash, g_strdup (uid), book_client);
 614 		}
 615 	}
 616 
 617 	g_list_free_full (addr_sources, (GDestroyNotify) g_object_unref);
 618 
 619 	g_free (query);
 620 
 621 	if (!found_any) {
 622 		g_hash_table_insert (contact_cache, lowercase_addr, NOT_FOUND_BOOK);
 623 		lowercase_addr = NULL;
 624 	}
 625 
 626 	G_UNLOCK (contact_cache);
 627 
 628 	g_free (lowercase_addr);
 629 
 630 	G_LOCK (search_addressbook_cancellables);
 631 	search_addressbook_cancellables = g_slist_remove (search_addressbook_cancellables, cancellable);
 632 	g_object_unref (cancellable);
 633 	G_UNLOCK (search_addressbook_cancellables);
 634 
 635 	return found_any;
 636 }
 637 
 638 gboolean
 639 em_utils_in_addressbook (ESourceRegistry *registry,
 640                          CamelInternetAddress *iaddr,
 641                          gboolean local_only,
 642                          GCancellable *cancellable)
 643 {
 644 	const gchar *addr;
 645 
 646 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
 647 
 648 	/* TODO: check all addresses? */
 649 	if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr))
 650 		return FALSE;
 651 
 652 	return search_address_in_addressbooks (
 653 		registry, addr, local_only, NULL, NULL, cancellable);
 654 }
 655 
 656 static gboolean
 657 extract_photo_data (EContact *contact,
 658                     gpointer user_data)
 659 {
 660 	EContactPhoto **photo = user_data;
 661 
 662 	g_return_val_if_fail (contact != NULL, FALSE);
 663 	g_return_val_if_fail (user_data != NULL, FALSE);
 664 
 665 	*photo = e_contact_get (contact, E_CONTACT_PHOTO);
 666 	if (!*photo)
 667 		*photo = e_contact_get (contact, E_CONTACT_LOGO);
 668 
 669 	return *photo != NULL;
 670 }
 671 
 672 typedef struct _PhotoInfo {
 673 	gchar *address;
 674 	EContactPhoto *photo;
 675 } PhotoInfo;
 676 
 677 static void
 678 emu_free_photo_info (PhotoInfo *pi)
 679 {
 680 	if (!pi)
 681 		return;
 682 
 683 	if (pi->address)
 684 		g_free (pi->address);
 685 	if (pi->photo)
 686 		e_contact_photo_free (pi->photo);
 687 	g_free (pi);
 688 }
 689 
 690 G_LOCK_DEFINE_STATIC (photos_cache);
 691 static GSList *photos_cache = NULL; /* list of PhotoInfo-s */
 692 
 693 CamelMimePart *
 694 em_utils_contact_photo (ESourceRegistry *registry,
 695                         CamelInternetAddress *cia,
 696                         gboolean local_only,
 697                         GCancellable *cancellable)
 698 {
 699 	const gchar *addr = NULL;
 700 	CamelMimePart *part = NULL;
 701 	EContactPhoto *photo = NULL;
 702 	GSList *p, *last = NULL;
 703 	gint cache_len;
 704 
 705 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
 706 
 707 	if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) {
 708 		return NULL;
 709 	}
 710 
 711 	G_LOCK (photos_cache);
 712 
 713 	/* search a cache first */
 714 	cache_len = 0;
 715 	last = NULL;
 716 	for (p = photos_cache; p; p = p->next) {
 717 		PhotoInfo *pi = p->data;
 718 
 719 		if (!pi)
 720 			continue;
 721 
 722 		if (g_ascii_strcasecmp (addr, pi->address) == 0) {
 723 			photo = pi->photo;
 724 			break;
 725 		}
 726 
 727 		cache_len++;
 728 		last = p;
 729 	}
 730 
 731 	/* !p means the address had not been found in the cache */
 732 	if (!p && search_address_in_addressbooks (
 733 		registry, addr, local_only, extract_photo_data, &photo, cancellable)) {
 734 
 735 		PhotoInfo *pi;
 736 
 737 		/* keep only up to 10 photos in memory */
 738 		if (last && (cache_len >= 10)) {
 739 			pi = last->data;
 740 			photos_cache = g_slist_remove (photos_cache, pi);
 741 
 742 			if (pi)
 743 				emu_free_photo_info (pi);
 744 		}
 745 
 746 		pi = g_new0 (PhotoInfo, 1);
 747 		pi->address = g_strdup (addr);
 748 		pi->photo = photo;
 749 
 750 		photos_cache = g_slist_prepend (photos_cache, pi);
 751 	}
 752 
 753 	/* some photo found, use it */
 754 	if (photo) {
 755 		/* Form a mime part out of the photo */
 756 		part = camel_mime_part_new ();
 757 
 758 		if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
 759 			camel_mime_part_set_content (
 760 				part,
 761 				(const gchar *) photo->data.inlined.data,
 762 				photo->data.inlined.length, "image/jpeg");
 763 		} else {
 764 			gchar *s = g_filename_from_uri (photo->data.uri, NULL, NULL);
 765 			camel_mime_part_set_filename (part, s);
 766 			g_free (s);
 767 		}
 768 	}
 769 
 770 	G_UNLOCK (photos_cache);
 771 
 772 	return part;
 773 }
 774 
 775 /* list of email addresses (strings) to remove from local cache of photos and
 776  * contacts, but only if the photo doesn't exist or is an not-found contact */
 777 void
 778 emu_remove_from_mail_cache (const GSList *addresses)
 779 {
 780 	const GSList *a;
 781 	GSList *p;
 782 	CamelInternetAddress *cia;
 783 
 784 	cia = camel_internet_address_new ();
 785 
 786 	for (a = addresses; a; a = a->next) {
 787 		const gchar *addr = NULL;
 788 
 789 		if (!a->data)
 790 			continue;
 791 
 792 		if (camel_address_decode ((CamelAddress *) cia, a->data) != -1 &&
 793 		    camel_internet_address_get (cia, 0, NULL, &addr) && addr) {
 794 			gchar *lowercase_addr = g_utf8_strdown (addr, -1);
 795 
 796 			G_LOCK (contact_cache);
 797 			if (g_hash_table_lookup (contact_cache, lowercase_addr) == NOT_FOUND_BOOK)
 798 				g_hash_table_remove (contact_cache, lowercase_addr);
 799 			G_UNLOCK (contact_cache);
 800 
 801 			g_free (lowercase_addr);
 802 
 803 			G_LOCK (photos_cache);
 804 			for (p = photos_cache; p; p = p->next) {
 805 				PhotoInfo *pi = p->data;
 806 
 807 				if (pi && !pi->photo && g_ascii_strcasecmp (pi->address, addr) == 0) {
 808 					photos_cache = g_slist_remove (photos_cache, pi);
 809 					emu_free_photo_info (pi);
 810 					break;
 811 				}
 812 			}
 813 			G_UNLOCK (photos_cache);
 814 		}
 815 	}
 816 
 817 	g_object_unref (cia);
 818 }
 819 
 820 void
 821 emu_remove_from_mail_cache_1 (const gchar *address)
 822 {
 823 	GSList *l;
 824 
 825 	g_return_if_fail (address != NULL);
 826 
 827 	l = g_slist_append (NULL, (gpointer) address);
 828 
 829 	emu_remove_from_mail_cache (l);
 830 
 831 	g_slist_free (l);
 832 }
 833 
 834 struct FreeMailCacheData
 835 {
 836 	GDestroyNotify done_cb;
 837 	gpointer user_data;
 838 };
 839 
 840 static gboolean
 841 free_mail_cache_idle (gpointer user_data)
 842 {
 843 	struct FreeMailCacheData *fmc = user_data;
 844 
 845 	g_return_val_if_fail (fmc != NULL, FALSE);
 846 
 847 	if (fmc->done_cb)
 848 		fmc->done_cb (fmc->user_data);
 849 	g_free (fmc);
 850 
 851 	return FALSE;
 852 }
 853 
 854 static gpointer
 855 free_mail_cache_thread (gpointer user_data)
 856 {
 857 	g_return_val_if_fail (user_data != NULL, NULL);
 858 
 859 	G_LOCK (contact_cache);
 860 
 861 	if (emu_books_hash) {
 862 		g_hash_table_destroy (emu_books_hash);
 863 		emu_books_hash = NULL;
 864 	}
 865 
 866 	if (emu_broken_books_hash) {
 867 		g_hash_table_destroy (emu_broken_books_hash);
 868 		emu_broken_books_hash = NULL;
 869 	}
 870 
 871 	if (contact_cache) {
 872 		g_hash_table_destroy (contact_cache);
 873 		contact_cache = NULL;
 874 	}
 875 
 876 	G_UNLOCK (contact_cache);
 877 
 878 	G_LOCK (photos_cache);
 879 
 880 	g_slist_foreach (photos_cache, (GFunc) emu_free_photo_info, NULL);
 881 	g_slist_free (photos_cache);
 882 	photos_cache = NULL;
 883 
 884 	G_UNLOCK (photos_cache);
 885 
 886 	/* Prioritize ahead of GTK+ redraws. */
 887 	g_idle_add_full (
 888 		G_PRIORITY_HIGH_IDLE,
 889 		free_mail_cache_idle, user_data, NULL);
 890 
 891 	return NULL;
 892 }
 893 
 894 /* frees all data created by call of em_utils_in_addressbook() or
 895  * em_utils_contact_photo(); done_cb is called when freeing is done,
 896  * in an idle callback
 897  */
 898 void
 899 emu_free_mail_cache (GDestroyNotify done_cb,
 900                      gpointer user_data)
 901 {
 902 	struct FreeMailCacheData *fmc;
 903 	GThread *thread;
 904 
 905 	G_LOCK (search_addressbook_cancellables);
 906 	g_slist_foreach (search_addressbook_cancellables, (GFunc) g_cancellable_cancel, NULL);
 907 	G_UNLOCK (search_addressbook_cancellables);
 908 
 909 	fmc = g_new0 (struct FreeMailCacheData, 1);
 910 	fmc->done_cb = done_cb;
 911 	fmc->user_data = user_data;
 912 
 913 	thread = g_thread_new (NULL, free_mail_cache_thread, fmc);
 914 	g_thread_unref (thread);
 915 }
 916 
 917 static ESource *
 918 guess_mail_account_from_folder (ESourceRegistry *registry,
 919                                 CamelFolder *folder,
 920                                 const gchar *message_uid)
 921 {
 922 	ESource *source;
 923 	CamelStore *store;
 924 	const gchar *uid;
 925 
 926 	/* Lookup an ESource by CamelStore UID. */
 927 	store = camel_folder_get_parent_store (folder);
 928 	if (message_uid && folder && CAMEL_IS_VEE_STORE (store)) {
 929 		CamelMessageInfo *mi = camel_folder_get_message_info (folder, message_uid);
 930 		if (mi) {
 931 			CamelFolder *location;
 932 
 933 			location = camel_vee_folder_get_location (CAMEL_VEE_FOLDER (folder), (CamelVeeMessageInfo *) mi, NULL);
 934 			if (location)
 935 				store = camel_folder_get_parent_store (location);
 936 			camel_folder_free_message_info (folder, mi);
 937 		}
 938 	}
 939 
 940 	uid = camel_service_get_uid (CAMEL_SERVICE (store));
 941 	source = e_source_registry_ref_source (registry, uid);
 942 
 943 	/* If we found an ESource, make sure it's a mail account. */
 944 	if (source != NULL) {
 945 		const gchar *extension_name;
 946 
 947 		extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
 948 		if (!e_source_has_extension (source, extension_name)) {
 949 			g_object_unref (source);
 950 			source = NULL;
 951 		}
 952 	}
 953 
 954 	return source;
 955 }
 956 
 957 static ESource *
 958 guess_mail_account_from_message (ESourceRegistry *registry,
 959                                  CamelMimeMessage *message)
 960 {
 961 	ESource *source = NULL;
 962 	const gchar *uid;
 963 
 964 	/* Lookup an ESource by 'X-Evolution-Source' header. */
 965 	uid = camel_mime_message_get_source (message);
 966 	if (uid != NULL)
 967 		source = e_source_registry_ref_source (registry, uid);
 968 
 969 	/* If we found an ESource, make sure it's a mail account. */
 970 	if (source != NULL) {
 971 		const gchar *extension_name;
 972 
 973 		extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
 974 		if (!e_source_has_extension (source, extension_name)) {
 975 			g_object_unref (source);
 976 			source = NULL;
 977 		}
 978 	}
 979 
 980 	return source;
 981 }
 982 
 983 ESource *
 984 em_utils_guess_mail_account (ESourceRegistry *registry,
 985                              CamelMimeMessage *message,
 986                              CamelFolder *folder,
 987                              const gchar *message_uid)
 988 {
 989 	ESource *source = NULL;
 990 	const gchar *newsgroups;
 991 
 992 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
 993 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
 994 
 995 	if (folder != NULL)
 996 		g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
 997 
 998 	/* check for newsgroup header */
 999 	newsgroups = camel_medium_get_header (
1000 		CAMEL_MEDIUM (message), "Newsgroups");
1001 	if (folder != NULL && newsgroups != NULL)
1002 		source = guess_mail_account_from_folder (registry, folder, message_uid);
1003 
1004 	/* check for source folder */
1005 	if (source == NULL && folder != NULL)
1006 		source = guess_mail_account_from_folder (registry, folder, message_uid);
1007 
1008 	/* then message source */
1009 	if (source == NULL)
1010 		source = guess_mail_account_from_message (registry, message);
1011 
1012 	return source;
1013 }
1014 
1015 ESource *
1016 em_utils_guess_mail_identity (ESourceRegistry *registry,
1017                               CamelMimeMessage *message,
1018                               CamelFolder *folder,
1019                               const gchar *message_uid)
1020 {
1021 	ESource *source;
1022 	ESourceExtension *extension;
1023 	const gchar *extension_name;
1024 	const gchar *uid;
1025 
1026 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1027 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
1028 
1029 	if (folder != NULL)
1030 		g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
1031 
1032 	source = em_utils_guess_mail_account (registry, message, folder, message_uid);
1033 
1034 	if (source == NULL)
1035 		return NULL;
1036 
1037 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
1038 	extension = e_source_get_extension (source, extension_name);
1039 
1040 	uid = e_source_mail_account_get_identity_uid (
1041 		E_SOURCE_MAIL_ACCOUNT (extension));
1042 	if (uid == NULL)
1043 		return NULL;
1044 
1045 	source = e_source_registry_ref_source (registry, uid);
1046 	if (source == NULL)
1047 		return NULL;
1048 
1049 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1050 	if (!e_source_has_extension (source, extension_name)) {
1051 		g_object_unref (source);
1052 		return NULL;
1053 	}
1054 
1055 	return source;
1056 }
1057 
1058 static gboolean
1059 mail_account_in_recipients (ESourceRegistry *registry,
1060                             ESource *source,
1061                             GHashTable *recipients)
1062 {
1063 	ESourceExtension *extension;
1064 	const gchar *extension_name;
1065 	const gchar *uid;
1066 	gboolean match = FALSE;
1067 	gchar *address;
1068 
1069 	/* Disregard disabled mail accounts. */
1070 	if (!e_source_get_enabled (source))
1071 		return FALSE;
1072 
1073 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
1074 	extension = e_source_get_extension (source, extension_name);
1075 
1076 	uid = e_source_mail_account_get_identity_uid (
1077 		E_SOURCE_MAIL_ACCOUNT (extension));
1078 	if (uid == NULL)
1079 		return FALSE;
1080 
1081 	source = e_source_registry_ref_source (registry, uid);
1082 	if (source == NULL)
1083 		return FALSE;
1084 
1085 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1086 	if (!e_source_has_extension (source, extension_name)) {
1087 		g_object_unref (source);
1088 		return FALSE;
1089 	}
1090 
1091 	extension = e_source_get_extension (source, extension_name);
1092 
1093 	address = e_source_mail_identity_dup_address (
1094 		E_SOURCE_MAIL_IDENTITY (extension));
1095 
1096 	g_object_unref (source);
1097 
1098 	if (address != NULL) {
1099 		match = (g_hash_table_lookup (recipients, address) != NULL);
1100 		g_free (address);
1101 	}
1102 
1103 	return match;
1104 }
1105 
1106 ESource *
1107 em_utils_guess_mail_account_with_recipients_and_sort (ESourceRegistry *registry,
1108 						      CamelMimeMessage *message,
1109 						      CamelFolder *folder,
1110 						      const gchar *message_uid,
1111 						      EMailUtilsSourtSourcesFunc sort_func,
1112 						      gpointer sort_func_data)
1113 {
1114 	ESource *source = NULL;
1115 	GHashTable *recipients;
1116 	CamelInternetAddress *addr;
1117 	GList *list, *iter;
1118 	const gchar *extension_name;
1119 	const gchar *type;
1120 	const gchar *key;
1121 
1122 	/* This policy is subject to debate and tweaking,
1123 	 * but please also document the rational here. */
1124 
1125 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1126 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
1127 
1128 	/* Build a set of email addresses in which to test for membership.
1129 	 * Only the keys matter here; the values just need to be non-NULL. */
1130 	recipients = g_hash_table_new (g_str_hash, g_str_equal);
1131 
1132 	type = CAMEL_RECIPIENT_TYPE_TO;
1133 	addr = camel_mime_message_get_recipients (message, type);
1134 	if (addr != NULL) {
1135 		gint index = 0;
1136 
1137 		while (camel_internet_address_get (addr, index++, NULL, &key))
1138 			g_hash_table_insert (
1139 				recipients, (gpointer) key,
1140 				GINT_TO_POINTER (1));
1141 	}
1142 
1143 	type = CAMEL_RECIPIENT_TYPE_CC;
1144 	addr = camel_mime_message_get_recipients (message, type);
1145 	if (addr != NULL) {
1146 		gint index = 0;
1147 
1148 		while (camel_internet_address_get (addr, index++, NULL, &key))
1149 			g_hash_table_insert (
1150 				recipients, (gpointer) key,
1151 				GINT_TO_POINTER (1));
1152 	}
1153 
1154 	/* First Preference: We were given a folder that maps to an
1155 	 * enabled mail account, and that account's address appears
1156 	 * in the list of To: or Cc: recipients. */
1157 
1158 	if (folder != NULL)
1159 		source = guess_mail_account_from_folder (
1160 			registry, folder, message_uid);
1161 
1162 	if (source == NULL)
1163 		goto second_preference;
1164 
1165 	if (mail_account_in_recipients (registry, source, recipients))
1166 		goto exit;
1167 
1168 second_preference:
1169 
1170 	/* Second Preference: Choose any enabled mail account whose
1171 	 * address appears in the list to To: or Cc: recipients. */
1172 
1173 	if (source != NULL) {
1174 		g_object_unref (source);
1175 		source = NULL;
1176 	}
1177 
1178 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
1179 	list = e_source_registry_list_sources (registry, extension_name);
1180 
1181 	if (sort_func)
1182 		sort_func (&list, sort_func_data);
1183 
1184 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
1185 		ESource *temp = E_SOURCE (iter->data);
1186 
1187 		if (em_utils_is_source_enabled_with_parents (registry, temp) &&
1188 		    mail_account_in_recipients (registry, temp, recipients)) {
1189 			source = g_object_ref (temp);
1190 			break;
1191 		}
1192 	}
1193 
1194 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
1195 
1196 	if (source != NULL)
1197 		goto exit;
1198 
1199 	/* Last Preference: Defer to em_utils_guess_mail_account(). */
1200 	source = em_utils_guess_mail_account (
1201 		registry, message, folder, message_uid);
1202 
1203 exit:
1204 	g_hash_table_destroy (recipients);
1205 
1206 	return source;
1207 }
1208 
1209 ESource *
1210 em_utils_guess_mail_identity_with_recipients_and_sort (ESourceRegistry *registry,
1211 						       CamelMimeMessage *message,
1212 						       CamelFolder *folder,
1213 						       const gchar *message_uid,
1214 						       EMailUtilsSourtSourcesFunc sort_func,
1215 						       gpointer sort_func_data)
1216 {
1217 	ESource *source;
1218 	ESourceExtension *extension;
1219 	const gchar *extension_name;
1220 	const gchar *uid;
1221 
1222 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1223 	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
1224 
1225 	source = em_utils_guess_mail_account_with_recipients_and_sort (
1226 		registry, message, folder, message_uid, sort_func, sort_func_data);
1227 
1228 	if (source == NULL)
1229 		return NULL;
1230 
1231 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
1232 	extension = e_source_get_extension (source, extension_name);
1233 
1234 	uid = e_source_mail_account_get_identity_uid (
1235 		E_SOURCE_MAIL_ACCOUNT (extension));
1236 	if (uid == NULL)
1237 		return NULL;
1238 
1239 	source = e_source_registry_ref_source (registry, uid);
1240 	if (source == NULL)
1241 		return NULL;
1242 
1243 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1244 	if (!e_source_has_extension (source, extension_name)) {
1245 		g_object_unref (source);
1246 		return NULL;
1247 	}
1248 
1249 	return source;
1250 }
1251 
1252 ESource *
1253 em_utils_guess_mail_account_with_recipients (ESourceRegistry *registry,
1254                                              CamelMimeMessage *message,
1255                                              CamelFolder *folder,
1256                                              const gchar *message_uid)
1257 {
1258 	return em_utils_guess_mail_account_with_recipients_and_sort (registry, message, folder, message_uid, NULL, NULL);
1259 }
1260 
1261 ESource *
1262 em_utils_guess_mail_identity_with_recipients (ESourceRegistry *registry,
1263                                               CamelMimeMessage *message,
1264                                               CamelFolder *folder,
1265                                               const gchar *message_uid)
1266 {
1267 	return em_utils_guess_mail_identity_with_recipients_and_sort (registry, message, folder, message_uid, NULL, NULL);
1268 }
1269 
1270 ESource *
1271 em_utils_ref_mail_identity_for_store (ESourceRegistry *registry,
1272                                       CamelStore *store)
1273 {
1274 	ESourceMailAccount *extension;
1275 	ESource *source;
1276 	const gchar *extension_name;
1277 	const gchar *store_uid;
1278 	gchar *identity_uid;
1279 
1280 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1281 	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
1282 
1283 	store_uid = camel_service_get_uid (CAMEL_SERVICE (store));
1284 	g_return_val_if_fail (store_uid != NULL, NULL);
1285 
1286 	source = e_source_registry_ref_source (registry, store_uid);
1287 	g_return_val_if_fail (source != NULL, NULL);
1288 
1289 	extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
1290 	extension = e_source_get_extension (source, extension_name);
1291 	identity_uid = e_source_mail_account_dup_identity_uid (extension);
1292 
1293 	g_object_unref (source);
1294 	source = NULL;
1295 
1296 	if (identity_uid != NULL) {
1297 		source = e_source_registry_ref_source (registry, identity_uid);
1298 		g_free (identity_uid);
1299 	}
1300 
1301 	return source;
1302 }
1303 
1304 gboolean
1305 em_utils_is_source_enabled_with_parents (ESourceRegistry *registry,
1306                                          ESource *source)
1307 {
1308 	ESource *parent;
1309 	const gchar *parent_uid;
1310 
1311 	g_return_val_if_fail (registry != NULL, FALSE);
1312 	g_return_val_if_fail (source != NULL, FALSE);
1313 
1314 	if (!e_source_get_enabled (source))
1315 		return FALSE;
1316 
1317 	parent = g_object_ref (source);
1318 	while (parent_uid = e_source_get_parent (parent), parent_uid) {
1319 		ESource *next = e_source_registry_ref_source (registry, parent_uid);
1320 
1321 		if (!next)
1322 			break;
1323 
1324 		g_object_unref (parent);
1325 
1326 		if (!e_source_get_enabled (next)) {
1327 			g_object_unref (next);
1328 			return FALSE;
1329 		}
1330 
1331 		parent = next;
1332 	}
1333 
1334 	g_object_unref (parent);
1335 
1336 	return TRUE;
1337 }
1338 
1339 /**
1340  * em_utils_uids_free:
1341  * @uids: array of uids
1342  *
1343  * Frees the array of uids pointed to by @uids back to the system.
1344  **/
1345 void
1346 em_utils_uids_free (GPtrArray *uids)
1347 {
1348 	gint i;
1349 
1350 	for (i = 0; i < uids->len; i++)
1351 		g_free (uids->pdata[i]);
1352 
1353 	g_ptr_array_free (uids, TRUE);
1354 }
1355 
1356 /* Returns TRUE if CamelURL points to a local mbox file. */
1357 gboolean
1358 em_utils_is_local_delivery_mbox_file (CamelURL *url)
1359 {
1360 	g_return_val_if_fail (url != NULL, FALSE);
1361 
1362 	return g_str_equal (url->protocol, "mbox") &&
1363 		(url->path != NULL) &&
1364 		g_file_test (url->path, G_FILE_TEST_EXISTS) &&
1365 		!g_file_test (url->path, G_FILE_TEST_IS_DIR);
1366 }