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