Do ignore empty recipients when checking names
[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
70 #include <modest-utils.h>
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 #include <tny-camel-bs-msg.h>
89 #include <tny-camel-bs-mime-part.h>
90
91 #include <gtk/gtk.h>
92 #include <gtkhtml/gtkhtml.h>
93
94 #define MODEST_MOVE_TO_DIALOG_FOLDER_VIEW "move-to-dialog-folder-view"
95
96 typedef struct _GetMsgAsyncHelper {
97         ModestWindow *window;
98         ModestMailOperation *mail_op;
99         TnyIterator *iter;
100         guint num_ops;
101         GFunc func;
102         gpointer user_data;
103 } GetMsgAsyncHelper;
104
105 typedef enum _ReplyForwardAction {
106         ACTION_REPLY,
107         ACTION_REPLY_TO_ALL,
108         ACTION_FORWARD
109 } ReplyForwardAction;
110
111 typedef struct _ReplyForwardHelper {
112         guint reply_forward_type;
113         ReplyForwardAction action;
114         gchar *account_name;
115         gchar *mailbox;
116         GtkWidget *parent_window;
117         TnyHeader *header;
118         TnyList *parts;
119 } ReplyForwardHelper;
120
121 typedef struct _MoveToHelper {
122         GtkTreeRowReference *reference;
123         GtkWidget *banner;
124 } MoveToHelper;
125
126 typedef struct _PasteAsAttachmentHelper {
127         ModestMsgEditWindow *window;
128         GtkWidget *banner;
129 } PasteAsAttachmentHelper;
130
131 typedef struct {
132         TnyList *list;
133         ModestWindow *win;
134 } MoveToInfo;
135
136 /*
137  * The do_headers_action uses this kind of functions to perform some
138  * action to each member of a list of headers
139  */
140 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
141
142 static void     do_headers_action     (ModestWindow *win,
143                                        HeadersFunc func,
144                                        gpointer user_data);
145
146 static void     open_msg_cb            (ModestMailOperation *mail_op,
147                                         TnyHeader *header,
148                                         gboolean canceled,
149                                         TnyMsg *msg,
150                                         GError *err,
151                                         gpointer user_data);
152
153 static void     reply_forward_cb       (ModestMailOperation *mail_op,
154                                         TnyHeader *header,
155                                         gboolean canceled,
156                                         TnyMsg *msg,
157                                         GError *err,
158                                         gpointer user_data);
159
160 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
161
162 static void     folder_refreshed_cb    (ModestMailOperation *mail_op,
163                                         TnyFolder *folder,
164                                         gpointer user_data);
165
166 static void     on_send_receive_finished (ModestMailOperation  *mail_op,
167                                           gpointer user_data);
168
169 static gint header_list_count_uncached_msgs (TnyList *header_list);
170
171 static gboolean connect_to_get_msg (ModestWindow *win,
172                                     gint num_of_uncached_msgs,
173                                     TnyAccount *account);
174
175 static gboolean remote_folder_has_leave_on_server (TnyFolderStore *folder);
176
177 static void     do_create_folder (GtkWindow *window,
178                                   TnyFolderStore *parent_folder,
179                                   const gchar *suggested_name);
180
181 static TnyAccount *get_account_from_folder_store (TnyFolderStore *folder_store);
182
183 static void modest_ui_actions_on_main_window_move_to (GtkAction *action,
184                                                       GtkWidget *folder_view,
185                                                       TnyFolderStore *dst_folder,
186                                                       ModestMainWindow *win);
187 #ifdef MODEST_TOOLKIT_HILDON2
188 static void modest_ui_actions_on_folder_window_move_to (GtkWidget *folder_view,
189                                                         TnyFolderStore *dst_folder,
190                                                         TnyList *selection,
191                                                         GtkWindow *win);
192 #endif
193
194 static void modest_ui_actions_on_window_move_to (GtkAction *action,
195                                                  TnyList *list_to_move,
196                                                  TnyFolderStore *dst_folder,
197                                                  ModestWindow *win);
198
199 /*
200  * This function checks whether a TnyFolderStore is a pop account
201  */
202 static gboolean
203 remote_folder_has_leave_on_server (TnyFolderStore *folder)
204 {
205         TnyAccount *account;
206         gboolean result;
207
208         g_return_val_if_fail (TNY_IS_FOLDER_STORE (folder), FALSE);
209
210         account = get_account_from_folder_store (folder);
211         result = (modest_protocol_registry_protocol_type_has_leave_on_server (modest_runtime_get_protocol_registry (),
212                                                                               modest_tny_account_get_protocol_type (account)));
213         g_object_unref (account);
214
215         return result;
216 }
217
218 /* FIXME: this should be merged with the similar code in modest-account-view-window */
219 /* Show the account creation wizard dialog.
220  * returns: TRUE if an account was created. FALSE if the user cancelled.
221  */
222 gboolean
223 modest_ui_actions_run_account_setup_wizard (ModestWindow *win)
224 {
225         gboolean result = FALSE;
226         GtkWindow *wizard;
227         gint dialog_response;
228
229         /* there is no such wizard yet */
230         wizard = GTK_WINDOW (modest_platform_get_account_settings_wizard ());
231         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (wizard), (GtkWindow *) win);
232
233 #ifndef MODEST_TOOLKIT_HILDON2
234         /* always present a main window in the background
235          * we do it here, so we cannot end up with two wizards (as this
236          * function might be called in modest_window_mgr_get_main_window as well */
237         if (!win)
238                 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
239                                                          TRUE);  /* create if not existent */
240 #else
241         if (!win) {
242                 GList *window_list;
243                 ModestWindowMgr *mgr;
244
245                 mgr = modest_runtime_get_window_mgr ();
246
247                 window_list = modest_window_mgr_get_window_list (mgr);
248                 if (window_list == NULL) {
249                         win = MODEST_WINDOW (modest_accounts_window_new ());
250                         if (modest_window_mgr_register_window (mgr, win, NULL)) {
251                                 gtk_widget_show_all (GTK_WIDGET (win));
252                         } else {
253                                 gtk_widget_destroy (GTK_WIDGET (win));
254                                 win = NULL;
255                         }
256
257                 } else {
258                         g_list_free (window_list);
259                 }
260         }
261 #endif
262
263         if (win)
264                 gtk_window_set_transient_for (GTK_WINDOW (wizard), GTK_WINDOW (win));
265
266         /* make sure the mainwindow is visible. We need to present the
267            wizard again to give it the focus back. show_all are needed
268            in order to get the widgets properly drawn (MainWindow main
269            paned won't be in its right position and the dialog will be
270            missplaced */
271 #ifndef MODEST_TOOLKIT_HILDON2
272         gtk_widget_show_all (GTK_WIDGET (win));
273         gtk_widget_show_all (GTK_WIDGET (wizard));
274         gtk_window_present (GTK_WINDOW (win));
275         gtk_window_present (GTK_WINDOW (wizard));
276 #endif
277
278         dialog_response = gtk_dialog_run (GTK_DIALOG (wizard));
279         gtk_widget_destroy (GTK_WIDGET (wizard));
280         if (gtk_events_pending ())
281                 gtk_main_iteration ();
282
283         if (dialog_response == GTK_RESPONSE_CANCEL) {
284                 result = FALSE;
285         } else {
286                 /* Check whether an account was created: */
287                 result = modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
288         }
289         return result;
290 }
291
292
293 void
294 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
295 {
296         GtkWidget *about;
297         const gchar *authors[] = {
298                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
299                 NULL
300         };
301         about = gtk_about_dialog_new ();
302         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
303         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
304         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
305                                         _("Copyright (c) 2006, Nokia Corporation\n"
306                                           "All rights reserved."));
307         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
308                                        _("a modest e-mail client\n\n"
309                                          "design and implementation: Dirk-Jan C. Binnema\n"
310                                          "contributions from the fine people at KC and Ig\n"
311                                          "uses the tinymail email framework written by Philip van Hoof"));
312         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
313         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
314         gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (win));
315         gtk_window_set_modal (GTK_WINDOW (about), TRUE);
316
317         gtk_dialog_run (GTK_DIALOG (about));
318         gtk_widget_destroy(about);
319 }
320
321 /*
322  * Gets the list of currently selected messages. If the win is the
323  * main window, then it returns a newly allocated list of the headers
324  * selected in the header view. If win is the msg view window, then
325  * the value returned is a list with just a single header.
326  *
327  * The caller of this funcion must free the list.
328  */
329 static TnyList *
330 get_selected_headers (ModestWindow *win)
331 {
332         if (MODEST_IS_MAIN_WINDOW(win)) {
333                 GtkWidget *header_view;
334
335                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
336                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
337                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
338
339         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
340                 /* for MsgViewWindows, we simply return a list with one element */
341                 TnyHeader *header;
342                 TnyList *list = NULL;
343
344                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
345                 if (header != NULL) {
346                         list = tny_simple_list_new ();
347                         tny_list_prepend (list, G_OBJECT(header));
348                         g_object_unref (G_OBJECT(header));
349                 }
350
351                 return list;
352
353 #ifdef MODEST_TOOLKIT_HILDON2
354         } else if (MODEST_IS_HEADER_WINDOW (win)) {
355                 GtkWidget *header_view;
356
357                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (win)));
358                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
359 #endif
360         } else
361                 return NULL;
362 }
363
364 static GtkTreeRowReference *
365 get_next_after_selected_headers (ModestHeaderView *header_view)
366 {
367         GtkTreeSelection *sel;
368         GList *selected_rows, *node;
369         GtkTreePath *path;
370         GtkTreeRowReference *result;
371         GtkTreeModel *model;
372
373         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
374         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
375         selected_rows = gtk_tree_selection_get_selected_rows (sel, NULL);
376
377         if (selected_rows == NULL)
378                 return NULL;
379
380         node = g_list_last (selected_rows);
381         path = gtk_tree_path_copy ((GtkTreePath *) node->data);
382         gtk_tree_path_next (path);
383
384         result = gtk_tree_row_reference_new (model, path);
385
386         gtk_tree_path_free (path);
387         g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
388         g_list_free (selected_rows);
389
390         return result;
391 }
392
393 static void
394 headers_action_mark_as_read (TnyHeader *header,
395                              ModestWindow *win,
396                              gpointer user_data)
397 {
398         TnyHeaderFlags flags;
399
400         g_return_if_fail (TNY_IS_HEADER(header));
401
402         flags = tny_header_get_flags (header);
403         if (flags & TNY_HEADER_FLAG_SEEN) return;
404         tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
405 }
406
407 static void
408 headers_action_mark_as_unread (TnyHeader *header,
409                                ModestWindow *win,
410                                gpointer user_data)
411 {
412         TnyHeaderFlags flags;
413
414         g_return_if_fail (TNY_IS_HEADER(header));
415
416         flags = tny_header_get_flags (header);
417         if (flags & TNY_HEADER_FLAG_SEEN)  {
418                 tny_header_unset_flag (header, TNY_HEADER_FLAG_SEEN);
419         }
420 }
421
422 /** After deleing a message that is currently visible in a window,
423  * show the next message from the list, or close the window if there are no more messages.
424  **/
425 void
426 modest_ui_actions_refresh_message_window_after_delete (ModestMsgViewWindow* win)
427 {
428         /* Close msg view window or select next */
429         if (!modest_msg_view_window_select_next_message (win) &&
430             !modest_msg_view_window_select_previous_message (win)) {
431                 gboolean ret_value;
432                 g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
433         }
434 }
435
436
437 void
438 modest_ui_actions_on_delete_message (GtkAction *action, ModestWindow *win)
439 {
440         modest_ui_actions_on_edit_mode_delete_message (win);
441 }
442
443 gboolean
444 modest_ui_actions_on_edit_mode_delete_message (ModestWindow *win)
445 {
446         TnyList *header_list = NULL;
447         TnyIterator *iter = NULL;
448         TnyHeader *header = NULL;
449         gchar *message = NULL;
450         gchar *desc = NULL;
451         gint response;
452         ModestWindowMgr *mgr;
453         GtkWidget *header_view = NULL;
454         gboolean retval = TRUE;
455
456         g_return_val_if_fail (MODEST_IS_WINDOW(win), FALSE);
457
458         /* Check first if the header view has the focus */
459         if (MODEST_IS_MAIN_WINDOW (win)) {
460                 header_view =
461                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
462                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
463                 if (!gtk_widget_is_focus (header_view))
464                         return FALSE;
465         }
466
467         /* Get the headers, either from the header view (if win is the main window),
468          * or from the message view window: */
469         header_list = get_selected_headers (win);
470         if (!header_list) return FALSE;
471
472         /* Check if any of the headers are already opened, or in the process of being opened */
473         if (MODEST_IS_MAIN_WINDOW (win)) {
474                 gint opened_headers = 0;
475
476                 iter = tny_list_create_iterator (header_list);
477                 mgr = modest_runtime_get_window_mgr ();
478                 while (!tny_iterator_is_done (iter)) {
479                         header = TNY_HEADER (tny_iterator_get_current (iter));
480                         if (header) {
481                                 if (modest_window_mgr_find_registered_header (mgr, header, NULL))
482                                         opened_headers++;
483                                 g_object_unref (header);
484                         }
485                         tny_iterator_next (iter);
486                 }
487                 g_object_unref (iter);
488
489                 if (opened_headers > 0) {
490                         gchar *msg;
491
492                         msg = g_strdup_printf (_("mcen_nc_unable_to_delete_n_messages"),
493                                                opened_headers);
494
495                         modest_platform_run_information_dialog (GTK_WINDOW (win), (const gchar *) msg, FALSE);
496
497                         g_free (msg);
498                         g_object_unref (header_list);
499                         return FALSE;
500                 }
501         }
502
503         /* Select message */
504         if (tny_list_get_length(header_list) == 1) {
505                 iter = tny_list_create_iterator (header_list);
506                 header = TNY_HEADER (tny_iterator_get_current (iter));
507                 if (header) {
508                         gchar *subject;
509                         subject = tny_header_dup_subject (header);
510                         if (!subject)
511                                 subject = g_strdup (_("mail_va_no_subject"));
512                         desc = g_strdup_printf ("%s", subject);
513                         g_free (subject);
514                         g_object_unref (header);
515                 }
516
517                 g_object_unref (iter);
518         }
519         message = g_strdup_printf(ngettext("emev_nc_delete_message", "emev_nc_delete_messages",
520                                            tny_list_get_length(header_list)), desc);
521
522         /* Confirmation dialog */
523         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
524                                                             message);
525
526
527         if (response == GTK_RESPONSE_OK) {
528                 ModestWindowMgr *mgr = NULL;
529                 GtkTreeModel *model = NULL;
530                 GtkTreeSelection *sel = NULL;
531                 GList *sel_list = NULL, *tmp = NULL;
532                 GtkTreeRowReference *next_row_reference = NULL;
533                 GtkTreeRowReference *prev_row_reference = NULL;
534                 GtkTreePath *next_path = NULL;
535                 GtkTreePath *prev_path = NULL;
536                 ModestMailOperation *mail_op = NULL;
537
538                 /* Find last selected row */
539                 if (MODEST_IS_MAIN_WINDOW (win)) {
540                         model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
541                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
542                         sel_list = gtk_tree_selection_get_selected_rows (sel, &model);
543                         for (tmp=sel_list; tmp; tmp=tmp->next) {
544                                 if (tmp->next == NULL) {
545                                         prev_path = gtk_tree_path_copy((GtkTreePath *) tmp->data);
546                                         next_path = gtk_tree_path_copy((GtkTreePath *) tmp->data);
547
548                                         gtk_tree_path_prev (prev_path);
549                                         gtk_tree_path_next (next_path);
550
551                                         prev_row_reference = gtk_tree_row_reference_new (model, prev_path);
552                                         next_row_reference = gtk_tree_row_reference_new (model, next_path);
553                                 }
554                         }
555                 }
556
557                 /* Disable window dimming management */
558                 modest_window_disable_dimming (win);
559
560                 /* Remove each header. If it's a view window header_view == NULL */
561                 mail_op = modest_mail_operation_new ((GObject *) win);
562                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
563                                                  mail_op);
564                 modest_mail_operation_remove_msgs (mail_op, header_list, FALSE);
565                 g_object_unref (mail_op);
566
567                 /* Enable window dimming management */
568                 if (sel != NULL) {
569                         gtk_tree_selection_unselect_all (sel);
570                 }
571                 modest_window_enable_dimming (win);
572
573                 if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
574                         modest_ui_actions_refresh_message_window_after_delete (MODEST_MSG_VIEW_WINDOW (win));
575
576                         /* Get main window */
577                         mgr = modest_runtime_get_window_mgr ();
578                 } else if (MODEST_IS_MAIN_WINDOW (win)) {
579                         /* Select next or previous row */
580                         if (gtk_tree_row_reference_valid (next_row_reference)) {
581                                 gtk_tree_selection_select_path (sel, next_path);
582                         }
583                         else if (gtk_tree_row_reference_valid (prev_row_reference)) {
584                                 gtk_tree_selection_select_path (sel, prev_path);
585                         }
586
587                         /* Free */
588                         if (gtk_tree_row_reference_valid (next_row_reference))
589                                 gtk_tree_row_reference_free (next_row_reference);
590                         if (next_path != NULL)
591                                 gtk_tree_path_free (next_path);
592                         if (gtk_tree_row_reference_valid (prev_row_reference))
593                                 gtk_tree_row_reference_free (prev_row_reference);
594                         if (prev_path != NULL)
595                                 gtk_tree_path_free (prev_path);
596                 }
597
598                 /* Update toolbar dimming state */
599                 modest_ui_actions_check_menu_dimming_rules (win);
600                 modest_ui_actions_check_toolbar_dimming_rules (win);
601
602                 /* Free */
603                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
604                 g_list_free (sel_list);
605                 retval = TRUE;
606         } else {
607                 retval = FALSE;
608         }
609
610         /* Free*/
611         g_free(message);
612         g_free(desc);
613         g_object_unref (header_list);
614
615         return retval;
616 }
617
618
619
620
621 /* delete either message or folder, based on where we are */
622 void
623 modest_ui_actions_on_delete_message_or_folder (GtkAction *action, ModestWindow *win)
624 {
625         g_return_if_fail (MODEST_IS_WINDOW(win));
626
627         /* Check first if the header view has the focus */
628         if (MODEST_IS_MAIN_WINDOW (win)) {
629                 GtkWidget *w;
630                 w = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
631                                                          MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
632                 if (gtk_widget_is_focus (w)) {
633                         modest_ui_actions_on_delete_folder (action, MODEST_WINDOW(win));
634                         return;
635                 }
636         }
637         modest_ui_actions_on_delete_message (action, win);
638 }
639
640 void
641 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
642 {
643         ModestWindowMgr *mgr = NULL;
644
645 #ifdef MODEST_PLATFORM_MAEMO
646         modest_window_mgr_save_state_for_all_windows (modest_runtime_get_window_mgr ());
647 #endif /* MODEST_PLATFORM_MAEMO */
648
649         g_debug ("closing down, clearing %d item(s) from operation queue",
650                  modest_mail_operation_queue_num_elements
651                  (modest_runtime_get_mail_operation_queue()));
652
653         /* cancel all outstanding operations */
654         modest_mail_operation_queue_cancel_all
655                 (modest_runtime_get_mail_operation_queue());
656
657         g_debug ("queue has been cleared");
658
659
660         /* Check if there are opened editing windows */
661         mgr = modest_runtime_get_window_mgr ();
662         modest_window_mgr_close_all_windows (mgr);
663
664         /* note: when modest-tny-account-store is finalized,
665            it will automatically set all network connections
666            to offline */
667
668 /*      gtk_main_quit (); */
669 }
670
671 void
672 modest_ui_actions_on_close_window (GtkAction *action, ModestWindow *win)
673 {
674         gboolean ret_value;
675
676         g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
677
678 /*      if (MODEST_IS_MSG_VIEW_WINDOW (win)) { */
679 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
680 /*      } else if (MODEST_IS_MSG_EDIT_WINDOW (win)) { */
681 /*              gboolean ret_value; */
682 /*              g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value); */
683 /*      } else if (MODEST_IS_WINDOW (win)) { */
684 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
685 /*      } else { */
686 /*              g_return_if_reached (); */
687 /*      } */
688 }
689
690 void
691 modest_ui_actions_add_to_contacts (GtkAction *action, ModestWindow *win)
692 {
693         if (MODEST_IS_MSG_VIEW_WINDOW (win))
694                 modest_msg_view_window_add_to_contacts (MODEST_MSG_VIEW_WINDOW (win));
695         else if (MODEST_IS_MSG_EDIT_WINDOW (win))
696                 modest_msg_edit_window_add_to_contacts (MODEST_MSG_EDIT_WINDOW (win));
697 }
698
699 void
700 modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
701 {
702         GtkClipboard *clipboard = NULL;
703         gchar *selection = NULL;
704
705         clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
706         selection = gtk_clipboard_wait_for_text (clipboard);
707
708         if (selection) {
709                 modest_address_book_add_address (selection, (GtkWindow *) win);
710                 g_free (selection);
711         }
712 }
713
714 void
715 modest_ui_actions_on_new_account (GtkAction *action,
716                                   ModestWindow *window)
717 {
718         if (!modest_ui_actions_run_account_setup_wizard (window)) {
719                 g_debug ("%s: wizard was already running", __FUNCTION__);
720         }
721 }
722
723 void
724 modest_ui_actions_on_accounts (GtkAction *action,
725                                ModestWindow *win)
726 {
727         /* This is currently only implemented for Maemo */
728         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE)) {
729                 if (!modest_ui_actions_run_account_setup_wizard (win))
730                         g_debug ("%s: wizard was already running", __FUNCTION__);
731
732                 return;
733         } else {
734                 /* Show the list of accounts */
735                 GtkWindow *account_win = GTK_WINDOW (modest_account_view_window_new ());
736
737                 /* The accounts dialog must be modal */
738                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (account_win), (GtkWindow *) win);
739                 modest_utils_show_dialog_and_forget (GTK_WINDOW (win), GTK_DIALOG (account_win));
740         }
741 }
742
743 void
744 modest_ui_actions_on_smtp_servers (GtkAction *action, ModestWindow *win)
745 {
746         /* This is currently only implemented for Maemo,
747          * because it requires an API (libconic) to detect different connection
748          * possiblities.
749          */
750 #ifndef MODEST_TOOLKIT_GTK /* Defined in config.h */
751
752         /* Create the window if necessary: */
753         GtkWidget *specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
754         modest_connection_specific_smtp_window_fill_with_connections (
755                 MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window),
756                 modest_runtime_get_account_mgr());
757
758         /* Show the window: */
759         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
760                                      GTK_WINDOW (specific_window), (GtkWindow *) win);
761         gtk_widget_show (specific_window);
762 #endif /* !MODEST_TOOLKIT_GTK */
763 }
764
765 static guint64
766 count_part_size (const gchar *part)
767 {
768         GnomeVFSURI *vfs_uri;
769         gchar *escaped_filename;
770         gchar *filename;
771         GnomeVFSFileInfo *info;
772         guint64 result;
773
774         /* Estimation of attachment size if we cannot get it from file info */
775         result = 32768;
776
777         vfs_uri = gnome_vfs_uri_new (part);
778
779         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
780         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
781         g_free (escaped_filename);
782         gnome_vfs_uri_unref (vfs_uri);
783
784         info = gnome_vfs_file_info_new ();
785         
786         if (gnome_vfs_get_file_info (part, 
787                                      info, 
788                                      GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
789             == GNOME_VFS_OK) {
790                 if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
791                         result = info->size;
792                 }
793         }
794         g_free (filename);
795         gnome_vfs_file_info_unref (info);
796
797         return result;
798 }
799
800 static guint64 
801 count_parts_size (GSList *parts)
802 {
803         GSList *node;
804         guint64 result = 0;
805
806         for (node = parts; node != NULL; node = g_slist_next (node)) {
807                 result += count_part_size ((const gchar *) node->data);
808         }
809
810         return result;
811 }
812
813 void
814 modest_ui_actions_compose_msg(ModestWindow *win,
815                               const gchar *to_str,
816                               const gchar *cc_str,
817                               const gchar *bcc_str,
818                               const gchar *subject_str,
819                               const gchar *body_str,
820                               GSList *attachments,
821                               gboolean set_as_modified)
822 {
823         gchar *account_name = NULL;
824         const gchar *mailbox;
825         TnyMsg *msg = NULL;
826         TnyAccount *account = NULL;
827         TnyFolder *folder = NULL;
828         gchar *from_str = NULL, *signature = NULL, *body = NULL;
829         gchar *recipient = NULL;
830         gboolean use_signature = FALSE;
831         ModestWindow *msg_win = NULL;
832         ModestAccountMgr *mgr = modest_runtime_get_account_mgr();
833         ModestTnyAccountStore *store = modest_runtime_get_account_store();
834         GnomeVFSFileSize total_size, allowed_size;
835         guint64 available_disk, expected_size, parts_size;
836         guint parts_count;
837
838         /* we check for low-mem */
839         if (modest_platform_check_memory_low (win, TRUE))
840                 goto cleanup;
841
842         available_disk = modest_utils_get_available_space (NULL);
843         parts_count = g_slist_length (attachments);
844         parts_size = count_parts_size (attachments);
845         expected_size = modest_tny_msg_estimate_size (body, NULL, parts_count, parts_size);
846
847         /* Double check: disk full condition or message too big */
848         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
849             expected_size > available_disk) {
850                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
851                 modest_platform_system_banner (NULL, NULL, msg);
852                 g_free (msg);
853
854                 return;
855         }
856
857         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
858                 modest_platform_run_information_dialog (
859                         GTK_WINDOW(win),
860                         _("mail_ib_error_attachment_size"),
861                         TRUE);
862                 return;
863         }
864
865
866 #ifdef MODEST_TOOLKIT_HILDON2
867         if (win)
868                 account_name = g_strdup (modest_window_get_active_account(win));
869 #endif
870         if (!account_name) {
871                 account_name = modest_account_mgr_get_default_account(mgr);
872         }
873         if (!account_name) {
874                 g_printerr ("modest: no account found\n");
875                 goto cleanup;
876         }
877
878         if (win)
879                 mailbox = modest_window_get_active_mailbox (win);
880         else
881                 mailbox = NULL;
882         account = modest_tny_account_store_get_server_account (store, account_name, TNY_ACCOUNT_TYPE_STORE);
883         if (!account) {
884                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
885                 goto cleanup;
886         }
887         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
888         if (!folder) {
889                 g_printerr ("modest: failed to find Drafts folder\n");
890                 goto cleanup;
891         }
892         from_str = modest_account_mgr_get_from_string (mgr, account_name, mailbox);
893         if (!from_str) {
894                 g_printerr ("modest: failed get from string for '%s'\n", account_name);
895                 goto cleanup;
896         }
897
898         recipient = modest_text_utils_get_email_address (from_str);
899         signature = modest_account_mgr_get_signature_from_recipient (mgr, recipient, &use_signature);
900         g_free (recipient);
901         if (body_str != NULL) {
902                 body = use_signature ? g_strconcat(body_str, "\n",
903                                                    MODEST_TEXT_UTILS_SIGNATURE_MARKER,
904                                                    "\n", signature, NULL) : g_strdup(body_str);
905         } else {
906
907                 gchar *gray_color_markup = NULL, *color_begin = NULL, *color_end = NULL;
908                 GdkColor color;
909
910                 if (win && gtk_style_lookup_color (gtk_widget_get_style ((GtkWidget *) win),
911                                                    "SecondaryTextColor", &color))
912                         gray_color_markup = modest_text_utils_get_color_string (&color);
913                 if (!gray_color_markup)
914                         gray_color_markup = g_strdup ("#babababababa");
915
916                 color_begin = g_strdup_printf ("<font color=\"%s\">", gray_color_markup);
917                 color_end = "</font>";
918
919                 body = use_signature ? g_strconcat("<br/>\n", color_begin,
920                                                 MODEST_TEXT_UTILS_SIGNATURE_MARKER, "<br/>\n",
921                                                 signature, color_end, NULL) : g_strdup("");
922
923                 g_free (gray_color_markup);
924                 g_free (color_begin);
925         }
926
927         msg = modest_tny_msg_new_html_plain (to_str, from_str, cc_str, bcc_str, subject_str,
928                                         NULL, NULL, body, NULL, NULL, NULL, NULL, NULL);
929         if (!msg) {
930                 g_printerr ("modest: failed to create new msg\n");
931                 goto cleanup;
932         }
933
934         /* Create and register edit window */
935         /* This is destroyed by TODO. */
936         total_size = 0;
937         allowed_size = MODEST_MAX_ATTACHMENT_SIZE;
938         msg_win = modest_msg_edit_window_new (msg, account_name, mailbox, FALSE);
939
940         if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr(), msg_win, win)) {
941                 gtk_widget_destroy (GTK_WIDGET (msg_win));
942                 goto cleanup;
943         }
944         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (msg_win), set_as_modified);
945         gtk_widget_show_all (GTK_WIDGET (msg_win));
946
947         while (attachments) {
948                 GnomeVFSFileSize att_size;
949                 att_size =
950                         modest_msg_edit_window_attach_file_one((ModestMsgEditWindow *)msg_win,
951                                                                attachments->data, allowed_size);
952                 total_size += att_size;
953
954                 if (att_size > allowed_size) {
955                         g_debug ("%s: total size: %u",
956                                  __FUNCTION__, (unsigned int)total_size);
957                         break;
958                 }
959                 allowed_size -= att_size;
960
961                 attachments = g_slist_next(attachments);
962         }
963
964 cleanup:
965         g_free (from_str);
966         g_free (signature);
967         g_free (body);
968         g_free (account_name);
969         if (account)
970                 g_object_unref (G_OBJECT(account));
971         if (folder)
972                 g_object_unref (G_OBJECT(folder));
973         if (msg)
974                 g_object_unref (G_OBJECT(msg));
975 }
976
977 void
978 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
979 {
980         /* if there are no accounts yet, just show the wizard */
981         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE))
982                 if (!modest_ui_actions_run_account_setup_wizard (win))
983                         return;
984
985         modest_ui_actions_compose_msg(win, NULL, NULL, NULL, NULL, NULL, NULL, FALSE);
986 }
987
988
989 gboolean
990 modest_ui_actions_msg_retrieval_check (ModestMailOperation *mail_op,
991                                        TnyHeader *header,
992                                        TnyMsg *msg)
993 {
994         ModestMailOperationStatus status;
995
996         /* If there is no message or the operation was not successful */
997         status = modest_mail_operation_get_status (mail_op);
998         if (!msg || status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
999                 const GError *error;
1000
1001                 /* If it's a memory low issue, then show a banner */
1002                 error = modest_mail_operation_get_error (mail_op);
1003                 if (error && error->domain == MODEST_MAIL_OPERATION_ERROR &&
1004                     error->code == MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY) {
1005                         GObject *source = modest_mail_operation_get_source (mail_op);
1006                         modest_platform_run_information_dialog (GTK_IS_WINDOW (source) ? GTK_WINDOW (source) : NULL,
1007                                                                 _KR("memr_ib_operation_disabled"),
1008                                                                 TRUE);
1009                         g_object_unref (source);
1010                 }
1011
1012                 if (error && ((error->code == TNY_SERVICE_ERROR_NO_SUCH_MESSAGE) ||
1013                               error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE)) {
1014                         gchar *subject, *msg, *format = NULL;
1015                         TnyAccount *account;
1016
1017                         subject = (header) ? tny_header_dup_subject (header) : NULL;
1018                         if (!subject)
1019                                 subject = g_strdup (_("mail_va_no_subject"));
1020
1021                         account = modest_mail_operation_get_account (mail_op);
1022                         if (account) {
1023                                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
1024                                 ModestProtocol *protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (), proto);
1025
1026                                 if (protocol) {
1027                                         if (tny_account_get_connection_status (account) ==
1028                                             TNY_CONNECTION_STATUS_CONNECTED) {
1029                                                 if (header) {
1030                                                         format = modest_protocol_get_translation (protocol,
1031                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE,
1032                                                                                                   subject);
1033                                                 } else {
1034                                                         format = modest_protocol_get_translation (protocol,
1035                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE_LOST_HEADER);
1036                                                 }
1037                                         } else {
1038                                                 format = g_strdup_printf (_("mail_ib_backend_server_invalid"),
1039                                                                           tny_account_get_hostname (account));
1040                                         }
1041                                 }
1042                                 g_object_unref (account);
1043                         }
1044
1045                         if (!format) {
1046                                 if (header) {
1047                                         format = g_strdup (_("emev_ni_ui_imap_message_not_available_in_server"));
1048                                 } else {
1049                                         format = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
1050                                 }
1051                         }
1052
1053                         msg = g_strdup_printf (format, subject);
1054                         modest_platform_run_information_dialog (NULL, msg, FALSE);
1055                         g_free (msg);
1056                         g_free (format);
1057                         g_free (subject);
1058                 }
1059
1060                 /* Remove the header from the preregistered uids */
1061                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1062                                                      header);
1063
1064                 return FALSE;
1065         }
1066
1067         return TRUE;
1068 }
1069
1070 typedef struct {
1071         guint idle_handler;
1072         gchar *message;
1073         GtkWidget *banner;
1074 } OpenMsgBannerInfo;
1075
1076 typedef struct {
1077         GtkTreeModel *model;
1078         TnyHeader *header;
1079         ModestWindow *caller_window;
1080         OpenMsgBannerInfo *banner_info;
1081         GtkTreeRowReference *rowref;
1082 } OpenMsgHelper;
1083
1084 gboolean
1085 open_msg_banner_idle (gpointer userdata)
1086 {
1087         OpenMsgBannerInfo *banner_info = (OpenMsgBannerInfo *) userdata;
1088
1089         gdk_threads_enter ();
1090         banner_info->idle_handler = 0;
1091         banner_info->banner = modest_platform_animation_banner (NULL, NULL, banner_info->message);
1092         if (banner_info->banner)
1093                 g_object_ref (banner_info->banner);
1094
1095         gdk_threads_leave ();
1096
1097         return FALSE;
1098 }
1099
1100 static GtkWidget *
1101 get_header_view_from_window (ModestWindow *window)
1102 {
1103         GtkWidget *header_view;
1104
1105         if (MODEST_IS_MAIN_WINDOW (window)) {
1106                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (window),
1107                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
1108 #ifdef MODEST_TOOLKIT_HILDON2
1109         } else if (MODEST_IS_HEADER_WINDOW (window)){
1110                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
1111 #endif
1112         } else {
1113                 header_view = NULL;
1114         }
1115
1116         return header_view;
1117 }
1118
1119 static gchar *
1120 get_info_from_header (TnyHeader *header, gboolean *is_draft, gboolean *can_open)
1121 {
1122         TnyFolder *folder;
1123         gchar *account = NULL;
1124         TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1125
1126         *is_draft = FALSE;
1127         *can_open = TRUE;
1128
1129         folder = tny_header_get_folder (header);
1130         /* Gets folder type (OUTBOX headers will be opened in edit window */
1131         if (modest_tny_folder_is_local_folder (folder)) {
1132                 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
1133                 if (folder_type == TNY_FOLDER_TYPE_INVALID)
1134                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1135         }
1136
1137         if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1138                 TnyTransportAccount *traccount = NULL;
1139                 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
1140                 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
1141                 if (traccount) {
1142                         ModestTnySendQueue *send_queue = NULL;
1143                         ModestTnySendQueueStatus status;
1144                         gchar *msg_id;
1145                         account = g_strdup(modest_tny_account_get_parent_modest_account_name_for_server_account(
1146                                                    TNY_ACCOUNT(traccount)));
1147                         send_queue = modest_runtime_get_send_queue(traccount, TRUE);
1148                         if (TNY_IS_SEND_QUEUE (send_queue)) {
1149                                 msg_id = modest_tny_send_queue_get_msg_id (header);
1150                                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1151                                 g_free (msg_id);
1152                                 /* Only open messages in outbox with the editor if they are in Failed state */
1153                                 if (status == MODEST_TNY_SEND_QUEUE_FAILED) {
1154                                         *is_draft = TRUE;
1155                                 }
1156 #ifdef MODEST_TOOLKIT_HILDON2
1157                                 else {
1158                                         /* In Fremantle we can not
1159                                            open any message from
1160                                            outbox which is not in
1161                                            failed state */
1162                                         *can_open = FALSE;
1163                                 }
1164 #endif
1165                         }
1166                         g_object_unref(traccount);
1167                 } else {
1168                         g_warning("Cannot get transport account for message in outbox!!");
1169                 }
1170         } else if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
1171                 *is_draft = TRUE; /* Open in editor if the message is in the Drafts folder */
1172         }
1173
1174         if (!account) {
1175                 TnyAccount *acc = tny_folder_get_account (folder);
1176                 if (acc) {
1177                         account =
1178                                 g_strdup (modest_tny_account_get_parent_modest_account_name_for_server_account (acc));
1179                         g_object_unref (acc);
1180                 }
1181         }
1182
1183         g_object_unref (folder);
1184
1185         return account;
1186 }
1187
1188 static void
1189 open_msg_cb (ModestMailOperation *mail_op,
1190              TnyHeader *header,
1191              gboolean canceled,
1192              TnyMsg *msg,
1193              GError *err,
1194              gpointer user_data)
1195 {
1196         ModestWindowMgr *mgr = NULL;
1197         ModestWindow *parent_win = NULL;
1198         ModestWindow *win = NULL;
1199         gchar *account = NULL;
1200         gboolean open_in_editor = FALSE;
1201         gboolean can_open;
1202         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1203
1204         /* Do nothing if there was any problem with the mail
1205            operation. The error will be shown by the error_handler of
1206            the mail operation */
1207         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1208                 return;
1209
1210         parent_win = (ModestWindow *) modest_mail_operation_get_source (mail_op);
1211
1212         /* Mark header as read */
1213         headers_action_mark_as_read (header, MODEST_WINDOW(parent_win), NULL);
1214
1215         account = get_info_from_header (header, &open_in_editor, &can_open);
1216
1217         /* Get account */
1218         if (!account)
1219                 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_win)));
1220         if (!account)
1221                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1222
1223         if (open_in_editor) {
1224                 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
1225                 gchar *from_header = NULL, *acc_name;
1226                 gchar *mailbox = NULL;
1227
1228                 from_header = tny_header_dup_from (header);
1229
1230                 /* we cannot edit without a valid account... */
1231                 if (!modest_account_mgr_has_accounts(mgr, TRUE)) {
1232                         if (!modest_ui_actions_run_account_setup_wizard(parent_win)) {
1233                                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1234                                                                      header);
1235                                 g_free (from_header);
1236                                 goto cleanup;
1237                         }
1238                 }
1239
1240                 acc_name = modest_utils_get_account_name_from_recipient (from_header, &mailbox);
1241                 g_free (from_header);
1242                 if (acc_name) {
1243                         g_free (account);
1244                         account = acc_name;
1245                 }
1246
1247                 win = modest_msg_edit_window_new (msg, account, mailbox, TRUE);
1248                 if (mailbox)
1249                         g_free (mailbox);
1250         } else {
1251                 gchar *uid = modest_tny_folder_get_header_unique_id (header);
1252                 const gchar *mailbox = NULL;
1253
1254                 if (parent_win && MODEST_IS_WINDOW (parent_win))
1255                         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (parent_win));
1256
1257                 if (helper->rowref && helper->model) {
1258                         win = modest_msg_view_window_new_with_header_model (msg, account, mailbox, (const gchar*) uid,
1259                                                                             helper->model, helper->rowref);
1260                 } else {
1261                         win = modest_msg_view_window_new_for_attachment (msg, account, mailbox, (const gchar*) uid);
1262                 }
1263                 g_free (uid);
1264         }
1265
1266         /* Register and show new window */
1267         if (win != NULL) {
1268                 mgr = modest_runtime_get_window_mgr ();
1269                 if (!modest_window_mgr_register_window (mgr, win, NULL)) {
1270                         gtk_widget_destroy (GTK_WIDGET (win));
1271                         goto cleanup;
1272                 }
1273                 gtk_widget_show_all (GTK_WIDGET(win));
1274         }
1275
1276         /* Update toolbar dimming state */
1277         if (MODEST_IS_MAIN_WINDOW (parent_win)) {
1278                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_win));
1279         }
1280
1281 cleanup:
1282         /* Free */
1283         g_free(account);
1284         g_object_unref (parent_win);
1285 }
1286
1287 void
1288 modest_ui_actions_disk_operations_error_handler (ModestMailOperation *mail_op,
1289                                                  gpointer user_data)
1290 {
1291         const GError *error;
1292         GObject *win = NULL;
1293         ModestMailOperationStatus status;
1294
1295         win = modest_mail_operation_get_source (mail_op);
1296         error = modest_mail_operation_get_error (mail_op);
1297         status = modest_mail_operation_get_status (mail_op);
1298
1299         /* If the mail op has been cancelled then it's not an error:
1300            don't show any message */
1301         if (status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1302                 TnyAccount *account = modest_mail_operation_get_account (mail_op);
1303                 if (modest_tny_account_store_is_disk_full_error (modest_runtime_get_account_store(),
1304                                                                  (GError *) error, account)) {
1305                         gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
1306                         modest_platform_information_banner ((GtkWidget *) win, NULL, msg);
1307                         g_free (msg);
1308                 } else if (error->code == TNY_SYSTEM_ERROR_MEMORY) {
1309                         modest_platform_information_banner ((GtkWidget *) win,
1310                                                             NULL, _("emev_ui_imap_inbox_select_error"));
1311                 } else if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
1312                            error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1313                         modest_platform_information_banner ((GtkWidget *) win,
1314                                                             NULL, _CS ("sfil_ni_unable_to_open_file_not_found"));
1315                 } else if (user_data) {
1316                         modest_platform_information_banner ((GtkWidget *) win,
1317                                                             NULL, user_data);
1318                 }
1319                 if (account)
1320                         g_object_unref (account);
1321         }
1322
1323         if (win)
1324                 g_object_unref (win);
1325 }
1326
1327 /**
1328  * Returns the account a list of headers belongs to. It returns a
1329  * *new* reference so don't forget to unref it
1330  */
1331 static TnyAccount*
1332 get_account_from_header_list (TnyList *headers)
1333 {
1334         TnyAccount *account = NULL;
1335
1336         if (tny_list_get_length (headers) > 0) {
1337                 TnyIterator *iter = tny_list_create_iterator (headers);
1338                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1339                 TnyFolder *folder = tny_header_get_folder (header);
1340
1341                 if (!folder) {
1342                         g_object_unref (header);
1343
1344                         while (!tny_iterator_is_done (iter)) {
1345                                 header = TNY_HEADER (tny_iterator_get_current (iter));
1346                                 folder = tny_header_get_folder (header);
1347                                 if (folder)
1348                                         break;
1349                                 g_object_unref (header);
1350                                 header = NULL;
1351                                 tny_iterator_next (iter);
1352                         }
1353                 }
1354
1355                 if (folder) {
1356                         account = tny_folder_get_account (folder);
1357                         g_object_unref (folder);
1358                 }
1359
1360                 if (header)
1361                         g_object_unref (header);
1362
1363                 g_object_unref (iter);
1364         }
1365         return account;
1366 }
1367
1368 static TnyAccount*
1369 get_account_from_header (TnyHeader *header)
1370 {
1371         TnyAccount *account = NULL;
1372         TnyFolder *folder;
1373
1374         folder = tny_header_get_folder (header);
1375
1376         if (folder) {
1377                 account = tny_folder_get_account (folder);
1378                 g_object_unref (folder);
1379         }
1380         return account;
1381 }
1382
1383 static void
1384 caller_win_destroyed (OpenMsgHelper *helper, GObject *object)
1385 {
1386         if (helper->caller_window)
1387                 helper->caller_window = NULL;
1388 }
1389
1390 static void
1391 open_msg_helper_destroyer (gpointer user_data)
1392 {
1393         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1394
1395         if (helper->caller_window) {
1396                 g_object_weak_unref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1397                 helper->caller_window = NULL;
1398         }
1399
1400         if (helper->banner_info) {
1401                 g_free (helper->banner_info->message);
1402                 if (helper->banner_info->idle_handler > 0) {
1403                         g_source_remove (helper->banner_info->idle_handler);
1404                         helper->banner_info->idle_handler = 0;
1405                 }
1406                 if (helper->banner_info->banner != NULL) {
1407                         gtk_widget_destroy (helper->banner_info->banner);
1408                         g_object_unref (helper->banner_info->banner);
1409                         helper->banner_info->banner = NULL;
1410                 }
1411                 g_slice_free (OpenMsgBannerInfo, helper->banner_info);
1412                 helper->banner_info = NULL;
1413         }
1414         g_object_unref (helper->model);
1415         g_object_unref (helper->header);
1416         gtk_tree_row_reference_free (helper->rowref);
1417         g_slice_free (OpenMsgHelper, helper);
1418 }
1419
1420 static void
1421 open_msg_performer(gboolean canceled,
1422                     GError *err,
1423                     GtkWindow *parent_window,
1424                     TnyAccount *account,
1425                     gpointer user_data)
1426 {
1427         ModestMailOperation *mail_op = NULL;
1428         gchar *error_msg = NULL;
1429         ModestProtocolType proto;
1430         TnyConnectionStatus status;
1431         OpenMsgHelper *helper = NULL;
1432         ModestProtocol *protocol;
1433         ModestProtocolRegistry *protocol_registry;
1434         gchar *subject;
1435
1436         helper = (OpenMsgHelper *) user_data;
1437
1438         status = tny_account_get_connection_status (account);
1439         if (err || canceled || helper->caller_window == NULL) {
1440                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1441                 /* Free the helper */
1442                 open_msg_helper_destroyer (helper);
1443
1444                 /* In disk full conditions we could get this error here */
1445                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
1446                                                                 (GtkWidget *) parent_window, err,
1447                                                                 account, NULL);
1448
1449                 goto clean;
1450         }
1451
1452         /* Get the error message depending on the protocol */
1453         proto = modest_tny_account_get_protocol_type (account);
1454         if (proto == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1455                 proto = MODEST_PROTOCOLS_STORE_MAILDIR;
1456         }
1457
1458         protocol_registry = modest_runtime_get_protocol_registry ();
1459         subject = tny_header_dup_subject (helper->header);
1460
1461         protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, proto);
1462         error_msg = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE, subject);
1463         if (subject)
1464                 g_free (subject);
1465
1466         if (error_msg == NULL) {
1467                 error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1468         }
1469
1470 #ifndef MODEST_TOOLKIT_HILDON2
1471         gboolean show_open_draft = FALSE;
1472         if (modest_protocol_registry_protocol_type_has_tag (protocol_registry,
1473                                                             proto,
1474                                                             MODEST_PROTOCOL_REGISTRY_LOCAL_STORE_PROTOCOLS)) {
1475                 TnyFolder *folder;
1476                 TnyFolderType folder_type;
1477
1478                 folder = tny_header_get_folder (helper->header);
1479                 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
1480                 show_open_draft = (folder_type == TNY_FOLDER_TYPE_DRAFTS);
1481                 g_object_unref (folder);
1482         }
1483 #endif
1484
1485 #ifdef MODEST_TOOLKIT_HILDON2
1486         gboolean is_draft;
1487         gboolean can_open;
1488         gchar *account_name = get_info_from_header (helper->header, &is_draft, &can_open);
1489
1490         if (!can_open) {
1491                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1492                 g_free (account_name);
1493                 open_msg_helper_destroyer (helper);
1494                 goto clean;
1495         }
1496
1497         if (!is_draft) {
1498                 ModestWindow *window;
1499                 GtkWidget *header_view;
1500                 gchar *uid;
1501
1502                 header_view = get_header_view_from_window (MODEST_WINDOW (parent_window));
1503                 uid = modest_tny_folder_get_header_unique_id (helper->header);
1504                 if (header_view) {
1505                         const gchar *mailbox = NULL;
1506                         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (parent_window));
1507                         window = modest_msg_view_window_new_from_header_view 
1508                                 (MODEST_HEADER_VIEW (header_view), account_name, mailbox, uid, helper->rowref);
1509                         if (window != NULL) {
1510                                 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
1511                                                                         window, NULL)) {
1512                                         gtk_widget_destroy (GTK_WIDGET (window));
1513                                 } else {
1514                                         gtk_widget_show_all (GTK_WIDGET(window));
1515                                 }
1516                         }
1517                 }
1518                 g_free (account_name);
1519                 g_free (uid);
1520                 open_msg_helper_destroyer (helper);
1521                 goto clean;
1522         }
1523         g_free (account_name);
1524 #endif
1525         /* Create the mail operation */
1526         mail_op =
1527                 modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
1528                                                                modest_ui_actions_disk_operations_error_handler,
1529                                                                g_strdup (error_msg), g_free);
1530         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1531                                          mail_op);
1532
1533
1534 #ifndef MODEST_TOOLKIT_HILDON2
1535         if (show_open_draft) {
1536                 helper->banner_info = g_slice_new (OpenMsgBannerInfo);
1537                 helper->banner_info->message = g_strdup (_("mail_ib_opening_draft_message"));
1538                 helper->banner_info->banner = NULL;
1539                 helper->banner_info->idle_handler = g_timeout_add (500, open_msg_banner_idle,
1540                                                                    helper->banner_info);
1541         }
1542 #endif
1543
1544
1545         TnyList *headers;
1546         headers = TNY_LIST (tny_simple_list_new ());
1547         tny_list_prepend (headers, G_OBJECT (helper->header));
1548         modest_mail_operation_get_msgs_full (mail_op,
1549                                              headers,
1550                                              open_msg_cb,
1551                                              helper,
1552                                              open_msg_helper_destroyer);
1553         g_object_unref (headers);
1554
1555         /* Frees */
1556  clean:
1557         if (error_msg)
1558                 g_free (error_msg);
1559         if (mail_op)
1560                 g_object_unref (mail_op);
1561         g_object_unref (account);
1562 }
1563
1564 /*
1565  * This function is used by both modest_ui_actions_on_open and
1566  * modest_ui_actions_on_header_activated. This way we always do the
1567  * same when trying to open messages.
1568  */
1569 static void
1570 open_msg_from_header (TnyHeader *header, GtkTreeRowReference *rowref, ModestWindow *win)
1571 {
1572         ModestWindowMgr *mgr = NULL;
1573         TnyAccount *account;
1574         gboolean cached = FALSE;
1575         gboolean found;
1576         GtkWidget *header_view = NULL;
1577         OpenMsgHelper *helper;
1578         ModestWindow *window;
1579
1580         g_return_if_fail (header != NULL && rowref != NULL && gtk_tree_row_reference_valid (rowref));
1581
1582         mgr = modest_runtime_get_window_mgr ();
1583
1584         /* get model */
1585         header_view = get_header_view_from_window (MODEST_WINDOW (win));
1586         if (header_view == NULL)
1587                 return;
1588
1589         /* Get the account */
1590         account = get_account_from_header (header);
1591         if (!account)
1592                 return;
1593
1594         window = NULL;
1595         found = modest_window_mgr_find_registered_header (mgr, header, &window);
1596
1597         /* Do not open again the message and present the
1598            window to the user */
1599         if (found) {
1600                 if (window) {
1601 #ifndef MODEST_TOOLKIT_HILDON2
1602                         gtk_window_present (GTK_WINDOW (window));
1603 #endif
1604                 } else {
1605                         /* the header has been registered already, we don't do
1606                          * anything but wait for the window to come up*/
1607                         g_debug ("header %p already registered, waiting for window", header);
1608                 }
1609                 goto cleanup;
1610         }
1611
1612         /* Open each message */
1613         cached = tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED;
1614         if (!cached) {
1615                 /* Allways download if we are online. */
1616                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1617                         gint response;
1618
1619                         /* If ask for user permission to download the messages */
1620                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1621                                                                             _("mcen_nc_get_msg"));
1622
1623                         /* End if the user does not want to continue */
1624                         if (response == GTK_RESPONSE_CANCEL) {
1625                                 goto cleanup;
1626                         }
1627                 }
1628         }
1629
1630         /* We register the window for opening */
1631         modest_window_mgr_register_header (mgr, header, NULL);
1632
1633         /* Create the helper. We need to get a reference to the model
1634            here because it could change while the message is readed
1635            (the user could switch between folders) */
1636         helper = g_slice_new (OpenMsgHelper);
1637         helper->model = g_object_ref (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)));
1638         helper->caller_window = win;
1639         g_object_weak_ref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1640         helper->header = g_object_ref (header);
1641         helper->rowref = gtk_tree_row_reference_copy (rowref);
1642         helper->banner_info = NULL;
1643
1644         /* Connect to the account and perform */
1645         if (!cached) {
1646                 modest_platform_connect_and_perform ((GtkWindow *) win, TRUE, g_object_ref (account),
1647                                                      open_msg_performer, helper);
1648         } else {
1649                 /* Call directly the performer, do not need to connect */
1650                 open_msg_performer (FALSE, NULL, (GtkWindow *) win,
1651                                     g_object_ref (account), helper);
1652         }
1653 cleanup:
1654         /* Clean */
1655         if (account)
1656                 g_object_unref (account);
1657 }
1658
1659 void
1660 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
1661 {
1662         TnyList *headers;
1663         TnyHeader *header;
1664         gint headers_count;
1665         TnyIterator *iter;
1666
1667         /* we check for low-mem; in that case, show a warning, and don't allow
1668          * opening
1669          */
1670         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1671                 return;
1672
1673         /* Get headers */
1674         headers = get_selected_headers (win);
1675         if (!headers)
1676                 return;
1677
1678         headers_count = tny_list_get_length (headers);
1679         if (headers_count != 1) {
1680                 if (headers_count > 1) {
1681                         /* Don't allow activation if there are more than one message selected */
1682                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
1683                 }
1684
1685                 g_object_unref (headers);
1686                 return;
1687         }
1688
1689         iter = tny_list_create_iterator (headers);
1690         header = TNY_HEADER (tny_iterator_get_current (iter));
1691         g_object_unref (iter);
1692
1693         /* Open them */
1694         if (header) {
1695                 open_msg_from_header (header, NULL, win);
1696                 g_object_unref (header);
1697         }
1698
1699         g_object_unref(headers);
1700 }
1701
1702 static void
1703 rf_helper_window_closed (gpointer data,
1704                          GObject *object)
1705 {
1706         ReplyForwardHelper *helper = (ReplyForwardHelper *) data;
1707
1708         helper->parent_window = NULL;
1709 }
1710
1711 static ReplyForwardHelper*
1712 create_reply_forward_helper (ReplyForwardAction action,
1713                              ModestWindow *win,
1714                              guint reply_forward_type,
1715                              TnyHeader *header,
1716                              TnyList *parts)
1717 {
1718         ReplyForwardHelper *rf_helper = NULL;
1719         const gchar *active_acc = modest_window_get_active_account (win);
1720         const gchar *active_mailbox = modest_window_get_active_mailbox (win);
1721
1722         rf_helper = g_slice_new0 (ReplyForwardHelper);
1723         rf_helper->reply_forward_type = reply_forward_type;
1724         rf_helper->action = action;
1725         rf_helper->parent_window = (MODEST_IS_WINDOW (win)) ? GTK_WIDGET (win) : NULL;
1726         rf_helper->header = (header) ? g_object_ref (header) : NULL;
1727         rf_helper->account_name = (active_acc) ?
1728                 g_strdup (active_acc) :
1729                 modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1730         rf_helper->mailbox = g_strdup (active_mailbox);
1731         if (parts)
1732                 rf_helper->parts = g_object_ref (parts);
1733         else
1734                 rf_helper->parts = NULL;
1735
1736         /* Note that window could be destroyed just AFTER calling
1737            register_window so we must ensure that this pointer does
1738            not hold invalid references */
1739         if (rf_helper->parent_window)
1740                 g_object_weak_ref (G_OBJECT (rf_helper->parent_window),
1741                                    rf_helper_window_closed, rf_helper);
1742
1743         return rf_helper;
1744 }
1745
1746 static void
1747 free_reply_forward_helper (gpointer data)
1748 {
1749         ReplyForwardHelper *helper;
1750
1751         helper = (ReplyForwardHelper *) data;
1752         g_free (helper->account_name);
1753         g_free (helper->mailbox);
1754         if (helper->header)
1755                 g_object_unref (helper->header);
1756         if (helper->parts)
1757                 g_object_unref (helper->parts);
1758         if (helper->parent_window)
1759                 g_object_weak_unref (G_OBJECT (helper->parent_window),
1760                                      rf_helper_window_closed, helper);
1761         g_slice_free (ReplyForwardHelper, helper);
1762 }
1763
1764 static void
1765 reply_forward_cb (ModestMailOperation *mail_op,
1766                   TnyHeader *header,
1767                   gboolean canceled,
1768                   TnyMsg *msg,
1769                   GError *err,
1770                   gpointer user_data)
1771 {
1772         TnyMsg *new_msg = NULL;
1773         ReplyForwardHelper *rf_helper;
1774         ModestWindow *msg_win = NULL;
1775         ModestEditType edit_type;
1776         gchar *from = NULL;
1777         TnyAccount *account = NULL;
1778         ModestWindowMgr *mgr = NULL;
1779         gchar *signature = NULL;
1780         gboolean use_signature;
1781         gchar *recipient;
1782
1783         /* If there was any error. The mail operation could be NULL,
1784            this means that we already have the message downloaded and
1785            that we didn't do a mail operation to retrieve it */
1786         rf_helper = (ReplyForwardHelper *) user_data;
1787         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1788                 goto cleanup;
1789
1790         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1791                                                    rf_helper->account_name, rf_helper->mailbox);
1792         recipient = modest_text_utils_get_email_address (from);
1793         signature = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr(), 
1794                                                                      recipient, 
1795                                                                      &use_signature);
1796         g_free (recipient);
1797
1798         /* Create reply mail */
1799         switch (rf_helper->action) {
1800                 /* Use the msg_header to ensure that we have all the
1801                    information. The summary can lack some data */
1802                 TnyHeader *msg_header;
1803         case ACTION_REPLY:
1804                 msg_header = tny_msg_get_header (msg);
1805                 new_msg =
1806                         modest_tny_msg_create_reply_msg (msg, msg_header, from,
1807                                                          (use_signature) ? signature : NULL,
1808                                                          rf_helper->reply_forward_type,
1809                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1810                 g_object_unref (msg_header);
1811                 break;
1812         case ACTION_REPLY_TO_ALL:
1813                 msg_header = tny_msg_get_header (msg);
1814                 new_msg =
1815                         modest_tny_msg_create_reply_msg (msg, msg_header, from,
1816                                                          (use_signature) ? signature : NULL,
1817                                                          rf_helper->reply_forward_type,
1818                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1819                 edit_type = MODEST_EDIT_TYPE_REPLY;
1820                 g_object_unref (msg_header);
1821                 break;
1822         case ACTION_FORWARD:
1823                 new_msg =
1824                         modest_tny_msg_create_forward_msg (msg, from, (use_signature) ? signature : NULL,
1825                                                            rf_helper->reply_forward_type);
1826                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1827                 break;
1828         default:
1829                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1830                                                      header);
1831                 g_return_if_reached ();
1832                 return;
1833         }
1834
1835         g_free (from);
1836         g_free (signature);
1837
1838         if (!new_msg) {
1839                 g_warning ("%s: failed to create message\n", __FUNCTION__);
1840                 goto cleanup;
1841         }
1842
1843         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1844                                                                        rf_helper->account_name,
1845                                                                        TNY_ACCOUNT_TYPE_STORE);
1846         if (!account) {
1847                 g_warning ("%s: failed to get tnyaccount for '%s'\n", __FUNCTION__, rf_helper->account_name);
1848                 goto cleanup;
1849         }
1850
1851         /* Create and register the windows */
1852         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name, rf_helper->mailbox, FALSE);
1853         mgr = modest_runtime_get_window_mgr ();
1854         modest_window_mgr_register_window (mgr, msg_win, (ModestWindow *) rf_helper->parent_window);
1855
1856         /* Note that register_window could have deleted the account */
1857         if (MODEST_IS_WINDOW (rf_helper->parent_window)) {
1858                 gdouble parent_zoom;
1859
1860                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1861                 modest_window_set_zoom (msg_win, parent_zoom);
1862         }
1863
1864         /* Show edit window */
1865         gtk_widget_show_all (GTK_WIDGET (msg_win));
1866
1867 cleanup:
1868         /* We always unregister the header because the message is
1869            forwarded or replied so the original one is no longer
1870            opened */
1871         modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1872                                              header);
1873         if (new_msg)
1874                 g_object_unref (G_OBJECT (new_msg));
1875         if (account)
1876                 g_object_unref (G_OBJECT (account));
1877         free_reply_forward_helper (rf_helper);
1878 }
1879
1880 /* Checks a list of headers. If any of them are not currently
1881  * downloaded (CACHED) then returns TRUE else returns FALSE.
1882  */
1883 static gint
1884 header_list_count_uncached_msgs (TnyList *header_list)
1885 {
1886         TnyIterator *iter;
1887         gint uncached_messages = 0;
1888
1889         iter = tny_list_create_iterator (header_list);
1890         while (!tny_iterator_is_done (iter)) {
1891                 TnyHeader *header;
1892
1893                 header = TNY_HEADER (tny_iterator_get_current (iter));
1894                 if (header) {
1895                         if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
1896                                 uncached_messages ++;
1897                         g_object_unref (header);
1898                 }
1899
1900                 tny_iterator_next (iter);
1901         }
1902         g_object_unref (iter);
1903
1904         return uncached_messages;
1905 }
1906
1907 /* Returns FALSE if the user does not want to download the
1908  * messages. Returns TRUE if the user allowed the download.
1909  */
1910 static gboolean
1911 connect_to_get_msg (ModestWindow *win,
1912                     gint num_of_uncached_msgs,
1913                     TnyAccount *account)
1914 {
1915         GtkResponseType response;
1916
1917         /* Allways download if we are online. */
1918         if (tny_device_is_online (modest_runtime_get_device ()))
1919                 return TRUE;
1920
1921         /* If offline, then ask for user permission to download the messages */
1922         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
1923                         ngettext("mcen_nc_get_msg",
1924                         "mcen_nc_get_msgs",
1925                         num_of_uncached_msgs));
1926
1927         if (response == GTK_RESPONSE_CANCEL)
1928                 return FALSE;
1929
1930         return modest_platform_connect_and_wait((GtkWindow *) win, account);
1931 }
1932
1933 static void
1934 reply_forward_performer (gboolean canceled,
1935                          GError *err,
1936                          GtkWindow *parent_window,
1937                          TnyAccount *account,
1938                          gpointer user_data)
1939 {
1940         ReplyForwardHelper *rf_helper = NULL;
1941         ModestMailOperation *mail_op;
1942
1943         rf_helper = (ReplyForwardHelper *) user_data;
1944
1945         if (canceled || err) {
1946                 free_reply_forward_helper (rf_helper);
1947                 return;
1948         }
1949
1950         /* Retrieve the message */
1951         modest_window_mgr_register_header (modest_runtime_get_window_mgr (), rf_helper->header, NULL);
1952         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (parent_window),
1953                                                                  modest_ui_actions_disk_operations_error_handler,
1954                                                                  NULL, NULL);
1955         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1956         modest_mail_operation_get_msg_and_parts (mail_op, rf_helper->header, rf_helper->parts, TRUE, reply_forward_cb, rf_helper);
1957
1958         /* Frees */
1959         g_object_unref(mail_op);
1960 }
1961
1962 static gboolean
1963 all_parts_retrieved (TnyMimePart *part)
1964 {
1965         if (!TNY_IS_CAMEL_BS_MIME_PART (part)) {
1966                 return TRUE;
1967         } else {
1968                 TnyList *pending_parts;
1969                 TnyIterator *iterator;
1970                 gboolean all_retrieved = TRUE;
1971
1972                 pending_parts = TNY_LIST (tny_simple_list_new ());
1973                 tny_mime_part_get_parts (part, pending_parts);
1974                 iterator = tny_list_create_iterator (pending_parts);
1975                 while (all_retrieved && !tny_iterator_is_done (iterator)) {
1976                         TnyMimePart *child;
1977
1978                         child = TNY_MIME_PART (tny_iterator_get_current (iterator));
1979
1980                         if (tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (child))) {
1981                                 all_retrieved = all_parts_retrieved (TNY_MIME_PART (child));
1982                         } else {
1983                                 all_retrieved = FALSE;
1984                         }
1985
1986                         g_object_unref (child);
1987                         tny_iterator_next (iterator);
1988                 }
1989                 g_object_unref (iterator);
1990                 g_object_unref (pending_parts);
1991                 return all_retrieved;
1992         }
1993 }
1994
1995 static void
1996 forward_pending_parts_helper (TnyMimePart *part, TnyList *list)
1997 {
1998         TnyList *parts;
1999         TnyIterator *iterator;
2000
2001         if (!tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (part))) {
2002                 tny_list_append (list, G_OBJECT (part));
2003         }
2004         parts = TNY_LIST (tny_simple_list_new ());
2005         tny_mime_part_get_parts (part, parts);
2006         for (iterator = tny_list_create_iterator (parts); 
2007              !tny_iterator_is_done (iterator);
2008              tny_iterator_next (iterator)) {
2009                 TnyMimePart *child;
2010
2011                 child = TNY_MIME_PART (tny_iterator_get_current (iterator));
2012                 forward_pending_parts_helper (child, list);
2013                 g_object_unref (child);
2014         }
2015         g_object_unref (iterator);
2016         g_object_unref (parts);
2017 }
2018
2019 static TnyList *
2020 forward_pending_parts (TnyMsg *msg)
2021 {
2022         TnyList *result = TNY_LIST (tny_simple_list_new ());
2023         if (TNY_IS_CAMEL_BS_MIME_PART (msg)) {
2024                 forward_pending_parts_helper (TNY_MIME_PART (msg), result);
2025         }
2026
2027         return result;
2028 }
2029
2030 /*
2031  * Common code for the reply and forward actions
2032  */
2033 static void
2034 reply_forward (ReplyForwardAction action, ModestWindow *win)
2035 {
2036         ReplyForwardHelper *rf_helper = NULL;
2037         guint reply_forward_type;
2038
2039         g_return_if_fail (win && MODEST_IS_WINDOW(win));
2040
2041         /* we check for low-mem; in that case, show a warning, and don't allow
2042          * reply/forward (because it could potentially require a lot of memory */
2043         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2044                 return;
2045
2046
2047         /* we need an account when editing */
2048         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
2049                 if (!modest_ui_actions_run_account_setup_wizard (win))
2050                         return;
2051         }
2052
2053         reply_forward_type =
2054                 modest_conf_get_int (modest_runtime_get_conf (),
2055                                      (action == ACTION_FORWARD) ?
2056                                      MODEST_CONF_FORWARD_TYPE :
2057                                      MODEST_CONF_REPLY_TYPE,
2058                                      NULL);
2059
2060         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
2061                 TnyMsg *msg = NULL;
2062                 TnyHeader *header = NULL;
2063                 /* Get header and message. Do not free them here, the
2064                    reply_forward_cb must do it */
2065                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
2066                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
2067
2068                 if (msg && header && (action != ACTION_FORWARD || all_parts_retrieved (TNY_MIME_PART (msg)))) {
2069                         /* Create helper */
2070                         rf_helper = create_reply_forward_helper (action, win,
2071                                                                  reply_forward_type, header, NULL);
2072                         reply_forward_cb (NULL, header, FALSE, msg, NULL, rf_helper);
2073                 } else {
2074                         gboolean do_download = TRUE;
2075
2076                         if (msg && header && action == ACTION_FORWARD) {
2077                                 /* Not all parts retrieved. Then we have to retrieve them all before
2078                                  * creating the forward message */
2079                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
2080                                         gint response;
2081
2082                                         /* If ask for user permission to download the messages */
2083                                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
2084                                                                                             ngettext("mcen_nc_get_msg",
2085                                                                                                      "mcen_nc_get_msgs",
2086                                                                                                      1));
2087
2088                                         /* End if the user does not want to continue */
2089                                         if (response == GTK_RESPONSE_CANCEL)
2090                                                 do_download = FALSE;
2091                                 }
2092
2093                                 if (do_download) {
2094                                         TnyList *pending_parts;
2095                                         TnyFolder *folder;
2096                                         TnyAccount *account;
2097
2098                                         /* Create helper */
2099                                         pending_parts = forward_pending_parts (msg);
2100                                         rf_helper = create_reply_forward_helper (action, win,
2101                                                                                  reply_forward_type, header, pending_parts);
2102                                         g_object_unref (pending_parts);
2103
2104                                         folder = tny_header_get_folder (header);
2105                                         account = tny_folder_get_account (folder);
2106                                         modest_platform_connect_and_perform (GTK_WINDOW (win),
2107                                                                              TRUE, account,
2108                                                                              reply_forward_performer,
2109                                                                              rf_helper);
2110                                         g_object_unref (folder);
2111                                         g_object_unref (account);
2112                                 }
2113
2114                         } else {
2115                                 g_warning("%s: no message or header found in viewer\n", __FUNCTION__);
2116                         }
2117                 }
2118
2119                 if (msg)
2120                         g_object_unref (msg);
2121                 if (header)
2122                         g_object_unref (header);
2123         } else {
2124                 TnyHeader *header = NULL;
2125                 TnyIterator *iter;
2126                 gboolean do_retrieve = TRUE;
2127                 TnyList *header_list = NULL;
2128
2129                 header_list = get_selected_headers (win);
2130                 if (!header_list)
2131                         return;
2132                 /* Check that only one message is selected for replying */
2133                 if (tny_list_get_length (header_list) != 1) {
2134                         modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
2135                                                             NULL, _("mcen_ib_select_one_message"));
2136                         g_object_unref (header_list);
2137                         return;
2138                 }
2139
2140                 /* Only reply/forward to one message */
2141                 iter = tny_list_create_iterator (header_list);
2142                 header = TNY_HEADER (tny_iterator_get_current (iter));
2143                 g_object_unref (iter);
2144
2145                 /* Retrieve messages */
2146                 do_retrieve = (action == ACTION_FORWARD) ||
2147                         (reply_forward_type != MODEST_TNY_MSG_REPLY_TYPE_CITE);
2148
2149                 if (do_retrieve) {
2150                         TnyAccount *account = NULL;
2151                         TnyFolder *folder = NULL;
2152                         gdouble download = TRUE;
2153                         guint uncached_msgs = 0;
2154
2155                         folder = tny_header_get_folder (header);
2156                         if (!folder)
2157                                 goto do_retrieve_frees;
2158                         account = tny_folder_get_account (folder);
2159                         if (!account)
2160                                 goto do_retrieve_frees;
2161
2162                         uncached_msgs = header_list_count_uncached_msgs (header_list);
2163
2164                         if (uncached_msgs > 0) {
2165                                 /* Allways download if we are online. */
2166                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
2167                                         gint response;
2168
2169                                         /* If ask for user permission to download the messages */
2170                                         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (win),
2171                                                                                             ngettext("mcen_nc_get_msg",
2172                                                                                                      "mcen_nc_get_msgs",
2173                                                                                                      uncached_msgs));
2174
2175                                         /* End if the user does not want to continue */
2176                                         if (response == GTK_RESPONSE_CANCEL)
2177                                                 download = FALSE;
2178                                 }
2179                         }
2180
2181                         if (download) {
2182                                 /* Create helper */
2183                                 rf_helper = create_reply_forward_helper (action, win,
2184                                                                          reply_forward_type, header, NULL);
2185                                 if (uncached_msgs > 0) {
2186                                         modest_platform_connect_and_perform (GTK_WINDOW (win),
2187                                                                              TRUE, account,
2188                                                                              reply_forward_performer,
2189                                                                              rf_helper);
2190                                 } else {
2191                                         reply_forward_performer (FALSE, NULL, GTK_WINDOW (win),
2192                                                                  account, rf_helper);
2193                                 }
2194                         }
2195                 do_retrieve_frees:
2196                         if (account)
2197                                 g_object_unref (account);
2198                         if (folder)
2199                                 g_object_unref (folder);
2200                 } else {
2201                         reply_forward_cb (NULL, header, FALSE, NULL, NULL, NULL);
2202                 }
2203                 /* Frees */
2204                 g_object_unref (header_list);
2205                 g_object_unref (header);
2206         }
2207 }
2208
2209 void
2210 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
2211 {
2212         g_return_if_fail (MODEST_IS_WINDOW(win));
2213
2214         reply_forward (ACTION_REPLY, win);
2215 }
2216
2217 void
2218 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
2219 {
2220         g_return_if_fail (MODEST_IS_WINDOW(win));
2221
2222         reply_forward (ACTION_FORWARD, win);
2223 }
2224
2225 void
2226 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
2227 {
2228         g_return_if_fail (MODEST_IS_WINDOW(win));
2229
2230         reply_forward (ACTION_REPLY_TO_ALL, win);
2231 }
2232
2233 void
2234 modest_ui_actions_on_next (GtkAction *action,
2235                            ModestWindow *window)
2236 {
2237         if (MODEST_IS_MAIN_WINDOW (window)) {
2238                 GtkWidget *header_view;
2239
2240                 header_view = modest_main_window_get_child_widget (
2241                                 MODEST_MAIN_WINDOW(window),
2242                                 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2243                 if (!header_view)
2244                         return;
2245
2246                 modest_header_view_select_next (
2247                                 MODEST_HEADER_VIEW(header_view));
2248         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2249                 modest_msg_view_window_select_next_message (
2250                                 MODEST_MSG_VIEW_WINDOW (window));
2251         } else {
2252                 g_return_if_reached ();
2253         }
2254 }
2255
2256 void
2257 modest_ui_actions_on_prev (GtkAction *action,
2258                            ModestWindow *window)
2259 {
2260         g_return_if_fail (MODEST_IS_WINDOW(window));
2261
2262         if (MODEST_IS_MAIN_WINDOW (window)) {
2263                 GtkWidget *header_view;
2264                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
2265                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2266                 if (!header_view)
2267                         return;
2268
2269                 modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view));
2270         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2271                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
2272         } else {
2273                 g_return_if_reached ();
2274         }
2275 }
2276
2277 void
2278 modest_ui_actions_on_sort (GtkAction *action,
2279                            ModestWindow *window)
2280 {
2281         GtkWidget *header_view = NULL;
2282
2283         g_return_if_fail (MODEST_IS_WINDOW(window));
2284
2285         if (MODEST_IS_MAIN_WINDOW (window)) {
2286                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(window),
2287                                                                    MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2288 #ifdef MODEST_TOOLKIT_HILDON2
2289         } else if (MODEST_IS_HEADER_WINDOW (window)) {
2290                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
2291 #endif
2292         }
2293
2294         if (!header_view) {
2295                 modest_platform_information_banner (NULL, NULL, _CS("ckdg_ib_nothing_to_sort"));
2296
2297                 return;
2298         }
2299
2300         /* Show sorting dialog */
2301         modest_utils_run_sort_dialog (GTK_WINDOW (window), MODEST_SORT_HEADERS);
2302 }
2303
2304 static void
2305 sync_folder_cb (ModestMailOperation *mail_op,
2306                 TnyFolder *folder,
2307                 gpointer user_data)
2308 {
2309         ModestHeaderView *header_view = (ModestHeaderView *) user_data;
2310
2311         if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
2312                 ModestWindow *parent = (ModestWindow *) modest_mail_operation_get_source (mail_op);
2313
2314                 /* We must clear first, because otherwise set_folder will ignore */
2315                 /*    the change as the folders are the same */
2316                 modest_header_view_clear (header_view);
2317                 modest_header_view_set_folder (header_view, folder, TRUE, parent, NULL, NULL);
2318
2319                 g_object_unref (parent);
2320         }
2321
2322         g_object_unref (header_view);
2323 }
2324
2325 static gboolean
2326 idle_refresh_folder (gpointer source)
2327 {
2328         ModestHeaderView *header_view = NULL;
2329
2330         /* If the window still exists */
2331         if (!GTK_IS_WIDGET (source) ||
2332             !GTK_WIDGET_VISIBLE (source))
2333                 return FALSE;
2334
2335         /* Refresh the current view */
2336 #ifdef MODEST_TOOLKIT_HILDON2
2337         if (MODEST_IS_HEADER_WINDOW (source))
2338                 header_view = modest_header_window_get_header_view ((ModestHeaderWindow *) source);
2339 #else
2340         if (MODEST_IS_MAIN_WINDOW (source))
2341                 header_view = MODEST_HEADER_VIEW (modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (source),
2342                                                                                        MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
2343 #endif
2344         if (header_view) {
2345                 TnyFolder *folder = modest_header_view_get_folder (header_view);
2346                 if (folder) {
2347                         /* Sync the folder status */
2348                         ModestMailOperation *mail_op = modest_mail_operation_new (source);
2349                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
2350                         modest_mail_operation_sync_folder (mail_op, folder, FALSE, sync_folder_cb, g_object_ref (header_view));
2351                         g_object_unref (folder);
2352                         g_object_unref (mail_op);
2353                 }
2354         }
2355
2356         return FALSE;
2357 }
2358
2359 static void
2360 update_account_cb (ModestMailOperation *self,
2361                    TnyList *new_headers,
2362                    gpointer user_data)
2363 {
2364         ModestWindow *top;
2365         gboolean show_visual_notifications;
2366
2367         top = modest_window_mgr_get_current_top (modest_runtime_get_window_mgr ());
2368         show_visual_notifications = (top) ? FALSE : TRUE;
2369
2370         /* Notify new messages have been downloaded. If the
2371            send&receive was invoked by the user then do not show any
2372            visual notification, only play a sound and activate the LED
2373            (for the Maemo version) */
2374         if (TNY_IS_LIST(new_headers) && (tny_list_get_length (new_headers)) > 0) {
2375
2376                 /* We only notify about really new messages (not seen) we get */
2377                 TnyList *actually_new_list;
2378                 TnyIterator *iterator;
2379                 actually_new_list = TNY_LIST (tny_simple_list_new ());
2380                 for (iterator = tny_list_create_iterator (new_headers);
2381                      !tny_iterator_is_done (iterator);
2382                      tny_iterator_next (iterator)) {
2383                         TnyHeader *header;
2384                         TnyHeaderFlags flags;
2385                         header = TNY_HEADER (tny_iterator_get_current (iterator));
2386                         flags = tny_header_get_flags (header);
2387
2388                         if (!(flags & TNY_HEADER_FLAG_SEEN)) {
2389                                 /* Messages are ordered from most
2390                                    recent to oldest. But we want to
2391                                    show notifications starting from
2392                                    the oldest message. That's why we
2393                                    reverse the list */
2394                                 tny_list_prepend (actually_new_list, G_OBJECT (header));
2395                         }
2396                         g_object_unref (header);
2397                 }
2398                 g_object_unref (iterator);
2399
2400                 if (tny_list_get_length (actually_new_list) > 0) {
2401                         GList *new_headers_list = NULL;
2402
2403                         new_headers_list = modest_utils_create_notification_list_from_header_list (actually_new_list);
2404
2405                         /* Send notifications */
2406                         if (new_headers_list) {
2407                                 modest_platform_on_new_headers_received (new_headers_list,
2408                                                                          show_visual_notifications);
2409                                 /* Free the list */
2410                                 modest_utils_free_notification_list (new_headers_list);
2411                         }
2412                 }
2413                 g_object_unref (actually_new_list);
2414         }
2415
2416         if (top) {
2417                 /* Refresh the current folder in an idle. We do this
2418                    in order to avoid refresh cancelations if the
2419                    currently viewed folder is the inbox */
2420                 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
2421                                  idle_refresh_folder,
2422                                  g_object_ref (top),
2423                                  g_object_unref);
2424         }
2425 }
2426
2427 typedef struct {
2428         TnyAccount *account;
2429         ModestWindow *win;
2430         gchar *account_name;
2431         gboolean poke_status;
2432         gboolean interactive;
2433         ModestMailOperation *mail_op;
2434 } SendReceiveInfo;
2435
2436 static void
2437 do_send_receive_performer (gboolean canceled,
2438                            GError *err,
2439                            GtkWindow *parent_window,
2440                            TnyAccount *account,
2441                            gpointer user_data)
2442 {
2443         SendReceiveInfo *info;
2444
2445         info = (SendReceiveInfo *) user_data;
2446
2447         if (err || canceled) {
2448                 /* In disk full conditions we could get this error here */
2449                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
2450                                                                 (GtkWidget *) parent_window, err,
2451                                                                 account, NULL);
2452
2453                 if (info->mail_op) {
2454                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
2455                                                             info->mail_op);
2456                 }
2457                 goto clean;
2458         }
2459
2460         /* Set send/receive operation in progress */
2461         if (info->win && MODEST_IS_MAIN_WINDOW (info->win)) {
2462                 modest_main_window_notify_send_receive_initied (MODEST_MAIN_WINDOW (info->win));
2463         }
2464
2465         if (info->win && MODEST_IS_MAIN_WINDOW (info->win))
2466                 g_signal_connect (G_OBJECT (info->mail_op), "operation-finished",
2467                                   G_CALLBACK (on_send_receive_finished),
2468                                   info->win);
2469
2470         /* Send & receive. */
2471         modest_mail_operation_update_account (info->mail_op, info->account_name, info->poke_status, info->interactive,
2472                                               update_account_cb, info->win);
2473
2474  clean:
2475         /* Frees */
2476         if (info->mail_op)
2477                 g_object_unref (G_OBJECT (info->mail_op));
2478         if (info->account_name)
2479                 g_free (info->account_name);
2480         if (info->win)
2481                 g_object_unref (info->win);
2482         if (info->account)
2483                 g_object_unref (info->account);
2484         g_slice_free (SendReceiveInfo, info);
2485 }
2486
2487 /*
2488  * This function performs the send & receive required actions. The
2489  * window is used to create the mail operation. Typically it should
2490  * always be the main window, but we pass it as argument in order to
2491  * be more flexible.
2492  */
2493 void
2494 modest_ui_actions_do_send_receive (const gchar *account_name,
2495                                    gboolean force_connection,
2496                                    gboolean poke_status,
2497                                    gboolean interactive,
2498                                    ModestWindow *win)
2499 {
2500         gchar *acc_name = NULL;
2501         SendReceiveInfo *info;
2502         ModestTnyAccountStore *acc_store;
2503         TnyAccount *account;
2504
2505         /* If no account name was provided then get the current account, and if
2506            there is no current account then pick the default one: */
2507         if (!account_name) {
2508                 if (win)
2509                         acc_name = g_strdup (modest_window_get_active_account (win));
2510                 if (!acc_name)
2511                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
2512                 if (!acc_name) {
2513                         modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2514                         return;
2515                 }
2516         } else {
2517                 acc_name = g_strdup (account_name);
2518         }
2519
2520         acc_store = modest_runtime_get_account_store ();
2521         account = modest_tny_account_store_get_server_account (acc_store, acc_name, TNY_ACCOUNT_TYPE_STORE);
2522
2523         if (!account) {
2524                 g_free (acc_name);
2525                 modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2526                 return;
2527         }
2528
2529         /* Do not automatically refresh accounts that are flagged as
2530            NO_AUTO_UPDATE. This could be useful for accounts that
2531            handle their own update times */
2532         if (!interactive) {
2533                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
2534                 if (proto != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
2535                         const gchar *tag = MODEST_PROTOCOL_REGISTRY_NO_AUTO_UPDATE_PROTOCOLS;
2536                         ModestProtocolRegistry *registry = modest_runtime_get_protocol_registry ();
2537
2538                         if (modest_protocol_registry_protocol_type_has_tag (registry, proto, tag)) {
2539                                 g_debug ("%s no auto update allowed for account %s", __FUNCTION__, account_name);
2540                                 g_object_unref (account);
2541                                 g_free (acc_name);
2542                                 return;
2543                         }
2544                 }
2545         }
2546
2547         /* Create the info for the connect and perform */
2548         info = g_slice_new (SendReceiveInfo);
2549         info->account_name = acc_name;
2550         info->win = (win) ? g_object_ref (win) : NULL;
2551         info->poke_status = poke_status;
2552         info->interactive = interactive;
2553         info->account = account;
2554         /* We need to create the operation here, because otherwise it
2555            could happen that the queue emits the queue-empty signal
2556            while we're trying to connect the account */
2557         info->mail_op = modest_mail_operation_new_with_error_handling ((info->win) ? G_OBJECT (info->win) : NULL,
2558                                                                        modest_ui_actions_disk_operations_error_handler,
2559                                                                        NULL, NULL);
2560         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), info->mail_op);
2561
2562         /* Invoke the connect and perform */
2563         modest_platform_connect_and_perform ((win) ? GTK_WINDOW (win) : NULL,
2564                                              force_connection, info->account,
2565                                              do_send_receive_performer, info);
2566 }
2567
2568
2569 static void
2570 modest_ui_actions_do_cancel_send (const gchar *account_name,
2571                                   ModestWindow *win)
2572 {
2573         TnyTransportAccount *transport_account;
2574         TnySendQueue *send_queue = NULL;
2575         GError *error = NULL;
2576
2577         /* Get transport account */
2578         transport_account =
2579                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2580                                       (modest_runtime_get_account_store(),
2581                                        account_name,
2582                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2583         if (!transport_account) {
2584                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2585                 goto frees;
2586         }
2587
2588         /* Get send queue*/
2589         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
2590         if (!TNY_IS_SEND_QUEUE(send_queue)) {
2591                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
2592                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2593                              "modest: could not find send queue for account\n");
2594         } else {
2595                 /* Cancel the current send */
2596                 tny_account_cancel (TNY_ACCOUNT (transport_account));
2597
2598                 /* Suspend all pending messages */
2599                 tny_send_queue_cancel (send_queue, TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, &error);
2600         }
2601
2602  frees:
2603         if (transport_account != NULL)
2604                 g_object_unref (G_OBJECT (transport_account));
2605 }
2606
2607 static void
2608 modest_ui_actions_cancel_send_all (ModestWindow *win)
2609 {
2610         GSList *account_names, *iter;
2611
2612         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2613                                                           TRUE);
2614
2615         iter = account_names;
2616         while (iter) {
2617                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
2618                 iter = g_slist_next (iter);
2619         }
2620
2621         modest_account_mgr_free_account_names (account_names);
2622         account_names = NULL;
2623 }
2624
2625 void
2626 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
2627
2628 {
2629         /* Check if accounts exist */
2630         gboolean accounts_exist =
2631                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2632
2633         /* If not, allow the user to create an account before trying to send/receive. */
2634         if (!accounts_exist)
2635                 modest_ui_actions_on_accounts (NULL, win);
2636
2637         /* Cancel all sending operaitons */
2638         modest_ui_actions_cancel_send_all (win);
2639 }
2640
2641 /*
2642  * Refreshes all accounts. This function will be used by automatic
2643  * updates
2644  */
2645 void
2646 modest_ui_actions_do_send_receive_all (ModestWindow *win,
2647                                        gboolean force_connection,
2648                                        gboolean poke_status,
2649                                        gboolean interactive)
2650 {
2651         GSList *account_names, *iter;
2652
2653         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2654                                                           TRUE);
2655
2656         iter = account_names;
2657         while (iter) {
2658                 modest_ui_actions_do_send_receive ((const char*) iter->data,
2659                                                    force_connection,
2660                                                    poke_status, interactive, win);
2661                 iter = g_slist_next (iter);
2662         }
2663
2664         modest_account_mgr_free_account_names (account_names);
2665         account_names = NULL;
2666 }
2667
2668 /*
2669  * Handler of the click on Send&Receive button in the main toolbar
2670  */
2671 void
2672 modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win)
2673 {
2674         /* Check if accounts exist */
2675         gboolean accounts_exist;
2676
2677         accounts_exist =
2678                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2679
2680         /* If not, allow the user to create an account before trying to send/receive. */
2681         if (!accounts_exist)
2682                 modest_ui_actions_on_accounts (NULL, win);
2683
2684         /* Refresh the current folder. The if is always TRUE it's just an extra check */
2685         if (MODEST_IS_MAIN_WINDOW (win)) {
2686                 GtkWidget *folder_view;
2687                 TnyFolderStore *folder_store;
2688
2689                 folder_view =
2690                         modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
2691                                                              MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2692                 if (!folder_view)
2693                         return;
2694
2695                 folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2696
2697                 if (folder_store)
2698                         g_object_unref (folder_store);
2699                 /* Refresh the active account. Force the connection if needed
2700                    and poke the status of all folders */
2701                 modest_ui_actions_do_send_receive (NULL, TRUE, TRUE, TRUE, win);
2702 #ifdef MODEST_TOOLKIT_HILDON2
2703         } else if (MODEST_IS_ACCOUNTS_WINDOW (win)) {
2704                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2705 #endif
2706         } else {
2707                 const gchar *active_account;
2708                 active_account = modest_window_get_active_account (MODEST_WINDOW (win));
2709
2710                 modest_ui_actions_do_send_receive (active_account, TRUE, TRUE, TRUE, win);
2711         }
2712
2713 }
2714
2715
2716 void
2717 modest_ui_actions_toggle_header_list_view (GtkAction *action, ModestMainWindow *main_window)
2718 {
2719         ModestConf *conf;
2720         GtkWidget *header_view;
2721
2722         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2723
2724         header_view = modest_main_window_get_child_widget (main_window,
2725                                                            MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2726         if (!header_view)
2727                 return;
2728
2729         conf = modest_runtime_get_conf ();
2730
2731         /* what is saved/restored is depending on the style; thus; we save with
2732          * old style, then update the style, and restore for this new style
2733          */
2734         modest_widget_memory_save (conf, G_OBJECT(header_view), MODEST_CONF_HEADER_VIEW_KEY);
2735
2736         if (modest_header_view_get_style
2737             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
2738                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2739                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
2740         else
2741                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
2742                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
2743
2744         modest_widget_memory_restore (conf, G_OBJECT(header_view),
2745                                       MODEST_CONF_HEADER_VIEW_KEY);
2746 }
2747
2748
2749 void
2750 modest_ui_actions_on_header_selected (ModestHeaderView *header_view,
2751                                       TnyHeader *header,
2752                                       ModestMainWindow *main_window)
2753 {
2754         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2755         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2756
2757         /* in the case the folder is empty, show the empty folder message and focus
2758          * folder view */
2759         if (!header && gtk_widget_is_focus (GTK_WIDGET (header_view))) {
2760                 if (modest_header_view_is_empty (header_view)) {
2761                         TnyFolder *folder = modest_header_view_get_folder (header_view);
2762                         GtkWidget *folder_view =
2763                                 modest_main_window_get_child_widget (main_window,
2764                                                                      MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2765                         if (folder != NULL) {
2766                                 modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view), folder, FALSE);
2767                                 g_object_unref (folder);
2768                         }
2769                         gtk_widget_grab_focus (GTK_WIDGET (folder_view));
2770                         return;
2771                 }
2772         }
2773         /* If no header has been selected then exit */
2774         if (!header)
2775                 return;
2776
2777         /* Update focus */
2778         if (!gtk_widget_is_focus (GTK_WIDGET(header_view)))
2779             gtk_widget_grab_focus (GTK_WIDGET(header_view));
2780
2781         /* Update toolbar dimming state */
2782         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2783         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2784 }
2785
2786 void
2787 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
2788                                        TnyHeader *header,
2789                                        GtkTreePath *path,
2790                                        ModestWindow *window)
2791 {
2792         GtkWidget *open_widget;
2793         GtkTreeRowReference *rowref;
2794
2795         g_return_if_fail (MODEST_IS_WINDOW(window));
2796         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2797         g_return_if_fail (TNY_IS_HEADER (header));
2798
2799         if (modest_header_view_count_selected_headers (header_view) > 1) {
2800                 /* Don't allow activation if there are more than one message selected */
2801                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
2802                 return;
2803         }
2804
2805         /* we check for low-mem; in that case, show a warning, and don't allow
2806          * activating headers
2807          */
2808         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2809                 return;
2810
2811         if (MODEST_IS_MAIN_WINDOW (window)) {
2812                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2813                 open_widget = modest_window_get_action_widget (MODEST_WINDOW (window), "/MenuBar/EmailMenu/EmailOpenMenu");
2814                 if (!GTK_WIDGET_IS_SENSITIVE (open_widget))
2815                         return;
2816         }
2817
2818         rowref = gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)), path);
2819         open_msg_from_header (header, rowref, MODEST_WINDOW (window));
2820         gtk_tree_row_reference_free (rowref);
2821 }
2822
2823 static void
2824 set_active_account_from_tny_account (TnyAccount *account,
2825                                      ModestWindow *window)
2826 {
2827         const gchar *server_acc_name = tny_account_get_id (account);
2828
2829         /* We need the TnyAccount provided by the
2830            account store because that is the one that
2831            knows the name of the Modest account */
2832         TnyAccount *modest_server_account =
2833                 modest_tny_account_store_get_tny_account_by (modest_runtime_get_account_store (),
2834                                                              MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
2835                                                              server_acc_name);
2836         if (!modest_server_account) {
2837                 g_warning ("%s: could not get tny account\n", __FUNCTION__);
2838                 return;
2839         }
2840
2841         /* Update active account, but only if it's not a pseudo-account */
2842         if ((!modest_tny_account_is_virtual_local_folders(modest_server_account)) &&
2843             (!modest_tny_account_is_memory_card_account(modest_server_account))) {
2844                 const gchar *modest_acc_name =
2845                         modest_tny_account_get_parent_modest_account_name_for_server_account (modest_server_account);
2846                 if (modest_acc_name)
2847                         modest_window_set_active_account (window, modest_acc_name);
2848         }
2849
2850         g_object_unref (modest_server_account);
2851 }
2852
2853
2854 static void
2855 folder_refreshed_cb (ModestMailOperation *mail_op,
2856                      TnyFolder *folder,
2857                      gpointer user_data)
2858 {
2859         ModestMainWindow *win = NULL;
2860         GtkWidget *folder_view, *header_view;
2861         const GError *error;
2862
2863         g_return_if_fail (TNY_IS_FOLDER (folder));
2864
2865         win = MODEST_MAIN_WINDOW (user_data);
2866
2867         /* Check if the operation failed due to memory low conditions */
2868         error = modest_mail_operation_get_error (mail_op);
2869         if (error && error->domain == MODEST_MAIL_OPERATION_ERROR &&
2870             error->code == MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY) {
2871                 modest_platform_run_information_dialog (GTK_WINDOW (win),
2872                                                         _KR("memr_ib_operation_disabled"),
2873                                                         TRUE);
2874                 return;
2875         }
2876
2877         folder_view =
2878                 modest_main_window_get_child_widget(win, MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW);
2879         header_view =
2880                 modest_main_window_get_child_widget(win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2881
2882         if (folder_view) {
2883                 TnyFolderStore *current_folder;
2884
2885                 current_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2886                 if (current_folder) {
2887                         gboolean different = ((TnyFolderStore *) folder != current_folder);
2888                         g_object_unref (current_folder);
2889                         if (different)
2890                                 return;
2891                 }
2892         }
2893
2894         /* Check if folder is empty and set headers view contents style */
2895         if ((tny_folder_get_all_count (folder) == 0) ||
2896             modest_header_view_is_empty (MODEST_HEADER_VIEW (header_view)))
2897                 modest_main_window_set_contents_style (win,
2898                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2899 }
2900
2901 void
2902 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
2903                                                TnyFolderStore *folder_store,
2904                                                gboolean selected,
2905                                                ModestMainWindow *main_window)
2906 {
2907         GtkWidget *header_view;
2908
2909         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
2910
2911         header_view = modest_main_window_get_child_widget(main_window,
2912                                                           MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
2913         if (!header_view)
2914                 return;
2915
2916
2917         if (TNY_IS_ACCOUNT (folder_store)) {
2918                 if (selected) {
2919                         set_active_account_from_tny_account (TNY_ACCOUNT (folder_store), MODEST_WINDOW (main_window));
2920
2921                         /* Show account details */
2922                         modest_main_window_set_contents_style (main_window, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
2923                 }
2924         } else {
2925                 if (TNY_IS_FOLDER (folder_store) && selected) {
2926                         TnyAccount *account;
2927
2928                         /* Update the active account */
2929                         account = modest_tny_folder_get_account (TNY_FOLDER (folder_store));
2930                         if (account) {
2931                                 set_active_account_from_tny_account (account, MODEST_WINDOW (main_window));
2932                                 g_object_unref (account);
2933                                 account = NULL;
2934                         }
2935
2936                         /* Set the header style by default, it could
2937                            be changed later by the refresh callback to
2938                            empty */
2939                         modest_main_window_set_contents_style (main_window,
2940                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2941
2942                         /* Set folder on header view. This function
2943                            will call tny_folder_refresh_async so we
2944                            pass a callback that will be called when
2945                            finished. We use that callback to set the
2946                            empty view if there are no messages */
2947                         modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view),
2948                                                        TNY_FOLDER (folder_store),
2949                                                        TRUE,
2950                                                        MODEST_WINDOW (main_window),
2951                                                        folder_refreshed_cb,
2952                                                        main_window);
2953
2954                         /* Restore configuration. We need to do this
2955                            *after* the set_folder because the widget
2956                            memory asks the header view about its
2957                            folder  */
2958                         modest_widget_memory_restore (modest_runtime_get_conf (),
2959                                                       G_OBJECT(header_view),
2960                                                       MODEST_CONF_HEADER_VIEW_KEY);
2961                 } else {
2962                         /* No need to save the header view
2963                            configuration for Maemo because it only
2964                            saves the sorting stuff and that it's
2965                            already being done by the sort
2966                            dialog. Remove it when the GNOME version
2967                            has the same behaviour */
2968 #ifdef MODEST_TOOLKIT_GTK
2969                         if (modest_main_window_get_contents_style (main_window) ==
2970                             MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
2971                                 modest_widget_memory_save (modest_runtime_get_conf (), 
2972                                                            G_OBJECT (header_view),
2973                                                            MODEST_CONF_HEADER_VIEW_KEY);
2974 #endif
2975                         modest_header_view_clear (MODEST_HEADER_VIEW(header_view));
2976                 }
2977         }
2978
2979         /* Update dimming state */
2980         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2981         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2982 }
2983
2984 void
2985 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
2986                                      ModestWindow *win)
2987 {
2988         GtkWidget *dialog;
2989         gchar *txt, *item;
2990         gboolean online;
2991
2992         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
2993
2994         online = tny_device_is_online (modest_runtime_get_device());
2995
2996         if (online) {
2997                 /* already online -- the item is simply not there... */
2998                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
2999                                                  GTK_DIALOG_MODAL,
3000                                                  GTK_MESSAGE_WARNING,
3001                                                  GTK_BUTTONS_NONE,
3002                                                  _("The %s you selected cannot be found"),
3003                                                  item);
3004                 gtk_dialog_add_button (GTK_DIALOG (dialog),_("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
3005                 gtk_dialog_run (GTK_DIALOG(dialog));
3006         } else {
3007                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
3008                                                       GTK_WINDOW (win),
3009                                                       GTK_DIALOG_MODAL,
3010                                                       _("mcen_bd_dialog_cancel"),
3011                                                       GTK_RESPONSE_REJECT,
3012                                                       _("mcen_bd_dialog_ok"),
3013                                                       GTK_RESPONSE_ACCEPT,
3014                                                       NULL);
3015                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
3016                                          "Do you want to get online?"), item);
3017                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
3018                                     gtk_label_new (txt), FALSE, FALSE, 0);
3019                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3020                 g_free (txt);
3021
3022                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
3023                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3024                         /* TODO: Comment about why is this commented out: */
3025                         /* modest_platform_connect_and_wait (); */
3026                 }
3027         }
3028         gtk_widget_destroy (dialog);
3029 }
3030
3031 void
3032 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
3033                                      ModestWindow *win)
3034 {
3035         /* g_debug ("%s %s", __FUNCTION__, link); */
3036 }
3037
3038
3039 void
3040 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
3041                                         ModestWindow *win)
3042 {
3043         modest_platform_activate_uri (link);
3044 }
3045
3046 void
3047 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
3048                                           ModestWindow *win)
3049 {
3050         modest_platform_show_uri_popup (link);
3051 }
3052
3053 void
3054 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
3055                                              ModestWindow *win)
3056 {
3057         /* we check for low-mem; in that case, show a warning, and don't allow
3058          * viewing attachments
3059          */
3060         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
3061                 return;
3062
3063         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
3064 }
3065
3066 void
3067 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
3068                                           const gchar *address,
3069                                           ModestWindow *win)
3070 {
3071         /* g_debug ("%s %s", __FUNCTION__, address); */
3072 }
3073
3074 static void
3075 on_save_to_drafts_cb (ModestMailOperation *mail_op,
3076                       TnyMsg *saved_draft,
3077                       gpointer user_data)
3078 {
3079         ModestMsgEditWindow *edit_window;
3080
3081         /* TODO: in hildon 2 we have to dim and undim the header views while we're saving */
3082 #ifndef MODEST_TOOLKIT_HILDON2
3083         ModestMainWindow *win;
3084
3085         /* FIXME. Make the header view sensitive again. This is a
3086          * temporary hack. See modest_ui_actions_on_save_to_drafts()
3087          * for details */
3088         win = MODEST_MAIN_WINDOW(modest_window_mgr_get_main_window(
3089                                          modest_runtime_get_window_mgr(), FALSE));
3090         if (win != NULL) {
3091                 GtkWidget *hdrview = modest_main_window_get_child_widget(
3092                         win, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW);
3093                 if (hdrview) gtk_widget_set_sensitive(hdrview, TRUE);
3094         }
3095 #endif
3096
3097         edit_window = MODEST_MSG_EDIT_WINDOW (user_data);
3098
3099         /* Set draft is there was no error */
3100         if (!modest_mail_operation_get_error (mail_op))
3101                 modest_msg_edit_window_set_draft (edit_window, saved_draft);
3102
3103         g_object_unref(edit_window);
3104 }
3105
3106 static gboolean
3107 enough_space_for_message (ModestMsgEditWindow *edit_window,
3108                           MsgData *data)
3109 {
3110         guint64 available_disk, expected_size;
3111         gint parts_count;
3112         guint64 parts_size;
3113
3114         /* Check size */
3115         available_disk = modest_utils_get_available_space (NULL);
3116         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
3117         expected_size = modest_tny_msg_estimate_size (data->plain_body,
3118                                                       data->html_body,
3119                                                       parts_count,
3120                                                       parts_size);
3121
3122         /* Double check: disk full condition or message too big */
3123         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
3124             expected_size > available_disk) {
3125                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3126                 modest_platform_information_banner (NULL, NULL, msg);
3127                 g_free (msg);
3128
3129                 return FALSE;
3130         }
3131
3132         /*
3133          * djcb: if we're in low-memory state, we only allow for
3134          * saving messages smaller than
3135          * MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h) this
3136          * should still allow for sending anything critical...
3137          */
3138         if ((expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) &&
3139             modest_platform_check_memory_low (MODEST_WINDOW(edit_window), TRUE))
3140                 return FALSE;
3141
3142         /*
3143          * djcb: we also make sure that the attachments are smaller than the max size
3144          * this is for the case where we'd try to forward a message with attachments
3145          * bigger than our max allowed size, or sending an message from drafts which
3146          * somehow got past our checks when attaching.
3147          */
3148         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
3149                 modest_platform_run_information_dialog (
3150                         GTK_WINDOW(edit_window),
3151                         _("mail_ib_error_attachment_size"),
3152                         TRUE);
3153                 return FALSE;
3154         }
3155
3156         return TRUE;
3157 }
3158
3159 gboolean
3160 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
3161 {
3162         TnyTransportAccount *transport_account;
3163         ModestMailOperation *mail_operation;
3164         MsgData *data;
3165         gchar *account_name;
3166         ModestAccountMgr *account_mgr;
3167         gboolean had_error = FALSE;
3168         ModestMainWindow *win = NULL;
3169
3170         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), FALSE);
3171
3172         data = modest_msg_edit_window_get_msg_data (edit_window);
3173
3174         /* Check size */
3175         if (!enough_space_for_message (edit_window, data)) {
3176                 modest_msg_edit_window_free_msg_data (edit_window, data);
3177                 return FALSE;
3178         }
3179
3180         account_name = g_strdup (data->account_name);
3181         account_mgr = modest_runtime_get_account_mgr();
3182         if (!account_name)
3183                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
3184         if (!account_name)
3185                 account_name = modest_account_mgr_get_default_account (account_mgr);
3186         if (!account_name) {
3187                 g_printerr ("modest: no account found\n");
3188                 modest_msg_edit_window_free_msg_data (edit_window, data);
3189                 return FALSE;
3190         }
3191
3192         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
3193                 account_name = g_strdup (data->account_name);
3194         }
3195
3196         transport_account =
3197                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
3198                                       (modest_runtime_get_account_store (),
3199                                        account_name,
3200                                        TNY_ACCOUNT_TYPE_TRANSPORT));
3201         if (!transport_account) {
3202                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
3203                 g_free (account_name);
3204                 modest_msg_edit_window_free_msg_data (edit_window, data);
3205                 return FALSE;
3206         }
3207
3208         /* Create the mail operation */
3209         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler,
3210                                                                         NULL, NULL);
3211         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
3212
3213         modest_mail_operation_save_to_drafts (mail_operation,
3214                                               transport_account,
3215                                               data->draft_msg,
3216                                               data->from,
3217                                               data->to, 
3218                                               data->cc, 
3219                                               data->bcc,
3220                                    &nbs