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