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