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