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