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