evolution-3.6.4/libemail-engine/mail-ops.c

Location Tool Test ID Function Issue
mail-ops.c:266:17 clang-analyzer Assigned value is garbage or undefined
mail-ops.c:266:17 clang-analyzer Assigned value is garbage or undefined
   1 /*
   2  * mail-ops.c: callbacks for the mail toolbar/menus
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Authors:
  19  *      Dan Winship <danw@ximian.com>
  20  *      Jeffrey Stedfast <fejj@ximian.com>
  21  *      Peter Williams <peterw@ximian.com>
  22  *      Michael Zucchi <notzed@ximian.com>
  23  *
  24  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  25  *
  26  */
  27 
  28 #ifdef HAVE_CONFIG_H
  29 #include <config.h>
  30 #endif
  31 
  32 #include <errno.h>
  33 
  34 #include <glib/gstdio.h>
  35 #include <glib/gi18n.h>
  36 
  37 #include <libedataserver/libedataserver.h>
  38 
  39 #include <libemail-utils/mail-mt.h>
  40 
  41 #include "e-mail-utils.h"
  42 #include "mail-ops.h"
  43 #include "mail-tools.h"
  44 
  45 #include "e-mail-folder-utils.h"
  46 #include "e-mail-session.h"
  47 #include "e-mail-session-utils.h"
  48 
  49 #define w(x)
  50 #define d(x)
  51 
  52 /* XXX Make this a preprocessor definition. */
  53 const gchar *x_mailer = "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT;
  54 
  55 /* used for both just filtering a folder + uid's, and for filtering a whole folder */
  56 /* used both for fetching mail, and for filtering mail */
  57 struct _filter_mail_msg {
  58 	MailMsg base;
  59 
  60 	EMailSession *session;
  61 	CamelFolder *source_folder;	/* where they come from */
  62 	GPtrArray *source_uids;		/* uids to copy, or NULL == copy all */
  63 	CamelUIDCache *cache;		/* UID cache if we are to cache
  64 					 * the uids, NULL otherwise */
  65 	CamelFilterDriver *driver;
  66 	gint delete;			/* delete messages after filtering? */
  67 	CamelFolder *destination;	/* default destination for any
  68 					 * messages, NULL for none */
  69 };
  70 
  71 /* since fetching also filters, we subclass the data here */
  72 struct _fetch_mail_msg {
  73 	struct _filter_mail_msg fmsg;
  74 
  75 	CamelStore *store;
  76 	GCancellable *cancellable;	/* we have our own cancellation
  77 					 * struct, the other should be empty */
  78 	gint keep;			/* keep on server? */
  79 	gint fetch_count;
  80 	CamelFetchType fetch_type;
  81 	gint still_more;
  82 
  83 	MailProviderFetchLockFunc provider_lock;
  84 	MailProviderFetchUnlockFunc provider_unlock;
  85 	MailProviderFetchInboxFunc provider_fetch_inbox;
  86 
  87 	void (*done)(gint still_more, gpointer data);
  88 	gpointer data;
  89 };
  90 
  91 static gchar *
  92 em_filter_folder_element_desc (struct _filter_mail_msg *m)
  93 {
  94 	return g_strdup (_("Filtering Selected Messages"));
  95 }
  96 
  97 /* filter a folder, or a subset thereof, uses source_folder/source_uids */
  98 /* this is shared with fetch_mail */
  99 static gboolean
 100 em_filter_folder_element_exec (struct _filter_mail_msg *m,
 101                                GCancellable *cancellable,
 102                                GError **error)
 103 {
 104 	CamelFolder *folder;
 105 	GPtrArray *uids, *folder_uids = NULL;
 106 	gboolean success = TRUE;
 107 
 108 	folder = m->source_folder;
 109 
 110 	if (folder == NULL || camel_folder_get_message_count (folder) == 0)
 111 		return success;
 112 
 113 	if (m->destination) {
 114 		camel_folder_freeze (m->destination);
 115 		camel_filter_driver_set_default_folder (m->driver, m->destination);
 116 	}
 117 
 118 	camel_folder_freeze (folder);
 119 
 120 	if (m->source_uids)
 121 		uids = m->source_uids;
 122 	else
 123 		folder_uids = uids = camel_folder_get_uids (folder);
 124 
 125 	success = camel_filter_driver_filter_folder (
 126 		m->driver, folder, m->cache, uids, m->delete,
 127 		cancellable, error) == 0;
 128 	camel_filter_driver_flush (m->driver, error);
 129 
 130 	if (folder_uids)
 131 		camel_folder_free_uids (folder, folder_uids);
 132 
 133 	/* sync our source folder */
 134 	if (!m->cache)
 135 		camel_folder_synchronize_sync (
 136 			folder, FALSE, cancellable, error);
 137 	camel_folder_thaw (folder);
 138 
 139 	if (m->destination)
 140 		camel_folder_thaw (m->destination);
 141 
 142 	/* this may thaw/unref source folders, do it here so we dont do
 143 	 * it in the main thread see also fetch_mail_fetch () below */
 144 	g_object_unref (m->driver);
 145 	m->driver = NULL;
 146 
 147 	return success;
 148 }
 149 
 150 static void
 151 em_filter_folder_element_done (struct _filter_mail_msg *m)
 152 {
 153 }
 154 
 155 static void
 156 em_filter_folder_element_free (struct _filter_mail_msg *m)
 157 {
 158 	mail_session_flush_filter_log (m->session);
 159 
 160 	if (m->session)
 161 		g_object_unref (m->session);
 162 
 163 	if (m->source_folder)
 164 		g_object_unref (m->source_folder);
 165 
 166 	if (m->source_uids)
 167 		em_utils_uids_free (m->source_uids);
 168 
 169 	if (m->destination)
 170 		g_object_unref (m->destination);
 171 
 172 	if (m->driver)
 173 		g_object_unref (m->driver);
 174 }
 175 
 176 static MailMsgInfo em_filter_folder_element_info = {
 177 	sizeof (struct _filter_mail_msg),
 178 	(MailMsgDescFunc) em_filter_folder_element_desc,
 179 	(MailMsgExecFunc) em_filter_folder_element_exec,
 180 	(MailMsgDoneFunc) em_filter_folder_element_done,
 181 	(MailMsgFreeFunc) em_filter_folder_element_free
 182 };
 183 
 184 void
 185 mail_filter_folder (EMailSession *session,
 186                     CamelFolder *source_folder,
 187                     GPtrArray *uids,
 188                     const gchar *type,
 189                     gboolean notify)
 190 {
 191 	struct _filter_mail_msg *m;
 192 
 193 	m = mail_msg_new (&em_filter_folder_element_info);
 194 	m->session = g_object_ref (session);
 195 	m->source_folder = g_object_ref (source_folder);
 196 	m->source_uids = uids;
 197 	m->cache = NULL;
 198 	m->delete = FALSE;
 199 
 200 	m->driver = camel_session_get_filter_driver (
 201 		CAMEL_SESSION (session), type, NULL);
 202 
 203 	if (!notify) {
 204 		/* FIXME: have a #define NOTIFY_FILTER_NAME macro? */
 205 		/* the filter name has to stay in sync
 206 		 * with mail-session::get_filter_driver */
 207 		camel_filter_driver_remove_rule_by_name (
 208 			m->driver, "new-mail-notification");
 209 	}
 210 
 211 	mail_msg_unordered_push (m);
 212 }
 213 
 214 /* ********************************************************************** */
 215 
 216 static gchar *
 217 fetch_mail_desc (struct _fetch_mail_msg *m)
 218 {
 219 	return g_strdup (_("Fetching Mail"));
 220 }
 221 
 222 static void
 223 fetch_mail_exec (struct _fetch_mail_msg *m,
 224                  GCancellable *cancellable,
 225                  GError **error)
 226 {
 227 	struct _filter_mail_msg *fm = (struct _filter_mail_msg *) m;
 228 	GObjectClass *class;
 229 	CamelFolder *folder = NULL;
 230 	CamelService *service;
 231 	CamelSession *session;
 232 	CamelSettings *settings;
 233 	CamelStore *parent_store;
 234 	CamelUIDCache *cache = NULL;
 235 	CamelURL *url;
 236 	gboolean keep;
 237 	gboolean delete_fetched;
 238 	gboolean is_local_delivery = FALSE;
 239 	const gchar *uid = NULL;
 240 	const gchar *data_dir;
 241 	gchar *cachename;
 242 	gint i;
 243 
 244 	service = CAMEL_SERVICE (m->store);
 245 	session = camel_service_get_session (service);
 246 
 247 	fm->destination = e_mail_session_get_local_folder (
 248 		E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_LOCAL_INBOX);
 249 	if (fm->destination == NULL)
 250 		goto exit;
 251 	g_object_ref (fm->destination);
 252 
 253 	service = CAMEL_SERVICE (m->store);
 254 	uid = camel_service_get_uid (service);
 255 
 256 	settings = camel_service_ref_settings (service);
 257 
 258 	/* XXX This is a POP3-specific setting. */
 259 	class = G_OBJECT_GET_CLASS (settings);
 260 	if (g_object_class_find_property (class, "keep-on-server") != NULL)
 261 		g_object_get (settings, "keep-on-server", &keep, NULL);
 262 
 263 	g_object_unref (settings);
 264 
 265 	/* Just for readability. */
 266 	delete_fetched = !keep;
Assigned value is garbage or undefined
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Assigned value is garbage or undefined
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

267 268 url = camel_service_new_camel_url (service); 269 is_local_delivery = em_utils_is_local_delivery_mbox_file (url); 270 271 if (is_local_delivery) { 272 gchar *path; 273 gchar *url_string; 274 275 path = mail_tool_do_movemail (m->store, error); 276 url_string = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); 277 278 if (path && (!error || !*error)) { 279 camel_folder_freeze (fm->destination); 280 camel_filter_driver_set_default_folder ( 281 fm->driver, fm->destination); 282 camel_filter_driver_filter_mbox ( 283 fm->driver, path, url_string, 284 cancellable, error); 285 camel_folder_thaw (fm->destination); 286 287 if (!error || !*error) 288 g_unlink (path); 289 } 290 291 g_free (path); 292 g_free (url_string); 293 } else { 294 uid = camel_service_get_uid (service); 295 if (m->provider_lock) 296 m->provider_lock (uid); 297 298 folder = fm->source_folder = 299 e_mail_session_get_inbox_sync ( 300 fm->session, uid, cancellable, error); 301 } 302 303 camel_url_free (url); 304 305 if (folder == NULL) 306 goto exit; 307 308 parent_store = camel_folder_get_parent_store (folder); 309 310 if (m->fetch_count > 0) { 311 /* We probably should fetch some old messages first. */ 312 m->still_more = camel_folder_fetch_messages_sync ( 313 folder, m->fetch_type, 314 m->fetch_count, cancellable, error) ? 1 : 0; 315 } 316 317 service = CAMEL_SERVICE (parent_store); 318 data_dir = camel_service_get_user_data_dir (service); 319 320 cachename = g_build_filename (data_dir, "uid-cache", NULL); 321 cache = camel_uid_cache_new (cachename); 322 g_free (cachename); 323 324 if (cache) { 325 GPtrArray *folder_uids, *cache_uids, *uids; 326 GError *local_error = NULL; 327 328 if (m->provider_fetch_inbox) { 329 g_object_unref (fm->destination); 330 fm->destination = m->provider_fetch_inbox (uid, cancellable, &local_error); 331 if (fm->destination == NULL) 332 goto exit; 333 g_object_ref (fm->destination); 334 } 335 336 if (!local_error) { 337 folder_uids = camel_folder_get_uids (folder); 338 cache_uids = camel_uid_cache_get_new_uids (cache, folder_uids); 339 340 if (cache_uids) { 341 gboolean success; 342 343 /* need to copy this, sigh */ 344 fm->source_uids = uids = g_ptr_array_new (); 345 g_ptr_array_set_size (uids, cache_uids->len); 346 347 /* Reverse it so that we fetch the latest as first, while fetching POP */ 348 for (i = 0; i < cache_uids->len; i++) { 349 uids->pdata[cache_uids->len - i - 1] = g_strdup (cache_uids->pdata[i]); 350 } 351 352 fm->cache = cache; 353 354 success = em_filter_folder_element_exec (fm, cancellable, &local_error); 355 356 /* need to uncancel so writes/etc. don't fail */ 357 if (g_cancellable_is_cancelled (m->cancellable)) 358 g_cancellable_reset (m->cancellable); 359 360 if (!success) { 361 /* re-enter known UIDs, thus they are not 362 * re-fetched next time */ 363 for (i = 0; i < cache_uids->len; i++) { 364 camel_uid_cache_save_uid (cache, cache_uids->pdata[i]); 365 } 366 } 367 368 /* save the cache of uids that we've just downloaded */ 369 camel_uid_cache_save (cache); 370 371 camel_uid_cache_free_uids (cache_uids); 372 } 373 374 if (delete_fetched && !local_error) { 375 /* not keep on server - just delete all 376 * the actual messages on the server */ 377 for (i = 0; i < folder_uids->len; i++) { 378 camel_folder_delete_message ( 379 folder, folder_uids->pdata[i]); 380 } 381 } 382 383 if ((delete_fetched || cache_uids) && !local_error) { 384 /* expunge messages (downloaded so far) */ 385 /* FIXME Not passing a GCancellable or GError here. */ 386 camel_folder_synchronize_sync ( 387 folder, delete_fetched, NULL, NULL); 388 } 389 390 camel_folder_free_uids (folder, folder_uids); 391 } 392 393 camel_uid_cache_destroy (cache); 394 395 if (local_error) 396 g_propagate_error (error, local_error); 397 } else { 398 em_filter_folder_element_exec (fm, cancellable, error); 399 } 400 401 /* we unref the source folder here since we 402 * may now block in finalize (we try to 403 * disconnect cleanly) */ 404 g_object_unref (fm->source_folder); 405 fm->source_folder = NULL; 406 407 exit: 408 if (!is_local_delivery && m->provider_unlock) 409 m->provider_unlock (uid); 410 411 /* we unref this here as it may have more work to do (syncing 412 * folders and whatnot) before we are really done */ 413 /* should this be cancellable too? (i.e. above unregister above) */ 414 if (fm->driver) { 415 g_object_unref (fm->driver); 416 fm->driver = NULL; 417 } 418 419 /* also disconnect if not a local delivery mbox; 420 * there is no need to keep the connection alive forever */ 421 if (!is_local_delivery) 422 camel_service_disconnect_sync ( 423 service, TRUE, cancellable, NULL); 424 } 425 426 static void 427 fetch_mail_done (struct _fetch_mail_msg *m) 428 { 429 if (m->done) 430 m->done (m->still_more, m->data); 431 } 432 433 static void 434 fetch_mail_free (struct _fetch_mail_msg *m) 435 { 436 if (m->store != NULL) 437 g_object_unref (m->store); 438 439 if (m->cancellable != NULL) 440 g_object_unref (m->cancellable); 441 442 em_filter_folder_element_free ((struct _filter_mail_msg *) m); 443 } 444 445 static MailMsgInfo fetch_mail_info = { 446 sizeof (struct _fetch_mail_msg), 447 (MailMsgDescFunc) fetch_mail_desc, 448 (MailMsgExecFunc) fetch_mail_exec, 449 (MailMsgDoneFunc) fetch_mail_done, 450 (MailMsgFreeFunc) fetch_mail_free 451 }; 452 453 /* ouch, a 'do everything' interface ... */ 454 void 455 mail_fetch_mail (CamelStore *store, 456 CamelFetchType fetch_type, 457 gint fetch_count, 458 const gchar *type, 459 MailProviderFetchLockFunc lock_func, 460 MailProviderFetchUnlockFunc unlock_func, 461 MailProviderFetchInboxFunc fetch_inbox_func, 462 GCancellable *cancellable, 463 CamelFilterGetFolderFunc get_folder, 464 gpointer get_data, 465 CamelFilterStatusFunc *status, 466 gpointer status_data, 467 void (*done)(gint still_more, 468 gpointer data), 469 gpointer data) 470 { 471 struct _fetch_mail_msg *m; 472 struct _filter_mail_msg *fm; 473 CamelSession *session; 474 475 g_return_if_fail (CAMEL_IS_STORE (store)); 476 477 session = camel_service_get_session (CAMEL_SERVICE (store)); 478 479 m = mail_msg_new (&fetch_mail_info); 480 fm = (struct _filter_mail_msg *) m; 481 fm->session = g_object_ref (session); 482 m->store = g_object_ref (store); 483 fm->cache = NULL; 484 if (cancellable) 485 m->cancellable = g_object_ref (cancellable); 486 m->done = done; 487 m->data = data; 488 489 m->fetch_count = fetch_count; 490 m->fetch_type = fetch_type; 491 m->still_more = -1; 492 493 m->provider_lock = lock_func; 494 m->provider_unlock = unlock_func; 495 m->provider_fetch_inbox = fetch_inbox_func; 496 497 fm->driver = camel_session_get_filter_driver (session, type, NULL); 498 camel_filter_driver_set_folder_func (fm->driver, get_folder, get_data); 499 if (status) 500 camel_filter_driver_set_status_func (fm->driver, status, status_data); 501 502 mail_msg_unordered_push (m); 503 } 504 505 /* ********************************************************************** */ 506 /* sending stuff */ 507 /* ** SEND MAIL *********************************************************** */ 508 509 static const gchar *normal_recipients[] = { 510 CAMEL_RECIPIENT_TYPE_TO, 511 CAMEL_RECIPIENT_TYPE_CC, 512 CAMEL_RECIPIENT_TYPE_BCC 513 }; 514 515 static const gchar *resent_recipients[] = { 516 CAMEL_RECIPIENT_TYPE_RESENT_TO, 517 CAMEL_RECIPIENT_TYPE_RESENT_CC, 518 CAMEL_RECIPIENT_TYPE_RESENT_BCC 519 }; 520 521 struct _send_queue_msg { 522 MailMsg base; 523 524 EMailSession *session; 525 CamelFolder *queue; 526 CamelTransport *transport; 527 528 CamelFilterDriver *driver; 529 530 /* we use camelfilterstatusfunc, even though its not the filter doing it */ 531 CamelFilterStatusFunc *status; 532 gpointer status_data; 533 534 void (*done)(gpointer data); 535 gpointer data; 536 }; 537 538 static void report_status (struct _send_queue_msg *m, 539 enum camel_filter_status_t status, 540 gint pc, 541 const gchar *desc, 542 ...); 543 544 static gboolean 545 get_submission_details_from_identity (EMailSession *session, 546 const gchar *identity_uid, 547 gchar **out_transport_uid, 548 gchar **out_sent_folder_uri) 549 { 550 ESource *source; 551 ESourceRegistry *registry; 552 ESourceExtension *extension; 553 const gchar *extension_name; 554 555 registry = e_mail_session_get_registry (session); 556 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; 557 source = e_source_registry_ref_source (registry, identity_uid); 558 559 if (source == NULL) 560 return FALSE; 561 562 if (!e_source_has_extension (source, extension_name)) { 563 g_object_unref (source); 564 return FALSE; 565 } 566 567 extension = e_source_get_extension (source, extension_name); 568 569 *out_sent_folder_uri = 570 e_source_mail_submission_dup_sent_folder ( 571 E_SOURCE_MAIL_SUBMISSION (extension)); 572 573 *out_transport_uid = 574 e_source_mail_submission_dup_transport_uid ( 575 E_SOURCE_MAIL_SUBMISSION (extension)); 576 577 g_object_unref (source); 578 579 return TRUE; 580 } 581 582 /* send 1 message to a specific transport */ 583 static void 584 mail_send_message (struct _send_queue_msg *m, 585 CamelFolder *queue, 586 const gchar *uid, 587 CamelTransport *transport, 588 CamelFilterDriver *driver, 589 GCancellable *cancellable, 590 GError **error) 591 { 592 CamelService *service; 593 const CamelInternetAddress *iaddr; 594 CamelAddress *from, *recipients; 595 CamelMessageInfo *info = NULL; 596 CamelProvider *provider = NULL; 597 gchar *transport_uid = NULL; 598 gchar *sent_folder_uri = NULL; 599 const gchar *resent_from, *tmp; 600 CamelFolder *folder = NULL; 601 GString *err = NULL; 602 struct _camel_header_raw *xev, *header; 603 CamelMimeMessage *message; 604 gint i; 605 GError *local_error = NULL; 606 607 message = camel_folder_get_message_sync ( 608 queue, uid, cancellable, error); 609 if (!message) 610 return; 611 612 camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer", x_mailer); 613 614 err = g_string_new (""); 615 xev = mail_tool_remove_xevolution_headers (message); 616 617 tmp = camel_header_raw_find (&xev, "X-Evolution-Identity", NULL); 618 if (tmp != NULL) { 619 gchar *identity_uid; 620 621 identity_uid = g_strstrip (g_strdup (tmp)); 622 get_submission_details_from_identity ( 623 m->session, identity_uid, 624 &transport_uid, &sent_folder_uri); 625 g_free (identity_uid); 626 } 627 628 tmp = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL); 629 if (transport_uid == NULL && tmp != NULL) 630 transport_uid = g_strstrip (g_strdup (tmp)); 631 632 tmp = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL); 633 if (sent_folder_uri == NULL && tmp != NULL) 634 sent_folder_uri = g_strstrip (g_strdup (tmp)); 635 636 service = camel_session_ref_service ( 637 CAMEL_SESSION (m->session), transport_uid); 638 if (service != NULL) 639 provider = camel_service_get_provider (service); 640 641 if (CAMEL_IS_TRANSPORT (service)) { 642 const gchar *tuid; 643 644 /* Let the dialog know the right account it is using. */ 645 tuid = camel_service_get_uid (CAMEL_SERVICE (transport)); 646 report_status (m, CAMEL_FILTER_STATUS_ACTION, 0, tuid); 647 } 648 649 /* Check for email sending */ 650 from = (CamelAddress *) camel_internet_address_new (); 651 resent_from = camel_medium_get_header (CAMEL_MEDIUM (message), "Resent-From"); 652 if (resent_from) { 653 camel_address_decode (from, resent_from); 654 } else { 655 iaddr = camel_mime_message_get_from (message); 656 camel_address_copy (from, CAMEL_ADDRESS (iaddr)); 657 } 658 659 recipients = (CamelAddress *) camel_internet_address_new (); 660 for (i = 0; i < 3; i++) { 661 const gchar *type; 662 663 type = resent_from ? resent_recipients[i] : normal_recipients[i]; 664 iaddr = camel_mime_message_get_recipients (message, type); 665 camel_address_cat (recipients, CAMEL_ADDRESS (iaddr)); 666 } 667 668 if (camel_address_length (recipients) > 0) { 669 if (!camel_service_connect_sync ( 670 service, cancellable, error)) 671 goto exit; 672 673 if (!camel_transport_send_to_sync ( 674 CAMEL_TRANSPORT (service), message, 675 from, recipients, cancellable, error)) 676 goto exit; 677 } 678 679 /* Now check for posting, failures are ignored */ 680 info = camel_message_info_new (NULL); 681 camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); 682 683 for (header = xev; header; header = header->next) { 684 gchar *uri; 685 686 if (strcmp (header->name, "X-Evolution-PostTo") != 0) 687 continue; 688 689 /* TODO: don't lose errors */ 690 691 uri = g_strstrip (g_strdup (header->value)); 692 /* FIXME Not passing a GCancellable or GError here. */ 693 folder = e_mail_session_uri_to_folder_sync ( 694 m->session, uri, 0, NULL, NULL); 695 if (folder) { 696 /* FIXME Not passing a GCancellable or GError here. */ 697 camel_folder_append_message_sync ( 698 folder, message, info, NULL, NULL, NULL); 699 g_object_unref (folder); 700 folder = NULL; 701 } 702 g_free (uri); 703 } 704 705 /* post process */ 706 mail_tool_restore_xevolution_headers (message, xev); 707 708 if (driver) { 709 camel_filter_driver_filter_message ( 710 driver, message, info, NULL, NULL, 711 NULL, "", cancellable, &local_error); 712 713 if (local_error != NULL) { 714 if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) 715 goto exit; 716 717 /* sending mail, filtering failed */ 718 g_string_append_printf ( 719 err, _("Failed to apply outgoing filters: %s"), 720 local_error->message); 721 722 g_clear_error (&local_error); 723 } 724 } 725 726 if (provider == NULL 727 || !(provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)) { 728 GError *local_error = NULL; 729 730 if (sent_folder_uri) { 731 folder = e_mail_session_uri_to_folder_sync ( 732 m->session, sent_folder_uri, 0, 733 cancellable, &local_error); 734 735 if (local_error != NULL) { 736 g_string_append_printf ( 737 err, _("Failed to append to %s: %s\n" 738 "Appending to local 'Sent' folder instead."), 739 sent_folder_uri, 740 local_error->message); 741 g_clear_error (&local_error); 742 } 743 } 744 745 if (!folder) { 746 folder = e_mail_session_get_local_folder ( 747 m->session, E_MAIL_LOCAL_FOLDER_SENT); 748 g_object_ref (folder); 749 } 750 751 if (!camel_folder_append_message_sync ( 752 folder, message, info, 753 NULL, cancellable, &local_error)) { 754 755 CamelFolder *sent_folder; 756 757 if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) 758 goto exit; 759 760 sent_folder = e_mail_session_get_local_folder ( 761 m->session, E_MAIL_LOCAL_FOLDER_SENT); 762 763 if (folder != sent_folder) { 764 const gchar *description; 765 766 description = camel_folder_get_description (folder); 767 if (err->len) 768 g_string_append (err, "\n\n"); 769 g_string_append_printf ( 770 err, _("Failed to append to %s: %s\n" 771 "Appending to local 'Sent' folder instead."), 772 description, local_error->message); 773 g_object_ref (sent_folder); 774 g_object_unref (folder); 775 folder = sent_folder; 776 777 g_clear_error (&local_error); 778 camel_folder_append_message_sync ( 779 folder, message, info, 780 NULL, cancellable, &local_error); 781 } 782 783 if (local_error != NULL) { 784 if (g_error_matches ( 785 local_error, G_IO_ERROR, 786 G_IO_ERROR_CANCELLED)) 787 goto exit; 788 789 if (err->len) 790 g_string_append (err, "\n\n"); 791 g_string_append_printf ( 792 err, _("Failed to append to " 793 "local 'Sent' folder: %s"), 794 local_error->message); 795 } 796 } 797 } 798 799 if (local_error == NULL) { 800 /* Mark the draft message for deletion, if present. */ 801 e_mail_session_handle_draft_headers_sync ( 802 m->session, message, cancellable, &local_error); 803 if (local_error != NULL) { 804 g_warning ( 805 "%s: Failed to handle draft headers: %s", 806 G_STRFUNC, local_error->message); 807 g_clear_error (&local_error); 808 } 809 810 /* Set flags on the original source message, if present. 811 * Source message refers to the message being forwarded 812 * or replied to. */ 813 e_mail_session_handle_source_headers_sync ( 814 m->session, message, cancellable, &local_error); 815 if (local_error != NULL) { 816 g_warning ( 817 "%s: Failed to handle source headers: %s", 818 G_STRFUNC, local_error->message); 819 g_clear_error (&local_error); 820 } 821 } 822 823 if (local_error == NULL) { 824 camel_folder_set_message_flags ( 825 queue, uid, CAMEL_MESSAGE_DELETED | 826 CAMEL_MESSAGE_SEEN, ~0); 827 /* Sync it to disk, since if it crashes in between, 828 * we keep sending it again on next start. */ 829 /* FIXME Not passing a GCancellable or GError here. */ 830 camel_folder_synchronize_sync (queue, FALSE, NULL, NULL); 831 } 832 833 if (err->len) { 834 /* set the culmulative exception report */ 835 g_set_error ( 836 &local_error, CAMEL_ERROR, 837 CAMEL_ERROR_GENERIC, "%s", err->str); 838 } 839 840 exit: 841 if (local_error != NULL) 842 g_propagate_error (error, local_error); 843 844 /* FIXME Not passing a GCancellable or GError here. */ 845 if (folder) { 846 camel_folder_synchronize_sync (folder, FALSE, NULL, NULL); 847 g_object_unref (folder); 848 } 849 if (info) 850 camel_message_info_free (info); 851 852 if (service != NULL) 853 g_object_unref (service); 854 855 g_object_unref (recipients); 856 g_object_unref (from); 857 g_free (sent_folder_uri); 858 g_free (transport_uid); 859 camel_header_raw_clear (&xev); 860 g_string_free (err, TRUE); 861 g_object_unref (message); 862 } 863 864 /* ** SEND MAIL QUEUE ***************************************************** */ 865 866 static void 867 report_status (struct _send_queue_msg *m, 868 enum camel_filter_status_t status, 869 gint pc, 870 const gchar *desc, 871 ...) 872 { 873 va_list ap; 874 gchar *str; 875 876 if (m->status) { 877 va_start (ap, desc); 878 str = g_strdup_vprintf (desc, ap); 879 va_end (ap); 880 m->status (m->driver, status, pc, str, m->status_data); 881 g_free (str); 882 } 883 } 884 885 static void 886 send_queue_exec (struct _send_queue_msg *m, 887 GCancellable *cancellable, 888 GError **error) 889 { 890 CamelFolder *sent_folder; 891 GPtrArray *uids, *send_uids = NULL; 892 gint i, j; 893 GError *local_error = NULL; 894 895 d (printf ("sending queue\n")); 896 897 sent_folder = 898 e_mail_session_get_local_folder ( 899 m->session, E_MAIL_LOCAL_FOLDER_SENT); 900 901 if (!(uids = camel_folder_get_uids (m->queue))) 902 return; 903 904 send_uids = g_ptr_array_sized_new (uids->len); 905 for (i = 0, j = 0; i < uids->len; i++) { 906 CamelMessageInfo *info; 907 908 info = camel_folder_get_message_info (m->queue, uids->pdata[i]); 909 if (info) { 910 if ((camel_message_info_flags (info) & CAMEL_MESSAGE_DELETED) == 0) 911 send_uids->pdata[j++] = uids->pdata[i]; 912 camel_folder_free_message_info (m->queue, info); 913 } 914 } 915 916 send_uids->len = j; 917 if (send_uids->len == 0) { 918 /* nothing to send */ 919 camel_folder_free_uids (m->queue, uids); 920 g_ptr_array_free (send_uids, TRUE); 921 return; 922 } 923 924 camel_operation_push_message (cancellable, _("Sending message")); 925 926 /* NB: This code somewhat abuses the 'exception' stuff. Apart from 927 * fatal problems, it is also used as a mechanism to accumualte 928 * warning messages and present them back to the user. */ 929 930 for (i = 0, j = 0; i < send_uids->len; i++) { 931 gint pc = (100 * i) / send_uids->len; 932 933 report_status ( 934 m, CAMEL_FILTER_STATUS_START, pc, 935 _("Sending message %d of %d"), i + 1, 936 send_uids->len); 937 938 camel_operation_progress ( 939 cancellable, (i + 1) * 100 / send_uids->len); 940 941 mail_send_message ( 942 m, m->queue, send_uids->pdata[i], m->transport, 943 m->driver, cancellable, &local_error); 944 if (local_error != NULL) { 945 if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { 946 /* merge exceptions into one */ 947 if (m->base.error != NULL) { 948 gchar *old_message; 949 950 old_message = g_strdup ( 951 m->base.error->message); 952 g_clear_error (&m->base.error); 953 g_set_error ( 954 &m->base.error, CAMEL_ERROR, 955 CAMEL_ERROR_GENERIC, 956 "%s\n\n%s", old_message, 957 local_error->message); 958 g_free (old_message); 959 960 g_clear_error (&local_error); 961 } else { 962 g_propagate_error (&m->base.error, local_error); 963 local_error = NULL; 964 } 965 966 /* keep track of the number of failures */ 967 j++; 968 } else { 969 /* transfer the USER_CANCEL error to the 970 * async op exception and then break */ 971 g_propagate_error (&m->base.error, local_error); 972 local_error = NULL; 973 break; 974 } 975 } 976 } 977 978 j += (send_uids->len - i); 979 980 if (j > 0) 981 report_status ( 982 m, CAMEL_FILTER_STATUS_END, 100, 983 /* Translators: The string is distinguished by total 984 * count of messages to be sent. Failed messages is 985 * always more than zero. */ 986 ngettext ( 987 "Failed to send a message", 988 "Failed to send %d of %d messages", 989 send_uids->len), 990 j, send_uids->len); 991 else if (g_error_matches ( 992 m->base.error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) 993 report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Canceled.")); 994 else 995 report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Complete.")); 996 997 if (m->driver) { 998 g_object_unref (m->driver); 999 m->driver = NULL; 1000 } 1001 1002 camel_folder_free_uids (m->queue, uids); 1003 g_ptr_array_free (send_uids, TRUE); 1004 1005 /* FIXME Not passing a GCancellable or GError here. */ 1006 if (j <= 0 && m->base.error == NULL) 1007 camel_folder_synchronize_sync (m->queue, TRUE, NULL, NULL); 1008 1009 /* FIXME Not passing a GCancellable or GError here. */ 1010 if (sent_folder) 1011 camel_folder_synchronize_sync (sent_folder, FALSE, NULL, NULL); 1012 1013 camel_operation_pop_message (cancellable); 1014 } 1015 1016 static void 1017 send_queue_done (struct _send_queue_msg *m) 1018 { 1019 if (m->done) 1020 m->done (m->data); 1021 } 1022 1023 static gchar * 1024 send_queue_desc (struct _send_queue_msg *m) 1025 { 1026 return g_strdup (_("Sending message")); 1027 } 1028 1029 static void 1030 send_queue_free (struct _send_queue_msg *m) 1031 { 1032 if (m->session != NULL) 1033 g_object_unref (m->session); 1034 if (m->driver != NULL) 1035 g_object_unref (m->driver); 1036 if (m->transport != NULL) 1037 g_object_unref (m->transport); 1038 g_object_unref (m->queue); 1039 } 1040 1041 static MailMsgInfo send_queue_info = { 1042 sizeof (struct _send_queue_msg), 1043 (MailMsgDescFunc) send_queue_desc, 1044 (MailMsgExecFunc) send_queue_exec, 1045 (MailMsgDoneFunc) send_queue_done, 1046 (MailMsgFreeFunc) send_queue_free 1047 }; 1048 1049 /* same interface as fetch_mail, just 'cause i'm lazy today 1050 * (and we need to run it from the same spot?) */ 1051 void 1052 mail_send_queue (EMailSession *session, 1053 CamelFolder *queue, 1054 CamelTransport *transport, 1055 const gchar *type, 1056 GCancellable *cancellable, 1057 CamelFilterGetFolderFunc get_folder, 1058 gpointer get_data, 1059 CamelFilterStatusFunc *status, 1060 gpointer status_data, 1061 void (*done)(gpointer data), 1062 gpointer data) 1063 { 1064 struct _send_queue_msg *m; 1065 1066 g_return_if_fail (E_IS_MAIL_SESSION (session)); 1067 1068 m = mail_msg_new (&send_queue_info); 1069 m->session = g_object_ref (session); 1070 m->queue = g_object_ref (queue); 1071 m->transport = g_object_ref (transport); 1072 if (G_IS_CANCELLABLE (cancellable)) 1073 m->base.cancellable = g_object_ref (cancellable); 1074 m->status = status; 1075 m->status_data = status_data; 1076 m->done = done; 1077 m->data = data; 1078 1079 m->driver = camel_session_get_filter_driver ( 1080 CAMEL_SESSION (session), type, NULL); 1081 camel_filter_driver_set_folder_func (m->driver, get_folder, get_data); 1082 1083 mail_msg_unordered_push (m); 1084 } 1085 1086 /* ** TRANSFER MESSAGES **************************************************** */ 1087 1088 struct _transfer_msg { 1089 MailMsg base; 1090 1091 EMailSession *session; 1092 CamelFolder *source; 1093 GPtrArray *uids; 1094 gboolean delete; 1095 gchar *dest_uri; 1096 guint32 dest_flags; 1097 1098 void (*done)(gboolean ok, gpointer data); 1099 gpointer data; 1100 }; 1101 1102 static gchar * 1103 transfer_messages_desc (struct _transfer_msg *m) 1104 { 1105 return g_strdup_printf ( 1106 m->delete ? 1107 _("Moving messages to '%s'") : 1108 _("Copying messages to '%s'"), 1109 m->dest_uri); 1110 1111 } 1112 1113 static void 1114 transfer_messages_exec (struct _transfer_msg *m, 1115 GCancellable *cancellable, 1116 GError **error) 1117 { 1118 CamelFolder *dest; 1119 1120 dest = e_mail_session_uri_to_folder_sync ( 1121 m->session, m->dest_uri, m->dest_flags, 1122 cancellable, error); 1123 if (dest == NULL) 1124 return; 1125 1126 if (dest == m->source) { 1127 g_object_unref (dest); 1128 /* no-op */ 1129 return; 1130 } 1131 1132 camel_folder_freeze (m->source); 1133 camel_folder_freeze (dest); 1134 1135 camel_folder_transfer_messages_to_sync ( 1136 m->source, m->uids, dest, m->delete, NULL, 1137 cancellable, error); 1138 1139 /* make sure all deleted messages are marked as seen */ 1140 1141 if (m->delete) { 1142 gint i; 1143 1144 for (i = 0; i < m->uids->len; i++) 1145 camel_folder_set_message_flags ( 1146 m->source, m->uids->pdata[i], 1147 CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); 1148 } 1149 1150 camel_folder_thaw (m->source); 1151 camel_folder_thaw (dest); 1152 1153 /* FIXME Not passing a GCancellable or GError here. */ 1154 camel_folder_synchronize_sync (dest, FALSE, NULL, NULL); 1155 g_object_unref (dest); 1156 } 1157 1158 static void 1159 transfer_messages_done (struct _transfer_msg *m) 1160 { 1161 if (m->done) 1162 m->done (m->base.error == NULL, m->data); 1163 } 1164 1165 static void 1166 transfer_messages_free (struct _transfer_msg *m) 1167 { 1168 g_object_unref (m->session); 1169 g_object_unref (m->source); 1170 g_free (m->dest_uri); 1171 em_utils_uids_free (m->uids); 1172 } 1173 1174 static MailMsgInfo transfer_messages_info = { 1175 sizeof (struct _transfer_msg), 1176 (MailMsgDescFunc) transfer_messages_desc, 1177 (MailMsgExecFunc) transfer_messages_exec, 1178 (MailMsgDoneFunc) transfer_messages_done, 1179 (MailMsgFreeFunc) transfer_messages_free 1180 }; 1181 1182 void 1183 mail_transfer_messages (EMailSession *session, 1184 CamelFolder *source, 1185 GPtrArray *uids, 1186 gboolean delete_from_source, 1187 const gchar *dest_uri, 1188 guint32 dest_flags, 1189 void (*done) (gboolean ok, 1190 gpointer data), 1191 gpointer data) 1192 { 1193 struct _transfer_msg *m; 1194 1195 g_return_if_fail (CAMEL_IS_FOLDER (source)); 1196 g_return_if_fail (uids != NULL); 1197 g_return_if_fail (dest_uri != NULL); 1198 1199 m = mail_msg_new (&transfer_messages_info); 1200 m->session = g_object_ref (session); 1201 m->source = g_object_ref (source); 1202 m->uids = uids; 1203 m->delete = delete_from_source; 1204 m->dest_uri = g_strdup (dest_uri); 1205 m->dest_flags = dest_flags; 1206 m->done = done; 1207 m->data = data; 1208 1209 mail_msg_slow_ordered_push (m); 1210 } 1211 1212 /* ** SYNC FOLDER ********************************************************* */ 1213 1214 struct _sync_folder_msg { 1215 MailMsg base; 1216 1217 CamelFolder *folder; 1218 void (*done) (CamelFolder *folder, gpointer data); 1219 gpointer data; 1220 }; 1221 1222 static gchar * 1223 sync_folder_desc (struct _sync_folder_msg *m) 1224 { 1225 return g_strdup_printf ( 1226 _("Storing folder '%s'"), 1227 camel_folder_get_full_name (m->folder)); 1228 } 1229 1230 static void 1231 sync_folder_exec (struct _sync_folder_msg *m, 1232 GCancellable *cancellable, 1233 GError **error) 1234 { 1235 camel_folder_synchronize_sync ( 1236 m->folder, FALSE, cancellable, error); 1237 } 1238 1239 static void 1240 sync_folder_done (struct _sync_folder_msg *m) 1241 { 1242 if (m->done) 1243 m->done (m->folder, m->data); 1244 } 1245 1246 static void 1247 sync_folder_free (struct _sync_folder_msg *m) 1248 { 1249 if (m->folder) 1250 g_object_unref (m->folder); 1251 } 1252 1253 static MailMsgInfo sync_folder_info = { 1254 sizeof (struct _sync_folder_msg), 1255 (MailMsgDescFunc) sync_folder_desc, 1256 (MailMsgExecFunc) sync_folder_exec, 1257 (MailMsgDoneFunc) sync_folder_done, 1258 (MailMsgFreeFunc) sync_folder_free 1259 }; 1260 1261 void 1262 mail_sync_folder (CamelFolder *folder, 1263 void (*done) (CamelFolder *folder, 1264 gpointer data), 1265 gpointer data) 1266 { 1267 struct _sync_folder_msg *m; 1268 1269 m = mail_msg_new (&sync_folder_info); 1270 m->folder = g_object_ref (folder); 1271 m->data = data; 1272 m->done = done; 1273 1274 mail_msg_slow_ordered_push (m); 1275 } 1276 1277 /* ** SYNC STORE ********************************************************* */ 1278 1279 struct _sync_store_msg { 1280 MailMsg base; 1281 1282 CamelStore *store; 1283 gint expunge; 1284 void (*done) (CamelStore *store, gpointer data); 1285 gpointer data; 1286 }; 1287 1288 static gchar * 1289 sync_store_desc (struct _sync_store_msg *m) 1290 { 1291 CamelURL *url; 1292 gchar *uri, *res; 1293 1294 url = camel_service_new_camel_url (CAMEL_SERVICE (m->store)); 1295 uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); 1296 camel_url_free (url); 1297 1298 res = g_strdup_printf ( 1299 m->expunge ? 1300 _("Expunging and storing account '%s'") : 1301 _("Storing account '%s'"), 1302 uri); 1303 g_free (uri); 1304 1305 return res; 1306 } 1307 1308 static void 1309 sync_store_exec (struct _sync_store_msg *m, 1310 GCancellable *cancellable, 1311 GError **error) 1312 { 1313 camel_store_synchronize_sync ( 1314 m->store, m->expunge, 1315 cancellable, error); 1316 } 1317 1318 static void 1319 sync_store_done (struct _sync_store_msg *m) 1320 { 1321 if (m->done) 1322 m->done (m->store, m->data); 1323 } 1324 1325 static void 1326 sync_store_free (struct _sync_store_msg *m) 1327 { 1328 g_object_unref (m->store); 1329 } 1330 1331 static MailMsgInfo sync_store_info = { 1332 sizeof (struct _sync_store_msg), 1333 (MailMsgDescFunc) sync_store_desc, 1334 (MailMsgExecFunc) sync_store_exec, 1335 (MailMsgDoneFunc) sync_store_done, 1336 (MailMsgFreeFunc) sync_store_free 1337 }; 1338 1339 void 1340 mail_sync_store (CamelStore *store, 1341 gint expunge, 1342 void (*done) (CamelStore *store, 1343 gpointer data), 1344 gpointer data) 1345 { 1346 struct _sync_store_msg *m; 1347 1348 m = mail_msg_new (&sync_store_info); 1349 m->store = g_object_ref (store); 1350 m->expunge = expunge; 1351 m->data = data; 1352 m->done = done; 1353 1354 mail_msg_slow_ordered_push (m); 1355 } 1356 1357 /* ******************************************************************************** */ 1358 1359 struct _empty_trash_msg { 1360 MailMsg base; 1361 1362 CamelStore *store; 1363 }; 1364 1365 static gchar * 1366 empty_trash_desc (struct _empty_trash_msg *m) 1367 { 1368 CamelService *service; 1369 const gchar *display_name; 1370 1371 service = CAMEL_SERVICE (m->store); 1372 display_name = camel_service_get_display_name (service); 1373 1374 return g_strdup_printf ( 1375 _("Emptying trash in '%s'"), display_name); 1376 } 1377 1378 static void 1379 empty_trash_exec (struct _empty_trash_msg *m, 1380 GCancellable *cancellable, 1381 GError **error) 1382 { 1383 CamelService *service; 1384 CamelFolder *trash; 1385 1386 service = CAMEL_SERVICE (m->store); 1387 1388 if (!camel_service_connect_sync (service, cancellable, error)) 1389 return; 1390 1391 trash = camel_store_get_trash_folder_sync ( 1392 m->store, cancellable, error); 1393 1394 if (trash != NULL) { 1395 e_mail_folder_expunge_sync (trash, cancellable, error); 1396 g_object_unref (trash); 1397 } 1398 } 1399 1400 static void 1401 empty_trash_done (struct _empty_trash_msg *m) 1402 { 1403 } 1404 1405 static void 1406 empty_trash_free (struct _empty_trash_msg *m) 1407 { 1408 if (m->store) 1409 g_object_unref (m->store); 1410 } 1411 1412 static MailMsgInfo empty_trash_info = { 1413 sizeof (struct _empty_trash_msg), 1414 (MailMsgDescFunc) empty_trash_desc, 1415 (MailMsgExecFunc) empty_trash_exec, 1416 (MailMsgDoneFunc) empty_trash_done, 1417 (MailMsgFreeFunc) empty_trash_free 1418 }; 1419 1420 void 1421 mail_empty_trash (CamelStore *store) 1422 { 1423 struct _empty_trash_msg *m; 1424 1425 g_return_if_fail (CAMEL_IS_STORE (store)); 1426 1427 m = mail_msg_new (&empty_trash_info); 1428 m->store = g_object_ref (store); 1429 1430 mail_msg_slow_ordered_push (m); 1431 } 1432 1433 /* ** Execute Shell Command ************************************************ */ 1434 1435 void 1436 mail_execute_shell_command (CamelFilterDriver *driver, 1437 gint argc, 1438 gchar **argv, 1439 gpointer data) 1440 { 1441 if (argc <= 0) 1442 return; 1443 1444 g_spawn_async (NULL, argv, NULL, 0, NULL, data, NULL, NULL); 1445 }