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