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