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