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