Modified webpage: now tinymail repository is in gitorious.
[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, FALSE);
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