* src/modest-ui-actions.c:
[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         gtk_widget_grab_focus (GTK_WIDGET (folder_view));       
3140 }
3141
3142 static void
3143 on_rename_folder_performer (gboolean canceled, 
3144                             GError *err, 
3145                             GtkWindow *parent_window, 
3146                             TnyAccount *account, 
3147                             gpointer user_data)
3148 {
3149         ModestMailOperation *mail_op = NULL;
3150         GtkTreeSelection *sel = NULL;
3151         GtkWidget *folder_view = NULL;
3152         RenameFolderInfo *data = (RenameFolderInfo*)user_data;
3153
3154         if (canceled || err) {
3155                 /* In memory full conditions we could get this error here */
3156                 if (err && is_memory_full_error (err)) {
3157                         modest_platform_information_banner ((GtkWidget *) parent_window,
3158                                                             NULL, dgettext("ke-recv",
3159                                                                            "cerm_device_memory_full"));
3160                 }
3161         } else if (MODEST_IS_MAIN_WINDOW(parent_window)) {
3162
3163                 folder_view = modest_main_window_get_child_widget (
3164                                 MODEST_MAIN_WINDOW (parent_window),
3165                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3166
3167                 mail_op = 
3168                         modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3169                                         modest_ui_actions_rename_folder_error_handler,
3170                                         parent_window, NULL);
3171
3172                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3173                                 mail_op);
3174
3175                 /* Clear the headers view */
3176                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3177                 gtk_tree_selection_unselect_all (sel);
3178
3179                 /* Actually rename the folder */
3180                 modest_mail_operation_rename_folder (mail_op,
3181                                                      TNY_FOLDER (data->folder),
3182                                                      (const gchar *) (data->new_name),
3183                                                      on_rename_folder_cb,
3184                                                      folder_view);
3185                 g_object_unref (mail_op);
3186         }
3187
3188         g_free (data->new_name);
3189         g_free (data);
3190 }
3191
3192 void 
3193 modest_ui_actions_on_rename_folder (GtkAction *action,
3194                                      ModestMainWindow *main_window)
3195 {
3196         TnyFolderStore *folder;
3197         GtkWidget *folder_view;
3198         GtkWidget *header_view; 
3199
3200         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3201
3202         folder_view = modest_main_window_get_child_widget (main_window,
3203                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3204         if (!folder_view)
3205                 return;
3206
3207         header_view = modest_main_window_get_child_widget (main_window,
3208                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
3209         
3210         if (!header_view)
3211                 return;
3212
3213         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3214
3215         if (!folder)
3216                 return;
3217
3218         if (TNY_IS_FOLDER (folder)) {
3219                 gchar *folder_name;
3220                 gint response;
3221                 const gchar *current_name;
3222                 TnyFolderStore *parent;
3223                 gboolean do_rename = TRUE;
3224
3225                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
3226                 parent = tny_folder_get_folder_store (TNY_FOLDER (folder));
3227                 response = modest_platform_run_rename_folder_dialog (GTK_WINDOW (main_window), 
3228                                                                      parent, current_name, 
3229                                                                      &folder_name);
3230                 g_object_unref (parent);
3231
3232                 if (response != GTK_RESPONSE_ACCEPT || strlen (folder_name) == 0) {
3233                         do_rename = FALSE;
3234                 } else {
3235                         RenameFolderInfo *rename_folder_data = g_new0 (RenameFolderInfo, 1);
3236                         rename_folder_data->folder = folder;
3237                         rename_folder_data->new_name = folder_name;
3238                         modest_platform_connect_if_remote_and_perform (GTK_WINDOW(main_window), TRUE,
3239                                         folder, on_rename_folder_performer, rename_folder_data);
3240                 }
3241         }
3242         g_object_unref (folder);
3243 }
3244
3245 static void
3246 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
3247                                                gpointer user_data)
3248 {
3249         GObject *win = modest_mail_operation_get_source (mail_op);
3250
3251         modest_platform_run_information_dialog ((win) ? GTK_WINDOW (win) : NULL,
3252                                                 _("mail_in_ui_folder_delete_error"),
3253                                                 FALSE);
3254         g_object_unref (win);
3255 }
3256
3257 typedef struct {
3258         TnyFolderStore *folder;
3259         gboolean move_to_trash;
3260 } DeleteFolderInfo;
3261
3262 static void
3263 on_delete_folder_cb (gboolean canceled, 
3264                   GError *err,
3265                   GtkWindow *parent_window, 
3266                   TnyAccount *account, 
3267                   gpointer user_data)
3268 {
3269         DeleteFolderInfo *info = (DeleteFolderInfo*) user_data;
3270         GtkWidget *folder_view;
3271         ModestMailOperation *mail_op;
3272         GtkTreeSelection *sel;
3273         
3274         if (!MODEST_IS_MAIN_WINDOW(parent_window) || canceled || (err!=NULL)) {
3275                 g_object_unref (G_OBJECT (info->folder));
3276                 g_free (info);
3277                 return;
3278         }
3279         
3280         folder_view = modest_main_window_get_child_widget (
3281                         MODEST_MAIN_WINDOW (parent_window),
3282                         MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3283
3284         /* Unselect the folder before deleting it to free the headers */
3285         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3286         gtk_tree_selection_unselect_all (sel);
3287
3288         /* Create the mail operation */
3289         mail_op =
3290                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3291                                 modest_ui_actions_delete_folder_error_handler,
3292                                 NULL, NULL);
3293
3294         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3295                         mail_op);
3296         modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (info->folder), info->move_to_trash);
3297         
3298         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (folder_view));
3299
3300         g_object_unref (G_OBJECT (mail_op));
3301         g_object_unref (G_OBJECT (info->folder));
3302         g_free (info);
3303 }
3304
3305 static void
3306 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash)
3307 {
3308         TnyFolderStore *folder;
3309         GtkWidget *folder_view;
3310         gint response;
3311         gchar *message;
3312         
3313         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3314
3315         folder_view = modest_main_window_get_child_widget (main_window,
3316                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
3317         if (!folder_view)
3318                 return;
3319
3320         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3321
3322         /* Show an error if it's an account */
3323         if (!TNY_IS_FOLDER (folder)) {
3324                 modest_platform_run_information_dialog (GTK_WINDOW (main_window),
3325                                                         _("mail_in_ui_folder_delete_error"),
3326                                                         FALSE);
3327                 g_object_unref (G_OBJECT (folder));
3328                 return;
3329         }
3330
3331         /* Ask the user */      
3332         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"), 
3333                                     tny_folder_get_name (TNY_FOLDER (folder)));
3334         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (main_window),
3335                                                             (const gchar *) message);
3336         g_free (message);
3337
3338         if (response == GTK_RESPONSE_OK) {
3339                 DeleteFolderInfo *info;
3340                 info = g_new0(DeleteFolderInfo, 1);
3341                 info->folder = folder;
3342                 info->move_to_trash = move_to_trash;
3343                 g_object_ref (G_OBJECT (info->folder));
3344                 TnyAccount *account = tny_folder_get_account (TNY_FOLDER (folder));
3345                 modest_platform_connect_if_remote_and_perform (GTK_WINDOW (main_window), 
3346                                                                TRUE,
3347                                                                TNY_FOLDER_STORE (account), 
3348                                                                on_delete_folder_cb, info);
3349                 g_object_unref (account);
3350         }
3351         g_object_unref (G_OBJECT (folder));
3352 }
3353
3354 void 
3355 modest_ui_actions_on_delete_folder (GtkAction *action,
3356                                      ModestMainWindow *main_window)
3357 {
3358         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3359         
3360         delete_folder (main_window, FALSE);
3361 }
3362
3363 void 
3364 modest_ui_actions_on_move_folder_to_trash_folder (GtkAction *action, ModestMainWindow *main_window)
3365 {
3366         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
3367         
3368         delete_folder (main_window, TRUE);
3369 }
3370
3371
3372 typedef struct _PasswordDialogFields {
3373         GtkWidget *username;
3374         GtkWidget *password;
3375         GtkWidget *dialog;
3376 } PasswordDialogFields;
3377
3378 static void
3379 password_dialog_check_field (GtkEditable *editable,
3380                              PasswordDialogFields *fields)
3381 {
3382         const gchar *value;
3383         gboolean any_value_empty = FALSE;
3384
3385         value = gtk_entry_get_text (GTK_ENTRY (fields->username));
3386         if ((value == NULL) || value[0] == '\0') {
3387                 any_value_empty = TRUE;
3388         }
3389         value = gtk_entry_get_text (GTK_ENTRY (fields->password));
3390         if ((value == NULL) || value[0] == '\0') {
3391                 any_value_empty = TRUE;
3392         }
3393         gtk_dialog_set_response_sensitive (GTK_DIALOG (fields->dialog), GTK_RESPONSE_ACCEPT, !any_value_empty);
3394 }
3395
3396 void
3397 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
3398                                          const gchar* server_account_name,
3399                                          gchar **username,
3400                                          gchar **password, 
3401                                          gboolean *cancel, 
3402                                          gboolean *remember,
3403                                          ModestMainWindow *main_window)
3404 {
3405         g_return_if_fail(server_account_name);
3406         gboolean completed = FALSE;
3407         PasswordDialogFields *fields = NULL;
3408         
3409         /* Initalize output parameters: */
3410         if (cancel)
3411                 *cancel = FALSE;
3412                 
3413         if (remember)
3414                 *remember = TRUE;
3415                 
3416 #ifdef MODEST_PLATFORM_MAEMO
3417         /* Maemo uses a different (awkward) button order,
3418          * It should probably just use gtk_alternative_dialog_button_order ().
3419          */
3420         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3421                                               NULL,
3422                                               GTK_DIALOG_MODAL,
3423                                               _("mcen_bd_dialog_ok"),
3424                                               GTK_RESPONSE_ACCEPT,
3425                                               _("mcen_bd_dialog_cancel"),
3426                                               GTK_RESPONSE_REJECT,
3427                                               NULL);
3428 #else
3429         GtkWidget *dialog = gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3430                                               NULL,
3431                                               GTK_DIALOG_MODAL,
3432                                               GTK_STOCK_CANCEL,
3433                                               GTK_RESPONSE_REJECT,
3434                                               GTK_STOCK_OK,
3435                                               GTK_RESPONSE_ACCEPT,
3436                                               NULL);
3437 #endif /* MODEST_PLATFORM_MAEMO */
3438
3439         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (dialog));
3440         
3441         gchar *server_name = modest_account_mgr_get_server_account_hostname (
3442                 modest_runtime_get_account_mgr(), server_account_name);
3443         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
3444                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
3445                 if (cancel)
3446                         *cancel = TRUE;
3447                 return;
3448         }
3449         
3450         /* This causes a warning because the logical ID has no %s in it, 
3451          * though the translation does, but there is not much we can do about that: */
3452         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
3453         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
3454                             FALSE, FALSE, 0);
3455         g_free (txt);
3456         g_free (server_name);
3457         server_name = NULL;
3458
3459         /* username: */
3460         gchar *initial_username = modest_account_mgr_get_server_account_username (
3461                 modest_runtime_get_account_mgr(), server_account_name);
3462         
3463         GtkWidget *entry_username = gtk_entry_new ();
3464         if (initial_username)
3465                 gtk_entry_set_text (GTK_ENTRY (entry_username), initial_username);
3466         /* Dim this if a connection has ever succeeded with this username,
3467          * as per the UI spec: */
3468         /* const gboolean username_known =  */
3469         /*      modest_account_mgr_get_server_account_username_has_succeeded( */
3470         /*              modest_runtime_get_account_mgr(), server_account_name); */
3471         /* gtk_widget_set_sensitive (entry_username, !username_known); */
3472
3473         /* We drop the username sensitive code and disallow changing it here
3474          * as tinymail does not support really changing the username in the callback
3475          */
3476         gtk_widget_set_sensitive (entry_username, FALSE);
3477
3478 #ifdef MODEST_PLATFORM_MAEMO
3479         /* Auto-capitalization is the default, so let's turn it off: */
3480         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
3481         
3482         /* Create a size group to be used by all captions.
3483          * Note that HildonCaption does not create a default size group if we do not specify one.
3484          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
3485         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3486         
3487         GtkWidget *caption = hildon_caption_new (sizegroup, 
3488                 _("mail_fi_username"), entry_username, NULL, HILDON_CAPTION_MANDATORY);
3489         gtk_widget_show (entry_username);
3490         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3491                 FALSE, FALSE, MODEST_MARGIN_HALF);
3492         gtk_widget_show (caption);
3493 #else 
3494         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_username,
3495                             TRUE, FALSE, 0);
3496 #endif /* MODEST_PLATFORM_MAEMO */      
3497                             
3498         /* password: */
3499         GtkWidget *entry_password = gtk_entry_new ();
3500         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
3501         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
3502         
3503 #ifdef MODEST_PLATFORM_MAEMO
3504         /* Auto-capitalization is the default, so let's turn it off: */
3505         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password), 
3506                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
3507         
3508         caption = hildon_caption_new (sizegroup, 
3509                 _("mail_fi_password"), entry_password, NULL, HILDON_CAPTION_MANDATORY);
3510         gtk_widget_show (entry_password);
3511         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption, 
3512                 FALSE, FALSE, MODEST_MARGIN_HALF);
3513         gtk_widget_show (caption);
3514         g_object_unref (sizegroup);
3515 #else 
3516         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry_password,
3517                             TRUE, FALSE, 0);
3518 #endif /* MODEST_PLATFORM_MAEMO */      
3519
3520         if (initial_username != NULL)
3521                 gtk_widget_grab_focus (GTK_WIDGET (entry_password));
3522                                 
3523 /* This is not in the Maemo UI spec:
3524         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
3525         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
3526                             TRUE, FALSE, 0);
3527 */
3528
3529         fields = g_slice_new0 (PasswordDialogFields);
3530         fields->username = entry_username;
3531         fields->password = entry_password;
3532         fields->dialog = dialog;
3533
3534         g_signal_connect (entry_username, "changed", G_CALLBACK (password_dialog_check_field), fields);
3535         g_signal_connect (entry_password, "changed", G_CALLBACK (password_dialog_check_field), fields);
3536         password_dialog_check_field (NULL, fields);
3537
3538         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3539
3540         while (!completed) {
3541         
3542                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3543                         if (username) {
3544                                 *username = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_username)));
3545                                 
3546                                 /* Note that an empty field becomes the "" string */
3547                                 if (*username && strlen (*username) > 0) {
3548                                         modest_account_mgr_set_server_account_username (modest_runtime_get_account_mgr(), 
3549                                                                                         server_account_name, 
3550                                                                                         *username);
3551                                         completed = TRUE;
3552                                 
3553                                         const gboolean username_was_changed = 
3554                                                 (strcmp (*username, initial_username) != 0);
3555                                         if (username_was_changed) {
3556                                                 g_warning ("%s: tinymail does not yet support changing the "
3557                                                            "username in the get_password() callback.\n", __FUNCTION__);
3558                                         }
3559                                 } else {
3560                                         /* Show error */
3561                                         modest_platform_information_banner (GTK_WIDGET (dialog), NULL, 
3562                                                                             _("mcen_ib_username_pw_incorrect"));
3563                                         completed = FALSE;
3564                                 }
3565                         }
3566                         
3567                         if (password) {
3568                                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry_password)));
3569                         
3570                                 /* We do not save the password in the configuration, 
3571                                  * because this function is only called for passwords that should 
3572                                  * not be remembered:
3573                                  modest_server_account_set_password (
3574                                  modest_runtime_get_account_mgr(), server_account_name, 
3575                                  *password);
3576                                  */
3577                         }                       
3578                         if (cancel)
3579                                 *cancel   = FALSE;                      
3580                 } else {
3581                         /* Set parent to NULL or the banner will disappear with its parent dialog */
3582                         modest_platform_information_banner(NULL, NULL, _("mail_ib_login_cancelled"));
3583                         completed = TRUE;
3584                         if (username)
3585                                 *username = NULL;                       
3586                         if (password)
3587                                 *password = NULL;                       
3588                         if (cancel)
3589                                 *cancel   = TRUE;
3590                 }
3591         }
3592
3593 /* This is not in the Maemo UI spec:
3594         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
3595                 *remember = TRUE;
3596         else
3597                 *remember = FALSE;
3598 */
3599
3600         gtk_widget_destroy (dialog);
3601         g_slice_free (PasswordDialogFields, fields);
3602         
3603         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
3604 }
3605
3606 void
3607 modest_ui_actions_on_cut (GtkAction *action,
3608                           ModestWindow *window)
3609 {
3610         GtkWidget *focused_widget;
3611         GtkClipboard *clipboard;
3612
3613         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3614         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3615         if (GTK_IS_EDITABLE (focused_widget)) {
3616                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
3617                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3618                 gtk_clipboard_store (clipboard);
3619         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3620                 GtkTextBuffer *buffer;
3621
3622                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3623                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
3624                         gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
3625                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3626                         gtk_clipboard_store (clipboard);
3627                 }
3628         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
3629                 TnyList *header_list = modest_header_view_get_selected_headers (
3630                                 MODEST_HEADER_VIEW (focused_widget));
3631                 gboolean continue_download = FALSE;
3632                 gint num_of_unc_msgs;
3633
3634                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
3635
3636                 if (num_of_unc_msgs) {
3637                         TnyAccount *account = get_account_from_header_list (header_list);
3638                         if (account) {
3639                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
3640                                 g_object_unref (account);
3641                         }
3642                 }
3643
3644                 if (num_of_unc_msgs == 0 || continue_download) {
3645 /*                      modest_platform_information_banner (
3646                                         NULL, NULL, _CS("mcen_ib_getting_items"));*/
3647                         modest_header_view_cut_selection (
3648                                         MODEST_HEADER_VIEW (focused_widget));
3649                 }
3650
3651                 g_object_unref (header_list);
3652         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3653                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
3654         }
3655 }
3656
3657 void
3658 modest_ui_actions_on_copy (GtkAction *action,
3659                            ModestWindow *window)
3660 {
3661         GtkClipboard *clipboard;
3662         GtkWidget *focused_widget;
3663         gboolean copied = TRUE;
3664
3665         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3666         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3667
3668         if (GTK_IS_LABEL (focused_widget)) {
3669                 gchar *selection;
3670                 selection = modest_text_utils_label_get_selection (GTK_LABEL (focused_widget));
3671                 gtk_clipboard_set_text (clipboard, selection, -1);
3672                 g_free (selection);
3673                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3674                 gtk_clipboard_store (clipboard);
3675         } else if (GTK_IS_EDITABLE (focused_widget)) {
3676                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
3677                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3678                 gtk_clipboard_store (clipboard);
3679         } else if (GTK_IS_HTML (focused_widget)) {
3680                 gtk_html_copy (GTK_HTML (focused_widget));
3681                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3682                 gtk_clipboard_store (clipboard);
3683         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3684                 GtkTextBuffer *buffer;
3685                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3686                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
3687                         gtk_text_buffer_copy_clipboard (buffer, clipboard);
3688                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3689                         gtk_clipboard_store (clipboard);
3690                 }
3691         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
3692                 TnyList *header_list = modest_header_view_get_selected_headers (
3693                                 MODEST_HEADER_VIEW (focused_widget));
3694                 gboolean continue_download = FALSE;
3695                 gint num_of_unc_msgs;
3696
3697                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
3698
3699                 if (num_of_unc_msgs) {
3700                         TnyAccount *account = get_account_from_header_list (header_list);
3701                         if (account) {
3702                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
3703                                 g_object_unref (account);
3704                         }
3705                 }
3706
3707                 if (num_of_unc_msgs == 0 || continue_download) {
3708                         modest_platform_information_banner (
3709                                         NULL, NULL, _CS("mcen_ib_getting_items"));
3710                         modest_header_view_copy_selection (
3711                                         MODEST_HEADER_VIEW (focused_widget));
3712                 } else
3713                         copied = FALSE;
3714
3715                 g_object_unref (header_list);
3716
3717         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3718                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
3719         }
3720
3721         /* Show information banner if there was a copy to clipboard */
3722         if(copied)
3723                 modest_platform_information_banner (
3724                                 NULL, NULL, _CS("ecoc_ib_edwin_copied"));
3725 }
3726
3727 void
3728 modest_ui_actions_on_undo (GtkAction *action,
3729                            ModestWindow *window)
3730 {
3731         ModestEmailClipboard *clipboard = NULL;
3732
3733         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3734                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
3735         } else if (MODEST_IS_MAIN_WINDOW (window)) {
3736                 /* Clear clipboard source */
3737                 clipboard = modest_runtime_get_email_clipboard ();
3738                 modest_email_clipboard_clear (clipboard);               
3739         }
3740         else {
3741                 g_return_if_reached ();
3742         }
3743 }
3744
3745 void
3746 modest_ui_actions_on_redo (GtkAction *action,
3747                            ModestWindow *window)
3748 {
3749         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3750                 modest_msg_edit_window_redo (MODEST_MSG_EDIT_WINDOW (window));
3751         }
3752         else {
3753                 g_return_if_reached ();
3754         }
3755 }
3756
3757
3758 static void
3759 destroy_information_note (ModestMailOperation *mail_op, 
3760                           gpointer user_data)
3761 {
3762         /* destroy information note */
3763         gtk_widget_destroy (GTK_WIDGET(user_data));
3764 }
3765
3766 static void
3767 destroy_folder_information_note (ModestMailOperation *mail_op, 
3768                                  TnyFolder *new_folder,
3769                                  gpointer user_data)
3770 {
3771         /* destroy information note */
3772         gtk_widget_destroy (GTK_WIDGET(user_data));
3773 }
3774
3775
3776 static void
3777 paste_as_attachment_free (gpointer data)
3778 {
3779         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) data;
3780
3781         gtk_widget_destroy (helper->banner);
3782         g_object_unref (helper->banner);
3783         g_free (helper);
3784 }
3785
3786 static void
3787 paste_msg_as_attachment_cb (ModestMailOperation *mail_op,
3788                             TnyHeader *header,
3789                             TnyMsg *msg,
3790                             gpointer userdata)
3791 {
3792         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) userdata;
3793         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (helper->window));
3794
3795         if (msg == NULL)
3796                 return;
3797
3798         modest_msg_edit_window_add_part (MODEST_MSG_EDIT_WINDOW (helper->window), TNY_MIME_PART (msg));
3799         
3800 }
3801
3802 void
3803 modest_ui_actions_on_paste (GtkAction *action,
3804                             ModestWindow *window)
3805 {
3806         GtkWidget *focused_widget = NULL;
3807         GtkWidget *inf_note = NULL;
3808         ModestMailOperation *mail_op = NULL;
3809
3810         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3811         if (GTK_IS_EDITABLE (focused_widget)) {
3812                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
3813         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3814                 ModestEmailClipboard *e_clipboard = NULL;
3815                 e_clipboard = modest_runtime_get_email_clipboard ();
3816                 if (modest_email_clipboard_cleared (e_clipboard)) {
3817                         GtkTextBuffer *buffer;
3818                         GtkClipboard *clipboard;
3819
3820                         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3821                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3822                         gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
3823                 } else if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
3824                         ModestMailOperation *mail_op;
3825                         TnyFolder *src_folder;
3826                         TnyList *data;
3827                         gboolean delete;
3828                         PasteAsAttachmentHelper *helper = g_new0 (PasteAsAttachmentHelper, 1);
3829                         helper->window = MODEST_MSG_EDIT_WINDOW (window);
3830                         helper->banner = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
3831                                                                            _CS("ckct_nw_pasting"));
3832                         modest_email_clipboard_get_data (e_clipboard, &src_folder, &data, &delete);
3833                         mail_op = modest_mail_operation_new (G_OBJECT (window));
3834                         if (helper->banner != NULL) {
3835                                 g_object_ref (G_OBJECT (helper->banner));
3836                                 gtk_window_set_modal (GTK_WINDOW (helper->banner), FALSE);
3837                                 gtk_widget_show (GTK_WIDGET (helper->banner));
3838                         }
3839
3840                         if (data != NULL) {
3841                                 modest_mail_operation_get_msgs_full (mail_op, 
3842                                                                      data,
3843                                                                      (GetMsgAsyncUserCallback) paste_msg_as_attachment_cb,
3844                                                                      helper,
3845                                                                      paste_as_attachment_free);
3846                         }
3847                 }
3848         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3849                 ModestEmailClipboard *clipboard = NULL;
3850                 TnyFolder *src_folder = NULL;
3851                 TnyFolderStore *folder_store = NULL;
3852                 TnyList *data = NULL;           
3853                 gboolean delete = FALSE;
3854                 
3855                 /* Check clipboard source */
3856                 clipboard = modest_runtime_get_email_clipboard ();
3857                 if (modest_email_clipboard_cleared (clipboard)) 
3858                         return;
3859                 
3860                 /* Get elements to paste */
3861                 modest_email_clipboard_get_data (clipboard, &src_folder, &data, &delete);
3862
3863                 /* Create a new mail operation */
3864                 mail_op = modest_mail_operation_new (G_OBJECT(window));
3865                 
3866                 /* Get destination folder */
3867                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (focused_widget));
3868
3869                 /* transfer messages  */
3870                 if (data != NULL) {
3871                         gint response = 0;
3872
3873                         /* Ask for user confirmation */
3874                         response = 
3875                                 modest_ui_actions_msgs_move_to_confirmation (window, 
3876                                                                              TNY_FOLDER (folder_store), 
3877                                                                              delete,
3878                                                                              data);
3879                         
3880                         if (response == GTK_RESPONSE_OK) {
3881                                 /* Launch notification */
3882                                 inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL, 
3883                                                                              _CS("ckct_nw_pasting"));
3884                                 if (inf_note != NULL)  {
3885                                         gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
3886                                         gtk_widget_show (GTK_WIDGET(inf_note));
3887                                 }
3888
3889                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3890                                 modest_mail_operation_xfer_msgs (mail_op, 
3891                                                                  data,
3892                                                                  TNY_FOLDER (folder_store),
3893                                                                  delete,
3894                                                                  destroy_information_note,
3895                                                                  inf_note);                             
3896                         } else {
3897                                 g_object_unref (mail_op);
3898                         }
3899                         
3900                 } else if (src_folder != NULL) {                        
3901                         /* Launch notification */
3902                         inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL, 
3903                                                                      _CS("ckct_nw_pasting"));
3904                         if (inf_note != NULL)  {
3905                                 gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
3906                                 gtk_widget_show (GTK_WIDGET(inf_note));
3907                         }
3908                         
3909                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
3910                         modest_mail_operation_xfer_folder (mail_op, 
3911                                                            src_folder,
3912                                                            folder_store,
3913                                                            delete,
3914                                                            destroy_folder_information_note,
3915                                                            inf_note);
3916                 }
3917
3918                 /* Free */
3919                 if (data != NULL) 
3920                         g_object_unref (data);
3921                 if (src_folder != NULL) 
3922                         g_object_unref (src_folder);
3923                 if (folder_store != NULL) 
3924                         g_object_unref (folder_store);
3925         }
3926 }
3927
3928
3929 void
3930 modest_ui_actions_on_select_all (GtkAction *action,
3931                                  ModestWindow *window)
3932 {
3933         GtkWidget *focused_widget;
3934
3935         focused_widget = gtk_window_get_focus (GTK_WINDOW (window));
3936         if (MODEST_IS_ATTACHMENTS_VIEW (focused_widget)) {
3937                 modest_attachments_view_select_all (MODEST_ATTACHMENTS_VIEW (focused_widget));
3938         } else if (GTK_IS_LABEL (focused_widget)) {
3939                 gtk_label_select_region (GTK_LABEL (focused_widget), 0, -1);
3940         } else if (GTK_IS_EDITABLE (focused_widget)) {
3941                 gtk_editable_select_region (GTK_EDITABLE(focused_widget), 0, -1);
3942         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3943                 GtkTextBuffer *buffer;
3944                 GtkTextIter start, end;
3945
3946                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3947                 gtk_text_buffer_get_start_iter (buffer, &start);
3948                 gtk_text_buffer_get_end_iter (buffer, &end);
3949                 gtk_text_buffer_select_range (buffer, &start, &end);
3950         } else if (GTK_IS_HTML (focused_widget)) {
3951                 gtk_html_select_all (GTK_HTML (focused_widget));
3952         } else if (MODEST_IS_MAIN_WINDOW (window)) {
3953                 GtkWidget *header_view = focused_widget;
3954                 GtkTreeSelection *selection = NULL;
3955                 
3956                 if (!(MODEST_IS_HEADER_VIEW (focused_widget))) {
3957                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
3958                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
3959                 }
3960                                 
3961                 /* Disable window dimming management */
3962                 modest_window_disable_dimming (MODEST_WINDOW(window));
3963                 
3964                 /* Select all messages */
3965                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
3966                 gtk_tree_selection_select_all (selection);
3967
3968                 /* Set focuse on header view */
3969                 gtk_widget_grab_focus (header_view);
3970
3971
3972                 /* Enable window dimming management */
3973                 modest_window_enable_dimming (MODEST_WINDOW(window));
3974                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3975         }
3976
3977 }
3978
3979 void
3980 modest_ui_actions_on_mark_as_read (GtkAction *action,
3981                                    ModestWindow *window)
3982 {       
3983         g_return_if_fail (MODEST_IS_WINDOW(window));
3984                 
3985         /* Mark each header as read */
3986         do_headers_action (window, headers_action_mark_as_read, NULL);
3987 }
3988
3989 void
3990 modest_ui_actions_on_mark_as_unread (GtkAction *action,
3991                                      ModestWindow *window)
3992 {       
3993         g_return_if_fail (MODEST_IS_WINDOW(window));
3994                 
3995         /* Mark each header as read */
3996         do_headers_action (window, headers_action_mark_as_unread, NULL);
3997 }
3998
3999 void
4000 modest_ui_actions_on_change_zoom (GtkRadioAction *action,
4001                                   GtkRadioAction *selected,
4002                                   ModestWindow *window)
4003 {
4004         gint value;
4005
4006         value = gtk_radio_action_get_current_value (selected);
4007         if (MODEST_IS_WINDOW (window)) {
4008                 modest_window_set_zoom (MODEST_WINDOW (window), ((gdouble)value)/100);
4009         }
4010 }
4011
4012 void
4013 modest_ui_actions_msg_edit_on_change_priority (GtkRadioAction *action,
4014                                                GtkRadioAction *selected,
4015                                                ModestWindow *window)
4016 {
4017         TnyHeaderFlags flags;
4018         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4019
4020         flags = gtk_radio_action_get_current_value (selected);
4021         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW (window), flags);
4022 }
4023
4024 void
4025 modest_ui_actions_msg_edit_on_change_file_format (GtkRadioAction *action,
4026                                                   GtkRadioAction *selected,
4027                                                   ModestWindow *window)
4028 {
4029         gint file_format;
4030
4031         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4032
4033         file_format = gtk_radio_action_get_current_value (selected);
4034         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (window), file_format);
4035 }
4036
4037
4038 void
4039 modest_ui_actions_on_zoom_plus (GtkAction *action,
4040                                 ModestWindow *window)
4041 {
4042         g_return_if_fail (MODEST_IS_WINDOW (window));
4043
4044         modest_window_zoom_plus (MODEST_WINDOW (window));
4045 }
4046
4047 void     
4048 modest_ui_actions_on_zoom_minus (GtkAction *action,
4049                                  ModestWindow *window)
4050 {
4051         g_return_if_fail (MODEST_IS_WINDOW (window));
4052
4053         modest_window_zoom_minus (MODEST_WINDOW (window));
4054 }
4055
4056 void     
4057 modest_ui_actions_on_toggle_fullscreen    (GtkToggleAction *toggle,
4058                                            ModestWindow *window)
4059 {
4060         ModestWindowMgr *mgr;
4061         gboolean fullscreen, active;
4062         g_return_if_fail (MODEST_IS_WINDOW (window));
4063
4064         mgr = modest_runtime_get_window_mgr ();
4065
4066         active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle)))?1:0;
4067         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4068
4069         if (active != fullscreen) {
4070                 modest_window_mgr_set_fullscreen_mode (mgr, active);
4071                 gtk_window_present (GTK_WINDOW (window));
4072         }
4073 }
4074
4075 void
4076 modest_ui_actions_on_change_fullscreen (GtkAction *action,
4077                                         ModestWindow *window)
4078 {
4079         ModestWindowMgr *mgr;
4080         gboolean fullscreen;
4081
4082         g_return_if_fail (MODEST_IS_WINDOW (window));
4083
4084         mgr = modest_runtime_get_window_mgr ();
4085         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4086         modest_window_mgr_set_fullscreen_mode (mgr, !fullscreen);
4087
4088         gtk_window_present (GTK_WINDOW (window));
4089 }
4090
4091 /* 
4092  * Used by modest_ui_actions_on_details to call do_headers_action 
4093  */
4094 static void
4095 headers_action_show_details (TnyHeader *header, 
4096                              ModestWindow *window,
4097                              gpointer user_data)
4098
4099 {
4100         GtkWidget *dialog;
4101         
4102         /* Create dialog */
4103         dialog = modest_details_dialog_new_with_header (GTK_WINDOW (window), header);
4104
4105         /* Run dialog */
4106         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4107         gtk_widget_show_all (dialog);
4108         gtk_dialog_run (GTK_DIALOG (dialog));
4109
4110         gtk_widget_destroy (dialog);
4111 }
4112
4113 /*
4114  * Show the folder details in a ModestDetailsDialog widget
4115  */
4116 static void
4117 show_folder_details (TnyFolder *folder, 
4118                      GtkWindow *window)
4119 {
4120         GtkWidget *dialog;
4121         
4122         /* Create dialog */
4123         dialog = modest_details_dialog_new_with_folder (window, folder);
4124
4125         /* Run dialog */
4126         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4127         gtk_widget_show_all (dialog);
4128         gtk_dialog_run (GTK_DIALOG (dialog));
4129
4130         gtk_widget_destroy (dialog);
4131 }
4132
4133 /*
4134  * Show the header details in a ModestDetailsDialog widget
4135  */
4136 void     
4137 modest_ui_actions_on_details (GtkAction *action, 
4138                               ModestWindow *win)
4139 {
4140         TnyList * headers_list;
4141         TnyIterator *iter;
4142         TnyHeader *header;              
4143
4144         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
4145                 TnyMsg *msg;
4146
4147                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (win));
4148                 if (!msg)
4149                         return;
4150                 g_object_unref (msg);           
4151
4152                 headers_list = get_selected_headers (win);
4153                 if (!headers_list)
4154                         return;
4155
4156                 iter = tny_list_create_iterator (headers_list);
4157
4158                 header = TNY_HEADER (tny_iterator_get_current (iter));
4159                 if (header) {
4160                         headers_action_show_details (header, win, NULL);
4161                         g_object_unref (header);
4162                 }
4163
4164                 g_object_unref (iter);
4165                 g_object_unref (headers_list);
4166
4167         } else if (MODEST_IS_MAIN_WINDOW (win)) {
4168                 GtkWidget *folder_view, *header_view;
4169
4170                 /* Check which widget has the focus */
4171                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4172                                                                     MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4173                 if (gtk_widget_is_focus (folder_view)) {
4174                         TnyFolderStore *folder_store
4175                                 = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
4176                         if (!folder_store) {
4177                                 g_warning ("%s: No item was selected.\n", __FUNCTION__);
4178                                 return; 
4179                         }
4180                         /* Show only when it's a folder */
4181                         /* This function should not be called for account items, 
4182                          * because we dim the menu item for them. */
4183                         if (TNY_IS_FOLDER (folder_store)) {
4184                                 show_folder_details (TNY_FOLDER (folder_store), GTK_WINDOW (win));
4185                         }
4186
4187                         g_object_unref (folder_store);
4188
4189                 } else {
4190                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4191                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4192                         /* Show details of each header */
4193                         do_headers_action (win, headers_action_show_details, header_view);
4194                 }
4195         }
4196 }
4197
4198 void     
4199 modest_ui_actions_on_toggle_show_cc (GtkToggleAction *toggle,
4200                                      ModestMsgEditWindow *window)
4201 {
4202         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4203
4204         modest_msg_edit_window_show_cc (window, gtk_toggle_action_get_active (toggle));
4205 }
4206
4207 void     
4208 modest_ui_actions_on_toggle_show_bcc (GtkToggleAction *toggle,
4209                                       ModestMsgEditWindow *window)
4210 {
4211         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4212
4213         modest_msg_edit_window_show_bcc (window, gtk_toggle_action_get_active (toggle));
4214 }
4215
4216 void
4217 modest_ui_actions_toggle_folders_view (GtkAction *action, 
4218                                        ModestMainWindow *main_window)
4219 {
4220         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
4221
4222         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
4223                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SPLIT);
4224         else
4225                 modest_main_window_set_style (main_window, MODEST_MAIN_WINDOW_STYLE_SIMPLE);
4226 }
4227
4228 void 
4229 modest_ui_actions_on_toggle_toolbar (GtkToggleAction *toggle, 
4230                                      ModestWindow *window)
4231 {
4232         gboolean active, fullscreen = FALSE;
4233         ModestWindowMgr *mgr;
4234
4235         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle));
4236
4237         /* Check if we want to toggle the toolbar vuew in fullscreen
4238            or normal mode */
4239         if (!strcmp (gtk_action_get_name (GTK_ACTION (toggle)), 
4240                      "ViewShowToolbarFullScreen")) {
4241                 fullscreen = TRUE;
4242         }
4243
4244         /* Toggle toolbar */
4245         mgr = modest_runtime_get_window_mgr ();
4246         modest_window_mgr_show_toolbars (mgr, G_TYPE_FROM_INSTANCE (window), active, fullscreen);
4247 }
4248
4249 void     
4250 modest_ui_actions_msg_edit_on_select_font (GtkAction *action,
4251                                            ModestMsgEditWindow *window)
4252 {
4253         modest_msg_edit_window_select_font (window);
4254 }
4255
4256
4257 void
4258 modest_ui_actions_on_folder_display_name_changed (ModestFolderView *folder_view,
4259                                                   const gchar *display_name,
4260                                                   GtkWindow *window)
4261 {
4262         /* don't update the display name if it was already set;
4263          * updating the display name apparently is expensive */
4264         const gchar* old_name = gtk_window_get_title (window);
4265
4266         if (display_name == NULL)
4267                 display_name = " ";
4268
4269         if (old_name && display_name && strcmp (old_name, display_name) == 0)
4270                 return; /* don't do anything */
4271
4272         /* This is usually used to change the title of the main window, which
4273          * is the one that holds the folder view. Note that this change can
4274          * happen even when the widget doesn't have the focus. */
4275         gtk_window_set_title (window, display_name);
4276
4277 }
4278
4279 void
4280 modest_ui_actions_on_select_contacts (GtkAction *action, ModestMsgEditWindow *window)
4281 {
4282         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4283         modest_msg_edit_window_select_contacts (window);
4284 }
4285
4286 void
4287 modest_ui_actions_on_check_names (GtkAction *action, ModestMsgEditWindow *window)
4288 {
4289         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4290         modest_msg_edit_window_check_names (window, FALSE);
4291 }
4292
4293 static void
4294 create_move_to_dialog_on_new_folder(GtkWidget *button, gpointer user_data)
4295 {
4296         modest_ui_actions_create_folder (gtk_widget_get_toplevel (button),
4297                                          GTK_WIDGET (user_data));
4298 }
4299
4300 /*
4301  * This function is used to track changes in the selection of the
4302  * folder view that is inside the "move to" dialog to enable/disable
4303  * the OK button because we do not want the user to select a disallowed
4304  * destination for a folder.
4305  * The user also not desired to be able to use NEW button on items where
4306  * folder creation is not possibel.
4307  */
4308 static void
4309 on_move_to_dialog_folder_selection_changed (ModestFolderView* self,
4310                                             TnyFolderStore *folder_store,
4311                                             gboolean selected,
4312                                             gpointer user_data)
4313 {
4314         GtkWidget *dialog = NULL;
4315         GtkWidget *ok_button = NULL, *new_button = NULL;
4316         GList *children = NULL;
4317         gboolean ok_sensitive = TRUE, new_sensitive = TRUE;
4318         gboolean moving_folder = FALSE;
4319         gboolean is_local_account = TRUE;
4320         GtkWidget *folder_view = NULL;
4321         ModestTnyFolderRules rules;
4322
4323         g_return_if_fail (MODEST_IS_FOLDER_VIEW(self));
4324         
4325         if (!selected)
4326                 return;
4327         
4328         /* Get the OK button */
4329         dialog = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_DIALOG);
4330         if (!dialog)
4331                 return;
4332
4333         children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
4334         ok_button = GTK_WIDGET (children->next->next->data);
4335         new_button = GTK_WIDGET (children->next->data);
4336         g_list_free (children);
4337
4338         /* check if folder_store is an remote account */
4339         if (TNY_IS_ACCOUNT (folder_store)) {
4340                 TnyAccount *local_account = NULL;
4341                 TnyAccount *mmc_account = NULL;
4342                 ModestTnyAccountStore *account_store = NULL;
4343
4344                 account_store = modest_runtime_get_account_store ();
4345                 local_account = modest_tny_account_store_get_local_folders_account (account_store);
4346                 mmc_account = modest_tny_account_store_get_mmc_folders_account (account_store);
4347
4348                 if ((gpointer) local_account != (gpointer) folder_store &&
4349                     (gpointer) mmc_account != (gpointer) folder_store) {
4350                         const char *proto_name = tny_account_get_proto (TNY_ACCOUNT (folder_store));
4351                         ModestTransportStoreProtocol proto = MODEST_PROTOCOL_STORE_MAILDIR;
4352                         if (proto_name != NULL) {
4353                                 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
4354                         }
4355                         is_local_account = FALSE;
4356                         /* New button should be dimmed on remote
4357                            POP account root */
4358                         new_sensitive = (proto != MODEST_PROTOCOL_STORE_POP);
4359                 }
4360                 g_object_unref (local_account);
4361                 g_object_unref (mmc_account);
4362         }
4363
4364         /* Check the target folder rules */
4365         if (TNY_IS_FOLDER (folder_store)) {
4366                 rules = modest_tny_folder_get_rules (TNY_FOLDER (folder_store));
4367                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
4368                         ok_sensitive = FALSE;
4369                         new_sensitive = FALSE;
4370                         goto end;
4371                 }
4372         }
4373
4374         /* Check if we're moving a folder */
4375         if (MODEST_IS_MAIN_WINDOW (user_data)) {
4376                 /* Get the widgets */
4377                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (user_data),
4378                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4379                 if (gtk_widget_is_focus (folder_view))
4380                         moving_folder = TRUE;
4381         }
4382
4383         if (moving_folder) {
4384                 TnyFolderStore *moved_folder = NULL, *parent = NULL;
4385
4386                 /* Get the folder to move */
4387                 moved_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
4388                 
4389                 /* Check that we're not moving to the same folder */
4390                 if (TNY_IS_FOLDER (moved_folder)) {
4391                         parent = tny_folder_get_folder_store (TNY_FOLDER (moved_folder));
4392                         if (parent == folder_store)
4393                                 ok_sensitive = FALSE;
4394                         g_object_unref (parent);
4395                 } 
4396
4397                 if (ok_sensitive && TNY_IS_ACCOUNT (folder_store)) {
4398                         /* Do not allow to move to an account unless it's the
4399                            local folders account */
4400                         if (!is_local_account)
4401                                 ok_sensitive = FALSE;
4402                 } 
4403
4404                 if (ok_sensitive && (moved_folder == folder_store)) {
4405                         /* Do not allow to move to itself */
4406                         ok_sensitive = FALSE;
4407                 }
4408                 g_object_unref (moved_folder);
4409         } else {
4410                 TnyFolder *src_folder = NULL;
4411
4412                 /* Moving a message */
4413                 if (MODEST_IS_MSG_VIEW_WINDOW (user_data)) {
4414
4415                         TnyHeader *header = NULL;
4416                         header = modest_msg_view_window_get_header
4417                                 (MODEST_MSG_VIEW_WINDOW (user_data));
4418                         if (!TNY_IS_HEADER(header))
4419                                 g_warning ("%s: could not get source header", __FUNCTION__);
4420                         else
4421                                 src_folder = tny_header_get_folder (header);
4422
4423                         if (header)
4424                                 g_object_unref (header);
4425                 } else {
4426                         src_folder = 
4427                                 TNY_FOLDER (modest_folder_view_get_selected
4428                                             (MODEST_FOLDER_VIEW (folder_view)));
4429                 }
4430
4431                 if (TNY_IS_FOLDER(src_folder)) {
4432                         /* Do not allow to move the msg to the same folder */
4433                         /* Do not allow to move the msg to an account */
4434                         if ((gpointer) src_folder == (gpointer) folder_store ||
4435                             TNY_IS_ACCOUNT (folder_store))
4436                                 ok_sensitive = FALSE;
4437                         g_object_unref (src_folder);
4438                 } else
4439                         g_warning ("%s: could not get source folder", __FUNCTION__);
4440         }
4441
4442  end:
4443         /* Set sensitivity of the OK button */
4444         gtk_widget_set_sensitive (ok_button, ok_sensitive);
4445         /* Set sensitivity of the NEW button */
4446         gtk_widget_set_sensitive (new_button, new_sensitive);
4447 }
4448
4449
4450 #define MODEST_MOVE_TO_DIALOG_FOLDER_VIEW "move-to-dialog-folder-view"
4451
4452 static GtkWidget*
4453 get_folder_view_from_move_to_dialog (GtkWidget *move_to_dialog)
4454 {
4455         return GTK_WIDGET(g_object_get_data (G_OBJECT(move_to_dialog),
4456                                              MODEST_MOVE_TO_DIALOG_FOLDER_VIEW));
4457 }
4458
4459 static GtkWidget*
4460 create_move_to_dialog (GtkWindow *win,
4461                        GtkWidget *folder_view,
4462                        GtkWidget **tree_view)
4463 {
4464         GtkWidget *dialog, *scroll;
4465         GtkWidget *new_button;
4466
4467         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
4468                                               GTK_WINDOW (win),
4469                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
4470                                               NULL);
4471
4472         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
4473         /* We do this manually so GTK+ does not associate a response ID for
4474          * the button. */
4475         new_button = gtk_button_new_from_stock (_("mcen_bd_new"));
4476         gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->action_area), new_button, FALSE, FALSE, 0);
4477         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_dialog_cancel"), GTK_RESPONSE_REJECT);
4478
4479         /* Create scrolled window */
4480         scroll = gtk_scrolled_window_new (NULL, NULL);
4481         gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW (scroll),
4482                                          GTK_POLICY_AUTOMATIC,
4483                                          GTK_POLICY_AUTOMATIC);
4484
4485         /* Create folder view */
4486         *tree_view = modest_platform_create_folder_view (NULL);
4487
4488         /* Track changes in the selection to
4489          * disable the OK button whenever "Move to" is not possible
4490          * disbale NEW button whenever New is not possible */
4491         g_signal_connect (*tree_view,
4492                           "folder_selection_changed",
4493                           G_CALLBACK (on_move_to_dialog_folder_selection_changed),
4494                           win);
4495
4496         /* Listen to clicks on New button */
4497         g_signal_connect (G_OBJECT (new_button), 
4498                           "clicked", 
4499                           G_CALLBACK(create_move_to_dialog_on_new_folder), 
4500                           *tree_view);
4501
4502         /* It could happen that we're trying to move a message from a
4503            window (msg window for example) after the main window was
4504            closed, so we can not just get the model of the folder
4505            view */
4506         if (MODEST_IS_FOLDER_VIEW (folder_view)) {
4507                 const gchar *visible_id = NULL;
4508
4509                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (*tree_view),
4510                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4511                 modest_folder_view_copy_model (MODEST_FOLDER_VIEW(folder_view), 
4512                                                MODEST_FOLDER_VIEW(*tree_view));
4513
4514                 visible_id = 
4515                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view));
4516
4517                 /* Show the same account than the one that is shown in the main window */
4518                 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(*tree_view), 
4519                                                                              visible_id);
4520         } else {
4521                 const gchar *active_account_name = NULL;
4522                 ModestAccountMgr *mgr = NULL;
4523                 ModestAccountSettings *settings = NULL;
4524                 ModestServerAccountSettings *store_settings = NULL;
4525
4526                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (*tree_view),
4527                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4528                 modest_folder_view_update_model (MODEST_FOLDER_VIEW (*tree_view), 
4529                                                  TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
4530
4531                 active_account_name = modest_window_get_active_account (MODEST_WINDOW (win));
4532                 mgr = modest_runtime_get_account_mgr ();
4533                 settings = modest_account_mgr_load_account_settings (mgr, active_account_name);
4534
4535                 if (settings) {
4536                         const gchar *store_account_name;
4537                         store_settings = modest_account_settings_get_store_settings (settings);
4538                         store_account_name = modest_server_account_settings_get_account_name (store_settings);
4539
4540                         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (*tree_view),
4541                                                                                      store_account_name);
4542                         g_object_unref (store_settings);
4543                         g_object_unref (settings);
4544                 }
4545         }
4546
4547         /* we keep a pointer to the embedded folder view, so we can retrieve it with
4548          *   get_folder_view_from_move_to_dialog 
4549          * (see above) later (needed for focus handling) 
4550          */
4551         g_object_set_data (G_OBJECT(dialog), MODEST_MOVE_TO_DIALOG_FOLDER_VIEW, *tree_view);
4552
4553         
4554         /* Hide special folders */
4555         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (*tree_view), FALSE);
4556
4557         gtk_container_add (GTK_CONTAINER (scroll), *tree_view);
4558
4559         /* Add scroll to dialog */
4560         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), 
4561                             scroll, TRUE, TRUE, 0);
4562
4563         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
4564         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
4565
4566         return dialog;
4567 }
4568
4569
4570
4571 /*
4572  * Shows a confirmation dialog to the user when we're moving messages
4573  * from a remote server to the local storage. Returns the dialog
4574  * response. If it's other kind of movement then it always returns
4575  * GTK_RESPONSE_OK
4576  *
4577  * This one is used by the next functions:
4578  *      modest_ui_actions_on_paste                      - commented out
4579  *      drag_and_drop_from_header_view (for d&d in modest_folder_view.c)
4580  */
4581 gint
4582 modest_ui_actions_msgs_move_to_confirmation (ModestWindow *win,
4583                                              TnyFolder *dest_folder,
4584                                              gboolean delete,
4585                                              TnyList *headers)
4586 {
4587         gint response = GTK_RESPONSE_OK;
4588         TnyAccount *account = NULL;
4589         TnyFolder *src_folder = NULL;
4590         TnyIterator *iter = NULL;
4591         TnyHeader *header = NULL;
4592
4593         /* return with OK if the destination is a remote folder */
4594         if (modest_tny_folder_is_remote_folder (dest_folder))
4595                 return GTK_RESPONSE_OK;
4596
4597         /* Get source folder */
4598         iter = tny_list_create_iterator (headers);
4599         header = TNY_HEADER (tny_iterator_get_current (iter));
4600         if (header) {
4601                 src_folder = tny_header_get_folder (header);
4602                 g_object_unref (header);
4603         }
4604         g_object_unref (iter);
4605
4606         /* if no src_folder, message may be an attahcment */
4607         if (src_folder == NULL) 
4608                 return GTK_RESPONSE_CANCEL;
4609
4610         /* If the source is a local or MMC folder */
4611         if (!modest_tny_folder_is_remote_folder (src_folder)) {
4612                 g_object_unref (src_folder);
4613                 return GTK_RESPONSE_OK;
4614         }
4615
4616         /* Get the account */
4617         account = tny_folder_get_account (src_folder);
4618
4619         /* now if offline we ask the user */
4620         if(connect_to_get_msg (win, tny_list_get_length (headers), account))
4621                 response = GTK_RESPONSE_OK;
4622         else
4623                 response = GTK_RESPONSE_CANCEL;
4624
4625         /* Frees */
4626         g_object_unref (src_folder);
4627         g_object_unref (account);
4628
4629         return response;
4630 }
4631
4632 static void
4633 move_to_cb (ModestMailOperation *mail_op, 
4634             gpointer user_data)
4635 {
4636         MoveToHelper *helper = (MoveToHelper *) user_data;
4637
4638         /* Note that the operation could have failed, in that case do
4639            nothing */
4640         if (modest_mail_operation_get_status (mail_op) == 
4641             MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
4642
4643                 GObject *object = modest_mail_operation_get_source (mail_op);
4644                 if (MODEST_IS_MSG_VIEW_WINDOW (object)) {
4645                         ModestMsgViewWindow *self = MODEST_MSG_VIEW_WINDOW (object);
4646
4647                         if (!modest_msg_view_window_select_next_message (self) &&
4648                             !modest_msg_view_window_select_previous_message (self)) {
4649                                 /* No more messages to view, so close this window */
4650                                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW(self));
4651                         }
4652                 } else if (MODEST_IS_MAIN_WINDOW (object) && helper->reference != NULL) {
4653                         GtkWidget *header_view;
4654                         GtkTreePath *path;
4655                         GtkTreeSelection *sel;
4656
4657                         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(object),
4658                                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4659                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
4660                         path = gtk_tree_row_reference_get_path (helper->reference);
4661                         /* We need to unselect the previous one
4662                            because we could be copying instead of
4663                            moving */
4664                         gtk_tree_selection_unselect_all (sel);
4665                         gtk_tree_selection_select_path (sel, path);
4666                         gtk_tree_path_free (path);
4667                 }
4668                 g_object_unref (object);
4669         }
4670
4671         /* Close the "Pasting" information banner */
4672         gtk_widget_destroy (GTK_WIDGET(helper->banner));
4673         g_object_unref (helper->banner);
4674         if (helper->reference != NULL)
4675                 gtk_tree_row_reference_free (helper->reference);
4676         g_free (helper);
4677 }
4678
4679 static void
4680 folder_move_to_cb (ModestMailOperation *mail_op, 
4681                    TnyFolder *new_folder,
4682                    gpointer user_data)
4683 {
4684         GtkWidget *folder_view;
4685         GObject *object;
4686
4687         object = modest_mail_operation_get_source (mail_op);
4688         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(object),
4689                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
4690         g_object_ref (folder_view);
4691         g_object_unref (object);
4692         move_to_cb (mail_op, user_data);
4693         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), new_folder, FALSE);
4694         g_object_unref (folder_view);
4695 }
4696
4697 static void
4698 msgs_move_to_cb (ModestMailOperation *mail_op, 
4699                  gpointer user_data)
4700 {
4701         move_to_cb (mail_op, user_data);
4702 }
4703
4704 void
4705 modest_ui_actions_move_folder_error_handler (ModestMailOperation *mail_op, 
4706                                              gpointer user_data)
4707 {
4708         ModestWindow *main_window = NULL;
4709         
4710         /* Disable next automatic folder selection */
4711         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
4712                                                          FALSE); /* don't create */
4713         if (main_window) {
4714                 GObject *win = NULL;
4715                 GtkWidget *folder_view = NULL;
4716         
4717                 folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (main_window),
4718                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW); 
4719                 modest_folder_view_disable_next_folder_selection (MODEST_FOLDER_VIEW(folder_view));
4720                 
4721                 if (user_data && TNY_IS_FOLDER (user_data)) {
4722                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), 
4723                                                           TNY_FOLDER (user_data), FALSE);
4724                 }
4725
4726                 /* Show notification dialog only if the main window exists */
4727                 win = modest_mail_operation_get_source (mail_op);
4728                 modest_platform_run_information_dialog ((GtkWindow *) win, 
4729                                                         _("mail_in_ui_folder_move_target_error"), 
4730                                                         FALSE);
4731                 if (win)
4732                         g_object_unref (win);
4733         }
4734 }
4735
4736 static void
4737 open_msg_for_purge_cb (ModestMailOperation *mail_op, 
4738                        TnyHeader *header, 
4739                        gboolean canceled,
4740                        TnyMsg *msg, 
4741                        GError *err,
4742                        gpointer user_data)
4743 {
4744         TnyList *parts;
4745         TnyIterator *iter;
4746         gint pending_purges = 0;
4747         gboolean some_purged = FALSE;
4748         ModestWindow *win = MODEST_WINDOW (user_data);
4749         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
4750
4751         /* If there was any error */
4752         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
4753                 modest_window_mgr_unregister_header (mgr, header);
4754                 return;
4755         }
4756
4757         /* Once the message has been retrieved for purging, we check if
4758          * it's all ok for purging */
4759
4760         parts = tny_simple_list_new ();
4761         tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
4762         iter = tny_list_create_iterator (parts);
4763
4764         while (!tny_iterator_is_done (iter)) {
4765                 TnyMimePart *part;
4766                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
4767                 if (part && (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part))) {
4768                         if (tny_mime_part_is_purged (part))
4769                                 some_purged = TRUE;
4770                         else
4771                                 pending_purges++;
4772                 }
4773
4774                 if (part)
4775                         g_object_unref (part);
4776
4777                 tny_iterator_next (iter);
4778         }
4779         g_object_unref (iter);
4780         
4781
4782         if (pending_purges>0) {
4783                 gint response;
4784                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),_("mcen_nc_purge_file_text_inbox"));
4785
4786                 if (response == GTK_RESPONSE_OK) {
4787                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_removing_attachment"));
4788                         iter = tny_list_create_iterator (parts);
4789                         while (!tny_iterator_is_done (iter)) {
4790                                 TnyMimePart *part;
4791                                 
4792                                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
4793                                 if (part && (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part)))
4794                                         tny_mime_part_set_purged (part);
4795
4796                                 if (part)
4797                                         g_object_unref (part);
4798
4799                                 tny_iterator_next (iter);
4800                         }
4801                         g_object_unref (iter);
4802                         
4803                         tny_msg_rewrite_cache (msg);
4804                 }
4805      /* } else { */
4806                 /* This string no longer exists, refer to NB#75415 for more info */
4807                 /* modest_platform_information_banner (NULL, NULL, _("mail_ib_attachment_already_purged")); */
4808         }
4809
4810         modest_window_mgr_unregister_header (mgr, header);
4811
4812         g_object_unref (parts);
4813 }
4814
4815 static void
4816 modest_ui_actions_on_main_window_remove_attachments (GtkAction *action,
4817                                                      ModestMainWindow *win)
4818 {
4819         GtkWidget *header_view;
4820         TnyList *header_list;
4821         TnyHeader *header;
4822         TnyHeaderFlags flags;
4823         ModestWindow *msg_view_window =  NULL;
4824         gboolean found;
4825
4826         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
4827
4828         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
4829                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
4830
4831         header_list = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
4832         if (!header_list) {
4833                 g_warning ("%s: no header selected", __FUNCTION__);
4834                 return;
4835         }
4836         
4837         if (tny_list_get_length (header_list) == 1) {
4838                 TnyIterator *iter = tny_list_create_iterator (header_list);
4839                 header = TNY_HEADER (tny_iterator_get_current (iter));
4840                 g_object_unref (iter);
4841         } else
4842                 return;
4843         
4844         if (!header || !TNY_IS_HEADER(header)) {
4845                 g_warning ("%s: header is not valid", __FUNCTION__);
4846                 return;
4847         }
4848         
4849         found = modest_window_mgr_find_registered_header (modest_runtime_get_window_mgr (),
4850                                                           header, &msg_view_window);
4851         flags = tny_header_get_flags (header);
4852         if (!(flags & TNY_HEADER_FLAG_CACHED))
4853                 return;
4854         if (found) {
4855                 if (msg_view_window != NULL) 
4856                         modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (msg_view_window), TRUE);
4857                 else {
4858                         /* do nothing; uid was registered before, so window is probably on it's way */
4859                         g_warning ("debug: header %p has already been registered", header);
4860                 }
4861         } else {
4862                 ModestMailOperation *mail_op = NULL;
4863                 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), header, NULL);
4864                 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (win),
4865                                                                          modest_ui_actions_disk_operations_error_handler,
4866                                                                          NULL, NULL);
4867                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
4868                 modest_mail_operation_get_msg (mail_op, header, FALSE, open_msg_for_purge_cb, win);
4869                 
4870                 g_object_unref (mail_op);
4871         }
4872         if (header)
4873                 g_object_unref (header);
4874         if (header_list)
4875                 g_object_unref (header_list);
4876 }
4877
4878 /*
4879  * Checks if we need a connection to do the transfer and if the user
4880  * wants to connect to complete it
4881  */
4882 void
4883 modest_ui_actions_xfer_messages_check (GtkWindow *parent_window,
4884                                        TnyFolderStore *src_folder,
4885                                        TnyList *headers,
4886                                        TnyFolder *dst_folder,
4887                                        gboolean delete_originals,
4888                                        gboolean *need_connection,
4889                                        gboolean *do_xfer)
4890 {
4891         TnyAccount *src_account;
4892         gint uncached_msgs = 0;
4893
4894         uncached_msgs = header_list_count_uncached_msgs (headers);
4895
4896         /* We don't need any further check if
4897          *
4898          * 1- the source folder is local OR
4899          * 2- the device is already online
4900          */
4901         if (!modest_tny_folder_store_is_remote (src_folder) ||
4902             tny_device_is_online (modest_runtime_get_device())) {
4903                 *need_connection = FALSE;
4904                 *do_xfer = TRUE;
4905                 return;
4906         }
4907
4908         /* We must ask for a connection when
4909          *
4910          *   - the message(s) is not already cached   OR 
4911          *   - the message(s) is cached but the leave_on_server setting
4912          * is FALSE (because we need to sync the source folder to
4913          * delete the message from the server (for IMAP we could do it
4914          * offline, it'll take place the next time we get a
4915          * connection)
4916          */
4917         src_account = get_account_from_folder_store (src_folder);
4918         if (uncached_msgs > 0) {
4919                 guint num_headers;
4920                 const gchar *msg;
4921
4922                 *need_connection = TRUE;
4923                 num_headers = tny_list_get_length (headers);
4924                 msg = ngettext ("mcen_nc_get_msg", "mcen_nc_get_msgs", num_headers);
4925
4926                 if (modest_platform_run_confirmation_dialog (parent_window, msg) ==
4927                     GTK_RESPONSE_CANCEL) {
4928                         *do_xfer = FALSE;
4929                 } else {
4930                         *do_xfer = TRUE;
4931                 }
4932         } else {
4933                 /* The transfer is possible and the user wants to */
4934                 *do_xfer = TRUE;
4935
4936                 if (remote_folder_is_pop (src_folder) && delete_originals) {
4937                         const gchar *account_name;
4938                         gboolean leave_on_server;
4939                         
4940                         account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (src_account);
4941                         leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
4942                                                                                   account_name);
4943                         
4944                         if (leave_on_server == TRUE) {
4945                                 *need_connection = FALSE;
4946                         } else {
4947                                 *need_connection = TRUE;
4948                         }
4949                 } else {
4950                         *need_connection = FALSE;
4951                 }
4952         }
4953
4954         /* Frees */
4955         g_object_unref (src_account);
4956 }
4957
4958 static void
4959 xfer_messages_error_handler (ModestMailOperation *mail_op, 
4960                              gpointer user_data)
4961 {
4962         ModestWindow *main_window = NULL;
4963         
4964         /* Disable next automatic folder selection */
4965         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
4966                                                          FALSE); /* don't create */
4967         if (main_window) {
4968                 GObject *win = modest_mail_operation_get_source (mail_op);
4969                 modest_platform_run_information_dialog ((GtkWindow *) win, 
4970                                                         _("mail_in_ui_folder_move_target_error"), 
4971                                                         FALSE);
4972                 if (win)
4973                         g_object_unref (win);
4974         }
4975 }
4976
4977 /**
4978  * Utility function that transfer messages from both the main window
4979  * and the msg view window when using the "Move to" dialog
4980  */
4981 static void
4982 xfer_messages_performer  (gboolean canceled, 
4983                           GError *err,
4984                           GtkWindow *parent_window, 
4985                           TnyAccount *account, 
4986                           gpointer user_data)
4987 {
4988         TnyFolderStore *dst_folder = TNY_FOLDER_STORE (user_data);
4989         ModestWindow *win = MODEST_WINDOW (parent_window);
4990         TnyList *headers = NULL;
4991         TnyAccount *dst_account = NULL;
4992         const gchar *proto_str = NULL;
4993         gboolean dst_is_pop = FALSE;
4994
4995         if (canceled)
4996                 goto end;
4997
4998         if (err) {
4999                 if (is_memory_full_error (err)) {
5000                         modest_platform_information_banner ((GtkWidget *) parent_window,
5001                                                             NULL, dgettext("ke-recv",
5002                                                                            "cerm_device_memory_full"));
5003                 } else {
5004                         /* Show the proper error message */
5005                         modest_ui_actions_on_account_connection_error (parent_window, account);
5006                 }
5007                 goto end;
5008         }
5009
5010         dst_account = tny_folder_get_account (TNY_FOLDER (dst_folder));
5011         proto_str = tny_account_get_proto (dst_account);
5012
5013         /* tinymail will return NULL for local folders it seems */
5014         dst_is_pop = proto_str &&
5015                 (modest_protocol_info_get_transport_store_protocol (proto_str) == 
5016                  MODEST_PROTOCOL_STORE_POP);
5017
5018         g_object_unref (dst_account);
5019
5020         /* Get selected headers */
5021         headers = get_selected_headers (MODEST_WINDOW (win));
5022         if (!headers) {
5023                 g_warning ("%s: no headers selected", __FUNCTION__);
5024                 goto end;
5025         }
5026
5027         if (dst_is_pop) {
5028                 modest_platform_information_banner (GTK_WIDGET (win),
5029                                                     NULL,
5030                                                     ngettext("mail_in_ui_folder_move_target_error",
5031                                                              "mail_in_ui_folder_move_targets_error",
5032                                                              tny_list_get_length (headers)));
5033                 g_object_unref (headers);
5034                 goto end;
5035         }
5036
5037         MoveToHelper *helper = g_new0 (MoveToHelper, 1);
5038         helper->banner = modest_platform_animation_banner (GTK_WIDGET (win), NULL,
5039                                                            _CS("ckct_nw_pasting"));
5040         if (helper->banner != NULL)  {
5041                 g_object_ref (helper->banner);
5042                 gtk_window_set_modal (GTK_WINDOW(helper->banner), FALSE);
5043                 gtk_widget_show (GTK_WIDGET(helper->banner));
5044         }
5045
5046         if (MODEST_IS_MAIN_WINDOW (win)) {
5047                 GtkWidget *header_view = 
5048                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
5049                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5050                 helper->reference = get_next_after_selected_headers (MODEST_HEADER_VIEW (header_view));
5051         }
5052
5053         ModestMailOperation *mail_op = 
5054                 modest_mail_operation_new_with_error_handling (G_OBJECT(win),
5055                                                                xfer_messages_error_handler,
5056                                                                NULL, NULL);
5057         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
5058                                          mail_op);
5059
5060         modest_mail_operation_xfer_msgs (mail_op, 
5061                                          headers,
5062                                          TNY_FOLDER (dst_folder),
5063                                          TRUE,
5064                                          msgs_move_to_cb,
5065                                          helper);
5066
5067         g_object_unref (G_OBJECT (mail_op));
5068         g_object_unref (headers);
5069  end:
5070         g_object_unref (dst_folder);
5071 }
5072
5073 typedef struct {
5074         TnyFolder *src_folder;
5075         TnyFolderStore *dst_folder;
5076         gboolean delete_original;
5077         GtkWidget *folder_view;
5078 } MoveFolderInfo;
5079
5080 static void
5081 on_move_folder_cb (gboolean canceled, GError *err, GtkWindow *parent_window, 
5082                 TnyAccount *account, gpointer user_data)
5083 {
5084         MoveFolderInfo *info = (MoveFolderInfo*)user_data;
5085         GtkTreeSelection *sel;
5086         ModestMailOperation *mail_op = NULL;
5087         
5088         if (canceled || err || !MODEST_IS_MAIN_WINDOW (parent_window)) {
5089                 g_object_unref (G_OBJECT (info->src_folder));
5090                 g_object_unref (G_OBJECT (info->dst_folder));
5091                 g_free (info);
5092                 return;
5093         }
5094         
5095         MoveToHelper *helper = g_new0 (MoveToHelper, 1);
5096         helper->banner = modest_platform_animation_banner (GTK_WIDGET (parent_window), NULL,
5097                         _CS("ckct_nw_pasting"));
5098         if (helper->banner != NULL)  {
5099                 g_object_ref (helper->banner);
5100                 gtk_window_set_modal (GTK_WINDOW(helper->banner), FALSE);
5101                 gtk_widget_show (GTK_WIDGET(helper->banner));
5102         }
5103         /* Clean folder on header view before moving it */
5104         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (info->folder_view));
5105         gtk_tree_selection_unselect_all (sel);
5106
5107         /* Let gtk events run. We need that the folder
5108            view frees its reference to the source
5109            folder *before* issuing the mail operation
5110            so we need the signal handler of selection
5111            changed to happen before the mail
5112            operation 
5113         while (gtk_events_pending ())
5114                 gtk_main_iteration ();   */
5115
5116         mail_op =
5117                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
5118                                 modest_ui_actions_move_folder_error_handler,
5119                                 info->src_folder, NULL);
5120         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
5121                         mail_op);
5122
5123         /* Select *after* the changes */
5124         /* TODO: this function hangs UI after transfer */ 
5125         /*                      modest_folder_view_select_folder (MODEST_FOLDER_VIEW(folder_view), */
5126         /*                                                        TNY_FOLDER (src_folder), TRUE); */
5127
5128         modest_folder_view_select_folder (MODEST_FOLDER_VIEW(info->folder_view),
5129                                           TNY_FOLDER (info->dst_folder), TRUE);
5130         modest_mail_operation_xfer_folder (mail_op,
5131                         TNY_FOLDER (info->src_folder),
5132                         info->dst_folder,
5133                         info->delete_original, 
5134                         folder_move_to_cb, 
5135                         helper);
5136         g_object_unref (G_OBJECT (info->src_folder));
5137
5138         /* if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {        */
5139         /* } */
5140         
5141         /* Unref mail operation */
5142         g_object_unref (G_OBJECT (mail_op));
5143         g_object_unref (G_OBJECT (info->dst_folder));
5144         g_free (user_data);
5145 }
5146
5147 static TnyAccount *
5148 get_account_from_folder_store (TnyFolderStore *folder_store) 
5149 {
5150         if (TNY_IS_ACCOUNT (folder_store))
5151                 return g_object_ref (folder_store);
5152         else
5153                 return tny_folder_get_account (TNY_FOLDER (folder_store));
5154 }
5155
5156 /*
5157  * UI handler for the "Move to" action when invoked from the
5158  * ModestMainWindow
5159  */
5160 static void 
5161 modest_ui_actions_on_main_window_move_to (GtkAction *action, 
5162                                           GtkWidget *folder_view,
5163                                           TnyFolderStore *dst_folder,
5164                                           ModestMainWindow *win)
5165 {
5166         ModestHeaderView *header_view = NULL;
5167         TnyFolderStore *src_folder = NULL;
5168
5169         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win));
5170
5171         /* Get the source folder */
5172         src_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5173
5174         /* Get header view */
5175         header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
5176
5177         /* Get folder or messages to transfer */
5178         if (gtk_widget_is_focus (folder_view)) {
5179                 gboolean do_xfer = TRUE;
5180
5181                 /* Allow only to transfer folders to the local root folder */
5182                 if (TNY_IS_ACCOUNT (dst_folder) && 
5183                     !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (dst_folder) &&
5184                     !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (dst_folder))) {
5185                         do_xfer = FALSE;
5186                 } else if (!TNY_IS_FOLDER (src_folder)) {
5187                         g_warning ("%s: src_folder is not a TnyFolder.\n", __FUNCTION__);
5188                         do_xfer = FALSE;
5189                 }
5190
5191                 if (do_xfer) {                  
5192                         MoveFolderInfo *info = g_new0 (MoveFolderInfo, 1);
5193                         DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5194
5195                         info->src_folder = g_object_ref (src_folder);
5196                         info->dst_folder = g_object_ref (dst_folder);
5197                         info->delete_original = TRUE;
5198                         info->folder_view = folder_view;
5199
5200                         connect_info->callback = on_move_folder_cb;
5201                         connect_info->dst_account = get_account_from_folder_store (TNY_FOLDER_STORE (dst_folder));
5202                         connect_info->data = info;
5203
5204                         modest_platform_double_connect_and_perform(GTK_WINDOW (win), TRUE,
5205                                                                    TNY_FOLDER_STORE (src_folder), 
5206                                                                    connect_info);
5207                 }
5208         } else if (gtk_widget_is_focus (GTK_WIDGET(header_view))) {
5209                 TnyList *headers;
5210
5211                 headers = modest_header_view_get_selected_headers(header_view);
5212
5213                 /* Transfer the messages */
5214                 modest_ui_actions_transfer_messages_helper (GTK_WINDOW (win), TNY_FOLDER (src_folder), 
5215                                                             headers, TNY_FOLDER (dst_folder));
5216
5217                 g_object_unref (headers);
5218         }
5219
5220         /* Frees */
5221         g_object_unref (src_folder);
5222 }
5223
5224
5225 void
5226 modest_ui_actions_transfer_messages_helper (GtkWindow *win,
5227                                             TnyFolder *src_folder,
5228                                             TnyList *headers,
5229                                             TnyFolder *dst_folder)
5230 {
5231         gboolean need_connection = TRUE;
5232         gboolean do_xfer = TRUE;
5233         
5234         modest_ui_actions_xfer_messages_check (win, TNY_FOLDER_STORE (src_folder), 
5235                                                headers, TNY_FOLDER (dst_folder),
5236                                                TRUE, &need_connection, 
5237                                                &do_xfer);
5238
5239         /* If we don't want to transfer just return */
5240         if (!do_xfer)
5241                 return;
5242
5243         if (need_connection) {
5244                 DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5245                 connect_info->callback = xfer_messages_performer;
5246                 connect_info->dst_account = tny_folder_get_account (TNY_FOLDER (dst_folder));
5247                 connect_info->data = g_object_ref (dst_folder);
5248                 
5249                 modest_platform_double_connect_and_perform(GTK_WINDOW (win), TRUE,
5250                                                            TNY_FOLDER_STORE (src_folder), 
5251                                                            connect_info);
5252         } else {
5253                 TnyAccount *src_account = get_account_from_folder_store (TNY_FOLDER_STORE (src_folder));
5254                 xfer_messages_performer (FALSE, NULL, GTK_WINDOW (win),
5255                                          src_account, g_object_ref (dst_folder));
5256                 g_object_unref (src_account);
5257         }
5258 }
5259
5260 /*
5261  * UI handler for the "Move to" action when invoked from the
5262  * ModestMsgViewWindow
5263  */
5264 static void 
5265 modest_ui_actions_on_msg_view_window_move_to (GtkAction *action, 
5266                                               TnyFolderStore *dst_folder,
5267                                               ModestMsgViewWindow *win)
5268 {
5269         TnyList *headers = NULL;
5270         TnyHeader *header = NULL;
5271         TnyFolder *src_folder = NULL;
5272
5273         g_return_if_fail (TNY_IS_FOLDER (dst_folder));
5274
5275         /* Create header list */
5276         header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
5277         src_folder = TNY_FOLDER (tny_header_get_folder(header));
5278         headers = tny_simple_list_new ();
5279         tny_list_append (headers, G_OBJECT (header));
5280
5281         /* Transfer the messages */
5282         modest_ui_actions_transfer_messages_helper (GTK_WINDOW (win), src_folder, headers, 
5283                                                     TNY_FOLDER (dst_folder));
5284
5285         /* Frees */
5286         g_object_unref (header);
5287         g_object_unref (headers);
5288 }
5289
5290 void 
5291 modest_ui_actions_on_move_to (GtkAction *action, 
5292                               ModestWindow *win)
5293 {
5294         GtkWidget *dialog = NULL, *folder_view = NULL, *tree_view = NULL;
5295         gint result = 0;
5296         TnyFolderStore *dst_folder = NULL;
5297         ModestMainWindow *main_window;
5298
5299         g_return_if_fail (MODEST_IS_MAIN_WINDOW (win) ||
5300                           MODEST_IS_MSG_VIEW_WINDOW (win));
5301
5302         /* Get the main window if exists */
5303         if (MODEST_IS_MAIN_WINDOW (win))
5304                 main_window = MODEST_MAIN_WINDOW (win);
5305         else
5306                 main_window = 
5307                         MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
5308                                                                                FALSE)); /* don't create */
5309
5310         /* Get the folder view widget if exists */
5311         if (main_window)
5312                 folder_view = modest_main_window_get_child_widget (main_window,
5313                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5314         else
5315                 folder_view = NULL;
5316
5317         /* Create and run the dialog */
5318         dialog = create_move_to_dialog (GTK_WINDOW (win), folder_view, &tree_view);
5319         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (tree_view));
5320         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
5321         result = gtk_dialog_run (GTK_DIALOG(dialog));
5322         g_object_ref (tree_view);
5323         gtk_widget_destroy (dialog);
5324
5325         if (result != GTK_RESPONSE_ACCEPT)
5326                 return;
5327
5328         dst_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (tree_view));
5329         /* Do window specific stuff */
5330         if (MODEST_IS_MAIN_WINDOW (win)) {
5331                 modest_ui_actions_on_main_window_move_to (action,
5332                                 folder_view,
5333                                 dst_folder,
5334                                 MODEST_MAIN_WINDOW (win));
5335         } else {
5336                 modest_ui_actions_on_msg_view_window_move_to (action,
5337                                 dst_folder,
5338                                 MODEST_MSG_VIEW_WINDOW (win));
5339         }
5340
5341         if (dst_folder)
5342                 g_object_unref (dst_folder);
5343 }
5344
5345 /*
5346  * Calls #HeadersFunc for each header already selected in the main
5347  * window or the message currently being shown in the msg view window
5348  */
5349 static void
5350 do_headers_action (ModestWindow *win, 
5351                    HeadersFunc func,
5352                    gpointer user_data)
5353 {
5354         TnyList *headers_list = NULL;
5355         TnyIterator *iter = NULL;
5356         TnyHeader *header = NULL;
5357         TnyFolder *folder = NULL;
5358
5359         /* Get headers */
5360         headers_list = get_selected_headers (win);
5361         if (!headers_list)
5362                 return;
5363
5364         /* Get the folder */
5365         iter = tny_list_create_iterator (headers_list);
5366         header = TNY_HEADER (tny_iterator_get_current (iter));
5367         if (header) {
5368                 folder = tny_header_get_folder (header);
5369                 g_object_unref (header);
5370         }
5371
5372         /* Call the function for each header */
5373         while (!tny_iterator_is_done (iter)) {
5374                 header = TNY_HEADER (tny_iterator_get_current (iter));
5375                 func (header, win, user_data);
5376                 g_object_unref (header);
5377                 tny_iterator_next (iter);
5378         }
5379
5380         /* Trick: do a poke status in order to speed up the signaling
5381            of observers */
5382         tny_folder_poke_status (folder);
5383
5384         /* Frees */
5385         g_object_unref (folder);
5386         g_object_unref (iter);
5387         g_object_unref (headers_list);
5388 }
5389
5390 void 
5391 modest_ui_actions_view_attachment (GtkAction *action,
5392                                    ModestWindow *window)
5393 {
5394         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5395                 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (window), NULL);
5396         } else {
5397                 /* not supported window for this action */
5398                 g_return_if_reached ();
5399         }
5400 }
5401
5402 void
5403 modest_ui_actions_save_attachments (GtkAction *action,
5404                                     ModestWindow *window)
5405 {
5406         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5407
5408                 if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
5409                         return;
5410
5411                 modest_msg_view_window_save_attachments (MODEST_MSG_VIEW_WINDOW (window), NULL);
5412         } else {
5413                 /* not supported window for this action */
5414                 g_return_if_reached ();
5415         }
5416 }
5417
5418 void
5419 modest_ui_actions_remove_attachments (GtkAction *action,
5420                                       ModestWindow *window)
5421 {
5422         if (MODEST_IS_MAIN_WINDOW (window)) {
5423                 modest_ui_actions_on_main_window_remove_attachments (action, MODEST_MAIN_WINDOW (window));
5424         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5425                 modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (window), FALSE);
5426         } else {
5427                 /* not supported window for this action */
5428                 g_return_if_reached ();
5429         }
5430 }
5431
5432 void 
5433 modest_ui_actions_on_settings (GtkAction *action, 
5434                                ModestWindow *win)
5435 {
5436         GtkWidget *dialog;
5437
5438         dialog = modest_platform_get_global_settings_dialog ();
5439         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (win));
5440         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
5441         gtk_widget_show_all (dialog);
5442
5443         gtk_dialog_run (GTK_DIALOG (dialog));
5444
5445         gtk_widget_destroy (dialog);
5446 }
5447
5448 void 
5449 modest_ui_actions_on_help (GtkAction *action, 
5450                            GtkWindow *win)
5451 {
5452         const gchar *help_id;
5453
5454         g_return_if_fail (action);
5455         g_return_if_fail (win && GTK_IS_WINDOW(win));
5456         
5457         help_id = modest_window_mgr_get_help_id (modest_runtime_get_window_mgr(), win);
5458         
5459         if (help_id)
5460                 modest_platform_show_help (GTK_WINDOW (win), help_id);
5461         else
5462                 g_warning ("%s: no help for window %p", __FUNCTION__, win);
5463 }
5464
5465 static void
5466 retrieve_msg_contents_performer (gboolean canceled, 
5467                                  GError *err,
5468                                  GtkWindow *parent_window, 
5469                                  TnyAccount *account, 
5470                                  gpointer user_data)
5471 {
5472         ModestMailOperation *mail_op;
5473         TnyList *headers = TNY_LIST (user_data);
5474
5475         if (err || canceled) {
5476                 if (err && is_memory_full_error (err)) {
5477                         modest_platform_information_banner ((GtkWidget *) parent_window,
5478                                                             NULL, dgettext("ke-recv",
5479                                                                            "cerm_device_memory_full"));
5480                 }
5481                 goto out;
5482         }
5483
5484         /* Create mail operation */
5485         mail_op = modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
5486                                                                  modest_ui_actions_disk_operations_error_handler, 
5487                                                                  NULL, NULL);
5488         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
5489         modest_mail_operation_get_msgs_full (mail_op, headers, NULL, NULL, NULL);
5490
5491         /* Frees */
5492         g_object_unref (mail_op);
5493  out:
5494         g_object_unref (headers);
5495         g_object_unref (account);
5496 }
5497
5498 void 
5499 modest_ui_actions_on_retrieve_msg_contents (GtkAction *action,
5500                                             ModestWindow *window)
5501 {
5502         TnyList *headers = NULL;
5503         TnyAccount *account = NULL;
5504         TnyIterator *iter = NULL;
5505         TnyHeader *header = NULL;
5506         TnyFolder *folder = NULL;
5507
5508         /* Get headers */
5509         headers = get_selected_headers (window);
5510         if (!headers)
5511                 return;
5512
5513         /* Pick the account */
5514         iter = tny_list_create_iterator (headers);
5515         header = TNY_HEADER (tny_iterator_get_current (iter));
5516         folder = tny_header_get_folder (header);
5517         account = tny_folder_get_account (folder);
5518         g_object_unref (folder);
5519         g_object_unref (header);
5520         g_object_unref (iter);
5521
5522         /* Connect and perform the message retrieval */
5523         modest_platform_connect_and_perform ((GtkWindow *) window, TRUE,
5524                                              g_object_ref (account), 
5525                                              retrieve_msg_contents_performer, 
5526                                              g_object_ref (headers));
5527
5528         /* Frees */
5529         g_object_unref (account);
5530         g_object_unref (headers);
5531 }
5532
5533 void
5534 modest_ui_actions_check_toolbar_dimming_rules (ModestWindow *window)
5535 {
5536         g_return_if_fail (MODEST_IS_WINDOW (window));
5537
5538         /* Update dimmed */
5539         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_TOOLBAR);
5540 }
5541
5542 void
5543 modest_ui_actions_check_menu_dimming_rules (ModestWindow *window)
5544 {
5545         g_return_if_fail (MODEST_IS_WINDOW (window));
5546
5547         /* Update dimmed */
5548         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_MENU);
5549 }
5550
5551 void
5552 modest_ui_actions_on_email_menu_activated (GtkAction *action,
5553                                           ModestWindow *window)
5554 {
5555         g_return_if_fail (MODEST_IS_WINDOW (window));
5556         
5557         /* Update dimmed */
5558         modest_ui_actions_check_menu_dimming_rules (window);
5559 }
5560
5561 void
5562 modest_ui_actions_on_edit_menu_activated (GtkAction *action,
5563                                           ModestWindow *window)
5564 {
5565         g_return_if_fail (MODEST_IS_WINDOW (window));
5566
5567         /* Update dimmed */
5568         modest_ui_actions_check_menu_dimming_rules (window);
5569 }
5570
5571 void
5572 modest_ui_actions_on_view_menu_activated (GtkAction *action,
5573                                           ModestWindow *window)
5574 {
5575         g_return_if_fail (MODEST_IS_WINDOW (window));
5576
5577         /* Update dimmed */
5578         modest_ui_actions_check_menu_dimming_rules (window);
5579 }
5580
5581 void
5582 modest_ui_actions_on_format_menu_activated (GtkAction *action,
5583                                             ModestWindow *window)
5584 {
5585         g_return_if_fail (MODEST_IS_WINDOW (window));
5586
5587         /* Update dimmed */
5588         modest_ui_actions_check_menu_dimming_rules (window);
5589 }
5590
5591 void
5592 modest_ui_actions_on_tools_menu_activated (GtkAction *action,
5593                                           ModestWindow *window)
5594 {
5595         g_return_if_fail (MODEST_IS_WINDOW (window));
5596
5597         /* Update dimmed */
5598         modest_ui_actions_check_menu_dimming_rules (window);
5599 }
5600
5601 void
5602 modest_ui_actions_on_attachment_menu_activated (GtkAction *action,
5603                                           ModestWindow *window)
5604 {
5605         g_return_if_fail (MODEST_IS_WINDOW (window));
5606
5607         /* Update dimmed */
5608         modest_ui_actions_check_menu_dimming_rules (window);
5609 }
5610
5611 void
5612 modest_ui_actions_on_toolbar_csm_menu_activated (GtkAction *action,
5613                                                  ModestWindow *window)
5614 {
5615         g_return_if_fail (MODEST_IS_WINDOW (window));
5616
5617         /* Update dimmed */
5618         modest_ui_actions_check_menu_dimming_rules (window);
5619 }
5620
5621 void
5622 modest_ui_actions_on_folder_view_csm_menu_activated (GtkAction *action,
5623                                                      ModestWindow *window)
5624 {
5625         g_return_if_fail (MODEST_IS_WINDOW (window));
5626
5627         /* Update dimmed */
5628         modest_ui_actions_check_menu_dimming_rules (window);
5629 }
5630
5631 void
5632 modest_ui_actions_on_header_view_csm_menu_activated (GtkAction *action,
5633                                                      ModestWindow *window)
5634 {
5635         g_return_if_fail (MODEST_IS_WINDOW (window));
5636
5637         /* Update dimmed */
5638         modest_ui_actions_check_menu_dimming_rules (window);
5639 }
5640
5641 void
5642 modest_ui_actions_on_search_messages (GtkAction *action, ModestWindow *window)
5643 {
5644         g_return_if_fail (MODEST_IS_WINDOW (window));
5645
5646         /* we check for low-mem; in that case, show a warning, and don't allow
5647          * searching
5648          */
5649         if (modest_platform_check_memory_low (window))
5650                 return;
5651         
5652         modest_platform_show_search_messages (GTK_WINDOW (window));
5653 }
5654
5655 void     
5656 modest_ui_actions_on_open_addressbook (GtkAction *action, ModestWindow *win)
5657 {
5658         g_return_if_fail (MODEST_IS_WINDOW (win));
5659
5660
5661         /* we check for low-mem; in that case, show a warning, and don't allow
5662          * for the addressbook
5663          */
5664         if (modest_platform_check_memory_low (win))
5665                 return;
5666
5667
5668         modest_platform_show_addressbook (GTK_WINDOW (win));
5669 }
5670
5671
5672 void
5673 modest_ui_actions_on_toggle_find_in_page (GtkToggleAction *action,
5674                                           ModestWindow *window)
5675 {
5676         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
5677
5678         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window), gtk_toggle_action_get_active (action));
5679 }
5680
5681 static void 
5682 on_send_receive_finished (ModestMailOperation  *mail_op, 
5683                            gpointer user_data)
5684 {
5685         GtkWidget *header_view, *folder_view;
5686         TnyFolderStore *folder_store;
5687         ModestMainWindow *main_win = MODEST_MAIN_WINDOW (user_data);
5688
5689         /* Set send/receive operation finished */       
5690         modest_main_window_notify_send_receive_completed (main_win);
5691
5692         /* Don't refresh the current folder if there were any errors */
5693         if (modest_mail_operation_get_status (mail_op) !=
5694             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
5695                 return;
5696         
5697         /* Refresh the current folder if we're viewing a window. We do
5698            this because the user won't be able to see the new mails in
5699            the selected folder after a Send&Receive because it only
5700            performs a poke_status, i.e, only the number of read/unread
5701            messages is updated, but the new headers are not
5702            downloaded */
5703         folder_view = modest_main_window_get_child_widget (main_win, 
5704                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5705         if (!folder_view)
5706                 return;
5707
5708         folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5709         
5710         /* Do not need to refresh INBOX again because the
5711            update_account does it always automatically */
5712         if (folder_store && TNY_IS_FOLDER (folder_store) && 
5713             tny_folder_get_folder_type (TNY_FOLDER (folder_store)) != TNY_FOLDER_TYPE_INBOX) {
5714                 ModestMailOperation *refresh_op;
5715
5716                 header_view = modest_main_window_get_child_widget (main_win,
5717                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5718                 
5719                 /* We do not need to set the contents style
5720                    because it hasn't changed. We also do not
5721                    need to save the widget status. Just force
5722                    a refresh */
5723                 refresh_op = modest_mail_operation_new (G_OBJECT (main_win));
5724                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), refresh_op);
5725                 modest_mail_operation_refresh_folder (refresh_op, TNY_FOLDER (folder_store),
5726                                                       folder_refreshed_cb, main_win);
5727                 g_object_unref (refresh_op);
5728         }
5729         
5730         if (folder_store)
5731                 g_object_unref (folder_store);
5732 }
5733
5734
5735 void 
5736 modest_ui_actions_on_send_queue_error_happened (TnySendQueue *self, 
5737                                                 TnyHeader *header, 
5738                                                 TnyMsg *msg, 
5739                                                 GError *err, 
5740                                                 gpointer user_data)
5741 {
5742         const gchar* server_name = NULL;
5743         TnyTransportAccount *server_account;
5744         gchar *message = NULL;
5745
5746         /* Don't show anything if the user cancelled something or the send receive request is not
5747          * interactive */
5748         if (err->code == TNY_SYSTEM_ERROR_CANCEL ||
5749             !modest_tny_send_queue_get_requested_send_receive (MODEST_TNY_SEND_QUEUE (self)))
5750                 return;
5751
5752
5753         /* Get the server name: */
5754         server_account = 
5755                 TNY_TRANSPORT_ACCOUNT (tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (self)));
5756         if (server_account)
5757                 server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account));          
5758         else
5759                 g_return_if_reached ();
5760
5761         /* Show the appropriate message text for the GError: */
5762         switch (err->code) {
5763         case TNY_SERVICE_ERROR_CONNECT:
5764                 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
5765                 break;
5766         case TNY_SERVICE_ERROR_AUTHENTICATE:
5767                 message = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"), server_name);
5768                 break;
5769         case TNY_SERVICE_ERROR_SEND:
5770                 message = g_strdup (dgettext("hildon-common-strings", "sfil_ib_unable_to_send"));
5771                 break;
5772         case TNY_SERVICE_ERROR_UNAVAILABLE:
5773                 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
5774                 break;
5775         default:
5776                 g_warning ("%s: unexpected ERROR %d",
5777                            __FUNCTION__, err->code);
5778                 message = g_strdup (dgettext("hildon-common-strings", "sfil_ib_unable_to_send"));
5779                 break;  
5780         }
5781         
5782         /* TODO if the username or the password where not defined we
5783            should show the Accounts Settings dialog or the Connection
5784            specific SMTP server window */
5785
5786         modest_platform_run_information_dialog (NULL, message, FALSE);
5787         g_free (message);
5788         g_object_unref (server_account);
5789 }
5790
5791 void
5792 modest_ui_actions_on_send_queue_status_changed (ModestTnySendQueue *send_queue,
5793                                                 gchar *msg_id, 
5794                                                 guint status,
5795                                                 gpointer user_data)
5796 {
5797         ModestMainWindow *main_window = NULL;
5798         ModestWindowMgr *mgr = NULL;
5799         GtkWidget *folder_view = NULL, *header_view = NULL;
5800         TnyFolderStore *selected_folder = NULL;
5801         TnyFolderType folder_type;
5802
5803         mgr = modest_runtime_get_window_mgr ();
5804         main_window = MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (mgr,
5805                                                                              FALSE));/* don't create */
5806         if (!main_window)
5807                 return;
5808
5809         /* Check if selected folder is OUTBOX */
5810         folder_view = modest_main_window_get_child_widget (main_window,
5811                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
5812         header_view = modest_main_window_get_child_widget (main_window,
5813                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5814
5815         selected_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
5816         if (!TNY_IS_FOLDER (selected_folder)) 
5817                 goto frees;
5818
5819         /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
5820 #if GTK_CHECK_VERSION(2, 8, 0) 
5821         folder_type = modest_tny_folder_guess_folder_type (TNY_FOLDER (selected_folder)); 
5822         if (folder_type ==  TNY_FOLDER_TYPE_OUTBOX) {           
5823                 GtkTreeViewColumn *tree_column;
5824
5825                 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (header_view), 
5826                                                         TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN);
5827                 gtk_tree_view_column_queue_resize (tree_column);
5828         }
5829 #else
5830         gtk_widget_queue_draw (header_view);
5831 #endif          
5832
5833         /* Rerun dimming rules, because the message could become deletable for example */
5834         modest_window_check_dimming_rules_group (MODEST_WINDOW (main_window), 
5835                                                  MODEST_DIMMING_RULES_TOOLBAR);
5836         
5837         /* Free */
5838  frees:
5839         if (selected_folder != NULL)
5840                 g_object_unref (selected_folder);
5841 }
5842
5843 void 
5844 modest_ui_actions_on_account_connection_error (GtkWindow *parent_window,
5845                                                TnyAccount *account)
5846 {
5847         ModestTransportStoreProtocol proto;
5848         const gchar *proto_name;
5849         gchar *error_note = NULL;
5850         
5851         proto_name = tny_account_get_proto (account);
5852         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
5853         
5854         switch (proto) {
5855         case MODEST_PROTOCOL_STORE_POP:
5856                 error_note = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"), 
5857                                               tny_account_get_hostname (account));
5858                 break;
5859         case MODEST_PROTOCOL_STORE_IMAP:
5860                 error_note = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"), 
5861                                               tny_account_get_hostname (account));
5862                 break;
5863         case MODEST_PROTOCOL_STORE_MAILDIR:
5864         case MODEST_PROTOCOL_STORE_MBOX:
5865                 error_note = g_strdup (_("emev_nc_mailbox_notavailable"));
5866                 break;
5867         default:
5868                 g_warning ("%s: This should not be reached", __FUNCTION__);
5869         }
5870
5871         if (error_note) {
5872                 modest_platform_run_information_dialog (parent_window, error_note, FALSE);
5873                 g_free (error_note);
5874         }
5875 }
5876
5877 gchar *
5878 modest_ui_actions_get_msg_already_deleted_error_msg (ModestWindow *win)
5879 {
5880         gchar *msg = NULL;
5881         TnyFolderStore *folder = NULL;
5882         TnyAccount *account = NULL;
5883         ModestTransportStoreProtocol proto;
5884         TnyHeader *header = NULL;
5885
5886         if (MODEST_IS_MAIN_WINDOW (win)) {
5887                 GtkWidget *header_view;
5888                 TnyList* headers = NULL;
5889                 TnyIterator *iter;
5890                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
5891                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
5892                 headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
5893                 if (!headers || tny_list_get_length (headers) == 0) {
5894                         if (headers)
5895                                 g_object_unref (headers);
5896                         return NULL;
5897                 }
5898                 iter = tny_list_create_iterator (headers);
5899                 header = TNY_HEADER (tny_iterator_get_current (iter));
5900                 folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5901                 g_object_unref (iter);
5902                 g_object_unref (headers);
5903         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
5904                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
5905                 folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5906         }
5907
5908         /* Get the account type */
5909         account = tny_folder_get_account (TNY_FOLDER (folder));
5910         proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
5911         if (proto == MODEST_PROTOCOL_STORE_POP) {
5912                 msg = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
5913         } else if (proto == MODEST_PROTOCOL_STORE_IMAP) {
5914                 gchar *subject;
5915                 subject = tny_header_dup_subject (header);
5916                 msg = g_strdup_printf (_("emev_ni_ui_imap_message_not_available_in_server"), 
5917                                        subject);
5918                 g_free (subject);
5919         } else {
5920                 msg = g_strdup_printf (_("mail_ni_ui_folder_get_msg_folder_error"));
5921         }
5922
5923         /* Frees */
5924         g_object_unref (account);
5925         g_object_unref (folder);
5926         g_object_unref (header);
5927
5928         return msg;
5929 }