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