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