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