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