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