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