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