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