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