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