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