* Fixes NB#85428, do not use connect_and_wait when replying to 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 #include "modest-protocol-info.h"
45 #include "modest-tny-platform-factory.h"
46 #include "modest-platform.h"
47 #include "modest-debug.h"
48 #include <tny-mime-part.h>
49 #include <tny-camel-folder.h>
50 #include <tny-camel-imap-folder.h>
51 #include <tny-camel-pop-folder.h>
52
53 #ifdef MODEST_PLATFORM_MAEMO
54 #include "maemo/modest-osso-state-saving.h"
55 #include "maemo/modest-hildon-includes.h"
56 #include "maemo/modest-connection-specific-smtp-window.h"
57 #endif /* MODEST_PLATFORM_MAEMO */
58 #include <modest-utils.h>
59
60 #include "widgets/modest-ui-constants.h"
61 #include <widgets/modest-main-window.h>
62 #include <widgets/modest-msg-view-window.h>
63 #include <widgets/modest-account-view-window.h>
64 #include <widgets/modest-details-dialog.h>
65 #include <widgets/modest-attachments-view.h>
66 #include "widgets/modest-folder-view.h"
67 #include "widgets/modest-global-settings-dialog.h"
68 #include "modest-account-mgr-helpers.h"
69 #include "modest-mail-operation.h"
70 #include "modest-text-utils.h"
71
72 #ifdef MODEST_HAVE_EASYSETUP
73 #include "easysetup/modest-easysetup-wizard-dialog.h"
74 #endif /* MODEST_HAVE_EASYSETUP */
75
76 #include <modest-widget-memory.h>
77 #include <tny-error.h>
78 #include <tny-simple-list.h>
79 #include <tny-msg-view.h>
80 #include <tny-device.h>
81 #include <tny-merge-folder.h>
82
83 #include <gtkhtml/gtkhtml.h>
84
85 typedef struct _GetMsgAsyncHelper {     
86         ModestWindow *window;
87         ModestMailOperation *mail_op;
88         TnyIterator *iter;
89         guint num_ops;
90         GFunc func;     
91         gpointer user_data;
92 } GetMsgAsyncHelper;
93
94 typedef enum _ReplyForwardAction {
95         ACTION_REPLY,
96         ACTION_REPLY_TO_ALL,
97         ACTION_FORWARD
98 } ReplyForwardAction;
99
100 typedef struct _ReplyForwardHelper {
101         guint reply_forward_type;
102         ReplyForwardAction action;
103         gchar *account_name;
104         GtkWidget *parent_window;
105         TnyHeader *header;
106 } ReplyForwardHelper;
107
108 typedef struct _MoveToHelper {
109         GtkTreeRowReference *reference;
110         GtkWidget *banner;
111 } MoveToHelper;
112
113 typedef struct _PasteAsAttachmentHelper {
114         ModestMsgEditWindow *window;
115         GtkWidget *banner;
116 } PasteAsAttachmentHelper;
117
118
119 /*
120  * The do_headers_action uses this kind of functions to perform some
121  * action to each member of a list of headers
122  */
123 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
124
125 static void     do_headers_action     (ModestWindow *win, 
126                                        HeadersFunc func,
127                                        gpointer user_data);
128
129 static void     open_msg_cb            (ModestMailOperation *mail_op, 
130                                         TnyHeader *header, 
131                                         gboolean canceled,
132                                         TnyMsg *msg,
133                                         GError *err,
134                                         gpointer user_data);
135
136 static void     reply_forward_cb       (ModestMailOperation *mail_op, 
137                                         TnyHeader *header, 
138                                         gboolean canceled,
139                                         TnyMsg *msg,
140                                         GError *err,
141                                         gpointer user_data);
142
143 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
144
145 static void     folder_refreshed_cb    (ModestMailOperation *mail_op, 
146                                         TnyFolder *folder, 
147                                         gpointer user_data);
148
149 static void     on_send_receive_finished (ModestMailOperation  *mail_op, 
150                                           gpointer user_data);
151
152 static gint header_list_count_uncached_msgs (TnyList *header_list);
153
154 static gboolean connect_to_get_msg (ModestWindow *win,
155                                     gint num_of_uncached_msgs,
156                                     TnyAccount *account);
157
158 static gboolean remote_folder_is_pop (TnyFolderStore *folder);
159
160 static void     do_create_folder (GtkWindow *window, 
161                                   TnyFolderStore *parent_folder, 
162                                   const gchar *suggested_name);
163
164 static GtkWidget* get_folder_view_from_move_to_dialog (GtkWidget *move_to_dialog);
165
166 static TnyAccount *get_account_from_folder_store (TnyFolderStore *folder_store);
167
168 /*
169  * This function checks whether a TnyFolderStore is a pop account
170  */
171 static gboolean
172 remote_folder_is_pop (TnyFolderStore *folder)
173 {
174         const gchar *proto = NULL;
175         TnyAccount *account = NULL;
176
177         g_return_val_if_fail (TNY_IS_FOLDER_STORE (folder), FALSE);
178         
179         account = get_account_from_folder_store (folder);
180         proto = tny_account_get_proto (account);
181         g_object_unref (account);
182
183         return (modest_protocol_info_get_transport_store_protocol (proto) == MODEST_PROTOCOL_STORE_POP);
184 }
185
186 /* FIXME: this should be merged with the similar code in modest-account-view-window */
187 /* Show the account creation wizard dialog.
188  * returns: TRUE if an account was created. FALSE if the user cancelled.
189  */
190 gboolean
191 modest_ui_actions_run_account_setup_wizard (ModestWindow *win)
192 {
193         gboolean result = FALSE;        
194         GtkWindow *dialog, *wizard;
195         gint dialog_response;
196
197         /* Show the easy-setup wizard: */       
198         dialog = modest_window_mgr_get_modal (modest_runtime_get_window_mgr());
199         if (dialog) {
200                 /* old wizard is active already; 
201                  */
202                 gtk_window_present (GTK_WINDOW(dialog));
203                 return FALSE;
204         }
205         
206
207         /* there is no such wizard yet */       
208         wizard = GTK_WINDOW (modest_platform_get_account_settings_wizard ());
209         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), wizard);
210
211         /* always present a main window in the background 
212          * we do it here, so we cannot end up with two wizards (as this
213          * function might be called in modest_window_mgr_get_main_window as well */
214         if (!win) 
215                 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
216                                                          TRUE);  /* create if not existent */
217         
218         /* make sure the mainwindow is visible */
219         gtk_window_set_transient_for (GTK_WINDOW (wizard), GTK_WINDOW (win));
220         gtk_widget_show_all (GTK_WIDGET(win));
221         gtk_window_present (GTK_WINDOW(win));
222         
223         dialog_response = gtk_dialog_run (GTK_DIALOG (wizard));
224         gtk_widget_destroy (GTK_WIDGET (wizard));
225         if (gtk_events_pending ())
226                 gtk_main_iteration ();
227
228         if (dialog_response == GTK_RESPONSE_CANCEL) {
229                 result = FALSE;
230         } else {
231                 /* Check whether an account was created: */
232                 result = modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
233         }
234         return result;
235 }
236
237
238 void   
239 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
240 {
241         GtkWidget *about;
242         const gchar *authors[] = {
243                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
244                 NULL
245         };
246         about = gtk_about_dialog_new ();
247         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
248         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
249         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
250                                         _("Copyright (c) 2006, Nokia Corporation\n"
251                                           "All rights reserved."));
252         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
253                                        _("a modest e-mail client\n\n"
254                                          "design and implementation: Dirk-Jan C. Binnema\n"
255                                          "contributions from the fine people at KC and Ig\n"
256                                          "uses the tinymail email framework written by Philip van Hoof"));
257         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
258         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
259         gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (win));
260         gtk_window_set_modal (GTK_WINDOW (about), TRUE);
261         
262         gtk_dialog_run (GTK_DIALOG (about));
263         gtk_widget_destroy(about);
264 }
265
266 /*
267  * Gets the list of currently selected messages. If the win is the
268  * main window, then it returns a newly allocated list of the headers
269  * selected in the header view. If win is the msg view window, then
270  * the value returned is a list with just a single header.
271  *
272  * The caller of this funcion must free the list.
273  */
274 static TnyList *
275 get_selected_headers (ModestWindow *win)
276 {
277         if (MODEST_IS_MAIN_WINDOW(win)) {
278                 GtkWidget *header_view;         
279                 
280                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
281                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
282                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
283                 
284         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
285                 /* for MsgViewWindows, we simply return a list with one element */
286                 TnyHeader *header;
287                 TnyList *list = NULL;
288                 
289                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
290                 if (header != NULL) {
291                         list = tny_simple_list_new ();
292                         tny_list_prepend (list, G_OBJECT(header));
293                         g_object_unref (G_OBJECT(header));
294                 }
295
296                 return list;
297
298         } else
299                 return NULL;
300 }
301
302 static GtkTreeRowReference *
303 get_next_after_selected_headers (ModestHeaderView *header_view)
304 {
305         GtkTreeSelection *sel;
306         GList *selected_rows, *node;
307         GtkTreePath *path;
308         GtkTreeRowReference *result;
309         GtkTreeModel *model;
310
311         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
312         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
313         selected_rows = gtk_tree_selection_get_selected_rows (sel, NULL);
314
315         if (selected_rows == NULL)
316                 return NULL;
317
318         node = g_list_last (selected_rows);
319         path = gtk_tree_path_copy ((GtkTreePath *) node->data);
320         gtk_tree_path_next (path);
321
322         result = gtk_tree_row_reference_new (model, path);
323
324         gtk_tree_path_free (path);
325         g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
326         g_list_free (selected_rows);
327
328         return result;
329 }
330
331 static void
332 headers_action_mark_as_read (TnyHeader *header,
333                              ModestWindow *win,
334                              gpointer user_data)
335 {
336         TnyHeaderFlags flags;
337
338         g_return_if_fail (TNY_IS_HEADER(header));
339
340         flags = tny_header_get_flags (header);
341         if (flags & TNY_HEADER_FLAG_SEEN) return;
342         tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
343 }
344
345 static void
346 headers_action_mark_as_unread (TnyHeader *header,
347                                ModestWindow *win,
348                                gpointer user_data)
349 {
350         TnyHeaderFlags flags;
351
352         g_return_if_fail (TNY_IS_HEADER(header));
353
354         flags = tny_header_get_flags (header);
355         if (flags & TNY_HEADER_FLAG_SEEN)  {
356                 tny_header_unset_flag (header, TNY_HEADER_FLAG_SEEN);
357         }
358 }
359
360 /** After deleing a message that is currently visible in a window, 
361  * show the next message from the list, or close the window if there are no more messages.
362  **/
363 void 
364 modest_ui_actions_refresh_message_window_after_delete (ModestMsgViewWindow* win)
365 {
366         /* Close msg view window or select next */
367         if (!modest_msg_view_window_select_next_message (win) &&
368             !modest_msg_view_window_select_previous_message (win)) {
369                 gboolean ret_value;
370                 g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);       
371         }
372 }
373
374
375 void
376 modest_ui_actions_on_delete_message (GtkAction *action, ModestWindow *win)
377 {
378         TnyList *header_list = NULL;
379         TnyIterator *iter = NULL;
380         TnyHeader *header = NULL;
381         gchar *message = NULL;
382         gchar *desc = NULL;
383         gint response;
384         ModestWindowMgr *mgr;
385         GtkWidget *header_view = NULL;
386
387         g_return_if_fail (MODEST_IS_WINDOW(win));
388         
389         /* Check first if the header view has the focus */
390         if (MODEST_IS_MAIN_WINDOW (win)) {
391                 header_view = 
392                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
393                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
394                 if (!gtk_widget_is_focus (header_view))
395                         return;
396         }
397         
398         /* Get the headers, either from the header view (if win is the main window),
399          * or from the message view window: */
400         header_list = get_selected_headers (win);
401         if (!header_list) return;
402                         
403         /* Check if any of the headers are already opened, or in the process of being opened */
404         if (MODEST_IS_MAIN_WINDOW (win)) {
405                 gint opened_headers = 0;
406
407                 iter = tny_list_create_iterator (header_list);
408                 mgr = modest_runtime_get_window_mgr ();
409                 while (!tny_iterator_is_done (iter)) {
410                         header = TNY_HEADER (tny_iterator_get_current (iter));
411                         if (header) {
412                                 if (modest_window_mgr_find_registered_header (mgr, header, NULL))
413                                         opened_headers++;
414                                 g_object_unref (header);
415                         }
416                         tny_iterator_next (iter);
417                 }
418                 g_object_unref (iter);
419
420                 if (opened_headers > 0) {
421                         gchar *msg;
422
423                         msg = g_strdup_printf (_("mcen_nc_unable_to_delete_n_messages"), 
424                                                opened_headers);
425
426                         modest_platform_run_information_dialog (GTK_WINDOW (win), (const gchar *) msg, FALSE);
427                         
428                         g_free (msg);
429                         g_object_unref (header_list);
430                         return;
431                 }
432         }
433
434         /* Select message */
435         if (tny_list_get_length(header_list) == 1) {
436                 iter = tny_list_create_iterator (header_list);
437                 header = TNY_HEADER (tny_iterator_get_current (iter));
438                 if (header) {
439                         gchar *subject;
440                         subject = tny_header_dup_subject (header);
441                         desc = g_strdup_printf ("%s", subject); 
442                         g_free (subject);
443                         g_object_unref (header);
444                 }
445
446                 g_object_unref (iter);
447         }
448         message = g_strdup_printf(ngettext("emev_nc_delete_message", "emev_nc_delete_messages", 
449                                            tny_list_get_length(header_list)), desc);
450
451         /* Confirmation dialog */
452         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
453                                                             message);
454         
455
456         if (response == GTK_RESPONSE_OK) {      
457                 ModestWindow *main_window = NULL;
458                 ModestWindowMgr *mgr = NULL;
459                 GtkTreeModel *model = NULL;
460                 GtkTreeSelection *sel = NULL;
461                 GList *sel_list = NULL, *tmp = NULL;
462                 GtkTreeRowReference *next_row_reference = NULL;
463                 GtkTreeRowReference *prev_row_reference = NULL;
464                 GtkTreePath *next_path = NULL;
465                 GtkTreePath *prev_path = NULL;
466                 ModestMailOperation *mail_op = NULL;
467
468                 /* Find last selected row */                    
469                 if (MODEST_IS_MAIN_WINDOW (win)) {
470                         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
471                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
472                         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
473                         for (tmp=sel_list; tmp; tmp=tmp->next) {
474                                 if (tmp->next == NULL) {
475                                         prev_path = gtk_tree_path_copy((GtkTreePath *) tmp->data);
476                                         next_path = gtk_tree_path_copy((GtkTreePath *) tmp->data);
477
478                                         gtk_tree_path_prev (prev_path);
479                                         gtk_tree_path_next (next_path);
480
481                                         prev_row_reference = gtk_tree_row_reference_new (model, prev_path);
482                                         next_row_reference = gtk_tree_row_reference_new (model, next_path);
483                                 }
484                         }
485                 }
486                 
487                 /* Disable window dimming management */
488                 modest_window_disable_dimming (MODEST_WINDOW(win));
489
490                 /* Remove each header. If it's a view window header_view == NULL */
491                 mail_op = modest_mail_operation_new ((GObject *) win);
492                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
493                                                  mail_op);
494                 modest_mail_operation_remove_msgs (mail_op, header_list, FALSE);
495                 g_object_unref (mail_op);
496                 
497                 /* Enable window dimming management */
498                 if (sel != NULL) {
499                         gtk_tree_selection_unselect_all (sel);
500                 }
501                 modest_window_enable_dimming (MODEST_WINDOW(win));
502                 
503                 if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
504                         modest_ui_actions_refresh_message_window_after_delete (MODEST_MSG_VIEW_WINDOW (win));
505                         
506                         /* Get main window */
507                         mgr = modest_runtime_get_window_mgr ();
508                         main_window = modest_window_mgr_get_main_window (mgr, FALSE); /* don't create */
509                 } else {                        
510                         /* Move cursor to next row */
511                         main_window = win; 
512
513                         /* Select next or previous row */
514                         if (gtk_tree_row_reference_valid (next_row_reference)) {
515 /*                              next_path = gtk_tree_row_reference_get_path (row_reference); */
516                                 gtk_tree_selection_select_path (sel, next_path);
517                         }
518                         else if (gtk_tree_row_reference_valid (prev_row_reference)) {                           
519                                 gtk_tree_selection_select_path (sel, prev_path);
520                         }
521
522                         /* Free */
523                         if (next_row_reference != NULL) 
524                                 gtk_tree_row_reference_free (next_row_reference);
525                         if (next_path != NULL) 
526                                 gtk_tree_path_free (next_path);                         
527                         if (prev_row_reference != NULL) 
528                                 gtk_tree_row_reference_free (prev_row_reference);
529                         if (prev_path != NULL) 
530                                 gtk_tree_path_free (prev_path);
531                 }
532                 
533                 /* Update toolbar dimming state */
534                 if (main_window)
535                         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
536
537                 /* Free */
538                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
539                 g_list_free (sel_list);
540         }
541
542         /* Free*/
543         g_free(message);
544         g_free(desc);
545         g_object_unref (header_list);
546 }
547
548
549
550
551 /* delete either message or folder, based on where we are */
552 void
553 modest_ui_actions_on_delete_message_or_folder (GtkAction *action, ModestWindow *win)
554 {
555         g_return_if_fail (MODEST_IS_WINDOW(win));
556         
557         /* Check first if the header view has the focus */
558         if (MODEST_IS_MAIN_WINDOW (win)) {
559                 GtkWidget *w;
560                 w = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
561                                                          MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
562                 if (gtk_widget_is_focus (w)) {
563                         modest_ui_actions_on_delete_folder (action, MODEST_MAIN_WINDOW(win));
564                         return;
565                 }
566         }
567         modest_ui_actions_on_delete_message (action, win);
568 }
569
570 void
571 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
572 {       
573         ModestWindowMgr *mgr = NULL;
574         
575 #ifdef MODEST_PLATFORM_MAEMO
576         modest_osso_save_state();
577 #endif /* MODEST_PLATFORM_MAEMO */
578
579         g_debug ("closing down, clearing %d item(s) from operation queue",
580                  modest_mail_operation_queue_num_elements
581                  (modest_runtime_get_mail_operation_queue()));
582
583         /* cancel all outstanding operations */
584         modest_mail_operation_queue_cancel_all 
585                 (modest_runtime_get_mail_operation_queue());
586         
587         g_debug ("queue has been cleared");
588
589
590         /* Check if there are opened editing windows */ 
591         mgr = modest_runtime_get_window_mgr ();
592         modest_window_mgr_close_all_windows (mgr);
593
594         /* note: when modest-tny-account-store is finalized,
595            it will automatically set all network connections
596            to offline */
597
598 /*      gtk_main_quit (); */
599 }
600
601 void
602 modest_ui_actions_on_close_window (GtkAction *action, ModestWindow *win)
603 {
604         gboolean ret_value;
605
606         g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
607
608 /*      if (MODEST_IS_MSG_VIEW_WINDOW (win)) { */
609 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
610 /*      } else if (MODEST_IS_MSG_EDIT_WINDOW (win)) { */
611 /*              gboolean ret_value; */
612 /*              g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value); */
613 /*      } else if (MODEST_IS_WINDOW (win)) { */
614 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
615 /*      } else { */
616 /*              g_return_if_reached (); */
617 /*      } */
618 }
619
620 void
621 modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
622 {
623         GtkClipboard *clipboard = NULL;
624         gchar *selection = NULL;
625
626         clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
627         selection = gtk_clipboard_wait_for_text (clipboard);
628
629         /* Question: why is the clipboard being used here? 
630          * It doesn't really make a lot of sense. */
631
632         if (selection)
633         {
634                 modest_address_book_add_address (selection);
635                 g_free (selection);
636         }
637 }
638
639 void
640 modest_ui_actions_on_accounts (GtkAction *action, 
641                                ModestWindow *win)
642 {
643         /* This is currently only implemented for Maemo */
644         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE)) {
645                 if (!modest_ui_actions_run_account_setup_wizard (win)) 
646                         g_debug ("%s: wizard was already running", __FUNCTION__);
647                 
648                 return;
649         } else {
650                 /* Show the list of accounts */
651                 GtkWindow *account_win = GTK_WINDOW (modest_account_view_window_new ());
652                 
653                 /* The accounts dialog must be modal */
654                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), account_win);
655                 modest_utils_show_dialog_and_forget (GTK_WINDOW (win), GTK_DIALOG (account_win)); 
656         }
657 }
658
659 void
660 modest_ui_actions_on_smtp_servers (GtkAction *action, ModestWindow *win)
661 {
662         /* This is currently only implemented for Maemo,
663          * because it requires an API (libconic) to detect different connection 
664          * possiblities.
665          */
666 #ifdef MODEST_PLATFORM_MAEMO /* Defined in config.h */
667         
668         /* Create the window if necessary: */
669         GtkWidget *specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
670         modest_connection_specific_smtp_window_fill_with_connections (
671                 MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window), 
672                 modest_runtime_get_account_mgr());
673
674         /* Show the window: */
675         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
676                                      GTK_WINDOW (specific_window));
677         gtk_widget_show (specific_window);
678 #endif /* MODEST_PLATFORM_MAEMO */
679 }
680
681 void
682 modest_ui_actions_compose_msg(ModestWindow *win,
683                               const gchar *to_str,
684                               const gchar *cc_str,
685                               const gchar *bcc_str,
686                               const gchar *subject_str,
687                               const gchar *body_str,
688                               GSList *attachments,
689                               gboolean set_as_modified)
690 {
691         gchar *account_name = NULL;
692         TnyMsg *msg = NULL;
693         TnyAccount *account = NULL;
694         TnyFolder *folder = NULL;
695         gchar *from_str = NULL, *signature = NULL, *body = NULL;
696         gboolean use_signature = FALSE;
697         ModestWindow *msg_win = NULL;
698         ModestAccountMgr *mgr = modest_runtime_get_account_mgr();
699         ModestTnyAccountStore *store = modest_runtime_get_account_store();
700         GnomeVFSFileSize total_size, allowed_size;
701
702         /* we check for low-mem; in that case, show a warning, and don't allow
703          * composing a message with attachments
704          */
705         if (attachments && modest_platform_check_memory_low (win))
706                 goto cleanup;
707
708         account_name = modest_account_mgr_get_default_account(mgr);
709         if (!account_name) {
710                 g_printerr ("modest: no account found\n");
711                 goto cleanup;
712         }
713         account = modest_tny_account_store_get_server_account (store, account_name, TNY_ACCOUNT_TYPE_STORE);
714         if (!account) {
715                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
716                 goto cleanup;
717         }
718         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
719         if (!folder) {
720                 g_printerr ("modest: failed to find Drafts folder\n");
721                 goto cleanup;
722         }
723         from_str = modest_account_mgr_get_from_string (mgr, account_name);
724         if (!from_str) {
725                 g_printerr ("modest: failed get from string for '%s'\n", account_name);
726                 goto cleanup;
727         }
728
729         signature = modest_account_mgr_get_signature (mgr, account_name, &use_signature);
730         if (body_str != NULL) {
731                 body = use_signature ? g_strconcat(body_str, "\n", signature, NULL) : g_strdup(body_str);
732         } else {
733                 body = use_signature ? g_strconcat("\n", signature, NULL) : g_strdup("");
734         }
735
736         msg = modest_tny_msg_new (to_str, from_str, cc_str, bcc_str, subject_str, body, NULL, NULL);
737         if (!msg) {
738                 g_printerr ("modest: failed to create new msg\n");
739                 goto cleanup;
740         }
741
742         /* Create and register edit window */
743         /* This is destroyed by TODO. */
744         total_size = 0;
745         allowed_size = MODEST_MAX_ATTACHMENT_SIZE;
746         msg_win = modest_msg_edit_window_new (msg, account_name, FALSE);
747         while (attachments) {
748                 total_size +=
749                         modest_msg_edit_window_attach_file_one(
750                                 (ModestMsgEditWindow *)msg_win,
751                                 attachments->data, allowed_size);
752
753                 if (total_size > allowed_size) {
754                         g_warning ("%s: total size: %u",
755                                    __FUNCTION__, (unsigned int)total_size);
756                         break;
757                 }
758                 allowed_size -= total_size;
759
760                 attachments = g_slist_next(attachments);
761         }
762         modest_window_mgr_register_window (modest_runtime_get_window_mgr(), msg_win);
763         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (msg_win), set_as_modified);
764
765         gtk_widget_show_all (GTK_WIDGET (msg_win));
766
767 cleanup:
768         g_free (from_str);
769         g_free (signature);
770         g_free (body);
771         g_free (account_name);
772         if (account) 
773                 g_object_unref (G_OBJECT(account));
774         if (folder)
775                 g_object_unref (G_OBJECT(folder));
776         if (msg_win)
777                 g_object_unref (G_OBJECT(msg_win));
778         if (msg)
779                 g_object_unref (G_OBJECT(msg));
780 }
781
782 void
783 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
784 {
785         /* if there are no accounts yet, just show the wizard */
786         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE))
787                 if (!modest_ui_actions_run_account_setup_wizard (win))
788                         return;
789                 
790         modest_ui_actions_compose_msg(win, NULL, NULL, NULL, NULL, NULL, NULL, FALSE);
791 }
792
793
794 gboolean 
795 modest_ui_actions_msg_retrieval_check (ModestMailOperation *mail_op,
796                                        TnyHeader *header,
797                                        TnyMsg *msg)
798 {
799         ModestMailOperationStatus status;
800
801         /* If there is no message or the operation was not successful */
802         status = modest_mail_operation_get_status (mail_op);
803         if (!msg || status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
804
805                 /* Remove the header from the preregistered uids */
806                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),  
807                                                      header);
808
809                 return FALSE;
810         }
811
812         return TRUE;
813 }
814
815 typedef struct {
816         guint idle_handler;
817         gchar *message;
818         GtkWidget *banner;
819 } OpenMsgBannerInfo;
820
821 typedef struct {
822         GtkTreeModel *model;
823         TnyList *headers;
824         OpenMsgBannerInfo *banner_info;
825         GHashTable *row_refs_per_header;
826 } OpenMsgHelper;
827
828 gboolean
829 open_msg_banner_idle (gpointer userdata)
830 {
831         OpenMsgBannerInfo *banner_info = (OpenMsgBannerInfo *) userdata;
832
833         gdk_threads_enter ();
834         banner_info->idle_handler = 0;
835         banner_info->banner = modest_platform_animation_banner (NULL, NULL, banner_info->message);
836         if (banner_info)
837                 g_object_ref (banner_info->banner);
838         
839         gdk_threads_leave ();
840
841         return FALSE;
842         
843 }
844
845 static void
846 open_msg_cb (ModestMailOperation *mail_op, 
847              TnyHeader *header,  
848              gboolean canceled,
849              TnyMsg *msg, 
850              GError *err,
851              gpointer user_data)
852 {
853         ModestWindowMgr *mgr = NULL;
854         ModestWindow *parent_win = NULL;
855         ModestWindow *win = NULL;
856         TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
857         gchar *account = NULL;
858         TnyFolder *folder;
859         gboolean open_in_editor = FALSE;
860         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
861         
862         /* Do nothing if there was any problem with the mail
863            operation. The error will be shown by the error_handler of
864            the mail operation */
865         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
866                 return;
867
868         parent_win = (ModestWindow *) modest_mail_operation_get_source (mail_op);
869         folder = tny_header_get_folder (header);
870
871         /* Mark header as read */
872         headers_action_mark_as_read (header, MODEST_WINDOW(parent_win), NULL);
873
874         /* Gets folder type (OUTBOX headers will be opened in edit window */
875         if (modest_tny_folder_is_local_folder (folder)) {
876                 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
877                 if (folder_type == TNY_FOLDER_TYPE_INVALID)
878                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
879         }
880
881                 
882         if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
883                 TnyTransportAccount *traccount = NULL;
884                 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
885                 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
886                 if (traccount) {
887                         ModestTnySendQueue *send_queue = NULL;
888                         ModestTnySendQueueStatus status;
889                         char *msg_id;
890                         account = g_strdup(modest_tny_account_get_parent_modest_account_name_for_server_account(
891                                                    TNY_ACCOUNT(traccount)));
892                         send_queue = modest_runtime_get_send_queue(traccount, TRUE);
893                         msg_id = modest_tny_send_queue_get_msg_id (header);
894                         status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
895                         /* Only open messages in outbox with the editor if they are in Failed state */
896                         if (status == MODEST_TNY_SEND_QUEUE_FAILED) {
897                                 open_in_editor = TRUE;
898                         }
899                         g_free(msg_id);
900                         g_object_unref(traccount);
901                 } else {
902                         g_warning("Cannot get transport account for message in outbox!!");
903                 }
904         } else if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
905                 open_in_editor = TRUE; /* Open in editor if the message is in the Drafts folder */
906         }
907
908         /* Get account */
909         if (!account)
910                 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_win)));
911         if (!account)
912                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
913         
914         if (open_in_editor) {
915                 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
916                 gchar *from_header = NULL;
917
918                 from_header = tny_header_dup_from (header);
919
920                 /* we cannot edit without a valid account... */
921                 if (!modest_account_mgr_has_accounts(mgr, TRUE)) {
922                         if (!modest_ui_actions_run_account_setup_wizard(parent_win)) {
923                                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), 
924                                                                      header);
925                                 g_free (from_header);
926                                 goto cleanup;
927                         }
928                 }
929                 
930                 if (from_header) {
931                         GSList *accounts = modest_account_mgr_account_names (mgr, TRUE);
932                         GSList *node = NULL;
933                         gchar *from_header_email;
934
935                         from_header_email = modest_text_utils_get_email_address ((const gchar *) from_header);
936
937                         for (node = accounts; node != NULL; node = g_slist_next (node)) {
938                                 gchar *from, *from_email;
939                                 
940                                 from = modest_account_mgr_get_from_string (mgr, node->data);
941                                 if (from) {
942                                         from_email = modest_text_utils_get_email_address ((const gchar *) from);
943                                         if (strcmp (from_header_email, from_email) == 0) {
944                                                 g_free (account);
945                                                 account = g_strdup (node->data);
946                                                 g_free (from_email);
947                                                 g_free (from);
948                                                 break;
949                                         }
950                                         g_free (from_email);
951                                         g_free (from);
952                                 }
953                         }
954                         g_free (from_header_email);
955                         g_free (from_header);
956                         g_slist_foreach (accounts, (GFunc) g_free, NULL);
957                         g_slist_free (accounts);
958                 }
959
960                 win = modest_msg_edit_window_new (msg, account, TRUE);
961
962
963
964         } else {
965                 gchar *uid = modest_tny_folder_get_header_unique_id (header);
966                 
967                 if (MODEST_IS_MAIN_WINDOW (parent_win)) {
968                         GtkTreeRowReference *row_reference;
969
970                         row_reference = (GtkTreeRowReference *) g_hash_table_lookup (helper->row_refs_per_header, header);
971                                 
972                         win = modest_msg_view_window_new_with_header_model (msg, account, (const gchar*) uid,
973                                                                             helper->model, row_reference);
974                 } else {
975                         win = modest_msg_view_window_new_for_attachment (msg, account, (const gchar*) uid);
976                 }
977                 g_free (uid);
978         }
979         
980         /* Register and show new window */
981         if (win != NULL) {
982                 mgr = modest_runtime_get_window_mgr ();
983                 modest_window_mgr_register_window (mgr, win);
984                 g_object_unref (win);
985                 gtk_widget_show_all (GTK_WIDGET(win));
986         }
987
988         /* Update toolbar dimming state */
989         if (MODEST_IS_MAIN_WINDOW (parent_win)) {
990                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_win));
991         }
992
993 cleanup:
994         /* Free */
995         g_free(account);
996         g_object_unref (parent_win);
997         g_object_unref (folder);
998 }
999
1000 static gboolean
1001 is_memory_full_error (GError *error)
1002 {
1003         if (error->code == TNY_SYSTEM_ERROR_MEMORY ||
1004             error->code == TNY_IO_ERROR_WRITE ||
1005             error->code == TNY_IO_ERROR_READ) {
1006                 return TRUE;
1007         } else {
1008                 return FALSE;
1009         }
1010 }
1011
1012 void
1013 modest_ui_actions_disk_operations_error_handler (ModestMailOperation *mail_op,
1014                                                  gpointer user_data)
1015 {
1016         const GError *error;
1017         GObject *win = NULL;
1018         ModestMailOperationStatus status;
1019
1020         win = modest_mail_operation_get_source (mail_op);
1021         error = modest_mail_operation_get_error (mail_op);
1022         status = modest_mail_operation_get_status (mail_op);
1023
1024         /* If the mail op has been cancelled then it's not an error:
1025            don't show any message */
1026         if (status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1027                 if (is_memory_full_error ((GError *) error)) {
1028                         modest_platform_information_banner ((GtkWidget *) win,
1029                                                             NULL, dgettext("ke-recv",
1030                                                                            "cerm_device_memory_full"));
1031                 } else if (error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1032                         modest_platform_information_banner ((GtkWidget *) win,
1033                                                             NULL, dgettext ("hildon-common-strings", "sfil_ni_unable_to_open_file_not_found"));
1034                 } else if (user_data) {
1035                         modest_platform_information_banner ((GtkWidget *) win, 
1036                                                             NULL, user_data);
1037                 }
1038         }
1039
1040         if (win)
1041                 g_object_unref (win);
1042 }
1043
1044 /**
1045  * Returns the account a list of headers belongs to. It returns a
1046  * *new* reference so don't forget to unref it
1047  */
1048 static TnyAccount*
1049 get_account_from_header_list (TnyList *headers)
1050 {
1051         TnyAccount *account = NULL;
1052
1053         if (tny_list_get_length (headers) > 0) {
1054                 TnyIterator *iter = tny_list_create_iterator (headers);
1055                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1056                 TnyFolder *folder = tny_header_get_folder (header);
1057                 
1058                 if (!folder) {
1059                         g_object_unref (header);
1060                         
1061                         while (!tny_iterator_is_done (iter)) {
1062                                 header = TNY_HEADER (tny_iterator_get_current (iter));
1063                                 folder = tny_header_get_folder (header);
1064                                 if (folder) 
1065                                         break;
1066                                 g_object_unref (header);
1067                                 header = NULL;
1068                                 tny_iterator_next (iter);
1069                         }
1070                 }
1071
1072                 if (folder) {
1073                         account = tny_folder_get_account (folder);
1074                         g_object_unref (folder);
1075                 }
1076                 
1077                 if (header)
1078                         g_object_unref (header);
1079                 
1080                 g_object_unref (iter);
1081         }
1082         return account;
1083 }
1084
1085 static void 
1086 foreach_unregister_headers (gpointer data,
1087                             gpointer user_data)
1088 {
1089         ModestWindowMgr *mgr = (ModestWindowMgr *) user_data;
1090         TnyHeader *header = TNY_HEADER (data);
1091
1092         modest_window_mgr_unregister_header (mgr, header);
1093 }
1094
1095 static void
1096 open_msgs_helper_destroyer (gpointer user_data)
1097 {
1098         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1099
1100         if (helper->banner_info) {
1101                 g_free (helper->banner_info->message);
1102                 if (helper->banner_info->idle_handler > 0) {
1103                         g_source_remove (helper->banner_info->idle_handler);
1104                         helper->banner_info->idle_handler = 0;
1105                 }
1106                 if (helper->banner_info->banner != NULL) {
1107                         gtk_widget_destroy (helper->banner_info->banner);
1108                         g_object_unref (helper->banner_info->banner);
1109                         helper->banner_info->banner = NULL;
1110                 }
1111                 g_slice_free (OpenMsgBannerInfo, helper->banner_info);
1112                 helper->banner_info = NULL;
1113         }
1114         g_object_unref (helper->model);
1115         g_object_unref (helper->headers);
1116         g_hash_table_destroy (helper->row_refs_per_header);
1117         g_slice_free (OpenMsgHelper, helper);
1118 }
1119
1120 static void
1121 open_msgs_performer(gboolean canceled, 
1122                     GError *err,
1123                     GtkWindow *parent_window,
1124                     TnyAccount *account,
1125                     gpointer user_data)
1126 {
1127         ModestMailOperation *mail_op = NULL;
1128         const gchar *proto_name;
1129         gchar *error_msg;
1130         ModestTransportStoreProtocol proto;
1131         TnyList *not_opened_headers;
1132         TnyConnectionStatus status;
1133         gboolean show_open_draft = FALSE;
1134         OpenMsgHelper *helper = NULL;
1135
1136         helper = (OpenMsgHelper *) user_data;
1137         not_opened_headers = helper->headers;
1138
1139         status = tny_account_get_connection_status (account);
1140         if (err || canceled) {
1141                 /* Unregister the already registered headers */
1142                 tny_list_foreach (not_opened_headers, foreach_unregister_headers, 
1143                                   modest_runtime_get_window_mgr ());
1144                 /* Free the helper */
1145                 open_msgs_helper_destroyer (helper);
1146
1147                 /* In memory full conditions we could get this error here */
1148                 if (err && is_memory_full_error (err)) {
1149                         modest_platform_information_banner ((GtkWidget *) parent_window,
1150                                                             NULL, dgettext("ke-recv",
1151                                                                            "cerm_device_memory_full"));
1152                 }
1153                 goto clean;
1154         }
1155
1156         /* Get the error message depending on the protocol */
1157         proto_name = tny_account_get_proto (account);
1158         if (proto_name != NULL) {
1159                 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1160         } else {
1161                 proto = MODEST_PROTOCOL_STORE_MAILDIR;
1162         }
1163         
1164         /* Create the error messages */
1165         if (tny_list_get_length (not_opened_headers) == 1) {
1166                 if (proto == MODEST_PROTOCOL_STORE_POP) {
1167                         error_msg = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
1168                 } else if (proto == MODEST_PROTOCOL_STORE_IMAP) {
1169                         TnyIterator *iter = tny_list_create_iterator (not_opened_headers);
1170                         TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1171                         gchar *subject = tny_header_dup_subject (header);
1172                         error_msg = g_strdup_printf (_("emev_ni_ui_imap_message_not_available_in_server"),
1173                                                      subject);
1174                         g_free (subject);
1175                         g_object_unref (header);
1176                         g_object_unref (iter);
1177                 } else {
1178                         TnyHeader *header;
1179                         TnyFolder *folder;
1180                         TnyIterator *iter;
1181                         TnyFolderType folder_type;
1182
1183                         iter = tny_list_create_iterator (not_opened_headers);
1184                         header = TNY_HEADER (tny_iterator_get_current (iter));
1185                         folder = tny_header_get_folder (header);
1186                         folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
1187                         show_open_draft = (folder_type == TNY_FOLDER_TYPE_DRAFTS);
1188                         g_object_unref (folder);
1189                         g_object_unref (header);
1190                         g_object_unref (iter);
1191                         error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1192                 }
1193         } else {
1194                 error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1195         }
1196
1197         /* Create the mail operation */
1198         mail_op = 
1199                 modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
1200                                                                modest_ui_actions_disk_operations_error_handler,
1201                                                                error_msg, g_free);
1202         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1203                                          mail_op);
1204
1205         if (show_open_draft) {
1206                 helper->banner_info = g_slice_new (OpenMsgBannerInfo);
1207                 helper->banner_info->message = g_strdup (_("mail_ib_opening_draft_message"));
1208                 helper->banner_info->banner = NULL;
1209                 helper->banner_info->idle_handler = g_timeout_add (500, open_msg_banner_idle, 
1210                                                                    helper->banner_info);
1211         }
1212
1213         modest_mail_operation_get_msgs_full (mail_op,
1214                                              not_opened_headers,
1215                                              open_msg_cb,
1216                                              helper,
1217                                              open_msgs_helper_destroyer);
1218
1219         /* Frees */
1220  clean:
1221         if (mail_op)
1222                 g_object_unref (mail_op);
1223         g_object_unref (account);
1224 }
1225
1226 /*
1227  * This function is used by both modest_ui_actions_on_open and
1228  * modest_ui_actions_on_header_activated. This way we always do the
1229  * same when trying to open messages.
1230  */
1231 static void
1232 open_msgs_from_headers (TnyList *headers, ModestWindow *win)
1233 {
1234         ModestWindowMgr *mgr = NULL;
1235         TnyIterator *iter = NULL, *iter_not_opened = NULL;
1236         TnyList *not_opened_headers = NULL;
1237         TnyHeaderFlags flags = 0;
1238         TnyAccount *account;
1239         gint uncached_msgs = 0;
1240         GtkWidget *header_view;
1241         GtkTreeModel *model;
1242         GHashTable *refs_for_headers;
1243         OpenMsgHelper *helper;
1244         GtkTreeSelection *sel;
1245         GList *sel_list = NULL, *sel_list_iter = NULL;
1246                 
1247         g_return_if_fail (headers != NULL);
1248
1249         /* Check that only one message is selected for opening */
1250         if (tny_list_get_length (headers) != 1) {
1251                 modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
1252                                                     NULL, _("mcen_ib_select_one_message"));
1253                 return;
1254         }
1255
1256         mgr = modest_runtime_get_window_mgr ();
1257         iter = tny_list_create_iterator (headers);
1258
1259         /* Get the account */
1260         account = get_account_from_header_list (headers);
1261
1262         if (!account)
1263                 return;
1264
1265         /* Get the selections, we need to get the references to the
1266            rows here because the treeview/model could dissapear (the
1267            user might want to select another folder)*/
1268         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
1269                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1270         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1271         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1272         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
1273         refs_for_headers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
1274                                                   (GDestroyNotify) gtk_tree_row_reference_free);
1275
1276         /* Look if we already have a message view for each header. If
1277            true, then remove the header from the list of headers to
1278            open */
1279         sel_list_iter = sel_list;
1280         not_opened_headers = tny_simple_list_new ();
1281         while (!tny_iterator_is_done (iter) && sel_list_iter) {
1282
1283                 ModestWindow *window = NULL;
1284                 TnyHeader *header = NULL;
1285                 gboolean found = FALSE;
1286                 
1287                 header = TNY_HEADER (tny_iterator_get_current (iter));
1288                 if (header)
1289                         flags = tny_header_get_flags (header);
1290
1291                 window = NULL;
1292                 found = modest_window_mgr_find_registered_header (mgr, header, &window);
1293                 
1294                 /* Do not open again the message and present the
1295                    window to the user */
1296                 if (found) {
1297                         if (window) {
1298                                 gtk_window_present (GTK_WINDOW (window));
1299                         } else {
1300                                 /* the header has been registered already, we don't do
1301                                  * anything but wait for the window to come up*/
1302                                 g_debug ("header %p already registered, waiting for window", header);
1303                         }
1304                 } else {
1305                         GtkTreeRowReference *row_reference;
1306
1307                         tny_list_append (not_opened_headers, G_OBJECT (header));
1308                         /* Create a new row reference and add it to the hash table */
1309                         row_reference = gtk_tree_row_reference_new (model, (GtkTreePath *) sel_list_iter->data);
1310                         g_hash_table_insert (refs_for_headers, header, row_reference);
1311                 }
1312
1313                 if (header)
1314                         g_object_unref (header);
1315
1316                 /* Go to next */
1317                 tny_iterator_next (iter);
1318                 sel_list_iter = g_list_next (sel_list_iter);
1319         }
1320         g_object_unref (iter);
1321         iter = NULL;
1322         g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
1323         g_list_free (sel_list);
1324
1325         /* Open each message */
1326         if (tny_list_get_length (not_opened_headers) == 0) {
1327                 g_hash_table_destroy (refs_for_headers);
1328                 goto cleanup;
1329         }
1330         
1331         /* If some messages would have to be downloaded, ask the user to 
1332          * make a connection. It's generally easier to do this here (in the mainloop) 
1333          * than later in a thread:
1334          */
1335         if (tny_list_get_length (not_opened_headers) > 0) {
1336                 uncached_msgs = header_list_count_uncached_msgs (not_opened_headers);
1337
1338                 if (uncached_msgs > 0) {
1339                         /* Allways download if we are online. */
1340                         if (!tny_device_is_online (modest_runtime_get_device ())) {
1341                                 gint response;
1342
1343                                 /* If ask for user permission to download the messages */
1344                                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1345                                                                                     ngettext("mcen_nc_get_msg",
1346                                                                                              "mcen_nc_get_msgs",
1347                                                                                              uncached_msgs));
1348
1349                                 /* End if the user does not want to continue */
1350                                 if (response == GTK_RESPONSE_CANCEL) {
1351                                         g_hash_table_destroy (refs_for_headers);
1352                                         goto cleanup;
1353                                 }
1354                         }
1355                 }
1356         }
1357         
1358         /* Register the headers before actually creating the windows: */
1359         iter_not_opened = tny_list_create_iterator (not_opened_headers);
1360         while (!tny_iterator_is_done (iter_not_opened)) {
1361                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter_not_opened));
1362                 if (header) {
1363                         modest_window_mgr_register_header (mgr, header, NULL);
1364                         g_object_unref (header);
1365                 }
1366                 tny_iterator_next (iter_not_opened);
1367         }
1368         g_object_unref (iter_not_opened);
1369         iter_not_opened = NULL;
1370
1371         /* Create the helper. We need to get a reference to the model
1372            here because it could change while the message is readed
1373            (the user could switch between folders) */
1374         helper = g_slice_new (OpenMsgHelper);
1375         helper->model = g_object_ref (model);
1376         helper->headers = g_object_ref (not_opened_headers);
1377         helper->row_refs_per_header = refs_for_headers;
1378         helper->banner_info = NULL;
1379
1380         /* Connect to the account and perform */
1381         if (uncached_msgs > 0) {
1382                 modest_platform_connect_and_perform ((GtkWindow *) win, TRUE, g_object_ref (account), 
1383                                                      open_msgs_performer, helper);
1384         } else {
1385                 /* Call directly the performer, do not need to connect */
1386                 open_msgs_performer (FALSE, NULL, (GtkWindow *) win, 
1387                                      g_object_ref (account), helper);
1388         }
1389 cleanup:
1390         /* Clean */
1391         if (account)
1392                 g_object_unref (account);
1393         if (not_opened_headers)
1394                 g_object_unref (not_opened_headers);
1395 }
1396
1397 void
1398 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
1399 {
1400         TnyList *headers;
1401         
1402         /* we check for low-mem; in that case, show a warning, and don't allow
1403          * opening
1404          */
1405         if (modest_platform_check_memory_low (MODEST_WINDOW(win)))
1406                 return;
1407
1408         /* Get headers */
1409         headers = get_selected_headers (win);
1410         if (!headers)
1411                 return;
1412
1413         /* Open them */
1414         open_msgs_from_headers (headers, win);
1415
1416         g_object_unref(headers);
1417 }
1418
1419 static ReplyForwardHelper*
1420 create_reply_forward_helper (ReplyForwardAction action, 
1421                              ModestWindow *win,
1422                              guint reply_forward_type,
1423                              TnyHeader *header)
1424 {
1425         ReplyForwardHelper *rf_helper = NULL;
1426         const gchar *active_acc = modest_window_get_active_account (win);
1427
1428         rf_helper = g_slice_new0 (ReplyForwardHelper);
1429         rf_helper->reply_forward_type = reply_forward_type;
1430         rf_helper->action = action;
1431         rf_helper->parent_window = (MODEST_IS_WINDOW (win)) ? GTK_WIDGET (win) : NULL;
1432         rf_helper->header = (header) ? g_object_ref (header) : NULL;
1433         rf_helper->account_name = (active_acc) ? 
1434                 g_strdup (active_acc) :
1435                 modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1436
1437         return rf_helper;
1438 }
1439
1440 static void
1441 free_reply_forward_helper (gpointer data)
1442 {
1443         ReplyForwardHelper *helper;
1444
1445         helper = (ReplyForwardHelper *) data;
1446         g_free (helper->account_name);
1447         if (helper->header)
1448                 g_object_unref (helper->header);
1449         g_slice_free (ReplyForwardHelper, helper);
1450 }
1451
1452 static void
1453 reply_forward_cb (ModestMailOperation *mail_op,  
1454                   TnyHeader *header, 
1455                   gboolean canceled,
1456                   TnyMsg *msg,
1457                   GError *err,
1458                   gpointer user_data)
1459 {
1460         TnyMsg *new_msg = NULL;
1461         ReplyForwardHelper *rf_helper;
1462         ModestWindow *msg_win = NULL;
1463         ModestEditType edit_type;
1464         gchar *from = NULL;
1465         TnyAccount *account = NULL;
1466         ModestWindowMgr *mgr = NULL;
1467         gchar *signature = NULL;
1468         gboolean use_signature;
1469
1470         /* If there was any error. The mail operation could be NULL,
1471            this means that we already have the message downloaded and
1472            that we didn't do a mail operation to retrieve it */
1473         rf_helper = (ReplyForwardHelper *) user_data;
1474         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1475                 goto cleanup;
1476
1477         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1478                                                    rf_helper->account_name);
1479         signature = modest_account_mgr_get_signature (modest_runtime_get_account_mgr(), 
1480                                                       rf_helper->account_name, 
1481                                                       &use_signature);
1482
1483         /* Create reply mail */
1484         switch (rf_helper->action) {
1485         case ACTION_REPLY:
1486                 new_msg = 
1487                         modest_tny_msg_create_reply_msg (msg, header, from, 
1488                                                          (use_signature) ? signature : NULL,
1489                                                          rf_helper->reply_forward_type,
1490                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1491                 break;
1492         case ACTION_REPLY_TO_ALL:
1493                 new_msg = 
1494                         modest_tny_msg_create_reply_msg (msg, header, from, 
1495                                                          (use_signature) ? signature : NULL, 
1496                                                          rf_helper->reply_forward_type,
1497                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1498                 edit_type = MODEST_EDIT_TYPE_REPLY;
1499                 break;
1500         case ACTION_FORWARD:
1501                 new_msg = 
1502                         modest_tny_msg_create_forward_msg (msg, from, (use_signature) ? signature : NULL, 
1503                                                            rf_helper->reply_forward_type);
1504                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1505                 break;
1506         default:
1507                 g_return_if_reached ();
1508                 return;
1509         }
1510
1511         g_free (from);
1512         g_free (signature);
1513
1514         if (!new_msg) {
1515                 g_warning ("%s: failed to create message\n", __FUNCTION__);
1516                 goto cleanup;
1517         }
1518
1519         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1520                                                                        rf_helper->account_name,
1521                                                                        TNY_ACCOUNT_TYPE_STORE);
1522         if (!account) {
1523                 g_warning ("%s: failed to get tnyaccount for '%s'\n", __FUNCTION__, rf_helper->account_name);
1524                 goto cleanup;
1525         }
1526
1527         /* Create and register the windows */
1528         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name, FALSE);
1529         mgr = modest_runtime_get_window_mgr ();
1530         modest_window_mgr_register_window (mgr, msg_win);
1531
1532         if (rf_helper->parent_window != NULL) {
1533                 gdouble parent_zoom;
1534
1535                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1536                 modest_window_set_zoom (msg_win, parent_zoom);
1537         }
1538
1539         /* Show edit window */
1540         gtk_widget_show_all (GTK_WIDGET (msg_win));
1541
1542 cleanup:
1543         if (msg_win)
1544                 g_object_unref (msg_win);
1545         if (new_msg)
1546                 g_object_unref (G_OBJECT (new_msg));
1547         if (account)
1548                 g_object_unref (G_OBJECT (account));
1549         free_reply_forward_helper (rf_helper);
1550 }
1551
1552 /* Checks a list of headers. If any of them are not currently
1553  * downloaded (CACHED) then returns TRUE else returns FALSE.
1554  */
1555 static gint
1556 header_list_count_uncached_msgs (TnyList *header_list)
1557 {
1558         TnyIterator *iter;
1559         gint uncached_messages = 0;
1560
1561         iter = tny_list_create_iterator (header_list);
1562         while (!tny_iterator_is_done (iter)) {
1563                 TnyHeader *header;
1564
1565                 header = TNY_HEADER (tny_iterator_get_current (iter));
1566                 if (header) {
1567                         if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
1568                                 uncached_messages ++;
1569                         g_object_unref (header);
1570                 }
1571
1572                 tny_iterator_next (iter);
1573         }
1574         g_object_unref (iter);
1575
1576         return uncached_messages;
1577 }
1578
1579 /* Returns FALSE if the user does not want to download the
1580  * messages. Returns TRUE if the user allowed the download.
1581  */
1582 static gboolean
1583 connect_to_get_msg (ModestWindow *win,
1584                     gint num_of_uncached_msgs,
1585                     TnyAccount *account)
1586 {
1587         GtkResponseType response;
1588
1589         /* Allways download if we are online. */
1590         if (tny_device_is_online (modest_runtime_get_device ()))
1591                 return TRUE;
1592
1593         /* If offline, then ask for user permission to download the messages */
1594         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1595                         ngettext("mcen_nc_get_msg",
1596                         "mcen_nc_get_msgs",
1597                         num_of_uncached_msgs));
1598
1599         if (response == GTK_RESPONSE_CANCEL)
1600                 return FALSE;
1601
1602         return modest_platform_connect_and_wait((GtkWindow *) win, account);
1603 }
1604
1605 static void
1606 reply_forward_performer (gboolean canceled, 
1607                          GError *err,
1608                          GtkWindow *parent_window, 
1609                          TnyAccount *account, 
1610                          gpointer user_data)
1611 {
1612         ReplyForwardHelper *rf_helper = NULL;
1613         ModestMailOperation *mail_op;
1614
1615         rf_helper = (ReplyForwardHelper *) user_data;
1616
1617         if (canceled || err) {
1618                 free_reply_forward_helper (rf_helper);
1619                 return;
1620         }
1621
1622         /* Retrieve the message */
1623         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (parent_window),
1624                                                                  modest_ui_actions_disk_operations_error_handler,
1625                                                                  NULL, NULL);
1626         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1627         modest_mail_operation_get_msg (mail_op, rf_helper->header, TRUE, reply_forward_cb, rf_helper);
1628
1629         /* Frees */
1630         g_object_unref(mail_op);
1631 }
1632
1633 /*
1634  * Common code for the reply and forward actions
1635  */
1636 static void
1637 reply_forward (ReplyForwardAction action, ModestWindow *win)
1638 {
1639         ReplyForwardHelper *rf_helper = NULL;
1640         guint reply_forward_type;
1641         
1642         g_return_if_fail (MODEST_IS_WINDOW(win));
1643                         
1644         /* we check for low-mem; in that case, show a warning, and don't allow
1645          * reply/forward (because it could potentially require a lot of memory */
1646         if (modest_platform_check_memory_low (MODEST_WINDOW(win)))
1647                 return;
1648
1649
1650         /* we need an account when editing */
1651         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
1652                 if (!modest_ui_actions_run_account_setup_wizard (win))
1653                         return;
1654         }
1655         
1656         reply_forward_type =
1657                 modest_conf_get_int (modest_runtime_get_conf (),
1658                                      (action == ACTION_FORWARD) ? 
1659                                      MODEST_CONF_FORWARD_TYPE :
1660                                      MODEST_CONF_REPLY_TYPE,
1661                                      NULL);
1662
1663         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
1664                 TnyMsg *msg = NULL;
1665                 TnyHeader *header = NULL;
1666                 /* Get header and message. Do not free them here, the
1667                    reply_forward_cb must do it */
1668                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
1669                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
1670
1671                 if (msg && header) {
1672                         /* Create helper */
1673                         rf_helper = create_reply_forward_helper (action, win, 
1674                                                                  reply_forward_type, header);
1675                         reply_forward_cb (NULL, header, FALSE, msg, NULL, rf_helper);
1676                 } else {
1677                         g_warning("%s: no message or header found in viewer\n", __FUNCTION__);
1678                 }
1679                 
1680                 if (msg)
1681                         g_object_unref (msg);
1682                 if (header)
1683                         g_object_unref (header);
1684         } else {
1685                 TnyHeader *header = NULL;
1686                 TnyIterator *iter;
1687                 gboolean do_retrieve = TRUE;
1688                 TnyList *header_list = NULL;
1689
1690                 header_list = get_selected_headers (win);
1691                 if (!header_list)
1692                         return;
1693                 if (tny_list_get_length (header_list) == 0) {
1694                         g_object_unref (header_list);
1695                         return;
1696                 }
1697
1698                 /* Only reply/forward to one message */
1699                 iter = tny_list_create_iterator (header_list);
1700                 header = TNY_HEADER (tny_iterator_get_current (iter));
1701                 g_object_unref (iter);
1702
1703                 /* Retrieve messages */
1704                 do_retrieve = (action == ACTION_FORWARD) ||
1705                         (reply_forward_type != MODEST_TNY_MSG_REPLY_TYPE_CITE);
1706
1707                 if (do_retrieve) {
1708                         TnyAccount *account = NULL;
1709                         TnyFolder *folder = NULL;
1710                         gdouble download = TRUE;
1711                         guint uncached_msgs = 0;
1712
1713                         folder = tny_header_get_folder (header);
1714                         if (!folder)
1715                                 goto do_retrieve_frees;
1716                         account = tny_folder_get_account (folder);
1717                         if (!account)
1718                                 goto do_retrieve_frees;
1719
1720                         uncached_msgs = header_list_count_uncached_msgs (header_list);
1721
1722                         if (uncached_msgs > 0) {
1723                                 /* Allways download if we are online. */
1724                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1725                                         gint response;
1726                                         
1727                                         /* If ask for user permission to download the messages */
1728                                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1729                                                                                             ngettext("mcen_nc_get_msg",
1730                                                                                                      "mcen_nc_get_msgs",
1731                                                                                                      uncached_msgs));
1732                                         
1733                                         /* End if the user does not want to continue */
1734                                         if (response == GTK_RESPONSE_CANCEL)
1735                                                 download = FALSE;
1736                                 }
1737                         }
1738                         
1739                         if (download) {
1740                                 /* Create helper */
1741                                 rf_helper = create_reply_forward_helper (action, win, 
1742                                                                          reply_forward_type, header);
1743                                 if (uncached_msgs > 0) {
1744                                         modest_platform_connect_and_perform (GTK_WINDOW (win), 
1745                                                                              TRUE, account, 
1746                                                                              reply_forward_performer, 
1747                                                                              rf_helper);
1748                                 } else {
1749                                         reply_forward_performer (FALSE, NULL, GTK_WINDOW (win), 
1750                                                                  account, rf_helper);
1751                                 }
1752                         }
1753                 do_retrieve_frees:
1754                         if (account)
1755                                 g_object_unref (account);
1756                         if (folder)
1757                                 g_object_unref (folder);
1758                 } else {
1759                         reply_forward_cb (NULL, header, FALSE, NULL, NULL, rf_helper);
1760                 }
1761                 /* Frees */
1762                 g_object_unref (header_list);
1763                 g_object_unref (header);
1764         }
1765 }
1766
1767 void
1768 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
1769 {
1770         g_return_if_fail (MODEST_IS_WINDOW(win));
1771
1772         reply_forward (ACTION_REPLY, win);
1773 }
1774
1775 void
1776 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
1777 {
1778         g_return_if_fail (MODEST_IS_WINDOW(win));
1779
1780         reply_forward (ACTION_FORWARD, win);
1781 }
1782
1783 void
1784 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
1785 {
1786         g_return_if_fail (MODEST_IS_WINDOW(win));
1787
1788         reply_forward (ACTION_REPLY_TO_ALL, win);
1789 }
1790
1791 void 
1792 modest_ui_actions_on_next (GtkAction *action, 
1793                            ModestWindow *window)
1794 {
1795         if (MODEST_IS_MAIN_WINDOW (window)) {
1796                 GtkWidget *header_view;
1797
1798                 header_view = modest_main_window_get_child_widget (
1799                                 MODEST_MAIN_WINDOW(window),
1800                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1801                 if (!header_view)
1802                         return;
1803         
1804                 modest_header_view_select_next (
1805                                 MODEST_HEADER_VIEW(header_view)); 
1806         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1807                 modest_msg_view_window_select_next_message (
1808                                 MODEST_MSG_VIEW_WINDOW (window));
1809         } else {
1810                 g_return_if_reached ();
1811         }
1812 }
1813
1814 void 
1815 modest_ui_actions_on_prev (GtkAction *action, 
1816                            ModestWindow *window)
1817 {
1818         g_return_if_fail (MODEST_IS_WINDOW(window));
1819
1820         if (MODEST_IS_MAIN_WINDOW (window)) {
1821                 GtkWidget *header_view;
1822                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1823                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1824                 if (!header_view)
1825                         return;
1826                 
1827                 modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
1828         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
1829                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
1830         } else {
1831                 g_return_if_reached ();
1832         }
1833 }
1834
1835 void 
1836 modest_ui_actions_on_sort (GtkAction *action, 
1837                            ModestWindow *window)
1838 {
1839         g_return_if_fail (MODEST_IS_WINDOW(window));
1840
1841         if (MODEST_IS_MAIN_WINDOW (window)) {
1842                 GtkWidget *header_view;
1843                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
1844                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1845                 if (!header_view) {
1846                         modest_platform_information_banner (NULL, NULL, _CS("ckdg_ib_nothing_to_sort"));
1847
1848                         return;
1849                 }
1850
1851                 /* Show sorting dialog */
1852                 modest_platform_run_sort_dialog (GTK_WINDOW (window), MODEST_SORT_HEADERS);     
1853         }
1854 }
1855
1856 static void
1857 new_messages_arrived (ModestMailOperation *self, 
1858                       TnyList *new_headers,
1859                       gpointer user_data)
1860 {
1861         GObject *source;
1862         gboolean show_visual_notifications;
1863
1864         source = modest_mail_operation_get_source (self);
1865         show_visual_notifications = (source) ? FALSE : TRUE;
1866         if (source)
1867                 g_object_unref (source);
1868
1869         /* Notify new messages have been downloaded. If the
1870            send&receive was invoked by the user then do not show any
1871            visual notification, only play a sound and activate the LED
1872            (for the Maemo version) */
1873         if (TNY_IS_LIST(new_headers) && (tny_list_get_length (new_headers)) > 0)
1874                 modest_platform_on_new_headers_received (new_headers, 
1875                                                          show_visual_notifications);
1876
1877 }
1878
1879 gboolean
1880 retrieve_all_messages_cb (GObject *source,
1881                           guint num_msgs,
1882                           guint retrieve_limit)
1883 {
1884         GtkWindow *window;
1885         gchar *msg;
1886         gint response;
1887
1888         window = GTK_WINDOW (source);
1889         msg = g_strdup_printf (_("mail_nc_msg_count_limit_exceeded"), 
1890                                num_msgs, retrieve_limit);
1891
1892         /* Ask the user if they want to retrieve all the messages */
1893         response = 
1894                 modest_platform_run_confirmation_dialog_with_buttons (window, msg,
1895                                                                       _("mcen_bd_get_all"),
1896                                                                       _("mcen_bd_newest_only"));
1897         /* Free and return */
1898         g_free (msg);
1899         return (response == GTK_RESPONSE_ACCEPT) ? TRUE : FALSE;
1900 }
1901
1902 typedef struct {
1903         TnyAccount *account;
1904         ModestWindow *win;
1905         gchar *account_name;
1906         gboolean poke_status;
1907         gboolean interactive;
1908         ModestMailOperation *mail_op;
1909 } SendReceiveInfo;
1910
1911 static void
1912 do_send_receive_performer (gboolean canceled, 
1913                            GError *err,
1914                            GtkWindow *parent_window, 
1915                            TnyAccount *account, 
1916                            gpointer user_data)
1917 {
1918         SendReceiveInfo *info;
1919
1920         info = (SendReceiveInfo *) user_data;
1921
1922         if (err || canceled) {
1923                 /* In memory full conditions we could get this error here */
1924                 if (err && is_memory_full_error (err)) {
1925                         modest_platform_information_banner ((GtkWidget *) parent_window,
1926                                                             NULL, dgettext("ke-recv",
1927                                                                            "cerm_device_memory_full"));
1928                 }
1929                 if (info->mail_op) {
1930                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
1931                                                             info->mail_op);
1932                 }
1933                 goto clean;
1934         }
1935
1936         /* Set send/receive operation in progress */    
1937         if (info->win && MODEST_IS_MAIN_WINDOW (info->win)) {
1938                 modest_main_window_notify_send_receive_initied (MODEST_MAIN_WINDOW (info->win));
1939         }
1940
1941         if (info->win && MODEST_IS_MAIN_WINDOW (info->win))
1942                 g_signal_connect (G_OBJECT (info->mail_op), "operation-finished", 
1943                                   G_CALLBACK (on_send_receive_finished), 
1944                                   info->win);
1945
1946         /* Send & receive. */
1947         modest_mail_operation_update_account (info->mail_op, info->account_name, info->poke_status, info->interactive,
1948                                               (info->win) ? retrieve_all_messages_cb : NULL, 
1949                                               new_messages_arrived, info->win);
1950         
1951  clean:
1952         /* Frees */
1953         if (info->mail_op)
1954                 g_object_unref (G_OBJECT (info->mail_op));
1955         if (info->account_name)
1956                 g_free (info->account_name);
1957         if (info->win)
1958                 g_object_unref (info->win);
1959         if (info->account)
1960                 g_object_unref (info->account);
1961         g_slice_free (SendReceiveInfo, info);
1962 }
1963
1964 /*
1965  * This function performs the send & receive required actions. The
1966  * window is used to create the mail operation. Typically it should
1967  * always be the main window, but we pass it as argument in order to
1968  * be more flexible.
1969  */
1970 void
1971 modest_ui_actions_do_send_receive (const gchar *account_name, 
1972                                    gboolean force_connection,
1973                                    gboolean poke_status,
1974                                    gboolean interactive,
1975                                    ModestWindow *win)
1976 {
1977         gchar *acc_name = NULL;
1978         SendReceiveInfo *info;
1979         ModestTnyAccountStore *acc_store;
1980
1981         /* If no account name was provided then get the current account, and if
1982            there is no current account then pick the default one: */
1983         if (!account_name) {
1984                 if (win)
1985                         acc_name = g_strdup (modest_window_get_active_account (win));
1986                 if (!acc_name)
1987                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1988                 if (!acc_name) {
1989                         g_printerr ("modest: cannot get default account\n");
1990                         return;
1991                 }
1992         } else {
1993                 acc_name = g_strdup (account_name);
1994         }
1995
1996         acc_store = modest_runtime_get_account_store ();
1997
1998         /* Create the info for the connect and perform */
1999         info = g_slice_new (SendReceiveInfo);
2000         info->account_name = acc_name;
2001         info->win = (win) ? g_object_ref (win) : NULL;
2002         info->poke_status = poke_status;
2003         info->interactive = interactive;
2004         info->account = modest_tny_account_store_get_server_account (acc_store, acc_name,
2005                                                                      TNY_ACCOUNT_TYPE_STORE);
2006         /* We need to create the operation here, because otherwise it
2007            could happen that the queue emits the queue-empty signal
2008            while we're trying to connect the account */
2009         info->mail_op = modest_mail_operation_new_with_error_handling ((info->win) ? G_OBJECT (info->win) : NULL,
2010                                                                        modest_ui_actions_disk_operations_error_handler,
2011                                                                        NULL, NULL);
2012         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), info->mail_op);
2013
2014         /* Invoke the connect and perform */
2015         modest_platform_connect_and_perform ((win) ? GTK_WINDOW (win) : NULL, 
2016                                              force_connection, info->account, 
2017                                              do_send_receive_performer, info);
2018 }
2019
2020
2021 static void
2022 modest_ui_actions_do_cancel_send (const gchar *account_name,  
2023                                   ModestWindow *win)
2024 {
2025         TnyTransportAccount *transport_account;
2026         TnySendQueue *send_queue = NULL;
2027         GError *error = NULL;
2028
2029         /* Get transport account */
2030         transport_account =
2031                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2032                                       (modest_runtime_get_account_store(),
2033                                        account_name,
2034                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2035         if (!transport_account) {
2036                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2037                 goto frees;
2038         }
2039
2040         /* Get send queue*/
2041         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
2042         if (!TNY_IS_SEND_QUEUE(send_queue)) {
2043                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
2044                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2045                              "modest: could not find send queue for account\n");
2046         } else {
2047                 /* Cancel the current send */
2048                 tny_account_cancel (TNY_ACCOUNT (transport_account));
2049
2050                 /* Suspend all pending messages */
2051                 tny_send_queue_cancel (send_queue, TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, &error);
2052         }
2053
2054  frees:
2055         if (transport_account != NULL) 
2056                 g_object_unref (G_OBJECT (transport_account));
2057 }
2058
2059 static void
2060 modest_ui_actions_cancel_send_all (ModestWindow *win) 
2061 {
2062         GSList *account_names, *iter;
2063
2064         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
2065                                                           TRUE);
2066
2067         iter = account_names;
2068         while (iter) {                  
2069                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
2070                 iter = g_slist_next (iter);
2071         }
2072
2073         modest_account_mgr_free_account_names (account_names);
2074         account_names = NULL;
2075 }
2076
2077 void
2078 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
2079
2080 {
2081         /* Check if accounts exist */
2082         gboolean accounts_exist = 
2083                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2084         
2085         /* If not, allow the user to create an account before trying to send/receive. */
2086         if (!accounts_exist)
2087                 modest_ui_actions_on_accounts (NULL, win);
2088         
2089         /* Cancel all sending operaitons */     
2090         modest_ui_actions_cancel_send_all (win);
2091 }
2092
2093 /*
2094  * Refreshes all accounts. This function will be used by automatic
2095  * updates
2096  */
2097 void
2098 modest_ui_actions_do_send_receive_all (ModestWindow *win, 
2099                                        gboolean force_connection,
2100                                        gboolean poke_status,
2101                                        gboolean interactive)
2102 {
2103         GSList *account_names, *iter;
2104
2105         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), 
2106                                                           TRUE);
2107
2108         iter = account_names;
2109         while (iter) {                  
2110                 modest_ui_actions_do_send_receive ((const char*) iter->data, 
2111                                                    force_connection, 
2112                                                    poke_status, interactive, win);
2113                 iter = g_slist_next (iter);
2114         }
2115
2116         modest_account_mgr_free_account_names (account_names);
2117         account_names = NULL;
2118 }
2119
2120 /*
2121  * Handler of the click on Send&Receive button in the main toolbar
2122  */
2123 void
2124 modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win)
2125 {
2126         /* Check if accounts exist */
2127         gboolean accounts_exist;
2128
2129         accounts_exist =
2130                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2131         
2132         /* If not, allow the user to create an account before trying to send/receive. */
2133         if (!accounts_exist)
2134                 modest_ui_actions_on_accounts (NULL, win);
2135         
2136         /* Refresh the current folder. The if is always TRUE it's just an extra check */
2137         if (MODEST_IS_MAIN_WINDOW (win)) {
2138                 GtkWidget *folder_view;
2139                 TnyFolderStore *folder_store;
2140
2141                 folder_view = 
2142                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win), 
2143                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2144                 if (!folder_view)
2145                         return;
2146                 
2147                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2148         
2149                 if (folder_store)
2150                         g_object_unref (folder_store);
2151         }       
2152         
2153         /* Refresh the active account. Force the connection if needed
2154            and poke the status of all folders */
2155         modest_ui_actions_do_send_receive (NULL, TRUE, TRUE, TRUE, win);
2156 }
2157
2158
2159 void
2160 modest_ui_actions_toggle_header_list_view (GtkAction *action, ModestMainWindow *main_window)
2161 {
2162         ModestConf *conf;
2163         GtkWidget *header_view;
2164         
2165         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2166
2167         header_view = modest_main_window_get_child_widget (main_window,
2168                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2169         if (!header_view)
2170                 return;
2171
2172         conf = modest_runtime_get_conf ();
2173         
2174         /* what is saved/restored is depending on the style; thus; we save with
2175          * old style, then update the style, and restore for this new style
2176          */
2177         modest_widget_memory_save (conf, G_OBJECT(header_view), MODEST_CONF_HEADER_VIEW_KEY);
2178         
2179         if (modest_header_view_get_style
2180             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
2181                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2182                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
2183         else
2184                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2185                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
2186
2187         modest_widget_memory_restore (conf, G_OBJECT(header_view),
2188                                       MODEST_CONF_HEADER_VIEW_KEY);
2189 }
2190
2191
2192 void 
2193 modest_ui_actions_on_header_selected (ModestHeaderView *header_view, 
2194                                       TnyHeader *header,
2195                                       ModestMainWindow *main_window)
2196 {
2197         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2198         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2199         
2200         /* in the case the folder is empty, show the empty folder message and focus
2201          * folder view */
2202         if (!header && gtk_widget_is_focus (GTK_WIDGET (header_view))) {
2203                 if (modest_header_view_is_empty (header_view)) {
2204                         TnyFolder *folder = modest_header_view_get_folder (header_view);
2205                         GtkWidget *folder_view = 
2206                                 modest_main_window_get_child_widget (main_window,
2207                                                                      MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2208                         if (folder != NULL) 
2209                                 modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), folder, FALSE);
2210                         gtk_widget_grab_focus (GTK_WIDGET (folder_view));
2211                         return;
2212                 }
2213         }
2214         /* If no header has been selected then exit */
2215         if (!header)
2216                 return;
2217
2218         /* Update focus */
2219         if (!gtk_widget_is_focus (GTK_WIDGET(header_view)))
2220             gtk_widget_grab_focus (GTK_WIDGET(header_view));
2221
2222         /* Update toolbar dimming state */
2223         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2224         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2225 }
2226
2227 void
2228 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
2229                                        TnyHeader *header,
2230                                        ModestMainWindow *main_window)
2231 {
2232         TnyList *headers;
2233         GtkWidget *open_widget;
2234
2235         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2236
2237         if (!header)
2238                 return;
2239
2240         if (modest_header_view_count_selected_headers (header_view) > 1) {
2241                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
2242                 return;
2243         }
2244
2245         /* we check for low-mem; in that case, show a warning, and don't allow
2246          * activating headers
2247          */
2248         if (modest_platform_check_memory_low (MODEST_WINDOW(main_window)))
2249                 return;
2250
2251         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2252         open_widget = modest_window_get_action_widget (MODEST_WINDOW (main_window), "/MenuBar/EmailMenu/EmailOpenMenu");
2253         if (!GTK_WIDGET_IS_SENSITIVE (open_widget))
2254                 return;
2255
2256 /*      headers = tny_simple_list_new (); */
2257 /*      tny_list_prepend (headers, G_OBJECT (header)); */
2258         headers = modest_header_view_get_selected_headers (header_view);
2259
2260         open_msgs_from_headers (headers, MODEST_WINDOW (main_window));
2261
2262         g_object_unref (headers);
2263 }
2264
2265 static void
2266 set_active_account_from_tny_account (TnyAccount *account,
2267                                      ModestWindow *window)
2268 {
2269         const gchar *server_acc_name = tny_account_get_id (account);
2270         
2271         /* We need the TnyAccount provided by the
2272            account store because that is the one that
2273            knows the name of the Modest account */
2274         TnyAccount *modest_server_account = modest_server_account = 
2275                 modest_tny_account_store_get_tny_account_by (modest_runtime_get_account_store (),
2276                                                              MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
2277                                                              server_acc_name);
2278         if (!modest_server_account) {
2279                 g_warning ("%s: could not get tny account\n", __FUNCTION__);
2280                 return;
2281         }
2282
2283         /* Update active account, but only if it's not a pseudo-account */
2284         if ((!modest_tny_account_is_virtual_local_folders(modest_server_account)) &&
2285             (!modest_tny_account_is_memory_card_account(modest_server_account))) {
2286                 const gchar *modest_acc_name = 
2287                         modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
2288                 if (modest_acc_name)
2289                         modest_window_set_active_account (window, modest_acc_name);
2290         }
2291         
2292         g_object_unref (modest_server_account);
2293 }
2294
2295
2296 static void
2297 folder_refreshed_cb (ModestMailOperation *mail_op, 
2298                      TnyFolder *folder, 
2299                      gpointer user_data)
2300 {
2301         ModestMainWindow *win = NULL;
2302         GtkWidget *header_view;
2303
2304         g_return_if_fail (TNY_IS_FOLDER (folder));
2305
2306         win = MODEST_MAIN_WINDOW (user_data);
2307         header_view = 
2308                 modest_main_window_get_child_widget(win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2309
2310         if (header_view) {
2311                 TnyFolder *current_folder;
2312
2313                 current_folder = modest_header_view_get_folder (MODEST_HEADER_VIEW (header_view));
2314                 if (current_folder != NULL && folder != current_folder) {
2315                         g_object_unref (current_folder);
2316                         return;
2317                 } else if (current_folder)
2318                         g_object_unref (current_folder);
2319         }
2320
2321         /* Check if folder is empty and set headers view contents style */
2322         if (tny_folder_get_all_count (folder) == 0)
2323                 modest_main_window_set_contents_style (win,
2324                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2325
2326 }
2327
2328 void 
2329 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
2330                                                TnyFolderStore *folder_store, 
2331                                                gboolean selected,
2332                                                ModestMainWindow *main_window)
2333 {
2334         ModestConf *conf;
2335         GtkWidget *header_view;
2336
2337         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2338
2339         header_view = modest_main_window_get_child_widget(main_window,
2340                                                           MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2341         if (!header_view)
2342                 return;
2343         
2344         conf = modest_runtime_get_conf ();
2345
2346         if (TNY_IS_ACCOUNT (folder_store)) {
2347                 if (selected) {
2348                         set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
2349                         
2350                         /* Show account details */
2351                         modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
2352                 }
2353         } else {
2354                 if (TNY_IS_FOLDER (folder_store) && selected) {
2355                         
2356                         /* Update the active account */
2357                         TnyAccount *account = modest_tny_folder_get_account (TNY_FOLDER (folder_store));
2358                         if (account) {
2359                                 set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
2360                                 g_object_unref (account);
2361                                 account = NULL;
2362                         }
2363
2364                         /* Set the header style by default, it could
2365                            be changed later by the refresh callback to
2366                            empty */
2367                         modest_main_window_set_contents_style (main_window, 
2368                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2369
2370                         /* Set folder on header view. This function
2371                            will call tny_folder_refresh_async so we
2372                            pass a callback that will be called when
2373                            finished. We use that callback to set the
2374                            empty view if there are no messages */
2375                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
2376                                                        TNY_FOLDER (folder_store),
2377                                                        folder_refreshed_cb,
2378                                                        main_window);
2379                         
2380                         /* Restore configuration. We need to do this
2381                            *after* the set_folder because the widget
2382                            memory asks the header view about its
2383                            folder  */
2384                         modest_widget_memory_restore (modest_runtime_get_conf (), 
2385                                                       G_OBJECT(header_view),
2386                                                       MODEST_CONF_HEADER_VIEW_KEY);
2387                 } else {
2388                         /* No need to save the header view
2389                            configuration for Maemo because it only
2390                            saves the sorting stuff and that it's
2391                            already being done by the sort
2392                            dialog. Remove it when the GNOME version
2393                            has the same behaviour */
2394 #ifdef MODEST_PLATFORM_GNOME
2395                         if (modest_main_window_get_contents_style (main_window) ==
2396                             MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
2397                                 modest_widget_memory_save (conf, G_OBJECT (header_view), 
2398                                                            MODEST_CONF_HEADER_VIEW_KEY);
2399 #endif
2400                         modest_header_view_clear (MODEST_HEADER_VIEW(header_view));
2401                 }
2402         }
2403
2404         /* Update dimming state */
2405         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2406         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2407 }
2408
2409 void 
2410 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
2411                                      ModestWindow *win)
2412 {
2413         GtkWidget *dialog;
2414         gchar *txt, *item;
2415         gboolean online;
2416
2417         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
2418         
2419         online = tny_device_is_online (modest_runtime_get_device());
2420
2421         if (online) {
2422                 /* already online -- the item is simply not there... */
2423                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
2424                                                  GTK_DIALOG_MODAL,
2425                                                  GTK_MESSAGE_WARNING,
2426                                                  GTK_BUTTONS_NONE,
2427                                                  _("The %s you selected cannot be found"),
2428                                                  item);
2429                 gtk_dialog_add_button (GTK_DIALOG (dialog),_("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
2430                 gtk_dialog_run (GTK_DIALOG(dialog));
2431         } else {
2432                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
2433                                                       GTK_WINDOW (win),
2434                                                       GTK_DIALOG_MODAL,
2435                                                       _("mcen_bd_dialog_cancel"),
2436                                                       GTK_RESPONSE_REJECT,
2437                                                       _("mcen_bd_dialog_ok"),
2438                                                       GTK_RESPONSE_ACCEPT,
2439                                                       NULL);
2440                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
2441                                          "Do you want to get online?"), item);
2442                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
2443                                     gtk_label_new (txt), FALSE, FALSE, 0);
2444                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2445                 g_free (txt);
2446
2447                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
2448                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2449                         /* TODO: Comment about why is this commented out: */
2450                         /* modest_platform_connect_and_wait (); */
2451                 }
2452         }
2453         gtk_widget_destroy (dialog);
2454 }
2455
2456 void
2457 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
2458                                      ModestWindow *win)
2459 {
2460         /* g_message ("%s %s", __FUNCTION__, link); */
2461 }       
2462
2463
2464 void
2465 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
2466                                         ModestWindow *win)
2467 {
2468         modest_platform_activate_uri (link);
2469 }
2470
2471 void
2472 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
2473                                           ModestWindow *win)
2474 {
2475         modest_platform_show_uri_popup (link);
2476 }
2477
2478 void
2479 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
2480                                              ModestWindow *win)
2481 {               
2482         /* we check for low-mem; in that case, show a warning, and don't allow
2483          * viewing attachments
2484          */
2485         if (modest_platform_check_memory_low (MODEST_WINDOW(win)))
2486                 return;
2487
2488         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
2489 }
2490
2491 void
2492 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
2493                                           const gchar *address,
2494                                           ModestWindow *win)
2495 {
2496         /* g_message ("%s %s", __FUNCTION__, address); */
2497 }
2498
2499 static void
2500 on_save_to_drafts_cb (ModestMailOperation *mail_op, 
2501                       TnyMsg *saved_draft,
2502                       gpointer user_data)
2503 {
2504         ModestMsgEditWindow *edit_window;
2505         ModestMainWindow *win;
2506
2507         /* FIXME. Make the header view sensitive again. This is a
2508          * temporary hack. See modest_ui_actions_on_save_to_drafts()
2509          * for details */
2510         win = MODEST_MAIN_WINDOW(modest_window_mgr_get_main_window(
2511                                          modest_runtime_get_window_mgr(), FALSE));
2512         if (win != NULL) {
2513                 GtkWidget *hdrview = modest_main_window_get_child_widget(
2514                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2515                 if (hdrview) gtk_widget_set_sensitive(hdrview, TRUE);
2516         }
2517
2518         edit_window = MODEST_MSG_EDIT_WINDOW (user_data);
2519
2520         /* Set draft is there was no error */
2521         if (!modest_mail_operation_get_error (mail_op))
2522                 modest_msg_edit_window_set_draft (edit_window, saved_draft);
2523
2524         g_object_unref(edit_window);
2525 }
2526
2527 gboolean
2528 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2529 {
2530         TnyTransportAccount *transport_account;
2531         ModestMailOperation *mail_operation;
2532         MsgData *data;
2533         gchar *account_name, *from;
2534         ModestAccountMgr *account_mgr;
2535 /*      char *info_text; */
2536         gboolean had_error = FALSE;
2537         guint64 available_disk, expected_size;
2538         gint parts_count;
2539         guint64 parts_size;
2540         ModestMainWindow *win;
2541
2542         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), FALSE);
2543         
2544         data = modest_msg_edit_window_get_msg_data (edit_window);
2545
2546         /* Check size */
2547         available_disk = modest_folder_available_space (NULL);
2548         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
2549         expected_size = modest_tny_msg_estimate_size (data->plain_body,
2550                                                  data->html_body,
2551                                                  parts_count,
2552                                                  parts_size);
2553
2554         if ((available_disk != -1) && expected_size > available_disk) {
2555                 modest_msg_edit_window_free_msg_data (edit_window, data);
2556
2557                 modest_platform_information_banner (NULL, NULL, dgettext("ke-recv", "cerm_device_memory_full"));
2558                 return FALSE;
2559         }
2560
2561         /*
2562          * djcb: if we're in low-memory state, we only allow for
2563          * saving messages smaller than
2564          * MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h) this
2565          * should still allow for sending anything critical...
2566          */
2567         if (expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) {
2568
2569                 if (modest_platform_check_memory_low (MODEST_WINDOW(edit_window))) {
2570                         modest_msg_edit_window_free_msg_data (edit_window, data);
2571                         return FALSE;
2572                 }
2573         }
2574
2575         /*
2576          * djcb: we also make sure that the attachments are smaller than the max size
2577          * this is for the case where we'd try to forward a message with attachments 
2578          * bigger than our max allowed size, or sending an message from drafts which
2579          * somehow got past our checks when attaching.
2580          */
2581         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
2582                 modest_platform_run_information_dialog (
2583                         GTK_WINDOW(edit_window),
2584                         dgettext("ke-recv","memr_ib_operation_disabled"),
2585                         TRUE);
2586                 modest_msg_edit_window_free_msg_data (edit_window, data);
2587                 return FALSE;
2588         }
2589
2590         account_name = g_strdup (data->account_name);
2591         account_mgr = modest_runtime_get_account_mgr();
2592         if (!account_name)
2593                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2594         if (!account_name) 
2595                 account_name = modest_account_mgr_get_default_account (account_mgr);
2596         if (!account_name) {
2597                 g_printerr ("modest: no account found\n");
2598                 modest_msg_edit_window_free_msg_data (edit_window, data);
2599                 return FALSE;
2600         }
2601
2602         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
2603                 account_name = g_strdup (data->account_name);
2604         }
2605
2606         transport_account =
2607                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2608                                       (modest_runtime_get_account_store(),
2609                                        account_name,
2610                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2611         if (!transport_account) {
2612                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2613                 g_free (account_name);
2614                 modest_msg_edit_window_free_msg_data (edit_window, data);
2615                 return FALSE;
2616         }
2617         from = modest_account_mgr_get_from_string (account_mgr, account_name);
2618
2619         /* Create the mail operation */         
2620         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler,
2621                                                                         NULL, NULL);
2622         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2623
2624         modest_mail_operation_save_to_drafts (mail_operation,
2625                                               transport_account,
2626                                               data->draft_msg,
2627                                               from,
2628                                               data->to, 
2629                                               data->cc, 
2630                                               data->bcc,
2631                                               data->subject, 
2632                                               data->plain_body, 
2633                                               data->html_body,
2634                                               data->attachments,
2635                                               data->images,
2636                                               data->priority_flags,
2637                                               on_save_to_drafts_cb,
2638                                               g_object_ref(edit_window));
2639
2640         /* Use the main window as the parent of the banner, if the
2641            main window does not exist it won't be shown, if the parent
2642            window exists then it's properly shown. We don't use the
2643            editor window because it could be closed (save to drafts
2644            could happen after closing the window */
2645         win = (ModestMainWindow *)
2646                 modest_window_mgr_get_main_window( modest_runtime_get_window_mgr(), FALSE);
2647         if (win) {
2648                 gchar *text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
2649                 modest_platform_information_banner (GTK_WIDGET (win), NULL, text);
2650                 g_free (text);
2651         }
2652         modest_msg_edit_window_set_modified (edit_window, FALSE);
2653
2654         /* Frees */
2655         g_free (from);
2656         g_free (account_name);
2657         g_object_unref (G_OBJECT (transport_account));
2658         g_object_unref (G_OBJECT (mail_operation));
2659
2660         modest_msg_edit_window_free_msg_data (edit_window, data);
2661
2662         /* ** FIXME **
2663          * If the drafts folder is selected then make the header view
2664          * insensitive while the message is being saved to drafts
2665          * (it'll be sensitive again in on_save_to_drafts_cb()). This
2666          * is not very clean but it avoids letting the drafts folder
2667          * in an inconsistent state: the user could edit the message
2668          * being saved and undesirable things would happen.
2669          * In the average case the user won't notice anything at
2670          * all. In the worst case (the user is editing a really big
2671          * file from Drafts) the header view will be insensitive
2672          * during the saving process (10 or 20 seconds, depending on
2673          * the message). Anyway this is just a quick workaround: once
2674          * we find a better solution it should be removed
2675          * See NB#65125 (commend #18) for details.
2676          */
2677         if (!had_error && win != NULL) {
2678                 ModestFolderView *view = MODEST_FOLDER_VIEW(modest_main_window_get_child_widget(
2679                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW));
2680                 if (view != NULL) {
2681                         TnyFolder *folder = TNY_FOLDER(modest_folder_view_get_selected(view));
2682                         if (folder) {
2683                                 if (modest_tny_folder_is_local_folder(folder)) {
2684                                         TnyFolderType folder_type;
2685                                         folder_type = modest_tny_folder_get_local_or_mmc_folder_type(folder);
2686                                         if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
2687                                                 GtkWidget *hdrview = modest_main_window_get_child_widget(
2688                                                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2689                                                 if (hdrview) gtk_widget_set_sensitive(hdrview, FALSE);
2690                                         }
2691                                 }
2692                         }
2693                         if (folder != NULL) g_object_unref(folder);
2694                 }
2695         }
2696
2697         return !had_error;
2698 }
2699
2700 /* For instance, when clicking the Send toolbar button when editing a message: */
2701 gboolean
2702 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2703 {
2704         TnyTransportAccount *transport_account = NULL;
2705         gboolean had_error = FALSE;
2706         guint64 available_disk, expected_size;
2707         gint parts_count;
2708         guint64 parts_size;
2709
2710         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), TRUE);
2711
2712         if (!modest_msg_edit_window_check_names (edit_window, TRUE))
2713                 return TRUE;
2714         
2715         MsgData *data = modest_msg_edit_window_get_msg_data (edit_window);
2716
2717         /* Check size */
2718         available_disk = modest_folder_available_space (NULL);
2719         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
2720         expected_size = modest_tny_msg_estimate_size (data->plain_body,
2721                                                  data->html_body,
2722                                                  parts_count,
2723                                                  parts_size);
2724
2725         if ((available_disk != -1) && expected_size > available_disk) {
2726                 modest_msg_edit_window_free_msg_data (edit_window, data);
2727
2728                 modest_platform_information_banner (NULL, NULL, dgettext("ke-recv", "cerm_device_memory_full"));
2729                 return FALSE;
2730         }
2731
2732         
2733         /*
2734          * djcb: if we're in low-memory state, we only allow for sending messages
2735          * smaller than MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h)
2736          * this should still allow for sending anything critical... 
2737          */
2738         if (expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) {
2739                 if (modest_platform_check_memory_low (MODEST_WINDOW(edit_window))) {
2740                         modest_msg_edit_window_free_msg_data (edit_window, data);
2741                         return FALSE;
2742                 }
2743         }
2744
2745         /*
2746          * djcb: we also make sure that the attachments are smaller than the max size
2747          * this is for the case where we'd try to forward a message with attachments 
2748          * bigger than our max allowed size, or sending an message from drafts which
2749          * somehow got past our checks when attaching.
2750          */
2751         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
2752                 modest_platform_run_information_dialog (
2753                         GTK_WINDOW(edit_window),
2754                         dgettext("ke-recv","memr_ib_operation_disabled"),
2755                         TRUE);
2756                 modest_msg_edit_window_free_msg_data (edit_window, data);
2757                 return FALSE;
2758         }
2759
2760         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2761         gchar *account_name = g_strdup (data->account_name);
2762         if (!account_name)
2763                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2764
2765         if (!account_name) 
2766                 account_name = modest_account_mgr_get_default_account (account_mgr);
2767                 
2768         if (!account_name) {
2769                 modest_msg_edit_window_free_msg_data (edit_window, data);
2770                 /* Run account setup wizard */
2771                 if (!modest_ui_actions_run_account_setup_wizard (MODEST_WINDOW(edit_window))) {
2772                         return TRUE;
2773                 }
2774         }
2775         
2776         /* Get the currently-active transport account for this modest account: */
2777         if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2778                 transport_account = TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2779                                                           (modest_runtime_get_account_store(),
2780                                                            account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2781         }
2782         
2783         if (!transport_account) {
2784                 modest_msg_edit_window_free_msg_data (edit_window, data);
2785                 /* Run account setup wizard */
2786                 if (!modest_ui_actions_run_account_setup_wizard(MODEST_WINDOW(edit_window)))
2787                         return TRUE;
2788         }
2789         
2790         gchar *from = modest_account_mgr_get_from_string (account_mgr, account_name);
2791
2792         /* Create the mail operation */
2793         ModestMailOperation *mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
2794         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2795
2796         modest_mail_operation_send_new_mail (mail_operation,
2797                                              transport_account,
2798                                              data->draft_msg,
2799                                              from,
2800                                              data->to, 
2801                                              data->cc, 
2802                                              data->bcc,
2803                                              data->subject, 
2804                                              data->plain_body, 
2805                                              data->html_body,
2806                                              data->attachments,
2807                                              data->images,
2808                                              data->priority_flags);
2809
2810         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2811                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
2812
2813
2814         if (modest_mail_operation_get_error (mail_operation) != NULL) {
2815                 const GError *error = modest_mail_operation_get_error (mail_operation);
2816                 if (error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
2817                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
2818                         modest_platform_information_banner (NULL, NULL, _CS("sfil_ni_not_enough_memory"));
2819                         had_error = TRUE;
2820                 }
2821         }
2822                                              
2823         /* Free data: */
2824         g_free (from);
2825         g_free (account_name);
2826         g_object_unref (G_OBJECT (transport_account));
2827         g_object_unref (G_OBJECT (mail_operation));
2828
2829         modest_msg_edit_window_free_msg_data (edit_window, data);
2830
2831         if (!had_error) {
2832                 modest_msg_edit_window_set_sent (edit_window, TRUE);
2833
2834                 /* Save settings and close the window: */
2835                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2836         }
2837
2838         return !had_error;
2839 }
2840
2841 void 
2842 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
2843                                   ModestMsgEditWindow *window)
2844 {
2845         ModestMsgEditFormatState *format_state = NULL;
2846
2847         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2848         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2849
2850         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2851                 return;
2852
2853         format_state = modest_msg_edit_window_get_format_state (window);
2854         g_return_if_fail (format_state != NULL);
2855
2856         format_state->bold = gtk_toggle_action_get_active (action);
2857         modest_msg_edit_window_set_format_state (window, format_state);
2858         g_free (format_state);
2859         
2860 }
2861
2862 void 
2863 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
2864                                      ModestMsgEditWindow *window)
2865 {
2866         ModestMsgEditFormatState *format_state = NULL;
2867
2868         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2869         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2870
2871         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2872                 return;
2873
2874         format_state = modest_msg_edit_window_get_format_state (window);
2875         g_return_if_fail (format_state != NULL);
2876
2877         format_state->italics = gtk_toggle_action_get_active (action);
2878         modest_msg_edit_window_set_format_state (window, format_state);
2879         g_free (format_state);
2880         
2881 }
2882
2883 void 
2884 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
2885                                      ModestMsgEditWindow *window)
2886 {
2887         ModestMsgEditFormatState *format_state = NULL;
2888
2889         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2890         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
2891
2892         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2893                 return;
2894
2895         format_state = modest_msg_edit_window_get_format_state (window);
2896         g_return_if_fail (format_state != NULL);
2897
2898         format_state->bullet = gtk_toggle_action_get_active (action);
2899         modest_msg_edit_window_set_format_state (window, format_state);
2900         g_free (format_state);
2901         
2902 }
2903
2904 void 
2905 modest_ui_actions_on_change_justify (GtkRadioAction *action,
2906                                      GtkRadioAction *selected,
2907                                      ModestMsgEditWindow *window)
2908 {
2909         ModestMsgEditFormatState *format_state = NULL;
2910         GtkJustification value;
2911
2912         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2913
2914         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2915                 return;
2916
2917         value = gtk_radio_action_get_current_value (selected);
2918
2919         format_state = modest_msg_edit_window_get_format_state (window);
2920         g_return_if_fail (format_state != NULL);
2921
2922         format_state->justification = value;
2923         modest_msg_edit_window_set_format_state (window, format_state);
2924         g_free (format_state);
2925 }
2926
2927 void 
2928 modest_ui_actions_on_select_editor_color (GtkAction *action,
2929                                           ModestMsgEditWindow *window)
2930 {
2931         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2932         g_return_if_fail (GTK_IS_ACTION (action));
2933
2934         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2935                 return;
2936
2937         modest_msg_edit_window_select_color (window);
2938 }
2939
2940 void 
2941 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
2942                                                      ModestMsgEditWindow *window)
2943 {
2944         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2945         g_return_if_fail (GTK_IS_ACTION (action));
2946
2947         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2948                 return;
2949
2950         modest_msg_edit_window_select_background_color (window);
2951 }
2952
2953 void 
2954 modest_ui_actions_on_insert_image (GtkAction *action,
2955                                    ModestMsgEditWindow *window)
2956 {
2957         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2958         g_return_if_fail (GTK_IS_ACTION (action));
2959
2960
2961         if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
2962                 return;
2963
2964         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
2965                 return;
2966
2967         modest_msg_edit_window_insert_image (window);
2968 }
2969
2970 void 
2971 modest_ui_actions_on_attach_file (GtkAction *action,
2972                                   ModestMsgEditWindow *window)
2973 {
2974         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2975         g_return_if_fail (GTK_IS_ACTION (action));
2976
2977         if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
2978                 return;
2979         
2980         modest_msg_edit_window_offer_attach_file (window);
2981 }
2982
2983 void 
2984 modest_ui_actions_on_remove_attachments (GtkAction *action,
2985                                          ModestMsgEditWindow *window)
2986 {
2987         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2988         g_return_if_fail (GTK_IS_ACTION (action));
2989
2990         modest_msg_edit_window_remove_attachments (window, NULL);
2991 }
2992
2993 static void
2994 do_create_folder_cb (ModestMailOperation *mail_op,
2995                      TnyFolderStore *parent_folder, 
2996                      TnyFolder *new_folder,
2997                      gpointer user_data)
2998 {
2999         gchar *suggested_name = (gchar *) user_data;
3000         GtkWindow *source_win = (GtkWindow *) modest_mail_operation_get_source (mail_op);
3001
3002         if (modest_mail_operation_get_error (mail_op)) {
3003
3004                 /* Show an error. If there was some problem writing to
3005                    disk, show it, otherwise show the generic folder
3006                    create error. We do it here and not in an error
3007                    handler because the call to do_create_folder will
3008                    stop the main loop in a gtk_dialog_run and then,
3009                    the message won't be shown until that dialog is
3010                    closed */
3011                 modest_ui_actions_disk_operations_error_handler (mail_op,
3012                                                                  _("mail_in_ui_folder_create_error"));
3013
3014                 /* Try again. Do *NOT* show any error because the mail
3015                    operations system will do it for us because we
3016                    created the mail_op with new_with_error_handler */
3017                 do_create_folder (source_win, parent_folder, (const gchar *) suggested_name);
3018         } else {
3019                 /* the 'source_win' is either the ModestMainWindow, or the 'Move to folder'-dialog
3020                  * FIXME: any other? */         
3021                 GtkWidget *folder_view;
3022
3023                 if (MODEST_IS_MAIN_WINDOW(source_win)) 
3024                         folder_view = 
3025                                 modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (source_win),
3026                                                                      MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3027                 else
3028                         folder_view =
3029                                 get_folder_view_from_move_to_dialog (GTK_WIDGET(source_win));
3030                 
3031                 /* Select the newly created folder. It could happen
3032                    that the widget is no longer there (i.e. the window
3033                    has been destroyed, so we need to check this */
3034                 if (folder_view)
3035                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view),
3036                                                           new_folder, FALSE);
3037                 g_object_unref (new_folder);
3038         }
3039         /* Free. Note that the first time it'll be NULL so noop */
3040         g_free (suggested_name);
3041         g_object_unref (source_win);
3042 }
3043
3044 static void
3045 do_create_folder (GtkWindow *parent_window, 
3046                   TnyFolderStore *parent_folder, 
3047                   const gchar *suggested_name)
3048 {
3049         gint result;
3050         gchar *folder_name = NULL;
3051
3052         result = modest_platform_run_new_folder_dialog (GTK_WINDOW (parent_window),
3053                                                         parent_folder,
3054                                                         (gchar *) suggested_name,
3055                                                         &folder_name);
3056         
3057         if (result == GTK_RESPONSE_ACCEPT) {
3058                 ModestMailOperation *mail_op;
3059                 
3060                 mail_op  = modest_mail_operation_new ((GObject *) parent_window);
3061                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
3062                                                  mail_op);
3063                 modest_mail_operation_create_folder (mail_op,
3064                                                      parent_folder,
3065                                                      (const gchar *) folder_name,
3066                                                      do_create_folder_cb,
3067                                                      folder_name);
3068                 g_object_unref (mail_op);
3069         }
3070 }
3071
3072 static void
3073 create_folder_performer (gboolean canceled, 
3074                          GError *err,
3075                          GtkWindow *parent_window, 
3076                          TnyAccount *account, 
3077                          gpointer user_data)
3078 {
3079         TnyFolderStore *parent_folder = TNY_FOLDER_STORE (user_data);
3080
3081         if (canceled || err) {
3082                 /* In memory full conditions we could get this error here */
3083                 if (err && is_memory_full_error (err)) {
3084                         modest_platform_information_banner ((GtkWidget *) parent_window,
3085                                                             NULL, dgettext("ke-recv",
3086                                                                            "cerm_device_memory_full"));
3087                 }
3088                 goto frees;
3089         }
3090
3091         /* Run the new folder dialog */
3092         do_create_folder (GTK_WINDOW (parent_window), parent_folder, NULL);
3093
3094  frees:
3095         g_object_unref (parent_folder);
3096 }
3097
3098 static void
3099 modest_ui_actions_create_folder(GtkWidget *parent_window,
3100                                 GtkWidget *folder_view)
3101 {
3102         TnyFolderStore *parent_folder;
3103
3104         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3105         
3106         if (parent_folder) {
3107                 /* The parent folder will be freed in the callback */
3108                 modest_platform_connect_if_remote_and_perform (GTK_WINDOW (parent_window), 
3109                                                                TRUE,
3110                                                                parent_folder,
3111                                                                create_folder_performer, 
3112                                                                parent_folder);
3113         }
3114 }
3115
3116 void 
3117 modest_ui_actions_on_new_folder (GtkAction *action, ModestMainWindow *main_window)
3118 {
3119         GtkWidget *folder_view;
3120         
3121         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3122
3123         folder_view = modest_main_window_get_child_widget (main_window,
3124                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3125         if (!folder_view)
3126                 return;
3127
3128         modest_ui_actions_create_folder (GTK_WIDGET (main_window), folder_view);
3129 }
3130
3131 static void
3132 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
3133                                                gpointer user_data)
3134 {
3135         const GError *error = NULL;
3136         const gchar *message = NULL;
3137         
3138         /* Get error message */
3139         error = modest_mail_operation_get_error (mail_op);
3140         if (!error)
3141                 g_return_if_reached ();
3142
3143         switch (error->code) {
3144         case MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS:
3145                 message = _CS("ckdg_ib_folder_already_exists");
3146                 break;
3147         default:
3148                 message = _("emev_ib_ui_imap_unable_to_rename");
3149         }
3150
3151         /* We don't set a parent for the dialog because the dialog
3152            will be destroyed so the banner won't appear */
3153         modest_platform_information_banner (NULL, NULL, message);
3154 }
3155
3156 typedef struct {
3157         TnyFolderStore *folder;
3158         gchar *new_name;
3159 } RenameFolderInfo;
3160
3161 static void
3162 on_rename_folder_cb (ModestMailOperation *mail_op, 
3163                      TnyFolder *new_folder,
3164                      gpointer user_data)
3165 {
3166         ModestFolderView *folder_view;
3167
3168         /* If the window was closed when renaming a folder this could
3169            happen */
3170         if (!MODEST_IS_FOLDER_VIEW (user_data))
3171                 return;
3172
3173         folder_view = MODEST_FOLDER_VIEW (user_data);
3174         /* Note that if the rename fails new_folder will be NULL */
3175         if (new_folder) {
3176                 modest_folder_view_select_folder (folder_view, new_folder, FALSE);
3177         } else {
3178                 modest_folder_view_select_first_inbox_or_local (folder_view);
3179         }
3180         gtk_widget_grab_focus (GTK_WIDGET (folder_view));       
3181 }
3182
3183 static void
3184 on_rename_folder_performer (gboolean canceled, 
3185                             GError *err, 
3186                             GtkWindow *parent_window, 
3187                             TnyAccount *account, 
3188                             gpointer user_data)
3189 {
3190         ModestMailOperation *mail_op = NULL;
3191         GtkTreeSelection *sel = NULL;
3192         GtkWidget *folder_view = NULL;
3193         RenameFolderInfo *data = (RenameFolderInfo*)user_data;
3194
3195         if (canceled || err) {
3196                 /* In memory full conditions we could get this error here */
3197                 if (err && is_memory_full_error (err)) {
3198                         modest_platform_information_banner ((GtkWidget *) parent_window,
3199                                                             NULL, dgettext("ke-recv",
3200                                                                            "cerm_device_memory_full"));
3201                 }
3202         } else if (MODEST_IS_MAIN_WINDOW(parent_window)) {
3203
3204                 folder_view = modest_main_window_get_child_widget (
3205                                 MODEST_MAIN_WINDOW (parent_window),
3206                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3207
3208                 mail_op = 
3209                         modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3210                                         modest_ui_actions_rename_folder_error_handler,
3211                                         parent_window, NULL);
3212
3213                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3214                                 mail_op);
3215
3216                 /* Clear the headers view */
3217                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3218                 gtk_tree_selection_unselect_all (sel);
3219
3220                 /* Actually rename the folder */
3221                 modest_mail_operation_rename_folder (mail_op,
3222                                                      TNY_FOLDER (data->folder),
3223                                                      (const gchar *) (data->new_name),
3224                                                      on_rename_folder_cb,
3225                                                      folder_view);
3226                 g_object_unref (mail_op);
3227         }
3228
3229         g_free (data->new_name);
3230         g_free (data);
3231 }
3232
3233 void 
3234 modest_ui_actions_on_rename_folder (GtkAction *action,
3235                                      ModestMainWindow *main_window)
3236 {
3237         TnyFolderStore *folder;
3238         GtkWidget *folder_view;
3239         GtkWidget *header_view; 
3240
3241         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3242
3243         folder_view = modest_main_window_get_child_widget (main_window,
3244                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3245         if (!folder_view)
3246                 return;
3247
3248         header_view = modest_main_window_get_child_widget (main_window,
3249                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
3250         
3251         if (!header_view)
3252                 return;
3253
3254         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3255
3256         if (!folder)
3257                 return;
3258
3259         if (TNY_IS_FOLDER (folder)) {
3260                 gchar *folder_name;
3261                 gint response;
3262                 const gchar *current_name;
3263                 TnyFolderStore *parent;
3264                 gboolean do_rename = TRUE;
3265
3266                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
3267                 parent = tny_folder_get_folder_store (TNY_FOLDER (folder));
3268                 response = modest_platform_run_rename_folder_dialog (GTK_WINDOW (main_window), 
3269                                                                      parent, current_name, 
3270                                                                      &folder_name);
3271                 g_object_unref (parent);
3272
3273                 if (response != GTK_RESPONSE_ACCEPT || strlen (folder_name) == 0) {
3274                         do_rename = FALSE;
3275                 } else {
3276                         RenameFolderInfo *rename_folder_data = g_new0 (RenameFolderInfo, 1);
3277                         rename_folder_data->folder = folder;
3278                         rename_folder_data->new_name = folder_name;
3279                         modest_platform_connect_if_remote_and_perform (GTK_WINDOW(main_window), TRUE,
3280                                         folder, on_rename_folder_performer, rename_folder_data);
3281                 }
3282         }
3283         g_object_unref (folder);
3284 }
3285
3286 static void
3287 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
3288                                                gpointer user_data)
3289 {
3290         GObject *win = modest_mail_operation_get_source (mail_op);
3291
3292         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
3293                                                 _("mail_in_ui_folder_delete_error"),
3294                                                 FALSE);
3295         g_object_unref (win);
3296 }
3297
3298 typedef struct {
3299         TnyFolderStore *folder;
3300         gboolean move_to_trash;
3301 } DeleteFolderInfo;
3302
3303 static void
3304 on_delete_folder_cb (gboolean canceled, 
3305                   GError *err,
3306                   GtkWindow *parent_window, 
3307                   TnyAccount *account, 
3308                   gpointer user_data)
3309 {
3310         DeleteFolderInfo *info = (DeleteFolderInfo*) user_data;
3311         GtkWidget *folder_view;
3312         ModestMailOperation *mail_op;
3313         GtkTreeSelection *sel;
3314         
3315         if (!MODEST_IS_MAIN_WINDOW(parent_window) || canceled || (err!=NULL)) {
3316                 g_object_unref (G_OBJECT (info->folder));
3317                 g_free (info);
3318                 return;
3319         }
3320         
3321         folder_view = modest_main_window_get_child_widget (
3322                         MODEST_MAIN_WINDOW (parent_window),
3323                         MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3324
3325         /* Unselect the folder before deleting it to free the headers */
3326         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3327         gtk_tree_selection_unselect_all (sel);
3328
3329         /* Create the mail operation */
3330         mail_op =
3331                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3332                                 modest_ui_actions_delete_folder_error_handler,
3333                                 NULL, NULL);
3334
3335         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3336                         mail_op);
3337         modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (info->folder), info->move_to_trash);
3338         
3339         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (folder_view));
3340
3341         g_object_unref (G_OBJECT (mail_op));
3342         g_object_unref (G_OBJECT (info->folder));
3343         g_free (info);
3344 }
3345
3346 static void
3347 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash)
3348 {
3349         TnyFolderStore *folder;
3350         GtkWidget *folder_view;
3351         gint response;
3352         gchar *message;
3353         
3354         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3355
3356         folder_view = modest_main_window_get_child_widget (main_window,
3357                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3358         if (!folder_view)
3359                 return;
3360
3361         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3362
3363         /* Show an error if it's an account */
3364         if (!TNY_IS_FOLDER (folder)) {
3365                 modest_platform_run_information_dialog (GTK_WINDOW (main_window),
3366                                                         _("mail_in_ui_folder_delete_error"),
3367                                                         FALSE);
3368                 g_object_unref (G_OBJECT (folder));
3369                 return;
3370         }
3371
3372         /* Ask the user */      
3373         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"), 
3374                                     tny_folder_get_name (TNY_FOLDER (folder)));
3375         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (main_window),
3376                                                             (const gchar *) message);
3377         g_free (message);
3378
3379         if (response == GTK_RESPONSE_OK) {
3380                 DeleteFolderInfo *info;
3381                 info = g_new0(DeleteFolderInfo, 1);
3382                 info->folder = folder;
3383                 info->move_to_trash = move_to_trash;
3384                 g_object_ref (G_OBJECT (info->folder));
3385                 TnyAccount *account = tny_folder_get_account (TNY_FOLDER (folder));
3386                 modest_platform_connect_if_remote_and_perform (GTK_WINDOW (main_window), 
3387                                                                TRUE,
3388                                                                TNY_FOLDER_STORE (account), 
3389                                                                on_delete_folder_cb, info);
3390                 g_object_unref (account);
3391         }
3392         g_object_unref (G_OBJECT (folder));
3393 }
3394
3395 void 
3396 modest_ui_actions_on_delete_folder (GtkAction *action,
3397                                      ModestMainWindow *main_window)
3398 {
3399         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3400         
3401         delete_folder (main_window, FALSE);
3402 }
3403
3404 void 
3405 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
3406 {
3407         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3408         
3409         delete_folder (main_window, TRUE);
3410 }
3411
3412
3413 typedef struct _PasswordDialogFields {
3414         GtkWidget *username;
3415         GtkWidget *password;
3416         GtkWidget *dialog;
3417 } PasswordDialogFields;
3418
3419 static void
3420 password_dialog_check_field (GtkEditable *editable,
3421                              PasswordDialogFields *fields)
3422 {
3423         const gchar *value;
3424         gboolean any_value_empty = FALSE;
3425
3426         value = gtk_entry_get_text (GTK_ENTRY (fields->username));
3427         if ((value == NULL) || value[0] == '\0') {
3428                 any_value_empty = TRUE;
3429         }
3430         value = gtk_entry_get_text (GTK_ENTRY (fields->password));
3431         if ((value == NULL) || value[0] == '\0') {
3432                 any_value_empty = TRUE;
3433         }
3434         gtk_dialog_set_response_sensitive (GTK_DIALOG (fields->dialog), GTK_RESPONSE_ACCEPT, !any_value_empty);
3435 }
3436
3437 void
3438 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
3439                                          const gchar* server_account_name,
3440                                          gchar **username,
3441                                          gchar **password, 
3442                                          gboolean *cancel, 
3443                                          gboolean *remember,
3444                                          ModestMainWindow *main_window)
3445 {
3446         g_return_if_fail(server_account_name);
3447         gboolean completed = FALSE;
3448         PasswordDialogFields *fields = NULL;
3449         
3450         /* Initalize output parameters: */
3451         if (cancel)
3452                 *cancel = FALSE;
3453                 
3454         if (remember)
3455                 *remember = TRUE;
3456                 
3457 #ifdef MODEST_PLATFORM_MAEMO
3458         /* Maemo uses a different (awkward) button order,
3459          * It should probably just use gtk_alternative_dialog_button_order ().
3460          */
3461         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3462                                               NULL,
3463                                               GTK_DIALOG_MODAL,
3464                                               _("mcen_bd_dialog_ok"),
3465                                               GTK_RESPONSE_ACCEPT,
3466                                               _("mcen_bd_dialog_cancel"),
3467                                               GTK_RESPONSE_REJECT,
3468                                               NULL);
3469 #else
3470         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3471                                               NULL,
3472                                               GTK_DIALOG_MODAL,
3473                                               GTK_STOCK_CANCEL,
3474                                               GTK_RESPONSE_REJECT,
3475                                               GTK_STOCK_OK,
3476                                               GTK_RESPONSE_ACCEPT,
3477                                               NULL);
3478 #endif /* MODEST_PLATFORM_MAEMO */
3479
3480         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (dialog));
3481         
3482         gchar *server_name = modest_account_mgr_get_server_account_hostname (
3483                 modest_runtime_get_account_mgr(), server_account_name);
3484         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
3485                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
3486                 if (cancel)
3487                         *cancel = TRUE;
3488                 return;
3489         }
3490         
3491         /* This causes a warning because the logical ID has no %s in it, 
3492          * though the translation does, but there is not much we can do about that: */
3493         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
3494         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
3495                             FALSE, FALSE, 0);
3496         g_free (txt);
3497         g_free (server_name);
3498         server_name = NULL;
3499
3500         /* username: */
3501         gchar *initial_username = modest_account_mgr_get_server_account_username (
3502                 modest_runtime_get_account_mgr(), server_account_name);
3503         
3504         GtkWidget *entry_username = gtk_entry_new ();
3505         if (initial_username)
3506                 gtk_entry_set_text (GTK_ENTRY (entry_username), initial_username);
3507         /* Dim this if a connection has ever succeeded with this username,
3508          * as per the UI spec: */
3509         /* const gboolean username_known =  */
3510         /*      modest_account_mgr_get_server_account_username_has_succeeded( */
3511         /*              modest_runtime_get_account_mgr(), server_account_name); */
3512         /* gtk_widget_set_sensitive (entry_username, !username_known); */
3513
3514         /* We drop the username sensitive code and disallow changing it here
3515          * as tinymail does not support really changing the username in the callback
3516          */
3517         gtk_widget_set_sensitive (entry_username, FALSE);
3518
3519 #ifdef MODEST_PLATFORM_MAEMO
3520         /* Auto-capitalization is the default, so let's turn it off: */
3521         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
3522         
3523         /* Create a size group to be used by all captions.
3524          * Note that HildonCaption does not create a default size group if we do not specify one.
3525          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
3526         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3527         
3528         GtkWidget *caption = hildon_caption_new (sizegroup, 
3529                 _("mail_fi_username"), entry_username, NULL, HILDON_CAPTION_MANDATORY);
3530         gtk_widget_show (entry_username);
3531         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3532                 FALSE, FALSE, MODEST_MARGIN_HALF);
3533         gtk_widget_show (caption);
3534 #else 
3535         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_username,
3536                             TRUE, FALSE, 0);
3537 #endif /* MODEST_PLATFORM_MAEMO */      
3538                             
3539         /* password: */
3540         GtkWidget *entry_password = gtk_entry_new ();
3541         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
3542         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
3543         
3544 #ifdef MODEST_PLATFORM_MAEMO
3545         /* Auto-capitalization is the default, so let's turn it off: */
3546         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password), 
3547                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
3548         
3549         caption = hildon_caption_new (sizegroup, 
3550                 _("mail_fi_password"), entry_password, NULL, HILDON_CAPTION_MANDATORY);
3551         gtk_widget_show (entry_password);
3552         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3553                 FALSE, FALSE, MODEST_MARGIN_HALF);
3554         gtk_widget_show (caption);
3555         g_object_unref (sizegroup);
3556 #else 
3557         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_password,
3558                             TRUE, FALSE, 0);
3559 #endif /* MODEST_PLATFORM_MAEMO */      
3560
3561         if (initial_username != NULL)
3562                 gtk_widget_grab_focus (GTK_WIDGET (entry_password));
3563                                 
3564 /* This is not in the Maemo UI spec:
3565         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
3566         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
3567                             TRUE, FALSE, 0);
3568 */
3569
3570         fields = g_slice_new0 (PasswordDialogFields);
3571         fields->username = entry_username;
3572         fields->password = entry_password;
3573         fields->dialog = dialog;
3574
3575         g_signal_connect (entry_username, "changed", G_CALLBACK (password_dialog_check_field), fields);
3576         g_signal_connect (entry_password, "changed", G_CALLBACK (password_dialog_check_field), fields);
3577         password_dialog_check_field (NULL, fields);
3578
3579         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3580
3581         while (!completed) {
3582         
3583                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3584                         if (username) {
3585                                 *username = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_username)));
3586                                 
3587                                 /* Note that an empty field becomes the "" string */
3588                                 if (*username && strlen (*username) > 0) {
3589                                         modest_account_mgr_set_server_account_username (modest_runtime_get_account_mgr(), 
3590                                                                                         server_account_name, 
3591                                                                                         *username);
3592                                         completed = TRUE;
3593                                 
3594                                         const gboolean username_was_changed = 
3595                                                 (strcmp (*username, initial_username) != 0);
3596                                         if (username_was_changed) {
3597                                                 g_warning ("%s: tinymail does not yet support changing the "
3598                                                            "username in the get_password() callback.\n", __FUNCTION__);
3599                                         }
3600                                 } else {
3601                                         /* Show error */
3602                                         modest_platform_information_banner (GTK_WIDGET (dialog), NULL, 
3603                                                                             _("mcen_ib_username_pw_incorrect"));
3604                                         completed = FALSE;
3605                                 }
3606                         }
3607                         
3608                         if (password) {
3609                                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_password)));
3610                         
3611                                 /* We do not save the password in the configuration, 
3612                                  * because this function is only called for passwords that should 
3613                                  * not be remembered:
3614                                  modest_server_account_set_password (
3615                                  modest_runtime_get_account_mgr(), server_account_name, 
3616                                  *password);
3617                                  */
3618                         }                       
3619                         if (cancel)
3620                                 *cancel   = FALSE;                      
3621                 } else {
3622                         /* Set parent to NULL or the banner will disappear with its parent dialog */
3623                         modest_platform_information_banner(NULL, NULL, _("mail_ib_login_cancelled"));
3624                         completed = TRUE;
3625                         if (username)
3626                                 *username = NULL;                       
3627                         if (password)
3628                                 *password = NULL;                       
3629                         if (cancel)
3630                                 *cancel   = TRUE;
3631                 }
3632         }
3633
3634 /* This is not in the Maemo UI spec:
3635         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
3636                 *remember = TRUE;
3637         else
3638                 *remember = FALSE;
3639 */
3640
3641         gtk_widget_destroy (dialog);
3642         g_slice_free (PasswordDialogFields, fields);
3643         
3644         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
3645 }
3646
3647 void
3648 modest_ui_actions_on_cut (GtkAction *action,
3649                           ModestWindow *window)
3650 {
3651         GtkWidget *focused_widget;
3652         GtkClipboard *clipboard;
3653
3654         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3655         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3656         if (GTK_IS_EDITABLE (focused_widget)) {
3657                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
3658                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3659                 gtk_clipboard_store (clipboard);
3660         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3661                 GtkTextBuffer *buffer;
3662
3663                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3664                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
3665                         gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
3666                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3667                         gtk_clipboard_store (clipboard);
3668                 }
3669         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
3670                 TnyList *header_list = modest_header_view_get_selected_headers (
3671                                 MODEST_HEADER_VIEW (focused_widget));
3672                 gboolean continue_download = FALSE;
3673                 gint num_of_unc_msgs;
3674
3675                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
3676
3677                 if (num_of_unc_msgs) {
3678                         TnyAccount *account = get_account_from_header_list (header_list);
3679                         if (account) {
3680                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
3681                                 g_object_unref (account);
3682                         }
3683                 }
3684
3685                 if (num_of_unc_msgs == 0 || continue_download) {
3686 /*                      modest_platform_information_banner (
3687                                         NULL, NULL, _CS("mcen_ib_getting_items"));*/
3688                         modest_header_view_cut_selection (
3689                                         MODEST_HEADER_VIEW (focused_widget));
3690                 }
3691
3692                 g_object_unref (header_list);
3693         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3694                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
3695         }
3696 }
3697
3698 void
3699 modest_ui_actions_on_copy (GtkAction *action,
3700                            ModestWindow *window)
3701 {
3702         GtkClipboard *clipboard;
3703         GtkWidget *focused_widget;
3704         gboolean copied = TRUE;
3705
3706         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3707         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3708
3709         if (GTK_IS_LABEL (focused_widget)) {
3710                 gchar *selection;
3711                 selection = modest_text_utils_label_get_selection (GTK_LABEL (focused_widget));
3712                 gtk_clipboard_set_text (clipboard, selection, -1);
3713                 g_free (selection);
3714                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3715                 gtk_clipboard_store (clipboard);
3716         } else if (GTK_IS_EDITABLE (focused_widget)) {
3717                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
3718                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3719                 gtk_clipboard_store (clipboard);
3720         } else if (GTK_IS_HTML (focused_widget)) {
3721                 gtk_html_copy (GTK_HTML (focused_widget));
3722                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3723                 gtk_clipboard_store (clipboard);
3724         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3725                 GtkTextBuffer *buffer;
3726                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3727                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
3728                         gtk_text_buffer_copy_clipboard (buffer, clipboard);
3729                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3730                         gtk_clipboard_store (clipboard);
3731                 }
3732         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
3733                 TnyList *header_list = modest_header_view_get_selected_headers (
3734                                 MODEST_HEADER_VIEW (focused_widget));
3735                 gboolean continue_download = FALSE;
3736                 gint num_of_unc_msgs;
3737
3738                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
3739
3740                 if (num_of_unc_msgs) {
3741                         TnyAccount *account = get_account_from_header_list (header_list);
3742                         if (account) {
3743                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
3744                                 g_object_unref (account);
3745                         }
3746                 }
3747
3748                 if (num_of_unc_msgs == 0 || continue_download) {
3749                         modest_platform_information_banner (
3750                                         NULL, NULL, _CS("mcen_ib_getting_items"));
3751                         modest_header_view_copy_selection (
3752                                         MODEST_HEADER_VIEW (focused_widget));
3753                 } else
3754                         copied = FALSE;
3755
3756                 g_object_unref (header_list);
3757
3758         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3759                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
3760         }
3761
3762         /* Show information banner if there was a copy to clipboard */
3763         if(copied)
3764                 modest_platform_information_banner (
3765                                 NULL, NULL, _CS("ecoc_ib_edwin_copied"));
3766 }
3767
3768 void
3769 modest_ui_actions_on_undo (GtkAction *action,
3770                            ModestWindow *window)
3771 {
3772         ModestEmailClipboard *clipboard = NULL;
3773
3774         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3775                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
3776         } else if (MODEST_IS_MAIN_WINDOW (window)) {
3777                 /* Clear clipboard source */
3778                 clipboard = modest_runtime_get_email_clipboard ();
3779                 modest_email_clipboard_clear (clipboard);               
3780         }
3781         else {
3782                 g_return_if_reached ();
3783         }
3784 }
3785
3786 void
3787 modest_ui_actions_on_redo (GtkAction *action,
3788                            ModestWindow *window)
3789 {
3790         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3791                 modest_msg_edit_window_redo (MODEST_MSG_EDIT_WINDOW (window));
3792         }
3793         else {
3794                 g_return_if_reached ();
3795         }
3796 }
3797
3798
3799 static void
3800 destroy_information_note (ModestMailOperation *mail_op, 
3801                           gpointer user_data)
3802 {
3803         /* destroy information note */
3804         gtk_widget_destroy (GTK_WIDGET(user_data));
3805 }
3806
3807 static void
3808 destroy_folder_information_note (ModestMailOperation *mail_op, 
3809                                  TnyFolder *new_folder,
3810                                  gpointer user_data)
3811 {
3812         /* destroy information note */
3813         gtk_widget_destroy (GTK_WIDGET(user_data));
3814 }
3815
3816
3817 static void
3818 paste_as_attachment_free (gpointer data)
3819 {
3820         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) data;
3821
3822         if (helper->banner) {
3823                 gtk_widget_destroy (helper->banner);
3824                 g_object_unref (helper->banner);
3825         }
3826         g_free (helper);
3827 }
3828
3829 static void
3830 paste_msg_as_attachment_cb (ModestMailOperation *mail_op,
3831                             TnyHeader *header,
3832                             TnyMsg *msg,
3833                             gpointer userdata)
3834 {
3835         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) userdata;
3836         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (helper->window));
3837
3838         if (msg == NULL)
3839                 return;
3840
3841         modest_msg_edit_window_add_part (MODEST_MSG_EDIT_WINDOW (helper->window), TNY_MIME_PART (msg));
3842         
3843 }
3844
3845 void
3846 modest_ui_actions_on_paste (GtkAction *action,
3847                             ModestWindow *window)
3848 {
3849         GtkWidget *focused_widget = NULL;
3850         GtkWidget *inf_note = NULL;
3851         ModestMailOperation *mail_op = NULL;
3852
3853         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3854         if (GTK_IS_EDITABLE (focused_widget)) {
3855                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
3856         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3857                 ModestEmailClipboard *e_clipboard = NULL;
3858                 e_clipboard = modest_runtime_get_email_clipboard ();
3859                 if (modest_email_clipboard_cleared (e_clipboard)) {
3860                         GtkTextBuffer *buffer;
3861                         GtkClipboard *clipboard;
3862
3863                         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3864                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3865                         gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
3866                 } else if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3867                         ModestMailOperation *mail_op;
3868                         TnyFolder *src_folder;
3869                         TnyList *data;
3870                         gboolean delete;
3871                         PasteAsAttachmentHelper *helper = g_new0 (PasteAsAttachmentHelper, 1);
3872                         helper->window = MODEST_MSG_EDIT_WINDOW (window);
3873                         helper->banner = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
3874                                                                            _CS("ckct_nw_pasting"));
3875                         modest_email_clipboard_get_data (e_clipboard, &src_folder, &data, &delete);
3876                         mail_op = modest_mail_operation_new (G_OBJECT (window));
3877                         if (helper->banner != NULL) {
3878                                 g_object_ref (G_OBJECT (helper->banner));
3879                                 gtk_widget_show (GTK_WIDGET (helper->banner));
3880                         }
3881
3882                         if (data != NULL) {
3883                                 modest_mail_operation_get_msgs_full (mail_op, 
3884                                                                      data,
3885                                                                      (GetMsgAsyncUserCallback) paste_msg_as_attachment_cb,
3886                                                                      helper,
3887                                                                      paste_as_attachment_free);
3888                         }
3889                 }
3890         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3891                 ModestEmailClipboard *clipboard = NULL;
3892                 TnyFolder *src_folder = NULL;
3893                 TnyFolderStore *folder_store = NULL;
3894                 TnyList *data = NULL;           
3895                 gboolean delete = FALSE;
3896                 
3897                 /* Check clipboard source */
3898                 clipboard = modest_runtime_get_email_clipboard ();
3899                 if (modest_email_clipboard_cleared (clipboard)) 
3900                         return;
3901                 
3902                 /* Get elements to paste */
3903                 modest_email_clipboard_get_data (clipboard, &src_folder, &data, &delete);
3904
3905                 /* Create a new mail operation */
3906                 mail_op = modest_mail_operation_new (G_OBJECT(window));
3907                 
3908                 /* Get destination folder */
3909                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (focused_widget));
3910
3911                 /* transfer messages  */
3912                 if (data != NULL) {
3913                         gint response = 0;
3914
3915                         /* Ask for user confirmation */
3916                         response = 
3917                                 modest_ui_actions_msgs_move_to_confirmation (window, 
3918                                                                              TNY_FOLDER (folder_store), 
3919                                                                              delete,
3920                                                                              data);
3921                         
3922                         if (response == GTK_RESPONSE_OK) {
3923                                 /* Launch notification */
3924                                 inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL, 
3925                                                                              _CS("ckct_nw_pasting"));
3926                                 if (inf_note != NULL)  {
3927                                         gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
3928                                         gtk_widget_show (GTK_WIDGET(inf_note));
3929                                 }
3930
3931                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3932                                 modest_mail_operation_xfer_msgs (mail_op, 
3933                                                                  data,
3934                                                                  TNY_FOLDER (folder_store),
3935                                                                  delete,
3936                                                                  destroy_information_note,
3937                                                                  inf_note);                             
3938                         } else {
3939                                 g_object_unref (mail_op);
3940                         }
3941                         
3942                 } else if (src_folder != NULL) {                        
3943                         /* Launch notification */
3944                         inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL, 
3945                                                                      _CS("ckct_nw_pasting"));
3946                         if (inf_note != NULL)  {
3947                                 gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
3948                                 gtk_widget_show (GTK_WIDGET(inf_note));
3949                         }
3950                         
3951                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3952                         modest_mail_operation_xfer_folder (mail_op, 
3953                                                            src_folder,
3954                                                            folder_store,
3955                                                            delete,
3956                                                            destroy_folder_information_note,
3957                                                            inf_note);
3958                 }
3959
3960                 /* Free */
3961                 if (data != NULL) 
3962                         g_object_unref (data);
3963                 if (src_folder != NULL) 
3964                         g_object_unref (src_folder);
3965                 if (folder_store != NULL) 
3966                         g_object_unref (folder_store);
3967         }
3968 }
3969
3970
3971 void
3972 modest_ui_actions_on_select_all (GtkAction *action,
3973                                  ModestWindow *window)
3974 {
3975         GtkWidget *focused_widget;
3976
3977         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3978         if (MODEST_IS_ATTACHMENTS_VIEW (focused_widget)) {
3979                 modest_attachments_view_select_all (MODEST_ATTACHMENTS_VIEW (focused_widget));
3980         } else if (GTK_IS_LABEL (focused_widget)) {
3981                 gtk_label_select_region (GTK_LABEL (focused_widget), 0, -1);
3982         } else if (GTK_IS_EDITABLE (focused_widget)) {
3983                 gtk_editable_select_region (GTK_EDITABLE(focused_widget), 0, -1);
3984         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3985                 GtkTextBuffer *buffer;
3986                 GtkTextIter start, end;
3987
3988                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3989                 gtk_text_buffer_get_start_iter (buffer, &start);
3990                 gtk_text_buffer_get_end_iter (buffer, &end);
3991                 gtk_text_buffer_select_range (buffer, &start, &end);
3992         } else if (GTK_IS_HTML (focused_widget)) {
3993                 gtk_html_select_all (GTK_HTML (focused_widget));
3994         } else if (MODEST_IS_MAIN_WINDOW (window)) {
3995                 GtkWidget *header_view = focused_widget;
3996                 GtkTreeSelection *selection = NULL;
3997                 
3998                 if (!(MODEST_IS_HEADER_VIEW (focused_widget))) {
3999                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
4000                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4001                 }
4002                                 
4003                 /* Disable window dimming management */
4004                 modest_window_disable_dimming (MODEST_WINDOW(window));
4005                 
4006                 /* Select all messages */
4007                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
4008                 gtk_tree_selection_select_all (selection);
4009
4010                 /* Set focuse on header view */
4011                 gtk_widget_grab_focus (header_view);
4012
4013
4014                 /* Enable window dimming management */
4015                 modest_window_enable_dimming (MODEST_WINDOW(window));
4016                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
4017         }
4018
4019 }
4020
4021 void
4022 modest_ui_actions_on_mark_as_read (GtkAction *action,
4023                                    ModestWindow *window)
4024 {       
4025         g_return_if_fail (MODEST_IS_WINDOW(window));
4026                 
4027         /* Mark each header as read */
4028         do_headers_action (window, headers_action_mark_as_read, NULL);
4029 }
4030
4031 void
4032 modest_ui_actions_on_mark_as_unread (GtkAction *action,
4033                                      ModestWindow *window)
4034 {       
4035         g_return_if_fail (MODEST_IS_WINDOW(window));
4036                 
4037         /* Mark each header as read */
4038         do_headers_action (window, headers_action_mark_as_unread, NULL);
4039 }
4040
4041 void
4042 modest_ui_actions_on_change_zoom (GtkRadioAction *action,
4043                                   GtkRadioAction *selected,
4044                                   ModestWindow *window)
4045 {
4046         gint value;
4047
4048         value = gtk_radio_action_get_current_value (selected);
4049         if (MODEST_IS_WINDOW (window)) {
4050                 modest_window_set_zoom (MODEST_WINDOW (window), ((gdouble)value)/100);
4051         }
4052 }
4053
4054 void
4055 modest_ui_actions_msg_edit_on_change_priority (GtkRadioAction *action,
4056                                                GtkRadioAction *selected,
4057                                                ModestWindow *window)
4058 {
4059         TnyHeaderFlags flags;
4060         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4061
4062         flags = gtk_radio_action_get_current_value (selected);
4063         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW (window), flags);
4064 }
4065
4066 void
4067 modest_ui_actions_msg_edit_on_change_file_format (GtkRadioAction *action,
4068                                                   GtkRadioAction *selected,
4069                                                   ModestWindow *window)
4070 {
4071         gint file_format;
4072
4073         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4074
4075         file_format = gtk_radio_action_get_current_value (selected);
4076         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (window), file_format);
4077 }
4078
4079
4080 void
4081 modest_ui_actions_on_zoom_plus (GtkAction *action,
4082                                 ModestWindow *window)
4083 {
4084         g_return_if_fail (MODEST_IS_WINDOW (window));
4085
4086         modest_window_zoom_plus (MODEST_WINDOW (window));
4087 }
4088
4089 void     
4090 modest_ui_actions_on_zoom_minus (GtkAction *action,
4091                                  ModestWindow *window)
4092 {
4093         g_return_if_fail (MODEST_IS_WINDOW (window));
4094
4095         modest_window_zoom_minus (MODEST_WINDOW (window));
4096 }
4097
4098 void     
4099 modest_ui_actions_on_toggle_fullscreen    (GtkToggleAction *toggle,
4100                                            ModestWindow *window)
4101 {
4102         ModestWindowMgr *mgr;
4103         gboolean fullscreen, active;
4104         g_return_if_fail (MODEST_IS_WINDOW (window));
4105
4106         mgr = modest_runtime_get_window_mgr ();
4107
4108         active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle)))?1:0;
4109         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4110
4111         if (active != fullscreen) {
4112                 modest_window_mgr_set_fullscreen_mode (mgr, active);
4113                 gtk_window_present (GTK_WINDOW (window));
4114         }
4115 }
4116
4117 void
4118 modest_ui_actions_on_change_fullscreen (GtkAction *action,
4119                                         ModestWindow *window)
4120 {
4121         ModestWindowMgr *mgr;
4122         gboolean fullscreen;
4123
4124         g_return_if_fail (MODEST_IS_WINDOW (window));
4125
4126         mgr = modest_runtime_get_window_mgr ();
4127         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4128         modest_window_mgr_set_fullscreen_mode (mgr, !fullscreen);
4129
4130         gtk_window_present (GTK_WINDOW (window));
4131 }
4132
4133 /* 
4134  * Used by modest_ui_actions_on_details to call do_headers_action 
4135  */
4136 static void
4137 headers_action_show_details (TnyHeader *header, 
4138                              ModestWindow *window,
4139                              gpointer user_data)
4140
4141 {
4142         GtkWidget *dialog;
4143         
4144         /* Create dialog */
4145         dialog = modest_details_dialog_new_with_header (GTK_WINDOW (window), header);
4146
4147         /* Run dialog */
4148         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4149         gtk_widget_show_all (dialog);
4150         gtk_dialog_run (GTK_DIALOG (dialog));
4151
4152         gtk_widget_destroy (dialog);
4153 }
4154
4155 /*
4156  * Show the folder details in a ModestDetailsDialog widget
4157  */
4158 static void
4159 show_folder_details (TnyFolder *folder, 
4160                      GtkWindow *window)
4161 {
4162         GtkWidget *dialog;
4163         
4164         /* Create dialog */
4165         dialog = modest_details_dialog_new_with_folder (window, folder);
4166
4167         /* Run dialog */
4168         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4169         gtk_widget_show_all (dialog);
4170         gtk_dialog_run (GTK_DIALOG (dialog));
4171
4172         gtk_widget_destroy (dialog);
4173 }
4174
4175 /*
4176  * Show the header details in a ModestDetailsDialog widget
4177  */
4178 void     
4179 modest_ui_actions_on_details (GtkAction *action, 
4180                               ModestWindow *win)
4181 {
4182         TnyList * headers_list;
4183         TnyIterator *iter;
4184         TnyHeader *header;              
4185
4186         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
4187                 TnyMsg *msg;
4188
4189                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (win));
4190                 if (!msg)
4191                         return;
4192                 g_object_unref (msg);           
4193
4194                 headers_list = get_selected_headers (win);
4195                 if (!headers_list)
4196                         return;
4197
4198                 iter = tny_list_create_iterator (headers_list);
4199
4200                 header = TNY_HEADER (tny_iterator_get_current (iter));
4201                 if (header) {
4202                         headers_action_show_details (header, win, NULL);
4203                         g_object_unref (header);
4204                 }
4205
4206                 g_object_unref (iter);
4207                 g_object_unref (headers_list);
4208
4209         } else if (MODEST_IS_MAIN_WINDOW (win)) {
4210                 GtkWidget *folder_view, *header_view;
4211
4212                 /* Check which widget has the focus */
4213                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4214                                                                     MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4215                 if (gtk_widget_is_focus (folder_view)) {
4216                         TnyFolderStore *folder_store
4217                                 = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
4218                         if (!folder_store) {
4219                                 g_warning ("%s: No item was selected.\n", __FUNCTION__);
4220                                 return; 
4221                         }
4222                         /* Show only when it's a folder */
4223                         /* This function should not be called for account items, 
4224                          * because we dim the menu item for them. */
4225                         if (TNY_IS_FOLDER (folder_store)) {
4226                                 show_folder_details (TNY_FOLDER (folder_store), GTK_WINDOW (win));
4227                         }
4228
4229                         g_object_unref (folder_store);
4230
4231                 } else {
4232                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4233                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4234                         /* Show details of each header */
4235                         do_headers_action (win, headers_action_show_details, header_view);
4236                 }
4237         }
4238 }
4239
4240 void     
4241 modest_ui_actions_on_toggle_show_cc (GtkToggleAction *toggle,
4242                                      ModestMsgEditWindow *window)
4243 {
4244         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4245
4246         modest_msg_edit_window_show_cc (window, gtk_toggle_action_get_active (toggle));
4247 }
4248
4249 void     
4250 modest_ui_actions_on_toggle_show_bcc (GtkToggleAction *toggle,
4251                                       ModestMsgEditWindow *window)
4252 {
4253         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4254
4255         modest_msg_edit_window_show_bcc (window, gtk_toggle_action_get_active (toggle));
4256 }
4257
4258 void
4259 modest_ui_actions_toggle_folders_view (GtkAction *action, 
4260                                        ModestMainWindow *main_window)
4261 {
4262         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
4263
4264         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
4265                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SPLIT);
4266         else
4267                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SIMPLE);
4268 }
4269
4270 void 
4271 modest_ui_actions_on_toggle_toolbar (GtkToggleAction *toggle, 
4272                                      ModestWindow *window)
4273 {
4274         gboolean active, fullscreen = FALSE;
4275         ModestWindowMgr *mgr;
4276
4277         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle));
4278
4279         /* Check if we want to toggle the toolbar vuew in fullscreen
4280            or normal mode */
4281         if (!strcmp (gtk_action_get_name (GTK_ACTION (toggle)), 
4282                      "ViewShowToolbarFullScreen")) {
4283                 fullscreen = TRUE;
4284         }
4285
4286         /* Toggle toolbar */
4287         mgr = modest_runtime_get_window_mgr ();
4288         modest_window_mgr_show_toolbars (mgr, G_TYPE_FROM_INSTANCE (window), active, fullscreen);
4289 }
4290
4291 void     
4292 modest_ui_actions_msg_edit_on_select_font (GtkAction *action,
4293                                            ModestMsgEditWindow *window)
4294 {
4295         modest_msg_edit_window_select_font (window);
4296 }
4297
4298
4299 void
4300 modest_ui_actions_on_folder_display_name_changed (ModestFolderView *folder_view,
4301                                                   const gchar *display_name,
4302                                                   GtkWindow *window)
4303 {
4304         /* don't update the display name if it was already set;
4305          * updating the display name apparently is expensive */
4306         const gchar* old_name = gtk_window_get_title (window);
4307
4308         if (display_name == NULL)
4309                 display_name = " ";
4310
4311         if (old_name && display_name && strcmp (old_name, display_name) == 0)
4312                 return; /* don't do anything */
4313
4314         /* This is usually used to change the title of the main window, which
4315          * is the one that holds the folder view. Note that this change can
4316          * happen even when the widget doesn't have the focus. */
4317         gtk_window_set_title (window, display_name);
4318
4319 }
4320
4321 void
4322 modest_ui_actions_on_select_contacts (GtkAction *action, ModestMsgEditWindow *window)
4323 {
4324         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4325         modest_msg_edit_window_select_contacts (window);
4326 }
4327
4328 void
4329 modest_ui_actions_on_check_names (GtkAction *action, ModestMsgEditWindow *window)
4330 {
4331         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4332         modest_msg_edit_window_check_names (window, FALSE);
4333 }
4334
4335 static void
4336 create_move_to_dialog_on_new_folder(GtkWidget *button, gpointer user_data)
4337 {
4338         modest_ui_actions_create_folder (gtk_widget_get_toplevel (button),
4339                                          GTK_WIDGET (user_data));
4340 }
4341
4342 /*
4343  * This function is used to track changes in the selection of the
4344  * folder view that is inside the "move to" dialog to enable/disable
4345  * the OK button because we do not want the user to select a disallowed
4346  * destination for a folder.
4347  * The user also not desired to be able to use NEW button on items where
4348  * folder creation is not possibel.
4349  */
4350 static void
4351 on_move_to_dialog_folder_selection_changed (ModestFolderView* self,
4352                                             TnyFolderStore *folder_store,
4353                                             gboolean selected,
4354                                             gpointer user_data)
4355 {
4356         GtkWidget *dialog = NULL;
4357         GtkWidget *ok_button = NULL, *new_button = NULL;
4358         GList *children = NULL;
4359         gboolean ok_sensitive = TRUE, new_sensitive = TRUE;
4360         gboolean moving_folder = FALSE;
4361         gboolean is_local_account = TRUE;
4362         GtkWidget *folder_view = NULL;
4363         ModestTnyFolderRules rules;
4364
4365         g_return_if_fail (MODEST_IS_FOLDER_VIEW(self));
4366         
4367         if (!selected)
4368                 return;
4369         
4370         /* Get the OK button */
4371         dialog = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_DIALOG);
4372         if (!dialog)
4373                 return;
4374
4375         children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
4376         ok_button = GTK_WIDGET (children->next->next->data);
4377         new_button = GTK_WIDGET (children->next->data);
4378         g_list_free (children);
4379
4380         /* check if folder_store is an remote account */
4381         if (TNY_IS_ACCOUNT (folder_store)) {
4382                 TnyAccount *local_account = NULL;
4383                 TnyAccount *mmc_account = NULL;
4384                 ModestTnyAccountStore *account_store = NULL;
4385
4386                 account_store = modest_runtime_get_account_store ();
4387                 local_account = modest_tny_account_store_get_local_folders_account (account_store);
4388                 mmc_account = modest_tny_account_store_get_mmc_folders_account (account_store);
4389
4390                 if ((gpointer) local_account != (gpointer) folder_store &&
4391                     (gpointer) mmc_account != (gpointer) folder_store) {
4392                         const char *proto_name = tny_account_get_proto (TNY_ACCOUNT (folder_store));
4393                         ModestTransportStoreProtocol proto = MODEST_PROTOCOL_STORE_MAILDIR;
4394                         if (proto_name != NULL) {
4395                                 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
4396                         }
4397                         is_local_account = FALSE;
4398                         /* New button should be dimmed on remote
4399                            POP account root */
4400                         new_sensitive = (proto != MODEST_PROTOCOL_STORE_POP);
4401                 }
4402                 g_object_unref (local_account);
4403                 g_object_unref (mmc_account);
4404         }
4405
4406         /* Check the target folder rules */
4407         if (TNY_IS_FOLDER (folder_store)) {
4408                 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder_store));
4409                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
4410                         ok_sensitive = FALSE;
4411                         new_sensitive = FALSE;
4412                         goto end;
4413                 }
4414         }
4415
4416         /* Check if we're moving a folder */
4417         if (MODEST_IS_MAIN_WINDOW (user_data)) {
4418                 /* Get the widgets */
4419                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (user_data),
4420                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4421                 if (gtk_widget_is_focus (folder_view))
4422                         moving_folder = TRUE;
4423         }
4424
4425         if (moving_folder) {
4426                 TnyFolderStore *moved_folder = NULL, *parent = NULL;
4427
4428                 /* Get the folder to move */
4429                 moved_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
4430                 
4431                 /* Check that we're not moving to the same folder */
4432                 if (TNY_IS_FOLDER (moved_folder)) {
4433                         parent = tny_folder_get_folder_store (TNY_FOLDER (moved_folder));
4434                         if (parent == folder_store)
4435                                 ok_sensitive = FALSE;
4436                         g_object_unref (parent);
4437                 } 
4438
4439                 if (ok_sensitive && TNY_IS_ACCOUNT (folder_store)) {
4440                         /* Do not allow to move to an account unless it's the
4441                            local folders account */
4442                         if (!is_local_account)
4443                                 ok_sensitive = FALSE;
4444                 } 
4445
4446                 if (ok_sensitive && (moved_folder == folder_store)) {
4447                         /* Do not allow to move to itself */
4448                         ok_sensitive = FALSE;
4449                 }
4450                 g_object_unref (moved_folder);
4451         } else {
4452                 TnyFolder *src_folder = NULL;
4453
4454                 /* Moving a message */
4455                 if (MODEST_IS_MSG_VIEW_WINDOW (user_data)) {
4456
4457                         TnyHeader *header = NULL;
4458                         header = modest_msg_view_window_get_header
4459                                 (MODEST_MSG_VIEW_WINDOW (user_data));
4460                         if (!TNY_IS_HEADER(header))
4461                                 g_warning ("%s: could not get source header", __FUNCTION__);
4462                         else
4463                                 src_folder = tny_header_get_folder (header);
4464
4465                         if (header)
4466                                 g_object_unref (header);
4467                 } else {
4468                         src_folder = 
4469                                 TNY_FOLDER (modest_folder_view_get_selected
4470                                             (MODEST_FOLDER_VIEW (folder_view)));
4471                 }
4472
4473                 if (TNY_IS_FOLDER(src_folder)) {
4474                         /* Do not allow to move the msg to the same folder */
4475                         /* Do not allow to move the msg to an account */
4476                         if ((gpointer) src_folder == (gpointer) folder_store ||
4477                             TNY_IS_ACCOUNT (folder_store))
4478                                 ok_sensitive = FALSE;
4479                         g_object_unref (src_folder);
4480                 } else
4481                         g_warning ("%s: could not get source folder", __FUNCTION__);
4482         }
4483
4484  end:
4485         /* Set sensitivity of the OK button */
4486         gtk_widget_set_sensitive (ok_button, ok_sensitive);
4487         /* Set sensitivity of the NEW button */
4488         gtk_widget_set_sensitive (new_button, new_sensitive);
4489 }
4490
4491
4492 #define MODEST_MOVE_TO_DIALOG_FOLDER_VIEW "move-to-dialog-folder-view"
4493
4494 static GtkWidget*
4495 get_folder_view_from_move_to_dialog (GtkWidget *move_to_dialog)
4496 {
4497         return GTK_WIDGET(g_object_get_data (G_OBJECT(move_to_dialog),
4498                                              MODEST_MOVE_TO_DIALOG_FOLDER_VIEW));
4499 }
4500
4501 static GtkWidget*
4502 create_move_to_dialog (GtkWindow *win,
4503                        GtkWidget *folder_view,
4504                        GtkWidget **tree_view)
4505 {
4506         GtkWidget *dialog, *scroll;
4507         GtkWidget *new_button;
4508
4509         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
4510                                               GTK_WINDOW (win),
4511                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
4512                                               NULL);
4513
4514         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
4515         /* We do this manually so GTK+ does not associate a response ID for
4516          * the button. */
4517         new_button = gtk_button_new_from_stock (_("mcen_bd_new"));
4518         gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area), new_button, FALSE, FALSE, 0);
4519         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_dialog_cancel"), GTK_RESPONSE_REJECT);
4520
4521         /* Create scrolled window */
4522         scroll = gtk_scrolled_window_new (NULL, NULL);
4523         gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW (scroll),
4524                                          GTK_POLICY_AUTOMATIC,
4525                                          GTK_POLICY_AUTOMATIC);
4526
4527         /* Create folder view */
4528         *tree_view = modest_platform_create_folder_view (NULL);
4529
4530         /* Track changes in the selection to
4531          * disable the OK button whenever "Move to" is not possible
4532          * disbale NEW button whenever New is not possible */
4533         g_signal_connect (*tree_view,
4534                           "folder_selection_changed",
4535                           G_CALLBACK (on_move_to_dialog_folder_selection_changed),
4536                           win);
4537
4538         /* Listen to clicks on New button */
4539         g_signal_connect (G_OBJECT (new_button), 
4540                           "clicked", 
4541                           G_CALLBACK(create_move_to_dialog_on_new_folder), 
4542                           *tree_view);
4543
4544         /* It could happen that we're trying to move a message from a
4545            window (msg window for example) after the main window was
4546            closed, so we can not just get the model of the folder
4547            view */
4548         if (MODEST_IS_FOLDER_VIEW (folder_view)) {
4549                 const gchar *visible_id = NULL;
4550
4551                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (*tree_view),
4552                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4553                 modest_folder_view_copy_model (MODEST_FOLDER_VIEW(folder_view), 
4554                                                MODEST_FOLDER_VIEW(*tree_view));
4555
4556                 visible_id = 
4557                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view));
4558
4559                 /* Show the same account than the one that is shown in the main window */
4560                 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(*tree_view), 
4561                                                                              visible_id);
4562         } else {
4563                 const gchar *active_account_name = NULL;
4564                 ModestAccountMgr *mgr = NULL;
4565                 ModestAccountSettings *settings = NULL;
4566                 ModestServerAccountSettings *store_settings = NULL;
4567
4568                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (*tree_view),
4569                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4570                 modest_folder_view_update_model (MODEST_FOLDER_VIEW (*tree_view), 
4571                                                  TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
4572
4573                 active_account_name = modest_window_get_active_account (MODEST_WINDOW (win));
4574                 mgr = modest_runtime_get_account_mgr ();
4575                 settings = modest_account_mgr_load_account_settings (mgr, active_account_name);
4576
4577                 if (settings) {
4578                         const gchar *store_account_name;
4579                         store_settings = modest_account_settings_get_store_settings (settings);
4580                         store_account_name = modest_server_account_settings_get_account_name (store_settings);
4581
4582                         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (*tree_view),
4583                                                                                      store_account_name);
4584                         g_object_unref (store_settings);
4585                         g_object_unref (settings);
4586                 }
4587         }
4588
4589         /* we keep a pointer to the embedded folder view, so we can retrieve it with
4590          *   get_folder_view_from_move_to_dialog 
4591          * (see above) later (needed for focus handling) 
4592          */
4593         g_object_set_data (G_OBJECT(dialog), MODEST_MOVE_TO_DIALOG_FOLDER_VIEW, *tree_view);
4594
4595         
4596         /* Hide special folders */
4597         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (*tree_view), FALSE);
4598
4599         gtk_container_add (GTK_CONTAINER (scroll), *tree_view);
4600
4601         /* Add scroll to dialog */
4602         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), 
4603                             scroll, TRUE, TRUE, 0);
4604
4605         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
4606         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
4607
4608         return dialog;
4609 }
4610
4611
4612
4613 /*
4614  * Shows a confirmation dialog to the user when we're moving messages
4615  * from a remote server to the local storage. Returns the dialog
4616  * response. If it's other kind of movement then it always returns
4617  * GTK_RESPONSE_OK
4618  *
4619  * This one is used by the next functions:
4620  *      modest_ui_actions_on_paste                      - commented out
4621  *      drag_and_drop_from_header_view (for d&d in modest_folder_view.c)
4622  */
4623 gint
4624 modest_ui_actions_msgs_move_to_confirmation (ModestWindow *win,
4625                                              TnyFolder *dest_folder,
4626                                              gboolean delete,
4627                                              TnyList *headers)
4628 {
4629         gint response = GTK_RESPONSE_OK;
4630         TnyAccount *account = NULL;
4631         TnyFolder *src_folder = NULL;
4632         TnyIterator *iter = NULL;
4633         TnyHeader *header = NULL;
4634
4635         /* return with OK if the destination is a remote folder */
4636         if (modest_tny_folder_is_remote_folder (dest_folder))
4637                 return GTK_RESPONSE_OK;
4638
4639         /* Get source folder */
4640         iter = tny_list_create_iterator (headers);
4641         header = TNY_HEADER (tny_iterator_get_current (iter));
4642         if (header) {
4643                 src_folder = tny_header_get_folder (header);
4644                 g_object_unref (header);
4645         }
4646         g_object_unref (iter);
4647
4648         /* if no src_folder, message may be an attahcment */
4649         if (src_folder == NULL) 
4650                 return GTK_RESPONSE_CANCEL;
4651
4652         /* If the source is a local or MMC folder */
4653         if (!modest_tny_folder_is_remote_folder (src_folder)) {
4654                 g_object_unref (src_folder);
4655                 return GTK_RESPONSE_OK;
4656         }
4657
4658         /* Get the account */
4659         account = tny_folder_get_account (src_folder);
4660
4661         /* now if offline we ask the user */
4662         if(connect_to_get_msg (win, tny_list_get_length (headers), account))
4663                 response = GTK_RESPONSE_OK;
4664         else
4665                 response = GTK_RESPONSE_CANCEL;
4666
4667         /* Frees */
4668         g_object_unref (src_folder);
4669         g_object_unref (account);
4670
4671         return response;
4672 }
4673
4674 static void
4675 move_to_cb (ModestMailOperation *mail_op, 
4676             gpointer user_data)
4677 {
4678         MoveToHelper *helper = (MoveToHelper *) user_data;
4679
4680         /* Note that the operation could have failed, in that case do
4681            nothing */
4682         if (modest_mail_operation_get_status (mail_op) == 
4683             MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
4684
4685                 GObject *object = modest_mail_operation_get_source (mail_op);
4686                 if (MODEST_IS_MSG_VIEW_WINDOW (object)) {
4687                         ModestMsgViewWindow *self = MODEST_MSG_VIEW_WINDOW (object);
4688
4689                         if (!modest_msg_view_window_select_next_message (self) &&
4690                             !modest_msg_view_window_select_previous_message (self)) {
4691                                 /* No more messages to view, so close this window */
4692                                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW(self));
4693                         }
4694                 } else if (MODEST_IS_MAIN_WINDOW (object) && helper->reference != NULL) {
4695                         GtkWidget *header_view;
4696                         GtkTreePath *path;
4697                         GtkTreeSelection *sel;
4698
4699                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(object),
4700                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4701                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
4702                         path = gtk_tree_row_reference_get_path (helper->reference);
4703                         /* We need to unselect the previous one
4704                            because we could be copying instead of
4705                            moving */
4706                         gtk_tree_selection_unselect_all (sel);
4707                         gtk_tree_selection_select_path (sel, path);
4708                         gtk_tree_path_free (path);
4709                 }
4710                 g_object_unref (object);
4711         }
4712
4713         /* Close the "Pasting" information banner */
4714         if (helper->banner) {
4715                 gtk_widget_destroy (GTK_WIDGET(helper->banner));
4716                 g_object_unref (helper->banner);
4717         }
4718         if (helper->reference != NULL)
4719                 gtk_tree_row_reference_free (helper->reference);
4720         g_free (helper);
4721 }
4722
4723 static void
4724 folder_move_to_cb (ModestMailOperation *mail_op, 
4725                    TnyFolder *new_folder,
4726                    gpointer user_data)
4727 {
4728         GtkWidget *folder_view;
4729         GObject *object;
4730
4731         object = modest_mail_operation_get_source (mail_op);
4732         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(object),
4733                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4734         g_object_ref (folder_view);
4735         g_object_unref (object);
4736         move_to_cb (mail_op, user_data);
4737         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), new_folder, FALSE);
4738         g_object_unref (folder_view);
4739 }
4740
4741 static void
4742 msgs_move_to_cb (ModestMailOperation *mail_op, 
4743                  gpointer user_data)
4744 {
4745         move_to_cb (mail_op, user_data);
4746 }
4747
4748 void
4749 modest_ui_actions_move_folder_error_handler (ModestMailOperation *mail_op, 
4750                                              gpointer user_data)
4751 {
4752         ModestWindow *main_window = NULL;
4753         
4754         /* Disable next automatic folder selection */
4755         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
4756                                                          FALSE); /* don't create */
4757         if (main_window) {
4758                 GObject *win = NULL;
4759                 GtkWidget *folder_view = NULL;
4760         
4761                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (main_window),
4762                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW); 
4763                 modest_folder_view_disable_next_folder_selection (MODEST_FOLDER_VIEW(folder_view));
4764                 
4765                 if (user_data && TNY_IS_FOLDER (user_data)) {
4766                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), 
4767                                                           TNY_FOLDER (user_data), FALSE);
4768                 }
4769
4770                 /* Show notification dialog only if the main window exists */
4771                 win = modest_mail_operation_get_source (mail_op);
4772                 modest_platform_run_information_dialog ((GtkWindow *) win, 
4773                                                         _("mail_in_ui_folder_move_target_error"), 
4774                                                         FALSE);
4775                 if (win)
4776                         g_object_unref (win);
4777         }
4778 }
4779
4780 static void
4781 open_msg_for_purge_cb (ModestMailOperation *mail_op, 
4782                        TnyHeader *header, 
4783                        gboolean canceled,
4784                        TnyMsg *msg, 
4785                        GError *err,
4786                        gpointer user_data)
4787 {
4788         TnyList *parts;
4789         TnyIterator *iter;
4790         gint pending_purges = 0;
4791         gboolean some_purged = FALSE;
4792         ModestWindow *win = MODEST_WINDOW (user_data);
4793         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
4794
4795         /* If there was any error */
4796         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
4797                 modest_window_mgr_unregister_header (mgr, header);
4798                 return;
4799         }
4800
4801         /* Once the message has been retrieved for purging, we check if
4802          * it's all ok for purging */
4803
4804         parts = tny_simple_list_new ();
4805         tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
4806         iter = tny_list_create_iterator (parts);
4807
4808         while (!tny_iterator_is_done (iter)) {
4809                 TnyMimePart *part;
4810                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
4811                 if (part && (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part))) {
4812                         if (tny_mime_part_is_purged (part))
4813                                 some_purged = TRUE;
4814                         else
4815                                 pending_purges++;
4816                 }
4817
4818                 if (part)
4819                         g_object_unref (part);
4820
4821                 tny_iterator_next (iter);
4822         }
4823         g_object_unref (iter);
4824         
4825
4826         if (pending_purges>0) {
4827                 gint response;
4828                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),_("mcen_nc_purge_file_text_inbox"));
4829
4830                 if (response == GTK_RESPONSE_OK) {
4831                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_removing_attachment"));
4832                         iter = tny_list_create_iterator (parts);
4833                         while (!tny_iterator_is_done (iter)) {
4834                                 TnyMimePart *part;
4835                                 
4836                                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
4837                                 if (part && (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part)))
4838                                         tny_mime_part_set_purged (part);
4839
4840                                 if (part)
4841                                         g_object_unref (part);
4842
4843                                 tny_iterator_next (iter);
4844                         }
4845                         g_object_unref (iter);
4846                         
4847                         tny_msg_rewrite_cache (msg);
4848                 }
4849      /* } else { */
4850                 /* This string no longer exists, refer to NB#75415 for more info */
4851                 /* modest_platform_information_banner (NULL, NULL, _("mail_ib_attachment_already_purged")); */
4852         }
4853
4854         modest_window_mgr_unregister_header (mgr, header);
4855
4856         g_object_unref (parts);
4857 }
4858
4859 static void
4860 modest_ui_actions_on_main_window_remove_attachments (GtkAction *action,
4861                                                      ModestMainWindow *win)
4862 {
4863         GtkWidget *header_view;
4864         TnyList *header_list;
4865         TnyHeader *header;
4866         TnyHeaderFlags flags;
4867         ModestWindow *msg_view_window =  NULL;
4868         gboolean found;
4869
4870         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
4871
4872         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4873                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4874
4875         header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
4876         if (!header_list) {
4877                 g_warning ("%s: no header selected", __FUNCTION__);
4878                 return;
4879         }
4880         
4881         if (tny_list_get_length (header_list) == 1) {
4882                 TnyIterator *iter = tny_list_create_iterator (header_list);
4883                 header = TNY_HEADER (tny_iterator_get_current (iter));
4884                 g_object_unref (iter);
4885         } else
4886                 return;
4887         
4888         if (!header || !TNY_IS_HEADER(header)) {
4889                 g_warning ("%s: header is not valid", __FUNCTION__);
4890                 return;
4891         }
4892         
4893         found = modest_window_mgr_find_registered_header (modest_runtime_get_window_mgr (),
4894                                                           header, &msg_view_window);
4895         flags = tny_header_get_flags (header);
4896         if (!(flags & TNY_HEADER_FLAG_CACHED))
4897                 return;
4898         if (found) {
4899                 if (msg_view_window != NULL) 
4900                         modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (msg_view_window), TRUE);
4901                 else {
4902                         /* do nothing; uid was registered before, so window is probably on it's way */
4903                         g_warning ("debug: header %p has already been registered", header);
4904                 }
4905         } else {
4906                 ModestMailOperation *mail_op = NULL;
4907                 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), header, NULL);
4908                 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (win),
4909                                                                          modest_ui_actions_disk_operations_error_handler,
4910                                                                          NULL, NULL);
4911                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
4912                 modest_mail_operation_get_msg (mail_op, header, FALSE, open_msg_for_purge_cb, win);
4913                 
4914                 g_object_unref (mail_op);
4915         }
4916         if (header)
4917                 g_object_unref (header);
4918         if (header_list)
4919                 g_object_unref (header_list);
4920 }
4921
4922 /*
4923  * Checks if we need a connection to do the transfer and if the user
4924  * wants to connect to complete it
4925  */
4926 void
4927 modest_ui_actions_xfer_messages_check (GtkWindow *parent_window,
4928                                        TnyFolderStore *src_folder,
4929                                        TnyList *headers,
4930                                        TnyFolder *dst_folder,
4931                                        gboolean delete_originals,
4932                                        gboolean *need_connection,
4933                                        gboolean *do_xfer)
4934 {
4935         TnyAccount *src_account;
4936         gint uncached_msgs = 0;
4937
4938         uncached_msgs = header_list_count_uncached_msgs (headers);
4939
4940         /* We don't need any further check if
4941          *
4942          * 1- the source folder is local OR
4943          * 2- the device is already online
4944          */
4945         if (!modest_tny_folder_store_is_remote (src_folder) ||
4946             tny_device_is_online (modest_runtime_get_device())) {
4947                 *need_connection = FALSE;
4948                 *do_xfer = TRUE;
4949                 return;
4950         }
4951
4952         /* We must ask for a connection when
4953          *
4954          *   - the message(s) is not already cached   OR 
4955          *   - the message(s) is cached but the leave_on_server setting
4956          * is FALSE (because we need to sync the source folder to
4957          * delete the message from the server (for IMAP we could do it
4958          * offline, it'll take place the next time we get a
4959          * connection)
4960          */
4961         src_account = get_account_from_folder_store (src_folder);
4962         if (uncached_msgs > 0) {
4963                 guint num_headers;
4964                 const gchar *msg;
4965
4966                 *need_connection = TRUE;
4967                 num_headers = tny_list_get_length (headers);
4968                 msg = ngettext ("mcen_nc_get_msg", "mcen_nc_get_msgs", num_headers);
4969
4970                 if (modest_platform_run_confirmation_dialog (parent_window, msg) ==
4971                     GTK_RESPONSE_CANCEL) {
4972                         *do_xfer = FALSE;
4973                 } else {
4974                         *do_xfer = TRUE;
4975                 }
4976         } else {
4977                 /* The transfer is possible and the user wants to */
4978                 *do_xfer = TRUE;
4979
4980                 if (remote_folder_is_pop (src_folder) && delete_originals) {
4981                         const gchar *account_name;
4982                         gboolean leave_on_server;
4983                         
4984                         account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (src_account);
4985                         leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
4986                                                                                   account_name);
4987                         
4988                         if (leave_on_server == TRUE) {
4989                                 *need_connection = FALSE;
4990                         } else {
4991                                 *need_connection = TRUE;
4992                         }
4993                 } else {
4994                         *need_connection = FALSE;
4995                 }
4996         }
4997
4998         /* Frees */
4999         g_object_unref (src_account);
5000 }
5001
5002 static void
5003 xfer_messages_error_handler (ModestMailOperation *mail_op, 
5004                              gpointer user_data)
5005 {
5006         ModestWindow *main_window = NULL;
5007         
5008         /* Disable next automatic folder selection */
5009         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
5010                                                          FALSE); /* don't create */
5011         if (main_window) {
5012                 GObject *win = modest_mail_operation_get_source (mail_op);
5013                 modest_platform_run_information_dialog ((GtkWindow *) win, 
5014                                                         _("mail_in_ui_folder_move_target_error"), 
5015                                                         FALSE);
5016                 if (win)
5017                         g_object_unref (win);
5018         }
5019 }
5020
5021 /**
5022  * Utility function that transfer messages from both the main window
5023  * and the msg view window when using the "Move to" dialog
5024  */
5025 static void
5026 xfer_messages_performer  (gboolean canceled, 
5027                           GError *err,
5028                           GtkWindow *parent_window, 
5029                           TnyAccount *account, 
5030                           gpointer user_data)
5031 {
5032         TnyFolderStore *dst_folder = TNY_FOLDER_STORE (user_data);
5033         ModestWindow *win = MODEST_WINDOW (parent_window);
5034         TnyList *headers = NULL;
5035         TnyAccount *dst_account = NULL;
5036         const gchar *proto_str = NULL;
5037         gboolean dst_is_pop = FALSE;
5038
5039         if (canceled)
5040                 goto end;
5041
5042         if (err) {
5043                 if (is_memory_full_error (err)) {
5044                         modest_platform_information_banner ((GtkWidget *) parent_window,
5045                                                             NULL, dgettext("ke-recv",
5046                                                                            "cerm_device_memory_full"));
5047                 } else {
5048                         /* Show the proper error message */
5049                         modest_ui_actions_on_account_connection_error (parent_window, account);
5050                 }
5051                 goto end;
5052         }
5053
5054         dst_account = tny_folder_get_account (TNY_FOLDER (dst_folder));
5055         proto_str = tny_account_get_proto (dst_account);
5056
5057         /* tinymail will return NULL for local folders it seems */
5058         dst_is_pop = proto_str &&
5059                 (modest_protocol_info_get_transport_store_protocol (proto_str) == 
5060                  MODEST_PROTOCOL_STORE_POP);
5061
5062         g_object_unref (dst_account);
5063
5064         /* Get selected headers */
5065         headers = get_selected_headers (MODEST_WINDOW (win));
5066         if (!headers) {
5067                 g_warning ("%s: no headers selected", __FUNCTION__);
5068                 goto end;
5069         }
5070
5071         if (dst_is_pop) {
5072                 modest_platform_information_banner (GTK_WIDGET (win),
5073                                                     NULL,
5074                                                     ngettext("mail_in_ui_folder_move_target_error",
5075                                                              "mail_in_ui_folder_move_targets_error",
5076                                                              tny_list_get_length (headers)));
5077                 g_object_unref (headers);
5078                 goto end;
5079         }
5080
5081         MoveToHelper *helper = g_new0 (MoveToHelper, 1);
5082         helper->banner = modest_platform_animation_banner (GTK_WIDGET (win), NULL,
5083                                                            _CS("ckct_nw_pasting"));
5084         if (helper->banner != NULL)  {
5085                 g_object_ref (helper->banner);
5086                 gtk_widget_show (GTK_WIDGET(helper->banner));
5087         }
5088
5089         if (MODEST_IS_MAIN_WINDOW (win)) {
5090                 GtkWidget *header_view = 
5091                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
5092                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5093                 helper->reference = get_next_after_selected_headers (MODEST_HEADER_VIEW (header_view));
5094         }
5095
5096         ModestMailOperation *mail_op = 
5097                 modest_mail_operation_new_with_error_handling (G_OBJECT(win),
5098                                                                xfer_messages_error_handler,
5099                                                                NULL, NULL);
5100         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
5101                                          mail_op);
5102
5103         modest_mail_operation_xfer_msgs (mail_op, 
5104                                          headers,
5105                                          TNY_FOLDER (dst_folder),
5106                                          TRUE,
5107                                          msgs_move_to_cb,
5108                                          helper);
5109
5110         g_object_unref (G_OBJECT (mail_op));
5111         g_object_unref (headers);
5112  end:
5113         g_object_unref (dst_folder);
5114 }
5115
5116 typedef struct {
5117         TnyFolder *src_folder;
5118         TnyFolderStore *dst_folder;
5119         gboolean delete_original;
5120         GtkWidget *folder_view;
5121 } MoveFolderInfo;
5122
5123 static void
5124 on_move_folder_cb (gboolean canceled, GError *err, GtkWindow *parent_window, 
5125                 TnyAccount *account, gpointer user_data)
5126 {
5127         MoveFolderInfo *info = (MoveFolderInfo*)user_data;
5128         GtkTreeSelection *sel;
5129         ModestMailOperation *mail_op = NULL;
5130         
5131         if (canceled || err || !MODEST_IS_MAIN_WINDOW (parent_window)) {
5132                 g_object_unref (G_OBJECT (info->src_folder));
5133                 g_object_unref (G_OBJECT (info->dst_folder));
5134                 g_free (info);
5135                 return;
5136         }
5137         
5138         MoveToHelper *helper = g_new0 (MoveToHelper, 1);
5139         helper->banner = modest_platform_animation_banner (GTK_WIDGET (parent_window), NULL,
5140                         _CS("ckct_nw_pasting"));
5141         if (helper->banner != NULL)  {
5142                 g_object_ref (helper->banner);
5143                 gtk_widget_show (GTK_WIDGET(helper->banner));
5144         }
5145         /* Clean folder on header view before moving it */
5146         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (info->folder_view));
5147         gtk_tree_selection_unselect_all (sel);
5148
5149         /* Let gtk events run. We need that the folder
5150            view frees its reference to the source
5151            folder *before* issuing the mail operation
5152            so we need the signal handler of selection
5153            changed to happen before the mail
5154            operation 
5155         while (gtk_events_pending ())
5156                 gtk_main_iteration ();   */
5157
5158         mail_op =
5159                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
5160                                 modest_ui_actions_move_folder_error_handler,
5161                                 info->src_folder, NULL);
5162         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
5163                         mail_op);
5164
5165         /* Select *after* the changes */
5166         /* TODO: this function hangs UI after transfer */ 
5167         /*                      modest_folder_view_select_folder (MODEST_FOLDER_VIEW(folder_view), */
5168         /*                                                        TNY_FOLDER (src_folder), TRUE); */
5169
5170         modest_folder_view_select_folder (MODEST_FOLDER_VIEW(info->folder_view),
5171                                           TNY_FOLDER (info->dst_folder), TRUE);
5172         modest_mail_operation_xfer_folder (mail_op,
5173                         TNY_FOLDER (info->src_folder),
5174                         info->dst_folder,
5175                         info->delete_original, 
5176                         folder_move_to_cb, 
5177                         helper);
5178         g_object_unref (G_OBJECT (info->src_folder));
5179
5180         /* if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {        */
5181         /* } */
5182         
5183         /* Unref mail operation */
5184         g_object_unref (G_OBJECT (mail_op));
5185         g_object_unref (G_OBJECT (info->dst_folder));
5186         g_free (user_data);
5187 }
5188
5189 static TnyAccount *
5190 get_account_from_folder_store (TnyFolderStore *folder_store) 
5191 {
5192         if (TNY_IS_ACCOUNT (folder_store))
5193                 return g_object_ref (folder_store);
5194         else
5195                 return tny_folder_get_account (TNY_FOLDER (folder_store));
5196 }
5197
5198 /*
5199  * UI handler for the "Move to" action when invoked from the
5200  * ModestMainWindow
5201  */
5202 static void 
5203 modest_ui_actions_on_main_window_move_to (GtkAction *action, 
5204                                           GtkWidget *folder_view,
5205                                           TnyFolderStore *dst_folder,
5206                                           ModestMainWindow *win)
5207 {
5208         ModestHeaderView *header_view = NULL;
5209         TnyFolderStore *src_folder = NULL;
5210
5211         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
5212
5213         /* Get the source folder */
5214         src_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5215
5216         /* Get header view */
5217         header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
5218
5219         /* Get folder or messages to transfer */
5220         if (gtk_widget_is_focus (folder_view)) {
5221                 gboolean do_xfer = TRUE;
5222
5223                 /* Allow only to transfer folders to the local root folder */
5224                 if (TNY_IS_ACCOUNT (dst_folder) && 
5225                     !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (dst_folder) &&
5226                     !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (dst_folder))) {
5227                         do_xfer = FALSE;
5228                 } else if (!TNY_IS_FOLDER (src_folder)) {
5229                         g_warning ("%s: src_folder is not a TnyFolder.\n", __FUNCTION__);
5230                         do_xfer = FALSE;
5231                 }
5232
5233                 if (do_xfer) {                  
5234                         MoveFolderInfo *info = g_new0 (MoveFolderInfo, 1);
5235                         DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5236
5237                         info->src_folder = g_object_ref (src_folder);
5238                         info->dst_folder = g_object_ref (dst_folder);
5239                         info->delete_original = TRUE;
5240                         info->folder_view = folder_view;
5241
5242                         connect_info->callback = on_move_folder_cb;
5243                         connect_info->dst_account = get_account_from_folder_store (TNY_FOLDER_STORE (dst_folder));
5244                         connect_info->data = info;
5245
5246                         modest_platform_double_connect_and_perform(GTK_WINDOW (win), TRUE,
5247                                                                    TNY_FOLDER_STORE (src_folder), 
5248                                                                    connect_info);
5249                 }
5250         } else if (gtk_widget_is_focus (GTK_WIDGET(header_view))) {
5251                 TnyList *headers;
5252
5253                 headers = modest_header_view_get_selected_headers(header_view);
5254
5255                 /* Transfer the messages */
5256                 modest_ui_actions_transfer_messages_helper (GTK_WINDOW (win), TNY_FOLDER (src_folder), 
5257                                                             headers, TNY_FOLDER (dst_folder));
5258
5259                 g_object_unref (headers);
5260         }
5261
5262         /* Frees */
5263         g_object_unref (src_folder);
5264 }
5265
5266
5267 void
5268 modest_ui_actions_transfer_messages_helper (GtkWindow *win,
5269                                             TnyFolder *src_folder,
5270                                             TnyList *headers,
5271                                             TnyFolder *dst_folder)
5272 {
5273         gboolean need_connection = TRUE;
5274         gboolean do_xfer = TRUE;
5275         
5276         modest_ui_actions_xfer_messages_check (win, TNY_FOLDER_STORE (src_folder), 
5277                                                headers, TNY_FOLDER (dst_folder),
5278                                                TRUE, &need_connection, 
5279                                                &do_xfer);
5280
5281         /* If we don't want to transfer just return */
5282         if (!do_xfer)
5283                 return;
5284
5285         if (need_connection) {
5286                 DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5287                 connect_info->callback = xfer_messages_performer;
5288                 connect_info->dst_account = tny_folder_get_account (TNY_FOLDER (dst_folder));
5289                 connect_info->data = g_object_ref (dst_folder);
5290                 
5291                 modest_platform_double_connect_and_perform(GTK_WINDOW (win), TRUE,
5292                                                            TNY_FOLDER_STORE (src_folder), 
5293                                                            connect_info);
5294         } else {
5295                 TnyAccount *src_account = get_account_from_folder_store (TNY_FOLDER_STORE (src_folder));
5296                 xfer_messages_performer (FALSE, NULL, GTK_WINDOW (win),
5297                                          src_account, g_object_ref (dst_folder));
5298                 g_object_unref (src_account);
5299         }
5300 }
5301
5302 /*
5303  * UI handler for the "Move to" action when invoked from the
5304  * ModestMsgViewWindow
5305  */
5306 static void 
5307 modest_ui_actions_on_msg_view_window_move_to (GtkAction *action, 
5308                                               TnyFolderStore *dst_folder,
5309                                               ModestMsgViewWindow *win)
5310 {
5311         TnyList *headers = NULL;
5312         TnyHeader *header = NULL;
5313         TnyFolder *src_folder = NULL;
5314
5315         g_return_if_fail (TNY_IS_FOLDER (dst_folder));
5316
5317         /* Create header list */
5318         header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
5319         src_folder = TNY_FOLDER (tny_header_get_folder(header));
5320         headers = tny_simple_list_new ();
5321         tny_list_append (headers, G_OBJECT (header));
5322
5323         /* Transfer the messages */
5324         modest_ui_actions_transfer_messages_helper (GTK_WINDOW (win), src_folder, headers, 
5325                                                     TNY_FOLDER (dst_folder));
5326
5327         /* Frees */
5328         g_object_unref (header);
5329         g_object_unref (headers);
5330 }
5331
5332 void 
5333 modest_ui_actions_on_move_to (GtkAction *action, 
5334                               ModestWindow *win)
5335 {
5336         GtkWidget *dialog = NULL, *folder_view = NULL, *tree_view = NULL;
5337         gint result = 0;
5338         TnyFolderStore *dst_folder = NULL;
5339         ModestMainWindow *main_window;
5340
5341         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win) ||
5342                           MODEST_IS_MSG_VIEW_WINDOW (win));
5343
5344         /* Get the main window if exists */
5345         if (MODEST_IS_MAIN_WINDOW (win))
5346                 main_window = MODEST_MAIN_WINDOW (win);
5347         else
5348                 main_window = 
5349                         MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
5350                                                                                FALSE)); /* don't create */
5351
5352         /* Get the folder view widget if exists */
5353         if (main_window)
5354                 folder_view = modest_main_window_get_child_widget (main_window,
5355                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5356         else
5357                 folder_view = NULL;
5358
5359         /* Create and run the dialog */
5360         dialog = create_move_to_dialog (GTK_WINDOW (win), folder_view, &tree_view);
5361         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (tree_view));
5362         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
5363         result = gtk_dialog_run (GTK_DIALOG(dialog));
5364         g_object_ref (tree_view);
5365         gtk_widget_destroy (dialog);
5366
5367         if (result != GTK_RESPONSE_ACCEPT)
5368                 return;
5369
5370         dst_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (tree_view));
5371         /* Do window specific stuff */
5372         if (MODEST_IS_MAIN_WINDOW (win)) {
5373                 modest_ui_actions_on_main_window_move_to (action,
5374                                 folder_view,
5375                                 dst_folder,
5376                                 MODEST_MAIN_WINDOW (win));
5377         } else {
5378                 modest_ui_actions_on_msg_view_window_move_to (action,
5379                                 dst_folder,
5380                                 MODEST_MSG_VIEW_WINDOW (win));
5381         }
5382
5383         if (dst_folder)
5384                 g_object_unref (dst_folder);
5385 }
5386
5387 /*
5388  * Calls #HeadersFunc for each header already selected in the main
5389  * window or the message currently being shown in the msg view window
5390  */
5391 static void
5392 do_headers_action (ModestWindow *win, 
5393                    HeadersFunc func,
5394                    gpointer user_data)
5395 {
5396         TnyList *headers_list = NULL;
5397         TnyIterator *iter = NULL;
5398         TnyHeader *header = NULL;
5399         TnyFolder *folder = NULL;
5400
5401         /* Get headers */
5402         headers_list = get_selected_headers (win);
5403         if (!headers_list)
5404                 return;
5405
5406         /* Get the folder */
5407         iter = tny_list_create_iterator (headers_list);
5408         header = TNY_HEADER (tny_iterator_get_current (iter));
5409         if (header) {
5410                 folder = tny_header_get_folder (header);
5411                 g_object_unref (header);
5412         }
5413
5414         /* Call the function for each header */
5415         while (!tny_iterator_is_done (iter)) {
5416                 header = TNY_HEADER (tny_iterator_get_current (iter));
5417                 func (header, win, user_data);
5418                 g_object_unref (header);
5419                 tny_iterator_next (iter);
5420         }
5421
5422         /* Trick: do a poke status in order to speed up the signaling
5423            of observers */
5424         tny_folder_poke_status (folder);
5425
5426         /* Frees */
5427         g_object_unref (folder);
5428         g_object_unref (iter);
5429         g_object_unref (headers_list);
5430 }
5431
5432 void 
5433 modest_ui_actions_view_attachment (GtkAction *action,
5434                                    ModestWindow *window)
5435 {
5436         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5437                 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (window), NULL);
5438         } else {
5439                 /* not supported window for this action */
5440                 g_return_if_reached ();
5441         }
5442 }
5443
5444 void
5445 modest_ui_actions_save_attachments (GtkAction *action,
5446                                     ModestWindow *window)
5447 {
5448         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5449
5450                 if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
5451                         return;
5452
5453                 modest_msg_view_window_save_attachments (MODEST_MSG_VIEW_WINDOW (window), NULL);
5454         } else {
5455                 /* not supported window for this action */
5456                 g_return_if_reached ();
5457         }
5458 }
5459
5460 void
5461 modest_ui_actions_remove_attachments (GtkAction *action,
5462                                       ModestWindow *window)
5463 {
5464         if (MODEST_IS_MAIN_WINDOW (window)) {
5465                 modest_ui_actions_on_main_window_remove_attachments (action, MODEST_MAIN_WINDOW (window));
5466         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5467                 modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (window), FALSE);
5468         } else {
5469                 /* not supported window for this action */
5470                 g_return_if_reached ();
5471         }
5472 }
5473
5474 void 
5475 modest_ui_actions_on_settings (GtkAction *action, 
5476                                ModestWindow *win)
5477 {
5478         GtkWidget *dialog;
5479
5480         dialog = modest_platform_get_global_settings_dialog ();
5481         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (win));
5482         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
5483         gtk_widget_show_all (dialog);
5484
5485         gtk_dialog_run (GTK_DIALOG (dialog));
5486
5487         gtk_widget_destroy (dialog);
5488 }
5489
5490 void 
5491 modest_ui_actions_on_help (GtkAction *action, 
5492                            GtkWindow *win)
5493 {
5494         const gchar *help_id;
5495
5496         g_return_if_fail (action);
5497         g_return_if_fail (win && GTK_IS_WINDOW(win));
5498         
5499         help_id = modest_window_mgr_get_help_id (modest_runtime_get_window_mgr(), win);
5500         
5501         if (help_id)
5502                 modest_platform_show_help (GTK_WINDOW (win), help_id);
5503         else
5504                 g_warning ("%s: no help for window %p", __FUNCTION__, win);
5505 }
5506
5507 static void
5508 retrieve_msg_contents_performer (gboolean canceled, 
5509                                  GError *err,
5510                                  GtkWindow *parent_window, 
5511                                  TnyAccount *account, 
5512                                  gpointer user_data)
5513 {
5514         ModestMailOperation *mail_op;
5515         TnyList *headers = TNY_LIST (user_data);
5516
5517         if (err || canceled) {
5518                 if (err && is_memory_full_error (err)) {
5519                         modest_platform_information_banner ((GtkWidget *) parent_window,
5520                                                             NULL, dgettext("ke-recv",
5521                                                                            "cerm_device_memory_full"));
5522                 }
5523                 goto out;
5524         }
5525
5526         /* Create mail operation */
5527         mail_op = modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
5528                                                                  modest_ui_actions_disk_operations_error_handler, 
5529                                                                  NULL, NULL);
5530         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
5531         modest_mail_operation_get_msgs_full (mail_op, headers, NULL, NULL, NULL);
5532
5533         /* Frees */
5534         g_object_unref (mail_op);
5535  out:
5536         g_object_unref (headers);
5537         g_object_unref (account);
5538 }
5539
5540 void 
5541 modest_ui_actions_on_retrieve_msg_contents (GtkAction *action,
5542                                             ModestWindow *window)
5543 {
5544         TnyList *headers = NULL;
5545         TnyAccount *account = NULL;
5546         TnyIterator *iter = NULL;
5547         TnyHeader *header = NULL;
5548         TnyFolder *folder = NULL;
5549
5550         /* Get headers */
5551         headers = get_selected_headers (window);
5552         if (!headers)
5553                 return;
5554
5555         /* Pick the account */
5556         iter = tny_list_create_iterator (headers);
5557         header = TNY_HEADER (tny_iterator_get_current (iter));
5558         folder = tny_header_get_folder (header);
5559         account = tny_folder_get_account (folder);
5560         g_object_unref (folder);
5561         g_object_unref (header);
5562         g_object_unref (iter);
5563
5564         /* Connect and perform the message retrieval */
5565         modest_platform_connect_and_perform ((GtkWindow *) window, TRUE,
5566                                              g_object_ref (account), 
5567                                              retrieve_msg_contents_performer, 
5568                                              g_object_ref (headers));
5569
5570         /* Frees */
5571         g_object_unref (account);
5572         g_object_unref (headers);
5573 }
5574
5575 void
5576 modest_ui_actions_check_toolbar_dimming_rules (ModestWindow *window)
5577 {
5578         g_return_if_fail (MODEST_IS_WINDOW (window));
5579
5580         /* Update dimmed */
5581         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_TOOLBAR);
5582 }
5583
5584 void
5585 modest_ui_actions_check_menu_dimming_rules (ModestWindow *window)
5586 {
5587         g_return_if_fail (MODEST_IS_WINDOW (window));
5588
5589         /* Update dimmed */
5590         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_MENU);
5591 }
5592
5593 void
5594 modest_ui_actions_on_email_menu_activated (GtkAction *action,
5595                                           ModestWindow *window)
5596 {
5597         g_return_if_fail (MODEST_IS_WINDOW (window));
5598         
5599         /* Update dimmed */
5600         modest_ui_actions_check_menu_dimming_rules (window);
5601 }
5602
5603 void
5604 modest_ui_actions_on_edit_menu_activated (GtkAction *action,
5605                                           ModestWindow *window)
5606 {
5607         g_return_if_fail (MODEST_IS_WINDOW (window));
5608
5609         /* Update dimmed */
5610         modest_ui_actions_check_menu_dimming_rules (window);
5611 }
5612
5613 void
5614 modest_ui_actions_on_view_menu_activated (GtkAction *action,
5615                                           ModestWindow *window)
5616 {
5617         g_return_if_fail (MODEST_IS_WINDOW (window));
5618
5619         /* Update dimmed */
5620         modest_ui_actions_check_menu_dimming_rules (window);
5621 }
5622
5623 void
5624 modest_ui_actions_on_format_menu_activated (GtkAction *action,
5625                                             ModestWindow *window)
5626 {
5627         g_return_if_fail (MODEST_IS_WINDOW (window));
5628
5629         /* Update dimmed */
5630         modest_ui_actions_check_menu_dimming_rules (window);
5631 }
5632
5633 void
5634 modest_ui_actions_on_tools_menu_activated (GtkAction *action,
5635                                           ModestWindow *window)
5636 {
5637         g_return_if_fail (MODEST_IS_WINDOW (window));
5638
5639         /* Update dimmed */
5640         modest_ui_actions_check_menu_dimming_rules (window);
5641 }
5642
5643 void
5644 modest_ui_actions_on_attachment_menu_activated (GtkAction *action,
5645                                           ModestWindow *window)
5646 {
5647         g_return_if_fail (MODEST_IS_WINDOW (window));
5648
5649         /* Update dimmed */
5650         modest_ui_actions_check_menu_dimming_rules (window);
5651 }
5652
5653 void
5654 modest_ui_actions_on_toolbar_csm_menu_activated (GtkAction *action,
5655                                                  ModestWindow *window)
5656 {
5657         g_return_if_fail (MODEST_IS_WINDOW (window));
5658
5659         /* Update dimmed */
5660         modest_ui_actions_check_menu_dimming_rules (window);
5661 }
5662
5663 void
5664 modest_ui_actions_on_folder_view_csm_menu_activated (GtkAction *action,
5665                                                      ModestWindow *window)
5666 {
5667         g_return_if_fail (MODEST_IS_WINDOW (window));
5668
5669         /* Update dimmed */
5670         modest_ui_actions_check_menu_dimming_rules (window);
5671 }
5672
5673 void
5674 modest_ui_actions_on_header_view_csm_menu_activated (GtkAction *action,
5675                                                      ModestWindow *window)
5676 {
5677         g_return_if_fail (MODEST_IS_WINDOW (window));
5678
5679         /* Update dimmed */
5680         modest_ui_actions_check_menu_dimming_rules (window);
5681 }
5682
5683 void
5684 modest_ui_actions_on_search_messages (GtkAction *action, ModestWindow *window)
5685 {
5686         g_return_if_fail (MODEST_IS_WINDOW (window));
5687
5688         /* we check for low-mem; in that case, show a warning, and don't allow
5689          * searching
5690          */
5691         if (modest_platform_check_memory_low (window))
5692                 return;
5693         
5694         modest_platform_show_search_messages (GTK_WINDOW (window));
5695 }
5696
5697 void     
5698 modest_ui_actions_on_open_addressbook (GtkAction *action, ModestWindow *win)
5699 {
5700         g_return_if_fail (MODEST_IS_WINDOW (win));
5701
5702
5703         /* we check for low-mem; in that case, show a warning, and don't allow
5704          * for the addressbook
5705          */
5706         if (modest_platform_check_memory_low (win))
5707                 return;
5708
5709
5710         modest_platform_show_addressbook (GTK_WINDOW (win));
5711 }
5712
5713
5714 void
5715 modest_ui_actions_on_toggle_find_in_page (GtkToggleAction *action,
5716                                           ModestWindow *window)
5717 {
5718         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
5719
5720         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window), gtk_toggle_action_get_active (action));
5721 }
5722
5723 static void 
5724 on_send_receive_finished (ModestMailOperation  *mail_op, 
5725                            gpointer user_data)
5726 {
5727         GtkWidget *header_view, *folder_view;
5728         TnyFolderStore *folder_store;
5729         ModestMainWindow *main_win = MODEST_MAIN_WINDOW (user_data);
5730
5731         /* Set send/receive operation finished */       
5732         modest_main_window_notify_send_receive_completed (main_win);
5733
5734         /* Don't refresh the current folder if there were any errors */
5735         if (modest_mail_operation_get_status (mail_op) !=
5736             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
5737                 return;
5738         
5739         /* Refresh the current folder if we're viewing a window. We do
5740            this because the user won't be able to see the new mails in
5741            the selected folder after a Send&Receive because it only
5742            performs a poke_status, i.e, only the number of read/unread
5743            messages is updated, but the new headers are not
5744            downloaded */
5745         folder_view = modest_main_window_get_child_widget (main_win, 
5746                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5747         if (!folder_view)
5748                 return;
5749
5750         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5751         
5752         /* Do not need to refresh INBOX again because the
5753            update_account does it always automatically */
5754         if (folder_store && TNY_IS_FOLDER (folder_store) && 
5755             tny_folder_get_folder_type (TNY_FOLDER (folder_store)) != TNY_FOLDER_TYPE_INBOX) {
5756                 ModestMailOperation *refresh_op;
5757
5758                 header_view = modest_main_window_get_child_widget (main_win,
5759                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5760                 
5761                 /* We do not need to set the contents style
5762                    because it hasn't changed. We also do not
5763                    need to save the widget status. Just force
5764                    a refresh */
5765                 refresh_op = modest_mail_operation_new (G_OBJECT (main_win));
5766                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), refresh_op);
5767                 modest_mail_operation_refresh_folder (refresh_op, TNY_FOLDER (folder_store),
5768                                                       folder_refreshed_cb, main_win);
5769                 g_object_unref (refresh_op);
5770         }
5771         
5772         if (folder_store)
5773                 g_object_unref (folder_store);
5774 }
5775
5776
5777 void 
5778 modest_ui_actions_on_send_queue_error_happened (TnySendQueue *self, 
5779                                                 TnyHeader *header, 
5780                                                 TnyMsg *msg, 
5781                                                 GError *err, 
5782                                                 gpointer user_data)
5783 {
5784         const gchar* server_name = NULL;
5785         TnyTransportAccount *server_account;
5786         gchar *message = NULL;
5787
5788         /* Don't show anything if the user cancelled something or the send receive request is not
5789          * interactive */
5790         if (err->code == TNY_SYSTEM_ERROR_CANCEL ||
5791             !modest_tny_send_queue_get_requested_send_receive (MODEST_TNY_SEND_QUEUE (self)))
5792                 return;
5793
5794
5795         /* Get the server name: */
5796         server_account = 
5797                 TNY_TRANSPORT_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (self)));
5798         if (server_account)
5799                 server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account));          
5800         else
5801                 g_return_if_reached ();
5802
5803         /* Show the appropriate message text for the GError: */
5804         switch (err->code) {
5805         case TNY_SERVICE_ERROR_CONNECT:
5806                 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
5807                 break;
5808         case TNY_SERVICE_ERROR_AUTHENTICATE:
5809                 message = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"), server_name);
5810                 break;
5811         case TNY_SERVICE_ERROR_SEND:
5812                 message = g_strdup (dgettext("hildon-common-strings", "sfil_ib_unable_to_send"));
5813                 break;
5814         case TNY_SERVICE_ERROR_UNAVAILABLE:
5815                 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
5816                 break;
5817         default:
5818                 g_warning ("%s: unexpected ERROR %d",
5819                            __FUNCTION__, err->code);
5820                 message = g_strdup (dgettext("hildon-common-strings", "sfil_ib_unable_to_send"));
5821                 break;  
5822         }
5823         
5824         /* TODO if the username or the password where not defined we
5825            should show the Accounts Settings dialog or the Connection
5826            specific SMTP server window */
5827
5828         modest_platform_run_information_dialog (NULL, message, FALSE);
5829         g_free (message);
5830         g_object_unref (server_account);
5831 }
5832
5833 void
5834 modest_ui_actions_on_send_queue_status_changed (ModestTnySendQueue *send_queue,
5835                                                 gchar *msg_id, 
5836                                                 guint status,
5837                                                 gpointer user_data)
5838 {
5839         ModestMainWindow *main_window = NULL;
5840         ModestWindowMgr *mgr = NULL;
5841         GtkWidget *folder_view = NULL, *header_view = NULL;
5842         TnyFolderStore *selected_folder = NULL;
5843         TnyFolderType folder_type;
5844
5845         mgr = modest_runtime_get_window_mgr ();
5846         main_window = MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (mgr,
5847                                                                              FALSE));/* don't create */
5848         if (!main_window)
5849                 return;
5850
5851         /* Check if selected folder is OUTBOX */
5852         folder_view = modest_main_window_get_child_widget (main_window,
5853                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5854         header_view = modest_main_window_get_child_widget (main_window,
5855                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5856
5857         selected_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5858         if (!TNY_IS_FOLDER (selected_folder)) 
5859                 goto frees;
5860
5861         /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
5862 #if GTK_CHECK_VERSION(2, 8, 0) 
5863         folder_type = modest_tny_folder_guess_folder_type (TNY_FOLDER (selected_folder)); 
5864         if (folder_type ==  TNY_FOLDER_TYPE_OUTBOX) {           
5865                 GtkTreeViewColumn *tree_column;
5866
5867                 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (header_view), 
5868                                                         TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN);
5869                 gtk_tree_view_column_queue_resize (tree_column);
5870         }
5871 #else
5872         gtk_widget_queue_draw (header_view);
5873 #endif          
5874
5875         /* Rerun dimming rules, because the message could become deletable for example */
5876         modest_window_check_dimming_rules_group (MODEST_WINDOW (main_window), 
5877                                                  MODEST_DIMMING_RULES_TOOLBAR);
5878         
5879         /* Free */
5880  frees:
5881         if (selected_folder != NULL)
5882                 g_object_unref (selected_folder);
5883 }
5884
5885 void 
5886 modest_ui_actions_on_account_connection_error (GtkWindow *parent_window,
5887                                                TnyAccount *account)
5888 {
5889         ModestTransportStoreProtocol proto;
5890         const gchar *proto_name;
5891         gchar *error_note = NULL;
5892         
5893         proto_name = tny_account_get_proto (account);
5894         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
5895         
5896         switch (proto) {
5897         case MODEST_PROTOCOL_STORE_POP:
5898                 error_note = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"), 
5899                                               tny_account_get_hostname (account));
5900                 break;
5901         case MODEST_PROTOCOL_STORE_IMAP:
5902                 error_note = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"), 
5903                                               tny_account_get_hostname (account));
5904                 break;
5905         case MODEST_PROTOCOL_STORE_MAILDIR:
5906         case MODEST_PROTOCOL_STORE_MBOX:
5907                 error_note = g_strdup (_("emev_nc_mailbox_notavailable"));
5908                 break;
5909         default:
5910                 g_warning ("%s: This should not be reached", __FUNCTION__);
5911         }
5912
5913         if (error_note) {
5914                 modest_platform_run_information_dialog (parent_window, error_note, FALSE);
5915                 g_free (error_note);
5916         }
5917 }
5918
5919 gchar *
5920 modest_ui_actions_get_msg_already_deleted_error_msg (ModestWindow *win)
5921 {
5922         gchar *msg = NULL;
5923         TnyFolderStore *folder = NULL;
5924         TnyAccount *account = NULL;
5925         ModestTransportStoreProtocol proto;
5926         TnyHeader *header = NULL;
5927
5928         if (MODEST_IS_MAIN_WINDOW (win)) {
5929                 GtkWidget *header_view;
5930                 TnyList* headers = NULL;
5931                 TnyIterator *iter;
5932                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
5933                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5934                 headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
5935                 if (!headers || tny_list_get_length (headers) == 0) {
5936                         if (headers)
5937                                 g_object_unref (headers);
5938                         return NULL;
5939                 }
5940                 iter = tny_list_create_iterator (headers);
5941                 header = TNY_HEADER (tny_iterator_get_current (iter));
5942                 folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5943                 g_object_unref (iter);
5944                 g_object_unref (headers);
5945         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
5946                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
5947                 folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5948         }
5949
5950         /* Get the account type */
5951         account = tny_folder_get_account (TNY_FOLDER (folder));
5952         proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
5953         if (proto == MODEST_PROTOCOL_STORE_POP) {
5954                 msg = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
5955         } else if (proto == MODEST_PROTOCOL_STORE_IMAP) {
5956                 gchar *subject;
5957                 subject = tny_header_dup_subject (header);
5958                 msg = g_strdup_printf (_("emev_ni_ui_imap_message_not_available_in_server"), 
5959                                        subject);
5960                 g_free (subject);
5961         } else {
5962                 msg = g_strdup_printf (_("mail_ni_ui_folder_get_msg_folder_error"));
5963         }
5964
5965         /* Frees */
5966         g_object_unref (account);
5967         g_object_unref (folder);
5968         g_object_unref (header);
5969
5970         return msg;
5971 }