evolution-3.6.4/modules/mail/e-mail-shell-view-private.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-shell-view-private.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-shell-view-private.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  * e-mail-shell-view-private.c
   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  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  19  *
  20  */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include <config.h>
  24 #endif
  25 
  26 #include "e-mail-shell-view-private.h"
  27 
  28 #include "widgets/menus/gal-view-factory-etable.h"
  29 #include "widgets/misc/e-menu-tool-button.h"
  30 
  31 #include "e-util/e-util-private.h"
  32 
  33 typedef struct _AsyncContext AsyncContext;
  34 
  35 struct _AsyncContext {
  36 	EActivity *activity;
  37 	EMailReader *reader;
  38 	EShellView *shell_view;
  39 };
  40 
  41 static void
  42 async_context_free (AsyncContext *context)
  43 {
  44 	if (context->activity != NULL)
  45 		g_object_unref (context->activity);
  46 
  47 	if (context->reader != NULL)
  48 		g_object_unref (context->reader);
  49 
  50 	if (context->shell_view != NULL)
  51 		g_object_unref (context->shell_view);
  52 
  53 	g_slice_free (AsyncContext, context);
  54 }
  55 
  56 static void
  57 mail_shell_view_got_folder_cb (CamelStore *store,
  58                                GAsyncResult *result,
  59                                AsyncContext *context)
  60 {
  61 	EAlertSink *alert_sink;
  62 	CamelFolder *folder;
  63 	GError *error = NULL;
  64 
  65 	alert_sink = e_activity_get_alert_sink (context->activity);
  66 
  67 	folder = camel_store_get_folder_finish (store, result, &error);
  68 
  69 	if (e_activity_handle_cancellation (context->activity, error)) {
  70 		g_warn_if_fail (folder == NULL);
  71 		async_context_free (context);
  72 		g_error_free (error);
  73 		return;
  74 
  75 	} else if (error != NULL) {
  76 		g_warn_if_fail (folder == NULL);
  77 		e_alert_submit (
  78 			alert_sink, "mail:folder-open",
  79 			error->message, NULL);
  80 		async_context_free (context);
  81 		g_error_free (error);
  82 		return;
  83 	}
  84 
  85 	e_mail_reader_set_folder (context->reader, folder);
  86 	e_shell_view_update_actions (context->shell_view);
  87 
  88 	g_object_unref (folder);
  89 
  90 	async_context_free (context);
  91 }
  92 
  93 static void
  94 mail_shell_view_folder_tree_selected_cb (EMailShellView *mail_shell_view,
  95                                          CamelStore *store,
  96                                          const gchar *folder_name,
  97                                          CamelFolderInfoFlags flags,
  98                                          EMFolderTree *folder_tree)
  99 {
 100 	EMailShellContent *mail_shell_content;
 101 	EShellView *shell_view;
 102 	EMailReader *reader;
 103 	EMailView *mail_view;
 104 	GCancellable *cancellable;
 105 	AsyncContext *context;
 106 	EActivity *activity;
 107 
 108 	shell_view = E_SHELL_VIEW (mail_shell_view);
 109 
 110 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 111 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 112 
 113 	reader = E_MAIL_READER (mail_view);
 114 
 115 	/* Cancel any unfinished open folder operations. */
 116 	if (mail_shell_view->priv->opening_folder != NULL) {
 117 		g_cancellable_cancel (mail_shell_view->priv->opening_folder);
 118 		g_object_unref (mail_shell_view->priv->opening_folder);
 119 		mail_shell_view->priv->opening_folder = NULL;
 120 	}
 121 
 122 	/* If we are to clear the message list, do so immediately. */
 123 	if ((flags & CAMEL_FOLDER_NOSELECT) || folder_name == NULL) {
 124 		e_mail_reader_set_folder (reader, NULL);
 125 		e_shell_view_update_actions (shell_view);
 126 		return;
 127 	}
 128 
 129 	g_warn_if_fail (CAMEL_IS_STORE (store));
 130 
 131 	/* Open the selected folder asynchronously. */
 132 
 133 	activity = e_mail_reader_new_activity (reader);
 134 	cancellable = e_activity_get_cancellable (activity);
 135 	mail_shell_view->priv->opening_folder = g_object_ref (cancellable);
 136 
 137 	context = g_slice_new0 (AsyncContext);
 138 	context->activity = activity;
 139 	context->reader = g_object_ref (reader);
 140 	context->shell_view = g_object_ref (shell_view);
 141 
 142 	camel_store_get_folder (
 143 		store, folder_name, 0, G_PRIORITY_DEFAULT, cancellable,
 144 		(GAsyncReadyCallback) mail_shell_view_got_folder_cb, context);
 145 }
 146 
 147 static gboolean
 148 mail_shell_view_folder_tree_key_press_event_cb (EMailShellView *mail_shell_view,
 149                                                 GdkEventKey *event)
 150 {
 151 	EMailShellContent *mail_shell_content;
 152 	EMailView *mail_view;
 153 	gboolean handled = FALSE;
 154 
 155 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 156 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 157 
 158 	if ((event->state & GDK_CONTROL_MASK) != 0)
 159 		goto ctrl;
 160 
 161 	/* <keyval> alone */
 162 	switch (event->keyval) {
 163 		case GDK_KEY_period:
 164 		case GDK_KEY_comma:
 165 		case GDK_KEY_bracketleft:
 166 		case GDK_KEY_bracketright:
 167 			goto emit;
 168 
 169 		default:
 170 			goto exit;
 171 	}
 172 
 173 ctrl:
 174 	/* Ctrl + <keyval> */
 175 	switch (event->keyval) {
 176 		case GDK_KEY_period:
 177 		case GDK_KEY_comma:
 178 			goto emit;
 179 
 180 		default:
 181 			goto exit;
 182 	}
 183 
 184 	/* All branches jump past this. */
 185 	g_return_val_if_reached (FALSE);
 186 
 187 emit:
 188 	/* Forward the key press to the EMailReader interface. */
 189 	g_signal_emit_by_name (mail_view, "key-press-event", event, &handled);
 190 
 191 exit:
 192 	return handled;
 193 }
 194 
 195 static void
 196 mail_shell_view_folder_tree_selection_done_cb (EMailShellView *mail_shell_view,
 197                                                GtkWidget *menu)
 198 {
 199 	EMailShellContent *mail_shell_content;
 200 	EMailShellSidebar *mail_shell_sidebar;
 201 	EMFolderTree *folder_tree;
 202 	GtkWidget *message_list;
 203 	EMailReader *reader;
 204 	EMailView *mail_view;
 205 	CamelFolder *folder;
 206 	gchar *list_uri;
 207 	gchar *tree_uri;
 208 
 209 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 210 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 211 
 212 	mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
 213 	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 214 
 215 	reader = E_MAIL_READER (mail_view);
 216 	message_list = e_mail_reader_get_message_list (reader);
 217 
 218 	/* Don't use e_mail_reader_get_folder() here.  The fact that the
 219 	 * method gets the folder from the message list is supposed to be
 220 	 * a hidden implementation detail, and we want to explicitly get
 221 	 * the folder URI from the message list here. */
 222 	folder = MESSAGE_LIST (message_list)->folder;
 223 	if (folder)
 224 		list_uri = e_mail_folder_uri_from_folder (folder);
 225 	else
 226 		list_uri = NULL;
 227 	tree_uri = em_folder_tree_get_selected_uri (folder_tree);
 228 
 229 	/* If the folder tree and message list disagree on the current
 230 	 * folder, reset the folder tree to match the message list. */
 231 	if (list_uri && g_strcmp0 (tree_uri, list_uri) != 0)
 232 		em_folder_tree_set_selected (folder_tree, list_uri, FALSE);
 233 
 234 	g_free (list_uri);
 235 	g_free (tree_uri);
 236 
 237 	/* Disconnect from the "selection-done" signal. */
 238 	g_signal_handlers_disconnect_by_func (
 239 		menu, mail_shell_view_folder_tree_selection_done_cb,
 240 		mail_shell_view);
 241 }
 242 
 243 static void
 244 mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
 245                                             GdkEventButton *event)
 246 {
 247 	GtkWidget *menu;
 248 	const gchar *widget_path;
 249 
 250 	widget_path = "/mail-folder-popup";
 251 	menu = e_shell_view_show_popup_menu (shell_view, widget_path, event);
 252 
 253 	g_signal_connect_object (
 254 		menu, "selection-done",
 255 		G_CALLBACK (mail_shell_view_folder_tree_selection_done_cb),
 256 		shell_view, G_CONNECT_SWAPPED);
 257 }
 258 
 259 #if !WEBKIT_CHECK_VERSION(1,10,0)
 260 static WebKitDOMDocument *
 261 find_dom_for_frame (WebKitDOMDocument *document,
 262                     const gchar *frame_name)
 263 {
 264 	WebKitDOMNodeList *frames;
 265 	gulong ii, length;
 266 
 267 	g_return_val_if_fail (frame_name != NULL, NULL);
 268 
 269 	if (!WEBKIT_DOM_IS_DOCUMENT (document))
 270 		return NULL;
 271 
 272 	frames = webkit_dom_document_get_elements_by_tag_name (
 273 		document, "iframe");
 274 	length = webkit_dom_node_list_get_length (frames);
 275 	for (ii = 0; ii < length; ii++) {
 276 		WebKitDOMHTMLIFrameElement *iframe;
 277 		WebKitDOMDocument *frame_doc;
 278 		gchar *name;
 279 
 280 		iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
 281 			webkit_dom_node_list_item (frames, ii));
 282 
 283 		frame_doc = webkit_dom_html_iframe_element_get_content_document (iframe);
 284 		name = webkit_dom_html_iframe_element_get_name (iframe);
 285 
 286 		if (g_strcmp0 (name, frame_name) == 0) {
 287 			g_free (name);
 288 			return frame_doc;
 289 		}
 290 
 291 		g_free (name);
 292 
 293 		frame_doc = find_dom_for_frame (frame_doc, frame_name);
 294 		if (frame_doc)
 295 			return frame_doc;
 296 	}
 297 
 298 	return NULL;
 299 }
 300 #endif
 301 
 302 static gboolean
 303 mail_shell_view_mail_display_needs_key (EMailDisplay *mail_display,
 304                                         gboolean with_input)
 305 {
 306 	gboolean needs_key = FALSE;
 307 
 308 	if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
 309 		WebKitWebFrame *frame;
 310 		WebKitDOMDocument *dom;
 311 		WebKitDOMElement *element;
 312 		gchar *name = NULL;
 313 
 314 		frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display));
 315 		#if WEBKIT_CHECK_VERSION(1,10,0)
 316 		dom = webkit_web_frame_get_dom_document (frame);
 317 		#else
 318 		dom = find_dom_for_frame (
 319 			webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display)),
 320 			webkit_web_frame_get_name (frame));
 321 		#endif
 322 		/* intentionally used "static_cast" */
 323 		element = webkit_dom_html_document_get_active_element ((WebKitDOMHTMLDocument *) dom);
 324 
 325 		if (element)
 326 			name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (element));
 327 
 328 		/* if INPUT or TEXTAREA has focus, then any key press should go there */
 329 		if (name && ((with_input && g_ascii_strcasecmp (name, "INPUT") == 0) || g_ascii_strcasecmp (name, "TEXTAREA") == 0)) {
 330 			needs_key = TRUE;
 331 		}
 332 
 333 		g_free (name);
 334 	}
 335 
 336 	return needs_key;
 337 }
 338 
 339 static gboolean
 340 mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
 341                                     GdkEventKey *event)
 342 {
 343 	EShellView *shell_view;
 344 	EShellWindow *shell_window;
 345 	EShellContent *shell_content;
 346 	EMailView *mail_view;
 347 	EMailReader *reader;
 348 	EMailDisplay *mail_display;
 349 	GtkAction *action;
 350 
 351 	shell_view = E_SHELL_VIEW (mail_shell_view);
 352 	shell_window = e_shell_view_get_shell_window (shell_view);
 353 
 354 	if ((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK)) != 0)
 355 		return FALSE;
 356 
 357 	shell_content = e_shell_view_get_shell_content (shell_view);
 358 	mail_view = e_mail_shell_content_get_mail_view (E_MAIL_SHELL_CONTENT (shell_content));
 359 	reader = E_MAIL_READER (mail_view);
 360 	mail_display = e_mail_reader_get_mail_display (reader);
 361 
 362 	switch (event->keyval) {
 363 		case GDK_KEY_space:
 364 			action = ACTION (MAIL_SMART_FORWARD);
 365 			break;
 366 
 367 		case GDK_KEY_BackSpace:
 368 			action = ACTION (MAIL_SMART_BACKWARD);
 369 			break;
 370 
 371 		case GDK_KEY_Home:
 372 		case GDK_KEY_Left:
 373 		case GDK_KEY_Up:
 374 		case GDK_KEY_Right:
 375 		case GDK_KEY_Down:
 376 		case GDK_KEY_Prior:
 377 		case GDK_KEY_Next:
 378 		case GDK_KEY_End:
 379 		case GDK_KEY_Begin:
 380 			if (!mail_shell_view_mail_display_needs_key (mail_display, FALSE) &&
 381 			    webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display)) !=
 382 			    webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display))) {
 383 				WebKitDOMDocument *document;
 384 				WebKitDOMDOMWindow *window;
 385 
 386 				document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display));
 387 				window = webkit_dom_document_get_default_view (document);
 388 
 389 				/* Workaround WebKit bug for key navigation, when inner IFRAME is focused.
 390 				 * EMailView's inner IFRAMEs have disabled scrolling, but WebKit doesn't post
 391 				 * key navigation events to parent's frame, thus the view doesn't scroll.
 392 				 * This is a poor workaround for this issue, the main frame is focused,
 393 				 * which has scrolling enabled.
 394 				*/
 395 				webkit_dom_dom_window_focus (window);
 396 			}
 397 
 398 			return FALSE;
 399 		default:
 400 			return FALSE;
 401 	}
 402 
 403 	if (mail_shell_view_mail_display_needs_key (mail_display, TRUE))
 404 		return FALSE;
 405 
 406 	gtk_action_activate (action);
 407 
 408 	return TRUE;
 409 }
 410 
 411 static gboolean
 412 mail_shell_view_message_list_key_press_cb (EMailShellView *mail_shell_view,
 413                                            gint row,
 414                                            ETreePath path,
 415                                            gint col,
 416                                            GdkEvent *event)
 417 {
 418 	return mail_shell_view_key_press_event_cb (
 419 		mail_shell_view, &event->key);
 420 }
 421 
 422 static gboolean
 423 mail_shell_view_message_list_popup_menu_cb (EShellView *shell_view)
 424 {
 425 	const gchar *widget_path;
 426 
 427 	widget_path = "/mail-message-popup";
 428 	e_shell_view_show_popup_menu (shell_view, widget_path, NULL);
 429 
 430 	return TRUE;
 431 }
 432 
 433 static gboolean
 434 mail_shell_view_message_list_right_click_cb (EShellView *shell_view,
 435                                              gint row,
 436                                              ETreePath path,
 437                                              gint col,
 438                                              GdkEventButton *event)
 439 {
 440 	const gchar *widget_path;
 441 
 442 	widget_path = "/mail-message-popup";
 443 	e_shell_view_show_popup_menu (shell_view, widget_path, event);
 444 
 445 	return TRUE;
 446 }
 447 
 448 static gboolean
 449 mail_shell_view_popup_event_cb (EMailShellView *mail_shell_view,
 450                                 GdkEventButton *event,
 451                                 const gchar *uri)
 452 {
 453 	EMailShellContent *mail_shell_content;
 454 	EMailDisplay *display;
 455 	EShellView *shell_view;
 456 	EMailReader *reader;
 457 	EMailView *mail_view;
 458 	GtkMenu *menu;
 459 
 460 	if (uri != NULL)
 461 		return FALSE;
 462 
 463 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 464 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 465 
 466 	reader = E_MAIL_READER (mail_view);
 467 	display = e_mail_reader_get_mail_display (reader);
 468 
 469 	if (e_web_view_get_cursor_image (E_WEB_VIEW (display)) != NULL)
 470 		return FALSE;
 471 
 472 	menu = e_mail_reader_get_popup_menu (reader);
 473 	shell_view = E_SHELL_VIEW (mail_shell_view);
 474 	e_shell_view_update_actions (shell_view);
 475 
 476 	if (event == NULL)
 477 		gtk_menu_popup (
 478 			menu, NULL, NULL, NULL, NULL,
 479 			0, gtk_get_current_event_time ());
 480 	else
 481 		gtk_menu_popup (
 482 			menu, NULL, NULL, NULL, NULL,
 483 			event->button, event->time);
 484 
 485 	return TRUE;
 486 }
 487 
 488 static void
 489 mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view,
 490                                    EMailReader *reader)
 491 {
 492 	GtkWidget *message_list;
 493 	EMailDisplay *display;
 494 	EShellView *shell_view;
 495 	EShellTaskbar *shell_taskbar;
 496 
 497 	shell_view = E_SHELL_VIEW (mail_shell_view);
 498 	shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
 499 
 500 	display = e_mail_reader_get_mail_display (reader);
 501 	message_list = e_mail_reader_get_message_list (reader);
 502 
 503 	e_shell_view_update_actions (E_SHELL_VIEW (mail_shell_view));
 504 	e_mail_shell_view_update_sidebar (mail_shell_view);
 505 
 506 	/* Connect if its not connected already */
 507 	if (g_signal_handler_find (
 508 		message_list, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
 509 		mail_shell_view_message_list_key_press_cb, NULL))
 510 		return;
 511 
 512 	g_signal_connect_object (
 513 		message_list, "key-press",
 514 		G_CALLBACK (mail_shell_view_message_list_key_press_cb),
 515 		mail_shell_view, G_CONNECT_SWAPPED);
 516 
 517 	g_signal_connect_object (
 518 		message_list, "popup-menu",
 519 		G_CALLBACK (mail_shell_view_message_list_popup_menu_cb),
 520 		mail_shell_view, G_CONNECT_SWAPPED);
 521 
 522 	g_signal_connect_object (
 523 		message_list, "right-click",
 524 		G_CALLBACK (mail_shell_view_message_list_right_click_cb),
 525 		mail_shell_view, G_CONNECT_SWAPPED);
 526 
 527 	g_signal_connect_object (
 528 		display, "key-press-event",
 529 		G_CALLBACK (mail_shell_view_key_press_event_cb),
 530 		mail_shell_view, G_CONNECT_SWAPPED);
 531 
 532 	g_signal_connect_object (
 533 		display, "popup-event",
 534 		G_CALLBACK (mail_shell_view_popup_event_cb),
 535 		mail_shell_view, G_CONNECT_SWAPPED);
 536 
 537 	g_signal_connect_object (
 538 		display, "status-message",
 539 		G_CALLBACK (e_shell_taskbar_set_message),
 540 		shell_taskbar, G_CONNECT_SWAPPED);
 541 }
 542 
 543 static void
 544 mail_shell_view_reader_update_actions_cb (EMailReader *reader,
 545                                           guint32 state,
 546                                           EMailShellView *mail_shell_view)
 547 {
 548 	EMailShellContent *mail_shell_content;
 549 
 550 	g_return_if_fail (mail_shell_view != NULL);
 551 	g_return_if_fail (mail_shell_view->priv != NULL);
 552 
 553 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 554 	e_mail_reader_update_actions (E_MAIL_READER (mail_shell_content), state);
 555 }
 556 
 557 static void
 558 mail_shell_view_prepare_for_quit_done_cb (CamelFolder *folder,
 559                                           gpointer user_data)
 560 {
 561 	g_object_unref (E_ACTIVITY (user_data));
 562 }
 563 
 564 static void
 565 mail_shell_view_prepare_for_quit_cb (EMailShellView *mail_shell_view,
 566                                      EActivity *activity)
 567 {
 568 	EMailShellContent *mail_shell_content;
 569 	CamelFolder *folder;
 570 	EMailReader *reader;
 571 	EMailView *mail_view;
 572 	GtkWidget *message_list;
 573 
 574 	/* If we got here, it means the application is shutting down
 575 	 * and this is the last EMailShellView instance.  Synchronize
 576 	 * the currently selected folder before we terminate. */
 577 
 578 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 579 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 580 
 581 	reader = E_MAIL_READER (mail_view);
 582 	folder = e_mail_reader_get_folder (reader);
 583 	message_list = e_mail_reader_get_message_list (reader);
 584 
 585 	message_list_save_state (MESSAGE_LIST (message_list));
 586 
 587 	if (folder == NULL)
 588 		return;
 589 
 590 	mail_sync_folder (
 591 		folder,
 592 		mail_shell_view_prepare_for_quit_done_cb,
 593 		g_object_ref (activity));
 594 }
 595 
 596 static void
 597 mail_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 598 {
 599 	GalViewCollection *collection;
 600 	GalViewFactory *factory;
 601 	ETableSpecification *spec;
 602 	const gchar *base_dir;
 603 	gchar *filename;
 604 
 605 	collection = shell_view_class->view_collection;
 606 
 607 	base_dir = EVOLUTION_ETSPECDIR;
 608 	spec = e_table_specification_new ();
 609 	filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
 610 	if (!e_table_specification_load_from_file (spec, filename))
 611 		g_critical (
 612 			"Unable to load ETable specification file "
 613 			"for mail");
 614 	g_free (filename);
 615 
 616 	factory = gal_view_factory_etable_new (spec);
 617 	gal_view_collection_add_factory (collection, factory);
 618 	g_object_unref (factory);
 619 	g_object_unref (spec);
 620 
 621 	gal_view_collection_load (collection);
 622 }
 623 
 624 static void
 625 mail_shell_view_notify_view_id_cb (EMailShellView *mail_shell_view)
 626 {
 627 	EMailShellContent *mail_shell_content;
 628 	GalViewInstance *view_instance;
 629 	EMailView *mail_view;
 630 	const gchar *view_id;
 631 
 632 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 633 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 634 
 635 	view_instance = e_mail_view_get_view_instance (mail_view);
 636 	view_id = e_shell_view_get_view_id (E_SHELL_VIEW (mail_shell_view));
 637 
 638 	/* A NULL view ID implies we're in a custom view.  But you can
 639 	 * only get to a custom view via the "Define Views" dialog, which
 640 	 * would have already modified the view instance appropriately.
 641 	 * Furthermore, there's no way to refer to a custom view by ID
 642 	 * anyway, since custom views have no IDs. */
 643 	if (view_id == NULL)
 644 		return;
 645 
 646 	gal_view_instance_set_current_view_id (view_instance, view_id);
 647 }
 648 
 649 static void
 650 mail_shell_view_search_filter_changed_cb (EMailShellView *mail_shell_view)
 651 {
 652 	EMailShellContent *mail_shell_content;
 653 	EMailView *mail_view;
 654 
 655 	g_return_if_fail (mail_shell_view != NULL);
 656 	g_return_if_fail (mail_shell_view->priv != NULL);
 657 
 658 	if (e_shell_view_is_execute_search_blocked (E_SHELL_VIEW (mail_shell_view)))
 659 		return;
 660 
 661 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 662 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 663 
 664 	e_mail_reader_avoid_next_mark_as_seen (E_MAIL_READER (mail_view));
 665 }
 666 
 667 void
 668 e_mail_shell_view_private_init (EMailShellView *mail_shell_view,
 669                                 EShellViewClass *shell_view_class)
 670 {
 671 	if (!gal_view_collection_loaded (shell_view_class->view_collection))
 672 		mail_shell_view_load_view_collection (shell_view_class);
 673 
 674 	g_signal_connect (
 675 		mail_shell_view, "notify::view-id",
 676 		G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL);
 677 }
 678 
 679 void
 680 e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 681 {
 682 	EMailShellViewPrivate *priv = mail_shell_view->priv;
 683 	EMailShellContent *mail_shell_content;
 684 	EMailShellSidebar *mail_shell_sidebar;
 685 	EShell *shell;
 686 	EShellView *shell_view;
 687 	EShellBackend *shell_backend;
 688 	EShellContent *shell_content;
 689 	EShellSidebar *shell_sidebar;
 690 	EShellTaskbar *shell_taskbar;
 691 	EShellWindow *shell_window;
 692 	EShellSearchbar *searchbar;
 693 	EMFolderTree *folder_tree;
 694 	EActionComboBox *combo_box;
 695 	ERuleContext *context;
 696 	EFilterRule *rule = NULL;
 697 	GtkTreeSelection *selection;
 698 	GtkUIManager *ui_manager;
 699 	GtkWidget *message_list;
 700 	EMailLabelListStore *label_store;
 701 	EMailBackend *backend;
 702 	EMailSession *session;
 703 	EMailReader *reader;
 704 	EMailView *mail_view;
 705 	EMailDisplay *display;
 706 	const gchar *source;
 707 	guint merge_id;
 708 	gint ii = 0;
 709 
 710 	shell_view = E_SHELL_VIEW (mail_shell_view);
 711 	shell_backend = e_shell_view_get_shell_backend (shell_view);
 712 	shell_content = e_shell_view_get_shell_content (shell_view);
 713 	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 714 	shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
 715 	shell_window = e_shell_view_get_shell_window (shell_view);
 716 
 717 	ui_manager = e_shell_window_get_ui_manager (shell_window);
 718 
 719 	shell = e_shell_window_get_shell (shell_window);
 720 
 721 	backend = E_MAIL_BACKEND (shell_backend);
 722 	session = e_mail_backend_get_session (backend);
 723 	label_store = e_mail_ui_session_get_label_store (
 724 		E_MAIL_UI_SESSION (session));
 725 
 726 	e_shell_window_add_action_group (shell_window, "mail");
 727 	e_shell_window_add_action_group (shell_window, "mail-filter");
 728 	e_shell_window_add_action_group (shell_window, "mail-label");
 729 	e_shell_window_add_action_group (shell_window, "search-folders");
 730 
 731 	merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 732 	priv->label_merge_id = merge_id;
 733 
 734 	/* Cache these to avoid lots of awkward casting. */
 735 	priv->mail_shell_backend = g_object_ref (shell_backend);
 736 	priv->mail_shell_content = g_object_ref (shell_content);
 737 	priv->mail_shell_sidebar = g_object_ref (shell_sidebar);
 738 
 739 	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 740 	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 741 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree));
 742 
 743 	mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content);
 744 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 745 	searchbar = e_mail_shell_content_get_searchbar (mail_shell_content);
 746 	combo_box = e_shell_searchbar_get_scope_combo_box (searchbar);
 747 
 748 	reader = E_MAIL_READER (shell_content);
 749 	display = e_mail_reader_get_mail_display (reader);
 750 	message_list = e_mail_reader_get_message_list (reader);
 751 
 752 	em_folder_tree_set_selectable_widget (folder_tree, message_list);
 753 
 754 	/* The folder tree and scope combo box are both insensitive
 755 	 * when searching beyond the currently selected folder. */
 756 	g_object_bind_property (
 757 		folder_tree, "sensitive",
 758 		combo_box, "sensitive",
 759 		G_BINDING_BIDIRECTIONAL |
 760 		G_BINDING_SYNC_CREATE);
 761 
 762 	combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
 763 	g_signal_connect_object (
 764 		combo_box, "changed",
 765 		G_CALLBACK (mail_shell_view_search_filter_changed_cb),
 766 		mail_shell_view, G_CONNECT_SWAPPED);
 767 
 768 	g_signal_connect_object (
 769 		folder_tree, "folder-selected",
 770 		G_CALLBACK (mail_shell_view_folder_tree_selected_cb),
 771 		mail_shell_view, G_CONNECT_SWAPPED);
 772 
 773 	g_signal_connect_object (
 774 		folder_tree, "key-press-event",
 775 		G_CALLBACK (mail_shell_view_folder_tree_key_press_event_cb),
 776 		mail_shell_view, G_CONNECT_SWAPPED);
 777 
 778 	g_signal_connect_object (
 779 		folder_tree, "popup-event",
 780 		G_CALLBACK (mail_shell_view_folder_tree_popup_event_cb),
 781 		mail_shell_view, G_CONNECT_SWAPPED);
 782 
 783 	g_signal_connect_object (
 784 		message_list, "key-press",
 785 		G_CALLBACK (mail_shell_view_message_list_key_press_cb),
 786 		mail_shell_view, G_CONNECT_SWAPPED);
 787 
 788 	g_signal_connect_object (
 789 		message_list, "popup-menu",
 790 		G_CALLBACK (mail_shell_view_message_list_popup_menu_cb),
 791 		mail_shell_view, G_CONNECT_SWAPPED);
 792 
 793 	g_signal_connect_object (
 794 		message_list, "right-click",
 795 		G_CALLBACK (mail_shell_view_message_list_right_click_cb),
 796 		mail_shell_view, G_CONNECT_SWAPPED);
 797 
 798 	g_signal_connect_object (
 799 		reader, "changed",
 800 		G_CALLBACK (mail_shell_view_reader_changed_cb),
 801 		mail_shell_view, G_CONNECT_SWAPPED);
 802 
 803 	g_signal_connect_object (
 804 		mail_view, "update-actions",
 805 		G_CALLBACK (mail_shell_view_reader_update_actions_cb),
 806 		mail_shell_view, 0);
 807 
 808 	g_signal_connect_object (
 809 		reader, "folder-loaded",
 810 		G_CALLBACK (e_mail_view_update_view_instance),
 811 		mail_view, G_CONNECT_SWAPPED);
 812 
 813 	/* Use the same callback as "changed". */
 814 	g_signal_connect_object (
 815 		reader, "folder-loaded",
 816 		G_CALLBACK (mail_shell_view_reader_changed_cb),
 817 		mail_shell_view, G_CONNECT_SWAPPED);
 818 
 819 	g_signal_connect_object (
 820 		reader, "folder-loaded",
 821 		G_CALLBACK (e_mail_shell_view_restore_state),
 822 		mail_shell_view, G_CONNECT_SWAPPED);
 823 
 824 	g_signal_connect_object (
 825 		label_store, "row-changed",
 826 		G_CALLBACK (e_mail_shell_view_update_search_filter),
 827 		mail_shell_view, G_CONNECT_SWAPPED);
 828 
 829 	g_signal_connect_object (
 830 		label_store, "row-deleted",
 831 		G_CALLBACK (e_mail_shell_view_update_search_filter),
 832 		mail_shell_view, G_CONNECT_SWAPPED);
 833 
 834 	g_signal_connect_object (
 835 		label_store, "row-inserted",
 836 		G_CALLBACK (e_mail_shell_view_update_search_filter),
 837 		mail_shell_view, G_CONNECT_SWAPPED);
 838 
 839 	g_signal_connect_object (
 840 		display, "key-press-event",
 841 		G_CALLBACK (mail_shell_view_key_press_event_cb),
 842 		mail_shell_view, G_CONNECT_SWAPPED);
 843 
 844 	g_signal_connect_object (
 845 		display, "popup-event",
 846 		G_CALLBACK (mail_shell_view_popup_event_cb),
 847 		mail_shell_view, G_CONNECT_SWAPPED);
 848 
 849 	g_signal_connect_object (
 850 		display, "status-message",
 851 		G_CALLBACK (e_shell_taskbar_set_message),
 852 		shell_taskbar, G_CONNECT_SWAPPED);
 853 
 854 	g_signal_connect_object (
 855 		mail_shell_view, "toggled",
 856 		G_CALLBACK (e_mail_shell_view_update_send_receive_menus),
 857 		mail_shell_view, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
 858 
 859 	/* Need to keep the handler ID so we can disconnect it in
 860 	 * dispose().  The shell outlives us and we don't want it
 861 	 * invoking callbacks on finalized shell views. */
 862 	priv->prepare_for_quit_handler_id =
 863 		g_signal_connect_object (
 864 			shell, "prepare-for-quit",
 865 			G_CALLBACK (mail_shell_view_prepare_for_quit_cb),
 866 			mail_shell_view, G_CONNECT_SWAPPED);
 867 
 868 	e_mail_reader_init (reader, TRUE, FALSE);
 869 	e_mail_shell_view_actions_init (mail_shell_view);
 870 	e_mail_shell_view_update_search_filter (mail_shell_view);
 871 
 872 	/* This binding must come after e_mail_reader_init(). */
 873 	g_object_bind_property (
 874 		shell_content, "group-by-threads",
 875 		mail_view, "group-by-threads",
 876 		G_BINDING_BIDIRECTIONAL |
 877 		G_BINDING_SYNC_CREATE);
 878 
 879 	/* Populate built-in rules for search entry popup menu.
 880 	 * Keep the assertions, please.  If the conditions aren't
 881 	 * met we're going to crash anyway, just more mysteriously. */
 882 	context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context;
 883 	source = E_FILTER_SOURCE_DEMAND;
 884 	while ((rule = e_rule_context_next_rule (context, rule, source))) {
 885 		if (!rule->system)
 886 			continue;
 887 		g_assert (ii < MAIL_NUM_SEARCH_RULES);
 888 		priv->search_rules[ii++] = g_object_ref (rule);
 889 	}
 890 	g_assert (ii == MAIL_NUM_SEARCH_RULES);
 891 
 892 	/* Now that we're all set up, simulate selecting a folder. */
 893 	g_signal_emit_by_name (selection, "changed");
 894 }
 895 
 896 void
 897 e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view)
 898 {
 899 	EMailShellViewPrivate *priv = mail_shell_view->priv;
 900 	gint ii;
 901 
 902 	/* XXX It's a little awkward to have to dig up the
 903 	 *     shell this late in the game.  Should we just
 904 	 *     keep a direct reference to it?  Not sure. */
 905 	if (priv->prepare_for_quit_handler_id > 0) {
 906 		EShellBackend *shell_backend;
 907 		EShell *shell;
 908 
 909 		shell_backend = E_SHELL_BACKEND (priv->mail_shell_backend);
 910 		shell = e_shell_backend_get_shell (shell_backend);
 911 
 912 		g_signal_handler_disconnect (
 913 			shell, priv->prepare_for_quit_handler_id);
 914 		priv->prepare_for_quit_handler_id = 0;
 915 	}
 916 
 917 	DISPOSE (priv->mail_shell_backend);
 918 	DISPOSE (priv->mail_shell_content);
 919 	DISPOSE (priv->mail_shell_sidebar);
 920 
 921 	for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++)
 922 		DISPOSE (priv->search_rules[ii]);
 923 
 924 	if (priv->opening_folder != NULL) {
 925 		g_cancellable_cancel (priv->opening_folder);
 926 		g_object_unref (priv->opening_folder);
 927 		priv->opening_folder = NULL;
 928 	}
 929 
 930 	if (priv->search_account_all != NULL) {
 931 		g_object_unref (priv->search_account_all);
 932 		priv->search_account_all = NULL;
 933 	}
 934 
 935 	if (priv->search_account_current != NULL) {
 936 		g_object_unref (priv->search_account_current);
 937 		priv->search_account_current = NULL;
 938 	}
 939 
 940 	if (priv->search_account_cancel != NULL) {
 941 		g_object_unref (priv->search_account_cancel);
 942 		priv->search_account_cancel = NULL;
 943 	}
 944 }
 945 
 946 void
 947 e_mail_shell_view_private_finalize (EMailShellView *mail_shell_view)
 948 {
 949 	/* XXX Nothing to do? */
 950 }
 951 
 952 void
 953 e_mail_shell_view_restore_state (EMailShellView *mail_shell_view)
 954 {
 955 	EMailShellContent *mail_shell_content;
 956 	EShellSearchbar *searchbar;
 957 	EMailReader *reader;
 958 	EMailView *mail_view;
 959 	CamelFolder *folder;
 960 	CamelVeeFolder *vee_folder;
 961 	const gchar *old_state_group;
 962 	gchar *folder_uri;
 963 	gchar *new_state_group;
 964 
 965 	/* XXX Move this to EMailShellContent. */
 966 
 967 	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
 968 
 969 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
 970 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
 971 	searchbar = e_mail_shell_content_get_searchbar (mail_shell_content);
 972 
 973 	reader = E_MAIL_READER (mail_view);
 974 	folder = e_mail_reader_get_folder (reader);
 975 
 976 	if (folder == NULL) {
 977 		if (e_shell_searchbar_get_state_group (searchbar)) {
 978 			e_shell_searchbar_set_state_group (searchbar, NULL);
 979 			e_shell_searchbar_load_state (searchbar);
 980 		}
 981 		return;
 982 	}
 983 
 984 	/* Do not restore state if we're running a "Current Account"
 985 	 * or "All Accounts" search, since we don't want the search
 986 	 * criteria to be destroyed in those cases. */
 987 
 988 	vee_folder = mail_shell_view->priv->search_account_all;
 989 	if (vee_folder != NULL && folder == CAMEL_FOLDER (vee_folder))
 990 		return;
 991 
 992 	vee_folder = mail_shell_view->priv->search_account_current;
 993 	if (vee_folder != NULL && folder == CAMEL_FOLDER (vee_folder))
 994 		return;
 995 
 996 	folder_uri = e_mail_folder_uri_from_folder (folder);
 997 	new_state_group = g_strdup_printf ("Folder %s", folder_uri);
 998 	old_state_group = e_shell_searchbar_get_state_group (searchbar);
 999 	g_free (folder_uri);
1000 
1001 	/* Avoid loading search state unnecessarily. */
1002 	if (g_strcmp0 (new_state_group, old_state_group) != 0) {
1003 		e_shell_searchbar_set_state_group (searchbar, new_state_group);
1004 		e_shell_searchbar_load_state (searchbar);
1005 	}
1006 
1007 	g_free (new_state_group);
1008 }
1009 
1010 void
1011 e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view)
1012 {
1013 	EMailShellContent *mail_shell_content;
1014 	EShellBackend *shell_backend;
1015 	EShellSidebar *shell_sidebar;
1016 	EShellView *shell_view;
1017 	EShell *shell;
1018 	EMailReader *reader;
1019 	EMailView *mail_view;
1020 	ESourceRegistry *registry;
1021 	CamelStore *parent_store;
1022 	CamelFolder *folder;
1023 	GPtrArray *uids;
1024 	GString *buffer;
1025 	gboolean store_is_local;
1026 	const gchar *display_name;
1027 	const gchar *folder_name;
1028 	const gchar *uid;
1029 	gchar *title;
1030 	guint32 num_deleted;
1031 	guint32 num_junked;
1032 	guint32 num_junked_not_deleted;
1033 	guint32 num_unread;
1034 	guint32 num_visible;
1035 
1036 	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
1037 
1038 	mail_shell_content = mail_shell_view->priv->mail_shell_content;
1039 	mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
1040 
1041 	shell_view = E_SHELL_VIEW (mail_shell_view);
1042 	shell_backend = e_shell_view_get_shell_backend (shell_view);
1043 	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
1044 
1045 	shell = e_shell_backend_get_shell (shell_backend);
1046 	registry = e_shell_get_registry (shell);
1047 
1048 	reader = E_MAIL_READER (mail_view);
1049 	folder = e_mail_reader_get_folder (reader);
1050 
1051 	/* If no folder is selected, reset the sidebar banners
1052 	 * to their default values and stop. */
1053 	if (folder == NULL) {
1054 		GtkAction *action;
1055 		gchar *label;
1056 
1057 		action = e_shell_view_get_action (shell_view);
1058 
1059 		g_object_get (action, "label", &label, NULL);
1060 		e_shell_sidebar_set_secondary_text (shell_sidebar, NULL);
1061 		e_shell_view_set_title (shell_view, label);
1062 		g_free (label);
1063 
1064 		return;
1065 	}
1066 
1067 	folder_name = camel_folder_get_display_name (folder);
1068 	parent_store = camel_folder_get_parent_store (folder);
1069 
1070 	num_deleted = camel_folder_summary_get_deleted_count (folder->summary);
1071 	num_junked = camel_folder_summary_get_junk_count (folder->summary);
1072 	num_junked_not_deleted =
1073 		camel_folder_summary_get_junk_not_deleted_count (folder->summary);
1074 	num_unread = camel_folder_summary_get_unread_count (folder->summary);
1075 	num_visible = camel_folder_summary_get_visible_count (folder->summary);
1076 
1077 	buffer = g_string_sized_new (256);
1078 	uids = e_mail_reader_get_selected_uids (reader);
1079 
1080 	if (uids->len > 1)
1081 		g_string_append_printf (
1082 			buffer, ngettext ("%d selected, ", "%d selected, ",
1083 			uids->len), uids->len);
1084 
1085 	if (CAMEL_IS_VTRASH_FOLDER (folder)) {
1086 		CamelVTrashFolder *trash_folder;
1087 
1088 		trash_folder = (CamelVTrashFolder *) folder;
1089 
1090 		/* "Trash" folder */
1091 		if (trash_folder->type == CAMEL_VTRASH_FOLDER_TRASH)
1092 			g_string_append_printf (
1093 				buffer, ngettext ("%d deleted",
1094 				"%d deleted", num_deleted), num_deleted);
1095 
1096 		/* "Junk" folder (hide deleted messages) */
1097 		else if (e_mail_reader_get_hide_deleted (reader))
1098 			g_string_append_printf (
1099 				buffer, ngettext ("%d junk",
1100 				"%d junk", num_junked_not_deleted),
1101 				num_junked_not_deleted);
1102 
1103 		/* "Junk" folder (show deleted messages) */
1104 		else
1105 			g_string_append_printf (
1106 				buffer, ngettext ("%d junk", "%d junk",
1107 				num_junked), num_junked);
1108 
1109 	/* "Drafts" folder */
1110 	} else if (em_utils_folder_is_drafts (registry, folder)) {
1111 		g_string_append_printf (
1112 			buffer, ngettext ("%d draft", "%d drafts",
1113 			num_visible), num_visible);
1114 
1115 	/* "Outbox" folder */
1116 	} else if (em_utils_folder_is_outbox (registry, folder)) {
1117 		g_string_append_printf (
1118 			buffer, ngettext ("%d unsent", "%d unsent",
1119 			num_visible), num_visible);
1120 
1121 	/* "Sent" folder */
1122 	} else if (em_utils_folder_is_sent (registry, folder)) {
1123 		g_string_append_printf (
1124 			buffer, ngettext ("%d sent", "%d sent",
1125 			num_visible), num_visible);
1126 
1127 	/* Normal folder */
1128 	} else {
1129 		if (!e_mail_reader_get_hide_deleted (reader))
1130 			num_visible +=
1131 				num_deleted - num_junked +
1132 				num_junked_not_deleted;
1133 
1134 		if (num_unread > 0 && uids->len <= 1)
1135 			g_string_append_printf (
1136 				buffer, ngettext ("%d unread, ",
1137 				"%d unread, ", num_unread), num_unread);
1138 		g_string_append_printf (
1139 			buffer, ngettext ("%d total", "%d total",
1140 			num_visible), num_visible);
1141 	}
1142 
1143 	em_utils_uids_free (uids);
1144 
1145 	uid = camel_service_get_uid (CAMEL_SERVICE (parent_store));
1146 	store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0);
1147 
1148 	/* Choose a suitable folder name for displaying. */
1149 	display_name = folder_name;
1150 	if (store_is_local) {
1151 		if (strcmp (folder_name, "Drafts") == 0)
1152 			display_name = _("Drafts");
1153 		else if (strcmp (folder_name, "Inbox") == 0)
1154 			display_name = _("Inbox");
1155 		else if (strcmp (folder_name, "Outbox") == 0)
1156 			display_name = _("Outbox");
1157 		else if (strcmp (folder_name, "Sent") == 0)
1158 			display_name = _("Sent");
1159 		else if (strcmp (folder_name, "Templates") == 0)
1160 			display_name = _("Templates");
1161 		else if (strcmp (folder_name, "Trash") == 0)
1162 			display_name = _("Trash");
1163 	}
1164 	if (strcmp (folder_name, "INBOX") == 0)
1165 		display_name = _("Inbox");
1166 
1167 	title = g_strdup_printf ("%s (%s)", display_name, buffer->str);
1168 	e_shell_sidebar_set_secondary_text (shell_sidebar, buffer->str);
1169 	e_shell_view_set_title (shell_view, title);
1170 	g_free (title);
1171 
1172 	g_string_free (buffer, TRUE);
1173 }
1174 
1175 typedef struct {
1176 	GtkMenuShell *menu;
1177 	CamelSession *session;
1178 	EMailAccountStore *account_store;
1179 
1180 	/* GtkMenuItem -> CamelService */
1181 	GHashTable *menu_items;
1182 
1183 	/* Signal handlers */
1184 	gulong service_added_id;
1185 	gulong service_removed_id;
1186 	gulong service_enabled_id;
1187 	gulong service_disabled_id;
1188 } SendReceiveData;
1189 
1190 static gboolean
1191 send_receive_can_use_service (EMailAccountStore *account_store,
1192                               CamelService *service,
1193                               GtkTreeIter *piter)
1194 {
1195 	GtkTreeModel *model;
1196 	GtkTreeIter iter;
1197 	gboolean found = FALSE, enabled = FALSE, builtin = TRUE;
1198 
1199 	if (!CAMEL_IS_STORE (service))
1200 		return FALSE;
1201 
1202 	model = GTK_TREE_MODEL (account_store);
1203 
1204 	if (piter) {
1205 		found = TRUE;
1206 		iter = *piter;
1207 	} else if (gtk_tree_model_get_iter_first (model, &iter)) {
1208 		CamelService *adept;
1209 
1210 		do {
1211 			adept = NULL;
1212 
1213 			gtk_tree_model_get (
1214 				model, &iter,
1215 				E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, &adept,
1216 				-1);
1217 
1218 			if (service == adept) {
1219 				found = TRUE;
1220 				g_object_unref (adept);
1221 				break;
1222 			}
1223 
1224 			if (adept)
1225 				g_object_unref (adept);
1226 		} while (gtk_tree_model_iter_next (model, &iter));
1227 	}
1228 
1229 	if (!found)
1230 		return FALSE;
1231 
1232 	gtk_tree_model_get (
1233 		model, &iter,
1234 		E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, &enabled,
1235 		E_MAIL_ACCOUNT_STORE_COLUMN_BUILTIN, &builtin,
1236 		-1);
1237 
1238 	return enabled && !builtin;
1239 }
1240 
1241 static GtkMenuItem *
1242 send_receive_find_menu_item (SendReceiveData *data,
1243                              gpointer service)
1244 {
1245 	GHashTableIter iter;
1246 	gpointer menu_item;
1247 	gpointer candidate;
1248 
1249 	g_hash_table_iter_init (&iter, data->menu_items);
1250 
1251 	while (g_hash_table_iter_next (&iter, &menu_item, &candidate))
1252 		if (service == candidate)
1253 			return GTK_MENU_ITEM (menu_item);
1254 
1255 	return NULL;
1256 }
1257 
1258 static void
1259 send_receive_account_item_activate_cb (GtkMenuItem *menu_item,
1260                                        SendReceiveData *data)
1261 {
1262 	CamelService *service;
1263 
1264 	service = g_hash_table_lookup (data->menu_items, menu_item);
1265 	g_return_if_fail (CAMEL_IS_SERVICE (service));
1266 
1267 	mail_receive_service (service);
1268 }
1269 
1270 static void
1271 send_receive_add_to_menu (SendReceiveData *data,
1272                           CamelService *service,
1273                           gint position)
1274 {
1275 	GtkWidget *menu_item;
1276 
1277 	if (send_receive_find_menu_item (data, service) != NULL)
1278 		return;
1279 
1280 	menu_item = gtk_menu_item_new ();
1281 	gtk_widget_show (menu_item);
1282 
1283 	g_object_bind_property (
1284 		service, "display-name",
1285 		menu_item, "label",
1286 		G_BINDING_SYNC_CREATE);
1287 
1288 	g_hash_table_insert (
1289 		data->menu_items, menu_item,
1290 		g_object_ref (service));
1291 
1292 	g_signal_connect (
1293 		menu_item, "activate",
1294 		G_CALLBACK (send_receive_account_item_activate_cb), data);
1295 
1296 	/* Position is with respect to the sorted list of CamelService-s,
1297 	 * not menu item position. */
1298 	if (position < 0)
1299 		gtk_menu_shell_append (data->menu, menu_item);
1300 	else
1301 		gtk_menu_shell_insert (data->menu, menu_item, position + 4);
1302 }
1303 
1304 static void
1305 send_receive_gather_services (gpointer menu_item,
1306                               gpointer service,
1307                               gpointer queue)
1308 {
1309 	g_queue_push_head (queue, service);
1310 }
1311 
1312 static gint
1313 sort_services_cb (gconstpointer service1,
1314                   gconstpointer service2,
1315                   gpointer account_store)
1316 {
1317 	return e_mail_account_store_compare_services (account_store, CAMEL_SERVICE (service1), CAMEL_SERVICE (service2));
1318 }
1319 
1320 static void
1321 send_receive_menu_service_added_cb (EMailAccountStore *account_store,
1322                                     CamelService *service,
1323                                     SendReceiveData *data)
1324 {
1325 	GQueue *services;
1326 
1327 	if (!send_receive_can_use_service (account_store, service, NULL))
1328 		return;
1329 
1330 	services = g_queue_new ();
1331 
1332 	g_queue_push_head (services, service);
1333 	g_hash_table_foreach (data->menu_items, send_receive_gather_services, services);
1334 	g_queue_sort (services, sort_services_cb, account_store);
1335 
1336 	send_receive_add_to_menu (data, service, g_queue_index (services, service));
1337 
1338 	g_queue_free (services);
1339 }
1340 
1341 static void
1342 send_receive_menu_service_removed_cb (EMailAccountStore *account_store,
1343                                       CamelService *service,
1344                                       SendReceiveData *data)
1345 {
1346 	GtkMenuItem *menu_item;
1347 
1348 	menu_item = send_receive_find_menu_item (data, service);
1349 	if (menu_item == NULL)
1350 		return;
1351 
1352 	g_hash_table_remove (data->menu_items, menu_item);
1353 
1354 	gtk_container_remove (
1355 		GTK_CONTAINER (data->menu),
1356 		GTK_WIDGET (menu_item));
1357 }
1358 
1359 static void
1360 send_receive_data_free (SendReceiveData *data)
1361 {
1362 	g_signal_handler_disconnect (data->account_store, data->service_added_id);
1363 	g_signal_handler_disconnect (data->account_store, data->service_removed_id);
1364 	g_signal_handler_disconnect (data->account_store, data->service_enabled_id);
1365 	g_signal_handler_disconnect (data->account_store, data->service_disabled_id);
1366 
1367 	g_object_unref (data->session);
1368 	g_object_unref (data->account_store);
1369 
1370 	g_hash_table_destroy (data->menu_items);
1371 
1372 	g_slice_free (SendReceiveData, data);
1373 }
1374 
1375 static SendReceiveData *
1376 send_receive_data_new (EMailShellView *mail_shell_view,
1377                        GtkWidget *menu)
1378 {
1379 	SendReceiveData *data;
1380 	EShellView *shell_view;
1381 	EShellBackend *shell_backend;
1382 	EMailAccountStore *account_store;
1383 	EMailBackend *backend;
1384 	EMailSession *session;
1385 
1386 	shell_view = E_SHELL_VIEW (mail_shell_view);
1387 	shell_backend = e_shell_view_get_shell_backend (shell_view);
1388 
1389 	backend = E_MAIL_BACKEND (shell_backend);
1390 	session = e_mail_backend_get_session (backend);
1391 	account_store = e_mail_ui_session_get_account_store (
1392 		E_MAIL_UI_SESSION (session));
1393 
1394 	data = g_slice_new0 (SendReceiveData);
1395 	data->menu = GTK_MENU_SHELL (menu);  /* do not reference */
1396 	data->session = g_object_ref (session);
1397 	data->account_store = g_object_ref (account_store);
1398 
1399 	data->menu_items = g_hash_table_new_full (
1400 		(GHashFunc) g_direct_hash,
1401 		(GEqualFunc) g_direct_equal,
1402 		(GDestroyNotify) NULL,
1403 		(GDestroyNotify) g_object_unref);
1404 
1405 	data->service_added_id = g_signal_connect (
1406 		account_store, "service-added",
1407 		G_CALLBACK (send_receive_menu_service_added_cb), data);
1408 	data->service_removed_id = g_signal_connect (
1409 		account_store, "service-removed",
1410 		G_CALLBACK (send_receive_menu_service_removed_cb), data);
1411 	data->service_enabled_id = g_signal_connect (
1412 		account_store, "service-enabled",
1413 		G_CALLBACK (send_receive_menu_service_added_cb), data);
1414 	data->service_disabled_id = g_signal_connect (
1415 		account_store, "service-disabled",
1416 		G_CALLBACK (send_receive_menu_service_removed_cb), data);
1417 
1418 	g_object_weak_ref (
1419 		G_OBJECT (menu), (GWeakNotify)
1420 		send_receive_data_free, data);
1421 
1422 	return data;
1423 }
1424 
1425 static GtkWidget *
1426 create_send_receive_submenu (EMailShellView *mail_shell_view)
1427 {
1428 	EShellView *shell_view;
1429 	EShellWindow *shell_window;
1430 	EShellBackend *shell_backend;
1431 	EMailAccountStore *account_store;
1432 	EMailBackend *backend;
1433 	EMailSession *session;
1434 	GtkWidget *menu;
1435 	GtkAccelGroup *accel_group;
1436 	GtkUIManager *ui_manager;
1437 	GtkAction *action;
1438 	GtkTreeModel *model;
1439 	GtkTreeIter iter;
1440 	SendReceiveData *data;
1441 
1442 	g_return_val_if_fail (mail_shell_view != NULL, NULL);
1443 
1444 	shell_view = E_SHELL_VIEW (mail_shell_view);
1445 	shell_window = e_shell_view_get_shell_window (shell_view);
1446 	shell_backend = e_shell_view_get_shell_backend (shell_view);
1447 
1448 	backend = E_MAIL_BACKEND (shell_backend);
1449 	session = e_mail_backend_get_session (backend);
1450 	account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session));
1451 
1452 	menu = gtk_menu_new ();
1453 	ui_manager = e_shell_window_get_ui_manager (shell_window);
1454 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
1455 
1456 	action = e_shell_window_get_action (shell_window, "mail-send-receive");
1457 	gtk_action_set_accel_group (action, accel_group);
1458 	gtk_menu_shell_append (
1459 		GTK_MENU_SHELL (menu),
1460 		gtk_action_create_menu_item (action));
1461 
1462 	action = e_shell_window_get_action (
1463 		shell_window, "mail-send-receive-receive-all");
1464 	gtk_action_set_accel_group (action, accel_group);
1465 	gtk_menu_shell_append (
1466 		GTK_MENU_SHELL (menu),
1467 		gtk_action_create_menu_item (action));
1468 
1469 	action = e_shell_window_get_action (
1470 		shell_window, "mail-send-receive-send-all");
1471 	gtk_action_set_accel_group (action, accel_group);
1472 	gtk_menu_shell_append (
1473 		GTK_MENU_SHELL (menu),
1474 		gtk_action_create_menu_item (action));
1475 
1476 	gtk_menu_shell_append (
1477 		GTK_MENU_SHELL (menu),
1478 		gtk_separator_menu_item_new ());
1479 
1480 	data = send_receive_data_new (mail_shell_view, menu);
1481 
1482 	model = GTK_TREE_MODEL (account_store);
1483 	if (gtk_tree_model_get_iter_first (model, &iter)) {
1484 		CamelService *service;
1485 
1486 		do {
1487 			service = NULL;
1488 
1489 			gtk_tree_model_get (
1490 				model, &iter,
1491 				E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, &service,
1492 				-1);
1493 
1494 			if (send_receive_can_use_service (account_store, service, &iter))
1495 				send_receive_add_to_menu (data, service, -1);
1496 
1497 			if (service)
1498 				g_object_unref (service);
1499 		} while (gtk_tree_model_iter_next (model, &iter));
1500 	}
1501 
1502 	gtk_widget_show_all (menu);
1503 
1504 	return menu;
1505 }
1506 
1507 void
1508 e_mail_shell_view_update_send_receive_menus (EMailShellView *mail_shell_view)
1509 {
1510 	EMailShellViewPrivate *priv;
1511 	EShellWindow *shell_window;
1512 	EShellView *shell_view;
1513 	GtkWidget *widget;
1514 	const gchar *widget_path;
1515 
1516 	g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
1517 
1518 	priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (mail_shell_view);
1519 
1520 	shell_view = E_SHELL_VIEW (mail_shell_view);
1521 	shell_window = e_shell_view_get_shell_window (shell_view);
1522 
1523 	if (!e_shell_view_is_active (shell_view)) {
1524 		if (priv->send_receive_tool_item) {
1525 			GtkWidget *toolbar;
1526 
1527 			toolbar = e_shell_window_get_managed_widget (
1528 				shell_window, "/main-toolbar");
1529 			g_return_if_fail (toolbar != NULL);
1530 
1531 			gtk_container_remove (
1532 				GTK_CONTAINER (toolbar),
1533 				GTK_WIDGET (priv->send_receive_tool_item));
1534 			gtk_container_remove (
1535 				GTK_CONTAINER (toolbar),
1536 				GTK_WIDGET (priv->send_receive_tool_separator));
1537 
1538 			priv->send_receive_tool_item = NULL;
1539 			priv->send_receive_tool_separator = NULL;
1540 		}
1541 
1542 		return;
1543 	}
1544 
1545 	widget_path =
1546 		"/main-menu/file-menu"
1547 		"/mail-send-receiver/mail-send-receive-submenu";
1548 	widget = e_shell_window_get_managed_widget (shell_window, widget_path);
1549 	if (widget != NULL)
1550 		gtk_menu_item_set_submenu (
1551 			GTK_MENU_ITEM (widget),
1552 			create_send_receive_submenu (mail_shell_view));
1553 
1554 	if (!priv->send_receive_tool_item) {
1555 		GtkWidget *toolbar;
1556 		GtkToolItem *tool_item;
1557 		gint index;
1558 
1559 		toolbar = e_shell_window_get_managed_widget (
1560 			shell_window, "/main-toolbar");
1561 		g_return_if_fail (toolbar != NULL);
1562 
1563 		widget_path =
1564 			"/main-toolbar/toolbar-actions/mail-send-receiver";
1565 		widget = e_shell_window_get_managed_widget (
1566 			shell_window, widget_path);
1567 		g_return_if_fail (widget != NULL);
1568 
1569 		index = gtk_toolbar_get_item_index (
1570 			GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget));
1571 
1572 		tool_item = gtk_separator_tool_item_new ();
1573 		gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, index);
1574 		gtk_widget_show (GTK_WIDGET (tool_item));
1575 		priv->send_receive_tool_separator = tool_item;
1576 
1577 		tool_item = GTK_TOOL_ITEM (
1578 			e_menu_tool_button_new (_("Send / Receive")));
1579 		gtk_tool_item_set_is_important (tool_item, TRUE);
1580 		gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, index);
1581 		gtk_widget_show (GTK_WIDGET (tool_item));
1582 		priv->send_receive_tool_item = tool_item;
1583 
1584 		g_object_bind_property (
1585 			ACTION (MAIL_SEND_RECEIVE), "sensitive",
1586 			tool_item, "sensitive",
1587 			G_BINDING_SYNC_CREATE);
1588 	}
1589 
1590 	if (priv->send_receive_tool_item)
1591 		gtk_menu_tool_button_set_menu (
1592 			GTK_MENU_TOOL_BUTTON (priv->send_receive_tool_item),
1593 			create_send_receive_submenu (mail_shell_view));
1594 }