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