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