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