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