a0eb7702215cba004a06303e30fe2c14750820f8
[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 had_error = FALSE, add_to_contacts;
2837         MsgData *data;
2838         ModestAccountMgr *account_mgr;
2839         gchar *account_name;
2840         ModestMailOperation *mail_operation;
2841         gchar *recipients;
2842
2843         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), TRUE);
2844
2845         /* Check whether to automatically add new contacts to addressbook or not */
2846         add_to_contacts = modest_conf_get_bool (modest_runtime_get_conf (),
2847                                                 MODEST_CONF_AUTO_ADD_TO_CONTACTS, NULL);
2848         if (!modest_msg_edit_window_check_names (edit_window, add_to_contacts))
2849                 return TRUE;
2850
2851         data = modest_msg_edit_window_get_msg_data (edit_window);
2852
2853         recipients = g_strconcat (data->to?data->to:"", 
2854                                   data->cc?data->cc:"",
2855                                   data->bcc?data->bcc:"",
2856                                   NULL);
2857         if (recipients == NULL || recipients[0] == '\0') {
2858                 /* Empty subject -> no send */
2859                 g_free (recipients);
2860                 modest_msg_edit_window_free_msg_data (edit_window, data);
2861                 return FALSE;
2862         }
2863         g_free (recipients);
2864
2865         /* Check size */
2866         if (!enough_space_for_message (edit_window, data)) {
2867                 modest_msg_edit_window_free_msg_data (edit_window, data);
2868                 return FALSE;
2869         }
2870
2871         account_mgr = modest_runtime_get_account_mgr();
2872         account_name = g_strdup (data->account_name);
2873         if (!account_name)
2874                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2875
2876         if (!account_name)
2877                 account_name = modest_account_mgr_get_default_account (account_mgr);
2878
2879         if (!account_name) {
2880                 modest_msg_edit_window_free_msg_data (edit_window, data);
2881                 /* Run account setup wizard */
2882                 if (!modest_ui_actions_run_account_setup_wizard (MODEST_WINDOW(edit_window))) {
2883                         return TRUE;
2884                 }
2885         }
2886
2887         /* Get the currently-active transport account for this modest account: */
2888         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2889                 transport_account =
2890                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2891                                               (modest_runtime_get_account_store (),
2892                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2893         }
2894
2895         if (!transport_account) {
2896                 modest_msg_edit_window_free_msg_data (edit_window, data);
2897                 /* Run account setup wizard */
2898                 if (!modest_ui_actions_run_account_setup_wizard(MODEST_WINDOW(edit_window)))
2899                         return TRUE;
2900         }
2901
2902
2903         /* Create the mail operation */
2904         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
2905         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2906
2907         modest_mail_operation_send_new_mail (mail_operation,
2908                                              transport_account,
2909                                              data->draft_msg,
2910                                              data->from,
2911                                              data->to,
2912                                              data->cc,
2913                                              data->bcc,
2914                                              data->subject,
2915                                              data->plain_body,
2916                                              data->html_body,
2917                                              data->attachments,
2918                                              data->images,
2919                                              data->references,
2920                                              data->in_reply_to,
2921                                              data->priority_flags,
2922                                              data->custom_header_pairs);
2923
2924         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2925                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
2926
2927         if (modest_mail_operation_get_error (mail_operation) != NULL) {
2928                 const GError *error = modest_mail_operation_get_error (mail_operation);
2929                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
2930                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
2931                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
2932                         modest_platform_information_banner (NULL, NULL, _CS_NOT_ENOUGH_MEMORY);
2933                         had_error = TRUE;
2934                 }
2935         }
2936
2937         /* Free data: */
2938         g_free (account_name);
2939         g_object_unref (G_OBJECT (transport_account));
2940         g_object_unref (G_OBJECT (mail_operation));
2941
2942         modest_msg_edit_window_free_msg_data (edit_window, data);
2943
2944         if (!had_error) {
2945                 modest_msg_edit_window_set_sent (edit_window, TRUE);
2946
2947                 /* Save settings and close the window: */
2948                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2949         }
2950
2951         return !had_error;
2952 }
2953
2954 gboolean
2955 modest_ui_actions_on_send_msg (ModestWindow *window,
2956                                TnyMsg *msg)
2957 {
2958         TnyTransportAccount *transport_account = NULL;
2959         gboolean had_error = FALSE;
2960         ModestAccountMgr *account_mgr;
2961         gchar *account_name;
2962         ModestMailOperation *mail_operation;
2963
2964         account_mgr = modest_runtime_get_account_mgr();
2965         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(window)));
2966
2967         if (!account_name)
2968                 account_name = modest_account_mgr_get_default_account (account_mgr);
2969
2970         /* Get the currently-active transport account for this modest account: */
2971         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2972                 transport_account =
2973                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2974                                               (modest_runtime_get_account_store (),
2975                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2976         }
2977
2978         /* Create the mail operation */
2979         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
2980         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2981
2982         modest_mail_operation_send_mail (mail_operation,
2983                                          transport_account,
2984                                          msg);
2985
2986         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
2987                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
2988
2989         if (modest_mail_operation_get_error (mail_operation) != NULL) {
2990                 const GError *error = modest_mail_operation_get_error (mail_operation);
2991                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
2992                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
2993                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
2994                         modest_platform_information_banner (NULL, NULL, _CS("sfil_ni_not_enough_memory"));
2995                         had_error = TRUE;
2996                 }
2997         }
2998
2999         /* Free data: */
3000         g_free (account_name);
3001         g_object_unref (G_OBJECT (transport_account));
3002         g_object_unref (G_OBJECT (mail_operation));
3003
3004         return !had_error;
3005 }
3006
3007 void
3008 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
3009                                   ModestMsgEditWindow *window)
3010 {
3011         ModestMsgEditFormatState *format_state = NULL;
3012
3013         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3014         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3015
3016         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3017                 return;
3018
3019         format_state = modest_msg_edit_window_get_format_state (window);
3020         g_return_if_fail (format_state != NULL);
3021
3022         format_state->bold = gtk_toggle_action_get_active (action);
3023         modest_msg_edit_window_set_format_state (window, format_state);
3024         g_free (format_state);
3025
3026 }
3027
3028 void
3029 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
3030                                      ModestMsgEditWindow *window)
3031 {
3032         ModestMsgEditFormatState *format_state = NULL;
3033
3034         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3035         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3036
3037         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3038                 return;
3039
3040         format_state = modest_msg_edit_window_get_format_state (window);
3041         g_return_if_fail (format_state != NULL);
3042
3043         format_state->italics = gtk_toggle_action_get_active (action);
3044         modest_msg_edit_window_set_format_state (window, format_state);
3045         g_free (format_state);
3046
3047 }
3048
3049 void
3050 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
3051                                      ModestMsgEditWindow *window)
3052 {
3053         ModestMsgEditFormatState *format_state = NULL;
3054
3055         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3056         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3057
3058         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3059                 return;
3060
3061         format_state = modest_msg_edit_window_get_format_state (window);
3062         g_return_if_fail (format_state != NULL);
3063
3064         format_state->bullet = gtk_toggle_action_get_active (action);
3065         modest_msg_edit_window_set_format_state (window, format_state);
3066         g_free (format_state);
3067
3068 }
3069
3070 void
3071 modest_ui_actions_on_change_justify (GtkRadioAction *action,
3072                                      GtkRadioAction *selected,
3073                                      ModestMsgEditWindow *window)
3074 {
3075         ModestMsgEditFormatState *format_state = NULL;
3076         GtkJustification value;
3077
3078         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3079
3080         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3081                 return;
3082
3083         value = gtk_radio_action_get_current_value (selected);
3084
3085         format_state = modest_msg_edit_window_get_format_state (window);
3086         g_return_if_fail (format_state != NULL);
3087
3088         format_state->justification = value;
3089         modest_msg_edit_window_set_format_state (window, format_state);
3090         g_free (format_state);
3091 }
3092
3093 void
3094 modest_ui_actions_on_select_editor_color (GtkAction *action,
3095                                           ModestMsgEditWindow *window)
3096 {
3097         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3098         g_return_if_fail (GTK_IS_ACTION (action));
3099
3100         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3101                 return;
3102
3103         modest_msg_edit_window_select_color (window);
3104 }
3105
3106 void
3107 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
3108                                                      ModestMsgEditWindow *window)
3109 {
3110         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3111         g_return_if_fail (GTK_IS_ACTION (action));
3112
3113         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3114                 return;
3115
3116 }
3117
3118 void
3119 modest_ui_actions_on_insert_image (GObject *object,
3120                                    ModestMsgEditWindow *window)
3121 {
3122         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3123
3124
3125         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3126                 return;
3127
3128         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3129                 return;
3130
3131         modest_msg_edit_window_insert_image (window);
3132 }
3133
3134 void
3135 modest_ui_actions_on_attach_file (GtkAction *action,
3136                                   ModestMsgEditWindow *window)
3137 {
3138         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3139         g_return_if_fail (GTK_IS_ACTION (action));
3140
3141         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3142                 return;
3143
3144         modest_msg_edit_window_offer_attach_file (window);
3145 }
3146
3147 void
3148 modest_ui_actions_on_remove_attachments (GtkAction *action,
3149                                          ModestMsgEditWindow *window)
3150 {
3151         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3152
3153         modest_msg_edit_window_remove_attachments (window, NULL);
3154 }
3155
3156 static void
3157 do_create_folder_cb (ModestMailOperation *mail_op,
3158                      TnyFolderStore *parent_folder,
3159                      TnyFolder *new_folder,
3160                      gpointer user_data)
3161 {
3162         gchar *suggested_name = (gchar *) user_data;
3163         GtkWindow *source_win = (GtkWindow *) modest_mail_operation_get_source (mail_op);
3164         const GError *error;
3165
3166         error = modest_mail_operation_get_error (mail_op);
3167         if (error) {
3168                 gboolean disk_full = FALSE;
3169                 TnyAccount *account;
3170                 /* Show an error. If there was some problem writing to
3171                    disk, show it, otherwise show the generic folder
3172                    create error. We do it here and not in an error
3173                    handler because the call to do_create_folder will
3174                    stop the main loop in a gtk_dialog_run and then,
3175                    the message won't be shown until that dialog is
3176                    closed */
3177                 account = modest_mail_operation_get_account (mail_op);
3178                 if (account) {
3179                         disk_full =
3180                                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3181                                                                                 (GtkWidget *) source_win,
3182                                                                                 (GError *) error,
3183                                                                                 account,
3184                                                                                 _("mail_in_ui_folder_create_error_memory"));
3185                         g_object_unref (account);
3186                 }
3187                 if (!disk_full) {
3188                         /* Show an error and try again if there is no
3189                            full memory condition */
3190                         modest_platform_information_banner ((GtkWidget *) source_win, NULL,
3191                                                             _("mail_in_ui_folder_create_error"));
3192                         do_create_folder ((ModestWindow *) source_win,
3193                                           parent_folder, (const gchar *) suggested_name);
3194                 }
3195
3196         } else {
3197                 /* the 'source_win' is either the ModestWindow, or the 'Move to folder'-dialog
3198                  * FIXME: any other? */
3199                 GtkWidget *folder_view;
3200
3201                         folder_view = GTK_WIDGET(g_object_get_data (G_OBJECT (source_win),
3202                                                                     MODEST_MOVE_TO_DIALOG_FOLDER_VIEW));
3203
3204                 /* Select the newly created folder. It could happen
3205                    that the widget is no longer there (i.e. the window
3206                    has been destroyed, so we need to check this */
3207                 if (folder_view)
3208                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view),
3209                                                           new_folder, FALSE);
3210                 g_object_unref (new_folder);
3211         }
3212         /* Free. Note that the first time it'll be NULL so noop */
3213         g_free (suggested_name);
3214         g_object_unref (source_win);
3215 }
3216
3217 typedef struct {
3218         gchar *folder_name;
3219         TnyFolderStore *parent;
3220 } CreateFolderConnect;
3221
3222 static void
3223 do_create_folder_performer (gboolean canceled,
3224                             GError *err,
3225                             ModestWindow *parent_window,
3226                             TnyAccount *account,
3227                             gpointer user_data)
3228 {
3229         CreateFolderConnect *helper = (CreateFolderConnect *) user_data;
3230         ModestMailOperation *mail_op;
3231
3232         if (canceled || err) {
3233                 /* In disk full conditions we could get this error here */
3234                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3235                                                                 (GtkWidget *) parent_window, err,
3236                                                                 NULL, _("mail_in_ui_folder_create_error_memory"));
3237
3238                 /* This happens if we have selected the outbox folder
3239                    as the parent */
3240                 if (err && err->code == TNY_SERVICE_ERROR_UNKNOWN &&
3241                     TNY_IS_MERGE_FOLDER (helper->parent)) {
3242                         /* Show an error and retry */
3243                         modest_platform_information_banner ((GtkWidget *) parent_window,
3244                                                             NULL,
3245                                                             _("mail_in_ui_folder_create_error"));
3246
3247                         do_create_folder (parent_window, helper->parent, helper->folder_name);
3248                 }
3249
3250                 goto frees;
3251         }
3252
3253         mail_op  = modest_mail_operation_new ((GObject *) parent_window);
3254         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3255                                          mail_op);
3256         modest_mail_operation_create_folder (mail_op,
3257                                              helper->parent,
3258                                              (const gchar *) helper->folder_name,
3259                                              do_create_folder_cb,
3260                                              g_strdup (helper->folder_name));
3261         g_object_unref (mail_op);
3262
3263  frees:
3264         if (helper->parent)
3265                 g_object_unref (helper->parent);
3266         if (helper->folder_name)
3267                 g_free (helper->folder_name);
3268         g_slice_free (CreateFolderConnect, helper);
3269 }
3270
3271
3272 static void
3273 do_create_folder (ModestWindow *parent_window,
3274                   TnyFolderStore *suggested_parent,
3275                   const gchar *suggested_name)
3276 {
3277         gint result;
3278         gchar *folder_name = NULL;
3279         TnyFolderStore *parent_folder = NULL;
3280         GtkWindow *toplevel;
3281
3282         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) parent_window);
3283         result = modest_platform_run_new_folder_dialog (toplevel,
3284                                                         suggested_parent,
3285                                                         (gchar *) suggested_name,
3286                                                         &folder_name,
3287                                                         &parent_folder);
3288
3289         if (result == GTK_RESPONSE_ACCEPT && parent_folder) {
3290                 CreateFolderConnect *helper = (CreateFolderConnect *) g_slice_new0 (CreateFolderConnect);
3291                 helper->folder_name = g_strdup (folder_name);
3292                 helper->parent = g_object_ref (parent_folder);
3293
3294                 modest_platform_connect_if_remote_and_perform (parent_window,
3295                                                                TRUE,
3296                                                                parent_folder,
3297                                                                do_create_folder_performer,
3298                                                                helper);
3299         }
3300
3301         if (folder_name)
3302                 g_free (folder_name);
3303         if (parent_folder)
3304                 g_object_unref (parent_folder);
3305 }
3306
3307 static void
3308 modest_ui_actions_create_folder(GtkWindow *parent_window,
3309                                 GtkWidget *folder_view,
3310                                 TnyFolderStore *parent_folder)
3311 {
3312         if (!parent_folder) {
3313                 ModestTnyAccountStore *acc_store;
3314
3315                 acc_store = modest_runtime_get_account_store ();
3316
3317                 parent_folder = (TnyFolderStore *)
3318                         modest_tny_account_store_get_local_folders_account (acc_store);
3319         }
3320
3321         if (parent_folder) {
3322                 do_create_folder (MODEST_WINDOW (parent_window), parent_folder, NULL);
3323                 g_object_unref (parent_folder);
3324         }
3325 }
3326
3327 void
3328 modest_ui_actions_on_new_folder (GtkAction *action, ModestWindow *window)
3329 {
3330
3331         g_return_if_fail (MODEST_IS_WINDOW(window));
3332
3333         if (MODEST_IS_FOLDER_WINDOW (window)) {
3334                 GtkWidget *folder_view;
3335                 GtkWindow *toplevel;
3336
3337                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3338                 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
3339                 modest_ui_actions_create_folder (toplevel, folder_view, NULL);
3340         } else {
3341                 g_assert_not_reached ();
3342         }
3343 }
3344
3345 static void
3346 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
3347                                                gpointer user_data)
3348 {
3349         const GError *error = NULL;
3350         gchar *message = NULL;
3351         gboolean mem_full;
3352         TnyAccount *account = modest_mail_operation_get_account (mail_op);
3353
3354         /* Get error message */
3355         error = modest_mail_operation_get_error (mail_op);
3356         if (!error)
3357                 g_return_if_reached ();
3358
3359         mem_full = modest_tny_account_store_is_disk_full_error (modest_runtime_get_account_store(),
3360                                                                 (GError *) error, account);
3361         if (mem_full) {
3362                 message = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3363         } else if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3364                    error->code == MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS) {
3365                 message = _CS_FOLDER_ALREADY_EXISTS;
3366         } else if (error->domain == TNY_ERROR_DOMAIN &&
3367                    error->code == TNY_SERVICE_ERROR_STATE) {
3368                 /* This means that the folder is already in use (a
3369                    message is opened for example */
3370                 message = _("emev_ni_internal_error");
3371         } else {
3372                 message = _CS_UNABLE_TO_RENAME;
3373         }
3374
3375         /* We don't set a parent for the dialog because the dialog
3376            will be destroyed so the banner won't appear */
3377         modest_platform_information_banner (NULL, NULL, message);
3378
3379         if (account)
3380                 g_object_unref (account);
3381         if (mem_full)
3382                 g_free (message);
3383 }
3384
3385 typedef struct {
3386         TnyFolderStore *folder;
3387         gchar *new_name;
3388 } RenameFolderInfo;
3389
3390 static void
3391 on_rename_folder_cb (ModestMailOperation *mail_op,
3392                      TnyFolder *new_folder,
3393                      gpointer user_data)
3394 {
3395         ModestFolderView *folder_view;
3396
3397         /* If the window was closed when renaming a folder, or if
3398          * it's not a main window this will happen */
3399         if (!MODEST_IS_FOLDER_VIEW (user_data))
3400                 return;
3401
3402         folder_view = MODEST_FOLDER_VIEW (user_data);
3403         /* Note that if the rename fails new_folder will be NULL */
3404         if (new_folder) {
3405                 modest_folder_view_select_folder (folder_view, new_folder, FALSE);
3406         }
3407         gtk_widget_grab_focus (GTK_WIDGET (folder_view));
3408 }
3409
3410 static void
3411 on_rename_folder_performer (gboolean canceled,
3412                             GError *err,
3413                             ModestWindow *parent_window,
3414                             TnyAccount *account,
3415                             gpointer user_data)
3416 {
3417         ModestMailOperation *mail_op = NULL;
3418         GtkTreeSelection *sel = NULL;
3419         GtkWidget *folder_view = NULL;
3420         RenameFolderInfo *data = (RenameFolderInfo*)user_data;
3421
3422         if (canceled || err) {
3423                 /* In disk full conditions we could get this error here */
3424                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3425                                                                 (GtkWidget *) parent_window, err,
3426                                                                 account, NULL);
3427         } else {
3428
3429                 mail_op =
3430                         modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3431                                         modest_ui_actions_rename_folder_error_handler,
3432                                         parent_window, NULL);
3433
3434                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3435                                 mail_op);
3436                 if (MODEST_IS_FOLDER_WINDOW (parent_window)) {
3437                         ModestFolderWindow *folder_window = (ModestFolderWindow *) parent_window;
3438                         folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (folder_window));
3439                 }
3440
3441                 /* Clear the folders view */
3442                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3443                 gtk_tree_selection_unselect_all (sel);
3444
3445                 /* Actually rename the folder */
3446                 modest_mail_operation_rename_folder (mail_op,
3447                                                      TNY_FOLDER (data->folder),
3448                                                      (const gchar *) (data->new_name),
3449                                                      on_rename_folder_cb,
3450                                                      folder_view);
3451                 g_object_unref (mail_op);
3452         }
3453
3454         g_object_unref (data->folder);
3455         g_free (data->new_name);
3456         g_free (data);
3457 }
3458
3459 void
3460 modest_ui_actions_on_rename_folder (GtkAction *action,
3461                                      ModestWindow *window)
3462 {
3463         modest_ui_actions_on_edit_mode_rename_folder (window);
3464 }
3465
3466 gboolean
3467 modest_ui_actions_on_edit_mode_rename_folder (ModestWindow *window)
3468 {
3469         TnyFolderStore *folder;
3470         GtkWidget *folder_view;
3471         gboolean do_rename = TRUE;
3472
3473         g_return_val_if_fail (MODEST_IS_WINDOW(window), FALSE);
3474
3475         if (MODEST_IS_FOLDER_WINDOW (window)) {
3476                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3477         } else {
3478                 return FALSE;
3479         }
3480
3481         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3482
3483         if (!folder)
3484                 return FALSE;
3485
3486         if (TNY_IS_FOLDER (folder)) {
3487                 gchar *folder_name = NULL;
3488                 gint response;
3489                 const gchar *current_name;
3490                 TnyFolderStore *parent;
3491
3492                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
3493                 parent = tny_folder_get_folder_store (TNY_FOLDER (folder));
3494                 response = modest_platform_run_rename_folder_dialog (MODEST_WINDOW (window),
3495                                                                      parent, current_name,
3496                                                                      &folder_name);
3497                 g_object_unref (parent);
3498
3499                 if (response != GTK_RESPONSE_ACCEPT || strlen (folder_name) == 0) {
3500                         do_rename = FALSE;
3501                 } else {
3502                         RenameFolderInfo *rename_folder_data = g_new0 (RenameFolderInfo, 1);
3503                         rename_folder_data->folder = g_object_ref (folder);
3504                         rename_folder_data->new_name = folder_name;
3505                         modest_platform_connect_if_remote_and_perform (window, TRUE,
3506                                         folder, on_rename_folder_performer, rename_folder_data);
3507                 }
3508         }
3509         g_object_unref (folder);
3510         return do_rename;
3511 }
3512
3513 static void
3514 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
3515                                                gpointer user_data)
3516 {
3517         GObject *win = modest_mail_operation_get_source (mail_op);
3518         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (win));
3519
3520         modest_platform_run_information_dialog (toplevel,
3521                                                 _("mail_in_ui_folder_delete_error"),
3522                                                 FALSE);
3523         g_object_unref (win);
3524 }
3525
3526 typedef struct {
3527         TnyFolderStore *folder;
3528         gboolean move_to_trash;
3529 } DeleteFolderInfo;
3530
3531 static void
3532 on_delete_folder_cb (gboolean canceled,
3533                      GError *err,
3534                      ModestWindow *parent_window,
3535                      TnyAccount *account,
3536                      gpointer user_data)
3537 {
3538         DeleteFolderInfo *info = (DeleteFolderInfo*) user_data;
3539         GtkWidget *folder_view;
3540         ModestMailOperation *mail_op;
3541         GtkTreeSelection *sel;
3542         ModestWindow *modest_window;
3543
3544 #ifdef MODEST_TOOLKIT_HILDON2
3545         modest_window = (ModestWindow*) parent_window;
3546 #else
3547         if (MODEST_IS_SHELL (parent_window)) {
3548                 modest_window = modest_shell_peek_window (MODEST_SHELL (parent_window));
3549         } else {
3550                 modest_window = NULL;
3551         }
3552 #endif
3553
3554         if (!MODEST_IS_WINDOW(modest_window) || canceled || (err!=NULL)) {
3555                 /* Note that the connection process can fail due to
3556                    memory low conditions as it can not successfully
3557                    store the summary */
3558                 if (!modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3559                                                                      (GtkWidget*) parent_window, err,
3560                                                                      account, NULL))
3561                         g_debug ("Error connecting when trying to delete a folder");
3562                 g_object_unref (G_OBJECT (info->folder));
3563                 g_free (info);
3564                 return;
3565         }
3566
3567         if (MODEST_IS_FOLDER_WINDOW (modest_window)) {
3568                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (modest_window)));
3569         } else {
3570                 g_object_unref (G_OBJECT (info->folder));
3571                 g_free (info);
3572                 return;
3573         }
3574
3575         /* Unselect the folder before deleting it to free the headers */
3576         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3577         gtk_tree_selection_unselect_all (sel);
3578
3579         /* Create the mail operation */
3580         mail_op =
3581                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3582                                 modest_ui_actions_delete_folder_error_handler,
3583                                 NULL, NULL);
3584
3585         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3586                         mail_op);
3587         modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (info->folder), info->move_to_trash);
3588
3589         g_object_unref (mail_op);
3590         g_object_unref (info->folder);
3591         g_free (info);
3592 }
3593
3594 static gboolean
3595 delete_folder (ModestWindow *window, gboolean move_to_trash)
3596 {
3597         TnyFolderStore *folder;
3598         GtkWidget *folder_view;
3599         gint response;
3600         gchar *message;
3601
3602         g_return_val_if_fail (MODEST_IS_WINDOW(window), FALSE);
3603
3604         if (MODEST_IS_FOLDER_WINDOW (window)) {
3605                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3606         } else {
3607                 return FALSE;
3608         }
3609         if (!folder_view)
3610                 return FALSE;
3611
3612         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3613
3614         if (!folder)
3615                 return FALSE;
3616
3617         /* Show an error if it's an account */
3618         if (!TNY_IS_FOLDER (folder)) {
3619                 modest_platform_run_information_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3620                                                         _("mail_in_ui_folder_delete_error"),
3621                                                         FALSE);
3622                 g_object_unref (G_OBJECT (folder));
3623                 return FALSE;
3624         }
3625
3626         /* Ask the user */
3627         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"),
3628                                     tny_folder_get_name (TNY_FOLDER (folder)));
3629         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3630                                                             (const gchar *) message);
3631         g_free (message);
3632
3633         if (response == GTK_RESPONSE_OK) {
3634                 TnyAccount *account = NULL;
3635                 DeleteFolderInfo *info = NULL;
3636                 info = g_new0(DeleteFolderInfo, 1);
3637                 info->folder = g_object_ref (folder);
3638                 info->move_to_trash = move_to_trash;
3639
3640                 account = tny_folder_get_account (TNY_FOLDER (folder));
3641                 modest_platform_connect_if_remote_and_perform (window,
3642                                                                TRUE,
3643                                                                TNY_FOLDER_STORE (account),
3644                                                                on_delete_folder_cb, info);
3645                 g_object_unref (account);
3646                 g_object_unref (folder);
3647                 return TRUE;
3648         } else {
3649                 return FALSE;
3650         }
3651 }
3652
3653 void
3654 modest_ui_actions_on_delete_folder (GtkAction *action,
3655                                     ModestWindow *window)
3656 {
3657         modest_ui_actions_on_edit_mode_delete_folder (window);
3658 }
3659
3660 gboolean
3661 modest_ui_actions_on_edit_mode_delete_folder (ModestWindow *window)
3662 {
3663         g_return_val_if_fail (MODEST_IS_WINDOW(window), TRUE);
3664
3665         return delete_folder (window, FALSE);
3666 }
3667
3668
3669 typedef struct _PasswordDialogFields {
3670         GtkWidget *username;
3671         GtkWidget *password;
3672         GtkWidget *dialog;
3673 } PasswordDialogFields;
3674
3675 static void
3676 password_dialog_check_field (GtkEditable *editable,
3677                              PasswordDialogFields *fields)
3678 {
3679         const gchar *value;
3680         gboolean any_value_empty = FALSE;
3681
3682         value = modest_entry_get_text (fields->username);
3683         if ((value == NULL) || value[0] == '\0') {
3684                 any_value_empty = TRUE;
3685         }
3686         value = modest_entry_get_text (fields->password);
3687         if ((value == NULL) || value[0] == '\0') {
3688                 any_value_empty = TRUE;
3689         }
3690         gtk_dialog_set_response_sensitive (GTK_DIALOG (fields->dialog), GTK_RESPONSE_ACCEPT, !any_value_empty);
3691 }
3692
3693 void
3694 modest_ui_actions_on_password_requested (TnyAccountStore *account_store,
3695                                          const gchar* server_account_name,
3696                                          gchar **username,
3697                                          gchar **password,
3698                                          gboolean *cancel,
3699                                          gboolean *remember,
3700                                          ModestWindow *window)
3701 {
3702         g_return_if_fail(server_account_name);
3703         gboolean completed = FALSE;
3704         PasswordDialogFields *fields = NULL;
3705
3706         /* Initalize output parameters: */
3707         if (cancel)
3708                 *cancel = FALSE;
3709
3710         if (remember)
3711                 *remember = TRUE;
3712
3713 #ifndef MODEST_TOOLKIT_GTK
3714         /* Maemo uses a different (awkward) button order,
3715          * It should probably just use gtk_alternative_dialog_button_order ().
3716          */
3717 #ifdef MODEST_TOOLKIT_HILDON2
3718         GtkWidget *dialog =
3719                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3720                                              NULL,
3721                                              GTK_DIALOG_MODAL,
3722                                              _HL_DONE,
3723                                              GTK_RESPONSE_ACCEPT,
3724                                              NULL);
3725         gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
3726                                         HILDON_MARGIN_DOUBLE);
3727 #else
3728         GtkWidget *dialog =
3729                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3730                                              NULL,
3731                                              GTK_DIALOG_MODAL,
3732                                              _("mcen_bd_dialog_ok"),
3733                                              GTK_RESPONSE_ACCEPT,
3734                                              _("mcen_bd_dialog_cancel"),
3735                                              GTK_RESPONSE_REJECT,
3736                                              NULL);
3737 #endif /* MODEST_TOOLKIT_HILDON2 */
3738 #else
3739         GtkWidget *dialog =
3740                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3741                                              NULL,
3742                                              GTK_DIALOG_MODAL,
3743                                              GTK_STOCK_CANCEL,
3744                                              GTK_RESPONSE_REJECT,
3745                                              GTK_STOCK_OK,
3746                                              GTK_RESPONSE_ACCEPT,
3747                                              NULL);
3748 #endif /* MODEST_TOOLKIT_GTK */
3749
3750         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (dialog), NULL);
3751
3752         gchar *server_name = modest_account_mgr_get_server_account_hostname (
3753                 modest_runtime_get_account_mgr(), server_account_name);
3754         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
3755                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
3756                 if (cancel)
3757                         *cancel = TRUE;
3758                 gtk_widget_destroy (dialog);
3759                 return;
3760         }
3761
3762         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
3763         GtkWidget *label = gtk_label_new (txt);
3764         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
3765         g_free (txt);
3766         g_free (server_name);
3767         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
3768                             FALSE, FALSE, 0);
3769         server_name = NULL;
3770
3771         /* username: */
3772         gchar *initial_username = modest_account_mgr_get_server_account_username (
3773                 modest_runtime_get_account_mgr(), server_account_name);
3774
3775         GtkWidget *entry_username = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
3776         if (initial_username)
3777                 modest_entry_set_text (entry_username, initial_username);
3778
3779         /* Dim this if a connection has ever succeeded with this username,
3780          * as per the UI spec: */
3781         /* const gboolean username_known =  */
3782         /*      modest_account_mgr_get_server_account_username_has_succeeded( */
3783         /*              modest_runtime_get_account_mgr(), server_account_name); */
3784         /* gtk_widget_set_sensitive (entry_username, !username_known); */
3785
3786         /* We drop the username sensitive code and disallow changing it here
3787          * as tinymail does not support really changing the username in the callback
3788          */
3789         gtk_widget_set_sensitive (entry_username, FALSE);
3790
3791         /* Auto-capitalization is the default, so let's turn it off: */
3792 #ifdef MAEMO_CHANGES
3793         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
3794 #endif
3795
3796         /* Create a size group to be used by all captions.
3797          * Note that HildonCaption does not create a default size group if we do not specify one.
3798          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
3799         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3800
3801         GtkWidget *caption = modest_toolkit_utils_create_captioned (sizegroup, NULL,
3802                                                                     _("mail_fi_username"), FALSE,
3803                                                                     entry_username);
3804         gtk_widget_show (entry_username);
3805         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption,
3806                 FALSE, FALSE, MODEST_MARGIN_HALF);
3807         gtk_widget_show (caption);
3808
3809         /* password: */
3810         GtkWidget *entry_password = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
3811         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
3812         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
3813
3814         /* Auto-capitalization is the default, so let's turn it off: */
3815 #ifdef MAEMO_CHANGES
3816         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password),
3817                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
3818 #endif
3819
3820         caption = modest_toolkit_utils_create_captioned (sizegroup, NULL,
3821                                                          _("mail_fi_password"), FALSE,
3822                                                          entry_password);
3823         gtk_widget_show (entry_password);
3824         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption,
3825                 FALSE, FALSE, MODEST_MARGIN_HALF);
3826         gtk_widget_show (caption);
3827         g_object_unref (sizegroup);
3828
3829         if (initial_username != NULL)
3830                 gtk_widget_grab_focus (GTK_WIDGET (entry_password));
3831
3832 /* This is not in the Maemo UI spec:
3833         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
3834         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
3835                             TRUE, FALSE, 0);
3836 */
3837
3838         fields = g_slice_new0 (PasswordDialogFields);
3839         fields->username = entry_username;
3840         fields->password = entry_password;
3841         fields->dialog = dialog;
3842
3843         g_signal_connect (entry_username, "changed", G_CALLBACK (password_dialog_check_field), fields);
3844         g_signal_connect (entry_password, "changed", G_CALLBACK (password_dialog_check_field), fields);
3845         password_dialog_check_field (NULL, fields);
3846
3847         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3848
3849         while (!completed) {
3850
3851                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3852                         if (username) {
3853                                 *username = g_strdup (modest_entry_get_text (entry_username));
3854
3855                                 /* Note that an empty field becomes the "" string */
3856                                 if (*username && strlen (*username) > 0) {
3857                                         modest_account_mgr_set_server_account_username (modest_runtime_get_account_mgr(),
3858                                                                                         server_account_name,
3859                                                                                         *username);
3860                                         completed = TRUE;
3861
3862                                         const gboolean username_was_changed =
3863                                                 (strcmp (*username, initial_username) != 0);
3864                                         if (username_was_changed) {
3865                                                 g_warning ("%s: tinymail does not yet support changing the "
3866                                                            "username in the get_password() callback.\n", __FUNCTION__);
3867                                         }
3868                                 } else {
3869                                         g_free (*username);
3870                                         *username = NULL;
3871                                         /* Show error */
3872                                         modest_platform_information_banner (GTK_WIDGET (dialog), NULL,
3873                                                                             _("mcen_ib_username_pw_incorrect"));
3874                                         completed = FALSE;
3875                                 }
3876                         }
3877
3878                         if (password) {
3879                                 *password = g_strdup (modest_entry_get_text (entry_password));
3880
3881                                 /* We do not save the password in the configuration,
3882                                  * because this function is only called for passwords that should
3883                                  * not be remembered:
3884                                  modest_server_account_set_password (
3885                                  modest_runtime_get_account_mgr(), server_account_name,
3886                                  *password);
3887                                  */
3888                         }
3889                         if (cancel)
3890                                 *cancel   = FALSE;
3891                 } else {
3892                         completed = TRUE;
3893                         if (username)
3894                                 *username = NULL;
3895                         if (password)
3896                                 *password = NULL;
3897                         if (cancel)
3898                                 *cancel   = TRUE;
3899                 }
3900         }
3901
3902 /* This is not in the Maemo UI spec:
3903         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
3904                 *remember = TRUE;
3905         else
3906                 *remember = FALSE;
3907 */
3908
3909         g_free (initial_username);
3910         gtk_widget_destroy (dialog);
3911         g_slice_free (PasswordDialogFields, fields);
3912
3913         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
3914 }
3915
3916 void
3917 modest_ui_actions_on_cut (GtkAction *action,
3918                           ModestWindow *window)
3919 {
3920         GtkWidget *focused_widget;
3921         GtkClipboard *clipboard;
3922
3923         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3924         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
3925         if (GTK_IS_EDITABLE (focused_widget)) {
3926                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
3927                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3928                 gtk_clipboard_store (clipboard);
3929         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
3930                 GtkTextBuffer *buffer;
3931
3932                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
3933                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
3934                         gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
3935                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3936                         gtk_clipboard_store (clipboard);
3937                 }
3938         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
3939                 TnyList *header_list = modest_header_view_get_selected_headers (
3940                                 MODEST_HEADER_VIEW (focused_widget));
3941                 gboolean continue_download = FALSE;
3942                 gint num_of_unc_msgs;
3943
3944                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
3945
3946                 if (num_of_unc_msgs) {
3947                         TnyAccount *account = get_account_from_header_list (header_list);
3948                         if (account) {
3949                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
3950                                 g_object_unref (account);
3951                         }
3952                 }
3953
3954                 if (num_of_unc_msgs == 0 || continue_download) {
3955 /*                      modest_platform_information_banner (
3956                                         NULL, NULL, _CS("mcen_ib_getting_items"));*/
3957                         modest_header_view_cut_selection (
3958                                         MODEST_HEADER_VIEW (focused_widget));
3959                 }
3960
3961                 g_object_unref (header_list);
3962         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
3963                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
3964         }
3965 }
3966
3967 void
3968 modest_ui_actions_on_copy (GtkAction *action,
3969                            ModestWindow *window)
3970 {
3971         GtkClipboard *clipboard;
3972         GtkWidget *focused_widget;
3973         gboolean copied = TRUE;
3974
3975         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3976         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
3977
3978         if (GTK_IS_LABEL (focused_widget)) {
3979                 gchar *selection;
3980                 selection = modest_text_utils_label_get_selection (GTK_LABEL (focused_widget));
3981                 gtk_clipboard_set_text (clipboard, selection, -1);
3982                 g_free (selection);
3983                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3984                 gtk_clipboard_store (clipboard);
3985         } else if (GTK_IS_EDITABLE (focused_widget)) {
3986                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
3987                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
3988                 gtk_clipboard_store (clipboard);
3989         } else if (GTK_IS_HTML (focused_widget)) {
3990                 const gchar *sel;
3991                 int len = -1;
3992                 sel = gtk_html_get_selection_html (GTK_HTML (focused_widget), &len);
3993                 if ((sel == NULL) || (sel[0] == '\0')) {
3994                         copied = FALSE;
3995                 } else {
3996                         gtk_html_copy (GTK_HTML (focused_widget));
3997                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
3998                         gtk_clipboard_store (clipboard);
3999                 }
4000         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4001                 GtkTextBuffer *buffer;
4002                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4003                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
4004                         gtk_text_buffer_copy_clipboard (buffer, clipboard);
4005                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
4006                         gtk_clipboard_store (clipboard);
4007                 }
4008         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
4009                 TnyList *header_list = modest_header_view_get_selected_headers (
4010                                 MODEST_HEADER_VIEW (focused_widget));
4011                 gboolean continue_download = FALSE;
4012                 gint num_of_unc_msgs;
4013
4014                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
4015
4016                 if (num_of_unc_msgs) {
4017                         TnyAccount *account = get_account_from_header_list (header_list);
4018                         if (account) {
4019                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
4020                                 g_object_unref (account);
4021                         }
4022                 }
4023
4024                 if (num_of_unc_msgs == 0 || continue_download) {
4025                         modest_platform_information_banner (
4026                                         NULL, NULL, _CS_GETTING_ITEMS);
4027                         modest_header_view_copy_selection (
4028                                         MODEST_HEADER_VIEW (focused_widget));
4029                 } else
4030                         copied = FALSE;
4031
4032                 g_object_unref (header_list);
4033
4034         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
4035                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
4036         }
4037
4038         /* Show information banner if there was a copy to clipboard */
4039         if(copied)
4040                 modest_platform_information_banner (
4041                                 NULL, NULL, _CS_COPIED);
4042 }
4043
4044 void
4045 modest_ui_actions_on_undo (GtkAction *action,
4046                            ModestWindow *window)
4047 {
4048         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4049                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
4050         } else {
4051                 g_return_if_reached ();
4052         }
4053 }
4054
4055 void
4056 modest_ui_actions_on_redo (GtkAction *action,
4057                            ModestWindow *window)
4058 {
4059         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4060                 modest_msg_edit_window_redo (MODEST_MSG_EDIT_WINDOW (window));
4061         }
4062         else {
4063                 g_return_if_reached ();
4064         }
4065 }
4066
4067
4068 static void
4069 destroy_information_note (ModestMailOperation *mail_op,
4070                           gpointer user_data)
4071 {
4072         /* destroy information note */
4073         gtk_widget_destroy (GTK_WIDGET(user_data));
4074 }
4075
4076 static void
4077 destroy_folder_information_note (ModestMailOperation *mail_op,
4078                                  TnyFolder *new_folder,
4079                                  gpointer user_data)
4080 {
4081         /* destroy information note */
4082         gtk_widget_destroy (GTK_WIDGET(user_data));
4083 }
4084
4085
4086 static void
4087 paste_as_attachment_free (gpointer data)
4088 {
4089         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) data;
4090
4091         if (helper->banner) {
4092                 gtk_widget_destroy (helper->banner);
4093                 g_object_unref (helper->banner);
4094         }
4095         g_free (helper);
4096 }
4097
4098 static void
4099 paste_msg_as_attachment_cb (ModestMailOperation *mail_op,
4100                             TnyHeader *header,
4101                             TnyMsg *msg,
4102                             gpointer userdata)
4103 {
4104         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) userdata;
4105         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (helper->window));
4106
4107         if (msg == NULL)
4108                 return;
4109
4110         modest_msg_edit_window_add_part (MODEST_MSG_EDIT_WINDOW (helper->window), TNY_MIME_PART (msg));
4111
4112 }
4113
4114 void
4115 modest_ui_actions_on_paste (GtkAction *action,
4116                             ModestWindow *window)
4117 {
4118         GtkWidget *focused_widget = NULL;
4119         GtkWidget *inf_note = NULL;
4120         ModestMailOperation *mail_op = NULL;
4121
4122         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
4123         if (GTK_IS_EDITABLE (focused_widget)) {
4124                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
4125         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4126                 ModestEmailClipboard *e_clipboard = NULL;
4127                 e_clipboard = modest_runtime_get_email_clipboard ();
4128                 if (modest_email_clipboard_cleared (e_clipboard)) {
4129                         GtkTextBuffer *buffer;
4130                         GtkClipboard *clipboard;
4131
4132                         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
4133                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4134                         gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
4135                 } else if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4136                         ModestMailOperation *mail_op;
4137                         TnyFolder *src_folder = NULL;
4138                         TnyList *data = NULL;
4139                         gboolean delete;
4140                         PasteAsAttachmentHelper *helper = g_new0 (PasteAsAttachmentHelper, 1);
4141                         helper->window = MODEST_MSG_EDIT_WINDOW (window);
4142                         helper->banner = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
4143                                                                            _CS_PASTING);
4144                         modest_email_clipboard_get_data (e_clipboard, &src_folder, &data, &delete);
4145                         mail_op = modest_mail_operation_new (G_OBJECT (window));
4146                         if (helper->banner != NULL) {
4147                                 g_object_ref (G_OBJECT (helper->banner));
4148                                 gtk_widget_show (GTK_WIDGET (helper->banner));
4149                         }
4150
4151                         if (data != NULL) {
4152                                 modest_mail_operation_get_msgs_full (mail_op,
4153                                                                      data,
4154                                                                      (GetMsgAsyncUserCallback) paste_msg_as_attachment_cb,
4155                                                                      helper,
4156                                                                      paste_as_attachment_free);
4157                         }
4158                         /* Free */
4159                         if (data)
4160                                 g_object_unref (data);
4161                         if (src_folder)
4162                                 g_object_unref (src_folder);
4163
4164                 }
4165         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
4166                 ModestEmailClipboard *clipboard = NULL;
4167                 TnyFolder *src_folder = NULL;
4168                 TnyFolderStore *folder_store = NULL;
4169                 TnyList *data = NULL;
4170                 gboolean delete = FALSE;
4171
4172                 /* Check clipboard source */
4173                 clipboard = modest_runtime_get_email_clipboard ();
4174                 if (modest_email_clipboard_cleared (clipboard))
4175                         return;
4176
4177                 /* Get elements to paste */
4178                 modest_email_clipboard_get_data (clipboard, &src_folder, &data, &delete);
4179
4180                 /* Create a new mail operation */
4181                 mail_op = modest_mail_operation_new (G_OBJECT(window));
4182
4183                 /* Get destination folder */
4184                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (focused_widget));
4185
4186                 /* transfer messages  */
4187                 if (data != NULL) {
4188                         gint response = 0;
4189
4190                         /* Ask for user confirmation */
4191                         response =
4192                                 modest_ui_actions_msgs_move_to_confirmation (window,
4193                                                                              TNY_FOLDER (folder_store),
4194                                                                              delete,
4195                                                                              data);
4196
4197                         if (response == GTK_RESPONSE_OK) {
4198                                 /* Launch notification */
4199                                 inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
4200                                                                              _CS_PASTING);
4201                                 if (inf_note != NULL)  {
4202                                         gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
4203                                         gtk_widget_show (GTK_WIDGET(inf_note));
4204                                 }
4205
4206                                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
4207                                 modest_mail_operation_xfer_msgs (mail_op,
4208                                                                  data,
4209                                                                  TNY_FOLDER (folder_store),
4210                                                                  delete,
4211                                                                  destroy_information_note,
4212                                                                  inf_note);
4213                         } else {
4214                                 g_object_unref (mail_op);
4215                         }
4216
4217                 } else if (src_folder != NULL) {
4218                         /* Launch notification */
4219                         inf_note = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
4220                                                                      _CS_PASTING);
4221                         if (inf_note != NULL)  {
4222                                 gtk_window_set_modal (GTK_WINDOW(inf_note), FALSE);
4223                                 gtk_widget_show (GTK_WIDGET(inf_note));
4224                         }
4225
4226                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
4227                         modest_mail_operation_xfer_folder (mail_op,
4228                                                            src_folder,
4229                                                            folder_store,
4230                                                            delete,
4231                                                            destroy_folder_information_note,
4232                                                            inf_note);
4233                 }
4234
4235                 /* Free */
4236                 if (data != NULL)
4237                         g_object_unref (data);
4238                 if (src_folder != NULL)
4239                         g_object_unref (src_folder);
4240                 if (folder_store != NULL)
4241                         g_object_unref (folder_store);
4242         }
4243 }
4244
4245
4246 void
4247 modest_ui_actions_on_select_all (GtkAction *action,
4248                                  ModestWindow *window)
4249 {
4250         GtkWidget *focused_widget;
4251
4252         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
4253         if (MODEST_IS_ATTACHMENTS_VIEW (focused_widget)) {
4254                 modest_attachments_view_select_all (MODEST_ATTACHMENTS_VIEW (focused_widget));
4255         } else if (GTK_IS_LABEL (focused_widget)) {
4256                 gtk_label_select_region (GTK_LABEL (focused_widget), 0, -1);
4257         } else if (GTK_IS_EDITABLE (focused_widget)) {
4258                 gtk_editable_select_region (GTK_EDITABLE(focused_widget), 0, -1);
4259         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4260                 GtkTextBuffer *buffer;
4261                 GtkTextIter start, end;
4262
4263                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4264                 gtk_text_buffer_get_start_iter (buffer, &start);
4265                 gtk_text_buffer_get_end_iter (buffer, &end);
4266                 gtk_text_buffer_select_range (buffer, &start, &end);
4267         } else if (GTK_IS_HTML (focused_widget)) {
4268                 gtk_html_select_all (GTK_HTML (focused_widget));
4269         }
4270
4271 }
4272
4273 void
4274 modest_ui_actions_on_mark_as_read (GtkAction *action,
4275                                    ModestWindow *window)
4276 {
4277         g_return_if_fail (MODEST_IS_WINDOW(window));
4278
4279         /* Mark each header as read */
4280         do_headers_action (window, headers_action_mark_as_read, NULL);
4281 }
4282
4283 void
4284 modest_ui_actions_on_mark_as_unread (GtkAction *action,
4285                                      ModestWindow *window)
4286 {
4287         g_return_if_fail (MODEST_IS_WINDOW(window));
4288
4289         /* Mark each header as read */
4290         do_headers_action (window, headers_action_mark_as_unread, NULL);
4291 }
4292
4293 void
4294 modest_ui_actions_on_change_zoom (GtkRadioAction *action,
4295                                   GtkRadioAction *selected,
4296                                   ModestWindow *window)
4297 {
4298         gint value;
4299
4300         value = gtk_radio_action_get_current_value (selected);
4301         if (MODEST_IS_WINDOW (window)) {
4302                 modest_window_set_zoom (MODEST_WINDOW (window), ((gdouble)value)/100);
4303         }
4304 }
4305
4306 void
4307 modest_ui_actions_msg_edit_on_change_priority (GtkRadioAction *action,
4308                                                GtkRadioAction *selected,
4309                                                ModestWindow *window)
4310 {
4311         TnyHeaderFlags flags;
4312         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4313
4314         flags = gtk_radio_action_get_current_value (selected);
4315         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW (window), flags);
4316 }
4317
4318 void
4319 modest_ui_actions_msg_edit_on_change_file_format (GtkRadioAction *action,
4320                                                   GtkRadioAction *selected,
4321                                                   ModestWindow *window)
4322 {
4323         gint file_format;
4324
4325         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4326
4327         file_format = gtk_radio_action_get_current_value (selected);
4328         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (window), file_format);
4329 }
4330
4331
4332 void
4333 modest_ui_actions_on_zoom_plus (GtkAction *action,
4334                                 ModestWindow *window)
4335 {
4336         g_return_if_fail (MODEST_IS_WINDOW (window));
4337
4338         modest_window_zoom_plus (MODEST_WINDOW (window));
4339 }
4340
4341 void
4342 modest_ui_actions_on_zoom_minus (GtkAction *action,
4343                                  ModestWindow *window)
4344 {
4345         g_return_if_fail (MODEST_IS_WINDOW (window));
4346
4347         modest_window_zoom_minus (MODEST_WINDOW (window));
4348 }
4349
4350 void
4351 modest_ui_actions_on_toggle_fullscreen    (GtkToggleAction *toggle,
4352                                            ModestWindow *window)
4353 {
4354         ModestWindowMgr *mgr;
4355         gboolean fullscreen, active;
4356         g_return_if_fail (MODEST_IS_WINDOW (window));
4357
4358         mgr = modest_runtime_get_window_mgr ();
4359
4360         active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle)))?1:0;
4361         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4362
4363         if (active != fullscreen) {
4364                 modest_window_mgr_set_fullscreen_mode (mgr, active);
4365 #ifndef MODEST_TOOLKIT_HILDON2
4366                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
4367                 gtk_window_present (toplevel);
4368 #endif
4369         }
4370 }
4371
4372 void
4373 modest_ui_actions_on_change_fullscreen (GtkAction *action,
4374                                         ModestWindow *window)
4375 {
4376         ModestWindowMgr *mgr;
4377         gboolean fullscreen;
4378
4379         g_return_if_fail (MODEST_IS_WINDOW (window));
4380
4381         mgr = modest_runtime_get_window_mgr ();
4382         fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
4383         modest_window_mgr_set_fullscreen_mode (mgr, !fullscreen);
4384
4385 }
4386
4387 /*
4388  * Used by modest_ui_actions_on_details to call do_headers_action
4389  */
4390 static void
4391 headers_action_show_details (TnyHeader *header,
4392                              ModestWindow *window,
4393                              gpointer user_data)
4394
4395 {
4396         gboolean async_retrieval;
4397         GtkWindow *toplevel;
4398         TnyMsg *msg = NULL;
4399
4400         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
4401                 async_retrieval = TRUE;
4402                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
4403                 async_retrieval = !TNY_IS_CAMEL_BS_MSG (msg);
4404         } else {
4405                 async_retrieval = FALSE;
4406         }
4407         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
4408         modest_platform_run_header_details_dialog (toplevel, header, async_retrieval, msg);
4409         if (msg)
4410                 g_object_unref (msg);
4411 }
4412
4413 /*
4414  * Show the header details in a ModestDetailsDialog widget
4415  */
4416 void
4417 modest_ui_actions_on_details (GtkAction *action,
4418                               ModestWindow *win)
4419 {
4420         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
4421                 TnyMsg *msg;
4422                 TnyHeader *header;
4423
4424                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (win));
4425                 if (!msg)
4426                         return;
4427
4428                 header = tny_msg_get_header (msg);
4429                 if (header) {
4430                         headers_action_show_details (header, win, NULL);
4431                         g_object_unref (header);
4432                 }
4433                 g_object_unref (msg);
4434         } else if (MODEST_IS_HEADER_WINDOW (win)) {
4435                 TnyFolder *folder;
4436                 GtkWidget *header_view;
4437
4438                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (win)));
4439                 folder = modest_header_view_get_folder (MODEST_HEADER_VIEW (header_view));
4440                 if (folder) {
4441                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
4442
4443                         modest_platform_run_folder_details_dialog (toplevel, folder);
4444                         g_object_unref (folder);
4445                 }
4446         }
4447 }
4448
4449 void
4450 modest_ui_actions_on_limit_error (GtkAction *action,
4451                                   ModestWindow *win)
4452 {
4453         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win));
4454
4455         modest_platform_information_banner ((GtkWidget *) win, NULL, _CS_MAXIMUM_CHARACTERS_REACHED);
4456
4457 }
4458
4459 void
4460 modest_ui_actions_on_toggle_show_cc (GtkToggleAction *toggle,
4461                                      ModestMsgEditWindow *window)
4462 {
4463         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4464
4465         modest_msg_edit_window_show_cc (window, gtk_toggle_action_get_active (toggle));
4466 }
4467
4468 void
4469 modest_ui_actions_on_toggle_show_bcc (GtkToggleAction *toggle,
4470                                       ModestMsgEditWindow *window)
4471 {
4472         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4473
4474         modest_msg_edit_window_show_bcc (window, gtk_toggle_action_get_active (toggle));
4475 }
4476
4477
4478 void
4479 modest_ui_actions_on_toggle_toolbar (GtkToggleAction *toggle,
4480                                      ModestWindow *window)
4481 {
4482         gboolean active, fullscreen = FALSE;
4483         ModestWindowMgr *mgr;
4484
4485         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (toggle));
4486
4487         /* Check if we want to toggle the toolbar view in fullscreen
4488            or normal mode */
4489         if (!strcmp (gtk_action_get_name (GTK_ACTION (toggle)),
4490                      "ViewShowToolbarFullScreen")) {
4491                 fullscreen = TRUE;
4492         }
4493
4494         /* Toggle toolbar */
4495         mgr = modest_runtime_get_window_mgr ();
4496         modest_window_mgr_show_toolbars (mgr, G_TYPE_FROM_INSTANCE (window), active, fullscreen);
4497 }
4498
4499 void
4500 modest_ui_actions_msg_edit_on_select_font (GtkAction *action,
4501                                            ModestMsgEditWindow *window)
4502 {
4503         modest_msg_edit_window_select_font (window);
4504 }
4505
4506
4507 void
4508 modest_ui_actions_on_folder_display_name_changed (ModestFolderView *folder_view,
4509                                                   const gchar *display_name,
4510                                                   GtkWindow *window)
4511 {
4512         /* don't update the display name if it was already set;
4513          * updating the display name apparently is expensive */
4514         const gchar* old_name = gtk_window_get_title (window);
4515
4516         if (display_name == NULL)
4517                 display_name = " ";
4518
4519         if (old_name && display_name && strcmp (old_name, display_name) == 0)
4520                 return; /* don't do anything */
4521
4522         /* This is usually used to change the title of the main window, which
4523          * is the one that holds the folder view. Note that this change can
4524          * happen even when the widget doesn't have the focus. */
4525         gtk_window_set_title (window, display_name);
4526
4527 }
4528
4529 void
4530 modest_ui_actions_on_select_contacts (GtkAction *action, ModestMsgEditWindow *window)
4531 {
4532         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4533         modest_msg_edit_window_select_contacts (window);
4534 }
4535
4536 void
4537 modest_ui_actions_on_check_names (GtkAction *action, ModestMsgEditWindow *window)
4538 {
4539         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4540         modest_msg_edit_window_check_names (window, FALSE);
4541 }
4542
4543
4544 static void
4545 on_move_to_dialog_response (GtkDialog *dialog,
4546                             gint       response,
4547                             gpointer   user_data)
4548 {
4549         GtkWidget *parent_win;
4550         MoveToInfo *helper = NULL;
4551         ModestFolderView *folder_view;
4552         gboolean unset_edit_mode = FALSE;
4553
4554         helper = (MoveToInfo *) user_data;
4555
4556         parent_win = (GtkWidget *) helper->win;
4557         folder_view = MODEST_FOLDER_VIEW (g_object_get_data (G_OBJECT (dialog),
4558                                                              MODEST_MOVE_TO_DIALOG_FOLDER_VIEW));
4559         switch (response) {
4560                 TnyFolderStore *dst_folder;
4561                 TnyFolderStore *selected;
4562
4563         case MODEST_GTK_RESPONSE_NEW_FOLDER:
4564                 selected = modest_folder_view_get_selected (folder_view);
4565                 modest_ui_actions_create_folder ((GtkWindow *) dialog, GTK_WIDGET (folder_view), selected);
4566                 g_object_unref (selected);
4567                 return;
4568         case GTK_RESPONSE_NONE:
4569         case GTK_RESPONSE_CANCEL:
4570         case GTK_RESPONSE_DELETE_EVENT:
4571                 break;
4572         case GTK_RESPONSE_OK:
4573                 dst_folder = modest_folder_view_get_selected (folder_view);
4574
4575                 if (MODEST_IS_FOLDER_WINDOW (parent_win)) {
4576                         /* Clean list to move used for filtering */
4577                         modest_folder_view_set_list_to_move (folder_view, NULL);
4578
4579                         modest_ui_actions_on_folder_window_move_to (GTK_WIDGET (folder_view),
4580                                                                     dst_folder,
4581                                                                     helper->list,
4582                                                                     MODEST_WINDOW (parent_win));
4583                 } else {
4584                         /* if the user selected a root folder
4585                            (account) then do not perform any action */
4586                         if (TNY_IS_ACCOUNT (dst_folder)) {
4587                                 g_signal_stop_emission_by_name (dialog, "response");
4588                                 return;
4589                         }
4590
4591                         /* Clean list to move used for filtering */
4592                         modest_folder_view_set_list_to_move (folder_view, NULL);
4593
4594                         /* Moving from headers window in edit mode */
4595                         modest_ui_actions_on_window_move_to (NULL, helper->list,
4596                                                              dst_folder,
4597                                                              MODEST_WINDOW (parent_win));
4598                 }
4599
4600                 if (dst_folder)
4601                         g_object_unref (dst_folder);
4602
4603                 unset_edit_mode = TRUE;
4604                 break;
4605         default:
4606                 g_warning ("%s unexpected response id %d", __FUNCTION__, response);
4607         }
4608
4609         /* Free the helper and exit */
4610         if (helper->list)
4611                 g_object_unref (helper->list);
4612         if (unset_edit_mode) {
4613 #ifdef MODEST_TOOLKIT_HILDON2
4614                 modest_hildon2_window_unset_edit_mode (MODEST_HILDON2_WINDOW (helper->win));
4615 #endif
4616         }
4617         g_slice_free (MoveToInfo, helper);
4618         gtk_widget_destroy (GTK_WIDGET (dialog));
4619 }
4620
4621 static GtkWidget*
4622 create_move_to_dialog (GtkWindow *win,
4623                        GtkWidget *folder_view,
4624                        TnyList *list_to_move)
4625 {
4626         GtkWidget *dialog, *tree_view = NULL;
4627
4628         dialog = modest_platform_create_move_to_dialog (win, &tree_view);
4629
4630
4631         /* It could happen that we're trying to move a message from a
4632            window (msg window for example) after the main window was
4633            closed, so we can not just get the model of the folder
4634            view */
4635         if (MODEST_IS_FOLDER_VIEW (folder_view)) {
4636                 const gchar *visible_id = NULL;
4637
4638                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (tree_view),
4639                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4640                 modest_folder_view_copy_model (MODEST_FOLDER_VIEW(folder_view),
4641                                                MODEST_FOLDER_VIEW(tree_view));
4642
4643                 visible_id =
4644                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view));
4645
4646                 /* Show the same account than the one that is shown in the main window */
4647                 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(tree_view),
4648                                                                              visible_id);
4649         } else {
4650                 const gchar *active_account_name = NULL;
4651                 ModestAccountMgr *mgr = NULL;
4652                 ModestAccountSettings *settings = NULL;
4653                 ModestServerAccountSettings *store_settings = NULL;
4654
4655                 modest_folder_view_set_style (MODEST_FOLDER_VIEW (tree_view),
4656                                               MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
4657
4658                 active_account_name = modest_window_get_active_account (MODEST_WINDOW (win));
4659                 mgr = modest_runtime_get_account_mgr ();
4660                 settings = modest_account_mgr_load_account_settings (mgr, active_account_name);
4661
4662                 if (settings) {
4663                         const gchar *store_account_name;
4664                         store_settings = modest_account_settings_get_store_settings (settings);
4665                         store_account_name = modest_server_account_settings_get_account_name (store_settings);
4666
4667                         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (tree_view),
4668                                                                                      store_account_name);
4669                         g_object_unref (store_settings);
4670                         g_object_unref (settings);
4671                 }
4672         }
4673
4674         /* we keep a pointer to the embedded folder view, so we can
4675          *   retrieve it with get_folder_view_from_move_to_dialog (see
4676          *   above) later (needed for focus handling)
4677          */
4678         g_object_set_data (G_OBJECT(dialog), MODEST_MOVE_TO_DIALOG_FOLDER_VIEW, tree_view);
4679
4680         /* Hide special folders */
4681         if (list_to_move)
4682                 modest_folder_view_set_list_to_move (MODEST_FOLDER_VIEW (tree_view), list_to_move);
4683
4684         gtk_widget_show (GTK_WIDGET (tree_view));
4685
4686         return dialog;
4687 }
4688
4689 /*
4690  * Shows a confirmation dialog to the user when we're moving messages
4691  * from a remote server to the local storage. Returns the dialog
4692  * response. If it's other kind of movement then it always returns
4693  * GTK_RESPONSE_OK
4694  *
4695  * This one is used by the next functions:
4696  *      modest_ui_actions_on_paste                      - commented out
4697  *      drag_and_drop_from_header_view (for d&d in modest_folder_view.c)
4698  */
4699 gint
4700 modest_ui_actions_msgs_move_to_confirmation (ModestWindow *win,
4701                                              TnyFolder *dest_folder,
4702                                              gboolean delete,
4703                                              TnyList *headers)
4704 {
4705         gint response = GTK_RESPONSE_OK;
4706         TnyAccount *account = NULL;
4707         TnyFolder *src_folder = NULL;
4708         TnyIterator *iter = NULL;
4709         TnyHeader *header = NULL;
4710
4711         /* return with OK if the destination is a remote folder */
4712         if (modest_tny_folder_is_remote_folder (dest_folder))
4713                 return GTK_RESPONSE_OK;
4714
4715         /* Get source folder */
4716         iter = tny_list_create_iterator (headers);
4717         header = TNY_HEADER (tny_iterator_get_current (iter));
4718         if (header) {
4719                 src_folder = tny_header_get_folder (header);
4720                 g_object_unref (header);
4721         }
4722         g_object_unref (iter);
4723
4724         /* if no src_folder, message may be an attahcment */
4725         if (src_folder == NULL)
4726                 return GTK_RESPONSE_CANCEL;
4727
4728         /* If the source is a local or MMC folder */
4729         if (!modest_tny_folder_is_remote_folder (src_folder)) {
4730                 g_object_unref (src_folder);
4731                 return GTK_RESPONSE_OK;
4732         }
4733
4734         /* Get the account */
4735         account = tny_folder_get_account (src_folder);
4736
4737         /* now if offline we ask the user */
4738         if(connect_to_get_msg (win, tny_list_get_length (headers), account))
4739                 response = GTK_RESPONSE_OK;
4740         else
4741                 response = GTK_RESPONSE_CANCEL;
4742
4743         /* Frees */
4744         g_object_unref (src_folder);
4745         g_object_unref (account);
4746
4747         return response;
4748 }
4749
4750 static void
4751 move_to_helper_destroyer (gpointer user_data)
4752 {
4753         MoveToHelper *helper = (MoveToHelper *) user_data;
4754
4755         /* Close the "Pasting" information banner */
4756         if (helper->banner) {
4757                 gtk_widget_destroy (GTK_WIDGET (helper->banner));
4758                 g_object_unref (helper->banner);
4759         }
4760         if (gtk_tree_row_reference_valid (helper->reference)) {
4761                 gtk_tree_row_reference_free (helper->reference);
4762                 helper->reference = NULL;
4763         }
4764         g_free (helper);
4765 }
4766
4767 static void
4768 move_to_cb (ModestMailOperation *mail_op,
4769             gpointer user_data)
4770 {
4771         MoveToHelper *helper = (MoveToHelper *) user_data;
4772         GObject *object = modest_mail_operation_get_source (mail_op);
4773
4774         /* Note that the operation could have failed, in that case do
4775            nothing */
4776         if (modest_mail_operation_get_status (mail_op) !=
4777             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
4778                 goto frees;
4779
4780         if (MODEST_IS_MSG_VIEW_WINDOW (object)) {
4781                 ModestMsgViewWindow *self = MODEST_MSG_VIEW_WINDOW (object);
4782
4783                 if (!modest_msg_view_window_select_next_message (self) &&
4784                     !modest_msg_view_window_select_previous_message (self)) {
4785                         /* No more messages to view, so close this window */
4786                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW(self));
4787                 }
4788         }
4789         g_object_unref (object);
4790
4791  frees:
4792         /* Destroy the helper */
4793         move_to_helper_destroyer (helper);
4794 }
4795
4796 static void
4797 folder_move_to_cb (ModestMailOperation *mail_op,
4798                    TnyFolder *new_folder,
4799                    gpointer user_data)
4800 {
4801         GObject *object;
4802
4803         object = modest_mail_operation_get_source (mail_op);
4804         {
4805                 move_to_cb (mail_op, user_data);
4806         }
4807 }
4808
4809 static void
4810 msgs_move_to_cb (ModestMailOperation *mail_op,
4811                  gpointer user_data)
4812 {
4813         move_to_cb (mail_op, user_data);
4814 }
4815
4816 void
4817 modest_ui_actions_move_folder_error_handler (ModestMailOperation *mail_op,
4818                                              gpointer user_data)
4819 {
4820         GObject *win = NULL;
4821         const GError *error;
4822         TnyAccount *account = NULL;
4823
4824         win = modest_mail_operation_get_source (mail_op);
4825         error = modest_mail_operation_get_error (mail_op);
4826
4827         if (TNY_IS_FOLDER (user_data))
4828                 account = modest_tny_folder_get_account (TNY_FOLDER (user_data));
4829         else if (TNY_IS_ACCOUNT (user_data))
4830                 account = g_object_ref (user_data);
4831
4832         /* If it's not a disk full error then show a generic error */
4833         if (!modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
4834                                                              (GtkWidget *) win, (GError *) error,
4835                                                              account, NULL))
4836                 modest_platform_run_information_dialog ((GtkWindow *) win,
4837                                                         _("mail_in_ui_folder_move_target_error"),
4838                                                         FALSE);
4839         if (account)
4840                 g_object_unref (account);
4841         if (win)
4842                 g_object_unref (win);
4843 }
4844
4845
4846 /*
4847  * Checks if we need a connection to do the transfer and if the user
4848  * wants to connect to complete it
4849  */
4850 static void
4851 modest_ui_actions_xfer_messages_check (ModestWindow *parent_window,
4852                                        TnyFolderStore *src_folder,
4853                                        TnyList *headers,
4854                                        TnyFolder *dst_folder,
4855                                        gboolean delete_originals,
4856                                        gboolean *need_connection,
4857                                        gboolean *do_xfer)
4858 {
4859         TnyAccount *src_account;
4860         gint uncached_msgs = 0;
4861
4862         /* We don't need any further check if
4863          *
4864          * 1- the source folder is local OR
4865          * 2- the device is already online
4866          */
4867         if (!modest_tny_folder_store_is_remote (src_folder) ||
4868             tny_device_is_online (modest_runtime_get_device())) {
4869                 *need_connection = FALSE;
4870                 *do_xfer = TRUE;
4871                 return;
4872         }
4873
4874         /* We must ask for a connection when
4875          *
4876          *   - the message(s) is not already cached   OR
4877          *   - the message(s) is cached but the leave_on_server setting
4878          * is FALSE (because we need to sync the source folder to
4879          * delete the message from the server (for IMAP we could do it
4880          * offline, it'll take place the next time we get a
4881          * connection)
4882          */
4883         uncached_msgs = header_list_count_uncached_msgs (headers);
4884         src_account = get_account_from_folder_store (src_folder);
4885         if (uncached_msgs > 0) {
4886                 guint num_headers;
4887                 const gchar *msg;
4888                 GtkWindow *toplevel;
4889
4890                 *need_connection = TRUE;
4891                 num_headers = tny_list_get_length (headers);
4892                 msg = ngettext ("mcen_nc_get_msg", "mcen_nc_get_msgs", num_headers);
4893                 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) parent_window);
4894
4895                 if (modest_platform_run_confirmation_dialog (toplevel, msg) ==
4896                     GTK_RESPONSE_CANCEL) {
4897                         *do_xfer = FALSE;
4898                 } else {
4899                         *do_xfer = TRUE;
4900                 }
4901         } else {
4902                 /* The transfer is possible and the user wants to */
4903                 *do_xfer = TRUE;
4904
4905                 if (remote_folder_has_leave_on_server (src_folder) && delete_originals) {
4906                         const gchar *account_name;
4907                         gboolean leave_on_server;
4908
4909                         account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (src_account);
4910                         leave_on_server = modest_account_mgr_get_leave_on_server (modest_runtime_get_account_mgr (),
4911                                                                                   account_name);
4912
4913                         if (leave_on_server == TRUE) {
4914                                 *need_connection = FALSE;
4915                         } else {
4916                                 *need_connection = TRUE;
4917                         }
4918                 } else {
4919                         *need_connection = FALSE;
4920                 }
4921         }
4922
4923         /* Frees */
4924         g_object_unref (src_account);
4925 }
4926
4927 static void
4928 xfer_messages_error_handler (ModestMailOperation *mail_op,
4929                              gpointer user_data)
4930 {
4931         GObject *win;
4932         const GError *error;
4933         TnyAccount *account;
4934
4935         win = modest_mail_operation_get_source (mail_op);
4936         error = modest_mail_operation_get_error (mail_op);
4937
4938         /* We cannot get the account from the mail op as that is the
4939            source account and for checking memory full conditions we
4940            need the destination one */
4941         account = TNY_ACCOUNT (user_data);
4942
4943         if (error &&
4944             !modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
4945                                                              (GtkWidget *) win, (GError*) error,
4946                                                              account, _KR("cerm_memory_card_full"))) {
4947                 modest_platform_run_information_dialog ((GtkWindow *) win,
4948                                                         _("mail_in_ui_folder_move_target_error"),
4949                                                         FALSE);
4950         }
4951         if (win)
4952                 g_object_unref (win);
4953 }
4954
4955 typedef struct {
4956         TnyFolderStore *dst_folder;
4957         TnyList *headers;
4958 } XferMsgsHelper;
4959
4960 /**
4961  * Utility function that transfer messages from both the main window
4962  * and the msg view window when using the "Move to" dialog
4963  */
4964 static void
4965 xfer_messages_performer  (gboolean canceled,
4966                           GError *err,
4967                           ModestWindow *parent_window,
4968                           TnyAccount *account,
4969                           gpointer user_data)
4970 {
4971         TnyAccount *dst_account = NULL;
4972         gboolean dst_forbids_message_add = FALSE;
4973         XferMsgsHelper *helper;
4974         MoveToHelper *movehelper;
4975         ModestMailOperation *mail_op;
4976
4977         helper = (XferMsgsHelper *) user_data;
4978
4979         if (canceled || err) {
4980                 if (!modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
4981                                                                      (GtkWidget *) parent_window, err,
4982                                                                      account, NULL)) {
4983                         /* Show the proper error message */
4984                         modest_ui_actions_on_account_connection_error (parent_window, account);
4985                 }
4986                 goto end;
4987         }
4988
4989         dst_account = tny_folder_get_account (TNY_FOLDER (helper->dst_folder));
4990
4991         /* tinymail will return NULL for local folders it seems */
4992         dst_forbids_message_add = modest_protocol_registry_protocol_type_has_tag (modest_runtime_get_protocol_registry (),
4993                                                                                   modest_tny_account_get_protocol_type (dst_account),
4994                                                                                   MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
4995
4996         if (dst_forbids_message_add) {
4997                 modest_platform_information_banner (GTK_WIDGET (parent_window),
4998                                                     NULL,
4999                                                     ngettext("mail_in_ui_folder_move_target_error",
5000                                                              "mail_in_ui_folder_move_targets_error",
5001                                                              tny_list_get_length (helper->headers)));
5002                 goto end;
5003         }
5004
5005         movehelper = g_new0 (MoveToHelper, 1);
5006
5007
5008         /* Perform the mail operation */
5009         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
5010                                                                  xfer_messages_error_handler,
5011                                                                  g_object_ref (dst_account),
5012                                                                  g_object_unref);
5013         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
5014                                          mail_op);
5015
5016         modest_mail_operation_xfer_msgs (mail_op,
5017                                          helper->headers,
5018                                          TNY_FOLDER (helper->dst_folder),
5019                                          TRUE,
5020                                          msgs_move_to_cb,
5021                                          movehelper);
5022
5023         g_object_unref (G_OBJECT (mail_op));
5024  end:
5025         if (dst_account)
5026                 g_object_unref (dst_account);
5027         g_object_unref (helper->dst_folder);
5028         g_object_unref (helper->headers);
5029         g_slice_free (XferMsgsHelper, helper);
5030 }
5031
5032 typedef struct {
5033         TnyFolder *src_folder;
5034         TnyFolderStore *dst_folder;
5035         gboolean delete_original;
5036         GtkWidget *folder_view;
5037 } MoveFolderInfo;
5038
5039 static void
5040 on_move_folder_cb (gboolean canceled,
5041                    GError *err,
5042                    ModestWindow *parent_window,
5043                    TnyAccount *account,
5044                    gpointer user_data)
5045 {
5046         MoveFolderInfo *info = (MoveFolderInfo*)user_data;
5047         GtkTreeSelection *sel;
5048         ModestMailOperation *mail_op = NULL;
5049
5050         if (canceled || err || !MODEST_IS_WINDOW (parent_window)) {
5051                 /* Note that the connection process can fail due to
5052                    memory low conditions as it can not successfully
5053                    store the summary */
5054                 if (!modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
5055                                                                      (GtkWidget*) parent_window, err,
5056                                                                      account, NULL))
5057                         g_debug ("Error connecting when trying to move a folder");
5058
5059                 g_object_unref (G_OBJECT (info->src_folder));
5060                 g_object_unref (G_OBJECT (info->dst_folder));
5061                 g_free (info);
5062                 return;
5063         }
5064
5065         MoveToHelper *helper = g_new0 (MoveToHelper, 1);
5066 #ifndef MODEST_TOOLKIT_HILDON2
5067         helper->banner = modest_platform_animation_banner (GTK_WIDGET (parent_window), NULL,
5068                         _CS_PASTING);
5069         if (helper->banner != NULL)  {
5070                 g_object_ref (helper->banner);
5071                 gtk_widget_show (GTK_WIDGET(helper->banner));
5072         }
5073 #endif
5074         /* Clean folder on header view before moving it */
5075         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (info->folder_view));
5076         gtk_tree_selection_unselect_all (sel);
5077
5078         /* Let gtk events run. We need that the folder
5079            view frees its reference to the source
5080            folder *before* issuing the mail operation
5081            so we need the signal handler of selection
5082            changed to happen before the mail
5083            operation
5084         while (gtk_events_pending ())
5085                 gtk_main_iteration ();   */
5086
5087         mail_op =
5088                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
5089                                                                modest_ui_actions_move_folder_error_handler,
5090                                                                g_object_ref (info->dst_folder), g_object_unref);
5091         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
5092                                          mail_op);
5093
5094         modest_mail_operation_xfer_folder (mail_op,
5095                         TNY_FOLDER (info->src_folder),
5096                         info->dst_folder,
5097                         info->delete_original,
5098                         folder_move_to_cb,
5099                         helper);
5100         g_object_unref (G_OBJECT (info->src_folder));
5101
5102         /* if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {        */
5103         /* } */
5104
5105         /* Unref mail operation */
5106         g_object_unref (G_OBJECT (mail_op));
5107         g_object_unref (G_OBJECT (info->dst_folder));
5108         g_free (user_data);
5109 }
5110
5111 static TnyAccount *
5112 get_account_from_folder_store (TnyFolderStore *folder_store)
5113 {
5114         if (TNY_IS_ACCOUNT (folder_store))
5115                 return g_object_ref (folder_store);
5116         else
5117                 return tny_folder_get_account (TNY_FOLDER (folder_store));
5118 }
5119
5120 /*
5121  * UI handler for the "Move to" action when invoked from the
5122  * ModestFolderWindow
5123  */
5124 static void
5125 modest_ui_actions_on_folder_window_move_to (GtkWidget *folder_view,
5126                                             TnyFolderStore *dst_folder,
5127                                             TnyList *selection,
5128                                             ModestWindow *win)
5129 {
5130         TnyFolderStore *src_folder = NULL;
5131         TnyIterator *iterator;
5132
5133         if (tny_list_get_length (selection) != 1)
5134                 return;
5135
5136         iterator = tny_list_create_iterator (selection);
5137         src_folder = TNY_FOLDER_STORE (tny_iterator_get_current (iterator));
5138         g_object_unref (iterator);
5139
5140
5141         gboolean do_xfer = TRUE;
5142
5143         /* Allow only to transfer folders to the local root folder */
5144         if (TNY_IS_ACCOUNT (dst_folder) &&
5145             !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (dst_folder) &&
5146             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (dst_folder))) {
5147                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
5148
5149                 do_xfer = FALSE;
5150                 /* Show an error */
5151                 modest_platform_run_information_dialog (toplevel,
5152                                                         _("mail_in_ui_folder_move_target_error"),
5153                                                         FALSE);
5154         } else if (!TNY_IS_FOLDER (src_folder)) {
5155                 g_warning ("%s: src_folder is not a TnyFolder.\n", __FUNCTION__);
5156                 do_xfer = FALSE;
5157         }
5158
5159         if (do_xfer) {
5160                 MoveFolderInfo *info = g_new0 (MoveFolderInfo, 1);
5161                 DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5162
5163                 info->src_folder = g_object_ref (src_folder);
5164                 info->dst_folder = g_object_ref (dst_folder);
5165                 info->delete_original = TRUE;
5166                 info->folder_view = folder_view;
5167
5168                 connect_info->callback = on_move_folder_cb;
5169                 connect_info->dst_account = get_account_from_folder_store (TNY_FOLDER_STORE (dst_folder));
5170                 connect_info->data = info;
5171
5172                 modest_platform_double_connect_and_perform(win, TRUE,
5173                                                            TNY_FOLDER_STORE (src_folder),
5174                                                            connect_info);
5175         }
5176
5177         /* Frees */
5178         g_object_unref (src_folder);
5179 }
5180
5181
5182 void
5183 modest_ui_actions_transfer_messages_helper (ModestWindow *win,
5184                                             TnyFolder *src_folder,
5185                                             TnyList *headers,
5186                                             TnyFolder *dst_folder)
5187 {
5188         gboolean need_connection = TRUE;
5189         gboolean do_xfer = TRUE;
5190         XferMsgsHelper *helper;
5191
5192         g_return_if_fail (TNY_IS_FOLDER (src_folder));
5193         g_return_if_fail (TNY_IS_FOLDER (dst_folder));
5194         g_return_if_fail (TNY_IS_LIST (headers));
5195
5196         modest_ui_actions_xfer_messages_check (win, TNY_FOLDER_STORE (src_folder),
5197                                                headers, TNY_FOLDER (dst_folder),
5198                                                TRUE, &need_connection,
5199                                                &do_xfer);
5200
5201         /* If we don't want to transfer just return */
5202         if (!do_xfer)
5203                 return;
5204
5205         /* Create the helper */
5206         helper = g_slice_new (XferMsgsHelper);
5207         helper->dst_folder = g_object_ref (dst_folder);
5208         helper->headers = g_object_ref (headers);
5209
5210         if (need_connection) {
5211                 DoubleConnectionInfo *connect_info = g_slice_new (DoubleConnectionInfo);
5212                 connect_info->callback = xfer_messages_performer;
5213                 connect_info->dst_account = tny_folder_get_account (TNY_FOLDER (dst_folder));
5214                 connect_info->data = helper;
5215
5216                 modest_platform_double_connect_and_perform(win, TRUE,
5217                                                            TNY_FOLDER_STORE (src_folder),
5218                                                            connect_info);
5219         } else {
5220                 TnyAccount *src_account = get_account_from_folder_store (TNY_FOLDER_STORE (src_folder));
5221                 xfer_messages_performer (FALSE, NULL, win,
5222                                          src_account, helper);
5223                 g_object_unref (src_account);
5224         }
5225 }
5226
5227 /*
5228  * UI handler for the "Move to" action when invoked from the
5229  * ModestMsgViewWindow
5230  */
5231 static void
5232 modest_ui_actions_on_window_move_to (GtkAction *action,
5233                                      TnyList *headers,
5234                                      TnyFolderStore *dst_folder,
5235                                      ModestWindow *win)
5236 {
5237         TnyFolder *src_folder = NULL;
5238
5239         g_return_if_fail (TNY_IS_FOLDER (dst_folder));
5240
5241         if (headers) {
5242                 TnyHeader *header = NULL;
5243                 TnyIterator *iter;
5244
5245                 iter = tny_list_create_iterator (headers);
5246                 header = (TnyHeader *) tny_iterator_get_current (iter);
5247                 src_folder = tny_header_get_folder (header);
5248
5249                 /* Transfer the messages */
5250                 modest_ui_actions_transfer_messages_helper (win, src_folder,
5251                                                             headers,
5252                                                             TNY_FOLDER (dst_folder));
5253
5254                 /* Frees */
5255                 g_object_unref (header);
5256                 g_object_unref (iter);
5257                 g_object_unref (src_folder);
5258         }
5259 }
5260
5261 void
5262 modest_ui_actions_on_move_to (GtkAction *action,
5263                               ModestWindow *win)
5264 {
5265         modest_ui_actions_on_edit_mode_move_to (win);
5266 }
5267
5268 gboolean
5269 modest_ui_actions_on_edit_mode_move_to (ModestWindow *win)
5270 {
5271         GtkWidget *dialog = NULL;
5272         GtkWindow *toplevel = NULL;
5273         MoveToInfo *helper = NULL;
5274         TnyList *list_to_move;
5275
5276         g_return_val_if_fail (MODEST_IS_WINDOW (win), FALSE);
5277
5278
5279         list_to_move = modest_platform_get_list_to_move (MODEST_WINDOW (win));
5280
5281         if (!list_to_move)
5282                 return FALSE;
5283
5284         if (tny_list_get_length (list_to_move) < 1) {
5285                 g_object_unref (list_to_move);
5286                 return FALSE;
5287         }
5288
5289         /* Create and run the dialog */
5290         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
5291         dialog = create_move_to_dialog (toplevel, NULL, list_to_move);
5292         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
5293                                      GTK_WINDOW (dialog),
5294                                      toplevel);
5295
5296         /* Create helper */
5297         helper = g_slice_new0 (MoveToInfo);
5298         helper->list = list_to_move;
5299         helper->win = win;
5300
5301         /* Listen to response signal */
5302         g_signal_connect (dialog, "response", G_CALLBACK (on_move_to_dialog_response), helper);
5303
5304         /* Show the dialog */
5305         gtk_widget_show (dialog);
5306
5307         return FALSE;
5308 }
5309
5310 /*
5311  * Calls #HeadersFunc for each header already selected in the main
5312  * window or the message currently being shown in the msg view window
5313  */
5314 static void
5315 do_headers_action (ModestWindow *win,
5316                    HeadersFunc func,
5317                    gpointer user_data)
5318 {
5319         TnyList *headers_list = NULL;
5320         TnyIterator *iter = NULL;
5321         TnyHeader *header = NULL;
5322         TnyFolder *folder = NULL;
5323
5324         /* Get headers */
5325         headers_list = get_selected_headers (win);
5326         if (!headers_list)
5327                 return;
5328
5329         /* Get the folder */
5330         iter = tny_list_create_iterator (headers_list);
5331         header = TNY_HEADER (tny_iterator_get_current (iter));
5332         if (header) {
5333                 folder = tny_header_get_folder (header);
5334                 g_object_unref (header);
5335         }
5336
5337         /* Call the function for each header */
5338         while (!tny_iterator_is_done (iter)) {
5339                 header = TNY_HEADER (tny_iterator_get_current (iter));
5340                 func (header, win, user_data);
5341                 g_object_unref (header);
5342                 tny_iterator_next (iter);
5343         }
5344
5345         /* Trick: do a poke status in order to speed up the signaling
5346            of observers */
5347         if (folder) {
5348                 tny_folder_poke_status (folder);
5349                 g_object_unref (folder);
5350         }
5351
5352         /* Frees */
5353         g_object_unref (iter);
5354         g_object_unref (headers_list);
5355 }
5356
5357 void
5358 modest_ui_actions_view_attachment (GtkAction *action,
5359                                    ModestWindow *window)
5360 {
5361         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5362                 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (window), NULL);
5363         } else {
5364                 /* not supported window for this action */
5365                 g_return_if_reached ();
5366         }
5367 }
5368
5369 void
5370 modest_ui_actions_save_attachments (GtkAction *action,
5371                                     ModestWindow *window)
5372 {
5373         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5374
5375                 if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
5376                         return;
5377
5378                 modest_msg_view_window_save_attachments (MODEST_MSG_VIEW_WINDOW (window), NULL);
5379         } else {
5380                 /* not supported window for this action */
5381                 g_return_if_reached ();
5382         }
5383 }
5384
5385 void
5386 modest_ui_actions_remove_attachments (GtkAction *action,
5387                                       ModestWindow *window)
5388 {
5389         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
5390                 modest_msg_view_window_remove_attachments (MODEST_MSG_VIEW_WINDOW (window), FALSE);
5391         } else {
5392                 /* not supported window for this action */
5393                 g_return_if_reached ();
5394         }
5395 }
5396
5397 void
5398 modest_ui_actions_on_settings (GtkAction *action,
5399                                ModestWindow *win)
5400 {
5401         GtkWidget *dialog;
5402         GtkWindow *toplevel;
5403
5404         dialog = modest_platform_get_global_settings_dialog ();
5405         toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (win));
5406         gtk_window_set_transient_for (GTK_WINDOW (dialog), toplevel);
5407         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
5408         gtk_widget_show_all (dialog);
5409
5410         gtk_dialog_run (GTK_DIALOG (dialog));
5411
5412         gtk_widget_destroy (dialog);
5413 }
5414
5415 void
5416 modest_ui_actions_on_help (GtkAction *action,
5417                            GtkWindow *win)
5418 {
5419         /* Help app is not available at all in fremantle */
5420 #ifndef MODEST_TOOLKIT_HILDON2
5421         const gchar *help_id;
5422
5423         g_return_if_fail (win && GTK_IS_WINDOW(win));
5424
5425         help_id = modest_window_mgr_get_help_id (modest_runtime_get_window_mgr(), win);
5426
5427         if (help_id)
5428                 modest_platform_show_help (win, help_id);
5429 #endif
5430 }
5431
5432 void
5433 modest_ui_actions_on_csm_help (GtkAction *action,
5434                                GtkWindow *win)
5435 {
5436         /* Help app is not available at all in fremantle */
5437 }
5438
5439 static void
5440 retrieve_contents_cb (ModestMailOperation *mail_op,
5441                       TnyHeader *header,
5442                       gboolean canceled,
5443                       TnyMsg *msg,
5444                       GError *err,
5445                       gpointer user_data)
5446 {
5447         /* We only need this callback to show an error in case of
5448            memory low condition */
5449         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
5450                 g_debug ("%s: message failed to retrieve. Memory low?", __FUNCTION__);
5451         }
5452 }
5453
5454 static void
5455 retrieve_msg_contents_performer (gboolean canceled,
5456                                  GError *err,
5457                                  ModestWindow *parent_window,
5458                                  TnyAccount *account,
5459                                  gpointer user_data)
5460 {
5461         ModestMailOperation *mail_op;
5462         TnyList *headers = TNY_LIST (user_data);
5463
5464         if (err || canceled) {
5465                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
5466                                                                 (GtkWidget *) parent_window, err,
5467                                                                 account, NULL);
5468                 goto out;
5469         }
5470
5471         /* Create mail operation */
5472         mail_op = modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
5473                                                                  modest_ui_actions_disk_operations_error_handler,
5474                                                                  NULL, NULL);
5475         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
5476         modest_mail_operation_get_msgs_full (mail_op, headers, retrieve_contents_cb, NULL, NULL);
5477
5478         /* Frees */
5479         g_object_unref (mail_op);
5480  out:
5481         g_object_unref (headers);
5482         g_object_unref (account);
5483 }
5484
5485 void
5486 modest_ui_actions_on_retrieve_msg_contents (GtkAction *action,
5487                                             ModestWindow *window)
5488 {
5489         TnyList *headers = NULL;
5490         TnyAccount *account = NULL;
5491         TnyIterator *iter = NULL;
5492         TnyHeader *header = NULL;
5493         TnyFolder *folder = NULL;
5494
5495         /* Get headers */
5496         headers = get_selected_headers (window);
5497         if (!headers)
5498                 return;
5499
5500         /* Pick the account */
5501         iter = tny_list_create_iterator (headers);
5502         header = TNY_HEADER (tny_iterator_get_current (iter));
5503         folder = tny_header_get_folder (header);
5504         account = tny_folder_get_account (folder);
5505         g_object_unref (folder);
5506         g_object_unref (header);
5507         g_object_unref (iter);
5508
5509         /* Connect and perform the message retrieval */
5510         modest_platform_connect_and_perform (window, TRUE,
5511                                              g_object_ref (account),
5512                                              retrieve_msg_contents_performer,
5513                                              g_object_ref (headers));
5514
5515         /* Frees */
5516         g_object_unref (account);
5517         g_object_unref (headers);
5518 }
5519
5520 void
5521 modest_ui_actions_check_toolbar_dimming_rules (ModestWindow *window)
5522 {
5523         g_return_if_fail (MODEST_IS_WINDOW (window));
5524
5525         /* Update dimmed */
5526         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_TOOLBAR);
5527 }
5528
5529 void
5530 modest_ui_actions_check_menu_dimming_rules (ModestWindow *window)
5531 {
5532         g_return_if_fail (MODEST_IS_WINDOW (window));
5533
5534         /* Update dimmed */
5535         modest_window_check_dimming_rules_group (window, MODEST_DIMMING_RULES_MENU);
5536 }
5537
5538 void
5539 modest_ui_actions_on_email_menu_activated (GtkAction *action,
5540                                           ModestWindow *window)
5541 {
5542         g_return_if_fail (MODEST_IS_WINDOW (window));
5543
5544         /* Update dimmed */
5545         modest_ui_actions_check_menu_dimming_rules (window);
5546 }
5547
5548 void
5549 modest_ui_actions_on_edit_menu_activated (GtkAction *action,
5550                                           ModestWindow *window)
5551 {
5552         g_return_if_fail (MODEST_IS_WINDOW (window));
5553
5554         /* Update dimmed */
5555         modest_ui_actions_check_menu_dimming_rules (window);
5556 }
5557
5558 void
5559 modest_ui_actions_on_view_menu_activated (GtkAction *action,
5560                                           ModestWindow *window)
5561 {
5562         g_return_if_fail (MODEST_IS_WINDOW (window));
5563
5564         /* Update dimmed */
5565         modest_ui_actions_check_menu_dimming_rules (window);
5566 }
5567
5568 void
5569 modest_ui_actions_on_format_menu_activated (GtkAction *action,
5570                                             ModestWindow *window)
5571 {
5572         g_return_if_fail (MODEST_IS_WINDOW (window));
5573
5574         /* Update dimmed */
5575         modest_ui_actions_check_menu_dimming_rules (window);
5576 }
5577
5578 void
5579 modest_ui_actions_on_tools_menu_activated (GtkAction *action,
5580                                           ModestWindow *window)
5581 {
5582         g_return_if_fail (MODEST_IS_WINDOW (window));
5583
5584         /* Update dimmed */
5585         modest_ui_actions_check_menu_dimming_rules (window);
5586 }
5587
5588 void
5589 modest_ui_actions_on_attachment_menu_activated (GtkAction *action,
5590                                           ModestWindow *window)
5591 {
5592         g_return_if_fail (MODEST_IS_WINDOW (window));
5593
5594         /* Update dimmed */
5595         modest_ui_actions_check_menu_dimming_rules (window);
5596 }
5597
5598 void
5599 modest_ui_actions_on_toolbar_csm_menu_activated (GtkAction *action,
5600                                                  ModestWindow *window)
5601 {
5602         g_return_if_fail (MODEST_IS_WINDOW (window));
5603
5604         /* Update dimmed */
5605         modest_ui_actions_check_menu_dimming_rules (window);
5606 }
5607
5608 void
5609 modest_ui_actions_on_folder_view_csm_menu_activated (GtkAction *action,
5610                                                      ModestWindow *window)
5611 {
5612         g_return_if_fail (MODEST_IS_WINDOW (window));
5613
5614         /* Update dimmed */
5615         modest_ui_actions_check_menu_dimming_rules (window);
5616 }
5617
5618 void
5619 modest_ui_actions_on_header_view_csm_menu_activated (GtkAction *action,
5620                                                      ModestWindow *window)
5621 {
5622         g_return_if_fail (MODEST_IS_WINDOW (window));
5623
5624         /* Update dimmed */
5625         modest_ui_actions_check_menu_dimming_rules (window);
5626 }
5627
5628 void
5629 modest_ui_actions_on_search_messages (GtkAction *action, ModestWindow *window)
5630 {
5631         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
5632
5633         g_return_if_fail (MODEST_IS_WINDOW (window));
5634
5635         /* we check for low-mem; in that case, show a warning, and don't allow
5636          * searching
5637          */
5638         if (modest_platform_check_memory_low (window, TRUE))
5639                 return;
5640
5641         modest_platform_show_search_messages (toplevel);
5642 }
5643
5644 void
5645 modest_ui_actions_on_open_addressbook (GtkAction *action, ModestWindow *win)
5646 {
5647         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
5648
5649         g_return_if_fail (MODEST_IS_WINDOW (win));
5650
5651         /* we check for low-mem; in that case, show a warning, and don't allow
5652          * for the addressbook
5653          */
5654         if (modest_platform_check_memory_low (win, TRUE))
5655                 return;
5656
5657         modest_platform_show_addressbook (toplevel);
5658 }
5659
5660
5661 void
5662 modest_ui_actions_on_toggle_find_in_page (GtkAction *action,
5663                                           ModestWindow *window)
5664 {
5665         gboolean active;
5666         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
5667
5668         if (GTK_IS_TOGGLE_ACTION (action))
5669                 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
5670         else
5671                 active = TRUE;
5672
5673         modest_msg_edit_window_toggle_isearch_toolbar (MODEST_MSG_EDIT_WINDOW (window),
5674                                                        active);
5675 }
5676
5677
5678 void
5679 modest_ui_actions_on_send_queue_error_happened (TnySendQueue *self,
5680                                                 TnyHeader *header,
5681                                                 TnyMsg *msg,
5682                                                 GError *err,
5683                                                 gpointer user_data)
5684 {
5685         const gchar* server_name = NULL;
5686         TnyTransportAccount *transport;
5687         gchar *message = NULL;
5688         ModestProtocol *protocol;
5689
5690         /* Don't show anything if the user cancelled something or the
5691          * send receive request is not interactive. Authentication
5692          * errors are managed by the account store so no need to show
5693          * a dialog here again */
5694         if (err->code == TNY_SYSTEM_ERROR_CANCEL ||
5695             err->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
5696             !modest_tny_send_queue_get_requested_send_receive (MODEST_TNY_SEND_QUEUE (self)))
5697                 return;
5698
5699
5700         /* Get the server name. Note that we could be using a
5701            connection specific transport account */
5702         transport = (TnyTransportAccount *)
5703                 tny_camel_send_queue_get_transport_account (TNY_CAMEL_SEND_QUEUE (self));
5704         if (transport) {
5705                 ModestTnyAccountStore *acc_store;
5706                 const gchar *acc_name;
5707                 TnyTransportAccount *conn_specific;
5708
5709                 acc_store = modest_runtime_get_account_store();
5710                 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (TNY_ACCOUNT (transport));
5711                 conn_specific = (TnyTransportAccount *)
5712                         modest_tny_account_store_get_transport_account_for_open_connection (acc_store, acc_name);
5713                 if (conn_specific) {
5714                         server_name = tny_account_get_hostname (TNY_ACCOUNT (conn_specific));
5715                         g_object_unref (conn_specific);
5716                 } else {
5717                         server_name = tny_account_get_hostname (TNY_ACCOUNT (transport));
5718                 }
5719                 g_object_unref (transport);
5720         }
5721
5722         /* Get protocol */
5723         protocol = modest_protocol_registry_get_protocol_by_name (modest_runtime_get_protocol_registry (),
5724                                                                   MODEST_PROTOCOL_REGISTRY_TRANSPORT_STORE_PROTOCOLS,
5725                                                                   tny_account_get_proto (TNY_ACCOUNT (transport)));
5726         if (!protocol) {
5727                 g_warning ("%s: Account with no proto", __FUNCTION__);
5728                 return;
5729         }
5730
5731         /* Show the appropriate message text for the GError: */
5732         switch (err->code) {
5733         case TNY_SERVICE_ERROR_CONNECT:
5734                 message = modest_protocol_get_translation (protocol,
5735                                                            MODEST_PROTOCOL_TRANSLATION_ACCOUNT_CONNECTION_ERROR,
5736                                                            server_name);
5737                 break;
5738         case TNY_SERVICE_ERROR_SEND:
5739                 message = g_strdup (_CS_UNABLE_TO_SEND);
5740                 break;
5741         case TNY_SERVICE_ERROR_UNAVAILABLE:
5742                 message = modest_protocol_get_translation (protocol,
5743                                                            MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR,
5744                                                            server_name);
5745                 break;
5746         default:
5747                 g_warning ("%s: unexpected ERROR %d",
5748                            __FUNCTION__, err->code);
5749                 message = g_strdup (_CS_UNABLE_TO_SEND);
5750                 break;
5751         }
5752
5753         modest_platform_run_information_dialog (NULL, message, FALSE);
5754         g_free (message);
5755 }
5756
5757 void
5758 modest_ui_actions_on_send_queue_status_changed (ModestTnySendQueue *send_queue,
5759                                                 gchar *msg_id,
5760                                                 guint status,
5761                                                 gpointer user_data)
5762 {
5763         ModestWindow *top_window = NULL;
5764         ModestWindowMgr *mgr = NULL;
5765         GtkWidget *header_view = NULL;
5766         TnyFolder *selected_folder = NULL;
5767         TnyFolderType folder_type;
5768
5769         mgr = modest_runtime_get_window_mgr ();
5770         top_window = modest_window_mgr_get_current_top (mgr);
5771
5772         if (!top_window)
5773                 return;
5774
5775         if (MODEST_IS_HEADER_WINDOW (top_window)) {
5776                 header_view = (GtkWidget *)
5777                         modest_header_window_get_header_view (MODEST_HEADER_WINDOW (top_window));
5778         }
5779
5780         /* Get selected folder */
5781         if (header_view)
5782                 selected_folder = modest_header_view_get_folder (MODEST_HEADER_VIEW (header_view));
5783         if (!selected_folder)
5784                 return;
5785
5786         /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
5787 #if GTK_CHECK_VERSION(2, 8, 0)
5788         folder_type = modest_tny_folder_guess_folder_type (selected_folder);
5789         if (folder_type ==  TNY_FOLDER_TYPE_OUTBOX) {
5790                 GtkTreeViewColumn *tree_column;
5791
5792                 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (header_view),
5793                                                         TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN);
5794                 if (tree_column)
5795                         gtk_tree_view_column_queue_resize (tree_column);
5796                 }
5797 #else /* #if GTK_CHECK_VERSION(2, 8, 0) */
5798         gtk_widget_queue_draw (header_view);
5799 #endif
5800
5801 #ifndef MODEST_TOOLKIT_HILDON2
5802         /* Rerun dimming rules, because the message could become deletable for example */
5803         modest_window_check_dimming_rules_group (MODEST_WINDOW (top_window),
5804                                                  MODEST_DIMMING_RULES_TOOLBAR);
5805         modest_window_check_dimming_rules_group (MODEST_WINDOW (top_window),
5806                                                  MODEST_DIMMING_RULES_MENU);
5807 #endif
5808
5809         /* Free */
5810         g_object_unref (selected_folder);
5811 }
5812
5813 void
5814 modest_ui_actions_on_account_connection_error (ModestWindow *parent_window,
5815                                                TnyAccount *account)
5816 {
5817         ModestProtocolType protocol_type;
5818         ModestProtocol *protocol;
5819         gchar *error_note = NULL;
5820
5821         protocol_type = modest_tny_account_get_protocol_type (account);
5822         protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
5823                                                                   protocol_type);
5824
5825         error_note = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_ACCOUNT_CONNECTION_ERROR, tny_account_get_hostname (account));
5826         if (error_note == NULL) {
5827                 g_warning ("%s: This should not be reached", __FUNCTION__);
5828         } else {
5829                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) parent_window);
5830                 modest_platform_run_information_dialog (toplevel, error_note, FALSE);
5831                 g_free (error_note);
5832         }
5833 }
5834
5835 gchar *
5836 modest_ui_actions_get_msg_already_deleted_error_msg (ModestWindow *win)
5837 {
5838         gchar *msg = NULL;
5839         gchar *subject;
5840         TnyFolderStore *folder = NULL;
5841         TnyAccount *account = NULL;
5842         ModestProtocolType proto;
5843         ModestProtocol *protocol;
5844         TnyHeader *header = NULL;
5845
5846         if (MODEST_IS_HEADER_WINDOW (win)) {
5847                 GtkWidget *header_view;
5848                 TnyList* headers = NULL;
5849                 TnyIterator *iter;
5850                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (win)));
5851                 headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
5852                 if (!headers || tny_list_get_length (headers) == 0) {
5853                         if (headers)
5854                                 g_object_unref (headers);
5855                         return NULL;
5856                 }
5857                 iter = tny_list_create_iterator (headers);
5858                 header = TNY_HEADER (tny_iterator_get_current (iter));
5859                 if (header) {
5860                         folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5861                 } else {
5862                         g_warning ("List should contain headers");
5863                 }
5864                 g_object_unref (iter);
5865                 g_object_unref (headers);
5866         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
5867                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
5868                 if (header)
5869                         folder = TNY_FOLDER_STORE (tny_header_get_folder (header));
5870         }
5871
5872         if (!header || !folder)
5873                 goto frees;
5874
5875         /* Get the account type */
5876         account = tny_folder_get_account (TNY_FOLDER (folder));
5877         proto = modest_tny_account_get_protocol_type (account);
5878         protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
5879                                                                   proto);
5880
5881         subject = tny_header_dup_subject (header);
5882         msg = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE, subject);
5883         if (subject)
5884                 g_free (subject);
5885         if (msg == NULL) {
5886                 msg = g_strdup_printf (_("mail_ni_ui_folder_get_msg_folder_error"));
5887         }
5888
5889  frees:
5890         /* Frees */
5891         if (account)
5892                 g_object_unref (account);
5893         if (folder)
5894                 g_object_unref (folder);
5895         if (header)
5896                 g_object_unref (header);
5897
5898         return msg;
5899 }
5900
5901 gboolean
5902 modest_ui_actions_on_delete_account (GtkWindow *parent_window,
5903                                      const gchar *account_name,
5904                                      const gchar *account_title)
5905 {
5906         ModestAccountMgr *account_mgr;
5907         gchar *txt = NULL;
5908         gint response;
5909         ModestProtocol *protocol;
5910         gboolean removed = FALSE;
5911
5912         g_return_val_if_fail (account_name, FALSE);
5913         g_return_val_if_fail (account_title, FALSE);
5914
5915         account_mgr = modest_runtime_get_account_mgr();
5916
5917         /* The warning text depends on the account type: */
5918         protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
5919                                                                   modest_account_mgr_get_store_protocol (account_mgr,
5920                                                                                                          account_name));
5921         txt = modest_protocol_get_translation (protocol,
5922                                                MODEST_PROTOCOL_TRANSLATION_DELETE_MAILBOX,
5923                                                account_title);
5924         if (txt == NULL)
5925                 txt = g_strdup_printf (_("emev_nc_delete_mailbox"), account_title);
5926
5927         response = modest_platform_run_confirmation_dialog (parent_window, txt);
5928         g_free (txt);
5929         txt = NULL;
5930
5931         if (response == GTK_RESPONSE_OK) {
5932                 /* Remove account. If it succeeds then it also removes
5933                    the account from the ModestAccountView: */
5934                 gboolean is_default = FALSE;
5935                 gchar *default_account_name = modest_account_mgr_get_default_account (account_mgr);
5936                 if (default_account_name && (strcmp (default_account_name, account_name) == 0))
5937                         is_default = TRUE;
5938                 g_free (default_account_name);
5939
5940                 removed = modest_account_mgr_remove_account (account_mgr, account_name);
5941                 if (removed) {
5942 #ifdef MODEST_TOOLKIT_HILDON2
5943                         hildon_gtk_window_take_screenshot (parent_window, FALSE);
5944 #endif
5945                         /* Close all email notifications, we cannot
5946                            distinguish if the notification belongs to
5947                            this account or not, so for safety reasons
5948                            we remove them all */
5949                         modest_platform_remove_new_mail_notifications (FALSE, account_name);
5950                 } else {
5951                         g_warning ("%s: modest_account_mgr_remove_account() failed.\n", __FUNCTION__);
5952                 }
5953         }
5954         return removed;
5955 }
5956
5957 static void
5958 on_fetch_images_performer (gboolean canceled,
5959                            GError *err,
5960                            ModestWindow *parent_window,
5961                            TnyAccount *account,
5962                            gpointer user_data)
5963 {
5964         if (err || canceled) {
5965                 /* Show an unable to retrieve images ??? */
5966                 return;
5967         }
5968
5969         /* Note that the user could have closed the window while connecting */
5970         if (GTK_WIDGET_VISIBLE (parent_window))
5971                 modest_msg_view_window_fetch_images ((ModestMsgViewWindow *) parent_window);
5972         g_object_unref ((GObject *) user_data);
5973 }
5974
5975 void
5976 modest_ui_actions_on_fetch_images (GtkAction *action,
5977                                    ModestWindow *window)
5978 {
5979         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
5980
5981         modest_platform_connect_and_perform (window, TRUE,
5982                                              NULL,
5983                                              on_fetch_images_performer,
5984                                              g_object_ref (window));
5985 }
5986
5987 void
5988 modest_ui_actions_on_reload_message (const gchar *msg_id)
5989 {
5990         ModestWindow *window = NULL;
5991
5992         g_return_if_fail (msg_id && msg_id[0] != '\0');
5993         if (!modest_window_mgr_find_registered_message_uid (modest_runtime_get_window_mgr (),
5994                                                             msg_id,
5995                                                             &window))
5996                 return;
5997
5998
5999         if (window == NULL || !MODEST_IS_MSG_VIEW_WINDOW (window))
6000                 return;
6001
6002         modest_msg_view_window_reload (MODEST_MSG_VIEW_WINDOW (window));
6003 }
6004
6005 /** Check whether any connections are active, and cancel them if 
6006  * the user wishes.
6007  * Returns TRUE is there was no problem, 
6008  * or if an operation was cancelled so we can continue.
6009  * Returns FALSE if the user chose to cancel his request instead.
6010  */
6011
6012 gboolean
6013 modest_ui_actions_check_for_active_account (ModestWindow *self,
6014                                             const gchar* account_name)
6015 {
6016         ModestTnySendQueue *send_queue;
6017         ModestTnyAccountStore *acc_store;
6018         ModestMailOperationQueue* queue;
6019         TnyConnectionStatus store_conn_status;
6020         TnyAccount *store_account = NULL, *transport_account = NULL;
6021         gboolean retval = TRUE, sending = FALSE;
6022
6023         acc_store = modest_runtime_get_account_store ();
6024         queue = modest_runtime_get_mail_operation_queue ();
6025
6026         store_account = 
6027                 modest_tny_account_store_get_server_account (acc_store,
6028                                                              account_name,
6029                                                              TNY_ACCOUNT_TYPE_STORE);
6030
6031         /* This could happen if the account was deleted before the
6032            call to this function */
6033         if (!store_account)
6034                 return FALSE;
6035
6036         transport_account = 
6037                 modest_tny_account_store_get_server_account (acc_store,
6038                                                              account_name,
6039                                                              TNY_ACCOUNT_TYPE_TRANSPORT);
6040
6041         /* This could happen if the account was deleted before the
6042            call to this function */
6043         if (!transport_account) {
6044                 g_object_unref (store_account);
6045                 return FALSE;
6046         }
6047
6048         /* If the transport account was not used yet, then the send
6049            queue could not exist (it's created on demand) */
6050         send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (transport_account), FALSE);
6051         if (TNY_IS_SEND_QUEUE (send_queue))
6052                 sending = modest_tny_send_queue_sending_in_progress (send_queue);
6053
6054         store_conn_status = tny_account_get_connection_status (store_account);
6055         if (store_conn_status == TNY_CONNECTION_STATUS_CONNECTED || sending) {
6056                 gint response;
6057
6058                 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), 
6059                                                                     _("emev_nc_disconnect_account"));
6060                 if (response == GTK_RESPONSE_OK) {
6061                         retval = TRUE;
6062                 } else {
6063                         retval = FALSE;
6064                 }
6065         }
6066
6067         if (retval) {
6068
6069                 /* FIXME: We should only cancel those of this account */
6070                 modest_mail_operation_queue_cancel_all (queue);
6071
6072                 /* Also disconnect the account */
6073                 if ((tny_account_get_connection_status (store_account) != TNY_CONNECTION_STATUS_DISCONNECTED) &&
6074                     (tny_account_get_connection_status (store_account) != TNY_CONNECTION_STATUS_DISCONNECTED_BROKEN)) {
6075                         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account),
6076                                                       FALSE, NULL, NULL);
6077                 }
6078                 if (sending) {
6079                         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account),
6080                                                       FALSE, NULL, NULL);
6081                 }
6082         }
6083                 
6084         /* Frees */
6085         g_object_unref (store_account);
6086         g_object_unref (transport_account);
6087         
6088         return retval;
6089 }