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