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