Refactored the code that offers UI to add contacts to address book
[modest] / src / hildon2 / modest-msg-view-window.c
index f81ce01..25659fe 100644 (file)
@@ -67,6 +67,7 @@
 #include <modest-debug.h>
 #include <modest-header-window.h>
 #include <modest-account-protocol.h>
+#include <tny-camel-msg.h>
 
 #define MYDOCS_ENV "MYDOCSDIR"
 #define DOCS_FOLDER ".documents"
@@ -229,7 +230,7 @@ static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
                                                   GdkEvent *event,
                                                   gpointer userdata);
 static void update_branding (ModestMsgViewWindow *self);
-
+static void sync_flags      (ModestMsgViewWindow *self);
 
 /* list my signals */
 enum {
@@ -290,22 +291,48 @@ static void
 save_state (ModestWindow *self)
 {
        modest_widget_memory_save (modest_runtime_get_conf (),
-                                  G_OBJECT(self), 
+                                  G_OBJECT(self),
                                   MODEST_CONF_MSG_VIEW_WINDOW_KEY);
 }
 
-static 
-gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
-                                             GtkScrollType scroll_type,
-                                             gboolean horizontal,
-                                             gpointer userdata)
+static gboolean
+modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
+                                    GtkScrollType scroll_type,
+                                    gboolean horizontal,
+                                    gpointer userdata)
 {
        ModestMsgViewWindowPrivate *priv;
-       gboolean return_value;
+       gint step = 0;
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
-       g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value);
-       return return_value;
+
+       switch (scroll_type) {
+       case GTK_SCROLL_STEP_UP:
+               step = -1;
+               break;
+       case GTK_SCROLL_STEP_DOWN:
+               step = +1;
+               break;
+       case GTK_SCROLL_PAGE_UP:
+               step = -6;
+               break;
+       case GTK_SCROLL_PAGE_DOWN:
+               step = +6;
+               break;
+       case GTK_SCROLL_START:
+               step = -100;
+               break;
+       case GTK_SCROLL_END:
+               step = +100;
+               break;
+       default:
+               step = 0;
+       }
+
+       if (step)
+               modest_maemo_utils_scroll_pannable((HildonPannableArea *) priv->main_scroll, 0, step);
+
+       return (gboolean) step;
 }
 
 static void
@@ -314,7 +341,7 @@ add_scroll_binding (GtkBindingSet *binding_set,
                    GtkScrollType scroll)
 {
        guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
-       
+
        gtk_binding_entry_add_signal (binding_set, keyval, 0,
                                      "scroll_child", 2,
                                      GTK_TYPE_SCROLL_TYPE, scroll,
@@ -577,7 +604,7 @@ modest_msg_view_window_disconnect_signals (ModestWindow *self)
                                                           MODEST_HEADER_VIEW_OBSERVER(self));
                }
        }
-}      
+}
 
 static void
 modest_msg_view_window_finalize (GObject *obj)
@@ -859,7 +886,7 @@ modest_msg_view_window_new_with_header_model (TnyMsg *msg,
        /* Setup row references and connect signals */
        priv->header_model = g_object_ref (model);
 
-       if (row_reference) {
+       if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
                priv->row_reference = gtk_tree_row_reference_copy (row_reference);
                priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
                select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
@@ -924,8 +951,6 @@ modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
 
-
-
        is_merge = g_str_has_prefix (msg_uid, "merge:");
 
        /* Get the account */
@@ -933,7 +958,6 @@ modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
                account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
                                                          msg_uid);
 
-       
        if (is_merge || account) {
                TnyFolder *folder = NULL;
 
@@ -966,6 +990,8 @@ modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
                                        update_window_title (MODEST_MSG_VIEW_WINDOW (window));
                                        update_branding (MODEST_MSG_VIEW_WINDOW (window));
                                        g_object_unref (msg);
+                                       /* Sync flags to server */
+                                       sync_flags (MODEST_MSG_VIEW_WINDOW (window));
                                } else {
                                        message_reader (window, priv, NULL, msg_uid, folder, NULL);
                                }
@@ -1026,7 +1052,7 @@ modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
        priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
        g_object_ref (priv->header_model);
 
-       if (row_reference) {
+       if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
                priv->row_reference = gtk_tree_row_reference_copy (row_reference);
                priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
                select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
@@ -1061,17 +1087,18 @@ modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
        tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
        update_branding (MODEST_MSG_VIEW_WINDOW (window));
 
-       path = gtk_tree_row_reference_get_path (row_reference);
-       if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
-               TnyHeader *header;
-               gtk_tree_model_get (priv->header_model, &iter, 
-                                   TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
-                                   &header, -1);
-               message_reader (window, priv, header, NULL, NULL, row_reference);
-               g_object_unref (header);
+       if (priv->row_reference) {
+               path = gtk_tree_row_reference_get_path (priv->row_reference);
+               if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
+                       TnyHeader *header;
+                       gtk_tree_model_get (priv->header_model, &iter, 
+                                           TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
+                                           &header, -1);
+                       message_reader (window, priv, header, NULL, NULL, priv->row_reference);
+                       g_object_unref (header);
+               }
+               gtk_tree_path_free (path);
        }
-       gtk_tree_path_free (path);
-
        /* Check dimming rules */
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
        modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
@@ -1685,7 +1712,6 @@ modest_msg_view_window_zoom_minus (ModestWindow *window)
        modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
 
        return TRUE;
-       
 }
 
 static gboolean
@@ -1705,52 +1731,11 @@ modest_msg_view_window_key_event (GtkWidget *window,
                        gtk_widget_event (focus, copy);
                        gdk_event_free (copy);
                        return TRUE;
-               } else 
-                       return FALSE;
-       }
-       if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
-           event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
-           event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
-           event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
-           event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
-           event->keyval == GDK_End || event->keyval == GDK_KP_End) {
-               /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
-               /* gboolean return_value; */
-
-               if (event->type == GDK_KEY_PRESS) {
-                       GtkScrollType scroll_type;
-
-                       switch (event->keyval) {
-                       case GDK_Up: 
-                       case GDK_KP_Up:
-                               scroll_type = GTK_SCROLL_STEP_UP; break;
-                       case GDK_Down: 
-                       case GDK_KP_Down:
-                               scroll_type = GTK_SCROLL_STEP_DOWN; break;
-                       case GDK_Page_Up:
-                       case GDK_KP_Page_Up:
-                               scroll_type = GTK_SCROLL_PAGE_UP; break;
-                       case GDK_Page_Down:
-                       case GDK_KP_Page_Down:
-                               scroll_type = GTK_SCROLL_PAGE_DOWN; break;
-                       case GDK_Home:
-                       case GDK_KP_Home:
-                               scroll_type = GTK_SCROLL_START; break;
-                       case GDK_End:
-                       case GDK_KP_End:
-                               scroll_type = GTK_SCROLL_END; break;
-                       default: scroll_type = GTK_SCROLL_NONE;
-                       }
-
-                       /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",  */
-                       /*                     scroll_type, FALSE, &return_value); */
-                       return FALSE;
                } else {
                        return FALSE;
                }
-       } else {
-               return FALSE;
        }
+       return FALSE;
 }
 
 gboolean
@@ -2063,9 +2048,14 @@ modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
           tree models and reports the deletion when the row is still
           there */
        if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
+               if (priv->next_row_reference) {
+                       gtk_tree_row_reference_free (priv->next_row_reference);
+               }
                if (gtk_tree_row_reference_valid (priv->row_reference)) {
                        priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
                        select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
+               } else {
+                       priv->next_row_reference = NULL;
                }
        }
        if (priv->next_row_reference)
@@ -2107,6 +2097,11 @@ modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
        g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
 
+       if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
+               gtk_tree_row_reference_free (priv->row_reference);
+               priv->row_reference = NULL;
+       }
+
        /* Return inmediatly if there is no header model */
        if (!priv->header_model || !priv->row_reference)
                return FALSE;
@@ -2162,6 +2157,7 @@ view_msg_cb (ModestMailOperation *mail_op,
                if (self) {
                        /* Restore window title */
                        update_window_title (self);
+                       modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
                        g_object_unref (self);
                }
                return;
@@ -2175,6 +2171,7 @@ view_msg_cb (ModestMailOperation *mail_op,
                if (self) {
                        /* Restore window title */
                        update_window_title (self);
+                       modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
                        g_object_unref (self);
                }
                return;
@@ -2188,11 +2185,11 @@ view_msg_cb (ModestMailOperation *mail_op,
        /* Update the row reference */
        if (priv->row_reference != NULL) {
                gtk_tree_row_reference_free (priv->row_reference);
-               priv->row_reference = row_reference?gtk_tree_row_reference_copy (row_reference):NULL;
+               priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
                if (priv->next_row_reference != NULL) {
                        gtk_tree_row_reference_free (priv->next_row_reference);
                }
-               if (row_reference) {
+               if (priv->row_reference) {
                        priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
                        select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
                } else {
@@ -2220,13 +2217,18 @@ view_msg_cb (ModestMailOperation *mail_op,
        }
 
        /* Notify the observers */
-       g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL], 
+       g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
                       0, priv->header_model, priv->row_reference);
 
+       /* Sync the flags if the message is not opened from a header
+          model, i.e, if it's opened from a notification */
+       if (!priv->header_model)
+               sync_flags (self);
+
        /* Frees */
        g_object_unref (self);
        if (row_reference)
-               gtk_tree_row_reference_free (row_reference);            
+               gtk_tree_row_reference_free (row_reference);
 }
 
 TnyFolderType
@@ -2265,7 +2267,7 @@ modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
 
-       if (priv->header_model && priv->row_reference) {
+       if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
                GtkTreeIter iter;
                GtkTreePath *path = NULL;
 
@@ -2313,24 +2315,22 @@ toolbar_resize (ModestMsgViewWindow *self)
        static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
 
        if (parent_priv->toolbar) {
-               /* left size buttons */
+               /* Set expandable and homogeneous tool buttons */
                widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
-               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
+               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
+               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
                widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
-               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
+               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
+               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
+               widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
+               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
+               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
                widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
-               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
+               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
+               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
                widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
-               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
-               gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
-
+               gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
+               gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
                gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
                gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
                gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
@@ -2572,6 +2572,7 @@ modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
 typedef struct {
        ModestMsgViewWindow *self;
        gchar *file_path;
+       gchar *attachment_uid;
 } DecodeAsyncHelper;
 
 static void
@@ -2582,30 +2583,83 @@ on_decode_to_stream_async_handler (TnyMimePart *mime_part,
                                   gpointer user_data)
 {
        DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
-
-       /* It could happen that the window was closed */
-       if (GTK_WIDGET_VISIBLE (helper->self))
-               set_progress_hint (helper->self, FALSE);
+       const gchar *content_type;
 
        if (cancelled || err) {
                if (err) {
-                       gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
+                       gchar *msg;
+                       if ((err->domain == TNY_ERROR_DOMAIN) && 
+                           (err->code == TNY_IO_ERROR_WRITE) &&
+                           (errno == ENOSPC)) {
+                               msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
+                       } else {
+                               msg = g_strdup (_("mail_ib_file_operation_failed"));
+                       }
                        modest_platform_information_banner (NULL, NULL, msg);
                        g_free (msg);
                }
                goto free;
        }
 
-       /* make the file read-only */
-       g_chmod(helper->file_path, 0444);
+       /* It could happen that the window was closed. So we
+          assume it is a cancelation */
+       if (!GTK_WIDGET_VISIBLE (helper->self))
+               goto free;
+
+       /* Remove the progress hint */
+       set_progress_hint (helper->self, FALSE);
+
+       content_type = tny_mime_part_get_content_type (mime_part);
+       if (g_str_has_prefix (content_type, "message/rfc822")) {
+               ModestWindowMgr *mgr;
+               ModestWindow *msg_win = NULL;
+               TnyMsg * msg;
+               gchar *account;
+               const gchar *mailbox;
+               TnyStream *file_stream;
+               gint fd;
+
+               fd = g_open (helper->file_path, O_RDONLY, 0644);
+               if (fd != -1) {
+                       file_stream = tny_fs_stream_new (fd);
+
+                       mgr = modest_runtime_get_window_mgr ();
+
+                       account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
+                       mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
+
+                       if (!account)
+                               account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
+
+                       msg = tny_camel_msg_new ();
+                       tny_camel_msg_parse (msg, file_stream);
+                       msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), account, mailbox, helper->attachment_uid);
+                       modest_window_set_zoom (MODEST_WINDOW (msg_win),
+                                               modest_window_get_zoom (MODEST_WINDOW (helper->self)));
+                       if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
+                               gtk_widget_show_all (GTK_WIDGET (msg_win));
+                       else
+                               gtk_widget_destroy (GTK_WIDGET (msg_win));
+                       g_object_unref (msg);
+                       g_object_unref (file_stream);
+               } else {
+                       modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
+               }
+
+       } else {
 
-       /* Activate the file */
-       modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
+               /* make the file read-only */
+               g_chmod(helper->file_path, 0444);
+
+               /* Activate the file */
+               modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
+       }
 
  free:
        /* Frees */
        g_object_unref (helper->self);
        g_free (helper->file_path);
+       g_free (helper->attachment_uid);
        g_slice_free (DecodeAsyncHelper, helper);
 }
 
@@ -2667,7 +2721,11 @@ modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
                                                               &filepath);
 
                if (temp_stream != NULL) {
+                       ModestAccountMgr *mgr;
                        DecodeAsyncHelper *helper;
+                       gboolean decode_in_provider;
+                       ModestProtocol *protocol;
+                       const gchar *account; 
 
                        /* Activate progress hint */
                        set_progress_hint (window, TRUE);
@@ -2675,11 +2733,33 @@ modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
                        helper = g_slice_new0 (DecodeAsyncHelper);
                        helper->self = g_object_ref (window);
                        helper->file_path = g_strdup (filepath);
+                       helper->attachment_uid = g_strdup (attachment_uid);
+
+                       decode_in_provider = FALSE;
+                       mgr = modest_runtime_get_account_mgr ();
+                       account = modest_window_get_active_account (MODEST_WINDOW (window));
+                       if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
+                               if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
+                                       gchar *uri;
+                                       uri = g_strconcat ("file://", filepath, NULL);
+                                       decode_in_provider = 
+                                               modest_account_protocol_decode_part_to_stream_async (
+                                                       MODEST_ACCOUNT_PROTOCOL (protocol),
+                                                       mime_part,
+                                                       filepath,
+                                                       TNY_STREAM (temp_stream),
+                                                       on_decode_to_stream_async_handler,
+                                                       NULL,
+                                                       helper);
+                                       g_free (uri);
+                               }
+                       }
 
-                       tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
-                                                             on_decode_to_stream_async_handler,
-                                                             NULL,
-                                                             helper);
+                       if (!decode_in_provider)
+                               tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
+                                                                     on_decode_to_stream_async_handler,
+                                                                     NULL,
+                                                                     helper);
                        g_object_unref (temp_stream);
                        /* NOTE: files in the temporary area will be automatically
                         * cleaned after some time if they are no longer in use */
@@ -2786,6 +2866,7 @@ typedef struct
        GList *pairs;
        GnomeVFSResult result;
        gchar *uri;
+       ModestMsgViewWindow *window;
 } SaveMimePartInfo;
 
 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
@@ -2807,6 +2888,8 @@ save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
        g_list_free (info->pairs);
        info->pairs = NULL;
        g_free (info->uri);
+       g_object_unref (info->window);
+       info->window = NULL;
        if (with_struct) {
                g_slice_free (SaveMimePartInfo, info);
        }
@@ -2850,8 +2933,33 @@ save_mime_part_to_file (SaveMimePartInfo *info)
        info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
        if (info->result == GNOME_VFS_OK) {
                GError *error = NULL;
+               gboolean decode_in_provider;
+               gssize written;
+               ModestAccountMgr *mgr;
+               const gchar *account;
+               ModestProtocol *protocol = NULL;
+
                stream = tny_vfs_stream_new (handle);
-               if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
+
+               decode_in_provider = FALSE;
+               mgr = modest_runtime_get_account_mgr ();
+               account = modest_window_get_active_account (MODEST_WINDOW (info->window));
+               if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
+                       if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
+                               decode_in_provider = 
+                                       modest_account_protocol_decode_part_to_stream (
+                                               MODEST_ACCOUNT_PROTOCOL (protocol),
+                                               pair->part,
+                                               pair->filename,
+                                               stream,
+                                               &written,
+                                               &error);
+                       }
+               }
+               if (!decode_in_provider)
+                       written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
+
+               if (written < 0) {
                        g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
 
                        if ((error->domain == TNY_ERROR_DOMAIN) && 
@@ -2930,6 +3038,11 @@ save_mime_parts_to_file_with_checks (GtkWindow *parent,
 
 }
 
+typedef struct _SaveAttachmentsInfo {
+       TnyList *attachments_list;
+       ModestMsgViewWindow *window;
+} SaveAttachmentsInfo;
+
 static void
 save_attachments_response (GtkDialog *dialog,
                           gint       arg1,
@@ -2939,8 +3052,9 @@ save_attachments_response (GtkDialog *dialog,
        gchar *chooser_uri;
        GList *files_to_save = NULL;
        gchar *current_folder;
+       SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
 
-       mime_parts = TNY_LIST (user_data);
+       mime_parts = TNY_LIST (sa_info->attachments_list);
 
        if (arg1 != GTK_RESPONSE_OK)
                goto end;
@@ -3006,6 +3120,7 @@ save_attachments_response (GtkDialog *dialog,
                info->pairs = files_to_save;
                info->result = TRUE;
                info->uri = g_strdup (chooser_uri);
+               info->window = g_object_ref (sa_info->window);
                save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
        }
        g_free (chooser_uri);
@@ -3013,6 +3128,8 @@ save_attachments_response (GtkDialog *dialog,
  end:
        /* Free and close the dialog */
        g_object_unref (mime_parts);
+       g_object_unref (sa_info->window);
+       g_slice_free (SaveAttachmentsInfo, sa_info);
        gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
@@ -3120,8 +3237,12 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
        /* We must run this asynchronously, because the hildon dialog
           performs a gtk_dialog_run by itself which leads to gdk
           deadlocks */
+       SaveAttachmentsInfo *sa_info;
+       sa_info = g_slice_new (SaveAttachmentsInfo);
+       sa_info->attachments_list = mime_parts;
+       sa_info->window = g_object_ref (window);
        g_signal_connect (save_dialog, "response", 
-                         G_CALLBACK (save_attachments_response), mime_parts);
+                         G_CALLBACK (save_attachments_response), sa_info);
 
        gtk_widget_show_all (save_dialog);
 }
@@ -3476,10 +3597,6 @@ setup_menu (ModestMsgViewWindow *self)
                                           APP_MENU_CALLBACK (modest_ui_actions_on_move_to),
                                           MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
 
-       modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_forward"), "<Control>d",
-                                          APP_MENU_CALLBACK (modest_ui_actions_on_forward),
-                                          MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
-
        modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
                                           APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
                                           MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
@@ -3514,7 +3631,6 @@ modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
        GSList *recipients = NULL;
        TnyMsg *msg = NULL;
-       gboolean contacts_to_add = FALSE;
 
        msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
        if (msg == NULL) {
@@ -3530,51 +3646,11 @@ modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
                g_object_unref (msg);
        }
 
-       if (recipients != NULL) {
-               GtkWidget *picker_dialog;
-               GtkWidget *selector;
-               GSList *node;
-               gchar *selected = NULL;
-
-               selector = hildon_touch_selector_new_text ();
-               g_object_ref (selector);
-
-               for (node = recipients; node != NULL; node = g_slist_next (node)) {
-                       if (!modest_address_book_has_address ((const gchar *) node->data)) {
-                               hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector), 
-                                                                  (const gchar *) node->data);
-                               contacts_to_add = TRUE;
-                       }
-               }
-
-               if (contacts_to_add) {
-                       gint picker_result;
-
-                       picker_dialog = hildon_picker_dialog_new (GTK_WINDOW (self));
-                       gtk_window_set_title (GTK_WINDOW (picker_dialog), _("mcen_me_viewer_addtocontacts"));
-
-                       hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (picker_dialog), 
-                                                          HILDON_TOUCH_SELECTOR (selector));
-                       
-                       picker_result = gtk_dialog_run (GTK_DIALOG (picker_dialog));
-
-                       if (picker_result == GTK_RESPONSE_OK) {
-                               selected = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
-                       }
-                       gtk_widget_destroy (picker_dialog);
-
-                       if (selected)
-                               modest_address_book_add_address (selected, (GtkWindow *) self);
-                       g_free (selected);
-
-               } else {
-
-                       g_object_unref (selector);
-
-               }
+       if (recipients) {
+               /* Offer the user to add recipients to the address book */
+               modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
+               g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
        }
-       
-       if (recipients) {g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);}
 }
 
 static gboolean 
@@ -3632,9 +3708,17 @@ modest_msg_view_window_reload (ModestMsgViewWindow *self)
                return;
 
        msg_uid = modest_msg_view_window_get_message_uid (self);
-        if (msg_uid)
-               if (!message_reader (self, priv, NULL, msg_uid, folder, priv->row_reference))
+        if (msg_uid) {
+               GtkTreeRowReference *row_reference;
+
+               if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
+                       row_reference = priv->row_reference;
+               } else {
+                       row_reference = NULL;
+               }
+               if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
                        g_warning ("Shouldn't happen, trying to reload a message failed");
+       }
 
        g_object_unref (folder);
 }
@@ -3669,3 +3753,35 @@ update_branding (ModestMsgViewWindow *self)
        modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
        g_free (service_name);
 }
+
+static void
+sync_flags (ModestMsgViewWindow *self)
+{
+       TnyHeader *header = NULL;
+
+       header = modest_msg_view_window_get_header (self);
+       if (!header) {
+               TnyMsg *msg = modest_msg_view_window_get_message (self);
+               if (msg) {
+                       header = tny_msg_get_header (msg);
+                       g_object_unref (msg);
+               }
+       }
+
+       if (header) {
+               TnyFolder *folder = tny_header_get_folder (header);
+
+               if (folder) {
+                       ModestMailOperation *mail_op;
+
+                       /* Sync folder, we need this to save the seen flag */
+                       mail_op = modest_mail_operation_new (NULL);
+                       modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
+                                                        mail_op);
+                       modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
+                       g_object_unref (mail_op);
+                       g_object_unref (folder);
+               }
+               g_object_unref (header);
+       }
+}