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