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