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