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