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