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