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