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