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