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