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