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