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