Remove mandatory dependency on libprofile in hildon2.2 platform
[modest] / src / hildon2 / 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-runtime.h>
36 #include <modest-main-window.h>
37 #include <modest-header-view.h>
38 #include "modest-hildon2-global-settings-dialog.h"
39 #include "modest-widget-memory.h"
40 #include <modest-hildon-includes.h>
41 #include <modest-maemo-utils.h>
42 #include <dbus_api/modest-dbus-callbacks.h>
43 #include <modest-osso-autosave-callbacks.h>
44 #include <libosso.h>
45 #include <tny-maemo-conic-device.h>
46 #include <tny-simple-list.h>
47 #include <tny-merge-folder.h>
48 #include <tny-error.h>
49 #include <tny-folder.h>
50 #include <tny-account-store-view.h>
51 #include <gtk/gtkicontheme.h>
52 #include <gtk/gtkmenuitem.h>
53 #include <gtk/gtkmain.h>
54 #include <modest-text-utils.h>
55 #include "modest-tny-folder.h"
56 #include "modest-tny-account.h"
57 #include <string.h>
58 #include <libgnomevfs/gnome-vfs-mime-utils.h>
59 #include <modest-account-settings-dialog.h>
60 #include <modest-easysetup-wizard-dialog.h>
61 #include "modest-hildon2-sort-dialog.h"
62 #include <hildon/hildon.h>
63 #include <osso-mem.h>
64 #include "hildon2/modest-hildon2-details-dialog.h"
65 #include "hildon2/modest-hildon2-window-mgr.h"
66 #ifdef MODEST_USE_PROFILE
67 #include <keys_nokia.h>
68 #include <libprofile.h>
69 #endif
70 #include <canberra.h>
71 #include <modest-datetime-formatter.h>
72 #include "modest-header-window.h"
73 #include <modest-folder-window.h>
74 #include <modest-account-mgr.h>
75 #include <modest-account-mgr-helpers.h>
76 #include <modest-ui-constants.h>
77 #include <modest-selector-picker.h>
78 #include <modest-icon-names.h>
79
80 #ifdef MODEST_HAVE_MCE
81 #include <mce/dbus-names.h>
82 #endif /*MODEST_HAVE_MCE*/
83
84 #ifdef MODEST_HAVE_ABOOK
85 #include <libosso-abook/osso-abook.h>
86 #endif /*MODEST_HAVE_ABOOK*/
87
88 #ifdef MODEST_HAVE_LIBALARM
89 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
90 #endif /*MODEST_HAVE_LIBALARM*/
91
92
93 #define HILDON_OSSO_URI_ACTION "uri-action"
94 #define URI_ACTION_COPY "copy:"
95 #define MODEST_NOTIFICATION_CATEGORY "email-message"
96 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
97 #ifdef MODEST_USE_PROFILE
98 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
99 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
100 #else
101 #define MAIL_TONE "message-new-email"
102 #endif
103
104 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
105 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
106 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
107 #define MODEST_ALARMD_APPID PACKAGE_NAME
108
109
110 static void _modest_platform_play_email_tone (void);
111
112
113 static void     
114 on_modest_conf_update_interval_changed (ModestConf* self, 
115                                         const gchar *key, 
116                                         ModestConfEvent event,
117                                         ModestConfNotificationId id, 
118                                         gpointer user_data)
119 {
120         g_return_if_fail (key);
121         
122         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
123                 const guint update_interval_minutes = 
124                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
125                 modest_platform_set_update_interval (update_interval_minutes);
126         }
127 }
128
129
130
131 static gboolean
132 check_required_files (void)
133 {
134         FILE *mcc_file = modest_maemo_open_mcc_mapping_file (NULL);
135         if (!mcc_file) {
136                 g_printerr ("modest: check for mcc file failed\n");
137                 return FALSE;
138         } else 
139                 fclose (mcc_file);
140         
141         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
142             access(MODEST_MAEMO_PROVIDER_DATA_FILE, R_OK) != 0) {
143                 g_printerr ("modest: cannot find providers data\n");
144                 return FALSE;
145         }
146         
147         return TRUE;
148 }
149
150
151 /* the gpointer here is the osso_context. */
152 gboolean
153 modest_platform_init (int argc, char *argv[])
154 {
155         osso_context_t *osso_context;
156         
157         osso_hw_state_t hw_state = { 0 };
158         DBusConnection *con;    
159         GSList *acc_names;
160         
161         if (!check_required_files ()) {
162                 g_printerr ("modest: missing required files\n");
163                 return FALSE;
164         }
165         
166         osso_context =  osso_initialize(PACKAGE,PACKAGE_VERSION,
167                                         FALSE, NULL);   
168         if (!osso_context) {
169                 g_printerr ("modest: failed to acquire osso context\n");
170                 return FALSE;
171         }
172         modest_maemo_utils_set_osso_context (osso_context);
173
174         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
175                 g_printerr ("modest: could not get dbus connection\n");
176                 return FALSE;
177         }
178
179         /* Add a D-Bus handler to be used when the main osso-rpc 
180          * D-Bus handler has not handled something.
181          * We use this for D-Bus methods that need to use more complex types 
182          * than osso-rpc supports. 
183          */
184         if (!dbus_connection_add_filter (con,
185                                          modest_dbus_req_filter,
186                                          NULL,
187                                          NULL)) {
188
189                 g_printerr ("modest: Could not add D-Bus filter\n");
190                 return FALSE;
191         }
192
193         /* Register our simple D-Bus callbacks, via the osso API: */
194         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
195                                MODEST_DBUS_SERVICE, 
196                                MODEST_DBUS_OBJECT, 
197                                MODEST_DBUS_IFACE,
198                                modest_dbus_req_handler, NULL /* user_data */);
199         if (result != OSSO_OK) {
200                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
201                 return FALSE;
202         }
203
204         /* Register hardware event dbus callback: */
205         hw_state.shutdown_ind = TRUE;
206         osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
207
208         /* Register osso auto-save callbacks: */
209         result = osso_application_set_autosave_cb (osso_context, 
210                 modest_on_osso_application_autosave, NULL /* user_data */);
211         if (result != OSSO_OK) {
212                 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
213                 return FALSE;
214         }
215         
216
217         /* Make sure that the update interval is changed whenever its gconf key 
218          * is changed */
219         /* CAUTION: we're not using here the
220            modest_conf_listen_to_namespace because we know that there
221            are other parts of Modest listening for this namespace, so
222            we'll receive the notifications anyway. We basically do not
223            use it because there is no easy way to do the
224            modest_conf_forget_namespace */
225         ModestConf *conf = modest_runtime_get_conf ();
226         g_signal_connect (G_OBJECT(conf),
227                           "key_changed",
228                           G_CALLBACK (on_modest_conf_update_interval_changed), 
229                           NULL);
230
231         /* only force the setting of the default interval, if there are actually
232          * any accounts */
233         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
234         if (acc_names) {
235                 /* Get the initial update interval from gconf: */
236                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
237                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
238                 modest_account_mgr_free_account_names (acc_names);
239         }
240
241         
242 #ifdef MODEST_HAVE_ABOOK
243         /* initialize the addressbook */
244         if (!osso_abook_init (&argc, &argv, osso_context)) {
245                 g_printerr ("modest: failed to initialized addressbook\n");
246                 return FALSE;
247         }
248 #endif /*MODEST_HAVE_ABOOK*/
249
250         return TRUE;
251 }
252
253 gboolean
254 modest_platform_uninit (void)
255 {
256         osso_context_t *osso_context =
257                 modest_maemo_utils_get_osso_context ();
258         if (osso_context)
259                 osso_deinitialize (osso_context);
260
261         return TRUE;
262 }
263
264
265
266
267 TnyDevice*
268 modest_platform_get_new_device (void)
269 {
270         return TNY_DEVICE (tny_maemo_conic_device_new ());
271 }
272
273 gchar*
274 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
275                                     gchar **effective_mime_type)
276 {
277         GString *mime_str = NULL;
278         gchar *icon_name  = NULL;
279         gchar **icons, **cursor;
280         
281         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) 
282                 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
283         else {
284                 mime_str = g_string_new (mime_type);
285                 g_string_ascii_down (mime_str);
286         }
287         
288         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
289         
290         for (cursor = icons; cursor; ++cursor) {
291                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
292                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
293                         icon_name = g_strdup ("qgn_list_messagin");
294                         break;
295                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
296                         icon_name = g_strdup (*cursor);
297                         break;
298                 }
299         }
300         g_strfreev (icons);
301
302         if (effective_mime_type)
303                 *effective_mime_type = g_string_free (mime_str, FALSE);
304         else
305                 g_string_free (mime_str, TRUE);
306         
307         return icon_name;
308 }
309
310
311 static gboolean
312 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
313 {
314         GError *err = NULL;
315         gboolean result;
316
317         g_return_val_if_fail (uri, FALSE);
318         
319         result = hildon_uri_open (uri, action, &err);
320         if (!result) {
321                 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
322                             uri, action,  err && err->message ? err->message : "unknown error");
323                 if (err)
324                         g_error_free (err);
325         }
326         return result;
327 }
328
329
330
331 gboolean 
332 modest_platform_activate_uri (const gchar *uri)
333 {
334         HildonURIAction *action;
335         gboolean result = FALSE;
336         GSList *actions, *iter = NULL;
337         
338         g_return_val_if_fail (uri, FALSE);
339         if (!uri)
340                 return FALSE;
341
342         /* don't try to activate file: uri's -- they might confuse the user,
343          * and/or might have security implications */
344         if (!g_str_has_prefix (uri, "file:")) {
345                 
346                 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
347                 
348                 for (iter = actions; iter; iter = g_slist_next (iter)) {
349                         action = (HildonURIAction*) iter->data;
350                         if (action && strcmp (hildon_uri_action_get_service (action),
351                                               "com.nokia.modest") == 0) {
352                                 result = checked_hildon_uri_open (uri, action);
353                                 break;
354                         }
355                 }
356                 
357                 /* if we could not open it with email, try something else */
358                 if (!result)
359                         result = checked_hildon_uri_open (uri, NULL);   
360         } 
361         
362         if (!result) {
363                 ModestWindow *parent =
364                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
365                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
366                                                 _("mcen_ib_unsupported_link"));
367                 g_warning ("%s: cannot open uri '%s'", __FUNCTION__,uri);
368         } 
369         
370         return result;
371 }
372
373 gboolean 
374 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
375 {
376         gint result = 0;
377         DBusConnection *con;
378         gchar *uri_path = NULL;
379         
380         uri_path = gnome_vfs_get_uri_from_local_path (path);    
381         con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
382         
383         if (mime_type)
384                 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
385         if (result != 1)
386                 result = hildon_mime_open_file (con, uri_path);
387         if (result != 1)
388                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
389         
390         return result != 1;
391 }
392
393 typedef struct  {
394         GSList *actions;
395         gchar  *uri;
396 } ModestPlatformPopupInfo;
397
398 static gboolean
399 delete_uri_popup (GtkWidget *menu,
400                   GdkEvent *event,
401                   gpointer userdata)
402 {
403         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
404
405         g_free (popup_info->uri);
406         hildon_uri_free_actions (popup_info->actions);
407
408         return FALSE;
409 }
410
411 static void
412 activate_uri_popup_item (GtkMenuItem *menu_item,
413                          gpointer userdata)
414 {
415         GSList *node;
416         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
417         const gchar* action_name;
418
419         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
420         if (!action_name) {
421                 g_printerr ("modest: no action name defined\n");
422                 return;
423         }
424
425         /* special handling for the copy menu item -- copy the uri to the clipboard */
426         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
427         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
428                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
429                 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
430
431                 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
432                         action_name += strlen ("mailto:");
433                 
434                 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
435                 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
436                 return; /* we're done */
437         }
438         
439         /* now, the real uri-actions... */
440         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
441                 HildonURIAction *action = (HildonURIAction *) node->data;
442                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
443                         if (!checked_hildon_uri_open (popup_info->uri, action)) {
444                                 ModestWindow *parent =
445                                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
446                                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
447                                                                 _("mcen_ib_unsupported_link"));
448                         }
449                         break;
450                 }
451         }
452 }
453
454 gboolean 
455 modest_platform_show_uri_popup (const gchar *uri)
456 {
457         GSList *actions_list;
458
459         if (uri == NULL)
460                 return FALSE;
461         
462         actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
463         if (actions_list) {
464
465                 GtkWidget *menu = gtk_menu_new ();
466                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
467
468                 /* don't add actions for file: uri's -- they might confuse the user,
469                  * and/or might have security implications
470                  * we still allow to copy the url though
471                  */
472                 if (!g_str_has_prefix (uri, "file:")) {                 
473                 
474                         GSList *node;                   
475                         popup_info->actions = actions_list;
476                         popup_info->uri = g_strdup (uri);
477
478                         for (node = actions_list; node != NULL; node = g_slist_next (node)) {
479                                 GtkWidget *menu_item;
480                                 const gchar *action_name;
481                                 const gchar *translation_domain;
482                                 HildonURIAction *action = (HildonURIAction *) node->data;
483                                 action_name = hildon_uri_action_get_name (action);
484                                 translation_domain = hildon_uri_action_get_translation_domain (action);
485                                 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
486                                 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
487                                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
488                                                   popup_info);
489
490                                 if (hildon_uri_is_default_action (action, NULL)) {
491                                         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
492                                 } else {
493                                         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
494                                 }
495                                 gtk_widget_show (menu_item);
496                         }
497                 }
498
499
500                 /* and what to do when the link is deleted */
501                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
502                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
503
504         } else {
505                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
506         }
507
508         return TRUE;
509 }
510
511
512 GdkPixbuf*
513 modest_platform_get_icon (const gchar *name, guint icon_size)
514 {
515         GError *err = NULL;
516         GdkPixbuf* pixbuf = NULL;
517         GtkIconTheme *current_theme = NULL;
518
519         g_return_val_if_fail (name, NULL);
520
521         /* strlen == 0 is not really an error; it just
522          * means the icon is not available
523          */
524         if (!name || strlen(name) == 0)
525                 return NULL;
526
527         current_theme = gtk_icon_theme_get_default ();
528         pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
529                                            GTK_ICON_LOOKUP_NO_SVG,
530                                            &err);
531         if (!pixbuf) {
532                 g_printerr ("modest: error loading theme icon '%s': %s\n",
533                             name, err->message);
534                 g_error_free (err);
535         } 
536         return pixbuf;
537 }
538
539 const gchar*
540 modest_platform_get_app_name (void)
541 {
542         return _("mcen_ap_name");
543 }
544
545 static void
546 entry_insert_text (GtkEditable *editable,
547                    const gchar *text,
548                    gint         length,
549                    gint        *position,
550                    gpointer     data)
551 {
552         gchar *chars;
553         gint chars_length;
554
555         chars = gtk_editable_get_chars (editable, 0, -1);
556         chars_length = g_utf8_strlen (chars, -1);
557         g_free (chars);
558
559         /* Show WID-INF036 */
560         if (chars_length >= 20) {
561                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
562                                                  _CS("ckdg_ib_maximum_characters_reached"));
563         } else {
564                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
565                         /* Show an error */
566                         gchar *tmp, *msg;
567
568                         tmp = g_strndup (folder_name_forbidden_chars,
569                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
570                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
571                         hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)),
572                                                          NULL, msg);
573                         g_free (msg);
574                         g_free (tmp);
575                 } else {
576                         if (length >= 20) {
577                                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
578                                                                  _CS("ckdg_ib_maximum_characters_reached"));
579                         }
580                         /* Write the text in the entry if it's valid */
581                         g_signal_handlers_block_by_func (editable,
582                                                          (gpointer) entry_insert_text, data);
583                         gtk_editable_insert_text (editable, text, length, position);
584                         g_signal_handlers_unblock_by_func (editable,
585                                                            (gpointer) entry_insert_text, data);
586                 }
587         }
588         /* Do not allow further processing */
589         g_signal_stop_emission_by_name (editable, "insert_text");
590 }
591
592 static void
593 entry_changed (GtkEditable *editable,
594                gpointer     user_data)
595 {
596         gchar *chars;
597         GtkWidget *ok_button;
598         GList *buttons;
599
600         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
601         ok_button = GTK_WIDGET (buttons->data);
602
603         chars = gtk_editable_get_chars (editable, 0, -1);
604         g_return_if_fail (chars != NULL);
605
606
607         if (g_utf8_strlen (chars,-1) >= 20) {
608                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
609                                                  _CS("ckdg_ib_maximum_characters_reached"));
610         }
611         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
612
613         /* Free */
614         g_list_free (buttons);
615         g_free (chars);
616 }
617
618
619
620 static void
621 on_response (GtkDialog *dialog,
622              gint response,
623              gpointer user_data)
624 {
625         GtkWidget *entry, *picker;
626         TnyFolderStore *parent;
627         const gchar *new_name;
628         gboolean exists;
629
630         if (response != GTK_RESPONSE_ACCEPT)
631                 return;
632         
633         /* Get entry */
634         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
635         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
636         
637         parent = TNY_FOLDER_STORE (user_data);
638         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
639         exists = FALSE;
640         
641         if (picker != NULL) {
642
643                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
644         }
645
646         /* Look for another folder with the same name */
647         if (modest_tny_folder_has_subfolder_with_name (parent, 
648                                                        new_name,
649                                                        TRUE)) {
650                 exists = TRUE;
651         }
652         
653         if (!exists) {
654                 if (TNY_IS_ACCOUNT (parent) &&
655                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
656                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
657                                                                          new_name)) {
658                         exists = TRUE;
659                 }
660         }
661         
662         if (exists) {
663                 
664                 /* Show an error */
665                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
666                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
667                 /* Select the text */
668                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
669                 gtk_widget_grab_focus (entry);
670                 /* Do not close the dialog */
671                 g_signal_stop_emission_by_name (dialog, "response");
672         }
673
674 }
675
676 typedef struct _FolderChooserData {
677         TnyFolderStore *store;
678         GtkWidget *dialog;
679 } FolderChooserData;
680
681 static void
682 folder_chooser_activated (ModestFolderView *folder_view,
683                           TnyFolderStore *folder,
684                           FolderChooserData *userdata)
685 {
686         userdata->store = folder;
687         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
688 }
689
690 static TnyFolderStore *
691 folder_chooser_dialog_run (ModestFolderView *original)
692 {
693         GtkWidget *folder_view;
694         FolderChooserData userdata = {NULL, NULL};
695         GtkWidget *pannable;
696         const gchar *visible_id = NULL;
697
698         userdata.dialog = hildon_dialog_new ();
699         pannable = hildon_pannable_area_new ();
700         folder_view = modest_platform_create_folder_view (NULL);
701
702         gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
703
704         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original), 
705                                        MODEST_FOLDER_VIEW (folder_view));
706
707         visible_id = 
708                 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
709         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
710                                                                      visible_id);
711
712         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
713         gtk_container_add (GTK_CONTAINER (pannable), folder_view);
714         gtk_widget_set_size_request (pannable, -1, 320);
715
716         gtk_widget_show (folder_view);
717         gtk_widget_show (pannable);
718         gtk_widget_show (userdata.dialog);
719         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
720                           G_CALLBACK (folder_chooser_activated), 
721                           (gpointer) &userdata);
722
723         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
724         gtk_widget_destroy (userdata.dialog);
725
726         return userdata.store;
727 }
728
729 static gchar *
730 folder_store_get_display_name (TnyFolderStore *store)
731 {
732         if (TNY_IS_ACCOUNT (store)) {
733                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
734                         return modest_conf_get_string (modest_runtime_get_conf(),
735                                                        MODEST_CONF_DEVICE_NAME, NULL);
736                 else
737                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
738         } else {
739                 gchar *fname;
740                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
741
742                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
743                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
744                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
745                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
746                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
747                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
748                                 g_free (fname);
749                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
750                         }
751                 } else {
752                         /* Sometimes an special folder is reported by the server as
753                            NORMAL, like some versions of Dovecot */
754                         if (type == TNY_FOLDER_TYPE_NORMAL ||
755                             type == TNY_FOLDER_TYPE_UNKNOWN) {
756                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
757                         }
758                 }
759
760                 if (type == TNY_FOLDER_TYPE_INBOX) {
761                         g_free (fname);
762                         fname = g_strdup (_("mcen_me_folder_inbox"));
763                 }
764                 return fname;
765         }
766 }
767
768 static void
769 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
770 {
771         gchar *name;
772
773         if (store == NULL) {
774                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
775         } else {
776                 GdkPixbuf *pixbuf;
777                 const gchar *icon_name = NULL;
778
779                 g_object_ref (store);
780                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, 
781                                         store, (GDestroyNotify) g_object_unref);
782                 name = folder_store_get_display_name (store);
783                 hildon_button_set_value (HILDON_BUTTON (button), name);
784                 g_free (name);
785
786                 /* Select icon */
787                 if (TNY_IS_ACCOUNT (store)) {
788                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
789                             icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
790                         else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
791                                 icon_name = MODEST_FOLDER_ICON_MMC;
792                         else
793                                 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
794                 } else {
795                         TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
796                         if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
797                                 switch (type) {
798                                 case TNY_FOLDER_TYPE_INBOX:
799                                         icon_name = MODEST_FOLDER_ICON_INBOX;
800                                         break;
801                                 default:
802                                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
803                                 }
804                         } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
805                                 switch (type) {
806                                 case TNY_FOLDER_TYPE_OUTBOX:
807                                         icon_name = MODEST_FOLDER_ICON_OUTBOX;
808                                         break;
809                                 case TNY_FOLDER_TYPE_DRAFTS:
810                                         icon_name = MODEST_FOLDER_ICON_DRAFTS;
811                                         break;
812                                 case TNY_FOLDER_TYPE_SENT:
813                                         icon_name = MODEST_FOLDER_ICON_SENT;
814                                         break;
815                                 default:
816                                         icon_name = MODEST_FOLDER_ICON_NORMAL;
817                                 }
818                         } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
819                                 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
820                         }
821                 }
822
823                 /* Set icon */
824                 pixbuf = modest_platform_get_icon (icon_name, MODEST_ICON_SIZE_SMALL);
825
826                 if (pixbuf) {
827                         hildon_button_set_image (HILDON_BUTTON (button),
828                                                  gtk_image_new_from_pixbuf (pixbuf));
829                         g_object_unref (pixbuf);
830                 }
831         }
832 }
833
834 /* Always returns DUPs so you must free the returned value */
835 static gchar *
836 get_next_folder_name (const gchar *suggested_name, 
837                       TnyFolderStore *suggested_folder)
838 {
839         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
840         unsigned int i;
841         gchar *real_suggested_name;
842
843         if (suggested_name !=NULL) {
844                 return g_strdup (suggested_name);
845         }
846
847         for(i = 0; i < 100; ++ i) {
848                 gboolean exists = FALSE;
849
850                 if (i == 0)
851                         real_suggested_name = g_strdup (default_name);
852                 else
853                         real_suggested_name = g_strdup_printf ("%s(%d)",
854                                                                _FM("ckdg_va_new_folder_name_stub"),
855                                                                i);
856                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
857                                                                     real_suggested_name,
858                                                                     TRUE);
859
860                 if (!exists)
861                         break;
862
863                 g_free (real_suggested_name);
864         }
865
866         /* Didn't find a free number */
867         if (i == 100)
868                 real_suggested_name = g_strdup (default_name);
869
870         return real_suggested_name;
871 }
872
873 typedef struct {
874         ModestFolderView *folder_view;
875         GtkEntry *entry;
876 } FolderPickerHelper;
877
878 static void
879 folder_picker_clicked (GtkButton *button,
880                        FolderPickerHelper *helper)
881 {
882         TnyFolderStore *store;
883
884         store = folder_chooser_dialog_run (helper->folder_view);
885         if (store) {
886                 const gchar *current_name;
887                 gboolean exists;
888
889                 folder_picker_set_store (GTK_BUTTON (button), store);
890
891                 /* Update the name of the folder */
892                 current_name = gtk_entry_get_text (helper->entry);
893                 exists = modest_tny_folder_has_subfolder_with_name (store,
894                                                                     current_name,
895                                                                     TRUE);
896                 if (exists) {
897                         gchar *new_name = get_next_folder_name (NULL, store);
898                         gtk_entry_set_text (helper->entry, new_name);
899                         g_free (new_name);
900                 }
901         }
902 }
903
904 static GtkWidget *
905 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
906 {
907         GtkWidget *button;
908
909         button = hildon_button_new (MODEST_EDITABLE_SIZE,
910                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
911
912         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
913
914         if (suggested) {
915                 folder_picker_set_store (GTK_BUTTON (button), suggested);
916         }
917
918         g_signal_connect (G_OBJECT (button), "clicked",
919                           G_CALLBACK (folder_picker_clicked),
920                           helper);
921
922         return button;
923 }
924
925
926 static gint
927 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
928                                           TnyFolderStore *suggested_parent,
929                                           const gchar *dialog_title,
930                                           const gchar *label_text,
931                                           const gchar *suggested_name,
932                                           gboolean show_name,
933                                           gboolean show_parent,
934                                           gchar **folder_name,
935                                           TnyFolderStore **parent)
936 {
937         GtkWidget *accept_btn = NULL; 
938         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
939         GtkWidget *account_picker = NULL;
940         GList *buttons = NULL;
941         gint result;
942         GtkSizeGroup *sizegroup;
943         ModestFolderView *folder_view;
944         ModestWindow *folder_window;
945         ModestHildon2WindowMgr *window_mgr;
946         FolderPickerHelper *helper = NULL;
947         GtkWidget *top_vbox, *top_align;
948
949         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
950         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
951         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
952         
953         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
954         
955         top_vbox = gtk_vbox_new (FALSE, 0);
956         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
957         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
958         
959         /* Ask the user for the folder name */
960         dialog = gtk_dialog_new_with_buttons (dialog_title,
961                                               parent_window,
962                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
963                                               _FM("ckdg_bd_new_folder_dialog_ok"),
964                                               GTK_RESPONSE_ACCEPT,
965                                               NULL);
966
967         /* Add accept button (with unsensitive handler) */
968         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
969         accept_btn = GTK_WIDGET (buttons->data);
970
971         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
972
973         if (show_name) {
974                 label_entry = gtk_label_new (label_text);
975                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
976                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
977
978                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
979                 gtk_size_group_add_widget (sizegroup, label_entry);
980                 
981                 if (suggested_name)
982                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
983                 else
984                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
985                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
986                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
987                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
988                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
989         }
990         
991         if (show_parent) {
992           
993                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
994
995                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
996                 gtk_size_group_add_widget (sizegroup, label_location);
997
998                 helper = g_slice_new0 (FolderPickerHelper);
999                 helper->folder_view = folder_view;
1000                 helper->entry = (GtkEntry *) entry;
1001
1002                 account_picker = folder_picker_new (suggested_parent, helper);
1003         }
1004
1005         g_object_unref (sizegroup);
1006         
1007         /* Connect to the response method to avoid closing the dialog
1008            when an invalid name is selected*/
1009         g_signal_connect (dialog,
1010                           "response",
1011                           G_CALLBACK (on_response),
1012                           suggested_parent);
1013         
1014         if (show_name) {
1015                 /* Track entry changes */
1016                 g_signal_connect (entry,
1017                                   "insert-text",
1018                                   G_CALLBACK (entry_insert_text),
1019                                   dialog);
1020                 g_signal_connect (entry,
1021                                   "changed",
1022                                   G_CALLBACK (entry_changed),
1023                                   dialog);
1024         }
1025         
1026         
1027         /* Some locales like pt_BR need this to get the full window
1028            title shown */
1029         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1030         
1031         /* Create the hbox */
1032         if (show_name) {
1033                 hbox = gtk_hbox_new (FALSE, 12);
1034                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1035                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1036                 
1037                 /* Add hbox to dialog */
1038                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1039                                     hbox, FALSE, FALSE, 0);
1040                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1041         }
1042
1043         if (show_parent) {
1044                 hbox = gtk_hbox_new (FALSE, 12);
1045                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1046                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1047
1048                 /* Add hbox to dialog */
1049                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1050                                     hbox, FALSE, FALSE, 0);
1051                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1052         }
1053         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1054                                      GTK_WINDOW (dialog), parent_window);
1055
1056         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1057         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1058
1059         gtk_widget_show_all (GTK_WIDGET(dialog));
1060
1061         result = gtk_dialog_run (GTK_DIALOG(dialog));
1062         if (result == GTK_RESPONSE_ACCEPT) {
1063                 if (show_name)
1064                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1065                 if (show_parent) {
1066                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1067                         if (*parent)
1068                                 g_object_ref (*parent);
1069                 }
1070         }
1071
1072         gtk_widget_destroy (dialog);
1073
1074         if (helper)
1075                 g_slice_free (FolderPickerHelper, helper);
1076
1077         while (gtk_events_pending ())
1078                 gtk_main_iteration ();
1079
1080         return result;
1081 }
1082
1083 gint
1084 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1085                                        TnyFolderStore *suggested_folder,
1086                                        gchar *suggested_name,
1087                                        gchar **folder_name,
1088                                        TnyFolderStore **parent_folder)
1089 {
1090         gchar *real_suggested_name = NULL;
1091         gint result;
1092         ModestTnyAccountStore *acc_store;
1093         TnyAccount *account;
1094
1095         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1096                                                     suggested_folder);
1097
1098         /* In hildon 2.2 we always suggest the archive folder as parent */
1099         acc_store = modest_runtime_get_account_store ();
1100         account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1101         if (account) {
1102                 suggested_folder = (TnyFolderStore *)
1103                         modest_tny_account_get_special_folder (account,
1104                                                                TNY_FOLDER_TYPE_ARCHIVE);
1105                 g_object_unref (account);
1106                 account = NULL;
1107         }
1108
1109         /* If there is not archive folder then fallback to local folders account */
1110         if (!suggested_folder)
1111                 suggested_folder = (TnyFolderStore *)
1112                         modest_tny_account_store_get_local_folders_account (acc_store);
1113
1114         result = modest_platform_run_folder_common_dialog (parent_window,
1115                                                            suggested_folder,
1116                                                            _HL("ckdg_ti_new_folder"),
1117                                                            _FM("ckdg_fi_new_folder_name"),
1118                                                            real_suggested_name,
1119                                                            TRUE,
1120                                                            TRUE,
1121                                                            folder_name,
1122                                                            parent_folder);
1123
1124         g_free(real_suggested_name);
1125
1126         return result;
1127 }
1128
1129 gint
1130 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1131                                           TnyFolderStore *parent_folder,
1132                                           const gchar *suggested_name,
1133                                           gchar **folder_name)
1134 {
1135         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1136
1137         return modest_platform_run_folder_common_dialog (parent_window, 
1138                                                          parent_folder,
1139                                                          _HL("ckdg_ti_rename_folder"),
1140                                                          _HL("ckdg_fi_rename_name"),
1141                                                          suggested_name,
1142                                                          TRUE,
1143                                                          FALSE,
1144                                                          folder_name,
1145                                                          NULL);
1146 }
1147
1148
1149
1150 static void
1151 on_destroy_dialog (GtkWidget *dialog)
1152 {
1153         /* This could happen when the dialogs get programatically
1154            hidden or destroyed (for example when closing the
1155            application while a dialog is being shown) */
1156         if (!GTK_IS_WIDGET (dialog))
1157                 return;
1158
1159         gtk_widget_destroy (dialog);
1160
1161         if (gtk_events_pending ())
1162                 gtk_main_iteration ();
1163 }
1164
1165 gint
1166 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1167                                          const gchar *message)
1168 {
1169         GtkWidget *dialog;
1170         gint response;
1171         
1172         dialog = hildon_note_new_confirmation (parent_window, message);
1173         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1174                                      GTK_WINDOW (dialog), parent_window);
1175
1176         response = gtk_dialog_run (GTK_DIALOG (dialog));
1177
1178         on_destroy_dialog (dialog);
1179
1180         return response;
1181 }
1182
1183 gint
1184 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1185                                                       const gchar *message,
1186                                                       const gchar *button_accept,
1187                                                       const gchar *button_cancel)
1188 {
1189         GtkWidget *dialog;
1190         gint response;
1191         
1192         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1193                                                            button_accept, GTK_RESPONSE_ACCEPT,
1194                                                            button_cancel, GTK_RESPONSE_CANCEL,
1195                                                            NULL);
1196
1197         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1198                                      GTK_WINDOW (dialog), parent_window);
1199
1200         response = gtk_dialog_run (GTK_DIALOG (dialog));
1201
1202         on_destroy_dialog (dialog);
1203
1204         return response;
1205 }
1206         
1207 void
1208 modest_platform_run_information_dialog (GtkWindow *parent_window,
1209                                         const gchar *message,
1210                                         gboolean block)
1211 {
1212         GtkWidget *note;
1213         
1214         note = hildon_note_new_information (parent_window, message);
1215         if (block)
1216                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1217                                              GTK_WINDOW (note), parent_window);
1218         
1219         if (block) {
1220                 gtk_dialog_run (GTK_DIALOG (note));
1221         
1222                 on_destroy_dialog (note);
1223         } else {
1224                 g_signal_connect_swapped (note,
1225                                           "response", 
1226                                           G_CALLBACK (on_destroy_dialog),
1227                                           note);
1228
1229                 gtk_widget_show_all (note);
1230         }
1231 }
1232
1233 typedef struct _ConnectAndWaitData {
1234         GMutex *mutex;
1235         GMainLoop *wait_loop;
1236         gboolean has_callback;
1237         gulong handler;
1238 } ConnectAndWaitData;
1239
1240
1241 static void
1242 quit_wait_loop (TnyAccount *account,
1243                 ConnectAndWaitData *data) 
1244 {
1245         /* Set the has_callback to TRUE (means that the callback was
1246            executed and wake up every code waiting for cond to be
1247            TRUE */
1248         g_mutex_lock (data->mutex);
1249         data->has_callback = TRUE;
1250         if (data->wait_loop)
1251                 g_main_loop_quit (data->wait_loop);
1252         g_mutex_unlock (data->mutex);
1253 }
1254
1255 static void
1256 on_connection_status_changed (TnyAccount *account, 
1257                               TnyConnectionStatus status,
1258                               gpointer user_data)
1259 {
1260         TnyConnectionStatus conn_status;
1261         ConnectAndWaitData *data;
1262                         
1263         /* Ignore if reconnecting or disconnected */
1264         conn_status = tny_account_get_connection_status (account);
1265         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1266             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1267                 return;
1268
1269         /* Remove the handler */
1270         data = (ConnectAndWaitData *) user_data;
1271         g_signal_handler_disconnect (account, data->handler);
1272
1273         /* Quit from wait loop */
1274         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1275 }
1276
1277 static void
1278 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1279                                     gboolean canceled, 
1280                                     GError *err, 
1281                                     gpointer user_data)
1282 {
1283         /* Quit from wait loop */
1284         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1285 }
1286
1287 gboolean 
1288 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1289                                   TnyAccount *account)
1290 {
1291         ConnectAndWaitData *data = NULL;
1292         gboolean device_online;
1293         TnyDevice *device;
1294         TnyConnectionStatus conn_status;
1295         gboolean user_requested;
1296         
1297         device = modest_runtime_get_device();
1298         device_online = tny_device_is_online (device);
1299
1300         /* Whether the connection is user requested or automatically
1301            requested, for example via D-Bus */
1302         user_requested = (parent_window) ? TRUE : FALSE;
1303
1304         /* If there is no account check only the device status */
1305         if (!account) {
1306                 if (device_online)
1307                         return TRUE;
1308                 else
1309                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1310                                                                NULL, user_requested);
1311         }
1312
1313         /* Return if the account is already connected */
1314         conn_status = tny_account_get_connection_status (account);
1315         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1316                 return TRUE;
1317
1318         /* Create the helper */
1319         data = g_slice_new0 (ConnectAndWaitData);
1320         data->mutex = g_mutex_new ();
1321         data->has_callback = FALSE;
1322
1323         /* Connect the device */
1324         if (!device_online) {
1325                 /* Track account connection status changes */
1326                 data->handler = g_signal_connect (account, "connection-status-changed",
1327                                                   G_CALLBACK (on_connection_status_changed),
1328                                                   data);
1329                 /* Try to connect the device */
1330                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1331                                                                 NULL, user_requested);
1332
1333                 /* If the device connection failed then exit */
1334                 if (!device_online && data->handler)
1335                         goto frees;
1336         } else {
1337                 /* Force a reconnection of the account */
1338                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1339                                               on_tny_camel_account_set_online_cb, data);
1340         }
1341
1342         /* Wait until the callback is executed */
1343         g_mutex_lock (data->mutex);
1344         if (!data->has_callback) {
1345                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1346                 gdk_threads_leave ();
1347                 g_mutex_unlock (data->mutex);
1348                 g_main_loop_run (data->wait_loop);
1349                 g_mutex_lock (data->mutex);
1350                 gdk_threads_enter ();
1351         }
1352         g_mutex_unlock (data->mutex);
1353
1354  frees:
1355         if (g_signal_handler_is_connected (account, data->handler))
1356                 g_signal_handler_disconnect (account, data->handler);
1357         g_mutex_free (data->mutex);
1358         g_main_loop_unref (data->wait_loop);
1359         g_slice_free (ConnectAndWaitData, data);
1360
1361         conn_status = tny_account_get_connection_status (account);
1362         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1363 }
1364
1365 gboolean 
1366 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1367 {
1368         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1369                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1370                         /* This must be a maildir account, which does not require a connection: */
1371                         return TRUE;
1372                 }
1373         }
1374
1375         return modest_platform_connect_and_wait (parent_window, account);
1376 }
1377
1378 gboolean 
1379 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1380 {
1381         if (!folder_store)
1382                 return TRUE; /* Maybe it is something local. */
1383                 
1384         gboolean result = TRUE;
1385         if (TNY_IS_FOLDER (folder_store)) {
1386                 /* Get the folder's parent account: */
1387                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1388                 if (account != NULL) {
1389                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1390                         g_object_unref (account);
1391                 }
1392         } else if (TNY_IS_ACCOUNT (folder_store)) {
1393                 /* Use the folder store as an account: */
1394                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1395         }
1396
1397         return result;
1398 }
1399
1400 GtkWidget *
1401 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1402 {
1403         GtkWidget *dialog;
1404
1405         dialog = modest_hildon2_sort_dialog_new (parent_window);
1406
1407         return dialog;
1408 }
1409
1410
1411 gboolean 
1412 modest_platform_set_update_interval (guint minutes)
1413 {
1414 #ifdef MODEST_HAVE_LIBALARM
1415         
1416         ModestConf *conf = modest_runtime_get_conf ();
1417         if (!conf)
1418                 return FALSE;
1419                 
1420         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1421
1422         /* Delete any existing alarm,
1423          * because we will replace it: */
1424         if (alarm_cookie) {
1425                 if (alarmd_event_del(alarm_cookie) != 0)
1426                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1427                 alarm_cookie = 0;
1428                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1429         }
1430         
1431         /* 0 means no updates: */
1432         if (minutes == 0)
1433                 return TRUE;
1434         
1435      
1436         /* Register alarm: */
1437         
1438         /* Set the interval in alarm_event_t structure: */
1439         alarm_event_t *event = alarm_event_create ();
1440         alarm_event_add_actions (event, 1);
1441         alarm_action_t *action = alarm_event_get_action (event, 0);
1442         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1443         event->alarm_time = minutes * 60; /* seconds */
1444         
1445         /* Set recurrence every few minutes: */
1446         event->recur_secs = minutes*60;
1447         event->recur_count = -1; /* Means infinite */
1448
1449         /* Specify what should happen when the alarm happens:
1450          * It should call this D-Bus method: */
1451          
1452         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1453         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1454         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1455         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1456         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1457
1458         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1459          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1460          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1461          * This is why we want to use the Alarm API instead of just g_timeout_add().
1462          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1463          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1464          */
1465         event->flags = ALARM_EVENT_CONNECTED;
1466         
1467         alarm_cookie = alarmd_event_add (event);
1468
1469         /* now, free it */
1470         alarm_event_delete (event);
1471         
1472         /* Store the alarm ID in GConf, so we can remove it later:
1473          * This is apparently valid between application instances. */
1474         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1475         
1476         if (!alarm_cookie) {
1477             /* Error */
1478             g_debug ("Error setting alarm event. \n");
1479             
1480             return FALSE;
1481         }
1482 #endif /* MODEST_HAVE_LIBALARM */       
1483         return TRUE;
1484 }
1485
1486 void
1487 modest_platform_push_email_notification(void)
1488 {
1489         gboolean screen_on, app_in_foreground;
1490
1491         /* Get the window status */
1492         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1493
1494         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1495
1496         /* If the screen is on and the app is in the
1497            foreground we don't show anything */
1498         if (!(screen_on && app_in_foreground)) {
1499
1500                 _modest_platform_play_email_tone ();
1501
1502                 /* Activate LED. This must be deactivated by
1503                    modest_platform_remove_new_mail_notifications */
1504 #ifdef MODEST_HAVE_MCE
1505                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1506                                      MCE_SERVICE,
1507                                      MCE_REQUEST_PATH,
1508                                      MCE_REQUEST_IF,
1509                                      MCE_ACTIVATE_LED_PATTERN,
1510                                      NULL,
1511                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1512                                      DBUS_TYPE_INVALID);
1513 #endif
1514         }
1515 }
1516
1517 void 
1518 modest_platform_on_new_headers_received (TnyList *header_list,
1519                                          gboolean show_visual)
1520 {
1521         g_return_if_fail (TNY_IS_LIST(header_list));
1522
1523         if (tny_list_get_length(header_list) == 0) {
1524                 g_warning ("%s: header list is empty", __FUNCTION__);
1525                 return;
1526         }
1527
1528         if (!show_visual) {
1529                 modest_platform_push_email_notification ();
1530                 /* We do a return here to avoid indentation with an else */
1531                 return;
1532         }
1533
1534 #ifdef MODEST_HAVE_HILDON_NOTIFY
1535         HildonNotification *notification;
1536         TnyIterator *iter;
1537         GSList *notifications_list = NULL;
1538
1539         /* Get previous notifications ids */
1540         notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1541                                                    MODEST_CONF_NOTIFICATION_IDS,
1542                                                    MODEST_CONF_VALUE_INT, NULL);
1543
1544         iter = tny_list_create_iterator (header_list);
1545         while (!tny_iterator_is_done (iter)) {
1546                 gchar *url = NULL, *display_address = NULL;
1547                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1548                 TnyFolder *folder = tny_header_get_folder (header);
1549                 gboolean first_notification = TRUE;
1550                 gint notif_id;
1551                 gchar *str;
1552
1553                 display_address = tny_header_dup_from (header);
1554                 /* string is changed in-place */
1555                 modest_text_utils_get_display_address (display_address);
1556
1557                 str = tny_header_dup_subject (header);
1558                 notification = hildon_notification_new (display_address,
1559                                                         str,
1560                                                         "qgn_list_messagin",
1561                                                         MODEST_NOTIFICATION_CATEGORY);
1562                 g_free (str);
1563                 /* Create the message URL */
1564                 str = tny_header_dup_uid (header);
1565                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1566                                        str);
1567                 g_free (str);
1568
1569                 hildon_notification_add_dbus_action(notification,
1570                                                     "default",
1571                                                     "Cancel",
1572                                                     MODEST_DBUS_SERVICE,
1573                                                     MODEST_DBUS_OBJECT,
1574                                                     MODEST_DBUS_IFACE,
1575                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1576                                                     G_TYPE_STRING, url,
1577                                                     -1);
1578
1579                 /* Play sound if the user wants. Show the LED
1580                    pattern. Show and play just one */
1581                 if (G_UNLIKELY (first_notification)) {
1582                         TnyAccount *account;
1583
1584                         first_notification = FALSE;
1585
1586                         /* Set the led pattern */
1587                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1588                                                             "dialog-type", 4);
1589                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1590                                                             "led-pattern",
1591                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1592
1593                         /* Set the account of the headers */
1594                         account = tny_folder_get_account (folder);
1595                         if (account) {
1596                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1597                                                                     "email-account",
1598                                                                     tny_account_get_id (account));
1599                                 g_object_unref (account);
1600                         }
1601                 }
1602
1603                 /* Notify. We need to do this in an idle because this function
1604                    could be called from a thread */
1605                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1606
1607                 /* Save id in the list */
1608                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1609                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1610                 /* We don't listen for the "closed" signal, because we
1611                    don't care about if the notification was removed or
1612                    not to store the list in gconf */
1613         
1614                 /* Free & carry on */
1615                 g_free (display_address);
1616                 g_free (url);
1617                 g_object_unref (folder);
1618                 g_object_unref (header);
1619                 tny_iterator_next (iter);
1620         }
1621         g_object_unref (iter);
1622
1623         /* Save the ids */
1624         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1625                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1626
1627         g_slist_free (notifications_list);
1628         
1629 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1630 }
1631
1632 void
1633 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1634 {
1635         if (only_visuals) {
1636 #ifdef MODEST_HAVE_MCE
1637                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1638                                      MCE_SERVICE,
1639                                      MCE_REQUEST_PATH,
1640                                      MCE_REQUEST_IF,
1641                                      MCE_DEACTIVATE_LED_PATTERN,
1642                                      NULL,
1643                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1644                                      DBUS_TYPE_INVALID);
1645 #endif
1646                 return;
1647         }
1648
1649 #ifdef MODEST_HAVE_HILDON_NOTIFY
1650         GSList *notif_list = NULL;
1651
1652         /* Get previous notifications ids */
1653         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1654                                            MODEST_CONF_NOTIFICATION_IDS, 
1655                                            MODEST_CONF_VALUE_INT, NULL);
1656
1657         while (notif_list) {
1658                 gint notif_id;
1659                 NotifyNotification *notif;
1660
1661                 /* Nasty HACK to remove the notifications, set the id
1662                    of the existing ones and then close them */
1663                 notif_id = GPOINTER_TO_INT(notif_list->data);
1664                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1665                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1666
1667                 /* Close the notification, note that some ids could be
1668                    already invalid, but we don't care because it does
1669                    not fail */
1670                 notify_notification_close(notif, NULL);
1671                 g_object_unref(notif);
1672
1673                 /* Delete the link, it's like going to the next */
1674                 notif_list = g_slist_delete_link (notif_list, notif_list);
1675         }
1676
1677         /* Save the ids */
1678         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1679                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1680
1681         g_slist_free (notif_list);
1682
1683 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1684 }
1685
1686
1687
1688 GtkWidget * 
1689 modest_platform_get_global_settings_dialog ()
1690 {
1691         return modest_hildon2_global_settings_dialog_new ();
1692 }
1693
1694 void
1695 modest_platform_show_help (GtkWindow *parent_window, 
1696                            const gchar *help_id)
1697 {
1698         return;
1699 }
1700
1701 void 
1702 modest_platform_show_search_messages (GtkWindow *parent_window)
1703 {
1704         osso_return_t result = OSSO_ERROR;
1705         
1706         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1707                                              "osso_global_search",
1708                                              "search_email", NULL, DBUS_TYPE_INVALID);
1709
1710         if (result != OSSO_OK) {
1711                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1712         }
1713 }
1714
1715 void 
1716 modest_platform_show_addressbook (GtkWindow *parent_window)
1717 {
1718         osso_return_t result = OSSO_ERROR;
1719
1720         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1721                                              "osso_addressbook",
1722                                              "top_application", NULL, DBUS_TYPE_INVALID);
1723
1724         if (result != OSSO_OK) {
1725                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1726         }
1727 }
1728
1729 GtkWidget *
1730 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1731 {
1732         GtkWidget *widget = modest_folder_view_new (query);
1733
1734         /* Show one account by default */
1735         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1736                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1737
1738         /* Restore settings */
1739         modest_widget_memory_restore (modest_runtime_get_conf(), 
1740                                       G_OBJECT (widget),
1741                                       MODEST_CONF_FOLDER_VIEW_KEY);
1742
1743         return widget;
1744 }
1745
1746 void
1747 banner_finish (gpointer data, GObject *object)
1748 {
1749         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1750         modest_window_mgr_unregister_banner (mgr);
1751         g_object_unref (mgr);
1752 }
1753
1754 void 
1755 modest_platform_information_banner (GtkWidget *parent,
1756                                     const gchar *icon_name,
1757                                     const gchar *text)
1758 {
1759         GtkWidget *banner, *banner_parent = NULL;
1760         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1761
1762         if (modest_window_mgr_get_num_windows (mgr) == 0)
1763                 return;
1764
1765         if (parent && GTK_IS_WINDOW (parent)) {
1766                 /* If the window is the active one then show the
1767                    banner on top of this window */
1768                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1769                         banner_parent = parent;
1770                 /* If the window is not the topmost but it's visible
1771                    (it's minimized for example) then show the banner
1772                    with no parent */ 
1773                 else if (GTK_WIDGET_VISIBLE (parent))
1774                         banner_parent = NULL;
1775                 /* If the window is hidden (like the main window when
1776                    running in the background) then do not show
1777                    anything */
1778                 else 
1779                         return;
1780         }
1781
1782
1783         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1784
1785         modest_window_mgr_register_banner (mgr);
1786         g_object_ref (mgr);
1787         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1788 }
1789
1790 void
1791 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1792                                                  const gchar *icon_name,
1793                                                  const gchar *text,
1794                                                  gint timeout)
1795 {
1796         GtkWidget *banner;
1797
1798         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1799                 return;
1800
1801         banner = hildon_banner_show_information (parent, icon_name, text);
1802         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1803 }
1804
1805 GtkWidget *
1806 modest_platform_animation_banner (GtkWidget *parent,
1807                                   const gchar *animation_name,
1808                                   const gchar *text)
1809 {
1810         GtkWidget *inf_note = NULL;
1811
1812         g_return_val_if_fail (text != NULL, NULL);
1813
1814         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1815                 return NULL;
1816
1817         /* If the parent is not visible then do not show */
1818         if (parent && !GTK_WIDGET_VISIBLE (parent))
1819                 return NULL;
1820
1821         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1822
1823         return inf_note;
1824 }
1825
1826 typedef struct
1827 {
1828         GMainLoop* loop;
1829         TnyAccount *account;
1830         gboolean is_online;
1831         gint count_tries;
1832 } CheckAccountIdleData;
1833
1834 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1835
1836 static gboolean 
1837 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1838 {
1839         gboolean stop_trying = FALSE;
1840         g_return_val_if_fail (data && data->account, FALSE);
1841         
1842         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1843                 tny_account_get_connection_status (data->account));     
1844         
1845         if (data && data->account && 
1846                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1847                  * after which the account is likely to be usable, or never likely to be usable soon: */
1848                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1849         {
1850                 data->is_online = TRUE;
1851                 
1852                 stop_trying = TRUE;
1853         } else {
1854                 /* Give up if we have tried too many times: */
1855                 if (data->count_tries >= NUMBER_OF_TRIES) {
1856                         stop_trying = TRUE;
1857                 } else {
1858                         /* Wait for another timeout: */
1859                         ++(data->count_tries);
1860                 }
1861         }
1862         
1863         if (stop_trying) {
1864                 /* Allow the function that requested this idle callback to continue: */
1865                 if (data->loop)
1866                         g_main_loop_quit (data->loop);
1867                         
1868                 if (data->account)
1869                         g_object_unref (data->account);
1870                 
1871                 return FALSE; /* Don't call this again. */
1872         } else {
1873                 return TRUE; /* Call this timeout callback again. */
1874         }
1875 }
1876
1877 /* Return TRUE immediately if the account is already online,
1878  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1879  * soon as the account is online, or FALSE if the account does 
1880  * not become online in the NUMBER_OF_TRIES seconds.
1881  * This is useful when the D-Bus method was run immediately after 
1882  * the application was started (when using D-Bus activation), 
1883  * because the account usually takes a short time to go online.
1884  * The return value is maybe not very useful.
1885  */
1886 gboolean
1887 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1888 {
1889         gboolean is_online;
1890
1891         g_return_val_if_fail (account, FALSE);
1892
1893         if (!tny_device_is_online (modest_runtime_get_device())) {
1894                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1895                 return FALSE;
1896         }
1897
1898         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1899          * so we avoid wait unnecessarily: */
1900         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1901                 return TRUE;
1902
1903         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1904          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1905          * we want to avoid. */
1906         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1907                 return TRUE;
1908                 
1909         /* This blocks on the result: */
1910         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1911         data->is_online = FALSE;
1912         data->account = account;
1913         g_object_ref (data->account);
1914         data->count_tries = 0;
1915                 
1916         GMainContext *context = NULL; /* g_main_context_new (); */
1917         data->loop = g_main_loop_new (context, FALSE /* not running */);
1918
1919         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1920
1921         /* This main loop will run until the idle handler has stopped it: */
1922         g_main_loop_run (data->loop);
1923
1924         g_main_loop_unref (data->loop);
1925         /* g_main_context_unref (context); */
1926
1927         is_online = data->is_online;
1928         g_slice_free (CheckAccountIdleData, data);
1929         
1930         return is_online;       
1931 }
1932
1933
1934
1935 static void
1936 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1937 {
1938         /* GTK_RESPONSE_HELP means we need to show the certificate */
1939         if (response_id == GTK_RESPONSE_APPLY) {
1940                 GtkWidget *note;
1941                 gchar *msg;
1942                 
1943                 /* Do not close the dialog */
1944                 g_signal_stop_emission_by_name (dialog, "response");
1945
1946                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1947                 note = hildon_note_new_information (NULL, msg);
1948                 gtk_dialog_run (GTK_DIALOG(note));
1949                 gtk_widget_destroy (note);
1950         }
1951 }
1952
1953
1954 gboolean
1955 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1956                                                      const gchar *certificate)
1957 {
1958         GtkWidget *note;
1959         gint response;
1960         ModestWindow *win;
1961         HildonWindowStack *stack;
1962
1963         stack = hildon_window_stack_get_default ();
1964         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1965
1966         if (!win) {
1967           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1968                            __FUNCTION__);
1969                 return FALSE;
1970         }
1971
1972         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1973                                            server_name);
1974
1975         /* We use GTK_RESPONSE_APPLY because we want the button in the
1976            middle of OK and CANCEL the same as the browser does for
1977            example. With GTK_RESPONSE_HELP the view button is aligned
1978            to the left while the other two to the right */
1979         note = hildon_note_new_confirmation_add_buttons  (
1980                 NULL,
1981                 question,
1982                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1983                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1984                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1985                 NULL, NULL);
1986
1987         g_signal_connect (G_OBJECT(note), "response", 
1988                           G_CALLBACK(on_cert_dialog_response),
1989                           (gpointer) certificate);
1990
1991         response = gtk_dialog_run(GTK_DIALOG(note));
1992
1993         on_destroy_dialog (note);
1994         g_free (question);
1995
1996         return response == GTK_RESPONSE_OK;
1997 }
1998
1999 gboolean
2000 modest_platform_run_alert_dialog (const gchar* prompt,
2001                                   gboolean is_question)
2002 {
2003         ModestWindow *top_win;
2004         HildonWindowStack *stack;
2005
2006         stack = hildon_window_stack_get_default ();
2007         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2008
2009         if (!top_win) {
2010                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2011                            __FUNCTION__);
2012                 return FALSE;
2013         }
2014
2015         gboolean retval = TRUE;
2016         if (is_question) {
2017                 /* The Tinymail documentation says that we should show Yes and No buttons,
2018                  * when it is a question.
2019                  * Obviously, we need tinymail to use more specific error codes instead,
2020                  * so we know what buttons to show. */
2021                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2022                                                                               prompt));
2023                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2024                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2025
2026                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2027                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2028
2029                 on_destroy_dialog (dialog);
2030         } else {
2031                 /* Just show the error text and use the default response: */
2032                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2033                                                         prompt, FALSE);
2034         }
2035         return retval;
2036 }
2037
2038 /***************/
2039 typedef struct {
2040         GtkWindow *parent_window;
2041         ModestConnectedPerformer callback;
2042         TnyAccount *account;
2043         gpointer user_data;
2044         gchar *iap;
2045         TnyDevice *device;
2046 } OnWentOnlineInfo;
2047  
2048 static void 
2049 on_went_online_info_free (OnWentOnlineInfo *info)
2050 {
2051         /* And if we cleanup, we DO cleanup  :-)  */
2052         
2053         if (info->device)
2054                 g_object_unref (info->device);
2055         if (info->iap)
2056                 g_free (info->iap);
2057         if (info->parent_window)
2058                 g_object_unref (info->parent_window);
2059         if (info->account)
2060                 g_object_unref (info->account);
2061         
2062         g_slice_free (OnWentOnlineInfo, info);
2063         
2064         /* We're done ... */
2065         
2066         return;
2067 }
2068  
2069 static void
2070 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2071 {
2072         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2073  
2074         /* Now it's really time to callback to the caller. If going online didn't succeed,
2075          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2076          * canceled will be set. Etcetera etcetera. */
2077         
2078         if (info->callback) {
2079                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2080         }
2081         
2082         /* This is our last call, we must cleanup here if we didn't yet do that */
2083         on_went_online_info_free (info);
2084         
2085         return;
2086 }
2087  
2088  
2089 static void
2090 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2091 {
2092         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2093         info->iap = g_strdup (iap_id);
2094         
2095         if (canceled || err || !info->account) {
2096         
2097                 /* If there's a problem or if there's no account (then that's it for us, we callback
2098                  * the caller's callback now. He'll have to handle err or canceled, of course.
2099                  * We are not really online, as the account is not really online here ... */    
2100                 
2101                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2102                  * this info. We don't cleanup err, Tinymail does that! */
2103                 
2104                 if (info->callback) {
2105                         
2106                         /* info->account can be NULL here, this means that the user did not
2107                          * provide a nice account instance. We'll assume that the user knows
2108                          * what he's doing and is happy with just the device going online. 
2109                          * 
2110                          * We can't do magic, we don't know what account the user wants to
2111                          * see going online. So just the device goes online, end of story */
2112                         
2113                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2114                 }
2115                 
2116         } else if (info->account) {
2117                 
2118                 /* If there's no problem and if we have an account, we'll put the account
2119                  * online too. When done, the callback of bringing the account online
2120                  * will callback the caller's callback. This is the most normal case. */
2121  
2122                 info->device = TNY_DEVICE (g_object_ref (device));
2123                 
2124                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2125                                               on_account_went_online, info);
2126                 
2127                 /* The on_account_went_online cb frees up the info, go look if you
2128                  * don't believe me! (so we return here) */
2129                 
2130                 return;
2131         }
2132         
2133         /* We cleanup if we are not bringing the account online too */
2134         on_went_online_info_free (info);
2135  
2136         return; 
2137 }
2138         
2139 void 
2140 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2141                                      gboolean force,
2142                                      TnyAccount *account, 
2143                                      ModestConnectedPerformer callback, 
2144                                      gpointer user_data)
2145 {
2146         gboolean device_online;
2147         TnyDevice *device;
2148         TnyConnectionStatus conn_status;
2149         OnWentOnlineInfo *info;
2150         
2151         device = modest_runtime_get_device();
2152         device_online = tny_device_is_online (device);
2153
2154         /* If there is no account check only the device status */
2155         if (!account) {
2156                 
2157                 if (device_online) {
2158  
2159                         /* We promise to instantly perform the callback, so ... */
2160                         if (callback) {
2161                                 callback (FALSE, NULL, parent_window, account, user_data);
2162                         }
2163                         
2164                 } else {
2165                         
2166                         info = g_slice_new0 (OnWentOnlineInfo);
2167                         
2168                         info->iap = NULL;
2169                         info->device = NULL;
2170                         info->account = NULL;
2171                 
2172                         if (parent_window)
2173                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2174                         else
2175                                 info->parent_window = NULL;
2176                         info->user_data = user_data;
2177                         info->callback = callback;
2178                 
2179                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2180                                                               force, on_conic_device_went_online, 
2181                                                               info);
2182  
2183                         /* We'll cleanup in on_conic_device_went_online */
2184                 }
2185  
2186                 /* The other code has no more reason to run. This is all that we can do for the
2187                  * caller (he should have given us a nice and clean account instance!). We
2188                  * can't do magic, we don't know what account he intends to bring online. So
2189                  * we'll just bring the device online (and await his false bug report). */
2190                 
2191                 return;
2192         }
2193  
2194         
2195         /* Return if the account is already connected */
2196         
2197         conn_status = tny_account_get_connection_status (account);
2198         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2199  
2200                 /* We promise to instantly perform the callback, so ... */
2201                 if (callback) {
2202                         callback (FALSE, NULL, parent_window, account, user_data);
2203                 }
2204                 
2205                 return;
2206         }
2207         
2208         /* Else, we are in a state that requires that we go online before we
2209          * call the caller's callback. */
2210         
2211         info = g_slice_new0 (OnWentOnlineInfo);
2212         
2213         info->device = NULL;
2214         info->iap = NULL;
2215         info->account = TNY_ACCOUNT (g_object_ref (account));
2216         
2217         if (parent_window)
2218                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2219         else
2220                 info->parent_window = NULL;
2221         
2222         /* So we'll put the callback away for later ... */
2223         
2224         info->user_data = user_data;
2225         info->callback = callback;
2226         
2227         if (!device_online) {
2228  
2229                 /* If also the device is offline, then we connect both the device 
2230                  * and the account */
2231                 
2232                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2233                                                       force, on_conic_device_went_online, 
2234                                                       info);
2235                 
2236         } else {
2237                 
2238                 /* If the device is online, we'll just connect the account */
2239                 
2240                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2241                                               on_account_went_online, info);
2242         }
2243  
2244         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2245          * in both situations, go look if you don't believe me! */
2246         
2247         return;
2248 }
2249
2250 void
2251 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2252                                                gboolean force,
2253                                                TnyFolderStore *folder_store, 
2254                                                ModestConnectedPerformer callback, 
2255                                                gpointer user_data)
2256 {
2257         TnyAccount *account = NULL;
2258
2259         if (!folder_store ||
2260             (TNY_IS_MERGE_FOLDER (folder_store) &&
2261              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2262
2263                 /* We promise to instantly perform the callback, so ... */
2264                 if (callback) {
2265                         GError *error = NULL;
2266                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2267                                      "Unable to move or not found folder");
2268                         callback (FALSE, error, parent_window, NULL, user_data);
2269                         g_error_free (error);
2270                 }
2271                 return;
2272
2273         } else if (TNY_IS_FOLDER (folder_store)) {
2274                 /* Get the folder's parent account: */
2275                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2276         } else if (TNY_IS_ACCOUNT (folder_store)) {
2277                 /* Use the folder store as an account: */
2278                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2279         }
2280
2281         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2282                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2283                         /* No need to connect a local account */
2284                         if (callback)
2285                                 callback (FALSE, NULL, parent_window, account, user_data);
2286
2287                         goto clean;
2288                 }
2289         }
2290         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2291
2292  clean:
2293         if (account)
2294                 g_object_unref (account);
2295 }
2296
2297 static void
2298 src_account_connect_performer (gboolean canceled,
2299                                GError *err,
2300                                GtkWindow *parent_window,
2301                                TnyAccount *src_account,
2302                                gpointer user_data)
2303 {
2304         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2305
2306         if (canceled || err) {
2307                 /* If there was any error call the user callback */
2308                 info->callback (canceled, err, parent_window, src_account, info->data);
2309         } else {
2310                 /* Connect the destination account */
2311                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2312                                                                TNY_FOLDER_STORE (info->dst_account),
2313                                                                info->callback, info->data);
2314         }
2315
2316         /* Free the info object */
2317         g_object_unref (info->dst_account);
2318         g_slice_free (DoubleConnectionInfo, info);
2319 }
2320
2321
2322 void 
2323 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2324                                             gboolean force,
2325                                             TnyFolderStore *folder_store,
2326                                             DoubleConnectionInfo *connect_info)
2327 {
2328         modest_platform_connect_if_remote_and_perform(parent_window, 
2329                                                       force,
2330                                                       folder_store, 
2331                                                       src_account_connect_performer, 
2332                                                       connect_info);
2333 }
2334
2335 GtkWidget *
2336 modest_platform_get_account_settings_wizard (void)
2337 {
2338         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2339
2340         return GTK_WIDGET (dialog);
2341 }
2342
2343 ModestConnectedVia
2344 modest_platform_get_current_connection (void)
2345 {
2346         TnyDevice *device = NULL;
2347         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2348         
2349         device = modest_runtime_get_device ();
2350
2351         if (!tny_device_is_online (device))
2352                 return MODEST_CONNECTED_VIA_ANY;
2353
2354 #ifdef MODEST_HAVE_CONIC
2355         /* Get iap id */
2356         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2357         if (iap_id) {
2358                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2359                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2360                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2361                 if (bearer_type) {
2362                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2363                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2364                             !strcmp (bearer_type, "WIMAX")) {
2365                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2366                         } else {
2367                                 retval = MODEST_CONNECTED_VIA_ANY;
2368                         }
2369                 }       
2370                 g_object_unref (iap);
2371         }
2372 #else
2373         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2374 #endif /* MODEST_HAVE_CONIC */
2375         return retval;
2376 }
2377
2378
2379
2380 gboolean
2381 modest_platform_check_memory_low (ModestWindow *win,
2382                                   gboolean visuals)
2383 {
2384         gboolean lowmem;
2385         
2386         /* are we in low memory state? */
2387         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2388         
2389         if (win && lowmem && visuals)
2390                 modest_platform_run_information_dialog (
2391                         GTK_WINDOW(win),
2392                         _KR("memr_ib_operation_disabled"),
2393                         TRUE);
2394
2395         if (lowmem)
2396                 g_debug ("%s: low memory reached. disallowing some operations",
2397                          __FUNCTION__);
2398
2399         return lowmem;
2400 }
2401
2402 void 
2403 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2404                                            TnyFolder *folder)
2405 {
2406         GtkWidget *dialog;
2407         
2408         /* Create dialog */
2409         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2410
2411         /* Run dialog */
2412         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2413                                      GTK_WINDOW (dialog), 
2414                                      parent_window);
2415         gtk_widget_show_all (dialog);
2416
2417         g_signal_connect_swapped (dialog, "response", 
2418                                   G_CALLBACK (gtk_widget_destroy),
2419                                   dialog);
2420 }
2421
2422 void
2423 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2424                                            TnyHeader *header)
2425 {
2426         GtkWidget *dialog;
2427
2428         /* Create dialog */
2429         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2430
2431         /* Run dialog */
2432         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2433                                      GTK_WINDOW (dialog),
2434                                      parent_window);
2435         gtk_widget_show_all (dialog);
2436
2437         g_signal_connect_swapped (dialog, "response", 
2438                                   G_CALLBACK (gtk_widget_destroy),
2439                                   dialog);
2440 }
2441
2442 osso_context_t *
2443 modest_platform_get_osso_context (void)
2444 {
2445         return modest_maemo_utils_get_osso_context ();
2446 }
2447
2448 static void
2449 _modest_platform_play_email_tone (void)
2450 {
2451         gchar *mail_tone;
2452         gint mail_volume_int;
2453         int ret;
2454         ca_context *ca_con = NULL;
2455         ca_proplist *pl = NULL;
2456
2457 #ifdef MODEST_USE_PROFILE
2458         gchar *active_profile;
2459         gchar *mail_volume;
2460
2461         active_profile = profile_get_profile ();
2462         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2463         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2464         mail_volume_int = profile_parse_int (mail_volume);
2465         g_free (mail_volume);
2466         g_free (active_profile);
2467 #else
2468         mail_tone = MAIL_TONE;
2469         mail_volume_int = 100;
2470 #endif
2471
2472         if (mail_tone && !strstr (mail_tone, "/")) {
2473                 gchar *tmp;
2474
2475                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2476                 g_free (mail_tone);
2477                 mail_tone = tmp;
2478         }
2479
2480         if (mail_volume_int > 0) {
2481
2482                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2483                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2484                         return;
2485                 }
2486
2487                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2488                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2489                         ca_context_destroy(ca_con);
2490                         return;
2491                 }
2492
2493                 ca_proplist_create(&pl);
2494                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2495                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2496
2497                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2498                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2499
2500                 ca_proplist_destroy(pl);
2501                 ca_context_destroy(ca_con);
2502         }
2503
2504         g_free (mail_tone);
2505 }
2506
2507 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2508 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2509 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2510 #define MOVE_TO_DIALOG_SELECTION_LABEL "selection-label"
2511 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2512 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2513
2514 static void
2515 move_to_dialog_show_accounts (GtkWidget *dialog)
2516 {
2517         GtkWidget *selection_label;
2518         GtkWidget *back_button;
2519         GtkWidget *folder_view;
2520         GtkWidget *pannable;
2521         GtkWidget *action_button;
2522
2523         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2524         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2525         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2526         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2527         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2528
2529         gtk_widget_set_sensitive (back_button, FALSE);
2530         gtk_widget_set_sensitive (action_button, FALSE);
2531
2532         /* Need to set this here, otherwise callbacks called because
2533            of filtering won't perform correctly */
2534         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2535
2536         gtk_label_set_text (GTK_LABEL (selection_label), "");
2537         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2538         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2539         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2540         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2541
2542         g_object_set (G_OBJECT (folder_view), 
2543                       "hildon-ui-mode", HILDON_UI_MODE_NORMAL, 
2544                       NULL);
2545 }
2546
2547 static void
2548 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2549 {
2550         GtkWidget *selection_label;
2551         GtkWidget *back_button;
2552         GtkWidget *folder_view;
2553         TnyAccount *account;
2554         const gchar *account_id;
2555         gchar *selection_label_text;
2556         GtkWidget *pannable;
2557         GtkWidget *action_button;
2558
2559         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2560         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2561         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2562         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2563         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2564
2565         gtk_widget_set_sensitive (back_button, TRUE);
2566         gtk_widget_set_sensitive (action_button, FALSE);
2567
2568         /* Need to set this here, otherwise callbacks called because
2569            of filtering won't perform correctly */
2570         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (TRUE));
2571
2572         g_object_set (G_OBJECT (folder_view),
2573                       "hildon-ui-mode", HILDON_UI_MODE_EDIT,
2574                       NULL);
2575
2576         account = TNY_ACCOUNT (folder_store);
2577         if (modest_tny_account_is_virtual_local_folders (account)) {
2578                 gchar *device_name;
2579                 account_id = tny_account_get_id (account);
2580                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2581                                                       MODEST_CONF_DEVICE_NAME, NULL);
2582                 if (device_name) {
2583                         selection_label_text = g_strconcat (device_name, "/", NULL);
2584                         g_free (device_name);
2585                 } else {
2586                         selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2587                 }
2588                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2589                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2590         } else if (modest_tny_account_is_memory_card_account (account)) {
2591                 account_id = tny_account_get_id (account);
2592                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2593                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2594                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2595         } else {
2596                 account_id = tny_account_get_id (account);
2597
2598                 selection_label_text = g_strconcat (tny_account_get_name (account), "/", NULL);
2599                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2600                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2601                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2602                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2603         }
2604         gtk_label_set_text (GTK_LABEL (selection_label), selection_label_text);
2605         g_free (selection_label_text);
2606
2607         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2608                                                                      account_id);
2609
2610         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2611         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2612         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2613         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2614 }
2615
2616 static void
2617 move_to_dialog_set_selected_folder (GtkWidget *dialog, TnyFolderStore *folder_store)
2618 {
2619         GtkWidget *selection_label;
2620         GtkWidget *action_button;
2621         gchar *folder_name;
2622
2623         selection_label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL));
2624         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2625
2626         gtk_widget_set_sensitive (action_button, TRUE);
2627
2628         if (TNY_IS_FOLDER (folder_store)) {
2629                 folder_name = modest_tny_folder_get_display_name (TNY_FOLDER (folder_store));
2630         } else if (TNY_IS_ACCOUNT (folder_store)) {
2631                 folder_name = g_strdup (tny_account_get_name (TNY_ACCOUNT (folder_store)));
2632         } else {
2633                 folder_name = g_strdup ("");
2634         }
2635
2636         gtk_label_set_text (GTK_LABEL (selection_label), folder_name);
2637         g_free (folder_name);
2638
2639 }
2640
2641 static void
2642 on_move_to_dialog_back_clicked (GtkButton *button,
2643                                 gpointer userdata)
2644 {
2645         GtkWidget *dialog = (GtkWidget *) userdata;
2646         ModestFolderView *folder_view;
2647
2648         /* Revert the effect of show_folders filters */
2649         folder_view = MODEST_FOLDER_VIEW (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2650         modest_folder_view_set_account_id_of_visible_server_account (folder_view, NULL);
2651         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2652         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2653         modest_folder_view_unset_filter (folder_view, MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2654
2655         /* Back to show accounts */
2656         move_to_dialog_show_accounts (dialog);
2657 }
2658
2659 static void
2660 on_move_to_dialog_folder_activated (GtkTreeView       *tree_view,
2661                                     GtkTreePath       *path,
2662                                     GtkTreeViewColumn *column,
2663                                     gpointer           user_data)
2664 {
2665         TnyFolderStore *selected;
2666         GtkWidget *dialog;
2667         GtkWidget *folder_view;
2668         gboolean showing_folders;
2669
2670         dialog = (GtkWidget *) user_data;
2671         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2672         if (!showing_folders) {
2673                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2674
2675                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2676                 if (selected) {
2677                         move_to_dialog_show_folders (dialog, selected);
2678                 }
2679         }
2680 }
2681
2682 static void
2683 on_move_to_dialog_selection_changed (GtkTreeSelection       *selection,
2684                                     gpointer           user_data)
2685 {
2686         gboolean showing_folders;
2687         GtkWidget *dialog;
2688
2689         dialog = (GtkWidget *) user_data;
2690         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2691         if (showing_folders) {
2692                 TnyFolderStore *selected;
2693                 GtkWidget *folder_view;
2694
2695                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2696                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2697
2698                 if (selected) {
2699                         move_to_dialog_set_selected_folder (dialog, selected);
2700                         g_object_unref (selected);
2701                 }
2702         }
2703 }
2704
2705 static void
2706 on_move_to_dialog_action_clicked (GtkButton       *selection,
2707                                   gpointer           user_data)
2708 {
2709         TnyFolderStore *selected;
2710         GtkWidget *dialog;
2711         GtkWidget *folder_view;
2712         gboolean showing_folders;
2713
2714         dialog = (GtkWidget *) user_data;
2715         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2716         if (showing_folders) {
2717                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2718                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2719
2720                 if (selected)
2721                         gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2722         }
2723 }
2724
2725 GtkWidget *
2726 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2727                                        GtkWidget **folder_view)
2728 {
2729         GtkWidget *dialog, *folder_view_container;
2730         GtkWidget *align;
2731         GtkWidget *buttons_hbox;
2732         GtkWidget *back_button, *selection_label;
2733         GdkPixbuf *back_pixbuf;
2734         GtkWidget *top_vbox;
2735         GtkWidget *action_button;
2736         GtkTreeSelection *selection;
2737
2738         /* Create dialog. We cannot use a touch selector because we
2739            need to use here the folder view widget directly */
2740         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2741                                               GTK_WINDOW (parent_window),
2742                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2743                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2744                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2745                                               NULL);
2746
2747         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2748         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2749         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2750
2751         /* Create folder view */
2752         *folder_view = modest_platform_create_folder_view (NULL);
2753
2754         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2755                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2756         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2757                                                FALSE);
2758         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2759                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2760
2761         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2762         back_button = gtk_button_new ();
2763         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2764         if (back_pixbuf) {
2765                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2766                 g_object_unref (back_pixbuf);
2767         }
2768         selection_label = gtk_label_new ("");
2769         gtk_misc_set_alignment (GTK_MISC (selection_label), 0.0, 0.5);
2770
2771         action_button = gtk_button_new ();
2772         gtk_container_add (GTK_CONTAINER (action_button), selection_label);
2773
2774         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2775         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2776         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2777         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2778         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2779
2780         /* Create pannable and add it to the dialog */
2781         folder_view_container = hildon_pannable_area_new ();
2782         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2783         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2784
2785         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2786         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2787
2788         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2789
2790         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2791         gtk_widget_show (folder_view_container);
2792         gtk_widget_show (align);
2793         gtk_widget_show (top_vbox);
2794         gtk_widget_show (*folder_view);
2795         gtk_widget_show_all (back_button);
2796         gtk_widget_show (selection_label);
2797         gtk_widget_show (action_button);
2798         gtk_widget_show (buttons_hbox);
2799         gtk_widget_show (dialog);
2800
2801         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2802         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2803         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2804         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SELECTION_LABEL, selection_label);
2805         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
2806
2807         /* Simulate the behaviour of a HildonPickerDialog by emitting
2808            a response when a folder is selected */
2809         g_signal_connect (*folder_view, "row-activated",
2810                           G_CALLBACK (on_move_to_dialog_folder_activated),
2811                           dialog);
2812
2813         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2814         g_signal_connect (selection, "changed",
2815                           G_CALLBACK (on_move_to_dialog_selection_changed),
2816                           dialog);
2817
2818         g_signal_connect (action_button, "clicked",
2819                           G_CALLBACK (on_move_to_dialog_action_clicked),
2820                           dialog);
2821
2822         g_signal_connect (back_button, "clicked",
2823                           G_CALLBACK (on_move_to_dialog_back_clicked),
2824                           dialog);
2825
2826         move_to_dialog_show_accounts (dialog);
2827
2828         return dialog;
2829 }
2830
2831 TnyList *
2832 modest_platform_get_list_to_move (ModestWindow *window)
2833 {
2834         TnyList *list = NULL;
2835
2836         if (MODEST_IS_HEADER_WINDOW (window)) {
2837                 ModestHeaderView *header_view;
2838
2839                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2840                 list = modest_header_view_get_selected_headers (header_view);
2841         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2842                 ModestFolderView *folder_view;
2843                 TnyFolderStore *selected_folder;
2844
2845                 list = TNY_LIST (tny_simple_list_new ());
2846                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2847                 selected_folder = modest_folder_view_get_selected (folder_view);
2848                 if (selected_folder) {
2849                         tny_list_prepend (list, G_OBJECT (selected_folder));
2850                         g_object_unref (selected_folder);
2851                 }
2852                 return list;
2853         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2854                 TnyHeader *header;
2855
2856                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2857                 if (header) {
2858                         list = TNY_LIST (tny_simple_list_new ());
2859                         tny_list_prepend (list, G_OBJECT (header));
2860                         g_object_unref (header);
2861                 }
2862         } else {
2863                 g_return_val_if_reached (NULL);
2864         }
2865
2866         return list;
2867 }