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