* fix some memory leaks (valgrind helps)
[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                 }
1087         } else {
1088                 TnyHeader *header;
1089                 TnyIterator *iter;
1090
1091                 /* Retrieve messages */
1092                 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
1093                                                                          G_OBJECT(win),
1094                                                                          modest_ui_actions_get_msgs_full_error_handler, 
1095                                                                          NULL);
1096                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1097
1098                 /* Only reply/forward to one message */
1099                 iter = tny_list_create_iterator (header_list);
1100                 header = TNY_HEADER (tny_iterator_get_current (iter));
1101                 g_object_unref (iter);
1102
1103                 modest_mail_operation_get_msg (mail_op,
1104                                                header,
1105                                                reply_forward_cb,
1106                                                rf_helper);
1107
1108 /*              modest_mail_operation_get_msgs_full (mail_op,  */
1109 /*                                                   header_list,  */
1110 /*                                                   reply_forward_cb,  */
1111 /*                                                   rf_helper,  */
1112 /*                                                   free_reply_forward_helper); */
1113
1114                 /* Clean */
1115                 g_object_unref(mail_op);
1116         }
1117
1118         /* Free */
1119         g_object_unref (header_list);
1120 }
1121
1122 void
1123 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
1124 {
1125         g_return_if_fail (MODEST_IS_WINDOW(win));
1126
1127         reply_forward (ACTION_REPLY, win);
1128 }
1129
1130 void
1131 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
1132 {
1133         g_return_if_fail (MODEST_IS_WINDOW(win));
1134
1135         reply_forward (ACTION_FORWARD, win);
1136 }
1137
1138 void
1139 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
1140 {
1141         g_return_if_fail (MODEST_IS_WINDOW(win));
1142
1143         reply_forward (ACTION_REPLY_TO_ALL, win);
1144 }
1145
1146 void 
1147 modest_ui_actions_on_next (GtkAction *action, 
1148                            ModestWindow *window)
1149 {
1150         if (MODEST_IS_MAIN_WINDOW (window)) {
1151                 GtkWidget *header_view;
1152
1153                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1154                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1155                 if (!header_view)
1156                         return;
1157         
1158                 modest_header_view_select_next (MODEST_HEADER_VIEW(header_view)); 
1159         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1160                 modest_msg_view_window_select_next_message (MODEST_MSG_VIEW_WINDOW (window));
1161         } else {
1162                 g_return_if_reached ();
1163         }
1164 }
1165
1166 void 
1167 modest_ui_actions_on_prev (GtkAction *action, 
1168                            ModestWindow *window)
1169 {
1170         g_return_if_fail (MODEST_IS_WINDOW(window));
1171
1172         if (MODEST_IS_MAIN_WINDOW (window)) {
1173                 GtkWidget *header_view;
1174                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1175                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1176                 if (!header_view)
1177                         return;
1178                 
1179                 modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
1180         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1181                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
1182         } else {
1183                 g_return_if_reached ();
1184         }
1185 }
1186
1187 void 
1188 modest_ui_actions_on_sort (GtkAction *action, 
1189                            ModestWindow *window)
1190 {
1191         g_return_if_fail (MODEST_IS_WINDOW(window));
1192
1193         if (MODEST_IS_MAIN_WINDOW (window)) {
1194                 GtkWidget *header_view;
1195                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1196                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
1197                 if (!header_view)
1198                         return;
1199
1200                 /* Show sorting dialog */
1201                 modest_platform_run_sort_dialog (GTK_WINDOW (window), MODEST_SORT_HEADERS);     
1202         }
1203 }
1204
1205 static void
1206 new_messages_arrived (ModestMailOperation *self, 
1207                       gint new_messages,
1208                       gpointer user_data)
1209 {
1210         if (new_messages == 0)
1211                 return;
1212
1213         modest_platform_on_new_msg ();
1214 }
1215
1216 /*
1217  * This function performs the send & receive required actions. The
1218  * window is used to create the mail operation. Typically it should
1219  * always be the main window, but we pass it as argument in order to
1220  * be more flexible.
1221  */
1222 void
1223 modest_ui_actions_do_send_receive (const gchar *account_name, ModestWindow *win)
1224 {
1225         gchar *acc_name = NULL;
1226         ModestMailOperation *mail_op;
1227
1228         /* If no account name was provided then get the current account, and if
1229            there is no current account then pick the default one: */
1230         if (!account_name) {
1231                 acc_name = g_strdup (modest_window_get_active_account(win));
1232                 if (!acc_name)
1233                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1234                 if (!acc_name) {
1235                         g_printerr ("modest: cannot get default account\n");
1236                         return;
1237                 }
1238         } else {
1239                 acc_name = g_strdup (account_name);
1240         }
1241
1242         /* Set send/receive operation in progress */    
1243         modest_main_window_notify_send_receive_initied (MODEST_MAIN_WINDOW(win));
1244
1245         mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1246                                                                  G_OBJECT (win),
1247                                                                  modest_ui_actions_send_receive_error_handler,
1248                                                                  NULL);
1249
1250         g_signal_connect (G_OBJECT(mail_op), "progress-changed", 
1251                           G_CALLBACK (_on_send_receive_progress_changed), 
1252                           win);
1253
1254         /* Send & receive. */
1255         /* TODO: The spec wants us to first do any pending deletions, before receiving. */
1256         /* Receive and then send. The operation is tagged initially as
1257            a receive operation because the account update performs a
1258            receive and then a send. The operation changes its type
1259            internally, so the progress objects will receive the proper
1260            progress information */
1261         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1262         modest_mail_operation_update_account (mail_op, acc_name, new_messages_arrived, NULL);
1263         g_object_unref (G_OBJECT (mail_op));
1264         
1265         /* Free */
1266         g_free (acc_name);
1267 }
1268
1269 /*
1270  * Refreshes all accounts. This function will be used by automatic
1271  * updates
1272  */
1273 void
1274 modest_ui_actions_do_send_receive_all (ModestWindow *win)
1275 {
1276         GSList *account_names, *iter;
1277
1278         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
1279                                                           TRUE);
1280
1281         iter = account_names;
1282         while (iter) {                  
1283                 modest_ui_actions_do_send_receive ((const char*) iter->data, win);
1284                 iter = g_slist_next (iter);
1285         }
1286
1287         modest_account_mgr_free_account_names (account_names);
1288         account_names = NULL;
1289 }
1290
1291 /*
1292  * Handler of the click on Send&Receive button in the main toolbar
1293  */
1294 void
1295 modest_ui_actions_on_send_receive (GtkAction *action,  ModestWindow *win)
1296 {
1297         /* Check if accounts exist */
1298         gboolean accounts_exist = 
1299                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1300         
1301         /* If not, allow the user to create an account before trying to send/receive. */
1302         if (!accounts_exist)
1303                 modest_ui_actions_on_accounts (NULL, win);
1304         
1305         /* Refresh the active account */
1306         modest_ui_actions_do_send_receive (NULL, win);
1307 }
1308
1309
1310 void
1311 modest_ui_actions_toggle_header_list_view (GtkAction *action, ModestMainWindow *main_window)
1312 {
1313         ModestConf *conf;
1314         GtkWidget *header_view;
1315         
1316         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1317
1318         header_view = modest_main_window_get_child_widget (main_window,
1319                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
1320         if (!header_view)
1321                 return;
1322
1323         conf = modest_runtime_get_conf ();
1324         
1325         /* what is saved/restored is depending on the style; thus; we save with
1326          * old style, then update the style, and restore for this new style
1327          */
1328         modest_widget_memory_save (conf, G_OBJECT(header_view), MODEST_CONF_HEADER_VIEW_KEY);
1329         
1330         if (modest_header_view_get_style
1331             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
1332                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
1333                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
1334         else
1335                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
1336                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
1337
1338         modest_widget_memory_restore (conf, G_OBJECT(header_view),
1339                                       MODEST_CONF_HEADER_VIEW_KEY);
1340 }
1341
1342
1343 void 
1344 modest_ui_actions_on_header_selected (ModestHeaderView *header_view, 
1345                                       TnyHeader *header,
1346                                       ModestMainWindow *main_window)
1347 {
1348         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1349         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
1350         
1351         /* If no header has been selected then exit */
1352         if (!header)
1353                 return;
1354
1355         /* Update focus */
1356         if (!gtk_widget_is_focus (GTK_WIDGET(header_view)))
1357             gtk_widget_grab_focus (GTK_WIDGET(header_view));
1358
1359         /* Update Main window title */
1360         if (gtk_widget_is_focus (GTK_WIDGET(header_view))) {
1361                 const gchar *subject = tny_header_get_subject (header);
1362                 if (subject && strlen(subject) > 0)
1363                         gtk_window_set_title (GTK_WINDOW (main_window), subject);
1364                 else
1365                         gtk_window_set_title (GTK_WINDOW (main_window), _("mail_va_no_subject"));
1366         }
1367
1368         /* Update toolbar dimming state */
1369         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
1370 }
1371
1372 void
1373 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
1374                                        TnyHeader *header,
1375                                        ModestMainWindow *main_window)
1376 {
1377         TnyList *headers;
1378
1379         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1380         
1381         if (!header)
1382                 return;
1383
1384         headers = tny_simple_list_new ();
1385         tny_list_prepend (headers, G_OBJECT (header));
1386
1387         _modest_ui_actions_open (headers, MODEST_WINDOW (main_window));
1388
1389         g_object_unref (headers);
1390 }
1391
1392 static void
1393 set_active_account_from_tny_account (TnyAccount *account,
1394                                      ModestWindow *window)
1395 {
1396         const gchar *server_acc_name = tny_account_get_id (account);
1397         
1398         /* We need the TnyAccount provided by the
1399            account store because that is the one that
1400            knows the name of the Modest account */
1401         TnyAccount *modest_server_account = modest_server_account = 
1402                 modest_tny_account_store_get_tny_account_by (modest_runtime_get_account_store (),
1403                                                              MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1404                                                              server_acc_name);
1405         
1406         const gchar *modest_acc_name = 
1407                 modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
1408         modest_window_set_active_account (window, modest_acc_name);
1409         g_object_unref (modest_server_account);
1410 }
1411
1412
1413 static void
1414 folder_refreshed_cb (const GObject *obj, 
1415                      TnyFolder *folder, 
1416                      gpointer user_data)
1417 {
1418         ModestMainWindow *win = NULL;
1419         GtkWidget *header_view;
1420
1421         g_return_if_fail (TNY_IS_FOLDER (folder));
1422
1423         win = MODEST_MAIN_WINDOW (user_data);
1424         header_view = 
1425                 modest_main_window_get_child_widget(win, MODEST_WIDGET_TYPE_HEADER_VIEW);
1426
1427         /* Check if folder is empty and set headers view contents style */
1428         if (tny_folder_get_all_count (folder) == 0) {
1429         printf ("DEBUG: %s: tny_folder_get_all_count() returned 0.\n", __FUNCTION__);
1430                 modest_main_window_set_contents_style (win,
1431                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1432         } else {
1433                 printf ("DEBUG: %s: tny_folder_get_all_count() returned >0.\n", __FUNCTION__);
1434         }
1435 }
1436
1437 void 
1438 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
1439                                                TnyFolderStore *folder_store, 
1440                                                gboolean selected,
1441                                                ModestMainWindow *main_window)
1442 {
1443         ModestConf *conf;
1444         GtkWidget *header_view;
1445
1446         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1447
1448         header_view = modest_main_window_get_child_widget(main_window,
1449                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
1450         if (!header_view)
1451                 return;
1452         
1453         conf = modest_runtime_get_conf ();
1454
1455         if (TNY_IS_ACCOUNT (folder_store)) {
1456                 if (selected) {
1457                         /* Update active account */
1458                         set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
1459                         /* Show account details */
1460                         modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1461                 }
1462         } else {
1463                 if (TNY_IS_FOLDER (folder_store) && selected) {
1464                         
1465                         /* Update the active account */
1466                         TnyAccount *account = modest_tny_folder_get_account (TNY_FOLDER (folder_store));
1467                         if (account) {
1468                                 set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
1469                                 g_object_unref (account);
1470                                 account = NULL;
1471                         }
1472
1473                         /* Set the header style by default, it could
1474                            be changed later by the refresh callback to
1475                            empty */
1476                         modest_main_window_set_contents_style (main_window, 
1477                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1478
1479                         /* Set folder on header view. This function
1480                            will call tny_folder_refresh_async so we
1481                            pass a callback that will be called when
1482                            finished. We use that callback to set the
1483                            empty view if there are no messages */
1484                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
1485                                                        TNY_FOLDER (folder_store),
1486                                                        folder_refreshed_cb,
1487                                                        main_window);
1488                         
1489                         /* Restore configuration. We need to do this
1490                            *after* the set_folder because the widget
1491                            memory asks the header view about its
1492                            folder  */
1493                         modest_widget_memory_restore (modest_runtime_get_conf (), 
1494                                                       G_OBJECT(header_view),
1495                                                       MODEST_CONF_HEADER_VIEW_KEY);
1496                 } else {
1497                         /* Update the active account */
1498                         modest_window_set_active_account (MODEST_WINDOW (main_window), NULL);
1499                         /* Save only if we're seeing headers */
1500                         if (modest_main_window_get_contents_style (main_window) ==
1501                             MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1502                                 modest_widget_memory_save (conf, G_OBJECT (header_view), 
1503                                                            MODEST_CONF_HEADER_VIEW_KEY);
1504                         modest_header_view_clear (MODEST_HEADER_VIEW(header_view));
1505                 }
1506         }
1507
1508         /* Update toolbar dimming state */
1509         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
1510 }
1511
1512 void 
1513 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
1514                                      ModestWindow *win)
1515 {
1516         GtkWidget *dialog;
1517         gchar *txt, *item;
1518         gboolean online;
1519
1520         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1521         
1522         online = tny_device_is_online (modest_runtime_get_device());
1523
1524         if (online) {
1525                 /* already online -- the item is simply not there... */
1526                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
1527                                                  GTK_DIALOG_MODAL,
1528                                                  GTK_MESSAGE_WARNING,
1529                                                  GTK_BUTTONS_OK,
1530                                                  _("The %s you selected cannot be found"),
1531                                                  item);
1532                 gtk_dialog_run (GTK_DIALOG(dialog));
1533         } else {
1534                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1535                                                       GTK_WINDOW (win),
1536                                                       GTK_DIALOG_MODAL,
1537                                                       GTK_STOCK_CANCEL,
1538                                                       GTK_RESPONSE_REJECT,
1539                                                       GTK_STOCK_OK,
1540                                                       GTK_RESPONSE_ACCEPT,
1541                                                       NULL);
1542                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1543                                          "Do you want to get online?"), item);
1544                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1545                                     gtk_label_new (txt), FALSE, FALSE, 0);
1546                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1547                 g_free (txt);
1548
1549                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1550                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1551 //                      modest_platform_connect_and_wait ();
1552                 }
1553         }
1554         gtk_widget_destroy (dialog);
1555 }
1556
1557 void
1558 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
1559                                      ModestWindow *win)
1560 {
1561         /* g_message ("%s %s", __FUNCTION__, link); */
1562 }       
1563
1564
1565 void
1566 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
1567                                         ModestWindow *win)
1568 {
1569         modest_platform_activate_uri (link);
1570 }
1571
1572 void
1573 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
1574                                           ModestWindow *win)
1575 {
1576         modest_platform_show_uri_popup (link);
1577 }
1578
1579 void
1580 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
1581                                              ModestWindow *win)
1582 {
1583         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
1584 }
1585
1586 void
1587 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
1588                                           const gchar *address,
1589                                           ModestWindow *win)
1590 {
1591         /* g_message ("%s %s", __FUNCTION__, address); */
1592 }
1593
1594 void
1595 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
1596 {
1597         TnyTransportAccount *transport_account;
1598         ModestMailOperation *mail_operation;
1599         MsgData *data;
1600         gchar *account_name, *from;
1601         ModestAccountMgr *account_mgr;
1602         gchar *info_text = NULL;
1603
1604         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
1605         
1606         data = modest_msg_edit_window_get_msg_data (edit_window);
1607
1608         account_mgr = modest_runtime_get_account_mgr();
1609         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
1610         if (!account_name) 
1611                 account_name = modest_account_mgr_get_default_account (account_mgr);
1612         if (!account_name) {
1613                 g_printerr ("modest: no account found\n");
1614                 modest_msg_edit_window_free_msg_data (edit_window, data);
1615                 return;
1616         }
1617
1618         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1619                 account_name = g_strdup (data->account_name);
1620         }
1621
1622         transport_account =
1623                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
1624                                       (modest_runtime_get_account_store(),
1625                                        account_name,
1626                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1627         if (!transport_account) {
1628                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1629                 g_free (account_name);
1630                 modest_msg_edit_window_free_msg_data (edit_window, data);
1631                 return;
1632         }
1633         from = modest_account_mgr_get_from_string (account_mgr, account_name);
1634
1635         /* Create the mail operation */         
1636         mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_INFO, G_OBJECT(edit_window));
1637         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
1638
1639         modest_mail_operation_save_to_drafts (mail_operation,
1640                                               transport_account,
1641                                               data->draft_msg,
1642                                               from,
1643                                               data->to, 
1644                                               data->cc, 
1645                                               data->bcc,
1646                                               data->subject, 
1647                                               data->plain_body, 
1648                                               data->html_body,
1649                                               data->attachments,
1650                                               data->priority_flags);
1651         /* Frees */
1652         g_free (from);
1653         g_free (account_name);
1654         g_object_unref (G_OBJECT (transport_account));
1655         g_object_unref (G_OBJECT (mail_operation));
1656
1657         modest_msg_edit_window_free_msg_data (edit_window, data);
1658
1659         info_text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
1660         modest_platform_information_banner (NULL, NULL, info_text);
1661         g_free (info_text);
1662 }
1663
1664 /* For instance, when clicking the Send toolbar button when editing a message: */
1665 void
1666 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
1667 {
1668         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
1669
1670         if (!modest_msg_edit_window_check_names (edit_window))
1671                 return;
1672         
1673         /* FIXME: Code added just for testing. The final version will
1674            use the send queue provided by tinymail and some
1675            classifier */
1676         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
1677         gchar *account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
1678         if (!account_name) 
1679                 account_name = modest_account_mgr_get_default_account (account_mgr);
1680                 
1681         if (!account_name) {
1682                 g_printerr ("modest: no account found\n");
1683                 return;
1684         }
1685         
1686         MsgData *data = modest_msg_edit_window_get_msg_data (edit_window);
1687
1688         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1689                 account_name = g_strdup (data->account_name);
1690         }
1691         
1692         /* Get the currently-active transport account for this modest account: */
1693         TnyTransportAccount *transport_account =
1694                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_transport_account_for_open_connection
1695                                       (modest_runtime_get_account_store(),
1696                                        account_name));
1697         if (!transport_account) {
1698                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
1699                 g_free (account_name);
1700                 modest_msg_edit_window_free_msg_data (edit_window, data);
1701                 return;
1702         }
1703         
1704         gchar *from = modest_account_mgr_get_from_string (account_mgr, account_name);
1705
1706         /* mail content checks and dialogs */
1707         if (data->subject == NULL || data->subject[0] == '\0') {
1708                 GtkResponseType response;
1709                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (edit_window),
1710                                                                     _("mcen_nc_subject_is_empty_send"));
1711                 if (response == GTK_RESPONSE_CANCEL) {
1712                         g_free (account_name);
1713                         return;
1714                 }
1715         }
1716
1717         if (data->plain_body == NULL || data->plain_body[0] == '\0') {
1718                 GtkResponseType response;
1719                 gchar *note_message;
1720                 gchar *note_subject = data->subject;
1721                 if (note_subject == NULL || note_subject[0] == '\0')
1722                         note_subject = _("mail_va_no_subject");
1723                 note_message = g_strdup_printf (_("emev_ni_ui_smtp_message_null"), note_subject);
1724                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (edit_window),
1725                                                                     note_message);
1726                 g_free (note_message);
1727                 if (response == GTK_RESPONSE_CANCEL) {
1728                         g_free (account_name);
1729                         return;
1730                 }
1731         }
1732
1733         modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
1734
1735         /* Create the mail operation */
1736         ModestMailOperation *mail_operation = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_SEND, G_OBJECT(edit_window));
1737         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
1738
1739         modest_mail_operation_send_new_mail (mail_operation,
1740                                              transport_account,
1741                                              data->draft_msg,
1742                                              from,
1743                                              data->to, 
1744                                              data->cc, 
1745                                              data->bcc,
1746                                              data->subject, 
1747                                              data->plain_body, 
1748                                              data->html_body,
1749                                              data->attachments,
1750                                              data->priority_flags);
1751                                              
1752         /* Free data: */
1753         g_free (from);
1754         g_free (account_name);
1755         g_object_unref (G_OBJECT (transport_account));
1756         g_object_unref (G_OBJECT (mail_operation));
1757
1758         modest_msg_edit_window_free_msg_data (edit_window, data);
1759         modest_msg_edit_window_set_sent (edit_window, TRUE);
1760
1761         /* Save settings and close the window: */
1762         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
1763 }
1764
1765 void 
1766 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
1767                                   ModestMsgEditWindow *window)
1768 {
1769         ModestMsgEditFormatState *format_state = NULL;
1770
1771         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1772         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
1773
1774         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1775                 return;
1776
1777         format_state = modest_msg_edit_window_get_format_state (window);
1778         g_return_if_fail (format_state != NULL);
1779
1780         format_state->bold = gtk_toggle_action_get_active (action);
1781         modest_msg_edit_window_set_format_state (window, format_state);
1782         g_free (format_state);
1783         
1784 }
1785
1786 void 
1787 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
1788                                      ModestMsgEditWindow *window)
1789 {
1790         ModestMsgEditFormatState *format_state = NULL;
1791
1792         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1793         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
1794
1795         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1796                 return;
1797
1798         format_state = modest_msg_edit_window_get_format_state (window);
1799         g_return_if_fail (format_state != NULL);
1800
1801         format_state->italics = gtk_toggle_action_get_active (action);
1802         modest_msg_edit_window_set_format_state (window, format_state);
1803         g_free (format_state);
1804         
1805 }
1806
1807 void 
1808 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
1809                                      ModestMsgEditWindow *window)
1810 {
1811         ModestMsgEditFormatState *format_state = NULL;
1812
1813         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1814         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
1815
1816         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1817                 return;
1818
1819         format_state = modest_msg_edit_window_get_format_state (window);
1820         g_return_if_fail (format_state != NULL);
1821
1822         format_state->bullet = gtk_toggle_action_get_active (action);
1823         modest_msg_edit_window_set_format_state (window, format_state);
1824         g_free (format_state);
1825         
1826 }
1827
1828 void 
1829 modest_ui_actions_on_change_justify (GtkRadioAction *action,
1830                                      GtkRadioAction *selected,
1831                                      ModestMsgEditWindow *window)
1832 {
1833         ModestMsgEditFormatState *format_state = NULL;
1834         GtkJustification value;
1835
1836         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1837
1838         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1839                 return;
1840
1841         value = gtk_radio_action_get_current_value (selected);
1842
1843         format_state = modest_msg_edit_window_get_format_state (window);
1844         g_return_if_fail (format_state != NULL);
1845
1846         format_state->justification = value;
1847         modest_msg_edit_window_set_format_state (window, format_state);
1848         g_free (format_state);
1849 }
1850
1851 void 
1852 modest_ui_actions_on_select_editor_color (GtkAction *action,
1853                                           ModestMsgEditWindow *window)
1854 {
1855         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1856         g_return_if_fail (GTK_IS_ACTION (action));
1857
1858         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1859                 return;
1860
1861         modest_msg_edit_window_select_color (window);
1862 }
1863
1864 void 
1865 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
1866                                                      ModestMsgEditWindow *window)
1867 {
1868         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1869         g_return_if_fail (GTK_IS_ACTION (action));
1870
1871         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1872                 return;
1873
1874         modest_msg_edit_window_select_background_color (window);
1875 }
1876
1877 void 
1878 modest_ui_actions_on_insert_image (GtkAction *action,
1879                                    ModestMsgEditWindow *window)
1880 {
1881         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1882         g_return_if_fail (GTK_IS_ACTION (action));
1883
1884         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
1885                 return;
1886
1887         modest_msg_edit_window_insert_image (window);
1888 }
1889
1890 void 
1891 modest_ui_actions_on_attach_file (GtkAction *action,
1892                                   ModestMsgEditWindow *window)
1893 {
1894         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1895         g_return_if_fail (GTK_IS_ACTION (action));
1896
1897         modest_msg_edit_window_attach_file (window);
1898 }
1899
1900 void 
1901 modest_ui_actions_on_remove_attachments (GtkAction *action,
1902                                          ModestMsgEditWindow *window)
1903 {
1904         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1905         g_return_if_fail (GTK_IS_ACTION (action));
1906
1907         modest_msg_edit_window_remove_attachments (window, NULL);
1908 }
1909
1910 void 
1911 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
1912 {
1913         TnyFolderStore *parent_folder;
1914         GtkWidget *folder_view;
1915         
1916         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1917
1918         folder_view = modest_main_window_get_child_widget (main_window,
1919                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1920         if (!folder_view)
1921                 return;
1922
1923         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1924         
1925         if (parent_folder) {
1926                 gboolean finished = FALSE;
1927                 gint result;
1928                 gchar *folder_name = NULL, *suggested_name = NULL;
1929
1930                 /* Run the new folder dialog */
1931                 while (!finished) {
1932                         result = modest_platform_run_new_folder_dialog (GTK_WINDOW (main_window),
1933                                                                         parent_folder,
1934                                                                         suggested_name,
1935                                                                         &folder_name);
1936
1937                         if (result == GTK_RESPONSE_REJECT) {
1938                                 finished = TRUE;
1939                         } else {
1940                                 ModestMailOperation *mail_op;
1941                                 TnyFolder *new_folder = NULL;
1942
1943                                 mail_op  = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_INFO, 
1944                                                                       G_OBJECT(main_window));
1945                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
1946                                                                  mail_op);
1947                                 new_folder = modest_mail_operation_create_folder (mail_op,
1948                                                                                   parent_folder,
1949                                                                                   (const gchar *) folder_name);
1950                                 if (new_folder) {
1951                                         g_object_unref (new_folder);
1952                                         finished = TRUE;
1953                                 }
1954                                 g_object_unref (mail_op);
1955                         }
1956                         g_free (folder_name);
1957                         folder_name = NULL;
1958                 }
1959
1960                 g_object_unref (parent_folder);
1961         }
1962 }
1963
1964 static void
1965 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
1966                                                gpointer user_data)
1967 {
1968         GObject *win = modest_mail_operation_get_source (mail_op);
1969         const GError *error = NULL;
1970         const gchar *message = NULL;
1971         
1972         /* Get error message */
1973         error = modest_mail_operation_get_error (mail_op);
1974         if (error != NULL && error->message != NULL) {
1975                 message = error->message;
1976         } else {
1977                 message = _("!!! FIXME: Unable to rename");
1978         }
1979         
1980         /* Show notification dialog */
1981         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, message);
1982         g_object_unref (win);
1983 }
1984
1985 void 
1986 modest_ui_actions_on_rename_folder (GtkAction *action,
1987                                      ModestMainWindow *main_window)
1988 {
1989         TnyFolderStore *folder;
1990         GtkWidget *folder_view;
1991         GtkWidget *header_view; 
1992
1993         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1994
1995         folder_view = modest_main_window_get_child_widget (main_window,
1996                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1997         if (!folder_view)
1998                 return;
1999
2000         header_view = modest_main_window_get_child_widget (main_window,
2001                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
2002         
2003         if (!header_view)
2004                 return;
2005
2006         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
2007         
2008         if (folder && TNY_IS_FOLDER (folder)) {
2009                 gchar *folder_name;
2010                 gint response;
2011                 const gchar *current_name;
2012
2013                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
2014                 response = modest_platform_run_rename_folder_dialog (GTK_WINDOW (main_window), NULL,
2015                                                                      current_name, &folder_name);
2016
2017                 if (response == GTK_RESPONSE_ACCEPT && strlen (folder_name) > 0) {
2018                         ModestMailOperation *mail_op;
2019
2020                         mail_op = 
2021                                 modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_INFO, 
2022                                                                                G_OBJECT(main_window),
2023                                                                                modest_ui_actions_rename_folder_error_handler,
2024                                                                                NULL);
2025
2026
2027                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2028                                                          mail_op);
2029
2030                         modest_header_view_clear (MODEST_HEADER_VIEW (header_view));
2031
2032                         modest_mail_operation_rename_folder (mail_op,
2033                                                              TNY_FOLDER (folder),
2034                                                              (const gchar *) folder_name);
2035
2036                         g_object_unref (mail_op);
2037                         g_free (folder_name);
2038                 }
2039                 g_object_unref (folder);
2040         }
2041 }
2042
2043 static void
2044 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
2045                                                gpointer user_data)
2046 {
2047         GObject *win = modest_mail_operation_get_source (mail_op);
2048
2049         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
2050                                                 _("mail_in_ui_folder_delete_error"));
2051         g_object_unref (win);
2052 }
2053
2054 static void
2055 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
2056 {
2057         TnyFolderStore *folder;
2058         GtkWidget *folder_view;
2059         gint response;
2060         gchar *message;
2061         
2062         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2063
2064         folder_view = modest_main_window_get_child_widget (main_window,
2065                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
2066         if (!folder_view)
2067                 return;
2068
2069         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2070
2071         /* Show an error if it's an account */
2072         if (!TNY_IS_FOLDER (folder)) {
2073                 modest_platform_run_information_dialog (GTK_WINDOW (main_window),
2074                                                         _("mail_in_ui_folder_delete_error"));
2075                 return ;
2076         }
2077
2078         /* Ask the user */      
2079         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"), 
2080                                     tny_folder_get_name (TNY_FOLDER (folder)));
2081         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (main_window),
2082                                                             (const gchar *) message);
2083         g_free (message);
2084
2085         if (response == GTK_RESPONSE_OK) {
2086                 ModestMailOperation *mail_op = 
2087                         modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_DELETE, 
2088                                                                        G_OBJECT(main_window),
2089                                                                        modest_ui_actions_delete_folder_error_handler,
2090                                                                        NULL);
2091
2092                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2093                                                  mail_op);
2094                 modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (folder), move_to_trash);
2095                 g_object_unref (G_OBJECT (mail_op));
2096         }
2097
2098         g_object_unref (G_OBJECT (folder));
2099 }
2100
2101 void 
2102 modest_ui_actions_on_delete_folder (GtkAction *action,
2103                                      ModestMainWindow *main_window)
2104 {
2105         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2106
2107         delete_folder (main_window, FALSE);
2108 }
2109
2110 void 
2111 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
2112 {
2113         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2114         
2115         delete_folder (main_window, TRUE);
2116 }
2117
2118 void
2119 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
2120                                          const gchar* server_account_name,
2121                                          gchar **username,
2122                                          gchar **password, 
2123                                          gboolean *cancel, 
2124                                          gboolean *remember,
2125                                          ModestMainWindow *main_window)
2126 {
2127         g_return_if_fail(server_account_name);
2128         /* printf("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
2129         
2130         /* Initalize output parameters: */
2131         if (cancel)
2132                 *cancel = FALSE;
2133                 
2134         if (remember)
2135                 *remember = TRUE;
2136                 
2137 #ifdef MODEST_PLATFORM_MAEMO
2138         /* Maemo uses a different (awkward) button order,
2139          * It should probably just use gtk_alternative_dialog_button_order ().
2140          */
2141         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
2142                                               NULL,
2143                                               GTK_DIALOG_MODAL,
2144                                               GTK_STOCK_OK,
2145                                               GTK_RESPONSE_ACCEPT,
2146                                               GTK_STOCK_CANCEL,
2147                                               GTK_RESPONSE_REJECT,
2148                                               NULL);
2149 #else
2150         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
2151                                               NULL,
2152                                               GTK_DIALOG_MODAL,
2153                                               GTK_STOCK_CANCEL,
2154                                               GTK_RESPONSE_REJECT,
2155                                               GTK_STOCK_OK,
2156                                               GTK_RESPONSE_ACCEPT,
2157                                               NULL);
2158 #endif /* MODEST_PLATFORM_MAEMO */
2159
2160         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
2161         
2162         gchar *server_name = modest_server_account_get_hostname (
2163                 modest_runtime_get_account_mgr(), server_account_name);
2164         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
2165                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
2166                 *cancel = TRUE;
2167                 return;
2168         }
2169         
2170         /* This causes a warning because the logical ID has no %s in it, 
2171          * though the translation does, but there is not much we can do about that: */
2172         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
2173         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
2174                             FALSE, FALSE, 0);
2175         g_free (txt);
2176         g_free (server_name);
2177         server_name = NULL;
2178
2179         /* username: */
2180         gchar *initial_username = modest_server_account_get_username (
2181                 modest_runtime_get_account_mgr(), server_account_name);
2182         
2183         GtkWidget *entry_username = gtk_entry_new ();
2184         if (initial_username)
2185                 gtk_entry_set_text (GTK_ENTRY (entry_username), initial_username);
2186         /* Dim this if a connection has ever succeeded with this username,
2187          * as per the UI spec: */
2188         const gboolean username_known = 
2189                 modest_server_account_get_username_has_succeeded(
2190                         modest_runtime_get_account_mgr(), server_account_name);
2191         gtk_widget_set_sensitive (entry_username, !username_known);
2192         
2193 #ifdef MODEST_PLATFORM_MAEMO
2194         /* Auto-capitalization is the default, so let's turn it off: */
2195         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
2196         
2197         /* Create a size group to be used by all captions.
2198          * Note that HildonCaption does not create a default size group if we do not specify one.
2199          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
2200         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2201         
2202         GtkWidget *caption = hildon_caption_new (sizegroup, 
2203                 _("mail_fi_username"), entry_username, NULL, HILDON_CAPTION_MANDATORY);
2204         gtk_widget_show (entry_username);
2205         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
2206                 FALSE, FALSE, MODEST_MARGIN_HALF);
2207         gtk_widget_show (caption);
2208 #else 
2209         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_username,
2210                             TRUE, FALSE, 0);
2211 #endif /* MODEST_PLATFORM_MAEMO */      
2212                             
2213         /* password: */
2214         GtkWidget *entry_password = gtk_entry_new ();
2215         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
2216         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
2217         
2218 #ifdef MODEST_PLATFORM_MAEMO
2219         /* Auto-capitalization is the default, so let's turn it off: */
2220         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password), 
2221                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
2222         
2223         caption = hildon_caption_new (sizegroup, 
2224                 _("mail_fi_password"), entry_password, NULL, HILDON_CAPTION_MANDATORY);
2225         gtk_widget_show (entry_password);
2226         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
2227                 FALSE, FALSE, MODEST_MARGIN_HALF);
2228         gtk_widget_show (caption);
2229         g_object_unref (sizegroup);
2230 #else 
2231         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_password,
2232                             TRUE, FALSE, 0);
2233 #endif /* MODEST_PLATFORM_MAEMO */      
2234                                 
2235 /* This is not in the Maemo UI spec:
2236         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
2237         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
2238                             TRUE, FALSE, 0);
2239 */
2240
2241         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2242         
2243         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2244                 if (username) {
2245                         *username = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_username)));
2246                         
2247                         modest_server_account_set_username (
2248                                  modest_runtime_get_account_mgr(), server_account_name, 
2249                                  *username);
2250                                  
2251                         const gboolean username_was_changed = 
2252                                 (strcmp (*username, initial_username) != 0);
2253                         if (username_was_changed) {
2254                                 g_warning ("%s: tinymail does not yet support changing the "
2255                                         "username in the get_password() callback.\n", __FUNCTION__);
2256                         }
2257                 }
2258                         
2259                 if (password) {
2260                         *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_password)));
2261                         
2262                         /* We do not save the password in the configuration, 
2263                          * because this function is only called for passwords that should 
2264                          * not be remembered:
2265                         modest_server_account_set_password (
2266                                  modest_runtime_get_account_mgr(), server_account_name, 
2267                                  *password);
2268                         */
2269                 }
2270                 
2271                 if (cancel)
2272                         *cancel   = FALSE;
2273                         
2274         } else {
2275                 if (username)
2276                         *username = NULL;
2277                         
2278                 if (password)
2279                         *password = NULL;
2280                         
2281                 if (cancel)
2282                         *cancel   = TRUE;
2283         }
2284
2285 /* This is not in the Maemo UI spec:
2286         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
2287                 *remember = TRUE;
2288         else
2289                 *remember = FALSE;
2290 */
2291
2292         gtk_widget_destroy (dialog);
2293         
2294         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
2295 }
2296
2297 void
2298 modest_ui_actions_on_cut (GtkAction *action,
2299                           ModestWindow *window)
2300 {
2301         GtkWidget *focused_widget;
2302
2303         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2304         if (GTK_IS_EDITABLE (focused_widget)) {
2305                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
2306         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2307                 GtkTextBuffer *buffer;
2308                 GtkClipboard *clipboard;
2309
2310                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2311                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2312                 gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
2313         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
2314                 modest_header_view_cut_selection (MODEST_HEADER_VIEW (focused_widget));
2315         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2316                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
2317         }
2318 }
2319
2320 void
2321 modest_ui_actions_on_copy (GtkAction *action,
2322                            ModestWindow *window)
2323 {
2324         GtkClipboard *clipboard;
2325         GtkWidget *focused_widget;
2326
2327         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2328         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2329
2330         if (GTK_IS_LABEL (focused_widget)) {
2331                 gtk_clipboard_set_text (clipboard, gtk_label_get_text (GTK_LABEL (focused_widget)), -1);
2332         } else if (GTK_IS_EDITABLE (focused_widget)) {
2333                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
2334         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2335                 GtkTextBuffer *buffer;
2336                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2337                 gtk_text_buffer_copy_clipboard (buffer, clipboard);
2338                 modest_header_view_copy_selection (MODEST_HEADER_VIEW (focused_widget));
2339         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
2340                 TnyList *header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (focused_widget));
2341                 TnyIterator *iter = tny_list_create_iterator (header_list);
2342                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
2343                 TnyFolder *folder = tny_header_get_folder (header);
2344                 TnyAccount *account = tny_folder_get_account (folder);
2345                 const gchar *proto_str = tny_account_get_proto (TNY_ACCOUNT (account));
2346                 /* If it's POP then ask */
2347                 gboolean ask = (modest_protocol_info_get_transport_store_protocol (proto_str) == 
2348                        MODEST_PROTOCOL_STORE_POP) ? TRUE : FALSE;
2349                 g_object_unref (account);
2350                 g_object_unref (folder);
2351                 g_object_unref (header);
2352                 g_object_unref (iter);
2353                 
2354                 /* Check that the messages have been previously downloaded */
2355                 gboolean continue_download = TRUE;
2356                 if (ask)
2357                         continue_download = download_uncached_messages (header_list, GTK_WINDOW (window));
2358                 if (continue_download)
2359                         modest_header_view_copy_selection (MODEST_HEADER_VIEW (focused_widget));
2360                 g_object_unref (header_list);
2361         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2362                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
2363         }    
2364
2365         /* Show information banner */
2366         modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
2367         
2368 }
2369
2370 void
2371 modest_ui_actions_on_undo (GtkAction *action,
2372                            ModestWindow *window)
2373 {
2374         ModestEmailClipboard *clipboard = NULL;
2375
2376         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
2377                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
2378         } else if (MODEST_IS_MAIN_WINDOW (window)) {
2379                 /* Clear clipboard source */
2380                 clipboard = modest_runtime_get_email_clipboard ();
2381                 modest_email_clipboard_clear (clipboard);               
2382         }
2383         else {
2384                 g_return_if_reached ();
2385         }
2386 }
2387
2388 void
2389 modest_ui_actions_on_paste (GtkAction *action,
2390                             ModestWindow *window)
2391 {
2392         GtkWidget *focused_widget;
2393         ModestMailOperation *mail_op = NULL;
2394
2395         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2396         if (GTK_IS_EDITABLE (focused_widget)) {
2397                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
2398         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2399                 GtkTextBuffer *buffer;
2400                 GtkClipboard *clipboard;
2401
2402                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2403                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2404                 gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
2405         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
2406                 ModestEmailClipboard *clipboard = NULL;
2407                 TnyFolder *src_folder = NULL;
2408                 TnyFolderStore *folder_store = NULL;
2409                 TnyList *data = NULL;           
2410                 gboolean delete = FALSE;
2411                 
2412                 /* Check clipboard source */
2413                 clipboard = modest_runtime_get_email_clipboard ();
2414                 if (modest_email_clipboard_cleared (clipboard)) 
2415                         return;
2416                 
2417                 /* Get elements to paste */
2418                 modest_email_clipboard_get_data (clipboard, &src_folder, &data, &delete);
2419
2420                 /* Create a new mail operation */
2421                 mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(window));
2422                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
2423                                                  mail_op);
2424                 
2425                 /* Get destination folder */
2426                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (focused_widget));
2427
2428                 /* transfer messages  */
2429                 if (data != NULL) {
2430                         modest_mail_operation_xfer_msgs (mail_op, 
2431                                                          data,
2432                                                          TNY_FOLDER (folder_store),
2433                                                          delete,
2434                                                          NULL,
2435                                                          NULL);
2436                         
2437                 } else if (src_folder != NULL) {                        
2438                         modest_mail_operation_xfer_folder (mail_op, 
2439                                                            src_folder,
2440                                                            folder_store,
2441                                                            delete);
2442                 }
2443
2444                 /* Free */
2445                 if (data != NULL) 
2446                         g_object_unref (data);
2447                 if (src_folder != NULL) 
2448                         g_object_unref (src_folder);
2449                 if (folder_store != NULL) 
2450                         g_object_unref (folder_store);
2451         }
2452 }
2453
2454 void
2455 modest_ui_actions_on_select_all (GtkAction *action,
2456                                  ModestWindow *window)
2457 {
2458         GtkWidget *focused_widget;
2459
2460         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
2461         if (MODEST_IS_ATTACHMENTS_VIEW (focused_widget)) {
2462                 modest_attachments_view_select_all (MODEST_ATTACHMENTS_VIEW (focused_widget));
2463         } else if (GTK_IS_LABEL (focused_widget)) {
2464                 gtk_label_select_region (GTK_LABEL (focused_widget), 0, -1);
2465         } else if (GTK_IS_EDITABLE (focused_widget)) {
2466                 gtk_editable_select_region (GTK_EDITABLE(focused_widget), 0, -1);
2467         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
2468                 GtkTextBuffer *buffer;
2469                 GtkTextIter start, end;
2470
2471                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
2472                 gtk_text_buffer_get_start_iter (buffer, &start);
2473                 gtk_text_buffer_get_end_iter (buffer, &end);
2474                 gtk_text_buffer_select_range (buffer, &start, &end);
2475         } else if (GTK_IS_HTML (focused_widget)) {
2476                 gtk_html_select_all (GTK_HTML (focused_widget));
2477         } else if (MODEST_IS_MAIN_WINDOW (window)) {
2478                 GtkWidget *header_view = focused_widget;
2479                 GtkTreeSelection *selection = NULL;
2480                 
2481                 if (!(MODEST_IS_HEADER_VIEW (focused_widget)))
2482                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
2483                                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
2484                                 
2485                 /* Select all messages */
2486                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
2487                 gtk_tree_selection_select_all (selection);
2488
2489                 /* Set focuse on header view */
2490                 gtk_widget_grab_focus (header_view);
2491         }
2492
2493 }
2494
2495 void
2496 modest_ui_actions_on_mark_as_read (GtkAction *action,
2497                                    ModestWindow *window)
2498 {       
2499         g_return_if_fail (MODEST_IS_WINDOW(window));
2500                 
2501         /* Mark each header as read */
2502         do_headers_action (window, headers_action_mark_as_read, NULL);
2503 }
2504
2505 void
2506 modest_ui_actions_on_mark_as_unread (GtkAction *action,
2507                                      ModestWindow *window)
2508 {       
2509         g_return_if_fail (MODEST_IS_WINDOW(window));
2510                 
2511         /* Mark each header as read */
2512         do_headers_action (window, headers_action_mark_as_unread, NULL);
2513 }
2514
2515 void
2516 modest_ui_actions_on_change_zoom (GtkRadioAction *action,
2517                                   GtkRadioAction *selected,
2518                                   ModestWindow *window)
2519 {
2520         gint value;
2521
2522         value = gtk_radio_action_get_current_value (selected);
2523         if (MODEST_IS_WINDOW (window)) {
2524                 modest_window_set_zoom (MODEST_WINDOW (window), ((gdouble)value)/100);
2525         }
2526 }
2527
2528 void     modest_ui_actions_msg_edit_on_change_priority (GtkRadioAction *action,
2529                                                         GtkRadioAction *selected,
2530                                                         ModestWindow *window)
2531 {
2532         TnyHeaderFlags flags;
2533         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2534
2535         flags = gtk_radio_action_get_current_value (selected);
2536         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW (window), flags);
2537 }
2538
2539 void     modest_ui_actions_msg_edit_on_change_file_format (GtkRadioAction *action,
2540                                                            GtkRadioAction *selected,
2541                                                            ModestWindow *window)
2542 {
2543         gint file_format;
2544
2545         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2546
2547         file_format = gtk_radio_action_get_current_value (selected);
2548         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (window), file_format);
2549 }
2550
2551
2552 void     
2553 modest_ui_actions_on_zoom_plus (GtkAction *action,
2554                                 ModestWindow *window)
2555 {
2556         g_return_if_fail (MODEST_IS_WINDOW (window));
2557
2558         modest_window_zoom_plus (MODEST_WINDOW (window));
2559 }
2560
2561 void     
2562 modest_ui_actions_on_zoom_minus (GtkAction *action,
2563                                  ModestWindow *window)
2564 {
2565         g_return_if_fail (MODEST_IS_WINDOW (window));
2566
2567         modest_window_zoom_minus (MODEST_WINDOW (window));
2568 }
2569
2570 void     
2571 modest_ui_actions_on_toggle_fullscreen    (GtkToggleAction *toggle,
2572                                            ModestWindow *window)
2573 {
2574         ModestWindowMgr *mgr;
2575         gboolean fullscreen, active;
2576         g_return_if_fail (MODEST_IS_WINDOW (window));
2577
2578         mgr = modest_runtime_get_window_mgr ();
2579
2580         active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle)))?1:0;
2581         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
2582
2583         if (active != fullscreen) {
2584                 modest_window_mgr_set_fullscreen_mode (mgr, active);
2585                 gtk_window_present (GTK_WINDOW (window));
2586         }
2587 }
2588
2589 void
2590 modest_ui_actions_on_change_fullscreen (GtkAction *action,
2591                                         ModestWindow *window)
2592 {
2593         ModestWindowMgr *mgr;
2594         gboolean fullscreen;
2595
2596         g_return_if_fail (MODEST_IS_WINDOW (window));
2597
2598         mgr = modest_runtime_get_window_mgr ();
2599         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
2600         modest_window_mgr_set_fullscreen_mode (mgr, !fullscreen);
2601
2602         gtk_window_present (GTK_WINDOW (window));
2603 }
2604
2605 /* 
2606  * Used by modest_ui_actions_on_details to call do_headers_action 
2607  */
2608 static void
2609 headers_action_show_details (TnyHeader *header, 
2610                              ModestWindow *window,
2611                              gpointer user_data)
2612
2613 {
2614         GtkWidget *dialog;
2615         
2616         /* Create dialog */
2617         dialog = modest_details_dialog_new_with_header (GTK_WINDOW (window), header);
2618
2619         /* Run dialog */
2620         gtk_widget_show_all (dialog);
2621         gtk_dialog_run (GTK_DIALOG (dialog));
2622
2623         gtk_widget_destroy (dialog);
2624 }
2625
2626 /*
2627  * Show the folder details in a ModestDetailsDialog widget
2628  */
2629 static void
2630 show_folder_details (TnyFolder *folder, 
2631                      GtkWindow *window)
2632 {
2633         GtkWidget *dialog;
2634         
2635         /* Create dialog */
2636         dialog = modest_details_dialog_new_with_folder (window, folder);
2637
2638         /* Run dialog */
2639         gtk_widget_show_all (dialog);
2640         gtk_dialog_run (GTK_DIALOG (dialog));
2641
2642         gtk_widget_destroy (dialog);
2643 }
2644
2645 /*
2646  * Show the header details in a ModestDetailsDialog widget
2647  */
2648 void     
2649 modest_ui_actions_on_details (GtkAction *action, 
2650                               ModestWindow *win)
2651 {
2652         TnyList * headers_list;
2653         TnyIterator *iter;
2654         TnyHeader *header;              
2655
2656         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
2657                 TnyMsg *msg;
2658
2659                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (win));
2660                 if (!msg)
2661                         return;
2662                 g_object_unref (msg);           
2663
2664                 headers_list = get_selected_headers (win);
2665                 if (!headers_list)
2666                         return;
2667
2668                 iter = tny_list_create_iterator (headers_list);
2669
2670                 header = TNY_HEADER (tny_iterator_get_current (iter));
2671                 headers_action_show_details (header, win, NULL);
2672                 g_object_unref (header);
2673
2674                 g_object_unref (iter);
2675                 g_object_unref (headers_list);
2676
2677         } else if (MODEST_IS_MAIN_WINDOW (win)) {
2678                 GtkWidget *folder_view, *header_view;
2679
2680                 /* Check which widget has the focus */
2681                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
2682                                                                     MODEST_WIDGET_TYPE_FOLDER_VIEW);
2683                 if (gtk_widget_is_focus (folder_view)) {
2684                         TnyFolderStore *folder_store
2685                                 = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2686                         if (!folder_store) {
2687                                 g_warning ("%s: No item was selected.\n", __FUNCTION__);
2688                                 return; 
2689                         }
2690                         /* Show only when it's a folder */
2691                         /* This function should not be called for account items, 
2692                          * because we dim the menu item for them. */
2693                         if (TNY_IS_FOLDER (folder_store)) {
2694                                 show_folder_details (TNY_FOLDER (folder_store), GTK_WINDOW (win));
2695                         }
2696
2697                         g_object_unref (folder_store);
2698
2699                 } else {
2700                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
2701                                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
2702                         /* Show details of each header */
2703                         do_headers_action (win, headers_action_show_details, header_view);
2704                 }
2705         }
2706 }
2707
2708 void     
2709 modest_ui_actions_on_toggle_show_cc (GtkToggleAction *toggle,
2710                                      ModestMsgEditWindow *window)
2711 {
2712         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2713
2714         modest_msg_edit_window_show_cc (window, gtk_toggle_action_get_active (toggle));
2715 }
2716
2717 void     
2718 modest_ui_actions_on_toggle_show_bcc (GtkToggleAction *toggle,
2719                                       ModestMsgEditWindow *window)
2720 {
2721         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2722
2723         modest_msg_edit_window_show_bcc (window, gtk_toggle_action_get_active (toggle));
2724 }
2725
2726 void
2727 modest_ui_actions_toggle_folders_view (GtkAction *action, 
2728                                        ModestMainWindow *main_window)
2729 {
2730         ModestConf *conf;
2731         
2732         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2733
2734         conf = modest_runtime_get_conf ();
2735         
2736         if (modest_main_window_get_style (main_window) == MODEST_MAIN_WINDOW_STYLE_SPLIT)
2737                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SIMPLE);
2738         else
2739                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SPLIT);
2740 }
2741
2742 void 
2743 modest_ui_actions_on_toggle_toolbar (GtkToggleAction *toggle, 
2744                                      ModestWindow *window)
2745 {
2746         gboolean active, fullscreen = FALSE;
2747         ModestWindowMgr *mgr;
2748
2749         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle));
2750
2751         /* Check if we want to toggle the toolbar vuew in fullscreen
2752            or normal mode */
2753         if (!strcmp (gtk_action_get_name (GTK_ACTION (toggle)), 
2754                      "ViewShowToolbarFullScreen")) {
2755                 fullscreen = TRUE;
2756         }
2757
2758         /* Toggle toolbar */
2759         mgr = modest_runtime_get_window_mgr ();
2760         modest_window_mgr_show_toolbars (mgr, active, fullscreen);
2761 }
2762
2763 void     
2764 modest_ui_actions_msg_edit_on_select_font (GtkAction *action,
2765                                            ModestMsgEditWindow *window)
2766 {
2767         modest_msg_edit_window_select_font (window);
2768 }
2769
2770 void
2771 modest_ui_actions_on_folder_display_name_changed (ModestFolderView *folder_view,
2772                                                   const gchar *display_name,
2773                                                   GtkWindow *window)
2774 {
2775         /* Do not change the application name if the widget has not
2776            the focus. This callback could be called even if the folder
2777            view has not the focus, because the handled signal could be
2778            emitted when the folder view is redrawn */
2779         if (gtk_widget_is_focus (GTK_WIDGET (folder_view))) {
2780                 if (display_name)
2781                         gtk_window_set_title (window, display_name);
2782                 else
2783                         gtk_window_set_title (window, " ");
2784         }
2785 }
2786
2787 void
2788 modest_ui_actions_on_select_contacts (GtkAction *action, ModestMsgEditWindow *window)
2789 {
2790         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2791         modest_msg_edit_window_select_contacts (window);
2792 }
2793
2794 void
2795 modest_ui_actions_on_check_names (GtkAction *action, ModestMsgEditWindow *window)
2796 {
2797         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2798         modest_msg_edit_window_check_names (window);
2799 }
2800
2801
2802 static GtkWidget*
2803 create_move_to_dialog (ModestWindow *win,
2804                        GtkWidget *folder_view,
2805                        GtkWidget **tree_view)
2806 {
2807         GtkWidget *dialog, *scroll;
2808
2809         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2810                                               GTK_WINDOW (win),
2811                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
2812                                               GTK_STOCK_OK,
2813                                               GTK_RESPONSE_ACCEPT,
2814                                               GTK_STOCK_CANCEL,
2815                                               GTK_RESPONSE_REJECT,
2816                                               NULL);
2817
2818         /* Create scrolled window */
2819         scroll = gtk_scrolled_window_new (NULL, NULL);
2820         gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW (scroll),
2821                                          GTK_POLICY_AUTOMATIC,
2822                                          GTK_POLICY_AUTOMATIC);
2823
2824         /* Create folder view */
2825         *tree_view = modest_platform_create_folder_view (NULL);
2826
2827         /* It could happen that we're trying to move a message from a
2828            window (msg window for example) after the main window was
2829            closed, so we can not just get the model of the folder
2830            view */
2831         if (MODEST_IS_FOLDER_VIEW (folder_view))
2832                 gtk_tree_view_set_model (GTK_TREE_VIEW (*tree_view),
2833                                          gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view)));
2834         else
2835                 modest_folder_view_update_model (MODEST_FOLDER_VIEW (*tree_view), 
2836                                                  TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
2837
2838         gtk_container_add (GTK_CONTAINER (scroll), *tree_view);
2839
2840         /* Add scroll to dialog */
2841         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), 
2842                             scroll, FALSE, FALSE, 0);
2843
2844         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2845
2846         /* Select INBOX or local account */
2847         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (*tree_view));
2848
2849         return dialog;
2850 }
2851
2852 /*
2853  * Returns TRUE if at least one of the headers of the list belongs to
2854  * a message that has been fully retrieved.
2855  */
2856 static gboolean
2857 has_retrieved_msgs (TnyList *list)
2858 {
2859         TnyIterator *iter;
2860         gboolean found = FALSE;
2861
2862         iter = tny_list_create_iterator (list);
2863         while (tny_iterator_is_done (iter) && !found) {
2864                 TnyHeader *header;
2865                 TnyHeaderFlags flags;
2866
2867                 header = TNY_HEADER (tny_iterator_get_current (iter));
2868                 flags = tny_header_get_flags (header);
2869                 if (!(flags & TNY_HEADER_FLAG_PARTIAL))
2870                         found = TRUE;
2871
2872                 if (!found)
2873                         tny_iterator_next (iter);
2874         }
2875         g_object_unref (iter);
2876
2877         return found;
2878 }
2879
2880 /*
2881  * Shows a confirmation dialog to the user when we're moving messages
2882  * from a remote server to the local storage. Returns the dialog
2883  * response. If it's other kind of movement the it always returns
2884  * GTK_RESPONSE_OK
2885  */
2886 static gint
2887 msgs_move_to_confirmation (GtkWindow *win,
2888                            TnyFolder *dest_folder,
2889                            TnyList *headers)
2890 {
2891         gint response = GTK_RESPONSE_OK;
2892
2893         /* If the destination is a local folder */
2894         if (modest_tny_folder_is_local_folder (dest_folder)) {
2895                 TnyFolder *src_folder;
2896                 TnyIterator *iter;
2897                 TnyHeader *header;
2898
2899                 /* Get source folder */
2900                 iter = tny_list_create_iterator (headers);
2901                 header = TNY_HEADER (tny_iterator_get_current (iter));
2902                 src_folder = tny_header_get_folder (header);
2903                 g_object_unref (header);
2904                 g_object_unref (iter);
2905
2906                 /* if no src_folder, message may be an attahcment */
2907                 if (src_folder == NULL) 
2908                         return GTK_RESPONSE_CANCEL;
2909
2910                 /* If the source is a remote folder */
2911                 if (!modest_tny_folder_is_local_folder (src_folder)) {
2912                         const gchar *message;
2913                         
2914                         if (has_retrieved_msgs (headers))
2915                                 message = ngettext ("mcen_nc_move_retrieve", "mcen_nc_move_retrieves",
2916                                                     tny_list_get_length (headers));
2917                         else 
2918                                 message = ngettext ("mcen_nc_move_header", "mcen_nc_move_headers",
2919                                                     tny_list_get_length (headers));
2920
2921                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
2922                                                                             (const gchar *) message);
2923                 }
2924                 g_object_unref (src_folder);
2925         }
2926         return response;
2927 }
2928
2929
2930 static void
2931 transfer_msgs_from_viewer_cb (const GObject *object, gpointer user_data)
2932 {
2933         ModestMsgViewWindow *self = NULL;
2934         gboolean last, first;
2935
2936         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (object));
2937         self = MODEST_MSG_VIEW_WINDOW (object);
2938         
2939         last = modest_msg_view_window_last_message_selected (self);
2940         first = modest_msg_view_window_first_message_selected (self);   
2941         if (last & first) {
2942                 /* No more messages to view, so close this window */
2943 /*              gboolean ret_value; */
2944 /*              g_signal_emit_by_name (G_OBJECT (self), "delete-event", NULL, &ret_value); */
2945                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW(self));
2946         } else if (last)
2947                 modest_msg_view_window_select_previous_message (self);
2948         else 
2949                 modest_msg_view_window_select_next_message (self);
2950 }
2951
2952 void
2953 modest_ui_actions_move_folder_error_handler (ModestMailOperation *mail_op, 
2954                                              gpointer user_data)
2955 {
2956         GObject *win = modest_mail_operation_get_source (mail_op);
2957         const GError *error = NULL;
2958         const gchar *message = NULL;
2959         
2960         /* Get error message */
2961         error = modest_mail_operation_get_error (mail_op);
2962         if (error != NULL && error->message != NULL) {
2963                 message = error->message;
2964         } else {
2965                 message = _("mail_in_ui_folder_move_target_error");
2966         }
2967         
2968         /* Show notification dialog */
2969         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, message);
2970         g_object_unref (win);
2971 }
2972
2973 void
2974 modest_ui_actions_send_receive_error_handler (ModestMailOperation *mail_op, 
2975                                               gpointer user_data)
2976 {
2977         GObject *win = modest_mail_operation_get_source (mail_op);
2978         const GError *error = modest_mail_operation_get_error (mail_op);
2979
2980         g_return_if_fail (error != NULL);
2981         if (error->message != NULL)             
2982                 g_printerr ("modest: %s\n", error->message);
2983         else
2984                 g_printerr ("modest: unkonw error on send&receive operation");
2985
2986         /* Show error message */
2987 /*      if (modest_mail_operation_get_id (mail_op) == MODEST_MAIL_OPERATION_TYPE_RECEIVE) */
2988 /*              modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, */
2989 /*                                                      _CS("sfil_ib_unable_to_receive")); */
2990 /*      else  */
2991 /*              modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL, */
2992 /*                                                      _CS("sfil_ib_unable_to_send")); */
2993         g_object_unref (win);
2994 }
2995
2996 static void
2997 open_msg_for_purge_cb (ModestMailOperation *mail_op, 
2998                        TnyHeader *header, 
2999                        TnyMsg *msg, 
3000                        gpointer user_data)
3001 {
3002         TnyList *parts;
3003         TnyIterator *iter;
3004         gint pending_purges = 0;
3005         gboolean some_purged = FALSE;
3006         ModestWindow *win = MODEST_WINDOW (user_data);
3007         if (!msg)
3008                 return;
3009
3010         /* Once the message has been retrieved for purging, we check if
3011          * it's all ok for purging */
3012
3013         parts = tny_simple_list_new ();
3014         tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
3015         iter = tny_list_create_iterator (parts);
3016
3017         while (!tny_iterator_is_done (iter)) {
3018                 TnyMimePart *part;
3019                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3020                 if (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part)) {
3021                         if (tny_mime_part_is_purged (part))
3022                                 some_purged = TRUE;
3023                         else
3024                                 pending_purges++;
3025                 }
3026                 tny_iterator_next (iter);
3027         }
3028
3029         if (pending_purges>0) {
3030                 gint response;
3031                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),_("mcen_nc_purge_file_text_inbox"));
3032
3033                 if (response == GTK_RESPONSE_OK) {
3034                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_removing_attachment"));
3035                         tny_iterator_first (iter);
3036                         while (!tny_iterator_is_done (iter)) {
3037                                 TnyMimePart *part;
3038                                 
3039                                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3040                                 if (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part))
3041                                         tny_mime_part_set_purged (part);
3042                                 tny_iterator_next (iter);
3043                         }
3044                         
3045                         tny_msg_rewrite_cache (msg);
3046                 }
3047         } else {
3048                 modest_platform_information_banner (NULL, NULL, _("mail_ib_attachment_already_purged"));
3049         }
3050
3051         /* remove attachments */
3052         tny_iterator_first (iter);
3053         while (!tny_iterator_is_done (iter)) {
3054                 TnyMimePart *part;
3055                         
3056                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
3057                 g_object_unref (part);
3058                 tny_iterator_next (iter);
3059         }
3060
3061         g_object_unref (iter);
3062         g_object_unref (parts);
3063 }
3064
3065 static void
3066 modest_ui_actions_on_main_window_remove_attachments (GtkAction *action,
3067                                                      ModestMainWindow *win)
3068 {
3069         GtkWidget *header_view;
3070         TnyList *header_list;
3071         TnyIterator *iter;
3072         TnyHeader *header;
3073         TnyHeaderFlags flags;
3074         ModestWindow *msg_view_window =  NULL;
3075         gboolean found;
3076
3077         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
3078
3079         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3080                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
3081
3082         header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
3083
3084         if (tny_list_get_length (header_list) == 1) {
3085                 iter = tny_list_create_iterator (header_list);
3086                 header = TNY_HEADER (tny_iterator_get_current (iter));
3087                 g_object_unref (iter);
3088         } else {
3089                 return;
3090         }
3091
3092         found = modest_window_mgr_find_registered_header (modest_runtime_get_window_mgr (),
3093                                                           header, &msg_view_window);
3094         flags = tny_header_get_flags (header);
3095         if (!(flags & TNY_HEADER_FLAG_CACHED))
3096                 return;
3097         if (found) {
3098                 if (msg_view_window != NULL) 
3099                         modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (msg_view_window), TRUE);
3100                 else {
3101                         /* do nothing; uid was registered before, so window is probably on it's way */
3102                         g_warning ("debug: header %p has already been registered", header);
3103                 }
3104         } else {
3105                 ModestMailOperation *mail_op = NULL;
3106                 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), header);
3107                 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
3108                                                                          G_OBJECT (win),
3109                                                                          modest_ui_actions_get_msgs_full_error_handler,
3110                                                                          NULL);
3111                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3112                 modest_mail_operation_get_msg (mail_op, header, open_msg_for_purge_cb, win);
3113                 
3114                 g_object_unref (mail_op);
3115         }
3116         if (header)
3117                 g_object_unref (header);
3118         if (header_list)
3119                 g_object_unref (header_list);
3120 }
3121
3122 /*
3123  * UI handler for the "Move to" action when invoked from the
3124  * ModestMainWindow
3125  */
3126 static void 
3127 modest_ui_actions_on_main_window_move_to (GtkAction *action, 
3128                                           ModestMainWindow *win)
3129 {
3130         GtkWidget *dialog = NULL, *folder_view = NULL, *tree_view = NULL;
3131         GtkWidget *header_view = NULL;
3132         gint result;
3133         TnyFolderStore *folder_store = NULL;
3134         ModestMailOperation *mail_op = NULL;
3135
3136         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
3137
3138         /* Get the folder view */
3139         folder_view = modest_main_window_get_child_widget (win,
3140                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
3141
3142         /* Get header view */
3143         header_view = modest_main_window_get_child_widget (win,
3144                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
3145
3146         /* Create and run the dialog */
3147         dialog = create_move_to_dialog (MODEST_WINDOW (win), folder_view, &tree_view);
3148         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (tree_view));
3149         result = gtk_dialog_run (GTK_DIALOG(dialog));
3150         g_object_ref (tree_view);
3151
3152         /* We do this to save an indentation level ;-) */
3153         if (result != GTK_RESPONSE_ACCEPT)
3154                 goto end;
3155
3156         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (tree_view));
3157
3158         if (TNY_IS_ACCOUNT (folder_store) && 
3159             !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (folder_store))
3160                 goto end;
3161
3162         /* Get folder or messages to transfer */
3163         if (gtk_widget_is_focus (folder_view)) {
3164                 TnyFolderStore *src_folder;
3165                 src_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3166
3167                 /* Clean folder on header view before moving it */
3168                 modest_header_view_clear (MODEST_HEADER_VIEW (header_view)); 
3169
3170                 if (TNY_IS_FOLDER (src_folder)) {
3171                         mail_op = 
3172                                 modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3173                                                                                G_OBJECT(win),
3174                                                                                modest_ui_actions_move_folder_error_handler,
3175                                                                                NULL);
3176                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3177
3178                         modest_mail_operation_xfer_folder (mail_op, 
3179                                                            TNY_FOLDER (src_folder),
3180                                                            folder_store,
3181                                                            TRUE);
3182                         /* Unref mail operation */
3183                         g_object_unref (G_OBJECT (mail_op));
3184                 }
3185
3186                 /* Frees */
3187                 g_object_unref (G_OBJECT (src_folder));
3188         } else {
3189                 if (gtk_widget_is_focus (header_view)) {
3190                         TnyList *headers;
3191                         gint response;
3192
3193                         headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
3194
3195                         /* Ask for user confirmation */
3196                         response = msgs_move_to_confirmation (GTK_WINDOW (win), 
3197                                                               TNY_FOLDER (folder_store), 
3198                                                               headers);
3199
3200                         /* Transfer messages */
3201                         if (response == GTK_RESPONSE_OK) {
3202                                 mail_op = 
3203                                         modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3204                                                                                        G_OBJECT(win),
3205                                                                                        modest_ui_actions_move_folder_error_handler,
3206                                                                                        NULL);
3207                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3208                                                                  mail_op);
3209
3210                                 modest_mail_operation_xfer_msgs (mail_op, 
3211                                                                  headers,
3212                                                                  TNY_FOLDER (folder_store),
3213                                                                  TRUE,
3214                                                                  NULL,
3215                                                                  NULL);
3216
3217                                 g_object_unref (G_OBJECT (mail_op));
3218                         }
3219                         g_object_unref (headers);
3220                 }
3221         }
3222  end:
3223         if (folder_store != NULL)
3224                 g_object_unref (folder_store);
3225         gtk_widget_destroy (dialog);
3226 }
3227
3228
3229 /*
3230  * UI handler for the "Move to" action when invoked from the
3231  * ModestMsgViewWindow
3232  */
3233 static void 
3234 modest_ui_actions_on_msg_view_window_move_to (GtkAction *action, 
3235                                               ModestMsgViewWindow *win)
3236 {
3237         GtkWidget *dialog, *folder_view, *tree_view = NULL;
3238         gint result;
3239         ModestMainWindow *main_window;
3240         TnyHeader *header;
3241         TnyList *headers;
3242
3243         /* Get the folder view */
3244         main_window = MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
3245         if (main_window)
3246                 folder_view = modest_main_window_get_child_widget (main_window,
3247                                                                    MODEST_WIDGET_TYPE_FOLDER_VIEW);
3248         else
3249                 folder_view = NULL;
3250
3251         /* Create and run the dialog */
3252         dialog = create_move_to_dialog (MODEST_WINDOW (win), folder_view, &tree_view);  
3253         result = gtk_dialog_run (GTK_DIALOG(dialog));
3254         g_object_ref (tree_view);
3255
3256         if (result == GTK_RESPONSE_ACCEPT) {
3257                 TnyFolderStore *folder_store;
3258                 gint response;
3259
3260                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (tree_view));
3261
3262                 /* Create header list */
3263                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));              
3264                         
3265                 headers = tny_simple_list_new ();
3266                 tny_list_prepend (headers, G_OBJECT (header));
3267                 g_object_unref (header);
3268
3269                 /* Ask user for confirmation. MSG-NOT404 */
3270                 response = msgs_move_to_confirmation (GTK_WINDOW (win), 
3271                                                       TNY_FOLDER (folder_store), 
3272                                                       headers);
3273
3274                 /* Transfer current msg */
3275                 if (response == GTK_RESPONSE_OK) {
3276                         ModestMailOperation *mail_op;
3277
3278                         /* Create mail op */
3279                         mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(win));
3280                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3281                                                          mail_op);
3282                         
3283                         /* Transfer messages */
3284                         modest_mail_operation_xfer_msgs (mail_op, 
3285                                                          headers,
3286                                                          TNY_FOLDER (folder_store),
3287                                                          TRUE,
3288                                                          transfer_msgs_from_viewer_cb,
3289                                                          NULL);
3290                         g_object_unref (G_OBJECT (mail_op));
3291                 }
3292                 g_object_unref (headers);
3293                 g_object_unref (folder_store);
3294         }
3295         gtk_widget_destroy (dialog);
3296 }
3297
3298 void 
3299 modest_ui_actions_on_move_to (GtkAction *action, 
3300                               ModestWindow *win)
3301 {
3302         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win) ||
3303                           MODEST_IS_MSG_VIEW_WINDOW (win));
3304
3305         if (MODEST_IS_MAIN_WINDOW (win)) 
3306                 modest_ui_actions_on_main_window_move_to (action, 
3307                                                           MODEST_MAIN_WINDOW (win));
3308         else
3309                 modest_ui_actions_on_msg_view_window_move_to (action, 
3310                                                               MODEST_MSG_VIEW_WINDOW (win));
3311 }
3312
3313 /*
3314  * Calls #HeadersFunc for each header already selected in the main
3315  * window or the message currently being shown in the msg view window
3316  */
3317 static void
3318 do_headers_action (ModestWindow *win, 
3319                    HeadersFunc func,
3320                    gpointer user_data)
3321 {
3322         TnyList *headers_list;
3323         TnyIterator *iter;
3324         TnyHeader *header;
3325         TnyFolder *folder;
3326
3327         /* Get headers */
3328         headers_list = get_selected_headers (win);
3329         if (!headers_list)
3330                 return;
3331
3332         /* Get the folder */
3333         iter = tny_list_create_iterator (headers_list);
3334         header = TNY_HEADER (tny_iterator_get_current (iter));
3335         folder = tny_header_get_folder (header);
3336         g_object_unref (header);
3337
3338         /* Call the function for each header */
3339         while (!tny_iterator_is_done (iter)) {
3340                 header = TNY_HEADER (tny_iterator_get_current (iter));
3341                 func (header, win, user_data);
3342                 g_object_unref (header);
3343                 tny_iterator_next (iter);
3344         }
3345
3346         /* Trick: do a poke status in order to speed up the signaling
3347            of observers */
3348         tny_folder_poke_status (folder);
3349
3350         /* Frees */
3351         g_object_unref (folder);
3352         g_object_unref (iter);
3353         g_object_unref (headers_list);
3354 }
3355
3356 void 
3357 modest_ui_actions_view_attachment (GtkAction *action,
3358                                    ModestWindow *window)
3359 {
3360         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3361                 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (window), NULL);
3362         } else {
3363                 /* not supported window for this action */
3364                 g_return_if_reached ();
3365         }
3366 }
3367
3368 void
3369 modest_ui_actions_save_attachments (GtkAction *action,
3370                                     ModestWindow *window)
3371 {
3372         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3373                 modest_msg_view_window_save_attachments (MODEST_MSG_VIEW_WINDOW (window), NULL);
3374         } else {
3375                 /* not supported window for this action */
3376                 g_return_if_reached ();
3377         }
3378 }
3379
3380 void
3381 modest_ui_actions_remove_attachments (GtkAction *action,
3382                                       ModestWindow *window)
3383 {
3384         if (MODEST_IS_MAIN_WINDOW (window)) {
3385                 modest_ui_actions_on_main_window_remove_attachments (action, MODEST_MAIN_WINDOW (window));
3386         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3387                 modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (window), FALSE);
3388         } else {
3389                 /* not supported window for this action */
3390                 g_return_if_reached ();
3391         }
3392 }
3393
3394 void 
3395 modest_ui_actions_on_settings (GtkAction *action, 
3396                                ModestWindow *win)
3397 {
3398         GtkWidget *dialog;
3399
3400         dialog = modest_platform_get_global_settings_dialog ();
3401         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (win));
3402         gtk_widget_show_all (dialog);
3403
3404         gtk_dialog_run (GTK_DIALOG (dialog));
3405
3406         gtk_widget_destroy (dialog);
3407 }
3408
3409 void 
3410 modest_ui_actions_on_help (GtkAction *action, 
3411                            ModestWindow *win)
3412 {
3413         const gchar *help_id = NULL;
3414
3415         if (MODEST_IS_MAIN_WINDOW (win)) {
3416                 const gchar *action_name;
3417                 action_name = gtk_action_get_name (action);
3418
3419                 if (!strcmp (action_name, "FolderViewCSMHelp") ||
3420                     !strcmp (action_name, "HeaderViewCSMHelp")) {
3421                         GtkWidget *folder_view;
3422                         TnyFolderStore *folder_store;
3423                         /* Get selected folder */
3424                         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
3425                                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
3426                         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3427
3428                         /* Switch help_id */
3429                         if (TNY_IS_FOLDER (folder_store)) {
3430                                 switch (tny_folder_get_folder_type (TNY_FOLDER (folder_store))) {
3431                                 case TNY_FOLDER_TYPE_NORMAL:
3432                                         help_id = "applications_email_userfolder";
3433                                         break;
3434                                 case TNY_FOLDER_TYPE_INBOX:
3435                                         help_id = "applications_email_inbox";
3436                                         break;
3437                                 case TNY_FOLDER_TYPE_OUTBOX:
3438                                         help_id = "applications_email_outbox";
3439                                         break;
3440                                 case TNY_FOLDER_TYPE_SENT:
3441                                         help_id = "applications_email_sent";
3442                                         break;
3443                                 case TNY_FOLDER_TYPE_DRAFTS:
3444                                         help_id = "applications_email_drafts";
3445                                         break;
3446                                 case TNY_FOLDER_TYPE_ARCHIVE:
3447                                         help_id = "applications_email_archive";
3448                                         break;
3449                                 default:
3450                                         help_id = NULL;
3451                                 }
3452                         }
3453                         g_object_unref (folder_store);
3454                 } else {
3455                         help_id = "applications_email_mainview";        
3456                 }
3457         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
3458                 help_id = "applications_email_viewer";
3459         } else if (MODEST_IS_MSG_EDIT_WINDOW (win))
3460                 help_id = "applications_email_editor";
3461
3462         modest_platform_show_help (GTK_WINDOW (win), help_id);
3463 }
3464
3465 void 
3466 modest_ui_actions_on_retrieve_msg_contents (GtkAction *action,
3467                                             ModestWindow *window)
3468 {
3469         ModestMailOperation *mail_op;
3470         TnyList *headers;
3471
3472         /* Get headers */
3473         headers = get_selected_headers (window);
3474         if (!headers)
3475                 return;
3476
3477         /* Create mail operation */
3478         mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE, 
3479                                                                  G_OBJECT (window),
3480                                                                  modest_ui_actions_get_msgs_full_error_handler, 
3481                                                                  NULL);
3482         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3483         modest_mail_operation_get_msgs_full (mail_op, headers, NULL, NULL, NULL);
3484
3485         /* Frees */
3486         g_object_unref (headers);
3487         g_object_unref (mail_op);
3488 }
3489
3490 void
3491 modest_ui_actions_on_email_menu_activated (GtkAction *action,
3492                                           ModestWindow *window)
3493 {
3494         g_return_if_fail (MODEST_IS_WINDOW (window));
3495
3496         /* Update dimmed */     
3497         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3498 }
3499
3500 void
3501 modest_ui_actions_on_edit_menu_activated (GtkAction *action,
3502                                           ModestWindow *window)
3503 {
3504         g_return_if_fail (MODEST_IS_WINDOW (window));
3505
3506         /* Update dimmed */     
3507         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3508 }
3509
3510 void
3511 modest_ui_actions_on_view_menu_activated (GtkAction *action,
3512                                           ModestWindow *window)
3513 {
3514         g_return_if_fail (MODEST_IS_WINDOW (window));
3515
3516         /* Update dimmed */     
3517         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3518 }
3519
3520 void
3521 modest_ui_actions_on_tools_menu_activated (GtkAction *action,
3522                                           ModestWindow *window)
3523 {
3524         g_return_if_fail (MODEST_IS_WINDOW (window));
3525
3526         /* Update dimmed */     
3527         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3528 }
3529
3530 void
3531 modest_ui_actions_on_attachment_menu_activated (GtkAction *action,
3532                                           ModestWindow *window)
3533 {
3534         g_return_if_fail (MODEST_IS_WINDOW (window));
3535
3536         /* Update dimmed */     
3537         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3538 }
3539
3540 void
3541 modest_ui_actions_on_toolbar_csm_menu_activated (GtkAction *action,
3542                                                  ModestWindow *window)
3543 {
3544         g_return_if_fail (MODEST_IS_WINDOW (window));
3545
3546         /* Update dimmed */     
3547         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3548 }
3549
3550 void
3551 modest_ui_actions_on_folder_view_csm_menu_activated (GtkAction *action,
3552                                                      ModestWindow *window)
3553 {
3554         g_return_if_fail (MODEST_IS_WINDOW (window));
3555
3556         /* Update dimmed */     
3557         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3558 }
3559
3560 void
3561 modest_ui_actions_on_header_view_csm_menu_activated (GtkAction *action,
3562                                                      ModestWindow *window)
3563 {
3564         g_return_if_fail (MODEST_IS_WINDOW (window));
3565
3566         /* Update dimmed */     
3567         modest_window_check_dimming_rules_group (window, "ModestMenuDimmingRules");     
3568 }
3569
3570 void
3571 modest_ui_actions_check_toolbar_dimming_rules (ModestWindow *window)
3572 {
3573         g_return_if_fail (MODEST_IS_WINDOW (window));
3574
3575         /* Update dimmed */     
3576         modest_window_check_dimming_rules_group (window, "ModestToolbarDimmingRules");  
3577 }
3578
3579 void
3580 modest_ui_actions_on_search_messages (GtkAction *action, ModestWindow *window)
3581 {
3582         g_return_if_fail (MODEST_IS_WINDOW (window));
3583
3584         modest_platform_show_search_messages (GTK_WINDOW (window));
3585 }
3586
3587 void     
3588 modest_ui_actions_on_open_addressbook (GtkAction *action, ModestWindow *win)
3589 {
3590         g_return_if_fail (MODEST_IS_WINDOW (win));
3591         modest_platform_show_addressbook (GTK_WINDOW (win));
3592 }
3593
3594
3595 void
3596 modest_ui_actions_on_toggle_find_in_page (GtkToggleAction *action,
3597                                           ModestWindow *window)
3598 {
3599         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3600
3601         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window), gtk_toggle_action_get_active (action));
3602 }
3603
3604 static void 
3605 _on_send_receive_progress_changed (ModestMailOperation  *mail_op, 
3606                                    ModestMailOperationState *state,
3607                                    gpointer user_data)
3608 {
3609         g_return_if_fail (MODEST_IS_MAIN_WINDOW(user_data));
3610
3611         /* Set send/receive operation finished */       
3612         if (state->status != MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3613                 modest_main_window_notify_send_receive_completed (MODEST_MAIN_WINDOW(user_data));
3614         
3615 }
3616
3617