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