Build fix
[modest] / src / modest-ui-actions.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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <glib/gprintf.h>
36 #include <string.h>
37 #include <modest-runtime.h>
38 #include <modest-defs.h>
39 #include <modest-tny-folder.h>
40 #include <modest-tny-msg.h>
41 #include <modest-tny-account.h>
42 #include <modest-address-book.h>
43 #include "modest-error.h"
44 #include "modest-ui-actions.h"
45 #include "modest-tny-platform-factory.h"
46 #include "modest-platform.h"
47 #include "modest-debug.h"
48 #include <tny-mime-part.h>
49 #include <tny-error.h>
50 #include <tny-camel-folder.h>
51 #include <tny-camel-imap-folder.h>
52 #include <tny-camel-pop-folder.h>
53 #include <widgets/modest-header-window.h>
54 #include <widgets/modest-folder-window.h>
55 #include <widgets/modest-accounts-window.h>
56
57 #ifdef MODEST_TOOLKIT_HILDON2
58 #include <hildon/hildon-gtk.h>
59 #include <modest-maemo-utils.h>
60 #else
61 #include <gtk/modest-shell-window.h>
62 #endif
63 #include "modest-utils.h"
64 #include "widgets/modest-connection-specific-smtp-window.h"
65 #include "widgets/modest-ui-constants.h"
66 #include <widgets/modest-msg-view-window.h>
67 #include <widgets/modest-account-view-window.h>
68 #include <widgets/modest-details-dialog.h>
69 #include <widgets/modest-attachments-view.h>
70 #include "widgets/modest-folder-view.h"
71 #include "widgets/modest-global-settings-dialog.h"
72 #include "modest-account-mgr-helpers.h"
73 #include "modest-mail-operation.h"
74 #include "modest-text-utils.h"
75 #include <modest-widget-memory.h>
76 #include <tny-error.h>
77 #include <tny-simple-list.h>
78 #include <tny-msg-view.h>
79 #include <tny-device.h>
80 #include <tny-merge-folder.h>
81 #include <widgets/modest-toolkit-utils.h>
82 #include <tny-camel-bs-msg.h>
83 #include <tny-camel-bs-mime-part.h>
84
85 #include <gtk/gtk.h>
86 #include <gtkhtml/gtkhtml.h>
87
88 #define MODEST_MOVE_TO_DIALOG_FOLDER_VIEW "move-to-dialog-folder-view"
89
90 typedef struct _GetMsgAsyncHelper {
91         ModestWindow *window;
92         ModestMailOperation *mail_op;
93         TnyIterator *iter;
94         guint num_ops;
95         GFunc func;
96         gpointer user_data;
97 } GetMsgAsyncHelper;
98
99 typedef enum _ReplyForwardAction {
100         ACTION_REPLY,
101         ACTION_REPLY_TO_ALL,
102         ACTION_FORWARD
103 } ReplyForwardAction;
104
105 typedef struct _ReplyForwardHelper {
106         guint reply_forward_type;
107         ReplyForwardAction action;
108         gchar *account_name;
109         gchar *mailbox;
110         GtkWidget *parent_window;
111         TnyHeader *header;
112         TnyHeader *top_header;
113         TnyMsg    *msg_part;
114         TnyList *parts;
115 } ReplyForwardHelper;
116
117 typedef struct _MoveToHelper {
118         GtkTreeRowReference *reference;
119         GtkWidget *banner;
120 } MoveToHelper;
121
122 typedef struct _PasteAsAttachmentHelper {
123         ModestMsgEditWindow *window;
124         GtkWidget *banner;
125 } PasteAsAttachmentHelper;
126
127 typedef struct {
128         TnyList *list;
129         ModestWindow *win;
130 } MoveToInfo;
131
132 /*
133  * The do_headers_action uses this kind of functions to perform some
134  * action to each member of a list of headers
135  */
136 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
137
138 static void     do_headers_action     (ModestWindow *win,
139                                        HeadersFunc func,
140                                        gpointer user_data);
141
142 static void     open_msg_cb            (ModestMailOperation *mail_op,
143                                         TnyHeader *header,
144                                         gboolean canceled,
145                                         TnyMsg *msg,
146                                         GError *err,
147                                         gpointer user_data);
148
149 static void     reply_forward_cb       (ModestMailOperation *mail_op,
150                                         TnyHeader *header,
151                                         gboolean canceled,
152                                         TnyMsg *msg,
153                                         GError *err,
154                                         gpointer user_data);
155
156 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
157
158 static gint header_list_count_uncached_msgs (TnyList *header_list);
159
160 static gboolean connect_to_get_msg (ModestWindow *win,
161                                     gint num_of_uncached_msgs,
162                                     TnyAccount *account);
163
164 static gboolean remote_folder_has_leave_on_server (TnyFolderStore *folder);
165
166 static void     do_create_folder (ModestWindow *window,
167                                   TnyFolderStore *parent_folder,
168                                   const gchar *suggested_name);
169
170 static TnyAccount *get_account_from_folder_store (TnyFolderStore *folder_store);
171
172 static void modest_ui_actions_on_folder_window_move_to (GtkWidget *folder_view,
173                                                         TnyFolderStore *dst_folder,
174                                                         TnyList *selection,
175                                                         ModestWindow *win);
176
177 static void modest_ui_actions_on_window_move_to (GtkAction *action,
178                                                  TnyList *list_to_move,
179                                                  TnyFolderStore *dst_folder,
180                                                  ModestWindow *win);
181
182 /*
183  * This function checks whether a TnyFolderStore is a pop account
184  */
185 static gboolean
186 remote_folder_has_leave_on_server (TnyFolderStore *folder)
187 {
188         TnyAccount *account;
189         gboolean result;
190
191         g_return_val_if_fail (TNY_IS_FOLDER_STORE (folder), FALSE);
192
193         account = get_account_from_folder_store (folder);
194         result = (modest_protocol_registry_protocol_type_has_leave_on_server (modest_runtime_get_protocol_registry (),
195                                                                               modest_tny_account_get_protocol_type (account)));
196         g_object_unref (account);
197
198         return result;
199 }
200
201 /* FIXME: this should be merged with the similar code in modest-account-view-window */
202 /* Show the account creation wizard dialog.
203  * returns: TRUE if an account was created. FALSE if the user cancelled.
204  */
205 gboolean
206 modest_ui_actions_run_account_setup_wizard (ModestWindow *win)
207 {
208         gboolean result = FALSE;
209         GtkWindow *wizard;
210         gint dialog_response;
211
212         /* there is no such wizard yet */
213         wizard = GTK_WINDOW (modest_platform_get_account_settings_wizard ());
214         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (wizard), (GtkWindow *) win);
215
216         if (!win) {
217                 GList *window_list;
218                 ModestWindowMgr *mgr;
219
220                 mgr = modest_runtime_get_window_mgr ();
221
222                 window_list = modest_window_mgr_get_window_list (mgr);
223                 if (window_list == NULL) {
224                         win = MODEST_WINDOW (modest_accounts_window_new ());
225                         if (modest_window_mgr_register_window (mgr, win, NULL)) {
226                                 gtk_widget_show_all (GTK_WIDGET (win));
227                         } else {
228                                 gtk_widget_destroy (GTK_WIDGET (win));
229                                 win = NULL;
230                         }
231
232                 } else {
233                         g_list_free (window_list);
234                 }
235         }
236
237         if (win) {
238                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
239                 gtk_window_set_transient_for (GTK_WINDOW (wizard), toplevel);
240         }
241
242         /* make sure the mainwindow is visible. We need to present the
243            wizard again to give it the focus back. show_all are needed
244            in order to get the widgets properly drawn (MainWindow main
245            paned won't be in its right position and the dialog will be
246            missplaced */
247
248         dialog_response = gtk_dialog_run (GTK_DIALOG (wizard));
249         gtk_widget_destroy (GTK_WIDGET (wizard));
250         if (gtk_events_pending ())
251                 gtk_main_iteration ();
252
253         if (dialog_response == GTK_RESPONSE_CANCEL) {
254                 result = FALSE;
255         } else {
256                 /* Check whether an account was created: */
257                 result = modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
258         }
259         return result;
260 }
261
262
263 void
264 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
265 {
266         GtkWindow *toplevel;
267         GtkWidget *about;
268         const gchar *authors[] = {
269                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
270                 NULL
271         };
272         about = gtk_about_dialog_new ();
273         gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
274         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
275         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
276                                         _("Copyright (c) 2006, Nokia Corporation\n"
277                                           "All rights reserved."));
278         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
279                                        _("a modest e-mail client\n\n"
280                                          "design and implementation: Dirk-Jan C. Binnema\n"
281                                          "contributions from the fine people at KC and Ig\n"
282                                          "uses the tinymail email framework written by Philip van Hoof"));
283         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
284         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
285
286         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
287         gtk_window_set_transient_for (GTK_WINDOW (about), toplevel);
288         gtk_window_set_modal (GTK_WINDOW (about), TRUE);
289
290         gtk_dialog_run (GTK_DIALOG (about));
291         gtk_widget_destroy(about);
292 }
293
294 /*
295  * Gets the list of currently selected messages. If the win is the
296  * main window, then it returns a newly allocated list of the headers
297  * selected in the header view. If win is the msg view window, then
298  * the value returned is a list with just a single header.
299  *
300  * The caller of this funcion must free the list.
301  */
302 static TnyList *
303 get_selected_headers (ModestWindow *win)
304 {
305         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
306                 /* for MsgViewWindows, we simply return a list with one element */
307                 TnyHeader *header;
308                 TnyList *list = NULL;
309
310                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
311                 if (header != NULL) {
312                         list = tny_simple_list_new ();
313                         tny_list_prepend (list, G_OBJECT(header));
314                         g_object_unref (G_OBJECT(header));
315                 }
316
317                 return list;
318         } else if (MODEST_IS_HEADER_WINDOW (win)) {
319                 GtkWidget *header_view;
320
321                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (win)));
322                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
323         } else {
324                 return NULL;
325         }
326 }
327
328 static void
329 headers_action_mark_as_read (TnyHeader *header,
330                              ModestWindow *win,
331                              gpointer user_data)
332 {
333         TnyHeaderFlags flags;
334         gchar *uid;
335
336         g_return_if_fail (TNY_IS_HEADER(header));
337
338         flags = tny_header_get_flags (header);
339         if (flags & TNY_HEADER_FLAG_SEEN) return;
340         tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
341         uid = modest_tny_folder_get_header_unique_id (header);
342         modest_platform_emit_msg_read_changed_signal (uid, TRUE);
343         g_free (uid);
344 }
345
346 static void
347 headers_action_mark_as_unread (TnyHeader *header,
348                                ModestWindow *win,
349                                gpointer user_data)
350 {
351         TnyHeaderFlags flags;
352
353         g_return_if_fail (TNY_IS_HEADER(header));
354
355         flags = tny_header_get_flags (header);
356         if (flags & TNY_HEADER_FLAG_SEEN)  {
357                 gchar *uid;
358                 uid = modest_tny_folder_get_header_unique_id (header);
359                 tny_header_unset_flag (header, TNY_HEADER_FLAG_SEEN);
360                 modest_platform_emit_msg_read_changed_signal (uid, FALSE);
361         }
362 }
363
364 /** After deleing a message that is currently visible in a window,
365  * show the next message from the list, or close the window if there are no more messages.
366  **/
367 void
368 modest_ui_actions_refresh_message_window_after_delete (ModestMsgViewWindow* win)
369 {
370         /* Close msg view window or select next */
371         if (!modest_msg_view_window_select_next_message (win) &&
372             !modest_msg_view_window_select_previous_message (win)) {
373                 gboolean ret_value;
374                 g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
375         }
376 }
377
378
379 void
380 modest_ui_actions_on_delete_message (GtkAction *action, ModestWindow *win)
381 {
382         modest_ui_actions_on_edit_mode_delete_message (win);
383 }
384
385 gboolean
386 modest_ui_actions_on_edit_mode_delete_message (ModestWindow *win)
387 {
388         TnyList *header_list = NULL;
389         TnyIterator *iter = NULL;
390         TnyHeader *header = NULL;
391         gchar *message = NULL;
392         gchar *desc = NULL;
393         gint response;
394         ModestWindowMgr *mgr;
395         gboolean retval = TRUE;
396
397         g_return_val_if_fail (MODEST_IS_WINDOW(win), FALSE);
398
399         /* Get the headers, either from the header view (if win is the main window),
400          * or from the message view window: */
401         header_list = get_selected_headers (win);
402         if (!header_list) return FALSE;
403
404         /* Check if any of the headers are already opened, or in the process of being opened */
405
406         /* Select message */
407         if (tny_list_get_length(header_list) == 1) {
408                 iter = tny_list_create_iterator (header_list);
409                 header = TNY_HEADER (tny_iterator_get_current (iter));
410                 if (header) {
411                         gchar *subject;
412                         subject = tny_header_dup_subject (header);
413                         if (!subject)
414                                 subject = g_strdup (_("mail_va_no_subject"));
415                         desc = g_strdup_printf ("%s", subject);
416                         g_free (subject);
417                         g_object_unref (header);
418                 }
419
420                 g_object_unref (iter);
421         }
422         message = g_strdup_printf(ngettext("emev_nc_delete_message", "emev_nc_delete_messages",
423                                            tny_list_get_length(header_list)), desc);
424
425         /* Confirmation dialog */
426         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (win))),
427                                                             message);
428
429         if (response == GTK_RESPONSE_OK) {
430                 GtkTreeSelection *sel = NULL;
431                 GList *sel_list = NULL;
432                 ModestMailOperation *mail_op = NULL;
433
434                 /* Find last selected row */
435
436                 /* Disable window dimming management */
437                 modest_window_disable_dimming (win);
438
439                 /* Remove each header. If it's a view window header_view == NULL */
440                 mail_op = modest_mail_operation_new ((GObject *) win);
441                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
442                                                  mail_op);
443                 modest_mail_operation_remove_msgs (mail_op, header_list, FALSE);
444                 g_object_unref (mail_op);
445
446                 /* Enable window dimming management */
447                 if (sel != NULL) {
448                         gtk_tree_selection_unselect_all (sel);
449                 }
450                 modest_window_enable_dimming (win);
451
452                 if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
453                         modest_ui_actions_refresh_message_window_after_delete (MODEST_MSG_VIEW_WINDOW (win));
454
455                         /* Get main window */
456                         mgr = modest_runtime_get_window_mgr ();
457                 }
458
459                 /* Update toolbar dimming state */
460                 modest_ui_actions_check_menu_dimming_rules (win);
461                 modest_ui_actions_check_toolbar_dimming_rules (win);
462
463                 /* Free */
464                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
465                 g_list_free (sel_list);
466                 retval = TRUE;
467         } else {
468                 retval = FALSE;
469         }
470
471         /* Free*/
472         g_free(message);
473         g_free(desc);
474         g_object_unref (header_list);
475
476         return retval;
477 }
478
479
480
481
482 /* delete either message or folder, based on where we are */
483 void
484 modest_ui_actions_on_delete_message_or_folder (GtkAction *action, ModestWindow *win)
485 {
486         g_return_if_fail (MODEST_IS_WINDOW(win));
487
488         /* Check first if the header view has the focus */
489         modest_ui_actions_on_delete_message (action, win);
490 }
491
492 void
493 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
494 {
495         ModestWindowMgr *mgr = NULL;
496
497 #ifdef MODEST_PLATFORM_MAEMO
498         modest_window_mgr_save_state_for_all_windows (modest_runtime_get_window_mgr ());
499 #endif /* MODEST_PLATFORM_MAEMO */
500
501         g_debug ("closing down, clearing %d item(s) from operation queue",
502                  modest_mail_operation_queue_num_elements
503                  (modest_runtime_get_mail_operation_queue()));
504
505         /* cancel all outstanding operations */
506         modest_mail_operation_queue_cancel_all
507                 (modest_runtime_get_mail_operation_queue());
508
509         g_debug ("queue has been cleared");
510
511
512         /* Check if there are opened editing windows */
513         mgr = modest_runtime_get_window_mgr ();
514         modest_window_mgr_close_all_windows (mgr);
515
516         /* note: when modest-tny-account-store is finalized,
517            it will automatically set all network connections
518            to offline */
519
520 /*      gtk_main_quit (); */
521 }
522
523 void
524 modest_ui_actions_on_close_window (GtkAction *action, ModestWindow *win)
525 {
526         gboolean ret_value;
527
528         g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
529
530 /*      if (MODEST_IS_MSG_VIEW_WINDOW (win)) { */
531 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
532 /*      } else if (MODEST_IS_MSG_EDIT_WINDOW (win)) { */
533 /*              gboolean ret_value; */
534 /*              g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value); */
535 /*      } else if (MODEST_IS_WINDOW (win)) { */
536 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
537 /*      } else { */
538 /*              g_return_if_reached (); */
539 /*      } */
540 }
541
542 void
543 modest_ui_actions_add_to_contacts (GtkAction *action, ModestWindow *win)
544 {
545         if (MODEST_IS_MSG_VIEW_WINDOW (win))
546                 modest_msg_view_window_add_to_contacts (MODEST_MSG_VIEW_WINDOW (win));
547         else if (MODEST_IS_MSG_EDIT_WINDOW (win))
548                 modest_msg_edit_window_add_to_contacts (MODEST_MSG_EDIT_WINDOW (win));
549 }
550
551 void
552 modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
553 {
554         GtkClipboard *clipboard = NULL;
555         gchar *selection = NULL;
556
557         clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
558         selection = gtk_clipboard_wait_for_text (clipboard);
559
560         if (selection) {
561                 modest_address_book_add_address (selection, (GtkWindow *) win);
562                 g_free (selection);
563         }
564 }
565
566 void
567 modest_ui_actions_on_new_account (GtkAction *action,
568                                   ModestWindow *window)
569 {
570         if (!modest_ui_actions_run_account_setup_wizard (window)) {
571                 g_debug ("%s: wizard was already running", __FUNCTION__);
572         }
573 }
574
575 void
576 modest_ui_actions_on_accounts (GtkAction *action,
577                                ModestWindow *win)
578 {
579         /* This is currently only implemented for Maemo */
580         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE)) {
581                 if (!modest_ui_actions_run_account_setup_wizard (win))
582                         g_debug ("%s: wizard was already running", __FUNCTION__);
583
584                 return;
585         } else {
586                 /* Show the list of accounts */
587                 GtkWindow *win_toplevel, *acc_toplevel;
588                 GtkWidget *account_win;
589
590                 account_win = modest_account_view_window_new ();
591                 acc_toplevel = (GtkWindow *) gtk_widget_get_toplevel (account_win);
592
593                 /* The accounts dialog must be modal */
594                 win_toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
595                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), acc_toplevel, win_toplevel);
596                 modest_utils_show_dialog_and_forget (win_toplevel, GTK_DIALOG (account_win));
597         }
598 }
599
600 void
601 modest_ui_actions_on_smtp_servers (GtkAction *action, ModestWindow *win)
602 {
603         /* Create the window if necessary: */
604         GtkWidget *specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
605         modest_connection_specific_smtp_window_fill_with_connections (
606                 MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window),
607                 modest_runtime_get_account_mgr());
608
609         /* Show the window: */
610         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
611                                      GTK_WINDOW (specific_window), (GtkWindow *) win);
612         gtk_widget_show (specific_window);
613 }
614
615 static guint64
616 count_part_size (const gchar *part)
617 {
618         GnomeVFSURI *vfs_uri;
619         gchar *escaped_filename;
620         gchar *filename;
621         GnomeVFSFileInfo *info;
622         guint64 result;
623
624         /* Estimation of attachment size if we cannot get it from file info */
625         result = 32768;
626
627         vfs_uri = gnome_vfs_uri_new (part);
628
629         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
630         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
631         g_free (escaped_filename);
632         gnome_vfs_uri_unref (vfs_uri);
633
634         info = gnome_vfs_file_info_new ();
635         
636         if (gnome_vfs_get_file_info (part, 
637                                      info, 
638                                      GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
639             == GNOME_VFS_OK) {
640                 if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
641                         result = info->size;
642                 }
643         }
644         g_free (filename);
645         gnome_vfs_file_info_unref (info);
646
647         return result;
648 }
649
650 static guint64 
651 count_parts_size (GSList *parts)
652 {
653         GSList *node;
654         guint64 result = 0;
655
656         for (node = parts; node != NULL; node = g_slist_next (node)) {
657                 result += count_part_size ((const gchar *) node->data);
658         }
659
660         return result;
661 }
662
663 void
664 modest_ui_actions_compose_msg(ModestWindow *win,
665                               const gchar *to_str,
666                               const gchar *cc_str,
667                               const gchar *bcc_str,
668                               const gchar *subject_str,
669                               const gchar *body_str,
670                               GSList *attachments,
671                               gboolean set_as_modified)
672 {
673         gchar *account_name = NULL;
674         const gchar *mailbox;
675         TnyMsg *msg = NULL;
676         TnyAccount *account = NULL;
677         TnyFolder *folder = NULL;
678         gchar *from_str = NULL, *signature = NULL, *body = NULL, *recipient = NULL, *tmp = NULL;
679         gboolean use_signature = FALSE;
680         ModestWindow *msg_win = NULL;
681         ModestAccountMgr *mgr = modest_runtime_get_account_mgr();
682         ModestTnyAccountStore *store = modest_runtime_get_account_store();
683         GnomeVFSFileSize total_size, allowed_size;
684         guint64 available_disk, expected_size, parts_size;
685         guint parts_count;
686         TnyList *header_pairs;
687
688         /* we check for low-mem */
689         if (modest_platform_check_memory_low (win, TRUE))
690                 goto cleanup;
691
692         available_disk = modest_utils_get_available_space (NULL);
693         parts_count = g_slist_length (attachments);
694         parts_size = count_parts_size (attachments);
695         expected_size = modest_tny_msg_estimate_size (body, NULL, parts_count, parts_size);
696
697         /* Double check: disk full condition or message too big */
698         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
699             expected_size > available_disk) {
700                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
701                 modest_platform_system_banner (NULL, NULL, msg);
702                 g_free (msg);
703
704                 return;
705         }
706
707         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
708                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
709                 modest_platform_run_information_dialog (toplevel,
710                                                         _("mail_ib_error_attachment_size"),
711                                                         TRUE);
712                 return;
713         }
714
715
716         if (win)
717                 account_name = g_strdup (modest_window_get_active_account(win));
718         if (!account_name) {
719                 account_name = modest_account_mgr_get_default_account(mgr);
720         }
721         if (!account_name) {
722                 g_printerr ("modest: no account found\n");
723                 goto cleanup;
724         }
725
726         if (win)
727                 mailbox = modest_window_get_active_mailbox (win);
728         else
729                 mailbox = NULL;
730         account = modest_tny_account_store_get_server_account (store, account_name, TNY_ACCOUNT_TYPE_STORE);
731         if (!account) {
732                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
733                 goto cleanup;
734         }
735         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
736         if (!folder) {
737                 g_printerr ("modest: failed to find Drafts folder\n");
738                 goto cleanup;
739         }
740         from_str = modest_account_mgr_get_from_string (mgr, account_name, mailbox);
741         if (!from_str) {
742                 g_printerr ("modest: failed get from string for '%s'\n", account_name);
743                 goto cleanup;
744         }
745
746
747         recipient = modest_text_utils_get_email_address (from_str);
748         tmp = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr (),
749                                                                recipient,
750                                                                &use_signature);
751         signature = modest_text_utils_create_colored_signature (tmp);
752         g_free (tmp);
753         g_free (recipient);
754
755         body = use_signature ? g_strconcat ((body_str) ? body_str : "", signature, NULL) :
756                 g_strdup(body_str);
757
758         header_pairs = TNY_LIST (tny_simple_list_new ());
759         msg = modest_tny_msg_new_html_plain (to_str, from_str, cc_str, bcc_str, subject_str,
760                                              NULL, NULL, body, NULL, NULL, NULL, NULL, header_pairs, NULL);
761         g_object_unref (header_pairs);
762
763         if (!msg) {
764                 g_printerr ("modest: failed to create new msg\n");
765                 goto cleanup;
766         }
767
768         /* Create and register edit window */
769         /* This is destroyed by TODO. */
770         total_size = 0;
771         allowed_size = MODEST_MAX_ATTACHMENT_SIZE;
772         msg_win = modest_msg_edit_window_new (msg, account_name, mailbox, FALSE);
773
774         if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr(), msg_win, win)) {
775                 gtk_widget_destroy (GTK_WIDGET (msg_win));
776                 goto cleanup;
777         }
778         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (msg_win), set_as_modified);
779         gtk_widget_show_all (GTK_WIDGET (msg_win));
780
781         while (attachments) {
782                 GnomeVFSFileSize att_size;
783                 att_size =
784                         modest_msg_edit_window_attach_file_one((ModestMsgEditWindow *)msg_win,
785                                                                attachments->data, allowed_size);
786                 total_size += att_size;
787
788                 if (att_size > allowed_size) {
789                         g_debug ("%s: total size: %u",
790                                  __FUNCTION__, (unsigned int)total_size);
791                         break;
792                 }
793                 allowed_size -= att_size;
794
795                 attachments = g_slist_next(attachments);
796         }
797
798 cleanup:
799         g_free (from_str);
800         g_free (signature);
801         g_free (body);
802         g_free (account_name);
803         if (account)
804                 g_object_unref (G_OBJECT(account));
805         if (folder)
806                 g_object_unref (G_OBJECT(folder));
807         if (msg)
808                 g_object_unref (G_OBJECT(msg));
809 }
810
811 void
812 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
813 {
814         /* if there are no accounts yet, just show the wizard */
815         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE))
816                 if (!modest_ui_actions_run_account_setup_wizard (win))
817                         return;
818
819         modest_ui_actions_compose_msg(win, NULL, NULL, NULL, NULL, NULL, NULL, FALSE);
820 }
821
822
823 gboolean
824 modest_ui_actions_msg_retrieval_check (ModestMailOperation *mail_op,
825                                        TnyHeader *header,
826                                        TnyMsg *msg)
827 {
828         ModestMailOperationStatus status;
829
830         /* If there is no message or the operation was not successful */
831         status = modest_mail_operation_get_status (mail_op);
832         if (!msg || status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
833                 const GError *error;
834
835                 /* If it's a memory low issue, then show a banner */
836                 error = modest_mail_operation_get_error (mail_op);
837                 if (error && error->domain == MODEST_MAIL_OPERATION_ERROR &&
838                     error->code == MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY) {
839                         GtkWindow *toplevel = NULL;
840                         GObject *source = modest_mail_operation_get_source (mail_op);
841
842                         toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (source));
843                         modest_platform_run_information_dialog (toplevel,
844                                                                 _KR("memr_ib_operation_disabled"),
845                                                                 TRUE);
846                         g_object_unref (source);
847                 }
848
849                 if (error && ((error->code == TNY_SERVICE_ERROR_NO_SUCH_MESSAGE) ||
850                               error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE)) {
851                         gchar *subject, *msg, *format = NULL;
852                         TnyAccount *account;
853
854                         subject = (header) ? tny_header_dup_subject (header) : NULL;
855                         if (!subject)
856                                 subject = g_strdup (_("mail_va_no_subject"));
857
858                         account = modest_mail_operation_get_account (mail_op);
859                         if (account) {
860                                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
861                                 ModestProtocol *protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (), proto);
862
863                                 if (protocol) {
864                                         if (tny_account_get_connection_status (account) ==
865                                             TNY_CONNECTION_STATUS_CONNECTED) {
866                                                 if (header) {
867                                                         format = modest_protocol_get_translation (protocol,
868                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE,
869                                                                                                   subject);
870                                                 } else {
871                                                         format = modest_protocol_get_translation (protocol,
872                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE_LOST_HEADER);
873                                                 }
874                                         } else {
875                                                 format = g_strdup_printf (_("mail_ib_backend_server_invalid"),
876                                                                           tny_account_get_hostname (account));
877                                         }
878                                 }
879                                 g_object_unref (account);
880                         }
881
882                         if (!format) {
883                                 if (header) {
884                                         format = g_strdup (_("emev_ni_ui_imap_message_not_available_in_server"));
885                                 } else {
886                                         format = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
887                                 }
888                         }
889
890                         msg = g_strdup_printf (format, subject);
891                         modest_platform_run_information_dialog (NULL, msg, FALSE);
892                         g_free (msg);
893                         g_free (format);
894                         g_free (subject);
895                 }
896
897                 /* Remove the header from the preregistered uids */
898                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
899                                                      header);
900
901                 return FALSE;
902         }
903
904         return TRUE;
905 }
906
907 typedef struct {
908         guint idle_handler;
909         gchar *message;
910         GtkWidget *banner;
911 } OpenMsgBannerInfo;
912
913 typedef struct {
914         GtkTreeModel *model;
915         TnyHeader *header;
916         ModestWindow *caller_window;
917         OpenMsgBannerInfo *banner_info;
918         GtkTreeRowReference *rowref;
919 } OpenMsgHelper;
920
921 gboolean
922 open_msg_banner_idle (gpointer userdata)
923 {
924         OpenMsgBannerInfo *banner_info = (OpenMsgBannerInfo *) userdata;
925
926         gdk_threads_enter ();
927         banner_info->idle_handler = 0;
928         banner_info->banner = modest_platform_animation_banner (NULL, NULL, banner_info->message);
929         if (banner_info->banner)
930                 g_object_ref (banner_info->banner);
931
932         gdk_threads_leave ();
933
934         return FALSE;
935 }
936
937 static GtkWidget *
938 get_header_view_from_window (ModestWindow *window)
939 {
940         GtkWidget *header_view;
941
942         if (MODEST_IS_HEADER_WINDOW (window)){
943                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
944         } else {
945                 header_view = NULL;
946         }
947
948         return header_view;
949 }
950
951 static gchar *
952 get_info_from_header (TnyHeader *header, gboolean *is_draft, gboolean *can_open)
953 {
954         TnyFolder *folder;
955         gchar *account = NULL;
956         TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
957
958         *is_draft = FALSE;
959         *can_open = TRUE;
960
961         folder = tny_header_get_folder (header);
962         /* Gets folder type (OUTBOX headers will be opened in edit window */
963         if (modest_tny_folder_is_local_folder (folder)) {
964                 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
965                 if (folder_type == TNY_FOLDER_TYPE_INVALID)
966                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
967         }
968
969         if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
970                 TnyTransportAccount *traccount = NULL;
971                 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
972                 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
973                 if (traccount) {
974                         ModestTnySendQueue *send_queue = NULL;
975                         ModestTnySendQueueStatus status;
976                         gchar *msg_id;
977                         account = g_strdup(modest_tny_account_get_parent_modest_account_name_for_server_account(
978                                                    TNY_ACCOUNT(traccount)));
979                         send_queue = modest_runtime_get_send_queue(traccount, TRUE);
980                         if (TNY_IS_SEND_QUEUE (send_queue)) {
981                                 msg_id = modest_tny_send_queue_get_msg_id (header);
982                                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
983                                 g_free (msg_id);
984                                 /* Only open messages in outbox with the editor if they are in Failed state */
985                                 if (status == MODEST_TNY_SEND_QUEUE_FAILED) {
986                                         *is_draft = TRUE;
987                                 }
988                                 else {
989                                         /* In Fremantle we can not
990                                            open any message from
991                                            outbox which is not in
992                                            failed state */
993                                         *can_open = FALSE;
994                                 }
995                         }
996                         g_object_unref(traccount);
997                 } else {
998                         g_warning("Cannot get transport account for message in outbox!!");
999                 }
1000         } else if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
1001                 *is_draft = TRUE; /* Open in editor if the message is in the Drafts folder */
1002         }
1003
1004         if (!account) {
1005                 TnyAccount *acc = tny_folder_get_account (folder);
1006                 if (acc) {
1007                         account =
1008                                 g_strdup (modest_tny_account_get_parent_modest_account_name_for_server_account (acc));
1009                         g_object_unref (acc);
1010                 }
1011         }
1012
1013         g_object_unref (folder);
1014
1015         return account;
1016 }
1017
1018 static void
1019 open_msg_cb (ModestMailOperation *mail_op,
1020              TnyHeader *header,
1021              gboolean canceled,
1022              TnyMsg *msg,
1023              GError *err,
1024              gpointer user_data)
1025 {
1026         ModestWindowMgr *mgr = NULL;
1027         ModestWindow *parent_win = NULL;
1028         ModestWindow *win = NULL;
1029         gchar *account = NULL;
1030         gboolean open_in_editor = FALSE;
1031         gboolean can_open;
1032         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1033
1034         /* Do nothing if there was any problem with the mail
1035            operation. The error will be shown by the error_handler of
1036            the mail operation */
1037         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1038                 return;
1039
1040         parent_win = (ModestWindow *) modest_mail_operation_get_source (mail_op);
1041
1042         /* Mark header as read */
1043         headers_action_mark_as_read (header, MODEST_WINDOW(parent_win), NULL);
1044
1045         account = get_info_from_header (header, &open_in_editor, &can_open);
1046
1047         /* Get account */
1048         if (!account)
1049                 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_win)));
1050         if (!account)
1051                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1052
1053         if (open_in_editor) {
1054                 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
1055                 gchar *from_header = NULL, *acc_name;
1056                 gchar *mailbox = NULL;
1057
1058                 from_header = tny_header_dup_from (header);
1059
1060                 /* we cannot edit without a valid account... */
1061                 if (!modest_account_mgr_has_accounts(mgr, TRUE)) {
1062                         if (!modest_ui_actions_run_account_setup_wizard(parent_win)) {
1063                                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1064                                                                      header);
1065                                 g_free (from_header);
1066                                 goto cleanup;
1067                         }
1068                 }
1069
1070                 acc_name = modest_utils_get_account_name_from_recipient (from_header, &mailbox);
1071                 g_free (from_header);
1072                 if (acc_name) {
1073                         g_free (account);
1074                         account = acc_name;
1075                 }
1076
1077                 win = modest_msg_edit_window_new (msg, account, mailbox, TRUE);
1078                 if (mailbox)
1079                         g_free (mailbox);
1080         } else {
1081                 gchar *uid = modest_tny_folder_get_header_unique_id (header);
1082                 const gchar *mailbox = NULL;
1083
1084                 if (parent_win && MODEST_IS_WINDOW (parent_win))
1085                         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (parent_win));
1086
1087                 if (helper->rowref && helper->model) {
1088                         win = modest_msg_view_window_new_with_header_model (msg, account, mailbox, (const gchar*) uid,
1089                                                                             helper->model, helper->rowref);
1090                 } else {
1091                         win = modest_msg_view_window_new_for_attachment (msg, NULL, account, mailbox, (const gchar*) uid);
1092                 }
1093                 g_free (uid);
1094         }
1095
1096         /* Register and show new window */
1097         if (win != NULL) {
1098                 mgr = modest_runtime_get_window_mgr ();
1099                 if (!modest_window_mgr_register_window (mgr, win, NULL)) {
1100                         gtk_widget_destroy (GTK_WIDGET (win));
1101                         goto cleanup;
1102                 }
1103                 gtk_widget_show_all (GTK_WIDGET(win));
1104         }
1105
1106
1107 cleanup:
1108         /* Free */
1109         g_free(account);
1110         g_object_unref (parent_win);
1111 }
1112
1113 void
1114 modest_ui_actions_disk_operations_error_handler (ModestMailOperation *mail_op,
1115                                                  gpointer user_data)
1116 {
1117         const GError *error;
1118         GObject *win = NULL;
1119         ModestMailOperationStatus status;
1120
1121         win = modest_mail_operation_get_source (mail_op);
1122         error = modest_mail_operation_get_error (mail_op);
1123         status = modest_mail_operation_get_status (mail_op);
1124
1125         /* If the mail op has been cancelled then it's not an error:
1126            don't show any message */
1127         if (status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1128                 TnyAccount *account = modest_mail_operation_get_account (mail_op);
1129                 if (modest_tny_account_store_is_disk_full_error (modest_runtime_get_account_store(),
1130                                                                  (GError *) error, account)) {
1131                         gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
1132                         modest_platform_information_banner ((GtkWidget *) win, NULL, msg);
1133                         g_free (msg);
1134                 } else if (error->code == TNY_SYSTEM_ERROR_MEMORY) {
1135                         modest_platform_information_banner ((GtkWidget *) win,
1136                                                             NULL, _("emev_ui_imap_inbox_select_error"));
1137                 } else if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
1138                            error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1139                         modest_platform_information_banner ((GtkWidget *) win,
1140                                                             NULL, _CS_UNABLE_TO_OPEN_FILE_NOT_FOUND);
1141                 } else if (user_data) {
1142                         modest_platform_information_banner ((GtkWidget *) win,
1143                                                             NULL, user_data);
1144                 }
1145                 if (account)
1146                         g_object_unref (account);
1147         }
1148
1149         if (win)
1150                 g_object_unref (win);
1151 }
1152
1153 /**
1154  * Returns the account a list of headers belongs to. It returns a
1155  * *new* reference so don't forget to unref it
1156  */
1157 static TnyAccount*
1158 get_account_from_header_list (TnyList *headers)
1159 {
1160         TnyAccount *account = NULL;
1161
1162         if (tny_list_get_length (headers) > 0) {
1163                 TnyIterator *iter = tny_list_create_iterator (headers);
1164                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1165                 TnyFolder *folder = tny_header_get_folder (header);
1166
1167                 if (!folder) {
1168                         g_object_unref (header);
1169
1170                         while (!tny_iterator_is_done (iter)) {
1171                                 header = TNY_HEADER (tny_iterator_get_current (iter));
1172                                 folder = tny_header_get_folder (header);
1173                                 if (folder)
1174                                         break;
1175                                 g_object_unref (header);
1176                                 header = NULL;
1177                                 tny_iterator_next (iter);
1178                         }
1179                 }
1180
1181                 if (folder) {
1182                         account = tny_folder_get_account (folder);
1183                         g_object_unref (folder);
1184                 }
1185
1186                 if (header)
1187                         g_object_unref (header);
1188
1189                 g_object_unref (iter);
1190         }
1191         return account;
1192 }
1193
1194 static TnyAccount*
1195 get_account_from_header (TnyHeader *header)
1196 {
1197         TnyAccount *account = NULL;
1198         TnyFolder *folder;
1199
1200         folder = tny_header_get_folder (header);
1201
1202         if (folder) {
1203                 account = tny_folder_get_account (folder);
1204                 g_object_unref (folder);
1205         }
1206         return account;
1207 }
1208
1209 static void
1210 caller_win_destroyed (OpenMsgHelper *helper, GObject *object)
1211 {
1212         if (helper->caller_window)
1213                 helper->caller_window = NULL;
1214 }
1215
1216 static void
1217 open_msg_helper_destroyer (gpointer user_data)
1218 {
1219         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1220
1221         if (helper->caller_window) {
1222                 g_object_weak_unref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1223                 helper->caller_window = NULL;
1224         }
1225
1226         if (helper->banner_info) {
1227                 g_free (helper->banner_info->message);
1228                 if (helper->banner_info->idle_handler > 0) {
1229                         g_source_remove (helper->banner_info->idle_handler);
1230                         helper->banner_info->idle_handler = 0;
1231                 }
1232                 if (helper->banner_info->banner != NULL) {
1233                         gtk_widget_destroy (helper->banner_info->banner);
1234                         g_object_unref (helper->banner_info->banner);
1235                         helper->banner_info->banner = NULL;
1236                 }
1237                 g_slice_free (OpenMsgBannerInfo, helper->banner_info);
1238                 helper->banner_info = NULL;
1239         }
1240         g_object_unref (helper->model);
1241         g_object_unref (helper->header);
1242         gtk_tree_row_reference_free (helper->rowref);
1243         g_slice_free (OpenMsgHelper, helper);
1244 }
1245
1246 static void
1247 open_msg_performer(gboolean canceled,
1248                     GError *err,
1249                     ModestWindow *parent_window,
1250                     TnyAccount *account,
1251                     gpointer user_data)
1252 {
1253         ModestMailOperation *mail_op = NULL;
1254         gchar *error_msg = NULL;
1255         ModestProtocolType proto;
1256         TnyConnectionStatus status;
1257         OpenMsgHelper *helper = NULL;
1258         ModestProtocol *protocol;
1259         ModestProtocolRegistry *protocol_registry;
1260         gchar *subject;
1261
1262         helper = (OpenMsgHelper *) user_data;
1263
1264         status = tny_account_get_connection_status (account);
1265         if (err || canceled || helper->caller_window == NULL) {
1266                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1267                 /* Free the helper */
1268                 open_msg_helper_destroyer (helper);
1269
1270                 /* In disk full conditions we could get this error here */
1271                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
1272                                                                 (GtkWidget *) parent_window, err,
1273                                                                 account, NULL);
1274
1275                 goto clean;
1276         }
1277
1278         /* Get the error message depending on the protocol */
1279         proto = modest_tny_account_get_protocol_type (account);
1280         if (proto == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1281                 proto = MODEST_PROTOCOLS_STORE_MAILDIR;
1282         }
1283
1284         protocol_registry = modest_runtime_get_protocol_registry ();
1285         subject = tny_header_dup_subject (helper->header);
1286
1287         protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, proto);
1288         error_msg = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE, subject);
1289         if (subject)
1290                 g_free (subject);
1291
1292         if (error_msg == NULL) {
1293                 error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1294         }
1295
1296         gboolean is_draft;
1297         gboolean can_open;
1298         gchar *account_name = get_info_from_header (helper->header, &is_draft, &can_open);
1299
1300         if (!g_strcmp0 (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) ||
1301             !g_strcmp0 (account_name, MODEST_MMC_ACCOUNT_ID)) {
1302                 g_free (account_name);
1303                 account_name = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_window)));
1304         }
1305
1306         if (!can_open) {
1307                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1308                 g_free (account_name);
1309                 open_msg_helper_destroyer (helper);
1310                 goto clean;
1311         }
1312
1313         if (!is_draft) {
1314                 ModestWindow *window;
1315                 GtkWidget *header_view;
1316                 gchar *uid;
1317
1318                 header_view = get_header_view_from_window (parent_window);
1319                 uid = modest_tny_folder_get_header_unique_id (helper->header);
1320                 if (header_view) {
1321                         const gchar *mailbox = NULL;
1322                         mailbox = modest_window_get_active_mailbox (parent_window);
1323                         window = modest_msg_view_window_new_from_header_view 
1324                                 (MODEST_HEADER_VIEW (header_view), account_name, mailbox, uid, helper->rowref);
1325                         if (window != NULL) {
1326                                 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
1327                                                                         window, NULL)) {
1328                                         gtk_widget_destroy (GTK_WIDGET (window));
1329                                 } else {
1330                                         gtk_widget_show_all (GTK_WIDGET(window));
1331                                 }
1332                         }
1333                 }
1334                 g_free (account_name);
1335                 g_free (uid);
1336                 open_msg_helper_destroyer (helper);
1337                 goto clean;
1338         }
1339         g_free (account_name);
1340         /* Create the mail operation */
1341         mail_op =
1342                 modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
1343                                                                modest_ui_actions_disk_operations_error_handler,
1344                                                                g_strdup (error_msg), g_free);
1345         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1346                                          mail_op);
1347
1348
1349
1350         TnyList *headers;
1351         headers = TNY_LIST (tny_simple_list_new ());
1352         tny_list_prepend (headers, G_OBJECT (helper->header));
1353         modest_mail_operation_get_msgs_full (mail_op,
1354                                              headers,
1355                                              open_msg_cb,
1356                                              helper,
1357                                              open_msg_helper_destroyer);
1358         g_object_unref (headers);
1359
1360         /* Frees */
1361  clean:
1362         if (error_msg)
1363                 g_free (error_msg);
1364         if (mail_op)
1365                 g_object_unref (mail_op);
1366         g_object_unref (account);
1367 }
1368
1369 /*
1370  * This function is used by both modest_ui_actions_on_open and
1371  * modest_ui_actions_on_header_activated. This way we always do the
1372  * same when trying to open messages.
1373  */
1374 static void
1375 open_msg_from_header (TnyHeader *header, GtkTreeRowReference *rowref, ModestWindow *win)
1376 {
1377         ModestWindowMgr *mgr = NULL;
1378         TnyAccount *account;
1379         gboolean cached = FALSE;
1380         gboolean found;
1381         GtkWidget *header_view = NULL;
1382         OpenMsgHelper *helper;
1383         ModestWindow *window;
1384
1385         g_return_if_fail (header != NULL && rowref != NULL && gtk_tree_row_reference_valid (rowref));
1386
1387         mgr = modest_runtime_get_window_mgr ();
1388
1389         /* get model */
1390         header_view = get_header_view_from_window (MODEST_WINDOW (win));
1391         if (header_view == NULL)
1392                 return;
1393
1394         /* Get the account */
1395         account = get_account_from_header (header);
1396         if (!account)
1397                 return;
1398
1399         window = NULL;
1400         found = modest_window_mgr_find_registered_header (mgr, header, &window);
1401
1402         /* Do not open again the message and present the
1403            window to the user */
1404         if (found) {
1405                 if (window) {
1406 #ifndef MODEST_TOOLKIT_HILDON2
1407                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
1408                         gtk_window_present (toplevel);
1409 #endif
1410                 } else {
1411                         /* the header has been registered already, we don't do
1412                          * anything but wait for the window to come up*/
1413                         g_debug ("header %p already registered, waiting for window", header);
1414                 }
1415                 goto cleanup;
1416         }
1417
1418         /* Open each message */
1419         cached = tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED;
1420         if (!cached) {
1421                 /* Allways download if we are online. */
1422                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1423                         gint response;
1424                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1425
1426                         /* If ask for user permission to download the messages */
1427                         response = modest_platform_run_confirmation_dialog (toplevel,
1428                                                                             _("mcen_nc_get_msg"));
1429
1430                         /* End if the user does not want to continue */
1431                         if (response == GTK_RESPONSE_CANCEL) {
1432                                 goto cleanup;
1433                         }
1434                 }
1435         }
1436
1437         /* We register the window for opening */
1438         modest_window_mgr_register_header (mgr, header, NULL);
1439
1440         /* Create the helper. We need to get a reference to the model
1441            here because it could change while the message is readed
1442            (the user could switch between folders) */
1443         helper = g_slice_new (OpenMsgHelper);
1444         helper->model = g_object_ref (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)));
1445         helper->caller_window = win;
1446         g_object_weak_ref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1447         helper->header = g_object_ref (header);
1448         helper->rowref = gtk_tree_row_reference_copy (rowref);
1449         helper->banner_info = NULL;
1450
1451         /* Connect to the account and perform */
1452         if (!cached) {
1453                 modest_platform_connect_and_perform (win, TRUE, g_object_ref (account),
1454                                                      open_msg_performer, helper);
1455         } else {
1456                 /* Call directly the performer, do not need to connect */
1457                 open_msg_performer (FALSE, NULL, win,
1458                                     g_object_ref (account), helper);
1459         }
1460 cleanup:
1461         /* Clean */
1462         if (account)
1463                 g_object_unref (account);
1464 }
1465
1466 void
1467 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
1468 {
1469         TnyList *headers;
1470         TnyHeader *header;
1471         gint headers_count;
1472         TnyIterator *iter;
1473
1474         /* we check for low-mem; in that case, show a warning, and don't allow
1475          * opening
1476          */
1477         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1478                 return;
1479
1480         /* Get headers */
1481         headers = get_selected_headers (win);
1482         if (!headers)
1483                 return;
1484
1485         headers_count = tny_list_get_length (headers);
1486         if (headers_count != 1) {
1487                 if (headers_count > 1) {
1488                         /* Don't allow activation if there are more than one message selected */
1489                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
1490                 }
1491
1492                 g_object_unref (headers);
1493                 return;
1494         }
1495
1496         iter = tny_list_create_iterator (headers);
1497         header = TNY_HEADER (tny_iterator_get_current (iter));
1498         g_object_unref (iter);
1499
1500         /* Open them */
1501         if (header) {
1502                 open_msg_from_header (header, NULL, win);
1503                 g_object_unref (header);
1504         }
1505
1506         g_object_unref(headers);
1507 }
1508
1509 static void
1510 rf_helper_window_closed (gpointer data,
1511                          GObject *object)
1512 {
1513         ReplyForwardHelper *helper = (ReplyForwardHelper *) data;
1514
1515         helper->parent_window = NULL;
1516 }
1517
1518 static ReplyForwardHelper*
1519 create_reply_forward_helper (ReplyForwardAction action,
1520                              ModestWindow *win,
1521                              guint reply_forward_type,
1522                              TnyHeader *header,
1523                              TnyMsg *msg_part,
1524                              TnyHeader *top_header,
1525                              TnyList *parts)
1526 {
1527         ReplyForwardHelper *rf_helper = NULL;
1528         const gchar *active_acc = modest_window_get_active_account (win);
1529         const gchar *active_mailbox = modest_window_get_active_mailbox (win);
1530
1531         rf_helper = g_slice_new0 (ReplyForwardHelper);
1532         rf_helper->reply_forward_type = reply_forward_type;
1533         rf_helper->action = action;
1534         rf_helper->parent_window = (MODEST_IS_WINDOW (win)) ? GTK_WIDGET (win) : NULL;
1535         rf_helper->header = (header) ? g_object_ref (header) : NULL;
1536         rf_helper->top_header = (top_header) ? g_object_ref (top_header) : NULL;
1537         rf_helper->msg_part = (msg_part) ? g_object_ref (msg_part) : NULL;
1538         rf_helper->account_name = (active_acc) ?
1539                 g_strdup (active_acc) :
1540                 modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1541         rf_helper->mailbox = g_strdup (active_mailbox);
1542         if (parts)
1543                 rf_helper->parts = g_object_ref (parts);
1544         else
1545                 rf_helper->parts = NULL;
1546
1547         /* Note that window could be destroyed just AFTER calling
1548            register_window so we must ensure that this pointer does
1549            not hold invalid references */
1550         if (rf_helper->parent_window)
1551                 g_object_weak_ref (G_OBJECT (rf_helper->parent_window),
1552                                    rf_helper_window_closed, rf_helper);
1553
1554         return rf_helper;
1555 }
1556
1557 static void
1558 free_reply_forward_helper (gpointer data)
1559 {
1560         ReplyForwardHelper *helper;
1561
1562         helper = (ReplyForwardHelper *) data;
1563         g_free (helper->account_name);
1564         g_free (helper->mailbox);
1565         if (helper->header)
1566                 g_object_unref (helper->header);
1567         if (helper->top_header)
1568                 g_object_unref (helper->top_header);
1569         if (helper->msg_part)
1570                 g_object_unref (helper->msg_part);
1571         if (helper->parts)
1572                 g_object_unref (helper->parts);
1573         if (helper->parent_window)
1574                 g_object_weak_unref (G_OBJECT (helper->parent_window),
1575                                      rf_helper_window_closed, helper);
1576         g_slice_free (ReplyForwardHelper, helper);
1577 }
1578
1579 static void
1580 reply_forward_cb (ModestMailOperation *mail_op,
1581                   TnyHeader *header,
1582                   gboolean canceled,
1583                   TnyMsg *msg,
1584                   GError *err,
1585                   gpointer user_data)
1586 {
1587         TnyMsg *new_msg = NULL;
1588         ReplyForwardHelper *rf_helper;
1589         ModestWindow *msg_win = NULL;
1590         ModestEditType edit_type;
1591         gchar *from = NULL;
1592         TnyAccount *account = NULL;
1593         ModestWindowMgr *mgr = NULL;
1594         gchar *signature = NULL, *recipient = NULL;
1595         gboolean use_signature;
1596
1597         /* If there was any error. The mail operation could be NULL,
1598            this means that we already have the message downloaded and
1599            that we didn't do a mail operation to retrieve it */
1600         rf_helper = (ReplyForwardHelper *) user_data;
1601         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1602                 goto cleanup;
1603
1604         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1605                                                    rf_helper->account_name, rf_helper->mailbox);
1606
1607         recipient = modest_text_utils_get_email_address (from);
1608         signature = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr (),
1609                                                                      recipient,
1610                                                                      &use_signature);
1611         g_free (recipient);
1612
1613         /* Create reply mail */
1614         switch (rf_helper->action) {
1615                 /* Use the msg_header to ensure that we have all the
1616                    information. The summary can lack some data */
1617                 TnyHeader *msg_header;
1618         case ACTION_REPLY:
1619                 msg_header = tny_msg_get_header (rf_helper->msg_part?rf_helper->msg_part:msg);
1620                 new_msg =
1621                         modest_tny_msg_create_reply_msg (rf_helper->msg_part?rf_helper->msg_part:msg, msg_header, from,
1622                                                          (use_signature) ? signature : NULL,
1623                                                          rf_helper->reply_forward_type,
1624                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1625                 g_object_unref (msg_header);
1626                 break;
1627         case ACTION_REPLY_TO_ALL:
1628                 msg_header = tny_msg_get_header (rf_helper->msg_part?rf_helper->msg_part:msg);
1629                 new_msg =
1630                         modest_tny_msg_create_reply_msg (rf_helper->msg_part?rf_helper->msg_part:msg, msg_header, from,
1631                                                          (use_signature) ? signature : NULL,
1632                                                          rf_helper->reply_forward_type,
1633                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1634                 edit_type = MODEST_EDIT_TYPE_REPLY;
1635                 g_object_unref (msg_header);
1636                 break;
1637         case ACTION_FORWARD:
1638                 new_msg =
1639                         modest_tny_msg_create_forward_msg (rf_helper->msg_part?rf_helper->msg_part:msg, from, 
1640                                                            (use_signature) ? signature : NULL,
1641                                                            rf_helper->reply_forward_type);
1642                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1643                 break;
1644         default:
1645                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1646                                                      header);
1647                 g_return_if_reached ();
1648                 return;
1649         }
1650
1651         g_free (from);
1652         g_free (signature);
1653
1654         if (!new_msg) {
1655                 g_warning ("%s: failed to create message\n", __FUNCTION__);
1656                 goto cleanup;
1657         }
1658
1659         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1660                                                                        rf_helper->account_name,
1661                                                                        TNY_ACCOUNT_TYPE_STORE);
1662         if (!account) {
1663                 g_warning ("%s: failed to get tnyaccount for '%s'\n", __FUNCTION__, rf_helper->account_name);
1664                 goto cleanup;
1665         }
1666
1667         /* Create and register the windows */
1668         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name, rf_helper->mailbox, FALSE);
1669         mgr = modest_runtime_get_window_mgr ();
1670         modest_window_mgr_register_window (mgr, msg_win, (ModestWindow *) rf_helper->parent_window);
1671
1672         /* Note that register_window could have deleted the account */
1673         if (MODEST_IS_WINDOW (rf_helper->parent_window)) {
1674                 gdouble parent_zoom;
1675
1676                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1677                 modest_window_set_zoom (msg_win, parent_zoom);
1678         }
1679
1680         /* Show edit window */
1681         gtk_widget_show_all (GTK_WIDGET (msg_win));
1682
1683 cleanup:
1684         /* We always unregister the header because the message is
1685            forwarded or replied so the original one is no longer
1686            opened */
1687         modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1688                                              header);
1689         if (new_msg)
1690                 g_object_unref (G_OBJECT (new_msg));
1691         if (account)
1692                 g_object_unref (G_OBJECT (account));
1693         free_reply_forward_helper (rf_helper);
1694 }
1695
1696 /* Checks a list of headers. If any of them are not currently
1697  * downloaded (CACHED) then returns TRUE else returns FALSE.
1698  */
1699 static gint
1700 header_list_count_uncached_msgs (TnyList *header_list)
1701 {
1702         TnyIterator *iter;
1703         gint uncached_messages = 0;
1704
1705         iter = tny_list_create_iterator (header_list);
1706         while (!tny_iterator_is_done (iter)) {
1707                 TnyHeader *header;
1708
1709                 header = TNY_HEADER (tny_iterator_get_current (iter));
1710                 if (header) {
1711                         if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
1712                                 uncached_messages ++;
1713                         g_object_unref (header);
1714                 }
1715
1716                 tny_iterator_next (iter);
1717         }
1718         g_object_unref (iter);
1719
1720         return uncached_messages;
1721 }
1722
1723 /* Returns FALSE if the user does not want to download the
1724  * messages. Returns TRUE if the user allowed the download.
1725  */
1726 static gboolean
1727 connect_to_get_msg (ModestWindow *win,
1728                     gint num_of_uncached_msgs,
1729                     TnyAccount *account)
1730 {
1731         GtkResponseType response;
1732         GtkWindow *toplevel;
1733
1734         /* Allways download if we are online. */
1735         if (tny_device_is_online (modest_runtime_get_device ()))
1736                 return TRUE;
1737
1738         /* If offline, then ask for user permission to download the messages */
1739         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1740         response = modest_platform_run_confirmation_dialog (toplevel,
1741                                                             ngettext("mcen_nc_get_msg",
1742                                                                      "mcen_nc_get_msgs",
1743                                                                      num_of_uncached_msgs));
1744
1745         if (response == GTK_RESPONSE_CANCEL)
1746                 return FALSE;
1747
1748         return modest_platform_connect_and_wait(toplevel, account);
1749 }
1750
1751 static void
1752 reply_forward_performer (gboolean canceled,
1753                          GError *err,
1754                          ModestWindow *parent_window,
1755                          TnyAccount *account,
1756                          gpointer user_data)
1757 {
1758         ReplyForwardHelper *rf_helper = NULL;
1759         ModestMailOperation *mail_op;
1760
1761         rf_helper = (ReplyForwardHelper *) user_data;
1762
1763         if (canceled || err) {
1764                 free_reply_forward_helper (rf_helper);
1765                 return;
1766         }
1767
1768         /* Retrieve the message */
1769         modest_window_mgr_register_header (modest_runtime_get_window_mgr (), rf_helper->header, NULL);
1770         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (parent_window),
1771                                                                  modest_ui_actions_disk_operations_error_handler,
1772                                                                  NULL, NULL);
1773         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1774         modest_mail_operation_get_msg_and_parts (mail_op, rf_helper->top_header, rf_helper->parts, TRUE, reply_forward_cb, rf_helper);
1775
1776         /* Frees */
1777         g_object_unref(mail_op);
1778 }
1779
1780 static gboolean
1781 all_parts_retrieved (TnyMimePart *part)
1782 {
1783         if (!TNY_IS_CAMEL_BS_MIME_PART (part)) {
1784                 return TRUE;
1785         } else {
1786                 TnyList *pending_parts;
1787                 TnyIterator *iterator;
1788                 gboolean all_retrieved = TRUE;
1789
1790                 pending_parts = TNY_LIST (tny_simple_list_new ());
1791                 tny_mime_part_get_parts (part, pending_parts);
1792                 iterator = tny_list_create_iterator (pending_parts);
1793                 while (all_retrieved && !tny_iterator_is_done (iterator)) {
1794                         TnyMimePart *child;
1795
1796                         child = TNY_MIME_PART (tny_iterator_get_current (iterator));
1797
1798                         if (tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (child))) {
1799                                 all_retrieved = all_parts_retrieved (TNY_MIME_PART (child));
1800                         } else {
1801                                 all_retrieved = FALSE;
1802                         }
1803
1804                         g_object_unref (child);
1805                         tny_iterator_next (iterator);
1806                 }
1807                 g_object_unref (iterator);
1808                 g_object_unref (pending_parts);
1809                 return all_retrieved;
1810         }
1811 }
1812
1813 static void
1814 forward_pending_parts_helper (TnyMimePart *part, TnyList *list)
1815 {
1816         TnyList *parts;
1817         TnyIterator *iterator;
1818
1819         if (!tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (part))) {
1820                 tny_list_append (list, G_OBJECT (part));
1821         }
1822         parts = TNY_LIST (tny_simple_list_new ());
1823         tny_mime_part_get_parts (part, parts);
1824         for (iterator = tny_list_create_iterator (parts); 
1825              !tny_iterator_is_done (iterator);
1826              tny_iterator_next (iterator)) {
1827                 TnyMimePart *child;
1828
1829                 child = TNY_MIME_PART (tny_iterator_get_current (iterator));
1830                 forward_pending_parts_helper (child, list);
1831                 g_object_unref (child);
1832         }
1833         g_object_unref (iterator);
1834         g_object_unref (parts);
1835 }
1836
1837 static TnyList *
1838 forward_pending_parts (TnyMsg *msg)
1839 {
1840         TnyList *result = TNY_LIST (tny_simple_list_new ());
1841         if (TNY_IS_CAMEL_BS_MIME_PART (msg)) {
1842                 forward_pending_parts_helper (TNY_MIME_PART (msg), result);
1843         }
1844
1845         return result;
1846 }
1847
1848 /*
1849  * Common code for the reply and forward actions
1850  */
1851 static void
1852 reply_forward (ReplyForwardAction action, ModestWindow *win)
1853 {
1854         ReplyForwardHelper *rf_helper = NULL;
1855         guint reply_forward_type;
1856
1857         g_return_if_fail (win && MODEST_IS_WINDOW(win));
1858
1859         /* we check for low-mem; in that case, show a warning, and don't allow
1860          * reply/forward (because it could potentially require a lot of memory */
1861         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1862                 return;
1863
1864
1865         /* we need an account when editing */
1866         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
1867                 if (!modest_ui_actions_run_account_setup_wizard (win))
1868                         return;
1869         }
1870
1871         reply_forward_type =
1872                 modest_conf_get_int (modest_runtime_get_conf (),
1873                                      (action == ACTION_FORWARD) ?
1874                                      MODEST_CONF_FORWARD_TYPE :
1875                                      MODEST_CONF_REPLY_TYPE,
1876                                      NULL);
1877
1878         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
1879                 TnyMsg *msg = NULL;
1880                 TnyMsg *top_msg = NULL;
1881                 TnyHeader *header = NULL;
1882                 /* Get header and message. Do not free them here, the
1883                    reply_forward_cb must do it */
1884                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
1885                 top_msg = modest_msg_view_window_get_top_message (MODEST_MSG_VIEW_WINDOW(win));
1886                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
1887
1888                 if (msg && header && (action != ACTION_FORWARD || all_parts_retrieved (TNY_MIME_PART (msg)))) {
1889                         /* Create helper */
1890                         rf_helper = create_reply_forward_helper (action, win,
1891                                                                  reply_forward_type, header, NULL, NULL, NULL);
1892                         reply_forward_cb (NULL, header, FALSE, msg, NULL, rf_helper);
1893                 } else {
1894                         gboolean do_download = TRUE;
1895
1896                         if (msg && header && action == ACTION_FORWARD) {
1897                                 if (top_msg == NULL)
1898                                         top_msg = g_object_ref (msg);
1899                                 /* Not all parts retrieved. Then we have to retrieve them all before
1900                                  * creating the forward message */
1901                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1902                                         gint response;
1903                                         GtkWindow *toplevel;
1904
1905                                         /* If ask for user permission to download the messages */
1906                                         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1907                                         response = modest_platform_run_confirmation_dialog (toplevel,
1908                                                                                             ngettext("mcen_nc_get_msg",
1909                                                                                                      "mcen_nc_get_msgs",
1910                                                                                                      1));
1911
1912                                         /* End if the user does not want to continue */
1913                                         if (response == GTK_RESPONSE_CANCEL)
1914                                                 do_download = FALSE;
1915                                 }
1916
1917                                 if (do_download) {
1918                                         TnyList *pending_parts;
1919                                         TnyFolder *folder;
1920                                         TnyAccount *account;
1921                                         TnyHeader *top_header;
1922
1923                                         /* Create helper */
1924                                         top_header = tny_msg_get_header (top_msg);
1925                                         pending_parts = forward_pending_parts (top_msg);
1926                                         rf_helper = create_reply_forward_helper (action, win,
1927                                                                                  reply_forward_type, header, msg, top_header, pending_parts);
1928                                         g_object_unref (pending_parts);
1929
1930                                         folder = tny_header_get_folder (top_header);
1931                                         account = tny_folder_get_account (folder);
1932                                         modest_platform_connect_and_perform (win,
1933                                                                              TRUE, account,
1934                                                                              reply_forward_performer,
1935                                                                              rf_helper);
1936                                         if (folder) g_object_unref (folder);
1937                                         g_object_unref (account);
1938                                         if (top_header) g_object_unref (top_header);
1939                                 }
1940
1941                         } else {
1942                                 g_warning("%s: no message or header found in viewer\n", __FUNCTION__);
1943                         }
1944                 }
1945
1946                 if (msg)
1947                         g_object_unref (msg);
1948                 if (top_msg)
1949                         g_object_unref (top_msg);
1950                 if (header)
1951                         g_object_unref (header);
1952         } else {
1953                 TnyHeader *header = NULL;
1954                 TnyIterator *iter;
1955                 gboolean do_retrieve = TRUE;
1956                 TnyList *header_list = NULL;
1957
1958                 header_list = get_selected_headers (win);
1959                 if (!header_list)
1960                         return;
1961                 /* Check that only one message is selected for replying */
1962                 if (tny_list_get_length (header_list) != 1) {
1963                         modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
1964                                                             NULL, _("mcen_ib_select_one_message"));
1965                         g_object_unref (header_list);
1966                         return;
1967                 }
1968
1969                 /* Only reply/forward to one message */
1970                 iter = tny_list_create_iterator (header_list);
1971                 header = TNY_HEADER (tny_iterator_get_current (iter));
1972                 g_object_unref (iter);
1973
1974                 /* Retrieve messages */
1975                 do_retrieve = (action == ACTION_FORWARD) ||
1976                         (reply_forward_type != MODEST_TNY_MSG_REPLY_TYPE_CITE);
1977
1978                 if (do_retrieve) {
1979                         TnyAccount *account = NULL;
1980                         TnyFolder *folder = NULL;
1981                         gdouble download = TRUE;
1982                         guint uncached_msgs = 0;
1983
1984                         folder = tny_header_get_folder (header);
1985                         if (!folder)
1986                                 goto do_retrieve_frees;
1987                         account = tny_folder_get_account (folder);
1988                         if (!account)
1989                                 goto do_retrieve_frees;
1990
1991                         uncached_msgs = header_list_count_uncached_msgs (header_list);
1992
1993                         if (uncached_msgs > 0) {
1994                                 /* Allways download if we are online. */
1995                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1996                                         gint response;
1997                                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1998
1999                                         /* If ask for user permission to download the messages */
2000                                         response = modest_platform_run_confirmation_dialog (toplevel,
2001                                                                                             ngettext("mcen_nc_get_msg",
2002                                                                                                      "mcen_nc_get_msgs",
2003                                                                                                      uncached_msgs));
2004
2005                                         /* End if the user does not want to continue */
2006                                         if (response == GTK_RESPONSE_CANCEL)
2007                                                 download = FALSE;
2008                                 }
2009                         }
2010
2011                         if (download) {
2012                                 /* Create helper */
2013                                 rf_helper = create_reply_forward_helper (action, win,
2014                                                                          reply_forward_type, header, NULL, NULL, NULL);
2015                                 if (uncached_msgs > 0) {
2016                                         modest_platform_connect_and_perform (win,
2017                                                                              TRUE, account,
2018                                                                              reply_forward_performer,
2019                                                                              rf_helper);
2020                                 } else {
2021                                         reply_forward_performer (FALSE, NULL, win,
2022                                                                  account, rf_helper);
2023                                 }
2024                         }
2025                 do_retrieve_frees:
2026                         if (account)
2027                                 g_object_unref (account);
2028                         if (folder)
2029                                 g_object_unref (folder);
2030                 } else {
2031                         reply_forward_cb (NULL, header, FALSE, NULL, NULL, NULL);
2032                 }
2033                 /* Frees */
2034                 g_object_unref (header_list);
2035                 g_object_unref (header);
2036         }
2037 }
2038
2039 void
2040 modest_ui_actions_reply_calendar (ModestWindow *win, TnyList *header_pairs)
2041 {
2042         modest_ui_actions_reply_calendar_with_subject (win, NULL, header_pairs);
2043 }
2044
2045 void
2046 modest_ui_actions_reply_calendar_with_subject (ModestWindow *win, const gchar *custom_subject, TnyList *header_pairs)
2047 {
2048         gchar *from;
2049         gchar *recipient;
2050         gchar *signature;
2051         gboolean use_signature;
2052         TnyMsg *new_msg;
2053         GtkWidget *msg_win;
2054         const gchar *account_name;
2055         const gchar *mailbox;
2056         TnyHeader *msg_header;
2057         ModestWindowMgr *mgr;
2058         TnyMsg *msg;
2059
2060         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(win));
2061
2062         /* we check for low-mem; in that case, show a warning, and don't allow
2063          * reply/forward (because it could potentially require a lot of memory */
2064         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2065                 return;
2066
2067         account_name = modest_window_get_active_account (MODEST_WINDOW (win));
2068         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (win));
2069         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
2070                                                    account_name, mailbox);
2071         recipient = modest_text_utils_get_email_address (from);
2072         signature = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr(), 
2073                                                                      recipient, 
2074                                                                      &use_signature);
2075         g_free (recipient);
2076
2077         msg = modest_msg_view_window_get_message(MODEST_MSG_VIEW_WINDOW(win));
2078         g_return_if_fail(msg);
2079
2080         msg_header = tny_msg_get_header (msg);
2081         new_msg =
2082                 modest_tny_msg_create_reply_calendar_msg (msg, msg_header, from,
2083                                                           (use_signature) ? signature : NULL,
2084                                                           header_pairs);
2085         g_object_unref (msg_header);
2086
2087         g_free (from);
2088         g_free (signature);
2089
2090         if (!new_msg) {
2091                 g_warning ("%s: failed to create message\n", __FUNCTION__);
2092                 goto cleanup;
2093         }
2094
2095         if (custom_subject) {
2096                 TnyHeader *new_msg_header;
2097
2098                 new_msg_header = tny_msg_get_header (new_msg);
2099                 tny_header_set_subject (new_msg_header, custom_subject);
2100                 g_object_unref (new_msg_header);
2101         }
2102
2103         msg_win = (GtkWidget *) modest_msg_edit_window_new (new_msg, account_name, mailbox, FALSE);
2104         mgr = modest_runtime_get_window_mgr ();
2105         modest_window_mgr_register_window (mgr, MODEST_WINDOW (msg_win), (ModestWindow *) win);
2106
2107         /* Show edit window */
2108         gtk_widget_show_all (GTK_WIDGET (msg_win));
2109
2110 cleanup:
2111         if (new_msg)
2112                 g_object_unref (G_OBJECT (new_msg));
2113 }
2114
2115 void
2116 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
2117 {
2118         g_return_if_fail (MODEST_IS_WINDOW(win));
2119
2120         reply_forward (ACTION_REPLY, win);
2121 }
2122
2123 void
2124 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
2125 {
2126         g_return_if_fail (MODEST_IS_WINDOW(win));
2127
2128         reply_forward (ACTION_FORWARD, win);
2129 }
2130
2131 void
2132 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
2133 {
2134         g_return_if_fail (MODEST_IS_WINDOW(win));
2135
2136         reply_forward (ACTION_REPLY_TO_ALL, win);
2137 }
2138
2139 void
2140 modest_ui_actions_on_next (GtkAction *action,
2141                            ModestWindow *window)
2142 {
2143         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2144                 modest_msg_view_window_select_next_message (
2145                                 MODEST_MSG_VIEW_WINDOW (window));
2146         } else {
2147                 g_return_if_reached ();
2148         }
2149 }
2150
2151 void
2152 modest_ui_actions_on_prev (GtkAction *action,
2153                            ModestWindow *window)
2154 {
2155         g_return_if_fail (MODEST_IS_WINDOW(window));
2156
2157         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2158                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
2159         } else {
2160                 g_return_if_reached ();
2161         }
2162 }
2163
2164 void
2165 modest_ui_actions_on_sort (GtkAction *action,
2166                            ModestWindow *window)
2167 {
2168         GtkWidget *header_view = NULL;
2169
2170         g_return_if_fail (MODEST_IS_WINDOW(window));
2171
2172         if (MODEST_IS_HEADER_WINDOW (window)) {
2173                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
2174         }
2175
2176         if (!header_view) {
2177                 modest_platform_information_banner (NULL, NULL, _CS_NOTHING_TO_SORT);
2178
2179                 return;
2180         }
2181
2182         /* Show sorting dialog */
2183         modest_utils_run_sort_dialog (MODEST_WINDOW (window), MODEST_SORT_HEADERS);
2184 }
2185
2186 static void
2187 sync_folder_cb (ModestMailOperation *mail_op,
2188                 TnyFolder *folder,
2189                 gpointer user_data)
2190 {
2191         ModestHeaderView *header_view = (ModestHeaderView *) user_data;
2192
2193         if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
2194                 ModestWindow *parent = (ModestWindow *) modest_mail_operation_get_source (mail_op);
2195
2196                 /* We must clear first, because otherwise set_folder will ignore */
2197                 /*    the change as the folders are the same */
2198                 modest_header_view_clear (header_view);
2199                 modest_header_view_set_folder (header_view, folder, TRUE, parent, NULL, NULL);
2200
2201                 g_object_unref (parent);
2202         }
2203
2204         g_object_unref (header_view);
2205 }
2206
2207 static gboolean
2208 idle_refresh_folder (gpointer source)
2209 {
2210         ModestHeaderView *header_view = NULL;
2211
2212         /* If the window still exists */
2213         if (!GTK_IS_WIDGET (source) ||
2214             !GTK_WIDGET_VISIBLE (source))
2215                 return FALSE;
2216
2217         /* Refresh the current view */
2218         if (MODEST_IS_HEADER_WINDOW (source))
2219                 header_view = modest_header_window_get_header_view ((ModestHeaderWindow *) source);
2220         if (header_view) {
2221                 TnyFolder *folder = modest_header_view_get_folder (header_view);
2222                 if (folder) {
2223                         /* Sync the folder status */
2224                         ModestMailOperation *mail_op = modest_mail_operation_new (source);
2225                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
2226                         modest_mail_operation_sync_folder (mail_op, folder, FALSE, sync_folder_cb, g_object_ref (header_view));
2227                         g_object_unref (folder);
2228                         g_object_unref (mail_op);
2229                 }
2230         }
2231
2232         return FALSE;
2233 }
2234
2235 static void
2236 update_account_cb (ModestMailOperation *self,
2237                    TnyList *new_headers,
2238                    gpointer user_data)
2239 {
2240         ModestWindow *top;
2241         gboolean show_visual_notifications;
2242
2243         top = modest_window_mgr_get_current_top (modest_runtime_get_window_mgr ());
2244         show_visual_notifications = (top) ? FALSE : TRUE;
2245
2246         /* Notify new messages have been downloaded. If the
2247            send&receive was invoked by the user then do not show any
2248            visual notification, only play a sound and activate the LED
2249            (for the Maemo version) */
2250         if (TNY_IS_LIST(new_headers) && (tny_list_get_length (new_headers)) > 0) {
2251
2252                 /* We only notify about really new messages (not seen) we get */
2253                 TnyList *actually_new_list;
2254                 TnyIterator *iterator;
2255                 actually_new_list = TNY_LIST (tny_simple_list_new ());
2256                 for (iterator = tny_list_create_iterator (new_headers);
2257                      !tny_iterator_is_done (iterator);
2258                      tny_iterator_next (iterator)) {
2259                         TnyHeader *header;
2260                         TnyHeaderFlags flags;
2261                         header = TNY_HEADER (tny_iterator_get_current (iterator));
2262                         flags = tny_header_get_flags (header);
2263
2264                         if (!(flags & TNY_HEADER_FLAG_SEEN)) {
2265                                 /* Messages are ordered from most
2266                                    recent to oldest. But we want to
2267                                    show notifications starting from
2268                                    the oldest message. That's why we
2269                                    reverse the list */
2270                                 tny_list_prepend (actually_new_list, G_OBJECT (header));
2271                         }
2272                         g_object_unref (header);
2273                 }
2274                 g_object_unref (iterator);
2275
2276                 if (tny_list_get_length (actually_new_list) > 0) {
2277                         GList *new_headers_list = NULL;
2278
2279                         new_headers_list = modest_utils_create_notification_list_from_header_list (actually_new_list);
2280
2281                         /* Send notifications */
2282                         if (new_headers_list) {
2283                                 modest_platform_on_new_headers_received (new_headers_list,
2284                                                                          show_visual_notifications);
2285                                 /* Free the list */
2286                                 modest_utils_free_notification_list (new_headers_list);
2287                         }
2288                 }
2289                 g_object_unref (actually_new_list);
2290         }
2291
2292         if (top) {
2293                 /* Refresh the current folder in an idle. We do this
2294                    in order to avoid refresh cancelations if the
2295                    currently viewed folder is the inbox */
2296                 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
2297                                  idle_refresh_folder,
2298                                  g_object_ref (top),
2299                                  g_object_unref);
2300         }
2301 }
2302
2303 typedef struct {
2304         TnyAccount *account;
2305         ModestWindow *win;
2306         gchar *account_name;
2307         gboolean poke_status;
2308         gboolean interactive;
2309         ModestMailOperation *mail_op;
2310 } SendReceiveInfo;
2311
2312 static void
2313 do_send_receive_performer (gboolean canceled,
2314                            GError *err,
2315                            ModestWindow *parent_window,
2316                            TnyAccount *account,
2317                            gpointer user_data)
2318 {
2319         SendReceiveInfo *info;
2320
2321         info = (SendReceiveInfo *) user_data;
2322
2323         if (err || canceled) {
2324                 /* In disk full conditions we could get this error here */
2325                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
2326                                                                 (GtkWidget *) parent_window, err,
2327                                                                 account, NULL);
2328
2329                 if (info->mail_op) {
2330                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
2331                                                             info->mail_op);
2332                 }
2333                 goto clean;
2334         }
2335
2336
2337         /* Send & receive. */
2338         modest_mail_operation_update_account (info->mail_op, info->account_name,
2339                                               info->poke_status, info->interactive,
2340                                               update_account_cb, info->win);
2341
2342  clean:
2343         /* Frees */
2344         if (info->mail_op)
2345                 g_object_unref (G_OBJECT (info->mail_op));
2346         if (info->account_name)
2347                 g_free (info->account_name);
2348         if (info->win)
2349                 g_object_unref (info->win);
2350         if (info->account)
2351                 g_object_unref (info->account);
2352         g_slice_free (SendReceiveInfo, info);
2353 }
2354
2355 /*
2356  * This function performs the send & receive required actions. The
2357  * window is used to create the mail operation. Typically it should
2358  * always be the main window, but we pass it as argument in order to
2359  * be more flexible.
2360  */
2361 void
2362 modest_ui_actions_do_send_receive (const gchar *account_name,
2363                                    gboolean force_connection,
2364                                    gboolean poke_status,
2365                                    gboolean interactive,
2366                                    ModestWindow *win)
2367 {
2368         gchar *acc_name = NULL;
2369         SendReceiveInfo *info;
2370         ModestTnyAccountStore *acc_store;
2371         TnyAccount *account;
2372
2373         /* If no account name was provided then get the current account, and if
2374            there is no current account then pick the default one: */
2375         if (!account_name) {
2376                 if (win)
2377                         acc_name = g_strdup (modest_window_get_active_account (win));
2378                 if (!acc_name)
2379                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
2380                 if (!acc_name) {
2381                         modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2382                         return;
2383                 }
2384         } else {
2385                 acc_name = g_strdup (account_name);
2386         }
2387
2388         acc_store = modest_runtime_get_account_store ();
2389         account = modest_tny_account_store_get_server_account (acc_store, acc_name, TNY_ACCOUNT_TYPE_STORE);
2390
2391         if (!account) {
2392                 g_free (acc_name);
2393                 modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2394                 return;
2395         }
2396
2397         /* Do not automatically refresh accounts that are flagged as
2398            NO_AUTO_UPDATE. This could be useful for accounts that
2399            handle their own update times */
2400         if (!interactive) {
2401                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
2402                 if (proto != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
2403                         const gchar *tag = MODEST_PROTOCOL_REGISTRY_NO_AUTO_UPDATE_PROTOCOLS;
2404                         ModestProtocolRegistry *registry = modest_runtime_get_protocol_registry ();
2405
2406                         if (modest_protocol_registry_protocol_type_has_tag (registry, proto, tag)) {
2407                                 g_debug ("%s no auto update allowed for account %s", __FUNCTION__, account_name);
2408                                 g_object_unref (account);
2409                                 g_free (acc_name);
2410                                 return;
2411                         }
2412                 }
2413         }
2414
2415         /* Create the info for the connect and perform */
2416         info = g_slice_new (SendReceiveInfo);
2417         info->account_name = acc_name;
2418         info->win = (win) ? g_object_ref (win) : NULL;
2419         info->poke_status = poke_status;
2420         info->interactive = interactive;
2421         info->account = account;
2422         /* We need to create the operation here, because otherwise it
2423            could happen that the queue emits the queue-empty signal
2424            while we're trying to connect the account */
2425         info->mail_op = modest_mail_operation_new_with_error_handling ((info->win) ? G_OBJECT (info->win) : NULL,
2426                                                                        modest_ui_actions_disk_operations_error_handler,
2427                                                                        NULL, NULL);
2428         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), info->mail_op);
2429
2430         /* Invoke the connect and perform */
2431         modest_platform_connect_and_perform (win, force_connection, info->account,
2432                                              do_send_receive_performer, info);
2433 }
2434
2435
2436 static void
2437 modest_ui_actions_do_cancel_send (const gchar *account_name,
2438                                   ModestWindow *win)
2439 {
2440         TnyTransportAccount *transport_account;
2441         TnySendQueue *send_queue = NULL;
2442         GError *error = NULL;
2443
2444         /* Get transport account */
2445         transport_account =
2446                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2447                                       (modest_runtime_get_account_store(),
2448                                        account_name,
2449                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2450         if (!transport_account) {
2451                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2452                 goto frees;
2453         }
2454
2455         /* Get send queue*/
2456         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
2457         if (!TNY_IS_SEND_QUEUE(send_queue)) {
2458                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
2459                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2460                              "modest: could not find send queue for account\n");
2461         } else {
2462                 /* Cancel the current send */
2463                 tny_account_cancel (TNY_ACCOUNT (transport_account));
2464
2465                 /* Suspend all pending messages */
2466                 tny_send_queue_cancel (send_queue, TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, &error);
2467         }
2468
2469  frees:
2470         if (transport_account != NULL)
2471                 g_object_unref (G_OBJECT (transport_account));
2472 }
2473
2474 static void
2475 modest_ui_actions_cancel_send_all (ModestWindow *win)
2476 {
2477         GSList *account_names, *iter;
2478
2479         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2480                                                           TRUE);
2481
2482         iter = account_names;
2483         while (iter) {
2484                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
2485                 iter = g_slist_next (iter);
2486         }
2487
2488         modest_account_mgr_free_account_names (account_names);
2489         account_names = NULL;
2490 }
2491
2492 void
2493 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
2494
2495 {
2496         /* Check if accounts exist */
2497         gboolean accounts_exist =
2498                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2499
2500         /* If not, allow the user to create an account before trying to send/receive. */
2501         if (!accounts_exist)
2502                 modest_ui_actions_on_accounts (NULL, win);
2503
2504         /* Cancel all sending operaitons */
2505         modest_ui_actions_cancel_send_all (win);
2506 }
2507
2508 /*
2509  * Refreshes all accounts. This function will be used by automatic
2510  * updates
2511  */
2512 void
2513 modest_ui_actions_do_send_receive_all (ModestWindow *win,
2514                                        gboolean force_connection,
2515                                        gboolean poke_status,
2516                                        gboolean interactive)
2517 {
2518         GSList *account_names, *iter;
2519
2520         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2521                                                           TRUE);
2522
2523         iter = account_names;
2524         while (iter) {
2525                 modest_ui_actions_do_send_receive ((const char*) iter->data,
2526                                                    force_connection,
2527                                                    poke_status, interactive, win);
2528                 iter = g_slist_next (iter);
2529         }
2530
2531         modest_account_mgr_free_account_names (account_names);
2532         account_names = NULL;
2533 }
2534
2535 /*
2536  * Handler of the click on Send&Receive button in the main toolbar
2537  */
2538 void
2539 modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win)
2540 {
2541         /* Check if accounts exist */
2542         gboolean accounts_exist;
2543
2544         accounts_exist =
2545                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2546
2547         /* If not, allow the user to create an account before trying to send/receive. */
2548         if (!accounts_exist)
2549                 modest_ui_actions_on_accounts (NULL, win);
2550
2551         /* Refresh the current folder. The if is always TRUE it's just an extra check */
2552         if (MODEST_IS_ACCOUNTS_WINDOW (win)) {
2553                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2554         } else {
2555                 const gchar *active_account;
2556                 active_account = modest_window_get_active_account (MODEST_WINDOW (win));
2557
2558                 modest_ui_actions_do_send_receive (active_account, TRUE, TRUE, TRUE, win);
2559         }
2560
2561 }
2562
2563
2564 void
2565 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
2566                                        TnyHeader *header,
2567                                        GtkTreePath *path,
2568                                        ModestWindow *window)
2569 {
2570         GtkTreeRowReference *rowref;
2571
2572         g_return_if_fail (MODEST_IS_WINDOW(window));
2573         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2574         g_return_if_fail (TNY_IS_HEADER (header));
2575
2576         if (modest_header_view_count_selected_headers (header_view) > 1) {
2577                 /* Don't allow activation if there are more than one message selected */
2578                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
2579                 return;
2580         }
2581
2582         /* we check for low-mem; in that case, show a warning, and don't allow
2583          * activating headers
2584          */
2585         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2586                 return;
2587
2588
2589         rowref = gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)), path);
2590         open_msg_from_header (header, rowref, MODEST_WINDOW (window));
2591         gtk_tree_row_reference_free (rowref);
2592 }
2593
2594 void
2595 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
2596                                      ModestWindow *win)
2597 {
2598         GtkWidget *dialog;
2599         gchar *txt, *item;
2600         gboolean online;
2601         GtkWindow *toplevel;
2602
2603         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
2604         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
2605
2606         online = tny_device_is_online (modest_runtime_get_device());
2607
2608         if (online) {
2609                 /* already online -- the item is simply not there... */
2610                 dialog = gtk_message_dialog_new (toplevel,
2611                                                  GTK_DIALOG_MODAL,
2612                                                  GTK_MESSAGE_WARNING,
2613                                                  GTK_BUTTONS_NONE,
2614                                                  _("The %s you selected cannot be found"),
2615                                                  item);
2616                 gtk_dialog_add_button (GTK_DIALOG (dialog),_("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
2617                 gtk_dialog_run (GTK_DIALOG(dialog));
2618         } else {
2619                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
2620                                                       toplevel,
2621                                                       GTK_DIALOG_MODAL,
2622                                                       _("mcen_bd_dialog_cancel"),
2623                                                       GTK_RESPONSE_REJECT,
2624                                                       _("mcen_bd_dialog_ok"),
2625                                                       GTK_RESPONSE_ACCEPT,
2626                                                       NULL);
2627                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
2628                                          "Do you want to get online?"), item);
2629                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
2630                                     gtk_label_new (txt), FALSE, FALSE, 0);
2631                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2632                 g_free (txt);
2633
2634                 gtk_window_set_default_size ((GtkWindow *) dialog, 300, 300);
2635                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2636                         /* TODO: Comment about why is this commented out: */
2637                         /* modest_platform_connect_and_wait (); */
2638                 }
2639         }
2640         gtk_widget_destroy (dialog);
2641 }
2642
2643 void
2644 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
2645                                      ModestWindow *win)
2646 {
2647         /* g_debug ("%s %s", __FUNCTION__, link); */
2648 }
2649
2650
2651 void
2652 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
2653                                         ModestWindow *win)
2654 {
2655         modest_platform_activate_uri (link);
2656 }
2657
2658 void
2659 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
2660                                           ModestWindow *win)
2661 {
2662         modest_platform_show_uri_popup (link);
2663 }
2664
2665 void
2666 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
2667                                              ModestWindow *win)
2668 {
2669         /* we check for low-mem; in that case, show a warning, and don't allow
2670          * viewing attachments
2671          */
2672         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2673                 return;
2674
2675         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
2676 }
2677
2678 void
2679 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
2680                                           const gchar *address,
2681                                           ModestWindow *win)
2682 {
2683         /* g_debug ("%s %s", __FUNCTION__, address); */
2684 }
2685
2686 static void
2687 on_save_to_drafts_cb (ModestMailOperation *mail_op,
2688                       TnyMsg *saved_draft,
2689                       gpointer user_data)
2690 {
2691         ModestMsgEditWindow *edit_window;
2692
2693         /* TODO: in hildon 2 we have to dim and undim the header views while we're saving */
2694
2695         edit_window = MODEST_MSG_EDIT_WINDOW (user_data);
2696
2697         /* Set draft is there was no error */
2698         if (!modest_mail_operation_get_error (mail_op))
2699                 modest_msg_edit_window_set_draft (edit_window, saved_draft);
2700
2701         g_object_unref(edit_window);
2702 }
2703
2704 static gboolean
2705 enough_space_for_message (ModestMsgEditWindow *edit_window,
2706                           MsgData *data)
2707 {
2708         guint64 available_disk, expected_size;
2709         gint parts_count;
2710         guint64 parts_size;
2711
2712         /* Check size */
2713         available_disk = modest_utils_get_available_space (NULL);
2714         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
2715         expected_size = modest_tny_msg_estimate_size (data->plain_body,
2716                                                       data->html_body,
2717                                                       parts_count,
2718                                                       parts_size);
2719
2720         /* Double check: disk full condition or message too big */
2721         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
2722             expected_size > available_disk) {
2723                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2724                 modest_platform_information_banner (NULL, NULL, msg);
2725                 g_free (msg);
2726
2727                 return FALSE;
2728         }
2729
2730         /*
2731          * djcb: if we're in low-memory state, we only allow for
2732          * saving messages smaller than
2733          * MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h) this
2734          * should still allow for sending anything critical...
2735          */
2736         if ((expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) &&
2737             modest_platform_check_memory_low (MODEST_WINDOW(edit_window), TRUE))
2738                 return FALSE;
2739
2740         /*
2741          * djcb: we also make sure that the attachments are smaller than the max size
2742          * this is for the case where we'd try to forward a message with attachments
2743          * bigger than our max allowed size, or sending an message from drafts which
2744          * somehow got past our checks when attaching.
2745          */
2746         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
2747                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) edit_window);
2748                 modest_platform_run_information_dialog (toplevel,
2749                                                         _("mail_ib_error_attachment_size"),
2750                                                         TRUE);
2751                 return FALSE;
2752         }
2753
2754         return TRUE;
2755 }
2756
2757 gboolean
2758 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2759 {
2760         TnyTransportAccount *transport_account;
2761         ModestMailOperation *mail_operation;
2762         MsgData *data;
2763         gchar *account_name;
2764         ModestAccountMgr *account_mgr;
2765         gboolean had_error = FALSE;
2766
2767         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), FALSE);
2768
2769         data = modest_msg_edit_window_get_msg_data (edit_window);
2770
2771         /* Check size */
2772         if (!enough_space_for_message (edit_window, data)) {
2773                 modest_msg_edit_window_free_msg_data (edit_window, data);
2774                 return FALSE;
2775         }
2776
2777         account_name = g_strdup (data->account_name);
2778         account_mgr = modest_runtime_get_account_mgr();
2779         if (!account_name)
2780                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2781         if (!account_name)
2782                 account_name = modest_account_mgr_get_default_account (account_mgr);
2783         if (!account_name) {
2784                 g_printerr ("modest: no account found\n");
2785                 modest_msg_edit_window_free_msg_data (edit_window, data);
2786                 return FALSE;
2787         }
2788
2789         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
2790                 account_name = g_strdup (data->account_name);
2791         }
2792
2793         transport_account =
2794                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2795                                       (modest_runtime_get_account_store (),
2796                                        account_name,
2797                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2798         if (!transport_account) {
2799                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2800                 g_free (account_name);
2801                 modest_msg_edit_window_free_msg_data (edit_window, data);
2802                 return FALSE;
2803         }
2804
2805         /* Create the mail operation */
2806         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler,
2807                                                                         NULL, NULL);
2808         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2809
2810         modest_mail_operation_save_to_drafts (mail_operation,
2811                                               transport_account,
2812                                               data->draft_msg,
2813                                               data->from,
2814                                               data->to, 
2815                                               data->cc, 
2816                                               data->bcc,
2817                                               data->subject,
2818                                               data->plain_body,
2819                                               data->html_body,
2820                                               data->attachments,
2821                                               data->images,
2822                                               data->priority_flags,
2823                                               data->references,
2824                                               data->in_reply_to,
2825                                               data->custom_header_pairs,
2826                                               on_save_to_drafts_cb,
2827                                               g_object_ref(edit_window));
2828
2829         /* In hildon2 we always show the information banner on saving to drafts.
2830          * It will be a system information banner in this case.
2831          */
2832         gchar *text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
2833         modest_platform_information_banner (NULL, NULL, text);
2834         g_free (text);
2835         modest_msg_edit_window_set_modified (edit_window, FALSE);
2836
2837         /* Frees */
2838         g_free (account_name);
2839         g_object_unref (G_OBJECT (transport_account));
2840         g_object_unref (G_OBJECT (mail_operation));
2841
2842         modest_msg_edit_window_free_msg_data (edit_window, data);
2843
2844
2845         return !had_error;
2846 }
2847
2848 /* For instance, when clicking the Send toolbar button when editing a message: */
2849 gboolean
2850 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2851 {
2852         TnyTransportAccount *transport_account = NULL;
2853         gboolean result = TRUE, add_to_contacts;
2854         MsgData *data;
2855         ModestAccountMgr *account_mgr;
2856         gchar *account_name;
2857         gchar *recipients;
2858
2859         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), TRUE);
2860
2861         /* Check whether to automatically add new contacts to addressbook or not */
2862         add_to_contacts = modest_conf_get_bool (modest_runtime_get_conf (),
2863                                                 MODEST_CONF_AUTO_ADD_TO_CONTACTS, NULL);
2864         if (!modest_msg_edit_window_check_names (edit_window, add_to_contacts))
2865                 return TRUE;
2866
2867         data = modest_msg_edit_window_get_msg_data (edit_window);
2868
2869         recipients = g_strconcat (data->to?data->to:"", 
2870                                   data->cc?data->cc:"",
2871                                   data->bcc?data->bcc:"",
2872                                   NULL);
2873         if (recipients == NULL || recipients[0] == '\0') {
2874                 /* Empty subject -> no send */
2875                 g_free (recipients);
2876                 modest_msg_edit_window_free_msg_data (edit_window, data);
2877                 return FALSE;
2878         }
2879         g_free (recipients);
2880
2881         /* Check size */
2882         if (!enough_space_for_message (edit_window, data)) {
2883                 modest_msg_edit_window_free_msg_data (edit_window, data);
2884                 return FALSE;
2885         }
2886
2887         account_mgr = modest_runtime_get_account_mgr();
2888         account_name = g_strdup (data->account_name);
2889         if (!account_name)
2890                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2891
2892         if (!account_name)
2893                 account_name = modest_account_mgr_get_default_account (account_mgr);
2894
2895         if (!account_name) {
2896                 modest_msg_edit_window_free_msg_data (edit_window, data);
2897                 /* Run account setup wizard */
2898                 if (!modest_ui_actions_run_account_setup_wizard (MODEST_WINDOW(edit_window))) {
2899                         return TRUE;
2900                 }
2901         }
2902
2903         /* Get the currently-active transport account for this modest account: */
2904         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2905                 transport_account =
2906                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2907                                               (modest_runtime_get_account_store (),
2908                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2909         }
2910
2911         if (!transport_account) {
2912                 modest_msg_edit_window_free_msg_data (edit_window, data);
2913                 /* Run account setup wizard */
2914                 if (!modest_ui_actions_run_account_setup_wizard(MODEST_WINDOW(edit_window)))
2915                         return TRUE;
2916         }
2917
2918         result = modest_ui_actions_send_msg_with_transport (transport_account,
2919                                                             data->draft_msg,
2920                                                             data->from,
2921                                                             data->to,
2922                                                             data->cc,
2923                                                             data->bcc,
2924                                                             data->subject,
2925                                                             data->plain_body,
2926                                                             data->html_body,
2927                                                             data->attachments,
2928                                                             data->images,
2929                                                             data->references,
2930                                                             data->in_reply_to,
2931                                                             data->priority_flags,
2932                                                             data->custom_header_pairs);
2933
2934
2935         /* Free data: */
2936         g_free (account_name);
2937         g_object_unref (G_OBJECT (transport_account));
2938
2939         modest_msg_edit_window_free_msg_data (edit_window, data);
2940
2941         if (result) {
2942                 modest_msg_edit_window_set_sent (edit_window, TRUE);
2943
2944                 /* Save settings and close the window: */
2945                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2946         }
2947
2948         return result;
2949 }
2950
2951 /* For instance, when clicking the Send toolbar button when editing a message: */
2952 gboolean
2953 modest_ui_actions_on_send_custom_msg (const gchar *account_name, 
2954                                       const gchar *from, const gchar *to, const gchar *cc, const gchar *bcc,
2955                                       const gchar *subject,
2956                                       const gchar *plain_body, const gchar *html_body,
2957                                       const GList *attachments_list, const GList *images_list,
2958                                       const gchar *references, const gchar *in_reply_to,
2959                                       TnyHeaderFlags priority_flags, TnyList *header_pairs)
2960 {
2961         TnyTransportAccount *transport_account = NULL;
2962         gboolean result = FALSE;
2963
2964         g_return_val_if_fail (account_name, FALSE);
2965
2966         transport_account =
2967           TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2968                                 (modest_runtime_get_account_store (),
2969                                  account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2970
2971         g_return_val_if_fail (transport_account, FALSE);
2972
2973         result = modest_ui_actions_send_msg_with_transport (transport_account,
2974                                                             NULL /*draft msg*/,
2975                                                             from, to, cc, bcc,
2976                                                             subject,
2977                                                             plain_body, html_body,
2978                                                             attachments_list, images_list,
2979                                                             references, in_reply_to,
2980                                                             priority_flags, header_pairs);
2981
2982         /* Free data: */
2983         g_object_unref (G_OBJECT (transport_account));
2984
2985         return result;
2986 }
2987
2988 gboolean
2989 modest_ui_actions_send_msg_with_transport (TnyTransportAccount *transport_account, 
2990                                            TnyMsg *draft_msg,
2991                                            const gchar *from, const gchar *to, const gchar *cc, const gchar *bcc,
2992                                            const gchar *subject,
2993                                            const gchar *plain_body, const gchar *html_body,
2994                                            const GList *attachments_list, const GList *images_list,
2995                                            const gchar *references, const gchar *in_reply_to,
2996                                            TnyHeaderFlags priority_flags, TnyList *header_pairs)
2997 {
2998         gboolean had_error = FALSE;
2999         ModestMailOperation *mail_operation;
3000
3001         g_return_val_if_fail (transport_account, FALSE);
3002
3003         /* Create the mail operation */
3004         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
3005         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
3006
3007         modest_mail_operation_send_new_mail (mail_operation,
3008                                              transport_account,
3009                                              draft_msg,
3010                                              from,
3011                                              to,
3012                                              cc,
3013                                              bcc,
3014                                              subject,
3015                                              plain_body,
3016                                              html_body,
3017                                              attachments_list,
3018                                              images_list,
3019                                              references,
3020                                              in_reply_to,
3021                                              priority_flags,
3022                                              header_pairs);
3023
3024         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3025                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
3026
3027         if (modest_mail_operation_get_error (mail_operation) != NULL) {
3028                 const GError *error = modest_mail_operation_get_error (mail_operation);
3029                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3030                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
3031                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
3032                         modest_platform_information_banner (NULL, NULL, _CS_NOT_ENOUGH_MEMORY);
3033                         had_error = TRUE;
3034                 }
3035         }
3036
3037         /* Free data: */
3038         g_object_unref (G_OBJECT (mail_operation));
3039
3040         return !had_error;
3041 }
3042
3043 gboolean
3044 modest_ui_actions_on_send_msg (ModestWindow *window,
3045                                TnyMsg *msg)
3046 {
3047         TnyTransportAccount *transport_account = NULL;
3048         gboolean had_error = FALSE;
3049         ModestAccountMgr *account_mgr;
3050         gchar *account_name;
3051         ModestMailOperation *mail_operation;
3052
3053         account_mgr = modest_runtime_get_account_mgr();
3054         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(window)));
3055
3056         if (!account_name)
3057                 account_name = modest_account_mgr_get_default_account (account_mgr);
3058
3059         /* Get the currently-active transport account for this modest account: */
3060         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
3061                 transport_account =
3062                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
3063                                               (modest_runtime_get_account_store (),
3064                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
3065         }
3066
3067         /* Create the mail operation */
3068         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
3069         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
3070
3071         modest_mail_operation_send_mail (mail_operation,
3072                                          transport_account,
3073                                          msg);
3074
3075         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3076                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
3077
3078         if (modest_mail_operation_get_error (mail_operation) != NULL) {
3079                 const GError *error = modest_mail_operation_get_error (mail_operation);
3080                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3081                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
3082                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
3083                         modest_platform_information_banner (NULL, NULL, _CS("sfil_ni_not_enough_memory"));
3084                         had_error = TRUE;
3085                 }
3086         }
3087
3088         /* Free data: */
3089         g_free (account_name);
3090         g_object_unref (G_OBJECT (transport_account));
3091         g_object_unref (G_OBJECT (mail_operation));
3092
3093         return !had_error;
3094 }
3095
3096 void
3097 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
3098                                   ModestMsgEditWindow *window)
3099 {
3100         ModestMsgEditFormatState *format_state = NULL;
3101
3102         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3103         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3104
3105         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3106                 return;
3107
3108         format_state = modest_msg_edit_window_get_format_state (window);
3109         g_return_if_fail (format_state != NULL);
3110
3111         format_state->bold = gtk_toggle_action_get_active (action);
3112         modest_msg_edit_window_set_format_state (window, format_state);
3113         g_free (format_state);
3114
3115 }
3116
3117 void
3118 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
3119                                      ModestMsgEditWindow *window)
3120 {
3121         ModestMsgEditFormatState *format_state = NULL;
3122
3123         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3124         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3125
3126         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3127                 return;
3128
3129         format_state = modest_msg_edit_window_get_format_state (window);
3130         g_return_if_fail (format_state != NULL);
3131
3132         format_state->italics = gtk_toggle_action_get_active (action);
3133         modest_msg_edit_window_set_format_state (window, format_state);
3134         g_free (format_state);
3135
3136 }
3137
3138 void
3139 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
3140                                      ModestMsgEditWindow *window)
3141 {
3142         ModestMsgEditFormatState *format_state = NULL;
3143
3144         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3145         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3146
3147         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3148                 return;
3149
3150         format_state = modest_msg_edit_window_get_format_state (window);
3151         g_return_if_fail (format_state != NULL);
3152
3153         format_state->bullet = gtk_toggle_action_get_active (action);
3154         modest_msg_edit_window_set_format_state (window, format_state);
3155         g_free (format_state);
3156
3157 }
3158
3159 void
3160 modest_ui_actions_on_change_justify (GtkRadioAction *action,
3161                                      GtkRadioAction *selected,
3162                                      ModestMsgEditWindow *window)
3163 {
3164         ModestMsgEditFormatState *format_state = NULL;
3165         GtkJustification value;
3166
3167         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3168
3169         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3170                 return;
3171
3172         value = gtk_radio_action_get_current_value (selected);
3173
3174         format_state = modest_msg_edit_window_get_format_state (window);
3175         g_return_if_fail (format_state != NULL);
3176
3177         format_state->justification = value;
3178         modest_msg_edit_window_set_format_state (window, format_state);
3179         g_free (format_state);
3180 }
3181
3182 void
3183 modest_ui_actions_on_select_editor_color (GtkAction *action,
3184                                           ModestMsgEditWindow *window)
3185 {
3186         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3187         g_return_if_fail (GTK_IS_ACTION (action));
3188
3189         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3190                 return;
3191
3192         modest_msg_edit_window_select_color (window);
3193 }
3194
3195 void
3196 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
3197                                                      ModestMsgEditWindow *window)
3198 {
3199         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3200         g_return_if_fail (GTK_IS_ACTION (action));
3201
3202         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3203                 return;
3204
3205 }
3206
3207 void
3208 modest_ui_actions_on_insert_image (GObject *object,
3209                                    ModestMsgEditWindow *window)
3210 {
3211         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3212
3213
3214         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3215                 return;
3216
3217         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3218                 return;
3219
3220         modest_msg_edit_window_insert_image (window);
3221 }
3222
3223 void
3224 modest_ui_actions_on_attach_file (GtkAction *action,
3225                                   ModestMsgEditWindow *window)
3226 {
3227         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3228         g_return_if_fail (GTK_IS_ACTION (action));
3229
3230         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3231                 return;
3232
3233         modest_msg_edit_window_offer_attach_file (window);
3234 }
3235
3236 void
3237 modest_ui_actions_on_remove_attachments (GtkAction *action,
3238                                          ModestMsgEditWindow *window)