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