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