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