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