3cc28de1bbadf51eabac58f6b1570e038668675c
[modest] / src / maemo / modest-platform.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "maemo/modest-maemo-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <osso-helplib.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <libosso-abook/osso-abook.h>
42 #include <maemo/modest-osso-autosave-callbacks.h>
43 #include <libosso.h>
44 #include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
45 #include <tny-maemo-conic-device.h>
46 #include <tny-simple-list.h>
47 #include <tny-folder.h>
48 #include <tny-camel-imap-store-account.h>
49 #include <tny-camel-pop-store-account.h>
50 #include <gtk/gtkicontheme.h>
51 #include <gtk/gtkmenuitem.h>
52 #include <gtk/gtkmain.h>
53 #include <modest-text-utils.h>
54 #include <string.h>
55
56
57 #define HILDON_OSSO_URI_ACTION "uri-action"
58 #define URI_ACTION_COPY "copy:"
59
60 static osso_context_t *osso_context = NULL;
61
62 static void  folder_name_insensitive_press (GtkWidget *widget, ModestWindow *window);
63         
64 static void     
65 on_modest_conf_update_interval_changed (ModestConf* self, const gchar *key, 
66         ModestConfEvent event, gpointer user_data)
67 {
68         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
69                 const guint update_interval_minutes = 
70                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
71                 modest_platform_set_update_interval (update_interval_minutes);
72         }
73 }
74
75 gboolean
76 modest_platform_init (int argc, char *argv[])
77 {
78         osso_hw_state_t hw_state = { 0 };
79         DBusConnection *con;    
80
81         osso_context =
82                 osso_initialize(PACKAGE,PACKAGE_VERSION,
83                                 FALSE, NULL);   
84         if (!osso_context) {
85                 g_printerr ("modest: failed to acquire osso context\n");
86                 return FALSE;
87         }
88
89         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
90                 g_printerr ("modest: could not get dbus connection\n");
91                 return FALSE;
92
93         }
94         
95         /* Add a D-Bus handler to be used when the main osso-rpc 
96          * D-Bus handler has not handled something.
97          * We use this for D-Bus methods that need to use more complex types 
98          * than osso-rpc supports. 
99          */
100         if (!dbus_connection_add_filter (con,
101                                          modest_dbus_req_filter,
102                                          NULL,
103                                          NULL)) {
104
105                 g_printerr ("modest: Could not add D-Bus filter\n");
106                 return FALSE;
107         }
108
109         /* Register our simple D-Bus callbacks, via the osso API: */
110         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
111                                MODEST_DBUS_SERVICE, 
112                                MODEST_DBUS_OBJECT, 
113                                MODEST_DBUS_IFACE,
114                                modest_dbus_req_handler, NULL /* user_data */);
115         if (result != OSSO_OK) {
116                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
117                 return FALSE;
118         }
119
120         /* Add handler for Exit D-BUS messages.
121          * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
122         result = osso_application_set_exit_cb(osso_context,
123                                           modest_dbus_exit_event_handler,
124                                           (gpointer) NULL);
125         if (result != OSSO_OK) {
126                 g_print("Error setting exit callback (%d)\n", result);
127                 return OSSO_ERROR;
128         }
129         */
130
131         /* Register hardware event dbus callback: */
132         hw_state.shutdown_ind = TRUE;
133         osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
134
135         /* Register osso auto-save callbacks: */
136         result = osso_application_set_autosave_cb (osso_context, 
137                 modest_on_osso_application_autosave, NULL /* user_data */);
138         if (result != OSSO_OK) {
139                 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
140                 return FALSE;
141         }
142         
143
144         /* Make sure that the update interval is changed whenever its gconf key 
145          * is changed: */
146         ModestConf *conf = modest_runtime_get_conf ();
147         g_signal_connect (G_OBJECT(conf),
148                           "key_changed",
149                           G_CALLBACK (on_modest_conf_update_interval_changed), 
150                           NULL);
151                           
152         /* Get the initial update interval from gconf: */
153         on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
154                 MODEST_CONF_EVENT_KEY_CHANGED, NULL);
155
156         /* initialize the addressbook */
157         if (!osso_abook_init (&argc, &argv, osso_context)) {
158                 g_printerr ("modest: failed to initialized addressbook\n");
159                 return FALSE;
160         }
161                 
162         return TRUE;
163 }
164
165 TnyDevice*
166 modest_platform_get_new_device (void)
167 {
168         return TNY_DEVICE (tny_maemo_conic_device_new ());
169 }
170
171
172 const gchar*
173 guess_mime_type_from_name (const gchar* name)
174 {
175         int i;
176         const gchar* ext;
177         const static gchar* octet_stream= "application/octet-stream";
178         const static gchar* mime_map[][2] = {
179                 { "pdf",  "application/pdf"},
180                 { "doc",  "application/msword"},
181                 { "xls",  "application/excel"},
182                 { "png",  "image/png" },
183                 { "gif",  "image/gif" },
184                 { "jpg",  "image/jpeg"},
185                 { "jpeg", "image/jpeg"},
186                 { "mp3",  "audio/mp3" }
187         };
188
189         if (!name)
190                 return octet_stream;
191         
192         ext = g_strrstr (name, ".");
193         if (!ext)
194                 return octet_stream;
195         
196         for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
197                 if (!g_ascii_strcasecmp (mime_map[i][0], ext + 1)) /* +1: ignore '.'*/
198                         return mime_map[i][1];
199         }
200         return octet_stream;
201 }
202
203
204 gchar*
205 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
206                                           gchar **effective_mime_type)
207 {
208         GString *mime_str = NULL;
209         gchar *icon_name  = NULL;
210         gchar **icons, **cursor;
211         
212         
213         g_return_val_if_fail (name || mime_type, NULL);
214
215         if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream")) 
216                 mime_str = g_string_new (guess_mime_type_from_name(name));
217         else {
218                 mime_str = g_string_new (mime_type);
219                 g_string_ascii_down (mime_str);
220         }
221
222 #ifdef MODEST_HAVE_OSSO_MIME
223         icons = osso_mime_get_icon_names (mime_str->str, NULL);
224 #else
225         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
226 #endif /*MODEST_HAVE_OSSO_MIME*/
227         for (cursor = icons; cursor; ++cursor) {
228                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
229                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
230                         icon_name = g_strdup ("qgn_list_messagin");
231                         break;
232                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
233                         icon_name = g_strdup (*cursor);
234                         break;
235                 }
236         }
237         g_strfreev (icons);
238
239         if (effective_mime_type)
240                 *effective_mime_type = g_string_free (mime_str, FALSE);
241         else
242                 g_string_free (mime_str, TRUE);
243
244         return icon_name;
245 }
246
247
248
249
250 #ifdef MODEST_HAVE_OSSO_MIME
251 gboolean 
252 modest_platform_activate_uri (const gchar *uri)
253 {
254         OssoURIAction *action;
255         gboolean result = FALSE;
256         GSList *actions, *iter = NULL;
257         const gchar *scheme;
258         
259         g_return_val_if_fail (uri, FALSE);
260         if (!uri)
261                 return FALSE;
262
263         /* the default action should be email */
264         scheme = osso_uri_get_scheme_from_uri (uri, NULL);
265         actions = osso_uri_get_actions (scheme, NULL);
266         
267         for (iter = actions; iter; iter = g_slist_next (iter)) {
268                 action = (OssoURIAction*) iter->data;
269                 if (action && strcmp (osso_uri_action_get_name (action), "uri_link_compose_email") == 0) {
270                         GError *err = NULL;
271                         result = osso_uri_open (uri, action, &err);
272                         if (!result && err) {
273                                 g_printerr ("modest: modest_platform_activate_uri : %s",
274                                             err->message ? err->message : "unknown error");
275                                 g_error_free (err);
276                         }
277                         break;
278                 }
279         }
280
281         /* if we could open it with email, try something else */
282         if (!result)
283                 result = osso_uri_open (uri, NULL, NULL);       
284         
285                         
286         if (!result)
287                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
288         return result;
289 }
290
291 #else /* !MODEST_HAVE_OSSO_MIME*/
292
293 gboolean 
294 modest_platform_activate_uri (const gchar *uri)
295 {
296         HildonURIAction *action;
297         gboolean result = FALSE;
298         GSList *actions, *iter = NULL;
299         const gchar *scheme;
300         
301         g_return_val_if_fail (uri, FALSE);
302         if (!uri)
303                 return FALSE;
304
305         scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
306         actions = hildon_uri_get_actions (scheme, NULL);
307         
308         for (iter = actions; iter; iter = g_slist_next (iter)) {
309                 action = (HildonURIAction*) iter->data;
310                 if (action && strcmp (hildon_uri_action_get_service (action), "com.nokia.modest") == 0) {
311                         GError *err = NULL;
312                         result = hildon_uri_open (uri, action, &err);
313                         if (!result && err) {
314                                 g_printerr ("modest: modest_platform_activate_uri : %s",
315                                             err->message ? err->message : "unknown error");
316                                 g_error_free (err);
317                         }
318                         break;
319                 }
320         }
321         
322         /* if we could open it with email, try something else */
323         if (!result)
324                 result = hildon_uri_open (uri, NULL, NULL);     
325                 
326         if (!result)
327                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
328         
329         return result;
330 }
331
332
333 #endif /* MODEST_HAVE_OSSO_MIME*/
334
335 gboolean 
336 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
337 {
338         gint result;
339         DBusConnection *con;
340         gchar *uri_path = NULL;
341         GString *mime_str = NULL;
342
343         if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream")) 
344                 mime_str = g_string_new (guess_mime_type_from_name(path));
345         else {
346                 mime_str = g_string_new (mime_type);
347                 g_string_ascii_down (mime_str);
348         }
349
350         uri_path = g_strconcat ("file://", path, NULL);
351         
352         con = osso_get_dbus_connection (osso_context);
353 #ifdef MODEST_HAVE_OSSO_MIME
354         result = osso_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
355 #else
356         result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_str->str);
357 #endif /*MODEST_HAVE_OSSO_MIME*/
358         g_string_free (mime_str, TRUE);
359
360         if (result != 1)
361                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
362         return result != 1;
363 }
364
365 typedef struct  {
366         GSList *actions;
367         gchar  *uri;
368 } ModestPlatformPopupInfo;
369
370 static gboolean
371 delete_uri_popup (GtkWidget *menu,
372                   GdkEvent *event,
373                   gpointer userdata)
374 {
375         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
376
377         g_free (popup_info->uri);
378 #ifdef MODEST_HAVE_OSSO_MIME
379         osso_uri_free_actions (popup_info->actions);
380 #else
381         hildon_uri_free_actions (popup_info->actions);
382 #endif /*MODEST_HAVE_OSSO_MIME*/
383         return FALSE;
384 }
385
386 static void
387 activate_uri_popup_item (GtkMenuItem *menu_item,
388                          gpointer userdata)
389 {
390         GSList *node;
391         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
392         const gchar* action_name;
393
394         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
395         if (!action_name) {
396                 g_printerr ("modest: no action name defined\n");
397                 return;
398         }
399
400         /* special handling for the copy menu item -- copy the uri to the clipboard */
401         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
402         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
403                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
404                 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
405
406                 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
407                         action_name += strlen ("mailto:");
408                 
409                 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
410                 return; /* we're done */
411         }
412         
413         /* now, the real uri-actions... */
414         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
415 #ifdef MODEST_HAVE_OSSO_MIME
416                 OssoURIAction *action = (OssoURIAction *) node->data;
417                 if (strcmp (action_name, osso_uri_action_get_name (action))==0) {
418                         osso_uri_open (popup_info->uri, action, NULL);
419                         break;
420                 }
421 #else
422                 HildonURIAction *action = (HildonURIAction *) node->data;
423                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
424                         hildon_uri_open (popup_info->uri, action, NULL);
425                         break;
426                 }
427 #endif /*MODEST_HAVE_OSSO_MIME*/
428         }
429 }
430
431 gboolean 
432 modest_platform_show_uri_popup (const gchar *uri)
433 {
434         gchar *scheme;
435         GSList *actions_list;
436
437         if (uri == NULL)
438                 return FALSE;
439         
440 #ifdef MODEST_HAVE_OSSO_MIME
441         scheme = osso_uri_get_scheme_from_uri (uri, NULL);
442         actions_list = osso_uri_get_actions (scheme, NULL);
443 #else
444         scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
445         actions_list = hildon_uri_get_actions (scheme, NULL);
446 #endif /* MODEST_HAVE_OSSO_MIME */
447         if (actions_list != NULL) {
448                 GSList *node;
449                 GtkWidget *menu = gtk_menu_new ();
450                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
451
452                 popup_info->actions = actions_list;
453                 popup_info->uri = g_strdup (uri);
454               
455                 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
456                         GtkWidget *menu_item;
457                         const gchar *action_name;
458                         const gchar *translation_domain;
459 #ifdef MODEST_HAVE_OSSO_MIME
460                         OssoURIAction *action = (OssoURIAction *) node->data;
461                         action_name = osso_uri_action_get_name (action);
462                         translation_domain = osso_uri_action_get_translation_domain (action);
463                         menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain,action_name));
464                         g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);
465                         /* hack, we add it as a gobject property*/
466                         g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
467                                           popup_info);
468                         
469                         if (osso_uri_is_default_action (action, NULL)) {
470                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
471                         } else {
472                                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
473                         }
474 #else
475                         HildonURIAction *action = (HildonURIAction *) node->data;
476                         action_name = hildon_uri_action_get_name (action);
477                         translation_domain = hildon_uri_action_get_translation_domain (action);
478                         menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
479                         g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
480                         g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
481                                           popup_info);
482                                                                   
483                         if (hildon_uri_is_default_action (action, NULL)) {
484                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
485                         } else {
486                                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
487                         }
488 #endif /*MODEST_HAVE_OSSO_MIME*/
489                         gtk_widget_show (menu_item);
490                 }
491
492                 /* always add the copy item */
493                 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
494                 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
495                                         g_strconcat (URI_ACTION_COPY, uri, NULL),
496                                         g_free);
497                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
498                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
499                 gtk_widget_show (menu_item);
500
501                 
502                 /* and what to do when the link is deleted */
503                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
504                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
505                                                   
506         } else {
507                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
508         }
509         
510         g_free (scheme);
511         return TRUE;
512 }
513
514
515 GdkPixbuf*
516 modest_platform_get_icon (const gchar *name)
517 {
518         GError *err = NULL;
519         GdkPixbuf* pixbuf = NULL;
520         GtkIconTheme *current_theme = NULL;
521
522         g_return_val_if_fail (name, NULL);
523         
524         if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
525                 pixbuf = gdk_pixbuf_new_from_file (name, &err);
526                 if (!pixbuf) {
527                         g_printerr ("modest: error loading icon '%s': %s\n",
528                                     name, err->message);
529                         g_error_free (err);
530                         return NULL;
531                 }
532                 return pixbuf;
533         }
534
535         current_theme = gtk_icon_theme_get_default ();
536         pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
537                                            GTK_ICON_LOOKUP_NO_SVG,
538                                            &err);
539         if (!pixbuf) {
540                 g_printerr ("modest: error loading theme icon '%s': %s\n",
541                             name, err->message);
542                 g_error_free (err);
543         } 
544         return pixbuf;
545 }
546
547 const gchar*
548 modest_platform_get_app_name (void)
549 {
550         return _("mcen_ap_name");
551 }
552
553 static void 
554 entry_insert_text (GtkEditable *editable,
555                    const gchar *text,
556                    gint         length,
557                    gint        *position,
558                    gpointer     data)
559 {
560         gchar *chars;
561         gint chars_length;
562
563         chars = gtk_editable_get_chars (editable, 0, -1);
564         chars_length = g_utf8_strlen (chars, -1);
565
566         /* Show WID-INF036 */
567         if (chars_length >= 20) {
568                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
569                                                  _CS("ckdg_ib_maximum_characters_reached"));
570         } else {
571                 if (chars_length == 0) {
572                         /* A blank space is not valid as first character */
573                         if (strcmp (text, " ")) {
574                                 GtkWidget *ok_button;
575                                 GList *buttons;
576
577                                 /* Show OK button */
578                                 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (data)->action_area));
579                                 ok_button = GTK_WIDGET (buttons->next->data);
580                                 gtk_widget_set_sensitive (ok_button, TRUE);
581                                 g_list_free (buttons);
582                         }
583                 }
584
585                 /* Write the text in the entry */
586                 g_signal_handlers_block_by_func (editable,
587                                                  (gpointer) entry_insert_text, data);
588                 gtk_editable_insert_text (editable, text, length, position);
589                 g_signal_handlers_unblock_by_func (editable,
590                                                    (gpointer) entry_insert_text, data);
591         }
592         /* Do not allow further processing */
593         g_signal_stop_emission_by_name (editable, "insert_text");
594 }
595
596 static void
597 entry_changed (GtkEditable *editable,
598                gpointer     user_data)
599 {
600         gchar *chars;
601
602         chars = gtk_editable_get_chars (editable, 0, -1);
603         g_return_if_fail (chars != NULL);
604
605         /* Dimm OK button. Do not allow also the "/" */
606         if (strlen (chars) == 0 || strchr (chars, '/')) {
607                 GtkWidget *ok_button;
608                 GList *buttons;
609
610                 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
611                 ok_button = GTK_WIDGET (buttons->next->data);
612                 gtk_widget_set_sensitive (ok_button, FALSE);
613
614                 g_list_free (buttons);
615         } else if (g_utf8_strlen (chars,-1) >= 21)
616                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
617                                                  _CS("ckdg_ib_maximum_characters_reached"));            
618         /* Free */
619         g_free (chars);
620 }
621
622 static void
623 launch_sort_headers_dialog (GtkWindow *parent_window,
624                             HildonSortDialog *dialog)
625 {
626         ModestHeaderView *header_view = NULL;
627         GList *cols = NULL;
628         GtkSortType sort_type;
629         gint sort_key;
630         gint default_key = 0;
631         gint result;
632         gboolean outgoing = FALSE;
633         gint current_sort_colid = -1;
634         GtkSortType current_sort_type;
635         gint attachments_sort_id;
636         gint priority_sort_id;
637         GtkTreeSortable *sortable;
638         
639         /* Get header window */
640         if (MODEST_IS_MAIN_WINDOW (parent_window)) {
641                 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
642                                                                                       MODEST_WIDGET_TYPE_HEADER_VIEW));
643         }
644         if (!header_view) return;
645
646         /* Add sorting keys */
647         cols = modest_header_view_get_columns (header_view);
648         if (cols == NULL) return;
649         int sort_model_ids[6];
650         int sort_ids[6];
651
652
653         outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
654                     MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
655
656         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
657         if (outgoing) {
658                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
659                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
660         } else {
661                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
662                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
663         }
664
665         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
666         if (outgoing) {
667                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
668                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
669         } else {
670                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
671                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
672         }
673         default_key = sort_key;
674
675         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
676         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
677         if (outgoing)
678                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
679         else
680                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
681
682         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
683         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
684         sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
685         attachments_sort_id = sort_key;
686
687         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
688         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
689         sort_ids[sort_key] = 0;
690
691         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
692         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
693         sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
694         priority_sort_id = sort_key;
695
696         sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
697         /* Launch dialogs */
698         if (!gtk_tree_sortable_get_sort_column_id (sortable,
699                                                    &current_sort_colid, &current_sort_type)) {
700                 hildon_sort_dialog_set_sort_key (dialog, default_key);
701                 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
702         } else {
703                 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
704                 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
705                         gpointer flags_sort_type_pointer;
706                         flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
707                         if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
708                                 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
709                         else
710                                 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
711                 } else {
712                         gint current_sort_keyid = 0;
713                         while (current_sort_keyid < 6) {
714                                 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
715                                         break;
716                                 else 
717                                         current_sort_keyid++;
718                         }
719                         hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
720                 }
721         }
722
723         result = gtk_dialog_run (GTK_DIALOG (dialog));
724         if (result == GTK_RESPONSE_OK) {
725                 sort_key = hildon_sort_dialog_get_sort_key (dialog);
726                 sort_type = hildon_sort_dialog_get_sort_order (dialog);
727                 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
728                         g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
729                                            GINT_TO_POINTER (sort_ids[sort_key]));
730                         /* This is a hack to make it resort rows always when flag fields are
731                          * selected. If we do not do this, changing sort field from priority to
732                          * attachments does not work */
733                         modest_header_view_sort_by_column_id (header_view, 0, sort_type);
734                 } else {
735                         gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data), 
736                                                                  sort_model_ids[sort_key]);
737                 }
738
739                 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
740                 gtk_tree_sortable_sort_column_changed (sortable);
741         }
742
743         modest_widget_memory_save (modest_runtime_get_conf (),
744                                    G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
745         
746         while (gtk_events_pending ())
747                 gtk_main_iteration ();
748
749         /* free */
750         g_list_free(cols);      
751 }
752
753 static gint
754 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
755                                         const gchar *dialog_title,
756                                         const gchar *label_text,
757                                         const gchar *suggested_name,
758                                         gchar **folder_name)
759 {
760         GtkWidget *accept_btn = NULL; 
761         GtkWidget *dialog, *entry, *label, *hbox;
762         GList *buttons = NULL;
763         gint result;
764
765         /* Ask the user for the folder name */
766         dialog = gtk_dialog_new_with_buttons (dialog_title,
767                                               parent_window,
768                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
769                                               GTK_STOCK_OK,
770                                               GTK_RESPONSE_ACCEPT,
771                                               GTK_STOCK_CANCEL,
772                                               GTK_RESPONSE_REJECT,
773                                               NULL);
774
775         /* Add accept button (with unsensitive handler) */
776         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
777         accept_btn = GTK_WIDGET (buttons->next->data);
778         g_signal_connect (G_OBJECT (accept_btn), "insensitive-press", G_CALLBACK (folder_name_insensitive_press), parent_window);
779
780         /* Create label and entry */
781         label = gtk_label_new (label_text);
782         /* TODO: check that the suggested name does not exist */
783         /* We set 21 as maximum because we want to show WID-INF036
784            when the user inputs more that 20 */
785         entry = gtk_entry_new_with_max_length (21);
786         if (suggested_name)
787                 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
788         else
789                 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
790         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
791
792         /* Track entry changes */
793         g_signal_connect (entry,
794                           "insert-text",
795                           G_CALLBACK (entry_insert_text),
796                           dialog);
797         g_signal_connect (entry,
798                           "changed",
799                           G_CALLBACK (entry_changed),
800                           dialog);
801
802         /* Create the hbox */
803         hbox = gtk_hbox_new (FALSE, 12);
804         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
805         gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
806
807         /* Add hbox to dialog */
808         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
809                             hbox, FALSE, FALSE, 0);
810         
811         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
812         
813         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
814         result = gtk_dialog_run (GTK_DIALOG(dialog));
815         if (result == GTK_RESPONSE_ACCEPT)
816                 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
817
818         gtk_widget_destroy (dialog);
819
820         while (gtk_events_pending ())
821                 gtk_main_iteration ();
822
823         return result;
824 }
825
826 static void  
827 folder_name_insensitive_press (GtkWidget *widget, ModestWindow *window)
828 {
829         hildon_banner_show_information (NULL, NULL, _("(empty)"));
830 }
831
832 gint
833 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
834                                        TnyFolderStore *parent_folder,
835                                        gchar *suggested_name,
836                                        gchar **folder_name)
837 {
838         gchar *real_suggested_name = NULL;
839         gint result;
840
841         if(suggested_name == NULL)
842         {
843                 const gchar *default_name = _("mcen_ia_default_folder_name");
844                 unsigned int i;
845                 gchar num_str[3];
846
847                 for(i = 0; i < 100; ++ i)
848                 {
849                         TnyList *list = tny_simple_list_new ();
850                         TnyFolderStoreQuery *query = tny_folder_store_query_new ();
851                         guint length;
852
853                         sprintf(num_str, "%.2u", i);
854
855                         if (i == 0)
856                                 real_suggested_name = g_strdup (default_name);
857                         else
858                                 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
859                                                                        num_str);
860
861                         tny_folder_store_query_add_item (query, real_suggested_name,
862                                                          TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
863
864                         tny_folder_store_get_folders (parent_folder, list, query, NULL);
865
866                         length = tny_list_get_length (list);
867                         g_object_unref (query);
868                         g_object_unref (list);
869
870                         if (length == 0)
871                                 break;
872
873                         g_free (real_suggested_name);
874                 }
875
876                 /* Didn't find a free number */
877                 if (i == 100)
878                         real_suggested_name = g_strdup (default_name);
879         }
880         else
881         {
882                 real_suggested_name = suggested_name;
883         }
884
885         result = modest_platform_run_folder_name_dialog (parent_window, 
886                                                          _("mcen_ti_new_folder"),
887                                                          _("mcen_fi_new_folder_name"),
888                                                          real_suggested_name,
889                                                          folder_name);
890         if (suggested_name == NULL)
891                 g_free(real_suggested_name);
892
893         return result;
894 }
895
896 gint
897 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
898                                           TnyFolderStore *parent_folder,
899                                           const gchar *suggested_name,
900                                           gchar **folder_name)
901 {
902         return modest_platform_run_folder_name_dialog (parent_window, 
903                                                        _("New folder name"),
904                                                        _("Enter new folder name:"),
905                                                        suggested_name,
906                                                        folder_name);
907 }
908
909 gint
910 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
911                                          const gchar *message)
912 {
913         GtkWidget *dialog;
914         gint response;
915
916         dialog = hildon_note_new_confirmation (parent_window, message);
917         gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
918
919         response = gtk_dialog_run (GTK_DIALOG (dialog));
920
921         gtk_widget_destroy (GTK_WIDGET (dialog));
922
923         while (gtk_events_pending ())
924                 gtk_main_iteration ();
925
926         return response;
927 }
928
929 gint
930 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
931                                    const gchar *message)
932 {
933         GtkWidget *dialog;
934         gint response;
935
936         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
937                                                            _("mcen_bd_yes"), GTK_RESPONSE_YES,
938                                                            _("mcen_bd_no"), GTK_RESPONSE_NO,
939                                                            NULL);
940         gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
941
942         response = gtk_dialog_run (GTK_DIALOG (dialog));
943
944         gtk_widget_destroy (GTK_WIDGET (dialog));
945
946         while (gtk_events_pending ())
947                 gtk_main_iteration ();
948
949         return response;
950 }
951
952 void
953 modest_platform_run_information_dialog (GtkWindow *parent_window,
954                                         const gchar *message)
955 {
956         GtkWidget *dialog;
957
958         dialog = hildon_note_new_information (parent_window, message);
959
960         g_signal_connect_swapped (dialog,
961                                   "response", 
962                                   G_CALLBACK (gtk_widget_destroy),
963                                   dialog);
964
965         gtk_widget_show_all (dialog);
966 }
967
968
969
970 typedef struct
971 {
972         GMainLoop* loop;
973 } UtilIdleData;
974
975 static gboolean 
976 on_idle_connect_and_wait(gpointer user_data)
977 {
978         printf ("DEBUG: %s:\n", __FUNCTION__);
979         TnyDevice *device = modest_runtime_get_device();
980         if (!tny_device_is_online (device)) {
981                 gdk_threads_enter();
982                 tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
983                 gdk_threads_leave();
984         }
985         
986         /* Allow the function that requested this idle callback to continue: */
987         UtilIdleData *data = (UtilIdleData*)user_data;
988         if (data->loop)
989                 g_main_loop_quit (data->loop);
990         
991         return FALSE; /* Don't call this again. */
992 }
993
994 static gboolean connect_request_in_progress = FALSE;
995
996 /* This callback is used when connect_and_wait() is already queued as an idle callback.
997  * This can happen because the gtk_dialog_run() for the connection dialog 
998  * (at least in the fake scratchbox version) allows idle handlers to keep running.
999  */
1000 static gboolean 
1001 on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
1002 {
1003         gboolean result = FALSE;
1004         TnyDevice *device = modest_runtime_get_device();
1005         if (tny_device_is_online (device))
1006                 result = FALSE; /* Stop trying. */
1007         else {
1008                 /* Keep trying until connect_request_in_progress is FALSE. */
1009                 if (connect_request_in_progress)
1010                         result = TRUE; /* Keep trying */
1011                 else {
1012                         printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
1013                                                 
1014                         result = FALSE; /* Stop trying, now that a result should be available. */
1015                 }
1016         }
1017         
1018         if (result == FALSE) {
1019                 /* Allow the function that requested this idle callback to continue: */
1020                 UtilIdleData *data = (UtilIdleData*)user_data;
1021                 if (data->loop)
1022                         g_main_loop_quit (data->loop);  
1023         }
1024                 
1025         return result;
1026 }
1027
1028 static void 
1029 set_account_to_online (TnyAccount *account)
1030 {
1031         /* TODO: This is necessary to prevent a cancel of the password dialog 
1032          * from making a restart necessary to be asked the password again,
1033          * but it causes a hang:
1034          */
1035         #if 0
1036         if (account && TNY_IS_CAMEL_STORE_ACCOUNT (account)) {
1037                 /* Make sure that store accounts are online too, 
1038                  * because tinymail sets accounts to offline if 
1039                  * a password dialog is ever cancelled.
1040                  * We don't do this for transport accounts because 
1041                  * a) They fundamentally need network access, so they can't really be offline.
1042                  * b) That might cause a transport connection to happen too early.
1043                  */
1044                 GError *error = NULL;
1045                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, &error);
1046                 if (error) {
1047                         g_warning ("%s: tny_camel_account_set_online() returned a GError:\n  %s\n", 
1048                                 __FUNCTION__, error->message);
1049                         g_error_free (error);   
1050                 }
1051         }
1052         #endif
1053 }
1054
1055 gboolean modest_platform_connect_and_wait (GtkWindow *parent_window, TnyAccount *account)
1056 {
1057         if (connect_request_in_progress)
1058                 return FALSE;
1059                 
1060         printf ("DEBUG: %s:\n", __FUNCTION__);
1061         TnyDevice *device = modest_runtime_get_device();
1062         
1063         if (tny_device_is_online (device)) {
1064                 printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
1065                 set_account_to_online (account);
1066                 return TRUE;
1067         } else
1068         {
1069                 printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
1070         }
1071                 
1072         /* This blocks on the result: */
1073         UtilIdleData *data = g_slice_new0 (UtilIdleData);
1074         
1075         GMainContext *context = NULL; /* g_main_context_new (); */
1076         data->loop = g_main_loop_new (context, FALSE /* not running */);
1077         
1078         /* Cause the function to be run in an idle-handler, which is always 
1079          * in the main thread:
1080          */
1081         if (!connect_request_in_progress) {
1082                 printf ("DEBUG: %s: First request\n", __FUNCTION__);
1083                 connect_request_in_progress = TRUE;
1084                 g_idle_add (&on_idle_connect_and_wait, data);
1085         }
1086         else {
1087                 printf ("DEBUG: %s: nth request\n", __FUNCTION__);
1088                 g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
1089         }
1090
1091         /* This main loop will run until the idle handler has stopped it: */
1092         printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
1093         GDK_THREADS_LEAVE();
1094         g_main_loop_run (data->loop);
1095         GDK_THREADS_ENTER();
1096         printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
1097         connect_request_in_progress = FALSE;
1098         printf ("DEBUG: %s: Finished\n", __FUNCTION__);
1099         g_main_loop_unref (data->loop);
1100         /* g_main_context_unref (context); */
1101
1102         g_slice_free (UtilIdleData, data);
1103
1104         gboolean result = tny_device_is_online (device);
1105
1106         if (result)
1107                 set_account_to_online (account);
1108
1109         return result;
1110 }
1111
1112 gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1113 {
1114         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1115                 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1116                     !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1117                         /* This must be a maildir account, which does not require a connection: */
1118                         return TRUE;
1119                 }
1120         }
1121
1122         return modest_platform_connect_and_wait (parent_window, account);
1123 }
1124
1125 gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1126 {
1127         if (!folder_store)
1128                 return TRUE; /* Maybe it is something local. */
1129                 
1130         gboolean result = TRUE;
1131         if (TNY_IS_FOLDER (folder_store)) {
1132                 /* Get the folder's parent account: */
1133                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1134                 if (account != NULL) {
1135                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1136                         g_object_unref (account);
1137                 }
1138         } else if (TNY_IS_ACCOUNT (folder_store)) {
1139                 /* Use the folder store as an account: */
1140                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1141         }
1142
1143         return result;
1144 }
1145
1146 void
1147 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1148                                  ModestSortDialogType type)
1149 {
1150         GtkWidget *dialog = NULL;
1151
1152         /* Build dialog */
1153         dialog = hildon_sort_dialog_new (parent_window);
1154         gtk_window_set_modal (GTK_WINDOW(dialog), TRUE);
1155         
1156         /* Fill sort keys */
1157         switch (type) {
1158         case MODEST_SORT_HEADERS:
1159                 launch_sort_headers_dialog (parent_window, 
1160                                             HILDON_SORT_DIALOG(dialog));
1161                 break;
1162         }
1163         
1164         /* Free */
1165         gtk_widget_destroy (GTK_WIDGET (dialog));
1166 }
1167
1168
1169 gboolean modest_platform_set_update_interval (guint minutes)
1170 {
1171         ModestConf *conf = modest_runtime_get_conf ();
1172         if (!conf)
1173                 return FALSE;
1174                 
1175         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1176
1177         /* Delete any existing alarm,
1178          * because we will replace it: */
1179         if (alarm_cookie) {
1180                 /* TODO: What does the alarm_event_del() return value mean? */
1181                 alarm_event_del(alarm_cookie);
1182                 alarm_cookie = 0;
1183                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1184         }
1185         
1186         /* 0 means no updates: */
1187         if (minutes == 0)
1188                 return TRUE;
1189                 
1190      
1191         /* Register alarm: */
1192         
1193         /* Get current time: */
1194         time_t time_now;
1195         time (&time_now);
1196         struct tm *st_time = localtime (&time_now);
1197         
1198         /* Add minutes to tm_min field: */
1199         st_time->tm_min += minutes;
1200         
1201         /* Set the time in alarm_event_t structure: */
1202         alarm_event_t *event = g_new0(alarm_event_t, 1);
1203         event->alarm_time = mktime (st_time);
1204
1205         /* Specify what should happen when the alarm happens:
1206          * It should call this D-Bus method: */
1207          
1208         /* Note: I am surpised that alarmd can't just use the modest.service file
1209          * for this. murrayc. */
1210         event->dbus_path = g_strdup(PREFIX "/bin/modest");
1211         
1212         event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1213         event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1214         event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1215
1216         /* Otherwise, a dialog will be shown if exect_name or dbus_path is NULL,
1217         even though we have specified no dialog text: */
1218         event->flags = ALARM_EVENT_NO_DIALOG;
1219         
1220         alarm_cookie = alarm_event_add (event);
1221
1222         /* now, free it */
1223         alarm_event_free (event);
1224         
1225         /* Store the alarm ID in GConf, so we can remove it later:
1226          * This is apparently valid between application instances. */
1227         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1228         
1229         if (!alarm_cookie) {
1230             /* Error */
1231             const alarm_error_t alarm_error = alarmd_get_error ();
1232             printf ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1233             
1234             /* Give people some clue: */
1235             /* The alarm API should have a function for this: */
1236             if (alarm_error == ALARMD_ERROR_DBUS) {
1237                 printf ("  ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1238             } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1239                 printf ("  ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1240             } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1241                 printf ("  ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1242             } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1243                 printf ("  ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1244             } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1245                 printf ("  ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1246             }
1247             
1248             return FALSE;
1249         }
1250         
1251         return TRUE;
1252 }
1253
1254 GtkWidget * 
1255 modest_platform_get_global_settings_dialog ()
1256 {
1257         return modest_maemo_global_settings_dialog_new ();
1258 }
1259
1260 void 
1261 modest_platform_on_new_msg (void)
1262 {
1263 #ifdef MODEST_HAVE_HILDON_NOTIFY
1264         HildonNotification *not;
1265
1266         /* Create a new notification. FIXME put the right values, need
1267            some more specs */
1268         not = hildon_notification_new ("TODO: (new email) Summary",
1269                                        "TODO: (new email) Description",
1270                                        "qgn_contact_group_chat_invitation",
1271                                        "system.note.dialog");
1272
1273         /* Play sound SR-SND-18. TODO: play the right file */
1274         /* TODO: Where is this declared? hildon_notification_set_sound (not, "/usr/share/sounds/ui-new_email.wav"); */
1275
1276         /* Set the led pattern */
1277         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (not), "led-pattern", 3);
1278
1279         /* Notify. We need to do this in an idle because this function
1280            could be called from a thread */
1281         if (!notify_notification_show (NOTIFY_NOTIFICATION (not), NULL))
1282                 g_error ("Failed to send notification");
1283                 
1284         g_object_unref (not);
1285 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1286 }
1287
1288
1289 void
1290 modest_platform_show_help (GtkWindow *parent_window, 
1291                            const gchar *help_id)
1292 {
1293         osso_return_t result;
1294
1295         g_return_if_fail (help_id);
1296         g_return_if_fail (osso_context);
1297
1298         /* Show help */
1299 #ifdef MODEST_HAVE_OSSO_HELP
1300         result = ossohelp_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1301 #else
1302         result = hildon_help_show (osso_context, help_id, OSSO_HELP_SHOW_DIALOG);
1303 #endif
1304
1305         if (result != OSSO_OK) {
1306                 gchar *error_msg;
1307                 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id); 
1308                 hildon_banner_show_information (GTK_WIDGET (parent_window),
1309                                                 NULL,
1310                                                 error_msg);
1311                 g_free (error_msg);
1312         }
1313 }
1314
1315 void 
1316 modest_platform_show_search_messages (GtkWindow *parent_window)
1317 {
1318         osso_return_t result = OSSO_ERROR;
1319         
1320         result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1321
1322         if (result != OSSO_OK) {
1323                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1324         }
1325 }
1326
1327 void 
1328 modest_platform_show_addressbook (GtkWindow *parent_window)
1329 {
1330         osso_return_t result = OSSO_ERROR;
1331         
1332         result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1333
1334         if (result != OSSO_OK) {
1335                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1336         }
1337 }
1338
1339 GtkWidget *
1340 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1341 {
1342         GtkWidget *widget = modest_folder_view_new (query);
1343
1344         /* Show all accounts by default */
1345         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1346                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1347
1348         /* Restore settings */
1349         modest_widget_memory_restore (modest_runtime_get_conf(), 
1350                                       G_OBJECT (widget),
1351                                       MODEST_CONF_FOLDER_VIEW_KEY);
1352
1353         return widget;
1354 }
1355
1356 void 
1357 modest_platform_information_banner (GtkWidget *parent,
1358                                     const gchar *icon_name,
1359                                     const gchar *text)
1360 {
1361         hildon_banner_show_information (parent, icon_name, text);
1362 }
1363
1364 GtkWidget *
1365 modest_platform_animation_banner (GtkWidget *parent,
1366                                   const gchar *animation_name,
1367                                   const gchar *text)
1368 {
1369         GtkWidget *inf_note = NULL;
1370
1371         g_return_val_if_fail (text != NULL, NULL);
1372
1373         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1374
1375         return inf_note;
1376 }