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