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