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