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