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