96a8b2d11208a13b4fec7a23155f905d9ed32553
[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
45 #include "modest-tny-platform-factory.h"
46 #include "modest-platform.h"
47 #include <tny-mime-part.h>
48
49 #ifdef MODEST_PLATFORM_MAEMO
50 #include "maemo/modest-osso-state-saving.h"
51 #include "maemo/modest-maemo-utils.h"
52 #endif /* MODEST_PLATFORM_MAEMO */
53
54 #include "widgets/modest-ui-constants.h"
55 #include <widgets/modest-main-window.h>
56 #include <widgets/modest-msg-view-window.h>
57 #include <widgets/modest-account-view-window.h>
58 #include <widgets/modest-details-dialog.h>
59 #include <widgets/modest-attachments-view.h>
60 #include "widgets/modest-folder-view.h"
61 #include "widgets/modest-global-settings-dialog.h"
62 #include "modest-connection-specific-smtp-window.h"
63 #include "modest-account-mgr-helpers.h"
64 #include "modest-mail-operation.h"
65 #include "modest-text-utils.h"
66
67 #ifdef MODEST_HAVE_EASYSETUP
68 #include "easysetup/modest-easysetup-wizard.h"
69 #endif /* MODEST_HAVE_EASYSETUP */
70
71 #include <modest-widget-memory.h>
72 #include <tny-error.h>
73 #include <tny-simple-list.h>
74 #include <tny-msg-view.h>
75 #include <tny-device.h>
76 #include <tny-merge-folder.h>
77
78 #include <gtkhtml/gtkhtml.h>
79
80 typedef struct _GetMsgAsyncHelper {     
81         ModestWindow *window;
82         ModestMailOperation *mail_op;
83         TnyIterator *iter;
84         guint num_ops;
85         GFunc func;     
86         gpointer user_data;
87 } GetMsgAsyncHelper;
88
89 typedef enum _ReplyForwardAction {
90         ACTION_REPLY,
91         ACTION_REPLY_TO_ALL,
92         ACTION_FORWARD
93 } ReplyForwardAction;
94
95 typedef struct _ReplyForwardHelper {
96         guint reply_forward_type;
97         ReplyForwardAction action;
98         gchar *account_name;
99         GtkWidget *parent_window;
100 } ReplyForwardHelper;
101
102
103 /*
104  * The do_headers_action uses this kind of functions to perform some
105  * action to each member of a list of headers
106  */
107 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
108
109 static void     do_headers_action     (ModestWindow *win, 
110                                        HeadersFunc func,
111                                        gpointer user_data);
112
113 static void     open_msg_cb            (ModestMailOperation *mail_op, 
114                                         TnyHeader *header, 
115                                         TnyMsg *msg,
116                                         gpointer user_data);
117
118 static void     reply_forward_cb       (ModestMailOperation *mail_op, 
119                                         TnyHeader *header, 
120                                         TnyMsg *msg,
121                                         gpointer user_data);
122
123 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
124
125 static void     folder_refreshed_cb    (ModestMailOperation *mail_op, 
126                                         TnyFolder *folder, 
127                                         gpointer user_data);
128
129 static void     _on_send_receive_progress_changed (ModestMailOperation  *mail_op, 
130                                                    ModestMailOperationState *state,
131                                                    gpointer user_data);
132
133
134
135 static void
136 run_account_setup_wizard (ModestWindow *win)
137 {
138         ModestEasysetupWizardDialog *wizard;
139
140         g_return_if_fail (MODEST_IS_WINDOW(win));
141         
142         wizard = modest_easysetup_wizard_dialog_new ();
143         gtk_window_set_transient_for (GTK_WINDOW (wizard), GTK_WINDOW (win));
144         gtk_dialog_run (GTK_DIALOG (wizard));
145         gtk_widget_destroy (GTK_WIDGET (wizard));
146 }
147
148
149 void   
150 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
151 {
152         GtkWidget *about;
153         const gchar *authors[] = {
154                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
155                 NULL
156         };
157         about = gtk_about_dialog_new ();
158         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
159         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
160         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
161                                         _("Copyright (c) 2006, Nokia Corporation\n"
162                                           "All rights reserved."));
163         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
164                                        _("a modest e-mail client\n\n"
165                                          "design and implementation: Dirk-Jan C. Binnema\n"
166                                          "contributions from the fine people at KC and Ig\n"
167                                          "uses the tinymail email framework written by Philip van Hoof"));
168         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
169         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
170         
171         gtk_dialog_run (GTK_DIALOG (about));
172         gtk_widget_destroy(about);
173 }
174
175 /*
176  * Gets the list of currently selected messages. If the win is the
177  * main window, then it returns a newly allocated list of the headers
178  * selected in the header view. If win is the msg view window, then
179  * the value returned is a list with just a single header.
180  *
181  * The caller of this funcion must free the list.
182  */
183 static TnyList *
184 get_selected_headers (ModestWindow *win)
185 {
186         if (MODEST_IS_MAIN_WINDOW(win)) {
187                 GtkWidget *header_view;         
188                 
189                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
190                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
191                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
192                 
193         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
194                 /* for MsgViewWindows, we simply return a list with one element */
195                 TnyHeader *header;
196                 TnyList *list = NULL;
197                 
198                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
199                 if (header != NULL) {
200                         list = tny_simple_list_new ();
201                         tny_list_prepend (list, G_OBJECT(header));
202                         g_object_unref (G_OBJECT(header));
203                 }
204
205                 return list;
206
207         } else
208                 return NULL;
209 }
210
211 static void
212 headers_action_mark_as_read (TnyHeader *header,
213                              ModestWindow *win,
214                              gpointer user_data)
215 {
216         TnyHeaderFlags flags;
217
218         g_return_if_fail (TNY_IS_HEADER(header));
219
220         flags = tny_header_get_flags (header);
221         if (flags & TNY_HEADER_FLAG_SEEN) return;
222         tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
223 }
224
225 static void
226 headers_action_mark_as_unread (TnyHeader *header,
227                                ModestWindow *win,
228                                gpointer user_data)
229 {
230         TnyHeaderFlags flags;
231
232         g_return_if_fail (TNY_IS_HEADER(header));
233
234         flags = tny_header_get_flags (header);
235         if (flags & TNY_HEADER_FLAG_SEEN)  {
236                 tny_header_unset_flags (header, TNY_HEADER_FLAG_SEEN);
237         }
238 }
239
240
241 static void
242 headers_action_delete (TnyHeader *header,
243                        ModestWindow *win,
244                        gpointer user_data)
245 {
246         ModestMailOperation *mail_op = NULL;
247
248         mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_DELETE, G_OBJECT(win));
249         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
250                                          mail_op);
251         
252         /* Always delete. TODO: Move to trash still not supported */
253         modest_mail_operation_remove_msg (mail_op, header, FALSE);
254         g_object_unref (G_OBJECT (mail_op));
255
256         /* refilter treemodel to hide marked-as-deleted rows */
257 /*      if (MODEST_IS_HEADER_VIEW (user_data)) */
258 /*              modest_header_view_refilter (MODEST_HEADER_VIEW (user_data)); */
259 }
260
261 void
262 modest_ui_actions_on_delete_message (GtkAction *action, ModestWindow *win)
263 {
264         TnyList *header_list = NULL;
265         TnyIterator *iter = NULL;
266         TnyHeader *header = NULL;
267         gchar *message = NULL;
268         gchar *desc = NULL;
269         gint response;
270         ModestWindowMgr *mgr;
271         GtkWidget *header_view = NULL;
272
273         g_return_if_fail (MODEST_IS_WINDOW(win));
274         
275         /* Check first if the header view has the focus */
276         if (MODEST_IS_MAIN_WINDOW (win)) {
277                 header_view = 
278                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
279                                                              MODEST_WIDGET_TYPE_HEADER_VIEW);
280                 if (!gtk_widget_is_focus (header_view))
281                         return;
282         }
283         
284         header_list = get_selected_headers (win);
285         if (!header_list) return;
286
287         /* Check if any of the headers is already opened, or in the process of being opened */
288         if (MODEST_IS_MAIN_WINDOW (win)) {
289                 gboolean found;
290                 iter = tny_list_create_iterator (header_list);
291                 found = FALSE;
292                 mgr = modest_runtime_get_window_mgr ();
293                 while (!tny_iterator_is_done (iter) && !found) {
294                         header = TNY_HEADER (tny_iterator_get_current (iter));
295                         found =  modest_window_mgr_find_registered_header (mgr, header, NULL);
296                         g_object_unref (header);
297                         tny_iterator_next (iter);
298                 }
299                 g_object_unref (iter);
300
301                 if (found) {
302                         gchar *num, *msg;
303
304                         num = g_strdup_printf ("%d", tny_list_get_length (header_list));
305                         msg = g_strdup_printf (_("mcen_nc_unable_to_delete_n_messages"), num);
306
307                         modest_platform_run_information_dialog (GTK_WINDOW (win), (const gchar *) msg);
308                         
309                         g_free (msg);
310                         g_free (num);
311                         g_object_unref (header_list);
312                         return;
313                 }
314         }
315
316         /* Select message */
317         if (tny_list_get_length(header_list) == 1) {
318                 iter = tny_list_create_iterator (header_list);
319                 header = TNY_HEADER (tny_iterator_get_current (iter));
320                 desc = g_strdup_printf ("%s", tny_header_get_subject (header)); 
321                 g_object_unref (header);
322                 g_object_unref (iter);
323         }
324         message = g_strdup_printf(ngettext("emev_nc_delete_message", "emev_nc_delete_messages", 
325                                            tny_list_get_length(header_list)), desc);
326
327         /* Confirmation dialog */               
328         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
329                                                             message);
330         
331
332         if (response == GTK_RESPONSE_OK) {      
333                 ModestWindow *main_window = NULL;
334                 ModestWindowMgr *mgr = NULL;
335                 GtkTreeModel *model = NULL;
336                 GtkTreeSelection *sel = NULL;
337                 GList *sel_list = NULL, *tmp = NULL;
338                 GtkTreeRowReference *row_reference = NULL;
339                 GtkTreePath *next_path = NULL;
340
341                 /* Find last selected row */                    
342                 if (MODEST_IS_MAIN_WINDOW (win)) {
343                         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
344                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
345                         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
346                         for (tmp=sel_list; tmp; tmp=tmp->next) {
347                                 if (tmp->next == NULL) {
348                                         next_path = gtk_tree_path_copy((GtkTreePath *) tmp->data);
349                                         gtk_tree_path_next (next_path);
350                                         row_reference = gtk_tree_row_reference_new (model, next_path);
351                                         gtk_tree_path_free (next_path);
352                                 }
353                         }
354                 }
355                 
356                 /* Remove each header. If it's a view window header_view == NULL */
357                 do_headers_action (win, headers_action_delete, header_view);
358
359                 if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
360                         /* Close msg view window or select next */
361                         if (modest_msg_view_window_last_message_selected (MODEST_MSG_VIEW_WINDOW (win)) &&
362                             modest_msg_view_window_first_message_selected (MODEST_MSG_VIEW_WINDOW (win))) {
363                                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (win));
364                         } else {
365                                 modest_msg_view_window_select_next_message (MODEST_MSG_VIEW_WINDOW (win));
366                         }
367                         
368                         /* Get main window */
369                         mgr = modest_runtime_get_window_mgr ();
370                         main_window = modest_window_mgr_get_main_window (mgr);
371                 }
372                 else {                  
373                         /* Move cursor to next row */
374                         main_window = win; 
375
376                         /* Select next row */
377                         if (gtk_tree_row_reference_valid (row_reference)) {
378                                 next_path = gtk_tree_row_reference_get_path (row_reference);
379                                 gtk_tree_selection_select_path (sel, next_path);
380                                 gtk_tree_path_free (next_path);
381                         }
382                         if (row_reference != NULL)
383                                 gtk_tree_row_reference_free (row_reference);
384                 }
385
386                 /* Update toolbar dimming state */
387                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
388
389                 /* Free */
390                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
391                 g_list_free (sel_list);
392         }
393
394         /* Free*/
395         g_free(message);
396         g_free(desc);
397         g_object_unref (header_list);
398 }
399
400
401
402
403 /* delete either message or folder, based on where we are */
404 void
405 modest_ui_actions_on_delete_message_or_folder (GtkAction *action, ModestWindow *win)
406 {
407         g_return_if_fail (MODEST_IS_WINDOW(win));
408         
409         /* Check first if the header view has the focus */
410         if (MODEST_IS_MAIN_WINDOW (win)) {
411                 GtkWidget *w;
412                 w = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
413                                                          MODEST_WIDGET_TYPE_FOLDER_VIEW);
414                 if (gtk_widget_is_focus (w)) {
415                         modest_ui_actions_on_delete_folder (action, MODEST_MAIN_WINDOW(win));
416                         return;
417                 }
418         }
419         modest_ui_actions_on_delete_message (action, win);
420 }
421
422
423
424 void
425 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
426 {
427 #ifdef MODEST_PLATFORM_MAEMO
428         modest_osso_save_state();
429 #endif /* MODEST_PLATFORM_MAEMO */
430
431         g_debug ("closing down, clearing %d item(s) from operation queue",
432                  modest_mail_operation_queue_num_elements
433                  (modest_runtime_get_mail_operation_queue()));
434
435         /* cancel all outstanding operations */
436         modest_mail_operation_queue_cancel_all 
437                 (modest_runtime_get_mail_operation_queue());
438         
439         g_debug ("queue has been cleared");
440
441         /* note: when modest-tny-account-store is finalized,
442            it will automatically set all network connections
443            to offline */
444
445         gtk_main_quit ();
446 }
447
448 void
449 modest_ui_actions_on_close_window (GtkAction *action, ModestWindow *win)
450 {
451         gboolean ret_value;
452         g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
453
454 /*      if (MODEST_IS_MSG_VIEW_WINDOW (win)) { */
455 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
456 /*      } else if (MODEST_IS_MSG_EDIT_WINDOW (win)) { */
457 /*              gboolean ret_value; */
458 /*              g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value); */
459 /*      } else if (MODEST_IS_WINDOW (win)) { */
460 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
461 /*      } else { */
462 /*              g_return_if_reached (); */
463 /*      } */
464 }
465
466 void
467 modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
468 {
469         GtkClipboard *clipboard = NULL;
470         gchar *selection = NULL;
471
472         clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
473         selection = gtk_clipboard_wait_for_text (clipboard);
474
475         /* Question: why is the clipboard being used here? 
476          * It doesn't really make a lot of sense. */
477
478         if (selection)
479         {
480                 modest_address_book_add_address (selection);
481                 g_free (selection);
482         }
483 }
484
485 void
486 modest_ui_actions_on_accounts (GtkAction *action, ModestWindow *win)
487 {
488         /* This is currently only implemented for Maemo */
489 #ifdef MODEST_PLATFORM_MAEMO /* Defined in config.h */
490         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
491                 run_account_setup_wizard (win);
492                 return;
493         } else  {
494                 /* Show the list of accounts: */
495                 GtkDialog *account_win = GTK_DIALOG(modest_account_view_window_new ());
496                 modest_maemo_show_dialog_and_forget (GTK_WINDOW (win), account_win); 
497         }
498 #else
499         GtkWidget *dialog, *label;
500         
501         /* Create the widgets */
502         
503         dialog = gtk_dialog_new_with_buttons ("Message",
504                                               GTK_WINDOW(win),
505                                               GTK_DIALOG_DESTROY_WITH_PARENT,
506                                               GTK_STOCK_OK,
507                                               GTK_RESPONSE_NONE,
508                                               NULL);
509         label = gtk_label_new ("Hello World!");
510         
511         /* Ensure that the dialog box is destroyed when the user responds. */
512         
513         g_signal_connect_swapped (dialog, "response", 
514                                   G_CALLBACK (gtk_widget_destroy),
515                                   dialog);
516         
517         /* Add the label, and show everything we've added to the dialog. */
518         
519         gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
520                            label);
521         gtk_widget_show_all (dialog);
522 #endif /* MODEST_PLATFORM_MAEMO */
523 }
524
525 static void
526 on_smtp_servers_window_hide (GtkWindow* window, gpointer user_data)
527 {
528         ModestWindow *main_window = MODEST_WINDOW (user_data);
529         
530         /* Save any changes. */
531         modest_connection_specific_smtp_window_save_server_accounts (
532                         MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (window), 
533                         modest_window_get_active_account (main_window));
534         gtk_widget_destroy (GTK_WIDGET (window));
535 }
536
537
538
539 void
540 modest_ui_actions_on_smtp_servers (GtkAction *action, ModestWindow *win)
541 {
542         /* This is currently only implemented for Maemo,
543          * because it requires an API (libconic) to detect different connection 
544          * possiblities.
545          */
546 #ifdef MODEST_PLATFORM_MAEMO /* Defined in config.h */
547         
548         /* Create the window if necessary: */
549         const gchar *active_account_name = modest_window_get_active_account (win);
550         
551         /* TODO: Dim the menu item (not in the UI spec)? or show a warning,
552          * or show the default account?
553          * If we show the default account then the account name should be shown in 
554          * the window when we show it. */
555         if (!active_account_name) {
556                 g_warning ("%s: No account is active.", __FUNCTION__);
557                 return;
558         }
559                 
560         GtkWidget *specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
561         modest_connection_specific_smtp_window_fill_with_connections (
562                 MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window), 
563                 modest_runtime_get_account_mgr(), 
564                 active_account_name);
565
566         /* Show the window: */  
567         gtk_window_set_transient_for (GTK_WINDOW (specific_window), GTK_WINDOW (win));
568         gtk_window_set_modal (GTK_WINDOW (specific_window), TRUE);
569         gtk_widget_show (specific_window);
570     
571         /* Save changes when the window is hidden: */
572         g_signal_connect (specific_window, "hide", 
573                 G_CALLBACK (on_smtp_servers_window_hide), win);
574 #endif /* MODEST_PLATFORM_MAEMO */
575 }
576
577 void
578 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
579 {
580         ModestWindow *msg_win = NULL;
581         TnyMsg *msg = NULL;
582         TnyFolder *folder = NULL;
583         gchar *account_name = NULL;
584         gchar *from_str = NULL;
585 /*      GError *err = NULL; */
586         TnyAccount *account = NULL;
587         ModestWindowMgr *mgr;
588         gchar *signature = NULL, *blank_and_signature = NULL;
589
590         /* if there are no accounts yet, just show the wizard */
591         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE)) {
592                         run_account_setup_wizard (win);
593                         return;
594         }
595         
596         account_name = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
597         if (!account_name)
598                 account_name = g_strdup (modest_window_get_active_account (win));
599         if (!account_name) {
600                 g_printerr ("modest: no account found\n");
601                 goto cleanup;
602         }
603         
604         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
605                                                                        account_name,
606                                                                        TNY_ACCOUNT_TYPE_STORE);
607         if (!account) {
608                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
609                 goto cleanup;
610         }
611
612         from_str = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(), account_name);
613         if (!from_str) {
614                 g_printerr ("modest: failed get from string for '%s'\n", account_name);
615                 goto cleanup;
616         }
617
618         if (modest_account_mgr_get_bool (modest_runtime_get_account_mgr (), account_name,
619                                          MODEST_ACCOUNT_USE_SIGNATURE, FALSE)) {
620                 signature = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), account_name,
621                                                            MODEST_ACCOUNT_SIGNATURE, FALSE);
622                 blank_and_signature = g_strconcat ("\n", signature, NULL);
623                 g_free (signature);
624         } else {
625                 blank_and_signature = g_strdup ("");
626         }
627
628         msg = modest_tny_msg_new ("", from_str, "", "", "", blank_and_signature, NULL);
629         if (!msg) {
630                 g_printerr ("modest: failed to create new msg\n");
631                 goto cleanup;
632         }
633         
634         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
635         if (!folder) {
636                 g_printerr ("modest: failed to find Drafts folder\n");
637                 goto cleanup;
638         }
639         
640
641         /* Create and register edit window */
642         /* This is destroyed by TOOD. */
643         msg_win = modest_msg_edit_window_new (msg, account_name);
644         mgr = modest_runtime_get_window_mgr ();
645         modest_window_mgr_register_window (mgr, msg_win);
646
647         if (win)
648                 gtk_window_set_transient_for (GTK_WINDOW (msg_win),
649                                               GTK_WINDOW (win));        
650         gtk_widget_show_all (GTK_WIDGET (msg_win));
651
652 cleanup:
653         g_free (account_name);
654         g_free (from_str);
655         g_free (blank_and_signature);
656         if (msg_win)
657                 g_object_unref (msg_win);
658         if (account)
659                 g_object_unref (G_OBJECT(account));
660         if (msg)
661                 g_object_unref (G_OBJECT(msg));
662         if (folder)
663                 g_object_unref (G_OBJECT(folder));
664 }
665
666 gboolean 
667 modest_ui_actions_msg_retrieval_check (ModestMailOperation *mail_op,
668                                        TnyHeader *header,
669                                        TnyMsg *msg)
670 {
671         ModestMailOperationStatus status;
672
673         /* If there is no message or the operation was not successful */
674         status = modest_mail_operation_get_status (mail_op);
675         if (!msg || status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
676
677                 /* Remove the header from the preregistered uids */
678                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),  
679                                                      header);
680
681                 return FALSE;
682         }
683
684         return TRUE;
685 }
686
687 static void
688 open_msg_cb (ModestMailOperation *mail_op, 
689              TnyHeader *header, 
690              TnyMsg *msg, 
691              gpointer user_data)
692 {
693         ModestWindowMgr *mgr = NULL;
694         ModestWindow *parent_win = NULL;
695         ModestWindow *win = NULL;
696         TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
697         gchar *account = NULL;
698         TnyFolder *folder;
699         
700         /* Do nothing if there was any problem with the mail
701            operation. The error will be shown by the error_handler of
702            the mail operation */
703         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
704                 printf ("DEBUG: %s: modest_ui_actions_msg_retrieval_check() failed.\n", 
705                         __FUNCTION__);
706                 return;
707         }
708
709         parent_win = (ModestWindow *) modest_mail_operation_get_source (mail_op);
710         folder = tny_header_get_folder (header);
711
712         /* Mark header as read */
713         headers_action_mark_as_read (header, MODEST_WINDOW(parent_win), NULL);
714
715         /* Get account */
716         account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
717         if (!account)
718                 account =  g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_win)));
719         
720         /* Gets folder type (OUTBOX headers will be opened in edit window */
721         if (modest_tny_folder_is_local_folder (folder))
722                 folder_type = modest_tny_folder_get_local_folder_type (folder);
723
724         /* If the header is in the drafts folder then open the editor,
725            else the message view window */
726         if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
727                 /* we cannot edit without a valid account... */
728                 if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
729                         run_account_setup_wizard(parent_win);
730                         goto cleanup;
731                 }
732                 win = modest_msg_edit_window_new (msg, account);
733         } else {
734                 gchar *uid = modest_tny_folder_get_header_unique_id (header);
735                 
736                 if (MODEST_IS_MAIN_WINDOW (parent_win)) {
737                         GtkWidget *header_view;
738                         GtkTreeSelection *sel;
739                         GList *sel_list = NULL;
740                         GtkTreeModel *model;
741                         
742                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_win),
743                                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
744
745                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
746                         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
747
748                         if (sel_list != NULL) {
749                                 GtkTreeRowReference *row_reference;
750
751                                 row_reference = gtk_tree_row_reference_new (model, (GtkTreePath *) sel_list->data);
752                                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
753                                 g_list_free (sel_list);
754                                 
755                                 win = modest_msg_view_window_new_with_header_model (msg, 
756                                                                                     account,
757                                                                                     (const gchar*) uid,
758                                                                                     model, 
759                                                                                     row_reference);
760                                 gtk_tree_row_reference_free (row_reference);
761                         } else {
762                                 win = modest_msg_view_window_new (msg, account, (const gchar*) uid);
763                         }
764                 } else {
765                         win = modest_msg_view_window_new (msg, account, (const gchar*) uid);
766                 }
767                 g_free (uid);
768         }
769         
770         /* Register and show new window */
771         if (win != NULL) {
772                 mgr = modest_runtime_get_window_mgr ();
773                 modest_window_mgr_register_window (mgr, win);
774                 g_object_unref (win);
775                 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent_win));
776                 gtk_widget_show_all (GTK_WIDGET(win));
777         }
778
779         /* Update toolbar dimming state */
780         if (MODEST_IS_MAIN_WINDOW (parent_win)) {
781                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_win));
782         }
783
784 cleanup:
785         /* Free */
786         g_free(account);
787         g_object_unref (parent_win);
788 /*      g_object_unref (msg); */
789         g_object_unref (folder);
790 }
791
792 void
793 modest_ui_actions_get_msgs_full_error_handler (ModestMailOperation *mail_op,
794                                                gpointer user_data)
795 {
796         const GError *error;
797         GObject *win = modest_mail_operation_get_source (mail_op);
798
799         error = modest_mail_operation_get_error (mail_op);
800         printf ("DEBUG: %s: Error: code=%d, text=%s\n", __FUNCTION__, error->code, error->message);
801  
802         if (error->code == MODEST_MAIL_OPERATION_ERROR_MESSAGE_SIZE_LIMIT) {
803
804                 modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
805                                                         error->message);
806         } else {
807                 modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
808                                                         _("mail_ni_ui_folder_get_msg_folder_error"));
809         }
810
811         if (win)
812                 g_object_unref (win);
813 }
814
815 /*
816  * This function is used by both modest_ui_actions_on_open and
817  * modest_ui_actions_on_header_activated. This way we always do the
818  * same when trying to open messages.
819  */
820 static void
821 _modest_ui_actions_open (TnyList *headers, ModestWindow *win)
822 {
823         ModestWindowMgr *mgr = NULL;
824         TnyIterator *iter = NULL;
825         ModestMailOperation *mail_op1 = NULL;
826         ModestMailOperation *mail_op2 = NULL;
827         TnyList *not_opened_headers = NULL;
828         TnyList *not_opened_cached_headers = NULL;
829         TnyHeaderFlags flags;
830                 
831         /* Look if we already have a message view for each header. If
832            true, then remove the header from the list of headers to
833            open */
834         mgr = modest_runtime_get_window_mgr ();
835         iter = tny_list_create_iterator (headers);
836         not_opened_headers = tny_simple_list_new ();
837         not_opened_cached_headers = tny_simple_list_new ();
838         while (!tny_iterator_is_done (iter)) {
839
840                 ModestWindow *window;
841                 TnyHeader *header;
842                 gboolean found;
843                 
844                 header = TNY_HEADER (tny_iterator_get_current (iter));
845                 flags = tny_header_get_flags (header);
846
847                 window = NULL;
848                 found = modest_window_mgr_find_registered_header (mgr, header, &window);
849                 
850                 /* Do not open again the message and present the
851                    window to the user */
852                 if (found) {
853                         if (window)
854                                 gtk_window_present (GTK_WINDOW (window));
855                         else
856                                 /* the header has been registered already, we don't do
857                                  * anything but wait for the window to come up*/
858                                 g_warning ("debug: header %p already registered, waiting for window",
859                                            header);
860                 } else {
861                         if (!(flags & TNY_HEADER_FLAG_CACHED))
862                                 tny_list_append (not_opened_headers, G_OBJECT (header));
863                         /* Check if msg has already been retreived */
864                         else
865                                 tny_list_append (not_opened_cached_headers, G_OBJECT (header));
866                 }
867                 g_object_unref (header);
868                 tny_iterator_next (iter);
869         }
870         g_object_unref (iter);
871         iter = NULL;
872         
873         /* If some messages would have to be downloaded, ask the user to 
874          * make a connection. It's generally easier to do this here (in the mainloop) 
875          * than later in a thread:
876          */
877         if (tny_list_get_length (not_opened_cached_headers) > 0) {
878                 gboolean connected = modest_platform_connect_and_wait (GTK_WINDOW (win));
879                 
880                 /* Don't go further if a connection would be necessary but none is available: */
881                 if (!connected) {
882                         g_object_unref (not_opened_headers);
883                         g_object_unref (not_opened_cached_headers);
884                         return;
885                 }
886         }
887         
888         /* Register the headers before actually creating the windows: */
889         TnyIterator *iter_not_opened = tny_list_create_iterator (not_opened_headers);
890         while (!tny_iterator_is_done (iter_not_opened)) {
891                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter_not_opened));
892                 modest_window_mgr_register_header (mgr, header);
893                 g_object_unref (header);
894                 
895                 tny_iterator_next (iter_not_opened);
896         }
897         g_object_unref (iter_not_opened);
898         iter_not_opened = NULL;
899         
900         TnyIterator *iter_cached = tny_list_create_iterator (not_opened_cached_headers);
901         while (!tny_iterator_is_done (iter_cached)) {
902                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter_cached));
903                 modest_window_mgr_register_header (mgr, header);
904                 g_object_unref (header);
905                 
906                 tny_iterator_next (iter_cached);
907         }
908         g_object_unref (iter_cached);
909         iter_cached = NULL;
910         
911         
912         /* Open each uncached message */
913         if (tny_list_get_length (not_opened_headers) > 0) {
914                 mail_op1 = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
915                                                                          G_OBJECT (win), 
916                                                                          modest_ui_actions_get_msgs_full_error_handler, 
917                                                                          NULL);
918                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op1);
919                 if (tny_list_get_length (not_opened_headers) > 1) {
920                         modest_mail_operation_get_msgs_full (mail_op1, 
921                                                              not_opened_headers, 
922                                                              open_msg_cb, 
923                                                              NULL, 
924                                                              NULL);
925                 } else {
926                         TnyIterator *iter = tny_list_create_iterator (not_opened_headers);
927                         TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
928                         modest_mail_operation_get_msg (mail_op1, header, open_msg_cb, NULL);
929                         g_object_unref (header);
930                         g_object_unref (iter);
931                 }
932         }
933
934         /* Open each cached message */
935         if (tny_list_get_length (not_opened_cached_headers) > 0) {
936                 mail_op2 = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
937                                                                          G_OBJECT (win), 
938                                                                          modest_ui_actions_get_msgs_full_error_handler, 
939                                                                          NULL);
940                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op2);
941                 if (tny_list_get_length (not_opened_cached_headers) > 1) {
942                         modest_mail_operation_get_msgs_full (mail_op2, 
943                                                              not_opened_headers, 
944                                                              open_msg_cb, 
945                                                              NULL, 
946                                                              NULL);
947                 } else {
948                         TnyIterator *iter = tny_list_create_iterator (not_opened_cached_headers);
949                         TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
950                         modest_mail_operation_get_msg (mail_op2, header, open_msg_cb, NULL);
951                         g_object_unref (header);
952                         g_object_unref (iter);
953                 }
954         }
955
956         /* Clean */
957         if (not_opened_headers != NULL)
958                 g_object_unref (not_opened_headers);
959         if (not_opened_cached_headers != NULL)
960                 g_object_unref (not_opened_cached_headers);
961         if (iter != NULL) 
962                 g_object_unref (iter);
963         if (mail_op1 != NULL)
964                 g_object_unref (mail_op1);
965         if (mail_op2 != NULL) 
966                 g_object_unref (mail_op2);
967 }
968
969 void
970 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
971 {
972         TnyList *headers;
973
974         /* Get headers */
975         headers = get_selected_headers (win);
976         if (!headers)
977                 return;
978
979         /* Open them */
980         _modest_ui_actions_open (headers, win);
981
982         g_object_unref(headers);
983 }
984
985
986 static void
987 free_reply_forward_helper (gpointer data)
988 {
989         ReplyForwardHelper *helper;
990
991         helper = (ReplyForwardHelper *) data;
992         g_free (helper->account_name);
993         g_slice_free (ReplyForwardHelper, helper);
994 }
995
996 static void
997 reply_forward_cb (ModestMailOperation *mail_op, 
998                   TnyHeader *header, 
999                   TnyMsg *msg,
1000                   gpointer user_data)
1001 {
1002         TnyMsg *new_msg;
1003         ReplyForwardHelper *rf_helper;
1004         ModestWindow *msg_win = NULL;
1005         ModestEditType edit_type;
1006         gchar *from = NULL;
1007         TnyAccount *account = NULL;
1008         ModestWindowMgr *mgr = NULL;
1009         gchar *signature = NULL;
1010
1011         /* If there was any error. The mail operation could be NULL,
1012            this means that we already have the message downloaded and
1013            that we didn't do a mail operation to retrieve it */
1014         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1015                 return;
1016                         
1017         g_return_if_fail (user_data != NULL);
1018         rf_helper = (ReplyForwardHelper *) user_data;
1019
1020         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1021                                                    rf_helper->account_name);
1022         if (modest_account_mgr_get_bool (modest_runtime_get_account_mgr(),
1023                                          rf_helper->account_name,
1024                                          MODEST_ACCOUNT_USE_SIGNATURE, FALSE)) {
1025                 signature = modest_account_mgr_get_string (modest_runtime_get_account_mgr (),
1026                                                            rf_helper->account_name,
1027                                                            MODEST_ACCOUNT_SIGNATURE, FALSE);
1028         }
1029
1030         /* Create reply mail */
1031         switch (rf_helper->action) {
1032         case ACTION_REPLY:
1033                 new_msg = 
1034                         modest_tny_msg_create_reply_msg (msg,  from, signature,
1035                                                          rf_helper->reply_forward_type,
1036                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1037                 break;
1038         case ACTION_REPLY_TO_ALL:
1039                 new_msg = 
1040                         modest_tny_msg_create_reply_msg (msg, from, signature, rf_helper->reply_forward_type,
1041                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1042                 edit_type = MODEST_EDIT_TYPE_REPLY;
1043                 break;
1044         case ACTION_FORWARD:
1045                 new_msg = 
1046                         modest_tny_msg_create_forward_msg (msg, from, signature, rf_helper->reply_forward_type);
1047                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1048                 break;
1049         default:
1050                 g_return_if_reached ();
1051                 return;
1052         }
1053
1054         g_free (signature);
1055
1056         if (!new_msg) {
1057                 g_printerr ("modest: failed to create message\n");
1058                 goto cleanup;
1059         }
1060
1061         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1062                                                                        rf_helper->account_name,
1063                                                                        TNY_ACCOUNT_TYPE_STORE);
1064         if (!account) {
1065                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", rf_helper->account_name);
1066                 goto cleanup;
1067         }
1068
1069         /* Create and register the windows */
1070         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name);
1071         mgr = modest_runtime_get_window_mgr ();
1072         modest_window_mgr_register_window (mgr, msg_win);
1073
1074         if (rf_helper->parent_window != NULL) {
1075                 gdouble parent_zoom;
1076
1077                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1078                 modest_window_set_zoom (msg_win, parent_zoom);
1079         }
1080
1081         /* Show edit window */
1082         gtk_widget_show_all (GTK_WIDGET (msg_win));
1083
1084 cleanup:
1085         if (msg_win)
1086                 g_object_unref (msg_win);
1087         if (new_msg)
1088                 g_object_unref (G_OBJECT (new_msg));
1089         if (account)
1090                 g_object_unref (G_OBJECT (account));
1091 /*      g_object_unref (msg); */
1092         g_object_unref (header);
1093         free_reply_forward_helper (rf_helper);
1094 }
1095
1096 /*
1097  * Checks a list of headers. If any of them are not currently
1098  * downloaded (CACHED) then it asks the user for permission to
1099  * download them.
1100  *
1101  * Returns FALSE if the user does not want to download the
1102  * messages. Returns TRUE if the user allowed the download or if all
1103  * of them are currently downloaded
1104  */
1105 static gboolean
1106 download_uncached_messages (TnyList *header_list, GtkWindow *win,
1107                             gboolean reply_fwd)
1108 {
1109         TnyIterator *iter;
1110         gboolean retval;
1111         gint uncached_messages = 0;
1112
1113         iter = tny_list_create_iterator (header_list);
1114         while (!tny_iterator_is_done (iter)) {
1115                 TnyHeader *header;
1116                 TnyHeaderFlags flags;
1117
1118                 header = TNY_HEADER (tny_iterator_get_current (iter));
1119                 flags = tny_header_get_flags (header);
1120                 /* TODO: is this the right flag?, it seems that some
1121                    headers that have been previously downloaded do not
1122                    come with it */
1123                 if (! (flags & TNY_HEADER_FLAG_CACHED))
1124                         uncached_messages ++;
1125                 g_object_unref (header);
1126                 tny_iterator_next (iter);
1127         }
1128         g_object_unref (iter);
1129
1130         /* Ask for user permission to download the messages */
1131         retval = TRUE;
1132         if (uncached_messages > 0) {
1133                 GtkResponseType response;
1134                 if (reply_fwd)
1135                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1136                                                                             _("emev_nc_include_original"));
1137                 else
1138                         response =
1139                                 modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1140                                                                          ngettext("mcen_nc_get_msg",
1141                                                                                   "mcen_nc_get_msgs",
1142                                                                                   uncached_messages));
1143                 if (response == GTK_RESPONSE_CANCEL)
1144                         retval = FALSE;
1145                 else {
1146                         /* If a download will be necessary, make sure that we have a connection: */
1147                         retval = modest_platform_connect_and_wait(win); 
1148                 }
1149         }
1150         return retval;
1151 }
1152
1153
1154 /*
1155  * Common code for the reply and forward actions
1156  */
1157 static void
1158 reply_forward (ReplyForwardAction action, ModestWindow *win)
1159 {
1160         ModestMailOperation *mail_op = NULL;
1161         TnyList *header_list = NULL;
1162         ReplyForwardHelper *rf_helper = NULL;
1163         guint reply_forward_type;
1164         gboolean continue_download;
1165         
1166         g_return_if_fail (MODEST_IS_WINDOW(win));
1167
1168         /* we need an account when editing */
1169         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
1170                 run_account_setup_wizard (win);
1171                 return;
1172         }
1173         
1174         header_list = get_selected_headers (win);
1175         if (!header_list)
1176                 return;
1177
1178         /* Check that the messages have been previously downloaded */
1179         continue_download = download_uncached_messages (header_list, GTK_WINDOW (win), TRUE);
1180         if (!continue_download) {
1181                 g_object_unref (header_list);
1182                 return;
1183         }
1184         
1185         reply_forward_type = 
1186                 modest_conf_get_int (modest_runtime_get_conf (),
1187                                      (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE,
1188                                      NULL);
1189         /* We assume that we can only select messages of the
1190            same folder and that we reply all of them from the
1191            same account. In fact the interface currently only
1192            allows single selection */
1193         
1194         /* Fill helpers */
1195         rf_helper = g_slice_new0 (ReplyForwardHelper);
1196         rf_helper->reply_forward_type = reply_forward_type;
1197         rf_helper->action = action;
1198         rf_helper->account_name = g_strdup (modest_window_get_active_account (win));
1199         if ((win != NULL) && (MODEST_IS_WINDOW (win)))
1200                 rf_helper->parent_window = GTK_WIDGET (win);
1201         if (!rf_helper->account_name)
1202                 rf_helper->account_name =
1203                         modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1204
1205         if (MODEST_IS_MSG_VIEW_WINDOW(win)) {
1206                 TnyMsg *msg;
1207                 TnyHeader *header;
1208                 /* Get header and message. Do not free them here, the
1209                    reply_forward_cb must do it */
1210                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
1211                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW(win));
1212                 if (!msg || !header) {
1213                         if (msg)
1214                                 g_object_unref (msg);
1215                         if (header)
1216                                 g_object_unref (header);
1217                         g_printerr ("modest: no message found\n");
1218                         return;
1219                 } else {
1220                         reply_forward_cb (NULL, header, msg, rf_helper);
1221                 }
1222         } else {
1223                 TnyHeader *header;
1224                 TnyIterator *iter;
1225
1226                 /* Retrieve messages */
1227                 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
1228                                                                          G_OBJECT(win),
1229                                                                          modest_ui_actions_get_msgs_full_error_handler, 
1230                                                                          NULL);
1231                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1232
1233                 /* Only reply/forward to one message */
1234                 iter = tny_list_create_iterator (header_list);
1235                 header = TNY_HEADER (tny_iterator_get_current (iter));
1236                 g_object_unref (iter);
1237
1238                 modest_mail_operation_get_msg (mail_op,
1239                                                header,
1240                                                reply_forward_cb,
1241                                                rf_helper);
1242
1243 /*              modest_mail_operation_get_msgs_full (mail_op,  */
1244 /*                                                   header_list,  */
1245 /*                                                   reply_forward_cb,  */
1246 /*                                                   rf_helper,  */
1247 /*                                                   free_reply_forward_helper); */
1248
1249                 /* Clean */
1250                 g_object_unref(mail_op);
1251         }
1252
1253         /* Free */
1254         g_object_unref (header_list);
1255 }
1256
1257 void
1258 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
1259 {
1260         g_return_if_fail (MODEST_IS_WINDOW(win));
1261
1262         reply_forward (ACTION_REPLY, win);
1263 }
1264
1265 void
1266 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
1267 {
1268         g_return_if_fail (MODEST_IS_WINDOW(win));
1269
1270         reply_forward (ACTION_FORWARD, win);
1271 }
1272
1273 void
1274 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
1275 {
1276         g_return_if_fail (MODEST_IS_WINDOW(win));
1277
1278         reply_forward (ACTION_REPLY_TO_ALL, win);
1279 }
1280
1281 void 
1282 modest_ui_actions_on_next (GtkAction *action, 
1283                            ModestWindow *window)
1284 {
1285         if (MODEST_IS_MAIN_WINDOW (window)) {
1286                 GtkWidget *header_view;
1287
1288                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1289                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1290                 if (!header_view)
1291                         return;
1292         
1293                 modest_header_view_select_next (MODEST_HEADER_VIEW(header_view)); 
1294         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1295                 modest_msg_view_window_select_next_message (MODEST_MSG_VIEW_WINDOW (window));
1296         } else {
1297                 g_return_if_reached ();
1298         }
1299 }
1300
1301 void 
1302 modest_ui_actions_on_prev (GtkAction *action, 
1303                            ModestWindow *window)
1304 {
1305         g_return_if_fail (MODEST_IS_WINDOW(window));
1306
1307         if (MODEST_IS_MAIN_WINDOW (window)) {
1308                 GtkWidget *header_view;
1309                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1310                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1311                 if (!header_view)
1312                         return;
1313                 
1314                 modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
1315         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1316                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
1317         } else {
1318                 g_return_if_reached ();
1319         }
1320 }
1321
1322 void 
1323 modest_ui_actions_on_sort (GtkAction *action, 
1324                            ModestWindow *window)
1325 {
1326         g_return_if_fail (MODEST_IS_WINDOW(window));
1327
1328         if (MODEST_IS_MAIN_WINDOW (window)) {
1329                 GtkWidget *header_view;
1330                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1331                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1332                 if (!header_view)
1333                         return;
1334
1335                 /* Show sorting dialog */
1336                 modest_platform_run_sort_dialog (GTK_WINDOW (window), MODEST_SORT_HEADERS);     
1337         }
1338 }
1339
1340 static void
1341 new_messages_arrived (ModestMailOperation *self, 
1342                       gint new_messages,
1343                       gpointer user_data)
1344 {
1345         if (new_messages == 0)
1346                 return;
1347
1348         modest_platform_on_new_msg ();
1349 }
1350
1351 /*
1352  * This function performs the send & receive required actions. The
1353  * window is used to create the mail operation. Typically it should
1354  * always be the main window, but we pass it as argument in order to
1355  * be more flexible.
1356  */
1357 void
1358 modest_ui_actions_do_send_receive (const gchar *account_name, ModestWindow *win)
1359 {
1360         gchar *acc_name = NULL;
1361         ModestMailOperation *mail_op;
1362
1363         /* If no account name was provided then get the current account, and if
1364            there is no current account then pick the default one: */
1365         if (!account_name) {
1366                 acc_name = g_strdup (modest_window_get_active_account(win));
1367                 if (!acc_name)
1368                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1369                 if (!acc_name) {
1370                         g_printerr ("modest: cannot get default account\n");
1371                         return;
1372                 }
1373         } else {
1374                 acc_name = g_strdup (account_name);
1375         }
1376
1377         /* Set send/receive operation in progress */    
1378         modest_main_window_notify_send_receive_initied (MODEST_MAIN_WINDOW(win));
1379
1380         mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1381                                                                  G_OBJECT (win),
1382                                                                  modest_ui_actions_send_receive_error_handler,
1383                                                                  NULL);
1384
1385         g_signal_connect (G_OBJECT(mail_op), "progress-changed", 
1386                           G_CALLBACK (_on_send_receive_progress_changed), 
1387                           win);
1388
1389         /* Send & receive. */
1390         /* TODO: The spec wants us to first do any pending deletions, before receiving. */
1391         /* Receive and then send. The operation is tagged initially as
1392            a receive operation because the account update performs a
1393            receive and then a send. The operation changes its type
1394            internally, so the progress objects will receive the proper
1395            progress information */
1396         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1397         modest_mail_operation_update_account (mail_op, acc_name, new_messages_arrived, NULL);
1398         g_object_unref (G_OBJECT (mail_op));
1399         
1400         /* Free */
1401         g_free (acc_name);
1402 }
1403
1404
1405 static void
1406 modest_ui_actions_do_cancel_send (const gchar *account_name,  
1407                                   ModestWindow *win)
1408 {
1409         TnyTransportAccount *transport_account;
1410         TnySendQueue *send_queue = NULL;
1411         GError *error = NULL;
1412
1413         /* Get transport account */
1414         transport_account =
1415                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
1416                                       (modest_runtime_get_account_store(),
1417                                        account_name,
1418                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1419         if (!transport_account) {
1420                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1421                 goto frees;
1422         }
1423
1424         /* Get send queue*/
1425         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account));
1426         if (!TNY_IS_SEND_QUEUE(send_queue)) {
1427                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
1428                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
1429                              "modest: could not find send queue for account\n");
1430         } else {
1431                 /* Keeep messages in outbox folder */
1432                 tny_send_queue_cancel (send_queue, FALSE, &error);
1433         }       
1434
1435  frees:
1436         if (transport_account != NULL) 
1437                 g_object_unref (G_OBJECT (transport_account));
1438 }
1439
1440 static void
1441 modest_ui_actions_cancel_send_all (ModestWindow *win) 
1442 {
1443         GSList *account_names, *iter;
1444
1445         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
1446                                                           TRUE);
1447
1448         iter = account_names;
1449         while (iter) {                  
1450                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
1451                 iter = g_slist_next (iter);
1452         }
1453
1454         modest_account_mgr_free_account_names (account_names);
1455         account_names = NULL;
1456 }
1457
1458 void
1459 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
1460
1461 {
1462         /* Check if accounts exist */
1463         gboolean accounts_exist = 
1464                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1465         
1466         /* If not, allow the user to create an account before trying to send/receive. */
1467         if (!accounts_exist)
1468                 modest_ui_actions_on_accounts (NULL, win);
1469         
1470         /* Cancel all sending operaitons */     
1471         modest_ui_actions_cancel_send_all (win);
1472 }
1473
1474 /*
1475  * Refreshes all accounts. This function will be used by automatic
1476  * updates
1477  */
1478 void
1479 modest_ui_actions_do_send_receive_all (ModestWindow *win)
1480 {
1481         GSList *account_names, *iter;
1482
1483         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
1484                                                           TRUE);
1485
1486         iter = account_names;
1487         while (iter) {                  
1488                 modest_ui_actions_do_send_receive ((const char*) iter->data, win);
1489                 iter = g_slist_next (iter);
1490         }
1491
1492         modest_account_mgr_free_account_names (account_names);
1493         account_names = NULL;
1494 }
1495
1496 /*
1497  * Handler of the click on Send&Receive button in the main toolbar
1498  */
1499 void
1500 modest_ui_actions_on_send_receive (GtkAction *action,  ModestWindow *win)
1501 {
1502         /* Check if accounts exist */
1503         gboolean accounts_exist = 
1504                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1505         
1506         /* If not, allow the user to create an account before trying to send/receive. */
1507         if (!accounts_exist)
1508                 modest_ui_actions_on_accounts (NULL, win);
1509
1510         /* Refresh currently selected folder. Note that if we only
1511            want to retrive the headers, then the refresh only will
1512            invoke a poke_status over all folders, i.e., only the
1513            total/unread count will be updated */
1514         if (MODEST_IS_MAIN_WINDOW (win)) {
1515                 GtkWidget *header_view, *folder_view;
1516                 TnyFolderStore *folder_store;
1517
1518                 /* Get folder and header view */
1519                 folder_view = 
1520                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win), 
1521                                                              MODEST_WIDGET_TYPE_FOLDER_VIEW);
1522
1523                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
1524
1525                 if (folder_store && TNY_IS_FOLDER (folder_store)) {
1526                         header_view = 
1527                                 modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
1528                                                                      MODEST_WIDGET_TYPE_HEADER_VIEW);
1529                 
1530                         /* We do not need to set the contents style
1531                            because it hasn't changed. We also do not
1532                            need to save the widget status. Just force
1533                            a refresh */
1534                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
1535                                                        TNY_FOLDER (folder_store),
1536                                                        folder_refreshed_cb,
1537                                                        MODEST_MAIN_WINDOW (win));
1538                 }
1539                 
1540                 if (folder_store)
1541                         g_object_unref (folder_store);
1542         }
1543         
1544         /* Refresh the active account */
1545         modest_ui_actions_do_send_receive (NULL, win);
1546 }
1547
1548
1549 void
1550 modest_ui_actions_toggle_header_list_view (GtkAction *action, ModestMainWindow *main_window)
1551 {
1552         ModestConf *conf;
1553         GtkWidget *header_view;
1554         
1555         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1556
1557         header_view = modest_main_window_get_child_widget (main_window,
1558                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
1559         if (!header_view)
1560                 return;
1561
1562         conf = modest_runtime_get_conf ();
1563         
1564         /* what is saved/restored is depending on the style; thus; we save with
1565          * old style, then update the style, and restore for this new style
1566          */
1567         modest_widget_memory_save (conf, G_OBJECT(header_view), MODEST_CONF_HEADER_VIEW_KEY);
1568         
1569         if (modest_header_view_get_style
1570             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
1571                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
1572                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
1573         else
1574                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
1575                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
1576
1577         modest_widget_memory_restore (conf, G_OBJECT(header_view),
1578                                       MODEST_CONF_HEADER_VIEW_KEY);
1579 }
1580
1581
1582 void 
1583 modest_ui_actions_on_header_selected (ModestHeaderView *header_view, 
1584                                       TnyHeader *header,
1585                                       ModestMainWindow *main_window)
1586 {
1587         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1588         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
1589         
1590         /* If no header has been selected then exit */
1591         if (!header)
1592                 return;
1593
1594         /* Update focus */
1595         if (!gtk_widget_is_focus (GTK_WIDGET(header_view)))
1596             gtk_widget_grab_focus (GTK_WIDGET(header_view));
1597
1598         /* Update Main window title */
1599         if (gtk_widget_is_focus (GTK_WIDGET(header_view))) {
1600                 const gchar *subject = tny_header_get_subject (header);
1601                 if (subject && strlen(subject) > 0)
1602                         gtk_window_set_title (GTK_WINDOW (main_window), subject);
1603                 else
1604                         gtk_window_set_title (GTK_WINDOW (main_window), _("mail_va_no_subject"));
1605         }
1606
1607         /* Update toolbar dimming state */
1608         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
1609 }
1610
1611 void
1612 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
1613                                        TnyHeader *header,
1614                                        ModestMainWindow *main_window)
1615 {
1616         TnyList *headers;
1617
1618         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1619         
1620         if (!header)
1621                 return;
1622
1623         headers = tny_simple_list_new ();
1624         tny_list_prepend (headers, G_OBJECT (header));
1625
1626         _modest_ui_actions_open (headers, MODEST_WINDOW (main_window));
1627
1628         g_object_unref (headers);
1629 }
1630
1631 static void
1632 set_active_account_from_tny_account (TnyAccount *account,
1633                                      ModestWindow *window)
1634 {
1635         const gchar *server_acc_name = tny_account_get_id (account);
1636         
1637         /* We need the TnyAccount provided by the
1638            account store because that is the one that
1639            knows the name of the Modest account */
1640         TnyAccount *modest_server_account = modest_server_account = 
1641                 modest_tny_account_store_get_tny_account_by (modest_runtime_get_account_store (),
1642                                                              MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1643                                                              server_acc_name);
1644         
1645         const gchar *modest_acc_name = 
1646                 modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
1647         modest_window_set_active_account (window, modest_acc_name);
1648         g_object_unref (modest_server_account);
1649 }
1650
1651
1652 static void
1653 folder_refreshed_cb (ModestMailOperation *mail_op, 
1654                      TnyFolder *folder, 
1655                      gpointer user_data)
1656 {
1657         ModestMainWindow *win = NULL;
1658         GtkWidget *header_view;
1659
1660         g_return_if_fail (TNY_IS_FOLDER (folder));
1661
1662         win = MODEST_MAIN_WINDOW (user_data);
1663         header_view = 
1664                 modest_main_window_get_child_widget(win, MODEST_WIDGET_TYPE_HEADER_VIEW);
1665
1666         /* Check if folder is empty and set headers view contents style */
1667         if (tny_folder_get_all_count (folder) == 0) {
1668         printf ("DEBUG: %s: tny_folder_get_all_count() returned 0.\n", __FUNCTION__);
1669                 modest_main_window_set_contents_style (win,
1670                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1671         } else {
1672                 printf ("DEBUG: %s: tny_folder_get_all_count() returned >0.\n", __FUNCTION__);
1673         }
1674 }
1675
1676 void 
1677 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
1678                                                TnyFolderStore *folder_store, 
1679                                                gboolean selected,
1680                                                ModestMainWindow *main_window)
1681 {
1682         ModestConf *conf;
1683         GtkWidget *header_view;
1684
1685         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1686
1687         header_view = modest_main_window_get_child_widget(main_window,
1688                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
1689         if (!header_view)
1690                 return;
1691         
1692         conf = modest_runtime_get_conf ();
1693
1694         if (TNY_IS_ACCOUNT (folder_store)) {
1695                 if (selected) {
1696                         /* Update active account */
1697                         set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
1698                         /* Show account details */
1699                         modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1700                 }
1701         } else {
1702                 if (TNY_IS_FOLDER (folder_store) && selected) {
1703                         
1704                         /* Update the active account */
1705                         TnyAccount *account = modest_tny_folder_get_account (TNY_FOLDER (folder_store));
1706                         if (account) {
1707                                 set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
1708                                 g_object_unref (account);
1709                                 account = NULL;
1710                         }
1711
1712                         /* Set the header style by default, it could
1713                            be changed later by the refresh callback to
1714                            empty */
1715                         modest_main_window_set_contents_style (main_window, 
1716                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1717
1718                         /* Set folder on header view. This function
1719                            will call tny_folder_refresh_async so we
1720                            pass a callback that will be called when
1721                            finished. We use that callback to set the
1722                            empty view if there are no messages */
1723                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
1724                                                        TNY_FOLDER (folder_store),
1725                                                        folder_refreshed_cb,
1726                                                        main_window);
1727                         
1728                         /* Restore configuration. We need to do this
1729                            *after* the set_folder because the widget
1730                            memory asks the header view about its
1731                            folder  */
1732                         modest_widget_memory_restore (modest_runtime_get_conf (), 
1733                                                       G_OBJECT(header_view),
1734                                                       MODEST_CONF_HEADER_VIEW_KEY);
1735                 } else {
1736                         /* Update the active account */
1737                         modest_window_set_active_account (MODEST_WINDOW (main_window), NULL);
1738                         /* Save only if we're seeing headers */
1739                         if (modest_main_window_get_contents_style (main_window) ==
1740                             MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1741                                 modest_widget_memory_save (conf, G_OBJECT (header_view), 
1742                                                            MODEST_CONF_HEADER_VIEW_KEY);
1743                         modest_header_view_clear (MODEST_HEADER_VIEW(header_view));
1744                 }
1745         }
1746
1747         /* Update toolbar dimming state */
1748         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
1749 }
1750
1751 void 
1752 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
1753                                      ModestWindow *win)
1754 {
1755         GtkWidget *dialog;
1756         gchar *txt, *item;
1757         gboolean online;
1758
1759         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1760         
1761         online = tny_device_is_online (modest_runtime_get_device());
1762
1763         if (online) {
1764                 /* already online -- the item is simply not there... */
1765                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
1766                                                  GTK_DIALOG_MODAL,
1767                                                  GTK_MESSAGE_WARNING,
1768                                                  GTK_BUTTONS_OK,
1769                                                  _("The %s you selected cannot be found"),
1770                                                  item);
1771                 gtk_dialog_run (GTK_DIALOG(dialog));
1772         } else {
1773                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1774                                                       GTK_WINDOW (win),
1775                                                       GTK_DIALOG_MODAL,
1776                                                       GTK_STOCK_CANCEL,
1777                                                       GTK_RESPONSE_REJECT,
1778                                                       GTK_STOCK_OK,
1779                                                       GTK_RESPONSE_ACCEPT,
1780                                                       NULL);
1781                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1782                                          "Do you want to get online?"), item);
1783                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1784                                     gtk_label_new (txt), FALSE, FALSE, 0);
1785                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1786                 g_free (txt);
1787
1788                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1789                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1790 //                      modest_platform_connect_and_wait ();
1791                 }
1792         }
1793         gtk_widget_destroy (dialog);
1794 }
1795
1796 void
1797 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
1798                                      ModestWindow *win)
1799 {
1800         /* g_message ("%s %s", __FUNCTION__, link); */
1801 }       
1802
1803
1804 void
1805 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
1806                                         ModestWindow *win)
1807 {
1808         modest_platform_activate_uri (link);
1809 }
1810
1811 void
1812 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
1813                                           ModestWindow *win)
1814 {
1815         modest_platform_show_uri_popup (link);
1816 }
1817
1818 void
1819 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
1820                                              ModestWindow *win)
1821 {
1822         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
1823 }
1824
1825 void
1826 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
1827                                           const gchar *address,
1828                                           ModestWindow *win)
1829 {
1830         /* g_message ("%s %s", __FUNCTION__, address); */
1831 }
1832
1833 void
1834 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
1835 {
1836         TnyTransportAccount *transport_account;
1837         ModestMailOperation *mail_operation;
1838         MsgData *data;
1839         gchar *account_name, *from;
1840         ModestAccountMgr *account_mgr;
1841         gchar *info_text = NULL;
1842
1843         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
1844         
1845         data = modest_msg_edit_window_get_msg_data (edit_window);
1846
1847         account_mgr = modest_runtime_get_account_mgr();
1848         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
1849         if (!account_name) 
1850                 account_name = modest_account_mgr_get_default_account (account_mgr);
1851         if (!account_name) {
1852                 g_printerr ("modest: no account found\n");
1853                 modest_msg_edit_window_free_msg_data (edit_window, data);
1854                 return;
1855         }
1856
1857         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1858                 account_name = g_strdup (data->account_name);
1859         }
1860
1861         transport_account =
1862                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
1863                                       (modest_runtime_get_account_store(),
1864                                        account_name,
1865                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1866         if (!transport_account) {
1867                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1868                 g_free (account_name);
1869                 modest_msg_edit_window_free_msg_data (edit_window, data);
1870                 return;
1871         }
1872         from = modest_account_mgr_get_from_string (account_mgr, account_name);
1873
1874         /* Create the mail operation */         
1875         mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_INFO, G_OBJECT(edit_window));
1876         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
1877
1878         modest_mail_operation_save_to_drafts (mail_operation,
1879                                               transport_account,
1880                                               data->draft_msg,
1881                                               edit_window,
1882                                               from,
1883                                               data->to, 
1884                                               data->cc, 
1885                                               data->bcc,
1886                                               data->subject, 
1887                                               data->plain_body, 
1888                                               data->html_body,
1889                                               data->attachments,
1890                                               data->priority_flags);
1891         /* Frees */
1892         g_free (from);
1893         g_free (account_name);
1894         g_object_unref (G_OBJECT (transport_account));
1895         g_object_unref (G_OBJECT (mail_operation));
1896
1897         modest_msg_edit_window_free_msg_data (edit_window, data);
1898
1899         info_text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
1900         modest_platform_information_banner (NULL, NULL, info_text);
1901         g_free (info_text);
1902 }
1903
1904 /* For instance, when clicking the Send toolbar button when editing a message: */
1905 void
1906 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
1907 {
1908         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
1909
1910         if (!modest_msg_edit_window_check_names (edit_window))
1911                 return;
1912         
1913         /* Offer the connection dialog, if necessary: */        
1914         if (!modest_platform_connect_and_wait (GTK_WINDOW (edit_window)))
1915                 return;
1916         
1917         /* FIXME: Code added just for testing. The final version will
1918            use the send queue provided by tinymail and some
1919            classifier */
1920         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
1921         gchar *account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
1922         if (!account_name) 
1923                 account_name = modest_account_mgr_get_default_account (account_mgr);
1924                 
1925         if (!account_name) {
1926                 g_printerr ("modest: no account found\n");
1927                 return;
1928         }
1929         
1930         MsgData *data = modest_msg_edit_window_get_msg_data (edit_window);
1931
1932         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1933                 account_name = g_strdup (data->account_name);
1934         }
1935         
1936         /* Get the currently-active transport account for this modest account: */
1937         TnyTransportAccount *transport_account =
1938                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_transport_account_for_open_connection
1939                                       (modest_runtime_get_account_store(),
1940                                        account_name));
1941         if (!transport_account) {
1942                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1943                 g_free (account_name);
1944                 modest_msg_edit_window_free_msg_data (edit_window, data);
1945                 return;
1946         }
1947         
1948         gchar *from = modest_account_mgr_get_from_string (account_mgr, account_name);
1949
1950         /* mail content checks and dialogs */
1951         if (data->subject == NULL || data->subject[0] == '\0') {
1952                 GtkResponseType response;
1953                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (edit_window),
1954                                                                     _("mcen_nc_subject_is_empty_send"));
1955                 if (response == GTK_RESPONSE_CANCEL) {
1956                         g_free (account_name);
1957                         return;
1958                 }
1959         }
1960
1961         if (data->plain_body == NULL || data->plain_body[0] == '\0') {
1962                 GtkResponseType response;
1963                 gchar *note_message;
1964                 gchar *note_subject = data->subject;
1965                 if (note_subject == NULL || note_subject[0] == '\0')
1966                         note_subject = _("mail_va_no_subject");
1967                 note_message = g_strdup_printf (_("emev_ni_ui_smtp_message_null"), note_subject);
1968                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (edit_window),
1969                                                                     note_message);
1970                 g_free (note_message);
1971                 if (response == GTK_RESPONSE_CANCEL) {
1972                         g_free (account_name);
1973                         return;
1974                 }
1975         }
1976
1977         modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
1978
1979         /* Create the mail operation */
1980         ModestMailOperation *mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_SEND, G_OBJECT(edit_window));
1981         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
1982
1983         modest_mail_operation_send_new_mail (mail_operation,
1984                                              transport_account,
1985                                              data->draft_msg,
1986                                              from,
1987                                              data->to, 
1988                                              data->cc, 
1989                                              data->bcc,
1990                                              data->subject, 
1991                                              data->plain_body, 
1992                                              data->html_body,
1993                                              data->attachments,
1994                                              data->priority_flags);
1995                                              
1996         /* Free data: */
1997         g_free (from);
1998         g_free (account_name);
1999         g_object_unref (G_OBJECT (transport_account));
2000         g_object_unref (G_OBJECT (mail_operation));
2001
2002         modest_msg_edit_window_free_msg_data (edit_window, data);
2003         modest_msg_edit_window_set_sent (edit_window, TRUE);
2004
2005         /* Save settings and close the window: */
2006         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2007 }
2008
2009 void 
2010 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
2011                                   ModestMsgEditWindow *window)
2012 {
2013         ModestMsgEditFormatState *format_state = NULL;
2014
2015         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2016         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2017
2018         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2019                 return;
2020
2021         format_state = modest_msg_edit_window_get_format_state (window);
2022         g_return_if_fail (format_state != NULL);
2023
2024         format_state->bold = gtk_toggle_action_get_active (action);
2025         modest_msg_edit_window_set_format_state (window, format_state);
2026         g_free (format_state);
2027         
2028 }
2029
2030 void 
2031 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
2032                                      ModestMsgEditWindow *window)
2033 {
2034         ModestMsgEditFormatState *format_state = NULL;
2035
2036         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2037         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2038
2039         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2040                 return;
2041
2042         format_state = modest_msg_edit_window_get_format_state (window);
2043         g_return_if_fail (format_state != NULL);
2044
2045         format_state->italics = gtk_toggle_action_get_active (action);
2046         modest_msg_edit_window_set_format_state (window, format_state);
2047         g_free (format_state);
2048         
2049 }
2050
2051 void 
2052 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
2053                                      ModestMsgEditWindow *window)
2054 {
2055         ModestMsgEditFormatState *format_state = NULL;
2056
2057         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2058         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2059
2060         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2061                 return;
2062
2063         format_state = modest_msg_edit_window_get_format_state (window);
2064         g_return_if_fail (format_state != NULL);
2065
2066         format_state->bullet = gtk_toggle_action_get_active (action);
2067         modest_msg_edit_window_set_format_state (window, format_state);
2068         g_free (format_state);
2069         
2070 }
2071
2072 void 
2073 modest_ui_actions_on_change_justify (GtkRadioAction *action,
2074                                      GtkRadioAction *selected,
2075                                      ModestMsgEditWindow *window)
2076 {
2077         ModestMsgEditFormatState *format_state = NULL;
2078         GtkJustification value;
2079
2080         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2081
2082         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2083                 return;
2084
2085         value = gtk_radio_action_get_current_value (selected);
2086
2087         format_state = modest_msg_edit_window_get_format_state (window);
2088         g_return_if_fail (format_state != NULL);
2089
2090         format_state->justification = value;
2091         modest_msg_edit_window_set_format_state (window, format_state);
2092         g_free (format_state);
2093 }
2094
2095 void 
2096 modest_ui_actions_on_select_editor_color (GtkAction *action,
2097                                           ModestMsgEditWindow *window)
2098 {
2099         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2100         g_return_if_fail (GTK_IS_ACTION (action));
2101
2102         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2103                 return;
2104
2105         modest_msg_edit_window_select_color (window);
2106 }
2107
2108 void 
2109 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
2110                                                      ModestMsgEditWindow *window)
2111 {
2112         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2113         g_return_if_fail (GTK_IS_ACTION (action));
2114
2115         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2116                 return;
2117
2118         modest_msg_edit_window_select_background_color (window);
2119 }
2120
2121 void 
2122 modest_ui_actions_on_insert_image (GtkAction *action,
2123                                    ModestMsgEditWindow *window)
2124 {
2125         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2126         g_return_if_fail (GTK_IS_ACTION (action));
2127
2128         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2129                 return;
2130
2131         modest_msg_edit_window_insert_image (window);
2132 }
2133
2134 void 
2135 modest_ui_actions_on_attach_file (GtkAction *action,
2136                                   ModestMsgEditWindow *window)
2137 {
2138         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2139         g_return_if_fail (GTK_IS_ACTION (action));
2140
2141         modest_msg_edit_window_attach_file (window);
2142 }
2143
2144 void 
2145 modest_ui_actions_on_remove_attachments (GtkAction *action,
2146                                          ModestMsgEditWindow *window)
2147 {
2148         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2149         g_return_if_fail (GTK_IS_ACTION (action));
2150
2151         modest_msg_edit_window_remove_attachments (window, NULL);
2152 }
2153
2154 static void
2155 modest_ui_actions_new_folder_error_handler (ModestMailOperation *mail_op,
2156                                             gpointer user_data)
2157 {
2158         ModestMainWindow *window = MODEST_MAIN_WINDOW (user_data);
2159
2160         /* TODO: Note that folder creation might go wrong due to other
2161          * failures such as when the parent folder is non-writable. We can
2162          * query a GError* with modest_mail_operation_get_error(), but the
2163          * the error code (from tinymail) does not give us a clue about what
2164          * has gone wrong. We might use the error->message but it might come
2165          * from camel and not be suitable to show to the user directly. */
2166         modest_platform_information_banner (GTK_WIDGET (window), NULL,
2167                                             _CS("ckdg_ib_folder_already_exists"));
2168
2169 /*      modest_platform_information_banner (GTK_WIDGET (window), NULL,
2170                                             modest_mail_operation_get_error (mail_op)->message);*/
2171 }
2172
2173
2174 void 
2175 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
2176 {
2177         TnyFolderStore *parent_folder;
2178         GtkWidget *folder_view;
2179         
2180         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2181
2182         folder_view = modest_main_window_get_child_widget (main_window,
2183                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
2184         if (!folder_view)
2185                 return;
2186
2187         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
2188         
2189         if (parent_folder) {
2190                 gboolean finished = FALSE;
2191                 gint result;
2192                 gchar *folder_name = NULL, *suggested_name = NULL;
2193
2194                 /* Run the new folder dialog */
2195                 while (!finished) {
2196                         result = modest_platform_run_new_folder_dialog (GTK_WINDOW (main_window),
2197                                                                         parent_folder,
2198                                                                         suggested_name,
2199                                                                         &folder_name);
2200
2201                         g_free (suggested_name);
2202                         suggested_name = NULL;
2203
2204                         if (result == GTK_RESPONSE_REJECT) {
2205                                 finished = TRUE;
2206                         } else {
2207                                 ModestMailOperation *mail_op;
2208                                 TnyFolder *new_folder = NULL;
2209
2210                                 mail_op  = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_INFO,
2211                                                                                           G_OBJECT(main_window),
2212                                                                                           modest_ui_actions_new_folder_error_handler,
2213                                                                                           main_window);
2214
2215                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
2216                                                                  mail_op);
2217                                 new_folder = modest_mail_operation_create_folder (mail_op,
2218                                                                                   parent_folder,
2219                                                                                   (const gchar *) folder_name);
2220                                 if (new_folder) {
2221                                         if (main_window) {
2222                                                 folder_view = modest_main_window_get_child_widget (main_window,
2223                                                                                                    MODEST_WIDGET_TYPE_FOLDER_VIEW);
2224                                                 if (folder_view)
2225                                                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW(folder_view), 
2226                                                                                           new_folder, TRUE);
2227                                         }
2228
2229                                         g_object_unref (new_folder);
2230                                         finished = TRUE;
2231                                 }
2232                                 g_object_unref (mail_op);
2233                         }
2234
2235                         suggested_name = folder_name;
2236                         folder_name = NULL;
2237                 }
2238
2239                 g_object_unref (parent_folder);
2240         }
2241 }
2242
2243 static void
2244 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
2245                                                gpointer user_data)
2246 {
2247         GObject *win = modest_mail_operation_get_source (mail_op);
2248         const GError *error = NULL;
2249         const gchar *message = NULL;
2250         
2251         /* Get error message */
2252         error = modest_mail_operation_get_error (mail_op);
2253         if (error != NULL && error->message != NULL) {
2254                 message = error->message;
2255         } else {
2256                 message = _("!!! FIXME: Unable to rename");
2257         }
2258         
2259         /* Show notification dialog */
2260         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, message);
2261         g_object_unref (win);
2262 }
2263
2264 void 
2265 modest_ui_actions_on_rename_folder (GtkAction *action,
2266                                      ModestMainWindow *main_window)
2267 {
2268         TnyFolderStore *folder;
2269         GtkWidget *folder_view;
2270         GtkWidget *header_view; 
2271
2272         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2273
2274         folder_view = modest_main_window_get_child_widget (main_window,
2275                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
2276         if (!folder_view)
2277                 return;
2278
2279         header_view = modest_main_window_get_child_widget (main_window,
2280                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
2281         
2282         if (!header_view)
2283                 return;
2284
2285         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
2286
2287         /* Offer the connection dialog if necessary: */
2288         if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, folder)) {
2289                 g_object_unref (G_OBJECT (folder));
2290                 return;
2291         }
2292
2293         
2294         if (folder && TNY_IS_FOLDER (folder)) {
2295                 gchar *folder_name;
2296                 gint response;
2297                 const gchar *current_name;
2298
2299                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
2300                 response = modest_platform_run_rename_folder_dialog (GTK_WINDOW (main_window), NULL,
2301                                                                      current_name, &folder_name);
2302
2303                 if (response == GTK_RESPONSE_ACCEPT && strlen (folder_name) > 0) {
2304                         ModestMailOperation *mail_op;
2305
2306                         mail_op = 
2307                                 modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_INFO, 
2308                                                                                G_OBJECT(main_window),
2309                                                                                modest_ui_actions_rename_folder_error_handler,
2310                                                                                NULL);
2311
2312
2313                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2314                                                          mail_op);
2315
2316                         modest_header_view_clear (MODEST_HEADER_VIEW (header_view));
2317                         
2318                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW(folder_view),
2319                                                           TNY_FOLDER(folder), TRUE);
2320
2321                         modest_mail_operation_rename_folder (mail_op,
2322                                                              TNY_FOLDER (folder),
2323                                                              (const gchar *) folder_name);
2324
2325                         g_object_unref (mail_op);
2326                         g_free (folder_name);
2327                 }
2328                 g_object_unref (folder);
2329         }
2330 }
2331
2332 static void
2333 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
2334                                                gpointer user_data)
2335 {
2336         GObject *win = modest_mail_operation_get_source (mail_op);
2337
2338         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
2339                                                 _("mail_in_ui_folder_delete_error"));
2340         g_object_unref (win);
2341 }
2342
2343 static void
2344 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
2345 {
2346         TnyFolderStore *folder;
2347         GtkWidget *folder_view;
2348         gint response;
2349         gchar *message;
2350         
2351         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2352
2353         folder_view = modest_main_window_get_child_widget (main_window,
2354                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
2355         if (!folder_view)
2356                 return;
2357
2358         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2359
2360         /* Show an error if it's an account */
2361         if (!TNY_IS_FOLDER (folder)) {
2362                 modest_platform_run_information_dialog (GTK_WINDOW (main_window),
2363                                                         _("mail_in_ui_folder_delete_error"));
2364                 g_object_unref (G_OBJECT (folder));
2365                 return ;
2366         }
2367
2368         /* Offer the connection dialog if necessary: */
2369         if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, folder)) {
2370                 g_object_unref (G_OBJECT (folder));
2371                 return;
2372         }
2373
2374         /* Ask the user */      
2375         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"), 
2376                                     tny_folder_get_name (TNY_FOLDER (folder)));
2377         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (main_window),
2378                                                             (const gchar *) message);
2379         g_free (message);
2380
2381         if (response == GTK_RESPONSE_OK) {
2382                 ModestMailOperation *mail_op = 
2383                         modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_DELETE, 
2384                                                                        G_OBJECT(main_window),
2385                                                                        modest_ui_actions_delete_folder_error_handler,
2386                                                                        NULL);
2387
2388                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2389                                                  mail_op);
2390                 modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (folder), move_to_trash);
2391                 g_object_unref (G_OBJECT (mail_op));
2392         }
2393
2394         g_object_unref (G_OBJECT (folder));
2395 }
2396
2397 void 
2398 modest_ui_actions_on_delete_folder (GtkAction *action,
2399                                      ModestMainWindow *main_window)
2400 {
2401         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2402
2403         delete_folder (main_window, FALSE);
2404 }
2405
2406 void 
2407 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
2408 {
2409         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2410         
2411         delete_folder (main_window, TRUE);
2412 }
2413
2414 void
2415 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
2416                                          const gchar* server_account_name,
2417                                          gchar **username,
2418                                          gchar **password, 
2419                                          gboolean *cancel, 
2420                                          gboolean *remember,
2421                                          ModestMainWindow *main_window)
2422 {
2423         g_return_if_fail(server_account_name);
2424         /* printf("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
2425         
2426         /* Initalize output parameters: */
2427         if (cancel)
2428                 *cancel = FALSE;
2429                 
2430         if (remember)
2431                 *remember = TRUE;
2432                 
2433 #ifdef MODEST_PLATFORM_MAEMO
2434         /* Maemo uses a different (awkward) button order,
2435          * It should probably just use gtk_alternative_dialog_button_order ().
2436          */
2437         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
2438                                               NULL,
2439                                               GTK_DIALOG_MODAL,
2440                                               GTK_STOCK_OK,
2441                                               GTK_RESPONSE_ACCEPT,
2442                                               GTK_STOCK_CANCEL,
2443                                               GTK_RESPONSE_REJECT,
2444                                               NULL);
2445 #else
2446         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
2447                                               NULL,
2448                                               GTK_DIALOG_MODAL,
2449                                               GTK_STOCK_CANCEL,
2450                                               GTK_RESPONSE_REJECT,
2451                                               GTK_STOCK_OK,
2452                                               GTK_RESPONSE_ACCEPT,
2453                                               NULL);
2454 #endif /* MODEST_PLATFORM_MAEMO */
2455
2456         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
2457         
2458         gchar *server_name = modest_server_account_get_hostname (
2459                 modest_runtime_get_account_mgr(), server_account_name);
2460         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
2461                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
2462                 *cancel = TRUE;
2463                 return;
2464         }
2465         
2466         /* This causes a warning because the logical ID has no %s in it, 
2467          * though the translation does, but there is not much we can do about that: */
2468         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
2469         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
2470                             FALSE, FALSE, 0);
2471         g_free (txt);
2472         g_free (server_name);
2473         server_name = NULL;
2474
2475         /* username: */
2476         gchar *initial_username = modest_server_account_get_username (
2477                 modest_runtime_get_account_mgr(), server_account_name);
2478         
2479         GtkWidget *entry_username = gtk_entry_new ();
2480         if (initial_username)
2481                 gtk_entry_set_text (GTK_ENTRY (entry_username), initial_username);
2482         /* Dim this if a connection has ever succeeded with this username,
2483          * as per the UI spec: */
2484         const gboolean username_known = 
2485                 modest_server_account_get_username_has_succeeded(
2486                         modest_runtime_get_account_mgr(), server_account_name);
2487         gtk_widget_set_sensitive (entry_username, !username_known);
2488         
2489 #ifdef MODEST_PLATFORM_MAEMO
2490         /* Auto-capitalization is the default, so let's turn it off: */
2491         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
2492         
2493         /* Create a size group to be used by all captions.
2494          * Note that HildonCaption does not create a default size group if we do not specify one.
2495          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
2496         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2497         
2498         GtkWidget *caption = hildon_caption_new (sizegroup, 
2499                 _("mail_fi_username"), entry_username, NULL, HILDON_CAPTION_MANDATORY);
2500         gtk_widget_show (entry_username);
2501         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
2502                 FALSE, FALSE, MODEST_MARGIN_HALF);
2503         gtk_widget_show (caption);
2504 #else 
2505         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_username,
2506                             TRUE, FALSE, 0);
2507 #endif /* MODEST_PLATFORM_MAEMO */      
2508                             
2509         /* password: */
2510         GtkWidget *entry_password = gtk_entry_new ();
2511         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
2512         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
2513         
2514 #ifdef MODEST_PLATFORM_MAEMO
2515         /* Auto-capitalization is the default, so let's turn it off: */
2516         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password), 
2517                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
2518         
2519         caption = hildon_caption_new (sizegroup, 
2520                 _("mail_fi_password"), entry_password, NULL, HILDON_CAPTION_MANDATORY);
2521         gtk_widget_show (entry_password);
2522         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
2523                 FALSE, FALSE, MODEST_MARGIN_HALF);
2524         gtk_widget_show (caption);
2525         g_object_unref (sizegroup);
2526 #else 
2527         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_password,
2528                             TRUE, FALSE, 0);
2529 #endif /* MODEST_PLATFORM_MAEMO */      
2530                                 
2531 /* This is not in the Maemo UI spec:
2532         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
2533         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
2534                             TRUE, FALSE, 0);
2535 */
2536
2537         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2538         
2539         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2540                 if (username) {
2541                         *username = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_username)));
2542                         
2543                         modest_server_account_set_username (
2544                                  modest_runtime_get_account_mgr(), server_account_name, 
2545                                  *username);
2546                                  
2547                         const gboolean username_was_changed = 
2548                                 (strcmp (*username, initial_username) != 0);
2549                         if (username_was_changed) {
2550                                 g_warning ("%s: tinymail does not yet support changing the "
2551                                         "username in the get_password() callback.\n", __FUNCTION__);
2552                         }
2553                 }
2554                         
2555                 if (password) {
2556                         *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_password)));
2557                         
2558                         /* We do not save the password in the configuration, 
2559                          * because this function is only called for passwords that should 
2560                          * not be remembered:
2561                         modest_server_account_set_password (
2562                                  modest_runtime_get_account_mgr(), server_account_name, 
2563                                  *password);
2564                         */
2565                 }
2566                 
2567                 if (cancel)
2568                         *cancel   = FALSE;
2569                         
2570         } else {
2571                 if (username)
2572                         *username = NULL;
2573                         
2574                 if (password)
2575                         *password = NULL;
2576                         
2577                 if (cancel)
2578                         *cancel   = TRUE;
2579         }
2580
2581 /* This is not in the Maemo UI spec:
2582         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
2583                 *remember = TRUE;
2584         else
2585                 *remember = FALSE;
2586 */
2587
2588         gtk_widget_destroy (dialog);
2589         
2590         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
2591 }
2592
2593 void
2594 modest_ui_actions_on_cut (GtkAction *action,
2595                           ModestWindow *window)
2596 {
2597         GtkWidget *focused_widget;
2598
2599         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2600         if (GTK_IS_EDITABLE (focused_widget)) {
2601                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
2602         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2603                 GtkTextBuffer *buffer;
2604                 GtkClipboard *clipboard;
2605
2606                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2607                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2608                 gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
2609                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
2610         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
2611                 modest_header_view_cut_selection (MODEST_HEADER_VIEW (focused_widget));
2612         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2613                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
2614         }
2615 }
2616
2617 void
2618 modest_ui_actions_on_copy (GtkAction *action,
2619                            ModestWindow *window)
2620 {
2621         GtkClipboard *clipboard;
2622         GtkWidget *focused_widget;
2623
2624         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2625         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2626
2627         if (GTK_IS_LABEL (focused_widget)) {
2628                 gtk_clipboard_set_text (clipboard, gtk_label_get_text (GTK_LABEL (focused_widget)), -1);
2629         } else if (GTK_IS_EDITABLE (focused_widget)) {
2630                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
2631         } else if (GTK_IS_HTML (focused_widget)) {
2632                 gtk_html_copy (GTK_HTML (focused_widget));
2633         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2634                 GtkTextBuffer *buffer;
2635                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2636                 gtk_text_buffer_copy_clipboard (buffer, clipboard);
2637                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
2638         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
2639                 TnyList *header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (focused_widget));
2640                 TnyIterator *iter = tny_list_create_iterator (header_list);
2641                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2642                 TnyFolder *folder = tny_header_get_folder (header);
2643                 TnyAccount *account = tny_folder_get_account (folder);
2644                 const gchar *proto_str = tny_account_get_proto (TNY_ACCOUNT (account));
2645                 /* If it's POP then ask */
2646                 gboolean ask = (modest_protocol_info_get_transport_store_protocol (proto_str) == 
2647                        MODEST_PROTOCOL_STORE_POP) ? TRUE : FALSE;
2648                 g_object_unref (account);
2649                 g_object_unref (folder);
2650                 g_object_unref (header);
2651                 g_object_unref (iter);
2652                 
2653                 /* Check that the messages have been previously downloaded */
2654                 gboolean continue_download = TRUE;
2655                 if (ask)
2656                         continue_download = download_uncached_messages (header_list, GTK_WINDOW (window), FALSE);
2657                 if (continue_download)
2658                         modest_header_view_copy_selection (MODEST_HEADER_VIEW (focused_widget));
2659                 g_object_unref (header_list);
2660         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2661                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
2662         }    
2663
2664         /* Show information banner */
2665         modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
2666         
2667 }
2668
2669 void
2670 modest_ui_actions_on_undo (GtkAction *action,
2671                            ModestWindow *window)
2672 {
2673         ModestEmailClipboard *clipboard = NULL;
2674
2675         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
2676                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
2677         } else if (MODEST_IS_MAIN_WINDOW (window)) {
2678                 /* Clear clipboard source */
2679                 clipboard = modest_runtime_get_email_clipboard ();
2680                 modest_email_clipboard_clear (clipboard);               
2681         }
2682         else {
2683                 g_return_if_reached ();
2684         }
2685 }
2686
2687 void
2688 modest_ui_actions_on_redo (GtkAction *action,
2689                            ModestWindow *window)
2690 {
2691         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
2692                 modest_msg_edit_window_redo (MODEST_MSG_EDIT_WINDOW (window));
2693         }
2694         else {
2695                 g_return_if_reached ();
2696         }
2697 }
2698
2699
2700 static void
2701 paste_msgs_cb (const GObject *object, gpointer user_data)
2702 {
2703         g_return_if_fail (MODEST_IS_MAIN_WINDOW (object));
2704         g_return_if_fail (GTK_IS_WIDGET (user_data));
2705         
2706         /* destroy information note */
2707         gtk_widget_destroy (GTK_WIDGET(user_data));
2708 }
2709
2710 void
2711 modest_ui_actions_on_paste (GtkAction *action,
2712                             ModestWindow *window)
2713 {
2714         GtkWidget *focused_widget = NULL;
2715         GtkWidget *inf_note = NULL;
2716         ModestMailOperation *mail_op = NULL;
2717
2718         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2719         if (GTK_IS_EDITABLE (focused_widget)) {
2720                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
2721         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2722                 GtkTextBuffer *buffer;
2723                 GtkClipboard *clipboard;
2724
2725                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2726                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2727                 gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
2728         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2729                 ModestEmailClipboard *clipboard = NULL;
2730                 TnyFolder *src_folder = NULL;
2731                 TnyFolderStore *folder_store = NULL;
2732                 TnyList *data = NULL;           
2733                 gboolean delete = FALSE;
2734                 
2735                 /* Check clipboard source */
2736                 clipboard = modest_runtime_get_email_clipboard ();
2737                 if (modest_email_clipboard_cleared (clipboard)) 
2738                         return;
2739                 
2740                 /* Get elements to paste */
2741                 modest_email_clipboard_get_data (clipboard, &src_folder, &data, &delete);
2742
2743                 /* Create a new mail operation */
2744                 mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(window));
2745                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
2746                                                  mail_op);
2747                 
2748                 /* Get destination folder */
2749                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (focused_widget));
2750
2751                 /* Launch notification */
2752                 inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL, 
2753                                                              _CS("ckct_nw_pasting"));
2754                 if (inf_note != NULL)  {
2755                         gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
2756                         gtk_widget_show (GTK_WIDGET(inf_note));
2757                 }
2758
2759                 /* transfer messages  */
2760                 if (data != NULL) {
2761                         modest_mail_operation_xfer_msgs (mail_op, 
2762                                                          data,
2763                                                          TNY_FOLDER (folder_store),
2764                                                          delete,
2765                                                          paste_msgs_cb,
2766                                                          inf_note);
2767                         
2768                 } else if (src_folder != NULL) {                        
2769                         modest_mail_operation_xfer_folder (mail_op, 
2770                                                            src_folder,
2771                                                            folder_store,
2772                                                            delete,
2773                                                            paste_msgs_cb,
2774                                                            inf_note);
2775                 }
2776
2777                 /* Free */
2778                 if (data != NULL) 
2779                         g_object_unref (data);
2780                 if (src_folder != NULL) 
2781                         g_object_unref (src_folder);
2782                 if (folder_store != NULL) 
2783                         g_object_unref (folder_store);
2784         }
2785 }
2786
2787
2788 void
2789 modest_ui_actions_on_select_all (GtkAction *action,
2790                                  ModestWindow *window)
2791 {
2792         GtkWidget *focused_widget;
2793
2794         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2795         if (MODEST_IS_ATTACHMENTS_VIEW (focused_widget)) {
2796                 modest_attachments_view_select_all (MODEST_ATTACHMENTS_VIEW (focused_widget));
2797         } else if (GTK_IS_LABEL (focused_widget)) {
2798                 gtk_label_select_region (GTK_LABEL (focused_widget), 0, -1);
2799         } else if (GTK_IS_EDITABLE (focused_widget)) {
2800                 gtk_editable_select_region (GTK_EDITABLE(focused_widget), 0, -1);
2801         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2802                 GtkTextBuffer *buffer;
2803                 GtkTextIter start, end;
2804
2805                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2806                 gtk_text_buffer_get_start_iter (buffer, &start);
2807                 gtk_text_buffer_get_end_iter (buffer, &end);
2808                 gtk_text_buffer_select_range (buffer, &start, &end);
2809         } else if (GTK_IS_HTML (focused_widget)) {
2810                 gtk_html_select_all (GTK_HTML (focused_widget));
2811         } else if (MODEST_IS_MAIN_WINDOW (window)) {
2812                 GtkWidget *header_view = focused_widget;
2813                 GtkTreeSelection *selection = NULL;
2814                 
2815                 if (!(MODEST_IS_HEADER_VIEW (focused_widget)))
2816                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
2817                                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
2818                                 
2819                 /* Select all messages */
2820                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
2821                 gtk_tree_selection_select_all (selection);
2822
2823                 /* Set focuse on header view */
2824                 gtk_widget_grab_focus (header_view);
2825         }
2826
2827 }
2828
2829 void
2830 modest_ui_actions_on_mark_as_read (GtkAction *action,
2831                                    ModestWindow *window)
2832 {       
2833         g_return_if_fail (MODEST_IS_WINDOW(window));
2834                 
2835         /* Mark each header as read */
2836         do_headers_action (window, headers_action_mark_as_read, NULL);
2837 }
2838
2839 void
2840 modest_ui_actions_on_mark_as_unread (GtkAction *action,
2841                                      ModestWindow *window)
2842 {       
2843         g_return_if_fail (MODEST_IS_WINDOW(window));
2844                 
2845         /* Mark each header as read */
2846         do_headers_action (window, headers_action_mark_as_unread, NULL);
2847 }
2848
2849 void
2850 modest_ui_actions_on_change_zoom (GtkRadioAction *action,
2851                                   GtkRadioAction *selected,
2852                                   ModestWindow *window)
2853 {
2854         gint value;
2855
2856         value = gtk_radio_action_get_current_value (selected);
2857         if (MODEST_IS_WINDOW (window)) {
2858                 modest_window_set_zoom (MODEST_WINDOW (window), ((gdouble)value)/100);
2859         }
2860 }
2861
2862 void     modest_ui_actions_msg_edit_on_change_priority (GtkRadioAction *action,
2863                                                         GtkRadioAction *selected,
2864                                                         ModestWindow *window)
2865 {
2866         TnyHeaderFlags flags;
2867         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2868
2869         flags = gtk_radio_action_get_current_value (selected);
2870         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW (window), flags);
2871 }
2872
2873 void     modest_ui_actions_msg_edit_on_change_file_format (GtkRadioAction *action,
2874                                                            GtkRadioAction *selected,
2875                                                            ModestWindow *window)
2876 {
2877         gint file_format;
2878
2879         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2880
2881         file_format = gtk_radio_action_get_current_value (selected);
2882         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (window), file_format);
2883 }
2884
2885
2886 void     
2887 modest_ui_actions_on_zoom_plus (GtkAction *action,
2888                                 ModestWindow *window)
2889 {
2890         g_return_if_fail (MODEST_IS_WINDOW (window));
2891
2892         modest_window_zoom_plus (MODEST_WINDOW (window));
2893 }
2894
2895 void     
2896 modest_ui_actions_on_zoom_minus (GtkAction *action,
2897                                  ModestWindow *window)
2898 {
2899         g_return_if_fail (MODEST_IS_WINDOW (window));
2900
2901         modest_window_zoom_minus (MODEST_WINDOW (window));
2902 }
2903
2904 void     
2905 modest_ui_actions_on_toggle_fullscreen    (GtkToggleAction *toggle,
2906                                            ModestWindow *window)
2907 {
2908         ModestWindowMgr *mgr;
2909         gboolean fullscreen, active;
2910         g_return_if_fail (MODEST_IS_WINDOW (window));
2911
2912         mgr = modest_runtime_get_window_mgr ();
2913
2914         active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle)))?1:0;
2915         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
2916
2917         if (active != fullscreen) {
2918                 modest_window_mgr_set_fullscreen_mode (mgr, active);
2919                 gtk_window_present (GTK_WINDOW (window));
2920         }
2921 }
2922
2923 void
2924 modest_ui_actions_on_change_fullscreen (GtkAction *action,
2925                                         ModestWindow *window)
2926 {
2927         ModestWindowMgr *mgr;
2928         gboolean fullscreen;
2929
2930         g_return_if_fail (MODEST_IS_WINDOW (window));
2931
2932         mgr = modest_runtime_get_window_mgr ();
2933         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
2934         modest_window_mgr_set_fullscreen_mode (mgr, !fullscreen);
2935
2936         gtk_window_present (GTK_WINDOW (window));
2937 }
2938
2939 /* 
2940  * Used by modest_ui_actions_on_details to call do_headers_action 
2941  */
2942 static void
2943 headers_action_show_details (TnyHeader *header, 
2944                              ModestWindow *window,
2945                              gpointer user_data)
2946
2947 {
2948         GtkWidget *dialog;
2949         
2950         /* Create dialog */
2951         dialog = modest_details_dialog_new_with_header (GTK_WINDOW (window), header);
2952
2953         /* Run dialog */
2954         gtk_widget_show_all (dialog);
2955         gtk_dialog_run (GTK_DIALOG (dialog));
2956
2957         gtk_widget_destroy (dialog);
2958 }
2959
2960 /*
2961  * Show the folder details in a ModestDetailsDialog widget
2962  */
2963 static void
2964 show_folder_details (TnyFolder *folder, 
2965                      GtkWindow *window)
2966 {
2967         GtkWidget *dialog;
2968         
2969         /* Create dialog */
2970         dialog = modest_details_dialog_new_with_folder (window, folder);
2971
2972         /* Run dialog */
2973         gtk_widget_show_all (dialog);
2974         gtk_dialog_run (GTK_DIALOG (dialog));
2975
2976         gtk_widget_destroy (dialog);
2977 }
2978
2979 /*
2980  * Show the header details in a ModestDetailsDialog widget
2981  */
2982 void     
2983 modest_ui_actions_on_details (GtkAction *action, 
2984                               ModestWindow *win)
2985 {
2986         TnyList * headers_list;
2987         TnyIterator *iter;
2988         TnyHeader *header;              
2989
2990         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
2991                 TnyMsg *msg;
2992
2993                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (win));
2994                 if (!msg)
2995                         return;
2996                 g_object_unref (msg);           
2997
2998                 headers_list = get_selected_headers (win);
2999                 if (!headers_list)
3000                         return;
3001
3002                 iter = tny_list_create_iterator (headers_list);
3003
3004                 header = TNY_HEADER (tny_iterator_get_current (iter));
3005                 headers_action_show_details (header, win, NULL);
3006                 g_object_unref (header);
3007
3008                 g_object_unref (iter);
3009                 g_object_unref (headers_list);
3010
3011         } else if (MODEST_IS_MAIN_WINDOW (win)) {
3012                 GtkWidget *folder_view, *header_view;
3013
3014                 /* Check which widget has the focus */
3015                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3016                                                                     MODEST_WIDGET_TYPE_FOLDER_VIEW);
3017                 if (gtk_widget_is_focus (folder_view)) {
3018                         TnyFolderStore *folder_store
3019                                 = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3020                         if (!folder_store) {
3021                                 g_warning ("%s: No item was selected.\n", __FUNCTION__);
3022                                 return; 
3023                         }
3024                         /* Show only when it's a folder */
3025                         /* This function should not be called for account items, 
3026                          * because we dim the menu item for them. */
3027                         if (TNY_IS_FOLDER (folder_store)) {
3028                                 show_folder_details (TNY_FOLDER (folder_store), GTK_WINDOW (win));
3029                         }
3030
3031                         g_object_unref (folder_store);
3032
3033                 } else {
3034                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3035                                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
3036                         /* Show details of each header */
3037                         do_headers_action (win, headers_action_show_details, header_view);
3038                 }
3039         }
3040 }
3041
3042 void     
3043 modest_ui_actions_on_toggle_show_cc (GtkToggleAction *toggle,
3044                                      ModestMsgEditWindow *window)
3045 {
3046         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3047
3048         modest_msg_edit_window_show_cc (window, gtk_toggle_action_get_active (toggle));
3049 }
3050
3051 void     
3052 modest_ui_actions_on_toggle_show_bcc (GtkToggleAction *toggle,
3053                                       ModestMsgEditWindow *window)
3054 {
3055         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3056
3057         modest_msg_edit_window_show_bcc (window, gtk_toggle_action_get_active (toggle));
3058 }
3059
3060 void
3061 modest_ui_actions_toggle_folders_view (GtkAction *action, 
3062                                        ModestMainWindow *main_window)
3063 {
3064         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3065
3066         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
3067                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SPLIT);
3068         else
3069                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SIMPLE);
3070 }
3071
3072 void 
3073 modest_ui_actions_on_toggle_toolbar (GtkToggleAction *toggle, 
3074                                      ModestWindow *window)
3075 {
3076         gboolean active, fullscreen = FALSE;
3077         ModestWindowMgr *mgr;
3078
3079         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle));
3080
3081         /* Check if we want to toggle the toolbar vuew in fullscreen
3082            or normal mode */
3083         if (!strcmp (gtk_action_get_name (GTK_ACTION (toggle)), 
3084                      "ViewShowToolbarFullScreen")) {
3085                 fullscreen = TRUE;
3086         }
3087
3088         /* Toggle toolbar */
3089         mgr = modest_runtime_get_window_mgr ();
3090         modest_window_mgr_show_toolbars (mgr, active, fullscreen);
3091 }
3092
3093 void     
3094 modest_ui_actions_msg_edit_on_select_font (GtkAction *action,
3095                                            ModestMsgEditWindow *window)
3096 {
3097         modest_msg_edit_window_select_font (window);
3098 }
3099
3100 void
3101 modest_ui_actions_on_folder_display_name_changed (ModestFolderView *folder_view,
3102                                                   const gchar *display_name,
3103                                                   GtkWindow *window)
3104 {
3105         /* Do not change the application name if the widget has not
3106            the focus. This callback could be called even if the folder
3107            view has not the focus, because the handled signal could be
3108            emitted when the folder view is redrawn */
3109         if (gtk_widget_is_focus (GTK_WIDGET (folder_view))) {
3110                 if (display_name)
3111                         gtk_window_set_title (window, display_name);
3112                 else
3113                         gtk_window_set_title (window, " ");
3114         }
3115 }
3116
3117 void
3118 modest_ui_actions_on_select_contacts (GtkAction *action, ModestMsgEditWindow *window)
3119 {
3120         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3121         modest_msg_edit_window_select_contacts (window);
3122 }
3123
3124 void
3125 modest_ui_actions_on_check_names (GtkAction *action, ModestMsgEditWindow *window)
3126 {
3127         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3128         modest_msg_edit_window_check_names (window);
3129 }
3130
3131
3132 static GtkWidget*
3133 create_move_to_dialog (GtkWindow *win,
3134                        GtkWidget *folder_view,
3135                        GtkWidget **tree_view)
3136 {
3137         GtkWidget *dialog, *scroll;
3138
3139         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
3140                                               GTK_WINDOW (win),
3141                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
3142                                               GTK_STOCK_OK,
3143                                               GTK_RESPONSE_ACCEPT,
3144                                               GTK_STOCK_CANCEL,
3145                                               GTK_RESPONSE_REJECT,
3146                                               NULL);
3147
3148         /* Create scrolled window */
3149         scroll = gtk_scrolled_window_new (NULL, NULL);
3150         gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW (scroll),
3151                                          GTK_POLICY_AUTOMATIC,
3152                                          GTK_POLICY_AUTOMATIC);
3153
3154         /* Create folder view */
3155         *tree_view = modest_platform_create_folder_view (NULL);
3156
3157         /* It could happen that we're trying to move a message from a
3158            window (msg window for example) after the main window was
3159            closed, so we can not just get the model of the folder
3160            view */
3161         if (MODEST_IS_FOLDER_VIEW (folder_view))
3162                 gtk_tree_view_set_model (GTK_TREE_VIEW (*tree_view),
3163                                          gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view)));
3164         else
3165                 modest_folder_view_update_model (MODEST_FOLDER_VIEW (*tree_view), 
3166                                                  TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
3167
3168         modest_folder_view_show_non_move_folders(MODEST_FOLDER_VIEW (*tree_view), FALSE);
3169         
3170         gtk_container_add (GTK_CONTAINER (scroll), *tree_view);
3171
3172         /* Add scroll to dialog */
3173         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), 
3174                             scroll, FALSE, FALSE, 0);
3175
3176         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3177
3178         /* Select INBOX or local account */
3179         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (*tree_view));
3180
3181         return dialog;
3182 }
3183
3184 /*
3185  * Returns TRUE if at least one of the headers of the list belongs to
3186  * a message that has been fully retrieved.
3187  */
3188 static gboolean
3189 has_retrieved_msgs (TnyList *list)
3190 {
3191         TnyIterator *iter;
3192         gboolean found = FALSE;
3193
3194         iter = tny_list_create_iterator (list);
3195         while (tny_iterator_is_done (iter) && !found) {
3196                 TnyHeader *header;
3197                 TnyHeaderFlags flags;
3198
3199                 header = TNY_HEADER (tny_iterator_get_current (iter));
3200                 flags = tny_header_get_flags (header);
3201                 if (!(flags & TNY_HEADER_FLAG_PARTIAL))
3202                         found = TRUE;
3203
3204                 if (!found)
3205                         tny_iterator_next (iter);
3206         }
3207         g_object_unref (iter);
3208
3209         return found;
3210 }
3211
3212 /*
3213  * Shows a confirmation dialog to the user when we're moving messages
3214  * from a remote server to the local storage. Returns the dialog
3215  * response. If it's other kind of movement the it always returns
3216  * GTK_RESPONSE_OK
3217  */
3218 static gint
3219 msgs_move_to_confirmation (GtkWindow *win,
3220                            TnyFolder *dest_folder,
3221                            TnyList *headers)
3222 {
3223         gint response = GTK_RESPONSE_OK;
3224
3225         /* If the destination is a local folder */
3226         if (modest_tny_folder_is_local_folder (dest_folder)) {
3227                 TnyFolder *src_folder;
3228                 TnyIterator *iter;
3229                 TnyHeader *header;
3230
3231                 /* Get source folder */
3232                 iter = tny_list_create_iterator (headers);
3233                 header = TNY_HEADER (tny_iterator_get_current (iter));
3234                 src_folder = tny_header_get_folder (header);
3235                 g_object_unref (header);
3236                 g_object_unref (iter);
3237
3238                 /* if no src_folder, message may be an attahcment */
3239                 if (src_folder == NULL) 
3240                         return GTK_RESPONSE_CANCEL;
3241
3242                 /* If the source is a remote folder */
3243                 if (!modest_tny_folder_is_local_folder (src_folder)) {
3244                         const gchar *message;
3245                         
3246                         if (has_retrieved_msgs (headers))
3247                                 message = ngettext ("mcen_nc_move_retrieve", "mcen_nc_move_retrieves",
3248                                                     tny_list_get_length (headers));
3249                         else 
3250                                 message = ngettext ("mcen_nc_move_header", "mcen_nc_move_headers",
3251                                                     tny_list_get_length (headers));
3252
3253                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
3254                                                                             (const gchar *) message);
3255                 }
3256                 g_object_unref (src_folder);
3257         }
3258         return response;
3259 }
3260
3261
3262
3263 static void
3264 transfer_msgs_from_viewer_cb (const GObject *object, gpointer user_data)
3265 {
3266         ModestMsgViewWindow *self = NULL;
3267         gboolean last, first;
3268
3269         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (object));
3270         self = MODEST_MSG_VIEW_WINDOW (object);
3271         
3272         last = modest_msg_view_window_last_message_selected (self);
3273         first = modest_msg_view_window_first_message_selected (self);   
3274         if (last & first) {
3275                 /* No more messages to view, so close this window */
3276 /*              gboolean ret_value; */
3277 /*              g_signal_emit_by_name (G_OBJECT (self), "delete-event", NULL, &ret_value); */
3278                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW(self));
3279         } else if (last)
3280                 modest_msg_view_window_select_previous_message (self);
3281         else 
3282                 modest_msg_view_window_select_next_message (self);
3283 }
3284
3285 void
3286 modest_ui_actions_move_folder_error_handler (ModestMailOperation *mail_op, 
3287                                              gpointer user_data)
3288 {
3289         GObject *win = modest_mail_operation_get_source (mail_op);
3290         const GError *error = NULL;
3291         const gchar *message = NULL;
3292         
3293         /* Get error message */
3294         error = modest_mail_operation_get_error (mail_op);
3295         if (error != NULL && error->message != NULL) {
3296                 message = error->message;
3297         } else {
3298                 message = _("mail_in_ui_folder_move_target_error");
3299         }
3300         
3301         /* Show notification dialog */
3302         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, message);
3303         g_object_unref (win);
3304 }
3305
3306 void
3307 modest_ui_actions_send_receive_error_handler (ModestMailOperation *mail_op, 
3308                                               gpointer user_data)
3309 {
3310         GObject *win = modest_mail_operation_get_source (mail_op);
3311         const GError *error = modest_mail_operation_get_error (mail_op);
3312
3313         g_return_if_fail (error != NULL);
3314         if (error->message != NULL)             
3315                 g_printerr ("modest: %s\n", error->message);
3316         else
3317                 g_printerr ("modest: unkonw error on send&receive operation");
3318
3319         /* Show error message */
3320 /*      if (modest_mail_operation_get_id (mail_op) == MODEST_MAIL_OPERATION_TYPE_RECEIVE) */
3321 /*              modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, */
3322 /*                                                      _CS("sfil_ib_unable_to_receive")); */
3323 /*      else  */
3324 /*              modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, */
3325 /*                                                      _CS("sfil_ib_unable_to_send")); */
3326         g_object_unref (win);
3327 }
3328
3329 static void
3330 open_msg_for_purge_cb (ModestMailOperation *mail_op, 
3331                        TnyHeader *header, 
3332                        TnyMsg *msg, 
3333                        gpointer user_data)
3334 {
3335         TnyList *parts;
3336         TnyIterator *iter;
3337         gint pending_purges = 0;
3338         gboolean some_purged = FALSE;
3339         ModestWindow *win = MODEST_WINDOW (user_data);
3340
3341         /* If there was any error */
3342         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
3343                 return;
3344
3345         /* Once the message has been retrieved for purging, we check if
3346          * it's all ok for purging */
3347
3348         parts = tny_simple_list_new ();
3349         tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
3350         iter = tny_list_create_iterator (parts);
3351
3352         while (!tny_iterator_is_done (iter)) {
3353                 TnyMimePart *part;
3354                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3355                 if (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part)) {
3356                         if (tny_mime_part_is_purged (part))
3357                                 some_purged = TRUE;
3358                         else
3359                                 pending_purges++;
3360                 }
3361                 tny_iterator_next (iter);
3362         }
3363
3364         if (pending_purges>0) {
3365                 gint response;
3366                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),_("mcen_nc_purge_file_text_inbox"));
3367
3368                 if (response == GTK_RESPONSE_OK) {
3369                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_removing_attachment"));
3370                         tny_iterator_first (iter);
3371                         while (!tny_iterator_is_done (iter)) {
3372                                 TnyMimePart *part;
3373                                 
3374                                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3375                                 if (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part))
3376                                         tny_mime_part_set_purged (part);
3377                                 tny_iterator_next (iter);
3378                         }
3379                         
3380                         tny_msg_rewrite_cache (msg);
3381                 }
3382         } else {
3383                 modest_platform_information_banner (NULL, NULL, _("mail_ib_attachment_already_purged"));
3384         }
3385
3386         /* remove attachments */
3387         tny_iterator_first (iter);
3388         while (!tny_iterator_is_done (iter)) {
3389                 TnyMimePart *part;
3390                         
3391                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3392                 g_object_unref (part);
3393                 tny_iterator_next (iter);
3394         }
3395
3396         g_object_unref (iter);
3397         g_object_unref (parts);
3398 }
3399
3400 static void
3401 modest_ui_actions_on_main_window_remove_attachments (GtkAction *action,
3402                                                      ModestMainWindow *win)
3403 {
3404         GtkWidget *header_view;
3405         TnyList *header_list;
3406         TnyIterator *iter;
3407         TnyHeader *header;
3408         TnyHeaderFlags flags;
3409         ModestWindow *msg_view_window =  NULL;
3410         gboolean found;
3411
3412         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
3413
3414         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3415                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
3416
3417         header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
3418
3419         if (tny_list_get_length (header_list) == 1) {
3420                 iter = tny_list_create_iterator (header_list);
3421                 header = TNY_HEADER (tny_iterator_get_current (iter));
3422                 g_object_unref (iter);
3423         } else {
3424                 return;
3425         }
3426
3427         found = modest_window_mgr_find_registered_header (modest_runtime_get_window_mgr (),
3428                                                           header, &msg_view_window);
3429         flags = tny_header_get_flags (header);
3430         if (!(flags & TNY_HEADER_FLAG_CACHED))
3431                 return;
3432         if (found) {
3433                 if (msg_view_window != NULL) 
3434                         modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (msg_view_window), TRUE);
3435                 else {
3436                         /* do nothing; uid was registered before, so window is probably on it's way */
3437                         g_warning ("debug: header %p has already been registered", header);
3438                 }
3439         } else {
3440                 ModestMailOperation *mail_op = NULL;
3441                 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), header);
3442                 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
3443                                                                          G_OBJECT (win),
3444                                                                          modest_ui_actions_get_msgs_full_error_handler,
3445                                                                          NULL);
3446                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3447                 modest_mail_operation_get_msg (mail_op, header, open_msg_for_purge_cb, win);
3448                 
3449                 g_object_unref (mail_op);
3450         }
3451         if (header)
3452                 g_object_unref (header);
3453         if (header_list)
3454                 g_object_unref (header_list);
3455 }
3456
3457 /*
3458  * UI handler for the "Move to" action when invoked from the
3459  * ModestMainWindow
3460  */
3461 static void 
3462 modest_ui_actions_on_main_window_move_to (GtkAction *action, 
3463                                           ModestMainWindow *win)
3464 {
3465         GtkWidget *dialog = NULL, *folder_view = NULL, *tree_view = NULL;
3466         GtkWidget *header_view = NULL;
3467         gint result = 0;
3468         TnyFolderStore *folder_store = NULL;
3469         ModestMailOperation *mail_op = NULL;
3470
3471         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
3472
3473         /* Get the folder view */
3474         folder_view = modest_main_window_get_child_widget (win,
3475                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
3476                                                            
3477         TnyFolderStore *src_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3478         
3479         /* Offer the connection dialog if necessary, if the source folder is in a networked account: */
3480         if (!modest_platform_connect_and_wait_if_network_folderstore (GTK_WINDOW (win), src_folder)) {
3481                 if (src_folder) {
3482                         g_object_unref (src_folder);
3483                 }
3484                 
3485                 return;
3486         }
3487
3488         /* Get header view */
3489         header_view = modest_main_window_get_child_widget (win,
3490                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
3491
3492         /* Create and run the dialog */
3493         dialog = create_move_to_dialog (GTK_WINDOW(win), folder_view, &tree_view);
3494         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (tree_view));
3495         result = gtk_dialog_run (GTK_DIALOG(dialog));
3496         modest_folder_view_show_non_move_folders(MODEST_FOLDER_VIEW (tree_view), TRUE);
3497         g_object_ref (tree_view);
3498
3499         /* We do this to save an indentation level ;-) */
3500         if (result != GTK_RESPONSE_ACCEPT)
3501                 goto end;
3502
3503         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (tree_view));
3504
3505         if (TNY_IS_ACCOUNT (folder_store) && 
3506             !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (folder_store))
3507                 goto end;
3508
3509         /* Offer the connection dialog if necessary: */
3510         if (!modest_platform_connect_and_wait_if_network_folderstore (GTK_WINDOW (win), folder_store)) {
3511                         goto end;
3512         }
3513
3514         /* Get folder or messages to transfer */
3515         if (gtk_widget_is_focus (folder_view)) {
3516                 
3517                 /* Clean folder on header view before moving it */
3518                 modest_header_view_clear (MODEST_HEADER_VIEW (header_view)); 
3519
3520                 if (TNY_IS_FOLDER (src_folder)) {
3521                         mail_op = 
3522                                 modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3523                                                                        G_OBJECT(win),
3524                                                                        modest_ui_actions_move_folder_error_handler,
3525                                                                        NULL);
3526                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3527
3528                         modest_mail_operation_xfer_folder (mail_op, 
3529                                                            TNY_FOLDER (src_folder),
3530                                                            folder_store,
3531                                                            TRUE, NULL, NULL);
3532                         /* Unref mail operation */
3533                         g_object_unref (G_OBJECT (mail_op));
3534                 } else {
3535                         g_warning ("%s: src_folder is not a TnyFolder.\n", __FUNCTION__);       
3536                 }
3537         } else {
3538                 if (gtk_widget_is_focus (header_view)) {
3539                         TnyList *headers = NULL;
3540                         gint response = 0;
3541
3542                         /* TODO: Check for connection if the headers are on a network account. */
3543                         headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
3544
3545                         /* Ask for user confirmation */
3546                         response = msgs_move_to_confirmation (GTK_WINDOW (win), 
3547                                                               TNY_FOLDER (folder_store), 
3548                                                               headers);
3549
3550                         /* Transfer messages */
3551                         if (response == GTK_RESPONSE_OK) {
3552                                 mail_op = 
3553                                         modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3554                                                                                        G_OBJECT(win),
3555                                                                                        modest_ui_actions_move_folder_error_handler,
3556                                                                                        NULL);
3557                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3558                                                                  mail_op);
3559
3560                                 modest_mail_operation_xfer_msgs (mail_op, 
3561                                                                  headers,
3562                                                                  TNY_FOLDER (folder_store),
3563                                                                  TRUE,
3564                                                                  NULL,
3565                                                                  NULL);
3566
3567                                 g_object_unref (G_OBJECT (mail_op));
3568                         }
3569                         g_object_unref (headers);
3570                 }
3571         }
3572         
3573  end:
3574     if (src_folder)
3575         g_object_unref (src_folder);
3576                         
3577         if (folder_store)
3578                 g_object_unref (folder_store);
3579
3580         gtk_widget_destroy (dialog);
3581 }
3582
3583
3584 /*
3585  * UI handler for the "Move to" action when invoked from the
3586  * ModestMsgViewWindow
3587  */
3588 static void 
3589 modest_ui_actions_on_msg_view_window_move_to (GtkAction *action, 
3590                                               ModestMsgViewWindow *win)
3591 {
3592         GtkWidget *dialog, *folder_view, *tree_view = NULL;
3593         gint result = 0;
3594         ModestMainWindow *main_window = NULL;
3595         TnyHeader *header = NULL;
3596         TnyList *headers = NULL;
3597
3598         /* Get the folder view */
3599         main_window = MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
3600         if (main_window)
3601                 folder_view = modest_main_window_get_child_widget (main_window,
3602                                                                    MODEST_WIDGET_TYPE_FOLDER_VIEW);
3603         else
3604                 folder_view = NULL;
3605
3606         /* Create and run the dialog */
3607         dialog = create_move_to_dialog (GTK_WINDOW (win), folder_view, &tree_view);     
3608         result = gtk_dialog_run (GTK_DIALOG(dialog));
3609         modest_folder_view_show_non_move_folders(MODEST_FOLDER_VIEW (tree_view), TRUE);
3610
3611         if (result == GTK_RESPONSE_ACCEPT) {
3612                 TnyFolderStore *folder_store;
3613                 gint response;
3614
3615                 /* Create header list */
3616                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));              
3617                 g_return_if_fail (header != NULL);
3618
3619                 /* Offer the connection dialog if necessary: */
3620                 /* TODO: What's the extra g_object_ref() for? Isn't this leaking a ref? */
3621                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (g_object_ref (tree_view)));
3622                 TnyFolder *header_folder = tny_header_get_folder(header);
3623                 if (modest_platform_connect_and_wait_if_network_folderstore (NULL, folder_store) &&
3624                     modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (header_folder))) {
3625                         
3626                         headers = tny_simple_list_new ();
3627                         tny_list_prepend (headers, G_OBJECT (header));
3628                         g_object_unref (header);
3629
3630                         /* Ask user for confirmation. MSG-NOT404 */
3631                         response = msgs_move_to_confirmation (GTK_WINDOW (win), 
3632                                                       TNY_FOLDER (folder_store), 
3633                                                       headers);
3634
3635                         /* Transfer current msg */
3636                         if (response == GTK_RESPONSE_OK) {
3637                                 ModestMailOperation *mail_op;
3638
3639                                 /* Create mail op */
3640                                 mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(win));
3641                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3642                                                          mail_op);
3643                         
3644                                 /* Transfer messages */
3645                                 modest_mail_operation_xfer_msgs (mail_op, 
3646                                                          headers,
3647                                                          TNY_FOLDER (folder_store),
3648                                                          TRUE,
3649                                                          transfer_msgs_from_viewer_cb,
3650                                                          NULL);
3651                                 g_object_unref (G_OBJECT (mail_op));
3652                         }
3653                 }
3654                 
3655                 if (header_folder)
3656                         g_object_unref (header_folder);
3657
3658                 if (headers)
3659                         g_object_unref (headers);
3660                         
3661                 if (folder_store)
3662                         g_object_unref (folder_store);
3663         }
3664         
3665         gtk_widget_destroy (dialog);
3666 }
3667
3668 void 
3669 modest_ui_actions_on_move_to (GtkAction *action, 
3670                               ModestWindow *win)
3671 {
3672         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win) ||
3673                           MODEST_IS_MSG_VIEW_WINDOW (win));
3674
3675         if (MODEST_IS_MAIN_WINDOW (win)) 
3676                 modest_ui_actions_on_main_window_move_to (action, 
3677                                                           MODEST_MAIN_WINDOW (win));
3678         else
3679                 modest_ui_actions_on_msg_view_window_move_to (action, 
3680                                                               MODEST_MSG_VIEW_WINDOW (win));
3681 }
3682
3683 /*
3684  * Calls #HeadersFunc for each header already selected in the main
3685  * window or the message currently being shown in the msg view window
3686  */
3687 static void
3688 do_headers_action (ModestWindow *win, 
3689                    HeadersFunc func,
3690                    gpointer user_data)
3691 {
3692         TnyList *headers_list;
3693         TnyIterator *iter;
3694         TnyHeader *header;
3695         TnyFolder *folder;
3696
3697         /* Get headers */
3698         headers_list = get_selected_headers (win);
3699         if (!headers_list)
3700                 return;
3701
3702         /* Get the folder */
3703         iter = tny_list_create_iterator (headers_list);
3704         header = TNY_HEADER (tny_iterator_get_current (iter));
3705         folder = tny_header_get_folder (header);
3706         g_object_unref (header);
3707
3708         /* Call the function for each header */
3709         while (!tny_iterator_is_done (iter)) {
3710                 header = TNY_HEADER (tny_iterator_get_current (iter));
3711                 func (header, win, user_data);
3712                 g_object_unref (header);
3713                 tny_iterator_next (iter);
3714         }
3715
3716         /* Trick: do a poke status in order to speed up the signaling
3717            of observers */
3718         tny_folder_poke_status (folder);
3719
3720         /* Frees */
3721         g_object_unref (folder);
3722         g_object_unref (iter);
3723         g_object_unref (headers_list);
3724 }
3725
3726 void 
3727 modest_ui_actions_view_attachment (GtkAction *action,
3728                                    ModestWindow *window)
3729 {
3730         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3731                 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (window), NULL);
3732         } else {
3733                 /* not supported window for this action */
3734                 g_return_if_reached ();
3735         }
3736 }
3737
3738 void
3739 modest_ui_actions_save_attachments (GtkAction *action,
3740                                     ModestWindow *window)
3741 {
3742         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3743                 modest_msg_view_window_save_attachments (MODEST_MSG_VIEW_WINDOW (window), NULL);
3744         } else {
3745                 /* not supported window for this action */
3746                 g_return_if_reached ();
3747         }
3748 }
3749
3750 void
3751 modest_ui_actions_remove_attachments (GtkAction *action,
3752                                       ModestWindow *window)
3753 {
3754         if (MODEST_IS_MAIN_WINDOW (window)) {
3755                 modest_ui_actions_on_main_window_remove_attachments (action, MODEST_MAIN_WINDOW (window));
3756         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3757                 modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (window), FALSE);
3758         } else {
3759                 /* not supported window for this action */
3760                 g_return_if_reached ();
3761         }
3762 }
3763
3764 void 
3765 modest_ui_actions_on_settings (GtkAction *action, 
3766                                ModestWindow *win)
3767 {
3768         GtkWidget *dialog;
3769
3770         dialog = modest_platform_get_global_settings_dialog ();
3771         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (win));
3772         gtk_widget_show_all (dialog);
3773
3774         gtk_dialog_run (GTK_DIALOG (dialog));
3775
3776         gtk_widget_destroy (dialog);
3777 }
3778
3779 void 
3780 modest_ui_actions_on_help (GtkAction *action, 
3781                            ModestWindow *win)
3782 {
3783         const gchar *help_id = NULL;
3784
3785         if (MODEST_IS_MAIN_WINDOW (win)) {
3786                 const gchar *action_name;
3787                 action_name = gtk_action_get_name (action);
3788
3789                 if (!strcmp (action_name, "FolderViewCSMHelp") ||
3790                     !strcmp (action_name, "HeaderViewCSMHelp")) {
3791                         GtkWidget *folder_view;
3792                         TnyFolderStore *folder_store;
3793                         /* Get selected folder */
3794                         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3795                                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
3796                         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3797
3798                         /* Switch help_id */
3799                         if (TNY_IS_FOLDER (folder_store)) {
3800                                 switch (tny_folder_get_folder_type (TNY_FOLDER (folder_store))) {
3801                                 case TNY_FOLDER_TYPE_NORMAL:
3802                                         help_id = "applications_email_userfolder";
3803                                         break;
3804                                 case TNY_FOLDER_TYPE_INBOX:
3805                                         help_id = "applications_email_inbox";
3806                                         break;
3807                                 case TNY_FOLDER_TYPE_OUTBOX:
3808                                         help_id = "applications_email_outbox";
3809                                         break;
3810                                 case TNY_FOLDER_TYPE_SENT:
3811                                         help_id = "applications_email_sent";
3812                                         break;
3813                                 case TNY_FOLDER_TYPE_DRAFTS:
3814                                         help_id = "applications_email_drafts";
3815                                         break;
3816                                 case TNY_FOLDER_TYPE_ARCHIVE:
3817                                         help_id = "applications_email_archive";
3818                                         break;
3819                                 default:
3820                                         help_id = "applications_email_mainview";
3821                                 }
3822                         } else {
3823                                 help_id = "applications_email_mainview";        
3824                         }
3825                         g_object_unref (folder_store);
3826                 } else {
3827                         help_id = "applications_email_mainview";        
3828                 }
3829         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
3830                 help_id = "applications_email_viewer";
3831         } else if (MODEST_IS_MSG_EDIT_WINDOW (win))
3832                 help_id = "applications_email_editor";
3833
3834         modest_platform_show_help (GTK_WINDOW (win), help_id);
3835 }
3836
3837 void 
3838 modest_ui_actions_on_retrieve_msg_contents (GtkAction *action,
3839                                             ModestWindow *window)
3840 {
3841         ModestMailOperation *mail_op;
3842         TnyList *headers;
3843
3844         /* Get headers */
3845         headers = get_selected_headers (window);
3846         if (!headers)
3847                 return;
3848
3849         /* Create mail operation */
3850         mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3851                                                                  G_OBJECT (window),
3852                                                                  modest_ui_actions_get_msgs_full_error_handler, 
3853                                                                  NULL);
3854         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3855         modest_mail_operation_get_msgs_full (mail_op, headers, NULL, NULL, NULL);
3856
3857         /* Frees */
3858         g_object_unref (headers);
3859         g_object_unref (mail_op);
3860 }
3861
3862 void
3863 modest_ui_actions_on_email_menu_activated (GtkAction *action,
3864                                           ModestWindow *window)
3865 {
3866         g_return_if_fail (MODEST_IS_WINDOW (window));
3867
3868         /* Update dimmed */     
3869         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3870 }
3871
3872 void
3873 modest_ui_actions_on_edit_menu_activated (GtkAction *action,
3874                                           ModestWindow *window)
3875 {
3876         g_return_if_fail (MODEST_IS_WINDOW (window));
3877
3878         /* Update dimmed */     
3879         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3880 }
3881
3882 void
3883 modest_ui_actions_on_view_menu_activated (GtkAction *action,
3884                                           ModestWindow *window)
3885 {
3886         g_return_if_fail (MODEST_IS_WINDOW (window));
3887
3888         /* Update dimmed */     
3889         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3890 }
3891
3892 void
3893 modest_ui_actions_on_tools_menu_activated (GtkAction *action,
3894                                           ModestWindow *window)
3895 {
3896         g_return_if_fail (MODEST_IS_WINDOW (window));
3897
3898         /* Update dimmed */     
3899         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3900 }
3901
3902 void
3903 modest_ui_actions_on_attachment_menu_activated (GtkAction *action,
3904                                           ModestWindow *window)
3905 {
3906         g_return_if_fail (MODEST_IS_WINDOW (window));
3907
3908         /* Update dimmed */     
3909         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3910 }
3911
3912 void
3913 modest_ui_actions_on_toolbar_csm_menu_activated (GtkAction *action,
3914                                                  ModestWindow *window)
3915 {
3916         g_return_if_fail (MODEST_IS_WINDOW (window));
3917
3918         /* Update dimmed */     
3919         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3920 }
3921
3922 void
3923 modest_ui_actions_on_folder_view_csm_menu_activated (GtkAction *action,
3924                                                      ModestWindow *window)
3925 {
3926         g_return_if_fail (MODEST_IS_WINDOW (window));
3927
3928         /* Update dimmed */     
3929         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3930 }
3931
3932 void
3933 modest_ui_actions_on_header_view_csm_menu_activated (GtkAction *action,
3934                                                      ModestWindow *window)
3935 {
3936         g_return_if_fail (MODEST_IS_WINDOW (window));
3937
3938         /* Update dimmed */     
3939         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3940 }
3941
3942 void
3943 modest_ui_actions_check_toolbar_dimming_rules (ModestWindow *window)
3944 {
3945         g_return_if_fail (MODEST_IS_WINDOW (window));
3946
3947         /* Update dimmed */     
3948         modest_window_check_dimming_rules_group (window, "ModestToolbarDimmingRules");  
3949 }
3950
3951 void
3952 modest_ui_actions_on_search_messages (GtkAction *action, ModestWindow *window)
3953 {
3954         g_return_if_fail (MODEST_IS_WINDOW (window));
3955
3956         modest_platform_show_search_messages (GTK_WINDOW (window));
3957 }
3958
3959 void     
3960 modest_ui_actions_on_open_addressbook (GtkAction *action, ModestWindow *win)
3961 {
3962         g_return_if_fail (MODEST_IS_WINDOW (win));
3963         modest_platform_show_addressbook (GTK_WINDOW (win));
3964 }
3965
3966
3967 void
3968 modest_ui_actions_on_toggle_find_in_page (GtkToggleAction *action,
3969                                           ModestWindow *window)
3970 {
3971         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3972
3973         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window), gtk_toggle_action_get_active (action));
3974 }
3975
3976 static void 
3977 _on_send_receive_progress_changed (ModestMailOperation  *mail_op, 
3978                                    ModestMailOperationState *state,
3979                                    gpointer user_data)
3980 {
3981         g_return_if_fail (MODEST_IS_MAIN_WINDOW(user_data));
3982
3983         /* Set send/receive operation finished */       
3984         if (state->status != MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3985                 modest_main_window_notify_send_receive_completed (MODEST_MAIN_WINDOW(user_data));
3986         
3987 }
3988
3989