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