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