* Added a new function to get the folder window
[modest] / src / hildon2 / modest-platform.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <modest-runtime.h>
34 #include <modest-main-window.h>
35 #include <modest-header-view.h>
36 #include "modest-hildon2-global-settings-dialog.h"
37 #include "modest-widget-memory.h"
38 #include <modest-hildon-includes.h>
39 #include <modest-maemo-utils.h>
40 #include <dbus_api/modest-dbus-callbacks.h>
41 #include <modest-osso-autosave-callbacks.h>
42 #include <libosso.h>
43 #include <tny-maemo-conic-device.h>
44 #include <tny-simple-list.h>
45 #include <tny-folder.h>
46 #include <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_show (folder_view);
707         gtk_widget_show (pannable);
708         gtk_widget_show_all (userdata.dialog);
709         gtk_widget_set_size_request (pannable, -1, 320);
710         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
711                           G_CALLBACK (folder_chooser_activated), 
712                           (gpointer) &userdata);
713
714         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
715         gtk_widget_destroy (userdata.dialog);
716
717         return userdata.store;
718 }
719
720 static gchar *
721 folder_store_get_display_name (TnyFolderStore *store)
722 {
723         if (TNY_IS_ACCOUNT (store)) {
724                 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
725         } else {
726                 gchar *fname;
727                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
728
729                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
730                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
731                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
732                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
733                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
734                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
735                                 g_free (fname);
736                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
737                         }
738                 } else {
739                         /* Sometimes an special folder is reported by the server as
740                            NORMAL, like some versions of Dovecot */
741                         if (type == TNY_FOLDER_TYPE_NORMAL ||
742                             type == TNY_FOLDER_TYPE_UNKNOWN) {
743                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
744                         }
745                 }
746
747                 if (type == TNY_FOLDER_TYPE_INBOX) {
748                         g_free (fname);
749                         fname = g_strdup (_("mcen_me_folder_inbox"));
750                 }
751                 return fname;
752         }
753 }
754
755 static void
756 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
757 {
758         gchar *name;
759
760         if (store == NULL) {
761                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
762         } else {
763                 g_object_ref (store);
764                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, 
765                                         store, (GDestroyNotify) g_object_unref);
766                 name = folder_store_get_display_name (store);
767                 hildon_button_set_value (HILDON_BUTTON (button), name);
768                 g_free (name);
769         }
770 }
771
772 static void
773 folder_picker_clicked (GtkButton *button,
774                        ModestFolderView *folder_view)
775 {
776         TnyFolderStore *store;
777
778         store = folder_chooser_dialog_run (folder_view);
779         if (store) {
780                 folder_picker_set_store (GTK_BUTTON (button), store);
781         }
782 }
783
784 static GtkWidget *
785 folder_picker_new (ModestFolderView *folder_view, TnyFolderStore *suggested)
786 {
787         GtkWidget *button;
788         GdkPixbuf *pixbuf;
789
790         button = hildon_button_new (MODEST_EDITABLE_SIZE,
791                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
792         pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL,
793                                            MODEST_ICON_SIZE_SMALL);
794
795         hildon_button_set_image (HILDON_BUTTON (button), 
796                                  gtk_image_new_from_pixbuf (pixbuf));
797         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
798
799         if (suggested) {
800                 folder_picker_set_store (GTK_BUTTON (button), suggested);
801         }
802
803         g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (folder_picker_clicked), folder_view);
804
805         return button;
806 }
807
808
809 static gint
810 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
811                                           TnyFolderStore *suggested_parent,
812                                           const gchar *dialog_title,
813                                           const gchar *label_text,
814                                           const gchar *suggested_name,
815                                           gboolean show_name,
816                                           gboolean show_parent,
817                                           gchar **folder_name,
818                                           TnyFolderStore **parent)
819 {
820         GtkWidget *accept_btn = NULL; 
821         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
822         GtkWidget *account_picker = NULL;
823         GList *buttons = NULL;
824         gint result;
825         GtkSizeGroup *sizegroup;
826         ModestFolderView *folder_view;
827         ModestWindow *folder_window;
828         ModestHildon2WindowMgr *window_mgr;
829
830         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
831         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
832         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
833
834         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
835
836         /* Ask the user for the folder name */
837         dialog = gtk_dialog_new_with_buttons (dialog_title,
838                                               parent_window,
839                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
840                                               _FM("ckdg_bd_new_folder_dialog_ok"),
841                                               GTK_RESPONSE_ACCEPT,
842                                               NULL);
843
844         /* Add accept button (with unsensitive handler) */
845         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
846         accept_btn = GTK_WIDGET (buttons->data);
847
848         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
849
850         if (show_name) {
851                 label_entry = gtk_label_new (label_text);
852                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
853                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
854
855                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
856                 gtk_size_group_add_widget (sizegroup, label_entry);
857
858                 if (suggested_name)
859                         gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
860                 else
861                         gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
862                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
863                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
864                                                 g_utf8_strlen (_("mcen_ia_default_folder_name"), -1)));
865                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
866         }
867
868         if (show_parent) {
869
870                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
871
872                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
873                 gtk_size_group_add_widget (sizegroup, label_location);
874
875                 account_picker = folder_picker_new (folder_view, suggested_parent);
876         }
877
878         g_object_unref (sizegroup);
879
880         /* Connect to the response method to avoid closing the dialog
881            when an invalid name is selected*/
882         g_signal_connect (dialog,
883                           "response",
884                           G_CALLBACK (on_response),
885                           suggested_parent);
886
887         if (show_name) {
888                 /* Track entry changes */
889                 g_signal_connect (entry,
890                                   "insert-text",
891                                   G_CALLBACK (entry_insert_text),
892                                   dialog);
893                 g_signal_connect (entry,
894                                   "changed",
895                                   G_CALLBACK (entry_changed),
896                                   dialog);
897         }
898
899
900         /* Some locales like pt_BR need this to get the full window
901            title shown */
902         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
903
904         /* Create the hbox */
905         if (show_name) {
906                 hbox = gtk_hbox_new (FALSE, 12);
907                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
908                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
909
910                 /* Add hbox to dialog */
911                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
912                                     hbox, FALSE, FALSE, 0);
913                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
914         }
915
916         if (show_parent) {
917                 hbox = gtk_hbox_new (FALSE, 12);
918                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
919                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
920
921                 /* Add hbox to dialog */
922                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
923                                     hbox, FALSE, FALSE, 0);
924                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
925         }
926         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
927                                      GTK_WINDOW (dialog), parent_window);
928         gtk_widget_show_all (GTK_WIDGET(dialog));
929
930         result = gtk_dialog_run (GTK_DIALOG(dialog));
931         if (result == GTK_RESPONSE_ACCEPT) {
932                 if (show_name)
933                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
934                 if (show_parent) {
935                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
936                         if (*parent)
937                                 g_object_ref (*parent);
938                 }
939         }
940
941         gtk_widget_destroy (dialog);
942
943         while (gtk_events_pending ())
944                 gtk_main_iteration ();
945
946         return result;
947 }
948
949 gint
950 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
951                                        TnyFolderStore *suggested_folder,
952                                        gchar *suggested_name,
953                                        gchar **folder_name,
954                                        TnyFolderStore **parent_folder)
955 {
956         gchar *real_suggested_name = NULL, *tmp = NULL;
957         gint result;
958
959         if(suggested_name == NULL)
960         {
961                 const gchar *default_name = _("mcen_ia_default_folder_name");
962                 unsigned int i;
963                 gchar num_str[3];
964
965                 for(i = 0; i < 100; ++ i) {
966                         gboolean exists = FALSE;
967
968                         sprintf(num_str, "%.2u", i);
969
970                         if (i == 0)
971                                 real_suggested_name = g_strdup (default_name);
972                         else
973                                 real_suggested_name = g_strdup_printf (_("mcen_ia_default_folder_name_s"),
974                                                                        num_str);
975                         exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
976                                                                             real_suggested_name,
977                                                                             TRUE);
978
979                         if (!exists)
980                                 break;
981
982                         g_free (real_suggested_name);
983                 }
984
985                 /* Didn't find a free number */
986                 if (i == 100)
987                         real_suggested_name = g_strdup (default_name);
988         } else {
989                 real_suggested_name = suggested_name;
990         }
991
992         /* In hildon 2.2 we always suggest the archive folder as parent */
993         suggested_folder = TNY_FOLDER_STORE (
994                 modest_tny_account_get_special_folder 
995                 (modest_tny_account_store_get_local_folders_account (modest_runtime_get_account_store ()),
996                  TNY_FOLDER_TYPE_ARCHIVE));
997
998         tmp = g_strconcat (_("mcen_fi_new_folder_name"), ":", NULL);
999         result = modest_platform_run_folder_common_dialog (parent_window, 
1000                                                            suggested_folder,
1001                                                            _("mcen_ti_new_folder"),
1002                                                            tmp,
1003                                                            real_suggested_name,
1004                                                            TRUE,
1005                                                            TRUE,
1006                                                            folder_name,
1007                                                            parent_folder);
1008         g_free (tmp);
1009
1010         if (suggested_name == NULL)
1011                 g_free(real_suggested_name);
1012
1013         return result;
1014 }
1015
1016 gint
1017 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1018                                           TnyFolderStore *parent_folder,
1019                                           const gchar *suggested_name,
1020                                           gchar **folder_name)
1021 {
1022         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1023
1024         return modest_platform_run_folder_common_dialog (parent_window, 
1025                                                          parent_folder,
1026                                                          _HL("ckdg_ti_rename_folder"),
1027                                                          _HL("ckdg_fi_rename_name"),
1028                                                          suggested_name,
1029                                                          TRUE,
1030                                                          FALSE,
1031                                                          folder_name,
1032                                                          NULL);
1033 }
1034
1035
1036
1037 static void
1038 on_destroy_dialog (GtkWidget *dialog)
1039 {
1040         /* This could happen when the dialogs get programatically
1041            hidden or destroyed (for example when closing the
1042            application while a dialog is being shown) */
1043         if (!GTK_IS_WIDGET (dialog))
1044                 return;
1045
1046         gtk_widget_destroy (dialog);
1047
1048         if (gtk_events_pending ())
1049                 gtk_main_iteration ();
1050 }
1051
1052 gint
1053 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1054                                          const gchar *message)
1055 {
1056         GtkWidget *dialog;
1057         gint response;
1058         
1059         dialog = hildon_note_new_confirmation (parent_window, message);
1060         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1061                                      GTK_WINDOW (dialog), parent_window);
1062
1063         response = gtk_dialog_run (GTK_DIALOG (dialog));
1064
1065         on_destroy_dialog (dialog);
1066
1067         return response;
1068 }
1069
1070 gint
1071 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1072                                                       const gchar *message,
1073                                                       const gchar *button_accept,
1074                                                       const gchar *button_cancel)
1075 {
1076         GtkWidget *dialog;
1077         gint response;
1078         
1079         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1080                                                            button_accept, GTK_RESPONSE_ACCEPT,
1081                                                            button_cancel, GTK_RESPONSE_CANCEL,
1082                                                            NULL);
1083
1084         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1085                                      GTK_WINDOW (dialog), parent_window);
1086
1087         response = gtk_dialog_run (GTK_DIALOG (dialog));
1088
1089         on_destroy_dialog (dialog);
1090
1091         return response;
1092 }
1093         
1094 void
1095 modest_platform_run_information_dialog (GtkWindow *parent_window,
1096                                         const gchar *message,
1097                                         gboolean block)
1098 {
1099         GtkWidget *note;
1100         
1101         note = hildon_note_new_information (parent_window, message);
1102         if (block)
1103                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1104                                              GTK_WINDOW (note), parent_window);
1105         
1106         if (block) {
1107                 gtk_dialog_run (GTK_DIALOG (note));
1108         
1109                 on_destroy_dialog (note);
1110         } else {
1111                 g_signal_connect_swapped (note,
1112                                           "response", 
1113                                           G_CALLBACK (on_destroy_dialog),
1114                                           note);
1115
1116                 gtk_widget_show_all (note);
1117         }
1118 }
1119
1120 typedef struct _ConnectAndWaitData {
1121         GMutex *mutex;
1122         GMainLoop *wait_loop;
1123         gboolean has_callback;
1124         gulong handler;
1125 } ConnectAndWaitData;
1126
1127
1128 static void
1129 quit_wait_loop (TnyAccount *account,
1130                 ConnectAndWaitData *data) 
1131 {
1132         /* Set the has_callback to TRUE (means that the callback was
1133            executed and wake up every code waiting for cond to be
1134            TRUE */
1135         g_mutex_lock (data->mutex);
1136         data->has_callback = TRUE;
1137         if (data->wait_loop)
1138                 g_main_loop_quit (data->wait_loop);
1139         g_mutex_unlock (data->mutex);
1140 }
1141
1142 static void
1143 on_connection_status_changed (TnyAccount *account, 
1144                               TnyConnectionStatus status,
1145                               gpointer user_data)
1146 {
1147         TnyConnectionStatus conn_status;
1148         ConnectAndWaitData *data;
1149                         
1150         /* Ignore if reconnecting or disconnected */
1151         conn_status = tny_account_get_connection_status (account);
1152         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1153             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1154                 return;
1155
1156         /* Remove the handler */
1157         data = (ConnectAndWaitData *) user_data;
1158         g_signal_handler_disconnect (account, data->handler);
1159
1160         /* Quit from wait loop */
1161         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1162 }
1163
1164 static void
1165 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1166                                     gboolean canceled, 
1167                                     GError *err, 
1168                                     gpointer user_data)
1169 {
1170         /* Quit from wait loop */
1171         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1172 }
1173
1174 gboolean 
1175 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1176                                   TnyAccount *account)
1177 {
1178         ConnectAndWaitData *data = NULL;
1179         gboolean device_online;
1180         TnyDevice *device;
1181         TnyConnectionStatus conn_status;
1182         gboolean user_requested;
1183         
1184         device = modest_runtime_get_device();
1185         device_online = tny_device_is_online (device);
1186
1187         /* Whether the connection is user requested or automatically
1188            requested, for example via D-Bus */
1189         user_requested = (parent_window) ? TRUE : FALSE;
1190
1191         /* If there is no account check only the device status */
1192         if (!account) {
1193                 if (device_online)
1194                         return TRUE;
1195                 else
1196                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1197                                                                NULL, user_requested);
1198         }
1199
1200         /* Return if the account is already connected */
1201         conn_status = tny_account_get_connection_status (account);
1202         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1203                 return TRUE;
1204
1205         /* Create the helper */
1206         data = g_slice_new0 (ConnectAndWaitData);
1207         data->mutex = g_mutex_new ();
1208         data->has_callback = FALSE;
1209
1210         /* Connect the device */
1211         if (!device_online) {
1212                 /* Track account connection status changes */
1213                 data->handler = g_signal_connect (account, "connection-status-changed",
1214                                                   G_CALLBACK (on_connection_status_changed),
1215                                                   data);
1216                 /* Try to connect the device */
1217                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1218                                                                 NULL, user_requested);
1219
1220                 /* If the device connection failed then exit */
1221                 if (!device_online && data->handler)
1222                         goto frees;
1223         } else {
1224                 /* Force a reconnection of the account */
1225                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1226                                               on_tny_camel_account_set_online_cb, data);
1227         }
1228
1229         /* Wait until the callback is executed */
1230         g_mutex_lock (data->mutex);
1231         if (!data->has_callback) {
1232                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1233                 gdk_threads_leave ();
1234                 g_mutex_unlock (data->mutex);
1235                 g_main_loop_run (data->wait_loop);
1236                 g_mutex_lock (data->mutex);
1237                 gdk_threads_enter ();
1238         }
1239         g_mutex_unlock (data->mutex);
1240
1241  frees:
1242         if (data) {
1243                 if (g_signal_handler_is_connected (account, data->handler))
1244                         g_signal_handler_disconnect (account, data->handler);
1245                 g_mutex_free (data->mutex);
1246                 g_main_loop_unref (data->wait_loop);
1247                 g_slice_free (ConnectAndWaitData, data);
1248         }
1249
1250         conn_status = tny_account_get_connection_status (account);
1251         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1252 }
1253
1254 gboolean 
1255 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1256 {
1257         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1258                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1259                         /* This must be a maildir account, which does not require a connection: */
1260                         return TRUE;
1261                 }
1262         }
1263
1264         return modest_platform_connect_and_wait (parent_window, account);
1265 }
1266
1267 gboolean 
1268 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1269 {
1270         if (!folder_store)
1271                 return TRUE; /* Maybe it is something local. */
1272                 
1273         gboolean result = TRUE;
1274         if (TNY_IS_FOLDER (folder_store)) {
1275                 /* Get the folder's parent account: */
1276                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1277                 if (account != NULL) {
1278                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1279                         g_object_unref (account);
1280                 }
1281         } else if (TNY_IS_ACCOUNT (folder_store)) {
1282                 /* Use the folder store as an account: */
1283                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1284         }
1285
1286         return result;
1287 }
1288
1289 GtkWidget *
1290 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1291 {
1292         GtkWidget *dialog;
1293
1294         dialog = modest_hildon2_sort_dialog_new (parent_window);
1295
1296         return dialog;
1297 }
1298
1299
1300 gboolean 
1301 modest_platform_set_update_interval (guint minutes)
1302 {
1303 #ifdef MODEST_HAVE_LIBALARM
1304         
1305         ModestConf *conf = modest_runtime_get_conf ();
1306         if (!conf)
1307                 return FALSE;
1308                 
1309         cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL);
1310
1311         /* Delete any existing alarm,
1312          * because we will replace it: */
1313         if (alarm_cookie) {
1314                 if (alarmd_event_del(alarm_cookie) != 1)
1315                         g_warning ("%s: alarm %d was not on the queue", __FUNCTION__, (int)alarm_cookie);
1316                 alarm_cookie = 0;
1317                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1318         }
1319         
1320         /* 0 means no updates: */
1321         if (minutes == 0)
1322                 return TRUE;
1323         
1324      
1325         /* Register alarm: */
1326         
1327         /* Set the interval in alarm_event_t structure: */
1328         alarm_event_t *event = alarm_event_create ();
1329         alarm_event_add_actions (event, 1);
1330         alarm_action_t *action = alarm_event_get_action (event, 0);
1331         event->alarm_time = minutes * 60; /* seconds */
1332         
1333         /* Set recurrence every few minutes: */
1334         event->recur_secs = minutes*60;
1335         event->recur_count = -1; /* Means infinite */
1336
1337         /* Specify what should happen when the alarm happens:
1338          * It should call this D-Bus method: */
1339          
1340         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1341         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1342         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1343         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1344         action->flags = ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1345
1346         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1347          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1348          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1349          * This is why we want to use the Alarm API instead of just g_timeout_add().
1350          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1351          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1352          */
1353         event->flags = ALARM_EVENT_CONNECTED;
1354         
1355         alarm_cookie = alarmd_event_add (event);
1356
1357         /* now, free it */
1358         alarm_event_delete (event);
1359         
1360         /* Store the alarm ID in GConf, so we can remove it later:
1361          * This is apparently valid between application instances. */
1362         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1363         
1364         if (!alarm_cookie) {
1365             /* Error */
1366             g_debug ("Error setting alarm event. \n");
1367             
1368             return FALSE;
1369         }
1370 #endif /* MODEST_HAVE_LIBALARM */       
1371         return TRUE;
1372 }
1373
1374 void
1375 modest_platform_push_email_notification(void)
1376 {
1377         gboolean screen_on = TRUE, app_in_foreground;
1378
1379         /* Get the window status */
1380         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1381
1382         /* If the screen is on and the app is in the
1383            foreground we don't show anything */
1384         if (!(screen_on && app_in_foreground)) {
1385
1386                 _modest_platform_play_email_tone ();
1387
1388                 /* Activate LED. This must be deactivated by
1389                    modest_platform_remove_new_mail_notifications */
1390 #ifdef MODEST_HAVE_MCE
1391                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1392                                      MCE_SERVICE,
1393                                      MCE_REQUEST_PATH,
1394                                      MCE_REQUEST_IF,
1395                                      MCE_ACTIVATE_LED_PATTERN,
1396                                      NULL,
1397                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1398                                      DBUS_TYPE_INVALID);
1399 #endif
1400         }
1401 }
1402
1403 void 
1404 modest_platform_on_new_headers_received (TnyList *header_list,
1405                                          gboolean show_visual)
1406 {
1407         g_return_if_fail (TNY_IS_LIST(header_list));
1408
1409         if (tny_list_get_length(header_list) == 0) {
1410                 g_warning ("%s: header list is empty", __FUNCTION__);
1411                 return;
1412         }
1413         
1414         if (!show_visual) {
1415                 modest_platform_push_email_notification ();
1416                 /* We do a return here to avoid indentation with an else */
1417                 return;
1418         }
1419
1420 #ifdef MODEST_HAVE_HILDON_NOTIFY
1421         HildonNotification *notification;
1422         TnyIterator *iter;
1423         GSList *notifications_list = NULL;
1424
1425         /* Get previous notifications ids */
1426         notifications_list = modest_conf_get_list (modest_runtime_get_conf (), 
1427                                                    MODEST_CONF_NOTIFICATION_IDS, 
1428                                                    MODEST_CONF_VALUE_INT, NULL);
1429
1430         iter = tny_list_create_iterator (header_list);
1431         while (!tny_iterator_is_done (iter)) {
1432                 gchar *url = NULL, *display_address = NULL,  *summary = NULL;
1433                 const gchar *display_date;
1434                 TnyHeader *header = TNY_HEADER (tny_iterator_get_current (iter));
1435                 TnyFolder *folder = tny_header_get_folder (header);
1436                 gboolean first_notification = TRUE;
1437                 gint notif_id;
1438                 gchar *str;
1439                 ModestDatetimeFormatter *datetime_formatter;
1440
1441                 /* constant string, don't free */
1442                 datetime_formatter = modest_datetime_formatter_new ();
1443                 display_date = modest_datetime_formatter_display_datetime (datetime_formatter,
1444                                                                            tny_header_get_date_received (header));
1445                 g_object_unref (datetime_formatter);
1446
1447                 display_address = tny_header_dup_from (header);
1448                 /* string is changed in-place */
1449                 modest_text_utils_get_display_address (display_address);
1450
1451                 summary = g_strdup_printf ("%s - %s", display_date, display_address);
1452                 str = tny_header_dup_subject (header);
1453                 notification = hildon_notification_new (summary,
1454                                                         str,
1455                                                         "qgn_list_messagin",
1456                                                         "email-message");
1457                 g_free (str);
1458                 /* Create the message URL */
1459                 str = tny_header_dup_uid (header);
1460                 url = g_strdup_printf ("%s/%s", tny_folder_get_url_string (folder), 
1461                                        str);
1462                 g_free (str);
1463
1464                 hildon_notification_add_dbus_action(notification,
1465                                                     "default",
1466                                                     "Cancel",
1467                                                     MODEST_DBUS_SERVICE,
1468                                                     MODEST_DBUS_OBJECT,
1469                                                     MODEST_DBUS_IFACE,
1470                                                     MODEST_DBUS_METHOD_OPEN_MESSAGE,
1471                                                     G_TYPE_STRING, url,
1472                                                     -1);
1473
1474                 /* Play sound if the user wants. Show the LED
1475                    pattern. Show and play just one */
1476                 if (G_UNLIKELY (first_notification)) {
1477                         gchar *active_profile;
1478                         gchar *mail_tone;
1479                         gchar *mail_volume;
1480                         gint mail_volume_int;
1481
1482                         first_notification = FALSE;
1483
1484                         active_profile = profile_get_profile ();
1485                         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
1486                         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
1487                         mail_volume_int = profile_parse_int (mail_volume);
1488
1489                         if (mail_volume_int > 0)
1490                                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1491                                                                     "sound-file", mail_tone);
1492
1493                         g_free (mail_volume);
1494                         g_free (mail_tone);
1495                         g_free (active_profile);
1496
1497                         /* Set the led pattern */
1498                         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1499                                                             "dialog-type", 4);
1500                         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1501                                                             "led-pattern",
1502                                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);                  
1503                 }
1504
1505                 /* Notify. We need to do this in an idle because this function
1506                    could be called from a thread */
1507                 notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL);
1508
1509                 /* Save id in the list */
1510                 g_object_get(G_OBJECT(notification), "id", &notif_id, NULL);
1511                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1512                 /* We don't listen for the "closed" signal, because we
1513                    don't care about if the notification was removed or
1514                    not to store the list in gconf */
1515         
1516                 /* Free & carry on */
1517                 g_free (display_address);
1518                 g_free (summary);
1519                 g_free (url);
1520                 g_object_unref (folder);
1521                 g_object_unref (header);
1522                 tny_iterator_next (iter);
1523         }
1524         g_object_unref (iter);
1525
1526         /* Save the ids */
1527         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1528                               notifications_list, MODEST_CONF_VALUE_INT, NULL);
1529
1530         g_slist_free (notifications_list);
1531         
1532 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1533 }
1534
1535 void
1536 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1537 {
1538         if (only_visuals) {
1539 #ifdef MODEST_HAVE_MCE
1540                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1541                                      MCE_SERVICE,
1542                                      MCE_REQUEST_PATH,
1543                                      MCE_REQUEST_IF,
1544                                      MCE_DEACTIVATE_LED_PATTERN,
1545                                      NULL,
1546                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1547                                      DBUS_TYPE_INVALID);
1548 #endif
1549                 return;
1550         }
1551
1552 #ifdef MODEST_HAVE_HILDON_NOTIFY
1553         GSList *notif_list = NULL;
1554
1555         /* Get previous notifications ids */
1556         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1557                                            MODEST_CONF_NOTIFICATION_IDS, 
1558                                            MODEST_CONF_VALUE_INT, NULL);
1559
1560         while (notif_list) {
1561                 gint notif_id;
1562                 NotifyNotification *notif;
1563
1564                 /* Nasty HACK to remove the notifications, set the id
1565                    of the existing ones and then close them */
1566                 notif_id = GPOINTER_TO_INT(notif_list->data);
1567                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1568                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1569
1570                 /* Close the notification, note that some ids could be
1571                    already invalid, but we don't care because it does
1572                    not fail */
1573                 notify_notification_close(notif, NULL);
1574                 g_object_unref(notif);
1575
1576                 /* Delete the link, it's like going to the next */
1577                 notif_list = g_slist_delete_link (notif_list, notif_list);
1578         }
1579
1580         /* Save the ids */
1581         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1582                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1583
1584         g_slist_free (notif_list);
1585
1586 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1587 }
1588
1589
1590
1591 GtkWidget * 
1592 modest_platform_get_global_settings_dialog ()
1593 {
1594         return modest_hildon2_global_settings_dialog_new ();
1595 }
1596
1597 void
1598 modest_platform_show_help (GtkWindow *parent_window, 
1599                            const gchar *help_id)
1600 {
1601         return;
1602 }
1603
1604 void 
1605 modest_platform_show_search_messages (GtkWindow *parent_window)
1606 {
1607         osso_return_t result = OSSO_ERROR;
1608         
1609         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1610                                              "osso_global_search",
1611                                              "search_email", NULL, DBUS_TYPE_INVALID);
1612
1613         if (result != OSSO_OK) {
1614                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1615         }
1616 }
1617
1618 void 
1619 modest_platform_show_addressbook (GtkWindow *parent_window)
1620 {
1621         osso_return_t result = OSSO_ERROR;
1622
1623         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1624                                              "osso_addressbook",
1625                                              "top_application", NULL, DBUS_TYPE_INVALID);
1626
1627         if (result != OSSO_OK) {
1628                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1629         }
1630 }
1631
1632 GtkWidget *
1633 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1634 {
1635         GtkWidget *widget = modest_folder_view_new (query);
1636
1637         /* Show one account by default */
1638         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1639                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1640
1641         /* Restore settings */
1642         modest_widget_memory_restore (modest_runtime_get_conf(), 
1643                                       G_OBJECT (widget),
1644                                       MODEST_CONF_FOLDER_VIEW_KEY);
1645
1646         return widget;
1647 }
1648
1649 void
1650 banner_finish (gpointer data, GObject *object)
1651 {
1652         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1653         modest_window_mgr_unregister_banner (mgr);
1654         g_object_unref (mgr);
1655 }
1656
1657 void 
1658 modest_platform_information_banner (GtkWidget *parent,
1659                                     const gchar *icon_name,
1660                                     const gchar *text)
1661 {
1662         GtkWidget *banner, *banner_parent = NULL;
1663         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1664
1665         if (modest_window_mgr_get_num_windows (mgr) == 0)
1666                 return;
1667
1668         if (parent && GTK_IS_WINDOW (parent)) {
1669                 /* If the window is the active one then show the
1670                    banner on top of this window */
1671                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1672                         banner_parent = parent;
1673                 /* If the window is not the topmost but it's visible
1674                    (it's minimized for example) then show the banner
1675                    with no parent */ 
1676                 else if (GTK_WIDGET_VISIBLE (parent))
1677                         banner_parent = NULL;
1678                 /* If the window is hidden (like the main window when
1679                    running in the background) then do not show
1680                    anything */
1681                 else 
1682                         return;
1683         }
1684
1685
1686         banner = hildon_banner_show_information (banner_parent, icon_name, text);
1687
1688         modest_window_mgr_register_banner (mgr);
1689         g_object_ref (mgr);
1690         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1691 }
1692
1693 void
1694 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1695                                                  const gchar *icon_name,
1696                                                  const gchar *text,
1697                                                  gint timeout)
1698 {
1699         GtkWidget *banner;
1700
1701         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1702                 return;
1703
1704         banner = hildon_banner_show_information (parent, icon_name, text);
1705         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1706 }
1707
1708 GtkWidget *
1709 modest_platform_animation_banner (GtkWidget *parent,
1710                                   const gchar *animation_name,
1711                                   const gchar *text)
1712 {
1713         GtkWidget *inf_note = NULL;
1714
1715         g_return_val_if_fail (text != NULL, NULL);
1716
1717         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1718                 return NULL;
1719
1720         /* If the parent is not visible then do not show */
1721         if (parent && !GTK_WIDGET_VISIBLE (parent))
1722                 return NULL;
1723
1724         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1725
1726         return inf_note;
1727 }
1728
1729 typedef struct
1730 {
1731         GMainLoop* loop;
1732         TnyAccount *account;
1733         gboolean is_online;
1734         gint count_tries;
1735 } CheckAccountIdleData;
1736
1737 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1738
1739 static gboolean 
1740 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1741 {
1742         gboolean stop_trying = FALSE;
1743         g_return_val_if_fail (data && data->account, FALSE);
1744         
1745         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1746                 tny_account_get_connection_status (data->account));     
1747         
1748         if (data && data->account && 
1749                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1750                  * after which the account is likely to be usable, or never likely to be usable soon: */
1751                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1752         {
1753                 data->is_online = TRUE;
1754                 
1755                 stop_trying = TRUE;
1756         } else {
1757                 /* Give up if we have tried too many times: */
1758                 if (data->count_tries >= NUMBER_OF_TRIES) {
1759                         stop_trying = TRUE;
1760                 } else {
1761                         /* Wait for another timeout: */
1762                         ++(data->count_tries);
1763                 }
1764         }
1765         
1766         if (stop_trying) {
1767                 /* Allow the function that requested this idle callback to continue: */
1768                 if (data->loop)
1769                         g_main_loop_quit (data->loop);
1770                         
1771                 if (data->account)
1772                         g_object_unref (data->account);
1773                 
1774                 return FALSE; /* Don't call this again. */
1775         } else {
1776                 return TRUE; /* Call this timeout callback again. */
1777         }
1778 }
1779
1780 /* Return TRUE immediately if the account is already online,
1781  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1782  * soon as the account is online, or FALSE if the account does 
1783  * not become online in the NUMBER_OF_TRIES seconds.
1784  * This is useful when the D-Bus method was run immediately after 
1785  * the application was started (when using D-Bus activation), 
1786  * because the account usually takes a short time to go online.
1787  * The return value is maybe not very useful.
1788  */
1789 gboolean
1790 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1791 {
1792         gboolean is_online;
1793
1794         g_return_val_if_fail (account, FALSE);
1795
1796         if (!tny_device_is_online (modest_runtime_get_device())) {
1797                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1798                 return FALSE;
1799         }
1800
1801         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1802          * so we avoid wait unnecessarily: */
1803         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1804                 return TRUE;
1805
1806         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1807          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1808          * we want to avoid. */
1809         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1810                 return TRUE;
1811                 
1812         /* This blocks on the result: */
1813         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1814         data->is_online = FALSE;
1815         data->account = account;
1816         g_object_ref (data->account);
1817         data->count_tries = 0;
1818                 
1819         GMainContext *context = NULL; /* g_main_context_new (); */
1820         data->loop = g_main_loop_new (context, FALSE /* not running */);
1821
1822         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1823
1824         /* This main loop will run until the idle handler has stopped it: */
1825         g_main_loop_run (data->loop);
1826
1827         g_main_loop_unref (data->loop);
1828         /* g_main_context_unref (context); */
1829
1830         is_online = data->is_online;
1831         g_slice_free (CheckAccountIdleData, data);
1832         
1833         return is_online;       
1834 }
1835
1836
1837
1838 static void
1839 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1840 {
1841         /* GTK_RESPONSE_HELP means we need to show the certificate */
1842         if (response_id == GTK_RESPONSE_APPLY) {
1843                 GtkWidget *note;
1844                 gchar *msg;
1845                 
1846                 /* Do not close the dialog */
1847                 g_signal_stop_emission_by_name (dialog, "response");
1848
1849                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1850                 note = hildon_note_new_information (GTK_WINDOW(dialog), msg);
1851                 gtk_dialog_run (GTK_DIALOG(note));
1852                 gtk_widget_destroy (note);
1853         }
1854 }
1855
1856
1857 gboolean
1858 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1859                                                      const gchar *certificate)
1860 {
1861         GtkWidget *note;
1862         gint response;
1863         ModestWindow *win;
1864         HildonWindowStack *stack;
1865
1866         stack = hildon_window_stack_get_default ();
1867         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1868
1869         if (!win) {
1870           g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1871                            __FUNCTION__);
1872                 return FALSE;
1873         }
1874
1875         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1876                                            server_name);
1877         
1878         /* We use GTK_RESPONSE_APPLY because we want the button in the
1879            middle of OK and CANCEL the same as the browser does for
1880            example. With GTK_RESPONSE_HELP the view button is aligned
1881            to the left while the other two to the right */
1882         note = hildon_note_new_confirmation_add_buttons  (
1883                 NULL,
1884                 question,
1885                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
1886                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
1887                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1888                 NULL, NULL);
1889         
1890         g_signal_connect (G_OBJECT(note), "response", 
1891                           G_CALLBACK(on_cert_dialog_response),
1892                           (gpointer) certificate);
1893
1894         response = gtk_dialog_run(GTK_DIALOG(note));
1895
1896         on_destroy_dialog (note);
1897         g_free (question);
1898
1899         return response == GTK_RESPONSE_OK;
1900 }
1901
1902 gboolean
1903 modest_platform_run_alert_dialog (const gchar* prompt,
1904                                   gboolean is_question)
1905 {
1906         ModestWindow *top_win;
1907         HildonWindowStack *stack;
1908
1909         stack = hildon_window_stack_get_default ();
1910         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
1911
1912         if (!top_win) {
1913                 g_warning ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
1914                            __FUNCTION__);
1915                 return FALSE;
1916         }
1917
1918         gboolean retval = TRUE;
1919         if (is_question) {
1920                 /* The Tinymail documentation says that we should show Yes and No buttons,
1921                  * when it is a question.
1922                  * Obviously, we need tinymail to use more specific error codes instead,
1923                  * so we know what buttons to show. */
1924                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
1925                                                                               prompt));
1926                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1927                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
1928
1929                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1930                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1931
1932                 on_destroy_dialog (dialog);
1933         } else {
1934                 /* Just show the error text and use the default response: */
1935                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
1936                                                         prompt, FALSE);
1937         }
1938         return retval;
1939 }
1940
1941 /***************/
1942 typedef struct {
1943         GtkWindow *parent_window;
1944         ModestConnectedPerformer callback;
1945         TnyAccount *account;
1946         gpointer user_data;
1947         gchar *iap;
1948         TnyDevice *device;
1949 } OnWentOnlineInfo;
1950  
1951 static void 
1952 on_went_online_info_free (OnWentOnlineInfo *info)
1953 {
1954         /* And if we cleanup, we DO cleanup  :-)  */
1955         
1956         if (info->device)
1957                 g_object_unref (info->device);
1958         if (info->iap)
1959                 g_free (info->iap);
1960         if (info->parent_window)
1961                 g_object_unref (info->parent_window);
1962         if (info->account)
1963                 g_object_unref (info->account);
1964         
1965         g_slice_free (OnWentOnlineInfo, info);
1966         
1967         /* We're done ... */
1968         
1969         return;
1970 }
1971  
1972 static void
1973 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1974 {
1975         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1976  
1977         /* Now it's really time to callback to the caller. If going online didn't succeed,
1978          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1979          * canceled will be set. Etcetera etcetera. */
1980         
1981         if (info->callback) {
1982                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1983         }
1984         
1985         /* This is our last call, we must cleanup here if we didn't yet do that */
1986         on_went_online_info_free (info);
1987         
1988         return;
1989 }
1990  
1991  
1992 static void
1993 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
1994 {
1995         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1996         info->iap = g_strdup (iap_id);
1997         
1998         if (canceled || err || !info->account) {
1999         
2000                 /* If there's a problem or if there's no account (then that's it for us, we callback
2001                  * the caller's callback now. He'll have to handle err or canceled, of course.
2002                  * We are not really online, as the account is not really online here ... */    
2003                 
2004                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2005                  * this info. We don't cleanup err, Tinymail does that! */
2006                 
2007                 if (info->callback) {
2008                         
2009                         /* info->account can be NULL here, this means that the user did not
2010                          * provide a nice account instance. We'll assume that the user knows
2011                          * what he's doing and is happy with just the device going online. 
2012                          * 
2013                          * We can't do magic, we don't know what account the user wants to
2014                          * see going online. So just the device goes online, end of story */
2015                         
2016                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2017                 }
2018                 
2019         } else if (info->account) {
2020                 
2021                 /* If there's no problem and if we have an account, we'll put the account
2022                  * online too. When done, the callback of bringing the account online
2023                  * will callback the caller's callback. This is the most normal case. */
2024  
2025                 info->device = TNY_DEVICE (g_object_ref (device));
2026                 
2027                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2028                                               on_account_went_online, info);
2029                 
2030                 /* The on_account_went_online cb frees up the info, go look if you
2031                  * don't believe me! (so we return here) */
2032                 
2033                 return;
2034         }
2035         
2036         /* We cleanup if we are not bringing the account online too */
2037         on_went_online_info_free (info);
2038  
2039         return; 
2040 }
2041         
2042 void 
2043 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2044                                      gboolean force,
2045                                      TnyAccount *account, 
2046                                      ModestConnectedPerformer callback, 
2047                                      gpointer user_data)
2048 {
2049         gboolean device_online;
2050         TnyDevice *device;
2051         TnyConnectionStatus conn_status;
2052         OnWentOnlineInfo *info;
2053         
2054         device = modest_runtime_get_device();
2055         device_online = tny_device_is_online (device);
2056
2057         /* If there is no account check only the device status */
2058         if (!account) {
2059                 
2060                 if (device_online) {
2061  
2062                         /* We promise to instantly perform the callback, so ... */
2063                         if (callback) {
2064                                 callback (FALSE, NULL, parent_window, account, user_data);
2065                         }
2066                         
2067                 } else {
2068                         
2069                         info = g_slice_new0 (OnWentOnlineInfo);
2070                         
2071                         info->iap = NULL;
2072                         info->device = NULL;
2073                         info->account = NULL;
2074                 
2075                         if (parent_window)
2076                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2077                         else
2078                                 info->parent_window = NULL;
2079                         info->user_data = user_data;
2080                         info->callback = callback;
2081                 
2082                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2083                                                               force, on_conic_device_went_online, 
2084                                                               info);
2085  
2086                         /* We'll cleanup in on_conic_device_went_online */
2087                 }
2088  
2089                 /* The other code has no more reason to run. This is all that we can do for the
2090                  * caller (he should have given us a nice and clean account instance!). We
2091                  * can't do magic, we don't know what account he intends to bring online. So
2092                  * we'll just bring the device online (and await his false bug report). */
2093                 
2094                 return;
2095         }
2096  
2097         
2098         /* Return if the account is already connected */
2099         
2100         conn_status = tny_account_get_connection_status (account);
2101         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2102  
2103                 /* We promise to instantly perform the callback, so ... */
2104                 if (callback) {
2105                         callback (FALSE, NULL, parent_window, account, user_data);
2106                 }
2107                 
2108                 return;
2109         }
2110         
2111         /* Else, we are in a state that requires that we go online before we
2112          * call the caller's callback. */
2113         
2114         info = g_slice_new0 (OnWentOnlineInfo);
2115         
2116         info->device = NULL;
2117         info->iap = NULL;
2118         info->account = TNY_ACCOUNT (g_object_ref (account));
2119         
2120         if (parent_window)
2121                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2122         else
2123                 info->parent_window = NULL;
2124         
2125         /* So we'll put the callback away for later ... */
2126         
2127         info->user_data = user_data;
2128         info->callback = callback;
2129         
2130         if (!device_online) {
2131  
2132                 /* If also the device is offline, then we connect both the device 
2133                  * and the account */
2134                 
2135                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2136                                                       force, on_conic_device_went_online, 
2137                                                       info);
2138                 
2139         } else {
2140                 
2141                 /* If the device is online, we'll just connect the account */
2142                 
2143                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2144                                               on_account_went_online, info);
2145         }
2146  
2147         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2148          * in both situations, go look if you don't believe me! */
2149         
2150         return;
2151 }
2152
2153 void
2154 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2155                                                gboolean force,
2156                                                TnyFolderStore *folder_store, 
2157                                                ModestConnectedPerformer callback, 
2158                                                gpointer user_data)
2159 {
2160         TnyAccount *account = NULL;
2161         
2162         if (!folder_store) {
2163                 /* We promise to instantly perform the callback, so ... */
2164                 if (callback) {
2165                         callback (FALSE, NULL, parent_window, NULL, user_data);
2166                 }
2167                 return;
2168
2169         } else if (TNY_IS_FOLDER (folder_store)) {
2170                 /* Get the folder's parent account: */
2171                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2172         } else if (TNY_IS_ACCOUNT (folder_store)) {
2173                 /* Use the folder store as an account: */
2174                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2175         }
2176
2177         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
2178                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2179                         /* No need to connect a local account */
2180                         if (callback)
2181                                 callback (FALSE, NULL, parent_window, account, user_data);
2182
2183                         goto clean;
2184                 }
2185         }
2186         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2187
2188  clean:
2189         if (account)
2190                 g_object_unref (account);
2191 }
2192
2193 static void
2194 src_account_connect_performer (gboolean canceled,
2195                                GError *err,
2196                                GtkWindow *parent_window,
2197                                TnyAccount *src_account,
2198                                gpointer user_data)
2199 {
2200         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2201
2202         if (canceled || err) {
2203                 /* If there was any error call the user callback */
2204                 info->callback (canceled, err, parent_window, src_account, info->data);
2205         } else {
2206                 /* Connect the destination account */
2207                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2208                                                                TNY_FOLDER_STORE (info->dst_account),
2209                                                                info->callback, info->data);
2210         }
2211
2212         /* Free the info object */
2213         g_object_unref (info->dst_account);
2214         g_slice_free (DoubleConnectionInfo, info);
2215 }
2216
2217
2218 void 
2219 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2220                                             gboolean force,
2221                                             TnyFolderStore *folder_store,
2222                                             DoubleConnectionInfo *connect_info)
2223 {
2224         modest_platform_connect_if_remote_and_perform(parent_window, 
2225                                                       force,
2226                                                       folder_store, 
2227                                                       src_account_connect_performer, 
2228                                                       connect_info);
2229 }
2230
2231 GtkWidget *
2232 modest_platform_get_account_settings_wizard (void)
2233 {
2234         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2235
2236         return GTK_WIDGET (dialog);
2237 }
2238
2239 ModestConnectedVia
2240 modest_platform_get_current_connection (void)
2241 {
2242         TnyDevice *device = NULL;
2243         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2244         
2245         device = modest_runtime_get_device ();
2246
2247         if (!tny_device_is_online (device))
2248                 return MODEST_CONNECTED_VIA_ANY;
2249
2250 #ifdef MODEST_HAVE_CONIC
2251         /* Get iap id */
2252         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2253         if (iap_id) {
2254                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2255                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2256                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2257                 if (bearer_type) {
2258                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2259                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2260                             !strcmp (bearer_type, "WIMAX")) {
2261                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2262                         } else {
2263                                 retval = MODEST_CONNECTED_VIA_ANY;
2264                         }
2265                 }       
2266                 g_object_unref (iap);
2267         }
2268 #else
2269         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2270 #endif /* MODEST_HAVE_CONIC */
2271         return retval;
2272 }
2273
2274
2275
2276 gboolean
2277 modest_platform_check_memory_low (ModestWindow *win,
2278                                   gboolean visuals)
2279 {
2280         gboolean lowmem;
2281         
2282         /* are we in low memory state? */
2283         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2284         
2285         if (win && lowmem && visuals)
2286                 modest_platform_run_information_dialog (
2287                         GTK_WINDOW(win),
2288                         dgettext("ke-recv","memr_ib_operation_disabled"),
2289                         TRUE);
2290
2291         if (lowmem)
2292                 g_debug ("%s: low memory reached. disallowing some operations",
2293                          __FUNCTION__);
2294
2295         return lowmem;
2296 }
2297
2298 void 
2299 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2300                                            TnyFolder *folder)
2301 {
2302         GtkWidget *dialog;
2303         
2304         /* Create dialog */
2305         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2306
2307         /* Run dialog */
2308         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2309                                      GTK_WINDOW (dialog), 
2310                                      parent_window);
2311         gtk_widget_show_all (dialog);
2312
2313         g_signal_connect_swapped (dialog, "response", 
2314                                   G_CALLBACK (gtk_widget_destroy),
2315                                   dialog);
2316 }
2317
2318 void
2319 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2320                                            TnyHeader *header)
2321 {
2322         GtkWidget *dialog;
2323
2324         /* Create dialog */
2325         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header);
2326
2327         /* Run dialog */
2328         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2329                                      GTK_WINDOW (dialog),
2330                                      parent_window);
2331         gtk_widget_show_all (dialog);
2332
2333         g_signal_connect_swapped (dialog, "response", 
2334                                   G_CALLBACK (gtk_widget_destroy),
2335                                   dialog);
2336 }
2337
2338 osso_context_t *
2339 modest_platform_get_osso_context (void)
2340 {
2341         return modest_maemo_utils_get_osso_context ();
2342 }
2343
2344 static void
2345 _modest_platform_play_email_tone (void)
2346 {
2347         gchar *active_profile;
2348         gchar *mail_tone;
2349         gchar *mail_volume;
2350         gint mail_volume_int;
2351         int ret;
2352         ca_context *ca_con = NULL;
2353         ca_proplist *pl = NULL;
2354
2355         active_profile = profile_get_profile ();
2356         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2357         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2358         mail_volume_int = profile_parse_int (mail_volume);
2359
2360         if (mail_volume_int > 0) {
2361
2362                 if ((ret = ca_context_create(&ca_con)) != CA_SUCCESS) {
2363                         g_warning("ca_context_create: %s\n", ca_strerror(ret));
2364                         return;
2365                 }
2366
2367                 if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2368                         g_warning("ca_context_open: %s\n", ca_strerror(ret));
2369                         ca_context_destroy(ca_con);
2370                         return;
2371                 }
2372
2373                 ca_proplist_create(&pl);
2374                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2375                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", (gfloat) mail_volume_int);
2376
2377                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2378                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2379
2380                 ca_proplist_destroy(pl);
2381                 ca_context_destroy(ca_con);
2382         }
2383
2384         g_free (mail_volume);
2385         g_free (mail_tone);
2386         g_free (active_profile);
2387 }
2388
2389 static void
2390 on_move_to_dialog_folder_activated (GtkTreeView       *tree_view,
2391                                     GtkTreePath       *path,
2392                                     GtkTreeViewColumn *column,
2393                                     gpointer           user_data)
2394 {
2395         gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
2396 }
2397
2398 GtkWidget *
2399 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2400                                        GtkWidget **folder_view)
2401 {
2402         GtkWidget *dialog, *folder_view_container;
2403
2404         /* Create dialog. We cannot use a touch selector because we
2405            need to use here the folder view widget directly */
2406         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2407                                               GTK_WINDOW (parent_window),
2408                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2409                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2410                                               _("mcen_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
2411                                               NULL);
2412
2413         /* Create folder view */
2414         *folder_view = modest_platform_create_folder_view (NULL);
2415
2416         /* Simulate the behaviour of a HildonPickerDialog by emitting
2417            a response when a folder is selected */
2418         g_signal_connect (*folder_view, "row-activated",
2419                           G_CALLBACK (on_move_to_dialog_folder_activated),
2420                           dialog);
2421
2422         /* Create pannable and add it to the dialog */
2423         folder_view_container = hildon_pannable_area_new ();
2424         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), folder_view_container);
2425         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2426
2427         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2428
2429         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2430         gtk_widget_show (folder_view_container);
2431         gtk_widget_show (*folder_view);
2432
2433         return dialog;
2434 }
2435
2436 TnyList *
2437 modest_platform_get_list_to_move (ModestWindow *window)
2438 {
2439         if (MODEST_IS_HEADER_WINDOW (window)) {
2440                 ModestHeaderView *header_view;
2441
2442                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2443
2444                 return modest_header_view_get_selected_headers (header_view);
2445         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2446                 ModestFolderView *folder_view;
2447                 TnyFolderStore *selected_folder;
2448                 TnyList *list;
2449
2450                 list = TNY_LIST (tny_simple_list_new ());
2451                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2452                 selected_folder = modest_folder_view_get_selected (folder_view);
2453                 if (selected_folder) {
2454                         tny_list_prepend (list, G_OBJECT (selected_folder));
2455                         g_object_unref (selected_folder);
2456                 }
2457                 return list;
2458         } else {
2459                 return NULL;
2460         }
2461 }