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