* Some improvements for the connect_and_wait, there is no need to disconnect the...
[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 <modest-maemo-utils.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 "modest-tny-folder.h"
55 #include <string.h>
56 #include <libgnomevfs/gnome-vfs-mime-utils.h>
57
58
59 #define HILDON_OSSO_URI_ACTION "uri-action"
60 #define URI_ACTION_COPY "copy:"
61
62 static osso_context_t *osso_context = NULL; /* urgh global */
63
64 static void     
65 on_modest_conf_update_interval_changed (ModestConf* self, 
66                                         const gchar *key, 
67                                         ModestConfEvent event,
68                                         ModestConfNotificationId id, 
69                                         gpointer user_data)
70 {
71         g_return_if_fail (key);
72         
73         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
74                 const guint update_interval_minutes = 
75                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
76                 modest_platform_set_update_interval (update_interval_minutes);
77         }
78 }
79
80
81
82 static gboolean
83 check_required_files (void)
84 {
85         FILE *mcc_file = modest_maemo_open_mcc_mapping_file ();
86         if (!mcc_file) {
87                 g_printerr ("modest: check for mcc file failed\n");
88                 return FALSE;
89         } else 
90                 fclose (mcc_file);
91
92         if (access (MODEST_PROVIDERS_DATA_PATH, R_OK) != 0) {
93                 g_printerr ("modest: cannot find providers data\n");
94                 return FALSE;
95         }
96
97         return TRUE;
98 }
99
100
101
102 gboolean
103 modest_platform_init (int argc, char *argv[])
104 {
105         osso_hw_state_t hw_state = { 0 };
106         DBusConnection *con;    
107         GSList *acc_names;
108         
109         if (!check_required_files ()) {
110                 g_printerr ("modest: missing required files\n");
111                 return FALSE;
112         }
113
114         
115         osso_context =
116                 osso_initialize(PACKAGE,PACKAGE_VERSION,
117                                 FALSE, NULL);   
118         if (!osso_context) {
119                 g_printerr ("modest: failed to acquire osso context\n");
120                 return FALSE;
121         }
122
123         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
124                 g_printerr ("modest: could not get dbus connection\n");
125                 return FALSE;
126
127         }
128
129         /* Add a D-Bus handler to be used when the main osso-rpc 
130          * D-Bus handler has not handled something.
131          * We use this for D-Bus methods that need to use more complex types 
132          * than osso-rpc supports. 
133          */
134         if (!dbus_connection_add_filter (con,
135                                          modest_dbus_req_filter,
136                                          NULL,
137                                          NULL)) {
138
139                 g_printerr ("modest: Could not add D-Bus filter\n");
140                 return FALSE;
141         }
142
143         /* Register our simple D-Bus callbacks, via the osso API: */
144         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
145                                MODEST_DBUS_SERVICE, 
146                                MODEST_DBUS_OBJECT, 
147                                MODEST_DBUS_IFACE,
148                                modest_dbus_req_handler, NULL /* user_data */);
149         if (result != OSSO_OK) {
150                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
151                 return FALSE;
152         }
153
154         /* Add handler for Exit D-BUS messages.
155          * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
156         result = osso_application_set_exit_cb(osso_context,
157                                           modest_dbus_exit_event_handler,
158                                           (gpointer) NULL);
159         if (result != OSSO_OK) {
160                 g_print("Error setting exit callback (%d)\n", result);
161                 return OSSO_ERROR;
162         }
163         */
164
165         /* Register hardware event dbus callback: */
166         hw_state.shutdown_ind = TRUE;
167         osso_hw_set_event_cb(osso_context, NULL,/*&hw_state*/ modest_osso_cb_hw_state_handler, NULL);
168
169         /* Register osso auto-save callbacks: */
170         result = osso_application_set_autosave_cb (osso_context, 
171                 modest_on_osso_application_autosave, NULL /* user_data */);
172         if (result != OSSO_OK) {
173                 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
174                 return FALSE;
175         }
176         
177
178         /* Make sure that the update interval is changed whenever its gconf key 
179          * is changed */
180         /* CAUTION: we're not using here the
181            modest_conf_listen_to_namespace because we know that there
182            are other parts of Modest listening for this namespace, so
183            we'll receive the notifications anyway. We basically do not
184            use it because there is no easy way to do the
185            modest_conf_forget_namespace */
186         ModestConf *conf = modest_runtime_get_conf ();
187         g_signal_connect (G_OBJECT(conf),
188                           "key_changed",
189                           G_CALLBACK (on_modest_conf_update_interval_changed), 
190                           NULL);
191
192         /* only force the setting of the default interval, if there are actually
193          * any accounts */
194         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
195         if (acc_names) {
196                 /* Get the initial update interval from gconf: */
197                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
198                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
199                 modest_account_mgr_free_account_names (acc_names);
200         }
201
202         /* initialize the addressbook */
203         if (!osso_abook_init (&argc, &argv, osso_context)) {
204                 g_printerr ("modest: failed to initialized addressbook\n");
205                 return FALSE;
206         }
207                 
208         return TRUE;
209 }
210
211 TnyDevice*
212 modest_platform_get_new_device (void)
213 {
214         return TNY_DEVICE (tny_maemo_conic_device_new ());
215 }
216
217 gchar*
218 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
219                                     gchar **effective_mime_type)
220 {
221         GString *mime_str = NULL;
222         gchar *icon_name  = NULL;
223         gchar **icons, **cursor;
224         
225         if (!mime_type || !g_ascii_strcasecmp (mime_type, "application/octet-stream")) 
226                 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
227         else {
228                 mime_str = g_string_new (mime_type);
229                 g_string_ascii_down (mime_str);
230         }
231
232         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
233         for (cursor = icons; cursor; ++cursor) {
234                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
235                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
236                         icon_name = g_strdup ("qgn_list_messagin");
237                         break;
238                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
239                         icon_name = g_strdup (*cursor);
240                         break;
241                 }
242         }
243         g_strfreev (icons);
244
245         if (effective_mime_type)
246                 *effective_mime_type = g_string_free (mime_str, FALSE);
247         else
248                 g_string_free (mime_str, TRUE);
249
250         return icon_name;
251 }
252
253
254 gboolean 
255 modest_platform_activate_uri (const gchar *uri)
256 {
257         HildonURIAction *action;
258         gboolean result = FALSE;
259         GSList *actions, *iter = NULL;
260         
261         g_return_val_if_fail (uri, FALSE);
262         if (!uri)
263                 return FALSE;
264         
265         actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
266         
267         for (iter = actions; iter; iter = g_slist_next (iter)) {
268                 action = (HildonURIAction*) iter->data;
269                 if (action && strcmp (hildon_uri_action_get_service (action),
270                                       "com.nokia.modest") == 0) {
271                         GError *err = NULL;
272                         result = hildon_uri_open (uri, action, &err);
273                         if (!result && err) {
274                                 g_printerr ("modest: modest_platform_activate_uri : %s",
275                                             err->message ? err->message : "unknown error");
276                                 g_error_free (err);
277                         }
278                         break;
279                 }
280         }
281         
282         /* if we could not open it with email, try something else */
283         if (!result)
284                 result = hildon_uri_open (uri, NULL, NULL);     
285                 
286         if (!result)
287                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
288         
289         return result;
290 }
291
292 gboolean 
293 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
294 {
295         gint result = 0;
296         DBusConnection *con;
297         gchar *uri_path = NULL;
298
299         uri_path = g_strconcat ("file://", path, NULL); 
300         con = osso_get_dbus_connection (osso_context);
301         
302         if (mime_type)
303                 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
304         if (result != 1)
305                 result = hildon_mime_open_file (con, uri_path);
306         if (result != 1)
307                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"));
308         
309         return result != 1;
310 }
311
312 typedef struct  {
313         GSList *actions;
314         gchar  *uri;
315 } ModestPlatformPopupInfo;
316
317 static gboolean
318 delete_uri_popup (GtkWidget *menu,
319                   GdkEvent *event,
320                   gpointer userdata)
321 {
322         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
323
324         g_free (popup_info->uri);
325         hildon_uri_free_actions (popup_info->actions);
326
327         return FALSE;
328 }
329
330 static void
331 activate_uri_popup_item (GtkMenuItem *menu_item,
332                          gpointer userdata)
333 {
334         GSList *node;
335         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
336         const gchar* action_name;
337
338         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
339         if (!action_name) {
340                 g_printerr ("modest: no action name defined\n");
341                 return;
342         }
343
344         /* special handling for the copy menu item -- copy the uri to the clipboard */
345         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
346         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
347                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
348                 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
349
350                 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
351                         action_name += strlen ("mailto:");
352                 
353                 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
354                 return; /* we're done */
355         }
356         
357         /* now, the real uri-actions... */
358         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
359                 HildonURIAction *action = (HildonURIAction *) node->data;
360                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
361                         hildon_uri_open (popup_info->uri, action, NULL);
362                         break;
363                 }
364         }
365 }
366
367 gboolean 
368 modest_platform_show_uri_popup (const gchar *uri)
369 {
370         GSList *actions_list;
371
372         if (uri == NULL)
373                 return FALSE;
374
375         actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
376         if (actions_list != NULL) {
377                 GSList *node;
378                 GtkWidget *menu = gtk_menu_new ();
379                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
380
381                 popup_info->actions = actions_list;
382                 popup_info->uri = g_strdup (uri);
383               
384                 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
385                         GtkWidget *menu_item;
386                         const gchar *action_name;
387                         const gchar *translation_domain;
388                         HildonURIAction *action = (HildonURIAction *) node->data;
389                         action_name = hildon_uri_action_get_name (action);
390                         translation_domain = hildon_uri_action_get_translation_domain (action);
391                         menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
392                         g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
393                         g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
394                                           popup_info);
395                                                                   
396                         if (hildon_uri_is_default_action (action, NULL)) {
397                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
398                         } else {
399                                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
400                         }
401                         gtk_widget_show (menu_item);
402                 }
403
404                 /* always add the copy item */
405                 GtkWidget* menu_item = gtk_menu_item_new_with_label (dgettext("osso-uri", "uri_link_copy_link_location"));
406                 g_object_set_data_full (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION,
407                                         g_strconcat (URI_ACTION_COPY, uri, NULL),
408                                         g_free);
409                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),NULL);
410                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
411                 gtk_widget_show (menu_item);
412
413                 
414                 /* and what to do when the link is deleted */
415                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
416                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
417                                                   
418         } else {
419                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
420         }
421
422         return TRUE;
423 }
424
425
426 GdkPixbuf*
427 modest_platform_get_icon (const gchar *name)
428 {
429         GError *err = NULL;
430         GdkPixbuf* pixbuf = NULL;
431         GtkIconTheme *current_theme = NULL;
432
433         g_return_val_if_fail (name, NULL);
434
435         /* strlen == 0 is not really an error; it just
436          * means the icon is not available
437          */
438         if (!name || strlen(name) == 0)
439                 return NULL;
440         
441 #if 0 /* do we still need this? */
442         if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
443                 pixbuf = gdk_pixbuf_new_from_file (name, &err);
444                 if (!pixbuf) {
445                         g_printerr ("modest: error loading icon '%s': %s\n",
446                                     name, err->message);
447                         g_error_free (err);
448                         return NULL;
449                 }
450                 return pixbuf;
451         }
452 #endif /* */
453         current_theme = gtk_icon_theme_get_default ();
454         pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
455                                            GTK_ICON_LOOKUP_NO_SVG,
456                                            &err);
457         if (!pixbuf) {
458                 g_printerr ("modest: error loading theme icon '%s': %s\n",
459                             name, err->message);
460                 g_error_free (err);
461         } 
462         return pixbuf;
463 }
464
465 const gchar*
466 modest_platform_get_app_name (void)
467 {
468         return _("mcen_ap_name");
469 }
470
471 static void 
472 entry_insert_text (GtkEditable *editable,
473                    const gchar *text,
474                    gint         length,
475                    gint        *position,
476                    gpointer     data)
477 {
478         gchar *chars;
479         gint chars_length;
480
481         chars = gtk_editable_get_chars (editable, 0, -1);
482         chars_length = g_utf8_strlen (chars, -1);
483
484         /* Show WID-INF036 */
485         if (chars_length >= 20) {
486                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
487                                                  _CS("ckdg_ib_maximum_characters_reached"));
488         } else {
489                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
490                         /* Show an error */
491                         gchar *tmp, *msg;
492                         
493                         tmp = g_strndup (folder_name_forbidden_chars, 
494                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
495                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
496                         hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), 
497                                                          NULL, msg);
498                         g_free (msg);
499                         g_free (tmp);
500                 } else {        
501                         /* Write the text in the entry if it's valid */
502                         g_signal_handlers_block_by_func (editable,
503                                                          (gpointer) entry_insert_text, data);
504                         gtk_editable_insert_text (editable, text, length, position);
505                         g_signal_handlers_unblock_by_func (editable,
506                                                            (gpointer) entry_insert_text, data);
507                 }
508         }
509         /* Do not allow further processing */
510         g_signal_stop_emission_by_name (editable, "insert_text");
511 }
512
513 static void
514 entry_changed (GtkEditable *editable,
515                gpointer     user_data)
516 {
517         gchar *chars;
518         GtkWidget *ok_button;
519         GList *buttons;
520
521         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
522         ok_button = GTK_WIDGET (buttons->next->data);
523         
524         chars = gtk_editable_get_chars (editable, 0, -1);
525         g_return_if_fail (chars != NULL);
526
527         
528         if (g_utf8_strlen (chars,-1) >= 21)
529                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
530                                                  _CS("ckdg_ib_maximum_characters_reached"));
531         else
532                 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
533                 
534         /* Free */
535         g_list_free (buttons);
536         g_free (chars);
537 }
538
539 static void
540 launch_sort_headers_dialog (GtkWindow *parent_window,
541                             HildonSortDialog *dialog)
542 {
543         ModestHeaderView *header_view = NULL;
544         GList *cols = NULL;
545         GtkSortType sort_type;
546         gint sort_key;
547         gint default_key = 0;
548         gint result;
549         gboolean outgoing = FALSE;
550         gint current_sort_colid = -1;
551         GtkSortType current_sort_type;
552         gint attachments_sort_id;
553         gint priority_sort_id;
554         GtkTreeSortable *sortable;
555         
556         /* Get header window */
557         if (MODEST_IS_MAIN_WINDOW (parent_window)) {
558                 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(parent_window),
559                                                                                       MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
560         }
561         if (!header_view) return;
562
563         /* Add sorting keys */
564         cols = modest_header_view_get_columns (header_view);
565         if (cols == NULL) return;
566         int sort_model_ids[6];
567         int sort_ids[6];
568
569
570         outgoing = (GPOINTER_TO_INT (g_object_get_data(G_OBJECT(cols->data), MODEST_HEADER_VIEW_COLUMN))==
571                     MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT);
572
573         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_sender_recipient"));
574         if (outgoing) {
575                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
576                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
577         } else {
578                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
579                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
580         }
581
582         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_date"));
583         if (outgoing) {
584                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
585                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_SENT_DATE;
586         } else {
587                 sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
588                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_RECEIVED_DATE;
589         }
590         default_key = sort_key;
591
592         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_subject"));
593         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN;
594         if (outgoing)
595                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_OUT;
596         else
597                 sort_ids[sort_key] = MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER_IN;
598
599         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_attachment"));
600         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
601         sort_ids[sort_key] = TNY_HEADER_FLAG_ATTACHMENTS;
602         attachments_sort_id = sort_key;
603
604         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_size"));
605         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN;
606         sort_ids[sort_key] = 0;
607
608         sort_key = hildon_sort_dialog_add_sort_key (dialog, _("mcen_li_sort_priority"));
609         sort_model_ids[sort_key] = TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN;
610         sort_ids[sort_key] = TNY_HEADER_FLAG_PRIORITY;
611         priority_sort_id = sort_key;
612
613         sortable = GTK_TREE_SORTABLE (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (header_view)))));
614         /* Launch dialogs */
615         if (!gtk_tree_sortable_get_sort_column_id (sortable,
616                                                    &current_sort_colid, &current_sort_type)) {
617                 hildon_sort_dialog_set_sort_key (dialog, default_key);
618                 hildon_sort_dialog_set_sort_order (dialog, GTK_SORT_DESCENDING);
619         } else {
620                 hildon_sort_dialog_set_sort_order (dialog, current_sort_type);
621                 if (current_sort_colid == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
622                         gpointer flags_sort_type_pointer;
623                         flags_sort_type_pointer = g_object_get_data (G_OBJECT (cols->data), MODEST_HEADER_VIEW_FLAG_SORT);
624                         if (GPOINTER_TO_INT (flags_sort_type_pointer) == TNY_HEADER_FLAG_PRIORITY)
625                                 hildon_sort_dialog_set_sort_key (dialog, priority_sort_id);
626                         else
627                                 hildon_sort_dialog_set_sort_key (dialog, attachments_sort_id);
628                 } else {
629                         gint current_sort_keyid = 0;
630                         while (current_sort_keyid < 6) {
631                                 if (sort_model_ids[current_sort_keyid] == current_sort_colid)
632                                         break;
633                                 else 
634                                         current_sort_keyid++;
635                         }
636                         hildon_sort_dialog_set_sort_key (dialog, current_sort_keyid);
637                 }
638         }
639
640         result = gtk_dialog_run (GTK_DIALOG (dialog));
641         if (result == GTK_RESPONSE_OK) {
642                 sort_key = hildon_sort_dialog_get_sort_key (dialog);
643                 sort_type = hildon_sort_dialog_get_sort_order (dialog);
644                 if (sort_model_ids[sort_key] == TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN) {
645                         g_object_set_data (G_OBJECT(cols->data), MODEST_HEADER_VIEW_FLAG_SORT,
646                                            GINT_TO_POINTER (sort_ids[sort_key]));
647                         /* This is a hack to make it resort rows always when flag fields are
648                          * selected. If we do not do this, changing sort field from priority to
649                          * attachments does not work */
650                         modest_header_view_sort_by_column_id (header_view, 0, sort_type);
651                 } else {
652                         gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (cols->data), 
653                                                                  sort_model_ids[sort_key]);
654                 }
655
656                 modest_header_view_sort_by_column_id (header_view, sort_model_ids[sort_key], sort_type);
657                 gtk_tree_sortable_sort_column_changed (sortable);
658         }
659
660         modest_widget_memory_save (modest_runtime_get_conf (),
661                                    G_OBJECT (header_view), MODEST_CONF_HEADER_VIEW_KEY);
662         
663 /*      while (gtk_events_pending ()) */
664 /*              gtk_main_iteration (); */
665
666         /* free */
667         g_list_free(cols);      
668 }
669
670
671
672 static void
673 on_response (GtkDialog *dialog,
674              gint response,
675              gpointer user_data)
676 {
677         GList *child_vbox, *child_hbox;
678         GtkWidget *hbox, *entry;
679         TnyFolderStore *parent;
680
681         if (response != GTK_RESPONSE_ACCEPT)
682                 return;
683
684         /* Get entry */
685         child_vbox = gtk_container_get_children (GTK_CONTAINER (dialog->vbox));
686         hbox = child_vbox->data;
687         child_hbox = gtk_container_get_children (GTK_CONTAINER (hbox));
688         entry = child_hbox->next->data;
689
690         parent = TNY_FOLDER_STORE (user_data);
691
692         /* Look for another folder with the same name */
693         if (modest_tny_folder_has_subfolder_with_name (parent, 
694                                                        gtk_entry_get_text (GTK_ENTRY (entry)))) {
695                 /* Show an error */
696                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
697                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
698                 /* Select the text */
699                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
700                 gtk_widget_grab_focus (entry);
701                 /* Do not close the dialog */
702                 g_signal_stop_emission_by_name (dialog, "response");
703         }
704 }
705
706
707
708 static gint
709 modest_platform_run_folder_name_dialog (GtkWindow *parent_window,
710                                         TnyFolderStore *parent,
711                                         const gchar *dialog_title,
712                                         const gchar *label_text,
713                                         const gchar *suggested_name,
714                                         gchar **folder_name)
715 {
716         GtkWidget *accept_btn = NULL; 
717         GtkWidget *dialog, *entry, *label, *hbox;
718         GList *buttons = NULL;
719         gint result;
720
721         /* Ask the user for the folder name */
722         dialog = gtk_dialog_new_with_buttons (dialog_title,
723                                               parent_window,
724                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
725                                               _("mcen_bd_dialog_ok"),
726                                               GTK_RESPONSE_ACCEPT,
727                                               _("mcen_bd_dialog_cancel"),
728                                               GTK_RESPONSE_REJECT,
729                                               NULL);
730
731         /* Add accept button (with unsensitive handler) */
732         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
733         accept_btn = GTK_WIDGET (buttons->next->data);
734         /* Create label and entry */
735         label = gtk_label_new (label_text);
736         /* TODO: check that the suggested name does not exist */
737         /* We set 21 as maximum because we want to show WID-INF036
738            when the user inputs more that 20 */
739         entry = gtk_entry_new_with_max_length (21);
740         if (suggested_name)
741                 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
742         else
743                 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
744         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
745
746         /* Connect to the response method to avoid closing the dialog
747            when an invalid name is selected*/
748         g_signal_connect (dialog,
749                           "response",
750                           G_CALLBACK (on_response),
751                           parent);
752
753         /* Track entry changes */
754         g_signal_connect (entry,
755                           "insert-text",
756                           G_CALLBACK (entry_insert_text),
757                           dialog);
758         g_signal_connect (entry,
759                           "changed",
760                           G_CALLBACK (entry_changed),
761                           dialog);
762
763         /* Create the hbox */
764         hbox = gtk_hbox_new (FALSE, 12);
765         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
766         gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
767
768         /* Add hbox to dialog */
769         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
770                             hbox, FALSE, FALSE, 0);
771         
772         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
773         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
774         
775         result = gtk_dialog_run (GTK_DIALOG(dialog));
776         if (result == GTK_RESPONSE_ACCEPT)
777                 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
778
779         gtk_widget_destroy (dialog);
780
781         while (gtk_events_pending ())
782                 gtk_main_iteration ();
783
784         return result;
785 }
786
787 gint
788 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
789                                        TnyFolderStore *parent_folder,
790                                        gchar *suggested_name,
791                                        gchar **folder_name)
792 {
793         gchar *real_suggested_name = NULL;
794         gint result;
795
796         if(suggested_name == NULL)
797         {
798                 const gchar *default_name = _("mcen_ia_default_folder_name");
799                 unsigned int i;
800                 gchar num_str[3];
801
802                 for(i = 0; i < 100; ++ i) {
803                         gboolean exists = FALSE;
804
805                         sprintf(num_str, "%.2u", i);
806
807                         if (i == 0)
808                                 real_suggested_name = g_strdup (default_name);
809                         else
810                                 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
811                                                                        num_str);
812
813                         exists = modest_tny_folder_has_subfolder_with_name (parent_folder,
814                                                                             real_suggested_name);
815
816                         if (!exists)
817                                 break;
818
819                         g_free (real_suggested_name);
820                 }
821
822                 /* Didn't find a free number */
823                 if (i == 100)
824                         real_suggested_name = g_strdup (default_name);
825         } else {
826                 real_suggested_name = suggested_name;
827         }
828
829         result = modest_platform_run_folder_name_dialog (parent_window, 
830                                                          parent_folder,
831                                                          _("mcen_ti_new_folder"),
832                                                          _("mcen_fi_new_folder_name"),
833                                                          real_suggested_name,
834                                                          folder_name);
835         if (suggested_name == NULL)
836                 g_free(real_suggested_name);
837
838         return result;
839 }
840
841 gint
842 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
843                                           TnyFolderStore *parent_folder,
844                                           const gchar *suggested_name,
845                                           gchar **folder_name)
846 {
847         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
848
849         return modest_platform_run_folder_name_dialog (parent_window, 
850                                                        parent_folder,
851                                                        _HL("ckdg_ti_rename_folder"),
852                                                        _HL("ckdg_fi_rename_name"),
853                                                        suggested_name,
854                                                        folder_name);
855 }
856
857
858
859 static void
860 on_destroy_dialog (GtkDialog *dialog)
861 {
862         gtk_widget_destroy (GTK_WIDGET(dialog));
863         if (gtk_events_pending ())
864                 gtk_main_iteration ();
865 }
866
867 gint
868 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
869                                          const gchar *message)
870 {
871         GtkWidget *dialog;
872         gint response;
873         
874         dialog = hildon_note_new_confirmation (parent_window, message);
875         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
876                                      GTK_WINDOW (dialog));
877
878         response = gtk_dialog_run (GTK_DIALOG (dialog));
879
880         on_destroy_dialog (GTK_DIALOG(dialog));
881         
882         while (gtk_events_pending ())
883                 gtk_main_iteration ();
884
885         return response;
886 }
887         
888 gint
889 modest_platform_run_yes_no_dialog (GtkWindow *parent_window,
890                                    const gchar *message)
891 {
892         GtkWidget *dialog;
893         gint response;
894         
895         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
896                                                            _("mcen_bd_yes"), GTK_RESPONSE_YES,
897                                                            _("mcen_bd_no"), GTK_RESPONSE_NO,
898                                                            NULL);
899         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
900         response = gtk_dialog_run (GTK_DIALOG (dialog));
901         
902         on_destroy_dialog (GTK_DIALOG(dialog));
903
904         while (gtk_events_pending ())
905                 gtk_main_iteration ();
906
907         return response;
908 }
909
910
911
912 void
913 modest_platform_run_information_dialog (GtkWindow *parent_window,
914                                         const gchar *message)
915 {
916         GtkWidget *note;
917         
918         note = hildon_note_new_information (parent_window, message);
919         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
920                                      GTK_WINDOW (note));
921         
922         g_signal_connect_swapped (note,
923                                   "response", 
924                                   G_CALLBACK (on_destroy_dialog),
925                                   note);
926
927         gtk_widget_show_all (note);
928 }
929
930
931
932 typedef struct _ConnectAndWaitData {
933         GMutex *mutex;
934         GMainLoop *wait_loop;
935         gboolean has_callback;
936         gulong handler;
937 } ConnectAndWaitData;
938
939
940 static void
941 quit_wait_loop (TnyAccount *account,
942                 ConnectAndWaitData *data) 
943 {
944         /* Set the has_callback to TRUE (means that the callback was
945            executed and wake up every code waiting for cond to be
946            TRUE */
947         g_mutex_lock (data->mutex);
948         data->has_callback = TRUE;
949         if (data->wait_loop)
950                 g_main_loop_quit (data->wait_loop);
951         g_mutex_unlock (data->mutex);
952 }
953
954 static void
955 on_connection_status_changed (TnyAccount *account, 
956                               TnyConnectionStatus status,
957                               gpointer user_data)
958 {
959         TnyConnectionStatus conn_status;
960         ConnectAndWaitData *data;
961                         
962         /* Ignore if reconnecting or disconnected */
963         conn_status = tny_account_get_connection_status (account);
964         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
965             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
966                 return;
967
968         /* Remove the handler */
969         data = (ConnectAndWaitData *) user_data;
970         g_signal_handler_disconnect (account, data->handler);
971
972         /* Quit from wait loop */
973         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
974 }
975
976 static void
977 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
978                                     gboolean canceled, 
979                                     GError *err, 
980                                     gpointer user_data)
981 {
982         /* Quit from wait loop */
983         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
984 }
985
986 gboolean 
987 modest_platform_connect_and_wait (GtkWindow *parent_window, 
988                                   TnyAccount *account)
989 {
990         ConnectAndWaitData *data = NULL;
991         gboolean device_online;
992         TnyDevice *device;
993         TnyConnectionStatus conn_status;
994         
995         device = modest_runtime_get_device();
996         device_online = tny_device_is_online (device);
997
998         /* If there is no account check only the device status */
999         if (!account) {
1000                 if (device_online)
1001                         return TRUE;
1002                 else
1003                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
1004         }
1005
1006         /* Return if the account is already connected */
1007         conn_status = tny_account_get_connection_status (account);
1008         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1009                 return TRUE;
1010
1011         /* Create the helper */
1012         data = g_slice_new0 (ConnectAndWaitData);
1013         data->mutex = g_mutex_new ();
1014         data->has_callback = FALSE;
1015
1016         /* Connect the device */
1017         if (!device_online) {
1018                 /* Track account connection status changes */
1019                 data->handler = g_signal_connect (account, "connection-status-changed",                                     
1020                                                   G_CALLBACK (on_connection_status_changed),
1021                                                   data);
1022                 /* Try to connect the device */
1023                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
1024
1025                 /* If the device connection failed then exit */
1026                 if (!device_online && data->handler)
1027                         goto frees;
1028         } else {
1029                 /* Force a reconnection of the account */
1030                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1031                                               on_tny_camel_account_set_online_cb, data);
1032         }
1033
1034         /* Wait until the callback is executed */
1035         g_mutex_lock (data->mutex);
1036         if (!data->has_callback) {
1037                 data->wait_loop = g_main_loop_new (NULL, FALSE);
1038                 gdk_threads_leave ();
1039                 g_mutex_unlock (data->mutex);
1040                 g_main_loop_run (data->wait_loop);
1041                 g_mutex_lock (data->mutex);
1042                 gdk_threads_enter ();
1043         }
1044         g_mutex_unlock (data->mutex);
1045
1046  frees:
1047         if (data) {
1048                 if (g_signal_handler_is_connected (account, data->handler))
1049                         g_signal_handler_disconnect (account, data->handler);
1050                 g_mutex_free (data->mutex);
1051                 g_main_loop_unref (data->wait_loop);
1052                 g_slice_free (ConnectAndWaitData, data);
1053         }
1054
1055         conn_status = tny_account_get_connection_status (account);
1056         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1057 }
1058
1059 gboolean 
1060 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1061 {
1062         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1063                 if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1064                     !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1065                         /* This must be a maildir account, which does not require a connection: */
1066                         return TRUE;
1067                 }
1068         }
1069
1070         return modest_platform_connect_and_wait (parent_window, account);
1071 }
1072
1073 gboolean 
1074 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1075 {
1076         if (!folder_store)
1077                 return TRUE; /* Maybe it is something local. */
1078                 
1079         gboolean result = TRUE;
1080         if (TNY_IS_FOLDER (folder_store)) {
1081                 /* Get the folder's parent account: */
1082                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1083                 if (account != NULL) {
1084                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1085                         g_object_unref (account);
1086                 }
1087         } else if (TNY_IS_ACCOUNT (folder_store)) {
1088                 /* Use the folder store as an account: */
1089                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1090         }
1091
1092         return result;
1093 }
1094
1095 gboolean 
1096 modest_platform_is_network_folderstore (TnyFolderStore *folder_store)
1097 {
1098         TnyAccount *account = NULL;
1099         gboolean result = TRUE;
1100
1101         g_return_val_if_fail(TNY_IS_FOLDER_STORE(folder_store), FALSE);
1102
1103         if (TNY_IS_FOLDER (folder_store)) {
1104                 /* Get the folder's parent account: */
1105                 account = tny_folder_get_account(TNY_FOLDER(folder_store));
1106         } else if (TNY_IS_ACCOUNT (folder_store)) {
1107                 account = TNY_ACCOUNT(folder_store);
1108                 g_object_ref(account);
1109         }
1110
1111         if (account != NULL) {
1112                 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1113                         if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
1114                             !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
1115                                 /* This must be a maildir account, which does
1116                                  * not require a connection: */
1117                                 result = FALSE;
1118                         }
1119                 }
1120                 g_object_unref (account);
1121         } else {
1122                 result = FALSE;
1123         }
1124
1125         return result;
1126 }
1127
1128 void
1129 modest_platform_run_sort_dialog (GtkWindow *parent_window,
1130                                  ModestSortDialogType type)
1131 {
1132         GtkWidget *dialog = NULL;
1133
1134         /* Build dialog */
1135         dialog = hildon_sort_dialog_new (parent_window);
1136         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1137                                      GTK_WINDOW (dialog));
1138         
1139         /* Fill sort keys */
1140         switch (type) {
1141         case MODEST_SORT_HEADERS:
1142                 launch_sort_headers_dialog (parent_window, 
1143                                             HILDON_SORT_DIALOG(dialog));
1144                 break;
1145         }
1146         
1147         /* Free */
1148         on_destroy_dialog (GTK_DIALOG(dialog));
1149 }
1150
1151
1152 gboolean 
1153 modest_platform_set_update_interval (guint minutes)
1154 {
1155         ModestConf *conf = modest_runtime_get_conf ();
1156         if (!conf)
1157                 return FALSE;
1158                 
1159         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1160
1161         /* Delete any existing alarm,
1162          * because we will replace it: */
1163         if (alarm_cookie) {
1164                 /* TODO: What does the alarm_event_del() return value mean? */
1165                 alarm_event_del(alarm_cookie);
1166                 alarm_cookie = 0;
1167                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1168         }
1169         
1170         /* 0 means no updates: */
1171         if (minutes == 0)
1172                 return TRUE;
1173                 
1174      
1175         /* Register alarm: */
1176         
1177         /* Set the interval in alarm_event_t structure: */
1178         alarm_event_t *event = g_new0(alarm_event_t, 1);
1179         event->alarm_time = minutes * 60; /* seconds */
1180         
1181         /* Set recurrence every few minutes: */
1182         event->recurrence = minutes;
1183         event->recurrence_count = -1; /* Means infinite */
1184
1185         /* Specify what should happen when the alarm happens:
1186          * It should call this D-Bus method: */
1187          
1188         event->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1189         event->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1190         event->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1191         event->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1192
1193         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1194          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1195          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1196          * This is why we want to use the Alarm API instead of just g_timeout_add().
1197          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1198          */
1199         event->flags = ALARM_EVENT_NO_DIALOG | ALARM_EVENT_ACTIVATION;
1200         
1201         alarm_cookie = alarm_event_add (event);
1202
1203         /* now, free it */
1204         alarm_event_free (event);
1205         
1206         /* Store the alarm ID in GConf, so we can remove it later:
1207          * This is apparently valid between application instances. */
1208         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1209         
1210         if (!alarm_cookie) {
1211             /* Error */
1212             const alarm_error_t alarm_error = alarmd_get_error ();
1213             g_debug ("Error setting alarm event. Error code: '%d'\n", alarm_error);
1214             
1215             /* Give people some clue: */
1216             /* The alarm API should have a function for this: */
1217             if (alarm_error == ALARMD_ERROR_DBUS) {
1218                 g_debug ("  ALARMD_ERROR_DBUS: An error with D-Bus occurred, probably coudn't get a D-Bus connection.\n");
1219             } else if (alarm_error == ALARMD_ERROR_CONNECTION) {
1220                 g_debug ("  ALARMD_ERROR_CONNECTION: Could not contact alarmd via D-Bus.\n");
1221             } else if (alarm_error == ALARMD_ERROR_INTERNAL) {
1222                 g_debug ("  ALARMD_ERROR_INTERNAL: Some alarmd or libalarm internal error, possibly a version mismatch.\n");
1223             } else if (alarm_error == ALARMD_ERROR_MEMORY) {
1224                 g_debug ("  ALARMD_ERROR_MEMORY: A memory allocation failed.\n");
1225             } else if (alarm_error == ALARMD_ERROR_ARGUMENT) {
1226                 g_debug ("  ALARMD_ERROR_ARGUMENT: An argument given by caller was invalid.\n");
1227             } else if (alarm_error == ALARMD_ERROR_NOT_RUNNING) {
1228                 g_debug ("  ALARMD_ERROR_NOT_RUNNING: alarmd is not running.\n");
1229             }
1230             
1231             return FALSE;
1232         }
1233         
1234         return TRUE;
1235 }
1236
1237 void 
1238 modest_platform_on_new_headers_received (TnyList *header_list) 
1239 {
1240 #ifdef MODEST_HAVE_HILDON_NOTIFY
1241         HildonNotification *notification;
1242         TnyIterator *iter;
1243         GSList *notifications_list = NULL;
1244
1245         /* Get previous notifications ids */
1246         notifications_list = modest_conf_get_list (modest_runtime_get_conf (), 
1247                                                    MODEST_CONF_NOTIFICATION_IDS, 
1248                                                    MODEST_CONF_VALUE_INT, NULL);
1249
1250         iter = tny_list_create_iterator (header_list);
1251         while (!tny_iterator_is_done (iter)) {
1252                 gchar *url = NULL, *display_address = NULL, *display_date = NULL, *summary = NULL;
1253                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1254                 TnyFolder *folder = tny_header_get_folder (header);
1255                 gboolean first_notification = TRUE;
1256                 gint notif_id;
1257         
1258                 display_date = modest_text_utils_get_display_date (tny_header_get_date_received (header));
1259
1260                 display_address = g_strdup(tny_header_get_from (header));
1261                 modest_text_utils_get_display_address (display_address); /* string is changed in-place */
1262                 
1263                 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1264                 notification = hildon_notification_new (summary,
1265                                                         tny_header_get_subject (header),
1266                                                         "qgn_list_messagin",
1267                                                         "email.arrive");
1268                 
1269                 /* Create the message URL */
1270                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1271                                        tny_header_get_uid (header));
1272
1273                 hildon_notification_add_dbus_action(notification,
1274                                                     "default",
1275                                                     "Cancel",
1276                                                     MODEST_DBUS_SERVICE,
1277                                                     MODEST_DBUS_OBJECT,
1278                                                     MODEST_DBUS_IFACE,
1279                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1280                                                     G_TYPE_STRING, url,
1281                                                     -1);
1282
1283                 /* Play sound if the user wants. Show the LED
1284                    pattern. Show and play just one */
1285                 if (G_UNLIKELY (first_notification)) {
1286                         first_notification = FALSE;
1287                         if (modest_conf_get_bool (modest_runtime_get_conf (),
1288                                                   MODEST_CONF_PLAY_SOUND_MSG_ARRIVE,
1289                                                   NULL))  {
1290                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1291                                                                     "sound-file", "/usr/share/sounds/ui-new_email.wav");
1292                         }
1293
1294                         /* Set the led pattern */
1295                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1296                                                             "dialog-type", 4);
1297                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1298                                                             "led-pattern",
1299                                                             "PatternCommunicationEmail");                       
1300                 }
1301
1302                 /* Notify. We need to do this in an idle because this function
1303                    could be called from a thread */
1304                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1305
1306                 /* Save id in the list */
1307                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1308                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1309                 /* We don't listen for the "closed" signal, because we
1310                    don't care about if the notification was removed or
1311                    not to store the list in gconf */
1312         
1313                 /* Free & carry on */
1314                 g_free (display_date);
1315                 g_free (display_address);
1316                 g_free (summary);
1317                 g_free (url);
1318                 g_object_unref (folder);
1319                 g_object_unref (header);
1320                 tny_iterator_next (iter);
1321         }
1322         g_object_unref (iter);
1323
1324         /* Save the ids */
1325         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1326                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1327
1328         g_slist_free (notifications_list);
1329         
1330 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1331 }
1332
1333 void
1334 modest_platform_remove_new_mail_notifications (void) 
1335 {
1336 #ifdef MODEST_HAVE_HILDON_NOTIFY
1337         GSList *notif_list = NULL;
1338
1339         /* Get previous notifications ids */
1340         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1341                                            MODEST_CONF_NOTIFICATION_IDS, 
1342                                            MODEST_CONF_VALUE_INT, NULL);
1343
1344         while (notif_list) {
1345                 gint notif_id;
1346                 NotifyNotification *notif;
1347
1348                 /* Nasty HACK to remove the notifications, set the id
1349                    of the existing ones and then close them */
1350                 notif_id = GPOINTER_TO_INT(notif_list->data);
1351                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1352                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1353
1354                 /* Close the notification, note that some ids could be
1355                    already invalid, but we don't care because it does
1356                    not fail */
1357                 notify_notification_close(notif, NULL);
1358                 g_object_unref(notif);
1359
1360                 /* Delete the link, it's like going to the next */
1361                 notif_list = g_slist_delete_link (notif_list, notif_list);
1362         }
1363
1364         /* Save the ids */
1365         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1366                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1367
1368         g_slist_free (notif_list);
1369
1370 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1371 }
1372
1373
1374
1375 GtkWidget * 
1376 modest_platform_get_global_settings_dialog ()
1377 {
1378         return modest_maemo_global_settings_dialog_new ();
1379 }
1380
1381 void
1382 modest_platform_show_help (GtkWindow *parent_window, 
1383                            const gchar *help_id)
1384 {
1385         osso_return_t result;
1386
1387         g_return_if_fail (help_id);
1388         g_return_if_fail (osso_context);
1389
1390         result = hildon_help_show (osso_context, help_id, HILDON_HELP_SHOW_DIALOG);
1391
1392         if (result != OSSO_OK) {
1393                 gchar *error_msg;
1394                 error_msg = g_strdup_printf ("FIXME The help topic %s could not be found", help_id); 
1395                 hildon_banner_show_information (GTK_WIDGET (parent_window),
1396                                                 NULL,
1397                                                 error_msg);
1398                 g_free (error_msg);
1399         }
1400 }
1401
1402 void
1403 modest_platform_set_dialog_help (GtkDialog *parent_window, 
1404                                  const gchar *help_id)
1405 {
1406         gboolean result;
1407         g_return_if_fail (help_id);
1408         g_return_if_fail (osso_context);
1409         g_return_if_fail (GTK_IS_DIALOG (parent_window));
1410
1411         result = hildon_help_dialog_help_enable (parent_window, help_id, osso_context);
1412
1413         if (!result)
1414                 g_warning ("Help topic %s not found", help_id);
1415
1416 }
1417
1418 void 
1419 modest_platform_show_search_messages (GtkWindow *parent_window)
1420 {
1421         osso_return_t result = OSSO_ERROR;
1422         
1423         result = osso_rpc_run_with_defaults (osso_context, "osso_global_search", "search_email", NULL, DBUS_TYPE_INVALID);
1424
1425         if (result != OSSO_OK) {
1426                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1427         }
1428 }
1429
1430 void 
1431 modest_platform_show_addressbook (GtkWindow *parent_window)
1432 {
1433         osso_return_t result = OSSO_ERROR;
1434         
1435         result = osso_rpc_run_with_defaults (osso_context, "osso_addressbook", "top_application", NULL, DBUS_TYPE_INVALID);
1436
1437         if (result != OSSO_OK) {
1438                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1439         }
1440 }
1441
1442 GtkWidget *
1443 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1444 {
1445         GtkWidget *widget = modest_folder_view_new (query);
1446
1447         /* Show one account by default */
1448         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1449                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1450
1451
1452         /* Restore settings */
1453         modest_widget_memory_restore (modest_runtime_get_conf(), 
1454                                       G_OBJECT (widget),
1455                                       MODEST_CONF_FOLDER_VIEW_KEY);
1456
1457         return widget;
1458 }
1459
1460 void 
1461 modest_platform_information_banner (GtkWidget *parent,
1462                                     const gchar *icon_name,
1463                                     const gchar *text)
1464 {
1465         hildon_banner_show_information (parent, icon_name, text);
1466 }
1467
1468 GtkWidget *
1469 modest_platform_animation_banner (GtkWidget *parent,
1470                                   const gchar *animation_name,
1471                                   const gchar *text)
1472 {
1473         GtkWidget *inf_note = NULL;
1474
1475         g_return_val_if_fail (text != NULL, NULL);
1476
1477         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1478
1479         return inf_note;
1480 }
1481
1482 typedef struct
1483 {
1484         GMainLoop* loop;
1485         TnyAccount *account;
1486         gboolean is_online;
1487         gint count_tries;
1488 } CheckAccountIdleData;
1489
1490 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1491
1492 static gboolean 
1493 on_timeout_check_account_is_online(gpointer user_data)
1494 {
1495         printf ("DEBUG: %s:\n", __FUNCTION__);
1496         CheckAccountIdleData *data = (CheckAccountIdleData*)user_data;
1497         
1498         if (!data) {
1499                 g_warning ("%s: data is NULL.\n", __FUNCTION__);
1500         }
1501         
1502         if (!(data->account)) {
1503                 g_warning ("%s: data->account is NULL.\n", __FUNCTION__);
1504         }
1505         
1506         if (data && data->account) {
1507                 printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__, tny_account_get_connection_status (data->account));       
1508         }
1509         
1510         gboolean stop_trying = FALSE;
1511         if (data && data->account && 
1512                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1513                  * after which the account is likely to be usable, or never likely to be usable soon: */
1514                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1515         {
1516                 data->is_online = TRUE;
1517                 
1518                 stop_trying = TRUE;
1519         }
1520         else {
1521                 /* Give up if we have tried too many times: */
1522                 if (data->count_tries >= NUMBER_OF_TRIES)
1523                 {
1524                         stop_trying = TRUE;
1525                 }
1526                 else {
1527                         /* Wait for another timeout: */
1528                         ++(data->count_tries);
1529                 }
1530         }
1531         
1532         if (stop_trying) {
1533                 /* Allow the function that requested this idle callback to continue: */
1534                 if (data->loop)
1535                         g_main_loop_quit (data->loop);
1536                         
1537                 if (data->account)
1538                         g_object_unref (data->account);
1539                 
1540                 return FALSE; /* Don't call this again. */
1541         } else {
1542                 return TRUE; /* Call this timeout callback again. */
1543         }
1544 }
1545
1546 /* Return TRUE immediately if the account is already online,
1547  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1548  * soon as the account is online, or FALSE if the account does 
1549  * not become online in the NUMBER_OF_TRIES seconds.
1550  * This is useful when the D-Bus method was run immediately after 
1551  * the application was started (when using D-Bus activation), 
1552  * because the account usually takes a short time to go online.
1553  * The return value is maybe not very useful.
1554  */
1555 gboolean
1556 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1557 {
1558         g_return_val_if_fail (account, FALSE);
1559         
1560         printf ("DEBUG: %s: account id=%s\n", __FUNCTION__, tny_account_get_id (account));
1561         
1562         if (!tny_device_is_online (modest_runtime_get_device())) {
1563                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1564                 return FALSE;
1565         }
1566         
1567         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1568          * so we avoid wait unnecessarily: */
1569         if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) && 
1570                 !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account) ) {
1571                 return TRUE;            
1572         }
1573                 
1574         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n",
1575                 __FUNCTION__, tny_account_get_connection_status (account));
1576         
1577         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1578          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1579          * we want to avoid. */
1580         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1581                 return TRUE;
1582                 
1583         /* This blocks on the result: */
1584         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1585         data->is_online = FALSE;
1586         data->account = account;
1587         g_object_ref (data->account);
1588         data->count_tries = 0;
1589                 
1590         GMainContext *context = NULL; /* g_main_context_new (); */
1591         data->loop = g_main_loop_new (context, FALSE /* not running */);
1592
1593         g_timeout_add (1000, on_timeout_check_account_is_online, data);
1594
1595         /* This main loop will run until the idle handler has stopped it: */
1596         g_main_loop_run (data->loop);
1597
1598         g_main_loop_unref (data->loop);
1599         /* g_main_context_unref (context); */
1600
1601         g_slice_free (CheckAccountIdleData, data);
1602         
1603         return data->is_online; 
1604 }
1605
1606
1607
1608 static void
1609 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1610 {
1611         /* GTK_RESPONSE_HELP means we need to show the certificate */
1612         if (response_id == GTK_RESPONSE_HELP) {
1613                 GtkWidget *note;
1614                 gchar *msg;
1615                 
1616                 /* Do not close the dialog */
1617                 g_signal_stop_emission_by_name (dialog, "response");
1618
1619                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1620                 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1621                 gtk_dialog_run (GTK_DIALOG(note));
1622                 gtk_widget_destroy (note);
1623         }
1624 }
1625
1626
1627 gboolean
1628 modest_platform_run_certificate_conformation_dialog (const gchar* server_name,
1629                                                      const gchar *certificate)
1630 {
1631         GtkWidget *note;
1632         gint response;
1633         GtkWindow *main_win =
1634                 (GtkWindow*)modest_window_mgr_get_main_window (modest_runtime_get_window_mgr());
1635
1636         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1637                                            server_name);
1638         
1639         note = hildon_note_new_confirmation_add_buttons  (
1640                 main_win,
1641                 question,
1642                 _("mcen_bd_dialog_ok"),     GTK_RESPONSE_OK,
1643                 _("mcen_bd_view"),          GTK_RESPONSE_HELP,   /* abusing this... */
1644                 _("mcen_bd_dialog_cancel"), GTK_RESPONSE_CANCEL,
1645                 NULL, NULL);
1646         
1647         g_signal_connect (G_OBJECT(note), "response", 
1648                           G_CALLBACK(on_cert_dialog_response),
1649                           (gpointer) certificate);
1650         
1651         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1652                                      GTK_WINDOW (note));
1653         response = gtk_dialog_run(GTK_DIALOG(note));
1654
1655         on_destroy_dialog (GTK_DIALOG(note));
1656         g_free (question);
1657         
1658         return response;
1659 }
1660         
1661
1662
1663 gboolean
1664 modest_platform_run_alert_dialog (const gchar* prompt, 
1665                                   gboolean is_question)
1666 {       
1667         ModestWindow *main_window = 
1668                 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
1669         
1670         gboolean retval = TRUE;
1671         if (is_question) {
1672                 /* The Tinymail documentation says that we should show Yes and No buttons, 
1673                  * when it is a question.
1674                  * Obviously, we need tinymail to use more specific error codes instead,
1675                  * so we know what buttons to show. */
1676                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (main_window), 
1677                                                                               prompt));
1678                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1679                                              GTK_WINDOW (dialog));
1680                 
1681                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1682                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1683                 
1684                 on_destroy_dialog (GTK_DIALOG(dialog));         
1685         } else {
1686                 /* Just show the error text and use the default response: */
1687                 modest_platform_run_information_dialog (GTK_WINDOW (main_window), 
1688                                                         prompt);
1689         }
1690         return retval;
1691 }