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