6890a4e172a80f3a1d7db574e0e94ed3767ea81a
[modest] / src / modest-ui-actions.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved. 
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29  
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <glib/gprintf.h>
36 #include <string.h>
37 #include <modest-runtime.h>
38 #include <modest-tny-folder.h>
39 #include <modest-tny-msg.h>
40 #include <modest-tny-account.h>
41 #include <modest-address-book.h>
42 #include "modest-error.h"
43 #include "modest-ui-actions.h"
44 #include "modest-tny-platform-factory.h"
45 #include "modest-platform.h"
46 #include "modest-debug.h"
47 #include <tny-mime-part.h>
48 #include <tny-camel-folder.h>
49 #include <tny-camel-imap-folder.h>
50 #include <tny-camel-pop-folder.h>
51
52 #ifdef MODEST_PLATFORM_MAEMO
53 #include "maemo/modest-osso-state-saving.h"
54 #include "maemo/modest-hildon-includes.h"
55 #include "maemo/modest-connection-specific-smtp-window.h"
56 #endif /* MODEST_PLATFORM_MAEMO */
57 #include <modest-utils.h>
58
59 #include "widgets/modest-ui-constants.h"
60 #include <widgets/modest-main-window.h>
61 #include <widgets/modest-msg-view-window.h>
62 #include <widgets/modest-account-view-window.h>
63 #include <widgets/modest-details-dialog.h>
64 #include <widgets/modest-attachments-view.h>
65 #include "widgets/modest-folder-view.h"
66 #include "widgets/modest-global-settings-dialog.h"
67 #include "modest-account-mgr-helpers.h"
68 #include "modest-mail-operation.h"
69 #include "modest-text-utils.h"
70
71 #ifdef MODEST_HAVE_EASYSETUP
72 #include "easysetup/modest-easysetup-wizard-dialog.h"
73 #endif /* MODEST_HAVE_EASYSETUP */
74
75 #include <modest-widget-memory.h>
76 #include <tny-error.h>
77 #include <tny-simple-list.h>
78 #include <tny-msg-view.h>
79 #include <tny-device.h>
80 #include <tny-merge-folder.h>
81
82 #include <gtkhtml/gtkhtml.h>
83
84 #define MIN_FREE_SPACE 5 * 1024 * 1024
85
86 typedef struct _GetMsgAsyncHelper {     
87         ModestWindow *window;
88         ModestMailOperation *mail_op;
89         TnyIterator *iter;
90         guint num_ops;
91         GFunc func;     
92         gpointer user_data;
93 } GetMsgAsyncHelper;
94
95 typedef enum _ReplyForwardAction {
96         ACTION_REPLY,
97         ACTION_REPLY_TO_ALL,
98         ACTION_FORWARD
99 } ReplyForwardAction;
100
101 typedef struct _ReplyForwardHelper {
102         guint reply_forward_type;
103         ReplyForwardAction action;
104         gchar *account_name;
105         GtkWidget *parent_window;
106         TnyHeader *header;
107 } ReplyForwardHelper;
108
109 typedef struct _MoveToHelper {
110         GtkTreeRowReference *reference;
111         GtkWidget *banner;
112 } MoveToHelper;
113
114 typedef struct _PasteAsAttachmentHelper {
115         ModestMsgEditWindow *window;
116         GtkWidget *banner;
117 } PasteAsAttachmentHelper;
118
119
120 /*
121  * The do_headers_action uses this kind of functions to perform some
122  * action to each member of a list of headers
123  */
124 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
125
126 static void     do_headers_action     (ModestWindow *win, 
127                                        HeadersFunc func,
128                                        gpointer user_data);
129
130 static void     open_msg_cb            (ModestMailOperation *mail_op, 
131                                         TnyHeader *header, 
132                                         gboolean canceled,
133                                         TnyMsg *msg,
134                                         GError *err,
135                                         gpointer user_data);
136
137 static void     reply_forward_cb       (ModestMailOperation *mail_op, 
138                                         TnyHeader *header, 
139                                         gboolean canceled,
140                                         TnyMsg *msg,
141                                         GError *err,
142                                         gpointer user_data);
143
144 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
145
146 static void     folder_refreshed_cb    (ModestMailOperation *mail_op, 
147                                         TnyFolder *folder, 
148                                         gpointer user_data);
149
150 static void     on_send_receive_finished (ModestMailOperation  *mail_op, 
151                                           gpointer user_data);
152
153 static gint header_list_count_uncached_msgs (TnyList *header_list);
154
155 static gboolean connect_to_get_msg (ModestWindow *win,
156                                     gint num_of_uncached_msgs,
157                                     TnyAccount *account);
158
159 static gboolean remote_folder_has_leave_on_server (TnyFolderStore *folder);
160
161 static void     do_create_folder (GtkWindow *window, 
162                                   TnyFolderStore *parent_folder, 
163                                   const gchar *suggested_name);
164
165 static GtkWidget* get_folder_view_from_move_to_dialog (GtkWidget *move_to_dialog);
166
167 static TnyAccount *get_account_from_folder_store (TnyFolderStore *folder_store);
168
169 /*
170  * This function checks whether a TnyFolderStore is a pop account
171  */
172 static gboolean
173 remote_folder_has_leave_on_server (TnyFolderStore *folder)
174 {
175         TnyAccount *account;
176         gboolean result;
177
178         g_return_val_if_fail (TNY_IS_FOLDER_STORE (folder), FALSE);
179         
180         account = get_account_from_folder_store (folder);
181         result = (modest_protocol_registry_protocol_type_has_leave_on_server (modest_runtime_get_protocol_registry (),
182                                                                               modest_tny_account_get_protocol_type (account)));
183         g_object_unref (account);
184
185         return result;
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--\n", signature, NULL) : g_strdup(body_str);
742         } else {
743                 body = use_signature ? g_strconcat("\n--\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
758         modest_window_mgr_register_window (modest_runtime_get_window_mgr(), msg_win);
759         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (msg_win), set_as_modified);
760         gtk_widget_show_all (GTK_WIDGET (msg_win));
761
762         while (attachments) {
763                 total_size +=
764                         modest_msg_edit_window_attach_file_one((ModestMsgEditWindow *)msg_win,
765                                                                attachments->data, allowed_size);
766
767                 if (total_size > allowed_size) {
768                         g_warning ("%s: total size: %u",
769                                    __FUNCTION__, (unsigned int)total_size);
770                         break;
771                 }
772                 allowed_size -= total_size;
773
774                 attachments = g_slist_next(attachments);
775         }
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         gchar *error_msg;
1169         ModestProtocolType proto;
1170         TnyList *not_opened_headers;
1171         TnyConnectionStatus status;
1172         gboolean show_open_draft = FALSE;
1173         OpenMsgHelper *helper = NULL;
1174
1175         helper = (OpenMsgHelper *) user_data;
1176         not_opened_headers = helper->headers;
1177
1178         status = tny_account_get_connection_status (account);
1179         if (err || canceled) {
1180                 /* Unregister the already registered headers */
1181                 tny_list_foreach (not_opened_headers, foreach_unregister_headers, 
1182                                   modest_runtime_get_window_mgr ());
1183                 /* Free the helper */
1184                 open_msgs_helper_destroyer (helper);
1185
1186                 /* In memory full conditions we could get this error here */
1187                 check_memory_full_error ((GtkWidget *) parent_window, err);
1188
1189                 goto clean;
1190         }
1191
1192         /* Get the error message depending on the protocol */
1193         proto = modest_tny_account_get_protocol_type (account);
1194         if (proto == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1195                 proto = MODEST_PROTOCOLS_STORE_MAILDIR;
1196         }
1197         
1198         /* Create the error messages */
1199         if (tny_list_get_length (not_opened_headers) == 1) {
1200                 ModestProtocol *protocol;
1201                 ModestProtocolRegistry *protocol_registry;
1202                 TnyIterator *iter;
1203                 TnyHeader *header;
1204                 gchar *subject;
1205
1206                 protocol_registry = modest_runtime_get_protocol_registry ();
1207                 iter = tny_list_create_iterator (not_opened_headers);
1208                 header = TNY_HEADER (tny_iterator_get_current (iter));
1209                 subject = tny_header_dup_subject (header);
1210
1211                 protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, proto);
1212                 error_msg = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE, subject);
1213                 g_free (subject);
1214                 g_object_unref (header);
1215                 g_object_unref (iter);
1216                 
1217                 if (error_msg == NULL) {
1218                         error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1219                 }
1220
1221                 if (modest_protocol_registry_protocol_type_has_tag (protocol_registry,
1222                                                                     proto,
1223                                                                     MODEST_PROTOCOL_REGISTRY_LOCAL_STORE_PROTOCOLS)) { 
1224                         TnyHeader *header;
1225                         TnyFolder *folder;
1226                         TnyIterator *iter;
1227                         TnyFolderType folder_type;
1228
1229                         iter = tny_list_create_iterator (not_opened_headers);
1230                         header = TNY_HEADER (tny_iterator_get_current (iter));
1231                         folder = tny_header_get_folder (header);
1232                         folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
1233                         show_open_draft = (folder_type == TNY_FOLDER_TYPE_DRAFTS);
1234                         g_object_unref (folder);
1235                         g_object_unref (header);
1236                         g_object_unref (iter);
1237                 }
1238         } else {
1239                 error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1240         }
1241
1242         /* Create the mail operation */
1243         mail_op = 
1244                 modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
1245                                                                modest_ui_actions_disk_operations_error_handler,
1246                                                                error_msg, g_free);
1247         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1248                                          mail_op);
1249
1250         if (show_open_draft) {
1251                 helper->banner_info = g_slice_new (OpenMsgBannerInfo);
1252                 helper->banner_info->message = g_strdup (_("mail_ib_opening_draft_message"));
1253                 helper->banner_info->banner = NULL;
1254                 helper->banner_info->idle_handler = g_timeout_add (500, open_msg_banner_idle, 
1255                                                                    helper->banner_info);
1256         }
1257
1258         modest_mail_operation_get_msgs_full (mail_op,
1259                                              not_opened_headers,
1260                                              open_msg_cb,
1261                                              helper,
1262                                              open_msgs_helper_destroyer);
1263
1264         /* Frees */
1265  clean:
1266         if (mail_op)
1267                 g_object_unref (mail_op);
1268         g_object_unref (account);
1269 }
1270
1271 /*
1272  * This function is used by both modest_ui_actions_on_open and
1273  * modest_ui_actions_on_header_activated. This way we always do the
1274  * same when trying to open messages.
1275  */
1276 static void
1277 open_msgs_from_headers (TnyList *headers, ModestWindow *win)
1278 {
1279         ModestWindowMgr *mgr = NULL;
1280         TnyIterator *iter = NULL, *iter_not_opened = NULL;
1281         TnyList *not_opened_headers = NULL;
1282         TnyHeaderFlags flags = 0;
1283         TnyAccount *account;
1284         gint uncached_msgs = 0;
1285         GtkWidget *header_view;
1286         GtkTreeModel *model;
1287         GHashTable *refs_for_headers;
1288         OpenMsgHelper *helper;
1289         GtkTreeSelection *sel;
1290         GList *sel_list = NULL, *sel_list_iter = NULL;
1291                 
1292         g_return_if_fail (headers != NULL);
1293
1294         /* Check that only one message is selected for opening */
1295         if (tny_list_get_length (headers) != 1) {
1296                 modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
1297                                                     NULL, _("mcen_ib_select_one_message"));
1298                 return;
1299         }
1300
1301         mgr = modest_runtime_get_window_mgr ();
1302         iter = tny_list_create_iterator (headers);
1303
1304         /* Get the account */
1305         account = get_account_from_header_list (headers);
1306
1307         if (!account)
1308                 return;
1309
1310         /* Get the selections, we need to get the references to the
1311            rows here because the treeview/model could dissapear (the
1312            user might want to select another folder)*/
1313         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
1314                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1315         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1316         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1317         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
1318         refs_for_headers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
1319                                                   (GDestroyNotify) gtk_tree_row_reference_free);
1320
1321         /* Look if we already have a message view for each header. If
1322            true, then remove the header from the list of headers to
1323            open */
1324         sel_list_iter = sel_list;
1325         not_opened_headers = tny_simple_list_new ();
1326         while (!tny_iterator_is_done (iter) && sel_list_iter) {
1327
1328                 ModestWindow *window = NULL;
1329                 TnyHeader *header = NULL;
1330                 gboolean found = FALSE;
1331                 
1332                 header = TNY_HEADER (tny_iterator_get_current (iter));
1333                 if (header)
1334                         flags = tny_header_get_flags (header);
1335
1336                 window = NULL;
1337                 found = modest_window_mgr_find_registered_header (mgr, header, &window);
1338                 
1339                 /* Do not open again the message and present the
1340                    window to the user */
1341                 if (found) {
1342                         if (window) {
1343                                 gtk_window_present (GTK_WINDOW (window));
1344                         } else {
1345                                 /* the header has been registered already, we don't do
1346                                  * anything but wait for the window to come up*/
1347                                 g_debug ("header %p already registered, waiting for window", header);
1348                         }
1349                 } else {
1350                         GtkTreeRowReference *row_reference;
1351
1352                         tny_list_append (not_opened_headers, G_OBJECT (header));
1353                         /* Create a new row reference and add it to the hash table */
1354                         row_reference = gtk_tree_row_reference_new (model, (GtkTreePath *) sel_list_iter->data);
1355                         g_hash_table_insert (refs_for_headers, header, row_reference);
1356                 }
1357
1358                 if (header)
1359                         g_object_unref (header);
1360
1361                 /* Go to next */
1362                 tny_iterator_next (iter);
1363                 sel_list_iter = g_list_next (sel_list_iter);
1364         }
1365         g_object_unref (iter);
1366         iter = NULL;
1367         g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
1368         g_list_free (sel_list);
1369
1370         /* Open each message */
1371         if (tny_list_get_length (not_opened_headers) == 0) {
1372                 g_hash_table_destroy (refs_for_headers);
1373                 goto cleanup;
1374         }
1375         
1376         /* If some messages would have to be downloaded, ask the user to 
1377          * make a connection. It's generally easier to do this here (in the mainloop) 
1378          * than later in a thread:
1379          */
1380         if (tny_list_get_length (not_opened_headers) > 0) {
1381                 uncached_msgs = header_list_count_uncached_msgs (not_opened_headers);
1382
1383                 if (uncached_msgs > 0) {
1384                         /* Allways download if we are online. */
1385                         if (!tny_device_is_online (modest_runtime_get_device ())) {
1386                                 gint response;
1387
1388                                 /* If ask for user permission to download the messages */
1389                                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1390                                                                                     ngettext("mcen_nc_get_msg",
1391                                                                                              "mcen_nc_get_msgs",
1392                                                                                              uncached_msgs));
1393
1394                                 /* End if the user does not want to continue */
1395                                 if (response == GTK_RESPONSE_CANCEL) {
1396                                         g_hash_table_destroy (refs_for_headers);
1397                                         goto cleanup;
1398                                 }
1399                         }
1400                 }
1401         }
1402
1403         /* Register the headers before actually creating the windows: */
1404         iter_not_opened = tny_list_create_iterator (not_opened_headers);
1405         while (!tny_iterator_is_done (iter_not_opened)) {
1406                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter_not_opened));
1407                 if (header) {
1408                         modest_window_mgr_register_header (mgr, header, NULL);
1409                         g_object_unref (header);
1410                 }
1411                 tny_iterator_next (iter_not_opened);
1412         }
1413         g_object_unref (iter_not_opened);
1414         iter_not_opened = NULL;
1415
1416         /* Create the helper. We need to get a reference to the model
1417            here because it could change while the message is readed
1418            (the user could switch between folders) */
1419         helper = g_slice_new (OpenMsgHelper);
1420         helper->model = g_object_ref (model);
1421         helper->headers = g_object_ref (not_opened_headers);
1422         helper->row_refs_per_header = refs_for_headers;
1423         helper->banner_info = NULL;
1424
1425         /* Connect to the account and perform */
1426         if (uncached_msgs > 0) {
1427                 modest_platform_connect_and_perform ((GtkWindow *) win, TRUE, g_object_ref (account), 
1428                                                      open_msgs_performer, helper);
1429         } else {
1430                 /* Call directly the performer, do not need to connect */
1431                 open_msgs_performer (FALSE, NULL, (GtkWindow *) win, 
1432                                      g_object_ref (account), helper);
1433         }
1434 cleanup:
1435         /* Clean */
1436         if (account)
1437                 g_object_unref (account);
1438         if (not_opened_headers)
1439                 g_object_unref (not_opened_headers);
1440 }
1441
1442 void
1443 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
1444 {
1445         TnyList *headers;
1446         
1447         /* we check for low-mem; in that case, show a warning, and don't allow
1448          * opening
1449          */
1450         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1451                 return;
1452
1453         /* Get headers */
1454         headers = get_selected_headers (win);
1455         if (!headers)
1456                 return;
1457
1458         /* Open them */
1459         open_msgs_from_headers (headers, win);
1460
1461         g_object_unref(headers);
1462 }
1463
1464 static ReplyForwardHelper*
1465 create_reply_forward_helper (ReplyForwardAction action, 
1466                              ModestWindow *win,
1467                              guint reply_forward_type,
1468                              TnyHeader *header)
1469 {
1470         ReplyForwardHelper *rf_helper = NULL;
1471         const gchar *active_acc = modest_window_get_active_account (win);
1472
1473         rf_helper = g_slice_new0 (ReplyForwardHelper);
1474         rf_helper->reply_forward_type = reply_forward_type;
1475         rf_helper->action = action;
1476         rf_helper->parent_window = (MODEST_IS_WINDOW (win)) ? GTK_WIDGET (win) : NULL;
1477         rf_helper->header = (header) ? g_object_ref (header) : NULL;
1478         rf_helper->account_name = (active_acc) ? 
1479                 g_strdup (active_acc) :
1480                 modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1481
1482         return rf_helper;
1483 }
1484
1485 static void
1486 free_reply_forward_helper (gpointer data)
1487 {
1488         ReplyForwardHelper *helper;
1489
1490         helper = (ReplyForwardHelper *) data;
1491         g_free (helper->account_name);
1492         if (helper->header)
1493                 g_object_unref (helper->header);
1494         g_slice_free (ReplyForwardHelper, helper);
1495 }
1496
1497 static void
1498 reply_forward_cb (ModestMailOperation *mail_op,  
1499                   TnyHeader *header, 
1500                   gboolean canceled,
1501                   TnyMsg *msg,
1502                   GError *err,
1503                   gpointer user_data)
1504 {
1505         TnyMsg *new_msg = NULL;
1506         ReplyForwardHelper *rf_helper;
1507         ModestWindow *msg_win = NULL;
1508         ModestEditType edit_type;
1509         gchar *from = NULL;
1510         TnyAccount *account = NULL;
1511         ModestWindowMgr *mgr = NULL;
1512         gchar *signature = NULL;
1513         gboolean use_signature;
1514
1515         /* If there was any error. The mail operation could be NULL,
1516            this means that we already have the message downloaded and
1517            that we didn't do a mail operation to retrieve it */
1518         rf_helper = (ReplyForwardHelper *) user_data;
1519         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1520                 goto cleanup;
1521
1522         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1523                                                    rf_helper->account_name);
1524         signature = modest_account_mgr_get_signature (modest_runtime_get_account_mgr(), 
1525                                                       rf_helper->account_name, 
1526                                                       &use_signature);
1527
1528         /* Create reply mail */
1529         switch (rf_helper->action) {
1530         case ACTION_REPLY:
1531                 new_msg = 
1532                         modest_tny_msg_create_reply_msg (msg, header, from, 
1533                                                          (use_signature) ? signature : NULL,
1534                                                          rf_helper->reply_forward_type,
1535                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1536                 break;
1537         case ACTION_REPLY_TO_ALL:
1538                 new_msg = 
1539                         modest_tny_msg_create_reply_msg (msg, header, from, 
1540                                                          (use_signature) ? signature : NULL, 
1541                                                          rf_helper->reply_forward_type,
1542                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1543                 edit_type = MODEST_EDIT_TYPE_REPLY;
1544                 break;
1545         case ACTION_FORWARD:
1546                 new_msg = 
1547                         modest_tny_msg_create_forward_msg (msg, from, (use_signature) ? signature : NULL, 
1548                                                            rf_helper->reply_forward_type);
1549                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1550                 break;
1551         default:
1552                 g_return_if_reached ();
1553                 return;
1554         }
1555
1556         g_free (from);
1557         g_free (signature);
1558
1559         if (!new_msg) {
1560                 g_warning ("%s: failed to create message\n", __FUNCTION__);
1561                 goto cleanup;
1562         }
1563
1564         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1565                                                                        rf_helper->account_name,
1566                                                                        TNY_ACCOUNT_TYPE_STORE);
1567         if (!account) {
1568                 g_warning ("%s: failed to get tnyaccount for '%s'\n", __FUNCTION__, rf_helper->account_name);
1569                 goto cleanup;
1570         }
1571
1572         /* Create and register the windows */
1573         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name, FALSE);
1574         mgr = modest_runtime_get_window_mgr ();
1575         modest_window_mgr_register_window (mgr, msg_win);
1576
1577         if (rf_helper->parent_window != NULL) {
1578                 gdouble parent_zoom;
1579
1580                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1581                 modest_window_set_zoom (msg_win, parent_zoom);
1582         }
1583
1584         /* Show edit window */
1585         gtk_widget_show_all (GTK_WIDGET (msg_win));
1586
1587 cleanup:
1588         if (new_msg)
1589                 g_object_unref (G_OBJECT (new_msg));
1590         if (account)
1591                 g_object_unref (G_OBJECT (account));
1592         free_reply_forward_helper (rf_helper);
1593 }
1594
1595 /* Checks a list of headers. If any of them are not currently
1596  * downloaded (CACHED) then returns TRUE else returns FALSE.
1597  */
1598 static gint
1599 header_list_count_uncached_msgs (TnyList *header_list)
1600 {
1601         TnyIterator *iter;
1602         gint uncached_messages = 0;
1603
1604         iter = tny_list_create_iterator (header_list);
1605         while (!tny_iterator_is_done (iter)) {
1606                 TnyHeader *header;
1607
1608                 header = TNY_HEADER (tny_iterator_get_current (iter));
1609                 if (header) {
1610                         if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
1611                                 uncached_messages ++;
1612                         g_object_unref (header);
1613                 }
1614
1615                 tny_iterator_next (iter);
1616         }
1617         g_object_unref (iter);
1618
1619         return uncached_messages;
1620 }
1621
1622 /* Returns FALSE if the user does not want to download the
1623  * messages. Returns TRUE if the user allowed the download.
1624  */
1625 static gboolean
1626 connect_to_get_msg (ModestWindow *win,
1627                     gint num_of_uncached_msgs,
1628                     TnyAccount *account)
1629 {
1630         GtkResponseType response;
1631
1632         /* Allways download if we are online. */
1633         if (tny_device_is_online (modest_runtime_get_device ()))
1634                 return TRUE;
1635
1636         /* If offline, then ask for user permission to download the messages */
1637         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1638                         ngettext("mcen_nc_get_msg",
1639                         "mcen_nc_get_msgs",
1640                         num_of_uncached_msgs));
1641
1642         if (response == GTK_RESPONSE_CANCEL)
1643                 return FALSE;
1644
1645         return modest_platform_connect_and_wait((GtkWindow *) win, account);
1646 }
1647
1648 static void
1649 reply_forward_performer (gboolean canceled, 
1650                          GError *err,
1651                          GtkWindow *parent_window, 
1652                          TnyAccount *account, 
1653                          gpointer user_data)
1654 {
1655         ReplyForwardHelper *rf_helper = NULL;
1656         ModestMailOperation *mail_op;
1657
1658         rf_helper = (ReplyForwardHelper *) user_data;
1659
1660         if (canceled || err) {
1661                 free_reply_forward_helper (rf_helper);
1662                 return;
1663         }
1664
1665         /* Retrieve the message */
1666         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (parent_window),
1667                                                                  modest_ui_actions_disk_operations_error_handler,
1668                                                                  NULL, NULL);
1669         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1670         modest_mail_operation_get_msg (mail_op, rf_helper->header, TRUE, reply_forward_cb, rf_helper);
1671
1672         /* Frees */
1673         g_object_unref(mail_op);
1674 }
1675
1676 /*
1677  * Common code for the reply and forward actions
1678  */
1679 static void
1680 reply_forward (ReplyForwardAction action, ModestWindow *win)
1681 {
1682         ReplyForwardHelper *rf_helper = NULL;
1683         guint reply_forward_type;
1684         
1685         g_return_if_fail (MODEST_IS_WINDOW(win));
1686                         
1687         /* we check for low-mem; in that case, show a warning, and don't allow
1688          * reply/forward (because it could potentially require a lot of memory */
1689         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1690                 return;
1691
1692
1693         /* we need an account when editing */
1694         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
1695                 if (!modest_ui_actions_run_account_setup_wizard (win))
1696                         return;
1697         }
1698         
1699         reply_forward_type =
1700                 modest_conf_get_int (modest_runtime_get_conf (),
1701                                      (action == ACTION_FORWARD) ? 
1702                                      MODEST_CONF_FORWARD_TYPE :
1703                                      MODEST_CONF_REPLY_TYPE,
1704                                      NULL);
1705
1706         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
1707                 TnyMsg *msg = NULL;
1708                 TnyHeader *header = NULL;
1709                 /* Get header and message. Do not free them here, the
1710                    reply_forward_cb must do it */
1711                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
1712                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
1713
1714                 if (msg && header) {
1715                         /* Create helper */
1716                         rf_helper = create_reply_forward_helper (action, win, 
1717                                                                  reply_forward_type, header);
1718                         reply_forward_cb (NULL, header, FALSE, msg, NULL, rf_helper);
1719                 } else {
1720                         g_warning("%s: no message or header found in viewer\n", __FUNCTION__);
1721                 }
1722                 
1723                 if (msg)
1724                         g_object_unref (msg);
1725                 if (header)
1726                         g_object_unref (header);
1727         } else {
1728                 TnyHeader *header = NULL;
1729                 TnyIterator *iter;
1730                 gboolean do_retrieve = TRUE;
1731                 TnyList *header_list = NULL;
1732
1733                 header_list = get_selected_headers (win);
1734                 if (!header_list)
1735                         return;
1736                 /* Check that only one message is selected for replying */
1737                 if (tny_list_get_length (header_list) != 1) {
1738                         modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
1739                                                             NULL, _("mcen_ib_select_one_message"));
1740                         g_object_unref (header_list);
1741                         return;
1742                 }
1743
1744                 /* Only reply/forward to one message */
1745                 iter = tny_list_create_iterator (header_list);
1746                 header = TNY_HEADER (tny_iterator_get_current (iter));
1747                 g_object_unref (iter);
1748
1749                 /* Retrieve messages */
1750                 do_retrieve = (action == ACTION_FORWARD) ||
1751                         (reply_forward_type != MODEST_TNY_MSG_REPLY_TYPE_CITE);
1752
1753                 if (do_retrieve) {
1754                         TnyAccount *account = NULL;
1755                         TnyFolder *folder = NULL;
1756                         gdouble download = TRUE;
1757                         guint uncached_msgs = 0;
1758
1759                         folder = tny_header_get_folder (header);
1760                         if (!folder)
1761                                 goto do_retrieve_frees;
1762                         account = tny_folder_get_account (folder);
1763                         if (!account)
1764                                 goto do_retrieve_frees;
1765
1766                         uncached_msgs = header_list_count_uncached_msgs (header_list);
1767
1768                         if (uncached_msgs > 0) {
1769                                 /* Allways download if we are online. */
1770                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1771                                         gint response;
1772                                         
1773                                         /* If ask for user permission to download the messages */
1774                                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1775                                                                                             ngettext("mcen_nc_get_msg",
1776                                                                                                      "mcen_nc_get_msgs",
1777                                                                                                      uncached_msgs));
1778                                         
1779                                         /* End if the user does not want to continue */
1780                                         if (response == GTK_RESPONSE_CANCEL)
1781                                                 download = FALSE;
1782                                 }
1783                         }
1784                         
1785                         if (download) {
1786                                 /* Create helper */
1787                                 rf_helper = create_reply_forward_helper (action, win, 
1788                                                                          reply_forward_type, header);
1789                                 if (uncached_msgs > 0) {
1790                                         modest_platform_connect_and_perform (GTK_WINDOW (win), 
1791                                                                              TRUE, account, 
1792                                                                              reply_forward_performer, 
1793                                                                              rf_helper);
1794                                 } else {
1795                                         reply_forward_performer (FALSE, NULL, GTK_WINDOW (win), 
1796                                                                  account, rf_helper);
1797                                 }
1798                         }
1799                 do_retrieve_frees:
1800                         if (account)
1801                                 g_object_unref (account);
1802                         if (folder)
1803                                 g_object_unref (folder);
1804                 } else {
1805                         reply_forward_cb (NULL, header, FALSE, NULL, NULL, rf_helper);
1806                 }
1807                 /* Frees */
1808                 g_object_unref (header_list);
1809                 g_object_unref (header);
1810         }
1811 }
1812
1813 void
1814 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
1815 {
1816         g_return_if_fail (MODEST_IS_WINDOW(win));
1817
1818         reply_forward (ACTION_REPLY, win);
1819 }
1820
1821 void
1822 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
1823 {
1824         g_return_if_fail (MODEST_IS_WINDOW(win));
1825
1826         reply_forward (ACTION_FORWARD, win);
1827 }
1828
1829 void
1830 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
1831 {
1832         g_return_if_fail (MODEST_IS_WINDOW(win));
1833
1834         reply_forward (ACTION_REPLY_TO_ALL, win);
1835 }
1836
1837 void 
1838 modest_ui_actions_on_next (GtkAction *action, 
1839                            ModestWindow *window)
1840 {
1841         if (MODEST_IS_MAIN_WINDOW (window)) {
1842                 GtkWidget *header_view;
1843
1844                 header_view = modest_main_window_get_child_widget (
1845                                 MODEST_MAIN_WINDOW(window),
1846                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1847                 if (!header_view)
1848                         return;
1849         
1850                 modest_header_view_select_next (
1851                                 MODEST_HEADER_VIEW(header_view)); 
1852         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1853                 modest_msg_view_window_select_next_message (
1854                                 MODEST_MSG_VIEW_WINDOW (window));
1855         } else {
1856                 g_return_if_reached ();
1857         }
1858 }
1859
1860 void 
1861 modest_ui_actions_on_prev (GtkAction *action, 
1862                            ModestWindow *window)
1863 {
1864         g_return_if_fail (MODEST_IS_WINDOW(window));
1865
1866         if (MODEST_IS_MAIN_WINDOW (window)) {
1867                 GtkWidget *header_view;
1868                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1869                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1870                 if (!header_view)
1871                         return;
1872                 
1873                 modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
1874         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1875                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
1876         } else {
1877                 g_return_if_reached ();
1878         }
1879 }
1880
1881 void 
1882 modest_ui_actions_on_sort (GtkAction *action, 
1883                            ModestWindow *window)
1884 {
1885         g_return_if_fail (MODEST_IS_WINDOW(window));
1886
1887         if (MODEST_IS_MAIN_WINDOW (window)) {
1888                 GtkWidget *header_view;
1889                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1890                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1891                 if (!header_view) {
1892                         modest_platform_information_banner (NULL, NULL, _CS("ckdg_ib_nothing_to_sort"));
1893
1894                         return;
1895                 }
1896
1897                 /* Show sorting dialog */
1898                 modest_utils_run_sort_dialog (GTK_WINDOW (window), MODEST_SORT_HEADERS);        
1899         }
1900 }
1901
1902 static void
1903 new_messages_arrived (ModestMailOperation *self, 
1904                       TnyList *new_headers,
1905                       gpointer user_data)
1906 {
1907         GObject *source;
1908         gboolean show_visual_notifications;
1909
1910         source = modest_mail_operation_get_source (self);
1911         show_visual_notifications = (source) ? FALSE : TRUE;
1912         if (source)
1913                 g_object_unref (source);
1914
1915         /* Notify new messages have been downloaded. If the
1916            send&receive was invoked by the user then do not show any
1917            visual notification, only play a sound and activate the LED
1918            (for the Maemo version) */
1919         if (TNY_IS_LIST(new_headers) && (tny_list_get_length (new_headers)) > 0)
1920                 modest_platform_on_new_headers_received (new_headers, 
1921                                                          show_visual_notifications);
1922
1923 }
1924
1925 gboolean
1926 retrieve_all_messages_cb (GObject *source,
1927                           guint num_msgs,
1928                           guint retrieve_limit)
1929 {
1930         GtkWindow *window;
1931         gchar *msg;
1932         gint response;
1933
1934         window = GTK_WINDOW (source);
1935         msg = g_strdup_printf (_("mail_nc_msg_count_limit_exceeded"), 
1936                                num_msgs, retrieve_limit);
1937
1938         /* Ask the user if they want to retrieve all the messages */
1939         response = 
1940                 modest_platform_run_confirmation_dialog_with_buttons (window, msg,
1941                                                                       _("mcen_bd_get_all"),
1942                                                                       _("mcen_bd_newest_only"));
1943         /* Free and return */
1944         g_free (msg);
1945         return (response == GTK_RESPONSE_ACCEPT) ? TRUE : FALSE;
1946 }
1947
1948 typedef struct {
1949         TnyAccount *account;
1950         ModestWindow *win;
1951         gchar *account_name;
1952         gboolean poke_status;
1953         gboolean interactive;
1954         ModestMailOperation *mail_op;
1955 } SendReceiveInfo;
1956
1957 static void
1958 do_send_receive_performer (gboolean canceled, 
1959                            GError *err,
1960                            GtkWindow *parent_window, 
1961                            TnyAccount *account, 
1962                            gpointer user_data)
1963 {
1964         SendReceiveInfo *info;
1965
1966         info = (SendReceiveInfo *) user_data;
1967
1968         if (err || canceled) {
1969                 /* In memory full conditions we could get this error here */
1970                 check_memory_full_error ((GtkWidget *) parent_window, err);
1971
1972                 if (info->mail_op) {
1973                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
1974                                                             info->mail_op);
1975                 }
1976                 goto clean;
1977         }
1978
1979         /* Set send/receive operation in progress */    
1980         if (info->win && MODEST_IS_MAIN_WINDOW (info->win)) {
1981                 modest_main_window_notify_send_receive_initied (MODEST_MAIN_WINDOW (info->win));
1982         }
1983
1984         if (info->win && MODEST_IS_MAIN_WINDOW (info->win))
1985                 g_signal_connect (G_OBJECT (info->mail_op), "operation-finished", 
1986                                   G_CALLBACK (on_send_receive_finished), 
1987                                   info->win);
1988
1989         /* Send & receive. */
1990         modest_mail_operation_update_account (info->mail_op, info->account_name, info->poke_status, info->interactive,
1991                                               (info->win) ? retrieve_all_messages_cb : NULL, 
1992                                               new_messages_arrived, info->win);
1993         
1994  clean:
1995         /* Frees */
1996         if (info->mail_op)
1997                 g_object_unref (G_OBJECT (info->mail_op));
1998         if (info->account_name)
1999                 g_free (info->account_name);
2000         if (info->win)
2001                 g_object_unref (info->win);
2002         if (info->account)
2003                 g_object_unref (info->account);
2004         g_slice_free (SendReceiveInfo, info);
2005 }
2006
2007 /*
2008  * This function performs the send & receive required actions. The
2009  * window is used to create the mail operation. Typically it should
2010  * always be the main window, but we pass it as argument in order to
2011  * be more flexible.
2012  */
2013 void
2014 modest_ui_actions_do_send_receive (const gchar *account_name, 
2015                                    gboolean force_connection,
2016                                    gboolean poke_status,
2017                                    gboolean interactive,
2018                                    ModestWindow *win)
2019 {
2020         gchar *acc_name = NULL;
2021         SendReceiveInfo *info;
2022         ModestTnyAccountStore *acc_store;
2023
2024         /* If no account name was provided then get the current account, and if
2025            there is no current account then pick the default one: */
2026         if (!account_name) {
2027                 if (win)
2028                         acc_name = g_strdup (modest_window_get_active_account (win));
2029                 if (!acc_name)
2030                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
2031                 if (!acc_name) {
2032                         g_printerr ("modest: cannot get default account\n");
2033                         return;
2034                 }
2035         } else {
2036                 acc_name = g_strdup (account_name);
2037         }
2038
2039         acc_store = modest_runtime_get_account_store ();
2040
2041         /* Create the info for the connect and perform */
2042         info = g_slice_new (SendReceiveInfo);
2043         info->account_name = acc_name;
2044         info->win = (win) ? g_object_ref (win) : NULL;
2045         info->poke_status = poke_status;
2046         info->interactive = interactive;
2047         info->account = modest_tny_account_store_get_server_account (acc_store, acc_name,
2048                                                                      TNY_ACCOUNT_TYPE_STORE);
2049         /* We need to create the operation here, because otherwise it
2050            could happen that the queue emits the queue-empty signal
2051            while we're trying to connect the account */
2052         info->mail_op = modest_mail_operation_new_with_error_handling ((info->win) ? G_OBJECT (info->win) : NULL,
2053                                                                        modest_ui_actions_disk_operations_error_handler,
2054                                                                        NULL, NULL);
2055         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), info->mail_op);
2056
2057         /* Invoke the connect and perform */
2058         modest_platform_connect_and_perform ((win) ? GTK_WINDOW (win) : NULL, 
2059                                              force_connection, info->account, 
2060                                              do_send_receive_performer, info);
2061 }
2062
2063
2064 static void
2065 modest_ui_actions_do_cancel_send (const gchar *account_name,  
2066                                   ModestWindow *win)
2067 {
2068         TnyTransportAccount *transport_account;
2069         TnySendQueue *send_queue = NULL;
2070         GError *error = NULL;
2071
2072         /* Get transport account */
2073         transport_account =
2074                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2075                                       (modest_runtime_get_account_store(),
2076                                        account_name,
2077                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2078         if (!transport_account) {
2079                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2080                 goto frees;
2081         }
2082
2083         /* Get send queue*/
2084         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
2085         if (!TNY_IS_SEND_QUEUE(send_queue)) {
2086                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
2087                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2088                              "modest: could not find send queue for account\n");
2089         } else {
2090                 /* Cancel the current send */
2091                 tny_account_cancel (TNY_ACCOUNT (transport_account));
2092
2093                 /* Suspend all pending messages */
2094                 tny_send_queue_cancel (send_queue, TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, &error);
2095         }
2096
2097  frees:
2098         if (transport_account != NULL) 
2099                 g_object_unref (G_OBJECT (transport_account));
2100 }
2101
2102 static void
2103 modest_ui_actions_cancel_send_all (ModestWindow *win) 
2104 {
2105         GSList *account_names, *iter;
2106
2107         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
2108                                                           TRUE);
2109
2110         iter = account_names;
2111         while (iter) {                  
2112                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
2113                 iter = g_slist_next (iter);
2114         }
2115
2116         modest_account_mgr_free_account_names (account_names);
2117         account_names = NULL;
2118 }
2119
2120 void
2121 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
2122
2123 {
2124         /* Check if accounts exist */
2125         gboolean accounts_exist = 
2126                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2127         
2128         /* If not, allow the user to create an account before trying to send/receive. */
2129         if (!accounts_exist)
2130                 modest_ui_actions_on_accounts (NULL, win);
2131         
2132         /* Cancel all sending operaitons */     
2133         modest_ui_actions_cancel_send_all (win);
2134 }
2135
2136 /*
2137  * Refreshes all accounts. This function will be used by automatic
2138  * updates
2139  */
2140 void
2141 modest_ui_actions_do_send_receive_all (ModestWindow *win, 
2142                                        gboolean force_connection,
2143                                        gboolean poke_status,
2144                                        gboolean interactive)
2145 {
2146         GSList *account_names, *iter;
2147
2148         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
2149                                                           TRUE);
2150
2151         iter = account_names;
2152         while (iter) {                  
2153                 modest_ui_actions_do_send_receive ((const char*) iter->data, 
2154                                                    force_connection, 
2155                                                    poke_status, interactive, win);
2156                 iter = g_slist_next (iter);
2157         }
2158
2159         modest_account_mgr_free_account_names (account_names);
2160         account_names = NULL;
2161 }
2162
2163 /*
2164  * Handler of the click on Send&Receive button in the main toolbar
2165  */
2166 void
2167 modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win)
2168 {
2169         /* Check if accounts exist */
2170         gboolean accounts_exist;
2171
2172         accounts_exist =
2173                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2174         
2175         /* If not, allow the user to create an account before trying to send/receive. */
2176         if (!accounts_exist)
2177                 modest_ui_actions_on_accounts (NULL, win);
2178         
2179         /* Refresh the current folder. The if is always TRUE it's just an extra check */
2180         if (MODEST_IS_MAIN_WINDOW (win)) {
2181                 GtkWidget *folder_view;
2182                 TnyFolderStore *folder_store;
2183
2184                 folder_view = 
2185                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win), 
2186                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2187                 if (!folder_view)
2188                         return;
2189                 
2190                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2191         
2192                 if (folder_store)
2193                         g_object_unref (folder_store);
2194         }       
2195         
2196         /* Refresh the active account. Force the connection if needed
2197            and poke the status of all folders */
2198         modest_ui_actions_do_send_receive (NULL, TRUE, TRUE, TRUE, win);
2199 }
2200
2201
2202 void
2203 modest_ui_actions_toggle_header_list_view (GtkAction *action, ModestMainWindow *main_window)
2204 {
2205         ModestConf *conf;
2206         GtkWidget *header_view;
2207         
2208         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2209
2210         header_view = modest_main_window_get_child_widget (main_window,
2211                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2212         if (!header_view)
2213                 return;
2214
2215         conf = modest_runtime_get_conf ();
2216         
2217         /* what is saved/restored is depending on the style; thus; we save with
2218          * old style, then update the style, and restore for this new style
2219          */
2220         modest_widget_memory_save (conf, G_OBJECT(header_view), MODEST_CONF_HEADER_VIEW_KEY);
2221         
2222         if (modest_header_view_get_style
2223             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
2224                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2225                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
2226         else
2227                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2228                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
2229
2230         modest_widget_memory_restore (conf, G_OBJECT(header_view),
2231                                       MODEST_CONF_HEADER_VIEW_KEY);
2232 }
2233
2234
2235 void 
2236 modest_ui_actions_on_header_selected (ModestHeaderView *header_view, 
2237                                       TnyHeader *header,
2238                                       ModestMainWindow *main_window)
2239 {
2240         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2241         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2242         
2243         /* in the case the folder is empty, show the empty folder message and focus
2244          * folder view */
2245         if (!header && gtk_widget_is_focus (GTK_WIDGET (header_view))) {
2246                 if (modest_header_view_is_empty (header_view)) {
2247                         TnyFolder *folder = modest_header_view_get_folder (header_view);
2248                         GtkWidget *folder_view = 
2249                                 modest_main_window_get_child_widget (main_window,
2250                                                                      MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2251                         if (folder != NULL) {
2252                                 modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), folder, FALSE);
2253                                 g_object_unref (folder);
2254                         }
2255                         gtk_widget_grab_focus (GTK_WIDGET (folder_view));
2256                         return;
2257                 }
2258         }
2259         /* If no header has been selected then exit */
2260         if (!header)
2261                 return;
2262
2263         /* Update focus */
2264         if (!gtk_widget_is_focus (GTK_WIDGET(header_view)))
2265             gtk_widget_grab_focus (GTK_WIDGET(header_view));
2266
2267         /* Update toolbar dimming state */
2268         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2269         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2270 }
2271
2272 void
2273 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
2274                                        TnyHeader *header,
2275                                        ModestMainWindow *main_window)
2276 {
2277         TnyList *headers;
2278         GtkWidget *open_widget;
2279
2280         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2281
2282         if (!header)
2283                 return;
2284
2285         if (modest_header_view_count_selected_headers (header_view) > 1) {
2286                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
2287                 return;
2288         }
2289
2290         /* we check for low-mem; in that case, show a warning, and don't allow
2291          * activating headers
2292          */
2293         if (modest_platform_check_memory_low (MODEST_WINDOW(main_window), TRUE))
2294                 return;
2295
2296         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2297         open_widget = modest_window_get_action_widget (MODEST_WINDOW (main_window), "/MenuBar/EmailMenu/EmailOpenMenu");
2298         if (!GTK_WIDGET_IS_SENSITIVE (open_widget))
2299                 return;
2300
2301         headers = modest_header_view_get_selected_headers (header_view);
2302
2303         open_msgs_from_headers (headers, MODEST_WINDOW (main_window));
2304
2305         g_object_unref (headers);
2306 }
2307
2308 static void
2309 set_active_account_from_tny_account (TnyAccount *account,
2310                                      ModestWindow *window)
2311 {
2312         const gchar *server_acc_name = tny_account_get_id (account);
2313         
2314         /* We need the TnyAccount provided by the
2315            account store because that is the one that
2316            knows the name of the Modest account */
2317         TnyAccount *modest_server_account = modest_server_account = 
2318                 modest_tny_account_store_get_tny_account_by (modest_runtime_get_account_store (),
2319                                                              MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
2320                                                              server_acc_name);
2321         if (!modest_server_account) {
2322                 g_warning ("%s: could not get tny account\n", __FUNCTION__);
2323                 return;
2324         }
2325
2326         /* Update active account, but only if it's not a pseudo-account */
2327         if ((!modest_tny_account_is_virtual_local_folders(modest_server_account)) &&
2328             (!modest_tny_account_is_memory_card_account(modest_server_account))) {
2329                 const gchar *modest_acc_name = 
2330                         modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
2331                 if (modest_acc_name)
2332                         modest_window_set_active_account (window, modest_acc_name);
2333         }
2334         
2335         g_object_unref (modest_server_account);
2336 }
2337
2338
2339 static void
2340 folder_refreshed_cb (ModestMailOperation *mail_op, 
2341                      TnyFolder *folder, 
2342                      gpointer user_data)
2343 {
2344         ModestMainWindow *win = NULL;
2345         GtkWidget *folder_view;
2346         const GError *error;
2347
2348         g_return_if_fail (TNY_IS_FOLDER (folder));
2349
2350         win = MODEST_MAIN_WINDOW (user_data);
2351
2352         /* Check if the operation failed due to memory low conditions */
2353         error = modest_mail_operation_get_error (mail_op);
2354         if (error && error->domain == MODEST_MAIL_OPERATION_ERROR && 
2355             error->code == MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY) {
2356                 modest_platform_run_information_dialog (GTK_WINDOW (win),
2357                                                         dgettext("ke-recv","memr_ib_operation_disabled"),
2358                                                         TRUE);
2359                 return;
2360         }
2361
2362         folder_view = 
2363                 modest_main_window_get_child_widget(win, MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2364
2365         if (folder_view) {
2366                 TnyFolderStore *current_folder;
2367
2368                 current_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2369                 if (current_folder) {
2370                         gboolean different = ((TnyFolderStore *) folder != current_folder);
2371                         g_object_unref (current_folder);
2372                         if (different)
2373                                 return;
2374                 }
2375         }
2376
2377         /* Check if folder is empty and set headers view contents style */
2378         if (tny_folder_get_all_count (folder) == 0)
2379                 modest_main_window_set_contents_style (win,
2380                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2381
2382 }
2383
2384 void 
2385 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
2386                                                TnyFolderStore *folder_store, 
2387                                                gboolean selected,
2388                                                ModestMainWindow *main_window)
2389 {
2390         ModestConf *conf;
2391         GtkWidget *header_view;
2392
2393         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2394
2395         header_view = modest_main_window_get_child_widget(main_window,
2396                                                           MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2397         if (!header_view)
2398                 return;
2399         
2400         conf = modest_runtime_get_conf ();
2401
2402         if (TNY_IS_ACCOUNT (folder_store)) {
2403                 if (selected) {
2404                         set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
2405                         
2406                         /* Show account details */
2407                         modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
2408                 }
2409         } else {
2410                 if (TNY_IS_FOLDER (folder_store) && selected) {
2411                         TnyAccount *account;
2412                         const gchar *account_name = NULL;
2413
2414                         /* Update the active account */
2415                         account = modest_tny_folder_get_account (TNY_FOLDER (folder_store));
2416                         if (account) {
2417                                 set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
2418                                 account_name = 
2419                                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2420                                 g_object_unref (account);
2421                                 account = NULL;
2422                         }
2423
2424                         /* Set the header style by default, it could
2425                            be changed later by the refresh callback to
2426                            empty */
2427                         modest_main_window_set_contents_style (main_window, 
2428                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2429
2430                         /* Set folder on header view. This function
2431                            will call tny_folder_refresh_async so we
2432                            pass a callback that will be called when
2433                            finished. We use that callback to set the
2434                            empty view if there are no messages */
2435                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
2436                                                        TNY_FOLDER (folder_store),
2437                                                        TRUE,
2438                                                        folder_refreshed_cb,
2439                                                        main_window);
2440                         
2441                         /* Restore configuration. We need to do this
2442                            *after* the set_folder because the widget
2443                            memory asks the header view about its
2444                            folder  */
2445                         modest_widget_memory_restore (modest_runtime_get_conf (), 
2446                                                       G_OBJECT(header_view),
2447                                                       MODEST_CONF_HEADER_VIEW_KEY);
2448                 } else {
2449                         /* No need to save the header view
2450                            configuration for Maemo because it only
2451                            saves the sorting stuff and that it's
2452                            already being done by the sort
2453                            dialog. Remove it when the GNOME version
2454                            has the same behaviour */
2455 #ifdef MODEST_PLATFORM_GNOME
2456                         if (modest_main_window_get_contents_style (main_window) ==
2457                             MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
2458                                 modest_widget_memory_save (conf, G_OBJECT (header_view), 
2459                                                            MODEST_CONF_HEADER_VIEW_KEY);
2460 #endif
2461                         modest_header_view_clear (MODEST_HEADER_VIEW(header_view));
2462                 }
2463         }
2464
2465         /* Update dimming state */
2466         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2467         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2468 }
2469
2470 void 
2471 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
2472                                      ModestWindow *win)
2473 {
2474         GtkWidget *dialog;
2475         gchar *txt, *item;
2476         gboolean online;
2477
2478         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
2479         
2480         online = tny_device_is_online (modest_runtime_get_device());
2481
2482         if (online) {
2483                 /* already online -- the item is simply not there... */
2484                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
2485                                                  GTK_DIALOG_MODAL,
2486                                                  GTK_MESSAGE_WARNING,
2487                                                  GTK_BUTTONS_NONE,
2488                                                  _("The %s you selected cannot be found"),
2489                                                  item);
2490                 gtk_dialog_add_button (GTK_DIALOG (dialog),_("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
2491                 gtk_dialog_run (GTK_DIALOG(dialog));
2492         } else {
2493                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
2494                                                       GTK_WINDOW (win),
2495                                                       GTK_DIALOG_MODAL,
2496                                                       _("mcen_bd_dialog_cancel"),
2497                                                       GTK_RESPONSE_REJECT,
2498                                                       _("mcen_bd_dialog_ok"),
2499                                                       GTK_RESPONSE_ACCEPT,
2500                                                       NULL);
2501                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
2502                                          "Do you want to get online?"), item);
2503                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
2504                                     gtk_label_new (txt), FALSE, FALSE, 0);
2505                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2506                 g_free (txt);
2507
2508                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
2509                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2510                         /* TODO: Comment about why is this commented out: */
2511                         /* modest_platform_connect_and_wait (); */
2512                 }
2513         }
2514         gtk_widget_destroy (dialog);
2515 }
2516
2517 void
2518 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
2519                                      ModestWindow *win)
2520 {
2521         /* g_message ("%s %s", __FUNCTION__, link); */
2522 }       
2523
2524
2525 void
2526 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
2527                                         ModestWindow *win)
2528 {
2529         modest_platform_activate_uri (link);
2530 }
2531
2532 void
2533 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
2534                                           ModestWindow *win)
2535 {
2536         modest_platform_show_uri_popup (link);
2537 }
2538
2539 void
2540 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
2541                                              ModestWindow *win)
2542 {               
2543         /* we check for low-mem; in that case, show a warning, and don't allow
2544          * viewing attachments
2545          */
2546         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2547                 return;
2548
2549         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
2550 }
2551
2552 void
2553 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
2554                                           const gchar *address,
2555                                           ModestWindow *win)
2556 {
2557         /* g_message ("%s %s", __FUNCTION__, address); */
2558 }
2559
2560 static void
2561 on_save_to_drafts_cb (ModestMailOperation *mail_op, 
2562                       TnyMsg *saved_draft,
2563                       gpointer user_data)
2564 {
2565         ModestMsgEditWindow *edit_window;
2566         ModestMainWindow *win;
2567
2568         /* FIXME. Make the header view sensitive again. This is a
2569          * temporary hack. See modest_ui_actions_on_save_to_drafts()
2570          * for details */
2571         win = MODEST_MAIN_WINDOW(modest_window_mgr_get_main_window(
2572                                          modest_runtime_get_window_mgr(), FALSE));
2573         if (win != NULL) {
2574                 GtkWidget *hdrview = modest_main_window_get_child_widget(
2575                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2576                 if (hdrview) gtk_widget_set_sensitive(hdrview, TRUE);
2577         }
2578
2579         edit_window = MODEST_MSG_EDIT_WINDOW (user_data);
2580
2581         /* Set draft is there was no error */
2582         if (!modest_mail_operation_get_error (mail_op))
2583                 modest_msg_edit_window_set_draft (edit_window, saved_draft);
2584
2585         g_object_unref(edit_window);
2586 }
2587
2588 static gboolean
2589 enough_space_for_message (ModestMsgEditWindow *edit_window,
2590                           MsgData *data)
2591 {
2592         TnyAccountStore *acc_store;
2593         guint64 available_disk, expected_size;
2594         gint parts_count;
2595         guint64 parts_size;
2596
2597         /* Check size */
2598         acc_store = TNY_ACCOUNT_STORE (modest_runtime_get_account_store());
2599         available_disk = modest_utils_get_available_space (NULL);
2600         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
2601         expected_size = modest_tny_msg_estimate_size (data->plain_body,
2602                                                       data->html_body,
2603                                                       parts_count,
2604                                                       parts_size);
2605
2606         /* Double check: memory full condition or message too big */
2607         if (available_disk < MIN_FREE_SPACE || 
2608             expected_size > available_disk) {
2609
2610                 modest_platform_information_banner (NULL, NULL, 
2611                                                     dgettext("ke-recv", 
2612                                                              "cerm_device_memory_full"));
2613                 return FALSE;
2614         }
2615
2616         /*
2617          * djcb: if we're in low-memory state, we only allow for
2618          * saving messages smaller than
2619          * MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h) this
2620          * should still allow for sending anything critical...
2621          */
2622         if ((expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) &&
2623             modest_platform_check_memory_low (MODEST_WINDOW(edit_window), TRUE))
2624                 return FALSE;
2625
2626         /*
2627          * djcb: we also make sure that the attachments are smaller than the max size
2628          * this is for the case where we'd try to forward a message with attachments 
2629          * bigger than our max allowed size, or sending an message from drafts which
2630          * somehow got past our checks when attaching.
2631          */
2632         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
2633                 modest_platform_run_information_dialog (
2634                         GTK_WINDOW(edit_window),
2635                         dgettext("ke-recv","memr_ib_operation_disabled"),
2636                         TRUE);
2637                 return FALSE;
2638         }
2639
2640         return TRUE;
2641 }
2642
2643 gboolean
2644 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2645 {
2646         TnyTransportAccount *transport_account;
2647         ModestMailOperation *mail_operation;
2648         MsgData *data;
2649         gchar *account_name, *from;
2650         ModestAccountMgr *account_mgr;
2651         gboolean had_error = FALSE;
2652         ModestMainWindow *win;
2653
2654         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), FALSE);
2655         
2656         data = modest_msg_edit_window_get_msg_data (edit_window);
2657
2658         /* Check size */
2659         if (!enough_space_for_message (edit_window, data)) {
2660                 modest_msg_edit_window_free_msg_data (edit_window, data);
2661                 return FALSE;
2662         }
2663
2664         account_name = g_strdup (data->account_name);
2665         account_mgr = modest_runtime_get_account_mgr();
2666         if (!account_name)
2667                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2668         if (!account_name) 
2669                 account_name = modest_account_mgr_get_default_account (account_mgr);
2670         if (!account_name) {
2671                 g_printerr ("modest: no account found\n");
2672                 modest_msg_edit_window_free_msg_data (edit_window, data);
2673                 return FALSE;
2674         }
2675
2676         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
2677                 account_name = g_strdup (data->account_name);
2678         }
2679
2680         transport_account =
2681                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2682                                       (modest_runtime_get_account_store (),
2683                                        account_name,
2684                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2685         if (!transport_account) {
2686                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2687                 g_free (account_name);
2688                 modest_msg_edit_window_free_msg_data (edit_window, data);
2689                 return FALSE;
2690         }
2691         from = modest_account_mgr_get_from_string (account_mgr, account_name);
2692
2693         /* Create the mail operation */         
2694         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler,
2695                                                                         NULL, NULL);
2696         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2697
2698         modest_mail_operation_save_to_drafts (mail_operation,
2699                                               transport_account,
2700                                               data->draft_msg,
2701                                               from,
2702                                               data->to, 
2703                                               data->cc, 
2704                                               data->bcc,
2705                                               data->subject, 
2706                                               data->plain_body, 
2707                                               data->html_body,
2708                                               data->attachments,
2709                                               data->images,
2710                                               data->priority_flags,
2711                                               on_save_to_drafts_cb,
2712                                               g_object_ref(edit_window));
2713
2714         /* Use the main window as the parent of the banner, if the
2715            main window does not exist it won't be shown, if the parent
2716            window exists then it's properly shown. We don't use the
2717            editor window because it could be closed (save to drafts
2718            could happen after closing the window */
2719         win = (ModestMainWindow *)
2720                 modest_window_mgr_get_main_window( modest_runtime_get_window_mgr(), FALSE);
2721         if (win) {
2722                 gchar *text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
2723                 modest_platform_information_banner (GTK_WIDGET (win), NULL, text);
2724                 g_free (text);
2725         }
2726         modest_msg_edit_window_set_modified (edit_window, FALSE);
2727
2728         /* Frees */
2729         g_free (from);
2730         g_free (account_name);
2731         g_object_unref (G_OBJECT (transport_account));
2732         g_object_unref (G_OBJECT (mail_operation));
2733
2734         modest_msg_edit_window_free_msg_data (edit_window, data);
2735
2736         /* ** FIXME **
2737          * If the drafts folder is selected then make the header view
2738          * insensitive while the message is being saved to drafts
2739          * (it'll be sensitive again in on_save_to_drafts_cb()). This
2740          * is not very clean but it avoids letting the drafts folder
2741          * in an inconsistent state: the user could edit the message
2742          * being saved and undesirable things would happen.
2743          * In the average case the user won't notice anything at
2744          * all. In the worst case (the user is editing a really big
2745          * file from Drafts) the header view will be insensitive
2746          * during the saving process (10 or 20 seconds, depending on
2747          * the message). Anyway this is just a quick workaround: once
2748          * we find a better solution it should be removed
2749          * See NB#65125 (commend #18) for details.
2750          */
2751         if (!had_error && win != NULL) {
2752                 ModestFolderView *view = MODEST_FOLDER_VIEW(modest_main_window_get_child_widget(
2753                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW));
2754                 if (view != NULL) {
2755                         TnyFolder *folder = TNY_FOLDER(modest_folder_view_get_selected(view));
2756                         if (folder) {
2757                                 if (modest_tny_folder_is_local_folder(folder)) {
2758                                         TnyFolderType folder_type;
2759                                         folder_type = modest_tny_folder_get_local_or_mmc_folder_type(folder);
2760                                         if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
2761                                                 GtkWidget *hdrview = modest_main_window_get_child_widget(
2762                                                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2763                                                 if (hdrview) gtk_widget_set_sensitive(hdrview, FALSE);
2764                                         }
2765                                 }
2766                         }
2767                         if (folder != NULL) g_object_unref(folder);
2768                 }
2769         }
2770
2771         return !had_error;
2772 }
2773
2774 /* For instance, when clicking the Send toolbar button when editing a message: */
2775 gboolean
2776 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2777 {
2778         TnyTransportAccount *transport_account = NULL;
2779         gboolean had_error = FALSE;
2780         MsgData *data;
2781         ModestAccountMgr *account_mgr;
2782         gchar *account_name;
2783         gchar *from;
2784         ModestMailOperation *mail_operation;
2785
2786         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), TRUE);
2787
2788         if (!modest_msg_edit_window_check_names (edit_window, TRUE))
2789                 return TRUE;
2790         
2791         data = modest_msg_edit_window_get_msg_data (edit_window);
2792
2793         /* Check size */
2794         if (!enough_space_for_message (edit_window, data)) {
2795                 modest_msg_edit_window_free_msg_data (edit_window, data);
2796                 return FALSE;
2797         }
2798
2799         account_mgr = modest_runtime_get_account_mgr();
2800         account_name = g_strdup (data->account_name);
2801         if (!account_name)
2802                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2803
2804         if (!account_name) 
2805                 account_name = modest_account_mgr_get_default_account (account_mgr);
2806                 
2807         if (!account_name) {
2808                 modest_msg_edit_window_free_msg_data (edit_window, data);
2809                 /* Run account setup wizard */
2810                 if (!modest_ui_actions_run_account_setup_wizard (MODEST_WINDOW(edit_window))) {
2811                         return TRUE;
2812                 }
2813         }
2814         
2815         /* Get the currently-active transport account for this modest account: */
2816         if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2817                 transport_account = 
2818                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2819                                               (modest_runtime_get_account_store (), 
2820                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2821         }
2822         
2823         if (!transport_account) {
2824                 modest_msg_edit_window_free_msg_data (edit_window, data);
2825                 /* Run account setup wizard */
2826                 if (!modest_ui_actions_run_account_setup_wizard(MODEST_WINDOW(edit_window)))
2827                         return TRUE;
2828         }
2829         
2830
2831         /* Create the mail operation */
2832         from = modest_account_mgr_get_from_string (account_mgr, account_name);
2833         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
2834         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2835
2836         modest_mail_operation_send_new_mail (mail_operation,
2837                                              transport_account,
2838                                              data->draft_msg,
2839                                              from,
2840                                              data->to,
2841                                              data->cc, 
2842                                              data->bcc,
2843                                              data->subject, 
2844                                              data->plain_body, 
2845                                              data->html_body,
2846                                              data->attachments,
2847                                              data->images,
2848                                              data->priority_flags);
2849
2850         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2851                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
2852
2853
2854         if (modest_mail_operation_get_error (mail_operation) != NULL) {
2855                 const GError *error = modest_mail_operation_get_error (mail_operation);
2856                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
2857                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
2858                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
2859                         modest_platform_information_banner (NULL, NULL, _CS("sfil_ni_not_enough_memory"));
2860                         had_error = TRUE;
2861                 }
2862         }
2863                                              
2864         /* Free data: */
2865         g_free (from);
2866         g_free (account_name);
2867         g_object_unref (G_OBJECT (transport_account));
2868         g_object_unref (G_OBJECT (mail_operation));
2869
2870         modest_msg_edit_window_free_msg_data (edit_window, data);
2871
2872         if (!had_error) {
2873                 modest_msg_edit_window_set_sent (edit_window, TRUE);
2874
2875                 /* Save settings and close the window: */
2876                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2877         }
2878
2879         return !had_error;
2880 }
2881
2882 void 
2883 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
2884                                   ModestMsgEditWindow *window)
2885 {
2886         ModestMsgEditFormatState *format_state = NULL;
2887
2888         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2889         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2890
2891         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2892                 return;
2893
2894         format_state = modest_msg_edit_window_get_format_state (window);
2895         g_return_if_fail (format_state != NULL);
2896
2897         format_state->bold = gtk_toggle_action_get_active (action);
2898         modest_msg_edit_window_set_format_state (window, format_state);
2899         g_free (format_state);
2900         
2901 }
2902
2903 void 
2904 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
2905                                      ModestMsgEditWindow *window)
2906 {
2907         ModestMsgEditFormatState *format_state = NULL;
2908
2909         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2910         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2911
2912         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2913                 return;
2914
2915         format_state = modest_msg_edit_window_get_format_state (window);
2916         g_return_if_fail (format_state != NULL);
2917
2918         format_state->italics = gtk_toggle_action_get_active (action);
2919         modest_msg_edit_window_set_format_state (window, format_state);
2920         g_free (format_state);
2921         
2922 }
2923
2924 void 
2925 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
2926                                      ModestMsgEditWindow *window)
2927 {
2928         ModestMsgEditFormatState *format_state = NULL;
2929
2930         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2931         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2932
2933         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2934                 return;
2935
2936         format_state = modest_msg_edit_window_get_format_state (window);
2937         g_return_if_fail (format_state != NULL);
2938
2939         format_state->bullet = gtk_toggle_action_get_active (action);
2940         modest_msg_edit_window_set_format_state (window, format_state);
2941         g_free (format_state);
2942         
2943 }
2944
2945 void 
2946 modest_ui_actions_on_change_justify (GtkRadioAction *action,
2947                                      GtkRadioAction *selected,
2948                                      ModestMsgEditWindow *window)
2949 {
2950         ModestMsgEditFormatState *format_state = NULL;
2951         GtkJustification value;
2952
2953         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2954
2955         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2956                 return;
2957
2958         value = gtk_radio_action_get_current_value (selected);
2959
2960         format_state = modest_msg_edit_window_get_format_state (window);
2961         g_return_if_fail (format_state != NULL);
2962
2963         format_state->justification = value;
2964         modest_msg_edit_window_set_format_state (window, format_state);
2965         g_free (format_state);
2966 }
2967
2968 void 
2969 modest_ui_actions_on_select_editor_color (GtkAction *action,
2970                                           ModestMsgEditWindow *window)
2971 {
2972         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2973         g_return_if_fail (GTK_IS_ACTION (action));
2974
2975         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2976                 return;
2977
2978         modest_msg_edit_window_select_color (window);
2979 }
2980
2981 void 
2982 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
2983                                                      ModestMsgEditWindow *window)
2984 {
2985         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2986         g_return_if_fail (GTK_IS_ACTION (action));
2987
2988         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2989                 return;
2990
2991         modest_msg_edit_window_select_background_color (window);
2992 }
2993
2994 void 
2995 modest_ui_actions_on_insert_image (GtkAction *action,
2996                                    ModestMsgEditWindow *window)
2997 {
2998         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2999         g_return_if_fail (GTK_IS_ACTION (action));
3000
3001
3002         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3003                 return;
3004
3005         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3006                 return;
3007
3008         modest_msg_edit_window_insert_image (window);
3009 }
3010
3011 void 
3012 modest_ui_actions_on_attach_file (GtkAction *action,
3013                                   ModestMsgEditWindow *window)
3014 {
3015         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3016         g_return_if_fail (GTK_IS_ACTION (action));
3017
3018         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3019                 return;
3020         
3021         modest_msg_edit_window_offer_attach_file (window);
3022 }
3023
3024 void 
3025 modest_ui_actions_on_remove_attachments (GtkAction *action,
3026                                          ModestMsgEditWindow *window)
3027 {
3028         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3029         g_return_if_fail (GTK_IS_ACTION (action));
3030
3031         modest_msg_edit_window_remove_attachments (window, NULL);
3032 }
3033
3034
3035 #ifdef MODEST_PLATFORM_MAEMO
3036 typedef struct {
3037         guint handler;
3038         gchar *name;
3039         GtkWindow *win;
3040         TnyFolderStore *folder;
3041 } CreateFolderHelper;
3042
3043 static gboolean
3044 show_create_folder_in_timeout (gpointer data)
3045 {
3046         CreateFolderHelper *helper = (CreateFolderHelper *) data;
3047
3048         /* Remove the timeout ASAP, we can not wait until the dialog
3049            is shown because it could take a lot of time and so the
3050            timeout could be called twice or more times */
3051         g_source_remove (helper->handler);
3052
3053         gdk_threads_enter ();
3054         do_create_folder (helper->win, helper->folder, helper->name);
3055         gdk_threads_leave ();
3056
3057         g_object_unref (helper->win);
3058         g_object_unref (helper->folder);
3059         g_free (helper->name);
3060         g_slice_free (CreateFolderHelper, helper);
3061
3062         return FALSE;
3063 }
3064 #endif
3065
3066 static void
3067 do_create_folder_cb (ModestMailOperation *mail_op,
3068                      TnyFolderStore *parent_folder, 
3069                      TnyFolder *new_folder,
3070                      gpointer user_data)
3071 {
3072         gchar *suggested_name = (gchar *) user_data;
3073         GtkWindow *source_win = (GtkWindow *) modest_mail_operation_get_source (mail_op);
3074
3075         if (modest_mail_operation_get_error (mail_op)) {
3076
3077                 /* Show an error. If there was some problem writing to
3078                    disk, show it, otherwise show the generic folder
3079                    create error. We do it here and not in an error
3080                    handler because the call to do_create_folder will
3081                    stop the main loop in a gtk_dialog_run and then,
3082                    the message won't be shown until that dialog is
3083                    closed */
3084                 modest_ui_actions_disk_operations_error_handler (mail_op,
3085                                                                  _("mail_in_ui_folder_create_error"));
3086
3087                 /* Try again. Do *NOT* show any error because the mail
3088                    operations system will do it for us because we
3089                    created the mail_op with new_with_error_handler */
3090 #ifdef MODEST_PLATFORM_MAEMO
3091                 CreateFolderHelper *helper;
3092                 helper = g_slice_new0 (CreateFolderHelper);
3093                 helper->name = g_strdup (suggested_name);
3094                 helper->folder = g_object_ref (parent_folder);
3095                 helper->win = g_object_ref (source_win);
3096
3097                 /* Ugly but neccesary stuff. The problem is that the
3098                    dialog when is shown calls a function that destroys
3099                    all the temporary windows, so the banner is
3100                    destroyed */
3101                 helper->handler = g_timeout_add (2000, show_create_folder_in_timeout, helper);
3102 #else
3103                 do_create_folder (source_win, parent_folder, (const gchar *) suggested_name);
3104 #endif
3105         } else {
3106                 /* the 'source_win' is either the ModestMainWindow, or the 'Move to folder'-dialog
3107                  * FIXME: any other? */         
3108                 GtkWidget *folder_view;
3109
3110                 if (MODEST_IS_MAIN_WINDOW(source_win)) 
3111                         folder_view = 
3112                                 modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (source_win),
3113                                                                      MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3114                 else
3115                         folder_view =
3116                                 get_folder_view_from_move_to_dialog (GTK_WIDGET(source_win));
3117                 
3118                 /* Select the newly created folder. It could happen
3119                    that the widget is no longer there (i.e. the window
3120                    has been destroyed, so we need to check this */
3121                 if (folder_view)
3122                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view),
3123                                                           new_folder, FALSE);
3124                 g_object_unref (new_folder);
3125         }
3126         /* Free. Note that the first time it'll be NULL so noop */
3127         g_free (suggested_name);
3128         g_object_unref (source_win);
3129 }
3130
3131 static void
3132 do_create_folder (GtkWindow *parent_window, 
3133                   TnyFolderStore *parent_folder, 
3134                   const gchar *suggested_name)
3135 {
3136         gint result;
3137         gchar *folder_name = NULL;
3138
3139         result = modest_platform_run_new_folder_dialog (GTK_WINDOW (parent_window),
3140                                                         parent_folder,
3141                                                         (gchar *) suggested_name,
3142                                                         &folder_name);
3143         
3144         if (result == GTK_RESPONSE_ACCEPT) {
3145                 ModestMailOperation *mail_op;
3146                 
3147                 mail_op  = modest_mail_operation_new ((GObject *) parent_window);
3148                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3149                                                  mail_op);
3150                 modest_mail_operation_create_folder (mail_op,
3151                                                      parent_folder,
3152                                                      (const gchar *) folder_name,
3153                                                      do_create_folder_cb,
3154                                                      folder_name);
3155                 g_object_unref (mail_op);
3156         }
3157 }
3158
3159 static void
3160 create_folder_performer (gboolean canceled, 
3161                          GError *err,
3162                          GtkWindow *parent_window, 
3163                          TnyAccount *account, 
3164                          gpointer user_data)
3165 {
3166         TnyFolderStore *parent_folder = TNY_FOLDER_STORE (user_data);
3167
3168         if (canceled || err) {
3169                 /* In memory full conditions we could get this error here */
3170                 check_memory_full_error ((GtkWidget *) parent_window, err);
3171                 goto frees;
3172         }
3173
3174         /* Run the new folder dialog */
3175         do_create_folder (GTK_WINDOW (parent_window), parent_folder, NULL);
3176
3177  frees:
3178         g_object_unref (parent_folder);
3179 }
3180
3181 static void
3182 modest_ui_actions_create_folder(GtkWidget *parent_window,
3183                                 GtkWidget *folder_view)
3184 {
3185         TnyFolderStore *parent_folder;
3186
3187         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3188         
3189         if (parent_folder) {
3190                 /* The parent folder will be freed in the callback */
3191                 modest_platform_connect_if_remote_and_perform (GTK_WINDOW (parent_window), 
3192                                                                TRUE,
3193                                                                parent_folder,
3194                                                                create_folder_performer, 
3195                                                                parent_folder);
3196         }
3197 }
3198
3199 void 
3200 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
3201 {
3202         GtkWidget *folder_view;
3203         
3204         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3205
3206         folder_view = modest_main_window_get_child_widget (main_window,
3207                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3208         if (!folder_view)
3209                 return;
3210
3211         modest_ui_actions_create_folder (GTK_WIDGET (main_window), folder_view);
3212 }
3213
3214 static void
3215 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
3216                                                gpointer user_data)
3217 {
3218         const GError *error = NULL;
3219         const gchar *message = NULL;
3220         
3221         /* Get error message */
3222         error = modest_mail_operation_get_error (mail_op);
3223         if (!error)
3224                 g_return_if_reached ();
3225
3226         if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3227             error->code == MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS) {
3228                 message = _CS("ckdg_ib_folder_already_exists");
3229         } else if (error->domain == TNY_ERROR_DOMAIN &&
3230                    error->code == TNY_SERVICE_ERROR_STATE) {
3231                 /* This means that the folder is already in use (a
3232                    message is opened for example */
3233                 message = _("emev_ni_internal_error");
3234         } else {
3235                 message = _("emev_ib_ui_imap_unable_to_rename");
3236         }
3237
3238         /* We don't set a parent for the dialog because the dialog
3239            will be destroyed so the banner won't appear */
3240         modest_platform_information_banner (NULL, NULL, message);
3241 }
3242
3243 typedef struct {
3244         TnyFolderStore *folder;
3245         gchar *new_name;
3246 } RenameFolderInfo;
3247
3248 static void
3249 on_rename_folder_cb (ModestMailOperation *mail_op, 
3250                      TnyFolder *new_folder,
3251                      gpointer user_data)
3252 {
3253         ModestFolderView *folder_view;
3254
3255         /* If the window was closed when renaming a folder this could
3256            happen */
3257         if (!MODEST_IS_FOLDER_VIEW (user_data))
3258                 return;
3259
3260         folder_view = MODEST_FOLDER_VIEW (user_data);
3261         /* Note that if the rename fails new_folder will be NULL */
3262         if (new_folder) {
3263                 modest_folder_view_select_folder (folder_view, new_folder, FALSE);
3264         } else {
3265                 modest_folder_view_select_first_inbox_or_local (folder_view);
3266         }
3267         gtk_widget_grab_focus (GTK_WIDGET (folder_view));       
3268 }
3269
3270 static void
3271 on_rename_folder_performer (gboolean canceled, 
3272                             GError *err, 
3273                             GtkWindow *parent_window, 
3274                             TnyAccount *account, 
3275                             gpointer user_data)
3276 {
3277         ModestMailOperation *mail_op = NULL;
3278         GtkTreeSelection *sel = NULL;
3279         GtkWidget *folder_view = NULL;
3280         RenameFolderInfo *data = (RenameFolderInfo*)user_data;
3281
3282         if (canceled || err) {
3283                 /* In memory full conditions we could get this error here */
3284                 check_memory_full_error ((GtkWidget *) parent_window, err);
3285         } else if (MODEST_IS_MAIN_WINDOW(parent_window)) {
3286
3287                 folder_view = modest_main_window_get_child_widget (
3288                                 MODEST_MAIN_WINDOW (parent_window),
3289                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3290
3291                 mail_op = 
3292                         modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3293                                         modest_ui_actions_rename_folder_error_handler,
3294                                         parent_window, NULL);
3295
3296                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3297                                 mail_op);
3298
3299                 /* Clear the headers view */
3300                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3301                 gtk_tree_selection_unselect_all (sel);
3302
3303                 /* Actually rename the folder */
3304                 modest_mail_operation_rename_folder (mail_op,
3305                                                      TNY_FOLDER (data->folder),
3306                                                      (const gchar *) (data->new_name),
3307                                                      on_rename_folder_cb,
3308                                                      folder_view);
3309                 g_object_unref (data->folder);
3310                 g_object_unref (mail_op);
3311         }
3312
3313         g_free (data->new_name);
3314         g_free (data);
3315 }
3316
3317 void 
3318 modest_ui_actions_on_rename_folder (GtkAction *action,
3319                                      ModestMainWindow *main_window)
3320 {
3321         TnyFolderStore *folder;
3322         GtkWidget *folder_view;
3323         GtkWidget *header_view; 
3324
3325         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3326
3327         folder_view = modest_main_window_get_child_widget (main_window,
3328                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3329         if (!folder_view)
3330                 return;
3331
3332         header_view = modest_main_window_get_child_widget (main_window,
3333                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
3334         
3335         if (!header_view)
3336                 return;
3337
3338         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3339
3340         if (!folder)
3341                 return;
3342
3343         if (TNY_IS_FOLDER (folder)) {
3344                 gchar *folder_name;
3345                 gint response;
3346                 const gchar *current_name;
3347                 TnyFolderStore *parent;
3348                 gboolean do_rename = TRUE;
3349
3350                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
3351                 parent = tny_folder_get_folder_store (TNY_FOLDER (folder));
3352                 response = modest_platform_run_rename_folder_dialog (GTK_WINDOW (main_window), 
3353                                                                      parent, current_name, 
3354                                                                      &folder_name);
3355                 g_object_unref (parent);
3356
3357                 if (response != GTK_RESPONSE_ACCEPT || strlen (folder_name) == 0) {
3358                         do_rename = FALSE;
3359                 } else {
3360                         RenameFolderInfo *rename_folder_data = g_new0 (RenameFolderInfo, 1);
3361                         rename_folder_data->folder = g_object_ref (folder);
3362                         rename_folder_data->new_name = folder_name;
3363                         modest_platform_connect_if_remote_and_perform (GTK_WINDOW(main_window), TRUE,
3364                                         folder, on_rename_folder_performer, rename_folder_data);
3365                 }
3366         }
3367         g_object_unref (folder);
3368 }
3369
3370 static void
3371 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
3372                                                gpointer user_data)
3373 {
3374         GObject *win = modest_mail_operation_get_source (mail_op);
3375
3376         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
3377                                                 _("mail_in_ui_folder_delete_error"),
3378                                                 FALSE);
3379         g_object_unref (win);
3380 }
3381
3382 typedef struct {
3383         TnyFolderStore *folder;
3384         gboolean move_to_trash;
3385 } DeleteFolderInfo;
3386
3387 static void
3388 on_delete_folder_cb (gboolean canceled, 
3389                   GError *err,
3390                   GtkWindow *parent_window, 
3391                   TnyAccount *account, 
3392                   gpointer user_data)
3393 {
3394         DeleteFolderInfo *info = (DeleteFolderInfo*) user_data;
3395         GtkWidget *folder_view;
3396         ModestMailOperation *mail_op;
3397         GtkTreeSelection *sel;
3398         
3399         if (!MODEST_IS_MAIN_WINDOW(parent_window) || canceled || (err!=NULL)) {
3400                 g_object_unref (G_OBJECT (info->folder));
3401                 g_free (info);
3402                 return;
3403         }
3404         
3405         folder_view = modest_main_window_get_child_widget (
3406                         MODEST_MAIN_WINDOW (parent_window),
3407                         MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3408
3409         /* Unselect the folder before deleting it to free the headers */
3410         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3411         gtk_tree_selection_unselect_all (sel);
3412
3413         /* Create the mail operation */
3414         mail_op =
3415                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3416                                 modest_ui_actions_delete_folder_error_handler,
3417                                 NULL, NULL);
3418
3419         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3420                         mail_op);
3421         modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (info->folder), info->move_to_trash);
3422         
3423         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (folder_view));
3424
3425         g_object_unref (G_OBJECT (mail_op));
3426         g_object_unref (G_OBJECT (info->folder));
3427         g_free (info);
3428 }
3429
3430 static void
3431 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash)
3432 {
3433         TnyFolderStore *folder;
3434         GtkWidget *folder_view;
3435         gint response;
3436         gchar *message;
3437         
3438         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3439
3440         folder_view = modest_main_window_get_child_widget (main_window,
3441                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3442         if (!folder_view)
3443                 return;
3444
3445         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3446
3447         /* Show an error if it's an account */
3448         if (!TNY_IS_FOLDER (folder)) {
3449                 modest_platform_run_information_dialog (GTK_WINDOW (main_window),
3450                                                         _("mail_in_ui_folder_delete_error"),
3451                                                         FALSE);
3452                 g_object_unref (G_OBJECT (folder));
3453                 return;
3454         }
3455
3456         /* Ask the user */      
3457         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"), 
3458                                     tny_folder_get_name (TNY_FOLDER (folder)));
3459         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (main_window),
3460                                                             (const gchar *) message);
3461         g_free (message);
3462
3463         if (response == GTK_RESPONSE_OK) {
3464                 DeleteFolderInfo *info;
3465                 info = g_new0(DeleteFolderInfo, 1);
3466                 info->folder = folder;
3467                 info->move_to_trash = move_to_trash;
3468                 g_object_ref (G_OBJECT (info->folder));
3469                 TnyAccount *account = tny_folder_get_account (TNY_FOLDER (folder));
3470                 modest_platform_connect_if_remote_and_perform (GTK_WINDOW (main_window), 
3471                                                                TRUE,
3472                                                                TNY_FOLDER_STORE (account), 
3473                                                                on_delete_folder_cb, info);
3474                 g_object_unref (account);
3475         }
3476         g_object_unref (G_OBJECT (folder));
3477 }
3478
3479 void 
3480 modest_ui_actions_on_delete_folder (GtkAction *action,
3481                                      ModestMainWindow *main_window)
3482 {
3483         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3484         
3485         delete_folder (main_window, FALSE);
3486 }
3487
3488 void 
3489 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
3490 {
3491         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3492         
3493         delete_folder (main_window, TRUE);
3494 }
3495
3496
3497 typedef struct _PasswordDialogFields {
3498         GtkWidget *username;
3499         GtkWidget *password;
3500         GtkWidget *dialog;
3501 } PasswordDialogFields;
3502
3503 static void
3504 password_dialog_check_field (GtkEditable *editable,
3505                              PasswordDialogFields *fields)
3506 {
3507         const gchar *value;
3508         gboolean any_value_empty = FALSE;
3509
3510         value = gtk_entry_get_text (GTK_ENTRY (fields->username));
3511         if ((value == NULL) || value[0] == '\0') {
3512                 any_value_empty = TRUE;
3513         }
3514         value = gtk_entry_get_text (GTK_ENTRY (fields->password));
3515         if ((value == NULL) || value[0] == '\0') {
3516                 any_value_empty = TRUE;
3517         }
3518         gtk_dialog_set_response_sensitive (GTK_DIALOG (fields->dialog), GTK_RESPONSE_ACCEPT, !any_value_empty);
3519 }
3520
3521 void
3522 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
3523                                          const gchar* server_account_name,
3524                                          gchar **username,
3525                                          gchar **password, 
3526                                          gboolean *cancel, 
3527                                          gboolean *remember,
3528                                          ModestMainWindow *main_window)
3529 {
3530         g_return_if_fail(server_account_name);
3531         gboolean completed = FALSE;
3532         PasswordDialogFields *fields = NULL;
3533         
3534         /* Initalize output parameters: */
3535         if (cancel)
3536                 *cancel = FALSE;
3537                 
3538         if (remember)
3539                 *remember = TRUE;
3540                 
3541 #ifdef MODEST_PLATFORM_MAEMO
3542         /* Maemo uses a different (awkward) button order,
3543          * It should probably just use gtk_alternative_dialog_button_order ().
3544          */
3545         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3546                                               NULL,
3547                                               GTK_DIALOG_MODAL,
3548                                               _("mcen_bd_dialog_ok"),
3549                                               GTK_RESPONSE_ACCEPT,
3550                                               _("mcen_bd_dialog_cancel"),
3551                                               GTK_RESPONSE_REJECT,
3552                                               NULL);
3553 #else
3554         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3555                                               NULL,
3556                                               GTK_DIALOG_MODAL,
3557                                               GTK_STOCK_CANCEL,
3558                                               GTK_RESPONSE_REJECT,
3559                                               GTK_STOCK_OK,
3560                                               GTK_RESPONSE_ACCEPT,
3561                                               NULL);
3562 #endif /* MODEST_PLATFORM_MAEMO */
3563
3564         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (dialog));
3565         
3566         gchar *server_name = modest_account_mgr_get_server_account_hostname (
3567                 modest_runtime_get_account_mgr(), server_account_name);
3568         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
3569                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
3570                 if (cancel)
3571                         *cancel = TRUE;
3572                 return;
3573         }
3574         
3575         /* This causes a warning because the logical ID has no %s in it, 
3576          * though the translation does, but there is not much we can do about that: */
3577         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
3578         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
3579                             FALSE, FALSE, 0);
3580         g_free (txt);
3581         g_free (server_name);
3582         server_name = NULL;
3583
3584         /* username: */
3585         gchar *initial_username = modest_account_mgr_get_server_account_username (
3586                 modest_runtime_get_account_mgr(), server_account_name);
3587         
3588         GtkWidget *entry_username = gtk_entry_new ();
3589         if (initial_username)
3590                 gtk_entry_set_text (GTK_ENTRY (entry_username), initial_username);
3591         /* Dim this if a connection has ever succeeded with this username,
3592          * as per the UI spec: */
3593         /* const gboolean username_known =  */
3594         /*      modest_account_mgr_get_server_account_username_has_succeeded( */
3595         /*              modest_runtime_get_account_mgr(), server_account_name); */
3596         /* gtk_widget_set_sensitive (entry_username, !username_known); */
3597
3598         /* We drop the username sensitive code and disallow changing it here
3599          * as tinymail does not support really changing the username in the callback
3600          */
3601         gtk_widget_set_sensitive (entry_username, FALSE);
3602
3603 #ifdef MODEST_PLATFORM_MAEMO
3604         /* Auto-capitalization is the default, so let's turn it off: */
3605         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
3606         
3607         /* Create a size group to be used by all captions.
3608          * Note that HildonCaption does not create a default size group if we do not specify one.
3609          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
3610         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3611         
3612         GtkWidget *caption = hildon_caption_new (sizegroup, 
3613                 _("mail_fi_username"), entry_username, NULL, HILDON_CAPTION_MANDATORY);
3614         gtk_widget_show (entry_username);
3615         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3616                 FALSE, FALSE, MODEST_MARGIN_HALF);
3617         gtk_widget_show (caption);
3618 #else 
3619         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_username,
3620                             TRUE, FALSE, 0);
3621 #endif /* MODEST_PLATFORM_MAEMO */      
3622                             
3623         /* password: */
3624         GtkWidget *entry_password = gtk_entry_new ();
3625         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
3626         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
3627         
3628 #ifdef MODEST_PLATFORM_MAEMO
3629         /* Auto-capitalization is the default, so let's turn it off: */
3630         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password), 
3631                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
3632         
3633         caption = hildon_caption_new (sizegroup, 
3634                 _("mail_fi_password"), entry_password, NULL, HILDON_CAPTION_MANDATORY);
3635         gtk_widget_show (entry_password);
3636         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3637                 FALSE, FALSE, MODEST_MARGIN_HALF);
3638         gtk_widget_show (caption);
3639         g_object_unref (sizegroup);
3640 #else 
3641         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_password,
3642                             TRUE, FALSE, 0);
3643 #endif /* MODEST_PLATFORM_MAEMO */      
3644
3645         if (initial_username != NULL)
3646                 gtk_widget_grab_focus (GTK_WIDGET (entry_password));
3647                                 
3648 /* This is not in the Maemo UI spec:
3649         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
3650         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
3651                             TRUE, FALSE, 0);
3652 */
3653
3654         fields = g_slice_new0 (PasswordDialogFields);
3655         fields->username = entry_username;
3656         fields->password = entry_password;
3657         fields->dialog = dialog;
3658
3659         g_signal_connect (entry_username, "changed", G_CALLBACK (password_dialog_check_field), fields);
3660         g_signal_connect (entry_password, "changed", G_CALLBACK (password_dialog_check_field), fields);
3661         password_dialog_check_field (NULL, fields);
3662
3663         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3664
3665         while (!completed) {
3666         
3667                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3668                         if (username) {
3669                                 *username = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_username)));
3670                                 
3671                                 /* Note that an empty field becomes the "" string */
3672                                 if (*username && strlen (*username) > 0) {
3673                                         modest_account_mgr_set_server_account_username (modest_runtime_get_account_mgr(), 
3674                                                                                         server_account_name, 
3675                                                                                         *username);
3676                                         completed = TRUE;
3677                                 
3678                                         const gboolean username_was_changed = 
3679                                                 (strcmp (*username, initial_username) != 0);
3680                                         if (username_was_changed) {
3681                                                 g_warning ("%s: tinymail does not yet support changing the "
3682                                                            "username in the get_password() callback.\n", __FUNCTION__);
3683                                         }
3684                                 } else {
3685                                         /* Show error */
3686                                         modest_platform_information_banner (GTK_WIDGET (dialog), NULL, 
3687                                                                             _("mcen_ib_username_pw_incorrect"));
3688                                         completed = FALSE;
3689                                 }
3690                         }
3691                         
3692                         if (password) {
3693                                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_password)));
3694                         
3695                                 /* We do not save the password in the configuration, 
3696                                  * because this function is only called for passwords that should 
3697                                  * not be remembered:
3698                                  modest_server_account_set_password (
3699                                  modest_runtime_get_account_mgr(), server_account_name, 
3700                                  *password);
3701                                  */
3702                         }                       
3703                         if (cancel)
3704                                 *cancel   = FALSE;                      
3705                 } else {
3706                         /* Set parent to NULL or the banner will disappear with its parent dialog */
3707     &nbs