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