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