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