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