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