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