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