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