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