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