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