No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-shell-view.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-shell-view.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-shell-view.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 #include "filter/e-filter-input.h"
28
29 static gpointer parent_class;
30 static GType mail_shell_view_type;
31
32 /* ETable spec for search results */
33 static const gchar *SEARCH_RESULTS_STATE =
34 "<ETableState>"
35 " <column source=\"0\"/>"
36 " <column source=\"3\"/>"
37 " <column source=\"1\"/>"
38 " <column source=\"14\"/>"
39 " <column source=\"5\"/>"
40 " <column source=\"7\"/>"
41 " <column source=\"13\"/>"
42 " <grouping>"
43 " <leaf column=\"7\" ascending=\"false\"/>"
44 " </grouping>"
45 "</ETableState>";
46
47 static void
48 add_folders_from_store (GList **folders,
49 CamelStore *store,
50 GCancellable *cancellable,
51 GError **error)
52 {
53 CamelFolderInfo *root, *fi;
54
55 g_return_if_fail (folders != NULL);
56 g_return_if_fail (store != NULL);
57
58 if (CAMEL_IS_VEE_STORE (store))
59 return;
60
61 root = camel_store_get_folder_info_sync (
62 store, NULL,
63 CAMEL_STORE_FOLDER_INFO_RECURSIVE, cancellable, error);
64 fi = root;
65 while (fi && !g_cancellable_is_cancelled (cancellable)) {
66 CamelFolderInfo *next;
67
68 if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) {
69 CamelFolder *fldr;
70
71 fldr = camel_store_get_folder_sync (
72 store, fi->full_name, 0, cancellable, error);
73 if (fldr) {
74 if (CAMEL_IS_VEE_FOLDER (fldr)) {
75 g_object_unref (fldr);
76 } else {
77 *folders = g_list_prepend (*folders, fldr);
78 }
79 }
80 }
81
82 /* pick the next */
83 next = fi->child;
84 if (!next)
85 next = fi->next;
86 if (!next) {
87 next = fi->parent;
88 while (next) {
89 if (next->next) {
90 next = next->next;
91 break;
92 }
93
94 next = next->parent;
95 }
96 }
97
98 fi = next;
99 }
100
101 if (root)
102 camel_store_free_folder_info_full (store, root);
103 }
104
105 typedef struct {
106 MailMsg base;
107
108 CamelFolder *folder;
109 GCancellable *cancellable;
110 GList *stores_list;
111 } SearchResultsMsg;
112
113 static gchar *
114 search_results_desc (SearchResultsMsg *msg)
115 {
116 return g_strdup (_("Searching"));
117 }
118
119 static void
120 search_results_exec (SearchResultsMsg *msg,
121 GCancellable *cancellable,
122 GError **error)
123 {
124 GList *folders = NULL, *iter;
125
126 for (iter = msg->stores_list; iter && !g_cancellable_is_cancelled (cancellable); iter = iter->next) {
127 CamelStore *store = iter->data;
128
129 add_folders_from_store (&folders, store, cancellable, error);
130 }
131
132 if (!g_cancellable_is_cancelled (cancellable)) {
133 CamelVeeFolder *vfolder = CAMEL_VEE_FOLDER (msg->folder);
134
135 folders = g_list_reverse (folders);
136
137 camel_vee_folder_set_folders (vfolder, folders, cancellable);
138 }
139
140 g_list_free_full (folders, g_object_unref);
141 }
142
143 static void
144 search_results_done (SearchResultsMsg *msg)
145 {
146 }
147
148 static void
149 search_results_free (SearchResultsMsg *msg)
150 {
151 g_object_unref (msg->folder);
152 g_list_free_full (msg->stores_list, g_object_unref);
153 }
154
155 static MailMsgInfo search_results_setup_info = {
156 sizeof (SearchResultsMsg),
157 (MailMsgDescFunc) search_results_desc,
158 (MailMsgExecFunc) search_results_exec,
159 (MailMsgDoneFunc) search_results_done,
160 (MailMsgFreeFunc) search_results_free
161 };
162
163 static gint
164 mail_shell_view_setup_search_results_folder (CamelFolder *folder,
165 GList *stores,
166 GCancellable *cancellable)
167 {
168 SearchResultsMsg *msg;
169 gint id;
170
171 g_object_ref (folder);
172
173 msg = mail_msg_new (&search_results_setup_info);
174 msg->folder = folder;
175 msg->cancellable = cancellable;
176 msg->stores_list = stores;
177
178 id = msg->base.seq;
179 mail_msg_slow_ordered_push (msg);
180
181 return id;
182 }
183
184 static void
185 mail_shell_view_show_search_results_folder (EMailShellView *mail_shell_view,
186 CamelFolder *folder)
187 {
188 EMailShellContent *mail_shell_content;
189 GtkWidget *message_list;
190 EMailView *mail_view;
191 EMailReader *reader;
192 GalViewInstance *view_instance;
193
194 mail_shell_content = mail_shell_view->priv->mail_shell_content;
195 mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
196 reader = E_MAIL_READER (mail_view);
197
198 message_list = e_mail_reader_get_message_list (reader);
199
200 message_list_freeze (MESSAGE_LIST (message_list));
201
202 e_mail_reader_set_folder (reader, folder);
203 view_instance = e_mail_view_get_view_instance (mail_view);
204
205 if (!view_instance || !gal_view_instance_exists (view_instance))
206 e_tree_set_state (E_TREE (message_list), SEARCH_RESULTS_STATE);
207
208 message_list_thaw (MESSAGE_LIST (message_list));
209 }
210
211 static void
212 mail_shell_view_dispose (GObject *object)
213 {
214 e_mail_shell_view_private_dispose (E_MAIL_SHELL_VIEW (object));
215
216 /* Chain up to parent's dispose() method. */
217 G_OBJECT_CLASS (parent_class)->dispose (object);
218 }
219
220 static void
221 mail_shell_view_finalize (GObject *object)
222 {
223 e_mail_shell_view_private_finalize (E_MAIL_SHELL_VIEW (object));
224
225 /* Chain up to parent's finalize() method. */
226 G_OBJECT_CLASS (parent_class)->finalize (object);
227 }
228
229 static void
230 mail_shell_view_constructed (GObject *object)
231 {
232 /* Chain up to parent's constructed() method. */
233 G_OBJECT_CLASS (parent_class)->constructed (object);
234
235 e_mail_shell_view_private_constructed (E_MAIL_SHELL_VIEW (object));
236 }
237
238 static void
239 mail_shell_view_toggled (EShellView *shell_view)
240 {
241 EMailShellViewPrivate *priv;
242 EShellWindow *shell_window;
243 GtkUIManager *ui_manager;
244 const gchar *basename;
245 gboolean view_is_active;
246
247 priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view);
248
249 shell_window = e_shell_view_get_shell_window (shell_view);
250 ui_manager = e_shell_window_get_ui_manager (shell_window);
251 view_is_active = e_shell_view_is_active (shell_view);
252 basename = E_MAIL_READER_UI_DEFINITION;
253
254 if (view_is_active && priv->merge_id == 0) {
255 EMailView *mail_view;
256
257 priv->merge_id = e_ui_manager_add_ui_from_file (
258 E_UI_MANAGER (ui_manager), basename);
259 mail_view = e_mail_shell_content_get_mail_view (
260 priv->mail_shell_content);
261 e_mail_reader_create_charset_menu (
262 E_MAIL_READER (mail_view),
263 ui_manager, priv->merge_id);
264 } else if (!view_is_active && priv->merge_id != 0) {
265 gtk_ui_manager_remove_ui (ui_manager, priv->merge_id);
266 gtk_ui_manager_ensure_update (ui_manager);
267 priv->merge_id = 0;
268 }
269
270 /* Chain up to parent's toggled() method. */
271 E_SHELL_VIEW_CLASS (parent_class)->toggled (shell_view);
272 }
273
274 static void
275 mail_shell_view_execute_search (EShellView *shell_view)
276 {
277 EMailShellViewPrivate *priv;
278 EMailShellContent *mail_shell_content;
279 EMailShellSidebar *mail_shell_sidebar;
280 EShellWindow *shell_window;
281 EShellBackend *shell_backend;
282 EShellContent *shell_content;
283 EShellSidebar *shell_sidebar;
284 EShellSearchbar *searchbar;
285 EActionComboBox *combo_box;
286 EMailBackend *backend;
287 EMailSession *session;
288 ESourceRegistry *registry;
289 EMFolderTree *folder_tree;
290 GtkWidget *message_list;
291 EFilterRule *rule;
292 EMailReader *reader;
293 EMailView *mail_view;
294 CamelVeeFolder *search_folder;
295 CamelFolder *folder;
296 CamelService *service;
297 CamelStore *store;
298 GtkAction *action;
299 EMailLabelListStore *label_store;
300 GtkTreePath *path;
301 GtkTreeIter tree_iter;
302 GString *string;
303 GList *list, *iter;
304 GSList *search_strings = NULL;
305 const gchar *text;
306 gboolean valid;
307 gchar *query;
308 gchar *temp;
309 gchar *tag;
310 const gchar *use_tag;
311 gint value;
312
313 priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view);
314
315 shell_window = e_shell_view_get_shell_window (shell_view);
316 shell_backend = e_shell_view_get_shell_backend (shell_view);
317 shell_content = e_shell_view_get_shell_content (shell_view);
318 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
319
320 backend = E_MAIL_BACKEND (shell_backend);
321 session = e_mail_backend_get_session (backend);
322
323 mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content);
324 mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
325 searchbar = e_mail_shell_content_get_searchbar (mail_shell_content);
326
327 mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
328 folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
329
330 reader = E_MAIL_READER (mail_view);
331 folder = e_mail_reader_get_folder (reader);
332 message_list = e_mail_reader_get_message_list (reader);
333
334 registry = e_mail_session_get_registry (session);
335 label_store = e_mail_ui_session_get_label_store (E_MAIL_UI_SESSION (session));
336
337 action = ACTION (MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN);
338 value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
339
340 text = e_shell_searchbar_get_search_text (searchbar);
341 if (value == MAIL_SEARCH_ADVANCED || text == NULL || *text == '\0') {
342 if (value != MAIL_SEARCH_ADVANCED)
343 e_shell_view_set_search_rule (shell_view, NULL);
344
345 query = e_shell_view_get_search_query (shell_view);
346
347 if (!query)
348 query = g_strdup ("");
349
350 goto filter;
351 }
352
353 /* Replace variables in the selected rule with the
354 * current search text and extract a query string. */
355
356 g_return_if_fail (value >= 0 && value < MAIL_NUM_SEARCH_RULES);
357 rule = priv->search_rules[value];
358
359 /* Set the search rule in EShellView so that "Create
360 * Search Folder from Search" works for quick searches. */
361 e_shell_view_set_search_rule (shell_view, rule);
362
363 for (iter = rule->parts; iter != NULL; iter = iter->next) {
364 EFilterPart *part = iter->data;
365 EFilterElement *element = NULL;
366
367 if (strcmp (part->name, "subject") == 0)
368 element = e_filter_part_find_element (part, "subject");
369 else if (strcmp (part->name, "body") == 0)
370 element = e_filter_part_find_element (part, "word");
371 else if (strcmp (part->name, "sender") == 0)
372 element = e_filter_part_find_element (part, "sender");
373 else if (strcmp (part->name, "to") == 0)
374 element = e_filter_part_find_element (part, "recipient");
375
376 if (strcmp (part->name, "body") == 0) {
377 struct _camel_search_words *words;
378 gint ii;
379
380 words = camel_search_words_split ((guchar *) text);
381 for (ii = 0; ii < words->len; ii++)
382 search_strings = g_slist_prepend (
383 search_strings, g_strdup (
384 words->words[ii]->word));
385 camel_search_words_free (words);
386 }
387
388 if (element != NULL) {
389 EFilterInput *input = E_FILTER_INPUT (element);
390 e_filter_input_set_value (input, text);
391 }
392 }
393
394 string = g_string_sized_new (1024);
395 e_filter_rule_build_code (rule, string);
396 query = g_string_free (string, FALSE);
397
398 filter:
399
400 /* Apply selected filter. */
401
402 combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
403 value = e_action_combo_box_get_current_value (combo_box);
404 switch (value) {
405 case MAIL_FILTER_ALL_MESSAGES:
406 break;
407
408 case MAIL_FILTER_UNREAD_MESSAGES:
409 temp = g_strdup_printf (
410 "(and %s (match-all (not "
411 "(system-flag \"Seen\"))))", query);
412 g_free (query);
413 query = temp;
414 break;
415
416 case MAIL_FILTER_NO_LABEL:
417 string = g_string_sized_new (1024);
418 g_string_append_printf (
419 string, "(and %s (and ", query);
420 valid = gtk_tree_model_get_iter_first (
421 GTK_TREE_MODEL (label_store), &tree_iter);
422 while (valid) {
423 tag = e_mail_label_list_store_get_tag (
424 label_store, &tree_iter);
425 use_tag = tag;
426 if (g_str_has_prefix (use_tag, "$Label"))
427 use_tag += 6;
428 g_string_append_printf (
429 string, " (match-all (not (or "
430 "(= (user-tag \"label\") \"%s\") "
431 "(user-flag \"$Label%s\") "
432 "(user-flag \"%s\"))))",
433 use_tag, use_tag, use_tag);
434 g_free (tag);
435
436 valid = gtk_tree_model_iter_next (
437 GTK_TREE_MODEL (label_store),
438 &tree_iter);
439 }
440 g_string_append_len (string, "))", 2);
441 g_free (query);
442 query = g_string_free (string, FALSE);
443 break;
444
445 case MAIL_FILTER_READ_MESSAGES:
446 temp = g_strdup_printf (
447 "(and %s (match-all "
448 "(system-flag \"Seen\")))", query);
449 g_free (query);
450 query = temp;
451 break;
452
453 case MAIL_FILTER_LAST_5_DAYS_MESSAGES:
454 if (em_utils_folder_is_sent (registry, folder))
455 temp = g_strdup_printf (
456 "(and %s (match-all "
457 "(> (get-sent-date) "
458 "(- (get-current-date) 432000))))",
459 query);
460 else
461 temp = g_strdup_printf (
462 "(and %s (match-all "
463 "(> (get-received-date) "
464 "(- (get-current-date) 432000))))",
465 query);
466 g_free (query);
467 query = temp;
468 break;
469
470 case MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS:
471 temp = g_strdup_printf (
472 "(and %s (match-all "
473 "(system-flag \"Attachments\")))", query);
474 g_free (query);
475 query = temp;
476 break;
477
478 case MAIL_FILTER_IMPORTANT_MESSAGES:
479 temp = g_strdup_printf (
480 "(and %s (match-all "
481 "(system-flag \"Flagged\")))", query);
482 g_free (query);
483 query = temp;
484 break;
485
486 case MAIL_FILTER_MESSAGES_NOT_JUNK:
487 temp = g_strdup_printf (
488 "(and %s (match-all (not "
489 "(system-flag \"junk\"))))", query);
490 g_free (query);
491 query = temp;
492 break;
493
494 default:
495 /* The action value also serves as a path for
496 * the label list store. That's why we number
497 * the label actions from zero. */
498 path = gtk_tree_path_new_from_indices (value, -1);
499 gtk_tree_model_get_iter (
500 GTK_TREE_MODEL (label_store),
501 &tree_iter, path);
502 gtk_tree_path_free (path);
503
504 tag = e_mail_label_list_store_get_tag (
505 label_store, &tree_iter);
506 use_tag = tag;
507 if (g_str_has_prefix (use_tag, "$Label"))
508 use_tag += 6;
509 temp = g_strdup_printf (
510 "(and %s (match-all (or "
511 "(= (user-tag \"label\") \"%s\") "
512 "(user-flag \"$Label%s\") "
513 "(user-flag \"%s\"))))",
514 query, use_tag, use_tag, use_tag);
515 g_free (tag);
516
517 g_free (query);
518 query = temp;
519 break;
520 }
521
522 /* Apply selected scope. */
523
524 combo_box = e_shell_searchbar_get_scope_combo_box (searchbar);
525 value = e_action_combo_box_get_current_value (combo_box);
526 switch (value) {
527 case MAIL_SCOPE_CURRENT_FOLDER:
528 goto execute;
529
530 case MAIL_SCOPE_CURRENT_ACCOUNT:
531 goto current_account;
532
533 case MAIL_SCOPE_ALL_ACCOUNTS:
534 goto all_accounts;
535
536 default:
537 g_warn_if_reached ();
538 goto execute;
539 }
540
541 all_accounts:
542
543 /* Prepare search folder for all accounts. */
544
545 /* If the search text is empty, cancel any
546 * account-wide searches still in progress. */
547 text = e_shell_searchbar_get_search_text (searchbar);
548 if (text == NULL || *text == '\0') {
549 CamelStore *selected_store = NULL;
550 gchar *selected_folder_name = NULL;
551
552 if (priv->search_account_all != NULL) {
553 g_object_unref (priv->search_account_all);
554 priv->search_account_all = NULL;
555 }
556
557 if (priv->search_account_cancel != NULL) {
558 g_cancellable_cancel (priv->search_account_cancel);
559 g_object_unref (priv->search_account_cancel);
560 priv->search_account_cancel = NULL;
561 }
562
563 /* Reset the message list to the current folder tree
564 * selection. This needs to happen synchronously to
565 * avoid search conflicts, so we can't just grab the
566 * folder URI and let the asynchronous callbacks run
567 * after we've already kicked off the search. */
568 if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_folder_name) &&
569 selected_store && selected_folder_name) {
570 folder = camel_store_get_folder_sync (
571 selected_store, selected_folder_name,
572 CAMEL_STORE_FOLDER_INFO_FAST, NULL, NULL);
573 e_mail_reader_set_folder (reader, folder);
574 g_object_unref (folder);
575 }
576
577 if (selected_store)
578 g_object_unref (selected_store);
579 g_free (selected_folder_name);
580
581 gtk_widget_set_sensitive (GTK_WIDGET (combo_box), TRUE);
582
583 goto execute;
584 }
585
586 search_folder = priv->search_account_all;
587
588 /* Skip the search if we already have the results. */
589 if (search_folder != NULL)
590 if (g_strcmp0 (query, camel_vee_folder_get_expression (search_folder)) == 0)
591 goto all_accounts_setup;
592
593 /* Disable the scope combo while search is in progress. */
594 gtk_widget_set_sensitive (GTK_WIDGET (combo_box), FALSE);
595
596 /* If we already have a search folder, reuse it. */
597 if (search_folder != NULL) {
598 if (priv->search_account_cancel != NULL) {
599 g_cancellable_cancel (priv->search_account_cancel);
600 g_object_unref (priv->search_account_cancel);
601 priv->search_account_cancel = NULL;
602 }
603
604 camel_vee_folder_set_expression (search_folder, query);
605
606 goto all_accounts_setup;
607 }
608
609 /* Create a new search folder. */
610
611 /* FIXME Complete lack of error checking here. */
612 service = camel_session_ref_service (
613 CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID);
614 camel_service_connect_sync (service, NULL, NULL);
615
616 search_folder = (CamelVeeFolder *) camel_vee_folder_new (
617 CAMEL_STORE (service), _("All Account Search"), CAMEL_STORE_FOLDER_PRIVATE);
618 priv->search_account_all = search_folder;
619
620 g_object_unref (service);
621
622 camel_vee_folder_set_expression (search_folder, query);
623
624 all_accounts_setup:
625 list = em_folder_tree_model_list_stores (EM_FOLDER_TREE_MODEL (
626 gtk_tree_view_get_model (GTK_TREE_VIEW (folder_tree))));
627 g_list_foreach (list, (GFunc) g_object_ref, NULL);
628
629 priv->search_account_cancel = camel_operation_new ();
630
631 /* This takes ownership of the stores list. */
632 mail_shell_view_setup_search_results_folder (
633 CAMEL_FOLDER (search_folder), list,
634 priv->search_account_cancel);
635
636 mail_shell_view_show_search_results_folder (
637 E_MAIL_SHELL_VIEW (shell_view),
638 CAMEL_FOLDER (search_folder));
639
640 goto execute;
641
642 current_account:
643
644 /* Prepare search folder for current account only. */
645
646 /* If the search text is empty, cancel any
647 * account-wide searches still in progress. */
648 text = e_shell_searchbar_get_search_text (searchbar);
649 if (text == NULL || *text == '\0') {
650 CamelStore *selected_store = NULL;
651 gchar *selected_folder_name = NULL;
652
653 if (priv->search_account_current != NULL) {
654 g_object_unref (priv->search_account_current);
655 priv->search_account_current = NULL;
656 }
657
658 if (priv->search_account_cancel != NULL) {
659 g_cancellable_cancel (priv->search_account_cancel);
660 g_object_unref (priv->search_account_cancel);
661 priv->search_account_cancel = NULL;
662 }
663
664 /* Reset the message list to the current folder tree
665 * selection. This needs to happen synchronously to
666 * avoid search conflicts, so we can't just grab the
667 * folder URI and let the asynchronous callbacks run
668 * after we've already kicked off the search. */
669 if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_folder_name) &&
670 selected_store && selected_folder_name) {
671 folder = camel_store_get_folder_sync (
672 selected_store, selected_folder_name,
673 CAMEL_STORE_FOLDER_INFO_FAST, NULL, NULL);
674 e_mail_reader_set_folder (reader, folder);
675 g_object_unref (folder);
676 }
677
678 if (selected_store)
679 g_object_unref (selected_store);
680 g_free (selected_folder_name);
681
682 gtk_widget_set_sensitive (GTK_WIDGET (combo_box), TRUE);
683
684 goto execute;
685 }
686
687 search_folder = priv->search_account_current;
688
689 /* Skip the search if we already have the results. */
690 if (search_folder != NULL)
691 if (g_strcmp0 (query, camel_vee_folder_get_expression (search_folder)) == 0)
692 goto current_accout_setup;
693
694 /* Disable the scope combo while search is in progress. */
695 gtk_widget_set_sensitive (GTK_WIDGET (combo_box), FALSE);
696
697 /* If we already have a search folder, reuse it. */
698 if (search_folder != NULL) {
699 if (priv->search_account_cancel != NULL) {
700 g_cancellable_cancel (priv->search_account_cancel);
701 g_object_unref (priv->search_account_cancel);
702 priv->search_account_cancel = NULL;
703 }
704
705 camel_vee_folder_set_expression (search_folder, query);
706
707 goto current_accout_setup;
708 }
709
710 /* Create a new search folder. */
711
712 /* FIXME Complete lack of error checking here. */
713 service = camel_session_ref_service (
714 CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID);
715 camel_service_connect_sync (service, NULL, NULL);
716
717 search_folder = (CamelVeeFolder *) camel_vee_folder_new (
718 CAMEL_STORE (service), _("Account Search"), CAMEL_STORE_FOLDER_PRIVATE);
719 priv->search_account_current = search_folder;
720
721 g_object_unref (service);
722
723 camel_vee_folder_set_expression (search_folder, query);
724
725 current_accout_setup:
726
727 if (folder != NULL && folder != CAMEL_FOLDER (search_folder)) {
728 store = camel_folder_get_parent_store (folder);
729 if (store != NULL)
730 g_object_ref (store);
731 } else {
732 store = NULL;
733 em_folder_tree_get_selected (folder_tree, &store, NULL);
734 }
735
736 list = NULL; /* list of CamelStore-s */
737
738 if (store != NULL)
739 list = g_list_append (NULL, store);
740
741 priv->search_account_cancel = camel_operation_new ();
742
743 /* This takes ownership of the stores list. */
744 mail_shell_view_setup_search_results_folder (
745 CAMEL_FOLDER (search_folder), list,
746 priv->search_account_cancel);
747
748 mail_shell_view_show_search_results_folder (
749 E_MAIL_SHELL_VIEW (shell_view),
750 CAMEL_FOLDER (search_folder));
751
752 execute:
753
754 /* Finally, execute the search. */
755
756 message_list_set_search (MESSAGE_LIST (message_list), query);
757
758 e_mail_view_set_search_strings (mail_view, search_strings);
759
760 g_slist_foreach (search_strings, (GFunc) g_free, NULL);
761 g_slist_free (search_strings);
762
763 g_free (query);
764 }
765
766 static void
767 has_unread_mail (GtkTreeModel *model,
768 GtkTreeIter *parent,
769 gboolean is_root,
770 gboolean *has_unread)
771 {
772 guint unread = 0;
773 GtkTreeIter iter, child;
774
775 g_return_if_fail (model != NULL);
776 g_return_if_fail (parent != NULL);
777 g_return_if_fail (has_unread != NULL);
778
779 if (is_root) {
780 gboolean is_store = FALSE, is_draft = FALSE;
781
782 gtk_tree_model_get (
783 model, parent,
784 COL_UINT_UNREAD, &unread,
785 COL_BOOL_IS_STORE, &is_store,
786 COL_BOOL_IS_DRAFT, &is_draft,
787 -1);
788
789 if (is_draft || is_store) {
790 *has_unread = FALSE;
791 return;
792 }
793
794 *has_unread = *has_unread || (unread > 0 && unread != ~((guint)0));
795
796 if (*has_unread)
797 return;
798
799 if (!gtk_tree_model_iter_children (model, &iter, parent))
800 return;
801 } else {
802 iter = *parent;
803 }
804
805 do {
806 gtk_tree_model_get (model, &iter, COL_UINT_UNREAD, &unread, -1);
807
808 *has_unread = *has_unread || (unread > 0 && unread != ~((guint)0));
809 if (*has_unread)
810 break;
811
812 if (gtk_tree_model_iter_children (model, &child, &iter))
813 has_unread_mail (model, &child, FALSE, has_unread);
814
815 } while (gtk_tree_model_iter_next (model, &iter) && !*has_unread);
816 }
817
818 static void
819 mail_shell_view_update_actions (EShellView *shell_view)
820 {
821 EMailShellView *mail_shell_view;
822 EMailShellContent *mail_shell_content;
823 EMailShellSidebar *mail_shell_sidebar;
824 EShellSidebar *shell_sidebar;
825 EShellWindow *shell_window;
826 EMFolderTree *folder_tree;
827 EMFolderTreeModel *model;
828 EMailReader *reader;
829 EMailView *mail_view;
830 GtkAction *action;
831 GList *list, *link;
832 gchar *uri;
833 gboolean sensitive;
834 guint32 state;
835
836 /* Be descriptive. */
837 gboolean folder_allows_children;
838 gboolean folder_can_be_deleted;
839 gboolean folder_is_outbox;
840 gboolean folder_is_store;
841 gboolean folder_is_trash;
842 gboolean folder_is_virtual;
843 gboolean folder_has_unread_rec = FALSE;
844 gboolean folder_tree_and_message_list_agree = TRUE;
845 gboolean store_is_builtin;
846 gboolean store_is_subscribable;
847 gboolean store_can_be_disabled;
848 gboolean any_store_is_subscribable = FALSE;
849
850 /* Chain up to parent's update_actions() method. */
851 E_SHELL_VIEW_CLASS (parent_class)->update_actions (shell_view);
852
853 shell_window = e_shell_view_get_shell_window (shell_view);
854
855 mail_shell_view = E_MAIL_SHELL_VIEW (shell_view);
856 mail_shell_content = mail_shell_view->priv->mail_shell_content;
857 mail_view = e_mail_shell_content_get_mail_view (mail_shell_content);
858
859 reader = E_MAIL_READER (mail_view);
860 state = e_mail_reader_check_state (reader);
861 e_mail_reader_update_actions (reader, state);
862
863 mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
864 folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
865
866 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
867 state = e_shell_sidebar_check_state (shell_sidebar);
868
869 model = em_folder_tree_model_get_default ();
870
871 folder_allows_children =
872 (state & E_MAIL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
873 folder_can_be_deleted =
874 (state & E_MAIL_SIDEBAR_FOLDER_CAN_DELETE);
875 folder_is_outbox =
876 (state & E_MAIL_SIDEBAR_FOLDER_IS_OUTBOX);
877 folder_is_store =
878 (state & E_MAIL_SIDEBAR_FOLDER_IS_STORE);
879 folder_is_trash =
880 (state & E_MAIL_SIDEBAR_FOLDER_IS_TRASH);
881 folder_is_virtual =
882 (state & E_MAIL_SIDEBAR_FOLDER_IS_VIRTUAL);
883 store_is_builtin =
884 (state & E_MAIL_SIDEBAR_STORE_IS_BUILTIN);
885 store_is_subscribable =
886 (state & E_MAIL_SIDEBAR_STORE_IS_SUBSCRIBABLE);
887 store_can_be_disabled =
888 (state & E_MAIL_SIDEBAR_STORE_CAN_BE_DISABLED);
889
890 uri = em_folder_tree_get_selected_uri (folder_tree);
891
892 if (uri != NULL) {
893 GtkTreeRowReference *reference;
894 CamelFolder *folder;
895
896 folder = e_mail_reader_get_folder (reader);
897
898 /* XXX If the user right-clicks on a folder other than what
899 * the message list is showing, disable folder rename.
900 * Between fetching the CamelFolder asynchronously and
901 * knowing when NOT to move the folder tree selection
902 * back to where it was to avoid cancelling the inline
903 * folder tree editing, it's just too hairy to try to
904 * get right. So we're punting. */
905 if (CAMEL_IS_FOLDER (folder)) {
906 gchar *folder_uri;
907
908 folder_uri = e_mail_folder_uri_from_folder (folder);
909 folder_tree_and_message_list_agree =
910 (g_strcmp0 (uri, folder_uri) == 0);
911 g_free (folder_uri);
912 }
913
914 reference = em_folder_tree_model_lookup_uri (model, uri);
915 if (reference != NULL) {
916 GtkTreePath *path;
917 GtkTreeIter iter;
918
919 path = gtk_tree_row_reference_get_path (reference);
920 gtk_tree_model_get_iter (
921 GTK_TREE_MODEL (model), &iter, path);
922 has_unread_mail (
923 GTK_TREE_MODEL (model), &iter,
924 TRUE, &folder_has_unread_rec);
925 gtk_tree_path_free (path);
926 }
927
928 g_free (uri);
929 }
930
931 /* Look for a CamelStore that supports subscriptions. */
932 list = em_folder_tree_model_list_stores (model);
933 for (link = list; link != NULL; link = g_list_next (link)) {
934 CamelStore *store = CAMEL_STORE (link->data);
935
936 if (CAMEL_IS_SUBSCRIBABLE (store)) {
937 any_store_is_subscribable = TRUE;
938 break;
939 }
940 }
941 g_list_free (list);
942
943 action = ACTION (MAIL_ACCOUNT_DISABLE);
944 sensitive = folder_is_store && store_can_be_disabled;
945 gtk_action_set_sensitive (action, sensitive);
946
947 action = ACTION (MAIL_ACCOUNT_EXPUNGE);
948 sensitive = folder_is_trash;
949 gtk_action_set_sensitive (action, sensitive);
950
951 action = ACTION (MAIL_ACCOUNT_PROPERTIES);
952 sensitive = folder_is_store && !store_is_builtin;
953 gtk_action_set_sensitive (action, sensitive);
954
955 action = ACTION (MAIL_FLUSH_OUTBOX);
956 sensitive = folder_is_outbox;
957 gtk_action_set_sensitive (action, sensitive);
958
959 action = ACTION (MAIL_FOLDER_COPY);
960 sensitive = !folder_is_store;
961 gtk_action_set_sensitive (action, sensitive);
962
963 action = ACTION (MAIL_FOLDER_DELETE);
964 sensitive = !folder_is_store && folder_can_be_deleted;
965 gtk_action_set_sensitive (action, sensitive);
966
967 action = ACTION (MAIL_FOLDER_EXPUNGE);
968 sensitive = !folder_is_store && !folder_is_virtual && uri != NULL;
969 gtk_action_set_sensitive (action, sensitive);
970
971 action = ACTION (MAIL_FOLDER_MOVE);
972 sensitive = !folder_is_store && folder_can_be_deleted;
973 gtk_action_set_sensitive (action, sensitive);
974
975 action = ACTION (MAIL_FOLDER_NEW);
976 sensitive = folder_allows_children;
977 gtk_action_set_sensitive (action, sensitive);
978
979 action = ACTION (MAIL_FOLDER_PROPERTIES);
980 sensitive = !folder_is_store && uri != NULL;
981 gtk_action_set_sensitive (action, sensitive);
982
983 action = ACTION (MAIL_FOLDER_REFRESH);
984 sensitive = !folder_is_store;
985 gtk_action_set_sensitive (action, sensitive);
986
987 action = ACTION (MAIL_FOLDER_RENAME);
988 sensitive =
989 !folder_is_store && folder_can_be_deleted &&
990 folder_tree_and_message_list_agree;
991 gtk_action_set_sensitive (action, sensitive);
992
993 action = ACTION (MAIL_FOLDER_SELECT_THREAD);
994 sensitive = !folder_is_store;
995 gtk_action_set_sensitive (action, sensitive);
996
997 action = ACTION (MAIL_FOLDER_SELECT_SUBTHREAD);
998 sensitive = !folder_is_store;
999 gtk_action_set_sensitive (action, sensitive);
1000
1001 action = ACTION (MAIL_FOLDER_UNSUBSCRIBE);
1002 sensitive =
1003 store_is_subscribable &&
1004 !folder_is_store && !folder_is_virtual;
1005 gtk_action_set_sensitive (action, sensitive);
1006
1007 action = ACTION (MAIL_FOLDER_MARK_ALL_AS_READ);
1008 sensitive = folder_has_unread_rec && !folder_is_store;
1009 gtk_action_set_sensitive (action, sensitive);
1010
1011 action = ACTION (MAIL_MANAGE_SUBSCRIPTIONS);
1012 sensitive = folder_is_store && store_is_subscribable;
1013 gtk_action_set_sensitive (action, sensitive);
1014
1015 action = ACTION (MAIL_TOOLS_SUBSCRIPTIONS);
1016 sensitive = any_store_is_subscribable;
1017 gtk_action_set_sensitive (action, sensitive);
1018
1019 /* folder_is_store + folder_is_virtual == "Search Folders" */
1020 action = ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE);
1021 gtk_action_set_visible (action, folder_is_store && folder_is_virtual);
1022
1023 e_mail_shell_view_update_popup_labels (mail_shell_view);
1024 }
1025
1026 static void
1027 mail_shell_view_class_init (EMailShellViewClass *class,
1028 GTypeModule *type_module)
1029 {
1030 GObjectClass *object_class;
1031 EShellViewClass *shell_view_class;
1032
1033 parent_class = g_type_class_peek_parent (class);
1034 g_type_class_add_private (class, sizeof (EMailShellViewPrivate));
1035
1036 object_class = G_OBJECT_CLASS (class);
1037 object_class->dispose = mail_shell_view_dispose;
1038 object_class->finalize = mail_shell_view_finalize;
1039 object_class->constructed = mail_shell_view_constructed;
1040
1041 shell_view_class = E_SHELL_VIEW_CLASS (class);
1042 shell_view_class->label = _("Mail");
1043 shell_view_class->icon_name = "evolution-mail";
1044 shell_view_class->ui_definition = "evolution-mail.ui";
1045 shell_view_class->ui_manager_id = "org.gnome.evolution.mail";
1046 shell_view_class->search_context_type = EM_SEARCH_TYPE_CONTEXT;
1047 shell_view_class->search_options = "/mail-search-options";
1048 shell_view_class->search_rules = "searchtypes.xml";
1049 shell_view_class->new_shell_content = e_mail_shell_content_new;
1050 shell_view_class->new_shell_sidebar = e_mail_shell_sidebar_new;
1051 shell_view_class->toggled = mail_shell_view_toggled;
1052 shell_view_class->execute_search = mail_shell_view_execute_search;
1053 shell_view_class->update_actions = mail_shell_view_update_actions;
1054 }
1055
1056 static void
1057 mail_shell_view_init (EMailShellView *mail_shell_view,
1058 EShellViewClass *shell_view_class)
1059 {
1060 mail_shell_view->priv =
1061 E_MAIL_SHELL_VIEW_GET_PRIVATE (mail_shell_view);
1062
1063 e_mail_shell_view_private_init (mail_shell_view, shell_view_class);
1064 }
1065
1066 GType
1067 e_mail_shell_view_get_type (void)
1068 {
1069 return mail_shell_view_type;
1070 }
1071
1072 void
1073 e_mail_shell_view_register_type (GTypeModule *type_module)
1074 {
1075 const GTypeInfo type_info = {
1076 sizeof (EMailShellViewClass),
1077 (GBaseInitFunc) NULL,
1078 (GBaseFinalizeFunc) NULL,
1079 (GClassInitFunc) mail_shell_view_class_init,
1080 (GClassFinalizeFunc) NULL,
1081 NULL, /* class_data */
1082 sizeof (EMailShellView),
1083 0, /* n_preallocs */
1084 (GInstanceInitFunc) mail_shell_view_init,
1085 NULL /* value_table */
1086 };
1087
1088 mail_shell_view_type = g_type_module_register_type (
1089 type_module, E_TYPE_SHELL_VIEW,
1090 "EMailShellView", &type_info, 0);
1091 }