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