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