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