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