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