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