Show cancel button in all folder dialogs.
[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_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_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_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_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_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_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_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_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                                               GTK_STOCK_CANCEL,
772                                               GTK_RESPONSE_CANCEL,
773                                               _FM_NEW_FOLDER_DIALOG_OK,
774                                               GTK_RESPONSE_ACCEPT,
775                                               NULL);
776
777         /* Add accept button (with unsensitive handler) */
778         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
779         accept_btn = GTK_WIDGET (buttons->data);
780
781         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
782
783         if (show_name) {
784                 label_entry = gtk_label_new (label_text);
785                 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
786                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
787
788                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
789                 gtk_size_group_add_widget (sizegroup, label_entry);
790                 
791                 if (suggested_name)
792                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
793                 else
794                         gtk_entry_set_text (GTK_ENTRY (entry), _FM_NEW_FOLDER_NAME_STUB);
795                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
796                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
797                                                 g_utf8_strlen (_FM_NEW_FOLDER_NAME_STUB, -1)));
798                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
799         }
800         
801         if (show_parent) {
802           
803                 label_location = gtk_label_new (_FM_NEW_FOLDER_LOCATION);
804
805                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
806                 gtk_size_group_add_widget (sizegroup, label_location);
807
808                 helper = g_slice_new0 (FolderPickerHelper);
809                 helper->folder_view = folder_view;
810                 helper->entry = (GtkEntry *) entry;
811
812                 account_picker = folder_picker_new (suggested_parent, helper);
813         }
814
815         g_object_unref (sizegroup);
816         
817         /* Connect to the response method to avoid closing the dialog
818            when an invalid name is selected*/
819         g_signal_connect (dialog,
820                           "response",
821                           G_CALLBACK (on_response),
822                           suggested_parent);
823         
824         if (show_name) {
825                 /* Track entry changes */
826                 g_signal_connect (entry,
827                                   "insert-text",
828                                   G_CALLBACK (entry_insert_text),
829                                   dialog);
830                 g_signal_connect (entry,
831                                   "changed",
832                                   G_CALLBACK (entry_changed),
833                                   dialog);
834         }
835         
836         
837         /* Some locales like pt_BR need this to get the full window
838            title shown */
839         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
840         
841         /* Create the hbox */
842         if (show_name) {
843                 hbox = gtk_hbox_new (FALSE, 12);
844                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
845                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
846                 
847                 /* Add hbox to dialog */
848                 gtk_box_pack_start (GTK_BOX (top_vbox), 
849                                     hbox, FALSE, FALSE, 0);
850                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
851         }
852
853         if (show_parent) {
854                 hbox = gtk_hbox_new (FALSE, 12);
855                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
856                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
857
858                 /* Add hbox to dialog */
859                 gtk_box_pack_start (GTK_BOX (top_vbox), 
860                                     hbox, FALSE, FALSE, 0);
861                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
862         }
863         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
864                                      GTK_WINDOW (dialog), parent_window);
865
866         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
867         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
868
869         gtk_widget_show_all (GTK_WIDGET(dialog));
870
871         result = gtk_dialog_run (GTK_DIALOG(dialog));
872         if (result == GTK_RESPONSE_ACCEPT) {
873                 if (show_name)
874                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
875                 if (show_parent) {
876                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
877                         if (*parent)
878                                 g_object_ref (*parent);
879                 }
880         }
881
882         gtk_widget_destroy (dialog);
883
884         if (helper)
885                 g_slice_free (FolderPickerHelper, helper);
886
887         while (gtk_events_pending ())
888                 gtk_main_iteration ();
889
890         return result;
891 }
892
893 gint
894 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
895                                        TnyFolderStore *suggested_folder,
896                                        gchar *suggested_name,
897                                        gchar **folder_name,
898                                        TnyFolderStore **parent_folder)
899 {
900         gchar *real_suggested_name = NULL;
901         gint result;
902         ModestTnyAccountStore *acc_store;
903         TnyAccount *account;
904         gboolean do_free = FALSE;
905
906         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
907                                                     suggested_folder);
908
909         /* In hildon 2.2 we always suggest the archive folder as parent */
910         if (!suggested_folder) {
911                 acc_store = modest_runtime_get_account_store ();
912                 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
913                 if (account) {
914                         suggested_folder = (TnyFolderStore *)
915                                 modest_tny_account_get_special_folder (account,
916                                                                        TNY_FOLDER_TYPE_ARCHIVE);
917                         g_object_unref (account);
918                         account = NULL;
919                 }
920         }
921
922         /* If there is not archive folder then fallback to local folders account */
923         if (!suggested_folder) {
924                 do_free = TRUE;
925                 suggested_folder = (TnyFolderStore *)
926                         modest_tny_account_store_get_local_folders_account (acc_store);
927         }
928
929         result = modest_platform_run_folder_common_dialog (parent_window,
930                                                            suggested_folder,
931                                                            _HL_TITLE_NEW_FOLDER,
932                                                            _FM_NEW_FOLDER_NAME,
933                                                            real_suggested_name,
934                                                            TRUE,
935                                                            TRUE,
936                                                            folder_name,
937                                                            parent_folder);
938
939         if (do_free)
940                 g_object_unref (suggested_folder);
941
942         g_free(real_suggested_name);
943
944         return result;
945 }
946
947 gint
948 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
949                                           TnyFolderStore *parent_folder,
950                                           const gchar *suggested_name,
951                                           gchar **folder_name)
952 {
953         GtkWindow *toplevel;
954
955         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
956
957         toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (parent_window));
958         return modest_platform_run_folder_common_dialog (toplevel,
959                                                          parent_folder,
960                                                          _HL_TITLE_RENAME_FOLDER,
961                                                          _HL_RENAME_NAME,
962                                                          suggested_name,
963                                                          TRUE,
964                                                          FALSE,
965                                                          folder_name,
966                                                          NULL);
967 }
968
969
970
971 static void
972 on_destroy_dialog (GtkWidget *dialog)
973 {
974         /* This could happen when the dialogs get programatically
975            hidden or destroyed (for example when closing the
976            application while a dialog is being shown) */
977         if (!GTK_IS_WIDGET (dialog))
978                 return;
979
980         gtk_widget_destroy (dialog);
981
982         if (gtk_events_pending ())
983                 gtk_main_iteration ();
984 }
985
986 gint
987 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
988                                          const gchar *message)
989 {
990         GtkWidget *dialog;
991         gint response;
992
993         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
994                                          GTK_MESSAGE_QUESTION,
995                                          GTK_BUTTONS_OK_CANCEL,
996                                          message);
997         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
998                                      GTK_WINDOW (dialog), parent_window);
999
1000         response = gtk_dialog_run (GTK_DIALOG (dialog));
1001
1002         on_destroy_dialog (dialog);
1003
1004         return response;
1005 }
1006
1007 gint
1008 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1009                                                       const gchar *message,
1010                                                       const gchar *button_accept,
1011                                                       const gchar *button_cancel)
1012 {
1013         GtkWidget *dialog;
1014         gint response;
1015         
1016         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1017                                          GTK_MESSAGE_QUESTION,
1018                                          GTK_BUTTONS_NONE,
1019                                          message);
1020         gtk_dialog_add_buttons (GTK_DIALOG (dialog),
1021                                 button_accept, GTK_RESPONSE_ACCEPT,
1022                                 button_cancel, GTK_RESPONSE_CANCEL,
1023                                 NULL);
1024
1025         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1026                                      GTK_WINDOW (dialog), parent_window);
1027
1028         response = gtk_dialog_run (GTK_DIALOG (dialog));
1029
1030         on_destroy_dialog (dialog);
1031
1032         return response;
1033 }
1034         
1035 void
1036 modest_platform_run_information_dialog (GtkWindow *parent_window,
1037                                         const gchar *message,
1038                                         gboolean block)
1039 {
1040         GtkWidget *note;
1041         
1042         note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1043                                        GTK_MESSAGE_INFO,
1044                                        GTK_BUTTONS_OK,
1045                                        message);
1046         if (block)
1047                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1048                                              GTK_WINDOW (note), parent_window);
1049         
1050         if (block) {
1051                 gtk_dialog_run (GTK_DIALOG (note));
1052         
1053                 on_destroy_dialog (note);
1054         } else {
1055                 g_signal_connect_swapped (note,
1056                                           "response", 
1057                                           G_CALLBACK (on_destroy_dialog),
1058                                           note);
1059
1060                 gtk_widget_show_all (note);
1061         }
1062 }
1063
1064 typedef struct _ConnectAndWaitData {
1065         GMutex *mutex;
1066         GMainLoop *wait_loop;
1067         gboolean has_callback;
1068         gulong handler;
1069 } ConnectAndWaitData;
1070
1071
1072 gboolean 
1073 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1074                                   TnyAccount *account)
1075 {
1076         gboolean device_online;
1077         TnyDevice *device;
1078         TnyConnectionStatus conn_status;
1079         gboolean user_requested;
1080         
1081         device = modest_runtime_get_device();
1082         device_online = tny_device_is_online (device);
1083
1084         /* Whether the connection is user requested or automatically
1085            requested, for example via D-Bus */
1086         user_requested = (parent_window) ? TRUE : FALSE;
1087
1088         /* If there is no account check only the device status */
1089         if (!account) {
1090                 if (device_online)
1091                         return TRUE;
1092                 else
1093                         /* TODO: should show connection dialog through gnome device */
1094                         return FALSE;
1095         }
1096
1097         /* Return if the account is already connected */
1098         conn_status = tny_account_get_connection_status (account);
1099         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1100                 return TRUE;
1101
1102         return FALSE;
1103 }
1104
1105 gboolean 
1106 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1107 {
1108         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1109                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1110                         /* This must be a maildir account, which does not require a connection: */
1111                         return TRUE;
1112                 }
1113         }
1114
1115         return modest_platform_connect_and_wait (parent_window, account);
1116 }
1117
1118 gboolean 
1119 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1120 {
1121         if (!folder_store)
1122                 return TRUE; /* Maybe it is something local. */
1123                 
1124         gboolean result = TRUE;
1125         if (TNY_IS_FOLDER (folder_store)) {
1126                 /* Get the folder's parent account: */
1127                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1128                 if (account != NULL) {
1129                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1130                         g_object_unref (account);
1131                 }
1132         } else if (TNY_IS_ACCOUNT (folder_store)) {
1133                 /* Use the folder store as an account: */
1134                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1135         }
1136
1137         return result;
1138 }
1139
1140 GtkWidget *
1141 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1142 {
1143         return NULL;
1144
1145 }
1146
1147
1148 gboolean 
1149 modest_platform_set_update_interval (guint minutes)
1150 {
1151         return TRUE;
1152 }
1153
1154 void
1155 modest_platform_push_email_notification(void)
1156 {
1157         return;
1158 }
1159
1160 void
1161 modest_platform_on_new_headers_received (GList *URI_list,
1162                                          gboolean show_visual)
1163 {
1164         return;
1165 }
1166
1167 void
1168 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1169 {
1170         return;
1171 }
1172
1173
1174
1175 GtkWidget * 
1176 modest_platform_get_global_settings_dialog ()
1177 {
1178         return modest_default_global_settings_dialog_new ();
1179 }
1180
1181 void
1182 modest_platform_show_help (GtkWindow *parent_window, 
1183                            const gchar *help_id)
1184 {
1185         return;
1186 }
1187
1188 void 
1189 modest_platform_show_search_messages (GtkWindow *parent_window)
1190 {
1191         return;
1192 }
1193
1194 void 
1195 modest_platform_show_addressbook (GtkWindow *parent_window)
1196 {
1197         return;
1198 }
1199
1200 static GtkWidget *
1201 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1202 {
1203         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1204
1205         /* Show one account by default */
1206         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1207                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1208
1209         return widget;
1210 }
1211
1212 GtkWidget *
1213 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1214 {
1215         return modest_platform_create_folder_view_full (query, TRUE);
1216 }
1217
1218 void
1219 banner_finish (gpointer data, GObject *object)
1220 {
1221         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1222         modest_window_mgr_unregister_banner (mgr);
1223         g_object_unref (mgr);
1224 }
1225
1226 void 
1227 modest_platform_information_banner (GtkWidget *parent,
1228                                     const gchar *icon_name,
1229                                     const gchar *text)
1230 {
1231         GtkWidget *banner;
1232
1233         banner = modest_shell_banner_new (parent);
1234         modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1235         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1236
1237         return;
1238 }
1239
1240 void 
1241 modest_platform_system_banner (GtkWidget *parent,
1242                                const gchar *icon_name,
1243                                const gchar *text)
1244 {
1245         modest_platform_information_banner (parent, icon_name, text);
1246 }
1247
1248 void
1249 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1250                                                  const gchar *icon_name,
1251                                                  const gchar *text,
1252                                                  gint timeout)
1253 {
1254         GtkWidget *banner;
1255
1256         banner = modest_shell_banner_new_with_timeout (parent, timeout);
1257         modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1258         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1259
1260         return;
1261 }
1262
1263 GtkWidget *
1264 modest_platform_animation_banner (GtkWidget *parent,
1265                                   const gchar *animation_name,
1266                                   const gchar *text)
1267 {
1268         GtkWidget *banner;
1269
1270         banner = modest_shell_banner_new_with_timeout (parent, 0);
1271         modest_shell_banner_set_animation (MODEST_SHELL_BANNER (banner), animation_name);
1272         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1273
1274         return banner;
1275 }
1276
1277 typedef struct
1278 {
1279         GMainLoop* loop;
1280         TnyAccount *account;
1281         gboolean is_online;
1282         gint count_tries;
1283 } CheckAccountIdleData;
1284
1285 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1286
1287 static gboolean 
1288 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1289 {
1290         gboolean stop_trying = FALSE;
1291         g_return_val_if_fail (data && data->account, FALSE);
1292
1293         if (data && data->account && 
1294                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1295                  * after which the account is likely to be usable, or never likely to be usable soon: */
1296                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1297         {
1298                 data->is_online = TRUE;
1299
1300                 stop_trying = TRUE;
1301         } else {
1302                 /* Give up if we have tried too many times: */
1303                 if (data->count_tries >= NUMBER_OF_TRIES) {
1304                         stop_trying = TRUE;
1305                 } else {
1306                         /* Wait for another timeout: */
1307                         ++(data->count_tries);
1308                 }
1309         }
1310
1311         if (stop_trying) {
1312                 /* Allow the function that requested this idle callback to continue: */
1313                 if (data->loop)
1314                         g_main_loop_quit (data->loop);
1315
1316                 if (data->account)
1317                         g_object_unref (data->account);
1318
1319                 return FALSE; /* Don't call this again. */
1320         } else {
1321                 return TRUE; /* Call this timeout callback again. */
1322         }
1323 }
1324
1325 /* Return TRUE immediately if the account is already online,
1326  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1327  * soon as the account is online, or FALSE if the account does 
1328  * not become online in the NUMBER_OF_TRIES seconds.
1329  * This is useful when the D-Bus method was run immediately after 
1330  * the application was started (when using D-Bus activation), 
1331  * because the account usually takes a short time to go online.
1332  * The return value is maybe not very useful.
1333  */
1334 gboolean
1335 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1336 {
1337         gboolean is_online;
1338
1339         g_return_val_if_fail (account, FALSE);
1340
1341         if (!tny_device_is_online (modest_runtime_get_device())) {
1342                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1343                 return FALSE;
1344         }
1345
1346         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1347          * so we avoid wait unnecessarily: */
1348         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1349                 return TRUE;
1350
1351         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1352          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1353          * we want to avoid. */
1354         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1355                 return TRUE;
1356                 
1357         /* This blocks on the result: */
1358         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1359         data->is_online = FALSE;
1360         data->account = account;
1361         g_object_ref (data->account);
1362         data->count_tries = 0;
1363                 
1364         GMainContext *context = NULL; /* g_main_context_new (); */
1365         data->loop = g_main_loop_new (context, FALSE /* not running */);
1366
1367         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1368
1369         /* This main loop will run until the idle handler has stopped it: */
1370         g_main_loop_run (data->loop);
1371
1372         g_main_loop_unref (data->loop);
1373         /* g_main_context_unref (context); */
1374
1375         is_online = data->is_online;
1376         g_slice_free (CheckAccountIdleData, data);
1377         
1378         return is_online;       
1379 }
1380
1381
1382
1383 static void
1384 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1385 {
1386         /* GTK_RESPONSE_HELP means we need to show the certificate */
1387         if (response_id == GTK_RESPONSE_APPLY) {
1388                 gchar *msg;
1389                 
1390                 /* Do not close the dialog */
1391                 g_signal_stop_emission_by_name (dialog, "response");
1392
1393                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1394                 modest_platform_run_information_dialog (NULL, msg, TRUE);
1395         }
1396 }
1397
1398
1399 gboolean
1400 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1401                                                      const gchar *certificate)
1402 {
1403         GtkWidget *note;
1404         gint response;
1405
1406         
1407         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1408                                            server_name);
1409
1410         /* We use GTK_RESPONSE_APPLY because we want the button in the
1411            middle of OK and CANCEL the same as the browser does for
1412            example. With GTK_RESPONSE_HELP the view button is aligned
1413            to the left while the other two to the right */
1414         note = gtk_message_dialog_new  (
1415                 NULL,
1416                 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1417                 GTK_MESSAGE_QUESTION,
1418                 GTK_BUTTONS_NONE,
1419                 question);
1420         gtk_dialog_add_buttons (GTK_DIALOG (note),
1421                                 _HL_YES,     GTK_RESPONSE_OK,
1422                                 _HL_VIEW,          GTK_RESPONSE_APPLY,   /* abusing this... */
1423                                 _HL_NO, GTK_RESPONSE_CANCEL,
1424                                 NULL, NULL);
1425
1426         g_signal_connect (G_OBJECT(note), "response",
1427                           G_CALLBACK(on_cert_dialog_response),
1428                           (gpointer) certificate);
1429
1430         response = gtk_dialog_run(GTK_DIALOG(note));
1431
1432         on_destroy_dialog (note);
1433         g_free (question);
1434
1435         return response == GTK_RESPONSE_OK;
1436 }
1437
1438 gboolean
1439 modest_platform_run_alert_dialog (const gchar* prompt,
1440                                   gboolean is_question)
1441 {
1442
1443         gboolean retval = TRUE;
1444         if (is_question) {
1445                 GtkWidget *dialog;
1446                 /* The Tinymail documentation says that we should show Yes and No buttons,
1447                  * when it is a question.
1448                  * Obviously, we need tinymail to use more specific error codes instead,
1449                  * so we know what buttons to show. */
1450                 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1451                                                  GTK_MESSAGE_QUESTION,
1452                                                  GTK_BUTTONS_YES_NO,
1453                                                  prompt);
1454
1455                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1456                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1457
1458                 on_destroy_dialog (dialog);
1459         } else {
1460                 /* Just show the error text and use the default response: */
1461                 modest_platform_run_information_dialog (NULL, 
1462                                                         prompt, FALSE);
1463         }
1464         return retval;
1465 }
1466
1467 /***************/
1468 typedef struct {
1469         ModestWindow *parent_window;
1470         ModestConnectedPerformer callback;
1471         TnyAccount *account;
1472         gpointer user_data;
1473         gchar *iap;
1474         TnyDevice *device;
1475 } OnWentOnlineInfo;
1476  
1477 static void 
1478 on_went_online_info_free (OnWentOnlineInfo *info)
1479 {
1480         /* And if we cleanup, we DO cleanup  :-)  */
1481         
1482         if (info->device)
1483                 g_object_unref (info->device);
1484         if (info->iap)
1485                 g_free (info->iap);
1486         if (info->parent_window)
1487                 g_object_unref (info->parent_window);
1488         if (info->account)
1489                 g_object_unref (info->account);
1490         
1491         g_slice_free (OnWentOnlineInfo, info);
1492         
1493         /* We're done ... */
1494         
1495         return;
1496 }
1497  
1498 static void
1499 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1500 {
1501         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1502  
1503         /* Now it's really time to callback to the caller. If going online didn't succeed,
1504          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1505          * canceled will be set. Etcetera etcetera. */
1506         
1507         if (info->callback) {
1508                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1509         }
1510         
1511         /* This is our last call, we must cleanup here if we didn't yet do that */
1512         on_went_online_info_free (info);
1513         
1514         return;
1515 }
1516  
1517 void 
1518 modest_platform_connect_and_perform (ModestWindow *parent_window,
1519                                      gboolean force,
1520                                      TnyAccount *account, 
1521                                      ModestConnectedPerformer callback, 
1522                                      gpointer user_data)
1523 {
1524         gboolean device_online;
1525         TnyDevice *device;
1526         TnyConnectionStatus conn_status;
1527         
1528         device = modest_runtime_get_device();
1529         device_online = tny_device_is_online (device);
1530
1531         /* If there is no account check only the device status */
1532         if (!account) {
1533                 
1534                 if (device_online) {
1535  
1536                         /* We promise to instantly perform the callback, so ... */
1537                         if (callback) {
1538                                 callback (FALSE, NULL, parent_window, account, user_data);
1539                         }
1540                         
1541                 } else {
1542                         
1543                 }
1544  
1545                 /* The other code has no more reason to run. This is all that we can do for the
1546                  * caller (he should have given us a nice and clean account instance!). We
1547                  * can't do magic, we don't know what account he intends to bring online. So
1548                  * we'll just bring the device online (and await his false bug report). */
1549                 
1550                 return;
1551         }
1552  
1553         
1554         /* Return if the account is already connected */
1555         
1556         conn_status = tny_account_get_connection_status (account);
1557         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1558
1559                 /* We promise to instantly perform the callback, so ... */
1560                 if (callback) {
1561                         callback (FALSE, NULL, parent_window, account, user_data);
1562                 }
1563
1564                 return;
1565         }
1566
1567         if (!device_online) {
1568                 OnWentOnlineInfo *info = NULL;
1569
1570                 info = g_slice_new0 (OnWentOnlineInfo);
1571
1572                 info->device = NULL;
1573                 info->iap = NULL;
1574                 info->account = TNY_ACCOUNT (g_object_ref (account));
1575
1576                 if (parent_window)
1577                         info->parent_window = (ModestWindow *) g_object_ref (parent_window);
1578                 else
1579                         info->parent_window = NULL;
1580
1581                 /* So we'll put the callback away for later ... */
1582                 info->user_data = user_data;
1583                 info->callback = callback;
1584
1585                 /* If the device is online, we'll just connect the account */
1586                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1587                                               on_account_went_online, info);
1588         }
1589
1590         /* The info gets freed by on_account_went_online or on_conic_device_went_online
1591          * in both situations, go look if you don't believe me! */
1592 }
1593
1594 void
1595 modest_platform_connect_if_remote_and_perform (ModestWindow *parent_window,
1596                                                gboolean force,
1597                                                TnyFolderStore *folder_store, 
1598                                                ModestConnectedPerformer callback, 
1599                                                gpointer user_data)
1600 {
1601         TnyAccount *account = NULL;
1602
1603         if (!folder_store ||
1604             (TNY_IS_MERGE_FOLDER (folder_store) &&
1605              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1606
1607                 /* We promise to instantly perform the callback, so ... */
1608                 if (callback) {
1609                         GError *error = NULL;
1610                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1611                                      "Unable to move or not found folder");
1612                         callback (FALSE, error, parent_window, NULL, user_data);
1613                         g_error_free (error);
1614                 }
1615                 return;
1616
1617         } else if (TNY_IS_FOLDER (folder_store)) {
1618                 /* Get the folder's parent account: */
1619                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1620         } else if (TNY_IS_ACCOUNT (folder_store)) {
1621                 /* Use the folder store as an account: */
1622                 account = TNY_ACCOUNT (g_object_ref (folder_store));
1623         }
1624
1625         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1626                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1627                         /* No need to connect a local account */
1628                         if (callback)
1629                                 callback (FALSE, NULL, parent_window, account, user_data);
1630
1631                         goto clean;
1632                 }
1633         }
1634         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1635
1636  clean:
1637         if (account)
1638                 g_object_unref (account);
1639 }
1640
1641 static void
1642 src_account_connect_performer (gboolean canceled,
1643                                GError *err,
1644                                ModestWindow *parent_window,
1645                                TnyAccount *src_account,
1646                                gpointer user_data)
1647 {
1648         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1649
1650         if (canceled || err) {
1651                 /* If there was any error call the user callback */
1652                 info->callback (canceled, err, parent_window, src_account, info->data);
1653         } else {
1654                 /* Connect the destination account */
1655                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
1656                                                                TNY_FOLDER_STORE (info->dst_account),
1657                                                                info->callback, info->data);
1658         }
1659
1660         /* Free the info object */
1661         g_object_unref (info->dst_account);
1662         g_slice_free (DoubleConnectionInfo, info);
1663 }
1664
1665
1666 void 
1667 modest_platform_double_connect_and_perform (ModestWindow *parent_window,
1668                                             gboolean force,
1669                                             TnyFolderStore *folder_store,
1670                                             DoubleConnectionInfo *connect_info)
1671 {
1672         modest_platform_connect_if_remote_and_perform(parent_window,
1673                                                       force,
1674                                                       folder_store, 
1675                                                       src_account_connect_performer, 
1676                                                       connect_info);
1677 }
1678
1679 GtkWidget *
1680 modest_platform_get_account_settings_wizard (void)
1681 {
1682         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1683
1684         return GTK_WIDGET (dialog);
1685 }
1686
1687 ModestConnectedVia
1688 modest_platform_get_current_connection (void)
1689 {
1690         TnyDevice *device = NULL;
1691         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1692         
1693         device = modest_runtime_get_device ();
1694
1695         if (!tny_device_is_online (device))
1696                 return MODEST_CONNECTED_VIA_ANY;
1697
1698         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
1699         return retval;
1700 }
1701
1702
1703
1704 gboolean
1705 modest_platform_check_memory_low (ModestWindow *win,
1706                                   gboolean visuals)
1707 {
1708         return FALSE;
1709         
1710 }
1711
1712 void 
1713 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1714                                            TnyFolder *folder)
1715 {
1716         GtkWidget *dialog;
1717         
1718         /* Create dialog */
1719         dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1720                                                                            parent_window, folder);
1721
1722         /* Run dialog */
1723         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1724                                      GTK_WINDOW (dialog), 
1725                                      parent_window);
1726         gtk_widget_show_all (dialog);
1727
1728         g_signal_connect_swapped (dialog, "response", 
1729                                   G_CALLBACK (gtk_widget_destroy),
1730                                   dialog);
1731 }
1732
1733 typedef struct _HeaderDetailsGetSizeInfo {
1734         GtkWidget *dialog;
1735         TnyMimePart *part;
1736         guint total;
1737 } HeaderDetailsGetSizeInfo;
1738
1739 static void 
1740 header_details_dialog_destroy (gpointer userdata,
1741                                GObject *object)
1742 {
1743         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1744
1745         info->dialog = NULL;
1746 }
1747
1748 static gboolean
1749 idle_get_mime_part_size_cb (gpointer userdata)
1750 {
1751         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1752         gdk_threads_enter ();
1753
1754         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1755                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1756                                                         info->total);
1757         }
1758
1759         if (info->dialog) {
1760                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1761                 info->dialog = NULL;
1762         }
1763         g_object_unref (info->part);
1764         g_slice_free (HeaderDetailsGetSizeInfo, info);
1765
1766         gdk_threads_leave ();
1767
1768         return FALSE;
1769 }
1770
1771 static gpointer
1772 get_mime_part_size_thread (gpointer thr_user_data)
1773 {
1774         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1775         gssize result = 0;
1776         TnyStream *count_stream;
1777
1778         count_stream = modest_count_stream_new ();
1779         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1780         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1781         if (info->total == 0) {
1782                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1783                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1784                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1785         }
1786         
1787         /* if there was an error, don't set the size (this is pretty uncommon) */
1788         if (result < 0) {
1789                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1790         }
1791         g_idle_add (idle_get_mime_part_size_cb, info);
1792
1793         return NULL;
1794 }
1795
1796 void
1797 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1798                                            TnyHeader *header,
1799                                            gboolean async_get_size,
1800                                            TnyMsg *msg)
1801 {
1802         GtkWidget *dialog;
1803
1804         /* Create dialog */
1805         dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1806                                                                            parent_window, header, !async_get_size);
1807
1808         if (async_get_size && msg && TNY_IS_MSG (msg)) {
1809                 HeaderDetailsGetSizeInfo *info;
1810                 info = g_slice_new (HeaderDetailsGetSizeInfo);
1811                 info->dialog = dialog;
1812                 info->total = 0;
1813                 info->part = TNY_MIME_PART (g_object_ref (msg));
1814
1815                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1816                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1817         }
1818
1819         /* Run dialog */
1820         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1821                                      GTK_WINDOW (dialog),
1822                                      parent_window);
1823         gtk_widget_show_all (dialog);
1824
1825         g_signal_connect_swapped (dialog, "response", 
1826                                   G_CALLBACK (gtk_widget_destroy),
1827                                   dialog);
1828 }
1829
1830 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1831 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1832 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1833 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1834 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1835 #define MOVE_TO_FOLDER_SEPARATOR "/"
1836
1837 static void
1838 translate_path (gchar **path)
1839 {
1840         gchar **parts;
1841         gchar **current;
1842         GString *output;
1843         gboolean add_separator;
1844
1845         parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1846         g_free (*path);
1847
1848         current = parts;
1849         output = g_string_new ("");
1850         add_separator = FALSE;
1851
1852         while (*current != NULL) {
1853                 TnyFolderType folder_type;
1854                 gchar *downcase;
1855
1856                 if (add_separator) {
1857                         output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1858                 } else {
1859                         add_separator = TRUE;
1860                 }
1861
1862                 downcase = g_ascii_strdown (*current, -1);
1863                 folder_type = modest_local_folder_info_get_type (downcase);
1864                 if (strcmp (downcase, "inbox") == 0) {
1865                         output = g_string_append (output, _("mcen_me_folder_inbox"));
1866                 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1867                     folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1868                     folder_type == TNY_FOLDER_TYPE_SENT ||
1869                     folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1870                         output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1871                 } else {
1872                         output = g_string_append (output, *current);
1873                 }
1874                 g_free (downcase);
1875
1876                 current++;
1877         }
1878
1879         g_strfreev (parts);
1880         *path = g_string_free (output, FALSE);
1881 }
1882
1883 static void
1884 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
1885                                           TnyFolderStore *folder_store)
1886 {
1887         GtkWidget *action_button;
1888         GtkWidget *image = NULL;
1889         TnyAccount *account;
1890         gchar *account_name = NULL, *short_name = NULL;
1891
1892         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1893
1894         /* Get account name */
1895         if (TNY_IS_FOLDER (folder_store))
1896                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1897         else
1898                 account = g_object_ref (folder_store);
1899
1900         if (modest_tny_account_is_virtual_local_folders (account))
1901                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1902                                                        MODEST_CONF_DEVICE_NAME, NULL);
1903
1904         if (!account_name)
1905                 account_name = g_strdup (tny_account_get_name (account));
1906
1907         g_object_unref (account);
1908
1909         /* Set title of button: account or folder name */
1910         if (TNY_IS_FOLDER (folder_store))
1911                 short_name = folder_store_get_display_name (folder_store);
1912         else
1913                 short_name = g_strdup (account_name);
1914
1915         gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1916
1917         /* Set value of button, folder full name */
1918         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1919                 const gchar *camel_full_name;
1920                 gchar *last_slash, *full_name;
1921
1922                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1923                 last_slash = g_strrstr (camel_full_name, "/");
1924                 if (last_slash) {
1925                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1926                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1927                         g_free (prefix);
1928                 } else {
1929                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1930                                                  short_name,
1931                                                  NULL);
1932                 }
1933                 translate_path (&full_name);
1934                 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1935                 g_free (full_name);
1936         }
1937         g_free (account_name);
1938         g_free (short_name);
1939
1940         /* Set image for the button */
1941         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1942         if (image)
1943                 gtk_button_set_image (GTK_BUTTON (action_button), image);
1944 }
1945
1946 static void
1947 move_to_dialog_show_accounts (GtkWidget *dialog)
1948 {
1949         GtkWidget *back_button;
1950         GtkWidget *folder_view;
1951         GtkWidget *scrollable;
1952         GtkWidget *action_button;
1953
1954         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1955         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1956         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1957         scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1958
1959         gtk_widget_set_sensitive (back_button, FALSE);
1960         gtk_widget_set_sensitive (action_button, FALSE);
1961
1962         /* Need to set this here, otherwise callbacks called because
1963            of filtering won't perform correctly */
1964         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1965
1966         /* Reset action button */
1967         gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1968         gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1969
1970         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1971         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1972         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1973         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1974                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1975         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1976                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1977         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
1978                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1979         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
1980                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1981         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1982 }
1983
1984 static void
1985 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1986 {
1987         GtkWidget *back_button;
1988         GtkWidget *folder_view;
1989         TnyAccount *account;
1990         const gchar *account_id;
1991         GtkWidget *scrollable;
1992         GtkWidget *action_button;
1993
1994         back_button =
1995                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1996         action_button =
1997                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1998         folder_view =
1999                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2000         scrollable =
2001                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
2002
2003         gtk_widget_set_sensitive (back_button, TRUE);
2004         gtk_widget_set_sensitive (action_button, TRUE);
2005
2006         /* Need to set this here, otherwise callbacks called because
2007            of filtering won't perform correctly */
2008         g_object_set_data (G_OBJECT (dialog),
2009                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2010                            GINT_TO_POINTER (TRUE));
2011
2012         account = TNY_ACCOUNT (folder_store);
2013         if (modest_tny_account_is_virtual_local_folders (account)) {
2014                 account_id = tny_account_get_id (account);
2015                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2016                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2017         } else if (modest_tny_account_is_memory_card_account (account)) {
2018                 account_id = tny_account_get_id (account);
2019                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2020                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2021         } else {
2022                 account_id = tny_account_get_id (account);
2023                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2024                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2025                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2026                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2027         }
2028
2029         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2030         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2031                                                                      account_id);
2032
2033         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2034         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2035         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2036         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2037         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
2038 }
2039
2040 static void
2041 on_move_to_dialog_back_clicked (GtkButton *button,
2042                                 gpointer userdata)
2043 {
2044         GtkWidget *dialog = (GtkWidget *) userdata;
2045
2046         /* Back to show accounts */
2047         move_to_dialog_show_accounts (dialog);
2048 }
2049
2050 static void
2051 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2052                                     GtkTreePath       *path,
2053                                     GtkTreeViewColumn *column,
2054                                     gpointer           user_data)
2055 {
2056         TnyFolderStore *selected = NULL;
2057         GtkWidget *dialog;
2058         GtkWidget *folder_view;
2059         gboolean showing_folders;
2060
2061         dialog = (GtkWidget *) user_data;
2062         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2063                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2064
2065         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2066                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2067
2068         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2069         if (!selected)
2070                 return;
2071
2072         if (!showing_folders) {
2073                 gboolean valid = TRUE;
2074
2075                 if (TNY_IS_ACCOUNT (selected) &&
2076                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2077                         ModestProtocolType protocol_type;
2078
2079                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2080                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2081                                 (modest_runtime_get_protocol_registry (),
2082                                  protocol_type,
2083                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2084                 }
2085                 if (valid)
2086                         move_to_dialog_show_folders (dialog, selected);
2087         } else {
2088                 move_to_dialog_set_selected_folder_store (dialog, selected);
2089         }
2090         g_object_unref (selected);
2091 }
2092
2093 static void
2094 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2095                                      gpointer          user_data)
2096 {
2097         gboolean showing_folders;
2098         GtkWidget *dialog;
2099
2100         dialog = (GtkWidget *) user_data;
2101         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2102         if (showing_folders) {
2103                 TnyFolderStore *selected;
2104                 GtkWidget *folder_view;
2105
2106                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2107                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2108
2109                 if (selected) {
2110                         move_to_dialog_set_selected_folder_store (dialog, selected);
2111                         g_object_unref (selected);
2112                 }
2113         }
2114 }
2115
2116 static void
2117 on_move_to_dialog_action_clicked (GtkButton *selection,
2118                                   gpointer   user_data)
2119 {
2120         GtkWidget *dialog;
2121         gboolean showing_folders;
2122
2123         dialog = (GtkWidget *) user_data;
2124         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2125         if (showing_folders) {
2126                 TnyFolderStore *selected;
2127                 GtkWidget *folder_view;
2128
2129                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2130                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2131
2132                 if (selected) {
2133                         /* It's not possible to select root folders as
2134                            targets unless they're the local account or
2135                            the memory card account */
2136                         if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2137                             (TNY_IS_ACCOUNT (selected) &&
2138                              (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2139                               modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2140                                 gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2141                         g_object_unref (selected);
2142                 }
2143         }
2144 }
2145
2146 static void
2147 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2148 {
2149 }
2150
2151 GtkWidget *
2152 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2153                                        GtkWidget **folder_view)
2154 {
2155         GtkWidget *dialog, *folder_view_container;
2156         GtkWidget *align;
2157         GtkWidget *buttons_hbox;
2158         GtkWidget *back_button;
2159         GdkPixbuf *back_pixbuf;
2160         GtkWidget *top_vbox;
2161         GtkWidget *action_button;
2162         GtkTreeSelection *selection;
2163
2164         /* Create dialog. We cannot use a touch selector because we
2165            need to use here the folder view widget directly */
2166         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2167                                               GTK_WINDOW (parent_window),
2168                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2169                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2170                                               _FM_CHANGE_FOLDER_NEW_FOLDER,
2171                                               MODEST_GTK_RESPONSE_NEW_FOLDER,
2172                                               NULL);
2173
2174         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2175         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2176         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2177
2178         /* Create folder view */
2179         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2180         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2181                           dialog);
2182
2183         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2184                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2185         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2186                                                FALSE);
2187         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2188                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2189
2190         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2191         back_button = gtk_button_new ();
2192         back_pixbuf = modest_platform_get_icon (_FM_FOLDER_UP, MODEST_ICON_SIZE_BIG);
2193         if (back_pixbuf) {
2194                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2195                 g_object_unref (back_pixbuf);
2196         }
2197
2198         action_button = gtk_button_new ();
2199         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2200
2201         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2202         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2203         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2204         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2205         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2206
2207         /* Create scrollable and add it to the dialog */
2208         folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2209         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2210         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2211
2212         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2213         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2214
2215         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2216
2217         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2218         gtk_widget_show (folder_view_container);
2219         gtk_widget_show (align);
2220         gtk_widget_show (top_vbox);
2221         gtk_widget_show (*folder_view);
2222         gtk_widget_show_all (back_button);
2223         gtk_widget_show (action_button);
2224         gtk_widget_show (buttons_hbox);
2225         gtk_widget_show (dialog);
2226
2227         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2228         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2229         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2230         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2231
2232         /* Simulate the behaviour of a HildonPickerDialog by emitting
2233            a response when a folder is selected */
2234         g_signal_connect (*folder_view, "row-activated",
2235                           G_CALLBACK (on_move_to_dialog_row_activated),
2236                           dialog);
2237
2238         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2239         g_signal_connect (selection, "changed",
2240                           G_CALLBACK (on_move_to_dialog_selection_changed),
2241                           dialog);
2242
2243         g_signal_connect (action_button, "clicked",
2244                           G_CALLBACK (on_move_to_dialog_action_clicked),
2245                           dialog);
2246
2247         g_signal_connect (back_button, "clicked",
2248                           G_CALLBACK (on_move_to_dialog_back_clicked),
2249                           dialog);
2250
2251         move_to_dialog_show_accounts (dialog);
2252
2253         return dialog;
2254 }
2255
2256 TnyList *
2257 modest_platform_get_list_to_move (ModestWindow *window)
2258 {
2259         TnyList *list = NULL;
2260
2261         if (MODEST_IS_HEADER_WINDOW (window)) {
2262                 ModestHeaderView *header_view;
2263
2264                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2265                 list = modest_header_view_get_selected_headers (header_view);
2266         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2267                 ModestFolderView *folder_view;
2268                 TnyFolderStore *selected_folder;
2269
2270                 list = TNY_LIST (tny_simple_list_new ());
2271                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2272                 selected_folder = modest_folder_view_get_selected (folder_view);
2273                 if (selected_folder) {
2274                         tny_list_prepend (list, G_OBJECT (selected_folder));
2275                         g_object_unref (selected_folder);
2276                 }
2277                 return list;
2278         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2279                 TnyHeader *header;
2280
2281                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2282                 if (header) {
2283                         list = TNY_LIST (tny_simple_list_new ());
2284                         tny_list_prepend (list, G_OBJECT (header));
2285                         g_object_unref (header);
2286                 }
2287         } else {
2288                 g_return_val_if_reached (NULL);
2289         }
2290
2291         return list;
2292 }