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