evolution-3.6.4/mail/mail-send-recv.c

No issues found

   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  *		Michael Zucchi <NotZed@ximian.com>
  18  *
  19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  20  *
  21  */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include <config.h>
  25 #endif
  26 
  27 #include <stdio.h>
  28 #include <string.h>
  29 
  30 #include <glib/gi18n.h>
  31 
  32 #include <shell/e-shell.h>
  33 #include <e-util/e-util.h>
  34 
  35 #include <libemail-utils/mail-mt.h>
  36 
  37 /* This is our hack, not part of libcamel. */
  38 #include <libemail-engine/camel-null-store.h>
  39 
  40 #include <libemail-engine/e-mail-folder-utils.h>
  41 #include <libemail-engine/e-mail-session.h>
  42 #include <libemail-engine/mail-folder-cache.h>
  43 #include <libemail-engine/mail-ops.h>
  44 #include <libemail-engine/mail-tools.h>
  45 
  46 #include "e-mail-account-store.h"
  47 #include "e-mail-ui-session.h"
  48 #include "em-event.h"
  49 #include "em-filter-rule.h"
  50 #include "em-utils.h"
  51 #include "mail-send-recv.h"
  52 
  53 #define d(x)
  54 
  55 /* ms between status updates to the gui */
  56 #define STATUS_TIMEOUT (250)
  57 
  58 /* pseudo-uri to key the send task on */
  59 #define SEND_URI_KEY "send-task:"
  60 
  61 #define SEND_RECV_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
  62 
  63 /* send/receive email */
  64 
  65 /* ********************************************************************** */
  66 /*  This stuff below is independent of the stuff above */
  67 
  68 /* this stuff is used to keep track of which folders filters have accessed, and
  69  * what not. the thaw/refreeze thing doesn't really seem to work though */
  70 struct _folder_info {
  71 	gchar *uri;
  72 	CamelFolder *folder;
  73 	time_t update;
  74 
  75 	/* How many times updated, to slow it
  76 	 * down as we go, if we have lots. */
  77 	gint count;
  78 };
  79 
  80 struct _send_data {
  81 	GList *infos;
  82 
  83 	GtkDialog *gd;
  84 	gint cancelled;
  85 
  86 	/* Since we're never asked to update
  87 	 * this one, do it ourselves. */
  88 	CamelFolder *inbox;
  89 	time_t inbox_update;
  90 
  91 	GMutex *lock;
  92 	GHashTable *folders;
  93 
  94 	GHashTable *active;	/* send_info's by uri */
  95 };
  96 
  97 typedef enum {
  98 	SEND_RECEIVE,		/* receiver */
  99 	SEND_SEND,		/* sender */
 100 	SEND_UPDATE,		/* imap-like 'just update folder info' */
 101 	SEND_INVALID
 102 } send_info_t;
 103 
 104 typedef enum {
 105 	SEND_ACTIVE,
 106 	SEND_CANCELLED,
 107 	SEND_COMPLETE
 108 } send_state_t;
 109 
 110 struct _send_info {
 111 	send_info_t type;		/* 0 = fetch, 1 = send */
 112 	GCancellable *cancellable;
 113 	CamelSession *session;
 114 	CamelService *service;
 115 	gboolean keep_on_server;
 116 	send_state_t state;
 117 	GtkWidget *progress_bar;
 118 	GtkWidget *cancel_button;
 119 
 120 	gint again;		/* need to run send again */
 121 
 122 	gint timeout_id;
 123 	gchar *what;
 124 	gint pc;
 125 
 126 	GtkWidget *send_account_label;
 127 	gchar *send_url;
 128 
 129 	/*time_t update;*/
 130 	struct _send_data *data;
 131 };
 132 
 133 static CamelFolder *
 134 		receive_get_folder		(CamelFilterDriver *d,
 135 						 const gchar *uri,
 136 						 gpointer data,
 137 						 GError **error);
 138 static void	send_done (gpointer data);
 139 
 140 static struct _send_data *send_data = NULL;
 141 static GtkWidget *send_recv_dialog = NULL;
 142 
 143 static void
 144 free_folder_info (struct _folder_info *info)
 145 {
 146 	/*camel_folder_thaw (info->folder);	*/
 147 	mail_sync_folder (info->folder, NULL, NULL);
 148 	g_object_unref (info->folder);
 149 	g_free (info->uri);
 150 	g_free (info);
 151 }
 152 
 153 static void
 154 free_send_info (struct _send_info *info)
 155 {
 156 	if (info->cancellable != NULL)
 157 		g_object_unref (info->cancellable);
 158 	if (info->session != NULL)
 159 		g_object_unref (info->session);
 160 	if (info->service != NULL)
 161 		g_object_unref (info->service);
 162 	if (info->timeout_id != 0)
 163 		g_source_remove (info->timeout_id);
 164 	g_free (info->what);
 165 	g_free (info->send_url);
 166 	g_free (info);
 167 }
 168 
 169 static struct _send_data *
 170 setup_send_data (EMailSession *session)
 171 {
 172 	struct _send_data *data;
 173 
 174 	if (send_data == NULL) {
 175 		send_data = data = g_malloc0 (sizeof (*data));
 176 		data->lock = g_mutex_new ();
 177 		data->folders = g_hash_table_new_full (
 178 			g_str_hash, g_str_equal,
 179 			(GDestroyNotify) NULL,
 180 			(GDestroyNotify) free_folder_info);
 181 		data->inbox =
 182 			e_mail_session_get_local_folder (
 183 			session, E_MAIL_LOCAL_FOLDER_LOCAL_INBOX);
 184 		g_object_ref (data->inbox);
 185 		data->active = g_hash_table_new_full (
 186 			g_str_hash, g_str_equal,
 187 			(GDestroyNotify) g_free,
 188 			(GDestroyNotify) free_send_info);
 189 	}
 190 
 191 	return send_data;
 192 }
 193 
 194 static void
 195 receive_cancel (GtkButton *button,
 196                 struct _send_info *info)
 197 {
 198 	if (info->state == SEND_ACTIVE) {
 199 		g_cancellable_cancel (info->cancellable);
 200 		if (info->progress_bar != NULL)
 201 			gtk_progress_bar_set_text (
 202 				GTK_PROGRESS_BAR (info->progress_bar),
 203 				_("Canceling..."));
 204 		info->state = SEND_CANCELLED;
 205 	}
 206 	if (info->cancel_button)
 207 		gtk_widget_set_sensitive (info->cancel_button, FALSE);
 208 }
 209 
 210 static void
 211 free_send_data (void)
 212 {
 213 	struct _send_data *data = send_data;
 214 
 215 	g_return_if_fail (g_hash_table_size (data->active) == 0);
 216 
 217 	if (data->inbox) {
 218 		mail_sync_folder (data->inbox, NULL, NULL);
 219 		/*camel_folder_thaw (data->inbox);		*/
 220 		g_object_unref (data->inbox);
 221 	}
 222 
 223 	g_list_free (data->infos);
 224 	g_hash_table_destroy (data->active);
 225 	g_hash_table_destroy (data->folders);
 226 	g_mutex_free (data->lock);
 227 	g_free (data);
 228 	send_data = NULL;
 229 }
 230 
 231 static void
 232 cancel_send_info (gpointer key,
 233                   struct _send_info *info,
 234                   gpointer data)
 235 {
 236 	receive_cancel (GTK_BUTTON (info->cancel_button), info);
 237 }
 238 
 239 static void
 240 hide_send_info (gpointer key,
 241                 struct _send_info *info,
 242                 gpointer data)
 243 {
 244 	info->cancel_button = NULL;
 245 	info->progress_bar = NULL;
 246 
 247 	if (info->timeout_id != 0) {
 248 		g_source_remove (info->timeout_id);
 249 		info->timeout_id = 0;
 250 	}
 251 }
 252 
 253 static void
 254 dialog_destroy_cb (struct _send_data *data,
 255                    GObject *deadbeef)
 256 {
 257 	g_hash_table_foreach (data->active, (GHFunc) hide_send_info, NULL);
 258 	data->gd = NULL;
 259 	send_recv_dialog = NULL;
 260 }
 261 
 262 static void
 263 dialog_response (GtkDialog *gd,
 264                  gint button,
 265                  struct _send_data *data)
 266 {
 267 	switch (button) {
 268 	case GTK_RESPONSE_CANCEL:
 269 		d (printf ("cancelled whole thing\n"));
 270 		if (!data->cancelled) {
 271 			data->cancelled = TRUE;
 272 			g_hash_table_foreach (data->active, (GHFunc) cancel_send_info, NULL);
 273 		}
 274 		gtk_dialog_set_response_sensitive (gd, GTK_RESPONSE_CANCEL, FALSE);
 275 		break;
 276 	default:
 277 		d (printf ("hiding dialog\n"));
 278 		g_hash_table_foreach (data->active, (GHFunc) hide_send_info, NULL);
 279 		data->gd = NULL;
 280 		/*gtk_widget_destroy((GtkWidget *)gd);*/
 281 		break;
 282 	}
 283 }
 284 
 285 static GStaticMutex status_lock = G_STATIC_MUTEX_INIT;
 286 static gchar *format_service_name (CamelService *service);
 287 
 288 static gint
 289 operation_status_timeout (gpointer data)
 290 {
 291 	struct _send_info *info = data;
 292 
 293 	if (info->progress_bar) {
 294 		GtkProgressBar *progress_bar;
 295 
 296 		g_static_mutex_lock (&status_lock);
 297 
 298 		progress_bar = GTK_PROGRESS_BAR (info->progress_bar);
 299 
 300 		gtk_progress_bar_set_fraction (progress_bar, info->pc / 100.0);
 301 		if (info->what != NULL)
 302 			gtk_progress_bar_set_text (progress_bar, info->what);
 303 		if (info->service != NULL && info->send_account_label) {
 304 			gchar *tmp = format_service_name (info->service);
 305 
 306 			gtk_label_set_markup (
 307 				GTK_LABEL (info->send_account_label), tmp);
 308 
 309 			g_free (tmp);
 310 		}
 311 
 312 		g_static_mutex_unlock (&status_lock);
 313 
 314 		return TRUE;
 315 	}
 316 
 317 	return FALSE;
 318 }
 319 
 320 static void
 321 set_send_status (struct _send_info *info,
 322                  const gchar *desc,
 323                  gint pc)
 324 {
 325 	g_static_mutex_lock (&status_lock);
 326 
 327 	g_free (info->what);
 328 	info->what = g_strdup (desc);
 329 	info->pc = pc;
 330 
 331 	g_static_mutex_unlock (&status_lock);
 332 }
 333 
 334 static void
 335 set_transport_service (struct _send_info *info,
 336                        const gchar *transport_uid)
 337 {
 338 	CamelService *service;
 339 
 340 	g_static_mutex_lock (&status_lock);
 341 
 342 	service = camel_session_ref_service (info->session, transport_uid);
 343 
 344 	if (CAMEL_IS_TRANSPORT (service)) {
 345 		if (info->service != NULL)
 346 			g_object_unref (info->service);
 347 		info->service = g_object_ref (service);
 348 	}
 349 
 350 	if (service != NULL)
 351 		g_object_unref (service);
 352 
 353 	g_static_mutex_unlock (&status_lock);
 354 }
 355 
 356 /* for camel operation status */
 357 static void
 358 operation_status (CamelOperation *op,
 359                   const gchar *what,
 360                   gint pc,
 361                   struct _send_info *info)
 362 {
 363 	set_send_status (info, what, pc);
 364 }
 365 
 366 static gchar *
 367 format_service_name (CamelService *service)
 368 {
 369 	CamelProvider *provider;
 370 	CamelSettings *settings;
 371 	gchar *service_name = NULL;
 372 	const gchar *display_name;
 373 	gchar *pretty_url = NULL;
 374 	gchar *host = NULL;
 375 	gchar *path = NULL;
 376 	gchar *user = NULL;
 377 	gchar *cp;
 378 	gboolean have_host = FALSE;
 379 	gboolean have_path = FALSE;
 380 	gboolean have_user = FALSE;
 381 
 382 	provider = camel_service_get_provider (service);
 383 	display_name = camel_service_get_display_name (service);
 384 
 385 	settings = camel_service_ref_settings (service);
 386 
 387 	if (CAMEL_IS_NETWORK_SETTINGS (settings)) {
 388 		host = camel_network_settings_dup_host (
 389 			CAMEL_NETWORK_SETTINGS (settings));
 390 		have_host = (host != NULL) && (*host != '\0');
 391 
 392 		user = camel_network_settings_dup_user (
 393 			CAMEL_NETWORK_SETTINGS (settings));
 394 		have_user = (user != NULL) && (*user != '\0');
 395 	}
 396 
 397 	if (CAMEL_IS_LOCAL_SETTINGS (settings)) {
 398 		path = camel_local_settings_dup_path (
 399 			CAMEL_LOCAL_SETTINGS (settings));
 400 		have_path = (path != NULL) && (*path != '\0');
 401 	}
 402 
 403 	g_object_unref (settings);
 404 
 405 	/* Shorten user names with '@', since multiple '@' in a
 406 	 * 'user@host' label look weird.  This is just supposed
 407 	 * to be a hint anyway so it doesn't matter if it's not
 408 	 * strictly correct. */
 409 	if (have_user && (cp = strchr (user, '@')) != NULL)
 410 		*cp = '\0';
 411 
 412 	g_return_val_if_fail (provider != NULL, NULL);
 413 
 414 	/* This should never happen, but if the service has no
 415 	 * display name, fall back to the generic service name. */
 416 	if (display_name == NULL || *display_name == '\0') {
 417 		service_name = camel_service_get_name (service, TRUE);
 418 		display_name = service_name;
 419 	}
 420 
 421 	if (have_host && have_user) {
 422 		pretty_url = g_markup_printf_escaped (
 423 			"<b>%s</b> <small>(%s@%s)</small>",
 424 			display_name, user, host);
 425 	} else if (have_host) {
 426 		pretty_url = g_markup_printf_escaped (
 427 			"<b>%s</b> <small>(%s)</small>",
 428 			display_name, host);
 429 	} else if (have_path) {
 430 		pretty_url = g_markup_printf_escaped (
 431 			"<b>%s</b> <small>(%s)</small>",
 432 			display_name, path);
 433 	} else {
 434 		pretty_url = g_markup_printf_escaped (
 435 			"<b>%s</b>", display_name);
 436 	}
 437 
 438 	g_free (service_name);
 439 	g_free (host);
 440 	g_free (path);
 441 	g_free (user);
 442 
 443 	return pretty_url;
 444 }
 445 
 446 static send_info_t
 447 get_receive_type (CamelService *service)
 448 {
 449 	CamelURL *url;
 450 	CamelProvider *provider;
 451 	const gchar *uid;
 452 	gboolean is_local_delivery;
 453 
 454 	/* Disregard CamelNullStores. */
 455 	if (CAMEL_IS_NULL_STORE (service))
 456 		return SEND_INVALID;
 457 
 458 	url = camel_service_new_camel_url (service);
 459 	is_local_delivery = em_utils_is_local_delivery_mbox_file (url);
 460 	camel_url_free (url);
 461 
 462 	/* mbox pointing to a file is a 'Local delivery'
 463 	 * source which requires special processing. */
 464 	if (is_local_delivery)
 465 		return SEND_RECEIVE;
 466 
 467 	provider = camel_service_get_provider (service);
 468 
 469 	if (provider == NULL)
 470 		return SEND_INVALID;
 471 
 472 	/* skip some well-known services */
 473 	uid = camel_service_get_uid (service);
 474 	if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0)
 475 		return SEND_INVALID;
 476 	if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0)
 477 		return SEND_INVALID;
 478 
 479 	if (provider->object_types[CAMEL_PROVIDER_STORE]) {
 480 		if (provider->flags & CAMEL_PROVIDER_IS_STORAGE)
 481 			return SEND_UPDATE;
 482 		else
 483 			return SEND_RECEIVE;
 484 	}
 485 
 486 	if (provider->object_types[CAMEL_PROVIDER_TRANSPORT])
 487 		return SEND_SEND;
 488 
 489 	return SEND_INVALID;
 490 }
 491 
 492 static gboolean
 493 get_keep_on_server (CamelService *service)
 494 {
 495 	GObjectClass *class;
 496 	CamelSettings *settings;
 497 	gboolean keep_on_server = FALSE;
 498 
 499 	settings = camel_service_ref_settings (service);
 500 	class = G_OBJECT_GET_CLASS (settings);
 501 
 502 	/* XXX This is a POP3-specific setting. */
 503 	if (g_object_class_find_property (class, "keep-on-server") != NULL)
 504 		g_object_get (
 505 			settings, "keep-on-server",
 506 			&keep_on_server, NULL);
 507 
 508 	g_object_unref (settings);
 509 
 510 	return keep_on_server;
 511 }
 512 
 513 static struct _send_data *
 514 build_dialog (GtkWindow *parent,
 515               EMailSession *session,
 516               CamelFolder *outbox,
 517               CamelService *transport,
 518               gboolean allow_send)
 519 {
 520 	GtkDialog *gd;
 521 	GtkWidget *wgrid;
 522 	GtkGrid *grid;
 523 	gint row;
 524 	GList *list = NULL;
 525 	struct _send_data *data;
 526 	GtkWidget *container;
 527 	GtkWidget *send_icon;
 528 	GtkWidget *recv_icon;
 529 	GtkWidget *scrolled_window;
 530 	GtkWidget *label;
 531 	GtkWidget *progress_bar;
 532 	GtkWidget *cancel_button;
 533 	EMailAccountStore *account_store;
 534 	struct _send_info *info;
 535 	gchar *pretty_url;
 536 	EMEventTargetSendReceive *target;
 537 	GQueue queue = G_QUEUE_INIT;
 538 
 539 	account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session));
 540 
 541 	send_recv_dialog = gtk_dialog_new ();
 542 
 543 	gd = GTK_DIALOG (send_recv_dialog);
 544 	gtk_window_set_modal (GTK_WINDOW (send_recv_dialog), FALSE);
 545 	gtk_window_set_icon_name (GTK_WINDOW (gd), "mail-send-receive");
 546 	gtk_window_set_default_size (GTK_WINDOW (gd), 600, 200);
 547 	gtk_window_set_title (GTK_WINDOW (gd), _("Send & Receive Mail"));
 548 	gtk_window_set_transient_for (GTK_WINDOW (gd), parent);
 549 
 550 	e_restore_window (
 551 		GTK_WINDOW (gd),
 552 		"/org/gnome/evolution/mail/send-recv-window/",
 553 		E_RESTORE_WINDOW_SIZE);
 554 
 555 	gtk_widget_ensure_style ((GtkWidget *) gd);
 556 
 557 	container = gtk_dialog_get_action_area (gd);
 558 	gtk_container_set_border_width (GTK_CONTAINER (container), 6);
 559 
 560 	container = gtk_dialog_get_content_area (gd);
 561 	gtk_container_set_border_width (GTK_CONTAINER (container), 0);
 562 
 563 	cancel_button = gtk_button_new_with_mnemonic (_("Cancel _All"));
 564 	gtk_button_set_image (
 565 		GTK_BUTTON (cancel_button),
 566 		gtk_image_new_from_stock (
 567 			GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON));
 568 	gtk_widget_show (cancel_button);
 569 	gtk_dialog_add_action_widget (gd, cancel_button, GTK_RESPONSE_CANCEL);
 570 
 571 	wgrid = gtk_grid_new ();
 572 	grid = GTK_GRID (wgrid);
 573 	gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
 574 	gtk_grid_set_column_spacing (grid, 6);
 575 
 576 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 577 	gtk_container_set_border_width (
 578 		GTK_CONTAINER (scrolled_window), 6);
 579 	gtk_scrolled_window_set_policy (
 580 		GTK_SCROLLED_WINDOW (scrolled_window),
 581 		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 582 	gtk_widget_set_size_request (scrolled_window, 50, 50);
 583 
 584 	container = gtk_dialog_get_content_area (gd);
 585 	gtk_scrolled_window_add_with_viewport (
 586 		GTK_SCROLLED_WINDOW (scrolled_window), wgrid);
 587 	gtk_box_pack_start (
 588 		GTK_BOX (container), scrolled_window, TRUE, TRUE, 0);
 589 	gtk_widget_show (scrolled_window);
 590 
 591 	/* must bet setup after send_recv_dialog as it may re-trigger send-recv button */
 592 	data = setup_send_data (session);
 593 
 594 	row = 0;
 595 	e_mail_account_store_queue_enabled_services (account_store, &queue);
 596 	while (!g_queue_is_empty (&queue)) {
 597 		CamelService *service;
 598 		const gchar *uid;
 599 
 600 		service = g_queue_pop_head (&queue);
 601 		uid = camel_service_get_uid (service);
 602 
 603 		/* see if we have an outstanding download active */
 604 		info = g_hash_table_lookup (data->active, uid);
 605 		if (info == NULL) {
 606 			send_info_t type = SEND_INVALID;
 607 
 608 			type = get_receive_type (service);
 609 
 610 			if (type == SEND_INVALID || type == SEND_SEND)
 611 				continue;
 612 
 613 			info = g_malloc0 (sizeof (*info));
 614 			info->type = type;
 615 			info->session = g_object_ref (session);
 616 			info->service = g_object_ref (service);
 617 			info->keep_on_server = get_keep_on_server (service);
 618 			info->cancellable = camel_operation_new ();
 619 			info->state = allow_send ? SEND_ACTIVE : SEND_COMPLETE;
 620 			info->timeout_id = g_timeout_add (
 621 				STATUS_TIMEOUT, operation_status_timeout, info);
 622 
 623 			g_signal_connect (
 624 				info->cancellable, "status",
 625 				G_CALLBACK (operation_status), info);
 626 
 627 			g_hash_table_insert (
 628 				data->active, g_strdup (uid), info);
 629 			list = g_list_prepend (list, info);
 630 
 631 		} else if (info->progress_bar != NULL) {
 632 			/* incase we get the same source pop up again */
 633 			continue;
 634 
 635 		} else if (info->timeout_id == 0)
 636 			info->timeout_id = g_timeout_add (
 637 				STATUS_TIMEOUT, operation_status_timeout, info);
 638 
 639 		recv_icon = gtk_image_new_from_icon_name (
 640 			"mail-inbox", SEND_RECV_ICON_SIZE);
 641 		gtk_widget_set_valign (recv_icon, GTK_ALIGN_START);
 642 
 643 		pretty_url = format_service_name (service);
 644 		label = gtk_label_new (NULL);
 645 		gtk_label_set_ellipsize (
 646 			GTK_LABEL (label), PANGO_ELLIPSIZE_END);
 647 		gtk_label_set_markup (GTK_LABEL (label), pretty_url);
 648 		g_free (pretty_url);
 649 
 650 		progress_bar = gtk_progress_bar_new ();
 651 		gtk_progress_bar_set_show_text (
 652 			GTK_PROGRESS_BAR (progress_bar), TRUE);
 653 		gtk_progress_bar_set_text (
 654 			GTK_PROGRESS_BAR (progress_bar),
 655 			(info->type == SEND_UPDATE) ?
 656 			_("Updating...") : _("Waiting..."));
 657 		gtk_widget_set_margin_bottom (progress_bar, 12);
 658 
 659 		cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
 660 		gtk_widget_set_valign (cancel_button, GTK_ALIGN_END);
 661 		gtk_widget_set_margin_bottom (cancel_button, 12);
 662 
 663 		/* g_object_set(data->label, "bold", TRUE, NULL); */
 664 		gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
 665 
 666 		gtk_widget_set_hexpand (label, TRUE);
 667 		gtk_widget_set_halign (label, GTK_ALIGN_FILL);
 668 
 669 		gtk_grid_attach (grid, recv_icon, 0, row, 1, 2);
 670 		gtk_grid_attach (grid, label, 1, row, 1, 1);
 671 		gtk_grid_attach (grid, progress_bar, 1, row + 1, 1, 1);
 672 		gtk_grid_attach (grid, cancel_button, 2, row, 1, 2);
 673 
 674 		info->progress_bar = progress_bar;
 675 		info->cancel_button = cancel_button;
 676 		info->data = data;
 677 
 678 		g_signal_connect (
 679 			cancel_button, "clicked",
 680 			G_CALLBACK (receive_cancel), info);
 681 
 682 		row = row + 2;
 683 	}
 684 
 685 	/* we also need gd during emition to be able to catch Cancel All */
 686 	data->gd = gd;
 687 	target = em_event_target_new_send_receive (
 688 		em_event_peek (), wgrid, data, row, EM_EVENT_SEND_RECEIVE);
 689 	e_event_emit (
 690 		(EEvent *) em_event_peek (), "mail.sendreceive",
 691 		(EEventTarget *) target);
 692 
 693 	/* Skip displaying the SMTP row if we've got no outbox,
 694 	 * outgoing account or unsent mails. */
 695 	if (allow_send && outbox && CAMEL_IS_TRANSPORT (transport)
 696 	 && (camel_folder_get_message_count (outbox) -
 697 		camel_folder_get_deleted_message_count (outbox)) != 0) {
 698 
 699 		info = g_hash_table_lookup (data->active, SEND_URI_KEY);
 700 		if (info == NULL) {
 701 			info = g_malloc0 (sizeof (*info));
 702 			info->type = SEND_SEND;
 703 			info->session = g_object_ref (session);
 704 			info->service = g_object_ref (transport);
 705 			info->keep_on_server = FALSE;
 706 			info->cancellable = camel_operation_new ();
 707 			info->state = SEND_ACTIVE;
 708 			info->timeout_id = g_timeout_add (
 709 				STATUS_TIMEOUT, operation_status_timeout, info);
 710 
 711 			g_signal_connect (
 712 				info->cancellable, "status",
 713 				G_CALLBACK (operation_status), info);
 714 
 715 			g_hash_table_insert (
 716 				data->active, g_strdup (SEND_URI_KEY), info);
 717 			list = g_list_prepend (list, info);
 718 		} else if (info->timeout_id == 0)
 719 			info->timeout_id = g_timeout_add (
 720 				STATUS_TIMEOUT, operation_status_timeout, info);
 721 
 722 		send_icon = gtk_image_new_from_icon_name (
 723 			"mail-outbox", SEND_RECV_ICON_SIZE);
 724 		gtk_widget_set_valign (send_icon, GTK_ALIGN_START);
 725 
 726 		pretty_url = format_service_name (transport);
 727 		label = gtk_label_new (NULL);
 728 		gtk_label_set_ellipsize (
 729 			GTK_LABEL (label), PANGO_ELLIPSIZE_END);
 730 		gtk_label_set_markup (GTK_LABEL (label), pretty_url);
 731 		g_free (pretty_url);
 732 
 733 		progress_bar = gtk_progress_bar_new ();
 734 		gtk_progress_bar_set_show_text (
 735 			GTK_PROGRESS_BAR (progress_bar), TRUE);
 736 		gtk_progress_bar_set_text (
 737 			GTK_PROGRESS_BAR (progress_bar), _("Waiting..."));
 738 		gtk_widget_set_margin_bottom (progress_bar, 12);
 739 
 740 		cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
 741 		gtk_widget_set_valign (cancel_button, GTK_ALIGN_END);
 742 
 743 		gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
 744 
 745 		gtk_widget_set_hexpand (label, TRUE);
 746 		gtk_widget_set_halign (label, GTK_ALIGN_FILL);
 747 
 748 		gtk_grid_attach (grid, send_icon, 0, row, 1, 2);
 749 		gtk_grid_attach (grid, label, 1, row, 1, 1);
 750 		gtk_grid_attach (grid, progress_bar, 1, row + 1, 1, 1);
 751 		gtk_grid_attach (grid, cancel_button, 2, row, 1, 2);
 752 
 753 		info->progress_bar = progress_bar;
 754 		info->cancel_button = cancel_button;
 755 		info->data = data;
 756 		info->send_account_label = label;
 757 
 758 		g_signal_connect (
 759 			cancel_button, "clicked",
 760 			G_CALLBACK (receive_cancel), info);
 761 	}
 762 
 763 	gtk_widget_show_all (wgrid);
 764 
 765 	if (parent != NULL)
 766 		gtk_widget_show (GTK_WIDGET (gd));
 767 
 768 	g_signal_connect (
 769 		gd, "response",
 770 		G_CALLBACK (dialog_response), data);
 771 
 772 	g_object_weak_ref ((GObject *) gd, (GWeakNotify) dialog_destroy_cb, data);
 773 
 774 	data->infos = list;
 775 
 776 	return data;
 777 }
 778 
 779 static void
 780 update_folders (gchar *uri,
 781                 struct _folder_info *info,
 782                 gpointer data)
 783 {
 784 	time_t now = *((time_t *) data);
 785 
 786 	d (printf ("checking update for folder: %s\n", info->uri));
 787 
 788 	/* let it flow through to the folders every 10 seconds */
 789 	/* we back off slowly as we progress */
 790 	if (now > info->update + 10 + info->count *5) {
 791 		d (printf ("upating a folder: %s\n", info->uri));
 792 		/*camel_folder_thaw(info->folder);
 793 		  camel_folder_freeze (info->folder);*/
 794 		info->update = now;
 795 		info->count++;
 796 	}
 797 }
 798 
 799 static void
 800 receive_status (CamelFilterDriver *driver,
 801                 enum camel_filter_status_t status,
 802                 gint pc,
 803                 const gchar *desc,
 804                 gpointer data)
 805 {
 806 	struct _send_info *info = data;
 807 	time_t now = time (NULL);
 808 
 809 	/* let it flow through to the folder, every now and then too? */
 810 	g_hash_table_foreach (info->data->folders, (GHFunc) update_folders, &now);
 811 
 812 	if (info->data->inbox && now > info->data->inbox_update + 20) {
 813 		d (printf ("updating inbox too\n"));
 814 		/* this doesn't seem to work right :( */
 815 		/*camel_folder_thaw(info->data->inbox);
 816 		  camel_folder_freeze (info->data->inbox);*/
 817 		info->data->inbox_update = now;
 818 	}
 819 
 820 	/* we just pile them onto the port, assuming it can handle it.
 821 	 * We could also have a receiver port and see if they've been processed
 822 	 * yet, so if this is necessary its not too hard to add */
 823 	/* the mail_gui_port receiver will free everything for us */
 824 	switch (status) {
 825 	case CAMEL_FILTER_STATUS_START:
 826 	case CAMEL_FILTER_STATUS_END:
 827 		set_send_status (info, desc, pc);
 828 		break;
 829 	case CAMEL_FILTER_STATUS_ACTION:
 830 		set_transport_service (info, desc);
 831 		break;
 832 	default:
 833 		break;
 834 	}
 835 }
 836 
 837 /* when receive/send is complete */
 838 static void
 839 receive_done (gint still_more,
 840               gpointer data)
 841 {
 842 	struct _send_info *info = data;
 843 	const gchar *uid;
 844 
 845 	uid = camel_service_get_uid (info->service);
 846 	g_return_if_fail (uid != NULL);
 847 
 848 	/* if we've been called to run again - run again */
 849 	if (info->type == SEND_SEND && info->state == SEND_ACTIVE && info->again) {
 850 		CamelFolder *local_outbox;
 851 
 852 		local_outbox =
 853 			e_mail_session_get_local_folder (
 854 			E_MAIL_SESSION (info->session),
 855 			E_MAIL_LOCAL_FOLDER_OUTBOX);
 856 
 857 		g_return_if_fail (CAMEL_IS_TRANSPORT (info->service));
 858 
 859 		info->again = 0;
 860 		mail_send_queue (
 861 			E_MAIL_SESSION (info->session),
 862 			local_outbox,
 863 			CAMEL_TRANSPORT (info->service),
 864 			E_FILTER_SOURCE_OUTGOING,
 865 			info->cancellable,
 866 			receive_get_folder, info,
 867 			receive_status, info,
 868 			send_done, info);
 869 		return;
 870 	}
 871 
 872 	if (info->progress_bar) {
 873 		const gchar *text;
 874 
 875 		gtk_progress_bar_set_fraction (
 876 			GTK_PROGRESS_BAR (info->progress_bar), 1.0);
 877 
 878 		if (info->state == SEND_CANCELLED)
 879 			text = _("Canceled");
 880 		else {
 881 			text = _("Complete");
 882 			info->state = SEND_COMPLETE;
 883 		}
 884 
 885 		gtk_progress_bar_set_text (
 886 			GTK_PROGRESS_BAR (info->progress_bar), text);
 887 	}
 888 
 889 	if (info->cancel_button)
 890 		gtk_widget_set_sensitive (info->cancel_button, FALSE);
 891 
 892 	/* remove/free this active download */
 893 	d (printf ("%s: freeing info %p\n", G_STRFUNC, info));
 894 	if (info->type == SEND_SEND) {
 895 		gpointer key = NULL, value = NULL;
 896 		if (!g_hash_table_lookup_extended (info->data->active, SEND_URI_KEY, &key, &value))
 897 			key = NULL;
 898 
 899 		g_hash_table_steal (info->data->active, SEND_URI_KEY);
 900 		g_free (key);
 901 	} else {
 902 		gpointer key = NULL, value = NULL;
 903 		if (!g_hash_table_lookup_extended (info->data->active, uid, &key, &value))
 904 			key = NULL;
 905 
 906 		g_hash_table_steal (info->data->active, uid);
 907 		g_free (key);
 908 	}
 909 	info->data->infos = g_list_remove (info->data->infos, info);
 910 
 911 	if (g_hash_table_size (info->data->active) == 0) {
 912 		if (info->data->gd)
 913 			gtk_widget_destroy ((GtkWidget *) info->data->gd);
 914 		free_send_data ();
 915 	}
 916 
 917 	free_send_info (info);
 918 }
 919 
 920 static void
 921 send_done (gpointer data)
 922 {
 923 	receive_done (-1, data);
 924 }
 925 /* although we dont do anythign smart here yet, there is no need for this interface to
 926  * be available to anyone else.
 927  * This can also be used to hook into which folders are being updated, and occasionally
 928  * let them refresh */
 929 static CamelFolder *
 930 receive_get_folder (CamelFilterDriver *d,
 931                     const gchar *uri,
 932                     gpointer data,
 933                     GError **error)
 934 {
 935 	struct _send_info *info = data;
 936 	CamelFolder *folder;
 937 	struct _folder_info *oldinfo;
 938 	gpointer oldkey, oldinfoptr;
 939 
 940 	g_mutex_lock (info->data->lock);
 941 	oldinfo = g_hash_table_lookup (info->data->folders, uri);
 942 	g_mutex_unlock (info->data->lock);
 943 
 944 	if (oldinfo) {
 945 		g_object_ref (oldinfo->folder);
 946 		return oldinfo->folder;
 947 	}
 948 
 949 	/* FIXME Not passing a GCancellable here. */
 950 	folder = e_mail_session_uri_to_folder_sync (
 951 		E_MAIL_SESSION (info->session), uri, 0, NULL, error);
 952 	if (!folder)
 953 		return NULL;
 954 
 955 	/* we recheck that the folder hasn't snuck in while we were loading it... */
 956 	/* and we assume the newer one is the same, but unref the old one anyway */
 957 	g_mutex_lock (info->data->lock);
 958 
 959 	if (g_hash_table_lookup_extended (
 960 			info->data->folders, uri, &oldkey, &oldinfoptr)) {
 961 		oldinfo = (struct _folder_info *) oldinfoptr;
 962 		g_object_unref (oldinfo->folder);
 963 		oldinfo->folder = folder;
 964 	} else {
 965 		oldinfo = g_malloc0 (sizeof (*oldinfo));
 966 		oldinfo->folder = folder;
 967 		oldinfo->uri = g_strdup (uri);
 968 		g_hash_table_insert (info->data->folders, oldinfo->uri, oldinfo);
 969 	}
 970 
 971 	g_object_ref (folder);
 972 
 973 	g_mutex_unlock (info->data->lock);
 974 
 975 	return folder;
 976 }
 977 
 978 /* ********************************************************************** */
 979 
 980 static void
 981 get_folders (CamelStore *store,
 982              GPtrArray *folders,
 983              CamelFolderInfo *info)
 984 {
 985 	while (info) {
 986 		if (camel_store_can_refresh_folder (store, info, NULL)) {
 987 			if ((info->flags & CAMEL_FOLDER_NOSELECT) == 0) {
 988 				gchar *folder_uri;
 989 
 990 				folder_uri = e_mail_folder_uri_build (
 991 					store, info->full_name);
 992 				g_ptr_array_add (folders, folder_uri);
 993 			}
 994 		}
 995 
 996 		get_folders (store, folders, info->child);
 997 		info = info->next;
 998 	}
 999 }
1000 
1001 static void
1002 main_op_cancelled_cb (GCancellable *main_op,
1003                       GCancellable *refresh_op)
1004 {
1005 	g_cancellable_cancel (refresh_op);
1006 }
1007 
1008 struct _refresh_folders_msg {
1009 	MailMsg base;
1010 
1011 	struct _send_info *info;
1012 	GPtrArray *folders;
1013 	CamelStore *store;
1014 	CamelFolderInfo *finfo;
1015 };
1016 
1017 static gchar *
1018 refresh_folders_desc (struct _refresh_folders_msg *m)
1019 {
1020 	return g_strdup_printf (_("Checking for new mail"));
1021 }
1022 
1023 static void
1024 refresh_folders_exec (struct _refresh_folders_msg *m,
1025                       GCancellable *cancellable,
1026                       GError **error)
1027 {
1028 	CamelFolder *folder;
1029 	gint i;
1030 	GError *local_error = NULL;
1031 	gulong handler_id = 0;
1032 
1033 	if (cancellable)
1034 		handler_id = g_signal_connect (
1035 			m->info->cancellable, "cancelled",
1036 			G_CALLBACK (main_op_cancelled_cb), cancellable);
1037 
1038 	get_folders (m->store, m->folders, m->finfo);
1039 
1040 	camel_operation_push_message (m->info->cancellable, _("Updating..."));
1041 
1042 	for (i = 0; i < m->folders->len; i++) {
1043 		folder = e_mail_session_uri_to_folder_sync (
1044 			E_MAIL_SESSION (m->info->session),
1045 			m->folders->pdata[i], 0,
1046 			cancellable, &local_error);
1047 		if (folder) {
1048 			if (camel_folder_synchronize_sync (folder, FALSE, cancellable, &local_error))
1049 				camel_folder_refresh_info_sync (folder, cancellable, &local_error);
1050 			g_object_unref (folder);
1051 		}
1052 
1053 		if (local_error != NULL) {
1054 			if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1055 				g_warning ("Failed to refresh folder: %s: %s", (const gchar *) m->folders->pdata[i], local_error->message);
1056 			g_clear_error (&local_error);
1057 		}
1058 
1059 		if (g_cancellable_is_cancelled (m->info->cancellable) ||
1060 		    g_cancellable_is_cancelled (cancellable))
1061 			break;
1062 
1063 		if (m->info->state != SEND_CANCELLED)
1064 			camel_operation_progress (
1065 				m->info->cancellable, 100 * i / m->folders->len);
1066 	}
1067 
1068 	camel_operation_pop_message (m->info->cancellable);
1069 
1070 	if (cancellable)
1071 		g_signal_handler_disconnect (m->info->cancellable, handler_id);
1072 }
1073 
1074 static void
1075 refresh_folders_done (struct _refresh_folders_msg *m)
1076 {
1077 	receive_done (-1, m->info);
1078 }
1079 
1080 static void
1081 refresh_folders_free (struct _refresh_folders_msg *m)
1082 {
1083 	gint i;
1084 
1085 	for (i = 0; i < m->folders->len; i++)
1086 		g_free (m->folders->pdata[i]);
1087 	g_ptr_array_free (m->folders, TRUE);
1088 
1089 	camel_store_free_folder_info (m->store, m->finfo);
1090 	g_object_unref (m->store);
1091 }
1092 
1093 static MailMsgInfo refresh_folders_info = {
1094 	sizeof (struct _refresh_folders_msg),
1095 	(MailMsgDescFunc) refresh_folders_desc,
1096 	(MailMsgExecFunc) refresh_folders_exec,
1097 	(MailMsgDoneFunc) refresh_folders_done,
1098 	(MailMsgFreeFunc) refresh_folders_free
1099 };
1100 
1101 static gboolean
1102 receive_update_got_folderinfo (MailFolderCache *folder_cache,
1103                                CamelStore *store,
1104                                CamelFolderInfo *info,
1105                                gpointer data)
1106 {
1107 	if (info) {
1108 		GPtrArray *folders = g_ptr_array_new ();
1109 		struct _refresh_folders_msg *m;
1110 		struct _send_info *sinfo = data;
1111 
1112 		m = mail_msg_new (&refresh_folders_info);
1113 		m->store = store;
1114 		g_object_ref (store);
1115 		m->folders = folders;
1116 		m->info = sinfo;
1117 		m->finfo = info;
1118 
1119 		mail_msg_unordered_push (m);
1120 
1121 		/* do not free folder info, we will free it later */
1122 		return FALSE;
1123 	} else {
1124 		receive_done (-1, data);
1125 	}
1126 
1127 	return TRUE;
1128 }
1129 
1130 static void
1131 receive_update_got_store (CamelStore *store,
1132                           struct _send_info *info)
1133 {
1134 	MailFolderCache *folder_cache;
1135 
1136 	folder_cache = e_mail_session_get_folder_cache (
1137 		E_MAIL_SESSION (info->session));
1138 
1139 	if (store != NULL) {
1140 		mail_folder_cache_note_store (
1141 			folder_cache, store, info->cancellable,
1142 			receive_update_got_folderinfo, info);
1143 	} else {
1144 		receive_done (-1, info);
1145 	}
1146 }
1147 
1148 static CamelService *
1149 ref_default_transport (EMailSession *session)
1150 {
1151 	ESource *source;
1152 	ESourceRegistry *registry;
1153 	CamelService *service;
1154 	const gchar *extension_name;
1155 	const gchar *uid;
1156 
1157 	registry = e_mail_session_get_registry (session);
1158 	source = e_source_registry_ref_default_mail_identity (registry);
1159 
1160 	if (source == NULL)
1161 		return NULL;
1162 
1163 	extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
1164 	if (e_source_has_extension (source, extension_name)) {
1165 		ESourceMailSubmission *extension;
1166 		gchar *uid;
1167 
1168 		extension = e_source_get_extension (source, extension_name);
1169 		uid = e_source_mail_submission_dup_transport_uid (extension);
1170 
1171 		g_object_unref (source);
1172 		source = e_source_registry_ref_source (registry, uid);
1173 
1174 		g_free (uid);
1175 	} else {
1176 		g_object_unref (source);
1177 		source = NULL;
1178 	}
1179 
1180 	if (source == NULL)
1181 		return NULL;
1182 
1183 	uid = e_source_get_uid (source);
1184 	service = camel_session_ref_service (CAMEL_SESSION (session), uid);
1185 
1186 	g_object_unref (source);
1187 
1188 	return service;
1189 }
1190 
1191 static GtkWidget *
1192 send_receive (GtkWindow *parent,
1193               EMailSession *session,
1194               gboolean allow_send)
1195 {
1196 	CamelFolder *local_outbox;
1197 	CamelService *transport;
1198 	struct _send_data *data;
1199 	GList *scan;
1200 
1201 	if (send_recv_dialog != NULL) {
1202 		if (parent != NULL && gtk_widget_get_realized (send_recv_dialog)) {
1203 			gtk_window_present (GTK_WINDOW (send_recv_dialog));
1204 		}
1205 		return send_recv_dialog;
1206 	}
1207 
1208 	if (!camel_session_get_online (CAMEL_SESSION (session)))
1209 		return send_recv_dialog;
1210 
1211 	transport = ref_default_transport (session);
1212 
1213 	local_outbox =
1214 		e_mail_session_get_local_folder (
1215 		session, E_MAIL_LOCAL_FOLDER_OUTBOX);
1216 
1217 	data = build_dialog (
1218 		parent, session, local_outbox, transport, allow_send);
1219 
1220 	if (transport != NULL)
1221 		g_object_unref (transport);
1222 
1223 	for (scan = data->infos; scan != NULL; scan = scan->next) {
1224 		struct _send_info *info = scan->data;
1225 
1226 		if (!CAMEL_IS_SERVICE (info->service))
1227 			continue;
1228 
1229 		switch (info->type) {
1230 		case SEND_RECEIVE:
1231 			mail_fetch_mail (
1232 				CAMEL_STORE (info->service),
1233 				CAMEL_FETCH_OLD_MESSAGES, -1,
1234 				E_FILTER_SOURCE_INCOMING,
1235 				NULL, NULL, NULL,
1236 				info->cancellable,
1237 				receive_get_folder, info,
1238 				receive_status, info,
1239 				receive_done, info);
1240 			break;
1241 		case SEND_SEND:
1242 			/* todo, store the folder in info? */
1243 			mail_send_queue (
1244 				session, local_outbox,
1245 				CAMEL_TRANSPORT (info->service),
1246 				E_FILTER_SOURCE_OUTGOING,
1247 				info->cancellable,
1248 				receive_get_folder, info,
1249 				receive_status, info,
1250 				send_done, info);
1251 			break;
1252 		case SEND_UPDATE:
1253 			receive_update_got_store (
1254 				CAMEL_STORE (info->service), info);
1255 			break;
1256 		default:
1257 			break;
1258 		}
1259 	}
1260 
1261 	return send_recv_dialog;
1262 }
1263 
1264 GtkWidget *
1265 mail_send_receive (GtkWindow *parent,
1266                    EMailSession *session)
1267 {
1268 	return send_receive (parent, session, TRUE);
1269 }
1270 
1271 GtkWidget *
1272 mail_receive (GtkWindow *parent,
1273               EMailSession *session)
1274 {
1275 	return send_receive (parent, session, FALSE);
1276 }
1277 
1278 /* We setup the download info's in a hashtable, if we later
1279  * need to build the gui, we insert them in to add them. */
1280 void
1281 mail_receive_service (CamelService *service)
1282 {
1283 	struct _send_info *info;
1284 	struct _send_data *data;
1285 	CamelSession *session;
1286 	CamelFolder *local_outbox;
1287 	const gchar *uid;
1288 	send_info_t type = SEND_INVALID;
1289 
1290 	g_return_if_fail (CAMEL_IS_SERVICE (service));
1291 
1292 	uid = camel_service_get_uid (service);
1293 	session = camel_service_get_session (service);
1294 
1295 	data = setup_send_data (E_MAIL_SESSION (session));
1296 	info = g_hash_table_lookup (data->active, uid);
1297 
1298 	if (info != NULL)
1299 		return;
1300 
1301 	type = get_receive_type (service);
1302 
1303 	if (type == SEND_INVALID || type == SEND_SEND)
1304 		return;
1305 
1306 	info = g_malloc0 (sizeof (*info));
1307 	info->type = type;
1308 	info->progress_bar = NULL;
1309 	info->session = g_object_ref (session);
1310 	info->service = g_object_ref (service);
1311 	info->keep_on_server = get_keep_on_server (service);
1312 	info->cancellable = camel_operation_new ();
1313 	info->cancel_button = NULL;
1314 	info->data = data;
1315 	info->state = SEND_ACTIVE;
1316 	info->timeout_id = 0;
1317 
1318 	g_signal_connect (
1319 		info->cancellable, "status",
1320 		G_CALLBACK (operation_status), info);
1321 
1322 	d (printf ("Adding new info %p\n", info));
1323 
1324 	g_hash_table_insert (data->active, g_strdup (uid), info);
1325 
1326 	switch (info->type) {
1327 	case SEND_RECEIVE:
1328 		mail_fetch_mail (
1329 			CAMEL_STORE (service),
1330 			CAMEL_FETCH_OLD_MESSAGES, -1,
1331 			E_FILTER_SOURCE_INCOMING,
1332 			NULL, NULL, NULL,
1333 			info->cancellable,
1334 			receive_get_folder, info,
1335 			receive_status, info,
1336 			receive_done, info);
1337 		break;
1338 	case SEND_SEND:
1339 		/* todo, store the folder in info? */
1340 		local_outbox =
1341 			e_mail_session_get_local_folder (
1342 			E_MAIL_SESSION (session),
1343 			E_MAIL_LOCAL_FOLDER_OUTBOX);
1344 		mail_send_queue (
1345 			E_MAIL_SESSION (session),
1346 			local_outbox,
1347 			CAMEL_TRANSPORT (service),
1348 			E_FILTER_SOURCE_OUTGOING,
1349 			info->cancellable,
1350 			receive_get_folder, info,
1351 			receive_status, info,
1352 			send_done, info);
1353 		break;
1354 	case SEND_UPDATE:
1355 		receive_update_got_store (CAMEL_STORE (service), info);
1356 		break;
1357 	default:
1358 		g_return_if_reached ();
1359 	}
1360 }
1361 
1362 void
1363 mail_send (EMailSession *session)
1364 {
1365 	CamelFolder *local_outbox;
1366 	CamelService *service;
1367 	struct _send_info *info;
1368 	struct _send_data *data;
1369 	send_info_t type = SEND_INVALID;
1370 
1371 	g_return_if_fail (E_IS_MAIL_SESSION (session));
1372 
1373 	service = ref_default_transport (session);
1374 	if (service == NULL)
1375 		return;
1376 
1377 	data = setup_send_data (session);
1378 	info = g_hash_table_lookup (data->active, SEND_URI_KEY);
1379 	if (info != NULL) {
1380 		info->again++;
1381 		d (printf ("send of %s still in progress\n", transport->url));
1382 		g_object_unref (service);
1383 		return;
1384 	}
1385 
1386 	d (printf ("starting non-interactive send of '%s'\n", transport->url));
1387 
1388 	type = get_receive_type (service);
1389 	if (type == SEND_INVALID) {
1390 		g_object_unref (service);
1391 		return;
1392 	}
1393 
1394 	info = g_malloc0 (sizeof (*info));
1395 	info->type = SEND_SEND;
1396 	info->progress_bar = NULL;
1397 	info->session = g_object_ref (session);
1398 	info->service = g_object_ref (service);
1399 	info->keep_on_server = FALSE;
1400 	info->cancellable = NULL;
1401 	info->cancel_button = NULL;
1402 	info->data = data;
1403 	info->state = SEND_ACTIVE;
1404 	info->timeout_id = 0;
1405 
1406 	d (printf ("Adding new info %p\n", info));
1407 
1408 	g_hash_table_insert (data->active, g_strdup (SEND_URI_KEY), info);
1409 
1410 	/* todo, store the folder in info? */
1411 	local_outbox =
1412 		e_mail_session_get_local_folder (
1413 		session, E_MAIL_LOCAL_FOLDER_OUTBOX);
1414 
1415 	mail_send_queue (
1416 		session, local_outbox,
1417 		CAMEL_TRANSPORT (service),
1418 		E_FILTER_SOURCE_OUTGOING,
1419 		info->cancellable,
1420 		receive_get_folder, info,
1421 		receive_status, info,
1422 		send_done, info);
1423 
1424 	g_object_unref (service);
1425 }