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