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