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