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