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