Copy only "X-as" headers from original emails, not all of them
[modest] / src / hildon2 / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38 #include <tny-camel-mem-stream.h>
39 #include <modest-account-protocol.h>
40
41 #include <config.h>
42
43 #include <modest-account-mgr.h>
44 #include <modest-account-mgr-helpers.h>
45
46 #include <widgets/modest-msg-edit-window.h>
47 #include <modest-selector-picker.h>
48 #include <widgets/modest-recpt-editor.h>
49 #include <widgets/modest-attachments-view.h>
50
51 #include <modest-runtime.h>
52
53 #include "modest-platform.h"
54 #include "modest-icon-names.h"
55 #include "modest-widget-memory.h"
56 #include "modest-window-priv.h"
57 #include "modest-mail-operation.h"
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-tny-folder.h"
61 #include "modest-tny-account.h"
62 #include "modest-address-book.h"
63 #include "modest-text-utils.h"
64 #include <tny-simple-list.h>
65 #include <modest-wp-text-view.h>
66 #include <wptextbuffer.h>
67 #include <hildon/hildon-pannable-area.h>
68 #include <hildon/hildon-touch-selector.h>
69 #include <hildon/hildon-picker-dialog.h>
70 #include "modest-msg-edit-window-ui-dimming.h"
71
72 #include "modest-hildon-includes.h"
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #include <modest-utils.h>
76 #include "modest-maemo-utils.h"
77 #include <modest-ui-constants.h>
78 #include "modest-color-button.h"
79
80 #ifdef MODEST_USE_CALENDAR_WIDGETS
81 #include <calendar-ui-widgets.h>
82 #endif
83
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 0
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91 #define ATTACHMENT_BUTTON_WIDTH 118
92 #define MAX_FROM_VALUE 36
93 #define MAX_BODY_LENGTH 128*1024
94 #define MAX_BODY_LINES 2048
95
96 static gboolean is_wp_text_buffer_started = FALSE;
97
98 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
99 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
100 static void  modest_msg_edit_window_finalize     (GObject *obj);
101
102 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
103 static void  body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
104 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
105
106 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
107 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
108 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
109 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
110                                     GtkTextIter *start, GtkTextIter *end,
111                                     gpointer userdata);
112 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
113 static void  body_insert_text (GtkTextBuffer *buffer, 
114                                       GtkTextIter *location,
115                                       gchar *text,
116                                       gint len,
117                                       ModestMsgEditWindow *window);
118 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
119 static void  subject_field_insert_text (GtkEditable *editable, 
120                                         gchar *new_text,
121                                         gint new_text_length,
122                                         gint *position,
123                                         ModestMsgEditWindow *window);
124 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
125                                                          gpointer userdata);
126 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
127
128 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
129                                                      ModestRecptEditor *editor);
130 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
131                                                            ModestMsgEditWindow *window);
132
133 /* ModestWindow methods implementation */
134 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
135 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
136                                                    gboolean show_toolbar);
137 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
138                                                            GdkEvent *event,
139                                                            ModestMsgEditWindow *window);
140 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
141 static void subject_field_move_cursor (GtkEntry *entry,
142                                        GtkMovementStep step,
143                                        gint a1,
144                                        gboolean a2,
145                                        gpointer userdata);
146 static void update_window_title (ModestMsgEditWindow *window);
147
148 /* Find toolbar */
149 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
150                                                         ModestMsgEditWindow *window);
151 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
152                                                        ModestMsgEditWindow *window);
153 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
154                                                           const gchar *str,
155                                                           GtkTextIter *match_start,
156                                                           GtkTextIter *match_end);
157
158 static void remove_tags (WPTextBuffer *buffer);
159
160 static void on_account_removed (TnyAccountStore *account_store, 
161                                 TnyAccount *account,
162                                 gpointer user_data);
163
164 static void init_window (ModestMsgEditWindow *obj);
165
166 gboolean scroll_drag_timeout (gpointer userdata);
167 static void correct_scroll (ModestMsgEditWindow *w);
168 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
169 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
170                                          ModestMsgEditWindow *userdata);
171 static void text_buffer_mark_set (GtkTextBuffer *buffer,
172                                   GtkTextIter *iter,
173                                   GtkTextMark *mark,
174                                   ModestMsgEditWindow *userdata);
175 static void on_show_toolbar_button_toggled (HildonCheckButton *button,
176                                             ModestMsgEditWindow *window);
177 static void on_message_settings (GtkAction *action,
178                                  ModestMsgEditWindow *window);
179 static void setup_menu (ModestMsgEditWindow *self);
180
181 static void from_field_changed (HildonPickerButton *button,
182                                 ModestMsgEditWindow *self);
183 static void font_size_clicked (GtkToolButton *button,
184                                ModestMsgEditWindow *window);
185 static void font_face_clicked (GtkToolButton *button,
186                                ModestMsgEditWindow *window);
187 static void update_signature (ModestMsgEditWindow *self,
188                               const gchar *old_account, 
189                               const gchar *new_account);
190 static void update_branding (ModestMsgEditWindow *self,
191                              const gchar *new_account);
192 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
193                                            const gchar *label, GtkWidget *control);
194 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
195 static void DEBUG_BUFFER (WPTextBuffer *buffer)
196 {
197 #ifdef DEBUG
198         GtkTextIter iter;
199         g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
200
201         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
202         while (!gtk_text_iter_is_end (&iter)) {
203                 GString *output = g_string_new ("");
204                 GSList *toggled_tags;
205                 GSList *node;
206
207                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
208                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
209                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
210                         GtkTextTag *tag = (GtkTextTag *) node->data;
211                         const gchar *name;
212                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
213                         output = g_string_append (output, name);
214                         g_string_append (output, " ");
215                 }
216                 output = g_string_append (output, "] OPENED [ ");
217                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
218                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
219                         GtkTextTag *tag = (GtkTextTag *) node->data;
220                         const gchar *name;
221                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
222                         output = g_string_append (output, name);
223                         g_string_append (output, " ");
224                 }
225                 output = g_string_append (output, "]\n");
226                 g_debug ("%s", output->str);
227                 g_string_free (output, TRUE);
228                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
229         }
230         g_debug ("END BUFFER");
231 #endif
232 }
233
234 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
235         { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
236 };
237
238
239 /* static gboolean */
240 /* on_key_pressed (GtkWidget *self, */
241 /*              GdkEventKey *event, */
242 /*              gpointer user_data); */
243
244 /* list my signals */
245 enum {
246         /* MY_SIGNAL_1, */
247         /* MY_SIGNAL_2, */
248         LAST_SIGNAL
249 };
250
251 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
252 struct _ModestMsgEditWindowPrivate {
253         GtkWidget   *msg_body;
254         GtkWidget   *header_box;
255         
256         ModestPairList *from_field_protos;
257         GtkWidget   *from_field;
258         gchar       *last_from_account;
259         gchar       *original_account_name;
260
261         gchar       *references;
262         gchar       *in_reply_to;
263
264         gchar       *original_mailbox;
265         
266         GtkWidget   *to_field;
267         GtkWidget   *cc_field;
268         GtkWidget   *bcc_field;
269         GtkWidget   *subject_field;
270         GtkWidget   *attachments_view;
271         GtkWidget   *priority_icon;
272         GtkWidget   *subject_box;
273         GtkWidget   *send_button;
274         GtkWidget   *bottom_send_button;
275         GtkWidget   *bottom_send_button_container;
276
277         GtkWidget   *cc_caption;
278         GtkWidget   *bcc_caption;
279         gboolean     update_caption_visibility;
280         GtkWidget   *attachments_caption;
281
282         GtkTextBuffer *text_buffer;
283
284         GtkWidget   *font_size_toolitem;
285         GtkWidget   *font_face_toolitem;
286         GtkWidget   *font_color_button;
287         GtkWidget   *font_color_toolitem;
288         GSList      *font_items_group;
289         GtkTreeModel *faces_model;
290         gint         current_face_index;
291         GtkWidget   *font_tool_button_label;
292         GtkTreeModel *sizes_model;
293         gint         current_size_index;
294         GtkWidget   *size_tool_button_label;
295
296         GtkWidget   *find_toolbar;
297         gchar       *last_search;
298
299         GtkWidget   *font_dialog;
300
301         GtkWidget   *pannable;
302         guint        correct_scroll_idle;
303         guint        scroll_drag_timeout_id;
304         gdouble      last_upper;
305
306         gint next_cid;
307         TnyList *attachments;
308         TnyList *images;
309         guint64 images_size;
310         gint images_count;
311
312         TnyHeaderFlags priority_flags;
313
314         gboolean    can_undo, can_redo;
315         gulong      clipboard_change_handler_id;
316         gulong      default_clipboard_change_handler_id;
317         gulong      account_removed_handler_id;
318         guint       clipboard_owner_idle;
319         gchar       *clipboard_text;
320
321         TnyMsg      *draft_msg;
322         TnyMsg      *outbox_msg;
323         gchar       *msg_uid;
324
325         gboolean    sent;
326
327         GtkWidget   *app_menu;
328         GtkWidget   *cc_button;
329         GtkWidget   *bcc_button;
330         GtkWidget   *show_toolbar_button;
331
332         GtkWidget   *max_chars_banner;
333
334         GtkWidget   *brand_icon;
335         GtkWidget   *brand_label;
336         GtkWidget   *brand_container;
337
338         TnyList     *custom_header_pairs;
339 };
340
341 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
342                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
343                                                     ModestMsgEditWindowPrivate))
344 /* globals */
345 static GtkWindowClass *parent_class = NULL;
346
347 /* uncomment the following if you have defined any signals */
348 /* static guint signals[LAST_SIGNAL] = {0}; */
349
350 GType
351 modest_msg_edit_window_get_type (void)
352 {
353         static GType my_type = 0;
354         if (!my_type) {
355                 static const GTypeInfo my_info = {
356                         sizeof(ModestMsgEditWindowClass),
357                         NULL,           /* base init */
358                         NULL,           /* base finalize */
359                         (GClassInitFunc) modest_msg_edit_window_class_init,
360                         NULL,           /* class finalize */
361                         NULL,           /* class data */
362                         sizeof(ModestMsgEditWindow),
363                         1,              /* n_preallocs */
364                         (GInstanceInitFunc) modest_msg_edit_window_init,
365                         NULL
366                 };
367                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
368                                                   "ModestMsgEditWindow",
369                                                   &my_info, 0);
370
371         }
372         return my_type;
373 }
374
375 static void
376 save_state (ModestWindow *self)
377 {
378         modest_widget_memory_save (modest_runtime_get_conf(),
379                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
380 }
381
382
383 static void
384 restore_settings (ModestMsgEditWindow *self)
385 {
386         ModestConf *conf = NULL;
387
388         conf = modest_runtime_get_conf ();
389
390         /* Dim at start clipboard actions */
391         modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
392 }
393
394
395 static void
396 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
397 {
398         GObjectClass *gobject_class;
399         ModestWindowClass *modest_window_class;
400         gobject_class = (GObjectClass*) klass;
401         modest_window_class = (ModestWindowClass*) klass;
402
403         parent_class            = g_type_class_peek_parent (klass);
404         gobject_class->finalize = modest_msg_edit_window_finalize;
405
406         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
407         modest_window_class->save_state_func = save_state;
408         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
409
410         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
411 }
412
413 static void
414 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
415 {
416         ModestMsgEditWindowPrivate *priv;
417         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
418
419         priv->msg_body      = NULL;
420         priv->from_field    = NULL;
421         priv->to_field      = NULL;
422         priv->cc_field      = NULL;
423         priv->bcc_field     = NULL;
424         priv->subject_field = NULL;
425         priv->attachments   = TNY_LIST (tny_simple_list_new ());
426         priv->images        = TNY_LIST (tny_simple_list_new ());
427         priv->images_size   = 0;
428         priv->images_count  = 0;
429         priv->next_cid      = 0;
430
431         priv->cc_caption    = NULL;
432         priv->bcc_caption    = NULL;
433         priv->update_caption_visibility = FALSE;
434
435         priv->priority_flags = 0;
436
437         priv->find_toolbar = NULL;
438         priv->last_search = NULL;
439
440         priv->draft_msg = NULL;
441         priv->outbox_msg = NULL;
442         priv->msg_uid = NULL;
443
444         priv->can_undo = FALSE;
445         priv->can_redo = FALSE;
446         priv->clipboard_change_handler_id = 0;
447         priv->default_clipboard_change_handler_id = 0;
448         priv->account_removed_handler_id = 0;
449         priv->clipboard_owner_idle = 0;
450         priv->clipboard_text = NULL;
451         priv->sent = FALSE;
452
453         priv->scroll_drag_timeout_id = 0;
454         priv->correct_scroll_idle = 0;
455         priv->last_upper = 0.0;
456
457         priv->font_dialog = NULL;
458         priv->app_menu = NULL;
459
460         priv->references = NULL;
461         priv->in_reply_to = NULL;
462         priv->max_chars_banner = NULL;
463         priv->custom_header_pairs = TNY_LIST (tny_simple_list_new ());
464
465         if (!is_wp_text_buffer_started) {
466                 is_wp_text_buffer_started = TRUE;
467                 wp_text_buffer_library_init ();
468         }
469
470         init_window (obj);
471         
472         hildon_program_add_window (hildon_program_get_instance(),
473                                    HILDON_WINDOW(obj));
474 }
475
476 static gchar *
477 multimailbox_get_default_mailbox (const gchar *account_name)
478 {
479         gchar *transport_account;
480         gchar *result = NULL;
481
482         transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
483                                                                         account_name,
484                                                                         TNY_ACCOUNT_TYPE_TRANSPORT);
485         if (transport_account) {
486                 gchar *proto;
487                 ModestProtocolRegistry *registry;
488
489                 registry = modest_runtime_get_protocol_registry ();
490
491                 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account, 
492                                                        MODEST_ACCOUNT_PROTO, TRUE);
493                 if (proto != NULL) {
494                         ModestProtocol *protocol = 
495                                 modest_protocol_registry_get_protocol_by_name (registry,
496                                                                                MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
497                                                                                proto);
498                         if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
499                                 ModestPairList *pair_list;
500
501                                 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
502                                                                                    account_name);
503                                 if (pair_list) {
504                                         ModestPair *pair = (ModestPair *) pair_list->data;
505                                         result = g_strdup ((const gchar *) pair->first);
506                                         modest_pair_list_free (pair_list);
507                                 }
508                         }
509                         
510                 }
511         }
512
513         return result;
514 }
515
516 /** 
517  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
518  */
519 static ModestPairList*
520 get_transports (void)
521 {
522         GSList *transports = NULL;
523         
524         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
525         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
526                                                              TRUE /* only enabled accounts. */); 
527                                                 
528         GSList *cursor = accounts;
529         while (cursor) {
530                 gchar *account_name = cursor->data;
531                 if (account_name) {
532
533                         gchar *transport_account;
534                         gboolean multi_mailbox = FALSE;
535                         ModestProtocol *protocol = NULL;
536
537                         if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
538
539                                 transport_account = modest_account_mgr_get_server_account_name 
540                                         (modest_runtime_get_account_mgr (),
541                                          account_name,
542                                          TNY_ACCOUNT_TYPE_TRANSPORT);
543                                 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
544                                         ModestPairList *pair_list;
545                                         pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
546                                                                                            account_name);
547                                         if (pair_list) {
548                                                 transports = g_slist_concat (transports, pair_list);
549                                                 multi_mailbox = TRUE;
550                                         }
551                                 }
552                         }
553
554                         if (!multi_mailbox) {
555                                 gchar *from_string  = NULL;
556
557                                 from_string = modest_account_mgr_get_from_string (account_mgr,
558                                                                                   account_name, NULL);
559                                 if (from_string && account_name) {
560                                         gchar *name = account_name;
561                                         ModestPair *pair = modest_pair_new ((gpointer) name,
562                                                                             (gpointer) from_string , TRUE);
563                                         transports = g_slist_prepend (transports, pair);
564                                 }
565                         }
566                 }
567                 
568                 cursor = cursor->next;
569         }
570         g_slist_free (accounts); /* only free the accounts, not the elements,
571                                   * because they are used in the pairlist */
572         return transports;
573 }
574
575 static void window_focus (GtkWindow *window,
576                           GtkWidget *widget,
577                           gpointer userdata)
578 {
579         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
580 }
581
582 gboolean
583 scroll_drag_timeout (gpointer userdata)
584 {
585         ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
586         ModestMsgEditWindowPrivate *priv;
587
588         /* It could happen that the window was already closed */
589         if (!GTK_WIDGET_VISIBLE (win))
590                 return FALSE;
591
592         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
593
594         correct_scroll_without_drag_check (win, TRUE);
595
596         priv->scroll_drag_timeout_id = 0;
597
598         return FALSE;
599 }
600
601 static gboolean 
602 correct_scroll_without_drag_check_idle (gpointer userdata)
603 {
604         ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
605         ModestMsgEditWindowPrivate *priv;
606         GtkTextIter iter;
607         GdkRectangle rectangle;
608         gint offset_min, offset_max;
609         GtkTextMark *insert;
610         GtkAdjustment *vadj;
611
612         /* It could happen that the window was already closed */
613         if (!GTK_WIDGET_VISIBLE (w))
614                 return FALSE;
615
616         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
617
618         insert = gtk_text_buffer_get_insert (priv->text_buffer);
619         gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
620
621         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
622         offset_min = priv->msg_body->allocation.y + rectangle.y;
623         offset_max = offset_min + rectangle.height;
624
625         vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
626         offset_min = MAX (offset_min - 48, 0);
627         offset_max = MIN (offset_max + 48, vadj->upper);
628
629         gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
630
631         priv->correct_scroll_idle = 0;
632         return FALSE;
633 }
634
635 static void
636 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
637 {
638         ModestMsgEditWindowPrivate *priv;
639
640         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
641
642         if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
643                 return;
644
645         if (priv->correct_scroll_idle > 0) {
646                 return;
647         }
648
649         priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
650                                                      (GSourceFunc) correct_scroll_without_drag_check_idle,
651                                                      g_object_ref (w),
652                                                      g_object_unref);
653 }
654
655 static void
656 correct_scroll (ModestMsgEditWindow *w)
657 {
658         ModestMsgEditWindowPrivate *priv;
659
660         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
661         if (gtk_grab_get_current () == priv->msg_body) {
662                 if (priv->scroll_drag_timeout_id == 0) {
663                         priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
664                                                                            500,
665                                                                            (GSourceFunc) scroll_drag_timeout,
666                                                                            g_object_ref (w),
667                                                                            g_object_unref);
668                 }
669                 return;
670         }
671
672         correct_scroll_without_drag_check (w, TRUE);
673 }
674
675 static void
676 text_buffer_end_user_action (GtkTextBuffer *buffer,
677                              ModestMsgEditWindow *userdata)
678 {
679
680         correct_scroll (userdata);
681 }
682
683 static void
684 text_buffer_mark_set (GtkTextBuffer *buffer,
685                       GtkTextIter *iter,
686                       GtkTextMark *mark,
687                       ModestMsgEditWindow *userdata)
688 {
689         gtk_text_buffer_begin_user_action (buffer);
690         gtk_text_buffer_end_user_action (buffer);
691 }
692
693 static void
694 cut_clipboard_check (GtkTextView *text_view,
695                      gpointer userdata)
696 {
697         GtkTextBuffer *buffer;
698         
699         buffer = gtk_text_view_get_buffer (text_view);
700         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
701                 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
702         }
703 }
704
705 static void
706 copy_clipboard_check (GtkTextView *text_view,
707                      gpointer userdata)
708 {
709         GtkTextBuffer *buffer;
710         
711         buffer = gtk_text_view_get_buffer (text_view);
712         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
713                 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
714         }
715 }
716
717 static void
718 attachment_deleted (ModestAttachmentsView *attachments_view,
719                     gpointer user_data)
720 {
721         modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
722                                                    NULL);
723 }
724
725 static void
726 body_size_request (GtkWidget *body,
727                    GtkRequisition *req,
728                    gpointer user_data)
729 {
730         ModestMsgEditWindowPrivate *priv;
731         GtkAdjustment *vadj;
732
733         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(user_data);
734
735         /* Make sure the body always get at least 70 pixels */
736         if (req->height < 70)
737                 req->height = 70;
738
739         vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
740         if (priv->header_box->allocation.height + req->height > GTK_WIDGET (user_data)->allocation.height) {
741                 if (!GTK_WIDGET_VISIBLE (priv->bottom_send_button_container)) {
742                         gtk_widget_show (priv->bottom_send_button_container);
743                 }
744         } else {
745                 if (GTK_WIDGET_VISIBLE (priv->bottom_send_button_container)) {
746                         gtk_widget_hide (priv->bottom_send_button_container);
747                 }
748         }
749 }
750
751 static void
752 connect_signals (ModestMsgEditWindow *obj)
753 {
754         ModestMsgEditWindowPrivate *priv;
755
756         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
757
758         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
759                           G_CALLBACK (text_buffer_refresh_attributes), obj);
760         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
761                           G_CALLBACK (text_buffer_can_undo), obj);
762         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
763                           G_CALLBACK (text_buffer_can_redo), obj);
764         g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
765                           G_CALLBACK (body_changed), obj);
766         g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text", 
767                           G_CALLBACK (body_insert_text), obj);
768         g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
769                           G_CALLBACK (body_changed), obj);
770         g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
771                           G_CALLBACK (text_buffer_end_user_action), obj);
772         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
773                           G_CALLBACK (text_buffer_mark_set), obj);
774         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
775                                 G_CALLBACK (text_buffer_apply_tag), obj);
776         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
777                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
778         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
779                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
780         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
781                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
782
783         g_signal_connect (G_OBJECT (priv->send_button), "clicked",
784                           G_CALLBACK (modest_ui_actions_on_send), obj);
785
786         g_signal_connect (G_OBJECT (priv->bottom_send_button), "clicked",
787                           G_CALLBACK (modest_ui_actions_on_send), obj);
788
789         g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
790                           G_CALLBACK (from_field_changed), obj);
791
792         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
793                           G_CALLBACK (msg_body_focus), obj);
794         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
795                           G_CALLBACK (msg_body_focus), obj);
796         g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
797                           G_CALLBACK (body_size_request), obj);
798         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
799         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
800                           "changed", G_CALLBACK (recpt_field_changed), obj);
801         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
802                           "changed", G_CALLBACK (recpt_field_changed), obj);
803         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
804                           "changed", G_CALLBACK (recpt_field_changed), obj);
805         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
806         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
807         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
808
809         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
810         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
811  
812         priv->clipboard_change_handler_id = 
813                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
814                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
815         priv->default_clipboard_change_handler_id = 
816                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
817                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
818
819         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
820         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
821         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
822 }
823
824 static void
825 init_wp_text_view_style ()
826 {
827         static gboolean initialized = FALSE;
828
829         if (!initialized) {
830                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
831                 initialized = TRUE;
832         }
833 }       
834
835 static void
836 init_window (ModestMsgEditWindow *obj)
837 {
838         GtkWidget *to_caption, *subject_caption;
839         GtkWidget *main_vbox;
840         ModestMsgEditWindowPrivate *priv;
841         GtkActionGroup *action_group;
842         ModestWindowPrivate *parent_priv;
843         GdkPixbuf *window_icon = NULL;
844         GError *error = NULL;
845
846         GtkSizeGroup *title_size_group;
847         GtkSizeGroup *value_size_group;
848         GtkWidget *window_box;
849         GtkWidget *window_align;
850 #if (GTK_MINOR_VERSION >= 10)
851         GdkAtom deserialize_type;
852 #endif
853         GtkWidget *from_send_hbox;
854         GtkWidget *send_icon;
855         GtkWidget *attachments_label;
856         GtkWidget *branding_box;
857
858         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
859         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
860
861         parent_priv->ui_manager = gtk_ui_manager_new();
862         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
863         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
864
865         /* Add common actions */
866         gtk_action_group_add_actions (action_group,
867                                       modest_msg_edit_action_entries,
868                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
869                                       obj);
870         gtk_action_group_add_actions (action_group,
871                                       hildon2_msg_edit_action_entries,
872                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
873                                       obj);
874         gtk_action_group_add_toggle_actions (action_group,
875                                              modest_msg_edit_toggle_action_entries,
876                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
877                                              obj);
878         gtk_action_group_add_radio_actions (action_group,
879                                             modest_msg_edit_alignment_radio_action_entries,
880                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
881                                             GTK_JUSTIFY_LEFT,
882                                             G_CALLBACK (modest_ui_actions_on_change_justify),
883                                             obj);
884         gtk_action_group_add_radio_actions (action_group,
885                                             modest_msg_edit_priority_action_entries,
886                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
887                                             0,
888                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
889                                             obj);
890         gtk_action_group_add_radio_actions (action_group,
891                                             modest_msg_edit_file_format_action_entries,
892                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
893                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
894                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
895                                             obj);
896         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
897         g_object_unref (action_group);
898
899         /* Load the UI definition */
900         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
901                                          &error);
902         if (error != NULL) {
903                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
904                 g_clear_error (&error);
905         }
906
907         /* Add accelerators */
908         gtk_window_add_accel_group (GTK_WINDOW (obj), 
909                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
910
911         parent_priv->menubar = NULL;
912
913         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
914         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
915
916         /* Note: This ModestPairList* must exist for as long as the picker
917          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
918          * so it can't know how to manage its memory. */ 
919         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
920                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
921                                                           NULL, g_str_equal);
922         modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
923         modest_maemo_utils_set_hbutton_layout (title_size_group, NULL, 
924                                                _("mail_va_from"), priv->from_field);
925         hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
926         hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
927         hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
928
929         priv->to_field      = modest_recpt_editor_new ();
930         priv->cc_field      = modest_recpt_editor_new ();
931         priv->bcc_field     = modest_recpt_editor_new ();
932         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
933         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
934         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
935         priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
936         priv->priority_icon = gtk_image_new ();
937         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
938         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
939         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
940         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
941         hildon_entry_set_placeholder ((HildonEntry *) priv->subject_field, _("mail_va_no_subject"));
942         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
943                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
944         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
945         priv->attachments_view = modest_attachments_view_new (NULL);
946         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
947                                            MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
948         
949         priv->header_box = gtk_vbox_new (FALSE, 0);
950         
951         to_caption = _create_addressbook_box
952                 (title_size_group, value_size_group,
953                  _("mail_va_to"), priv->to_field);
954         priv->cc_caption = _create_addressbook_box
955                 (title_size_group, value_size_group,
956                  _("mail_va_cc"), priv->cc_field);
957         priv->bcc_caption = _create_addressbook_box
958                 (title_size_group, value_size_group,
959                  _("mail_va_hotfix1"), priv->bcc_field);
960         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
961                                                                _("mail_va_subject"), FALSE, priv->subject_box);
962         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
963                                                                                         _("mail_va_attachment"), 
964                                                                                         FALSE,
965                                                                                         priv->attachments_view,
966                                                                                         HILDON_SIZE_AUTO_WIDTH |
967                                                                                         HILDON_SIZE_AUTO_HEIGHT);
968         attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
969         hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
970
971
972         priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
973         send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
974         gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
975         gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
976
977         priv->bottom_send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
978         send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
979         gtk_container_add (GTK_CONTAINER (priv->bottom_send_button), send_icon);
980         gtk_widget_set_size_request (GTK_WIDGET (priv->bottom_send_button), 148, -1);
981
982         priv->bottom_send_button_container = gtk_hbox_new (FALSE, 0);
983         gtk_widget_show (priv->bottom_send_button_container);
984         gtk_box_pack_end (GTK_BOX (priv->bottom_send_button_container), priv->bottom_send_button, FALSE, FALSE, 0);
985         gtk_widget_show (priv->bottom_send_button_container);
986
987         g_object_unref (title_size_group);
988         g_object_unref (value_size_group);
989
990         priv->brand_icon = gtk_image_new ();
991         gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
992         priv->brand_label = gtk_label_new (NULL);
993         hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
994         gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
995         gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
996         gtk_widget_set_no_show_all (priv->brand_label, TRUE);
997
998         from_send_hbox = gtk_hbox_new (FALSE, 0);
999         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
1000         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
1001
1002         branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1003         gtk_widget_show (branding_box);
1004         gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
1005         gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
1006
1007         priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
1008         gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1009         gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
1010         gtk_widget_set_no_show_all (priv->brand_container, TRUE);
1011
1012
1013         gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
1014         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
1015         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
1016         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
1017         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
1018         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
1019         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
1020         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
1021
1022         init_wp_text_view_style ();
1023
1024         priv->msg_body = modest_wp_text_view_new ();
1025         
1026
1027         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
1028         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1029         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
1030         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1031 #if (GTK_MINOR_VERSION >= 10)
1032         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
1033         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
1034                                                                        NULL);
1035         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
1036                                                          deserialize_type, TRUE);
1037 #endif
1038         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1039
1040         priv->find_toolbar = hildon_find_toolbar_new (NULL);
1041         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1042
1043         priv->pannable = hildon_pannable_area_new ();
1044
1045         g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1046
1047         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1048         window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1049         gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), MODEST_MARGIN_HALF, 0,
1050                                    MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1051
1052         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1053         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1054         gtk_box_pack_start (GTK_BOX (main_vbox), priv->bottom_send_button_container, FALSE, FALSE, 0);
1055         gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1056
1057         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1058         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1059
1060         window_box = gtk_vbox_new (FALSE, 0);
1061         gtk_container_add (GTK_CONTAINER(obj), window_box);
1062
1063         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1064
1065         /* Set window icon */
1066         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG);
1067         if (window_icon) {
1068                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1069                 g_object_unref (window_icon);
1070         }
1071 }
1072
1073 static void
1074 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1075 {
1076         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1077
1078         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1079             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1080                                            priv->clipboard_change_handler_id))
1081                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1082                                              priv->clipboard_change_handler_id);
1083         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1084             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1085                                            priv->default_clipboard_change_handler_id))
1086                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1087                                              priv->default_clipboard_change_handler_id);
1088
1089         if (priv->account_removed_handler_id && 
1090             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
1091                                            priv->account_removed_handler_id))
1092                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
1093                                            priv->account_removed_handler_id);
1094 }
1095
1096 static void
1097 modest_msg_edit_window_finalize (GObject *obj)
1098 {
1099         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1100
1101         g_object_unref (priv->custom_header_pairs);
1102
1103         if (priv->max_chars_banner) {
1104                 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1105                 priv->max_chars_banner = FALSE;
1106         }
1107
1108         /* Sanity check: shouldn't be needed, the window mgr should
1109            call this function before */
1110         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1111
1112         if (priv->font_dialog != NULL) {
1113                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1114         }
1115
1116         if (priv->clipboard_text != NULL) {
1117                 g_free (priv->clipboard_text);
1118                 priv->clipboard_text = NULL;
1119         }
1120         
1121         if (priv->draft_msg != NULL) {
1122                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1123                 if (TNY_IS_HEADER (header)) {
1124                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1125                         modest_window_mgr_unregister_header (mgr, header);
1126                 }
1127                 g_object_unref (priv->draft_msg);
1128                 priv->draft_msg = NULL;
1129         }
1130         if (priv->outbox_msg != NULL) {
1131                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1132                 if (TNY_IS_HEADER (header)) {
1133                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1134                         modest_window_mgr_unregister_header (mgr, header);
1135                 }
1136                 g_object_unref (priv->outbox_msg);
1137                 priv->outbox_msg = NULL;
1138         }
1139         if (priv->correct_scroll_idle > 0) {
1140                 g_source_remove (priv->correct_scroll_idle);
1141                 priv->correct_scroll_idle = 0;
1142         }
1143         if (priv->scroll_drag_timeout_id > 0) {
1144                 g_source_remove (priv->scroll_drag_timeout_id);
1145                 priv->scroll_drag_timeout_id = 0;
1146         }
1147         if (priv->clipboard_owner_idle > 0) {
1148                 g_source_remove (priv->clipboard_owner_idle);
1149                 priv->clipboard_owner_idle = 0;
1150         }
1151         if (priv->original_account_name)
1152                 g_free (priv->original_account_name);
1153         if (priv->original_mailbox)
1154                 g_free (priv->original_mailbox);
1155         g_free (priv->msg_uid);
1156         g_free (priv->last_search);
1157         g_free (priv->references);
1158         g_free (priv->in_reply_to);
1159         g_object_unref (priv->attachments);
1160         g_object_unref (priv->images);
1161
1162         /* This had to stay alive for as long as the picker that used it: */
1163         modest_pair_list_free (priv->from_field_protos);
1164         
1165         G_OBJECT_CLASS(parent_class)->finalize (obj);
1166 }
1167
1168 static void
1169 pixbuf_size_prepared (GdkPixbufLoader *loader,
1170                       gint width,
1171                       gint height,
1172                       ModestMsgEditWindow *self)
1173 {
1174         gint new_height, new_width;
1175         gboolean set_size;
1176         
1177         new_height = height;
1178         new_width = width;
1179         set_size = FALSE;
1180
1181         if (width > IMAGE_MAX_WIDTH) {
1182                 new_height = height * IMAGE_MAX_WIDTH / width;
1183                 new_width = IMAGE_MAX_WIDTH;
1184         }
1185
1186         gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1187 }
1188
1189 static GdkPixbuf *
1190 pixbuf_from_stream (TnyStream *stream,
1191                     const gchar *mime_type,
1192                     guint64 *stream_size,
1193                     ModestMsgEditWindow *self)
1194 {
1195         GdkPixbufLoader *loader;
1196         GdkPixbuf *pixbuf;
1197         guint64 size;
1198         GError *error = NULL;
1199
1200         size = 0;
1201
1202         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1203
1204         if (loader == NULL) {
1205                 if (stream_size)
1206                         *stream_size = 0;
1207                 return NULL;
1208         }
1209         g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1210
1211         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1212
1213         tny_stream_reset (TNY_STREAM (stream));
1214         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1215                 unsigned char read_buffer[128];
1216                 gint readed;
1217                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1218                 size += readed;
1219                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1220                         break;
1221                 }
1222                 /* Allow some UI responsiveness */
1223                 while (gtk_events_pending ())
1224                         gtk_main_iteration ();
1225         }
1226         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1227
1228         gdk_pixbuf_loader_close (loader, &error);
1229
1230         if (error)
1231                 g_error_free (error);
1232         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1233         if (pixbuf) 
1234                 g_object_ref (pixbuf);
1235         g_object_unref (loader);
1236
1237         if (!pixbuf)
1238                 return NULL;
1239
1240         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1241                 GdkPixbuf *new_pixbuf;
1242                 gint new_height;
1243                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1244                         gdk_pixbuf_get_width (pixbuf);
1245                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1246                 g_object_unref (pixbuf);
1247                 pixbuf = new_pixbuf;
1248         }
1249
1250         if (stream_size)
1251                 *stream_size = size;
1252
1253         return pixbuf;
1254 }
1255
1256 static void
1257 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1258 {
1259         ModestMsgEditWindowPrivate *priv;
1260         TnyIterator *iter;
1261
1262         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1263
1264         g_object_ref (self);
1265         for (iter = tny_list_create_iterator (attachments);
1266              !tny_iterator_is_done (iter);
1267              tny_iterator_next (iter)) {
1268                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1269                 const gchar *cid = tny_mime_part_get_content_id (part);
1270                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1271                 if ((cid != NULL)&&(mime_type != NULL)) {
1272                         guint64 stream_size;
1273                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1274                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1275
1276
1277                         g_object_unref (stream);
1278
1279                         if (pixbuf != NULL) {
1280                                 priv->images_count ++;
1281                                 priv->images_size += stream_size;
1282                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1283                                 g_object_unref (pixbuf);
1284                         }
1285                 }
1286                 g_object_unref (part);
1287         }
1288         g_object_unref (iter);
1289         g_object_unref (self);
1290 }
1291
1292 static void
1293 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1294 {
1295         TnyMimePart *parent = NULL;
1296         const gchar *content_type = NULL;
1297         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1298
1299         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1300
1301         if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1302                 parent = g_object_ref (msg);
1303         } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1304                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1305                 TnyIterator *iter;
1306
1307                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1308                 iter = tny_list_create_iterator (parts);
1309                 while (!tny_iterator_is_done (iter)) {
1310                         TnyMimePart *part;
1311                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1312                         content_type = tny_mime_part_get_content_type (part);
1313                         if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1314                                 parent = part;
1315                                 break;
1316                         } else {
1317                                 g_object_unref (part);
1318                         }
1319                         tny_iterator_next (iter);
1320                 }
1321                 g_object_unref (iter);
1322                 g_object_unref (parts);
1323         }
1324
1325         if (parent != NULL) {
1326                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1327                 TnyIterator *iter;
1328
1329                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1330                 iter = tny_list_create_iterator (parts);
1331                 while (!tny_iterator_is_done (iter)) {
1332                         TnyMimePart *part;
1333                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1334                         content_type = tny_mime_part_get_content_type (part);
1335                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1336                                 tny_list_prepend (priv->images, (GObject *) part);
1337                         } 
1338                         g_object_unref (part);
1339                         tny_iterator_next (iter);
1340                 }
1341                 g_object_unref (iter);
1342                 g_object_unref (parts);
1343                 g_object_unref (parent);
1344         }
1345 }
1346
1347 static void
1348 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1349 {
1350         TnyIterator *iter;
1351         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1352
1353         for (iter = tny_list_create_iterator (attachments) ; 
1354              !tny_iterator_is_done (iter);
1355              tny_iterator_next (iter)) {
1356                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1357                 const gchar *cid = tny_mime_part_get_content_id (part);
1358                 if (cid != NULL) {
1359                         char *invalid = NULL;
1360                         gint int_cid = strtol (cid, &invalid, 10);
1361                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1362                                 priv->next_cid = int_cid + 1;
1363                         }
1364                 }
1365                 g_object_unref (part);
1366         }
1367         g_object_unref (iter);
1368 }
1369
1370 static gboolean
1371 remove_non_calendar_headers (TnyList *list,
1372                              GObject *item,
1373                              gpointer match_data)
1374 {
1375         if (g_str_has_prefix (tny_pair_get_name (TNY_PAIR (item)), "X-as"))
1376                 return FALSE;
1377         else
1378                 return TRUE;
1379 }
1380
1381 static void
1382 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1383 {
1384         TnyHeader *header;
1385         gchar *to, *cc, *bcc, *subject;
1386         gchar *body;
1387         ModestMsgEditWindowPrivate *priv;
1388         ModestWindowPrivate *parent_priv;
1389         GtkTextIter iter;
1390         TnyHeaderFlags priority_flags;
1391         TnyFolder *msg_folder;
1392         gboolean is_html = FALSE;
1393         gboolean field_view_set;
1394         TnyList *orig_header_pairs;
1395         
1396         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1397         g_return_if_fail (TNY_IS_MSG (msg));
1398
1399         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1400         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1401
1402         header = tny_msg_get_header (msg);
1403         to      = tny_header_dup_to (header);
1404         cc      = tny_header_dup_cc (header);
1405         bcc     = tny_header_dup_bcc (header);
1406         subject = tny_header_dup_subject (header);
1407
1408         modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1409         priority_flags = tny_header_get_priority (header);
1410
1411         if (to) {
1412                 gchar *quoted_names = modest_text_utils_quote_names (to);
1413                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1414                 g_free (quoted_names);
1415         }
1416
1417         field_view_set = TRUE;
1418         if (cc) {
1419                 gchar *quoted_names = modest_text_utils_quote_names (cc);
1420                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  quoted_names);
1421                 g_free (quoted_names);
1422                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1423                 gtk_widget_show (priv->cc_caption);
1424         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1425                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1426                 gtk_widget_hide (priv->cc_caption);
1427                 field_view_set = FALSE;
1428         }
1429         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1430
1431         field_view_set = TRUE;
1432         if (bcc) {
1433                 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1434                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1435                 g_free (quoted_names);
1436                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1437                 gtk_widget_show (priv->bcc_caption);
1438         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1439                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1440                 gtk_widget_hide (priv->bcc_caption);
1441                 field_view_set = FALSE;
1442         }
1443         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1444
1445
1446         if (subject)
1447                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1448         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1449                                                    priority_flags);
1450
1451         update_window_title (self);
1452
1453         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1454         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1455
1456         if ((body == NULL)||(body[0] == '\0')) {
1457                 g_free (body);
1458                 body = modest_text_utils_convert_to_html ("");
1459                 is_html = FALSE;
1460         }
1461         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1462         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1463                                             (gchar *) body,
1464                                             strlen (body));
1465         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1466         g_free (body);
1467
1468         /* Add attachments to the view */
1469         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1470         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1471         if (tny_list_get_length (priv->attachments) == 0) {
1472                 gtk_widget_hide (priv->attachments_caption);
1473         } else {
1474                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1475                 gtk_widget_show_all (priv->attachments_caption);
1476         }
1477         get_related_images (self, msg);
1478         update_next_cid (self, priv->attachments);
1479         update_next_cid (self, priv->images);
1480         replace_with_images (self, priv->images);
1481
1482         if (preserve_is_rich && !is_html) {
1483                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1484         /* Get the default format required from configuration */
1485         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1486                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1487         }
1488
1489         /* Set the default focus depending on having already a To: field or not */
1490         if ((!to)||(*to == '\0')) {
1491                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1492         } else {
1493                 gtk_widget_grab_focus (priv->msg_body);
1494         }
1495
1496         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1497
1498         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1499         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1500
1501         modest_msg_edit_window_set_modified (self, FALSE);
1502
1503         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1504         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1505         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1506         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1507
1508         if (priv->msg_uid) {
1509                 g_free (priv->msg_uid);
1510                 priv->msg_uid = NULL;
1511         }
1512
1513         /* we should set a reference to the incoming message if it is a draft */
1514         msg_folder = tny_msg_get_folder (msg);
1515         if (msg_folder) {               
1516                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1517                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1518                         if (type == TNY_FOLDER_TYPE_INVALID)
1519                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1520
1521                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1522                                 priv->draft_msg = g_object_ref(msg);
1523                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1524                                 priv->outbox_msg = g_object_ref(msg);
1525                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1526                 }
1527                 g_object_unref (msg_folder);
1528         }
1529
1530         /* Copy orig headers used by ActiveSync calendar invitations */
1531         orig_header_pairs = TNY_LIST (tny_simple_list_new ());
1532         tny_mime_part_get_header_pairs (TNY_MIME_PART (msg), orig_header_pairs);
1533         tny_list_remove_matches (orig_header_pairs, remove_non_calendar_headers, NULL);
1534         if (tny_list_get_length (orig_header_pairs) > 0)
1535                 modest_msg_edit_window_set_custom_header_pairs (self, orig_header_pairs);
1536         g_object_unref (orig_header_pairs);
1537
1538         g_free (to);
1539         g_free (subject);
1540         g_free (cc);
1541         g_free (bcc);
1542 }
1543
1544 static void
1545 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1546 {
1547         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1548         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1549         GtkWidget *placeholder;
1550         GtkWidget *tool_item;
1551         gint insert_index;
1552         gchar size_text[5];
1553         gint size_index;
1554         gint font_index;
1555         GtkWidget *sizes_menu;
1556         GtkWidget *fonts_menu;
1557         gchar *markup;
1558         GtkWidget *arrow;
1559         GtkWidget *hbox;
1560
1561         /* Toolbar */
1562         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1563         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1564         gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1565         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1566
1567         /* Font color placeholder */
1568         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1569         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1570
1571         /* font color */
1572         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1573         priv->font_color_button = modest_color_button_new ();
1574         gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1575         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1576         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1577         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1578         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1579         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1580         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1581         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1582                                   "notify::color", 
1583                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1584                                   window);
1585
1586         /* Font size and face placeholder */
1587         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1588         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1589         /* font_size */
1590         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1591         priv->size_tool_button_label = gtk_label_new (NULL);
1592         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1593         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1594                               size_text, "</span>", NULL);
1595         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1596         gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1597         g_free (markup);
1598         hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1599         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1600         gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1601         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1602         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1603         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1604         gtk_widget_set_sensitive (arrow, FALSE);
1605         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1606         sizes_menu = gtk_menu_new ();
1607         priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1608         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1609                 GtkTreeIter iter;
1610
1611                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1612                 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1613
1614                 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter, 
1615                                     0, size_text,
1616                                     -1);
1617
1618                 if (wp_font_size[size_index] == 12)
1619                         priv->current_size_index = size_index;
1620                                         
1621         }
1622
1623         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1624         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1625         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1626         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1627         priv->font_size_toolitem = tool_item;
1628
1629         /* font face */
1630         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1631         priv->font_tool_button_label = gtk_label_new (NULL);
1632         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1633         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1634         gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1635         g_free(markup);
1636         hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1637         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1638         gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1639         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1640         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1641         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1642         gtk_widget_set_sensitive (arrow, FALSE);
1643         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1644         fonts_menu = gtk_menu_new ();
1645         priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1646         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1647                 GtkTreeIter iter;
1648
1649                 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1650
1651                 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter, 
1652                                     0, wp_get_font_name (font_index),
1653                                     -1);
1654
1655                 if (font_index == DEFAULT_FONT)
1656                         priv->current_face_index = font_index;
1657         }
1658         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1659         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1660         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1661         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1662         priv->font_face_toolitem = tool_item;
1663
1664         /* Set expand and homogeneous for remaining items */
1665         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1666         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1667         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1668         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1669         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1670         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1671         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsInsertImage");
1672         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1673         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1674
1675         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1676            will not show the tool items added to the placeholders) */
1677         gtk_widget_show_all (parent_priv->toolbar);
1678
1679         /* Set the no show all *after* showing all items. We do not
1680            want the toolbar to be shown with a show all because it
1681            could go against the gconf setting regarding showing or not
1682            the toolbar of the editor window */
1683         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1684 }
1685
1686
1687
1688 ModestWindow*
1689 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1690 {
1691         GObject *obj;
1692         ModestWindowPrivate *parent_priv;
1693         ModestMsgEditWindowPrivate *priv;
1694         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1695         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1696         ModestWindowMgr *mgr = NULL;
1697
1698         g_return_val_if_fail (msg, NULL);
1699         g_return_val_if_fail (account_name, NULL);
1700
1701         mgr = modest_runtime_get_window_mgr ();
1702         
1703         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1704
1705         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1706         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1707
1708         /* Menubar. Update the state of some toggles */
1709         priv->from_field_protos = get_transports ();
1710         priv->original_mailbox = NULL;
1711         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1712         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1713         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1714         if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1715                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1716                 priv->original_mailbox = g_strdup (mailbox);
1717         } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1718                 /* We set the first mailbox as the active mailbox */
1719                 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1720                 if (priv->original_mailbox != NULL)
1721                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1722                                                               (gpointer) priv->original_mailbox);
1723                 else
1724                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1725                                                               (gpointer) account_name);
1726         } else {
1727                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1728         }
1729         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1730         update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1731         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1732                                  _("mail_va_from"));
1733         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1734                                  hildon_touch_selector_get_current_text 
1735                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1736         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1737         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1738
1739         /* Init window */
1740         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1741
1742         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1743                 
1744         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1745         modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1746
1747         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1748
1749         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1750         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1751         /* Add common dimming rules */
1752         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1753                                               modest_msg_edit_window_toolbar_dimming_entries,
1754                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1755                                               MODEST_WINDOW (obj));
1756         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1757                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1758                                                     MODEST_WINDOW (obj));
1759         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1760                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1761                                                     MODEST_WINDOW (obj));
1762         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1763                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1764                                                     MODEST_WINDOW (obj));
1765         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1766                                                     G_CALLBACK (modest_ui_dimming_rules_on_send),
1767                                                     MODEST_WINDOW (obj));
1768         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->bottom_send_button,
1769                                                     G_CALLBACK (modest_ui_dimming_rules_on_send),
1770                                                     MODEST_WINDOW (obj));
1771         /* Insert dimming rules group for this window */
1772         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1773         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1774
1775         /* Setup app menu */
1776         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1777
1778         /* Checks the dimming rules */
1779         g_object_unref (toolbar_rules_group);
1780         g_object_unref (clipboard_rules_group);
1781         gtk_widget_hide (priv->priority_icon);
1782         gtk_widget_queue_resize (priv->subject_box);
1783         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1784
1785         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1786
1787         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1788         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1789         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1790         priv->update_caption_visibility = TRUE;
1791
1792         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1793
1794         /* Track account-removed signal, this window should be closed
1795            in the case we're creating a mail associated to the account
1796            that is deleted */
1797         priv->account_removed_handler_id = 
1798                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1799                                   "account_removed",
1800                                   G_CALLBACK(on_account_removed),
1801                                   obj);
1802
1803         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1804
1805         return (ModestWindow*) obj;
1806 }
1807
1808 static gint
1809 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1810 {
1811         GString **string_buffer = (GString **) user_data;
1812
1813         *string_buffer = g_string_append (*string_buffer, buffer);
1814    
1815         return 0;
1816 }
1817
1818 /**
1819  * @result: A new string which should be freed with g_free().
1820  */
1821 static gchar *
1822 get_formatted_data (ModestMsgEditWindow *edit_window)
1823 {
1824         ModestMsgEditWindowPrivate *priv;
1825         GString *string_buffer = g_string_new ("");
1826         
1827         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1828
1829         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1830
1831         modest_text_utils_hyperlinkify (string_buffer);
1832
1833         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1834
1835         return g_string_free (string_buffer, FALSE);
1836                                                                         
1837 }
1838
1839 MsgData * 
1840 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1841 {
1842         MsgData *data;
1843         const gchar *account_name;
1844         ModestMsgEditWindowPrivate *priv;
1845         TnyIterator *att_iter;
1846         const gchar *picker_active_id;
1847         
1848         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1849
1850         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1851         
1852         picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1853         g_return_val_if_fail (picker_active_id, NULL);
1854         account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1855         
1856         /* don't free these (except from) */
1857         data = g_slice_new0 (MsgData);
1858         data->from    =  g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1859         data->account_name = g_strdup (account_name);
1860         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1861         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1862         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1863         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1864         data->references = g_strdup (priv->references);
1865         data->in_reply_to = g_strdup (priv->in_reply_to);
1866         if (priv->draft_msg) {
1867                 data->draft_msg = g_object_ref (priv->draft_msg);
1868         } else if (priv->outbox_msg) {
1869                 data->draft_msg = g_object_ref (priv->outbox_msg);
1870         } else {
1871                 data->draft_msg = NULL;
1872         }
1873
1874         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1875         GtkTextIter b, e;
1876         gtk_text_buffer_get_bounds (buf, &b, &e);
1877         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1878
1879         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1880                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1881         else
1882                 data->html_body = NULL;
1883
1884         /* deep-copy the data */
1885         att_iter = tny_list_create_iterator (priv->attachments);
1886         data->attachments = NULL;
1887         while (!tny_iterator_is_done (att_iter)) {
1888                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1889                 if (!(TNY_IS_MIME_PART(part))) {
1890                         g_warning ("strange data in attachment list");
1891                         g_object_unref (part);
1892                         tny_iterator_next (att_iter);
1893                         continue;
1894                 }
1895                 data->attachments = g_list_append (data->attachments,
1896                                                    part);
1897                 tny_iterator_next (att_iter);
1898         }
1899         g_object_unref (att_iter);
1900
1901         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1902         att_iter = tny_list_create_iterator (priv->images);
1903         data->images = NULL;
1904         while (!tny_iterator_is_done (att_iter)) {
1905                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1906                 const gchar *cid;
1907                 if (!(TNY_IS_MIME_PART(part))) {
1908                         g_warning ("strange data in attachment list");
1909                         g_object_unref (part);
1910                         tny_iterator_next (att_iter);
1911                         continue;
1912                 }
1913                 cid = tny_mime_part_get_content_id (part);
1914                 if (cid) {                      
1915                         gchar *image_tag_id;
1916                         GtkTextTag *image_tag;
1917                         GtkTextIter iter;
1918                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1919                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1920                         g_free (image_tag_id);
1921                         
1922                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1923                         if (image_tag && 
1924                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1925                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1926                                 data->images = g_list_append (data->images,
1927                                                               g_object_ref (part));
1928                 }
1929                 g_object_unref (part);
1930                 tny_iterator_next (att_iter);
1931         }
1932         g_object_unref (att_iter);
1933         
1934         data->priority_flags = priv->priority_flags;
1935         data->custom_header_pairs = tny_list_copy (priv->custom_header_pairs);
1936
1937         return data;
1938 }
1939
1940
1941 static void
1942 unref_gobject (GObject *obj, gpointer data)
1943 {
1944         if (!G_IS_OBJECT(obj))
1945                 return;
1946         g_object_unref (obj);
1947 }
1948
1949 void 
1950 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1951                                                       MsgData *data)
1952 {
1953         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1954
1955         if (!data)
1956                 return;
1957
1958         g_free (data->to);
1959         g_free (data->cc);
1960         g_free (data->bcc);
1961         g_free (data->from);
1962         g_free (data->subject);
1963         g_free (data->plain_body);
1964         g_free (data->html_body);
1965         g_free (data->account_name);
1966         g_free (data->references);
1967         g_free (data->in_reply_to);
1968
1969         g_object_unref (data->custom_header_pairs);
1970         
1971         if (data->draft_msg != NULL) {
1972                 g_object_unref (data->draft_msg);
1973                 data->draft_msg = NULL;
1974         }
1975         
1976         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1977         g_list_free (data->attachments);
1978         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1979         g_list_free (data->images);
1980         
1981         g_slice_free (MsgData, data);
1982 }
1983
1984 void                    
1985 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1986                                        gint *parts_count,
1987                                        guint64 *parts_size)
1988 {
1989         ModestMsgEditWindowPrivate *priv;
1990
1991         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1992
1993         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1994
1995         /* TODO: add images */
1996         *parts_size += priv->images_size;
1997         *parts_count += priv->images_count;
1998
1999 }
2000
2001 ModestMsgEditFormat
2002 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
2003 {
2004         gboolean rich_text;
2005         ModestMsgEditWindowPrivate *priv = NULL;
2006         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
2007
2008         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2009
2010         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2011         if (rich_text)
2012                 return MODEST_MSG_EDIT_FORMAT_HTML;
2013         else
2014                 return MODEST_MSG_EDIT_FORMAT_TEXT;
2015 }
2016
2017 void
2018 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
2019                                    ModestMsgEditFormat format)
2020 {
2021         ModestMsgEditWindowPrivate *priv;
2022         ModestWindowPrivate *parent_priv;
2023
2024         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2025         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2026         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
2027
2028         switch (format) {
2029         case MODEST_MSG_EDIT_FORMAT_HTML:
2030                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2031                 update_signature (self, priv->last_from_account, priv->last_from_account);
2032                 if (parent_priv->toolbar) 
2033                         on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
2034                                                         MODEST_MSG_EDIT_WINDOW (self));
2035                 break;
2036         case MODEST_MSG_EDIT_FORMAT_TEXT:
2037                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2038                 if (parent_priv->toolbar) 
2039                         on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
2040                                                         MODEST_MSG_EDIT_WINDOW (self));
2041                 break;
2042         default:
2043                 g_return_if_reached ();
2044         }
2045 }
2046
2047 ModestMsgEditFormatState *
2048 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
2049 {
2050         ModestMsgEditFormatState *format_state = NULL;
2051         ModestMsgEditWindowPrivate *priv;
2052         WPTextBufferFormat *buffer_format;
2053
2054         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
2055
2056         buffer_format = g_new0 (WPTextBufferFormat, 1);
2057         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2058
2059         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
2060
2061         format_state = g_new0 (ModestMsgEditFormatState, 1);
2062         format_state->bold = buffer_format->bold&0x1;
2063         format_state->italics = buffer_format->italic&0x1;
2064         format_state->bullet = buffer_format->bullet&0x1;
2065         format_state->color = buffer_format->color;
2066         format_state->font_size = buffer_format->font_size;
2067         format_state->font_family = wp_get_font_name (buffer_format->font);
2068         format_state->justification = buffer_format->justification;
2069         g_free (buffer_format);
2070
2071         return format_state;
2072  
2073 }
2074
2075 void
2076 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2077                                          const ModestMsgEditFormatState *format_state)
2078 {
2079         ModestMsgEditWindowPrivate *priv;
2080         WPTextBufferFormat *buffer_format;
2081         WPTextBufferFormat *current_format;
2082
2083         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2084         g_return_if_fail (format_state != NULL);
2085
2086         buffer_format = g_new0 (WPTextBufferFormat, 1);
2087         current_format = g_new0 (WPTextBufferFormat, 1);
2088
2089         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2090         gtk_widget_grab_focus (priv->msg_body);
2091         buffer_format->bold = (format_state->bold != FALSE);
2092         buffer_format->italic = (format_state->italics != FALSE);
2093         buffer_format->color = format_state->color;
2094         buffer_format->font_size = format_state->font_size;
2095         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2096         buffer_format->justification = format_state->justification;
2097         buffer_format->bullet = format_state->bullet;
2098
2099         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2100
2101         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2102         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2103         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2104         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
2105         buffer_format->cs.font = (buffer_format->font != current_format->font);
2106         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2107         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2108
2109         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2110         if (buffer_format->cs.bold) {
2111                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2112                                               GINT_TO_POINTER (buffer_format->bold&0x1));
2113         }
2114         if (buffer_format->cs.italic) {
2115                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2116                                               GINT_TO_POINTER (buffer_format->italic&0x1));
2117         }
2118         if (buffer_format->cs.color) {
2119                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2120                                               GINT_TO_POINTER (&(buffer_format->color)));
2121         }
2122         if (buffer_format->cs.font_size) {
2123                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2124                                               GINT_TO_POINTER (buffer_format->font_size));
2125         }
2126         if (buffer_format->cs.justification) {
2127                 switch (buffer_format->justification) {
2128                 case GTK_JUSTIFY_LEFT:
2129                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2130                                                       GINT_TO_POINTER(TRUE));
2131                         break;
2132                 case GTK_JUSTIFY_CENTER:
2133                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2134                                                       GINT_TO_POINTER(TRUE));
2135                         break;
2136                 case GTK_JUSTIFY_RIGHT:
2137                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2138                                                       GINT_TO_POINTER(TRUE));
2139                         break;
2140                 default:
2141                         break;
2142                 }
2143                         
2144         }
2145         if (buffer_format->cs.font) {
2146                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2147                                               GINT_TO_POINTER (buffer_format->font));
2148         }
2149         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2150         if (buffer_format->cs.bullet) {
2151                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2152                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2153         }
2154 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2155         
2156         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2157         
2158         g_free (buffer_format);
2159         g_free (current_format);
2160
2161         /* Check dimming rules */
2162         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2163         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2164 }
2165
2166 static void
2167 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2168 {
2169         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2170         GtkAction *action;
2171         ModestWindowPrivate *parent_priv;
2172         ModestMsgEditWindowPrivate *priv;
2173         
2174         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2175         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2176
2177         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2178                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2179                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2180                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2181         } else {
2182                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2183                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2184                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2185         }
2186
2187         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2188
2189         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2190         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2191
2192         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2193         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2194
2195 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2196 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2197
2198         action = NULL;
2199         switch (buffer_format->justification)
2200         {
2201         case GTK_JUSTIFY_LEFT:
2202                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2203                 break;
2204         case GTK_JUSTIFY_CENTER:
2205                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2206                 break;
2207         case GTK_JUSTIFY_RIGHT:
2208                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2209                 break;
2210         default:
2211                 break;
2212         }
2213         
2214         if (action != NULL)
2215                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2216         
2217         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
2218                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
2219                                          window);
2220         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2221         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
2222                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
2223                                            window);
2224
2225         if (priv->current_size_index != buffer_format->font_size) {
2226                 GtkTreeIter iter;
2227                 GtkTreePath *path;
2228
2229                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2230                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2231                         gchar *size_text;
2232                         gchar *markup;
2233
2234                         priv->current_size_index = buffer_format->font_size;
2235
2236                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2237                         markup = g_strconcat ("<span font_family='Sans'>", 
2238                                               size_text, "</span>", NULL);
2239                         
2240                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2241                         g_free (markup);
2242                         g_free (size_text);
2243                 }
2244                 gtk_tree_path_free (path);              
2245         }
2246
2247         if (priv->current_face_index != buffer_format->font) {
2248                 GtkTreeIter iter;
2249                 GtkTreePath *path;
2250
2251                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2252                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2253                         gchar *face_name;
2254                         gchar *markup;
2255
2256                         priv->current_face_index = buffer_format->font;
2257                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2258                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2259                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2260                         g_free (face_name);
2261                         g_free (markup);
2262                 }
2263
2264         }
2265
2266         g_free (buffer_format);
2267
2268 }
2269
2270
2271 void
2272 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2273 {
2274         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2275         ModestMsgEditWindowPrivate *priv;
2276         GtkWidget *dialog = NULL;
2277
2278         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2279         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2280
2281         dialog = hildon_color_chooser_new ();
2282         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2283         g_free (buffer_format);
2284
2285         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2286                 GdkColor col;
2287                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2288                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2289                                               (gpointer) &col);
2290         }
2291         gtk_widget_destroy (dialog);
2292 }
2293
2294
2295 void
2296 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2297 {
2298         ModestMsgEditWindowPrivate *priv;
2299         GtkWidget *dialog = NULL;
2300         GdkColor *old_color = NULL;
2301         
2302         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2303         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2304         
2305         dialog = hildon_color_chooser_new ();
2306         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2307
2308         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2309                 GdkColor col;
2310                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2311                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2312         }
2313         gtk_widget_destroy (dialog);
2314 }
2315
2316
2317 static TnyStream*
2318 create_stream_for_uri (const gchar* uri)
2319 {
2320         if (!uri)
2321                 return NULL;
2322                 
2323         TnyStream *result = NULL;
2324
2325         GnomeVFSHandle *handle = NULL;
2326         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2327         if (test == GNOME_VFS_OK) {
2328                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2329                 /* Streams over OBEX (Bluetooth) are not seekable but
2330                  * we expect them to be (we might need to read them
2331                  * several times). So if this is a Bluetooth URI just
2332                  * read the whole file into memory (this is not a fast
2333                  * protocol so we can assume that these files are not
2334                  * going to be very big) */
2335                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2336                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2337                         TnyStream *memstream = tny_camel_mem_stream_new ();
2338                         tny_stream_write_to_stream (vfssstream, memstream);
2339                         g_object_unref (vfssstream);
2340                         result = memstream;
2341                 } else {
2342                         result = vfssstream;
2343                 }
2344         }
2345         
2346         return result;
2347 }
2348
2349 void
2350 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2351 {
2352         
2353         ModestMsgEditWindowPrivate *priv;
2354         GtkWidget *dialog = NULL;
2355         gint response = 0;
2356         GSList *uris = NULL;
2357         GSList *uri_node = NULL;
2358
2359         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2360
2361         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2362         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2363         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2364
2365         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2366
2367         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2368                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2369
2370         response = gtk_dialog_run (GTK_DIALOG (dialog));
2371         switch (response) {
2372         case GTK_RESPONSE_OK:
2373         {
2374                 gchar *current_folder;
2375                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2376                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2377                 if (current_folder && current_folder != '\0') {
2378                         GError *err = NULL;
2379                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH, 
2380                                                 current_folder, &err);
2381                         if (err != NULL) {
2382                                 g_debug ("Error storing latest used folder: %s", err->message);
2383                                 g_error_free (err);
2384                         }
2385                 }
2386                 g_free (current_folder);
2387         }
2388         break;
2389         default:
2390                 break;
2391         }
2392         gtk_widget_destroy (dialog);
2393
2394         g_object_ref (window);
2395         /* The operation could take some time so allow the dialog to be closed */
2396         while (gtk_events_pending ())
2397                 gtk_main_iteration ();
2398
2399         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2400                 const gchar *uri;
2401                 GnomeVFSHandle *handle = NULL;
2402                 GnomeVFSResult result;
2403                 GtkTextIter position;
2404                 GtkTextMark *insert_mark;
2405
2406                 uri = (const gchar *) uri_node->data;
2407                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2408                 if (result == GNOME_VFS_OK) {
2409                         GdkPixbuf *pixbuf;
2410                         GnomeVFSFileInfo *info;
2411                         gchar *filename, *basename, *escaped_filename;
2412                         TnyMimePart *mime_part;
2413                         gchar *content_id;
2414                         const gchar *mime_type = NULL;
2415                         GnomeVFSURI *vfs_uri;
2416                         guint64 stream_size;
2417
2418                         gnome_vfs_close (handle);
2419                         vfs_uri = gnome_vfs_uri_new (uri);
2420
2421                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2422                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2423                         g_free (escaped_filename);
2424                         gnome_vfs_uri_unref (vfs_uri);
2425                         info = gnome_vfs_file_info_new ();
2426
2427                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2428                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2429                             == GNOME_VFS_OK)
2430                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2431
2432                         mime_part = tny_platform_factory_new_mime_part
2433                                 (modest_runtime_get_platform_factory ());
2434
2435                         TnyStream *stream = create_stream_for_uri (uri);
2436
2437                         if (stream == NULL) {
2438
2439                                 modest_platform_information_banner (NULL, NULL, 
2440                                                                     _FM("sfil_ib_opening_not_allowed"));
2441                                 g_free (filename);
2442                                 g_object_unref (mime_part);
2443                                 gnome_vfs_file_info_unref (info);
2444                                 continue;
2445                         }
2446
2447                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2448
2449                         content_id = g_strdup_printf ("%d", priv->next_cid);
2450                         tny_mime_part_set_content_id (mime_part, content_id);
2451                         g_free (content_id);
2452                         priv->next_cid++;
2453
2454                         basename = g_path_get_basename (filename);
2455                         tny_mime_part_set_filename (mime_part, basename);
2456                         g_free (basename);
2457
2458                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2459
2460                         if (pixbuf != NULL) {
2461                                 priv->images_size += stream_size;
2462                                 priv->images_count ++;
2463                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2464                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2465                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, 
2466                                                              tny_mime_part_get_content_id (mime_part), pixbuf);
2467                                 g_object_unref (pixbuf);
2468
2469                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2470                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2471                         } else {
2472                                 modest_platform_information_banner (NULL, NULL,
2473                                                                     _("mail_ib_file_operation_failed"));
2474                         }
2475
2476                         g_free (filename);
2477                         g_object_unref (mime_part);
2478                         gnome_vfs_file_info_unref (info);
2479
2480                 }
2481         }
2482         g_object_unref (window);
2483 }
2484
2485 static void
2486 on_attach_file_response (GtkDialog *dialog,
2487                          gint       arg1,
2488                          gpointer   user_data)
2489 {
2490         GSList *uris = NULL;
2491         GSList *uri_node;
2492         GnomeVFSFileSize total_size, allowed_size;
2493         ModestMsgEditWindow *window;
2494         ModestMsgEditWindowPrivate *priv;
2495         gint att_num;
2496         guint64 att_size;
2497
2498         switch (arg1) {
2499         case GTK_RESPONSE_OK:
2500         {
2501                 gchar *current_folder;
2502
2503                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2504                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2505                 if (current_folder && current_folder != '\0') {
2506                         GError *err = NULL;
2507                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, 
2508                                                 current_folder, &err);
2509                         if (err != NULL) {
2510                                 g_debug ("Error storing latest used folder: %s", err->message);
2511                                 g_error_free (err);
2512                         }
2513                 }
2514                 g_free (current_folder);
2515         }
2516         break;
2517         default:
2518                 break;
2519         }
2520
2521         window = MODEST_MSG_EDIT_WINDOW (user_data);
2522         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2523
2524         /* allowed size is the maximum size - what's already there */
2525         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2526                                            &att_num, &att_size);
2527         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2528
2529         total_size = 0;
2530         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2531
2532                 const gchar *uri = (const gchar *) uri_node->data;
2533
2534                 total_size += 
2535                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2536
2537                 if (total_size > allowed_size) {
2538                         g_debug ("%s: total size: %u", 
2539                                    __FUNCTION__, (unsigned int)total_size);
2540                         break;
2541                 }
2542                 allowed_size -= total_size;
2543         }
2544         g_slist_foreach (uris, (GFunc) g_free, NULL);
2545         g_slist_free (uris);
2546
2547         gtk_widget_destroy (GTK_WIDGET (dialog));
2548 }
2549
2550 void
2551 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2552 {
2553         GtkWidget *dialog = NULL;
2554         ModestMsgEditWindowPrivate *priv;
2555         gchar *conf_folder;
2556
2557         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2558
2559         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2560
2561         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2562                 return;
2563
2564         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2565                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2566         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2567         conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2568                                               MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2569         if (conf_folder && conf_folder[0] != '\0') {
2570                 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2571         } else {
2572                 gchar *docs_folder;
2573                 /* Set the default folder to documents folder */
2574                 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2575                 if (!docs_folder) {
2576                         /* fallback */
2577                         docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2578                                                         ".documents", NULL);
2579                 }
2580                 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2581                 g_free (docs_folder);
2582         }
2583         g_free (conf_folder);
2584         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2585         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2586                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2587
2588         /* Connect to response & show */
2589         g_signal_connect (dialog, "response", 
2590                           G_CALLBACK (on_attach_file_response), window);
2591         gtk_widget_show (dialog);
2592 }
2593
2594
2595 GnomeVFSFileSize
2596 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2597                                         const gchar *uri, 
2598                                         GnomeVFSFileSize allowed_size)
2599
2600 {
2601         GnomeVFSHandle *handle = NULL;
2602         ModestMsgEditWindowPrivate *priv;
2603         GnomeVFSResult result;
2604         GnomeVFSFileSize size = 0;
2605         g_return_val_if_fail (window, 0);
2606         g_return_val_if_fail (uri, 0);
2607
2608         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2609
2610         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2611         if (result == GNOME_VFS_OK) {
2612                 TnyMimePart *mime_part;
2613                 TnyStream *stream;
2614                 const gchar *mime_type = NULL;
2615                 gchar *basename;
2616                 gchar *escaped_filename;
2617                 gchar *filename;
2618                 gchar *content_id;
2619                 GnomeVFSFileInfo *info;
2620                 GnomeVFSURI *vfs_uri;
2621
2622                 gnome_vfs_close (handle);
2623                 vfs_uri = gnome_vfs_uri_new (uri);
2624                 
2625
2626                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2627                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2628                 g_free (escaped_filename);
2629                 gnome_vfs_uri_unref (vfs_uri);
2630
2631                 info = gnome_vfs_file_info_new ();
2632                 
2633                 if (gnome_vfs_get_file_info (uri, 
2634                                              info, 
2635                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2636                     == GNOME_VFS_OK)
2637                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2638                 mime_part = tny_platform_factory_new_mime_part
2639                         (modest_runtime_get_platform_factory ());
2640                 
2641                 /* try to get the attachment's size; this may fail for weird
2642                  * file systems, like obex, upnp... */
2643                 if (allowed_size != 0 &&
2644                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2645                         size = info->size;
2646                         if (size > allowed_size) {
2647                                 modest_platform_information_banner (NULL, NULL,
2648                                                                     _("mail_ib_error_attachment_size"));
2649                                 g_free (filename);
2650                                 return 0;
2651                         }
2652                 } else
2653                         g_debug ("%s: could not get attachment size", __FUNCTION__);
2654                 
2655                 stream = create_stream_for_uri (uri);
2656                 
2657                 if (stream == NULL) {
2658
2659                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2660
2661                         g_object_unref (mime_part);
2662                         g_free (filename);
2663                         gnome_vfs_file_info_unref (info);
2664                         return 0;
2665                 }
2666
2667                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2668                 g_object_unref (stream);
2669                 
2670                 content_id = g_strdup_printf ("%d", priv->next_cid);
2671                 tny_mime_part_set_content_id (mime_part, content_id);
2672                 g_free (content_id);
2673                 priv->next_cid++;
2674                 
2675                 basename = g_path_get_basename (filename);
2676                 tny_mime_part_set_filename (mime_part, basename);
2677                 g_free (basename);
2678                 
2679                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2680                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2681                                                         mime_part,
2682                                                         info->size == 0, info->size);
2683                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2684                 gtk_widget_show_all (priv->attachments_caption);
2685                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2686                 g_free (filename);
2687                 g_object_unref (mime_part);
2688                 gnome_vfs_file_info_unref (info);
2689         }
2690
2691         return size;
2692 }
2693
2694 void
2695 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2696                                            TnyList *att_list)
2697 {
2698         ModestMsgEditWindowPrivate *priv;
2699         TnyIterator *iter;
2700
2701         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2702         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2703
2704         if (att_list == NULL) {
2705                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2706                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2707                         g_object_unref (att_list);
2708                         return;
2709                 }
2710         } else {
2711                 g_object_ref (att_list);
2712         }
2713
2714         if (tny_list_get_length (att_list) == 0) {
2715                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2716         } else {
2717                 gboolean dialog_response;
2718                 gchar *message = NULL;
2719                 gchar *filename = NULL;
2720
2721                 if (tny_list_get_length (att_list) == 1) {
2722                         TnyMimePart *part;
2723                         iter = tny_list_create_iterator (att_list);
2724                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2725                         g_object_unref (iter);
2726                         if (TNY_IS_MSG (part)) {
2727                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2728                                 if (header) {
2729                                         filename = tny_header_dup_subject (header);
2730                                         g_object_unref (header);
2731                                 }
2732                                 if (filename == NULL) {
2733                                         filename = g_strdup (_("mail_va_no_subject"));
2734                                 }
2735                         } else {
2736                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2737                         }
2738                         g_object_unref (part);
2739                 } else {
2740                         filename = g_strdup ("");
2741                 }
2742                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2743                                                     "emev_nc_delete_attachments",
2744                                                     tny_list_get_length (att_list)), filename);
2745                 g_free (filename);
2746
2747                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2748                                                                            message);
2749                 g_free (message);
2750
2751                 if (dialog_response != GTK_RESPONSE_OK) {
2752                         g_object_unref (att_list);
2753                         return;
2754                 }
2755
2756                 for (iter = tny_list_create_iterator (att_list);
2757                      !tny_iterator_is_done (iter);
2758                      tny_iterator_next (iter)) {
2759                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2760                         const gchar *att_id;
2761                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2762
2763                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2764                                                                    mime_part);
2765                         if (tny_list_get_length (priv->attachments) == 0)
2766                                 gtk_widget_hide (priv->attachments_caption);
2767                         att_id = tny_mime_part_get_content_id (mime_part);
2768                         if (att_id != NULL)
2769                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2770                                                                  att_id);
2771                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2772                         g_object_unref (mime_part);
2773                 }
2774                 g_object_unref (iter);
2775         }
2776
2777         g_object_unref (att_list);
2778
2779         /* if the last attachment has been removed, focus the Subject: field */
2780         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2781                 gtk_widget_grab_focus (priv->subject_field);
2782 }
2783
2784 static void
2785 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2786                                             gpointer userdata)
2787 {
2788         ModestMsgEditWindowPrivate *priv;
2789         GdkColor new_color;
2790
2791         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2792
2793         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &new_color);
2794
2795         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) &new_color);
2796
2797         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2798 }
2799
2800 static void
2801 font_size_clicked (GtkToolButton *button,
2802                    ModestMsgEditWindow *window)
2803 {
2804         ModestMsgEditWindowPrivate *priv;
2805         GtkWidget *selector, *dialog;
2806         
2807         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2808
2809         selector = hildon_touch_selector_new ();
2810         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2811         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2812
2813         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2814         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2815         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2816
2817         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2818                 gint new_index;
2819                 gchar *size_text;
2820                 gchar *markup;
2821                 WPTextBufferFormat format;
2822
2823                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2824
2825                 memset (&format, 0, sizeof (format));
2826                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2827
2828                 format.cs.font_size = TRUE;
2829                 format.cs.text_position = TRUE;
2830                 format.cs.font = TRUE;
2831                 format.font_size = new_index;
2832 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2833
2834                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2835                                                    GINT_TO_POINTER (new_index)))
2836                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2837                 
2838                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2839                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2840                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2841                                       size_text, "</span>", NULL);
2842                 g_free (size_text);
2843                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2844                 g_free (markup);
2845
2846         }
2847         gtk_widget_destroy (dialog);
2848
2849         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2850
2851 }
2852
2853 static void
2854 font_face_clicked (GtkToolButton *button,
2855                    ModestMsgEditWindow *window)
2856 {
2857         ModestMsgEditWindowPrivate *priv;
2858         GtkWidget *selector, *dialog;
2859         GtkCellRenderer *renderer;
2860         
2861         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2862
2863         selector = hildon_touch_selector_new ();
2864         renderer = gtk_cell_renderer_text_new ();
2865         g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2866         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2867                                              renderer, "family", 0, "text", 0, NULL);
2868         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2869
2870         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2871         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2872         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2873
2874         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2875                 gint new_font_index;
2876                 GtkTreePath *path;
2877                 GtkTreeIter iter;
2878
2879                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2880                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2881                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2882                         gchar *face_name;
2883                         gchar *markup;
2884
2885                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2886
2887                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2888                                                            GINT_TO_POINTER(new_font_index)))
2889                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2890
2891                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2892                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2893
2894                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2895                         g_free (face_name);
2896                         g_free (markup);
2897                 }
2898                 gtk_tree_path_free (path);
2899
2900         }
2901         gtk_widget_destroy (dialog);
2902
2903         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2904
2905 }
2906
2907 void
2908 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2909                                 gboolean show)
2910 {
2911         ModestMsgEditWindowPrivate *priv = NULL;
2912         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2913
2914         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915         if (!priv->update_caption_visibility)
2916                 return;
2917
2918         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2919         if (show)
2920                 gtk_widget_show (priv->cc_caption);
2921         else
2922                 gtk_widget_hide (priv->cc_caption);
2923
2924         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2925 }
2926
2927 void
2928 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2929                                  gboolean show)
2930 {
2931         ModestMsgEditWindowPrivate *priv = NULL;
2932         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2933
2934         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935         if (!priv->update_caption_visibility)
2936                 return;
2937
2938         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2939         if (show)
2940                 gtk_widget_show (priv->bcc_caption);
2941         else
2942                 gtk_widget_hide (priv->bcc_caption);
2943
2944         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2945 }
2946
2947 static void
2948 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2949                                          ModestRecptEditor *editor)
2950 {
2951         ModestMsgEditWindowPrivate *priv;
2952
2953         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2954         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2955         
2956         /* we check for low-mem; in that case, show a warning, and don't allow
2957          * for the addressbook
2958          */
2959         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2960                 return;
2961
2962         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2963
2964         if (editor == NULL) {
2965                 GtkWidget *view_focus, *parent;
2966                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2967
2968                 /* This code should be kept in sync with ModestRecptEditor. The
2969                    textview inside the recpt editor is the one that really gets the
2970                    focus. As it's inside a scrolled window, and this one inside the
2971                    hbox recpt editor inherits from, we'll need to go up in the 
2972                    hierarchy to know if the text view is part of the recpt editor
2973                    or if it's a different text entry */
2974                 parent = gtk_widget_get_parent (view_focus);
2975                 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2976                         editor = MODEST_RECPT_EDITOR (parent);
2977
2978                 if (editor == NULL)
2979                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2980         }
2981
2982         modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2983 }
2984
2985 void
2986 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2987 {
2988         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2989
2990         modest_msg_edit_window_open_addressbook (window, NULL);
2991 }
2992
2993 static void
2994 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2995                                      gboolean show_toolbar)
2996 {
2997         ModestWindowPrivate *parent_priv;
2998         ModestMsgEditWindowPrivate *priv;
2999
3000         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
3001         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3002         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
3003
3004         /* We can not just use the code of
3005            modest_msg_edit_window_setup_toolbar because it has a
3006            mixture of both initialization and creation code. */
3007         if (show_toolbar) {
3008                 gint current_format;
3009                 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3010                         ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3011                 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3012                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3013                 } else {
3014                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3015                 }
3016         } else {
3017                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3018         }
3019         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, show_toolbar, NULL);
3020         if (hildon_check_button_get_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button)) != show_toolbar) {
3021                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button), show_toolbar);
3022         }
3023 }
3024
3025 void
3026 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3027                                            TnyHeaderFlags priority_flags)
3028 {
3029         ModestMsgEditWindowPrivate *priv;
3030         ModestWindowPrivate *parent_priv;
3031
3032         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3033
3034         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3035         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3036
3037         if (priv->priority_flags != priority_flags) {
3038                 GtkAction *priority_action = NULL;
3039
3040                 priv->priority_flags = priority_flags;
3041
3042                 switch (priority_flags) {
3043                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3044                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3045                                                       MODEST_HEADER_ICON_HIGH, 
3046                                                       HILDON_ICON_SIZE_SMALL);
3047                         gtk_widget_show (priv->priority_icon);
3048                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3049                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3050                         break;
3051                 case TNY_HEADER_FLAG_LOW_PRIORITY:
3052                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3053                                                       MODEST_HEADER_ICON_LOW,
3054                                                       HILDON_ICON_SIZE_SMALL);
3055                         gtk_widget_show (priv->priority_icon);
3056                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3057                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3058                         break;
3059                 default:
3060                         gtk_widget_hide (priv->priority_icon);
3061                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3062                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3063                         break;
3064                 }
3065                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3066                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3067         }
3068         gtk_widget_queue_resize (priv->subject_box);
3069 }
3070
3071 void
3072 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3073                                         gint file_format)
3074 {
3075         ModestMsgEditWindowPrivate *priv;
3076         ModestWindowPrivate *parent_priv;
3077         gint current_format;
3078
3079         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3080
3081         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3082         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3083
3084         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3085                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3086
3087         gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3088
3089         if (current_format != file_format) {
3090                 switch (file_format) {
3091                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3092                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3093                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3094                         update_signature (window, priv->last_from_account, priv->last_from_account);
3095                         if (parent_priv->toolbar)
3096                                 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3097                                                                 MODEST_MSG_EDIT_WINDOW (window));
3098                         break;
3099                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3100                 {
3101                         GtkWidget *dialog;
3102                         gint response;
3103                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3104                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3105                         gtk_widget_destroy (dialog);
3106                         if (response == GTK_RESPONSE_OK) {
3107                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3108                                 if (parent_priv->toolbar)
3109                                         on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3110                                                                         MODEST_MSG_EDIT_WINDOW (window));
3111                         } else {
3112                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3113                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3114                         }
3115                 }
3116                         break;
3117                 }
3118                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3119                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3120                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3121         }
3122 }
3123
3124 void
3125 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3126 {
3127         GtkWidget *dialog;
3128         ModestMsgEditWindowPrivate *priv;
3129         WPTextBufferFormat oldfmt, fmt;
3130         gint old_position = 0;
3131         gint response = 0;
3132         gint position = 0;
3133         gint font_size;
3134         GdkColor *color = NULL;
3135         gboolean bold, bold_set, italic, italic_set;
3136         gboolean underline, underline_set;
3137         gboolean strikethrough, strikethrough_set;
3138         gboolean position_set;
3139         gboolean font_size_set, font_set, color_set;
3140         gchar *font_name;
3141
3142         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3143         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3144         
3145         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3146         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3147                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
3148
3149         /* First we get the currently selected font information */
3150         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3151
3152         switch (oldfmt.text_position) {
3153         case TEXT_POSITION_NORMAL:
3154                 old_position = 0;
3155                 break;
3156         case TEXT_POSITION_SUPERSCRIPT:
3157                 old_position = 1;
3158                 break;
3159         default:
3160                 old_position = -1;
3161                 break;
3162         }
3163
3164         g_object_set (G_OBJECT (dialog),
3165                       "bold", oldfmt.bold != FALSE,
3166                       "bold-set", !oldfmt.cs.bold,
3167                       "underline", oldfmt.underline != FALSE,
3168                       "underline-set", !oldfmt.cs.underline,
3169                       "italic", oldfmt.italic != FALSE,
3170                       "italic-set", !oldfmt.cs.italic,
3171                       "strikethrough", oldfmt.strikethrough != FALSE,
3172                       "strikethrough-set", !oldfmt.cs.strikethrough,
3173                       "color", &oldfmt.color,
3174                       "color-set", !oldfmt.cs.color,
3175                       "size", wp_font_size[oldfmt.font_size],
3176                       "size-set", !oldfmt.cs.font_size,
3177                       "position", old_position,
3178                       "position-set", !oldfmt.cs.text_position,
3179                       "family", wp_get_font_name (oldfmt.font),
3180                       "family-set", !oldfmt.cs.font,
3181                       NULL);
3182
3183         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
3184                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
3185         gtk_widget_show_all (dialog);
3186         priv->font_dialog = dialog;
3187         response = gtk_dialog_run (GTK_DIALOG (dialog));
3188         priv->font_dialog = NULL;
3189         if (response == GTK_RESPONSE_OK) {
3190
3191                 g_object_get( dialog,
3192                               "bold", &bold,
3193                               "bold-set", &bold_set,
3194                               "underline", &underline,
3195                               "underline-set", &underline_set,
3196                               "italic", &italic,
3197                               "italic-set", &italic_set,
3198                               "strikethrough", &strikethrough,
3199                               "strikethrough-set", &strikethrough_set,
3200                               "color", &color,
3201                               "color-set", &color_set,
3202                               "size", &font_size,
3203                               "size-set", &font_size_set,
3204                               "family", &font_name,
3205                               "family-set", &font_set,
3206                               "position", &position,
3207                               "position-set", &position_set,
3208                               NULL );
3209                 
3210         }       
3211
3212         if (response == GTK_RESPONSE_OK) {
3213                 memset(&fmt, 0, sizeof(fmt));
3214                 if (bold_set) {
3215                         fmt.bold = bold;
3216                         fmt.cs.bold = TRUE;
3217                 }
3218                 if (italic_set) {
3219                         fmt.italic = italic;
3220                         fmt.cs.italic = TRUE;
3221                 }
3222                 if (underline_set) {
3223                         fmt.underline = underline;
3224                         fmt.cs.underline = TRUE;
3225                 }
3226                 if (strikethrough_set) {
3227                         fmt.strikethrough = strikethrough;
3228                         fmt.cs.strikethrough = TRUE;
3229                 }
3230                 if (position_set) {
3231                         fmt.text_position =
3232                                 ( position == 0 )
3233                                 ? TEXT_POSITION_NORMAL
3234                                 : ( ( position == 1 )
3235                                     ? TEXT_POSITION_SUPERSCRIPT
3236                                     : TEXT_POSITION_SUBSCRIPT );
3237                         fmt.cs.text_position = TRUE;
3238                         fmt.font_size = oldfmt.font_size;
3239                 }
3240                 if (color_set) {
3241                         fmt.color = *color;
3242                         fmt.cs.color = TRUE;
3243                 }
3244                 if (font_set) {
3245                         fmt.font = wp_get_font_index(font_name,
3246                                                      DEFAULT_FONT);
3247                         fmt.cs.font = TRUE;
3248                 }
3249                 g_free(font_name);
3250                 if (font_size_set) {
3251                         fmt.cs.font_size = TRUE;
3252                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3253                 }
3254                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3255                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3256         }
3257         gtk_widget_destroy (dialog);
3258         
3259         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3260 }
3261
3262 void
3263 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3264 {
3265         ModestMsgEditWindowPrivate *priv;
3266         ModestWindowPrivate *parent_priv;
3267         gboolean was_rich_text, is_rich_text;
3268
3269         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3270         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3271         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3272
3273         was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3274
3275         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3276
3277         is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3278
3279         if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3280                 on_show_toolbar_button_toggled (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
3281                                                 MODEST_MSG_EDIT_WINDOW (window));
3282         }
3283
3284         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3285         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3286 }
3287
3288 void
3289 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3290 {
3291         ModestMsgEditWindowPrivate *priv;
3292
3293         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3294         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3295         
3296         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3297
3298         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3299         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3300
3301 }
3302
3303 static void  
3304 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3305 {
3306         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3307
3308         priv->can_undo = can_undo;
3309 }
3310
3311 static void  
3312 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3313 {
3314         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3315
3316         priv->can_redo = can_redo;
3317 }
3318
3319 gboolean            
3320 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3321 {
3322         ModestMsgEditWindowPrivate *priv;
3323         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3324         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3325
3326         return priv->can_undo;
3327 }
3328
3329 gboolean            
3330 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3331 {
3332         ModestMsgEditWindowPrivate *priv;
3333         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3334         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3335
3336         return priv->can_redo;
3337 }
3338
3339
3340 static void
3341 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3342 {
3343         GtkTextIter iter;
3344         GtkTextIter match_start, match_end;
3345
3346         if (image_id == NULL)
3347                 return;
3348
3349         gtk_text_buffer_get_start_iter (buffer, &iter);
3350
3351         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3352                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3353                 GSList *node;
3354                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3355                         GtkTextTag *tag = (GtkTextTag *) node->data;
3356                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3357                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3358                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3359                                         gint offset;
3360                                         offset = gtk_text_iter_get_offset (&match_start);
3361                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3362                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3363                                 }
3364                         }
3365                 }
3366                 gtk_text_iter_forward_char (&iter);
3367         }
3368 }
3369
3370 gboolean
3371 message_is_empty (ModestMsgEditWindow *window)
3372 {
3373         ModestMsgEditWindowPrivate *priv = NULL;
3374
3375         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3376         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3377
3378         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3379          * so we can ignore markup.
3380          */
3381         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3382         gint count = 0;
3383         if (buf)
3384                 count = gtk_text_buffer_get_char_count (buf);
3385
3386         return count == 0;
3387 }
3388
3389 static gboolean
3390 msg_body_focus (GtkWidget *focus,
3391                 GdkEventFocus *event,
3392                 gpointer userdata)
3393 {
3394         
3395         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3396         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3397         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3398         return FALSE;
3399 }
3400
3401 static void
3402 recpt_field_changed (GtkTextBuffer *buffer,
3403                   ModestMsgEditWindow *editor)
3404 {
3405         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3406         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3407 }
3408
3409 static void
3410 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3411 {
3412         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3413         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3414 }
3415
3416 void
3417 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3418                                      gboolean modified)
3419 {
3420         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3421         GtkTextBuffer *buffer;
3422
3423         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3424         gtk_text_buffer_set_modified (buffer, modified);
3425         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3426         gtk_text_buffer_set_modified (buffer, modified);
3427         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3428         gtk_text_buffer_set_modified (buffer, modified);
3429         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3430 }
3431
3432 gboolean
3433 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3434 {
3435         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3436         const char *account_name;
3437         GtkTextBuffer *buffer;
3438
3439         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3440         if (gtk_text_buffer_get_modified (buffer))
3441                 return TRUE;
3442         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3443         if (gtk_text_buffer_get_modified (buffer))
3444                 return TRUE;
3445         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3446         if (gtk_text_buffer_get_modified (buffer))
3447                 return TRUE;
3448         if (gtk_text_buffer_get_modified (priv->text_buffer))
3449                 return TRUE;
3450
3451         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3452         if (priv->original_mailbox) {
3453                 if (!account_name || strcmp (account_name, priv->original_mailbox))
3454                         return TRUE;
3455         } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3456                 return TRUE;
3457         }
3458
3459         return FALSE;
3460 }
3461
3462
3463
3464
3465 gboolean
3466 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3467 {
3468         ModestMsgEditWindowPrivate *priv = NULL;
3469         GSList *address_list = NULL;
3470         gboolean no_to, no_cc, no_bcc;
3471
3472         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3473         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3474
3475         /* check if there's no recipient added */
3476         no_to = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)));
3477         no_cc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field)));
3478         no_bcc = modest_text_utils_no_recipient (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field)));
3479
3480
3481         if (no_to && no_cc && no_bcc) {
3482                 /* no recipient contents, then select contacts */
3483                 modest_msg_edit_window_open_addressbook (window, NULL);
3484                 return FALSE;
3485         }
3486
3487         /* Check names */
3488         g_object_ref (window);
3489         if (!no_to && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),
3490                                               (add_to_addressbook) ? &address_list : NULL)) {
3491                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3492                 g_object_unref (window);
3493                 return FALSE;
3494         }
3495         if (!no_cc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),
3496                                               (add_to_addressbook) ? &address_list : NULL)) {
3497                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3498                 g_object_unref (window);
3499                 return FALSE;
3500         }
3501         if (!no_bcc && !modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field),
3502                                               (add_to_addressbook) ? &address_list : NULL)) {
3503                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3504                 g_object_unref (window);
3505                 return FALSE;
3506         }
3507
3508         /* Add contacts to address book */
3509         if (add_to_addressbook && address_list)
3510                 modest_address_book_add_address_list (address_list);
3511
3512         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3513             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3514                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3515         g_object_unref (window);
3516
3517         return TRUE;
3518
3519 }
3520
3521 void
3522 modest_msg_edit_window_add_to_contacts (ModestMsgEditWindow *self)
3523 {
3524         GSList *recipients = NULL;
3525         ModestMsgEditWindowPrivate *priv;
3526         gchar *joined, *after_remove, *to, *cc, *bcc;
3527
3528         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3529
3530         /* First of all check names */
3531         if (!modest_msg_edit_window_check_names (self, FALSE))
3532                 return;
3533
3534         if (!modest_msg_edit_window_has_pending_addresses (self))
3535                 return;
3536
3537         /* Don't add the from obviously */
3538         to  =  g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->to_field));
3539         cc  =  g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->cc_field));
3540         bcc =  g_strdup (modest_recpt_editor_get_recipients ((ModestRecptEditor *) priv->bcc_field));
3541
3542         joined = modest_text_utils_join_addresses (NULL, to, cc, bcc);
3543         g_free (to);
3544         g_free (cc);
3545         g_free (bcc);
3546
3547         after_remove = modest_text_utils_remove_duplicate_addresses (joined);
3548         g_free (joined);
3549
3550         recipients = modest_text_utils_split_addresses_list (after_remove);
3551         g_free (after_remove);
3552
3553         if (recipients) {
3554                 /* Offer the user to add recipients to the address book */
3555                 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3556                 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3557         }
3558 }
3559
3560 static void
3561 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3562                                                ModestMsgEditWindow *window)
3563 {
3564         modest_msg_edit_window_offer_attach_file (window);
3565 }
3566
3567 const gchar *
3568 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3569 {
3570         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3571
3572         return priv->clipboard_text;
3573 }
3574
3575 static void
3576 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3577                                                GdkEvent *event,
3578                                                ModestMsgEditWindow *window)
3579 {
3580         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3581         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3582         gchar *text = NULL;
3583
3584         /* It could happen that the window was already closed */
3585         if (!GTK_WIDGET_VISIBLE (window))
3586                 return;
3587
3588         g_object_ref (window);
3589         text = gtk_clipboard_wait_for_text (selection_clipboard);
3590
3591         if (priv->clipboard_text != NULL) {
3592                 g_free (priv->clipboard_text);
3593         }
3594         priv->clipboard_text = text;
3595
3596         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3597
3598         g_object_unref (window);
3599 }
3600
3601 static gboolean clipboard_owner_change_idle (gpointer userdata)
3602 {
3603         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3604         ModestMsgEditWindowPrivate *priv;
3605
3606         gdk_threads_enter ();
3607         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3608         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3609
3610         priv->clipboard_owner_idle = 0;
3611         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3612         gdk_threads_leave ();
3613
3614         return FALSE;
3615 }
3616
3617 static void
3618 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3619 {
3620         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3621         if (priv->clipboard_owner_idle == 0) {
3622                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3623                                                               clipboard_owner_change_idle, 
3624                                                               g_object_ref (window),
3625                                                               g_object_unref);
3626         }
3627 }
3628
3629 static void 
3630 subject_field_move_cursor (GtkEntry *entry,
3631                            GtkMovementStep step,
3632                            gint a1,
3633                            gboolean a2,
3634                            gpointer window)
3635 {
3636         /* It could happen that the window was already closed */
3637         if (!GTK_WIDGET_VISIBLE (window))
3638                 return;
3639
3640         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3641 }
3642
3643 static void 
3644 update_window_title (ModestMsgEditWindow *window)
3645 {
3646         ModestMsgEditWindowPrivate *priv = NULL;
3647         const gchar *subject;
3648
3649         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3650         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3651         if (subject == NULL || subject[0] == '\0')
3652                 subject = _("mail_va_new_email");
3653
3654         gtk_window_set_title (GTK_WINDOW (window), subject);
3655
3656 }
3657
3658
3659 static void  
3660 body_insert_text (GtkTextBuffer *buffer, 
3661                   GtkTextIter *location,
3662                   gchar *text,
3663                   gint len,
3664                   ModestMsgEditWindow *window)
3665 {
3666         GtkTextIter end_iter;
3667         gint offset;
3668         glong utf8_len;
3669         gint line;
3670         gchar *text_offset;
3671         gint text_lines;
3672
3673         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3674
3675         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3676
3677         offset = gtk_text_iter_get_offset (&end_iter);
3678         line = gtk_text_iter_get_line (&end_iter);
3679
3680         text_offset = text;
3681         text_lines = 0;
3682         while (text_offset < text + len) {
3683                 if (*text_offset == '\n')
3684                         text_lines++;
3685                 if (text_lines + line >= MAX_BODY_LINES) {
3686                         len = text_offset - text;
3687                         break;
3688                 }
3689                 text_offset++;
3690         }
3691
3692         utf8_len = g_utf8_strlen (text, len);
3693
3694         if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3695                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3696                 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3697                 {
3698                         gchar *result;
3699                         gchar *utf8_end;
3700
3701                         utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3702
3703                         /* Prevent endless recursion */
3704                         result = g_strndup (text, utf8_end - text);
3705                         g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3706                         g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3707                                                (gpointer) result, (gpointer) (utf8_end - text),
3708                                                (gpointer) window);
3709                         g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3710                 }
3711
3712         }
3713         if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3714                 if (priv->max_chars_banner == NULL) {
3715                         priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3716                                                                                  _CS("ckdg_ib_maximum_characters_reached"));
3717                         g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3718                 }
3719         }
3720 }
3721
3722 static void  
3723 subject_field_changed (GtkEditable *editable, 
3724                        ModestMsgEditWindow *window)
3725 {
3726         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3727         update_window_title (window);
3728         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3729         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3730         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3731 }
3732 static void  
3733 subject_field_insert_text (GtkEditable *editable, 
3734                            gchar *new_text,
3735                            gint new_text_length,
3736                            gint *position,
3737                            ModestMsgEditWindow *window)
3738 {
3739         GString *result = g_string_new ("");
3740         gchar *current;
3741         gint result_len = 0;
3742         const gchar *entry_text = NULL;
3743         gint old_length;
3744
3745         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3746         old_length = g_utf8_strlen (entry_text, -1);
3747
3748         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3749                 gunichar c = g_utf8_get_char_validated (current, 8);
3750                 /* Invalid unichar, stop */
3751                 if (c == -1)
3752                         break;
3753                 /* a bullet */
3754                 if (c == 0x2022)
3755                         continue;
3756                 result = g_string_append_unichar (result, c);
3757                 result_len++;
3758         }
3759
3760         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3761                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3762                 if (result_len > 0)
3763                 {
3764                         /* Prevent endless recursion */
3765                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3766                         g_signal_emit_by_name (editable, "insert-text", 
3767                                                (gpointer) result->str, (gpointer) result->len,
3768                                                (gpointer) position, (gpointer) window);
3769                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3770                 }
3771         }
3772
3773         if (result_len + old_length > 1000) {
3774                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3775                                                 _CS("ckdg_ib_maximum_characters_reached"));
3776         }
3777         g_string_free (result, TRUE);
3778 }
3779
3780 void
3781 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3782                                             gboolean show)
3783 {
3784         ModestMsgEditWindowPrivate *priv = NULL;
3785
3786         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3787         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3788
3789         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3790
3791         if (show) {
3792                 gtk_widget_show_all (priv->find_toolbar);
3793                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3794         } else {
3795                 gtk_widget_hide_all (priv->find_toolbar);
3796                 gtk_widget_grab_focus (priv->msg_body);
3797         }
3798 }
3799
3800 static gboolean 
3801 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3802                                           const gchar *str,
3803                                           GtkTextIter *match_start,
3804                                           GtkTextIter *match_end)
3805 {
3806         GtkTextIter end_iter;
3807         gchar *str_casefold;
3808         gint str_chars_n;
3809         gchar *range_text;
3810         gchar *range_casefold;
3811         gint offset;
3812         gint range_chars_n;
3813         gboolean result = FALSE;
3814
3815         if (str == NULL)
3816                 return TRUE;
3817         
3818         /* get end iter */
3819         end_iter = *iter;
3820         gtk_text_iter_forward_to_end (&end_iter);
3821
3822         str_casefold = g_utf8_casefold (str, -1);
3823         str_chars_n = strlen (str);
3824
3825         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3826         range_casefold = g_utf8_casefold (range_text, -1);
3827         range_chars_n = strlen (range_casefold);
3828
3829         if (range_chars_n < str_chars_n) {
3830                 g_free (str_casefold);
3831                 g_free (range_text);
3832                 g_free (range_casefold);
3833                 return FALSE;
3834         }
3835
3836         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3837                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3838                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3839                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3840                         result = TRUE;
3841                         if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3842                                                            match_start, match_end, NULL)) {
3843                                 g_debug ("Matched string with collate, but not matched in model");
3844                         }
3845                         g_free (found_text);
3846                 }
3847                 g_free (range_subtext);
3848                 if (result)
3849                         break;
3850         }
3851         g_free (str_casefold);
3852         g_free (range_text);
3853         g_free (range_casefold);
3854
3855         return result;
3856 }
3857
3858
3859 static void 
3860 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3861                                             ModestMsgEditWindow *window)
3862 {
3863         gchar *current_search = NULL;
3864         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3865         gboolean result;
3866         GtkTextIter selection_start, selection_end;
3867         GtkTextIter match_start, match_end;
3868         gboolean continue_search = FALSE;
3869
3870         if (message_is_empty (window)) {
3871                 g_free (priv->last_search);
3872                 priv->last_search = NULL;
3873                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3874                 return;
3875         }
3876
3877         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3878         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3879                 g_free (current_search);
3880                 g_free (priv->last_search);
3881                 priv->last_search = NULL;
3882                 /* Information banner about empty search */
3883                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3884                 return;
3885         }
3886
3887         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3888                 continue_search = TRUE;
3889         } else {
3890                 g_free (priv->last_search);
3891                 priv->last_search = g_strdup (current_search);
3892         }
3893
3894         if (continue_search) {
3895                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3896                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3897                                                                    &match_start, &match_end);
3898                 if (!result)
3899                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3900         } else {
3901                 GtkTextIter buffer_start;
3902                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3903                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3904                                                                    &match_start, &match_end);
3905                 if (!result)
3906                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3907         }
3908
3909         /* Mark as selected the string found in search */
3910         if (result) {
3911                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3912                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3913                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3914         } else {
3915                 g_free (priv->last_search);
3916                 priv->last_search = NULL;
3917         }
3918         g_free (current_search);
3919 }
3920
3921 gboolean 
3922 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3923 {
3924         ModestMsgEditWindowPrivate *priv;
3925
3926         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3927         return priv->sent;
3928 }
3929
3930 void 
3931 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3932                                  gboolean sent)
3933 {
3934         ModestMsgEditWindowPrivate *priv;
3935
3936         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3937         priv->sent = sent;
3938 }
3939
3940 static void
3941 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3942                                           ModestMsgEditWindow *window)
3943 {
3944         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3945 }
3946
3947 void
3948 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3949                                   TnyMsg *draft)
3950 {
3951         ModestMsgEditWindowPrivate *priv;
3952         TnyHeader *header = NULL;
3953
3954         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3955         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3956
3957         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3958
3959         if (priv->draft_msg != NULL) {
3960                 g_object_unref (priv->draft_msg);
3961         }
3962
3963         if (draft != NULL) {
3964                 g_object_ref (draft);
3965                 header = tny_msg_get_header (draft);
3966                 if (priv->msg_uid) {
3967                         g_free (priv->msg_uid);
3968                         priv->msg_uid = NULL;
3969                 }
3970                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3971         }
3972
3973         priv->draft_msg = draft;
3974 }
3975
3976 static void  
3977 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3978                        GtkTextIter *start, GtkTextIter *end,
3979                        gpointer userdata)
3980 {
3981         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3982         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3983         gchar *tag_name;
3984
3985         if (tag == NULL) return;
3986         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3987         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3988                 replace_with_images (window, priv->images);
3989         }
3990 }
3991
3992 void                    
3993 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3994                                  TnyMimePart *part)
3995 {
3996         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3997
3998         g_return_if_fail (TNY_IS_MIME_PART (part));
3999         tny_list_prepend (priv->attachments, (GObject *) part);
4000         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
4001         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
4002         gtk_widget_show_all (priv->attachments_caption);
4003         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
4004 }
4005
4006 const gchar*    
4007 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
4008 {
4009         ModestMsgEditWindowPrivate *priv;
4010
4011         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
4012         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4013
4014         return priv->msg_uid;
4015 }
4016
4017 GtkWidget *
4018 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
4019                                          ModestMsgEditWindowWidgetType widget_type)
4020 {
4021         ModestMsgEditWindowPrivate *priv;
4022
4023         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
4024         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
4025
4026         switch (widget_type) {
4027         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
4028                 return priv->msg_body;
4029                 break;
4030         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
4031                 return priv->to_field;
4032                 break;
4033         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
4034                 return priv->cc_field;
4035                 break;
4036         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
4037                 return priv->bcc_field;
4038                 break;
4039         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
4040                 return priv->subject_field;
4041                 break;
4042         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
4043                 return priv->attachments_view;
4044                 break;
4045         default:
4046                 return NULL;
4047         }
4048 }
4049
4050 static void 
4051 remove_tags (WPTextBuffer *buffer)
4052 {
4053         GtkTextIter start, end;
4054
4055         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
4056         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
4057
4058         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
4059 }
4060
4061 static void
4062 on_account_removed (TnyAccountStore *account_store, 
4063                     TnyAccount *account,
4064                     gpointer user_data)
4065 {
4066         /* Do nothing if it's a store account, because we use the
4067            transport to send the messages */
4068         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
4069                 const gchar *parent_acc = NULL;
4070                 const gchar *our_acc = NULL;
4071
4072                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
4073                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
4074                 /* Close this window if I'm showing a message of the removed account */
4075                 if (strcmp (parent_acc, our_acc) == 0)
4076                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
4077         }
4078 }
4079
4080 static void
4081 update_signature (ModestMsgEditWindow *self,
4082                   const gchar *old_account,
4083                   const gchar *new_account)
4084 {
4085         ModestMsgEditWindowPrivate *priv;
4086         gboolean has_old_signature, has_new_signature;
4087         GtkTextIter iter;
4088         ModestAccountMgr *mgr;
4089         gchar *signature;
4090
4091         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4092
4093         gtk_text_buffer_begin_user_action (priv->text_buffer);
4094
4095         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
4096         mgr = modest_runtime_get_account_mgr ();
4097
4098
4099         if (old_account) {
4100                 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
4101                 if (has_old_signature) {
4102                         GtkTextIter match_start, match_end;
4103                         /* We cannot use
4104                            MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
4105                            seems that the search has some problems
4106                            with the blank space at the end */
4107                         if (gtk_text_iter_forward_search (&iter, "--",
4108                                                           GTK_TEXT_SEARCH_TEXT_ONLY,
4109                                                           &match_start, NULL, NULL)) {
4110                                 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
4111                                 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
4112                                 iter = match_start;
4113                         } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
4114                                                                  &match_start, &match_end, NULL)) {
4115                                 iter = match_start;
4116                         }
4117                 } else {
4118                         gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
4119                 }
4120                 g_free (signature);
4121         }
4122
4123         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4124         signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
4125         if (has_new_signature) {
4126                 gboolean is_rich;
4127
4128                 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4129                                                      MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4130                                                      signature, NULL);
4131                 is_rich = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
4132                 if (is_rich) {
4133                         WPTextBufferFormat *fmt;
4134                         GdkColor style_color;
4135                         if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4136                                 gdk_color_parse ("grey", &style_color);
4137                         }
4138                         fmt = g_new0 (WPTextBufferFormat, 1);
4139                         fmt->color = style_color;
4140                         fmt->cs.color = 0x1;
4141                         wp_text_buffer_insert_with_attribute (WP_TEXT_BUFFER (priv->text_buffer), &iter, 
4142                                                               full_signature, -1,
4143                                                               fmt, TRUE);
4144                         g_free (fmt);
4145                         g_free (full_signature);
4146                 } else {
4147                         gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4148                 }
4149         }
4150         g_free (signature);
4151         gtk_text_buffer_end_user_action (priv->text_buffer);
4152 }
4153
4154 static void update_branding (ModestMsgEditWindow *self,
4155                              const gchar *new_account)
4156 {
4157         ModestMsgEditWindowPrivate *priv;
4158         ModestAccountMgr *mgr;
4159         const GdkPixbuf *new_icon = NULL;
4160         gchar *new_label = NULL;
4161         gboolean show = FALSE;
4162
4163         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4164
4165         mgr = modest_runtime_get_account_mgr ();
4166
4167         modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4168         if (new_icon) {
4169                 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4170                 gtk_widget_show (priv->brand_icon);
4171                 show = TRUE;
4172         } else {
4173                 gtk_widget_hide (priv->brand_icon);
4174         }
4175         if (new_label) {
4176                 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4177                 gtk_widget_show (priv->brand_label);
4178                 g_free (new_label);
4179                 show = TRUE;
4180         } else {
4181                 gtk_widget_hide (priv->brand_label);
4182         }
4183
4184         if (show)
4185                 gtk_widget_show (priv->brand_container);
4186         else
4187                 gtk_widget_hide (priv->brand_container);
4188 }
4189
4190 static void
4191 from_field_changed (HildonPickerButton *button,
4192                     ModestMsgEditWindow *self)
4193 {
4194         ModestMsgEditWindowPrivate *priv;
4195         gchar *old_account, *new_account;
4196
4197         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4198
4199         old_account = priv->last_from_account;
4200         new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4201
4202         if (!new_account) {
4203                 g_warning ("%s, could not get the new account", __FUNCTION__);
4204                 return;
4205         }
4206
4207         /* If the From is the same do nothing */
4208         if (old_account && new_account && !strcmp (old_account, new_account))
4209                 return;
4210
4211         priv->last_from_account = new_account;
4212
4213         update_signature (self, old_account, new_account);
4214         update_branding (self, new_account);
4215
4216 }
4217
4218 typedef struct _MessageSettingsHelper {
4219         ModestMsgEditWindow *window;
4220         GSList *priority_group;
4221         GSList *format_group;
4222         GtkToggleButton *current_priority;
4223         GtkToggleButton *current_format;
4224 } MessageSettingsHelper;
4225
4226 static void
4227 on_priority_toggle (GtkToggleButton *button, 
4228                     MessageSettingsHelper *helper)
4229 {
4230         GSList *node;
4231         ModestMsgEditWindowPrivate *priv;
4232
4233         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4234         if (gtk_toggle_button_get_active (button)) {
4235
4236                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4237                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4238                         if ((node_button != button) &&
4239                             gtk_toggle_button_get_active (node_button)) {
4240                                 gtk_toggle_button_set_active (node_button, FALSE);
4241                         }
4242                 }
4243                 helper->current_priority = button;
4244         } else {
4245                 gboolean found = FALSE;
4246                 /* If no one is active, activate it again */
4247                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4248                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4249                         if (gtk_toggle_button_get_active (node_button)) {
4250                                 found = TRUE;
4251                                 break;
4252                         }
4253                 }
4254                 if (!found) {
4255                         gtk_toggle_button_set_active (button, TRUE);
4256                 }
4257         }
4258 }
4259
4260 static void
4261 on_format_toggle (GtkToggleButton *button,
4262                   MessageSettingsHelper *helper)
4263 {
4264         GSList *node;
4265         ModestMsgEditWindowPrivate *priv;
4266
4267         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4268         if (gtk_toggle_button_get_active (button)) {
4269
4270                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4271                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4272                         if ((node_button != button) &&
4273                             gtk_toggle_button_get_active (node_button)) {
4274                                 gtk_toggle_button_set_active (node_button, FALSE);
4275                         }
4276                 }
4277                 helper->current_format = button;
4278         } else {
4279                 gboolean found = FALSE;
4280                 /* If no one is active, activate it again */
4281                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4282                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4283                         if (gtk_toggle_button_get_active (node_button)) {
4284                                 found = TRUE;
4285                                 break;
4286                         }
4287                 }
4288                 if (!found) {
4289                         gtk_toggle_button_set_active (button, TRUE);
4290                 }
4291         }
4292
4293 }
4294
4295 static void
4296 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4297 {
4298         GtkWidget *dialog;
4299         GtkWidget *align;
4300         GtkWidget *vbox;
4301         GtkWidget *priority_hbox;
4302         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4303         GtkWidget *captioned;
4304         GtkSizeGroup *title_sizegroup, *value_sizegroup;
4305         GtkWidget *format_hbox;
4306         GtkWidget *html_toggle, *text_toggle;
4307         ModestMsgEditWindowPrivate *priv;
4308         MessageSettingsHelper helper = {0,};
4309
4310         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4311         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4312         helper.window = window;
4313         helper.priority_group = NULL;
4314         helper.format_group = NULL;
4315
4316         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4317         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4318
4319         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4320                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4321                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4322         vbox = gtk_vbox_new (FALSE, 0);
4323         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4324         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4325         gtk_container_add (GTK_CONTAINER (align), vbox);
4326         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4327         gtk_widget_show (align);
4328         gtk_widget_show (vbox);
4329
4330         /* Priority toggles */
4331         priority_hbox = gtk_hbox_new (TRUE, 0);
4332         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4333         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4334         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4335         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4336         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4337         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4338         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4339         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4340         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4341         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4342         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4343         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4344         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4345         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4346         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4347         gtk_widget_show_all (priority_hbox);
4348         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4349                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4350         gtk_widget_show (captioned);
4351         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4352
4353         /* format toggles */
4354         format_hbox = gtk_hbox_new (TRUE, 0);
4355         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4356         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4357         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4358         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4359         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4360         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4361         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4362         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4363         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4364         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4365         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4366         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4367         gtk_widget_show_all (format_hbox);
4368         gtk_widget_show (format_hbox);
4369         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4370
4371
4372         g_object_unref (title_sizegroup);
4373         g_object_unref (value_sizegroup);
4374
4375         /* Set current values */
4376         switch (priv->priority_flags) {
4377         case TNY_HEADER_FLAG_HIGH_PRIORITY:
4378                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4379                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4380                 break;
4381         case TNY_HEADER_FLAG_LOW_PRIORITY:
4382                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4383                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4384                 break;
4385         default:
4386                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4387                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4388                 break;
4389         }
4390
4391         switch (modest_msg_edit_window_get_format (window)) {
4392         case MODEST_MSG_EDIT_FORMAT_TEXT:
4393                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4394                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4395                 break;
4396         case MODEST_MSG_EDIT_FORMAT_HTML:
4397         default:
4398                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4399                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4400                 break;
4401         }
4402
4403         /* Signal connects */
4404         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4405         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4406         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4407         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4408         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4409
4410         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4411                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
4412
4413         /* Save settings if the user clicked on done */
4414         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4415                 TnyHeaderFlags flags;
4416                 ModestMsgEditFormat old_format, new_format;
4417
4418                 /* Set priority flags */
4419                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4420                 if (priv->priority_flags !=  flags)
4421                         modest_msg_edit_window_set_priority_flags (window, flags);
4422
4423                 /* Set edit format */
4424                 old_format = modest_msg_edit_window_get_format (window);
4425                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4426                 if (old_format != new_format) {
4427                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4428                         modest_msg_edit_window_set_file_format (window, file_format);
4429                 }
4430         }
4431
4432         gtk_widget_destroy (dialog);
4433         g_slist_free (helper.priority_group);
4434 }
4435
4436 static void
4437 on_message_settings (GtkAction *action,
4438                      ModestMsgEditWindow *window)
4439 {
4440         modest_msg_edit_window_show_msg_settings_dialog (window);
4441 }
4442
4443 static void
4444 on_show_toolbar_button_toggled (HildonCheckButton *button,
4445                                 ModestMsgEditWindow *window)
4446 {
4447         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4448
4449         modest_msg_edit_window_show_toolbar (MODEST_WINDOW (window),
4450                                              hildon_check_button_get_active (button));
4451 }
4452
4453 static void
4454 on_cc_button_toggled (HildonCheckButton *button,
4455                       ModestMsgEditWindow *window)
4456 {
4457         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4458
4459         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4460                                         hildon_check_button_get_active (button));
4461 }
4462
4463 static void
4464 on_bcc_button_toggled (HildonCheckButton *button,
4465                       ModestMsgEditWindow *window)
4466 {
4467         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4468
4469         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4470                                         hildon_check_button_get_active (button));
4471 }
4472
4473 static void 
4474 setup_menu (ModestMsgEditWindow *self)
4475 {
4476         ModestMsgEditWindowPrivate *priv = NULL;
4477
4478         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4479
4480         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4481
4482         /* Settings menu buttons */
4483         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4484                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4485                                            NULL);
4486         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4487                                            APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4488                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4489         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4490                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4491                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4492
4493         priv->cc_button = hildon_check_button_new (0);
4494         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4495         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4496                                         FALSE);
4497         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4498                                                   NULL);
4499         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4500                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4501         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4502         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4503
4504         priv->bcc_button = hildon_check_button_new (0);
4505         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4506         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4507                                         FALSE);
4508         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4509                                                   NULL);
4510         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4511                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4512         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4513         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4514
4515         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4516                                            APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4517                                            NULL);
4518         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4519                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4520                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4521         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4522                                            APP_MENU_CALLBACK (on_message_settings),
4523                                            NULL);
4524         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4525                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4526                                            NULL);
4527         priv->show_toolbar_button = hildon_check_button_new (0);
4528         gtk_button_set_label (GTK_BUTTON (priv->show_toolbar_button), _("mcen_bd_show_toolbar"));
4529         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->show_toolbar_button),
4530                                         FALSE);
4531         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->show_toolbar_button),
4532                                                   MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_show_toolbar));
4533         g_signal_connect (G_OBJECT (priv->show_toolbar_button), "toggled",
4534                           G_CALLBACK (on_show_toolbar_button_toggled), (gpointer) self);
4535         gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4536         gtk_button_set_alignment (GTK_BUTTON (priv->show_toolbar_button), 0.5, 0.5);
4537
4538 }
4539
4540 static void
4541 emit_open_addressbook (GtkButton *button,
4542                        ModestRecptEditor *editor)
4543 {
4544         g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4545 }
4546
4547 static GtkWidget *
4548 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4549                          const gchar *label, GtkWidget *control)
4550 {
4551         GtkWidget *abook_button;
4552         GtkWidget *align;
4553         GtkWidget *box;
4554         GtkWidget *label_widget;
4555
4556         box = gtk_hbox_new (FALSE, 0);
4557
4558         align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4559         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4560
4561         abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4562         label_widget = gtk_label_new (label);
4563         gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4564         gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4565
4566         gtk_container_add (GTK_CONTAINER (align), abook_button);
4567         gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4568         gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4569         gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4570         if (title_size_group)
4571                 gtk_size_group_add_widget (title_size_group, label_widget);
4572         if (value_size_group)
4573                 gtk_size_group_add_widget (value_size_group, control);
4574
4575         g_signal_connect (G_OBJECT (abook_button), "clicked",
4576                           G_CALLBACK (emit_open_addressbook), control);
4577   
4578         return box;  
4579 }
4580
4581 static void 
4582 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4583 {
4584         ModestMsgEditWindowPrivate *priv = NULL;
4585
4586         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4587
4588         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4589         priv->max_chars_banner = NULL;
4590 }
4591
4592 static gboolean
4593 has_pending_addresses (ModestRecptEditor *recpt_editor)
4594 {
4595         const gchar *recipients = NULL;
4596         GSList *start_indexes = NULL, *end_indexes = NULL;
4597         GSList *current_start, *current_end;
4598         GtkTextBuffer *buffer;
4599         gint offset_delta = 0;
4600         gint last_length;
4601         gboolean has_recipients_to_add = FALSE;
4602
4603         recipients = modest_recpt_editor_get_recipients (recpt_editor);
4604         last_length = g_utf8_strlen (recipients, -1);
4605         modest_text_utils_get_addresses_indexes (recipients, &start_indexes, &end_indexes);
4606
4607         if (!start_indexes)
4608                 return FALSE;
4609
4610         current_start = start_indexes;
4611         current_end = end_indexes;
4612         buffer = modest_recpt_editor_get_buffer (recpt_editor);
4613
4614         while (current_start && !has_recipients_to_add) {
4615                 gchar *address;
4616                 gchar *start_ptr, *end_ptr;
4617                 gint start_pos, end_pos;
4618
4619                 start_pos = (*((gint*) current_start->data)) + offset_delta;
4620                 end_pos = (*((gint*) current_end->data)) + offset_delta;
4621
4622                 start_ptr = g_utf8_offset_to_pointer (recipients, start_pos);
4623                 end_ptr = g_utf8_offset_to_pointer (recipients, end_pos);
4624
4625                 address = g_strstrip (g_strndup (start_ptr, end_ptr - start_ptr));
4626
4627                 if (modest_text_utils_validate_recipient (address, NULL)) {
4628                         if (!modest_address_book_has_address (address)) {
4629                                 has_recipients_to_add = TRUE;
4630                         }
4631                 }
4632                 current_start = g_slist_next (current_start);
4633                 current_end = g_slist_next (current_end);
4634         }
4635         return has_recipients_to_add;
4636 }
4637
4638 gboolean
4639 modest_msg_edit_window_has_pending_addresses (ModestMsgEditWindow *self)
4640 {
4641         ModestMsgEditWindowPrivate *priv = NULL;
4642
4643         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self), FALSE);
4644
4645         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4646
4647         if (!has_pending_addresses ((ModestRecptEditor *) priv->to_field) &&
4648             !has_pending_addresses ((ModestRecptEditor *) priv->cc_field) &&
4649             !has_pending_addresses ((ModestRecptEditor *) priv->bcc_field))
4650                 return FALSE;
4651         else
4652                 return TRUE;
4653 }
4654
4655 void
4656 modest_msg_edit_window_set_custom_header_pairs (ModestMsgEditWindow *self,
4657                                                 TnyList *header_pairs)
4658 {
4659         ModestMsgEditWindowPrivate *priv = NULL;
4660
4661         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
4662         g_return_if_fail (TNY_IS_LIST (header_pairs));
4663
4664         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4665         g_object_unref (priv->custom_header_pairs);
4666         priv->custom_header_pairs = tny_list_copy (header_pairs);
4667 }