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