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