1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include <tny-error.h>
37 #include "modest-marshal.h"
38 #include "modest-platform.h"
39 #include <modest-utils.h>
40 #include <modest-toolkit-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-progress-object.h>
46 #include <modest-runtime.h>
47 #include <modest-window-priv.h>
48 #include <modest-tny-folder.h>
49 #include <modest-text-utils.h>
50 #include <modest-account-mgr-helpers.h>
51 #include <modest-toolkit-factory.h>
52 #include <modest-scrollable.h>
53 #include <modest-isearch-toolbar.h>
54 #include "modest-defs.h"
55 #include "modest-ui-dimming-manager.h"
56 #include <gdk/gdkkeysyms.h>
57 #include <modest-tny-account.h>
58 #include <modest-mime-part-view.h>
59 #include <modest-isearch-view.h>
60 #include <modest-tny-mime-part.h>
61 #include <modest-address-book.h>
64 #include <glib/gstdio.h>
65 #include <modest-debug.h>
66 #include <modest-header-window.h>
67 #include <modest-account-protocol.h>
68 #include <modest-icon-names.h>
69 #include <modest-ui-actions.h>
70 #include <modest-window-mgr.h>
71 #include <tny-camel-msg.h>
72 #include <modest-icon-names.h>
74 #ifdef MODEST_PLATFORM_MAEMO
75 #include <modest-maemo-utils.h>
78 #ifdef MODEST_TOOLKIT_HILDON2
79 #include <hildon/hildon.h>
81 #include <tny-camel-bs-mime-part.h>
82 #include <tny-camel-bs-msg.h>
84 #define MYDOCS_ENV "MYDOCSDIR"
85 #define DOCS_FOLDER ".documents"
87 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
88 struct _ModestMsgViewWindowPrivate {
91 GtkWidget *main_scroll;
92 GtkWidget *isearch_toolbar;
95 /* Progress observers */
96 GSList *progress_widgets;
99 GtkWidget *prev_toolitem;
100 GtkWidget *next_toolitem;
101 gboolean progress_hint;
102 gint fetching_images;
104 /* Optimized view enabled */
105 gboolean optimized_view;
107 /* Whether this was created via the *_new_for_search_result() function. */
108 gboolean is_search_result;
110 /* Whether the message is in outbox */
113 /* A reference to the @model of the header view
114 * to allow selecting previous/next messages,
115 * if the message is currently selected in the header view.
117 const gchar *header_folder_id;
118 GtkTreeModel *header_model;
119 GtkTreeRowReference *row_reference;
120 GtkTreeRowReference *next_row_reference;
122 gulong clipboard_change_handler;
123 gulong queue_change_handler;
124 gulong account_removed_handler;
125 gulong row_changed_handler;
126 gulong row_deleted_handler;
127 gulong row_inserted_handler;
128 gulong rows_reordered_handler;
129 gulong fetch_image_redraw_handler;
132 GtkWidget *remove_attachment_banner;
135 TnyMimePart *other_body;
141 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
142 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
143 static void modest_header_view_observer_init (ModestHeaderViewObserverIface *iface_class);
144 static void modest_msg_view_window_finalize (GObject *obj);
145 static void modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj, gpointer data);
146 static void modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
147 ModestMsgViewWindow *obj);
148 static void modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
149 ModestMsgViewWindow *obj);
150 static void modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
152 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
154 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
155 static void modest_msg_view_window_set_zoom (ModestWindow *window,
157 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
158 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
159 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
162 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
164 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
165 gboolean show_toolbar);
167 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
169 ModestMsgViewWindow *window);
171 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
174 ModestMsgViewWindow *window);
176 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
178 ModestMsgViewWindow *window);
180 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
181 GtkTreePath *tree_path,
182 GtkTreeIter *tree_iter,
183 ModestMsgViewWindow *window);
185 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
189 ModestMsgViewWindow *window);
191 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
193 const gchar *tny_folder_id);
195 static void on_queue_changed (ModestMailOperationQueue *queue,
196 ModestMailOperation *mail_op,
197 ModestMailOperationQueueNotification type,
198 ModestMsgViewWindow *self);
200 static void on_account_removed (TnyAccountStore *account_store,
204 static void on_move_focus (GtkWidget *widget,
205 GtkDirectionType direction,
208 static void view_msg_cb (ModestMailOperation *mail_op,
215 static void set_progress_hint (ModestMsgViewWindow *self,
218 static void update_window_title (ModestMsgViewWindow *window);
220 static void init_window (ModestMsgViewWindow *obj);
222 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
224 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
226 static gboolean on_fetch_image (ModestMsgView *msgview,
229 ModestMsgViewWindow *window);
231 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
232 GtkScrollType scroll_type,
235 static gboolean message_reader (ModestMsgViewWindow *window,
236 ModestMsgViewWindowPrivate *priv,
238 const gchar *msg_uid,
240 GtkTreeRowReference *row_reference);
242 static void setup_menu (ModestMsgViewWindow *self);
243 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
246 static void update_branding (ModestMsgViewWindow *self);
247 static void sync_flags (ModestMsgViewWindow *self);
249 /* list my signals */
256 static const GtkActionEntry msg_view_toolbar_action_entries [] = {
259 { "ToolbarMessageReply", MODEST_STOCK_REPLY, N_("mcen_me_inbox_reply"), "<CTRL>R", NULL, G_CALLBACK (modest_ui_actions_on_reply) },
260 { "ToolbarMessageReplyAll", MODEST_STOCK_REPLY_ALL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
261 { "ToolbarMessageForward", MODEST_STOCK_FORWARD, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
262 { "ToolbarDeleteMessage", MODEST_STOCK_DELETE, N_("qgn_toolb_gene_deletebutton"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message_or_folder) },
263 { "ToolbarMessageBack", MODEST_TOOLBAR_ICON_PREV, N_("qgn_toolb_gene_back"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_prev) },
264 { "ToolbarMessageNext", MODEST_TOOLBAR_ICON_NEXT, N_("qgn_toolb_gene_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_next) },
265 { "ToolbarDownloadExternalImages", MODEST_TOOLBAR_ICON_DOWNLOAD_IMAGES, N_("mail_bd_external_images"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_fetch_images) },
268 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
269 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_isearch_toolbar), FALSE },
272 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
273 MODEST_TYPE_MSG_VIEW_WINDOW, \
274 ModestMsgViewWindowPrivate))
276 static GtkWindowClass *parent_class = NULL;
278 /* uncomment the following if you have defined any signals */
279 static guint signals[LAST_SIGNAL] = {0};
282 modest_msg_view_window_get_type (void)
284 static GType my_type = 0;
286 static const GTypeInfo my_info = {
287 sizeof(ModestMsgViewWindowClass),
288 NULL, /* base init */
289 NULL, /* base finalize */
290 (GClassInitFunc) modest_msg_view_window_class_init,
291 NULL, /* class finalize */
292 NULL, /* class data */
293 sizeof(ModestMsgViewWindow),
295 (GInstanceInitFunc) modest_msg_view_window_init,
298 #ifndef MODEST_TOOLKIT_HILDON2
299 my_type = g_type_register_static (MODEST_TYPE_SHELL_WINDOW,
300 "ModestMsgViewWindow",
303 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
304 "ModestMsgViewWindow",
308 static const GInterfaceInfo modest_header_view_observer_info =
310 (GInterfaceInitFunc) modest_header_view_observer_init,
311 NULL, /* interface_finalize */
312 NULL /* interface_data */
315 g_type_add_interface_static (my_type,
316 MODEST_TYPE_HEADER_VIEW_OBSERVER,
317 &modest_header_view_observer_info);
323 save_state (ModestWindow *self)
325 modest_widget_memory_save (modest_runtime_get_conf (),
327 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
331 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
332 GtkScrollType scroll_type,
336 ModestMsgViewWindowPrivate *priv;
339 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
341 switch (scroll_type) {
342 case GTK_SCROLL_STEP_UP:
345 case GTK_SCROLL_STEP_DOWN:
348 case GTK_SCROLL_PAGE_UP:
351 case GTK_SCROLL_PAGE_DOWN:
354 case GTK_SCROLL_START:
365 modest_scrollable_scroll ((ModestScrollable *) priv->main_scroll, 0, step);
367 return (gboolean) step;
371 add_scroll_binding (GtkBindingSet *binding_set,
373 GtkScrollType scroll)
375 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
377 gtk_binding_entry_add_signal (binding_set, keyval, 0,
379 GTK_TYPE_SCROLL_TYPE, scroll,
380 G_TYPE_BOOLEAN, FALSE);
381 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
383 GTK_TYPE_SCROLL_TYPE, scroll,
384 G_TYPE_BOOLEAN, FALSE);
388 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
390 GObjectClass *gobject_class;
391 ModestWindowClass *modest_window_class;
392 GtkBindingSet *binding_set;
394 gobject_class = (GObjectClass*) klass;
395 modest_window_class = (ModestWindowClass *) klass;
397 parent_class = g_type_class_peek_parent (klass);
398 gobject_class->finalize = modest_msg_view_window_finalize;
400 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
401 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
402 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
403 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
404 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
405 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
407 modest_window_class->save_state_func = save_state;
409 klass->scroll_child = modest_msg_view_window_scroll_child;
411 signals[MSG_CHANGED_SIGNAL] =
412 g_signal_new ("msg-changed",
413 G_TYPE_FROM_CLASS (gobject_class),
415 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
417 modest_marshal_VOID__POINTER_POINTER,
418 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
420 signals[SCROLL_CHILD_SIGNAL] =
421 g_signal_new ("scroll-child",
422 G_TYPE_FROM_CLASS (gobject_class),
423 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
424 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
426 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
427 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
429 binding_set = gtk_binding_set_by_class (klass);
430 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
431 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
432 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
433 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
434 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
435 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
437 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
441 static void modest_header_view_observer_init(
442 ModestHeaderViewObserverIface *iface_class)
444 iface_class->update_func = modest_msg_view_window_update_model_replaced;
448 modest_msg_view_window_init (ModestMsgViewWindow *obj)
450 ModestMsgViewWindowPrivate *priv;
451 ModestWindowPrivate *parent_priv = NULL;
452 GtkActionGroup *action_group = NULL;
453 GError *error = NULL;
455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
456 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
457 parent_priv->ui_manager = gtk_ui_manager_new();
459 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
460 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
462 /* Add common actions */
463 gtk_action_group_add_actions (action_group,
464 msg_view_toolbar_action_entries,
465 G_N_ELEMENTS (msg_view_toolbar_action_entries),
467 gtk_action_group_add_toggle_actions (action_group,
468 msg_view_toggle_action_entries,
469 G_N_ELEMENTS (msg_view_toggle_action_entries),
472 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
473 g_object_unref (action_group);
475 /* Load the UI definition */
476 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
479 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
480 g_error_free (error);
484 priv->is_search_result = FALSE;
485 priv->is_outbox = FALSE;
487 priv->msg_view = NULL;
488 priv->header_model = NULL;
489 priv->header_folder_id = NULL;
490 priv->clipboard_change_handler = 0;
491 priv->queue_change_handler = 0;
492 priv->account_removed_handler = 0;
493 priv->row_changed_handler = 0;
494 priv->row_deleted_handler = 0;
495 priv->row_inserted_handler = 0;
496 priv->rows_reordered_handler = 0;
497 priv->fetch_image_redraw_handler = 0;
498 priv->progress_hint = FALSE;
499 priv->fetching_images = 0;
501 priv->optimized_view = FALSE;
502 priv->purge_timeout = 0;
503 priv->remove_attachment_banner = NULL;
504 priv->msg_uid = NULL;
505 priv->other_body = NULL;
507 priv->sighandlers = NULL;
510 init_window (MODEST_MSG_VIEW_WINDOW(obj));
515 update_progress_hint (ModestMsgViewWindow *self)
517 ModestMsgViewWindowPrivate *priv;
518 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
520 if (GTK_WIDGET_VISIBLE (self)) {
521 modest_window_show_progress (MODEST_WINDOW (self),
522 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
527 set_progress_hint (ModestMsgViewWindow *self,
530 ModestWindowPrivate *parent_priv;
531 ModestMsgViewWindowPrivate *priv;
533 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
535 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
536 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
538 /* Sets current progress hint */
539 priv->progress_hint = enabled;
541 update_progress_hint (self);
547 init_window (ModestMsgViewWindow *obj)
549 GtkWidget *main_vbox;
550 ModestMsgViewWindowPrivate *priv;
552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
554 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
555 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
556 main_vbox = gtk_vbox_new (FALSE, 6);
558 priv->main_scroll = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
559 modest_scrollable_set_horizontal_policy (MODEST_SCROLLABLE (priv->main_scroll), GTK_POLICY_AUTOMATIC);
560 g_object_set (G_OBJECT (priv->main_scroll),
561 "movement-mode", MODEST_MOVEMENT_MODE_BOTH,
562 "horizontal-max-overshoot", 0,
564 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
565 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
566 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
568 /* NULL-ize fields if the window is destroyed */
569 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
571 gtk_widget_show_all (GTK_WIDGET(main_vbox));
575 modest_msg_view_window_disconnect_signals (ModestWindow *self)
577 ModestMsgViewWindowPrivate *priv;
578 GtkWidget *header_view = NULL;
579 GtkWindow *parent_window = NULL;
581 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
583 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
584 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
585 priv->clipboard_change_handler))
586 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
587 priv->clipboard_change_handler);
589 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
590 priv->queue_change_handler))
591 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
592 priv->queue_change_handler);
594 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
595 priv->account_removed_handler))
596 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
597 priv->account_removed_handler);
599 if (priv->header_model) {
600 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
601 priv->row_changed_handler))
602 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
603 priv->row_changed_handler);
605 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
606 priv->row_deleted_handler))
607 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
608 priv->row_deleted_handler);
610 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
611 priv->row_inserted_handler))
612 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
613 priv->row_inserted_handler);
615 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
616 priv->rows_reordered_handler))
617 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
618 priv->rows_reordered_handler);
621 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
622 priv->sighandlers = NULL;
624 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
625 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
626 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
628 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
629 MODEST_HEADER_VIEW_OBSERVER(self));
635 modest_msg_view_window_finalize (GObject *obj)
637 ModestMsgViewWindowPrivate *priv;
639 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
641 /* Sanity check: shouldn't be needed, the window mgr should
642 call this function before */
643 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
645 if (priv->fetch_image_redraw_handler > 0) {
646 g_source_remove (priv->fetch_image_redraw_handler);
647 priv->fetch_image_redraw_handler = 0;
650 if (priv->other_body != NULL) {
651 g_object_unref (priv->other_body);
652 priv->other_body = NULL;
655 if (priv->top_msg != NULL) {
656 g_object_unref (priv->top_msg);
657 priv->top_msg = NULL;
660 if (priv->header_model != NULL) {
661 g_object_unref (priv->header_model);
662 priv->header_model = NULL;
665 if (priv->remove_attachment_banner) {
666 gtk_widget_destroy (priv->remove_attachment_banner);
667 g_object_unref (priv->remove_attachment_banner);
668 priv->remove_attachment_banner = NULL;
671 if (priv->purge_timeout > 0) {
672 g_source_remove (priv->purge_timeout);
673 priv->purge_timeout = 0;
676 if (priv->row_reference) {
677 gtk_tree_row_reference_free (priv->row_reference);
678 priv->row_reference = NULL;
681 if (priv->next_row_reference) {
682 gtk_tree_row_reference_free (priv->next_row_reference);
683 priv->next_row_reference = NULL;
687 g_free (priv->msg_uid);
688 priv->msg_uid = NULL;
691 G_OBJECT_CLASS(parent_class)->finalize (obj);
695 select_next_valid_row (GtkTreeModel *model,
696 GtkTreeRowReference **row_reference,
700 GtkTreeIter tmp_iter;
702 GtkTreePath *next = NULL;
703 gboolean retval = FALSE, finished;
705 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
707 path = gtk_tree_row_reference_get_path (*row_reference);
708 gtk_tree_model_get_iter (model, &tmp_iter, path);
709 gtk_tree_row_reference_free (*row_reference);
710 *row_reference = NULL;
714 TnyHeader *header = NULL;
716 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
717 gtk_tree_model_get (model, &tmp_iter,
718 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
722 if (msg_is_visible (header, is_outbox)) {
723 next = gtk_tree_model_get_path (model, &tmp_iter);
724 *row_reference = gtk_tree_row_reference_new (model, next);
725 gtk_tree_path_free (next);
729 g_object_unref (header);
732 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
733 next = gtk_tree_model_get_path (model, &tmp_iter);
735 /* Ensure that we are not selecting the same */
736 if (gtk_tree_path_compare (path, next) != 0) {
737 gtk_tree_model_get (model, &tmp_iter,
738 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
741 if (msg_is_visible (header, is_outbox)) {
742 *row_reference = gtk_tree_row_reference_new (model, next);
746 g_object_unref (header);
750 /* If we ended up in the same message
751 then there is no valid next
755 gtk_tree_path_free (next);
757 /* If there are no more messages and we don't
758 want to start again in the first one then
759 there is no valid next message */
765 gtk_tree_path_free (path);
770 /* TODO: This should be in _init(), with the parameters as properties. */
772 modest_msg_view_window_construct (ModestMsgViewWindow *self,
773 const gchar *modest_account_name,
774 const gchar *mailbox,
775 const gchar *msg_uid)
778 ModestMsgViewWindowPrivate *priv = NULL;
779 ModestWindowPrivate *parent_priv = NULL;
780 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
781 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
783 obj = G_OBJECT (self);
784 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
785 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
787 priv->msg_uid = g_strdup (msg_uid);
790 parent_priv->menubar = NULL;
792 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
793 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
796 /* Add common dimming rules */
797 modest_dimming_rules_group_add_rules (toolbar_rules_group,
798 modest_msg_view_toolbar_dimming_entries,
799 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
800 MODEST_WINDOW (self));
801 modest_dimming_rules_group_add_rules (clipboard_rules_group,
802 modest_msg_view_clipboard_dimming_entries,
803 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
804 MODEST_WINDOW (self));
806 /* Insert dimming rules group for this window */
807 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
808 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
809 g_object_unref (toolbar_rules_group);
810 g_object_unref (clipboard_rules_group);
812 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
814 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
815 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
816 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
817 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
818 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
819 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
820 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
821 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
822 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
823 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
824 G_CALLBACK (modest_ui_actions_on_details), obj);
825 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
826 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
827 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
828 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
829 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
830 G_CALLBACK (on_fetch_image), obj);
832 g_signal_connect (G_OBJECT (obj), "key-release-event",
833 G_CALLBACK (modest_msg_view_window_key_event),
836 g_signal_connect (G_OBJECT (obj), "key-press-event",
837 G_CALLBACK (modest_msg_view_window_key_event),
840 g_signal_connect (G_OBJECT (obj), "move-focus",
841 G_CALLBACK (on_move_focus), obj);
843 g_signal_connect (G_OBJECT (obj), "map-event",
844 G_CALLBACK (_modest_msg_view_window_map_event),
847 /* Mail Operation Queue */
848 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
850 G_CALLBACK (on_queue_changed),
853 /* Account manager */
854 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
856 G_CALLBACK(on_account_removed),
859 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
860 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
862 /* First add out toolbar ... */
863 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
865 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
867 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
868 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
869 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
870 G_CALLBACK (modest_msg_view_window_isearch_toolbar_close), obj);
871 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
872 G_CALLBACK (modest_msg_view_window_isearch_toolbar_search), obj);
873 priv->last_search = NULL;
875 /* Init the clipboard actions dim status */
876 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
878 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
883 /* FIXME: parameter checks */
885 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
886 const gchar *modest_account_name,
887 const gchar *mailbox,
888 const gchar *msg_uid,
890 GtkTreeRowReference *row_reference)
892 ModestMsgViewWindow *window = NULL;
893 ModestMsgViewWindowPrivate *priv = NULL;
894 TnyFolder *header_folder = NULL;
895 ModestHeaderView *header_view = NULL;
896 ModestWindowMgr *mgr = NULL;
899 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
902 mgr = modest_runtime_get_window_mgr ();
903 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
904 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
906 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
908 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
909 priv->top_msg = NULL;
911 /* Remember the message list's TreeModel so we can detect changes
912 * and change the list selection when necessary: */
913 header_folder = modest_header_view_get_folder (header_view);
915 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
916 TNY_FOLDER_TYPE_OUTBOX);
917 priv->header_folder_id = tny_folder_get_id (header_folder);
918 g_object_unref(header_folder);
921 /* Setup row references and connect signals */
922 priv->header_model = g_object_ref (model);
924 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
925 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
926 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
927 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
929 priv->row_reference = NULL;
930 priv->next_row_reference = NULL;
933 /* Connect signals */
934 priv->row_changed_handler =
935 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
936 G_CALLBACK(modest_msg_view_window_on_row_changed),
938 priv->row_deleted_handler =
939 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
940 G_CALLBACK(modest_msg_view_window_on_row_deleted),
942 priv->row_inserted_handler =
943 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
944 G_CALLBACK(modest_msg_view_window_on_row_inserted),
946 priv->rows_reordered_handler =
947 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
948 G_CALLBACK(modest_msg_view_window_on_row_reordered),
951 if (header_view != NULL){
952 modest_header_view_add_observer(header_view,
953 MODEST_HEADER_VIEW_OBSERVER(window));
956 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
957 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
958 update_branding (MODEST_MSG_VIEW_WINDOW (window));
960 /* gtk_widget_show_all (GTK_WIDGET (window)); */
961 modest_msg_view_window_update_priority (window);
962 /* Check dimming rules */
963 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
964 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
965 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
967 return MODEST_WINDOW(window);
971 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
972 const gchar *mailbox,
973 const gchar *msg_uid)
975 ModestMsgViewWindow *window = NULL;
976 ModestMsgViewWindowPrivate *priv = NULL;
977 ModestWindowMgr *mgr = NULL;
979 TnyAccount *account = NULL;
981 mgr = modest_runtime_get_window_mgr ();
982 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
983 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
985 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
987 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
988 priv->top_msg = NULL;
990 is_merge = g_str_has_prefix (msg_uid, "merge:");
992 /* Get the account */
994 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
997 if (is_merge || account) {
998 TnyFolder *folder = NULL;
1000 /* Try to get the message, if it's already downloaded
1001 we don't need to connect */
1003 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1005 ModestTnyAccountStore *account_store;
1006 ModestTnyLocalFoldersAccount *local_folders_account;
1008 account_store = modest_runtime_get_account_store ();
1009 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1010 modest_tny_account_store_get_local_folders_account (account_store));
1011 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1012 g_object_unref (local_folders_account);
1016 gboolean device_online;
1018 device = modest_runtime_get_device();
1019 device_online = tny_device_is_online (device);
1020 if (device_online) {
1021 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1023 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1025 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1026 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1027 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1028 g_object_unref (msg);
1029 /* Sync flags to server */
1030 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1032 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1035 g_object_unref (folder);
1040 /* Check dimming rules */
1041 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1042 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1043 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1045 return MODEST_WINDOW(window);
1049 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1050 const gchar *modest_account_name,
1051 const gchar *mailbox,
1052 const gchar *msg_uid,
1053 GtkTreeRowReference *row_reference)
1055 ModestMsgViewWindow *window = NULL;
1056 ModestMsgViewWindowPrivate *priv = NULL;
1057 TnyFolder *header_folder = NULL;
1058 ModestWindowMgr *mgr = NULL;
1062 mgr = modest_runtime_get_window_mgr ();
1063 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1064 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1066 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1068 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1069 priv->top_msg = NULL;
1071 /* Remember the message list's TreeModel so we can detect changes
1072 * and change the list selection when necessary: */
1074 if (header_view != NULL){
1075 header_folder = modest_header_view_get_folder(header_view);
1076 /* This could happen if the header folder was
1077 unseleted before opening this msg window (for
1078 example if the user selects an account in the
1079 folder view of the main window */
1080 if (header_folder) {
1081 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1082 TNY_FOLDER_TYPE_OUTBOX);
1083 priv->header_folder_id = tny_folder_get_id(header_folder);
1084 g_object_unref(header_folder);
1088 /* Setup row references and connect signals */
1089 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1090 g_object_ref (priv->header_model);
1092 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1093 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1094 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1095 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1097 priv->row_reference = NULL;
1098 priv->next_row_reference = NULL;
1101 /* Connect signals */
1102 priv->row_changed_handler =
1103 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1104 G_CALLBACK(modest_msg_view_window_on_row_changed),
1106 priv->row_deleted_handler =
1107 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1108 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1110 priv->row_inserted_handler =
1111 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1112 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1114 priv->rows_reordered_handler =
1115 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1116 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1119 if (header_view != NULL){
1120 modest_header_view_add_observer(header_view,
1121 MODEST_HEADER_VIEW_OBSERVER(window));
1124 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1125 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1127 if (priv->row_reference) {
1128 path = gtk_tree_row_reference_get_path (priv->row_reference);
1129 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1131 gtk_tree_model_get (priv->header_model, &iter,
1132 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1134 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1135 g_object_unref (header);
1137 gtk_tree_path_free (path);
1139 /* Check dimming rules */
1140 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1141 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1142 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1144 return MODEST_WINDOW(window);
1148 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1149 const gchar *modest_account_name,
1150 const gchar *mailbox,
1151 const gchar *msg_uid)
1153 ModestMsgViewWindow *window = NULL;
1154 ModestMsgViewWindowPrivate *priv = NULL;
1155 ModestWindowMgr *mgr = NULL;
1157 mgr = modest_runtime_get_window_mgr ();
1158 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1159 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1160 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1162 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1163 priv->top_msg = NULL;
1165 /* Remember that this is a search result,
1166 * so we can disable some UI appropriately: */
1167 priv->is_search_result = TRUE;
1169 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1170 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1172 update_window_title (window);
1173 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1174 modest_msg_view_window_update_priority (window);
1176 /* Check dimming rules */
1177 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1178 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1179 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1181 return MODEST_WINDOW(window);
1185 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1187 ModestMsgViewWindowPrivate *priv = NULL;
1189 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1190 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1192 return (priv->other_body != NULL);
1196 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1197 TnyMimePart *other_body,
1199 const gchar *modest_account_name,
1200 const gchar *mailbox,
1201 const gchar *msg_uid)
1203 GObject *obj = NULL;
1204 ModestMsgViewWindowPrivate *priv;
1205 ModestWindowMgr *mgr = NULL;
1207 g_return_val_if_fail (msg, NULL);
1208 mgr = modest_runtime_get_window_mgr ();
1209 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1210 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1211 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1212 modest_account_name, mailbox, msg_uid);
1215 priv->other_body = g_object_ref (other_body);
1216 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1218 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1221 priv->top_msg = g_object_ref (top_msg);
1223 priv->top_msg = NULL;
1225 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1226 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1228 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1230 /* Check dimming rules */
1231 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1232 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1233 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1235 return MODEST_WINDOW(obj);
1239 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1241 const gchar *modest_account_name,
1242 const gchar *mailbox,
1243 const gchar *msg_uid)
1245 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1249 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1252 ModestMsgViewWindow *window)
1254 check_dimming_rules_after_change (window);
1258 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1260 ModestMsgViewWindow *window)
1262 check_dimming_rules_after_change (window);
1264 /* The window could have dissapeared */
1267 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1269 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1270 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1274 /* On insertions we check if the folder still has the message we are
1275 * showing or do not. If do not, we do nothing. Which means we are still
1276 * not attached to any header folder and thus next/prev buttons are
1277 * still dimmed. Once the message that is shown by msg-view is found, the
1278 * new model of header-view will be attached and the references will be set.
1279 * On each further insertions dimming rules will be checked. However
1280 * this requires extra CPU time at least works.
1281 * (An message might be deleted from TnyFolder and thus will not be
1282 * inserted into the model again for example if it is removed by the
1283 * imap server and the header view is refreshed.)
1286 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1287 GtkTreePath *tree_path,
1288 GtkTreeIter *tree_iter,
1289 ModestMsgViewWindow *window)
1291 ModestMsgViewWindowPrivate *priv = NULL;
1292 TnyHeader *header = NULL;
1294 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1295 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1297 g_assert (model == priv->header_model);
1299 /* Check if the newly inserted message is the same we are actually
1300 * showing. IF not, we should remain detached from the header model
1301 * and thus prev and next toolbar buttons should remain dimmed. */
1302 gtk_tree_model_get (model, tree_iter,
1303 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1306 if (TNY_IS_HEADER (header)) {
1309 uid = modest_tny_folder_get_header_unique_id (header);
1310 if (!g_str_equal(priv->msg_uid, uid)) {
1311 check_dimming_rules_after_change (window);
1313 g_object_unref (G_OBJECT(header));
1317 g_object_unref(G_OBJECT(header));
1320 if (priv->row_reference) {
1321 gtk_tree_row_reference_free (priv->row_reference);
1324 /* Setup row_reference for the actual msg. */
1325 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1326 if (priv->row_reference == NULL) {
1327 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1331 /* Now set up next_row_reference. */
1332 if (priv->next_row_reference) {
1333 gtk_tree_row_reference_free (priv->next_row_reference);
1336 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1337 select_next_valid_row (priv->header_model,
1338 &(priv->next_row_reference), FALSE, priv->is_outbox);
1340 /* Connect the remaining callbacks to become able to detect
1341 * changes in header-view. */
1342 priv->row_changed_handler =
1343 g_signal_connect (priv->header_model, "row-changed",
1344 G_CALLBACK (modest_msg_view_window_on_row_changed),
1346 priv->row_deleted_handler =
1347 g_signal_connect (priv->header_model, "row-deleted",
1348 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1350 priv->rows_reordered_handler =
1351 g_signal_connect (priv->header_model, "rows-reordered",
1352 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1355 check_dimming_rules_after_change (window);
1359 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1363 ModestMsgViewWindow *window)
1365 ModestMsgViewWindowPrivate *priv = NULL;
1366 gboolean already_changed = FALSE;
1368 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1370 /* If the current row was reordered select the proper next
1371 valid row. The same if the next row reference changes */
1372 if (!priv->row_reference ||
1373 !gtk_tree_row_reference_valid (priv->row_reference))
1376 if (priv->next_row_reference &&
1377 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1378 GtkTreePath *cur, *next;
1379 /* Check that the order is still the correct one */
1380 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1381 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1382 gtk_tree_path_next (cur);
1383 if (gtk_tree_path_compare (cur, next) != 0) {
1384 gtk_tree_row_reference_free (priv->next_row_reference);
1385 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1386 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1387 already_changed = TRUE;
1389 gtk_tree_path_free (cur);
1390 gtk_tree_path_free (next);
1392 if (priv->next_row_reference)
1393 gtk_tree_row_reference_free (priv->next_row_reference);
1394 /* Update next row reference */
1395 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1396 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1397 already_changed = TRUE;
1400 check_dimming_rules_after_change (window);
1403 /* The modest_msg_view_window_update_model_replaced implements update
1404 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1405 * actually belongs to the header-view is the same as the TnyFolder of
1406 * the message of msg-view or not. If they are different, there is
1407 * nothing to do. If they are the same, then the model has replaced and
1408 * the reference in msg-view shall be replaced from the old model to
1409 * the new model. In this case the view will be detached from it's
1410 * header folder. From this point the next/prev buttons are dimmed.
1413 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1414 GtkTreeModel *model,
1415 const gchar *tny_folder_id)
1417 ModestMsgViewWindowPrivate *priv = NULL;
1418 ModestMsgViewWindow *window = NULL;
1420 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1421 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1423 window = MODEST_MSG_VIEW_WINDOW(observer);
1424 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1426 /* If there is an other folder in the header-view then we do
1427 * not care about it's model (msg list). Else if the
1428 * header-view shows the folder the msg shown by us is in, we
1429 * shall replace our model reference and make some check. */
1430 if(model == NULL || tny_folder_id == NULL ||
1431 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1434 /* Model is changed(replaced), so we should forget the old
1435 * one. Because there might be other references and there
1436 * might be some change on the model even if we unreferenced
1437 * it, we need to disconnect our signals here. */
1438 if (priv->header_model) {
1439 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1440 priv->row_changed_handler))
1441 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1442 priv->row_changed_handler);
1443 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1444 priv->row_deleted_handler))
1445 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1446 priv->row_deleted_handler);
1447 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1448 priv->row_inserted_handler))
1449 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1450 priv->row_inserted_handler);
1451 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1452 priv->rows_reordered_handler))
1453 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1454 priv->rows_reordered_handler);
1457 if (priv->row_reference)
1458 gtk_tree_row_reference_free (priv->row_reference);
1459 if (priv->next_row_reference)
1460 gtk_tree_row_reference_free (priv->next_row_reference);
1461 g_object_unref(priv->header_model);
1464 priv->row_changed_handler = 0;
1465 priv->row_deleted_handler = 0;
1466 priv->row_inserted_handler = 0;
1467 priv->rows_reordered_handler = 0;
1468 priv->next_row_reference = NULL;
1469 priv->row_reference = NULL;
1470 priv->header_model = NULL;
1473 priv->header_model = g_object_ref (model);
1475 /* Also we must connect to the new model for row insertions.
1476 * Only for insertions now. We will need other ones only after
1477 * the msg is show by msg-view is added to the new model. */
1478 priv->row_inserted_handler =
1479 g_signal_connect (priv->header_model, "row-inserted",
1480 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1483 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1484 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1488 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1490 ModestMsgViewWindowPrivate *priv= NULL;
1492 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1493 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1495 return priv->progress_hint;
1499 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1501 ModestMsgViewWindowPrivate *priv= NULL;
1503 TnyHeader *header = NULL;
1504 GtkTreePath *path = NULL;
1507 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1508 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1510 /* If the message was not obtained from a treemodel,
1511 * for instance if it was opened directly by the search UI:
1513 if (priv->header_model == NULL ||
1514 priv->row_reference == NULL ||
1515 !gtk_tree_row_reference_valid (priv->row_reference)) {
1516 msg = modest_msg_view_window_get_message (self);
1518 header = tny_msg_get_header (msg);
1519 g_object_unref (msg);
1524 /* Get iter of the currently selected message in the header view: */
1525 path = gtk_tree_row_reference_get_path (priv->row_reference);
1526 g_return_val_if_fail (path != NULL, NULL);
1527 gtk_tree_model_get_iter (priv->header_model,
1531 /* Get current message header */
1532 gtk_tree_model_get (priv->header_model, &iter,
1533 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1536 gtk_tree_path_free (path);
1541 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1543 ModestMsgViewWindowPrivate *priv;
1545 g_return_val_if_fail (self, NULL);
1547 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1549 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1553 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1555 ModestMsgViewWindowPrivate *priv;
1557 g_return_val_if_fail (self, NULL);
1559 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1562 return g_object_ref (priv->top_msg);
1568 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1570 ModestMsgViewWindowPrivate *priv;
1572 g_return_val_if_fail (self, NULL);
1574 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1576 return (const gchar*) priv->msg_uid;
1579 /* Used for the Ctrl+F accelerator */
1581 modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
1584 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1585 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1587 if (GTK_WIDGET_VISIBLE (priv->isearch_toolbar)) {
1588 modest_msg_view_window_isearch_toolbar_close (obj, data);
1590 modest_msg_view_window_show_isearch_toolbar (obj, data);
1594 /* Handler for menu option */
1596 modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj,
1599 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1600 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1602 gtk_widget_show (priv->isearch_toolbar);
1603 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1606 /* Handler for click on the "X" close button in isearch toolbar */
1608 modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
1609 ModestMsgViewWindow *obj)
1611 ModestMsgViewWindowPrivate *priv;
1613 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1616 gtk_widget_hide (priv->isearch_toolbar);
1617 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1621 modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
1622 ModestMsgViewWindow *obj)
1624 const gchar *current_search;
1625 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1627 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1628 modest_platform_system_banner (NULL, NULL, _("mail_ib_nothing_to_find"));
1632 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
1634 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1635 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
1639 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1641 g_free (priv->last_search);
1642 priv->last_search = g_strdup (current_search);
1643 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1646 modest_platform_system_banner (NULL, NULL,
1647 _HL_IB_FIND_NO_MATCHES);
1648 g_free (priv->last_search);
1649 priv->last_search = NULL;
1651 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1654 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1655 modest_platform_system_banner (NULL, NULL,
1656 _HL_IB_FIND_COMPLETE);
1657 g_free (priv->last_search);
1658 priv->last_search = NULL;
1660 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1667 modest_msg_view_window_set_zoom (ModestWindow *window,
1670 ModestMsgViewWindowPrivate *priv;
1671 ModestWindowPrivate *parent_priv;
1673 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1675 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1676 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1677 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1682 modest_msg_view_window_get_zoom (ModestWindow *window)
1684 ModestMsgViewWindowPrivate *priv;
1686 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1688 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1689 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1693 modest_msg_view_window_zoom_plus (ModestWindow *window)
1696 ModestMsgViewWindowPrivate *priv;
1700 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1701 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1703 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1705 if (zoom_level >= 2.0) {
1706 modest_platform_system_banner (NULL, NULL,
1707 _CS_MAX_ZOOM_LEVEL_REACHED);
1709 } else if (zoom_level >= 1.5) {
1711 } else if (zoom_level >= 1.2) {
1713 } else if (zoom_level >= 1.0) {
1715 } else if (zoom_level >= 0.8) {
1717 } else if (zoom_level >= 0.5) {
1723 /* set zoom level */
1724 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1725 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1726 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1727 g_free (banner_text);
1728 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1734 modest_msg_view_window_zoom_minus (ModestWindow *window)
1737 ModestMsgViewWindowPrivate *priv;
1741 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1742 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1744 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1746 if (zoom_level <= 0.5) {
1747 modest_platform_system_banner (NULL, NULL,
1748 _CS_MIN_ZOOM_LEVEL_REACHED);
1750 } else if (zoom_level <= 0.8) {
1752 } else if (zoom_level <= 1.0) {
1754 } else if (zoom_level <= 1.2) {
1756 } else if (zoom_level <= 1.5) {
1758 } else if (zoom_level <= 2.0) {
1764 /* set zoom level */
1765 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1766 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1767 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1768 g_free (banner_text);
1769 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1775 modest_msg_view_window_key_event (GtkWidget *window,
1781 focus = gtk_container_get_focus_child ((GtkContainer *) window);
1783 /* for the isearch toolbar case */
1784 if (focus && GTK_IS_ENTRY (focus)) {
1785 if (event->keyval == GDK_BackSpace) {
1787 copy = gdk_event_copy ((GdkEvent *) event);
1788 gtk_widget_event (focus, copy);
1789 gdk_event_free (copy);
1799 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1802 ModestMsgViewWindowPrivate *priv;
1803 GtkTreeIter tmp_iter;
1804 gboolean is_last_selected;
1806 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1807 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1809 /*if no model (so no rows at all), then virtually we are the last*/
1810 if (!priv->header_model || !priv->row_reference)
1813 if (!gtk_tree_row_reference_valid (priv->row_reference))
1816 path = gtk_tree_row_reference_get_path (priv->row_reference);
1820 is_last_selected = TRUE;
1821 while (is_last_selected) {
1823 gtk_tree_path_next (path);
1824 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1826 gtk_tree_model_get (priv->header_model, &tmp_iter,
1827 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1830 if (msg_is_visible (header, priv->is_outbox))
1831 is_last_selected = FALSE;
1832 g_object_unref(G_OBJECT(header));
1835 gtk_tree_path_free (path);
1836 return is_last_selected;
1840 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1842 ModestMsgViewWindowPrivate *priv;
1844 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1845 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1847 return priv->header_model != NULL;
1851 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1853 ModestMsgViewWindowPrivate *priv;
1855 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1856 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1858 return priv->is_search_result;
1862 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1864 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1866 if (!check_outbox) {
1869 ModestTnySendQueueStatus status;
1870 status = modest_tny_all_send_queues_get_msg_status (header);
1871 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1872 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1877 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1880 ModestMsgViewWindowPrivate *priv;
1881 gboolean is_first_selected;
1882 GtkTreeIter tmp_iter;
1884 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1885 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1887 /*if no model (so no rows at all), then virtually we are the first*/
1888 if (!priv->header_model || !priv->row_reference)
1891 if (!gtk_tree_row_reference_valid (priv->row_reference))
1894 path = gtk_tree_row_reference_get_path (priv->row_reference);
1898 is_first_selected = TRUE;
1899 while (is_first_selected) {
1901 if(!gtk_tree_path_prev (path))
1903 /* Here the 'if' is needless for logic, but let make sure
1904 * iter is valid for gtk_tree_model_get. */
1905 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1907 gtk_tree_model_get (priv->header_model, &tmp_iter,
1908 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1911 if (msg_is_visible (header, priv->is_outbox))
1912 is_first_selected = FALSE;
1913 g_object_unref(G_OBJECT(header));
1916 gtk_tree_path_free (path);
1917 return is_first_selected;
1924 GtkTreeRowReference *row_reference;
1928 message_reader_performer (gboolean canceled,
1930 ModestWindow *parent_window,
1931 TnyAccount *account,
1934 ModestMailOperation *mail_op = NULL;
1935 MsgReaderInfo *info;
1937 info = (MsgReaderInfo *) user_data;
1938 if (canceled || err) {
1939 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1940 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1944 /* Register the header - it'll be unregistered in the callback */
1946 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1948 /* New mail operation */
1949 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1950 modest_ui_actions_disk_operations_error_handler,
1953 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1955 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1957 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1958 g_object_unref (mail_op);
1960 /* Update dimming rules */
1961 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1962 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1965 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1966 g_free (info->msg_uid);
1968 g_object_unref (info->folder);
1970 g_object_unref (info->header);
1971 g_slice_free (MsgReaderInfo, info);
1976 * Reads the message whose summary item is @header. It takes care of
1977 * several things, among others:
1979 * If the message was not previously downloaded then ask the user
1980 * before downloading. If there is no connection launch the connection
1981 * dialog. Update toolbar dimming rules.
1983 * Returns: TRUE if the mail operation was started, otherwise if the
1984 * user do not want to download the message, or if the user do not
1985 * want to connect, then the operation is not issued
1988 message_reader (ModestMsgViewWindow *window,
1989 ModestMsgViewWindowPrivate *priv,
1991 const gchar *msg_uid,
1993 GtkTreeRowReference *row_reference)
1995 ModestWindowMgr *mgr;
1996 TnyAccount *account = NULL;
1997 MsgReaderInfo *info;
1999 /* We set the header from model while we're loading */
2000 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2001 modest_window_set_title (MODEST_WINDOW (window), _CS_UPDATING);
2007 g_object_ref (folder);
2009 mgr = modest_runtime_get_window_mgr ();
2010 /* Msg download completed */
2011 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2013 /* Ask the user if he wants to download the message if
2015 if (!tny_device_is_online (modest_runtime_get_device())) {
2016 GtkResponseType response;
2017 GtkWindow *toplevel;
2019 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
2020 response = modest_platform_run_confirmation_dialog (toplevel, _("mcen_nc_get_msg"));
2021 if (response == GTK_RESPONSE_CANCEL) {
2022 update_window_title (window);
2027 folder = tny_header_get_folder (header);
2029 info = g_slice_new (MsgReaderInfo);
2030 info->msg_uid = g_strdup (msg_uid);
2032 info->header = g_object_ref (header);
2034 info->header = NULL;
2036 info->folder = g_object_ref (folder);
2038 info->folder = NULL;
2039 if (row_reference) {
2040 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2042 info->row_reference = NULL;
2045 /* Offer the connection dialog if necessary */
2046 modest_platform_connect_if_remote_and_perform ((ModestWindow *) window,
2048 TNY_FOLDER_STORE (folder),
2049 message_reader_performer,
2052 g_object_unref (folder);
2058 folder = tny_header_get_folder (header);
2061 account = tny_folder_get_account (folder);
2063 info = g_slice_new (MsgReaderInfo);
2064 info->msg_uid = g_strdup (msg_uid);
2066 info->folder = g_object_ref (folder);
2068 info->folder = NULL;
2070 info->header = g_object_ref (header);
2072 info->header = NULL;
2074 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2076 info->row_reference = NULL;
2078 message_reader_performer (FALSE, NULL, (ModestWindow *) window, account, info);
2080 g_object_unref (account);
2082 g_object_unref (folder);
2088 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2090 ModestMsgViewWindowPrivate *priv;
2091 GtkTreePath *path= NULL;
2092 GtkTreeIter tmp_iter;
2094 gboolean retval = TRUE;
2095 GtkTreeRowReference *row_reference = NULL;
2097 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2098 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2100 if (!priv->row_reference)
2103 /* Update the next row reference if it's not valid. This could
2104 happen if for example the header which it was pointing to,
2105 was deleted. The best place to do it is in the row-deleted
2106 handler but the tinymail model do not work like the glib
2107 tree models and reports the deletion when the row is still
2109 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2110 if (priv->next_row_reference) {
2111 gtk_tree_row_reference_free (priv->next_row_reference);
2113 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2114 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2115 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2117 priv->next_row_reference = NULL;
2120 if (priv->next_row_reference)
2121 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2125 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2127 gtk_tree_model_get_iter (priv->header_model,
2130 gtk_tree_path_free (path);
2132 gtk_tree_model_get (priv->header_model, &tmp_iter,
2133 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2136 /* Read the message & show it */
2137 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2140 gtk_tree_row_reference_free (row_reference);
2143 g_object_unref (header);
2149 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2151 ModestMsgViewWindowPrivate *priv = NULL;
2153 gboolean finished = FALSE;
2154 gboolean retval = FALSE;
2156 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2157 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2159 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2160 gtk_tree_row_reference_free (priv->row_reference);
2161 priv->row_reference = NULL;
2164 /* Return inmediatly if there is no header model */
2165 if (!priv->header_model || !priv->row_reference)
2168 path = gtk_tree_row_reference_get_path (priv->row_reference);
2169 while (!finished && gtk_tree_path_prev (path)) {
2173 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2174 gtk_tree_model_get (priv->header_model, &iter,
2175 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2179 if (msg_is_visible (header, priv->is_outbox)) {
2180 GtkTreeRowReference *row_reference;
2181 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2182 /* Read the message & show it */
2183 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2184 gtk_tree_row_reference_free (row_reference);
2188 g_object_unref (header);
2192 gtk_tree_path_free (path);
2197 view_msg_cb (ModestMailOperation *mail_op,
2204 ModestMsgViewWindow *self = NULL;
2205 ModestMsgViewWindowPrivate *priv = NULL;
2206 GtkTreeRowReference *row_reference = NULL;
2208 /* Unregister the header (it was registered before creating the mail operation) */
2209 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2211 row_reference = (GtkTreeRowReference *) user_data;
2214 gtk_tree_row_reference_free (row_reference);
2215 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2217 /* Restore window title */
2218 update_window_title (self);
2219 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2220 g_object_unref (self);
2225 /* If there was any error */
2226 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2228 gtk_tree_row_reference_free (row_reference);
2229 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2231 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2232 /* First we check if the parent is a folder window */
2233 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2235 TnyAccount *account = NULL;
2236 GtkWidget *header_window = NULL;
2238 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2240 /* Get the account */
2242 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2245 if (is_merge || account) {
2246 TnyFolder *folder = NULL;
2248 /* Try to get the message, if it's already downloaded
2249 we don't need to connect */
2251 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2254 ModestTnyAccountStore *account_store;
2255 ModestTnyLocalFoldersAccount *local_folders_account;
2257 account_store = modest_runtime_get_account_store ();
2258 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2259 modest_tny_account_store_get_local_folders_account (account_store));
2260 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2261 g_object_unref (local_folders_account);
2263 if (account) g_object_unref (account);
2266 header_window = (GtkWidget *)
2267 modest_header_window_new (
2269 modest_window_get_active_account (MODEST_WINDOW (self)),
2270 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2271 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2272 MODEST_WINDOW (header_window),
2274 gtk_widget_destroy (GTK_WIDGET (header_window));
2276 gtk_widget_show_all (GTK_WIDGET (header_window));
2278 g_object_unref (folder);
2284 /* Restore window title */
2285 update_window_title (self);
2286 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2287 g_object_unref (self);
2292 /* Get the window */
2293 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2294 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2295 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2297 /* Update the row reference */
2298 if (priv->row_reference != NULL) {
2299 gtk_tree_row_reference_free (priv->row_reference);
2300 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2301 if (priv->next_row_reference != NULL) {
2302 gtk_tree_row_reference_free (priv->next_row_reference);
2304 if (priv->row_reference) {
2305 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2306 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2308 priv->next_row_reference = NULL;
2312 /* Mark header as read */
2313 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2314 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2316 /* Set new message */
2317 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2318 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2319 modest_msg_view_window_update_priority (self);
2320 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2321 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2322 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2325 /* Set the new message uid of the window */
2326 if (priv->msg_uid) {
2327 g_free (priv->msg_uid);
2328 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2331 /* Notify the observers */
2332 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2333 0, priv->header_model, priv->row_reference);
2335 /* Sync the flags if the message is not opened from a header
2336 model, i.e, if it's opened from a notification */
2337 if (!priv->header_model)
2341 g_object_unref (self);
2343 gtk_tree_row_reference_free (row_reference);
2347 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2349 ModestMsgViewWindowPrivate *priv;
2351 TnyFolderType folder_type;
2353 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2355 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2357 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2361 folder = tny_msg_get_folder (msg);
2363 folder_type = modest_tny_folder_guess_folder_type (folder);
2364 g_object_unref (folder);
2366 g_object_unref (msg);
2374 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2376 ModestMsgViewWindowPrivate *priv;
2377 TnyHeader *header = NULL;
2378 TnyHeaderFlags flags = 0;
2380 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2382 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2384 GtkTreePath *path = NULL;
2386 path = gtk_tree_row_reference_get_path (priv->row_reference);
2387 g_return_if_fail (path != NULL);
2388 gtk_tree_model_get_iter (priv->header_model,
2390 gtk_tree_row_reference_get_path (priv->row_reference));
2392 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2394 gtk_tree_path_free (path);
2397 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2399 header = tny_msg_get_header (msg);
2400 g_object_unref (msg);
2405 flags = tny_header_get_flags (header);
2406 g_object_unref(G_OBJECT(header));
2409 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2414 toolbar_resize (ModestMsgViewWindow *self)
2416 ModestMsgViewWindowPrivate *priv = NULL;
2417 ModestWindowPrivate *parent_priv = NULL;
2419 gint static_button_size;
2420 ModestWindowMgr *mgr;
2422 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2423 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2424 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2426 mgr = modest_runtime_get_window_mgr ();
2427 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2429 if (parent_priv->toolbar) {
2430 /* Set expandable and homogeneous tool buttons */
2431 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2432 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2433 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2434 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2435 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2436 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2437 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2438 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2439 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2440 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2441 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2442 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2443 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2444 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2445 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2446 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2447 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2448 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2449 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2454 modest_msg_view_window_show_toolbar (ModestWindow *self,
2455 gboolean show_toolbar)
2457 ModestMsgViewWindowPrivate *priv = NULL;
2458 ModestWindowPrivate *parent_priv;
2460 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2461 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2463 /* Set optimized view status */
2464 priv->optimized_view = !show_toolbar;
2466 if (!parent_priv->toolbar) {
2467 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2470 #ifdef MODEST_TOOLKIT_HILDON2
2471 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2473 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2475 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2477 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2478 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2479 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2481 modest_window_add_toolbar (MODEST_WINDOW (self),
2482 GTK_TOOLBAR (parent_priv->toolbar));
2487 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2488 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2489 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2491 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2492 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2493 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2495 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2498 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2499 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2504 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2506 ModestMsgViewWindow *window)
2508 if (!GTK_WIDGET_VISIBLE (window))
2511 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2515 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2517 ModestMsgViewWindowPrivate *priv;
2519 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2520 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2522 return priv->progress_hint;
2526 observers_empty (ModestMsgViewWindow *self)
2529 ModestMsgViewWindowPrivate *priv;
2530 gboolean is_empty = TRUE;
2531 guint pending_ops = 0;
2533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2534 tmp = priv->progress_widgets;
2536 /* Check all observers */
2537 while (tmp && is_empty) {
2538 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2539 is_empty = pending_ops == 0;
2541 tmp = g_slist_next(tmp);
2548 on_account_removed (TnyAccountStore *account_store,
2549 TnyAccount *account,
2552 /* Do nothing if it's a transport account, because we only
2553 show the messages of a store account */
2554 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2555 const gchar *parent_acc = NULL;
2556 const gchar *our_acc = NULL;
2558 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2559 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2561 /* Close this window if I'm showing a message of the removed account */
2562 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2563 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2568 on_mail_operation_started (ModestMailOperation *mail_op,
2571 ModestMsgViewWindow *self;
2572 ModestMailOperationTypeOperation op_type;
2574 ModestMsgViewWindowPrivate *priv;
2575 GObject *source = NULL;
2577 self = MODEST_MSG_VIEW_WINDOW (user_data);
2578 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2579 op_type = modest_mail_operation_get_type_operation (mail_op);
2580 tmp = priv->progress_widgets;
2581 source = modest_mail_operation_get_source(mail_op);
2582 if (G_OBJECT (self) == source) {
2583 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2584 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2585 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2586 set_progress_hint (self, TRUE);
2588 modest_progress_object_add_operation (
2589 MODEST_PROGRESS_OBJECT (tmp->data),
2591 tmp = g_slist_next (tmp);
2595 g_object_unref (source);
2597 /* Update dimming rules */
2598 check_dimming_rules_after_change (self);
2602 on_mail_operation_finished (ModestMailOperation *mail_op,
2605 ModestMsgViewWindow *self;
2606 ModestMailOperationTypeOperation op_type;
2608 ModestMsgViewWindowPrivate *priv;
2610 self = MODEST_MSG_VIEW_WINDOW (user_data);
2611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2612 op_type = modest_mail_operation_get_type_operation (mail_op);
2613 tmp = priv->progress_widgets;
2615 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2616 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2617 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2619 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2621 tmp = g_slist_next (tmp);
2624 /* If no more operations are being observed, NORMAL mode is enabled again */
2625 if (observers_empty (self)) {
2626 set_progress_hint (self, FALSE);
2630 /* Update dimming rules. We have to do this right here
2631 and not in view_msg_cb because at that point the
2632 transfer mode is still enabled so the dimming rule
2633 won't let the user delete the message that has been
2634 readed for example */
2635 check_dimming_rules_after_change (self);
2639 on_queue_changed (ModestMailOperationQueue *queue,
2640 ModestMailOperation *mail_op,
2641 ModestMailOperationQueueNotification type,
2642 ModestMsgViewWindow *self)
2644 ModestMsgViewWindowPrivate *priv;
2646 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2648 /* If this operations was created by another window, do nothing */
2649 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2652 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2653 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2655 "operation-started",
2656 G_CALLBACK (on_mail_operation_started),
2658 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2660 "operation-finished",
2661 G_CALLBACK (on_mail_operation_finished),
2663 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2664 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2666 "operation-started");
2667 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2669 "operation-finished");
2674 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2676 ModestMsgViewWindowPrivate *priv;
2677 TnyList *selected_attachments = NULL;
2679 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2680 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2682 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2683 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2685 return selected_attachments;
2689 ModestMsgViewWindow *self;
2691 gchar *attachment_uid;
2692 } DecodeAsyncHelper;
2695 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2701 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2702 const gchar *content_type;
2703 ModestMsgViewWindowPrivate *priv;
2705 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2707 if (cancelled || err) {
2710 if ((err->domain == TNY_ERROR_DOMAIN) &&
2711 (err->code == TNY_IO_ERROR_WRITE) &&
2712 (errno == ENOSPC)) {
2713 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2715 msg = g_strdup (_("mail_ib_file_operation_failed"));
2717 modest_platform_information_banner (NULL, NULL, msg);
2723 /* It could happen that the window was closed. So we
2724 assume it is a cancelation */
2725 if (!GTK_WIDGET_VISIBLE (helper->self))
2728 /* Remove the progress hint */
2729 set_progress_hint (helper->self, FALSE);
2731 content_type = tny_mime_part_get_content_type (mime_part);
2732 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2733 ModestWindowMgr *mgr;
2734 ModestWindow *msg_win = NULL;
2737 const gchar *mailbox;
2738 TnyStream *file_stream;
2741 fd = g_open (helper->file_path, O_RDONLY, 0644);
2744 file_stream = tny_fs_stream_new (fd);
2746 mgr = modest_runtime_get_window_mgr ();
2748 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2749 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2752 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2754 msg = tny_camel_msg_new ();
2755 tny_camel_msg_parse (TNY_CAMEL_MSG (msg), file_stream);
2758 top_msg = g_object_ref (priv->top_msg);
2760 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2762 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2763 account, mailbox, helper->attachment_uid);
2764 if (top_msg) g_object_unref (top_msg);
2765 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2766 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2767 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2768 gtk_widget_show_all (GTK_WIDGET (msg_win));
2770 gtk_widget_destroy (GTK_WIDGET (msg_win));
2771 g_object_unref (msg);
2772 g_object_unref (file_stream);
2774 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2779 /* make the file read-only */
2780 g_chmod(helper->file_path, 0444);
2782 /* Activate the file */
2783 modest_platform_activate_file (helper->file_path, content_type);
2788 g_object_unref (helper->self);
2789 g_free (helper->file_path);
2790 g_free (helper->attachment_uid);
2791 g_slice_free (DecodeAsyncHelper, helper);
2795 view_attachment_connect_handler (gboolean canceled,
2797 GtkWindow *parent_window,
2798 TnyAccount *account,
2802 if (canceled || err) {
2803 g_object_unref (part);
2807 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2809 g_object_unref (part);
2813 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2814 TnyMimePart *mime_part)
2816 ModestMsgViewWindowPrivate *priv;
2817 const gchar *msg_uid;
2818 gchar *attachment_uid = NULL;
2819 gint attachment_index = 0;
2820 TnyList *attachments;
2822 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2823 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2824 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2826 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2827 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2828 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2829 g_object_unref (attachments);
2831 if (msg_uid && attachment_index >= 0) {
2832 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2835 if (mime_part == NULL) {
2836 gboolean error = FALSE;
2837 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2838 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2840 } else if (tny_list_get_length (selected_attachments) > 1) {
2841 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2845 iter = tny_list_create_iterator (selected_attachments);
2846 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2847 g_object_unref (iter);
2849 if (selected_attachments)
2850 g_object_unref (selected_attachments);
2855 g_object_ref (mime_part);
2858 if (tny_mime_part_is_purged (mime_part))
2861 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2862 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2864 TnyAccount *account;
2866 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2868 /* Get the account */
2870 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2873 if (!tny_device_is_online (modest_runtime_get_device())) {
2874 modest_platform_connect_and_perform ((ModestWindow *) window,
2876 TNY_ACCOUNT (account),
2877 (ModestConnectedPerformer) view_attachment_connect_handler,
2878 g_object_ref (mime_part));
2883 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2884 gchar *filepath = NULL;
2885 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2886 gboolean show_error_banner = FALSE;
2887 TnyFsStream *temp_stream = NULL;
2888 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2891 if (temp_stream != NULL) {
2892 ModestAccountMgr *mgr;
2893 DecodeAsyncHelper *helper;
2894 gboolean decode_in_provider;
2895 ModestProtocol *protocol;
2896 const gchar *account;
2898 /* Activate progress hint */
2899 set_progress_hint (window, TRUE);
2901 helper = g_slice_new0 (DecodeAsyncHelper);
2902 helper->self = g_object_ref (window);
2903 helper->file_path = g_strdup (filepath);
2904 helper->attachment_uid = g_strdup (attachment_uid);
2906 decode_in_provider = FALSE;
2907 mgr = modest_runtime_get_account_mgr ();
2908 account = modest_window_get_active_account (MODEST_WINDOW (window));
2909 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2910 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2912 uri = g_strconcat ("file://", filepath, NULL);
2913 decode_in_provider =
2914 modest_account_protocol_decode_part_to_stream_async (
2915 MODEST_ACCOUNT_PROTOCOL (protocol),
2918 TNY_STREAM (temp_stream),
2919 on_decode_to_stream_async_handler,
2926 if (!decode_in_provider)
2927 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2928 on_decode_to_stream_async_handler,
2931 g_object_unref (temp_stream);
2932 /* NOTE: files in the temporary area will be automatically
2933 * cleaned after some time if they are no longer in use */
2936 const gchar *content_type;
2937 /* the file may already exist but it isn't writable,
2938 * let's try to open it anyway */
2939 content_type = tny_mime_part_get_content_type (mime_part);
2940 modest_platform_activate_file (filepath, content_type);
2942 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2943 show_error_banner = TRUE;
2948 if (show_error_banner)
2949 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2950 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2951 ModestWindowMgr *mgr;
2952 ModestWindow *msg_win = NULL;
2953 TnyMsg *current_msg;
2957 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2958 mgr = modest_runtime_get_window_mgr ();
2959 header = tny_msg_get_header (TNY_MSG (current_msg));
2960 found = modest_window_mgr_find_registered_message_uid (mgr,
2965 g_debug ("window for this body is already being created");
2969 /* it's not found, so create a new window for it */
2970 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2971 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2972 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2974 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2977 top_msg = g_object_ref (priv->top_msg);
2979 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2981 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
2982 account, mailbox, attachment_uid);
2984 if (top_msg) g_object_unref (top_msg);
2986 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2987 modest_window_get_zoom (MODEST_WINDOW (window)));
2988 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2989 gtk_widget_show_all (GTK_WIDGET (msg_win));
2991 gtk_widget_destroy (GTK_WIDGET (msg_win));
2993 g_object_unref (current_msg);
2995 /* message attachment */
2996 TnyHeader *header = NULL;
2997 ModestWindowMgr *mgr;
2998 ModestWindow *msg_win = NULL;
3001 header = tny_msg_get_header (TNY_MSG (mime_part));
3002 mgr = modest_runtime_get_window_mgr ();
3003 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3006 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3007 * thus, we don't do anything */
3008 g_debug ("window for is already being created");
3011 /* it's not found, so create a new window for it */
3012 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3013 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3014 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3016 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3018 top_msg = g_object_ref (priv->top_msg);
3020 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3021 msg_win = modest_msg_view_window_new_for_attachment (
3022 TNY_MSG (mime_part), top_msg, account,
3023 mailbox, attachment_uid);
3024 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3025 modest_window_get_zoom (MODEST_WINDOW (window)));
3026 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3027 gtk_widget_show_all (GTK_WIDGET (msg_win));
3029 gtk_widget_destroy (GTK_WIDGET (msg_win));
3035 g_free (attachment_uid);
3037 g_object_unref (mime_part);
3049 GnomeVFSResult result;
3051 ModestMsgViewWindow *window;
3054 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3055 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3056 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3057 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3060 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3064 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3065 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3066 g_free (pair->filename);
3067 g_object_unref (pair->part);
3068 g_slice_free (SaveMimePartPair, pair);
3070 g_list_free (info->pairs);
3073 g_object_unref (info->window);
3074 info->window = NULL;
3076 g_slice_free (SaveMimePartInfo, info);
3081 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3083 /* This is a GDK lock because we are an idle callback and
3084 * modest_platform_system_banner is or does Gtk+ code */
3086 gdk_threads_enter (); /* CHECKED */
3087 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3089 } else if (info->result == GNOME_VFS_OK) {
3090 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3091 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3094 /* Check if the uri belongs to the external mmc */
3095 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3096 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3098 msg = g_strdup (_KR("cerm_memory_card_full"));
3099 modest_platform_information_banner (NULL, NULL, msg);
3102 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3104 save_mime_part_info_free (info, FALSE);
3105 gdk_threads_leave (); /* CHECKED */
3111 save_mime_part_to_file_connect_handler (gboolean canceled,
3113 GtkWindow *parent_window,
3114 TnyAccount *account,
3115 SaveMimePartInfo *info)
3117 if (canceled || err) {
3118 if (canceled && !err) {
3119 info->result = GNOME_VFS_ERROR_CANCELLED;
3121 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3123 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3128 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3131 TnyAccount *account;
3132 ModestMsgViewWindowPrivate *priv;
3134 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3136 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3139 /* Get the account */
3141 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3144 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3146 TNY_ACCOUNT (account),
3147 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3151 g_object_unref (account);
3157 save_mime_part_to_file (SaveMimePartInfo *info)
3159 GnomeVFSHandle *handle;
3161 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3163 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3164 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3165 gboolean check_online = TRUE;
3166 ModestMsgViewWindowPrivate *priv = NULL;
3168 /* Check if we really need to connect to save the mime part */
3169 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3170 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3171 check_online = FALSE;
3173 TnyAccountStore *acc_store;
3174 TnyAccount *account = NULL;
3176 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3177 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3180 if (tny_account_get_connection_status (account) ==
3181 TNY_CONNECTION_STATUS_CONNECTED)
3182 check_online = FALSE;
3183 g_object_unref (account);
3185 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3190 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3195 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3196 if (info->result == GNOME_VFS_OK) {
3197 GError *error = NULL;
3198 gboolean decode_in_provider;
3200 ModestAccountMgr *mgr;
3201 const gchar *account;
3202 ModestProtocol *protocol = NULL;
3204 stream = tny_vfs_stream_new (handle);
3206 decode_in_provider = FALSE;
3207 mgr = modest_runtime_get_account_mgr ();
3208 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3209 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3210 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3211 decode_in_provider =
3212 modest_account_protocol_decode_part_to_stream (
3213 MODEST_ACCOUNT_PROTOCOL (protocol),
3221 if (!decode_in_provider)
3222 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3225 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3227 if ((error->domain == TNY_ERROR_DOMAIN) &&
3228 (error->code == TNY_IO_ERROR_WRITE) &&
3229 (errno == ENOSPC)) {
3230 info->result = GNOME_VFS_ERROR_NO_SPACE;
3232 info->result = GNOME_VFS_ERROR_IO;
3235 g_object_unref (G_OBJECT (stream));
3237 g_warning ("Could not create save attachment %s: %s\n",
3238 pair->filename, gnome_vfs_result_to_string (info->result));
3241 /* Go on saving remaining files */
3242 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3243 if (info->pairs != NULL) {
3244 save_mime_part_to_file (info);
3246 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3253 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3254 SaveMimePartInfo *info)
3256 gboolean is_ok = TRUE;
3257 gint replaced_files = 0;
3258 const GList *files = info->pairs;
3259 const GList *iter, *to_replace = NULL;
3261 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3262 SaveMimePartPair *pair = iter->data;
3263 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3265 if (modest_utils_file_exists (unescaped)) {
3267 if (replaced_files == 1)
3272 if (replaced_files) {
3275 if (replaced_files == 1) {
3276 SaveMimePartPair *pair = to_replace->data;
3277 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3278 gchar *escaped_basename, *message;
3280 escaped_basename = g_uri_unescape_string (basename, NULL);
3281 message = g_strdup_printf ("%s\n%s",
3283 (escaped_basename) ? escaped_basename : "");
3284 response = modest_platform_run_confirmation_dialog (parent, message);
3286 g_free (escaped_basename);
3288 response = modest_platform_run_confirmation_dialog (parent,
3289 _FM_REPLACE_MULTIPLE);
3291 if (response != GTK_RESPONSE_OK)
3296 save_mime_part_info_free (info, TRUE);
3298 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3303 typedef struct _SaveAttachmentsInfo {
3304 TnyList *attachments_list;
3305 ModestMsgViewWindow *window;
3306 } SaveAttachmentsInfo;
3309 save_attachments_response (GtkDialog *dialog,
3313 TnyList *mime_parts;
3315 GList *files_to_save = NULL;
3316 gchar *current_folder;
3317 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3319 mime_parts = TNY_LIST (sa_info->attachments_list);
3321 if (arg1 != GTK_RESPONSE_OK)
3324 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3325 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3326 if (current_folder && *current_folder != '\0') {
3328 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3329 current_folder,&err);
3331 g_debug ("Error storing latest used folder: %s", err->message);
3335 g_free (current_folder);
3337 if (!modest_utils_folder_writable (chooser_uri)) {
3338 const gchar *err_msg;
3340 #ifdef MODEST_PLATFORM_MAEMO
3341 if (modest_maemo_utils_in_usb_mode ()) {
3342 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3344 err_msg = _FM_READ_ONLY_LOCATION;
3347 err_msg = _FM_READ_ONLY_LOCATION;
3349 modest_platform_system_banner (NULL, NULL, err_msg);
3353 iter = tny_list_create_iterator (mime_parts);
3354 while (!tny_iterator_is_done (iter)) {
3355 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3357 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3358 !tny_mime_part_is_purged (mime_part) &&
3359 (tny_mime_part_get_filename (mime_part) != NULL)) {
3360 SaveMimePartPair *pair;
3362 pair = g_slice_new0 (SaveMimePartPair);
3364 if (tny_list_get_length (mime_parts) > 1) {
3366 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3367 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3370 pair->filename = g_strdup (chooser_uri);
3372 pair->part = mime_part;
3373 files_to_save = g_list_prepend (files_to_save, pair);
3375 tny_iterator_next (iter);
3377 g_object_unref (iter);
3380 if (files_to_save != NULL) {
3381 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3382 info->pairs = files_to_save;
3383 info->result = TRUE;
3384 info->uri = g_strdup (chooser_uri);
3385 info->window = g_object_ref (sa_info->window);
3386 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3388 g_free (chooser_uri);
3391 /* Free and close the dialog */
3392 g_object_unref (mime_parts);
3393 g_object_unref (sa_info->window);
3394 g_slice_free (SaveAttachmentsInfo, sa_info);
3395 gtk_widget_destroy (GTK_WIDGET (dialog));
3399 msg_is_attachment (TnyList *mime_parts)
3402 gboolean retval = FALSE;
3404 if (tny_list_get_length (mime_parts) > 1)
3407 iter = tny_list_create_iterator (mime_parts);
3409 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3411 if (TNY_IS_MSG (part))
3413 g_object_unref (part);
3415 g_object_unref (iter);
3421 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3422 TnyList *mime_parts)
3424 ModestMsgViewWindowPrivate *priv;
3425 GtkWidget *save_dialog = NULL;
3426 gchar *conf_folder = NULL;
3427 gchar *filename = NULL;
3428 gchar *save_multiple_str = NULL;
3429 const gchar *root_folder = "file:///";
3431 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3432 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3434 if (mime_parts == NULL) {
3435 gboolean allow_msgs = FALSE;
3437 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3438 * selection available */
3439 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3441 /* Check if the message is composed by an unique MIME
3442 part whose content disposition is attachment. There
3443 could be messages like this:
3445 Date: Tue, 12 Jan 2010 20:40:59 +0000
3446 From: <sender@example.org>
3447 To: <recipient@example.org>
3449 Content-Type: image/jpeg
3450 Content-Disposition: attachment; filename="bug7718.jpeg"
3452 whose unique MIME part is the message itself whose
3453 content disposition is attachment
3455 if (mime_parts && msg_is_attachment (mime_parts))
3458 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3459 g_object_unref (mime_parts);
3463 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3465 g_object_unref (mime_parts);
3471 g_object_ref (mime_parts);
3474 /* prepare dialog */
3475 if (tny_list_get_length (mime_parts) == 1) {
3477 /* only one attachment selected */
3478 iter = tny_list_create_iterator (mime_parts);
3479 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3480 g_object_unref (iter);
3481 if (!modest_tny_mime_part_is_msg (mime_part) &&
3482 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3483 !tny_mime_part_is_purged (mime_part)) {
3484 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3486 /* TODO: show any error? */
3487 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3488 g_object_unref (mime_parts);
3491 g_object_unref (mime_part);
3493 gint num = tny_list_get_length (mime_parts);
3494 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3495 "sfil_va_number_of_objects_attachment",
3496 "sfil_va_number_of_objects_attachments",
3500 /* Creation of hildon file chooser dialog for saving */
3501 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3503 (GtkWindow *) window,
3504 GTK_FILE_CHOOSER_ACTION_SAVE);
3506 /* Get last used folder */
3507 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3508 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3510 /* File chooser stops working if we select "file:///" as current folder */
3511 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3512 g_free (conf_folder);
3516 if (conf_folder && conf_folder[0] != '\0') {
3517 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3520 /* Set the default folder to documents folder */
3521 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3524 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3526 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3527 g_free (docs_folder);
3529 g_free (conf_folder);
3533 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3538 /* if multiple, set multiple string */
3539 if (save_multiple_str) {
3540 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3541 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3542 g_free (save_multiple_str);
3545 /* We must run this asynchronously, because the hildon dialog
3546 performs a gtk_dialog_run by itself which leads to gdk
3548 SaveAttachmentsInfo *sa_info;
3549 sa_info = g_slice_new (SaveAttachmentsInfo);
3550 sa_info->attachments_list = mime_parts;
3551 sa_info->window = g_object_ref (window);
3552 g_signal_connect (save_dialog, "response",
3553 G_CALLBACK (save_attachments_response), sa_info);
3555 gtk_widget_show_all (save_dialog);
3559 show_remove_attachment_information (gpointer userdata)
3561 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3562 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3564 /* We're outside the main lock */
3565 gdk_threads_enter ();
3567 if (priv->remove_attachment_banner != NULL) {
3568 gtk_widget_destroy (priv->remove_attachment_banner);
3569 g_object_unref (priv->remove_attachment_banner);
3572 priv->remove_attachment_banner = g_object_ref (
3573 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3575 gdk_threads_leave ();
3581 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3583 ModestMsgViewWindowPrivate *priv;
3584 TnyList *mime_parts = NULL, *tmp;
3585 gchar *confirmation_message;
3591 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3592 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3594 #ifdef MODEST_TOOLKIT_HILDON2
3595 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3596 * because we don't have selection
3598 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3600 /* Remove already purged messages from mime parts list. We use
3601 a copy of the list to remove items in the original one */
3602 tmp = tny_list_copy (mime_parts);
3603 iter = tny_list_create_iterator (tmp);
3604 while (!tny_iterator_is_done (iter)) {
3605 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3606 if (tny_mime_part_is_purged (part))
3607 tny_list_remove (mime_parts, (GObject *) part);
3609 g_object_unref (part);
3610 tny_iterator_next (iter);
3612 g_object_unref (tmp);
3613 g_object_unref (iter);
3615 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3616 tny_list_get_length (mime_parts) == 0) {
3617 g_object_unref (mime_parts);
3621 /* In gtk we get only selected attachments for the operation.
3623 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3625 /* Remove already purged messages from mime parts list. We use
3626 a copy of the list to remove items in the original one */
3627 tmp = tny_list_copy (mime_parts);
3628 iter = tny_list_create_iterator (tmp);
3629 while (!tny_iterator_is_done (iter)) {
3630 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3631 if (tny_mime_part_is_purged (part))
3632 tny_list_remove (mime_parts, (GObject *) part);
3634 g_object_unref (part);
3635 tny_iterator_next (iter);
3637 g_object_unref (tmp);
3638 g_object_unref (iter);
3640 if (tny_list_get_length (mime_parts) == 0) {
3641 g_object_unref (mime_parts);
3646 n_attachments = tny_list_get_length (mime_parts);
3647 if (n_attachments == 1) {
3651 iter = tny_list_create_iterator (mime_parts);
3652 part = (TnyMimePart *) tny_iterator_get_current (iter);
3653 g_object_unref (iter);
3654 if (modest_tny_mime_part_is_msg (part)) {
3656 header = tny_msg_get_header (TNY_MSG (part));
3657 filename = tny_header_dup_subject (header);
3658 g_object_unref (header);
3659 if (filename == NULL)
3660 filename = g_strdup (_("mail_va_no_subject"));
3662 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3664 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3666 g_object_unref (part);
3668 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3669 "mcen_nc_purge_files_text",
3670 n_attachments), n_attachments);
3672 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3673 confirmation_message);
3674 g_free (confirmation_message);
3676 if (response != GTK_RESPONSE_OK) {
3677 g_object_unref (mime_parts);
3681 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3683 iter = tny_list_create_iterator (mime_parts);
3684 while (!tny_iterator_is_done (iter)) {
3687 part = (TnyMimePart *) tny_iterator_get_current (iter);
3688 tny_mime_part_set_purged (TNY_MIME_PART (part));
3689 g_object_unref (part);
3690 tny_iterator_next (iter);
3692 g_object_unref (iter);
3694 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3695 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3696 tny_msg_rewrite_cache (msg);
3697 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3698 g_object_unref (msg);
3699 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3701 g_object_unref (mime_parts);
3703 if (priv->purge_timeout > 0) {
3704 g_source_remove (priv->purge_timeout);
3705 priv->purge_timeout = 0;
3708 if (priv->remove_attachment_banner) {
3709 gtk_widget_destroy (priv->remove_attachment_banner);
3710 g_object_unref (priv->remove_attachment_banner);
3711 priv->remove_attachment_banner = NULL;
3717 update_window_title (ModestMsgViewWindow *window)
3719 ModestMsgViewWindowPrivate *priv;
3721 TnyHeader *header = NULL;
3722 gchar *subject = NULL;
3724 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3726 /* Note that if the window is closed while we're retrieving
3727 the message, this widget could de deleted */
3728 if (!priv->msg_view)
3731 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3733 if (priv->other_body) {
3736 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3738 g_strstrip (description);
3739 subject = description;
3741 } else if (msg != NULL) {
3742 header = tny_msg_get_header (msg);
3743 subject = tny_header_dup_subject (header);
3744 g_object_unref (header);
3745 g_object_unref (msg);
3748 if ((subject == NULL)||(subject[0] == '\0')) {
3750 subject = g_strdup (_("mail_va_no_subject"));
3753 modest_window_set_title (MODEST_WINDOW (window), subject);
3758 on_move_focus (GtkWidget *widget,
3759 GtkDirectionType direction,
3762 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3766 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3768 GnomeVFSResult result;
3769 GnomeVFSHandle *handle = NULL;
3770 GnomeVFSFileInfo *info = NULL;
3773 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3774 if (result != GNOME_VFS_OK) {
3779 info = gnome_vfs_file_info_new ();
3780 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3781 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3782 /* We put a "safe" default size for going to cache */
3783 *expected_size = (300*1024);
3785 *expected_size = info->size;
3787 gnome_vfs_file_info_unref (info);
3789 stream = tny_vfs_stream_new (handle);
3798 TnyStream *output_stream;
3799 GtkWidget *msg_view;
3804 on_fetch_image_timeout_refresh_view (gpointer userdata)
3806 ModestMsgViewWindowPrivate *priv;
3808 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3809 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3810 /* Note that priv->msg_view is set to NULL when this window is
3812 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3813 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3815 priv->fetch_image_redraw_handler = 0;
3816 g_object_unref (userdata);
3821 on_fetch_image_idle_refresh_view (gpointer userdata)
3824 FetchImageData *fidata = (FetchImageData *) userdata;
3826 gdk_threads_enter ();
3827 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3828 ModestMsgViewWindowPrivate *priv;
3830 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3831 priv->fetching_images--;
3832 if (priv->fetch_image_redraw_handler == 0) {
3833 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3837 gdk_threads_leave ();
3839 g_object_unref (fidata->msg_view);
3840 g_object_unref (fidata->window);
3841 g_slice_free (FetchImageData, fidata);
3846 on_fetch_image_thread (gpointer userdata)
3848 FetchImageData *fidata = (FetchImageData *) userdata;
3849 TnyStreamCache *cache;
3850 TnyStream *cache_stream;
3852 cache = modest_runtime_get_images_cache ();
3854 tny_stream_cache_get_stream (cache,
3856 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3857 (gpointer) fidata->uri);
3858 g_free (fidata->cache_id);
3859 g_free (fidata->uri);
3861 if (cache_stream != NULL) {
3864 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3867 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3868 if (G_UNLIKELY (nb_read < 0)) {
3870 } else if (G_LIKELY (nb_read > 0)) {
3871 gssize nb_written = 0;
3873 while (G_UNLIKELY (nb_written < nb_read)) {
3876 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3877 nb_read - nb_written);
3878 if (G_UNLIKELY (len < 0))
3884 tny_stream_close (cache_stream);
3885 g_object_unref (cache_stream);
3888 tny_stream_close (fidata->output_stream);
3889 g_object_unref (fidata->output_stream);
3891 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3897 on_fetch_image (ModestMsgView *msgview,
3900 ModestMsgViewWindow *window)
3902 const gchar *current_account;
3903 ModestMsgViewWindowPrivate *priv;
3904 FetchImageData *fidata;
3906 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3908 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3910 fidata = g_slice_new0 (FetchImageData);
3911 fidata->msg_view = g_object_ref (msgview);
3912 fidata->window = g_object_ref (window);
3913 fidata->uri = g_strdup (uri);
3914 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3915 fidata->output_stream = g_object_ref (stream);
3917 priv->fetching_images++;
3918 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3919 g_object_unref (fidata->output_stream);
3920 g_free (fidata->cache_id);
3921 g_free (fidata->uri);
3922 g_object_unref (fidata->msg_view);
3923 g_slice_free (FetchImageData, fidata);
3924 tny_stream_close (stream);
3925 priv->fetching_images--;
3926 update_progress_hint (window);
3929 update_progress_hint (window);
3935 setup_menu (ModestMsgViewWindow *self)
3937 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3939 /* Settings menu buttons */
3940 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3941 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
3942 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3944 modest_window_add_to_menu (MODEST_WINDOW (self),
3945 dngettext(GETTEXT_PACKAGE,
3946 "mcen_me_move_message",
3947 "mcen_me_move_messages",
3950 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3951 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3953 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3954 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3955 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3957 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3958 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3959 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3961 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3962 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3963 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3964 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3965 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3966 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3968 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3969 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3970 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3971 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3972 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3973 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3975 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3976 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
3977 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3981 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3983 ModestMsgViewWindowPrivate *priv;
3984 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3985 GSList *recipients = NULL;
3988 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3992 header = modest_msg_view_window_get_header (self);
3995 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3996 g_object_unref (header);
3998 recipients = modest_tny_msg_get_all_recipients_list (msg);
3999 g_object_unref (msg);
4003 /* Offer the user to add recipients to the address book */
4004 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4005 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4010 _modest_msg_view_window_map_event (GtkWidget *widget,
4014 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4016 update_progress_hint (self);
4022 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4024 ModestMsgViewWindowPrivate *priv;
4025 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4027 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4031 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4033 ModestMsgViewWindowPrivate *priv;
4034 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4036 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4038 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4042 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4044 ModestMsgViewWindowPrivate *priv;
4045 const gchar *msg_uid;
4046 TnyHeader *header = NULL;
4047 TnyFolder *folder = NULL;
4049 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4051 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4053 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4057 folder = tny_header_get_folder (header);
4058 g_object_unref (header);
4063 msg_uid = modest_msg_view_window_get_message_uid (self);
4065 GtkTreeRowReference *row_reference;
4067 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4068 row_reference = priv->row_reference;
4070 row_reference = NULL;
4072 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4073 g_warning ("Shouldn't happen, trying to reload a message failed");
4076 g_object_unref (folder);
4080 update_branding (ModestMsgViewWindow *self)
4082 const gchar *account;
4083 const gchar *mailbox;
4084 ModestAccountMgr *mgr;
4085 ModestProtocol *protocol = NULL;
4086 gchar *service_name = NULL;
4087 const GdkPixbuf *service_icon = NULL;
4088 ModestMsgViewWindowPrivate *priv;
4090 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4092 account = modest_window_get_active_account (MODEST_WINDOW (self));
4093 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4095 mgr = modest_runtime_get_account_mgr ();
4097 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4098 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4099 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4101 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4102 account, mailbox, MODEST_ICON_SIZE_SMALL);
4106 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4107 g_free (service_name);
4111 sync_flags (ModestMsgViewWindow *self)
4113 TnyHeader *header = NULL;
4115 header = modest_msg_view_window_get_header (self);
4117 TnyMsg *msg = modest_msg_view_window_get_message (self);
4119 header = tny_msg_get_header (msg);
4120 g_object_unref (msg);
4125 TnyFolder *folder = tny_header_get_folder (header);
4128 ModestMailOperation *mail_op;
4130 /* Sync folder, we need this to save the seen flag */
4131 mail_op = modest_mail_operation_new (NULL);
4132 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4134 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4135 g_object_unref (mail_op);
4136 g_object_unref (folder);
4138 g_object_unref (header);