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