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