New details dialog for gtk
[modest] / src / gtk / modest-platform.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 #include <config.h>
31 #include <glib/gi18n.h>
32
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-scrollable.h>
36 #include <modest-runtime.h>
37 #include <modest-main-window.h>
38 #include <modest-header-view.h>
39 #include "modest-widget-memory.h"
40 #include <modest-utils.h>
41 #include <tny-camel-folder.h>
42 #include <tny-simple-list.h>
43 #include <tny-merge-folder.h>
44 #include <tny-error.h>
45 #include <tny-folder.h>
46 #include <tny-account-store-view.h>
47 #include <tny-gnome-device.h>
48 #include <gtk/gtk.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
52 #include <string.h>
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "widgets/modest-window-mgr.h"
57 #include <modest-datetime-formatter.h>
58 #include "modest-header-window.h"
59 #include <modest-folder-window.h>
60 #include <modest-account-mgr.h>
61 #include <modest-account-mgr-helpers.h>
62 #include <modest-ui-constants.h>
63 #include <modest-icon-names.h>
64 #include <modest-count-stream.h>
65 #include <modest-gtk-details-dialog.h>
66 #include <math.h>
67
68
69 #define HILDON_OSSO_URI_ACTION "uri-action"
70 #define URI_ACTION_COPY "copy:"
71 #define MODEST_NOTIFICATION_CATEGORY "email-message"
72 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
73
74 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
75 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
76 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
77 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
78
79 static gboolean ca_con_opened = FALSE;
80
81
82 static void modest_platform_play_email_tone (void);
83
84
85 static void     
86 on_modest_conf_update_interval_changed (ModestConf* self, 
87                                         const gchar *key, 
88                                         ModestConfEvent event,
89                                         ModestConfNotificationId id, 
90                                         gpointer user_data)
91 {
92         g_return_if_fail (key);
93         
94         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
95                 const guint update_interval_minutes = 
96                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
97                 modest_platform_set_update_interval (update_interval_minutes);
98         }
99 }
100
101
102
103 static gboolean
104 check_required_files (void)
105 {
106         FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
107
108         if (!mcc_file) {
109                 g_printerr ("modest: check for mcc file (for LANG) failed\n");
110                 return FALSE;
111         } else {
112                 fclose (mcc_file);
113         }
114
115         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
116             access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
117                 g_printerr ("modest: cannot find providers data\n");
118                 return FALSE;
119         }
120
121         return TRUE;
122 }
123
124
125 /* the gpointer here is the osso_context. */
126 gboolean
127 modest_platform_init (int argc, char *argv[])
128 {
129         GSList *acc_names;
130
131         if (!check_required_files ()) {
132                 g_printerr ("modest: missing required files\n");
133                 return FALSE;
134         }
135
136         /* Make sure that the update interval is changed whenever its gconf key 
137          * is changed */
138         /* CAUTION: we're not using here the
139            modest_conf_listen_to_namespace because we know that there
140            are other parts of Modest listening for this namespace, so
141            we'll receive the notifications anyway. We basically do not
142            use it because there is no easy way to do the
143            modest_conf_forget_namespace */
144         ModestConf *conf = modest_runtime_get_conf ();
145         g_signal_connect (G_OBJECT(conf),
146                           "key_changed",
147                           G_CALLBACK (on_modest_conf_update_interval_changed), 
148                           NULL);
149
150         /* only force the setting of the default interval, if there are actually
151          * any accounts */
152         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
153         if (acc_names) {
154                 /* Get the initial update interval from gconf: */
155                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
156                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
157                 modest_account_mgr_free_account_names (acc_names);
158         }
159         
160         return TRUE;
161 }
162
163 gboolean
164 modest_platform_uninit (void)
165 {
166         return TRUE;
167 }
168
169
170
171
172 TnyDevice*
173 modest_platform_get_new_device (void)
174 {
175         return TNY_DEVICE (tny_gnome_device_new ());
176 }
177
178 gchar*
179 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
180                                     gchar **effective_mime_type)
181 {
182
183         g_warning ("Not implemented %s", __FUNCTION__);
184
185         return NULL;
186         
187 }
188
189
190
191 gboolean 
192 modest_platform_activate_uri (const gchar *uri)
193 {
194         g_warning ("Not implemented %s", __FUNCTION__);
195
196         return FALSE;
197
198 }
199
200 gboolean 
201 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
202 {
203         g_warning ("Not implemented %s", __FUNCTION__);
204
205         return FALSE;
206 }
207
208 gboolean
209 modest_platform_show_uri_popup (const gchar *uri)
210 {
211         g_warning ("Not implemented %s", __FUNCTION__);
212
213         return FALSE;
214 }
215
216
217 GdkPixbuf*
218 modest_platform_get_icon (const gchar *name, guint icon_size)
219 {
220         g_warning ("Not implemented %s", __FUNCTION__);
221
222         return NULL;
223 }
224
225 const gchar*
226 modest_platform_get_app_name (void)
227 {
228         return _("mcen_ap_name");
229 }
230
231 static void
232 entry_insert_text (GtkEditable *editable,
233                    const gchar *text,
234                    gint         length,
235                    gint        *position,
236                    gpointer     data)
237 {
238         gchar *chars;
239         gint chars_length;
240
241         chars = gtk_editable_get_chars (editable, 0, -1);
242         chars_length = g_utf8_strlen (chars, -1);
243         g_free (chars);
244
245         /* Show WID-INF036 */
246         if (chars_length >= 20) {
247                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
248                                                    _CS("ckdg_ib_maximum_characters_reached"));
249         } else {
250                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
251                         /* Show an error */
252                         gchar *tmp, *msg;
253
254                         tmp = g_strndup (folder_name_forbidden_chars,
255                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
256                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
257                         modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)),
258                                                              NULL, msg);
259                         g_free (msg);
260                         g_free (tmp);
261                 } else {
262                         if (length >= 20) {
263                                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
264                                                                      _CS("ckdg_ib_maximum_characters_reached"));
265                         }
266                         /* Write the text in the entry if it's valid */
267                         g_signal_handlers_block_by_func (editable,
268                                                          (gpointer) entry_insert_text, data);
269                         gtk_editable_insert_text (editable, text, length, position);
270                         g_signal_handlers_unblock_by_func (editable,
271                                                            (gpointer) entry_insert_text, data);
272                 }
273         }
274         /* Do not allow further processing */
275         g_signal_stop_emission_by_name (editable, "insert_text");
276 }
277
278 static void
279 entry_changed (GtkEditable *editable,
280                gpointer     user_data)
281 {
282         gchar *chars;
283         GtkWidget *ok_button;
284         GList *buttons;
285
286         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
287         ok_button = GTK_WIDGET (buttons->data);
288
289         chars = gtk_editable_get_chars (editable, 0, -1);
290         g_return_if_fail (chars != NULL);
291
292
293         if (g_utf8_strlen (chars,-1) >= 20) {
294                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
295                                                      _CS("ckdg_ib_maximum_characters_reached"));
296         }
297         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
298
299         /* Free */
300         g_list_free (buttons);
301         g_free (chars);
302 }
303
304
305
306 static void
307 on_response (GtkDialog *dialog,
308              gint response,
309              gpointer user_data)
310 {
311         GtkWidget *entry, *picker;
312         TnyFolderStore *parent;
313         const gchar *new_name;
314         gboolean exists;
315
316         if (response != GTK_RESPONSE_ACCEPT)
317                 return;
318
319         /* Get entry */
320         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
321         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
322
323         parent = TNY_FOLDER_STORE (user_data);
324         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
325         exists = FALSE;
326
327         if (picker != NULL)
328                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
329
330         /* Look for another folder with the same name */
331         if (!TNY_IS_MERGE_FOLDER (parent) &&
332             modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
333                 exists = TRUE;
334
335         if (!exists) {
336                 if (TNY_IS_ACCOUNT (parent) &&
337                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
338                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
339                                                                          new_name)) {
340                         exists = TRUE;
341                 }
342         }
343
344         if (exists) {
345                 /* Show an error */
346                 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
347                                                     NULL, _CS("ckdg_ib_folder_already_exists"));
348                 /* Select the text */
349                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
350                 gtk_widget_grab_focus (entry);
351                 /* Do not close the dialog */
352                 g_signal_stop_emission_by_name (dialog, "response");
353         }
354 }
355
356 typedef struct _FolderChooserData {
357         TnyFolderStore *store;
358         GtkWidget *dialog;
359 } FolderChooserData;
360
361 static void
362 folder_chooser_activated (ModestFolderView *folder_view,
363                           TnyFolderStore *folder,
364                           FolderChooserData *userdata)
365 {
366         userdata->store = folder;
367         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
368 }
369
370 static TnyFolderStore *
371 folder_chooser_dialog_run (ModestFolderView *original,
372                            TnyFolderStore *current,
373                            GtkButton *picker)
374 {
375         GtkWidget *folder_view;
376         FolderChooserData userdata = {NULL, NULL};
377         GtkWidget *scrollable;
378         const gchar *visible_id = NULL;
379
380         userdata.dialog = gtk_dialog_new ();
381         scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
382         folder_view = modest_platform_create_folder_view (NULL);
383
384         gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
385
386         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
387                                        MODEST_FOLDER_VIEW (folder_view));
388
389         if (TNY_IS_ACCOUNT (current)) {
390                 /* Local folders and MMC account are always shown
391                    along with the currently visible server account */
392                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
393                     modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
394                         visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
395                 else
396                         visible_id = tny_account_get_id (TNY_ACCOUNT (current));
397         } else if (TNY_IS_FOLDER (current)) {
398                 TnyAccount *account;
399                 account = modest_tny_folder_get_account ((TnyFolder *) current);
400                 if (account) {
401                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
402                             modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
403                                 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
404                         } else {
405                                 visible_id = tny_account_get_id (account);
406                         }
407                         g_object_unref (account);
408                 }
409         } else {
410                 visible_id =
411                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
412         }
413
414         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
415                                                                      visible_id);
416
417         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
418         gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
419         gtk_widget_set_size_request (scrollable, -1, 320);
420
421         gtk_widget_show (folder_view);
422         gtk_widget_show (scrollable);
423         gtk_widget_show (userdata.dialog);
424         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
425                           G_CALLBACK (folder_chooser_activated), 
426                           (gpointer) &userdata);
427
428         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
429         gtk_widget_destroy (userdata.dialog);
430
431         return userdata.store;
432 }
433
434 static gchar *
435 folder_store_get_display_name (TnyFolderStore *store)
436 {
437         if (TNY_IS_ACCOUNT (store)) {
438                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
439                         return modest_conf_get_string (modest_runtime_get_conf(),
440                                                        MODEST_CONF_DEVICE_NAME, NULL);
441                 else
442                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
443         } else {
444                 gchar *fname;
445                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
446
447                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
448                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
449                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
450                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
451                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
452                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
453                                 g_free (fname);
454                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
455                         }
456                 } else {
457                         /* Sometimes an special folder is reported by the server as
458                            NORMAL, like some versions of Dovecot */
459                         if (type == TNY_FOLDER_TYPE_NORMAL ||
460                             type == TNY_FOLDER_TYPE_UNKNOWN) {
461                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
462                         }
463                 }
464
465                 if (type == TNY_FOLDER_TYPE_INBOX) {
466                         g_free (fname);
467                         fname = g_strdup (_("mcen_me_folder_inbox"));
468                 }
469                 return fname;
470         }
471 }
472
473 GtkWidget *
474 get_image_for_folder_store (TnyFolderStore *store,
475                             gint size)
476 {
477         GdkPixbuf *pixbuf;
478         const gchar *icon_name = NULL;
479         GtkWidget *image = NULL;
480
481         if (TNY_IS_ACCOUNT (store)) {
482                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
483                         icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
484                 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
485                         icon_name = MODEST_FOLDER_ICON_MMC;
486                 else
487                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
488         } else {
489                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
490                 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
491                         switch (type) {
492                         case TNY_FOLDER_TYPE_INBOX:
493                                 icon_name = MODEST_FOLDER_ICON_INBOX;
494                                 break;
495                         default:
496                                 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
497                         }
498                 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
499                         switch (type) {
500                         case TNY_FOLDER_TYPE_OUTBOX:
501                                 icon_name = MODEST_FOLDER_ICON_OUTBOX;
502                                 break;
503                         case TNY_FOLDER_TYPE_DRAFTS:
504                                 icon_name = MODEST_FOLDER_ICON_DRAFTS;
505                                 break;
506                         case TNY_FOLDER_TYPE_SENT:
507                                 icon_name = MODEST_FOLDER_ICON_SENT;
508                                 break;
509                         default:
510                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
511                         }
512                 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
513                         icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
514                 }
515         }
516
517         /* Set icon */
518         pixbuf = modest_platform_get_icon (icon_name, size);
519
520         if (pixbuf) {
521                 image = gtk_image_new_from_pixbuf (pixbuf);
522                 g_object_unref (pixbuf);
523         }
524
525         return image;
526 }
527
528 static void
529 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
530 {
531         gchar *name;
532
533         if (store == NULL) {
534                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
535         } else {
536                 GtkWidget *image;
537
538                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
539                                         g_object_ref (store),
540                                         (GDestroyNotify) g_object_unref);
541                 name = folder_store_get_display_name (store);
542                 gtk_button_set_label (GTK_BUTTON (button), name);
543                 g_free (name);
544
545                 /* Select icon */
546                 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
547                 if (image)
548                         gtk_button_set_image (GTK_BUTTON (button), image);
549         }
550 }
551
552 /* Always returns DUPs so you must free the returned value */
553 static gchar *
554 get_next_folder_name (const gchar *suggested_name, 
555                       TnyFolderStore *suggested_folder)
556 {
557         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
558         unsigned int i;
559         gchar *real_suggested_name;
560
561         if (suggested_name !=NULL) {
562                 return g_strdup (suggested_name);
563         }
564
565         for(i = 0; i < 100; ++ i) {
566                 gboolean exists = FALSE;
567
568                 if (i == 0)
569                         real_suggested_name = g_strdup (default_name);
570                 else
571                         real_suggested_name = g_strdup_printf ("%s(%d)",
572                                                                _FM("ckdg_va_new_folder_name_stub"),
573                                                                i);
574                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
575                                                                     real_suggested_name,
576                                                                     TRUE);
577
578                 if (!exists)
579                         break;
580
581                 g_free (real_suggested_name);
582         }
583
584         /* Didn't find a free number */
585         if (i == 100)
586                 real_suggested_name = g_strdup (default_name);
587
588         return real_suggested_name;
589 }
590
591 typedef struct {
592         ModestFolderView *folder_view;
593         GtkEntry *entry;
594 } FolderPickerHelper;
595
596 static void
597 folder_picker_clicked (GtkButton *button,
598                        FolderPickerHelper *helper)
599 {
600         TnyFolderStore *store, *current;
601
602         current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
603
604         store = folder_chooser_dialog_run (helper->folder_view, current, button);
605         if (store) {
606                 const gchar *current_name;
607                 gboolean exists = FALSE;
608
609                 folder_picker_set_store (GTK_BUTTON (button), store);
610
611                 /* Update the name of the folder */
612                 current_name = gtk_entry_get_text (helper->entry);
613
614                 if (TNY_IS_FOLDER_STORE (store))
615                         exists = modest_tny_folder_has_subfolder_with_name (store,
616                                                                             current_name,
617                                                                             TRUE);
618                 if (exists) {
619                         gchar *new_name = get_next_folder_name (NULL, store);
620                         gtk_entry_set_text (helper->entry, new_name);
621                         g_free (new_name);
622                 }
623         }
624 }
625
626 static GtkWidget *
627 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
628 {
629         GtkWidget *button;
630         const gchar *acc_id = NULL;
631
632         button = gtk_button_new ();
633
634         gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
635
636         if (suggested) {
637
638                 folder_picker_set_store (GTK_BUTTON (button), suggested);
639
640                 if (TNY_IS_ACCOUNT (suggested)) {
641                         if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
642                             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
643                                 acc_id = tny_account_get_id ((TnyAccount *) suggested);
644                 } else {
645                         TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
646                         if (account) {
647                                 acc_id = tny_account_get_id ((TnyAccount *) account);
648                                 g_object_unref (account);
649                         }
650                 }
651         }
652
653         if (!acc_id)
654                 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
655
656         g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
657                                 g_strdup (acc_id), (GDestroyNotify) g_free);
658
659
660         g_signal_connect (G_OBJECT (button), "clicked",
661                           G_CALLBACK (folder_picker_clicked),
662                           helper);
663
664         return button;
665 }
666
667
668 static gint
669 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
670                                           TnyFolderStore *suggested_parent,
671                                           const gchar *dialog_title,
672                                           const gchar *label_text,
673                                           const gchar *suggested_name,
674                                           gboolean show_name,
675                                           gboolean show_parent,
676                                           gchar **folder_name,
677                                           TnyFolderStore **parent)
678 {
679         GtkWidget *accept_btn = NULL;
680         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
681         GtkWidget *account_picker = NULL;
682         GList *buttons = NULL;
683         gint result;
684         GtkSizeGroup *sizegroup;
685         ModestFolderView *folder_view;
686         ModestWindow *folder_window;
687         ModestWindowMgr *window_mgr;
688         FolderPickerHelper *helper = NULL;
689         GtkWidget *top_vbox, *top_align;
690
691         window_mgr = modest_runtime_get_window_mgr ();
692         folder_window = modest_window_mgr_get_folder_window (window_mgr);
693         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
694         
695         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
696         
697         top_vbox = gtk_vbox_new (FALSE, 0);
698         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
699         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
700         
701         /* Ask the user for the folder name */
702         dialog = gtk_dialog_new_with_buttons (dialog_title,
703                                               parent_window,
704                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
705                                               _FM("ckdg_bd_new_folder_dialog_ok"),
706                                               GTK_RESPONSE_ACCEPT,
707                                               NULL);
708
709         /* Add accept button (with unsensitive handler) */
710         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
711         accept_btn = GTK_WIDGET (buttons->data);
712
713         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
714
715         if (show_name) {
716                 label_entry = gtk_label_new (label_text);
717                 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
718                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
719
720                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
721                 gtk_size_group_add_widget (sizegroup, label_entry);
722                 
723                 if (suggested_name)
724                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
725                 else
726                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
727                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
728                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
729                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
730                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
731         }
732         
733         if (show_parent) {
734           
735                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
736
737                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
738                 gtk_size_group_add_widget (sizegroup, label_location);
739
740                 helper = g_slice_new0 (FolderPickerHelper);
741                 helper->folder_view = folder_view;
742                 helper->entry = (GtkEntry *) entry;
743
744                 account_picker = folder_picker_new (suggested_parent, helper);
745         }
746
747         g_object_unref (sizegroup);
748         
749         /* Connect to the response method to avoid closing the dialog
750            when an invalid name is selected*/
751         g_signal_connect (dialog,
752                           "response",
753                           G_CALLBACK (on_response),
754                           suggested_parent);
755         
756         if (show_name) {
757                 /* Track entry changes */
758                 g_signal_connect (entry,
759                                   "insert-text",
760                                   G_CALLBACK (entry_insert_text),
761                                   dialog);
762                 g_signal_connect (entry,
763                                   "changed",
764                                   G_CALLBACK (entry_changed),
765                                   dialog);
766         }
767         
768         
769         /* Some locales like pt_BR need this to get the full window
770            title shown */
771         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
772         
773         /* Create the hbox */
774         if (show_name) {
775                 hbox = gtk_hbox_new (FALSE, 12);
776                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
777                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
778                 
779                 /* Add hbox to dialog */
780                 gtk_box_pack_start (GTK_BOX (top_vbox), 
781                                     hbox, FALSE, FALSE, 0);
782                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
783         }
784
785         if (show_parent) {
786                 hbox = gtk_hbox_new (FALSE, 12);
787                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
788                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
789
790                 /* Add hbox to dialog */
791                 gtk_box_pack_start (GTK_BOX (top_vbox), 
792                                     hbox, FALSE, FALSE, 0);
793                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
794         }
795         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
796                                      GTK_WINDOW (dialog), parent_window);
797
798         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
799         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
800
801         gtk_widget_show_all (GTK_WIDGET(dialog));
802
803         result = gtk_dialog_run (GTK_DIALOG(dialog));
804         if (result == GTK_RESPONSE_ACCEPT) {
805                 if (show_name)
806                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
807                 if (show_parent) {
808                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
809                         if (*parent)
810                                 g_object_ref (*parent);
811                 }
812         }
813
814         gtk_widget_destroy (dialog);
815
816         if (helper)
817                 g_slice_free (FolderPickerHelper, helper);
818
819         while (gtk_events_pending ())
820                 gtk_main_iteration ();
821
822         return result;
823 }
824
825 gint
826 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
827                                        TnyFolderStore *suggested_folder,
828                                        gchar *suggested_name,
829                                        gchar **folder_name,
830                                        TnyFolderStore **parent_folder)
831 {
832         gchar *real_suggested_name = NULL;
833         gint result;
834         ModestTnyAccountStore *acc_store;
835         TnyAccount *account;
836         gboolean do_free = FALSE;
837
838         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
839                                                     suggested_folder);
840
841         /* In hildon 2.2 we always suggest the archive folder as parent */
842         if (!suggested_folder) {
843                 acc_store = modest_runtime_get_account_store ();
844                 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
845                 if (account) {
846                         suggested_folder = (TnyFolderStore *)
847                                 modest_tny_account_get_special_folder (account,
848                                                                        TNY_FOLDER_TYPE_ARCHIVE);
849                         g_object_unref (account);
850                         account = NULL;
851                 }
852         }
853
854         /* If there is not archive folder then fallback to local folders account */
855         if (!suggested_folder) {
856                 do_free = TRUE;
857                 suggested_folder = (TnyFolderStore *)
858                         modest_tny_account_store_get_local_folders_account (acc_store);
859         }
860
861         result = modest_platform_run_folder_common_dialog (parent_window,
862                                                            suggested_folder,
863                                                            _HL("ckdg_ti_new_folder"),
864                                                            _FM("ckdg_fi_new_folder_name"),
865                                                            real_suggested_name,
866                                                            TRUE,
867                                                            TRUE,
868                                                            folder_name,
869                                                            parent_folder);
870
871         if (do_free)
872                 g_object_unref (suggested_folder);
873
874         g_free(real_suggested_name);
875
876         return result;
877 }
878
879 gint
880 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
881                                           TnyFolderStore *parent_folder,
882                                           const gchar *suggested_name,
883                                           gchar **folder_name)
884 {
885         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
886
887         return modest_platform_run_folder_common_dialog (parent_window, 
888                                                          parent_folder,
889                                                          _HL("ckdg_ti_rename_folder"),
890                                                          _HL("ckdg_fi_rename_name"),
891                                                          suggested_name,
892                                                          TRUE,
893                                                          FALSE,
894                                                          folder_name,
895                                                          NULL);
896 }
897
898
899
900 static void
901 on_destroy_dialog (GtkWidget *dialog)
902 {
903         /* This could happen when the dialogs get programatically
904            hidden or destroyed (for example when closing the
905            application while a dialog is being shown) */
906         if (!GTK_IS_WIDGET (dialog))
907                 return;
908
909         gtk_widget_destroy (dialog);
910
911         if (gtk_events_pending ())
912                 gtk_main_iteration ();
913 }
914
915 gint
916 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
917                                          const gchar *message)
918 {
919         GtkWidget *dialog;
920         gint response;
921
922         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
923                                          GTK_MESSAGE_QUESTION,
924                                          GTK_BUTTONS_OK_CANCEL,
925                                          message);
926         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
927                                      GTK_WINDOW (dialog), parent_window);
928
929         response = gtk_dialog_run (GTK_DIALOG (dialog));
930
931         on_destroy_dialog (dialog);
932
933         return response;
934 }
935
936 gint
937 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
938                                                       const gchar *message,
939                                                       const gchar *button_accept,
940                                                       const gchar *button_cancel)
941 {
942         GtkWidget *dialog;
943         gint response;
944         
945         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
946                                          GTK_MESSAGE_QUESTION,
947                                          GTK_BUTTONS_NONE,
948                                          message);
949         gtk_dialog_add_buttons (GTK_DIALOG (dialog),
950                                 button_accept, GTK_RESPONSE_ACCEPT,
951                                 button_cancel, GTK_RESPONSE_CANCEL,
952                                 NULL);
953
954         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
955                                      GTK_WINDOW (dialog), parent_window);
956
957         response = gtk_dialog_run (GTK_DIALOG (dialog));
958
959         on_destroy_dialog (dialog);
960
961         return response;
962 }
963         
964 void
965 modest_platform_run_information_dialog (GtkWindow *parent_window,
966                                         const gchar *message,
967                                         gboolean block)
968 {
969         GtkWidget *note;
970         
971         note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
972                                        GTK_MESSAGE_INFO,
973                                        GTK_BUTTONS_OK,
974                                        message);
975         if (block)
976                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
977                                              GTK_WINDOW (note), parent_window);
978         
979         if (block) {
980                 gtk_dialog_run (GTK_DIALOG (note));
981         
982                 on_destroy_dialog (note);
983         } else {
984                 g_signal_connect_swapped (note,
985                                           "response", 
986                                           G_CALLBACK (on_destroy_dialog),
987                                           note);
988
989                 gtk_widget_show_all (note);
990         }
991 }
992
993 typedef struct _ConnectAndWaitData {
994         GMutex *mutex;
995         GMainLoop *wait_loop;
996         gboolean has_callback;
997         gulong handler;
998 } ConnectAndWaitData;
999
1000
1001 static void
1002 quit_wait_loop (TnyAccount *account,
1003                 ConnectAndWaitData *data) 
1004 {
1005         /* Set the has_callback to TRUE (means that the callback was
1006            executed and wake up every code waiting for cond to be
1007            TRUE */
1008         g_mutex_lock (data->mutex);
1009         data->has_callback = TRUE;
1010         if (data->wait_loop)
1011                 g_main_loop_quit (data->wait_loop);
1012         g_mutex_unlock (data->mutex);
1013 }
1014
1015 static void
1016 on_connection_status_changed (TnyAccount *account, 
1017                               TnyConnectionStatus status,
1018                               gpointer user_data)
1019 {
1020         TnyConnectionStatus conn_status;
1021         ConnectAndWaitData *data;
1022                         
1023         /* Ignore if reconnecting or disconnected */
1024         conn_status = tny_account_get_connection_status (account);
1025         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1026             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1027                 return;
1028
1029         /* Remove the handler */
1030         data = (ConnectAndWaitData *) user_data;
1031         g_signal_handler_disconnect (account, data->handler);
1032
1033         /* Quit from wait loop */
1034         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1035 }
1036
1037 static void
1038 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1039                                     gboolean canceled, 
1040                                     GError *err, 
1041                                     gpointer user_data)
1042 {
1043         /* Quit from wait loop */
1044         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1045 }
1046
1047 gboolean 
1048 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1049                                   TnyAccount *account)
1050 {
1051         gboolean device_online;
1052         TnyDevice *device;
1053         TnyConnectionStatus conn_status;
1054         gboolean user_requested;
1055         
1056         device = modest_runtime_get_device();
1057         device_online = tny_device_is_online (device);
1058
1059         /* Whether the connection is user requested or automatically
1060            requested, for example via D-Bus */
1061         user_requested = (parent_window) ? TRUE : FALSE;
1062
1063         /* If there is no account check only the device status */
1064         if (!account) {
1065                 if (device_online)
1066                         return TRUE;
1067                 else
1068                         /* TODO: should show connection dialog through gnome device */
1069                         return FALSE;
1070         }
1071
1072         /* Return if the account is already connected */
1073         conn_status = tny_account_get_connection_status (account);
1074         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1075                 return TRUE;
1076
1077         return FALSE;
1078 }
1079
1080 gboolean 
1081 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1082 {
1083         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1084                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1085                         /* This must be a maildir account, which does not require a connection: */
1086                         return TRUE;
1087                 }
1088         }
1089
1090         return modest_platform_connect_and_wait (parent_window, account);
1091 }
1092
1093 gboolean 
1094 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1095 {
1096         if (!folder_store)
1097                 return TRUE; /* Maybe it is something local. */
1098                 
1099         gboolean result = TRUE;
1100         if (TNY_IS_FOLDER (folder_store)) {
1101                 /* Get the folder's parent account: */
1102                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1103                 if (account != NULL) {
1104                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1105                         g_object_unref (account);
1106                 }
1107         } else if (TNY_IS_ACCOUNT (folder_store)) {
1108                 /* Use the folder store as an account: */
1109                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1110         }
1111
1112         return result;
1113 }
1114
1115 GtkWidget *
1116 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1117 {
1118         return NULL;
1119
1120 }
1121
1122
1123 gboolean 
1124 modest_platform_set_update_interval (guint minutes)
1125 {
1126         return TRUE;
1127 }
1128
1129 void
1130 modest_platform_push_email_notification(void)
1131 {
1132         return;
1133 }
1134
1135 void
1136 modest_platform_on_new_headers_received (GList *URI_list,
1137                                          gboolean show_visual)
1138 {
1139         return;
1140 }
1141
1142 void
1143 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1144 {
1145         return;
1146 }
1147
1148
1149
1150 GtkWidget * 
1151 modest_platform_get_global_settings_dialog ()
1152 {
1153         return NULL;
1154 }
1155
1156 void
1157 modest_platform_show_help (GtkWindow *parent_window, 
1158                            const gchar *help_id)
1159 {
1160         return;
1161 }
1162
1163 void 
1164 modest_platform_show_search_messages (GtkWindow *parent_window)
1165 {
1166         return;
1167 }
1168
1169 void 
1170 modest_platform_show_addressbook (GtkWindow *parent_window)
1171 {
1172         return;
1173 }
1174
1175 static GtkWidget *
1176 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1177 {
1178         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1179
1180         /* Show one account by default */
1181         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1182                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1183
1184         return widget;
1185 }
1186
1187 GtkWidget *
1188 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1189 {
1190         return modest_platform_create_folder_view_full (query, TRUE);
1191 }
1192
1193 void
1194 banner_finish (gpointer data, GObject *object)
1195 {
1196         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1197         modest_window_mgr_unregister_banner (mgr);
1198         g_object_unref (mgr);
1199 }
1200
1201 void 
1202 modest_platform_information_banner (GtkWidget *parent,
1203                                     const gchar *icon_name,
1204                                     const gchar *text)
1205 {
1206         return;
1207 }
1208
1209 void 
1210 modest_platform_system_banner (GtkWidget *parent,
1211                                const gchar *icon_name,
1212                                const gchar *text)
1213 {
1214         return;
1215 }
1216
1217 void
1218 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1219                                                  const gchar *icon_name,
1220                                                  const gchar *text,
1221                                                  gint timeout)
1222 {
1223         return;
1224 }
1225
1226 GtkWidget *
1227 modest_platform_animation_banner (GtkWidget *parent,
1228                                   const gchar *animation_name,
1229                                   const gchar *text)
1230 {
1231         return NULL;
1232 }
1233
1234 typedef struct
1235 {
1236         GMainLoop* loop;
1237         TnyAccount *account;
1238         gboolean is_online;
1239         gint count_tries;
1240 } CheckAccountIdleData;
1241
1242 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1243
1244 static gboolean 
1245 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1246 {
1247         gboolean stop_trying = FALSE;
1248         g_return_val_if_fail (data && data->account, FALSE);
1249
1250         if (data && data->account && 
1251                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1252                  * after which the account is likely to be usable, or never likely to be usable soon: */
1253                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1254         {
1255                 data->is_online = TRUE;
1256
1257                 stop_trying = TRUE;
1258         } else {
1259                 /* Give up if we have tried too many times: */
1260                 if (data->count_tries >= NUMBER_OF_TRIES) {
1261                         stop_trying = TRUE;
1262                 } else {
1263                         /* Wait for another timeout: */
1264                         ++(data->count_tries);
1265                 }
1266         }
1267
1268         if (stop_trying) {
1269                 /* Allow the function that requested this idle callback to continue: */
1270                 if (data->loop)
1271                         g_main_loop_quit (data->loop);
1272
1273                 if (data->account)
1274                         g_object_unref (data->account);
1275
1276                 return FALSE; /* Don't call this again. */
1277         } else {
1278                 return TRUE; /* Call this timeout callback again. */
1279         }
1280 }
1281
1282 /* Return TRUE immediately if the account is already online,
1283  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1284  * soon as the account is online, or FALSE if the account does 
1285  * not become online in the NUMBER_OF_TRIES seconds.
1286  * This is useful when the D-Bus method was run immediately after 
1287  * the application was started (when using D-Bus activation), 
1288  * because the account usually takes a short time to go online.
1289  * The return value is maybe not very useful.
1290  */
1291 gboolean
1292 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1293 {
1294         gboolean is_online;
1295
1296         g_return_val_if_fail (account, FALSE);
1297
1298         if (!tny_device_is_online (modest_runtime_get_device())) {
1299                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1300                 return FALSE;
1301         }
1302
1303         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1304          * so we avoid wait unnecessarily: */
1305         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1306                 return TRUE;
1307
1308         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1309          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1310          * we want to avoid. */
1311         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1312                 return TRUE;
1313                 
1314         /* This blocks on the result: */
1315         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1316         data->is_online = FALSE;
1317         data->account = account;
1318         g_object_ref (data->account);
1319         data->count_tries = 0;
1320                 
1321         GMainContext *context = NULL; /* g_main_context_new (); */
1322         data->loop = g_main_loop_new (context, FALSE /* not running */);
1323
1324         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1325
1326         /* This main loop will run until the idle handler has stopped it: */
1327         g_main_loop_run (data->loop);
1328
1329         g_main_loop_unref (data->loop);
1330         /* g_main_context_unref (context); */
1331
1332         is_online = data->is_online;
1333         g_slice_free (CheckAccountIdleData, data);
1334         
1335         return is_online;       
1336 }
1337
1338
1339
1340 static void
1341 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1342 {
1343         /* GTK_RESPONSE_HELP means we need to show the certificate */
1344         if (response_id == GTK_RESPONSE_APPLY) {
1345                 gchar *msg;
1346                 
1347                 /* Do not close the dialog */
1348                 g_signal_stop_emission_by_name (dialog, "response");
1349
1350                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1351                 modest_platform_run_information_dialog (NULL, msg, TRUE);
1352         }
1353 }
1354
1355
1356 gboolean
1357 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1358                                                      const gchar *certificate)
1359 {
1360         GtkWidget *note;
1361         gint response;
1362
1363         
1364         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1365                                            server_name);
1366
1367         /* We use GTK_RESPONSE_APPLY because we want the button in the
1368            middle of OK and CANCEL the same as the browser does for
1369            example. With GTK_RESPONSE_HELP the view button is aligned
1370            to the left while the other two to the right */
1371         note = gtk_message_dialog_new  (
1372                 NULL,
1373                 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1374                 GTK_MESSAGE_QUESTION,
1375                 GTK_BUTTONS_NONE,
1376                 question);
1377         gtk_dialog_add_buttons (GTK_DIALOG (note),
1378                                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1379                                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1380                                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1381                                 NULL, NULL);
1382
1383         g_signal_connect (G_OBJECT(note), "response",
1384                           G_CALLBACK(on_cert_dialog_response),
1385                           (gpointer) certificate);
1386
1387         response = gtk_dialog_run(GTK_DIALOG(note));
1388
1389         on_destroy_dialog (note);
1390         g_free (question);
1391
1392         return response == GTK_RESPONSE_OK;
1393 }
1394
1395 gboolean
1396 modest_platform_run_alert_dialog (const gchar* prompt,
1397                                   gboolean is_question)
1398 {
1399
1400         gboolean retval = TRUE;
1401         if (is_question) {
1402                 GtkWidget *dialog;
1403                 /* The Tinymail documentation says that we should show Yes and No buttons,
1404                  * when it is a question.
1405                  * Obviously, we need tinymail to use more specific error codes instead,
1406                  * so we know what buttons to show. */
1407                 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1408                                                  GTK_MESSAGE_QUESTION,
1409                                                  GTK_BUTTONS_YES_NO,
1410                                                  prompt);
1411
1412                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1413                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1414
1415                 on_destroy_dialog (dialog);
1416         } else {
1417                 /* Just show the error text and use the default response: */
1418                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
1419                                                         prompt, FALSE);
1420         }
1421         return retval;
1422 }
1423
1424 /***************/
1425 typedef struct {
1426         GtkWindow *parent_window;
1427         ModestConnectedPerformer callback;
1428         TnyAccount *account;
1429         gpointer user_data;
1430         gchar *iap;
1431         TnyDevice *device;
1432 } OnWentOnlineInfo;
1433  
1434 static void 
1435 on_went_online_info_free (OnWentOnlineInfo *info)
1436 {
1437         /* And if we cleanup, we DO cleanup  :-)  */
1438         
1439         if (info->device)
1440                 g_object_unref (info->device);
1441         if (info->iap)
1442                 g_free (info->iap);
1443         if (info->parent_window)
1444                 g_object_unref (info->parent_window);
1445         if (info->account)
1446                 g_object_unref (info->account);
1447         
1448         g_slice_free (OnWentOnlineInfo, info);
1449         
1450         /* We're done ... */
1451         
1452         return;
1453 }
1454  
1455 static void
1456 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1457 {
1458         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1459  
1460         /* Now it's really time to callback to the caller. If going online didn't succeed,
1461          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1462          * canceled will be set. Etcetera etcetera. */
1463         
1464         if (info->callback) {
1465                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1466         }
1467         
1468         /* This is our last call, we must cleanup here if we didn't yet do that */
1469         on_went_online_info_free (info);
1470         
1471         return;
1472 }
1473  
1474 void 
1475 modest_platform_connect_and_perform (GtkWindow *parent_window, 
1476                                      gboolean force,
1477                                      TnyAccount *account, 
1478                                      ModestConnectedPerformer callback, 
1479                                      gpointer user_data)
1480 {
1481         gboolean device_online;
1482         TnyDevice *device;
1483         TnyConnectionStatus conn_status;
1484         OnWentOnlineInfo *info;
1485         
1486         device = modest_runtime_get_device();
1487         device_online = tny_device_is_online (device);
1488
1489         /* If there is no account check only the device status */
1490         if (!account) {
1491                 
1492                 if (device_online) {
1493  
1494                         /* We promise to instantly perform the callback, so ... */
1495                         if (callback) {
1496                                 callback (FALSE, NULL, parent_window, account, user_data);
1497                         }
1498                         
1499                 } else {
1500                         
1501                 }
1502  
1503                 /* The other code has no more reason to run. This is all that we can do for the
1504                  * caller (he should have given us a nice and clean account instance!). We
1505                  * can't do magic, we don't know what account he intends to bring online. So
1506                  * we'll just bring the device online (and await his false bug report). */
1507                 
1508                 return;
1509         }
1510  
1511         
1512         /* Return if the account is already connected */
1513         
1514         conn_status = tny_account_get_connection_status (account);
1515         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1516  
1517                 /* We promise to instantly perform the callback, so ... */
1518                 if (callback) {
1519                         callback (FALSE, NULL, parent_window, account, user_data);
1520                 }
1521                 
1522                 return;
1523         }
1524         
1525         if (device_online) {
1526         } else {
1527                 
1528                 /* If the device is online, we'll just connect the account */
1529                 
1530                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1531                                               on_account_went_online, info);
1532         }
1533  
1534         /* The info gets freed by on_account_went_online or on_conic_device_went_online
1535          * in both situations, go look if you don't believe me! */
1536         
1537         return;
1538 }
1539
1540 void
1541 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
1542                                                gboolean force,
1543                                                TnyFolderStore *folder_store, 
1544                                                ModestConnectedPerformer callback, 
1545                                                gpointer user_data)
1546 {
1547         TnyAccount *account = NULL;
1548
1549         if (!folder_store ||
1550             (TNY_IS_MERGE_FOLDER (folder_store) &&
1551              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1552
1553                 /* We promise to instantly perform the callback, so ... */
1554                 if (callback) {
1555                         GError *error = NULL;
1556                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1557                                      "Unable to move or not found folder");
1558                         callback (FALSE, error, parent_window, NULL, user_data);
1559                         g_error_free (error);
1560                 }
1561                 return;
1562
1563         } else if (TNY_IS_FOLDER (folder_store)) {
1564                 /* Get the folder's parent account: */
1565                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1566         } else if (TNY_IS_ACCOUNT (folder_store)) {
1567                 /* Use the folder store as an account: */
1568                 account = TNY_ACCOUNT (g_object_ref (folder_store));
1569         }
1570
1571         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1572                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1573                         /* No need to connect a local account */
1574                         if (callback)
1575                                 callback (FALSE, NULL, parent_window, account, user_data);
1576
1577                         goto clean;
1578                 }
1579         }
1580         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1581
1582  clean:
1583         if (account)
1584                 g_object_unref (account);
1585 }
1586
1587 static void
1588 src_account_connect_performer (gboolean canceled,
1589                                GError *err,
1590                                GtkWindow *parent_window,
1591                                TnyAccount *src_account,
1592                                gpointer user_data)
1593 {
1594         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1595
1596         if (canceled || err) {
1597                 /* If there was any error call the user callback */
1598                 info->callback (canceled, err, parent_window, src_account, info->data);
1599         } else {
1600                 /* Connect the destination account */
1601                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
1602                                                                TNY_FOLDER_STORE (info->dst_account),
1603                                                                info->callback, info->data);
1604         }
1605
1606         /* Free the info object */
1607         g_object_unref (info->dst_account);
1608         g_slice_free (DoubleConnectionInfo, info);
1609 }
1610
1611
1612 void 
1613 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
1614                                             gboolean force,
1615                                             TnyFolderStore *folder_store,
1616                                             DoubleConnectionInfo *connect_info)
1617 {
1618         modest_platform_connect_if_remote_and_perform(parent_window, 
1619                                                       force,
1620                                                       folder_store, 
1621                                                       src_account_connect_performer, 
1622                                                       connect_info);
1623 }
1624
1625 GtkWidget *
1626 modest_platform_get_account_settings_wizard (void)
1627 {
1628         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1629
1630         return GTK_WIDGET (dialog);
1631 }
1632
1633 ModestConnectedVia
1634 modest_platform_get_current_connection (void)
1635 {
1636         TnyDevice *device = NULL;
1637         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1638         
1639         device = modest_runtime_get_device ();
1640
1641         if (!tny_device_is_online (device))
1642                 return MODEST_CONNECTED_VIA_ANY;
1643
1644         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
1645         return retval;
1646 }
1647
1648
1649
1650 gboolean
1651 modest_platform_check_memory_low (ModestWindow *win,
1652                                   gboolean visuals)
1653 {
1654         return FALSE;
1655         
1656 }
1657
1658 void 
1659 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1660                                            TnyFolder *folder)
1661 {
1662         GtkWidget *dialog;
1663         
1664         /* Create dialog */
1665         dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1666                                                                            parent_window, folder);
1667
1668         /* Run dialog */
1669         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1670                                      GTK_WINDOW (dialog), 
1671                                      parent_window);
1672         gtk_widget_show_all (dialog);
1673
1674         g_signal_connect_swapped (dialog, "response", 
1675                                   G_CALLBACK (gtk_widget_destroy),
1676                                   dialog);
1677 }
1678
1679 typedef struct _HeaderDetailsGetSizeInfo {
1680         GtkWidget *dialog;
1681         TnyMimePart *part;
1682         guint total;
1683 } HeaderDetailsGetSizeInfo;
1684
1685 static void 
1686 header_details_dialog_destroy (gpointer userdata,
1687                                GObject *object)
1688 {
1689         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1690
1691         info->dialog = NULL;
1692 }
1693
1694 static gboolean
1695 idle_get_mime_part_size_cb (gpointer userdata)
1696 {
1697         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1698         gdk_threads_enter ();
1699
1700         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1701                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1702                                                         info->total);
1703         }
1704
1705         if (info->dialog) {
1706                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1707                 info->dialog = NULL;
1708         }
1709         g_object_unref (info->part);
1710         g_slice_free (HeaderDetailsGetSizeInfo, info);
1711
1712         gdk_threads_leave ();
1713
1714         return FALSE;
1715 }
1716
1717 static gpointer
1718 get_mime_part_size_thread (gpointer thr_user_data)
1719 {
1720         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1721         gssize result = 0;
1722         TnyStream *count_stream;
1723
1724         count_stream = modest_count_stream_new ();
1725         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1726         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1727         if (info->total == 0) {
1728                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1729                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1730                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1731         }
1732         
1733         /* if there was an error, don't set the size (this is pretty uncommon) */
1734         if (result < 0) {
1735                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1736         }
1737         g_idle_add (idle_get_mime_part_size_cb, info);
1738
1739         return NULL;
1740 }
1741
1742 void
1743 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1744                                            TnyHeader *header,
1745                                            gboolean async_get_size,
1746                                            TnyMsg *msg)
1747 {
1748         GtkWidget *dialog;
1749
1750         /* Create dialog */
1751         dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1752                                                                            parent_window, header, !async_get_size);
1753
1754         if (async_get_size && msg && TNY_IS_MSG (msg)) {
1755                 HeaderDetailsGetSizeInfo *info;
1756                 info = g_slice_new (HeaderDetailsGetSizeInfo);
1757                 info->dialog = dialog;
1758                 info->total = 0;
1759                 info->part = TNY_MIME_PART (g_object_ref (msg));
1760
1761                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1762                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1763         }
1764
1765         /* Run dialog */
1766         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1767                                      GTK_WINDOW (dialog),
1768                                      parent_window);
1769         gtk_widget_show_all (dialog);
1770
1771         g_signal_connect_swapped (dialog, "response", 
1772                                   G_CALLBACK (gtk_widget_destroy),
1773                                   dialog);
1774 }
1775
1776 static void
1777 modest_platform_play_email_tone (void)
1778 {
1779         return;
1780 }
1781
1782 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1783 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1784 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1785 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1786 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1787 #define MOVE_TO_FOLDER_SEPARATOR "/"
1788
1789 static void
1790 translate_path (gchar **path)
1791 {
1792         gchar **parts;
1793         gchar **current;
1794         GString *output;
1795         gboolean add_separator;
1796
1797         parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1798         g_free (*path);
1799
1800         current = parts;
1801         output = g_string_new ("");
1802         add_separator = FALSE;
1803
1804         while (*current != NULL) {
1805                 TnyFolderType folder_type;
1806                 gchar *downcase;
1807
1808                 if (add_separator) {
1809                         output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1810                 } else {
1811                         add_separator = TRUE;
1812                 }
1813
1814                 downcase = g_ascii_strdown (*current, -1);
1815                 folder_type = modest_local_folder_info_get_type (downcase);
1816                 if (strcmp (downcase, "inbox") == 0) {
1817                         output = g_string_append (output, _("mcen_me_folder_inbox"));
1818                 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1819                     folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1820                     folder_type == TNY_FOLDER_TYPE_SENT ||
1821                     folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1822                         output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1823                 } else {
1824                         output = g_string_append (output, *current);
1825                 }
1826                 g_free (downcase);
1827
1828                 current++;
1829         }
1830
1831         g_strfreev (parts);
1832         *path = g_string_free (output, FALSE);
1833 }
1834
1835 static void
1836 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
1837                                           TnyFolderStore *folder_store)
1838 {
1839         GtkWidget *action_button;
1840         GtkWidget *image = NULL;
1841         TnyAccount *account;
1842         gchar *account_name = NULL, *short_name = NULL;
1843
1844         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1845
1846         /* Get account name */
1847         if (TNY_IS_FOLDER (folder_store))
1848                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1849         else
1850                 account = g_object_ref (folder_store);
1851
1852         if (modest_tny_account_is_virtual_local_folders (account))
1853                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1854                                                        MODEST_CONF_DEVICE_NAME, NULL);
1855
1856         if (!account_name)
1857                 account_name = g_strdup (tny_account_get_name (account));
1858
1859         g_object_unref (account);
1860
1861         /* Set title of button: account or folder name */
1862         if (TNY_IS_FOLDER (folder_store))
1863                 short_name = folder_store_get_display_name (folder_store);
1864         else
1865                 short_name = g_strdup (account_name);
1866
1867         gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1868
1869         /* Set value of button, folder full name */
1870         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1871                 const gchar *camel_full_name;
1872                 gchar *last_slash, *full_name;
1873
1874                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1875                 last_slash = g_strrstr (camel_full_name, "/");
1876                 if (last_slash) {
1877                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1878                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1879                         g_free (prefix);
1880                 } else {
1881                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1882                                                  short_name,
1883                                                  NULL);
1884                 }
1885                 translate_path (&full_name);
1886                 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1887                 g_free (full_name);
1888         }
1889         g_free (account_name);
1890         g_free (short_name);
1891
1892         /* Set image for the button */
1893         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1894         if (image)
1895                 gtk_button_set_image (GTK_BUTTON (action_button), image);
1896 }
1897
1898 static void
1899 move_to_dialog_show_accounts (GtkWidget *dialog)
1900 {
1901         GtkWidget *back_button;
1902         GtkWidget *folder_view;
1903         GtkWidget *scrollable;
1904         GtkWidget *action_button;
1905
1906         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1907         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1908         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1909         scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1910
1911         gtk_widget_set_sensitive (back_button, FALSE);
1912         gtk_widget_set_sensitive (action_button, FALSE);
1913
1914         /* Need to set this here, otherwise callbacks called because
1915            of filtering won't perform correctly */
1916         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1917
1918         /* Reset action button */
1919         gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1920         gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1921
1922         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1923         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1924         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1925         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1926                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1927         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1928                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1929         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
1930                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1931         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
1932                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1933         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1934 }
1935
1936 static void
1937 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1938 {
1939         GtkWidget *back_button;
1940         GtkWidget *folder_view;
1941         TnyAccount *account;
1942         const gchar *account_id;
1943         GtkWidget *scrollable;
1944         GtkWidget *action_button;
1945
1946         back_button =
1947                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1948         action_button =
1949                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1950         folder_view =
1951                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1952         scrollable =
1953                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1954
1955         gtk_widget_set_sensitive (back_button, TRUE);
1956         gtk_widget_set_sensitive (action_button, TRUE);
1957
1958         /* Need to set this here, otherwise callbacks called because
1959            of filtering won't perform correctly */
1960         g_object_set_data (G_OBJECT (dialog),
1961                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
1962                            GINT_TO_POINTER (TRUE));
1963
1964         account = TNY_ACCOUNT (folder_store);
1965         if (modest_tny_account_is_virtual_local_folders (account)) {
1966                 account_id = tny_account_get_id (account);
1967                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1968                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1969         } else if (modest_tny_account_is_memory_card_account (account)) {
1970                 account_id = tny_account_get_id (account);
1971                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1972                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1973         } else {
1974                 account_id = tny_account_get_id (account);
1975                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1976                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1977                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1978                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1979         }
1980
1981         move_to_dialog_set_selected_folder_store (dialog, folder_store);
1982         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
1983                                                                      account_id);
1984
1985         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
1986         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1987         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1988         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1989         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1990 }
1991
1992 static void
1993 on_move_to_dialog_back_clicked (GtkButton *button,
1994                                 gpointer userdata)
1995 {
1996         GtkWidget *dialog = (GtkWidget *) userdata;
1997
1998         /* Back to show accounts */
1999         move_to_dialog_show_accounts (dialog);
2000 }
2001
2002 static void
2003 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2004                                     GtkTreePath       *path,
2005                                     GtkTreeViewColumn *column,
2006                                     gpointer           user_data)
2007 {
2008         TnyFolderStore *selected = NULL;
2009         GtkWidget *dialog;
2010         GtkWidget *folder_view;
2011         gboolean showing_folders;
2012
2013         dialog = (GtkWidget *) user_data;
2014         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2015                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2016
2017         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2018                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2019
2020         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2021         if (!selected)
2022                 return;
2023
2024         if (!showing_folders) {
2025                 gboolean valid = TRUE;
2026
2027                 if (TNY_IS_ACCOUNT (selected) &&
2028                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2029                         ModestProtocolType protocol_type;
2030
2031                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2032                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2033                                 (modest_runtime_get_protocol_registry (),
2034                                  protocol_type,
2035                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2036                 }
2037                 if (valid)
2038                         move_to_dialog_show_folders (dialog, selected);
2039         } else {
2040                 move_to_dialog_set_selected_folder_store (dialog, selected);
2041         }
2042         g_object_unref (selected);
2043 }
2044
2045 static void
2046 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2047                                      gpointer          user_data)
2048 {
2049         gboolean showing_folders;
2050         GtkWidget *dialog;
2051
2052         dialog = (GtkWidget *) user_data;
2053         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2054         if (showing_folders) {
2055                 TnyFolderStore *selected;
2056                 GtkWidget *folder_view;
2057
2058                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2059                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2060
2061                 if (selected) {
2062                         move_to_dialog_set_selected_folder_store (dialog, selected);
2063                         g_object_unref (selected);
2064                 }
2065         }
2066 }
2067
2068 static void
2069 on_move_to_dialog_action_clicked (GtkButton *selection,
2070                                   gpointer   user_data)
2071 {
2072         GtkWidget *dialog;
2073         gboolean showing_folders;
2074
2075         dialog = (GtkWidget *) user_data;
2076         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2077         if (showing_folders) {
2078                 TnyFolderStore *selected;
2079                 GtkWidget *folder_view;
2080
2081                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2082                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2083
2084                 if (selected) {
2085                         /* It's not possible to select root folders as
2086                            targets unless they're the local account or
2087                            the memory card account */
2088                         if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2089                             (TNY_IS_ACCOUNT (selected) &&
2090                              (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2091                               modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2092                                 gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2093                         g_object_unref (selected);
2094                 }
2095         }
2096 }
2097
2098 static void
2099 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2100 {
2101 }
2102
2103 GtkWidget *
2104 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2105                                        GtkWidget **folder_view)
2106 {
2107         GtkWidget *dialog, *folder_view_container;
2108         GtkWidget *align;
2109         GtkWidget *buttons_hbox;
2110         GtkWidget *back_button;
2111         GdkPixbuf *back_pixbuf;
2112         GtkWidget *top_vbox;
2113         GtkWidget *action_button;
2114         GtkTreeSelection *selection;
2115
2116         /* Create dialog. We cannot use a touch selector because we
2117            need to use here the folder view widget directly */
2118         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2119                                               GTK_WINDOW (parent_window),
2120                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2121                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2122                                               _FM ("ckdg_bd_change_folder_new_folder"),
2123                                               MODEST_GTK_RESPONSE_NEW_FOLDER,
2124                                               NULL);
2125
2126         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2127         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2128         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2129
2130         /* Create folder view */
2131         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2132         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2133                           dialog);
2134
2135         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2136                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2137         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2138                                                FALSE);
2139         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2140                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2141
2142         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2143         back_button = gtk_button_new ();
2144         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2145         if (back_pixbuf) {
2146                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2147                 g_object_unref (back_pixbuf);
2148         }
2149
2150         action_button = gtk_button_new ();
2151         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2152
2153         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2154         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2155         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2156         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2157         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2158
2159         /* Create scrollable and add it to the dialog */
2160         folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2161         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2162         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2163
2164         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2165         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2166
2167         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2168
2169         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2170         gtk_widget_show (folder_view_container);
2171         gtk_widget_show (align);
2172         gtk_widget_show (top_vbox);
2173         gtk_widget_show (*folder_view);
2174         gtk_widget_show_all (back_button);
2175         gtk_widget_show (action_button);
2176         gtk_widget_show (buttons_hbox);
2177         gtk_widget_show (dialog);
2178
2179         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2180         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2181         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2182         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2183
2184         /* Simulate the behaviour of a HildonPickerDialog by emitting
2185            a response when a folder is selected */
2186         g_signal_connect (*folder_view, "row-activated",
2187                           G_CALLBACK (on_move_to_dialog_row_activated),
2188                           dialog);
2189
2190         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2191         g_signal_connect (selection, "changed",
2192                           G_CALLBACK (on_move_to_dialog_selection_changed),
2193                           dialog);
2194
2195         g_signal_connect (action_button, "clicked",
2196                           G_CALLBACK (on_move_to_dialog_action_clicked),
2197                           dialog);
2198
2199         g_signal_connect (back_button, "clicked",
2200                           G_CALLBACK (on_move_to_dialog_back_clicked),
2201                           dialog);
2202
2203         move_to_dialog_show_accounts (dialog);
2204
2205         return dialog;
2206 }
2207
2208 TnyList *
2209 modest_platform_get_list_to_move (ModestWindow *window)
2210 {
2211         TnyList *list = NULL;
2212
2213         if (MODEST_IS_HEADER_WINDOW (window)) {
2214                 ModestHeaderView *header_view;
2215
2216                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2217                 list = modest_header_view_get_selected_headers (header_view);
2218         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2219                 ModestFolderView *folder_view;
2220                 TnyFolderStore *selected_folder;
2221
2222                 list = TNY_LIST (tny_simple_list_new ());
2223                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2224                 selected_folder = modest_folder_view_get_selected (folder_view);
2225                 if (selected_folder) {
2226                         tny_list_prepend (list, G_OBJECT (selected_folder));
2227                         g_object_unref (selected_folder);
2228                 }
2229                 return list;
2230         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2231                 TnyHeader *header;
2232
2233                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2234                 if (header) {
2235                         list = TNY_LIST (tny_simple_list_new ());
2236                         tny_list_prepend (list, G_OBJECT (header));
2237                         g_object_unref (header);
2238                 }
2239         } else {
2240                 g_return_val_if_reached (NULL);
2241         }
2242
2243         return list;
2244 }