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