* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-msg-edit-window.c
index 6edffce..04b467d 100644 (file)
@@ -104,6 +104,11 @@ static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, Mod
 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
                                    GtkTextIter *start, GtkTextIter *end,
                                    gpointer userdata);
+static void  text_buffer_insert_text (GtkTextBuffer *buffer,
+                                     GtkTextIter *location,
+                                     gchar *text,
+                                     gint len,
+                                     ModestMsgEditWindow *window);
 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
 static void  subject_field_insert_text (GtkEditable *editable, 
@@ -157,13 +162,29 @@ static void on_account_removed (TnyAccountStore *account_store,
                                gpointer user_data);
 
 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
-
 static void set_zoom_do_nothing (ModestWindow *window, gdouble zoom);
-
 static gdouble get_zoom_do_nothing (ModestWindow *window);
 
 static void init_window (ModestMsgEditWindow *obj);
 
+gboolean scroll_drag_timeout (gpointer userdata);
+static void correct_scroll (ModestMsgEditWindow *w);
+static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
+static void text_buffer_end_user_action (GtkTextBuffer *buffer,
+                                        ModestMsgEditWindow *userdata);
+static void text_buffer_mark_set (GtkTextBuffer *buffer,
+                                 GtkTextIter *iter,
+                                 GtkTextMark *mark,
+                                 ModestMsgEditWindow *userdata);
+void vadj_changed (GtkAdjustment *adj, 
+                  ModestMsgEditWindow *window);
+
+static ModestPair *find_transport_from_message_sender (ModestPairList *transports,
+                                                      TnyMsg *msg);
+
+
+
+
 static void DEBUG_BUFFER (WPTextBuffer *buffer)
 {
 #ifdef DEBUG
@@ -219,10 +240,12 @@ enum {
 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
 struct _ModestMsgEditWindowPrivate {
        GtkWidget   *msg_body;
+       GtkWidget   *frame;
        GtkWidget   *header_box;
        
        ModestPairList *from_field_protos;
        GtkWidget   *from_field;
+       const gchar *original_account_name;
        
        GtkWidget   *to_field;
        GtkWidget   *cc_field;
@@ -251,12 +274,14 @@ struct _ModestMsgEditWindowPrivate {
        gchar       *last_search;
 
        GtkWidget   *scroll;
-       GtkWidget   *scroll_area;
-       gint        last_vadj_upper;
+       guint        scroll_drag_timeout_id;
+       gdouble      last_upper;
 
        gint last_cid;
-       GList *attachments;
-       GList *images;
+       TnyList *attachments;
+       TnyList *images;
+       guint64 images_size;
+       gint images_count;
 
        TnyHeaderFlags priority_flags;
        
@@ -382,13 +407,16 @@ modest_msg_edit_window_init (ModestMsgEditWindow *obj)
        priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
 
        priv->msg_body      = NULL;
+       priv->frame         = NULL;
        priv->from_field    = NULL;
        priv->to_field      = NULL;
        priv->cc_field      = NULL;
        priv->bcc_field     = NULL;
        priv->subject_field = NULL;
-       priv->attachments   = NULL;
-       priv->images        = NULL;
+       priv->attachments   = TNY_LIST (tny_simple_list_new ());
+       priv->images        = TNY_LIST (tny_simple_list_new ());
+       priv->images_size   = 0;
+       priv->images_count  = 0;
        priv->last_cid      = 0;
 
        priv->cc_caption    = NULL;
@@ -412,7 +440,8 @@ modest_msg_edit_window_init (ModestMsgEditWindow *obj)
        priv->clipboard_text = NULL;
        priv->sent = FALSE;
 
-       priv->last_vadj_upper = 0;
+       priv->scroll_drag_timeout_id = 0;
+       priv->last_upper = 0.0;
 
        modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
                                            GTK_WINDOW(obj),"applications_email_editor");
@@ -466,40 +495,188 @@ get_transports (void)
        return transports;
 }
 
-void vadj_changed (GtkAdjustment *adj,
-                  ModestMsgEditWindow *window)
+/**
+ * Search an (account, address) ModestPairList for a pair whose
+ * address matches the one in the From: header of a TnyMsg
+ *
+ * @result: A ModestPair * with a matching address, or NULL if none found
+ */
+static ModestPair *
+find_transport_from_message_sender (ModestPairList *transports, TnyMsg *msg)
 {
-       ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
+       g_return_val_if_fail (transports, NULL);
+       g_return_val_if_fail (msg, NULL);
 
-       GdkRectangle rectangle, cursor_rectangle;
-       GtkTextIter position;
-       gboolean visible;
-       gint cursor_bottom;
-
-       /* We detect if cursor is visible using the full height, not only the center. This
-          seems to work */
-       gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
-       gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
-                                         &position,
-                                         gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
-       gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
-
-       cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
-       visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
-
-       if (gtk_widget_is_focus (priv->msg_body) && 
-           !visible) {
-               if (priv->last_vadj_upper != adj->upper) {
-                       GtkTextMark *insert;
-                       
-                       insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
-                       gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body), 
-                                                     insert, 0.1, FALSE, 0.0, 0.0);
+       ModestPair *account_pair = NULL;
+       TnyHeader *header = tny_msg_get_header (msg);
+
+       if (header != NULL && tny_header_get_from (header)) {
+               char *from_addr = modest_text_utils_get_email_address (tny_header_get_from (header));
+               GSList *iter;
+               for (iter = transports; iter && !account_pair; iter = iter->next) {
+                       ModestPair *pair = (ModestPair *) iter->data;
+                       char *account_addr = modest_text_utils_get_email_address ((char *) pair->second);
+                       if (account_addr && !strcasecmp(from_addr, account_addr)) {
+                               account_pair = pair;
+                       }
+                       g_free (account_addr);
+               }
+               g_free (from_addr);
+       }
+
+       if (header)
+               g_object_unref (header);
+
+       return account_pair;
+}
+
+static void window_focus (GtkWindow *window,
+                         GtkWidget *widget,
+                         gpointer userdata)
+{
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
+}
+
+gboolean
+scroll_drag_timeout (gpointer userdata)
+{
+       ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
+       ModestMsgEditWindowPrivate *priv;
+
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
+
+       correct_scroll_without_drag_check (win, TRUE);
+
+       priv->scroll_drag_timeout_id = 0;
+
+       return FALSE;
+}
+
+static void
+correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
+{
+       ModestMsgEditWindowPrivate *priv;
+       GtkTextMark *insert;
+       GtkTextIter iter;
+       GdkRectangle rectangle;
+       GtkAdjustment *vadj;
+       gdouble new_value;
+       gint offset;
+       GdkWindow *window;
+
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
+
+       if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
+               return;
+
+       insert = gtk_text_buffer_get_insert (priv->text_buffer);
+       gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
+
+       gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
+       vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll));
+       offset = priv->msg_body->allocation.y;
+
+       new_value = vadj->value;
+       
+       if ((offset + rectangle.y + rectangle.height) > 
+           ((gint) (vadj->value +vadj->page_size))) {
+               new_value = (offset + rectangle.y) - vadj->page_size * 0.25;
+               if (new_value > vadj->upper - vadj->page_size)
+                       new_value = vadj->upper - vadj->page_size;
+       } else if ((offset + rectangle.y) < ((gint) vadj->value)) {
+               new_value = (offset + rectangle.y - vadj->page_size * 0.75);
+               if (((gint) (new_value + vadj->page_size)) < (offset + rectangle.y + rectangle.height))
+                       new_value = offset + rectangle.y + rectangle.height - (gint) vadj->page_size;
+               if (new_value < 0.0)
+                       new_value = 0.0;
+               if (new_value > vadj->value)
+                       new_value = vadj->value;
+       }
+
+       if (vadj->value != new_value) {
+               g_signal_emit_by_name (GTK_TEXT_VIEW(priv->msg_body)->layout,
+                                      "invalidated");
+               vadj->value = new_value;
+               gtk_adjustment_value_changed (vadj);
+               /* invalidate body */
+               window = gtk_widget_get_parent_window (priv->msg_body);
+               if (window)
+                       gdk_window_invalidate_rect (window, NULL, TRUE);
+       }
+
+}
+
+static void
+correct_scroll (ModestMsgEditWindow *w)
+{
+       ModestMsgEditWindowPrivate *priv;
+
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
+       if (gtk_grab_get_current () == priv->msg_body) {
+               if (priv->scroll_drag_timeout_id == 0) {
+                       priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
+                                                                     (gpointer) w);
                }
+               return;
+       }
+
+       correct_scroll_without_drag_check (w, TRUE);
+}
+
+static void
+text_buffer_end_user_action (GtkTextBuffer *buffer,
+                            ModestMsgEditWindow *userdata)
+{
+
+       correct_scroll (userdata);
+}
+
+static void
+text_buffer_mark_set (GtkTextBuffer *buffer,
+                     GtkTextIter *iter,
+                     GtkTextMark *mark,
+                     ModestMsgEditWindow *userdata)
+{
+       gtk_text_buffer_begin_user_action (buffer);
+       gtk_text_buffer_end_user_action (buffer);
+}
+
+static void
+cut_clipboard_check (GtkTextView *text_view,
+                    gpointer userdata)
+{
+       GtkTextBuffer *buffer;
+       
+       buffer = gtk_text_view_get_buffer (text_view);
+       if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
+               g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
        }
-       priv->last_vadj_upper = adj->upper;
 }
 
+static void
+copy_clipboard_check (GtkTextView *text_view,
+                    gpointer userdata)
+{
+       GtkTextBuffer *buffer;
+       
+       buffer = gtk_text_view_get_buffer (text_view);
+       if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
+               g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
+       }
+}
+
+void vadj_changed (GtkAdjustment *adj,
+                  ModestMsgEditWindow *window)
+{
+       ModestMsgEditWindowPrivate *priv;
+
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
+
+       if (priv->last_upper != adj->upper) {
+               priv->last_upper = adj->upper;
+               correct_scroll (window);
+       }
+}
 
 static void
 connect_signals (ModestMsgEditWindow *obj)
@@ -516,9 +693,15 @@ connect_signals (ModestMsgEditWindow *obj)
                          G_CALLBACK (text_buffer_can_redo), obj);
        g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
                           G_CALLBACK (body_changed), obj);
+       g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text", 
+                         G_CALLBACK (text_buffer_insert_text), obj);
        g_signal_connect (G_OBJECT (obj), "window-state-event",
                          G_CALLBACK (modest_msg_edit_window_window_state_event),
                          NULL);
+       g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
+                         G_CALLBACK (text_buffer_end_user_action), obj);
+       g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
+                         G_CALLBACK (text_buffer_mark_set), obj);
        g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
                                G_CALLBACK (text_buffer_apply_tag), obj);
        g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
@@ -535,6 +718,7 @@ connect_signals (ModestMsgEditWindow *obj)
                          G_CALLBACK (msg_body_focus), obj);
        g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
                          G_CALLBACK (msg_body_focus), obj);
+       g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
        g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
                          "changed", G_CALLBACK (recpt_field_changed), obj);
        g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
@@ -560,6 +744,9 @@ connect_signals (ModestMsgEditWindow *obj)
                g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
                                  G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
 
+       g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
+       g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
+
 }
 
 static void
@@ -574,7 +761,6 @@ init_window (ModestMsgEditWindow *obj)
        GError *error = NULL;
 
        GtkSizeGroup *size_group;
-       GtkWidget *frame;
        GtkWidget *subject_box;
        GtkWidget *attachment_icon;
        GtkWidget *window_box;
@@ -714,22 +900,19 @@ init_window (ModestMsgEditWindow *obj)
        main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
 
        gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
-       frame = gtk_frame_new (NULL);
-       gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
+       priv->frame = gtk_frame_new (NULL);
+       gtk_box_pack_start (GTK_BOX(main_vbox), priv->frame, TRUE, TRUE, 0);
 
        gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
        gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
-       g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
-                         "changed",
-                         G_CALLBACK (vadj_changed),
-                         obj);
        gtk_widget_show_all (GTK_WIDGET(priv->scroll));
        
        window_box = gtk_vbox_new (FALSE, 0);
-       gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
        gtk_container_add (GTK_CONTAINER(obj), window_box);
-       priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
-       gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
+
+       gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
+
+       gtk_container_add (GTK_CONTAINER (priv->frame), priv->msg_body);
 
        /* Set window icon */
        window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
@@ -794,14 +977,16 @@ modest_msg_edit_window_finalize (GObject *obj)
                g_object_unref (priv->outbox_msg);
                priv->outbox_msg = NULL;
        }
+       if (priv->scroll_drag_timeout_id > 0) {
+               g_source_remove (priv->scroll_drag_timeout_id);
+               priv->scroll_drag_timeout_id = 0;
+       }
        g_free (priv->msg_uid);
        g_free (priv->last_search);
        g_slist_free (priv->font_items_group);
        g_slist_free (priv->size_items_group);
-       g_list_foreach (priv->attachments, (GFunc) g_object_unref, NULL);
-       g_list_free (priv->attachments);
-       g_list_foreach (priv->images, (GFunc) g_object_unref, NULL);
-       g_list_free (priv->images);
+       g_object_unref (priv->attachments);
+       g_object_unref (priv->images);
 
        /* This had to stay alive for as long as the combobox that used it: */
        modest_pair_list_free (priv->from_field_protos);
@@ -810,30 +995,43 @@ modest_msg_edit_window_finalize (GObject *obj)
 }
 
 static GdkPixbuf *
-pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
+pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
 {
        GdkPixbufLoader *loader;
        GdkPixbuf *pixbuf;
+       guint64 size;
+       
+       size = 0;
 
        loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
 
-       if (loader == NULL)
+       if (loader == NULL) {
+               if (stream_size)
+                       *stream_size = 0;
                return NULL;
+       }
 
        tny_stream_reset (TNY_STREAM (stream));
        while (!tny_stream_is_eos (TNY_STREAM (stream))) {
+               GError *error = NULL;
                unsigned char read_buffer[128];
                gint readed;
                readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
-               if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
+               size += readed;
+               if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
                        break;
+               }
        }
 
        pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-       g_object_ref (pixbuf);
+       if (pixbuf) 
+               g_object_ref (pixbuf);
        gdk_pixbuf_loader_close (loader, NULL);
        g_object_unref (loader);
 
+       if (!pixbuf)
+               return NULL;
+
        if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
                GdkPixbuf *new_pixbuf;
                gint new_height;
@@ -844,32 +1042,44 @@ pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
                pixbuf = new_pixbuf;
        }
 
+       if (stream_size)
+               *stream_size = size;
+
        return pixbuf;
 }
 
 static void
-replace_with_images (ModestMsgEditWindow *self, GList *attachments)
+replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
 {
        ModestMsgEditWindowPrivate *priv;
-       GList *node;
+       TnyIterator *iter;
 
        priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
 
-       for (node = attachments; node != NULL; node = g_list_next (node)) {
-               TnyMimePart *part = (TnyMimePart *) node->data;
+       for (iter = tny_list_create_iterator (attachments);
+            !tny_iterator_is_done (iter);
+            tny_iterator_next (iter)) {
+               TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
                const gchar *cid = tny_mime_part_get_content_id (part);
                const gchar *mime_type = tny_mime_part_get_content_type (part);
                if ((cid != NULL)&&(mime_type != NULL)) {
-                       TnyStream *stream = tny_mime_part_get_stream (part);
-                       GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
+                       guint64 stream_size;
+                       TnyStream *stream = tny_mime_part_get_decoded_stream (part);
+                       GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
+
+
                        g_object_unref (stream);
 
                        if (pixbuf != NULL) {
+                               priv->images_count ++;
+                               priv->images_size += stream_size;
                                wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
                                g_object_unref (pixbuf);
                        }
                }
+               g_object_unref (part);
        }
+       g_object_unref (iter);
 }
 
 static void
@@ -916,10 +1126,9 @@ get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
                        part = TNY_MIME_PART (tny_iterator_get_current (iter));
                        content_type = tny_mime_part_get_content_type (part);
                        if (content_type && g_str_has_prefix (content_type, "image/")) {
-                               priv->images = g_list_prepend (priv->images, part);
-                       } else {
-                               g_object_unref (part);
-                       }
+                               tny_list_prepend (priv->images, (GObject *) part);
+                       } 
+                       g_object_unref (part);
                        tny_iterator_next (iter);
                }
                g_object_unref (iter);
@@ -929,13 +1138,15 @@ get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
 }
 
 static void
-update_last_cid (ModestMsgEditWindow *self, GList *attachments)
+update_last_cid (ModestMsgEditWindow *self, TnyList *attachments)
 {
-       GList *node;
+       TnyIterator *iter;
        ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
 
-       for (node = attachments; node != NULL; node = g_list_next (node)) {
-               TnyMimePart *part = (TnyMimePart *) node->data;
+       for (iter = tny_list_create_iterator (attachments) ; 
+            !tny_iterator_is_done (iter);
+            tny_iterator_next (iter)) {
+               TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
                const gchar *cid = tny_mime_part_get_content_id (part);
                if (cid != NULL) {
                        char *invalid = NULL;
@@ -944,8 +1155,9 @@ update_last_cid (ModestMsgEditWindow *self, GList *attachments)
                                priv->last_cid = int_cid;
                        }
                }
-               
+               g_object_unref (part);
        }
+       g_object_unref (iter);
 }
 
 static void
@@ -1015,7 +1227,7 @@ set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
        /* Add attachments to the view */
        modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
        priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
-       if (priv->attachments == NULL) {
+       if (tny_list_get_length (priv->attachments) == 0) {
                gtk_widget_hide (priv->attachments_caption);
        } else {
                gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
@@ -1049,9 +1261,10 @@ set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
        gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
        gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
 
-       modest_msg_edit_window_reset_modified (self);
+       modest_msg_edit_window_set_modified (self, FALSE);
 
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
        text_buffer_can_undo (priv->text_buffer, FALSE, self);
        text_buffer_can_redo (priv->text_buffer, FALSE, self);
 
@@ -1305,14 +1518,19 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean pre
                
        modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
 
-       account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
+       account_pair = find_transport_from_message_sender (priv->from_field_protos, msg);
+       if (account_pair == NULL) {
+               account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
+       }
        if (account_pair != NULL)
                modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
 
+       priv->original_account_name = account_pair ? (const gchar *) account_pair->first : NULL;
+
        parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
-       menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
-       toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
-       clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
+       menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
+       toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
+       clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
        /* Add common dimming rules */
        modest_dimming_rules_group_add_rules (menu_rules_group, 
                                              modest_msg_edit_window_menu_dimming_entries,
@@ -1343,17 +1561,18 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean pre
        g_object_unref (menu_rules_group);
        g_object_unref (toolbar_rules_group);
        g_object_unref (clipboard_rules_group);
-       gtk_widget_show_all (GTK_WIDGET (obj));
+       modest_msg_edit_window_clipboard_owner_change (NULL, NULL, MODEST_MSG_EDIT_WINDOW (obj));
 
        set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
 
        text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
 
-        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
-       modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
+       modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
        priv->update_caption_visibility = TRUE;
 
-       modest_msg_edit_window_reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
+       modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
 
        /* Track account-removed signal, this window should be closed
           in the case we're creating a mail associated to the account
@@ -1390,6 +1609,8 @@ get_formatted_data (ModestMsgEditWindow *edit_window)
 
        wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
 
+       gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
+
        return g_string_free (string_buffer, FALSE);
                                                                        
 }
@@ -1400,6 +1621,7 @@ modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
        MsgData *data;
        const gchar *account_name;
        ModestMsgEditWindowPrivate *priv;
+       TnyIterator *att_iter;
        
        g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
 
@@ -1437,30 +1659,35 @@ modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
                data->html_body = NULL;
 
        /* deep-copy the data */
-       GList *cursor = priv->attachments;
+       att_iter = tny_list_create_iterator (priv->attachments);
        data->attachments = NULL;
-       while (cursor) {
-               if (!(TNY_IS_MIME_PART(cursor->data))) {
+       while (!tny_iterator_is_done (att_iter)) {
+               TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
+               if (!(TNY_IS_MIME_PART(part))) {
                        g_warning ("strange data in attachment list");
-                       cursor = g_list_next (cursor);
+                       g_object_unref (part);
+                       tny_iterator_next (att_iter);
                        continue;
                }
                data->attachments = g_list_append (data->attachments,
-                                                  g_object_ref (cursor->data));
-               cursor = g_list_next (cursor);
+                                                  part);
+               tny_iterator_next (att_iter);
        }
+       g_object_unref (att_iter);
 
        GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
-       cursor = priv->images;
+       att_iter = tny_list_create_iterator (priv->images);
        data->images = NULL;
-       while (cursor) {
+       while (!tny_iterator_is_done (att_iter)) {
+               TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
                const gchar *cid;
-               if (!(TNY_IS_MIME_PART(cursor->data))) {
+               if (!(TNY_IS_MIME_PART(part))) {
                        g_warning ("strange data in attachment list");
-                       cursor = g_list_next (cursor);
+                       g_object_unref (part);
+                       tny_iterator_next (att_iter);
                        continue;
                }
-               cid = tny_mime_part_get_content_id (cursor->data);
+               cid = tny_mime_part_get_content_id (part);
                if (cid) {                      
                        gchar *image_tag_id;
                        GtkTextTag *image_tag;
@@ -1474,10 +1701,12 @@ modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
                            ((gtk_text_iter_has_tag (&iter, image_tag))||
                             (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
                                data->images = g_list_append (data->images,
-                                                             g_object_ref (cursor->data));
+                                                             g_object_ref (part));
                }
-               cursor = g_list_next (cursor);
+               g_object_unref (part);
+               tny_iterator_next (att_iter);
        }
+       g_object_unref (att_iter);
        
        data->priority_flags = priv->priority_flags;
 
@@ -1524,6 +1753,23 @@ modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
        g_slice_free (MsgData, data);
 }
 
+void                    
+modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
+                                      gint *parts_count,
+                                      guint64 *parts_size)
+{
+       ModestMsgEditWindowPrivate *priv;
+
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
+
+       modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
+
+       /* TODO: add images */
+       *parts_size += priv->images_size;
+       *parts_count += priv->images_count;
+
+}
+
 ModestMsgEditFormat
 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
 {
@@ -1664,6 +1910,8 @@ modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
        }
 /*     wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
        
+       text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
+       
        g_free (current_format);
 
 }
@@ -1702,6 +1950,25 @@ text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *windo
 /*     action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
 /*     modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
 
+       action = NULL;
+       switch (buffer_format->justification)
+       {
+       case GTK_JUSTIFY_LEFT:
+               action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
+               break;
+       case GTK_JUSTIFY_CENTER:
+               action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
+               break;
+       case GTK_JUSTIFY_RIGHT:
+               action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
+               break;
+       default:
+               break;
+       }
+       
+       if (action != NULL)
+               gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+       
        g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
                                         G_CALLBACK (modest_msg_edit_window_color_button_change),
                                         window);
@@ -1915,12 +2182,13 @@ modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
                result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
                if (result == GNOME_VFS_OK) {
                        GdkPixbuf *pixbuf;
-                       GnomeVFSFileInfo info;
+                       GnomeVFSFileInfo *info;
                        gchar *filename, *basename, *escaped_filename;
                        TnyMimePart *mime_part;
                        gchar *content_id;
                        const gchar *mime_type = NULL;
                        GnomeVFSURI *vfs_uri;
+                       guint64 stream_size;
 
                        vfs_uri = gnome_vfs_uri_new (uri);
 
@@ -1928,17 +2196,18 @@ modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
                        filename = gnome_vfs_unescape_string_for_display (escaped_filename);
                        g_free (escaped_filename);
                        gnome_vfs_uri_unref (vfs_uri);
+                       info = gnome_vfs_file_info_new ();
 
-                       if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
+                       if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
                                                     | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
                            == GNOME_VFS_OK)
-                               mime_type = gnome_vfs_file_info_get_mime_type (&info);
+                               mime_type = gnome_vfs_file_info_get_mime_type (info);
 
                        mime_part = tny_platform_factory_new_mime_part
                                (modest_runtime_get_platform_factory ());
                                
                        TnyStream *stream = create_stream_for_uri (uri);
-                       tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
+                       tny_mime_part_construct (mime_part, stream, mime_type, "base64");
                        
                        content_id = g_strdup_printf ("%d", priv->last_cid);
                        tny_mime_part_set_content_id (mime_part, content_id);
@@ -1949,17 +2218,21 @@ modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
                        tny_mime_part_set_filename (mime_part, basename);
                        g_free (basename);
 
-                       pixbuf = pixbuf_from_stream (stream, mime_type);
+                       pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
                        
                        if (pixbuf != NULL) {
+                               priv->images_size += stream_size;
+                               priv->images_count ++;
                                insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
                                gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
                                wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
                        } 
 
-                       priv->images = g_list_prepend (priv->images, mime_part);
+                       tny_list_prepend (priv->images, (GObject *) mime_part);
                        gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
                        g_free (filename);
+                       g_object_unref (mime_part);
+                       gnome_vfs_file_info_unref (info);
 
                }
        }
@@ -2002,14 +2275,16 @@ modest_msg_edit_window_attach_file_one (
                ModestMsgEditWindow *window,
                const gchar *uri)
 {
+       GnomeVFSHandle *handle = NULL;
+       ModestMsgEditWindowPrivate *priv;
+       GnomeVFSResult result;
+
        g_return_if_fail (window);
        g_return_if_fail (uri);
                
-       ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
-       
+       priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
        
-       GnomeVFSHandle *handle = NULL;
-       GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
+       result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
        if (result == GNOME_VFS_OK) {
                TnyMimePart *mime_part;
                TnyStream *stream;
@@ -2018,7 +2293,7 @@ modest_msg_edit_window_attach_file_one (
                gchar *escaped_filename;
                gchar *filename;
                gchar *content_id;
-               GnomeVFSFileInfo info;
+               GnomeVFSFileInfo *info;
                GnomeVFSURI *vfs_uri;
 
                vfs_uri = gnome_vfs_uri_new (uri);
@@ -2028,17 +2303,21 @@ modest_msg_edit_window_attach_file_one (
                filename = gnome_vfs_unescape_string_for_display (escaped_filename);
                g_free (escaped_filename);
                gnome_vfs_uri_unref (vfs_uri);
+
+               info = gnome_vfs_file_info_new ();
                
                if (gnome_vfs_get_file_info (uri, 
-                                            &info, 
+                                            info, 
                                             GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
                    == GNOME_VFS_OK)
-                       mime_type = gnome_vfs_file_info_get_mime_type (&info);
+                       mime_type = gnome_vfs_file_info_get_mime_type (info);
                mime_part = tny_platform_factory_new_mime_part
                        (modest_runtime_get_platform_factory ());
                stream = TNY_STREAM (tny_vfs_stream_new (handle));
                
-               tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
+               tny_mime_part_construct (mime_part, stream, mime_type, "base64");
+
+               g_object_unref (stream);
                
                content_id = g_strdup_printf ("%d", priv->last_cid);
                tny_mime_part_set_content_id (mime_part, content_id);
@@ -2049,43 +2328,50 @@ modest_msg_edit_window_attach_file_one (
                tny_mime_part_set_filename (mime_part, basename);
                g_free (basename);
                
-               priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
+               tny_list_prepend (priv->attachments, (GObject *) mime_part);
                modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
-                                                       mime_part);
+                                                       mime_part,
+                                                       info->size == 0, info->size);
                gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
                gtk_widget_show_all (priv->attachments_caption);
                gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
                g_free (filename);
+               g_object_unref (mime_part);
+               gnome_vfs_file_info_unref (info);
        }
 }
 
 void
 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
-                                         GList *att_list)
+                                          TnyList *att_list)
 {
        ModestMsgEditWindowPrivate *priv;
-       gboolean clean_list = FALSE;
+       TnyIterator *iter;
 
        g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
        priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
 
        if (att_list == NULL) {
                att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
-               clean_list = TRUE;
+       } else {
+               g_object_ref (att_list);
        }
 
-       if (att_list == NULL) {
+       if (tny_list_get_length (att_list) == 0) {
                hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
        } else {
                GtkWidget *confirmation_dialog = NULL;
                gboolean dialog_response;
-               GList *node;
                gchar *message = NULL;
                gchar *filename = NULL;
 
-               if (att_list->next == NULL) {
-                       if (TNY_IS_MSG (att_list->data)) {
-                               TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
+               if (tny_list_get_length (att_list) == 1) {
+                       TnyMimePart *part;
+                       iter = tny_list_create_iterator (att_list);
+                       part = (TnyMimePart *) tny_iterator_get_current (iter);
+                       g_object_unref (iter);
+                       if (TNY_IS_MSG (part)) {
+                               TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
                                if (header) {
                                        filename = g_strdup (tny_header_get_subject (header));
                                        g_object_unref (header);
@@ -2094,45 +2380,51 @@ modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
                                        filename = g_strdup (_("mail_va_no_subject"));
                                }
                        } else {
-                               filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
+                               filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
                        }
+                       g_object_unref (part);
                } else {
                        filename = g_strdup ("");
                }
                message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
-                                                   att_list->next == NULL), filename);
+                                                   (tny_list_get_length (att_list) == 1)), filename);
                g_free (filename);
                confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
                g_free (message);
                dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
                gtk_widget_destroy (confirmation_dialog);
                if (!dialog_response) {
-                       if (clean_list)
-                               g_list_free (att_list);
+                       g_object_unref (att_list);
                        return;
                }
                hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
-
-               for (node = att_list; node != NULL; node = g_list_next (node)) {
-                       TnyMimePart *mime_part = (TnyMimePart *) node->data;
+               
+               for (iter = tny_list_create_iterator (att_list);
+                    !tny_iterator_is_done (iter);
+                    tny_iterator_next (iter)) {
+                       TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
                        const gchar *att_id;
-                       priv->attachments = g_list_remove (priv->attachments, mime_part);
+                       tny_list_remove (priv->attachments, (GObject *) mime_part);
 
                        modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
                                                                   mime_part);
-                       if (priv->attachments == NULL)
+                       if (tny_list_get_length (priv->attachments) == 0)
                                gtk_widget_hide (priv->attachments_caption);
                        att_id = tny_mime_part_get_content_id (mime_part);
                        if (att_id != NULL)
                                text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
                                                                 att_id);
-                       g_object_unref (mime_part);
                        gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
+                       g_object_unref (mime_part);
                }
+               g_object_unref (iter);
        }
 
-       if (clean_list)
-               g_list_free (att_list);
+       g_object_unref (att_list);
+
+       /* if the last attachment has been removed, focus the Subject: field */
+       if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
+               gtk_widget_grab_focus (priv->subject_field);
 }
 
 static void
@@ -2602,6 +2894,7 @@ modest_msg_edit_window_undo (ModestMsgEditWindow *window)
        wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
 
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
 
 }
 
@@ -2616,6 +2909,7 @@ modest_msg_edit_window_redo (ModestMsgEditWindow *window)
        wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
 
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
 
 }
 
@@ -2712,6 +3006,8 @@ msg_body_focus (GtkWidget *focus,
 {
        
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
        return FALSE;
 }
 
@@ -2720,33 +3016,37 @@ recpt_field_changed (GtkTextBuffer *buffer,
                  ModestMsgEditWindow *editor)
 {
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
 }
 
 static void
 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
 {
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
 }
 
 void
-modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
+modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
+                                    gboolean modified)
 {
        ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
        GtkTextBuffer *buffer;
 
        buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
-       gtk_text_buffer_set_modified (buffer, FALSE);
+       gtk_text_buffer_set_modified (buffer, modified);
        buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
-       gtk_text_buffer_set_modified (buffer, FALSE);
+       gtk_text_buffer_set_modified (buffer, modified);
        buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
-       gtk_text_buffer_set_modified (buffer, FALSE);
-       gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
+       gtk_text_buffer_set_modified (buffer, modified);
+       gtk_text_buffer_set_modified (priv->text_buffer, modified);
 }
 
 gboolean
 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
 {
        ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
+       const char *account_name;
        GtkTextBuffer *buffer;
 
        buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
@@ -2760,6 +3060,10 @@ modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
                return TRUE;
        if (gtk_text_buffer_get_modified (priv->text_buffer))
                return TRUE;
+       account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
+       if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
+               return TRUE;
+       }
 
        return FALSE;
 }
@@ -2838,7 +3142,7 @@ modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
        }
        priv->clipboard_text = text;
 
-       modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
 }
 static void 
 subject_field_move_cursor (GtkEntry *entry,
@@ -2850,7 +3154,7 @@ subject_field_move_cursor (GtkEntry *entry,
        if (!GTK_WIDGET_VISIBLE (window))
                return;
 
-       modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
+       modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
 }
 
 static void 
@@ -2876,6 +3180,7 @@ subject_field_changed (GtkEditable *editable,
        update_window_title (window);
        gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
        modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
+       modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
 }
 
 static void  
@@ -2928,6 +3233,48 @@ subject_field_insert_text (GtkEditable *editable,
        g_string_free (result, TRUE);
 }
 
+static void  
+text_buffer_insert_text (GtkTextBuffer *buffer, 
+                        GtkTextIter *iter,
+                        gchar *new_text,
+                        gint new_text_length,
+                        ModestMsgEditWindow *window)
+{
+       GString *result = g_string_new ("");
+       gchar *current;
+       gint result_len = 0;
+       gboolean changed = FALSE;
+
+       for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
+               gunichar c = g_utf8_get_char_validated (current, 8);
+               /* Invalid unichar, stop */
+               if (c == -1)
+                       break;
+               /* a bullet */
+               switch (c) {
+               case 0x2022:
+                       result = g_string_append_c (result, ' ');
+                       changed = TRUE;
+                       break;
+               default:
+                       result = g_string_append_unichar (result, c);
+               }
+               result_len++;
+       }
+
+       if (changed) {
+               g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
+               g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
+               g_signal_emit_by_name (buffer, "insert-text", 
+                                      (gpointer) iter,
+                                      (gpointer) result->str, (gpointer) result->len,
+                                      (gpointer) window);
+               g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
+       }
+
+       g_string_free (result, TRUE);
+}
+
 void
 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
                                            gboolean show)
@@ -3060,6 +3407,7 @@ modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
        if (result) {
                gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
                gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
+               correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
        } else {
                g_free (priv->last_search);
                priv->last_search = NULL;
@@ -3154,9 +3502,8 @@ modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
        ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
 
        g_return_if_fail (TNY_IS_MIME_PART (part));
-       priv->attachments = g_list_prepend (priv->attachments, part);
-       g_object_ref (part);
-       modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
+       tny_list_prepend (priv->attachments, (GObject *) part);
+       modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
        gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
        gtk_widget_show_all (priv->attachments_caption);
        gtk_text_buffer_set_modified (priv->text_buffer, TRUE);