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