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