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-maemo-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include <modest-main-window-ui.h>
44 #include "modest-msg-view-window-ui-dimming.h"
45 #include <modest-widget-memory.h>
46 #include <modest-progress-object.h>
47 #include <modest-runtime.h>
48 #include <modest-window-priv.h>
49 #include <modest-tny-folder.h>
50 #include <modest-text-utils.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <hildon/hildon-pannable-area.h>
53 #include <hildon/hildon-picker-dialog.h>
54 #include <hildon/hildon-app-menu.h>
55 #include "modest-defs.h"
56 #include "modest-hildon-includes.h"
57 #include "modest-ui-dimming-manager.h"
58 #include <gdk/gdkkeysyms.h>
59 #include <modest-tny-account.h>
60 #include <modest-mime-part-view.h>
61 #include <modest-isearch-view.h>
62 #include <modest-tny-mime-part.h>
63 #include <modest-address-book.h>
66 #include <glib/gstdio.h>
67 #include <modest-debug.h>
68 #include <modest-header-window.h>
69 #include <modest-account-protocol.h>
70 #include <modest-hildon2-window-mgr.h>
71 #include <tny-camel-msg.h>
72 #include <tny-camel-bs-mime-part.h>
73 #include <tny-camel-bs-msg.h>
75 #include <X11/Xatom.h>
76 #include <X11/XKBlib.h>
77 #include <X11/Xdmcp.h>
79 #define MYDOCS_ENV "MYDOCSDIR"
80 #define DOCS_FOLDER ".documents"
82 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
83 struct _ModestMsgViewWindowPrivate {
86 GtkWidget *main_scroll;
87 GtkWidget *find_toolbar;
90 /* Progress observers */
91 GSList *progress_widgets;
94 GtkWidget *prev_toolitem;
95 GtkWidget *next_toolitem;
96 gboolean progress_hint;
99 /* Optimized view enabled */
100 gboolean optimized_view;
102 /* Whether this was created via the *_new_for_search_result() function. */
103 gboolean is_search_result;
105 /* Whether the message is in outbox */
108 /* A reference to the @model of the header view
109 * to allow selecting previous/next messages,
110 * if the message is currently selected in the header view.
112 const gchar *header_folder_id;
113 GtkTreeModel *header_model;
114 GtkTreeRowReference *row_reference;
115 GtkTreeRowReference *next_row_reference;
117 gulong clipboard_change_handler;
118 gulong queue_change_handler;
119 gulong account_removed_handler;
120 gulong row_changed_handler;
121 gulong row_deleted_handler;
122 gulong row_inserted_handler;
123 gulong rows_reordered_handler;
124 gulong fetch_image_redraw_handler;
127 GtkWidget *remove_attachment_banner;
130 TnyMimePart *other_body;
136 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
137 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
138 static void modest_header_view_observer_init (ModestHeaderViewObserverIface *iface_class);
139 static void modest_msg_view_window_finalize (GObject *obj);
140 static void modest_msg_view_window_show_find_toolbar (GtkWidget *obj, gpointer data);
141 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
142 ModestMsgViewWindow *obj);
143 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgViewWindow *obj);
145 static void modest_msg_view_window_toggle_find_toolbar (GtkWidget *obj,
147 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
149 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
150 static void modest_msg_view_window_set_zoom (ModestWindow *window,
152 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
153 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
154 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
157 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
159 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
160 gboolean show_toolbar);
162 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
164 ModestMsgViewWindow *window);
166 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
169 ModestMsgViewWindow *window);
171 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
173 ModestMsgViewWindow *window);
175 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
176 GtkTreePath *tree_path,
177 GtkTreeIter *tree_iter,
178 ModestMsgViewWindow *window);
180 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
184 ModestMsgViewWindow *window);
186 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
188 const gchar *tny_folder_id);
190 static void on_queue_changed (ModestMailOperationQueue *queue,
191 ModestMailOperation *mail_op,
192 ModestMailOperationQueueNotification type,
193 ModestMsgViewWindow *self);
195 static void on_account_removed (TnyAccountStore *account_store,
199 static void on_move_focus (GtkWidget *widget,
200 GtkDirectionType direction,
203 static void view_msg_cb (ModestMailOperation *mail_op,
210 static void set_progress_hint (ModestMsgViewWindow *self,
213 static void update_window_title (ModestMsgViewWindow *window);
215 static void init_window (ModestMsgViewWindow *obj);
217 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
219 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
221 static gboolean on_fetch_image (ModestMsgView *msgview,
224 ModestMsgViewWindow *window);
226 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
227 GtkScrollType scroll_type,
230 static gboolean message_reader (ModestMsgViewWindow *window,
231 ModestMsgViewWindowPrivate *priv,
233 const gchar *msg_uid,
235 GtkTreeRowReference *row_reference);
237 static void setup_menu (ModestMsgViewWindow *self);
238 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
241 static void update_branding (ModestMsgViewWindow *self);
242 static void sync_flags (ModestMsgViewWindow *self);
243 static gboolean on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part,
244 GtkContainer *container, ModestMsgViewWindow *self);
246 static gboolean on_realize (GtkWidget *widget,
249 /* list my signals */
256 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
257 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
260 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
261 MODEST_TYPE_MSG_VIEW_WINDOW, \
262 ModestMsgViewWindowPrivate))
264 static GtkWindowClass *parent_class = NULL;
266 /* uncomment the following if you have defined any signals */
267 static guint signals[LAST_SIGNAL] = {0};
270 modest_msg_view_window_get_type (void)
272 static GType my_type = 0;
274 static const GTypeInfo my_info = {
275 sizeof(ModestMsgViewWindowClass),
276 NULL, /* base init */
277 NULL, /* base finalize */
278 (GClassInitFunc) modest_msg_view_window_class_init,
279 NULL, /* class finalize */
280 NULL, /* class data */
281 sizeof(ModestMsgViewWindow),
283 (GInstanceInitFunc) modest_msg_view_window_init,
286 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
287 "ModestMsgViewWindow",
290 static const GInterfaceInfo modest_header_view_observer_info =
292 (GInterfaceInitFunc) modest_header_view_observer_init,
293 NULL, /* interface_finalize */
294 NULL /* interface_data */
297 g_type_add_interface_static (my_type,
298 MODEST_TYPE_HEADER_VIEW_OBSERVER,
299 &modest_header_view_observer_info);
305 save_state (ModestWindow *self)
307 modest_widget_memory_save (modest_runtime_get_conf (),
309 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
313 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
314 GtkScrollType scroll_type,
318 ModestMsgViewWindowPrivate *priv;
321 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
323 switch (scroll_type) {
324 case GTK_SCROLL_STEP_UP:
327 case GTK_SCROLL_STEP_DOWN:
330 case GTK_SCROLL_PAGE_UP:
333 case GTK_SCROLL_PAGE_DOWN:
336 case GTK_SCROLL_START:
347 modest_maemo_utils_scroll_pannable((HildonPannableArea *) priv->main_scroll, 0, step);
349 return (gboolean) step;
353 add_scroll_binding (GtkBindingSet *binding_set,
355 GtkScrollType scroll)
357 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
359 gtk_binding_entry_add_signal (binding_set, keyval, 0,
361 GTK_TYPE_SCROLL_TYPE, scroll,
362 G_TYPE_BOOLEAN, FALSE);
363 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
365 GTK_TYPE_SCROLL_TYPE, scroll,
366 G_TYPE_BOOLEAN, FALSE);
370 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
372 GObjectClass *gobject_class;
373 HildonWindowClass *hildon_window_class;
374 ModestWindowClass *modest_window_class;
375 GtkBindingSet *binding_set;
377 gobject_class = (GObjectClass*) klass;
378 hildon_window_class = (HildonWindowClass *) klass;
379 modest_window_class = (ModestWindowClass *) klass;
381 parent_class = g_type_class_peek_parent (klass);
382 gobject_class->finalize = modest_msg_view_window_finalize;
384 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
385 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
386 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
387 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
388 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
389 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
391 modest_window_class->save_state_func = save_state;
393 klass->scroll_child = modest_msg_view_window_scroll_child;
395 signals[MSG_CHANGED_SIGNAL] =
396 g_signal_new ("msg-changed",
397 G_TYPE_FROM_CLASS (gobject_class),
399 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
401 modest_marshal_VOID__POINTER_POINTER,
402 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
404 signals[SCROLL_CHILD_SIGNAL] =
405 g_signal_new ("scroll-child",
406 G_TYPE_FROM_CLASS (gobject_class),
407 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
408 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
410 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
411 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
413 binding_set = gtk_binding_set_by_class (klass);
414 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
415 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
416 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
417 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
418 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
419 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
421 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
425 static void modest_header_view_observer_init(
426 ModestHeaderViewObserverIface *iface_class)
428 iface_class->update_func = modest_msg_view_window_update_model_replaced;
432 modest_msg_view_window_init (ModestMsgViewWindow *obj)
434 ModestMsgViewWindowPrivate *priv;
435 ModestWindowPrivate *parent_priv = NULL;
436 GtkActionGroup *action_group = NULL;
437 GError *error = NULL;
439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
440 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
441 parent_priv->ui_manager = gtk_ui_manager_new();
443 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
444 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
446 /* Add common actions */
447 gtk_action_group_add_actions (action_group,
448 modest_action_entries,
449 G_N_ELEMENTS (modest_action_entries),
451 gtk_action_group_add_toggle_actions (action_group,
452 msg_view_toggle_action_entries,
453 G_N_ELEMENTS (msg_view_toggle_action_entries),
456 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
457 g_object_unref (action_group);
459 /* Load the UI definition */
460 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
463 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
464 g_error_free (error);
469 /* Add accelerators */
470 gtk_window_add_accel_group (GTK_WINDOW (obj),
471 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
473 priv->is_search_result = FALSE;
474 priv->is_outbox = FALSE;
476 priv->msg_view = NULL;
477 priv->header_model = NULL;
478 priv->header_folder_id = NULL;
479 priv->clipboard_change_handler = 0;
480 priv->queue_change_handler = 0;
481 priv->account_removed_handler = 0;
482 priv->row_changed_handler = 0;
483 priv->row_deleted_handler = 0;
484 priv->row_inserted_handler = 0;
485 priv->rows_reordered_handler = 0;
486 priv->fetch_image_redraw_handler = 0;
487 priv->progress_hint = FALSE;
488 priv->fetching_images = 0;
490 priv->optimized_view = FALSE;
491 priv->purge_timeout = 0;
492 priv->remove_attachment_banner = NULL;
493 priv->msg_uid = NULL;
494 priv->other_body = NULL;
496 priv->sighandlers = NULL;
499 init_window (MODEST_MSG_VIEW_WINDOW(obj));
501 hildon_program_add_window (hildon_program_get_instance(),
504 /* Grab the zoom keys, it will be used for Zoom and not for
506 g_signal_connect (G_OBJECT (obj), "realize",
507 G_CALLBACK (on_realize),
512 update_progress_hint (ModestMsgViewWindow *self)
514 ModestMsgViewWindowPrivate *priv;
515 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
517 if (GTK_WIDGET_VISIBLE (self)) {
518 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self),
519 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
524 set_progress_hint (ModestMsgViewWindow *self,
527 ModestWindowPrivate *parent_priv;
528 ModestMsgViewWindowPrivate *priv;
530 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
532 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
535 /* Sets current progress hint */
536 priv->progress_hint = enabled;
538 update_progress_hint (self);
544 init_window (ModestMsgViewWindow *obj)
546 GtkWidget *main_vbox;
547 ModestMsgViewWindowPrivate *priv;
549 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
551 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
552 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
553 main_vbox = gtk_vbox_new (FALSE, 6);
554 priv->main_scroll = hildon_pannable_area_new ();
555 g_object_set (G_OBJECT (priv->main_scroll),
556 "mov-mode", HILDON_MOVEMENT_MODE_BOTH,
559 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
560 g_object_ref (priv->msg_view);
561 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
562 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
564 /* NULL-ize fields if the window is destroyed */
565 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
567 gtk_widget_show_all (GTK_WIDGET(main_vbox));
571 modest_msg_view_window_disconnect_signals (ModestWindow *self)
573 ModestMsgViewWindowPrivate *priv;
574 GtkWidget *header_view = NULL;
575 GtkWindow *parent_window = NULL;
577 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
579 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
580 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
581 priv->clipboard_change_handler))
582 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
583 priv->clipboard_change_handler);
585 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
586 priv->queue_change_handler))
587 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
588 priv->queue_change_handler);
590 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
591 priv->account_removed_handler))
592 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
593 priv->account_removed_handler);
595 if (priv->header_model) {
596 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
597 priv->row_changed_handler))
598 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
599 priv->row_changed_handler);
601 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
602 priv->row_deleted_handler))
603 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
604 priv->row_deleted_handler);
606 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
607 priv->row_inserted_handler))
608 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
609 priv->row_inserted_handler);
611 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
612 priv->rows_reordered_handler))
613 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
614 priv->rows_reordered_handler);
617 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
618 priv->sighandlers = NULL;
620 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
621 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
622 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
624 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
625 MODEST_HEADER_VIEW_OBSERVER(self));
631 modest_msg_view_window_finalize (GObject *obj)
633 ModestMsgViewWindowPrivate *priv;
635 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
637 /* Sanity check: shouldn't be needed, the window mgr should
638 call this function before */
639 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
640 g_object_unref (priv->msg_view);
642 if (priv->fetch_image_redraw_handler > 0) {
643 g_source_remove (priv->fetch_image_redraw_handler);
644 priv->fetch_image_redraw_handler = 0;
647 if (priv->other_body != NULL) {
648 g_object_unref (priv->other_body);
649 priv->other_body = NULL;
652 if (priv->top_msg != NULL) {
653 g_object_unref (priv->top_msg);
654 priv->top_msg = NULL;
657 if (priv->header_model != NULL) {
658 g_object_unref (priv->header_model);
659 priv->header_model = NULL;
662 if (priv->remove_attachment_banner) {
663 gtk_widget_destroy (priv->remove_attachment_banner);
664 g_object_unref (priv->remove_attachment_banner);
665 priv->remove_attachment_banner = NULL;
668 if (priv->purge_timeout > 0) {
669 g_source_remove (priv->purge_timeout);
670 priv->purge_timeout = 0;
673 if (priv->row_reference) {
674 gtk_tree_row_reference_free (priv->row_reference);
675 priv->row_reference = NULL;
678 if (priv->next_row_reference) {
679 gtk_tree_row_reference_free (priv->next_row_reference);
680 priv->next_row_reference = NULL;
684 g_free (priv->msg_uid);
685 priv->msg_uid = NULL;
688 G_OBJECT_CLASS(parent_class)->finalize (obj);
692 select_next_valid_row (GtkTreeModel *model,
693 GtkTreeRowReference **row_reference,
697 GtkTreeIter tmp_iter;
699 GtkTreePath *next = NULL;
700 gboolean retval = FALSE, finished;
702 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
704 path = gtk_tree_row_reference_get_path (*row_reference);
705 gtk_tree_model_get_iter (model, &tmp_iter, path);
706 gtk_tree_row_reference_free (*row_reference);
707 *row_reference = NULL;
711 TnyHeader *header = NULL;
713 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
714 gtk_tree_model_get (model, &tmp_iter,
715 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
719 if (msg_is_visible (header, is_outbox)) {
720 next = gtk_tree_model_get_path (model, &tmp_iter);
721 *row_reference = gtk_tree_row_reference_new (model, next);
722 gtk_tree_path_free (next);
726 g_object_unref (header);
729 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
730 next = gtk_tree_model_get_path (model, &tmp_iter);
732 /* Ensure that we are not selecting the same */
733 if (gtk_tree_path_compare (path, next) != 0) {
734 gtk_tree_model_get (model, &tmp_iter,
735 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
738 if (msg_is_visible (header, is_outbox)) {
739 *row_reference = gtk_tree_row_reference_new (model, next);
743 g_object_unref (header);
747 /* If we ended up in the same message
748 then there is no valid next
752 gtk_tree_path_free (next);
754 /* If there are no more messages and we don't
755 want to start again in the first one then
756 there is no valid next message */
762 gtk_tree_path_free (path);
767 /* TODO: This should be in _init(), with the parameters as properties. */
769 modest_msg_view_window_construct (ModestMsgViewWindow *self,
770 const gchar *modest_account_name,
771 const gchar *mailbox,
772 const gchar *msg_uid)
775 ModestMsgViewWindowPrivate *priv = NULL;
776 ModestWindowPrivate *parent_priv = NULL;
777 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
778 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
780 obj = G_OBJECT (self);
781 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
782 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
784 priv->msg_uid = g_strdup (msg_uid);
787 parent_priv->menubar = NULL;
789 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
790 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
793 /* Add common dimming rules */
794 modest_dimming_rules_group_add_rules (toolbar_rules_group,
795 modest_msg_view_toolbar_dimming_entries,
796 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
797 MODEST_WINDOW (self));
798 modest_dimming_rules_group_add_rules (clipboard_rules_group,
799 modest_msg_view_clipboard_dimming_entries,
800 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
801 MODEST_WINDOW (self));
803 /* Insert dimming rules group for this window */
804 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
805 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
806 g_object_unref (toolbar_rules_group);
807 g_object_unref (clipboard_rules_group);
809 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
811 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);
812 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
813 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
814 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
815 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
816 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
817 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
818 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
819 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
820 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
821 G_CALLBACK (modest_ui_actions_on_details), obj);
822 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
823 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
824 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
825 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
826 g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
827 G_CALLBACK (on_handle_calendar), obj);
828 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
829 G_CALLBACK (on_fetch_image), obj);
831 g_signal_connect (G_OBJECT (obj), "key-release-event",
832 G_CALLBACK (modest_msg_view_window_key_event),
835 g_signal_connect (G_OBJECT (obj), "key-press-event",
836 G_CALLBACK (modest_msg_view_window_key_event),
839 g_signal_connect (G_OBJECT (obj), "move-focus",
840 G_CALLBACK (on_move_focus), obj);
842 g_signal_connect (G_OBJECT (obj), "map-event",
843 G_CALLBACK (_modest_msg_view_window_map_event),
846 /* Mail Operation Queue */
847 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
849 G_CALLBACK (on_queue_changed),
852 /* Account manager */
853 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
855 G_CALLBACK(on_account_removed),
858 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
859 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
861 /* First add out toolbar ... */
862 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
864 /* ... and later the find toolbar. This way find toolbar will
865 be shown over the other */
866 priv->find_toolbar = hildon_find_toolbar_new (NULL);
867 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
868 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
869 g_signal_connect (G_OBJECT (priv->find_toolbar), "close",
870 G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
871 g_signal_connect (G_OBJECT (priv->find_toolbar), "search",
872 G_CALLBACK (modest_msg_view_window_find_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_find_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->find_toolbar)) {
1588 modest_msg_view_window_find_toolbar_close (obj, data);
1590 modest_msg_view_window_show_find_toolbar (obj, data);
1594 /* Handler for menu option */
1596 modest_msg_view_window_show_find_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->find_toolbar);
1603 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1606 /* Handler for click on the "X" close button in find toolbar */
1608 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1609 ModestMsgViewWindow *obj)
1611 ModestMsgViewWindowPrivate *priv;
1613 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1616 gtk_widget_hide (priv->find_toolbar);
1617 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1621 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1622 ModestMsgViewWindow *obj)
1624 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 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1632 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1634 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1635 g_free (current_search);
1636 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1640 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1642 g_free (priv->last_search);
1643 priv->last_search = g_strdup (current_search);
1644 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1647 hildon_banner_show_information (NULL, NULL,
1648 _HL("ckct_ib_find_no_matches"));
1649 g_free (priv->last_search);
1650 priv->last_search = NULL;
1652 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1655 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1656 hildon_banner_show_information (NULL, NULL,
1657 _HL("ckct_ib_find_search_complete"));
1658 g_free (priv->last_search);
1659 priv->last_search = NULL;
1661 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1665 g_free (current_search);
1670 modest_msg_view_window_set_zoom (ModestWindow *window,
1673 ModestMsgViewWindowPrivate *priv;
1674 ModestWindowPrivate *parent_priv;
1676 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1678 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1679 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1680 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1685 modest_msg_view_window_get_zoom (ModestWindow *window)
1687 ModestMsgViewWindowPrivate *priv;
1689 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1691 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1692 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1696 modest_msg_view_window_zoom_plus (ModestWindow *window)
1699 ModestMsgViewWindowPrivate *priv;
1703 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1704 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1706 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1708 if (zoom_level >= 2.0) {
1709 hildon_banner_show_information (NULL, NULL,
1710 _CS("ckct_ib_max_zoom_level_reached"));
1712 } else if (zoom_level >= 1.5) {
1714 } else if (zoom_level >= 1.2) {
1716 } else if (zoom_level >= 1.0) {
1718 } else if (zoom_level >= 0.8) {
1720 } else if (zoom_level >= 0.5) {
1726 /* set zoom level */
1727 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1728 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1729 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1730 g_free (banner_text);
1731 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1737 modest_msg_view_window_zoom_minus (ModestWindow *window)
1740 ModestMsgViewWindowPrivate *priv;
1744 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1745 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1747 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1749 if (zoom_level <= 0.5) {
1750 hildon_banner_show_information (NULL, NULL,
1751 _CS("ckct_ib_min_zoom_level_reached"));
1753 } else if (zoom_level <= 0.8) {
1755 } else if (zoom_level <= 1.0) {
1757 } else if (zoom_level <= 1.2) {
1759 } else if (zoom_level <= 1.5) {
1761 } else if (zoom_level <= 2.0) {
1767 /* set zoom level */
1768 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1769 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1770 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1771 g_free (banner_text);
1772 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1778 modest_msg_view_window_key_event (GtkWidget *window,
1784 focus = gtk_window_get_focus (GTK_WINDOW (window));
1786 /* for the find toolbar case */
1787 if (focus && GTK_IS_ENTRY (focus)) {
1788 if (event->keyval == GDK_BackSpace) {
1790 copy = gdk_event_copy ((GdkEvent *) event);
1791 gtk_widget_event (focus, copy);
1792 gdk_event_free (copy);
1802 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1805 ModestMsgViewWindowPrivate *priv;
1806 GtkTreeIter tmp_iter;
1807 gboolean is_last_selected;
1809 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1810 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1812 /*if no model (so no rows at all), then virtually we are the last*/
1813 if (!priv->header_model || !priv->row_reference)
1816 if (!gtk_tree_row_reference_valid (priv->row_reference))
1819 path = gtk_tree_row_reference_get_path (priv->row_reference);
1823 is_last_selected = TRUE;
1824 while (is_last_selected) {
1826 gtk_tree_path_next (path);
1827 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1829 gtk_tree_model_get (priv->header_model, &tmp_iter,
1830 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1833 if (msg_is_visible (header, priv->is_outbox))
1834 is_last_selected = FALSE;
1835 g_object_unref(G_OBJECT(header));
1838 gtk_tree_path_free (path);
1839 return is_last_selected;
1843 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1845 ModestMsgViewWindowPrivate *priv;
1847 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1848 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1850 return priv->header_model != NULL;
1854 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1856 ModestMsgViewWindowPrivate *priv;
1858 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1859 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1861 return priv->is_search_result;
1865 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1867 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1869 if (!check_outbox) {
1872 ModestTnySendQueueStatus status;
1873 status = modest_tny_all_send_queues_get_msg_status (header);
1874 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1875 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1880 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1883 ModestMsgViewWindowPrivate *priv;
1884 gboolean is_first_selected;
1885 GtkTreeIter tmp_iter;
1887 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1888 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1890 /*if no model (so no rows at all), then virtually we are the first*/
1891 if (!priv->header_model || !priv->row_reference)
1894 if (!gtk_tree_row_reference_valid (priv->row_reference))
1897 path = gtk_tree_row_reference_get_path (priv->row_reference);
1901 is_first_selected = TRUE;
1902 while (is_first_selected) {
1904 if(!gtk_tree_path_prev (path))
1906 /* Here the 'if' is needless for logic, but let make sure
1907 * iter is valid for gtk_tree_model_get. */
1908 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1910 gtk_tree_model_get (priv->header_model, &tmp_iter,
1911 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1914 if (msg_is_visible (header, priv->is_outbox))
1915 is_first_selected = FALSE;
1916 g_object_unref(G_OBJECT(header));
1919 gtk_tree_path_free (path);
1920 return is_first_selected;
1927 GtkTreeRowReference *row_reference;
1931 message_reader_performer (gboolean canceled,
1933 GtkWindow *parent_window,
1934 TnyAccount *account,
1937 ModestMailOperation *mail_op = NULL;
1938 MsgReaderInfo *info;
1940 info = (MsgReaderInfo *) user_data;
1941 if (canceled || err) {
1942 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1943 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1947 /* Register the header - it'll be unregistered in the callback */
1949 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1951 /* New mail operation */
1952 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1953 modest_ui_actions_disk_operations_error_handler,
1956 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1958 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1960 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1961 g_object_unref (mail_op);
1963 /* Update dimming rules */
1964 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1965 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1968 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1969 g_free (info->msg_uid);
1971 g_object_unref (info->folder);
1973 g_object_unref (info->header);
1974 g_slice_free (MsgReaderInfo, info);
1979 * Reads the message whose summary item is @header. It takes care of
1980 * several things, among others:
1982 * If the message was not previously downloaded then ask the user
1983 * before downloading. If there is no connection launch the connection
1984 * dialog. Update toolbar dimming rules.
1986 * Returns: TRUE if the mail operation was started, otherwise if the
1987 * user do not want to download the message, or if the user do not
1988 * want to connect, then the operation is not issued
1991 message_reader (ModestMsgViewWindow *window,
1992 ModestMsgViewWindowPrivate *priv,
1994 const gchar *msg_uid,
1996 GtkTreeRowReference *row_reference)
1998 ModestWindowMgr *mgr;
1999 TnyAccount *account = NULL;
2000 MsgReaderInfo *info;
2002 /* We set the header from model while we're loading */
2003 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2004 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
2010 g_object_ref (folder);
2012 mgr = modest_runtime_get_window_mgr ();
2013 /* Msg download completed */
2014 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2016 /* Ask the user if he wants to download the message if
2018 if (!tny_device_is_online (modest_runtime_get_device())) {
2019 GtkResponseType response;
2021 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2022 _("mcen_nc_get_msg"));
2023 if (response == GTK_RESPONSE_CANCEL) {
2024 update_window_title (window);
2029 folder = tny_header_get_folder (header);
2031 info = g_slice_new (MsgReaderInfo);
2032 info->msg_uid = g_strdup (msg_uid);
2034 info->header = g_object_ref (header);
2036 info->header = NULL;
2038 info->folder = g_object_ref (folder);
2040 info->folder = NULL;
2041 if (row_reference) {
2042 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2044 info->row_reference = NULL;
2047 /* Offer the connection dialog if necessary */
2048 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
2050 TNY_FOLDER_STORE (folder),
2051 message_reader_performer,
2054 g_object_unref (folder);
2060 folder = tny_header_get_folder (header);
2063 account = tny_folder_get_account (folder);
2065 info = g_slice_new (MsgReaderInfo);
2066 info->msg_uid = g_strdup (msg_uid);
2068 info->folder = g_object_ref (folder);
2070 info->folder = NULL;
2072 info->header = g_object_ref (header);
2074 info->header = NULL;
2076 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2078 info->row_reference = NULL;
2080 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
2082 g_object_unref (account);
2084 g_object_unref (folder);
2090 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2092 ModestMsgViewWindowPrivate *priv;
2093 GtkTreePath *path= NULL;
2094 GtkTreeIter tmp_iter;
2096 gboolean retval = TRUE;
2097 GtkTreeRowReference *row_reference = NULL;
2099 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2100 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2102 if (!priv->row_reference)
2105 /* Update the next row reference if it's not valid. This could
2106 happen if for example the header which it was pointing to,
2107 was deleted. The best place to do it is in the row-deleted
2108 handler but the tinymail model do not work like the glib
2109 tree models and reports the deletion when the row is still
2111 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2112 if (priv->next_row_reference) {
2113 gtk_tree_row_reference_free (priv->next_row_reference);
2115 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2116 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2117 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2119 priv->next_row_reference = NULL;
2122 if (priv->next_row_reference)
2123 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2127 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2129 gtk_tree_model_get_iter (priv->header_model,
2132 gtk_tree_path_free (path);
2134 gtk_tree_model_get (priv->header_model, &tmp_iter,
2135 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2138 /* Read the message & show it */
2139 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2142 gtk_tree_row_reference_free (row_reference);
2145 g_object_unref (header);
2151 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2153 ModestMsgViewWindowPrivate *priv = NULL;
2155 gboolean finished = FALSE;
2156 gboolean retval = FALSE;
2158 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2159 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2161 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2162 gtk_tree_row_reference_free (priv->row_reference);
2163 priv->row_reference = NULL;
2166 /* Return inmediatly if there is no header model */
2167 if (!priv->header_model || !priv->row_reference)
2170 path = gtk_tree_row_reference_get_path (priv->row_reference);
2171 while (!finished && gtk_tree_path_prev (path)) {
2175 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2176 gtk_tree_model_get (priv->header_model, &iter,
2177 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2181 if (msg_is_visible (header, priv->is_outbox)) {
2182 GtkTreeRowReference *row_reference;
2183 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2184 /* Read the message & show it */
2185 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2186 gtk_tree_row_reference_free (row_reference);
2190 g_object_unref (header);
2194 gtk_tree_path_free (path);
2199 view_msg_cb (ModestMailOperation *mail_op,
2206 ModestMsgViewWindow *self = NULL;
2207 ModestMsgViewWindowPrivate *priv = NULL;
2208 GtkTreeRowReference *row_reference = NULL;
2210 /* Unregister the header (it was registered before creating the mail operation) */
2211 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2213 row_reference = (GtkTreeRowReference *) user_data;
2216 gtk_tree_row_reference_free (row_reference);
2217 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2219 /* Restore window title */
2220 update_window_title (self);
2221 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2222 g_object_unref (self);
2227 /* If there was any error */
2228 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2230 gtk_tree_row_reference_free (row_reference);
2231 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2233 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2234 /* First we check if the parent is a folder window */
2235 if (priv->msg_uid && !modest_hildon2_window_mgr_get_folder_window (MODEST_HILDON2_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2237 TnyAccount *account = NULL;
2238 GtkWidget *header_window = NULL;
2240 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2242 /* Get the account */
2244 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2247 if (is_merge || account) {
2248 TnyFolder *folder = NULL;
2250 /* Try to get the message, if it's already downloaded
2251 we don't need to connect */
2253 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2256 ModestTnyAccountStore *account_store;
2257 ModestTnyLocalFoldersAccount *local_folders_account;
2259 account_store = modest_runtime_get_account_store ();
2260 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2261 modest_tny_account_store_get_local_folders_account (account_store));
2262 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2263 g_object_unref (local_folders_account);
2265 if (account) g_object_unref (account);
2268 header_window = (GtkWidget *)
2269 modest_header_window_new (
2271 modest_window_get_active_account (MODEST_WINDOW (self)),
2272 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2273 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2274 MODEST_WINDOW (header_window),
2276 gtk_widget_destroy (GTK_WIDGET (header_window));
2278 gtk_widget_show_all (GTK_WIDGET (header_window));
2280 g_object_unref (folder);
2286 /* Restore window title */
2287 update_window_title (self);
2288 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2289 g_object_unref (self);
2294 /* Get the window */
2295 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2296 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2297 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2299 /* Update the row reference */
2300 if (priv->row_reference != NULL) {
2301 gtk_tree_row_reference_free (priv->row_reference);
2302 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2303 if (priv->next_row_reference != NULL) {
2304 gtk_tree_row_reference_free (priv->next_row_reference);
2306 if (priv->row_reference) {
2307 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2308 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2310 priv->next_row_reference = NULL;
2314 /* Mark header as read */
2315 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN)) {
2318 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2319 uid = modest_tny_folder_get_header_unique_id (header);
2320 modest_platform_emit_msg_read_changed_signal (uid, TRUE);
2324 /* Set new message */
2325 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2326 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2327 modest_msg_view_window_update_priority (self);
2328 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2329 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2330 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2333 /* Set the new message uid of the window */
2334 if (priv->msg_uid) {
2335 g_free (priv->msg_uid);
2336 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2339 /* Notify the observers */
2340 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2341 0, priv->header_model, priv->row_reference);
2343 /* Sync the flags if the message is not opened from a header
2344 model, i.e, if it's opened from a notification */
2345 if (!priv->header_model)
2349 g_object_unref (self);
2351 gtk_tree_row_reference_free (row_reference);
2355 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2357 ModestMsgViewWindowPrivate *priv;
2359 TnyFolderType folder_type;
2361 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2363 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2365 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2369 folder = tny_msg_get_folder (msg);
2371 folder_type = modest_tny_folder_guess_folder_type (folder);
2372 g_object_unref (folder);
2374 g_object_unref (msg);
2382 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2384 ModestMsgViewWindowPrivate *priv;
2385 TnyHeader *header = NULL;
2386 TnyHeaderFlags flags = 0;
2388 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2390 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2392 GtkTreePath *path = NULL;
2394 path = gtk_tree_row_reference_get_path (priv->row_reference);
2395 g_return_if_fail (path != NULL);
2396 gtk_tree_model_get_iter (priv->header_model,
2398 gtk_tree_row_reference_get_path (priv->row_reference));
2400 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2402 gtk_tree_path_free (path);
2405 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2407 header = tny_msg_get_header (msg);
2408 g_object_unref (msg);
2413 flags = tny_header_get_flags (header);
2414 g_object_unref(G_OBJECT(header));
2417 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2422 toolbar_resize (ModestMsgViewWindow *self)
2424 ModestMsgViewWindowPrivate *priv = NULL;
2425 ModestWindowPrivate *parent_priv = NULL;
2427 gint static_button_size;
2428 ModestWindowMgr *mgr;
2430 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2431 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2432 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2434 mgr = modest_runtime_get_window_mgr ();
2435 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2437 if (parent_priv->toolbar) {
2438 /* Set expandable and homogeneous tool buttons */
2439 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2440 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2441 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2442 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2443 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2444 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2445 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2446 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2447 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2448 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2449 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2450 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2451 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2452 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2453 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2454 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2455 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2456 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2457 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2462 modest_msg_view_window_show_toolbar (ModestWindow *self,
2463 gboolean show_toolbar)
2465 ModestMsgViewWindowPrivate *priv = NULL;
2466 ModestWindowPrivate *parent_priv;
2468 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2469 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2471 /* Set optimized view status */
2472 priv->optimized_view = !show_toolbar;
2474 if (!parent_priv->toolbar) {
2475 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2477 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2478 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2480 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2481 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2482 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2485 hildon_window_add_toolbar (HILDON_WINDOW (self),
2486 GTK_TOOLBAR (parent_priv->toolbar));
2491 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2492 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2493 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2495 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2496 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2497 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2499 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2502 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2503 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2508 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2510 ModestMsgViewWindow *window)
2512 if (!GTK_WIDGET_VISIBLE (window))
2515 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2519 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2521 ModestMsgViewWindowPrivate *priv;
2523 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2524 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2526 return priv->progress_hint;
2530 observers_empty (ModestMsgViewWindow *self)
2533 ModestMsgViewWindowPrivate *priv;
2534 gboolean is_empty = TRUE;
2535 guint pending_ops = 0;
2537 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2538 tmp = priv->progress_widgets;
2540 /* Check all observers */
2541 while (tmp && is_empty) {
2542 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2543 is_empty = pending_ops == 0;
2545 tmp = g_slist_next(tmp);
2552 on_account_removed (TnyAccountStore *account_store,
2553 TnyAccount *account,
2556 /* Do nothing if it's a transport account, because we only
2557 show the messages of a store account */
2558 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2559 const gchar *parent_acc = NULL;
2560 const gchar *our_acc = NULL;
2562 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2563 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2565 /* Close this window if I'm showing a message of the removed account */
2566 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2567 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2572 on_mail_operation_started (ModestMailOperation *mail_op,
2575 ModestMsgViewWindow *self;
2576 ModestMailOperationTypeOperation op_type;
2578 ModestMsgViewWindowPrivate *priv;
2579 GObject *source = NULL;
2581 self = MODEST_MSG_VIEW_WINDOW (user_data);
2582 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2583 op_type = modest_mail_operation_get_type_operation (mail_op);
2584 tmp = priv->progress_widgets;
2585 source = modest_mail_operation_get_source(mail_op);
2586 if (G_OBJECT (self) == source) {
2587 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2588 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2589 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2590 set_progress_hint (self, TRUE);
2592 modest_progress_object_add_operation (
2593 MODEST_PROGRESS_OBJECT (tmp->data),
2595 tmp = g_slist_next (tmp);
2599 g_object_unref (source);
2601 /* Update dimming rules */
2602 check_dimming_rules_after_change (self);
2606 on_mail_operation_finished (ModestMailOperation *mail_op,
2609 ModestMsgViewWindow *self;
2610 ModestMailOperationTypeOperation op_type;
2612 ModestMsgViewWindowPrivate *priv;
2614 self = MODEST_MSG_VIEW_WINDOW (user_data);
2615 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2616 op_type = modest_mail_operation_get_type_operation (mail_op);
2617 tmp = priv->progress_widgets;
2619 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2620 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2621 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2623 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2625 tmp = g_slist_next (tmp);
2628 /* If no more operations are being observed, NORMAL mode is enabled again */
2629 if (observers_empty (self)) {
2630 set_progress_hint (self, FALSE);
2634 /* Update dimming rules. We have to do this right here
2635 and not in view_msg_cb because at that point the
2636 transfer mode is still enabled so the dimming rule
2637 won't let the user delete the message that has been
2638 readed for example */
2639 check_dimming_rules_after_change (self);
2643 on_queue_changed (ModestMailOperationQueue *queue,
2644 ModestMailOperation *mail_op,
2645 ModestMailOperationQueueNotification type,
2646 ModestMsgViewWindow *self)
2648 ModestMsgViewWindowPrivate *priv;
2650 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2652 /* If this operations was created by another window, do nothing */
2653 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2656 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2657 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2659 "operation-started",
2660 G_CALLBACK (on_mail_operation_started),
2662 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2664 "operation-finished",
2665 G_CALLBACK (on_mail_operation_finished),
2667 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2668 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2670 "operation-started");
2671 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2673 "operation-finished");
2678 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2680 ModestMsgViewWindowPrivate *priv;
2681 TnyList *selected_attachments = NULL;
2683 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2684 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2686 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2687 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2689 return selected_attachments;
2693 ModestMsgViewWindow *self;
2695 gchar *attachment_uid;
2696 } DecodeAsyncHelper;
2699 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2705 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2706 const gchar *content_type;
2707 ModestMsgViewWindowPrivate *priv;
2709 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2711 if (cancelled || err) {
2714 if ((err->domain == TNY_ERROR_DOMAIN) &&
2715 (err->code == TNY_IO_ERROR_WRITE) &&
2716 (errno == ENOSPC)) {
2717 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2719 msg = g_strdup (_("mail_ib_file_operation_failed"));
2721 modest_platform_information_banner (NULL, NULL, msg);
2727 /* It could happen that the window was closed. So we
2728 assume it is a cancelation */
2729 if (!GTK_WIDGET_VISIBLE (helper->self))
2732 /* Remove the progress hint */
2733 set_progress_hint (helper->self, FALSE);
2735 content_type = tny_mime_part_get_content_type (mime_part);
2736 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2737 ModestWindowMgr *mgr;
2738 ModestWindow *msg_win = NULL;
2741 const gchar *mailbox;
2742 TnyStream *file_stream;
2745 fd = g_open (helper->file_path, O_RDONLY, 0644);
2748 file_stream = tny_fs_stream_new (fd);
2750 mgr = modest_runtime_get_window_mgr ();
2752 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2753 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2756 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2758 msg = tny_camel_msg_new ();
2759 tny_camel_msg_parse (msg, file_stream);
2762 top_msg = g_object_ref (priv->top_msg);
2764 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2766 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2767 account, mailbox, helper->attachment_uid);
2768 if (top_msg) g_object_unref (top_msg);
2769 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2770 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2771 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2772 gtk_widget_show_all (GTK_WIDGET (msg_win));
2774 gtk_widget_destroy (GTK_WIDGET (msg_win));
2775 g_object_unref (msg);
2776 g_object_unref (file_stream);
2778 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2783 /* make the file read-only */
2784 g_chmod(helper->file_path, 0444);
2786 /* Activate the file */
2787 modest_platform_activate_file (helper->file_path, content_type);
2792 g_object_unref (helper->self);
2793 g_free (helper->file_path);
2794 g_free (helper->attachment_uid);
2795 g_slice_free (DecodeAsyncHelper, helper);
2799 view_attachment_connect_handler (gboolean canceled,
2801 GtkWindow *parent_window,
2802 TnyAccount *account,
2806 if (canceled || err) {
2807 g_object_unref (part);
2811 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2813 g_object_unref (part);
2817 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2818 TnyMimePart *mime_part)
2820 ModestMsgViewWindowPrivate *priv;
2821 const gchar *msg_uid;
2822 gchar *attachment_uid = NULL;
2823 gint attachment_index = 0;
2824 TnyList *attachments;
2826 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2827 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2828 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2830 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2831 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2832 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2833 g_object_unref (attachments);
2835 if (msg_uid && attachment_index >= 0) {
2836 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2839 if (mime_part == NULL) {
2840 gboolean error = FALSE;
2841 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2842 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2844 } else if (tny_list_get_length (selected_attachments) > 1) {
2845 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2849 iter = tny_list_create_iterator (selected_attachments);
2850 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2851 g_object_unref (iter);
2853 if (selected_attachments)
2854 g_object_unref (selected_attachments);
2859 g_object_ref (mime_part);
2862 if (tny_mime_part_is_purged (mime_part))
2865 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2866 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2868 TnyAccount *account;
2870 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2872 /* Get the account */
2874 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2877 if (!tny_device_is_online (modest_runtime_get_device())) {
2878 modest_platform_connect_and_perform (GTK_WINDOW (window),
2880 TNY_ACCOUNT (account),
2881 (ModestConnectedPerformer) view_attachment_connect_handler,
2882 g_object_ref (mime_part));
2887 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2888 gchar *filepath = NULL;
2889 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2890 gboolean show_error_banner = FALSE;
2891 TnyFsStream *temp_stream = NULL;
2892 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2895 if (temp_stream != NULL) {
2896 ModestAccountMgr *mgr;
2897 DecodeAsyncHelper *helper;
2898 gboolean decode_in_provider;
2899 ModestProtocol *protocol;
2900 const gchar *account;
2902 /* Activate progress hint */
2903 set_progress_hint (window, TRUE);
2905 helper = g_slice_new0 (DecodeAsyncHelper);
2906 helper->self = g_object_ref (window);
2907 helper->file_path = g_strdup (filepath);
2908 helper->attachment_uid = g_strdup (attachment_uid);
2910 decode_in_provider = FALSE;
2911 mgr = modest_runtime_get_account_mgr ();
2912 account = modest_window_get_active_account (MODEST_WINDOW (window));
2913 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2914 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2916 uri = g_strconcat ("file://", filepath, NULL);
2917 decode_in_provider =
2918 modest_account_protocol_decode_part_to_stream_async (
2919 MODEST_ACCOUNT_PROTOCOL (protocol),
2922 TNY_STREAM (temp_stream),
2923 on_decode_to_stream_async_handler,
2930 if (!decode_in_provider)
2931 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2932 on_decode_to_stream_async_handler,
2935 g_object_unref (temp_stream);
2936 /* NOTE: files in the temporary area will be automatically
2937 * cleaned after some time if they are no longer in use */
2940 const gchar *content_type;
2941 /* the file may already exist but it isn't writable,
2942 * let's try to open it anyway */
2943 content_type = tny_mime_part_get_content_type (mime_part);
2944 modest_platform_activate_file (filepath, content_type);
2946 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2947 show_error_banner = TRUE;
2952 if (show_error_banner)
2953 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2954 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2955 ModestWindowMgr *mgr;
2956 ModestWindow *msg_win = NULL;
2957 TnyMsg *current_msg;
2961 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2962 mgr = modest_runtime_get_window_mgr ();
2963 header = tny_msg_get_header (TNY_MSG (current_msg));
2964 found = modest_window_mgr_find_registered_message_uid (mgr,
2969 g_debug ("window for this body is already being created");
2973 /* it's not found, so create a new window for it */
2974 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2975 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2976 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2978 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2981 top_msg = g_object_ref (priv->top_msg);
2983 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2985 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
2986 account, mailbox, attachment_uid);
2988 if (top_msg) g_object_unref (top_msg);
2990 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2991 modest_window_get_zoom (MODEST_WINDOW (window)));
2992 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2993 gtk_widget_show_all (GTK_WIDGET (msg_win));
2995 gtk_widget_destroy (GTK_WIDGET (msg_win));
2997 g_object_unref (current_msg);
2999 /* message attachment */
3000 TnyHeader *header = NULL;
3001 ModestWindowMgr *mgr;
3002 ModestWindow *msg_win = NULL;
3005 header = tny_msg_get_header (TNY_MSG (mime_part));
3006 mgr = modest_runtime_get_window_mgr ();
3007 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3010 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3011 * thus, we don't do anything */
3012 g_debug ("window for is already being created");
3015 /* it's not found, so create a new window for it */
3016 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3017 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3018 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3020 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3022 top_msg = g_object_ref (priv->top_msg);
3024 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3025 msg_win = modest_msg_view_window_new_for_attachment (
3026 TNY_MSG (mime_part), top_msg, account,
3027 mailbox, attachment_uid);
3028 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3029 modest_window_get_zoom (MODEST_WINDOW (window)));
3030 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3031 gtk_widget_show_all (GTK_WIDGET (msg_win));
3033 gtk_widget_destroy (GTK_WIDGET (msg_win));
3039 g_free (attachment_uid);
3041 g_object_unref (mime_part);
3053 GnomeVFSResult result;
3055 ModestMsgViewWindow *window;
3058 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3059 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3060 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3061 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3064 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3068 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3069 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3070 g_free (pair->filename);
3071 g_object_unref (pair->part);
3072 g_slice_free (SaveMimePartPair, pair);
3074 g_list_free (info->pairs);
3077 g_object_unref (info->window);
3078 info->window = NULL;
3080 g_slice_free (SaveMimePartInfo, info);
3085 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3087 /* This is a GDK lock because we are an idle callback and
3088 * hildon_banner_show_information is or does Gtk+ code */
3090 gdk_threads_enter (); /* CHECKED */
3091 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3093 } else if (info->result == GNOME_VFS_OK) {
3094 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
3095 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3098 /* Check if the uri belongs to the external mmc */
3099 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3100 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3102 msg = g_strdup (_KR("cerm_memory_card_full"));
3103 modest_platform_information_banner (NULL, NULL, msg);
3106 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
3108 set_progress_hint (info->window, FALSE);
3109 save_mime_part_info_free (info, FALSE);
3110 gdk_threads_leave (); /* CHECKED */
3116 save_mime_part_to_file_connect_handler (gboolean canceled,
3118 GtkWindow *parent_window,
3119 TnyAccount *account,
3120 SaveMimePartInfo *info)
3122 if (canceled || err) {
3123 if (canceled && !err) {
3124 info->result = GNOME_VFS_ERROR_CANCELLED;
3126 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3128 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3133 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3136 TnyAccount *account;
3137 ModestMsgViewWindowPrivate *priv;
3139 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3141 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3144 /* Get the account */
3146 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3149 modest_platform_connect_and_perform (GTK_WINDOW (info->window),
3151 TNY_ACCOUNT (account),
3152 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3156 g_object_unref (account);
3162 save_mime_part_to_file (SaveMimePartInfo *info)
3164 GnomeVFSHandle *handle;
3166 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3168 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3169 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3170 gboolean check_online = TRUE;
3171 ModestMsgViewWindowPrivate *priv = NULL;
3173 /* Check if we really need to connect to save the mime part */
3174 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3175 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3176 check_online = FALSE;
3178 TnyAccountStore *acc_store;
3179 TnyAccount *account = NULL;
3181 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3182 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3185 if (tny_account_get_connection_status (account) ==
3186 TNY_CONNECTION_STATUS_CONNECTED)
3187 check_online = FALSE;
3188 g_object_unref (account);
3190 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3195 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3200 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3201 if (info->result == GNOME_VFS_OK) {
3202 GError *error = NULL;
3203 gboolean decode_in_provider;
3205 ModestAccountMgr *mgr;
3206 const gchar *account;
3207 ModestProtocol *protocol = NULL;
3209 stream = tny_vfs_stream_new (handle);
3211 decode_in_provider = FALSE;
3212 mgr = modest_runtime_get_account_mgr ();
3213 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3214 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3215 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3216 decode_in_provider =
3217 modest_account_protocol_decode_part_to_stream (
3218 MODEST_ACCOUNT_PROTOCOL (protocol),
3226 if (!decode_in_provider)
3227 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3230 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3232 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3233 (error->code == TNY_IO_ERROR_WRITE) &&
3234 (errno == ENOSPC)) {
3235 info->result = GNOME_VFS_ERROR_NO_SPACE;
3237 info->result = GNOME_VFS_ERROR_IO;
3240 g_object_unref (G_OBJECT (stream));
3242 g_warning ("Could not create save attachment %s: %s\n",
3243 pair->filename, gnome_vfs_result_to_string (info->result));
3246 /* Go on saving remaining files */
3247 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3248 if (info->pairs != NULL) {
3249 save_mime_part_to_file (info);
3251 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3258 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3259 SaveMimePartInfo *info)
3261 gboolean is_ok = TRUE;
3262 gint replaced_files = 0;
3263 const GList *files = info->pairs;
3264 const GList *iter, *to_replace = NULL;
3266 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3267 SaveMimePartPair *pair = iter->data;
3268 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3270 if (modest_utils_file_exists (unescaped)) {
3272 if (replaced_files == 1)
3277 if (replaced_files) {
3280 if (replaced_files == 1) {
3281 SaveMimePartPair *pair = to_replace->data;
3282 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3283 gchar *escaped_basename, *message;
3285 escaped_basename = g_uri_unescape_string (basename, NULL);
3286 message = g_strdup_printf ("%s\n%s",
3287 _FM("docm_nc_replace_file"),
3288 (escaped_basename) ? escaped_basename : "");
3289 response = modest_platform_run_confirmation_dialog (parent, message);
3291 g_free (escaped_basename);
3293 response = modest_platform_run_confirmation_dialog (parent,
3294 _FM("docm_nc_replace_multiple"));
3296 if (response != GTK_RESPONSE_OK)
3301 save_mime_part_info_free (info, TRUE);
3303 /* Start progress and launch thread */
3304 set_progress_hint (info->window, TRUE);
3305 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3310 typedef struct _SaveAttachmentsInfo {
3311 TnyList *attachments_list;
3312 ModestMsgViewWindow *window;
3313 } SaveAttachmentsInfo;
3316 save_attachments_response (GtkDialog *dialog,
3320 TnyList *mime_parts;
3322 GList *files_to_save = NULL;
3323 gchar *current_folder;
3324 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3326 mime_parts = TNY_LIST (sa_info->attachments_list);
3328 if (arg1 != GTK_RESPONSE_OK)
3331 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3332 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3333 if (current_folder && *current_folder != '\0') {
3335 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3336 current_folder,&err);
3338 g_debug ("Error storing latest used folder: %s", err->message);
3342 g_free (current_folder);
3344 if (!modest_utils_folder_writable (chooser_uri)) {
3345 const gchar *err_msg;
3347 #ifdef MODEST_PLATFORM_MAEMO
3348 if (modest_maemo_utils_in_usb_mode ()) {
3349 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3351 err_msg = _FM("sfil_ib_readonly_location");
3354 err_msg = _FM("sfil_ib_readonly_location");
3356 hildon_banner_show_information (NULL, NULL, err_msg);
3360 iter = tny_list_create_iterator (mime_parts);
3361 while (!tny_iterator_is_done (iter)) {
3362 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3364 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3365 !tny_mime_part_is_purged (mime_part) &&
3366 (tny_mime_part_get_filename (mime_part) != NULL)) {
3367 SaveMimePartPair *pair;
3369 pair = g_slice_new0 (SaveMimePartPair);
3371 if (tny_list_get_length (mime_parts) > 1) {
3373 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3374 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3377 pair->filename = g_strdup (chooser_uri);
3379 pair->part = mime_part;
3380 files_to_save = g_list_prepend (files_to_save, pair);
3382 tny_iterator_next (iter);
3384 g_object_unref (iter);
3387 if (files_to_save != NULL) {
3388 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3389 info->pairs = files_to_save;
3390 info->result = TRUE;
3391 info->uri = g_strdup (chooser_uri);
3392 info->window = g_object_ref (sa_info->window);
3393 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3395 g_free (chooser_uri);
3398 /* Free and close the dialog */
3399 g_object_unref (mime_parts);
3400 g_object_unref (sa_info->window);
3401 g_slice_free (SaveAttachmentsInfo, sa_info);
3402 gtk_widget_destroy (GTK_WIDGET (dialog));
3406 msg_is_attachment (TnyList *mime_parts)
3409 gboolean retval = FALSE;
3411 if (tny_list_get_length (mime_parts) > 1)
3414 iter = tny_list_create_iterator (mime_parts);
3416 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3418 if (TNY_IS_MSG (part))
3420 g_object_unref (part);
3422 g_object_unref (iter);
3428 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3429 TnyList *mime_parts)
3431 ModestMsgViewWindowPrivate *priv;
3432 GtkWidget *save_dialog = NULL;
3433 gchar *conf_folder = NULL;
3434 gchar *filename = NULL;
3435 gchar *save_multiple_str = NULL;
3436 const gchar *root_folder = "file:///";
3438 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3441 if (mime_parts == NULL) {
3442 gboolean allow_msgs = FALSE;
3444 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3445 * selection available */
3446 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3448 /* Check if the message is composed by an unique MIME
3449 part whose content disposition is attachment. There
3450 could be messages like this:
3452 Date: Tue, 12 Jan 2010 20:40:59 +0000
3453 From: <sender@example.org>
3454 To: <recipient@example.org>
3456 Content-Type: image/jpeg
3457 Content-Disposition: attachment; filename="bug7718.jpeg"
3459 whose unique MIME part is the message itself whose
3460 content disposition is attachment
3462 if (mime_parts && msg_is_attachment (mime_parts))
3466 !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, allow_msgs)) {
3467 g_object_unref (mime_parts);
3470 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3472 g_object_unref (mime_parts);
3478 g_object_ref (mime_parts);
3481 /* prepare dialog */
3482 if (tny_list_get_length (mime_parts) == 1) {
3484 /* only one attachment selected */
3485 iter = tny_list_create_iterator (mime_parts);
3486 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3487 g_object_unref (iter);
3488 if (!modest_tny_mime_part_is_msg (mime_part) &&
3489 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3490 !tny_mime_part_is_purged (mime_part)) {
3491 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3493 /* TODO: show any error? */
3494 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3495 g_object_unref (mime_parts);
3498 g_object_unref (mime_part);
3500 gint num = tny_list_get_length (mime_parts);
3501 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3502 "sfil_va_number_of_objects_attachment",
3503 "sfil_va_number_of_objects_attachments",
3507 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
3508 GTK_FILE_CHOOSER_ACTION_SAVE);
3510 /* Get last used folder */
3511 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3512 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3514 /* File chooser stops working if we select "file:///" as current folder */
3515 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3516 g_free (conf_folder);
3520 if (conf_folder && conf_folder[0] != '\0') {
3521 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3524 /* Set the default folder to documents folder */
3525 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3528 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3530 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3531 g_free (docs_folder);
3533 g_free (conf_folder);
3537 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3542 /* if multiple, set multiple string */
3543 if (save_multiple_str) {
3544 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3545 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3546 g_free (save_multiple_str);
3549 /* We must run this asynchronously, because the hildon dialog
3550 performs a gtk_dialog_run by itself which leads to gdk
3552 SaveAttachmentsInfo *sa_info;
3553 sa_info = g_slice_new (SaveAttachmentsInfo);
3554 sa_info->attachments_list = mime_parts;
3555 sa_info->window = g_object_ref (window);
3556 g_signal_connect (save_dialog, "response",
3557 G_CALLBACK (save_attachments_response), sa_info);
3559 gtk_widget_show_all (save_dialog);
3563 show_remove_attachment_information (gpointer userdata)
3565 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3566 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3568 /* We're outside the main lock */
3569 gdk_threads_enter ();
3571 if (priv->remove_attachment_banner != NULL) {
3572 gtk_widget_destroy (priv->remove_attachment_banner);
3573 g_object_unref (priv->remove_attachment_banner);
3576 priv->remove_attachment_banner = g_object_ref (
3577 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3579 gdk_threads_leave ();
3585 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3587 ModestMsgViewWindowPrivate *priv;
3588 TnyList *mime_parts = NULL, *tmp;
3589 gchar *confirmation_message;
3595 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3596 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3598 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3599 * because we don't have selection
3601 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3603 /* Remove already purged messages from mime parts list. We use
3604 a copy of the list to remove items in the original one */
3605 tmp = tny_list_copy (mime_parts);
3606 iter = tny_list_create_iterator (tmp);
3607 while (!tny_iterator_is_done (iter)) {
3608 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3609 if (tny_mime_part_is_purged (part))
3610 tny_list_remove (mime_parts, (GObject *) part);
3612 g_object_unref (part);
3613 tny_iterator_next (iter);
3615 g_object_unref (tmp);
3616 g_object_unref (iter);
3618 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3619 tny_list_get_length (mime_parts) == 0) {
3620 g_object_unref (mime_parts);
3624 n_attachments = tny_list_get_length (mime_parts);
3625 if (n_attachments == 1) {
3629 iter = tny_list_create_iterator (mime_parts);
3630 part = (TnyMimePart *) tny_iterator_get_current (iter);
3631 g_object_unref (iter);
3632 if (modest_tny_mime_part_is_msg (part)) {
3634 header = tny_msg_get_header (TNY_MSG (part));
3635 filename = tny_header_dup_subject (header);
3636 g_object_unref (header);
3637 if (filename == NULL)
3638 filename = g_strdup (_("mail_va_no_subject"));
3640 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3642 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3644 g_object_unref (part);
3646 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3647 "mcen_nc_purge_files_text",
3648 n_attachments), n_attachments);
3650 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3651 confirmation_message);
3652 g_free (confirmation_message);
3654 if (response != GTK_RESPONSE_OK) {
3655 g_object_unref (mime_parts);
3659 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3661 iter = tny_list_create_iterator (mime_parts);
3662 while (!tny_iterator_is_done (iter)) {
3665 part = (TnyMimePart *) tny_iterator_get_current (iter);
3666 tny_mime_part_set_purged (TNY_MIME_PART (part));
3667 g_object_unref (part);
3668 tny_iterator_next (iter);
3670 g_object_unref (iter);
3672 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3673 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3674 tny_msg_rewrite_cache (msg);
3675 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3676 g_object_unref (msg);
3677 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3679 g_object_unref (mime_parts);
3681 if (priv->purge_timeout > 0) {
3682 g_source_remove (priv->purge_timeout);
3683 priv->purge_timeout = 0;
3686 if (priv->remove_attachment_banner) {
3687 gtk_widget_destroy (priv->remove_attachment_banner);
3688 g_object_unref (priv->remove_attachment_banner);
3689 priv->remove_attachment_banner = NULL;
3695 update_window_title (ModestMsgViewWindow *window)
3697 ModestMsgViewWindowPrivate *priv;
3699 TnyHeader *header = NULL;
3700 gchar *subject = NULL;
3702 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3704 /* Note that if the window is closed while we're retrieving
3705 the message, this widget could de deleted */
3706 if (!priv->msg_view)
3709 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3711 if (priv->other_body) {
3714 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3716 g_strstrip (description);
3717 subject = description;
3719 } else if (msg != NULL) {
3720 header = tny_msg_get_header (msg);
3721 subject = tny_header_dup_subject (header);
3722 g_object_unref (header);
3723 g_object_unref (msg);
3726 if ((subject == NULL)||(subject[0] == '\0')) {
3728 subject = g_strdup (_("mail_va_no_subject"));
3731 gtk_window_set_title (GTK_WINDOW (window), subject);
3736 on_move_focus (GtkWidget *widget,
3737 GtkDirectionType direction,
3740 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3744 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3746 GnomeVFSResult result;
3747 GnomeVFSHandle *handle = NULL;
3748 GnomeVFSFileInfo *info = NULL;
3751 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3752 if (result != GNOME_VFS_OK) {
3757 info = gnome_vfs_file_info_new ();
3758 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3759 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3760 /* We put a "safe" default size for going to cache */
3761 *expected_size = (300*1024);
3763 *expected_size = info->size;
3765 gnome_vfs_file_info_unref (info);
3767 stream = tny_vfs_stream_new (handle);
3776 TnyStream *output_stream;
3777 GtkWidget *msg_view;
3782 on_fetch_image_timeout_refresh_view (gpointer userdata)
3784 ModestMsgViewWindowPrivate *priv;
3786 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3787 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3788 /* Note that priv->msg_view is set to NULL when this window is
3790 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3791 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3793 priv->fetch_image_redraw_handler = 0;
3794 g_object_unref (userdata);
3799 on_fetch_image_idle_refresh_view (gpointer userdata)
3802 FetchImageData *fidata = (FetchImageData *) userdata;
3804 gdk_threads_enter ();
3805 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3806 ModestMsgViewWindowPrivate *priv;
3808 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3809 priv->fetching_images--;
3810 if (priv->fetch_image_redraw_handler == 0) {
3811 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3815 gdk_threads_leave ();
3817 g_object_unref (fidata->msg_view);
3818 g_object_unref (fidata->window);
3819 g_slice_free (FetchImageData, fidata);
3824 on_fetch_image_thread (gpointer userdata)
3826 FetchImageData *fidata = (FetchImageData *) userdata;
3827 TnyStreamCache *cache;
3828 TnyStream *cache_stream;
3830 cache = modest_runtime_get_images_cache ();
3832 tny_stream_cache_get_stream (cache,
3834 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3835 (gpointer) fidata->uri);
3836 g_free (fidata->cache_id);
3837 g_free (fidata->uri);
3839 if (cache_stream != NULL) {
3842 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3845 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3846 if (G_UNLIKELY (nb_read < 0)) {
3848 } else if (G_LIKELY (nb_read > 0)) {
3849 gssize nb_written = 0;
3851 while (G_UNLIKELY (nb_written < nb_read)) {
3854 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3855 nb_read - nb_written);
3856 if (G_UNLIKELY (len < 0))
3862 tny_stream_close (cache_stream);
3863 g_object_unref (cache_stream);
3866 tny_stream_close (fidata->output_stream);
3867 g_object_unref (fidata->output_stream);
3869 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3875 on_fetch_image (ModestMsgView *msgview,
3878 ModestMsgViewWindow *window)
3880 const gchar *current_account;
3881 ModestMsgViewWindowPrivate *priv;
3882 FetchImageData *fidata;
3884 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3886 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3888 fidata = g_slice_new0 (FetchImageData);
3889 fidata->msg_view = g_object_ref (msgview);
3890 fidata->window = g_object_ref (window);
3891 fidata->uri = g_strdup (uri);
3892 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3893 fidata->output_stream = g_object_ref (stream);
3895 priv->fetching_images++;
3896 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3897 g_object_unref (fidata->output_stream);
3898 g_free (fidata->cache_id);
3899 g_free (fidata->uri);
3900 g_object_unref (fidata->msg_view);
3901 g_slice_free (FetchImageData, fidata);
3902 tny_stream_close (stream);
3903 priv->fetching_images--;
3904 update_progress_hint (window);
3907 update_progress_hint (window);
3913 setup_menu (ModestMsgViewWindow *self)
3915 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3917 /* Settings menu buttons */
3918 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3919 APP_MENU_CALLBACK (modest_msg_view_window_show_find_toolbar),
3920 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3922 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self),
3923 dngettext(GETTEXT_PACKAGE,
3924 "mcen_me_move_message",
3925 "mcen_me_move_messages",
3928 APP_MENU_CALLBACK (modest_ui_actions_on_move_to),
3929 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3931 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3932 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3933 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3935 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3936 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3937 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3939 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3940 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3941 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3942 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3943 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3944 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3946 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3947 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3948 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3949 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3950 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3951 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3953 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3954 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3955 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3959 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3961 ModestMsgViewWindowPrivate *priv;
3962 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3963 GSList *recipients = NULL;
3966 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3970 header = modest_msg_view_window_get_header (self);
3973 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3974 g_object_unref (header);
3976 recipients = modest_tny_msg_get_all_recipients_list (msg);
3977 g_object_unref (msg);
3981 /* Offer the user to add recipients to the address book */
3982 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3983 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3988 _modest_msg_view_window_map_event (GtkWidget *widget,
3992 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3994 update_progress_hint (self);
4000 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4002 ModestMsgViewWindowPrivate *priv;
4003 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4005 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4009 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4011 ModestMsgViewWindowPrivate *priv;
4012 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4014 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4016 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4020 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4022 ModestMsgViewWindowPrivate *priv;
4023 const gchar *msg_uid;
4024 TnyHeader *header = NULL;
4025 TnyFolder *folder = NULL;
4027 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4029 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4031 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4035 folder = tny_header_get_folder (header);
4036 g_object_unref (header);
4041 msg_uid = modest_msg_view_window_get_message_uid (self);
4043 GtkTreeRowReference *row_reference;
4045 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4046 row_reference = priv->row_reference;
4048 row_reference = NULL;
4050 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4051 g_warning ("Shouldn't happen, trying to reload a message failed");
4054 g_object_unref (folder);
4058 update_branding (ModestMsgViewWindow *self)
4060 const gchar *account;
4061 const gchar *mailbox;
4062 ModestAccountMgr *mgr;
4063 ModestProtocol *protocol = NULL;
4064 gchar *service_name = NULL;
4065 const GdkPixbuf *service_icon = NULL;
4066 ModestMsgViewWindowPrivate *priv;
4068 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4070 account = modest_window_get_active_account (MODEST_WINDOW (self));
4071 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4073 mgr = modest_runtime_get_account_mgr ();
4075 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4076 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4077 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4079 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4080 account, mailbox, MODEST_ICON_SIZE_SMALL);
4084 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4085 g_free (service_name);
4089 sync_flags (ModestMsgViewWindow *self)
4091 TnyHeader *header = NULL;
4093 header = modest_msg_view_window_get_header (self);
4095 TnyMsg *msg = modest_msg_view_window_get_message (self);
4097 header = tny_msg_get_header (msg);
4098 g_object_unref (msg);
4103 TnyFolder *folder = tny_header_get_folder (header);
4106 ModestMailOperation *mail_op;
4108 /* Sync folder, we need this to save the seen flag */
4109 mail_op = modest_mail_operation_new (NULL);
4110 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4112 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4113 g_object_unref (mail_op);
4114 g_object_unref (folder);
4116 g_object_unref (header);
4121 on_realize (GtkWidget *widget,
4124 GdkDisplay *display;
4126 unsigned long val = 1;
4128 display = gdk_drawable_get_display (widget->window);
4129 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4130 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4131 GDK_WINDOW_XID (widget->window), atom,
4132 XA_INTEGER, 32, PropModeReplace,
4133 (unsigned char *) &val, 1);
4139 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4141 const gchar *account_name;
4142 ModestProtocolType proto_type;
4143 ModestProtocol *protocol;
4144 gboolean retval = FALSE;
4146 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4149 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4152 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4155 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4156 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4157 calendar_part, container);