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