Modified webpage: now tinymail repository is in gitorious.
[modest] / src / modest-ui-actions.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <glib/gprintf.h>
36 #include <string.h>
37 #include <modest-runtime.h>
38 #include <modest-defs.h>
39 #include <modest-tny-folder.h>
40 #include <modest-tny-msg.h>
41 #include <modest-tny-account.h>
42 #include <modest-address-book.h>
43 #include "modest-error.h"
44 #include "modest-ui-actions.h"
45 #include "modest-tny-platform-factory.h"
46 #include "modest-platform.h"
47 #include "modest-debug.h"
48 #include <tny-mime-part.h>
49 #include <tny-error.h>
50 #include <tny-camel-folder.h>
51 #include <tny-camel-imap-folder.h>
52 #include <tny-camel-pop-folder.h>
53 #include <widgets/modest-header-window.h>
54 #include <widgets/modest-folder-window.h>
55 #include <widgets/modest-accounts-window.h>
56
57 #ifdef MODEST_TOOLKIT_HILDON2
58 #include <hildon/hildon-gtk.h>
59 #include <modest-maemo-utils.h>
60 #else
61 #include <gtk/modest-shell-window.h>
62 #endif
63 #include "modest-utils.h"
64 #include "widgets/modest-connection-specific-smtp-window.h"
65 #include "widgets/modest-ui-constants.h"
66 #include <widgets/modest-msg-view-window.h>
67 #include <widgets/modest-account-view-window.h>
68 #include <widgets/modest-details-dialog.h>
69 #include <widgets/modest-attachments-view.h>
70 #include "widgets/modest-folder-view.h"
71 #include "widgets/modest-global-settings-dialog.h"
72 #include "modest-account-mgr-helpers.h"
73 #include "modest-mail-operation.h"
74 #include "modest-text-utils.h"
75 #include <modest-widget-memory.h>
76 #include <tny-error.h>
77 #include <tny-simple-list.h>
78 #include <tny-msg-view.h>
79 #include <tny-device.h>
80 #include <tny-merge-folder.h>
81 #include <widgets/modest-toolkit-utils.h>
82 #include <tny-camel-bs-msg.h>
83 #include <tny-camel-bs-mime-part.h>
84
85 #include <gtk/gtk.h>
86 #include <gtkhtml/gtkhtml.h>
87
88 #define MODEST_MOVE_TO_DIALOG_FOLDER_VIEW "move-to-dialog-folder-view"
89
90 typedef struct _GetMsgAsyncHelper {
91         ModestWindow *window;
92         ModestMailOperation *mail_op;
93         TnyIterator *iter;
94         guint num_ops;
95         GFunc func;
96         gpointer user_data;
97 } GetMsgAsyncHelper;
98
99 typedef enum _ReplyForwardAction {
100         ACTION_REPLY,
101         ACTION_REPLY_TO_ALL,
102         ACTION_FORWARD
103 } ReplyForwardAction;
104
105 typedef struct _ReplyForwardHelper {
106         guint reply_forward_type;
107         ReplyForwardAction action;
108         gchar *account_name;
109         gchar *mailbox;
110         GtkWidget *parent_window;
111         TnyHeader *header;
112         TnyHeader *top_header;
113         TnyMsg    *msg_part;
114         TnyList *parts;
115 } ReplyForwardHelper;
116
117 typedef struct _MoveToHelper {
118         GtkTreeRowReference *reference;
119         GtkWidget *banner;
120 } MoveToHelper;
121
122 typedef struct _PasteAsAttachmentHelper {
123         ModestMsgEditWindow *window;
124         GtkWidget *banner;
125 } PasteAsAttachmentHelper;
126
127 typedef struct {
128         TnyList *list;
129         ModestWindow *win;
130 } MoveToInfo;
131
132 /*
133  * The do_headers_action uses this kind of functions to perform some
134  * action to each member of a list of headers
135  */
136 typedef void (*HeadersFunc) (TnyHeader *header, ModestWindow *win, gpointer user_data);
137
138 static void     do_headers_action     (ModestWindow *win,
139                                        HeadersFunc func,
140                                        gpointer user_data);
141
142 static void     open_msg_cb            (ModestMailOperation *mail_op,
143                                         TnyHeader *header,
144                                         gboolean canceled,
145                                         TnyMsg *msg,
146                                         GError *err,
147                                         gpointer user_data);
148
149 static void     reply_forward_cb       (ModestMailOperation *mail_op,
150                                         TnyHeader *header,
151                                         gboolean canceled,
152                                         TnyMsg *msg,
153                                         GError *err,
154                                         gpointer user_data);
155
156 static void     reply_forward          (ReplyForwardAction action, ModestWindow *win);
157
158 static gint header_list_count_uncached_msgs (TnyList *header_list);
159
160 static gboolean connect_to_get_msg (ModestWindow *win,
161                                     gint num_of_uncached_msgs,
162                                     TnyAccount *account);
163
164 static gboolean remote_folder_has_leave_on_server (TnyFolderStore *folder);
165
166 static void     do_create_folder (ModestWindow *window,
167                                   TnyFolderStore *parent_folder,
168                                   const gchar *suggested_name);
169
170 static TnyAccount *get_account_from_folder_store (TnyFolderStore *folder_store);
171
172 static void modest_ui_actions_on_folder_window_move_to (GtkWidget *folder_view,
173                                                         TnyFolderStore *dst_folder,
174                                                         TnyList *selection,
175                                                         ModestWindow *win);
176
177 static void modest_ui_actions_on_window_move_to (GtkAction *action,
178                                                  TnyList *list_to_move,
179                                                  TnyFolderStore *dst_folder,
180                                                  ModestWindow *win);
181
182 /*
183  * This function checks whether a TnyFolderStore is a pop account
184  */
185 static gboolean
186 remote_folder_has_leave_on_server (TnyFolderStore *folder)
187 {
188         TnyAccount *account;
189         gboolean result;
190
191         g_return_val_if_fail (TNY_IS_FOLDER_STORE (folder), FALSE);
192
193         account = get_account_from_folder_store (folder);
194         result = (modest_protocol_registry_protocol_type_has_leave_on_server (modest_runtime_get_protocol_registry (),
195                                                                               modest_tny_account_get_protocol_type (account)));
196         g_object_unref (account);
197
198         return result;
199 }
200
201 /* FIXME: this should be merged with the similar code in modest-account-view-window */
202 /* Show the account creation wizard dialog.
203  * returns: TRUE if an account was created. FALSE if the user cancelled.
204  */
205 gboolean
206 modest_ui_actions_run_account_setup_wizard (ModestWindow *win)
207 {
208         gboolean result = FALSE;
209         GtkWindow *wizard;
210         gint dialog_response;
211
212         /* there is no such wizard yet */
213         wizard = GTK_WINDOW (modest_platform_get_account_settings_wizard ());
214         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (wizard), (GtkWindow *) win);
215
216         if (!win) {
217                 GList *window_list;
218                 ModestWindowMgr *mgr;
219
220                 mgr = modest_runtime_get_window_mgr ();
221
222                 window_list = modest_window_mgr_get_window_list (mgr);
223                 if (window_list == NULL) {
224                         win = MODEST_WINDOW (modest_accounts_window_new ());
225                         if (modest_window_mgr_register_window (mgr, win, NULL)) {
226                                 gtk_widget_show_all (GTK_WIDGET (win));
227                         } else {
228                                 gtk_widget_destroy (GTK_WIDGET (win));
229                                 win = NULL;
230                         }
231
232                 } else {
233                         g_list_free (window_list);
234                 }
235         }
236
237         if (win) {
238                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
239                 gtk_window_set_transient_for (GTK_WINDOW (wizard), toplevel);
240         }
241
242         /* make sure the mainwindow is visible. We need to present the
243            wizard again to give it the focus back. show_all are needed
244            in order to get the widgets properly drawn (MainWindow main
245            paned won't be in its right position and the dialog will be
246            missplaced */
247
248         dialog_response = gtk_dialog_run (GTK_DIALOG (wizard));
249         gtk_widget_destroy (GTK_WIDGET (wizard));
250         if (gtk_events_pending ())
251                 gtk_main_iteration ();
252
253         if (dialog_response == GTK_RESPONSE_CANCEL) {
254                 result = FALSE;
255         } else {
256                 /* Check whether an account was created: */
257                 result = modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
258         }
259         return result;
260 }
261
262
263 void
264 modest_ui_actions_on_about (GtkAction *action, ModestWindow *win)
265 {
266         GtkWindow *toplevel;
267         GtkWidget *about;
268         const gchar *authors[] = {
269                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
270                 NULL
271         };
272         about = gtk_about_dialog_new ();
273         gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
274         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
275         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
276                                         _("Copyright (c) 2006, Nokia Corporation\n"
277                                           "All rights reserved."));
278         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
279                                        _("a modest e-mail client\n\n"
280                                          "design and implementation: Dirk-Jan C. Binnema\n"
281                                          "contributions from the fine people at KC and Ig\n"
282                                          "uses the tinymail email framework written by Philip van Hoof"));
283         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
284         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
285
286         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
287         gtk_window_set_transient_for (GTK_WINDOW (about), toplevel);
288         gtk_window_set_modal (GTK_WINDOW (about), TRUE);
289
290         gtk_dialog_run (GTK_DIALOG (about));
291         gtk_widget_destroy(about);
292 }
293
294 /*
295  * Gets the list of currently selected messages. If the win is the
296  * main window, then it returns a newly allocated list of the headers
297  * selected in the header view. If win is the msg view window, then
298  * the value returned is a list with just a single header.
299  *
300  * The caller of this funcion must free the list.
301  */
302 static TnyList *
303 get_selected_headers (ModestWindow *win)
304 {
305         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
306                 /* for MsgViewWindows, we simply return a list with one element */
307                 TnyHeader *header;
308                 TnyList *list = NULL;
309
310                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
311                 if (header != NULL) {
312                         list = tny_simple_list_new ();
313                         tny_list_prepend (list, G_OBJECT(header));
314                         g_object_unref (G_OBJECT(header));
315                 }
316
317                 return list;
318         } else if (MODEST_IS_HEADER_WINDOW (win)) {
319                 GtkWidget *header_view;
320
321                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (win)));
322                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
323         } else {
324                 return NULL;
325         }
326 }
327
328 static void
329 headers_action_mark_as_read (TnyHeader *header,
330                              ModestWindow *win,
331                              gpointer user_data)
332 {
333         TnyHeaderFlags flags;
334         gchar *uid;
335
336         g_return_if_fail (TNY_IS_HEADER(header));
337
338         flags = tny_header_get_flags (header);
339         if (flags & TNY_HEADER_FLAG_SEEN) return;
340         tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
341         uid = modest_tny_folder_get_header_unique_id (header);
342         modest_platform_emit_msg_read_changed_signal (uid, TRUE);
343         g_free (uid);
344 }
345
346 static void
347 headers_action_mark_as_unread (TnyHeader *header,
348                                ModestWindow *win,
349                                gpointer user_data)
350 {
351         TnyHeaderFlags flags;
352
353         g_return_if_fail (TNY_IS_HEADER(header));
354
355         flags = tny_header_get_flags (header);
356         if (flags & TNY_HEADER_FLAG_SEEN)  {
357                 gchar *uid;
358                 uid = modest_tny_folder_get_header_unique_id (header);
359                 tny_header_unset_flag (header, TNY_HEADER_FLAG_SEEN);
360                 modest_platform_emit_msg_read_changed_signal (uid, FALSE);
361         }
362 }
363
364 /** After deleing a message that is currently visible in a window,
365  * show the next message from the list, or close the window if there are no more messages.
366  **/
367 void
368 modest_ui_actions_refresh_message_window_after_delete (ModestMsgViewWindow* win)
369 {
370         /* Close msg view window or select next */
371         if (!modest_msg_view_window_select_next_message (win) &&
372             !modest_msg_view_window_select_previous_message (win)) {
373                 gboolean ret_value;
374                 g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
375         }
376 }
377
378
379 void
380 modest_ui_actions_on_delete_message (GtkAction *action, ModestWindow *win)
381 {
382         modest_ui_actions_on_edit_mode_delete_message (win);
383 }
384
385 gboolean
386 modest_ui_actions_on_edit_mode_delete_message (ModestWindow *win)
387 {
388         TnyList *header_list = NULL;
389         TnyIterator *iter = NULL;
390         TnyHeader *header = NULL;
391         gchar *message = NULL;
392         gchar *desc = NULL;
393         gint response;
394         ModestWindowMgr *mgr;
395         gboolean retval = TRUE;
396
397         g_return_val_if_fail (MODEST_IS_WINDOW(win), FALSE);
398
399         /* Get the headers, either from the header view (if win is the main window),
400          * or from the message view window: */
401         header_list = get_selected_headers (win);
402         if (!header_list) return FALSE;
403
404         /* Check if any of the headers are already opened, or in the process of being opened */
405
406         /* Select message */
407         if (tny_list_get_length(header_list) == 1) {
408                 iter = tny_list_create_iterator (header_list);
409                 header = TNY_HEADER (tny_iterator_get_current (iter));
410                 if (header) {
411                         gchar *subject;
412                         subject = tny_header_dup_subject (header);
413                         if (!subject)
414                                 subject = g_strdup (_("mail_va_no_subject"));
415                         desc = g_strdup_printf ("%s", subject);
416                         g_free (subject);
417                         g_object_unref (header);
418                 }
419
420                 g_object_unref (iter);
421         }
422         message = g_strdup_printf(ngettext("emev_nc_delete_message", "emev_nc_delete_messages",
423                                            tny_list_get_length(header_list)), desc);
424
425         /* Confirmation dialog */
426         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (win))),
427                                                             message);
428
429         if (response == GTK_RESPONSE_OK) {
430                 GtkTreeSelection *sel = NULL;
431                 GList *sel_list = NULL;
432                 ModestMailOperation *mail_op = NULL;
433
434                 /* Find last selected row */
435
436                 /* Disable window dimming management */
437                 modest_window_disable_dimming (win);
438
439                 /* Remove each header. If it's a view window header_view == NULL */
440                 mail_op = modest_mail_operation_new ((GObject *) win);
441                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
442                                                  mail_op);
443                 modest_mail_operation_remove_msgs (mail_op, header_list, FALSE);
444                 g_object_unref (mail_op);
445
446                 /* Enable window dimming management */
447                 if (sel != NULL) {
448                         gtk_tree_selection_unselect_all (sel);
449                 }
450                 modest_window_enable_dimming (win);
451
452                 if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
453                         modest_ui_actions_refresh_message_window_after_delete (MODEST_MSG_VIEW_WINDOW (win));
454
455                         /* Get main window */
456                         mgr = modest_runtime_get_window_mgr ();
457                 }
458
459                 /* Update toolbar dimming state */
460                 modest_ui_actions_check_menu_dimming_rules (win);
461                 modest_ui_actions_check_toolbar_dimming_rules (win);
462
463                 /* Free */
464                 g_list_foreach (sel_list, (GFunc) gtk_tree_path_free, NULL);
465                 g_list_free (sel_list);
466                 retval = TRUE;
467         } else {
468                 retval = FALSE;
469         }
470
471         /* Free*/
472         g_free(message);
473         g_free(desc);
474         g_object_unref (header_list);
475
476         return retval;
477 }
478
479
480
481
482 /* delete either message or folder, based on where we are */
483 void
484 modest_ui_actions_on_delete_message_or_folder (GtkAction *action, ModestWindow *win)
485 {
486         g_return_if_fail (MODEST_IS_WINDOW(win));
487
488         /* Check first if the header view has the focus */
489         modest_ui_actions_on_delete_message (action, win);
490 }
491
492 void
493 modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
494 {
495         ModestWindowMgr *mgr = NULL;
496
497 #ifdef MODEST_PLATFORM_MAEMO
498         modest_window_mgr_save_state_for_all_windows (modest_runtime_get_window_mgr ());
499 #endif /* MODEST_PLATFORM_MAEMO */
500
501         g_debug ("closing down, clearing %d item(s) from operation queue",
502                  modest_mail_operation_queue_num_elements
503                  (modest_runtime_get_mail_operation_queue()));
504
505         /* cancel all outstanding operations */
506         modest_mail_operation_queue_cancel_all
507                 (modest_runtime_get_mail_operation_queue());
508
509         g_debug ("queue has been cleared");
510
511
512         /* Check if there are opened editing windows */
513         mgr = modest_runtime_get_window_mgr ();
514         modest_window_mgr_close_all_windows (mgr);
515
516         /* note: when modest-tny-account-store is finalized,
517            it will automatically set all network connections
518            to offline */
519
520 /*      gtk_main_quit (); */
521 }
522
523 void
524 modest_ui_actions_on_close_window (GtkAction *action, ModestWindow *win)
525 {
526         gboolean ret_value;
527
528         g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value);
529
530 /*      if (MODEST_IS_MSG_VIEW_WINDOW (win)) { */
531 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
532 /*      } else if (MODEST_IS_MSG_EDIT_WINDOW (win)) { */
533 /*              gboolean ret_value; */
534 /*              g_signal_emit_by_name (G_OBJECT (win), "delete-event", NULL, &ret_value); */
535 /*      } else if (MODEST_IS_WINDOW (win)) { */
536 /*              gtk_widget_destroy (GTK_WIDGET (win)); */
537 /*      } else { */
538 /*              g_return_if_reached (); */
539 /*      } */
540 }
541
542 void
543 modest_ui_actions_add_to_contacts (GtkAction *action, ModestWindow *win)
544 {
545         if (MODEST_IS_MSG_VIEW_WINDOW (win))
546                 modest_msg_view_window_add_to_contacts (MODEST_MSG_VIEW_WINDOW (win));
547         else if (MODEST_IS_MSG_EDIT_WINDOW (win))
548                 modest_msg_edit_window_add_to_contacts (MODEST_MSG_EDIT_WINDOW (win));
549 }
550
551 void
552 modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
553 {
554         GtkClipboard *clipboard = NULL;
555         gchar *selection = NULL;
556
557         clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
558         selection = gtk_clipboard_wait_for_text (clipboard);
559
560         if (selection) {
561                 modest_address_book_add_address (selection, (GtkWindow *) win);
562                 g_free (selection);
563         }
564 }
565
566 void
567 modest_ui_actions_on_new_account (GtkAction *action,
568                                   ModestWindow *window)
569 {
570         if (!modest_ui_actions_run_account_setup_wizard (window)) {
571                 g_debug ("%s: wizard was already running", __FUNCTION__);
572         }
573 }
574
575 void
576 modest_ui_actions_on_accounts (GtkAction *action,
577                                ModestWindow *win)
578 {
579         /* This is currently only implemented for Maemo */
580         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE)) {
581                 if (!modest_ui_actions_run_account_setup_wizard (win))
582                         g_debug ("%s: wizard was already running", __FUNCTION__);
583
584                 return;
585         } else {
586                 /* Show the list of accounts */
587                 GtkWindow *win_toplevel, *acc_toplevel;
588                 GtkWidget *account_win;
589
590                 account_win = modest_account_view_window_new ();
591                 acc_toplevel = (GtkWindow *) gtk_widget_get_toplevel (account_win);
592
593                 /* The accounts dialog must be modal */
594                 win_toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
595                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), acc_toplevel, win_toplevel);
596                 modest_utils_show_dialog_and_forget (win_toplevel, GTK_DIALOG (account_win));
597         }
598 }
599
600 void
601 modest_ui_actions_on_smtp_servers (GtkAction *action, ModestWindow *win)
602 {
603         /* Create the window if necessary: */
604         GtkWidget *specific_window = GTK_WIDGET (modest_connection_specific_smtp_window_new ());
605         modest_connection_specific_smtp_window_fill_with_connections (
606                 MODEST_CONNECTION_SPECIFIC_SMTP_WINDOW (specific_window),
607                 modest_runtime_get_account_mgr());
608
609         /* Show the window: */
610         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
611                                      GTK_WINDOW (specific_window), (GtkWindow *) win);
612         gtk_widget_show (specific_window);
613 }
614
615 static guint64
616 count_part_size (const gchar *part)
617 {
618         GnomeVFSURI *vfs_uri;
619         gchar *escaped_filename;
620         gchar *filename;
621         GnomeVFSFileInfo *info;
622         guint64 result;
623
624         /* Estimation of attachment size if we cannot get it from file info */
625         result = 32768;
626
627         vfs_uri = gnome_vfs_uri_new (part);
628
629         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
630         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
631         g_free (escaped_filename);
632         gnome_vfs_uri_unref (vfs_uri);
633
634         info = gnome_vfs_file_info_new ();
635         
636         if (gnome_vfs_get_file_info (part, 
637                                      info, 
638                                      GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
639             == GNOME_VFS_OK) {
640                 if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
641                         result = info->size;
642                 }
643         }
644         g_free (filename);
645         gnome_vfs_file_info_unref (info);
646
647         return result;
648 }
649
650 static guint64 
651 count_parts_size (GSList *parts)
652 {
653         GSList *node;
654         guint64 result = 0;
655
656         for (node = parts; node != NULL; node = g_slist_next (node)) {
657                 result += count_part_size ((const gchar *) node->data);
658         }
659
660         return result;
661 }
662
663 void
664 modest_ui_actions_compose_msg(ModestWindow *win,
665                               const gchar *to_str,
666                               const gchar *cc_str,
667                               const gchar *bcc_str,
668                               const gchar *subject_str,
669                               const gchar *body_str,
670                               GSList *attachments,
671                               gboolean set_as_modified)
672 {
673         gchar *account_name = NULL;
674         const gchar *mailbox;
675         TnyMsg *msg = NULL;
676         TnyAccount *account = NULL;
677         TnyFolder *folder = NULL;
678         gchar *from_str = NULL, *signature = NULL, *body = NULL, *recipient = NULL, *tmp = NULL;
679         gboolean use_signature = FALSE;
680         ModestWindow *msg_win = NULL;
681         ModestAccountMgr *mgr = modest_runtime_get_account_mgr();
682         ModestTnyAccountStore *store = modest_runtime_get_account_store();
683         GnomeVFSFileSize total_size, allowed_size;
684         guint64 available_disk, expected_size, parts_size;
685         guint parts_count;
686         TnyList *header_pairs;
687
688         /* we check for low-mem */
689         if (modest_platform_check_memory_low (win, TRUE))
690                 goto cleanup;
691
692         available_disk = modest_utils_get_available_space (NULL);
693         parts_count = g_slist_length (attachments);
694         parts_size = count_parts_size (attachments);
695         expected_size = modest_tny_msg_estimate_size (body, NULL, parts_count, parts_size);
696
697         /* Double check: disk full condition or message too big */
698         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
699             expected_size > available_disk) {
700                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
701                 modest_platform_system_banner (NULL, NULL, msg);
702                 g_free (msg);
703
704                 return;
705         }
706
707         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
708                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
709                 modest_platform_run_information_dialog (toplevel,
710                                                         _("mail_ib_error_attachment_size"),
711                                                         TRUE);
712                 return;
713         }
714
715
716         if (win)
717                 account_name = g_strdup (modest_window_get_active_account(win));
718         if (!account_name) {
719                 account_name = modest_account_mgr_get_default_account(mgr);
720         }
721         if (!account_name) {
722                 g_printerr ("modest: no account found\n");
723                 goto cleanup;
724         }
725
726         if (win)
727                 mailbox = modest_window_get_active_mailbox (win);
728         else
729                 mailbox = NULL;
730         account = modest_tny_account_store_get_server_account (store, account_name, TNY_ACCOUNT_TYPE_STORE);
731         if (!account) {
732                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
733                 goto cleanup;
734         }
735         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
736         if (!folder) {
737                 g_printerr ("modest: failed to find Drafts folder\n");
738                 goto cleanup;
739         }
740         from_str = modest_account_mgr_get_from_string (mgr, account_name, mailbox);
741         if (!from_str) {
742                 g_printerr ("modest: failed get from string for '%s'\n", account_name);
743                 goto cleanup;
744         }
745
746
747         recipient = modest_text_utils_get_email_address (from_str);
748         tmp = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr (),
749                                                                recipient,
750                                                                &use_signature);
751         signature = modest_text_utils_create_colored_signature (tmp);
752         g_free (tmp);
753         g_free (recipient);
754
755         body = use_signature ? g_strconcat ((body_str) ? body_str : "", signature, NULL) :
756                 g_strdup(body_str);
757
758         header_pairs = TNY_LIST (tny_simple_list_new ());
759         msg = modest_tny_msg_new_html_plain (to_str, from_str, cc_str, bcc_str, subject_str,
760                                              NULL, NULL, body, NULL, NULL, NULL, NULL, header_pairs, NULL);
761         g_object_unref (header_pairs);
762
763         if (!msg) {
764                 g_printerr ("modest: failed to create new msg\n");
765                 goto cleanup;
766         }
767
768         /* Create and register edit window */
769         /* This is destroyed by TODO. */
770         total_size = 0;
771         allowed_size = MODEST_MAX_ATTACHMENT_SIZE;
772         msg_win = modest_msg_edit_window_new (msg, account_name, mailbox, FALSE);
773
774         if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr(), msg_win, win)) {
775                 gtk_widget_destroy (GTK_WIDGET (msg_win));
776                 goto cleanup;
777         }
778         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (msg_win), set_as_modified);
779         gtk_widget_show_all (GTK_WIDGET (msg_win));
780
781         while (attachments) {
782                 GnomeVFSFileSize att_size;
783                 att_size =
784                         modest_msg_edit_window_attach_file_one((ModestMsgEditWindow *)msg_win,
785                                                                attachments->data, allowed_size);
786                 total_size += att_size;
787
788                 if (att_size > allowed_size) {
789                         g_debug ("%s: total size: %u",
790                                  __FUNCTION__, (unsigned int)total_size);
791                         break;
792                 }
793                 allowed_size -= att_size;
794
795                 attachments = g_slist_next(attachments);
796         }
797
798 cleanup:
799         g_free (from_str);
800         g_free (signature);
801         g_free (body);
802         g_free (account_name);
803         if (account)
804                 g_object_unref (G_OBJECT(account));
805         if (folder)
806                 g_object_unref (G_OBJECT(folder));
807         if (msg)
808                 g_object_unref (G_OBJECT(msg));
809 }
810
811 void
812 modest_ui_actions_on_new_msg (GtkAction *action, ModestWindow *win)
813 {
814         /* if there are no accounts yet, just show the wizard */
815         if (!modest_account_mgr_has_accounts (modest_runtime_get_account_mgr(), TRUE))
816                 if (!modest_ui_actions_run_account_setup_wizard (win))
817                         return;
818
819         modest_ui_actions_compose_msg(win, NULL, NULL, NULL, NULL, NULL, NULL, FALSE);
820 }
821
822
823 gboolean
824 modest_ui_actions_msg_retrieval_check (ModestMailOperation *mail_op,
825                                        TnyHeader *header,
826                                        TnyMsg *msg)
827 {
828         ModestMailOperationStatus status;
829
830         /* If there is no message or the operation was not successful */
831         status = modest_mail_operation_get_status (mail_op);
832         if (!msg || status != MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
833                 const GError *error;
834
835                 /* If it's a memory low issue, then show a banner */
836                 error = modest_mail_operation_get_error (mail_op);
837                 if (error && error->domain == MODEST_MAIL_OPERATION_ERROR &&
838                     error->code == MODEST_MAIL_OPERATION_ERROR_LOW_MEMORY) {
839                         GtkWindow *toplevel = NULL;
840                         GObject *source = modest_mail_operation_get_source (mail_op);
841
842                         toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (source));
843                         modest_platform_run_information_dialog (toplevel,
844                                                                 _KR("memr_ib_operation_disabled"),
845                                                                 TRUE);
846                         g_object_unref (source);
847                 }
848
849                 if (error && ((error->code == TNY_SERVICE_ERROR_NO_SUCH_MESSAGE) ||
850                               error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE)) {
851                         gchar *subject, *msg, *format = NULL;
852                         TnyAccount *account;
853
854                         subject = (header) ? tny_header_dup_subject (header) : NULL;
855                         if (!subject)
856                                 subject = g_strdup (_("mail_va_no_subject"));
857
858                         account = modest_mail_operation_get_account (mail_op);
859                         if (account) {
860                                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
861                                 ModestProtocol *protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (), proto);
862
863                                 if (protocol) {
864                                         if (tny_account_get_connection_status (account) ==
865                                             TNY_CONNECTION_STATUS_CONNECTED) {
866                                                 if (header) {
867                                                         format = modest_protocol_get_translation (protocol,
868                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE,
869                                                                                                   subject);
870                                                 } else {
871                                                         format = modest_protocol_get_translation (protocol,
872                                                                                                   MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE_LOST_HEADER);
873                                                 }
874                                         } else {
875                                                 format = g_strdup_printf (_("mail_ib_backend_server_invalid"),
876                                                                           tny_account_get_hostname (account));
877                                         }
878                                 }
879                                 g_object_unref (account);
880                         }
881
882                         if (!format) {
883                                 if (header) {
884                                         format = g_strdup (_("emev_ni_ui_imap_message_not_available_in_server"));
885                                 } else {
886                                         format = g_strdup (_("emev_ni_ui_pop3_msg_recv_error"));
887                                 }
888                         }
889
890                         msg = g_strdup_printf (format, subject);
891                         modest_platform_run_information_dialog (NULL, msg, FALSE);
892                         g_free (msg);
893                         g_free (format);
894                         g_free (subject);
895                 }
896
897                 /* Remove the header from the preregistered uids */
898                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
899                                                      header);
900
901                 return FALSE;
902         }
903
904         return TRUE;
905 }
906
907 typedef struct {
908         guint idle_handler;
909         gchar *message;
910         GtkWidget *banner;
911 } OpenMsgBannerInfo;
912
913 typedef struct {
914         GtkTreeModel *model;
915         TnyHeader *header;
916         ModestWindow *caller_window;
917         OpenMsgBannerInfo *banner_info;
918         GtkTreeRowReference *rowref;
919 } OpenMsgHelper;
920
921 gboolean
922 open_msg_banner_idle (gpointer userdata)
923 {
924         OpenMsgBannerInfo *banner_info = (OpenMsgBannerInfo *) userdata;
925
926         gdk_threads_enter ();
927         banner_info->idle_handler = 0;
928         banner_info->banner = modest_platform_animation_banner (NULL, NULL, banner_info->message);
929         if (banner_info->banner)
930                 g_object_ref (banner_info->banner);
931
932         gdk_threads_leave ();
933
934         return FALSE;
935 }
936
937 static GtkWidget *
938 get_header_view_from_window (ModestWindow *window)
939 {
940         GtkWidget *header_view;
941
942         if (MODEST_IS_HEADER_WINDOW (window)){
943                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
944         } else {
945                 header_view = NULL;
946         }
947
948         return header_view;
949 }
950
951 static gchar *
952 get_info_from_header (TnyHeader *header, gboolean *is_draft, gboolean *can_open)
953 {
954         TnyFolder *folder;
955         gchar *account = NULL;
956         TnyFolderType folder_type = TNY_FOLDER_TYPE_UNKNOWN;
957
958         *is_draft = FALSE;
959         *can_open = TRUE;
960
961         folder = tny_header_get_folder (header);
962         /* Gets folder type (OUTBOX headers will be opened in edit window */
963         if (modest_tny_folder_is_local_folder (folder)) {
964                 folder_type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
965                 if (folder_type == TNY_FOLDER_TYPE_INVALID)
966                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
967         }
968
969         if (folder_type == TNY_FOLDER_TYPE_OUTBOX) {
970                 TnyTransportAccount *traccount = NULL;
971                 ModestTnyAccountStore *accstore = modest_runtime_get_account_store();
972                 traccount = modest_tny_account_store_get_transport_account_from_outbox_header(accstore, header);
973                 if (traccount) {
974                         ModestTnySendQueue *send_queue = NULL;
975                         ModestTnySendQueueStatus status;
976                         gchar *msg_id;
977                         account = g_strdup(modest_tny_account_get_parent_modest_account_name_for_server_account(
978                                                    TNY_ACCOUNT(traccount)));
979                         send_queue = modest_runtime_get_send_queue(traccount, TRUE);
980                         if (TNY_IS_SEND_QUEUE (send_queue)) {
981                                 msg_id = modest_tny_send_queue_get_msg_id (header);
982                                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
983                                 g_free (msg_id);
984                                 /* Only open messages in outbox with the editor if they are in Failed state */
985                                 if (status == MODEST_TNY_SEND_QUEUE_FAILED) {
986                                         *is_draft = TRUE;
987                                 }
988                                 else {
989                                         /* In Fremantle we can not
990                                            open any message from
991                                            outbox which is not in
992                                            failed state */
993                                         *can_open = FALSE;
994                                 }
995                         }
996                         g_object_unref(traccount);
997                 } else {
998                         g_warning("Cannot get transport account for message in outbox!!");
999                 }
1000         } else if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
1001                 *is_draft = TRUE; /* Open in editor if the message is in the Drafts folder */
1002         }
1003
1004         if (!account) {
1005                 TnyAccount *acc = tny_folder_get_account (folder);
1006                 if (acc) {
1007                         account =
1008                                 g_strdup (modest_tny_account_get_parent_modest_account_name_for_server_account (acc));
1009                         g_object_unref (acc);
1010                 }
1011         }
1012
1013         g_object_unref (folder);
1014
1015         return account;
1016 }
1017
1018 static void
1019 open_msg_cb (ModestMailOperation *mail_op,
1020              TnyHeader *header,
1021              gboolean canceled,
1022              TnyMsg *msg,
1023              GError *err,
1024              gpointer user_data)
1025 {
1026         ModestWindowMgr *mgr = NULL;
1027         ModestWindow *parent_win = NULL;
1028         ModestWindow *win = NULL;
1029         gchar *account = NULL;
1030         gboolean open_in_editor = FALSE;
1031         gboolean can_open;
1032         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1033
1034         /* Do nothing if there was any problem with the mail
1035            operation. The error will be shown by the error_handler of
1036            the mail operation */
1037         if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1038                 return;
1039
1040         parent_win = (ModestWindow *) modest_mail_operation_get_source (mail_op);
1041
1042         /* Mark header as read */
1043         headers_action_mark_as_read (header, MODEST_WINDOW(parent_win), NULL);
1044
1045         account = get_info_from_header (header, &open_in_editor, &can_open);
1046
1047         /* Get account */
1048         if (!account)
1049                 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_win)));
1050         if (!account)
1051                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1052
1053         if (open_in_editor) {
1054                 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
1055                 gchar *from_header = NULL, *acc_name;
1056                 gchar *mailbox = NULL;
1057
1058                 from_header = tny_header_dup_from (header);
1059
1060                 /* we cannot edit without a valid account... */
1061                 if (!modest_account_mgr_has_accounts(mgr, TRUE)) {
1062                         if (!modest_ui_actions_run_account_setup_wizard(parent_win)) {
1063                                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1064                                                                      header);
1065                                 g_free (from_header);
1066                                 goto cleanup;
1067                         }
1068                 }
1069
1070                 acc_name = modest_utils_get_account_name_from_recipient (from_header, &mailbox);
1071                 g_free (from_header);
1072                 if (acc_name) {
1073                         g_free (account);
1074                         account = acc_name;
1075                 }
1076
1077                 win = modest_msg_edit_window_new (msg, account, mailbox, TRUE);
1078                 if (mailbox)
1079                         g_free (mailbox);
1080         } else {
1081                 gchar *uid = modest_tny_folder_get_header_unique_id (header);
1082                 const gchar *mailbox = NULL;
1083
1084                 if (parent_win && MODEST_IS_WINDOW (parent_win))
1085                         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (parent_win));
1086
1087                 if (helper->rowref && helper->model) {
1088                         win = modest_msg_view_window_new_with_header_model (msg, account, mailbox, (const gchar*) uid,
1089                                                                             helper->model, helper->rowref);
1090                 } else {
1091                         win = modest_msg_view_window_new_for_attachment (msg, NULL, account, mailbox, (const gchar*) uid);
1092                 }
1093                 g_free (uid);
1094         }
1095
1096         /* Register and show new window */
1097         if (win != NULL) {
1098                 mgr = modest_runtime_get_window_mgr ();
1099                 if (!modest_window_mgr_register_window (mgr, win, NULL)) {
1100                         gtk_widget_destroy (GTK_WIDGET (win));
1101                         goto cleanup;
1102                 }
1103                 gtk_widget_show_all (GTK_WIDGET(win));
1104         }
1105
1106
1107 cleanup:
1108         /* Free */
1109         g_free(account);
1110         g_object_unref (parent_win);
1111 }
1112
1113 void
1114 modest_ui_actions_disk_operations_error_handler (ModestMailOperation *mail_op,
1115                                                  gpointer user_data)
1116 {
1117         const GError *error;
1118         GObject *win = NULL;
1119         ModestMailOperationStatus status;
1120
1121         win = modest_mail_operation_get_source (mail_op);
1122         error = modest_mail_operation_get_error (mail_op);
1123         status = modest_mail_operation_get_status (mail_op);
1124
1125         /* If the mail op has been cancelled then it's not an error:
1126            don't show any message */
1127         if (status != MODEST_MAIL_OPERATION_STATUS_CANCELED) {
1128                 TnyAccount *account = modest_mail_operation_get_account (mail_op);
1129                 if (modest_tny_account_store_is_disk_full_error (modest_runtime_get_account_store(),
1130                                                                  (GError *) error, account)) {
1131                         gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
1132                         modest_platform_information_banner ((GtkWidget *) win, NULL, msg);
1133                         g_free (msg);
1134                 } else if (error->code == TNY_SYSTEM_ERROR_MEMORY) {
1135                         modest_platform_information_banner ((GtkWidget *) win,
1136                                                             NULL, _("emev_ui_imap_inbox_select_error"));
1137                 } else if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
1138                            error->code == MODEST_MAIL_OPERATION_ERROR_FILE_IO) {
1139                         modest_platform_information_banner ((GtkWidget *) win,
1140                                                             NULL, _CS_UNABLE_TO_OPEN_FILE_NOT_FOUND);
1141                 } else if (user_data) {
1142                         modest_platform_information_banner ((GtkWidget *) win,
1143                                                             NULL, user_data);
1144                 }
1145                 if (account)
1146                         g_object_unref (account);
1147         }
1148
1149         if (win)
1150                 g_object_unref (win);
1151 }
1152
1153 /**
1154  * Returns the account a list of headers belongs to. It returns a
1155  * *new* reference so don't forget to unref it
1156  */
1157 static TnyAccount*
1158 get_account_from_header_list (TnyList *headers)
1159 {
1160         TnyAccount *account = NULL;
1161
1162         if (tny_list_get_length (headers) > 0) {
1163                 TnyIterator *iter = tny_list_create_iterator (headers);
1164                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1165                 TnyFolder *folder = tny_header_get_folder (header);
1166
1167                 if (!folder) {
1168                         g_object_unref (header);
1169
1170                         while (!tny_iterator_is_done (iter)) {
1171                                 header = TNY_HEADER (tny_iterator_get_current (iter));
1172                                 folder = tny_header_get_folder (header);
1173                                 if (folder)
1174                                         break;
1175                                 g_object_unref (header);
1176                                 header = NULL;
1177                                 tny_iterator_next (iter);
1178                         }
1179                 }
1180
1181                 if (folder) {
1182                         account = tny_folder_get_account (folder);
1183                         g_object_unref (folder);
1184                 }
1185
1186                 if (header)
1187                         g_object_unref (header);
1188
1189                 g_object_unref (iter);
1190         }
1191         return account;
1192 }
1193
1194 static TnyAccount*
1195 get_account_from_header (TnyHeader *header)
1196 {
1197         TnyAccount *account = NULL;
1198         TnyFolder *folder;
1199
1200         folder = tny_header_get_folder (header);
1201
1202         if (folder) {
1203                 account = tny_folder_get_account (folder);
1204                 g_object_unref (folder);
1205         }
1206         return account;
1207 }
1208
1209 static void
1210 caller_win_destroyed (OpenMsgHelper *helper, GObject *object)
1211 {
1212         if (helper->caller_window)
1213                 helper->caller_window = NULL;
1214 }
1215
1216 static void
1217 open_msg_helper_destroyer (gpointer user_data)
1218 {
1219         OpenMsgHelper *helper = (OpenMsgHelper *) user_data;
1220
1221         if (helper->caller_window) {
1222                 g_object_weak_unref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1223                 helper->caller_window = NULL;
1224         }
1225
1226         if (helper->banner_info) {
1227                 g_free (helper->banner_info->message);
1228                 if (helper->banner_info->idle_handler > 0) {
1229                         g_source_remove (helper->banner_info->idle_handler);
1230                         helper->banner_info->idle_handler = 0;
1231                 }
1232                 if (helper->banner_info->banner != NULL) {
1233                         gtk_widget_destroy (helper->banner_info->banner);
1234                         g_object_unref (helper->banner_info->banner);
1235                         helper->banner_info->banner = NULL;
1236                 }
1237                 g_slice_free (OpenMsgBannerInfo, helper->banner_info);
1238                 helper->banner_info = NULL;
1239         }
1240         g_object_unref (helper->model);
1241         g_object_unref (helper->header);
1242         gtk_tree_row_reference_free (helper->rowref);
1243         g_slice_free (OpenMsgHelper, helper);
1244 }
1245
1246 static void
1247 open_msg_performer(gboolean canceled,
1248                     GError *err,
1249                     ModestWindow *parent_window,
1250                     TnyAccount *account,
1251                     gpointer user_data)
1252 {
1253         ModestMailOperation *mail_op = NULL;
1254         gchar *error_msg = NULL;
1255         ModestProtocolType proto;
1256         TnyConnectionStatus status;
1257         OpenMsgHelper *helper = NULL;
1258         ModestProtocol *protocol;
1259         ModestProtocolRegistry *protocol_registry;
1260         gchar *subject;
1261
1262         helper = (OpenMsgHelper *) user_data;
1263
1264         status = tny_account_get_connection_status (account);
1265         if (err || canceled || helper->caller_window == NULL) {
1266                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1267                 /* Free the helper */
1268                 open_msg_helper_destroyer (helper);
1269
1270                 /* In disk full conditions we could get this error here */
1271                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
1272                                                                 (GtkWidget *) parent_window, err,
1273                                                                 account, NULL);
1274
1275                 goto clean;
1276         }
1277
1278         /* Get the error message depending on the protocol */
1279         proto = modest_tny_account_get_protocol_type (account);
1280         if (proto == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
1281                 proto = MODEST_PROTOCOLS_STORE_MAILDIR;
1282         }
1283
1284         protocol_registry = modest_runtime_get_protocol_registry ();
1285         subject = tny_header_dup_subject (helper->header);
1286
1287         protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, proto);
1288         error_msg = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_MSG_NOT_AVAILABLE, subject);
1289         if (subject)
1290                 g_free (subject);
1291
1292         if (error_msg == NULL) {
1293                 error_msg = g_strdup (_("mail_ni_ui_folder_get_msg_folder_error"));
1294         }
1295
1296         gboolean is_draft;
1297         gboolean can_open;
1298         gchar *account_name = get_info_from_header (helper->header, &is_draft, &can_open);
1299
1300         if (!g_strcmp0 (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) ||
1301             !g_strcmp0 (account_name, MODEST_MMC_ACCOUNT_ID)) {
1302                 g_free (account_name);
1303                 account_name = g_strdup (modest_window_get_active_account (MODEST_WINDOW (parent_window)));
1304         }
1305
1306         if (!can_open) {
1307                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), helper->header);
1308                 g_free (account_name);
1309                 open_msg_helper_destroyer (helper);
1310                 goto clean;
1311         }
1312
1313         if (!is_draft) {
1314                 ModestWindow *window;
1315                 GtkWidget *header_view;
1316                 gchar *uid;
1317
1318                 header_view = get_header_view_from_window (parent_window);
1319                 uid = modest_tny_folder_get_header_unique_id (helper->header);
1320                 if (header_view) {
1321                         const gchar *mailbox = NULL;
1322                         mailbox = modest_window_get_active_mailbox (parent_window);
1323                         window = modest_msg_view_window_new_from_header_view 
1324                                 (MODEST_HEADER_VIEW (header_view), account_name, mailbox, uid, helper->rowref);
1325                         if (window != NULL) {
1326                                 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
1327                                                                         window, NULL)) {
1328                                         gtk_widget_destroy (GTK_WIDGET (window));
1329                                 } else {
1330                                         gtk_widget_show_all (GTK_WIDGET(window));
1331                                 }
1332                         }
1333                 }
1334                 g_free (account_name);
1335                 g_free (uid);
1336                 open_msg_helper_destroyer (helper);
1337                 goto clean;
1338         }
1339         g_free (account_name);
1340         /* Create the mail operation */
1341         mail_op =
1342                 modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
1343                                                                modest_ui_actions_disk_operations_error_handler,
1344                                                                g_strdup (error_msg), g_free);
1345         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1346                                          mail_op);
1347
1348
1349
1350         TnyList *headers;
1351         headers = TNY_LIST (tny_simple_list_new ());
1352         tny_list_prepend (headers, G_OBJECT (helper->header));
1353         modest_mail_operation_get_msgs_full (mail_op,
1354                                              headers,
1355                                              open_msg_cb,
1356                                              helper,
1357                                              open_msg_helper_destroyer);
1358         g_object_unref (headers);
1359
1360         /* Frees */
1361  clean:
1362         if (error_msg)
1363                 g_free (error_msg);
1364         if (mail_op)
1365                 g_object_unref (mail_op);
1366         g_object_unref (account);
1367 }
1368
1369 /*
1370  * This function is used by both modest_ui_actions_on_open and
1371  * modest_ui_actions_on_header_activated. This way we always do the
1372  * same when trying to open messages.
1373  */
1374 static void
1375 open_msg_from_header (TnyHeader *header, GtkTreeRowReference *rowref, ModestWindow *win)
1376 {
1377         ModestWindowMgr *mgr = NULL;
1378         TnyAccount *account;
1379         gboolean cached = FALSE;
1380         gboolean found;
1381         GtkWidget *header_view = NULL;
1382         OpenMsgHelper *helper;
1383         ModestWindow *window;
1384
1385         g_return_if_fail (header != NULL && rowref != NULL && gtk_tree_row_reference_valid (rowref));
1386
1387         mgr = modest_runtime_get_window_mgr ();
1388
1389         /* get model */
1390         header_view = get_header_view_from_window (MODEST_WINDOW (win));
1391         if (header_view == NULL)
1392                 return;
1393
1394         /* Get the account */
1395         account = get_account_from_header (header);
1396         if (!account)
1397                 return;
1398
1399         window = NULL;
1400         found = modest_window_mgr_find_registered_header (mgr, header, &window);
1401
1402         /* Do not open again the message and present the
1403            window to the user */
1404         if (found) {
1405                 if (window) {
1406 #ifndef MODEST_TOOLKIT_HILDON2
1407                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
1408                         gtk_window_present (toplevel);
1409 #endif
1410                 } else {
1411                         /* the header has been registered already, we don't do
1412                          * anything but wait for the window to come up*/
1413                         g_debug ("header %p already registered, waiting for window", header);
1414                 }
1415                 goto cleanup;
1416         }
1417
1418         /* Open each message */
1419         cached = tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED;
1420         if (!cached) {
1421                 /* Allways download if we are online. */
1422                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1423                         gint response;
1424                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1425
1426                         /* If ask for user permission to download the messages */
1427                         response = modest_platform_run_confirmation_dialog (toplevel,
1428                                                                             _("mcen_nc_get_msg"));
1429
1430                         /* End if the user does not want to continue */
1431                         if (response == GTK_RESPONSE_CANCEL) {
1432                                 goto cleanup;
1433                         }
1434                 }
1435         }
1436
1437         /* We register the window for opening */
1438         modest_window_mgr_register_header (mgr, header, NULL);
1439
1440         /* Create the helper. We need to get a reference to the model
1441            here because it could change while the message is readed
1442            (the user could switch between folders) */
1443         helper = g_slice_new (OpenMsgHelper);
1444         helper->model = g_object_ref (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)));
1445         helper->caller_window = win;
1446         g_object_weak_ref ((GObject *) helper->caller_window, (GWeakNotify) caller_win_destroyed, helper);
1447         helper->header = g_object_ref (header);
1448         helper->rowref = gtk_tree_row_reference_copy (rowref);
1449         helper->banner_info = NULL;
1450
1451         /* Connect to the account and perform */
1452         if (!cached) {
1453                 modest_platform_connect_and_perform (win, TRUE, g_object_ref (account),
1454                                                      open_msg_performer, helper);
1455         } else {
1456                 /* Call directly the performer, do not need to connect */
1457                 open_msg_performer (FALSE, NULL, win,
1458                                     g_object_ref (account), helper);
1459         }
1460 cleanup:
1461         /* Clean */
1462         if (account)
1463                 g_object_unref (account);
1464 }
1465
1466 void
1467 modest_ui_actions_on_open (GtkAction *action, ModestWindow *win)
1468 {
1469         TnyList *headers;
1470         TnyHeader *header;
1471         gint headers_count;
1472         TnyIterator *iter;
1473
1474         /* we check for low-mem; in that case, show a warning, and don't allow
1475          * opening
1476          */
1477         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1478                 return;
1479
1480         /* Get headers */
1481         headers = get_selected_headers (win);
1482         if (!headers)
1483                 return;
1484
1485         headers_count = tny_list_get_length (headers);
1486         if (headers_count != 1) {
1487                 if (headers_count > 1) {
1488                         /* Don't allow activation if there are more than one message selected */
1489                         modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
1490                 }
1491
1492                 g_object_unref (headers);
1493                 return;
1494         }
1495
1496         iter = tny_list_create_iterator (headers);
1497         header = TNY_HEADER (tny_iterator_get_current (iter));
1498         g_object_unref (iter);
1499
1500         /* Open them */
1501         if (header) {
1502                 open_msg_from_header (header, NULL, win);
1503                 g_object_unref (header);
1504         }
1505
1506         g_object_unref(headers);
1507 }
1508
1509 static void
1510 rf_helper_window_closed (gpointer data,
1511                          GObject *object)
1512 {
1513         ReplyForwardHelper *helper = (ReplyForwardHelper *) data;
1514
1515         helper->parent_window = NULL;
1516 }
1517
1518 static ReplyForwardHelper*
1519 create_reply_forward_helper (ReplyForwardAction action,
1520                              ModestWindow *win,
1521                              guint reply_forward_type,
1522                              TnyHeader *header,
1523                              TnyMsg *msg_part,
1524                              TnyHeader *top_header,
1525                              TnyList *parts)
1526 {
1527         ReplyForwardHelper *rf_helper = NULL;
1528         const gchar *active_acc = modest_window_get_active_account (win);
1529         const gchar *active_mailbox = modest_window_get_active_mailbox (win);
1530
1531         rf_helper = g_slice_new0 (ReplyForwardHelper);
1532         rf_helper->reply_forward_type = reply_forward_type;
1533         rf_helper->action = action;
1534         rf_helper->parent_window = (MODEST_IS_WINDOW (win)) ? GTK_WIDGET (win) : NULL;
1535         rf_helper->header = (header) ? g_object_ref (header) : NULL;
1536         rf_helper->top_header = (top_header) ? g_object_ref (top_header) : NULL;
1537         rf_helper->msg_part = (msg_part) ? g_object_ref (msg_part) : NULL;
1538         rf_helper->account_name = (active_acc) ?
1539                 g_strdup (active_acc) :
1540                 modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
1541         rf_helper->mailbox = g_strdup (active_mailbox);
1542         if (parts)
1543                 rf_helper->parts = g_object_ref (parts);
1544         else
1545                 rf_helper->parts = NULL;
1546
1547         /* Note that window could be destroyed just AFTER calling
1548            register_window so we must ensure that this pointer does
1549            not hold invalid references */
1550         if (rf_helper->parent_window)
1551                 g_object_weak_ref (G_OBJECT (rf_helper->parent_window),
1552                                    rf_helper_window_closed, rf_helper);
1553
1554         return rf_helper;
1555 }
1556
1557 static void
1558 free_reply_forward_helper (gpointer data)
1559 {
1560         ReplyForwardHelper *helper;
1561
1562         helper = (ReplyForwardHelper *) data;
1563         g_free (helper->account_name);
1564         g_free (helper->mailbox);
1565         if (helper->header)
1566                 g_object_unref (helper->header);
1567         if (helper->top_header)
1568                 g_object_unref (helper->top_header);
1569         if (helper->msg_part)
1570                 g_object_unref (helper->msg_part);
1571         if (helper->parts)
1572                 g_object_unref (helper->parts);
1573         if (helper->parent_window)
1574                 g_object_weak_unref (G_OBJECT (helper->parent_window),
1575                                      rf_helper_window_closed, helper);
1576         g_slice_free (ReplyForwardHelper, helper);
1577 }
1578
1579 static void
1580 reply_forward_cb (ModestMailOperation *mail_op,
1581                   TnyHeader *header,
1582                   gboolean canceled,
1583                   TnyMsg *msg,
1584                   GError *err,
1585                   gpointer user_data)
1586 {
1587         TnyMsg *new_msg = NULL;
1588         ReplyForwardHelper *rf_helper;
1589         ModestWindow *msg_win = NULL;
1590         ModestEditType edit_type;
1591         gchar *from = NULL;
1592         TnyAccount *account = NULL;
1593         ModestWindowMgr *mgr = NULL;
1594         gchar *signature = NULL, *recipient = NULL;
1595         gboolean use_signature;
1596
1597         /* If there was any error. The mail operation could be NULL,
1598            this means that we already have the message downloaded and
1599            that we didn't do a mail operation to retrieve it */
1600         rf_helper = (ReplyForwardHelper *) user_data;
1601         if (mail_op && !modest_ui_actions_msg_retrieval_check (mail_op, header, msg))
1602                 goto cleanup;
1603
1604         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1605                                                    rf_helper->account_name, rf_helper->mailbox);
1606
1607         recipient = modest_text_utils_get_email_address (from);
1608         signature = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr (),
1609                                                                      recipient,
1610                                                                      &use_signature);
1611         g_free (recipient);
1612
1613         /* Create reply mail */
1614         switch (rf_helper->action) {
1615                 /* Use the msg_header to ensure that we have all the
1616                    information. The summary can lack some data */
1617                 TnyHeader *msg_header;
1618         case ACTION_REPLY:
1619                 msg_header = tny_msg_get_header (rf_helper->msg_part?rf_helper->msg_part:msg);
1620                 new_msg =
1621                         modest_tny_msg_create_reply_msg (rf_helper->msg_part?rf_helper->msg_part:msg, msg_header, from,
1622                                                          (use_signature) ? signature : NULL,
1623                                                          rf_helper->reply_forward_type,
1624                                                          MODEST_TNY_MSG_REPLY_MODE_SENDER);
1625                 g_object_unref (msg_header);
1626                 break;
1627         case ACTION_REPLY_TO_ALL:
1628                 msg_header = tny_msg_get_header (rf_helper->msg_part?rf_helper->msg_part:msg);
1629                 new_msg =
1630                         modest_tny_msg_create_reply_msg (rf_helper->msg_part?rf_helper->msg_part:msg, msg_header, from,
1631                                                          (use_signature) ? signature : NULL,
1632                                                          rf_helper->reply_forward_type,
1633                                                          MODEST_TNY_MSG_REPLY_MODE_ALL);
1634                 edit_type = MODEST_EDIT_TYPE_REPLY;
1635                 g_object_unref (msg_header);
1636                 break;
1637         case ACTION_FORWARD:
1638                 new_msg =
1639                         modest_tny_msg_create_forward_msg (rf_helper->msg_part?rf_helper->msg_part:msg, from, 
1640                                                            (use_signature) ? signature : NULL,
1641                                                            rf_helper->reply_forward_type);
1642                 edit_type = MODEST_EDIT_TYPE_FORWARD;
1643                 break;
1644         default:
1645                 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1646                                                      header);
1647                 g_return_if_reached ();
1648                 return;
1649         }
1650
1651         g_free (from);
1652         g_free (signature);
1653
1654         if (!new_msg) {
1655                 g_warning ("%s: failed to create message\n", __FUNCTION__);
1656                 goto cleanup;
1657         }
1658
1659         account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(),
1660                                                                        rf_helper->account_name,
1661                                                                        TNY_ACCOUNT_TYPE_STORE);
1662         if (!account) {
1663                 g_warning ("%s: failed to get tnyaccount for '%s'\n", __FUNCTION__, rf_helper->account_name);
1664                 goto cleanup;
1665         }
1666
1667         /* Create and register the windows */
1668         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name, rf_helper->mailbox, FALSE);
1669         mgr = modest_runtime_get_window_mgr ();
1670         modest_window_mgr_register_window (mgr, msg_win, (ModestWindow *) rf_helper->parent_window);
1671
1672         /* Note that register_window could have deleted the account */
1673         if (MODEST_IS_WINDOW (rf_helper->parent_window)) {
1674                 gdouble parent_zoom;
1675
1676                 parent_zoom = modest_window_get_zoom (MODEST_WINDOW (rf_helper->parent_window));
1677                 modest_window_set_zoom (msg_win, parent_zoom);
1678         }
1679
1680         /* Show edit window */
1681         gtk_widget_show_all (GTK_WIDGET (msg_win));
1682
1683 cleanup:
1684         /* We always unregister the header because the message is
1685            forwarded or replied so the original one is no longer
1686            opened */
1687         modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (),
1688                                              header);
1689         if (new_msg)
1690                 g_object_unref (G_OBJECT (new_msg));
1691         if (account)
1692                 g_object_unref (G_OBJECT (account));
1693         free_reply_forward_helper (rf_helper);
1694 }
1695
1696 /* Checks a list of headers. If any of them are not currently
1697  * downloaded (CACHED) then returns TRUE else returns FALSE.
1698  */
1699 static gint
1700 header_list_count_uncached_msgs (TnyList *header_list)
1701 {
1702         TnyIterator *iter;
1703         gint uncached_messages = 0;
1704
1705         iter = tny_list_create_iterator (header_list);
1706         while (!tny_iterator_is_done (iter)) {
1707                 TnyHeader *header;
1708
1709                 header = TNY_HEADER (tny_iterator_get_current (iter));
1710                 if (header) {
1711                         if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED))
1712                                 uncached_messages ++;
1713                         g_object_unref (header);
1714                 }
1715
1716                 tny_iterator_next (iter);
1717         }
1718         g_object_unref (iter);
1719
1720         return uncached_messages;
1721 }
1722
1723 /* Returns FALSE if the user does not want to download the
1724  * messages. Returns TRUE if the user allowed the download.
1725  */
1726 static gboolean
1727 connect_to_get_msg (ModestWindow *win,
1728                     gint num_of_uncached_msgs,
1729                     TnyAccount *account)
1730 {
1731         GtkResponseType response;
1732         GtkWindow *toplevel;
1733
1734         /* Allways download if we are online. */
1735         if (tny_device_is_online (modest_runtime_get_device ()))
1736                 return TRUE;
1737
1738         /* If offline, then ask for user permission to download the messages */
1739         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1740         response = modest_platform_run_confirmation_dialog (toplevel,
1741                                                             ngettext("mcen_nc_get_msg",
1742                                                                      "mcen_nc_get_msgs",
1743                                                                      num_of_uncached_msgs));
1744
1745         if (response == GTK_RESPONSE_CANCEL)
1746                 return FALSE;
1747
1748         return modest_platform_connect_and_wait(toplevel, account);
1749 }
1750
1751 static void
1752 reply_forward_performer (gboolean canceled,
1753                          GError *err,
1754                          ModestWindow *parent_window,
1755                          TnyAccount *account,
1756                          gpointer user_data)
1757 {
1758         ReplyForwardHelper *rf_helper = NULL;
1759         ModestMailOperation *mail_op;
1760
1761         rf_helper = (ReplyForwardHelper *) user_data;
1762
1763         if (canceled || err) {
1764                 free_reply_forward_helper (rf_helper);
1765                 return;
1766         }
1767
1768         /* Retrieve the message */
1769         modest_window_mgr_register_header (modest_runtime_get_window_mgr (), rf_helper->header, NULL);
1770         mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT (parent_window),
1771                                                                  modest_ui_actions_disk_operations_error_handler,
1772                                                                  NULL, NULL);
1773         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1774         modest_mail_operation_get_msg_and_parts (mail_op, rf_helper->top_header, rf_helper->parts, TRUE, reply_forward_cb, rf_helper);
1775
1776         /* Frees */
1777         g_object_unref(mail_op);
1778 }
1779
1780 static gboolean
1781 all_parts_retrieved (TnyMimePart *part)
1782 {
1783         if (!TNY_IS_CAMEL_BS_MIME_PART (part)) {
1784                 return TRUE;
1785         } else {
1786                 TnyList *pending_parts;
1787                 TnyIterator *iterator;
1788                 gboolean all_retrieved = TRUE;
1789
1790                 pending_parts = TNY_LIST (tny_simple_list_new ());
1791                 tny_mime_part_get_parts (part, pending_parts);
1792                 iterator = tny_list_create_iterator (pending_parts);
1793                 while (all_retrieved && !tny_iterator_is_done (iterator)) {
1794                         TnyMimePart *child;
1795
1796                         child = TNY_MIME_PART (tny_iterator_get_current (iterator));
1797
1798                         if (tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (child))) {
1799                                 all_retrieved = all_parts_retrieved (TNY_MIME_PART (child));
1800                         } else {
1801                                 all_retrieved = FALSE;
1802                         }
1803
1804                         g_object_unref (child);
1805                         tny_iterator_next (iterator);
1806                 }
1807                 g_object_unref (iterator);
1808                 g_object_unref (pending_parts);
1809                 return all_retrieved;
1810         }
1811 }
1812
1813 static void
1814 forward_pending_parts_helper (TnyMimePart *part, TnyList *list)
1815 {
1816         TnyList *parts;
1817         TnyIterator *iterator;
1818
1819         if (!tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (part))) {
1820                 tny_list_append (list, G_OBJECT (part));
1821         }
1822         parts = TNY_LIST (tny_simple_list_new ());
1823         tny_mime_part_get_parts (part, parts);
1824         for (iterator = tny_list_create_iterator (parts); 
1825              !tny_iterator_is_done (iterator);
1826              tny_iterator_next (iterator)) {
1827                 TnyMimePart *child;
1828
1829                 child = TNY_MIME_PART (tny_iterator_get_current (iterator));
1830                 forward_pending_parts_helper (child, list);
1831                 g_object_unref (child);
1832         }
1833         g_object_unref (iterator);
1834         g_object_unref (parts);
1835 }
1836
1837 static TnyList *
1838 forward_pending_parts (TnyMsg *msg)
1839 {
1840         TnyList *result = TNY_LIST (tny_simple_list_new ());
1841         if (TNY_IS_CAMEL_BS_MIME_PART (msg)) {
1842                 forward_pending_parts_helper (TNY_MIME_PART (msg), result);
1843         }
1844
1845         return result;
1846 }
1847
1848 /*
1849  * Common code for the reply and forward actions
1850  */
1851 static void
1852 reply_forward (ReplyForwardAction action, ModestWindow *win)
1853 {
1854         ReplyForwardHelper *rf_helper = NULL;
1855         guint reply_forward_type;
1856
1857         g_return_if_fail (win && MODEST_IS_WINDOW(win));
1858
1859         /* we check for low-mem; in that case, show a warning, and don't allow
1860          * reply/forward (because it could potentially require a lot of memory */
1861         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
1862                 return;
1863
1864
1865         /* we need an account when editing */
1866         if (!modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE)) {
1867                 if (!modest_ui_actions_run_account_setup_wizard (win))
1868                         return;
1869         }
1870
1871         reply_forward_type =
1872                 modest_conf_get_int (modest_runtime_get_conf (),
1873                                      (action == ACTION_FORWARD) ?
1874                                      MODEST_CONF_FORWARD_TYPE :
1875                                      MODEST_CONF_REPLY_TYPE,
1876                                      NULL);
1877
1878         if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
1879                 TnyMsg *msg = NULL;
1880                 TnyMsg *top_msg = NULL;
1881                 TnyHeader *header = NULL;
1882                 /* Get header and message. Do not free them here, the
1883                    reply_forward_cb must do it */
1884                 msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
1885                 top_msg = modest_msg_view_window_get_top_message (MODEST_MSG_VIEW_WINDOW(win));
1886                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
1887
1888                 if (msg && header && (action != ACTION_FORWARD || all_parts_retrieved (TNY_MIME_PART (msg)))) {
1889                         /* Create helper */
1890                         rf_helper = create_reply_forward_helper (action, win,
1891                                                                  reply_forward_type, header, NULL, NULL, NULL);
1892                         reply_forward_cb (NULL, header, FALSE, msg, NULL, rf_helper);
1893                 } else {
1894                         gboolean do_download = TRUE;
1895
1896                         if (msg && header && action == ACTION_FORWARD) {
1897                                 if (top_msg == NULL)
1898                                         top_msg = g_object_ref (msg);
1899                                 /* Not all parts retrieved. Then we have to retrieve them all before
1900                                  * creating the forward message */
1901                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1902                                         gint response;
1903                                         GtkWindow *toplevel;
1904
1905                                         /* If ask for user permission to download the messages */
1906                                         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1907                                         response = modest_platform_run_confirmation_dialog (toplevel,
1908                                                                                             ngettext("mcen_nc_get_msg",
1909                                                                                                      "mcen_nc_get_msgs",
1910                                                                                                      1));
1911
1912                                         /* End if the user does not want to continue */
1913                                         if (response == GTK_RESPONSE_CANCEL)
1914                                                 do_download = FALSE;
1915                                 }
1916
1917                                 if (do_download) {
1918                                         TnyList *pending_parts;
1919                                         TnyFolder *folder;
1920                                         TnyAccount *account;
1921                                         TnyHeader *top_header;
1922
1923                                         /* Create helper */
1924                                         top_header = tny_msg_get_header (top_msg);
1925                                         pending_parts = forward_pending_parts (top_msg);
1926                                         rf_helper = create_reply_forward_helper (action, win,
1927                                                                                  reply_forward_type, header, msg, top_header, pending_parts);
1928                                         g_object_unref (pending_parts);
1929
1930                                         folder = tny_header_get_folder (top_header);
1931                                         account = tny_folder_get_account (folder);
1932                                         modest_platform_connect_and_perform (win,
1933                                                                              TRUE, account,
1934                                                                              reply_forward_performer,
1935                                                                              rf_helper);
1936                                         if (folder) g_object_unref (folder);
1937                                         g_object_unref (account);
1938                                         if (top_header) g_object_unref (top_header);
1939                                 }
1940
1941                         } else {
1942                                 g_warning("%s: no message or header found in viewer\n", __FUNCTION__);
1943                         }
1944                 }
1945
1946                 if (msg)
1947                         g_object_unref (msg);
1948                 if (top_msg)
1949                         g_object_unref (top_msg);
1950                 if (header)
1951                         g_object_unref (header);
1952         } else {
1953                 TnyHeader *header = NULL;
1954                 TnyIterator *iter;
1955                 gboolean do_retrieve = TRUE;
1956                 TnyList *header_list = NULL;
1957
1958                 header_list = get_selected_headers (win);
1959                 if (!header_list)
1960                         return;
1961                 /* Check that only one message is selected for replying */
1962                 if (tny_list_get_length (header_list) != 1) {
1963                         modest_platform_information_banner ((win) ? GTK_WIDGET (win) : NULL,
1964                                                             NULL, _("mcen_ib_select_one_message"));
1965                         g_object_unref (header_list);
1966                         return;
1967                 }
1968
1969                 /* Only reply/forward to one message */
1970                 iter = tny_list_create_iterator (header_list);
1971                 header = TNY_HEADER (tny_iterator_get_current (iter));
1972                 g_object_unref (iter);
1973
1974                 /* Retrieve messages */
1975                 do_retrieve = (action == ACTION_FORWARD) ||
1976                         (reply_forward_type != MODEST_TNY_MSG_REPLY_TYPE_CITE);
1977
1978                 if (do_retrieve) {
1979                         TnyAccount *account = NULL;
1980                         TnyFolder *folder = NULL;
1981                         gdouble download = TRUE;
1982                         guint uncached_msgs = 0;
1983
1984                         folder = tny_header_get_folder (header);
1985                         if (!folder)
1986                                 goto do_retrieve_frees;
1987                         account = tny_folder_get_account (folder);
1988                         if (!account)
1989                                 goto do_retrieve_frees;
1990
1991                         uncached_msgs = header_list_count_uncached_msgs (header_list);
1992
1993                         if (uncached_msgs > 0) {
1994                                 /* Allways download if we are online. */
1995                                 if (!tny_device_is_online (modest_runtime_get_device ())) {
1996                                         gint response;
1997                                         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
1998
1999                                         /* If ask for user permission to download the messages */
2000                                         response = modest_platform_run_confirmation_dialog (toplevel,
2001                                                                                             ngettext("mcen_nc_get_msg",
2002                                                                                                      "mcen_nc_get_msgs",
2003                                                                                                      uncached_msgs));
2004
2005                                         /* End if the user does not want to continue */
2006                                         if (response == GTK_RESPONSE_CANCEL)
2007                                                 download = FALSE;
2008                                 }
2009                         }
2010
2011                         if (download) {
2012                                 /* Create helper */
2013                                 rf_helper = create_reply_forward_helper (action, win,
2014                                                                          reply_forward_type, header, NULL, NULL, NULL);
2015                                 if (uncached_msgs > 0) {
2016                                         modest_platform_connect_and_perform (win,
2017                                                                              TRUE, account,
2018                                                                              reply_forward_performer,
2019                                                                              rf_helper);
2020                                 } else {
2021                                         reply_forward_performer (FALSE, NULL, win,
2022                                                                  account, rf_helper);
2023                                 }
2024                         }
2025                 do_retrieve_frees:
2026                         if (account)
2027                                 g_object_unref (account);
2028                         if (folder)
2029                                 g_object_unref (folder);
2030                 } else {
2031                         reply_forward_cb (NULL, header, FALSE, NULL, NULL, NULL);
2032                 }
2033                 /* Frees */
2034                 g_object_unref (header_list);
2035                 g_object_unref (header);
2036         }
2037 }
2038
2039 void
2040 modest_ui_actions_reply_calendar (ModestWindow *win, TnyList *header_pairs)
2041 {
2042         modest_ui_actions_reply_calendar_with_subject (win, NULL, header_pairs);
2043 }
2044
2045 void
2046 modest_ui_actions_reply_calendar_with_subject (ModestWindow *win, const gchar *custom_subject, TnyList *header_pairs)
2047 {
2048         gchar *from;
2049         gchar *recipient;
2050         gchar *signature;
2051         gboolean use_signature;
2052         TnyMsg *new_msg;
2053         GtkWidget *msg_win;
2054         const gchar *account_name;
2055         const gchar *mailbox;
2056         TnyHeader *msg_header;
2057         ModestWindowMgr *mgr;
2058         TnyMsg *msg;
2059
2060         g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(win));
2061
2062         /* we check for low-mem; in that case, show a warning, and don't allow
2063          * reply/forward (because it could potentially require a lot of memory */
2064         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2065                 return;
2066
2067         account_name = modest_window_get_active_account (MODEST_WINDOW (win));
2068         mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (win));
2069         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
2070                                                    account_name, mailbox);
2071         recipient = modest_text_utils_get_email_address (from);
2072         signature = modest_account_mgr_get_signature_from_recipient (modest_runtime_get_account_mgr(), 
2073                                                                      recipient, 
2074                                                                      &use_signature);
2075         g_free (recipient);
2076
2077         msg = modest_msg_view_window_get_message(MODEST_MSG_VIEW_WINDOW(win));
2078         g_return_if_fail(msg);
2079
2080         msg_header = tny_msg_get_header (msg);
2081         new_msg =
2082                 modest_tny_msg_create_reply_calendar_msg (msg, msg_header, from,
2083                                                           (use_signature) ? signature : NULL,
2084                                                           header_pairs);
2085         g_object_unref (msg_header);
2086
2087         g_free (from);
2088         g_free (signature);
2089
2090         if (!new_msg) {
2091                 g_warning ("%s: failed to create message\n", __FUNCTION__);
2092                 goto cleanup;
2093         }
2094
2095         if (custom_subject) {
2096                 TnyHeader *new_msg_header;
2097
2098                 new_msg_header = tny_msg_get_header (new_msg);
2099                 tny_header_set_subject (new_msg_header, custom_subject);
2100                 g_object_unref (new_msg_header);
2101         }
2102
2103         msg_win = (GtkWidget *) modest_msg_edit_window_new (new_msg, account_name, mailbox, FALSE);
2104         mgr = modest_runtime_get_window_mgr ();
2105         modest_window_mgr_register_window (mgr, MODEST_WINDOW (msg_win), (ModestWindow *) win);
2106
2107         /* Show edit window */
2108         gtk_widget_show_all (GTK_WIDGET (msg_win));
2109
2110 cleanup:
2111         if (new_msg)
2112                 g_object_unref (G_OBJECT (new_msg));
2113 }
2114
2115 void
2116 modest_ui_actions_on_reply (GtkAction *action, ModestWindow *win)
2117 {
2118         g_return_if_fail (MODEST_IS_WINDOW(win));
2119
2120         reply_forward (ACTION_REPLY, win);
2121 }
2122
2123 void
2124 modest_ui_actions_on_forward (GtkAction *action, ModestWindow *win)
2125 {
2126         g_return_if_fail (MODEST_IS_WINDOW(win));
2127
2128         reply_forward (ACTION_FORWARD, win);
2129 }
2130
2131 void
2132 modest_ui_actions_on_reply_all (GtkAction *action, ModestWindow *win)
2133 {
2134         g_return_if_fail (MODEST_IS_WINDOW(win));
2135
2136         reply_forward (ACTION_REPLY_TO_ALL, win);
2137 }
2138
2139 void
2140 modest_ui_actions_on_next (GtkAction *action,
2141                            ModestWindow *window)
2142 {
2143         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2144                 modest_msg_view_window_select_next_message (
2145                                 MODEST_MSG_VIEW_WINDOW (window));
2146         } else {
2147                 g_return_if_reached ();
2148         }
2149 }
2150
2151 void
2152 modest_ui_actions_on_prev (GtkAction *action,
2153                            ModestWindow *window)
2154 {
2155         g_return_if_fail (MODEST_IS_WINDOW(window));
2156
2157         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2158                 modest_msg_view_window_select_previous_message (MODEST_MSG_VIEW_WINDOW (window));
2159         } else {
2160                 g_return_if_reached ();
2161         }
2162 }
2163
2164 void
2165 modest_ui_actions_on_sort (GtkAction *action,
2166                            ModestWindow *window)
2167 {
2168         GtkWidget *header_view = NULL;
2169
2170         g_return_if_fail (MODEST_IS_WINDOW(window));
2171
2172         if (MODEST_IS_HEADER_WINDOW (window)) {
2173                 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window)));
2174         }
2175
2176         if (!header_view) {
2177                 modest_platform_information_banner (NULL, NULL, _CS_NOTHING_TO_SORT);
2178
2179                 return;
2180         }
2181
2182         /* Show sorting dialog */
2183         modest_utils_run_sort_dialog (MODEST_WINDOW (window), MODEST_SORT_HEADERS);
2184 }
2185
2186 static void
2187 sync_folder_cb (ModestMailOperation *mail_op,
2188                 TnyFolder *folder,
2189                 gpointer user_data)
2190 {
2191         ModestHeaderView *header_view = (ModestHeaderView *) user_data;
2192
2193         if (modest_mail_operation_get_status (mail_op) == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
2194                 ModestWindow *parent = (ModestWindow *) modest_mail_operation_get_source (mail_op);
2195
2196                 /* We must clear first, because otherwise set_folder will ignore */
2197                 /*    the change as the folders are the same */
2198                 modest_header_view_clear (header_view);
2199                 modest_header_view_set_folder (header_view, folder, TRUE, parent, NULL, NULL);
2200
2201                 g_object_unref (parent);
2202         }
2203
2204         g_object_unref (header_view);
2205 }
2206
2207 static gboolean
2208 idle_refresh_folder (gpointer source)
2209 {
2210         ModestHeaderView *header_view = NULL;
2211
2212         /* If the window still exists */
2213         if (!GTK_IS_WIDGET (source) ||
2214             !GTK_WIDGET_VISIBLE (source))
2215                 return FALSE;
2216
2217         /* Refresh the current view */
2218         if (MODEST_IS_HEADER_WINDOW (source))
2219                 header_view = modest_header_window_get_header_view ((ModestHeaderWindow *) source);
2220         if (header_view) {
2221                 TnyFolder *folder = modest_header_view_get_folder (header_view);
2222                 if (folder) {
2223                         /* Sync the folder status */
2224                         ModestMailOperation *mail_op = modest_mail_operation_new (source);
2225                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
2226                         modest_mail_operation_sync_folder (mail_op, folder, FALSE, sync_folder_cb, g_object_ref (header_view));
2227                         g_object_unref (folder);
2228                         g_object_unref (mail_op);
2229                 }
2230         }
2231
2232         return FALSE;
2233 }
2234
2235 static void
2236 update_account_cb (ModestMailOperation *self,
2237                    TnyList *new_headers,
2238                    gpointer user_data)
2239 {
2240         ModestWindow *top;
2241         gboolean show_visual_notifications;
2242
2243         top = modest_window_mgr_get_current_top (modest_runtime_get_window_mgr ());
2244         show_visual_notifications = (top) ? FALSE : TRUE;
2245
2246         /* Notify new messages have been downloaded. If the
2247            send&receive was invoked by the user then do not show any
2248            visual notification, only play a sound and activate the LED
2249            (for the Maemo version) */
2250         if (TNY_IS_LIST(new_headers) && (tny_list_get_length (new_headers)) > 0) {
2251
2252                 /* We only notify about really new messages (not seen) we get */
2253                 TnyList *actually_new_list;
2254                 TnyIterator *iterator;
2255                 actually_new_list = TNY_LIST (tny_simple_list_new ());
2256                 for (iterator = tny_list_create_iterator (new_headers);
2257                      !tny_iterator_is_done (iterator);
2258                      tny_iterator_next (iterator)) {
2259                         TnyHeader *header;
2260                         TnyHeaderFlags flags;
2261                         header = TNY_HEADER (tny_iterator_get_current (iterator));
2262                         flags = tny_header_get_flags (header);
2263
2264                         if (!(flags & TNY_HEADER_FLAG_SEEN)) {
2265                                 /* Messages are ordered from most
2266                                    recent to oldest. But we want to
2267                                    show notifications starting from
2268                                    the oldest message. That's why we
2269                                    reverse the list */
2270                                 tny_list_prepend (actually_new_list, G_OBJECT (header));
2271                         }
2272                         g_object_unref (header);
2273                 }
2274                 g_object_unref (iterator);
2275
2276                 if (tny_list_get_length (actually_new_list) > 0) {
2277                         GList *new_headers_list = NULL;
2278
2279                         new_headers_list = modest_utils_create_notification_list_from_header_list (actually_new_list);
2280
2281                         /* Send notifications */
2282                         if (new_headers_list) {
2283                                 modest_platform_on_new_headers_received (new_headers_list,
2284                                                                          show_visual_notifications);
2285                                 /* Free the list */
2286                                 modest_utils_free_notification_list (new_headers_list);
2287                         }
2288                 }
2289                 g_object_unref (actually_new_list);
2290         }
2291
2292         if (top) {
2293                 /* Refresh the current folder in an idle. We do this
2294                    in order to avoid refresh cancelations if the
2295                    currently viewed folder is the inbox */
2296                 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
2297                                  idle_refresh_folder,
2298                                  g_object_ref (top),
2299                                  g_object_unref);
2300         }
2301 }
2302
2303 typedef struct {
2304         TnyAccount *account;
2305         ModestWindow *win;
2306         gchar *account_name;
2307         gboolean poke_status;
2308         gboolean interactive;
2309         ModestMailOperation *mail_op;
2310 } SendReceiveInfo;
2311
2312 static void
2313 do_send_receive_performer (gboolean canceled,
2314                            GError *err,
2315                            ModestWindow *parent_window,
2316                            TnyAccount *account,
2317                            gpointer user_data)
2318 {
2319         SendReceiveInfo *info;
2320
2321         info = (SendReceiveInfo *) user_data;
2322
2323         if (err || canceled) {
2324                 /* In disk full conditions we could get this error here */
2325                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
2326                                                                 (GtkWidget *) parent_window, err,
2327                                                                 account, NULL);
2328
2329                 if (info->mail_op) {
2330                         modest_mail_operation_queue_remove (modest_runtime_get_mail_operation_queue (),
2331                                                             info->mail_op);
2332                 }
2333                 goto clean;
2334         }
2335
2336
2337         /* Send & receive. */
2338         modest_mail_operation_update_account (info->mail_op, info->account_name,
2339                                               info->poke_status, info->interactive,
2340                                               update_account_cb, info->win);
2341
2342  clean:
2343         /* Frees */
2344         if (info->mail_op)
2345                 g_object_unref (G_OBJECT (info->mail_op));
2346         if (info->account_name)
2347                 g_free (info->account_name);
2348         if (info->win)
2349                 g_object_unref (info->win);
2350         if (info->account)
2351                 g_object_unref (info->account);
2352         g_slice_free (SendReceiveInfo, info);
2353 }
2354
2355 /*
2356  * This function performs the send & receive required actions. The
2357  * window is used to create the mail operation. Typically it should
2358  * always be the main window, but we pass it as argument in order to
2359  * be more flexible.
2360  */
2361 void
2362 modest_ui_actions_do_send_receive (const gchar *account_name,
2363                                    gboolean force_connection,
2364                                    gboolean poke_status,
2365                                    gboolean interactive,
2366                                    ModestWindow *win)
2367 {
2368         gchar *acc_name = NULL;
2369         SendReceiveInfo *info;
2370         ModestTnyAccountStore *acc_store;
2371         TnyAccount *account;
2372
2373         /* If no account name was provided then get the current account, and if
2374            there is no current account then pick the default one: */
2375         if (!account_name) {
2376                 if (win)
2377                         acc_name = g_strdup (modest_window_get_active_account (win));
2378                 if (!acc_name)
2379                         acc_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
2380                 if (!acc_name) {
2381                         modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2382                         return;
2383                 }
2384         } else {
2385                 acc_name = g_strdup (account_name);
2386         }
2387
2388         acc_store = modest_runtime_get_account_store ();
2389         account = modest_tny_account_store_get_server_account (acc_store, acc_name, TNY_ACCOUNT_TYPE_STORE);
2390
2391         if (!account) {
2392                 g_free (acc_name);
2393                 modest_platform_information_banner (NULL, NULL, _("emev_ni_internal_error"));
2394                 return;
2395         }
2396
2397         /* Do not automatically refresh accounts that are flagged as
2398            NO_AUTO_UPDATE. This could be useful for accounts that
2399            handle their own update times */
2400         if (!interactive) {
2401                 ModestProtocolType proto = modest_tny_account_get_protocol_type (account);
2402                 if (proto != MODEST_PROTOCOL_REGISTRY_TYPE_INVALID) {
2403                         const gchar *tag = MODEST_PROTOCOL_REGISTRY_NO_AUTO_UPDATE_PROTOCOLS;
2404                         ModestProtocolRegistry *registry = modest_runtime_get_protocol_registry ();
2405
2406                         if (modest_protocol_registry_protocol_type_has_tag (registry, proto, tag)) {
2407                                 g_debug ("%s no auto update allowed for account %s", __FUNCTION__, account_name);
2408                                 g_object_unref (account);
2409                                 g_free (acc_name);
2410                                 return;
2411                         }
2412                 }
2413         }
2414
2415         /* Create the info for the connect and perform */
2416         info = g_slice_new (SendReceiveInfo);
2417         info->account_name = acc_name;
2418         info->win = (win) ? g_object_ref (win) : NULL;
2419         info->poke_status = poke_status;
2420         info->interactive = interactive;
2421         info->account = account;
2422         /* We need to create the operation here, because otherwise it
2423            could happen that the queue emits the queue-empty signal
2424            while we're trying to connect the account */
2425         info->mail_op = modest_mail_operation_new_with_error_handling ((info->win) ? G_OBJECT (info->win) : NULL,
2426                                                                        modest_ui_actions_disk_operations_error_handler,
2427                                                                        NULL, NULL);
2428         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), info->mail_op);
2429
2430         /* Invoke the connect and perform */
2431         modest_platform_connect_and_perform (win, force_connection, info->account,
2432                                              do_send_receive_performer, info);
2433 }
2434
2435
2436 static void
2437 modest_ui_actions_do_cancel_send (const gchar *account_name,
2438                                   ModestWindow *win)
2439 {
2440         TnyTransportAccount *transport_account;
2441         TnySendQueue *send_queue = NULL;
2442         GError *error = NULL;
2443
2444         /* Get transport account */
2445         transport_account =
2446                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2447                                       (modest_runtime_get_account_store(),
2448                                        account_name,
2449                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2450         if (!transport_account) {
2451                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2452                 goto frees;
2453         }
2454
2455         /* Get send queue*/
2456         send_queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (transport_account, TRUE));
2457         if (!TNY_IS_SEND_QUEUE(send_queue)) {
2458                 g_set_error (&error, MODEST_MAIL_OPERATION_ERROR,
2459                              MODEST_MAIL_OPERATION_ERROR_ITEM_NOT_FOUND,
2460                              "modest: could not find send queue for account\n");
2461         } else {
2462                 /* Cancel the current send */
2463                 tny_account_cancel (TNY_ACCOUNT (transport_account));
2464
2465                 /* Suspend all pending messages */
2466                 tny_send_queue_cancel (send_queue, TNY_SEND_QUEUE_CANCEL_ACTION_SUSPEND, &error);
2467         }
2468
2469  frees:
2470         if (transport_account != NULL)
2471                 g_object_unref (G_OBJECT (transport_account));
2472 }
2473
2474 static void
2475 modest_ui_actions_cancel_send_all (ModestWindow *win)
2476 {
2477         GSList *account_names, *iter;
2478
2479         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2480                                                           TRUE);
2481
2482         iter = account_names;
2483         while (iter) {
2484                 modest_ui_actions_do_cancel_send ((const char*) iter->data, win);
2485                 iter = g_slist_next (iter);
2486         }
2487
2488         modest_account_mgr_free_account_names (account_names);
2489         account_names = NULL;
2490 }
2491
2492 void
2493 modest_ui_actions_cancel_send (GtkAction *action,  ModestWindow *win)
2494
2495 {
2496         /* Check if accounts exist */
2497         gboolean accounts_exist =
2498                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2499
2500         /* If not, allow the user to create an account before trying to send/receive. */
2501         if (!accounts_exist)
2502                 modest_ui_actions_on_accounts (NULL, win);
2503
2504         /* Cancel all sending operaitons */
2505         modest_ui_actions_cancel_send_all (win);
2506 }
2507
2508 /*
2509  * Refreshes all accounts. This function will be used by automatic
2510  * updates
2511  */
2512 void
2513 modest_ui_actions_do_send_receive_all (ModestWindow *win,
2514                                        gboolean force_connection,
2515                                        gboolean poke_status,
2516                                        gboolean interactive)
2517 {
2518         GSList *account_names, *iter;
2519
2520         account_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(),
2521                                                           TRUE);
2522
2523         iter = account_names;
2524         while (iter) {
2525                 modest_ui_actions_do_send_receive ((const char*) iter->data,
2526                                                    force_connection,
2527                                                    poke_status, interactive, win);
2528                 iter = g_slist_next (iter);
2529         }
2530
2531         modest_account_mgr_free_account_names (account_names);
2532         account_names = NULL;
2533 }
2534
2535 /*
2536  * Handler of the click on Send&Receive button in the main toolbar
2537  */
2538 void
2539 modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win)
2540 {
2541         /* Check if accounts exist */
2542         gboolean accounts_exist;
2543
2544         accounts_exist =
2545                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
2546
2547         /* If not, allow the user to create an account before trying to send/receive. */
2548         if (!accounts_exist)
2549                 modest_ui_actions_on_accounts (NULL, win);
2550
2551         /* Refresh the current folder. The if is always TRUE it's just an extra check */
2552         if (MODEST_IS_ACCOUNTS_WINDOW (win)) {
2553                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2554         } else {
2555                 const gchar *active_account;
2556                 active_account = modest_window_get_active_account (MODEST_WINDOW (win));
2557
2558                 modest_ui_actions_do_send_receive (active_account, TRUE, TRUE, TRUE, win);
2559         }
2560
2561 }
2562
2563
2564 void
2565 modest_ui_actions_on_header_activated (ModestHeaderView *header_view,
2566                                        TnyHeader *header,
2567                                        GtkTreePath *path,
2568                                        ModestWindow *window)
2569 {
2570         GtkTreeRowReference *rowref;
2571
2572         g_return_if_fail (MODEST_IS_WINDOW(window));
2573         g_return_if_fail (MODEST_IS_HEADER_VIEW (header_view));
2574         g_return_if_fail (TNY_IS_HEADER (header));
2575
2576         if (modest_header_view_count_selected_headers (header_view) > 1) {
2577                 /* Don't allow activation if there are more than one message selected */
2578                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_select_one_message"));
2579                 return;
2580         }
2581
2582         /* we check for low-mem; in that case, show a warning, and don't allow
2583          * activating headers
2584          */
2585         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2586                 return;
2587
2588
2589         rowref = gtk_tree_row_reference_new (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)), path);
2590         open_msg_from_header (header, rowref, MODEST_WINDOW (window));
2591         gtk_tree_row_reference_free (rowref);
2592 }
2593
2594 void
2595 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
2596                                      ModestWindow *win)
2597 {
2598         GtkWidget *dialog;
2599         gchar *txt, *item;
2600         gboolean online;
2601         GtkWindow *toplevel;
2602
2603         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) win);
2604         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
2605
2606         online = tny_device_is_online (modest_runtime_get_device());
2607
2608         if (online) {
2609                 /* already online -- the item is simply not there... */
2610                 dialog = gtk_message_dialog_new (toplevel,
2611                                                  GTK_DIALOG_MODAL,
2612                                                  GTK_MESSAGE_WARNING,
2613                                                  GTK_BUTTONS_NONE,
2614                                                  _("The %s you selected cannot be found"),
2615                                                  item);
2616                 gtk_dialog_add_button (GTK_DIALOG (dialog),_("mcen_bd_dialog_ok"), GTK_RESPONSE_ACCEPT);
2617                 gtk_dialog_run (GTK_DIALOG(dialog));
2618         } else {
2619                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
2620                                                       toplevel,
2621                                                       GTK_DIALOG_MODAL,
2622                                                       _("mcen_bd_dialog_cancel"),
2623                                                       GTK_RESPONSE_REJECT,
2624                                                       _("mcen_bd_dialog_ok"),
2625                                                       GTK_RESPONSE_ACCEPT,
2626                                                       NULL);
2627                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
2628                                          "Do you want to get online?"), item);
2629                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
2630                                     gtk_label_new (txt), FALSE, FALSE, 0);
2631                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
2632                 g_free (txt);
2633
2634                 gtk_window_set_default_size ((GtkWindow *) dialog, 300, 300);
2635                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
2636                         /* TODO: Comment about why is this commented out: */
2637                         /* modest_platform_connect_and_wait (); */
2638                 }
2639         }
2640         gtk_widget_destroy (dialog);
2641 }
2642
2643 void
2644 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
2645                                      ModestWindow *win)
2646 {
2647         /* g_debug ("%s %s", __FUNCTION__, link); */
2648 }
2649
2650
2651 void
2652 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
2653                                         ModestWindow *win)
2654 {
2655         modest_platform_activate_uri (link);
2656 }
2657
2658 void
2659 modest_ui_actions_on_msg_link_contextual (ModestMsgView *msgview, const gchar* link,
2660                                           ModestWindow *win)
2661 {
2662         modest_platform_show_uri_popup (link);
2663 }
2664
2665 void
2666 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part,
2667                                              ModestWindow *win)
2668 {
2669         /* we check for low-mem; in that case, show a warning, and don't allow
2670          * viewing attachments
2671          */
2672         if (modest_platform_check_memory_low (MODEST_WINDOW(win), TRUE))
2673                 return;
2674
2675         modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (win), mime_part);
2676 }
2677
2678 void
2679 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
2680                                           const gchar *address,
2681                                           ModestWindow *win)
2682 {
2683         /* g_debug ("%s %s", __FUNCTION__, address); */
2684 }
2685
2686 static void
2687 on_save_to_drafts_cb (ModestMailOperation *mail_op,
2688                       TnyMsg *saved_draft,
2689                       gpointer user_data)
2690 {
2691         ModestMsgEditWindow *edit_window;
2692
2693         /* TODO: in hildon 2 we have to dim and undim the header views while we're saving */
2694
2695         edit_window = MODEST_MSG_EDIT_WINDOW (user_data);
2696
2697         /* Set draft is there was no error */
2698         if (!modest_mail_operation_get_error (mail_op))
2699                 modest_msg_edit_window_set_draft (edit_window, saved_draft);
2700
2701         g_object_unref(edit_window);
2702 }
2703
2704 static gboolean
2705 enough_space_for_message (ModestMsgEditWindow *edit_window,
2706                           MsgData *data)
2707 {
2708         guint64 available_disk, expected_size;
2709         gint parts_count;
2710         guint64 parts_size;
2711
2712         /* Check size */
2713         available_disk = modest_utils_get_available_space (NULL);
2714         modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
2715         expected_size = modest_tny_msg_estimate_size (data->plain_body,
2716                                                       data->html_body,
2717                                                       parts_count,
2718                                                       parts_size);
2719
2720         /* Double check: disk full condition or message too big */
2721         if (available_disk < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE ||
2722             expected_size > available_disk) {
2723                 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2724                 modest_platform_information_banner (NULL, NULL, msg);
2725                 g_free (msg);
2726
2727                 return FALSE;
2728         }
2729
2730         /*
2731          * djcb: if we're in low-memory state, we only allow for
2732          * saving messages smaller than
2733          * MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE (see modest-defs.h) this
2734          * should still allow for sending anything critical...
2735          */
2736         if ((expected_size > MODEST_MAX_LOW_MEMORY_MESSAGE_SIZE) &&
2737             modest_platform_check_memory_low (MODEST_WINDOW(edit_window), TRUE))
2738                 return FALSE;
2739
2740         /*
2741          * djcb: we also make sure that the attachments are smaller than the max size
2742          * this is for the case where we'd try to forward a message with attachments
2743          * bigger than our max allowed size, or sending an message from drafts which
2744          * somehow got past our checks when attaching.
2745          */
2746         if (expected_size > MODEST_MAX_ATTACHMENT_SIZE) {
2747                 GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) edit_window);
2748                 modest_platform_run_information_dialog (toplevel,
2749                                                         _("mail_ib_error_attachment_size"),
2750                                                         TRUE);
2751                 return FALSE;
2752         }
2753
2754         return TRUE;
2755 }
2756
2757 gboolean
2758 modest_ui_actions_on_save_to_drafts (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2759 {
2760         TnyTransportAccount *transport_account;
2761         ModestMailOperation *mail_operation;
2762         MsgData *data;
2763         gchar *account_name;
2764         ModestAccountMgr *account_mgr;
2765         gboolean had_error = FALSE;
2766
2767         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), FALSE);
2768
2769         data = modest_msg_edit_window_get_msg_data (edit_window);
2770
2771         /* Check size */
2772         if (!enough_space_for_message (edit_window, data)) {
2773                 modest_msg_edit_window_free_msg_data (edit_window, data);
2774                 return FALSE;
2775         }
2776
2777         account_name = g_strdup (data->account_name);
2778         account_mgr = modest_runtime_get_account_mgr();
2779         if (!account_name)
2780                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2781         if (!account_name)
2782                 account_name = modest_account_mgr_get_default_account (account_mgr);
2783         if (!account_name) {
2784                 g_printerr ("modest: no account found\n");
2785                 modest_msg_edit_window_free_msg_data (edit_window, data);
2786                 return FALSE;
2787         }
2788
2789         if (!strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
2790                 account_name = g_strdup (data->account_name);
2791         }
2792
2793         transport_account =
2794                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2795                                       (modest_runtime_get_account_store (),
2796                                        account_name,
2797                                        TNY_ACCOUNT_TYPE_TRANSPORT));
2798         if (!transport_account) {
2799                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
2800                 g_free (account_name);
2801                 modest_msg_edit_window_free_msg_data (edit_window, data);
2802                 return FALSE;
2803         }
2804
2805         /* Create the mail operation */
2806         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler,
2807                                                                         NULL, NULL);
2808         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
2809
2810         modest_mail_operation_save_to_drafts (mail_operation,
2811                                               transport_account,
2812                                               data->draft_msg,
2813                                               data->from,
2814                                               data->to, 
2815                                               data->cc, 
2816                                               data->bcc,
2817                                               data->subject,
2818                                               data->plain_body,
2819                                               data->html_body,
2820                                               data->attachments,
2821                                               data->images,
2822                                               data->priority_flags,
2823                                               data->references,
2824                                               data->in_reply_to,
2825                                               data->custom_header_pairs,
2826                                               on_save_to_drafts_cb,
2827                                               g_object_ref(edit_window));
2828
2829         /* In hildon2 we always show the information banner on saving to drafts.
2830          * It will be a system information banner in this case.
2831          */
2832         gchar *text = g_strdup_printf (_("mail_va_saved_to_drafts"), _("mcen_me_folder_drafts"));
2833         modest_platform_information_banner (NULL, NULL, text);
2834         g_free (text);
2835         modest_msg_edit_window_set_modified (edit_window, FALSE);
2836
2837         /* Frees */
2838         g_free (account_name);
2839         g_object_unref (G_OBJECT (transport_account));
2840         g_object_unref (G_OBJECT (mail_operation));
2841
2842         modest_msg_edit_window_free_msg_data (edit_window, data);
2843
2844
2845         return !had_error;
2846 }
2847
2848 /* For instance, when clicking the Send toolbar button when editing a message: */
2849 gboolean
2850 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
2851 {
2852         TnyTransportAccount *transport_account = NULL;
2853         gboolean result = TRUE, add_to_contacts;
2854         MsgData *data;
2855         ModestAccountMgr *account_mgr;
2856         gchar *account_name;
2857         gchar *recipients;
2858
2859         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window), TRUE);
2860
2861         /* Check whether to automatically add new contacts to addressbook or not */
2862         add_to_contacts = modest_conf_get_bool (modest_runtime_get_conf (),
2863                                                 MODEST_CONF_AUTO_ADD_TO_CONTACTS, NULL);
2864         if (!modest_msg_edit_window_check_names (edit_window, add_to_contacts))
2865                 return TRUE;
2866
2867         data = modest_msg_edit_window_get_msg_data (edit_window);
2868
2869         recipients = g_strconcat (data->to?data->to:"", 
2870                                   data->cc?data->cc:"",
2871                                   data->bcc?data->bcc:"",
2872                                   NULL);
2873         if (recipients == NULL || recipients[0] == '\0') {
2874                 /* Empty subject -> no send */
2875                 g_free (recipients);
2876                 modest_msg_edit_window_free_msg_data (edit_window, data);
2877                 return FALSE;
2878         }
2879         g_free (recipients);
2880
2881         /* Check size */
2882         if (!enough_space_for_message (edit_window, data)) {
2883                 modest_msg_edit_window_free_msg_data (edit_window, data);
2884                 return FALSE;
2885         }
2886
2887         account_mgr = modest_runtime_get_account_mgr();
2888         account_name = g_strdup (data->account_name);
2889         if (!account_name)
2890                 account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
2891
2892         if (!account_name)
2893                 account_name = modest_account_mgr_get_default_account (account_mgr);
2894
2895         if (!account_name) {
2896                 modest_msg_edit_window_free_msg_data (edit_window, data);
2897                 /* Run account setup wizard */
2898                 if (!modest_ui_actions_run_account_setup_wizard (MODEST_WINDOW(edit_window))) {
2899                         return TRUE;
2900                 }
2901         }
2902
2903         /* Get the currently-active transport account for this modest account: */
2904         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
2905                 transport_account =
2906                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2907                                               (modest_runtime_get_account_store (),
2908                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2909         }
2910
2911         if (!transport_account) {
2912                 modest_msg_edit_window_free_msg_data (edit_window, data);
2913                 /* Run account setup wizard */
2914                 if (!modest_ui_actions_run_account_setup_wizard(MODEST_WINDOW(edit_window)))
2915                         return TRUE;
2916         }
2917
2918         result = modest_ui_actions_send_msg_with_transport (transport_account,
2919                                                             data->draft_msg,
2920                                                             data->from,
2921                                                             data->to,
2922                                                             data->cc,
2923                                                             data->bcc,
2924                                                             data->subject,
2925                                                             data->plain_body,
2926                                                             data->html_body,
2927                                                             data->attachments,
2928                                                             data->images,
2929                                                             data->references,
2930                                                             data->in_reply_to,
2931                                                             data->priority_flags,
2932                                                             data->custom_header_pairs);
2933
2934
2935         /* Free data: */
2936         g_free (account_name);
2937         g_object_unref (G_OBJECT (transport_account));
2938
2939         modest_msg_edit_window_free_msg_data (edit_window, data);
2940
2941         if (result) {
2942                 modest_msg_edit_window_set_sent (edit_window, TRUE);
2943
2944                 /* Save settings and close the window: */
2945                 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (edit_window));
2946         }
2947
2948         return result;
2949 }
2950
2951 /* For instance, when clicking the Send toolbar button when editing a message: */
2952 gboolean
2953 modest_ui_actions_on_send_custom_msg (const gchar *account_name, 
2954                                       const gchar *from, const gchar *to, const gchar *cc, const gchar *bcc,
2955                                       const gchar *subject,
2956                                       const gchar *plain_body, const gchar *html_body,
2957                                       const GList *attachments_list, const GList *images_list,
2958                                       const gchar *references, const gchar *in_reply_to,
2959                                       TnyHeaderFlags priority_flags, TnyList *header_pairs)
2960 {
2961         TnyTransportAccount *transport_account = NULL;
2962         gboolean result = FALSE;
2963
2964         g_return_val_if_fail (account_name, FALSE);
2965
2966         transport_account =
2967           TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
2968                                 (modest_runtime_get_account_store (),
2969                                  account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
2970
2971         g_return_val_if_fail (transport_account, FALSE);
2972
2973         result = modest_ui_actions_send_msg_with_transport (transport_account,
2974                                                             NULL /*draft msg*/,
2975                                                             from, to, cc, bcc,
2976                                                             subject,
2977                                                             plain_body, html_body,
2978                                                             attachments_list, images_list,
2979                                                             references, in_reply_to,
2980                                                             priority_flags, header_pairs);
2981
2982         /* Free data: */
2983         g_object_unref (G_OBJECT (transport_account));
2984
2985         return result;
2986 }
2987
2988 gboolean
2989 modest_ui_actions_send_msg_with_transport (TnyTransportAccount *transport_account, 
2990                                            TnyMsg *draft_msg,
2991                                            const gchar *from, const gchar *to, const gchar *cc, const gchar *bcc,
2992                                            const gchar *subject,
2993                                            const gchar *plain_body, const gchar *html_body,
2994                                            const GList *attachments_list, const GList *images_list,
2995                                            const gchar *references, const gchar *in_reply_to,
2996                                            TnyHeaderFlags priority_flags, TnyList *header_pairs)
2997 {
2998         gboolean had_error = FALSE;
2999         ModestMailOperation *mail_operation;
3000
3001         g_return_val_if_fail (transport_account, FALSE);
3002
3003         /* Create the mail operation */
3004         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
3005         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
3006
3007         modest_mail_operation_send_new_mail (mail_operation,
3008                                              transport_account,
3009                                              draft_msg,
3010                                              from,
3011                                              to,
3012                                              cc,
3013                                              bcc,
3014                                              subject,
3015                                              plain_body,
3016                                              html_body,
3017                                              attachments_list,
3018                                              images_list,
3019                                              references,
3020                                              in_reply_to,
3021                                              priority_flags,
3022                                              header_pairs);
3023
3024         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3025                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
3026
3027         if (modest_mail_operation_get_error (mail_operation) != NULL) {
3028                 const GError *error = modest_mail_operation_get_error (mail_operation);
3029                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3030                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
3031                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
3032                         modest_platform_information_banner (NULL, NULL, _CS_NOT_ENOUGH_MEMORY);
3033                         had_error = TRUE;
3034                 }
3035         }
3036
3037         /* Free data: */
3038         g_object_unref (G_OBJECT (mail_operation));
3039
3040         return !had_error;
3041 }
3042
3043 gboolean
3044 modest_ui_actions_on_send_msg (ModestWindow *window,
3045                                TnyMsg *msg)
3046 {
3047         TnyTransportAccount *transport_account = NULL;
3048         gboolean had_error = FALSE;
3049         ModestAccountMgr *account_mgr;
3050         gchar *account_name;
3051         ModestMailOperation *mail_operation;
3052
3053         account_mgr = modest_runtime_get_account_mgr();
3054         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(window)));
3055
3056         if (!account_name)
3057                 account_name = modest_account_mgr_get_default_account (account_mgr);
3058
3059         /* Get the currently-active transport account for this modest account: */
3060         if (account_name && strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) != 0) {
3061                 transport_account =
3062                         TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
3063                                               (modest_runtime_get_account_store (),
3064                                                account_name, TNY_ACCOUNT_TYPE_TRANSPORT));
3065         }
3066
3067         /* Create the mail operation */
3068         mail_operation = modest_mail_operation_new_with_error_handling (NULL, modest_ui_actions_disk_operations_error_handler, NULL, NULL);
3069         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_operation);
3070
3071         modest_mail_operation_send_mail (mail_operation,
3072                                          transport_account,
3073                                          msg);
3074
3075         if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS)
3076                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_outbox_waiting_to_be_sent"));
3077
3078         if (modest_mail_operation_get_error (mail_operation) != NULL) {
3079                 const GError *error = modest_mail_operation_get_error (mail_operation);
3080                 if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3081                     error->code == MODEST_MAIL_OPERATION_ERROR_INSTANCE_CREATION_FAILED) {
3082                         g_warning ("%s failed: %s\n", __FUNCTION__, (modest_mail_operation_get_error (mail_operation))->message);
3083                         modest_platform_information_banner (NULL, NULL, _CS("sfil_ni_not_enough_memory"));
3084                         had_error = TRUE;
3085                 }
3086         }
3087
3088         /* Free data: */
3089         g_free (account_name);
3090         g_object_unref (G_OBJECT (transport_account));
3091         g_object_unref (G_OBJECT (mail_operation));
3092
3093         return !had_error;
3094 }
3095
3096 void
3097 modest_ui_actions_on_toggle_bold (GtkToggleAction *action,
3098                                   ModestMsgEditWindow *window)
3099 {
3100         ModestMsgEditFormatState *format_state = NULL;
3101
3102         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3103         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3104
3105         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3106                 return;
3107
3108         format_state = modest_msg_edit_window_get_format_state (window);
3109         g_return_if_fail (format_state != NULL);
3110
3111         format_state->bold = gtk_toggle_action_get_active (action);
3112         modest_msg_edit_window_set_format_state (window, format_state);
3113         g_free (format_state);
3114
3115 }
3116
3117 void
3118 modest_ui_actions_on_toggle_italics (GtkToggleAction *action,
3119                                      ModestMsgEditWindow *window)
3120 {
3121         ModestMsgEditFormatState *format_state = NULL;
3122
3123         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3124         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3125
3126         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3127                 return;
3128
3129         format_state = modest_msg_edit_window_get_format_state (window);
3130         g_return_if_fail (format_state != NULL);
3131
3132         format_state->italics = gtk_toggle_action_get_active (action);
3133         modest_msg_edit_window_set_format_state (window, format_state);
3134         g_free (format_state);
3135
3136 }
3137
3138 void
3139 modest_ui_actions_on_toggle_bullets (GtkToggleAction *action,
3140                                      ModestMsgEditWindow *window)
3141 {
3142         ModestMsgEditFormatState *format_state = NULL;
3143
3144         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3145         g_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
3146
3147         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3148                 return;
3149
3150         format_state = modest_msg_edit_window_get_format_state (window);
3151         g_return_if_fail (format_state != NULL);
3152
3153         format_state->bullet = gtk_toggle_action_get_active (action);
3154         modest_msg_edit_window_set_format_state (window, format_state);
3155         g_free (format_state);
3156
3157 }
3158
3159 void
3160 modest_ui_actions_on_change_justify (GtkRadioAction *action,
3161                                      GtkRadioAction *selected,
3162                                      ModestMsgEditWindow *window)
3163 {
3164         ModestMsgEditFormatState *format_state = NULL;
3165         GtkJustification value;
3166
3167         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3168
3169         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3170                 return;
3171
3172         value = gtk_radio_action_get_current_value (selected);
3173
3174         format_state = modest_msg_edit_window_get_format_state (window);
3175         g_return_if_fail (format_state != NULL);
3176
3177         format_state->justification = value;
3178         modest_msg_edit_window_set_format_state (window, format_state);
3179         g_free (format_state);
3180 }
3181
3182 void
3183 modest_ui_actions_on_select_editor_color (GtkAction *action,
3184                                           ModestMsgEditWindow *window)
3185 {
3186         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3187         g_return_if_fail (GTK_IS_ACTION (action));
3188
3189         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3190                 return;
3191
3192         modest_msg_edit_window_select_color (window);
3193 }
3194
3195 void
3196 modest_ui_actions_on_select_editor_background_color (GtkAction *action,
3197                                                      ModestMsgEditWindow *window)
3198 {
3199         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3200         g_return_if_fail (GTK_IS_ACTION (action));
3201
3202         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3203                 return;
3204
3205 }
3206
3207 void
3208 modest_ui_actions_on_insert_image (GObject *object,
3209                                    ModestMsgEditWindow *window)
3210 {
3211         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3212
3213
3214         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3215                 return;
3216
3217         if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT)
3218                 return;
3219
3220         modest_msg_edit_window_insert_image (window);
3221 }
3222
3223 void
3224 modest_ui_actions_on_attach_file (GtkAction *action,
3225                                   ModestMsgEditWindow *window)
3226 {
3227         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3228         g_return_if_fail (GTK_IS_ACTION (action));
3229
3230         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
3231                 return;
3232
3233         modest_msg_edit_window_offer_attach_file (window);
3234 }
3235
3236 void
3237 modest_ui_actions_on_remove_attachments (GtkAction *action,
3238                                          ModestMsgEditWindow *window)
3239 {
3240         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3241
3242         modest_msg_edit_window_remove_attachments (window, NULL);
3243 }
3244
3245 static void
3246 do_create_folder_cb (ModestMailOperation *mail_op,
3247                      TnyFolderStore *parent_folder,
3248                      TnyFolder *new_folder,
3249                      gpointer user_data)
3250 {
3251         gchar *suggested_name = (gchar *) user_data;
3252         GtkWindow *source_win = (GtkWindow *) modest_mail_operation_get_source (mail_op);
3253         const GError *error;
3254
3255         error = modest_mail_operation_get_error (mail_op);
3256         if (error) {
3257                 gboolean disk_full = FALSE;
3258                 TnyAccount *account;
3259                 /* Show an error. If there was some problem writing to
3260                    disk, show it, otherwise show the generic folder
3261                    create error. We do it here and not in an error
3262                    handler because the call to do_create_folder will
3263                    stop the main loop in a gtk_dialog_run and then,
3264                    the message won't be shown until that dialog is
3265                    closed */
3266                 account = modest_mail_operation_get_account (mail_op);
3267                 if (account) {
3268                         disk_full =
3269                                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3270                                                                                 (GtkWidget *) source_win,
3271                                                                                 (GError *) error,
3272                                                                                 account,
3273                                                                                 _("mail_in_ui_folder_create_error_memory"));
3274                         g_object_unref (account);
3275                 }
3276                 if (!disk_full) {
3277                         /* Show an error and try again if there is no
3278                            full memory condition */
3279                         modest_platform_information_banner ((GtkWidget *) source_win, NULL,
3280                                                             _("mail_in_ui_folder_create_error"));
3281                         do_create_folder ((ModestWindow *) source_win,
3282                                           parent_folder, (const gchar *) suggested_name);
3283                 }
3284
3285         } else {
3286                 /* the 'source_win' is either the ModestWindow, or the 'Move to folder'-dialog
3287                  * FIXME: any other? */
3288                 GtkWidget *folder_view;
3289
3290                         folder_view = GTK_WIDGET(g_object_get_data (G_OBJECT (source_win),
3291                                                                     MODEST_MOVE_TO_DIALOG_FOLDER_VIEW));
3292
3293                 /* Select the newly created folder. It could happen
3294                    that the widget is no longer there (i.e. the window
3295                    has been destroyed, so we need to check this */
3296                 if (folder_view)
3297                         modest_folder_view_select_folder (MODEST_FOLDER_VIEW (folder_view),
3298                                                           new_folder, FALSE);
3299                 g_object_unref (new_folder);
3300         }
3301         /* Free. Note that the first time it'll be NULL so noop */
3302         g_free (suggested_name);
3303         g_object_unref (source_win);
3304 }
3305
3306 typedef struct {
3307         gchar *folder_name;
3308         TnyFolderStore *parent;
3309 } CreateFolderConnect;
3310
3311 static void
3312 do_create_folder_performer (gboolean canceled,
3313                             GError *err,
3314                             ModestWindow *parent_window,
3315                             TnyAccount *account,
3316                             gpointer user_data)
3317 {
3318         CreateFolderConnect *helper = (CreateFolderConnect *) user_data;
3319         ModestMailOperation *mail_op;
3320
3321         if (canceled || err) {
3322                 /* In disk full conditions we could get this error here */
3323                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3324                                                                 (GtkWidget *) parent_window, err,
3325                                                                 NULL, _("mail_in_ui_folder_create_error_memory"));
3326
3327                 /* This happens if we have selected the outbox folder
3328                    as the parent */
3329                 if (err && err->code == TNY_SERVICE_ERROR_UNKNOWN &&
3330                     TNY_IS_MERGE_FOLDER (helper->parent)) {
3331                         /* Show an error and retry */
3332                         modest_platform_information_banner ((GtkWidget *) parent_window,
3333                                                             NULL,
3334                                                             _("mail_in_ui_folder_create_error"));
3335
3336                         do_create_folder (parent_window, helper->parent, helper->folder_name);
3337                 }
3338
3339                 goto frees;
3340         }
3341
3342         mail_op  = modest_mail_operation_new ((GObject *) parent_window);
3343         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3344                                          mail_op);
3345         modest_mail_operation_create_folder (mail_op,
3346                                              helper->parent,
3347                                              (const gchar *) helper->folder_name,
3348                                              do_create_folder_cb,
3349                                              g_strdup (helper->folder_name));
3350         g_object_unref (mail_op);
3351
3352  frees:
3353         if (helper->parent)
3354                 g_object_unref (helper->parent);
3355         if (helper->folder_name)
3356                 g_free (helper->folder_name);
3357         g_slice_free (CreateFolderConnect, helper);
3358 }
3359
3360
3361 static void
3362 do_create_folder (ModestWindow *parent_window,
3363                   TnyFolderStore *suggested_parent,
3364                   const gchar *suggested_name)
3365 {
3366         gint result;
3367         gchar *folder_name = NULL;
3368         TnyFolderStore *parent_folder = NULL;
3369         GtkWindow *toplevel;
3370
3371         toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) parent_window);
3372         result = modest_platform_run_new_folder_dialog (toplevel,
3373                                                         suggested_parent,
3374                                                         (gchar *) suggested_name,
3375                                                         &folder_name,
3376                                                         &parent_folder);
3377
3378         if (result == GTK_RESPONSE_ACCEPT && parent_folder) {
3379                 CreateFolderConnect *helper = (CreateFolderConnect *) g_slice_new0 (CreateFolderConnect);
3380                 helper->folder_name = g_strdup (folder_name);
3381                 helper->parent = g_object_ref (parent_folder);
3382
3383                 modest_platform_connect_if_remote_and_perform (parent_window,
3384                                                                TRUE,
3385                                                                parent_folder,
3386                                                                do_create_folder_performer,
3387                                                                helper);
3388         }
3389
3390         if (folder_name)
3391                 g_free (folder_name);
3392         if (parent_folder)
3393                 g_object_unref (parent_folder);
3394 }
3395
3396 static void
3397 modest_ui_actions_create_folder(GtkWindow *parent_window,
3398                                 GtkWidget *folder_view,
3399                                 TnyFolderStore *parent_folder)
3400 {
3401         if (!parent_folder) {
3402                 ModestTnyAccountStore *acc_store;
3403
3404                 acc_store = modest_runtime_get_account_store ();
3405
3406                 parent_folder = (TnyFolderStore *)
3407                         modest_tny_account_store_get_local_folders_account (acc_store);
3408         }
3409
3410         if (parent_folder) {
3411                 do_create_folder (MODEST_WINDOW (parent_window), parent_folder, NULL);
3412                 g_object_unref (parent_folder);
3413         }
3414 }
3415
3416 void
3417 modest_ui_actions_on_new_folder (GtkAction *action, ModestWindow *window)
3418 {
3419
3420         g_return_if_fail (MODEST_IS_WINDOW(window));
3421
3422         if (MODEST_IS_FOLDER_WINDOW (window)) {
3423                 GtkWidget *folder_view;
3424                 GtkWindow *toplevel;
3425
3426                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3427                 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
3428                 modest_ui_actions_create_folder (toplevel, folder_view, NULL);
3429         } else {
3430                 g_assert_not_reached ();
3431         }
3432 }
3433
3434 static void
3435 modest_ui_actions_rename_folder_error_handler (ModestMailOperation *mail_op,
3436                                                gpointer user_data)
3437 {
3438         const GError *error = NULL;
3439         gchar *message = NULL;
3440         gboolean mem_full;
3441         TnyAccount *account = modest_mail_operation_get_account (mail_op);
3442
3443         /* Get error message */
3444         error = modest_mail_operation_get_error (mail_op);
3445         if (!error)
3446                 g_return_if_reached ();
3447
3448         mem_full = modest_tny_account_store_is_disk_full_error (modest_runtime_get_account_store(),
3449                                                                 (GError *) error, account);
3450         if (mem_full) {
3451                 message = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3452         } else if (error->domain == MODEST_MAIL_OPERATION_ERROR &&
3453                    error->code == MODEST_MAIL_OPERATION_ERROR_FOLDER_EXISTS) {
3454                 message = _CS_FOLDER_ALREADY_EXISTS;
3455         } else if (error->domain == TNY_ERROR_DOMAIN &&
3456                    error->code == TNY_SERVICE_ERROR_STATE) {
3457                 /* This means that the folder is already in use (a
3458                    message is opened for example */
3459                 message = _("emev_ni_internal_error");
3460         } else {
3461                 message = _CS_UNABLE_TO_RENAME;
3462         }
3463
3464         /* We don't set a parent for the dialog because the dialog
3465            will be destroyed so the banner won't appear */
3466         modest_platform_information_banner (NULL, NULL, message);
3467
3468         if (account)
3469                 g_object_unref (account);
3470         if (mem_full)
3471                 g_free (message);
3472 }
3473
3474 typedef struct {
3475         TnyFolderStore *folder;
3476         gchar *new_name;
3477 } RenameFolderInfo;
3478
3479 static void
3480 on_rename_folder_cb (ModestMailOperation *mail_op,
3481                      TnyFolder *new_folder,
3482                      gpointer user_data)
3483 {
3484         ModestFolderView *folder_view;
3485
3486         /* If the window was closed when renaming a folder, or if
3487          * it's not a main window this will happen */
3488         if (!MODEST_IS_FOLDER_VIEW (user_data))
3489                 return;
3490
3491         folder_view = MODEST_FOLDER_VIEW (user_data);
3492         /* Note that if the rename fails new_folder will be NULL */
3493         if (new_folder) {
3494                 modest_folder_view_select_folder (folder_view, new_folder, FALSE);
3495         }
3496         gtk_widget_grab_focus (GTK_WIDGET (folder_view));
3497 }
3498
3499 static void
3500 on_rename_folder_performer (gboolean canceled,
3501                             GError *err,
3502                             ModestWindow *parent_window,
3503                             TnyAccount *account,
3504                             gpointer user_data)
3505 {
3506         ModestMailOperation *mail_op = NULL;
3507         GtkTreeSelection *sel = NULL;
3508         GtkWidget *folder_view = NULL;
3509         RenameFolderInfo *data = (RenameFolderInfo*)user_data;
3510
3511         if (canceled || err) {
3512                 /* In disk full conditions we could get this error here */
3513                 modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3514                                                                 (GtkWidget *) parent_window, err,
3515                                                                 account, NULL);
3516         } else {
3517
3518                 mail_op =
3519                         modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3520                                         modest_ui_actions_rename_folder_error_handler,
3521                                         parent_window, NULL);
3522
3523                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3524                                 mail_op);
3525                 if (MODEST_IS_FOLDER_WINDOW (parent_window)) {
3526                         ModestFolderWindow *folder_window = (ModestFolderWindow *) parent_window;
3527                         folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (folder_window));
3528                 }
3529
3530                 /* Clear the folders view */
3531                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3532                 gtk_tree_selection_unselect_all (sel);
3533
3534                 /* Actually rename the folder */
3535                 modest_mail_operation_rename_folder (mail_op,
3536                                                      TNY_FOLDER (data->folder),
3537                                                      (const gchar *) (data->new_name),
3538                                                      on_rename_folder_cb,
3539                                                      folder_view);
3540                 g_object_unref (mail_op);
3541         }
3542
3543         g_object_unref (data->folder);
3544         g_free (data->new_name);
3545         g_free (data);
3546 }
3547
3548 void
3549 modest_ui_actions_on_rename_folder (GtkAction *action,
3550                                      ModestWindow *window)
3551 {
3552         modest_ui_actions_on_edit_mode_rename_folder (window);
3553 }
3554
3555 gboolean
3556 modest_ui_actions_on_edit_mode_rename_folder (ModestWindow *window)
3557 {
3558         TnyFolderStore *folder;
3559         GtkWidget *folder_view;
3560         gboolean do_rename = TRUE;
3561
3562         g_return_val_if_fail (MODEST_IS_WINDOW(window), FALSE);
3563
3564         if (MODEST_IS_FOLDER_WINDOW (window)) {
3565                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3566         } else {
3567                 return FALSE;
3568         }
3569
3570         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
3571
3572         if (!folder)
3573                 return FALSE;
3574
3575         if (TNY_IS_FOLDER (folder)) {
3576                 gchar *folder_name = NULL;
3577                 gint response;
3578                 const gchar *current_name;
3579                 TnyFolderStore *parent;
3580
3581                 current_name = tny_folder_get_name (TNY_FOLDER (folder));
3582                 parent = tny_folder_get_folder_store (TNY_FOLDER (folder));
3583                 response = modest_platform_run_rename_folder_dialog (MODEST_WINDOW (window),
3584                                                                      parent, current_name,
3585                                                                      &folder_name);
3586                 g_object_unref (parent);
3587
3588                 if (response != GTK_RESPONSE_ACCEPT || strlen (folder_name) == 0) {
3589                         do_rename = FALSE;
3590                 } else {
3591                         RenameFolderInfo *rename_folder_data = g_new0 (RenameFolderInfo, 1);
3592                         rename_folder_data->folder = g_object_ref (folder);
3593                         rename_folder_data->new_name = folder_name;
3594                         modest_platform_connect_if_remote_and_perform (window, TRUE,
3595                                         folder, on_rename_folder_performer, rename_folder_data);
3596                 }
3597         }
3598         g_object_unref (folder);
3599         return do_rename;
3600 }
3601
3602 static void
3603 modest_ui_actions_delete_folder_error_handler (ModestMailOperation *mail_op,
3604                                                gpointer user_data)
3605 {
3606         GObject *win = modest_mail_operation_get_source (mail_op);
3607         GtkWindow *toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (win));
3608
3609         modest_platform_run_information_dialog (toplevel,
3610                                                 _("mail_in_ui_folder_delete_error"),
3611                                                 FALSE);
3612         g_object_unref (win);
3613 }
3614
3615 typedef struct {
3616         TnyFolderStore *folder;
3617         gboolean move_to_trash;
3618 } DeleteFolderInfo;
3619
3620 static void
3621 on_delete_folder_cb (gboolean canceled,
3622                      GError *err,
3623                      ModestWindow *parent_window,
3624                      TnyAccount *account,
3625                      gpointer user_data)
3626 {
3627         DeleteFolderInfo *info = (DeleteFolderInfo*) user_data;
3628         GtkWidget *folder_view;
3629         ModestMailOperation *mail_op;
3630         GtkTreeSelection *sel;
3631         ModestWindow *modest_window;
3632
3633 #ifdef MODEST_TOOLKIT_HILDON2
3634         modest_window = (ModestWindow*) parent_window;
3635 #else
3636         if (MODEST_IS_SHELL (parent_window)) {
3637                 modest_window = modest_shell_peek_window (MODEST_SHELL (parent_window));
3638         } else {
3639                 modest_window = NULL;
3640         }
3641 #endif
3642
3643         if (!MODEST_IS_WINDOW(modest_window) || canceled || (err!=NULL)) {
3644                 /* Note that the connection process can fail due to
3645                    memory low conditions as it can not successfully
3646                    store the summary */
3647                 if (!modest_tny_account_store_check_disk_full_error (modest_runtime_get_account_store(),
3648                                                                      (GtkWidget*) parent_window, err,
3649                                                                      account, NULL))
3650                         g_debug ("Error connecting when trying to delete a folder");
3651                 g_object_unref (G_OBJECT (info->folder));
3652                 g_free (info);
3653                 return;
3654         }
3655
3656         if (MODEST_IS_FOLDER_WINDOW (modest_window)) {
3657                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (modest_window)));
3658         } else {
3659                 g_object_unref (G_OBJECT (info->folder));
3660                 g_free (info);
3661                 return;
3662         }
3663
3664         /* Unselect the folder before deleting it to free the headers */
3665         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_view));
3666         gtk_tree_selection_unselect_all (sel);
3667
3668         /* Create the mail operation */
3669         mail_op =
3670                 modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
3671                                 modest_ui_actions_delete_folder_error_handler,
3672                                 NULL, NULL);
3673
3674         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3675                         mail_op);
3676         modest_mail_operation_remove_folder (mail_op, TNY_FOLDER (info->folder), info->move_to_trash);
3677
3678         g_object_unref (mail_op);
3679         g_object_unref (info->folder);
3680         g_free (info);
3681 }
3682
3683 static gboolean
3684 delete_folder (ModestWindow *window, gboolean move_to_trash)
3685 {
3686         TnyFolderStore *folder;
3687         GtkWidget *folder_view;
3688         gint response;
3689         gchar *message;
3690
3691         g_return_val_if_fail (MODEST_IS_WINDOW(window), FALSE);
3692
3693         if (MODEST_IS_FOLDER_WINDOW (window)) {
3694                 folder_view = GTK_WIDGET (modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window)));
3695         } else {
3696                 return FALSE;
3697         }
3698         if (!folder_view)
3699                 return FALSE;
3700
3701         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
3702
3703         if (!folder)
3704                 return FALSE;
3705
3706         /* Show an error if it's an account */
3707         if (!TNY_IS_FOLDER (folder)) {
3708                 modest_platform_run_information_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3709                                                         _("mail_in_ui_folder_delete_error"),
3710                                                         FALSE);
3711                 g_object_unref (G_OBJECT (folder));
3712                 return FALSE;
3713         }
3714
3715         /* Ask the user */
3716         message =  g_strdup_printf (_("mcen_nc_delete_folder_text"),
3717                                     tny_folder_get_name (TNY_FOLDER (folder)));
3718         response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3719                                                             (const gchar *) message);
3720         g_free (message);
3721
3722         if (response == GTK_RESPONSE_OK) {
3723                 TnyAccount *account = NULL;
3724                 DeleteFolderInfo *info = NULL;
3725                 info = g_new0(DeleteFolderInfo, 1);
3726                 info->folder = g_object_ref (folder);
3727                 info->move_to_trash = move_to_trash;
3728
3729                 account = tny_folder_get_account (TNY_FOLDER (folder));
3730                 modest_platform_connect_if_remote_and_perform (window,
3731                                                                TRUE,
3732                                                                TNY_FOLDER_STORE (account),
3733                                                                on_delete_folder_cb, info);
3734                 g_object_unref (account);
3735                 g_object_unref (folder);
3736                 return TRUE;
3737         } else {
3738                 return FALSE;
3739         }
3740 }
3741
3742 void
3743 modest_ui_actions_on_delete_folder (GtkAction *action,
3744                                     ModestWindow *window)
3745 {
3746         modest_ui_actions_on_edit_mode_delete_folder (window);
3747 }
3748
3749 gboolean
3750 modest_ui_actions_on_edit_mode_delete_folder (ModestWindow *window)
3751 {
3752         g_return_val_if_fail (MODEST_IS_WINDOW(window), TRUE);
3753
3754         return delete_folder (window, FALSE);
3755 }
3756
3757
3758 typedef struct _PasswordDialogFields {
3759         GtkWidget *username;
3760         GtkWidget *password;
3761         GtkWidget *dialog;
3762 } PasswordDialogFields;
3763
3764 static void
3765 password_dialog_check_field (GtkEditable *editable,
3766                              PasswordDialogFields *fields)
3767 {
3768         const gchar *value;
3769         gboolean any_value_empty = FALSE;
3770
3771         value = modest_entry_get_text (fields->username);
3772         if ((value == NULL) || value[0] == '\0') {
3773                 any_value_empty = TRUE;
3774         }
3775         value = modest_entry_get_text (fields->password);
3776         if ((value == NULL) || value[0] == '\0') {
3777                 any_value_empty = TRUE;
3778         }
3779         gtk_dialog_set_response_sensitive (GTK_DIALOG (fields->dialog), GTK_RESPONSE_ACCEPT, !any_value_empty);
3780 }
3781
3782 void
3783 modest_ui_actions_on_password_requested (TnyAccountStore *account_store,
3784                                          const gchar* server_account_name,
3785                                          gchar **username,
3786                                          gchar **password,
3787                                          gboolean *cancel,
3788                                          gboolean *remember,
3789                                          ModestWindow *window)
3790 {
3791         g_return_if_fail(server_account_name);
3792         gboolean completed = FALSE;
3793         PasswordDialogFields *fields = NULL;
3794
3795         /* Initalize output parameters: */
3796         if (cancel)
3797                 *cancel = FALSE;
3798
3799         if (remember)
3800                 *remember = TRUE;
3801
3802 #ifndef MODEST_TOOLKIT_GTK
3803         /* Maemo uses a different (awkward) button order,
3804          * It should probably just use gtk_alternative_dialog_button_order ().
3805          */
3806 #ifdef MODEST_TOOLKIT_HILDON2
3807         GtkWidget *dialog =
3808                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3809                                              NULL,
3810                                              GTK_DIALOG_MODAL,
3811                                              _HL_DONE,
3812                                              GTK_RESPONSE_ACCEPT,
3813                                              NULL);
3814         gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
3815                                         HILDON_MARGIN_DOUBLE);
3816 #else
3817         GtkWidget *dialog =
3818                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3819                                              NULL,
3820                                              GTK_DIALOG_MODAL,
3821                                              _("mcen_bd_dialog_ok"),
3822                                              GTK_RESPONSE_ACCEPT,
3823                                              _("mcen_bd_dialog_cancel"),
3824                                              GTK_RESPONSE_REJECT,
3825                                              NULL);
3826 #endif /* MODEST_TOOLKIT_HILDON2 */
3827 #else
3828         GtkWidget *dialog =
3829                 gtk_dialog_new_with_buttons (_("mail_ti_password_protected"),
3830                                              NULL,
3831                                              GTK_DIALOG_MODAL,
3832                                              GTK_STOCK_CANCEL,
3833                                              GTK_RESPONSE_REJECT,
3834                                              GTK_STOCK_OK,
3835                                              GTK_RESPONSE_ACCEPT,
3836                                              NULL);
3837 #endif /* MODEST_TOOLKIT_GTK */
3838
3839         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(), GTK_WINDOW (dialog), NULL);
3840
3841         gchar *server_name = modest_account_mgr_get_server_account_hostname (
3842                 modest_runtime_get_account_mgr(), server_account_name);
3843         if (!server_name) {/* This happened once, though I don't know why. murrayc. */
3844                 g_warning("%s: Could not get server name for server account '%s'", __FUNCTION__, server_account_name);
3845                 if (cancel)
3846                         *cancel = TRUE;
3847                 gtk_widget_destroy (dialog);
3848                 return;
3849         }
3850
3851         gchar *txt = g_strdup_printf (_("mail_ia_password_info"), server_name);
3852         GtkWidget *label = gtk_label_new (txt);
3853         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
3854         g_free (txt);
3855         g_free (server_name);
3856         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
3857                             FALSE, FALSE, 0);
3858         server_name = NULL;
3859
3860         /* username: */
3861         gchar *initial_username = modest_account_mgr_get_server_account_username (
3862                 modest_runtime_get_account_mgr(), server_account_name);
3863
3864         GtkWidget *entry_username = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
3865         if (initial_username)
3866                 modest_entry_set_text (entry_username, initial_username);
3867
3868         /* Dim this if a connection has ever succeeded with this username,
3869          * as per the UI spec: */
3870         /* const gboolean username_known =  */
3871         /*      modest_account_mgr_get_server_account_username_has_succeeded( */
3872         /*              modest_runtime_get_account_mgr(), server_account_name); */
3873         /* gtk_widget_set_sensitive (entry_username, !username_known); */
3874
3875         /* We drop the username sensitive code and disallow changing it here
3876          * as tinymail does not support really changing the username in the callback
3877          */
3878         gtk_widget_set_sensitive (entry_username, FALSE);
3879
3880         /* Auto-capitalization is the default, so let's turn it off: */
3881 #ifdef MAEMO_CHANGES
3882         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_username), HILDON_GTK_INPUT_MODE_FULL);
3883 #endif
3884
3885         /* Create a size group to be used by all captions.
3886          * Note that HildonCaption does not create a default size group if we do not specify one.
3887          * We use GTK_SIZE_GROUP_HORIZONTAL, so that the widths are the same. */
3888         GtkSizeGroup *sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3889
3890         GtkWidget *caption = modest_toolkit_utils_create_captioned (sizegroup, NULL,
3891                                                                     _("mail_fi_username"), FALSE,
3892                                                                     entry_username);
3893         gtk_widget_show (entry_username);
3894         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption,
3895                 FALSE, FALSE, MODEST_MARGIN_HALF);
3896         gtk_widget_show (caption);
3897
3898         /* password: */
3899         GtkWidget *entry_password = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
3900         gtk_entry_set_visibility (GTK_ENTRY(entry_password), FALSE);
3901         /* gtk_entry_set_invisible_char (GTK_ENTRY(entry_password), "*"); */
3902
3903         /* Auto-capitalization is the default, so let's turn it off: */
3904 #ifdef MAEMO_CHANGES
3905         hildon_gtk_entry_set_input_mode (GTK_ENTRY (entry_password),
3906                 HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_INVISIBLE);
3907 #endif
3908
3909         caption = modest_toolkit_utils_create_captioned (sizegroup, NULL,
3910                                                          _("mail_fi_password"), FALSE,
3911                                                          entry_password);
3912         gtk_widget_show (entry_password);
3913         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), caption,
3914                 FALSE, FALSE, MODEST_MARGIN_HALF);
3915         gtk_widget_show (caption);
3916         g_object_unref (sizegroup);
3917
3918         if (initial_username != NULL)
3919                 gtk_widget_grab_focus (GTK_WIDGET (entry_password));
3920
3921 /* This is not in the Maemo UI spec:
3922         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
3923         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
3924                             TRUE, FALSE, 0);
3925 */
3926
3927         fields = g_slice_new0 (PasswordDialogFields);
3928         fields->username = entry_username;
3929         fields->password = entry_password;
3930         fields->dialog = dialog;
3931
3932         g_signal_connect (entry_username, "changed", G_CALLBACK (password_dialog_check_field), fields);
3933         g_signal_connect (entry_password, "changed", G_CALLBACK (password_dialog_check_field), fields);
3934         password_dialog_check_field (NULL, fields);
3935
3936         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
3937
3938         while (!completed) {
3939
3940                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
3941                         if (username) {
3942                                 *username = g_strdup (modest_entry_get_text (entry_username));
3943
3944                                 /* Note that an empty field becomes the "" string */
3945                                 if (*username && strlen (*username) > 0) {
3946                                         modest_account_mgr_set_server_account_username (modest_runtime_get_account_mgr(),
3947                                                                                         server_account_name,
3948                                                                                         *username);
3949                                         completed = TRUE;
3950
3951                                         const gboolean username_was_changed =
3952                                                 (strcmp (*username, initial_username) != 0);
3953                                         if (username_was_changed) {
3954                                                 g_warning ("%s: tinymail does not yet support changing the "
3955                                                            "username in the get_password() callback.\n", __FUNCTION__);
3956                                         }
3957                                 } else {
3958                                         g_free (*username);
3959                                         *username = NULL;
3960                                         /* Show error */
3961                                         modest_platform_information_banner (GTK_WIDGET (dialog), NULL,
3962                                                                             _("mcen_ib_username_pw_incorrect"));
3963                                         completed = FALSE;
3964                                 }
3965                         }
3966
3967                         if (password) {
3968                                 *password = g_strdup (modest_entry_get_text (entry_password));
3969
3970                                 /* We do not save the password in the configuration,
3971                                  * because this function is only called for passwords that should
3972                                  * not be remembered:
3973                                  modest_server_account_set_password (
3974                                  modest_runtime_get_account_mgr(), server_account_name,
3975                                  *password);
3976                                  */
3977                         }
3978                         if (cancel)
3979                                 *cancel   = FALSE;
3980                 } else {
3981                         completed = TRUE;
3982                         if (username)
3983                                 *username = NULL;
3984                         if (password)
3985                                 *password = NULL;
3986                         if (cancel)
3987                                 *cancel   = TRUE;
3988                 }
3989         }
3990
3991 /* This is not in the Maemo UI spec:
3992         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
3993                 *remember = TRUE;
3994         else
3995                 *remember = FALSE;
3996 */
3997
3998         g_free (initial_username);
3999         gtk_widget_destroy (dialog);
4000         g_slice_free (PasswordDialogFields, fields);
4001
4002         /* printf ("DEBUG: %s: cancel=%d\n", __FUNCTION__, *cancel); */
4003 }
4004
4005 void
4006 modest_ui_actions_on_cut (GtkAction *action,
4007                           ModestWindow *window)
4008 {
4009         GtkWidget *focused_widget;
4010         GtkClipboard *clipboard;
4011
4012         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
4013         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
4014         if (GTK_IS_EDITABLE (focused_widget)) {
4015                 gtk_editable_cut_clipboard (GTK_EDITABLE(focused_widget));
4016                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
4017                 gtk_clipboard_store (clipboard);
4018         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4019                 GtkTextBuffer *buffer;
4020
4021                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4022                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
4023                         gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
4024                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
4025                         gtk_clipboard_store (clipboard);
4026                 }
4027         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
4028                 TnyList *header_list = modest_header_view_get_selected_headers (
4029                                 MODEST_HEADER_VIEW (focused_widget));
4030                 gboolean continue_download = FALSE;
4031                 gint num_of_unc_msgs;
4032
4033                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
4034
4035                 if (num_of_unc_msgs) {
4036                         TnyAccount *account = get_account_from_header_list (header_list);
4037                         if (account) {
4038                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
4039                                 g_object_unref (account);
4040                         }
4041                 }
4042
4043                 if (num_of_unc_msgs == 0 || continue_download) {
4044 /*                      modest_platform_information_banner (
4045                                         NULL, NULL, _CS("mcen_ib_getting_items"));*/
4046                         modest_header_view_cut_selection (
4047                                         MODEST_HEADER_VIEW (focused_widget));
4048                 }
4049
4050                 g_object_unref (header_list);
4051         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
4052                 modest_folder_view_cut_selection (MODEST_FOLDER_VIEW (focused_widget));
4053         }
4054 }
4055
4056 void
4057 modest_ui_actions_on_copy (GtkAction *action,
4058                            ModestWindow *window)
4059 {
4060         GtkClipboard *clipboard;
4061         GtkWidget *focused_widget;
4062         gboolean copied = TRUE;
4063
4064         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
4065         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
4066
4067         if (GTK_IS_LABEL (focused_widget)) {
4068                 gchar *selection;
4069                 selection = modest_text_utils_label_get_selection (GTK_LABEL (focused_widget));
4070                 gtk_clipboard_set_text (clipboard, selection, -1);
4071                 g_free (selection);
4072                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
4073                 gtk_clipboard_store (clipboard);
4074         } else if (GTK_IS_EDITABLE (focused_widget)) {
4075                 gtk_editable_copy_clipboard (GTK_EDITABLE(focused_widget));
4076                 gtk_clipboard_set_can_store (clipboard, NULL, 0);
4077                 gtk_clipboard_store (clipboard);
4078         } else if (GTK_IS_HTML (focused_widget)) {
4079                 const gchar *sel;
4080                 int len = -1;
4081                 sel = gtk_html_get_selection_html (GTK_HTML (focused_widget), &len);
4082                 if ((sel == NULL) || (sel[0] == '\0')) {
4083                         copied = FALSE;
4084                 } else {
4085                         gtk_html_copy (GTK_HTML (focused_widget));
4086                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
4087                         gtk_clipboard_store (clipboard);
4088                 }
4089         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4090                 GtkTextBuffer *buffer;
4091                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4092                 if (modest_text_utils_buffer_selection_is_valid (buffer)) {
4093                         gtk_text_buffer_copy_clipboard (buffer, clipboard);
4094                         gtk_clipboard_set_can_store (clipboard, NULL, 0);
4095                         gtk_clipboard_store (clipboard);
4096                 }
4097         } else if (MODEST_IS_HEADER_VIEW (focused_widget)) {
4098                 TnyList *header_list = modest_header_view_get_selected_headers (
4099                                 MODEST_HEADER_VIEW (focused_widget));
4100                 gboolean continue_download = FALSE;
4101                 gint num_of_unc_msgs;
4102
4103                 num_of_unc_msgs = header_list_count_uncached_msgs(header_list);
4104
4105                 if (num_of_unc_msgs) {
4106                         TnyAccount *account = get_account_from_header_list (header_list);
4107                         if (account) {
4108                                 continue_download = connect_to_get_msg (window, num_of_unc_msgs, account);
4109                                 g_object_unref (account);
4110                         }
4111                 }
4112
4113                 if (num_of_unc_msgs == 0 || continue_download) {
4114                         modest_platform_information_banner (
4115                                         NULL, NULL, _CS_GETTING_ITEMS);
4116                         modest_header_view_copy_selection (
4117                                         MODEST_HEADER_VIEW (focused_widget));
4118                 } else
4119                         copied = FALSE;
4120
4121                 g_object_unref (header_list);
4122
4123         } else if (MODEST_IS_FOLDER_VIEW (focused_widget)) {
4124                 modest_folder_view_copy_selection (MODEST_FOLDER_VIEW (focused_widget));
4125         }
4126
4127         /* Show information banner if there was a copy to clipboard */
4128         if(copied)
4129                 modest_platform_information_banner (
4130                                 NULL, NULL, _CS_COPIED);
4131 }
4132
4133 void
4134 modest_ui_actions_on_undo (GtkAction *action,
4135                            ModestWindow *window)
4136 {
4137         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4138                 modest_msg_edit_window_undo (MODEST_MSG_EDIT_WINDOW (window));
4139         } else {
4140                 g_return_if_reached ();
4141         }
4142 }
4143
4144 void
4145 modest_ui_actions_on_redo (GtkAction *action,
4146                            ModestWindow *window)
4147 {
4148         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4149                 modest_msg_edit_window_redo (MODEST_MSG_EDIT_WINDOW (window));
4150         }
4151         else {
4152                 g_return_if_reached ();
4153         }
4154 }
4155
4156
4157 static void
4158 destroy_information_note (ModestMailOperation *mail_op,
4159                           gpointer user_data)
4160 {
4161         /* destroy information note */
4162         gtk_widget_destroy (GTK_WIDGET(user_data));
4163 }
4164
4165 static void
4166 destroy_folder_information_note (ModestMailOperation *mail_op,
4167                                  TnyFolder *new_folder,
4168                                  gpointer user_data)
4169 {
4170         /* destroy information note */
4171         gtk_widget_destroy (GTK_WIDGET(user_data));
4172 }
4173
4174
4175 static void
4176 paste_as_attachment_free (gpointer data)
4177 {
4178         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) data;
4179
4180         if (helper->banner) {
4181                 gtk_widget_destroy (helper->banner);
4182                 g_object_unref (helper->banner);
4183         }
4184         g_free (helper);
4185 }
4186
4187 static void
4188 paste_msg_as_attachment_cb (ModestMailOperation *mail_op,
4189                             TnyHeader *header,
4190                             TnyMsg *msg,
4191                             gpointer userdata)
4192 {
4193         PasteAsAttachmentHelper *helper = (PasteAsAttachmentHelper *) userdata;
4194         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (helper->window));
4195
4196         if (msg == NULL)
4197                 return;
4198
4199         modest_msg_edit_window_add_part (MODEST_MSG_EDIT_WINDOW (helper->window), TNY_MIME_PART (msg));
4200
4201 }
4202
4203 void
4204 modest_ui_actions_on_paste (GtkAction *action,
4205                             ModestWindow *window)
4206 {
4207         GtkWidget *focused_widget = NULL;
4208         GtkWidget *inf_note = NULL;
4209         ModestMailOperation *mail_op = NULL;
4210
4211         focused_widget = gtk_container_get_focus_child ((GtkContainer *) window);
4212         if (GTK_IS_EDITABLE (focused_widget)) {
4213                 gtk_editable_paste_clipboard (GTK_EDITABLE(focused_widget));
4214         } else if (GTK_IS_TEXT_VIEW (focused_widget)) {
4215                 ModestEmailClipboard *e_clipboard = NULL;
4216                 e_clipboard = modest_runtime_get_email_clipboard ();
4217                 if (modest_email_clipboard_cleared (e_clipboard)) {
4218                         GtkTextBuffer *buffer;
4219                         GtkClipboard *clipboard;
4220
4221                         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
4222                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused_widget));
4223                         gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
4224                 } else if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
4225                         ModestMailOperation *mail_op;
4226                         TnyFolder *src_folder = NULL;
4227                         TnyList *data = NULL;
4228                         gboolean delete;
4229                         PasteAsAttachmentHelper *helper = g_new0 (PasteAsAttachmentHelper, 1);
4230                         helper->window = MODEST_MSG_EDIT_WINDOW (window);
4231                         helper->banner = modest_platform_animation_banner (GTK_WIDGET (window), NULL,
4232                                                                            _CS_PASTING);
4233                         modest_email_clipboard_get_data (e_clipboard, &src_folder, &data, &delete);
4234                         mail_op = modest_mail_operation_new (G_OBJECT (window));
4235                         if (helper->banner != NULL) {
4236                                 g_object_ref (G_OBJECT (helper->banner));
4237                                 gtk_widget_show (GTK_WIDGET (helper->banner));
4238                         }
4239
4240                         if (data != NULL) {
4241                                 modest_mail_operation_get_msgs_full (mail_op,
4242                                                                      data,
4243                     &nbs