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