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