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