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