Fixes NB#126941 fixes some potential invalid dereference issues
[modest] / src / hildon2 / modest-msg-view-window.c
index 70effef..772f440 100644 (file)
@@ -125,26 +125,25 @@ struct _ModestMsgViewWindowPrivate {
 
 static void  modest_msg_view_window_class_init   (ModestMsgViewWindowClass *klass);
 static void  modest_msg_view_window_init         (ModestMsgViewWindow *obj);
-static void  modest_header_view_observer_init(
-               ModestHeaderViewObserverIface *iface_class);
+static void  modest_header_view_observer_init    (ModestHeaderViewObserverIface *iface_class);
 static void  modest_msg_view_window_finalize     (GObject *obj);
-static void  modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
-                                                        gpointer data);
-static void  modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
-                                                       ModestMsgViewWindow *obj);
+static void  modest_msg_view_window_show_find_toolbar   (GtkWidget *obj, gpointer data);
+static void  modest_msg_view_window_find_toolbar_close  (GtkWidget *widget,
+                                                        ModestMsgViewWindow *obj);
 static void  modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
-                                                       ModestMsgViewWindow *obj);
-
+                                                        ModestMsgViewWindow *obj);
+static void  modest_msg_view_window_toggle_find_toolbar (GtkWidget *obj,
+                                                        gpointer data);
 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
 
-static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
-static void modest_msg_view_window_set_zoom (ModestWindow *window,
-                                            gdouble zoom);
+static gdouble modest_msg_view_window_get_zoom    (ModestWindow *window);
+static void modest_msg_view_window_set_zoom       (ModestWindow *window,
+                                                  gdouble zoom);
 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
-static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
-static gboolean modest_msg_view_window_key_event (GtkWidget *window,
-                                                 GdkEventKey *event,
-                                                 gpointer userdata);
+static gboolean modest_msg_view_window_zoom_plus  (ModestWindow *window);
+static gboolean modest_msg_view_window_key_event  (GtkWidget *window,
+                                                  GdkEventKey *event,
+                                                  gpointer userdata);
 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
 
 static void modest_msg_view_window_show_toolbar   (ModestWindow *window,
@@ -203,7 +202,6 @@ static void set_progress_hint    (ModestMsgViewWindow *self,
 
 static void update_window_title (ModestMsgViewWindow *window);
 
-static gboolean set_toolbar_transfer_mode     (ModestMsgViewWindow *self); 
 static void init_window (ModestMsgViewWindow *obj);
 
 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
@@ -222,6 +220,8 @@ static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
 static gboolean message_reader (ModestMsgViewWindow *window,
                                ModestMsgViewWindowPrivate *priv,
                                TnyHeader *header,
+                               const gchar *msg_uid,
+                               TnyFolder *folder,
                                GtkTreeRowReference *row_reference);
 
 static void setup_menu (ModestMsgViewWindow *self);
@@ -394,7 +394,6 @@ modest_msg_view_window_init (ModestMsgViewWindow *obj)
        ModestWindowPrivate *parent_priv = NULL;
        GtkActionGroup *action_group = NULL;
        GError *error = NULL;
-       GdkPixbuf *window_icon;
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
        parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
@@ -457,33 +456,11 @@ modest_msg_view_window_init (ModestMsgViewWindow *obj)
        /* Init window */
        init_window (MODEST_MSG_VIEW_WINDOW(obj));
        
-       /* Set window icon */
-       window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG); 
-       if (window_icon) {
-               gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
-               g_object_unref (window_icon);
-       }       
-       
        hildon_program_add_window (hildon_program_get_instance(),
                                   HILDON_WINDOW(obj));
 
 }
 
-
-static gboolean
-set_toolbar_transfer_mode (ModestMsgViewWindow *self)
-{
-       ModestMsgViewWindowPrivate *priv = NULL;
-       
-       g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
-
-       priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
-
-       set_progress_hint (self, TRUE);
-       
-       return FALSE;
-}
-
 static void
 update_progress_hint (ModestMsgViewWindow *self)
 {
@@ -528,6 +505,7 @@ init_window (ModestMsgViewWindow *obj)
        modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
        main_vbox = gtk_vbox_new  (FALSE, 6);
        priv->main_scroll = hildon_pannable_area_new ();
+        g_object_set (G_OBJECT (priv->main_scroll), "mov-mode", HILDON_MOVEMENT_MODE_BOTH, NULL);
        gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
        gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
        gtk_container_add   (GTK_CONTAINER(obj), main_vbox);
@@ -781,6 +759,8 @@ modest_msg_view_window_construct (ModestMsgViewWindow *self,
                          G_CALLBACK (modest_ui_actions_on_details), obj);
        g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
                          G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
+       g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
+                         G_CALLBACK (modest_ui_actions_on_limit_error), obj);
        g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
                          G_CALLBACK (on_fetch_image), obj);
 
@@ -923,6 +903,84 @@ modest_msg_view_window_new_with_header_model (TnyMsg *msg,
 }
 
 ModestWindow *
+modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
+                                    const gchar *mailbox,
+                                    const gchar *msg_uid)
+{
+       ModestMsgViewWindow *window = NULL;
+       ModestMsgViewWindowPrivate *priv = NULL;
+       ModestWindowMgr *mgr = NULL;
+       gboolean is_merge;
+       TnyAccount *account = NULL;
+
+       mgr = modest_runtime_get_window_mgr ();
+       window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
+       g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
+
+       modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
+
+       priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
+
+
+
+       is_merge = g_str_has_prefix (msg_uid, "merge:");
+
+       /* Get the account */
+       if (!is_merge)
+               account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
+                                                         msg_uid);
+
+       
+       if (is_merge || account) {
+               TnyFolder *folder = NULL;
+
+               /* Try to get the message, if it's already downloaded
+                  we don't need to connect */
+               if (account) {
+                       folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
+               } else {
+                       ModestTnyAccountStore *account_store;
+                       ModestTnyLocalFoldersAccount *local_folders_account;
+
+                       account_store = modest_runtime_get_account_store ();
+                       local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
+                               modest_tny_account_store_get_local_folders_account (account_store));
+                       folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
+                       g_object_unref (local_folders_account);
+               }
+               if (folder) {
+                       TnyDevice *device;
+                       gboolean device_online;
+
+                       device = modest_runtime_get_device();
+                       device_online = tny_device_is_online (device);
+                       if (device_online) {
+                               message_reader (window, priv, NULL, msg_uid, folder, NULL);
+                       } else {
+                               TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
+                               if (msg) {
+                                       tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
+                                       update_window_title (MODEST_MSG_VIEW_WINDOW (window));
+                                       update_branding (MODEST_MSG_VIEW_WINDOW (window));
+                                       g_object_unref (msg);
+                               } else {
+                                       message_reader (window, priv, NULL, msg_uid, folder, NULL);
+                               }
+                       }
+                       g_object_unref (folder);
+               }
+
+       }
+
+       /* Check dimming rules */
+       modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
+
+       return MODEST_WINDOW(window);
+}
+
+ModestWindow *
 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
                                             const gchar *modest_account_name,
                                             const gchar *mailbox,
@@ -1006,7 +1064,7 @@ modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
                gtk_tree_model_get (priv->header_model, &iter, 
                                    TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
                                    &header, -1);
-               message_reader (window, priv, header, row_reference);
+               message_reader (window, priv, header, NULL, NULL, row_reference);
                g_object_unref (header);
        }
        gtk_tree_path_free (path);
@@ -1020,7 +1078,7 @@ modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
 }
 
 ModestWindow *
-modest_msg_view_window_new_for_search_result (TnyMsg *msg, 
+modest_msg_view_window_new_for_search_result (TnyMsg *msg,
                                              const gchar *modest_account_name,
                                              const gchar *mailbox,
                                              const gchar *msg_uid)
@@ -1229,41 +1287,41 @@ modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
                                         gpointer arg3,
                                         ModestMsgViewWindow *window)
 {
-       ModestMsgViewWindowPrivate *priv = NULL; 
+       ModestMsgViewWindowPrivate *priv = NULL;
        gboolean already_changed = FALSE;
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
 
        /* If the current row was reordered select the proper next
           valid row. The same if the next row reference changes */
-       if (priv->row_reference && 
-           gtk_tree_row_reference_valid (priv->row_reference)) {
-               GtkTreePath *path;
-               path = gtk_tree_row_reference_get_path (priv->row_reference);
-               if (gtk_tree_path_compare (path, arg1) == 0) {
-                       if (priv->next_row_reference) {
-                               gtk_tree_row_reference_free (priv->next_row_reference);
-                       }
-                       priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
-                       select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
-                       already_changed = TRUE;
-               }
-               gtk_tree_path_free (path);
-       }
-       if (!already_changed &&
-           priv->next_row_reference &&
+       if (!priv->row_reference ||
+           !gtk_tree_row_reference_valid (priv->row_reference))
+               return;
+
+       if (priv->next_row_reference &&
            gtk_tree_row_reference_valid (priv->next_row_reference)) {
-               GtkTreePath *path;
-               path = gtk_tree_row_reference_get_path (priv->next_row_reference);
-               if (gtk_tree_path_compare (path, arg1) == 0) {
-                       if (priv->next_row_reference) {
-                               gtk_tree_row_reference_free (priv->next_row_reference);
-                       }
+               GtkTreePath *cur, *next;
+               /* Check that the order is still the correct one */
+               cur = gtk_tree_row_reference_get_path (priv->row_reference);
+               next = gtk_tree_row_reference_get_path (priv->next_row_reference);
+               gtk_tree_path_next (cur);
+               if (gtk_tree_path_compare (cur, next) != 0) {
+                       gtk_tree_row_reference_free (priv->next_row_reference);
                        priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
                        select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
+                       already_changed = TRUE;
                }
-               gtk_tree_path_free (path);
+               gtk_tree_path_free (cur);
+               gtk_tree_path_free (next);
+       } else {
+               if (priv->next_row_reference)
+                       gtk_tree_row_reference_free (priv->next_row_reference);
+               /* Update next row reference */
+               priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
+               select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
+               already_changed = TRUE;
        }
+
        check_dimming_rules_after_change (window);
 }
 
@@ -1428,46 +1486,44 @@ modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
        return (const gchar*) priv->msg_uid;
 }
 
-static void 
-modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
+/* Used for the Ctrl+F accelerator */
+static void
+modest_msg_view_window_toggle_find_toolbar (GtkWidget *obj,
                                            gpointer data)
 {
        ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
        ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
-       ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
-       gboolean is_active;
-       GtkAction *action;
 
-       is_active = gtk_toggle_action_get_active (toggle);
-
-       if (is_active) {
-               gtk_widget_show (priv->find_toolbar);
-               hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
-       } else {
-               gtk_widget_hide (priv->find_toolbar);
-               modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
-       }
+       if (GTK_WIDGET_VISIBLE (priv->find_toolbar)) {
+               modest_msg_view_window_find_toolbar_close (obj, data);
+       } else {
+               modest_msg_view_window_show_find_toolbar (obj, data);
+       }
+}
 
-       /* update the toggle buttons status */
-       action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
-       if (action)
-               modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
+/* Handler for menu option */
+static void
+modest_msg_view_window_show_find_toolbar (GtkWidget *obj,
+                                         gpointer data)
+{
+       ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
+       ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
 
+       gtk_widget_show (priv->find_toolbar);
+       hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
 }
 
+/* Handler for click on the "X" close button in find toolbar */
 static void
 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
                                           ModestMsgViewWindow *obj)
 {
-       GtkToggleAction *toggle;
-       ModestWindowPrivate *parent_priv;
        ModestMsgViewWindowPrivate *priv;
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
-       parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
 
-       toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
-       gtk_toggle_action_set_active (toggle, FALSE);
+       /* Hide toolbar */
+       gtk_widget_hide (priv->find_toolbar);
        modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
 }
 
@@ -1818,6 +1874,8 @@ modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
 
 typedef struct {
        TnyHeader *header;
+       gchar *msg_uid;
+       TnyFolder *folder;
        GtkTreeRowReference *row_reference;
 } MsgReaderInfo;
 
@@ -1838,7 +1896,8 @@ message_reader_performer (gboolean canceled,
        }
 
        /* Register the header - it'll be unregistered in the callback */
-       modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
+       if (info->header)
+               modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
 
        /* New mail operation */
        mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
@@ -1846,7 +1905,10 @@ message_reader_performer (gboolean canceled,
                                                                 NULL, NULL);
 
        modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
-       modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
+       if (info->header)
+               modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
+       else
+               modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
        g_object_unref (mail_op);
 
        /* Update dimming rules */
@@ -1855,7 +1917,11 @@ message_reader_performer (gboolean canceled,
 
  frees:
        /* Frees. The row_reference will be freed by the view_msg_cb callback */
-       g_object_unref (info->header);
+       g_free (info->msg_uid);
+       if (info->folder)
+               g_object_unref (info->folder);
+       if (info->header)
+               g_object_unref (info->header);
        g_slice_free (MsgReaderInfo, info);
 }
 
@@ -1876,22 +1942,27 @@ static gboolean
 message_reader (ModestMsgViewWindow *window,
                ModestMsgViewWindowPrivate *priv,
                TnyHeader *header,
+               const gchar *msg_uid,
+               TnyFolder *folder,
                GtkTreeRowReference *row_reference)
 {
        ModestWindowMgr *mgr;
-       TnyAccount *account;
-       TnyFolder *folder;
+       TnyAccount *account = NULL;
        MsgReaderInfo *info;
 
-       g_return_val_if_fail (row_reference != NULL, FALSE);
-
        /* We set the header from model while we're loading */
        tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
        gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
 
+       if (header)
+               folder = NULL;
+
+       if (folder)
+               g_object_ref (folder);
+
        mgr = modest_runtime_get_window_mgr ();
        /* Msg download completed */
-       if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
+       if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
 
                /* Ask the user if he wants to download the message if
                   we're not online */
@@ -1905,10 +1976,24 @@ message_reader (ModestMsgViewWindow *window,
                                return FALSE;
                        }
 
-                       folder = tny_header_get_folder (header);
+                       if (header) {
+                               folder = tny_header_get_folder (header);
+                       }
                        info = g_slice_new (MsgReaderInfo);
-                       info->header = g_object_ref (header);
-                       info->row_reference = gtk_tree_row_reference_copy (row_reference);
+                       info->msg_uid = g_strdup (msg_uid);
+                       if (header)
+                               info->header = g_object_ref (header);
+                       else
+                               info->header = NULL;    
+                       if (folder)
+                               info->folder = g_object_ref (folder);
+                       else
+                               info->folder = NULL;
+                       if (row_reference) {
+                               info->row_reference = gtk_tree_row_reference_copy (row_reference);
+                       } else {
+                               info->row_reference = NULL;
+                       }
 
                        /* Offer the connection dialog if necessary */
                        modest_platform_connect_if_remote_and_perform ((GtkWindow *) window, 
@@ -1916,25 +2001,43 @@ message_reader (ModestMsgViewWindow *window,
                                                                       TNY_FOLDER_STORE (folder),
                                                                       message_reader_performer, 
                                                                       info);
-                       g_object_unref (folder);
+                       if (folder)
+                               g_object_unref (folder);
                        return TRUE;
                }
        }
 
-       folder = tny_header_get_folder (header);
-       account = tny_folder_get_account (folder);
+       if (header) {
+               folder = tny_header_get_folder (header);
+       }
+        if (folder)
+               account = tny_folder_get_account (folder);
+
        info = g_slice_new (MsgReaderInfo);
-       info->header = g_object_ref (header);
-       info->row_reference = gtk_tree_row_reference_copy (row_reference);
+       info->msg_uid = g_strdup (msg_uid);
+       if (folder)
+               info->folder = g_object_ref (folder);
+       else
+               info->folder = NULL;
+       if (header)
+               info->header = g_object_ref (header);
+       else
+               info->header = NULL;
+       if (row_reference)
+               info->row_reference = gtk_tree_row_reference_copy (row_reference);
+       else
+               info->row_reference = NULL;
 
        message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
-       g_object_unref (account);
-       g_object_unref (folder);
+        if (account)
+               g_object_unref (account);
+       if (folder)
+               g_object_unref (folder);
 
        return TRUE;
 }
 
-gboolean        
+gboolean
 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
 {
        ModestMsgViewWindowPrivate *priv;
@@ -1979,7 +2082,7 @@ modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
                            &header, -1);
        
        /* Read the message & show it */
-       if (!message_reader (window, priv, header, row_reference)) {
+       if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
                retval = FALSE;
        }
        gtk_tree_row_reference_free (row_reference);
@@ -2020,7 +2123,7 @@ modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
                                GtkTreeRowReference *row_reference;
                                row_reference = gtk_tree_row_reference_new (priv->header_model, path);
                                /* Read the message & show it */
-                               retval = message_reader (window, priv, header, row_reference);
+                               retval = message_reader (window, priv, header, NULL, NULL, row_reference);
                                gtk_tree_row_reference_free (row_reference);
                        } else {
                                finished = FALSE;
@@ -2050,7 +2153,8 @@ view_msg_cb (ModestMailOperation *mail_op,
 
        row_reference = (GtkTreeRowReference *) user_data;
        if (canceled) {
-               gtk_tree_row_reference_free (row_reference);
+               if (row_reference)
+                       gtk_tree_row_reference_free (row_reference);
                self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
                if (self) {
                        /* Restore window title */
@@ -2062,7 +2166,8 @@ view_msg_cb (ModestMailOperation *mail_op,
 
        /* If there was any error */
        if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
-               gtk_tree_row_reference_free (row_reference);
+               if (row_reference)
+                       gtk_tree_row_reference_free (row_reference);
                self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
                if (self) {
                        /* Restore window title */
@@ -2080,12 +2185,16 @@ 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 = gtk_tree_row_reference_copy (row_reference);
+               priv->row_reference = 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);
                }
-               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);
+               if (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 {
+                       priv->next_row_reference = NULL;
+               }
        }
 
        /* Mark header as read */
@@ -2113,7 +2222,8 @@ view_msg_cb (ModestMailOperation *mail_op,
 
        /* Frees */
        g_object_unref (self);
-       gtk_tree_row_reference_free (row_reference);            
+       if (row_reference)
+               gtk_tree_row_reference_free (row_reference);            
 }
 
 TnyFolderType
@@ -2205,7 +2315,7 @@ toolbar_resize (ModestMsgViewWindow *self)
                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);
-               widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
+               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);
@@ -2213,7 +2323,7 @@ toolbar_resize (ModestMsgViewWindow *self)
                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);
-               widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
+               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);
@@ -2351,8 +2461,10 @@ on_mail_operation_started (ModestMailOperation *mail_op,
        tmp = priv->progress_widgets;
        source = modest_mail_operation_get_source(mail_op);
        if (G_OBJECT (self) == source) {
-               if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
-                       set_toolbar_transfer_mode(self);
+               if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
+                   op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
+                   op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
+                       set_progress_hint (self, TRUE);
                        while (tmp) {
                                modest_progress_object_add_operation (
                                                MODEST_PROGRESS_OBJECT (tmp->data),
@@ -2362,9 +2474,12 @@ on_mail_operation_started (ModestMailOperation *mail_op,
                }
        }
        g_object_unref (source);
+
+       /* Update dimming rules */
+       check_dimming_rules_after_change (self);
 }
 
-static void 
+static void
 on_mail_operation_finished (ModestMailOperation *mail_op,
                            gpointer user_data)
 {
@@ -2372,13 +2487,15 @@ on_mail_operation_finished (ModestMailOperation *mail_op,
        ModestMailOperationTypeOperation op_type;
        GSList *tmp;
        ModestMsgViewWindowPrivate *priv;
-       
+
        self = MODEST_MSG_VIEW_WINDOW (user_data);
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
        op_type = modest_mail_operation_get_type_operation (mail_op);
        tmp = priv->progress_widgets;
-       
-       if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
+
+       if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
+           op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
+           op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
                while (tmp) {
                        modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
                                                                 mail_op);
@@ -2397,7 +2514,6 @@ on_mail_operation_finished (ModestMailOperation *mail_op,
           won't let the user delete the message that has been
           readed for example */
        check_dimming_rules_after_change (self);
-
 }
 
 static void
@@ -2666,6 +2782,7 @@ typedef struct
 {
        GList *pairs;
        GnomeVFSResult result;
+       gchar *uri;
 } SaveMimePartInfo;
 
 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
@@ -2686,6 +2803,7 @@ save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
        }
        g_list_free (info->pairs);
        info->pairs = NULL;
+       g_free (info->uri);
        if (with_struct) {
                g_slice_free (SaveMimePartInfo, info);
        }
@@ -2694,25 +2812,27 @@ save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
 static gboolean
 idle_save_mime_part_show_result (SaveMimePartInfo *info)
 {
-       if (info->pairs != NULL) {
-               save_mime_part_to_file (info);
-       } else {
-               /* This is a GDK lock because we are an idle callback and
-                * hildon_banner_show_information is or does Gtk+ code */
+       /* This is a GDK lock because we are an idle callback and
+        * hildon_banner_show_information is or does Gtk+ code */
 
-               gdk_threads_enter (); /* CHECKED */
-               save_mime_part_info_free (info, TRUE);
-               if (info->result == GNOME_VFS_OK) {
-                       hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
-               } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
-                       gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
-                       modest_platform_information_banner (NULL, NULL, msg);
-                       g_free (msg);
-               } else {
-                       hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
-               }
-               gdk_threads_leave (); /* CHECKED */
+       gdk_threads_enter (); /* CHECKED */
+       if (info->result == GNOME_VFS_OK) {
+               hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
+       } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
+               gchar *msg = NULL;
+
+               /* Check if the uri belongs to the external mmc */
+               if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
+                       msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
+               else
+                       msg = g_strdup (_KR("cerm_memory_card_full"));
+               modest_platform_information_banner (NULL, NULL, msg);
+               g_free (msg);
+       } else {
+               hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
        }
+       save_mime_part_info_free (info, FALSE);
+       gdk_threads_leave (); /* CHECKED */
 
        return FALSE;
 }
@@ -2740,15 +2860,19 @@ save_mime_part_to_file (SaveMimePartInfo *info)
                        }
                }
                g_object_unref (G_OBJECT (stream));
-               g_object_unref (pair->part);
-               g_slice_free (SaveMimePartPair, pair);
-               info->pairs = g_list_delete_link (info->pairs, info->pairs);
        } else {
-               g_warning ("Could not create save attachment %s: %s\n", pair->filename, gnome_vfs_result_to_string (info->result));
-               save_mime_part_info_free (info, FALSE);
+               g_warning ("Could not create save attachment %s: %s\n", 
+                          pair->filename, gnome_vfs_result_to_string (info->result));
+       }
+
+       /* Go on saving remaining files */
+       info->pairs = g_list_remove_link (info->pairs, info->pairs);
+       if (info->pairs != NULL) {
+               save_mime_part_to_file (info);
+       } else {
+               g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
        }
 
-       g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
        return NULL;
 }
 
@@ -2763,11 +2887,14 @@ save_mime_parts_to_file_with_checks (GtkWindow *parent,
 
         for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
                 SaveMimePartPair *pair = iter->data;
-                if (modest_utils_file_exists (pair->filename)) {
+               gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
+
+                if (modest_utils_file_exists (unescaped)) {
                        replaced_files++;
                        if (replaced_files == 1)
                                to_replace = iter;
                 }
+               g_free (unescaped);
         }
        if (replaced_files) {
                gint response;
@@ -2817,9 +2944,9 @@ save_attachments_response (GtkDialog *dialog,
 
        chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
        current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
-       if (current_folder && current_folder != '\0') {
+       if (current_folder && *current_folder != '\0') {
                GError *err = NULL;
-               modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, 
+               modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
                                        current_folder,&err);
                if (err != NULL) {
                        g_debug ("Error storing latest used folder: %s", err->message);
@@ -2829,8 +2956,18 @@ save_attachments_response (GtkDialog *dialog,
        g_free (current_folder);
 
        if (!modest_utils_folder_writable (chooser_uri)) {
-               hildon_banner_show_information 
-                       (NULL, NULL, _FM("sfil_ib_readonly_location"));
+               const gchar *err_msg;
+
+#ifdef MODEST_PLATFORM_MAEMO
+               if (modest_maemo_utils_in_usb_mode ()) {
+                       err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
+               } else {
+                       err_msg = _FM("sfil_ib_readonly_location");
+               }
+#else
+               err_msg = _FM("sfil_ib_readonly_location");
+#endif
+               hildon_banner_show_information (NULL, NULL, err_msg);
        } else {
                TnyIterator *iter;
 
@@ -2860,14 +2997,15 @@ save_attachments_response (GtkDialog *dialog,
                }
                g_object_unref (iter);
        }
-       g_free (chooser_uri);
 
        if (files_to_save != NULL) {
                SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
                info->pairs = files_to_save;
                info->result = TRUE;
+               info->uri = g_strdup (chooser_uri);
                save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
        }
+       g_free (chooser_uri);
 
  end:
        /* Free and close the dialog */
@@ -2884,6 +3022,7 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
        gchar *conf_folder = NULL;
        gchar *filename = NULL;
        gchar *save_multiple_str = NULL;
+       const gchar *root_folder = "file:///";
 
        g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
@@ -2936,14 +3075,26 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
        save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
                                                      GTK_FILE_CHOOSER_ACTION_SAVE);
 
-       /* set folder */
-       conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
+       /* Get last used folder */
+       conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
+                                             MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
+
+       /* File chooser stops working if we select "file:///" as current folder */
+       if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
+               g_free (conf_folder);
+               conf_folder = NULL;
+       }
+
        if (conf_folder && conf_folder[0] != '\0') {
                gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
        } else {
                gchar *docs_folder;
-               /* Set the default folder to images folder */
-               docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
+               /* Set the default folder to documents folder */
+               docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
+               if (!docs_folder) {
+                       /* fallback */
+                       docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
+               }
                gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
                g_free (docs_folder);
        }
@@ -2960,6 +3111,7 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
        if (save_multiple_str) {
                g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
                gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
+               g_free (save_multiple_str);
        }
 
        /* We must run this asynchronously, because the hildon dialog
@@ -3308,9 +3460,19 @@ setup_menu (ModestMsgViewWindow *self)
        g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
 
        /* Settings menu buttons */
-       modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_replytoall"), NULL,
-                                          APP_MENU_CALLBACK (modest_ui_actions_on_reply_all),
-                                          MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
+       modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), NULL,
+                                          APP_MENU_CALLBACK (modest_msg_view_window_show_find_toolbar),
+                                          MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
+
+       modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self),
+                                          dngettext(GETTEXT_PACKAGE,
+                                                    "mcen_me_move_message",
+                                                    "mcen_me_move_messages",
+                                                    1),
+                                          NULL,
+                                          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));
@@ -3318,6 +3480,7 @@ setup_menu (ModestMsgViewWindow *self)
        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));
+
        modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
                                           APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
                                           MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
@@ -3336,9 +3499,6 @@ setup_menu (ModestMsgViewWindow *self)
                                           APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
                                           MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
 
-       modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mail_bd_external_images"), NULL,
-                                          APP_MENU_CALLBACK (modest_ui_actions_on_fetch_images),
-                                          MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_fetch_images));
        modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
                                           APP_MENU_CALLBACK (modest_ui_actions_on_details),
                                           MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
@@ -3401,7 +3561,7 @@ modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
                        gtk_widget_destroy (picker_dialog);
 
                        if (selected)
-                               modest_address_book_add_address (selected);
+                               modest_address_book_add_address (selected, (GtkWindow *) self);
                        g_free (selected);
 
                } else {
@@ -3457,7 +3617,7 @@ modest_msg_view_window_reload (ModestMsgViewWindow *self)
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
        header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));     
 
-       if (!message_reader (self, priv, header, priv->row_reference)) {
+       if (!message_reader (self, priv, header, NULL, NULL, priv->row_reference)) {
                g_warning ("Shouldn't happen, trying to reload a message failed");
        }
 
@@ -3481,7 +3641,7 @@ update_branding (ModestMsgViewWindow *self)
        mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
 
        mgr = modest_runtime_get_account_mgr ();
-       
+
        if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
                if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
                        service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),