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