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