Fixes NB#141137, do not play email tone twice when sending notifications
[modest] / src / hildon2 / modest-platform.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <glib/gi18n.h>
32
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-runtime.h>
36 #include <modest-main-window.h>
37 #include <modest-header-view.h>
38 #include "modest-hildon2-global-settings-dialog.h"
39 #include "modest-widget-memory.h"
40 #include <modest-hildon-includes.h>
41 #include <modest-maemo-utils.h>
42 #include <modest-utils.h>
43 #include <dbus_api/modest-dbus-callbacks.h>
44 #include <modest-osso-autosave-callbacks.h>
45 #include <libosso.h>
46 #include <tny-maemo-conic-device.h>
47 #include <tny-camel-folder.h>
48 #include <tny-simple-list.h>
49 #include <tny-merge-folder.h>
50 #include <tny-error.h>
51 #include <tny-folder.h>
52 #include <tny-account-store-view.h>
53 #include <gtk/gtkicontheme.h>
54 #include <gtk/gtkmenuitem.h>
55 #include <gtk/gtkmain.h>
56 #include <modest-text-utils.h>
57 #include "modest-tny-folder.h"
58 #include "modest-tny-account.h"
59 #include <string.h>
60 #include <libgnomevfs/gnome-vfs-mime-utils.h>
61 #include <modest-account-settings-dialog.h>
62 #include <modest-easysetup-wizard-dialog.h>
63 #include "modest-hildon2-sort-dialog.h"
64 #include <hildon/hildon.h>
65 #include <osso-mem.h>
66 #include "hildon2/modest-hildon2-details-dialog.h"
67 #include "hildon2/modest-hildon2-window-mgr.h"
68 #ifdef MODEST_USE_PROFILE
69 #include <keys_nokia.h>
70 #include <libprofile.h>
71 #endif
72 #include <canberra.h>
73 #include <modest-datetime-formatter.h>
74 #include "modest-header-window.h"
75 #include <modest-folder-window.h>
76 #include <modest-account-mgr.h>
77 #include <modest-account-mgr-helpers.h>
78 #include <modest-ui-constants.h>
79 #include <modest-selector-picker.h>
80 #include <modest-icon-names.h>
81 #include <modest-count-stream.h>
82 #include <math.h>
83
84 #ifdef MODEST_HAVE_MCE
85 #include <mce/dbus-names.h>
86 #endif /*MODEST_HAVE_MCE*/
87
88 #ifdef MODEST_HAVE_ABOOK
89 #include <libosso-abook/osso-abook.h>
90 #endif /*MODEST_HAVE_ABOOK*/
91
92 #ifdef MODEST_HAVE_LIBALARM
93 #include <alarmd/libalarm.h> /* For alarm_event_add(), etc. */
94 #endif /*MODEST_HAVE_LIBALARM*/
95
96
97 #define HILDON_OSSO_URI_ACTION "uri-action"
98 #define URI_ACTION_COPY "copy:"
99 #define MODEST_NOTIFICATION_CATEGORY "email-message"
100 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternCommunicationEmail"
101 #ifdef MODEST_USE_PROFILE
102 #define PROFILE_MAIL_TONE PROFILEKEY_EMAIL_ALERT_TONE
103 #define PROFILE_MAIL_VOLUME PROFILEKEY_EMAIL_ALERT_VOLUME
104 #else
105 #define MAIL_TONE "message-new-email"
106 #endif
107
108 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
109 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
110 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
111 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
112 #define MODEST_ALARMD_APPID PACKAGE_NAME
113
114 static ca_context *ca_con = NULL;
115 static gboolean ca_con_opened = FALSE;
116
117
118 static void modest_platform_play_email_tone (void);
119
120
121 static void     
122 on_modest_conf_update_interval_changed (ModestConf* self, 
123                                         const gchar *key, 
124                                         ModestConfEvent event,
125                                         ModestConfNotificationId id, 
126                                         gpointer user_data)
127 {
128         g_return_if_fail (key);
129         
130         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
131                 const guint update_interval_minutes = 
132                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
133                 modest_platform_set_update_interval (update_interval_minutes);
134         }
135 }
136
137
138
139 static gboolean
140 check_required_files (void)
141 {
142         FILE *mcc_file = modest_utils_open_mcc_mapping_file (FALSE, NULL);
143         if (!mcc_file) {
144                 g_printerr ("modest: check for mcc file (for LANG) failed\n");
145                 return FALSE;
146         } else 
147                 fclose (mcc_file);
148         
149         mcc_file = modest_utils_open_mcc_mapping_file (TRUE, NULL);
150         if (!mcc_file) {
151                 g_printerr ("modest: check for mcc file (for LC_MESSAGES) failed\n");
152                 return FALSE;
153         } else 
154                 fclose (mcc_file);
155         
156         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
157             access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
158                 g_printerr ("modest: cannot find providers data\n");
159                 return FALSE;
160         }
161         
162         return TRUE;
163 }
164
165
166 /* the gpointer here is the osso_context. */
167 gboolean
168 modest_platform_init (int argc, char *argv[])
169 {
170         osso_context_t *osso_context;
171         osso_hw_state_t hw_state = { 0 };
172         DBusConnection *con;
173         GSList *acc_names;
174
175         if (!check_required_files ()) {
176                 g_printerr ("modest: missing required files\n");
177                 return FALSE;
178         }
179
180         osso_context = modest_maemo_utils_get_osso_context();
181
182         if ((con = osso_get_dbus_connection (osso_context)) == NULL) {
183                 g_printerr ("modest: could not get dbus connection\n");
184                 return FALSE;
185         }
186
187         /* Add a D-Bus handler to be used when the main osso-rpc 
188          * D-Bus handler has not handled something.
189          * We use this for D-Bus methods that need to use more complex types 
190          * than osso-rpc supports. 
191          */
192         if (!dbus_connection_add_filter (con,
193                                          modest_dbus_req_filter,
194                                          NULL,
195                                          NULL)) {
196
197                 g_printerr ("modest: Could not add D-Bus filter\n");
198                 return FALSE;
199         }
200
201         /* Register our simple D-Bus callbacks, via the osso API: */
202         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
203                                MODEST_DBUS_SERVICE, 
204                                MODEST_DBUS_OBJECT, 
205                                MODEST_DBUS_IFACE,
206                                modest_dbus_req_handler, NULL /* user_data */);
207         if (result != OSSO_OK) {
208                 g_printerr ("modest: Error setting D-BUS callback (%d)\n", result);
209                 return FALSE;
210         }
211
212         /* Register hardware event dbus callback: */
213         hw_state.shutdown_ind = TRUE;
214         osso_hw_set_event_cb(osso_context, NULL, NULL, NULL);
215
216         /* Register osso auto-save callbacks: */
217         result = osso_application_set_autosave_cb (osso_context, 
218                 modest_on_osso_application_autosave, NULL /* user_data */);
219         if (result != OSSO_OK) {
220                 g_printerr ("modest: osso_application_set_autosave_cb() failed.\n");
221                 return FALSE;
222         }
223         
224
225         /* Make sure that the update interval is changed whenever its gconf key 
226          * is changed */
227         /* CAUTION: we're not using here the
228            modest_conf_listen_to_namespace because we know that there
229            are other parts of Modest listening for this namespace, so
230            we'll receive the notifications anyway. We basically do not
231            use it because there is no easy way to do the
232            modest_conf_forget_namespace */
233         ModestConf *conf = modest_runtime_get_conf ();
234         g_signal_connect (G_OBJECT(conf),
235                           "key_changed",
236                           G_CALLBACK (on_modest_conf_update_interval_changed), 
237                           NULL);
238
239         /* only force the setting of the default interval, if there are actually
240          * any accounts */
241         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
242         if (acc_names) {
243                 /* Get the initial update interval from gconf: */
244                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
245                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
246                 modest_account_mgr_free_account_names (acc_names);
247         }
248
249         
250 #ifdef MODEST_HAVE_ABOOK
251         /* initialize the addressbook */
252         if (!osso_abook_init (&argc, &argv, osso_context)) {
253                 g_printerr ("modest: failed to initialized addressbook\n");
254                 return FALSE;
255         }
256 #endif /*MODEST_HAVE_ABOOK*/
257
258         return TRUE;
259 }
260
261 gboolean
262 modest_platform_uninit (void)
263 {
264         osso_context_t *osso_context =
265                 modest_maemo_utils_get_osso_context ();
266         if (osso_context)
267                 osso_deinitialize (osso_context);
268
269         return TRUE;
270 }
271
272
273
274
275 TnyDevice*
276 modest_platform_get_new_device (void)
277 {
278         return TNY_DEVICE (tny_maemo_conic_device_new ());
279 }
280
281 gchar*
282 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
283                                     gchar **effective_mime_type)
284 {
285         GString *mime_str = NULL;
286         gchar *icon_name  = NULL;
287         gchar **icons, **cursor;
288         
289         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) 
290                 mime_str = g_string_new (gnome_vfs_get_mime_type_for_name (name));
291         else {
292                 mime_str = g_string_new (mime_type);
293                 g_string_ascii_down (mime_str);
294         }
295         
296         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
297         
298         for (cursor = icons; cursor; ++cursor) {
299                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
300                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
301                         icon_name = g_strdup ("qgn_list_messagin");
302                         break;
303                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
304                         icon_name = g_strdup (*cursor);
305                         break;
306                 }
307         }
308         g_strfreev (icons);
309
310         if (effective_mime_type)
311                 *effective_mime_type = g_string_free (mime_str, FALSE);
312         else
313                 g_string_free (mime_str, TRUE);
314         
315         return icon_name;
316 }
317
318
319 static gboolean
320 checked_hildon_uri_open (const gchar *uri, HildonURIAction *action)
321 {
322         GError *err = NULL;
323         gboolean result;
324
325         g_return_val_if_fail (uri, FALSE);
326         
327         result = hildon_uri_open (uri, action, &err);
328         if (!result) {
329                 g_printerr ("modest: hildon_uri_open ('%s', %p) failed: %s",
330                             uri, action,  err && err->message ? err->message : "unknown error");
331                 if (err)
332                         g_error_free (err);
333         }
334         return result;
335 }
336
337
338
339 gboolean 
340 modest_platform_activate_uri (const gchar *uri)
341 {
342         HildonURIAction *action;
343         gboolean result = FALSE;
344         GSList *actions, *iter = NULL;
345         
346         g_return_val_if_fail (uri, FALSE);
347         if (!uri)
348                 return FALSE;
349
350         /* don't try to activate file: uri's -- they might confuse the user,
351          * and/or might have security implications */
352         if (!g_str_has_prefix (uri, "file:")) {
353                 
354                 actions = hildon_uri_get_actions_by_uri (uri, -1, NULL);
355                 
356                 for (iter = actions; iter; iter = g_slist_next (iter)) {
357                         action = (HildonURIAction*) iter->data;
358                         if (action && strcmp (hildon_uri_action_get_service (action),
359                                               "com.nokia.modest") == 0) {
360                                 result = checked_hildon_uri_open (uri, action);
361                                 break;
362                         }
363                 }
364                 
365                 /* if we could not open it with email, try something else */
366                 if (!result)
367                         result = checked_hildon_uri_open (uri, NULL);   
368         } 
369         
370         if (!result) {
371                 ModestWindow *parent =
372                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
373                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
374                                                 _("mcen_ib_unsupported_link"));
375                 g_debug ("%s: cannot open uri '%s'", __FUNCTION__,uri);
376         } 
377         
378         return result;
379 }
380
381 gboolean 
382 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
383 {
384         gint result = 0;
385         DBusConnection *con;
386         gchar *uri_path = NULL;
387         
388         uri_path = gnome_vfs_get_uri_from_local_path (path);    
389         con = osso_get_dbus_connection (modest_maemo_utils_get_osso_context());
390         
391         if (mime_type)
392                 result = hildon_mime_open_file_with_mime_type (con, uri_path, mime_type);
393         if (result != 1)
394                 result = hildon_mime_open_file (con, uri_path);
395         if (result != 1)
396                 modest_platform_run_information_dialog (NULL, _("mcen_ni_noregistered_viewer"), FALSE);
397         
398         return result != 1;
399 }
400
401 typedef struct  {
402         GSList *actions;
403         gchar  *uri;
404 } ModestPlatformPopupInfo;
405
406 static gboolean
407 delete_uri_popup (GtkWidget *menu,
408                   GdkEvent *event,
409                   gpointer userdata)
410 {
411         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
412
413         g_free (popup_info->uri);
414         hildon_uri_free_actions (popup_info->actions);
415
416         return FALSE;
417 }
418
419 static void
420 activate_uri_popup_item (GtkMenuItem *menu_item,
421                          gpointer userdata)
422 {
423         GSList *node;
424         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
425         const gchar* action_name;
426
427         action_name = g_object_get_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION);
428         if (!action_name) {
429                 g_printerr ("modest: no action name defined\n");
430                 return;
431         }
432
433         /* special handling for the copy menu item -- copy the uri to the clipboard */
434         /* if it's a copy thingy, the uri will look like 'copy:http://slashdot.org' */
435         if (g_str_has_prefix (action_name, URI_ACTION_COPY)) {
436                 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
437                 action_name += strlen(URI_ACTION_COPY); /* jump past the prefix */
438
439                 if (g_str_has_prefix (action_name, "mailto:")) /* ignore mailto: prefixes */
440                         action_name += strlen ("mailto:");
441                 
442                 gtk_clipboard_set_text (clipboard, action_name, strlen (action_name));
443                 modest_platform_information_banner (NULL, NULL, _CS("ecoc_ib_edwin_copied"));
444                 return; /* we're done */
445         }
446         
447         /* now, the real uri-actions... */
448         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
449                 HildonURIAction *action = (HildonURIAction *) node->data;
450                 if (strcmp (action_name, hildon_uri_action_get_name (action))==0) {
451                         if (!checked_hildon_uri_open (popup_info->uri, action)) {
452                                 ModestWindow *parent =
453                                         modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE);
454                                 hildon_banner_show_information (parent ? GTK_WIDGET(parent): NULL, NULL,
455                                                                 _("mcen_ib_unsupported_link"));
456                         }
457                         break;
458                 }
459         }
460 }
461
462 gboolean 
463 modest_platform_show_uri_popup (const gchar *uri)
464 {
465         GSList *actions_list;
466
467         if (uri == NULL)
468                 return FALSE;
469         
470         actions_list = hildon_uri_get_actions_by_uri (uri, -1, NULL);
471         if (actions_list) {
472
473                 GtkWidget *menu = gtk_menu_new ();
474                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
475
476                 /* don't add actions for file: uri's -- they might confuse the user,
477                  * and/or might have security implications
478                  * we still allow to copy the url though
479                  */
480                 if (!g_str_has_prefix (uri, "file:")) {
481
482                         GSList *node;
483                         popup_info->actions = actions_list;
484                         popup_info->uri = g_strdup (uri);
485
486                         for (node = actions_list; node != NULL; node = g_slist_next (node)) {
487                                 GtkWidget *menu_item;
488                                 const gchar *action_name;
489                                 const gchar *translation_domain;
490                                 HildonURIAction *action = (HildonURIAction *) node->data;
491                                 action_name = hildon_uri_action_get_name (action);
492                                 translation_domain = hildon_uri_action_get_translation_domain (action);
493                                 menu_item = gtk_menu_item_new_with_label (dgettext(translation_domain, action_name));
494                                 hildon_gtk_widget_set_theme_size (menu_item, MODEST_EDITABLE_SIZE);
495                                 g_object_set_data (G_OBJECT(menu_item), HILDON_OSSO_URI_ACTION, (gpointer)action_name);  /* hack */
496                                 g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item),
497                                                   popup_info);
498
499                                 if (hildon_uri_is_default_action (action, NULL)) {
500                                         gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
501                                 } else {
502                                         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
503                                 }
504                                 gtk_widget_show (menu_item);
505                         }
506                 }
507
508
509                 /* and what to do when the link is deleted */
510                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
511                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
512
513         } else {
514                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
515         }
516
517         return TRUE;
518 }
519
520
521 GdkPixbuf*
522 modest_platform_get_icon (const gchar *name, guint icon_size)
523 {
524         GError *err = NULL;
525         GdkPixbuf* pixbuf = NULL;
526         GtkIconTheme *current_theme = NULL;
527
528         g_return_val_if_fail (name, NULL);
529
530         /* strlen == 0 is not really an error; it just
531          * means the icon is not available
532          */
533         if (!name || strlen(name) == 0)
534                 return NULL;
535
536         current_theme = gtk_icon_theme_get_default ();
537         pixbuf = gtk_icon_theme_load_icon (current_theme, name, icon_size,
538                                            GTK_ICON_LOOKUP_NO_SVG,
539                                            &err);
540         if (!pixbuf) {
541                 g_warning ("Error loading theme icon '%s': %s\n",
542                             name, err->message);
543                 g_error_free (err);
544         } 
545         return pixbuf;
546 }
547
548 const gchar*
549 modest_platform_get_app_name (void)
550 {
551         return _("mcen_ap_name");
552 }
553
554 static void
555 entry_insert_text (GtkEditable *editable,
556                    const gchar *text,
557                    gint         length,
558                    gint        *position,
559                    gpointer     data)
560 {
561         gchar *chars;
562         gint chars_length;
563
564         chars = gtk_editable_get_chars (editable, 0, -1);
565         chars_length = g_utf8_strlen (chars, -1);
566         g_free (chars);
567
568         /* Show WID-INF036 */
569         if (chars_length >= 20) {
570                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
571                                                  _CS("ckdg_ib_maximum_characters_reached"));
572         } else {
573                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
574                         /* Show an error */
575                         gchar *tmp, *msg;
576
577                         tmp = g_strndup (folder_name_forbidden_chars,
578                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
579                         msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
580                         hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)),
581                                                          NULL, msg);
582                         g_free (msg);
583                         g_free (tmp);
584                 } else {
585                         if (length >= 20) {
586                                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
587                                                                  _CS("ckdg_ib_maximum_characters_reached"));
588                         }
589                         /* Write the text in the entry if it's valid */
590                         g_signal_handlers_block_by_func (editable,
591                                                          (gpointer) entry_insert_text, data);
592                         gtk_editable_insert_text (editable, text, length, position);
593                         g_signal_handlers_unblock_by_func (editable,
594                                                            (gpointer) entry_insert_text, data);
595                 }
596         }
597         /* Do not allow further processing */
598         g_signal_stop_emission_by_name (editable, "insert_text");
599 }
600
601 static void
602 entry_changed (GtkEditable *editable,
603                gpointer     user_data)
604 {
605         gchar *chars;
606         GtkWidget *ok_button;
607         GList *buttons;
608
609         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
610         ok_button = GTK_WIDGET (buttons->data);
611
612         chars = gtk_editable_get_chars (editable, 0, -1);
613         g_return_if_fail (chars != NULL);
614
615
616         if (g_utf8_strlen (chars,-1) >= 20) {
617                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
618                                                  _CS("ckdg_ib_maximum_characters_reached"));
619         }
620         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
621
622         /* Free */
623         g_list_free (buttons);
624         g_free (chars);
625 }
626
627
628
629 static void
630 on_response (GtkDialog *dialog,
631              gint response,
632              gpointer user_data)
633 {
634         GtkWidget *entry, *picker;
635         TnyFolderStore *parent;
636         const gchar *new_name;
637         gboolean exists;
638
639         if (response != GTK_RESPONSE_ACCEPT)
640                 return;
641
642         /* Get entry */
643         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
644         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
645
646         parent = TNY_FOLDER_STORE (user_data);
647         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
648         exists = FALSE;
649
650         if (picker != NULL)
651                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
652
653         /* Look for another folder with the same name */
654         if (!TNY_IS_MERGE_FOLDER (parent) &&
655             modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
656                 exists = TRUE;
657
658         if (!exists) {
659                 if (TNY_IS_ACCOUNT (parent) &&
660                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
661                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
662                                                                          new_name)) {
663                         exists = TRUE;
664                 }
665         }
666
667         if (exists) {
668                 /* Show an error */
669                 hildon_banner_show_information (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
670                                                 NULL, _CS("ckdg_ib_folder_already_exists"));
671                 /* Select the text */
672                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
673                 gtk_widget_grab_focus (entry);
674                 /* Do not close the dialog */
675                 g_signal_stop_emission_by_name (dialog, "response");
676         }
677 }
678
679 typedef struct _FolderChooserData {
680         TnyFolderStore *store;
681         GtkWidget *dialog;
682 } FolderChooserData;
683
684 static void
685 folder_chooser_activated (ModestFolderView *folder_view,
686                           TnyFolderStore *folder,
687                           FolderChooserData *userdata)
688 {
689         userdata->store = folder;
690         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
691 }
692
693 static TnyFolderStore *
694 folder_chooser_dialog_run (ModestFolderView *original,
695                            TnyFolderStore *current,
696                            GtkButton *picker)
697 {
698         GtkWidget *folder_view;
699         FolderChooserData userdata = {NULL, NULL};
700         GtkWidget *pannable;
701         const gchar *visible_id = NULL;
702
703         userdata.dialog = hildon_dialog_new ();
704         pannable = hildon_pannable_area_new ();
705         folder_view = modest_platform_create_folder_view (NULL);
706
707         gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
708
709         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
710                                        MODEST_FOLDER_VIEW (folder_view));
711
712         if (TNY_IS_ACCOUNT (current)) {
713                 /* Local folders and MMC account are always shown
714                    along with the currently visible server account */
715                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
716                     modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
717                         visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
718                 else
719                         visible_id = tny_account_get_id (TNY_ACCOUNT (current));
720         } else if (TNY_IS_FOLDER (current)) {
721                 TnyAccount *account;
722                 account = modest_tny_folder_get_account ((TnyFolder *) current);
723                 if (account) {
724                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
725                             modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
726                                 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
727                         } else {
728                                 visible_id = tny_account_get_id (account);
729                         }
730                         g_object_unref (account);
731                 }
732         } else {
733                 visible_id =
734                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
735         }
736
737         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
738                                                                      visible_id);
739
740         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), pannable);
741         gtk_container_add (GTK_CONTAINER (pannable), folder_view);
742         gtk_widget_set_size_request (pannable, -1, 320);
743
744         gtk_widget_show (folder_view);
745         gtk_widget_show (pannable);
746         gtk_widget_show (userdata.dialog);
747         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
748                           G_CALLBACK (folder_chooser_activated), 
749                           (gpointer) &userdata);
750
751         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
752         gtk_widget_destroy (userdata.dialog);
753
754         return userdata.store;
755 }
756
757 static gchar *
758 folder_store_get_display_name (TnyFolderStore *store)
759 {
760         if (TNY_IS_ACCOUNT (store)) {
761                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
762                         return modest_conf_get_string (modest_runtime_get_conf(),
763                                                        MODEST_CONF_DEVICE_NAME, NULL);
764                 else
765                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
766         } else {
767                 gchar *fname;
768                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
769
770                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
771                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
772                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
773                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
774                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
775                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
776                                 g_free (fname);
777                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
778                         }
779                 } else {
780                         /* Sometimes an special folder is reported by the server as
781                            NORMAL, like some versions of Dovecot */
782                         if (type == TNY_FOLDER_TYPE_NORMAL ||
783                             type == TNY_FOLDER_TYPE_UNKNOWN) {
784                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
785                         }
786                 }
787
788                 if (type == TNY_FOLDER_TYPE_INBOX) {
789                         g_free (fname);
790                         fname = g_strdup (_("mcen_me_folder_inbox"));
791                 }
792                 return fname;
793         }
794 }
795
796 GtkWidget *
797 get_image_for_folder_store (TnyFolderStore *store,
798                             gint size)
799 {
800         GdkPixbuf *pixbuf;
801         const gchar *icon_name = NULL;
802         GtkWidget *image = NULL;
803
804         if (TNY_IS_ACCOUNT (store)) {
805                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
806                         icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
807                 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
808                         icon_name = MODEST_FOLDER_ICON_MMC;
809                 else
810                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
811         } else {
812                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
813                 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
814                         switch (type) {
815                         case TNY_FOLDER_TYPE_INBOX:
816                                 icon_name = MODEST_FOLDER_ICON_INBOX;
817                                 break;
818                         default:
819                                 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
820                         }
821                 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
822                         switch (type) {
823                         case TNY_FOLDER_TYPE_OUTBOX:
824                                 icon_name = MODEST_FOLDER_ICON_OUTBOX;
825                                 break;
826                         case TNY_FOLDER_TYPE_DRAFTS:
827                                 icon_name = MODEST_FOLDER_ICON_DRAFTS;
828                                 break;
829                         case TNY_FOLDER_TYPE_SENT:
830                                 icon_name = MODEST_FOLDER_ICON_SENT;
831                                 break;
832                         default:
833                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
834                         }
835                 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
836                         icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
837                 }
838         }
839
840         /* Set icon */
841         pixbuf = modest_platform_get_icon (icon_name, size);
842
843         if (pixbuf) {
844                 image = gtk_image_new_from_pixbuf (pixbuf);
845                 g_object_unref (pixbuf);
846         }
847
848         return image;
849 }
850
851 static void
852 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
853 {
854         gchar *name;
855
856         if (store == NULL) {
857                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
858         } else {
859                 GtkWidget *image;
860
861                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
862                                         g_object_ref (store),
863                                         (GDestroyNotify) g_object_unref);
864                 name = folder_store_get_display_name (store);
865                 hildon_button_set_value (HILDON_BUTTON (button), name);
866                 g_free (name);
867
868                 /* Select icon */
869                 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
870                 if (image)
871                         hildon_button_set_image (HILDON_BUTTON (button), image);
872         }
873 }
874
875 /* Always returns DUPs so you must free the returned value */
876 static gchar *
877 get_next_folder_name (const gchar *suggested_name, 
878                       TnyFolderStore *suggested_folder)
879 {
880         const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
881         unsigned int i;
882         gchar *real_suggested_name;
883
884         if (suggested_name !=NULL) {
885                 return g_strdup (suggested_name);
886         }
887
888         for(i = 0; i < 100; ++ i) {
889                 gboolean exists = FALSE;
890
891                 if (i == 0)
892                         real_suggested_name = g_strdup (default_name);
893                 else
894                         real_suggested_name = g_strdup_printf ("%s(%d)",
895                                                                _FM("ckdg_va_new_folder_name_stub"),
896                                                                i);
897                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
898                                                                     real_suggested_name,
899                                                                     TRUE);
900
901                 if (!exists)
902                         break;
903
904                 g_free (real_suggested_name);
905         }
906
907         /* Didn't find a free number */
908         if (i == 100)
909                 real_suggested_name = g_strdup (default_name);
910
911         return real_suggested_name;
912 }
913
914 typedef struct {
915         ModestFolderView *folder_view;
916         GtkEntry *entry;
917 } FolderPickerHelper;
918
919 static void
920 folder_picker_clicked (GtkButton *button,
921                        FolderPickerHelper *helper)
922 {
923         TnyFolderStore *store, *current;
924
925         current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
926
927         store = folder_chooser_dialog_run (helper->folder_view, current, button);
928         if (store) {
929                 const gchar *current_name;
930                 gboolean exists = FALSE;
931
932                 folder_picker_set_store (GTK_BUTTON (button), store);
933
934                 /* Update the name of the folder */
935                 current_name = gtk_entry_get_text (helper->entry);
936
937                 if (TNY_IS_FOLDER_STORE (store))
938                         exists = modest_tny_folder_has_subfolder_with_name (store,
939                                                                             current_name,
940                                                                             TRUE);
941                 if (exists) {
942                         gchar *new_name = get_next_folder_name (NULL, store);
943                         gtk_entry_set_text (helper->entry, new_name);
944                         g_free (new_name);
945                 }
946         }
947 }
948
949 static GtkWidget *
950 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
951 {
952         GtkWidget *button;
953         const gchar *acc_id = NULL;
954
955         button = hildon_button_new (MODEST_EDITABLE_SIZE,
956                                     HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
957
958         hildon_button_set_alignment (HILDON_BUTTON (button), 0.0, 0.5, 1.0, 1.0);
959
960         if (suggested) {
961
962                 folder_picker_set_store (GTK_BUTTON (button), suggested);
963
964                 if (TNY_IS_ACCOUNT (suggested)) {
965                         if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
966                             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
967                                 acc_id = tny_account_get_id ((TnyAccount *) suggested);
968                 } else {
969                         TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
970                         if (account) {
971                                 acc_id = tny_account_get_id ((TnyAccount *) account);
972                                 g_object_unref (account);
973                         }
974                 }
975         }
976
977         if (!acc_id)
978                 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
979
980         g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
981                                 g_strdup (acc_id), (GDestroyNotify) g_free);
982
983
984         g_signal_connect (G_OBJECT (button), "clicked",
985                           G_CALLBACK (folder_picker_clicked),
986                           helper);
987
988         return button;
989 }
990
991
992 static gint
993 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
994                                           TnyFolderStore *suggested_parent,
995                                           const gchar *dialog_title,
996                                           const gchar *label_text,
997                                           const gchar *suggested_name,
998                                           gboolean show_name,
999                                           gboolean show_parent,
1000                                           gchar **folder_name,
1001                                           TnyFolderStore **parent)
1002 {
1003         GtkWidget *accept_btn = NULL;
1004         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
1005         GtkWidget *account_picker = NULL;
1006         GList *buttons = NULL;
1007         gint result;
1008         GtkSizeGroup *sizegroup;
1009         ModestFolderView *folder_view;
1010         ModestWindow *folder_window;
1011         ModestHildon2WindowMgr *window_mgr;
1012         FolderPickerHelper *helper = NULL;
1013         GtkWidget *top_vbox, *top_align;
1014
1015         window_mgr = (ModestHildon2WindowMgr *) modest_runtime_get_window_mgr ();
1016         folder_window = modest_hildon2_window_mgr_get_folder_window (window_mgr);
1017         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
1018         
1019         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
1020         
1021         top_vbox = gtk_vbox_new (FALSE, 0);
1022         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1023         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
1024         
1025         /* Ask the user for the folder name */
1026         dialog = gtk_dialog_new_with_buttons (dialog_title,
1027                                               parent_window,
1028                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
1029                                               _FM("ckdg_bd_new_folder_dialog_ok"),
1030                                               GTK_RESPONSE_ACCEPT,
1031                                               NULL);
1032
1033         /* Add accept button (with unsensitive handler) */
1034         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
1035         accept_btn = GTK_WIDGET (buttons->data);
1036
1037         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1038
1039         if (show_name) {
1040                 label_entry = gtk_label_new (label_text);
1041                 entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
1042                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
1043
1044                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
1045                 gtk_size_group_add_widget (sizegroup, label_entry);
1046                 
1047                 if (suggested_name)
1048                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
1049                 else
1050                         gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
1051                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
1052                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
1053                                                 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
1054                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
1055         }
1056         
1057         if (show_parent) {
1058           
1059                 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
1060
1061                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
1062                 gtk_size_group_add_widget (sizegroup, label_location);
1063
1064                 helper = g_slice_new0 (FolderPickerHelper);
1065                 helper->folder_view = folder_view;
1066                 helper->entry = (GtkEntry *) entry;
1067
1068                 account_picker = folder_picker_new (suggested_parent, helper);
1069         }
1070
1071         g_object_unref (sizegroup);
1072         
1073         /* Connect to the response method to avoid closing the dialog
1074            when an invalid name is selected*/
1075         g_signal_connect (dialog,
1076                           "response",
1077                           G_CALLBACK (on_response),
1078                           suggested_parent);
1079         
1080         if (show_name) {
1081                 /* Track entry changes */
1082                 g_signal_connect (entry,
1083                                   "insert-text",
1084                                   G_CALLBACK (entry_insert_text),
1085                                   dialog);
1086                 g_signal_connect (entry,
1087                                   "changed",
1088                                   G_CALLBACK (entry_changed),
1089                                   dialog);
1090         }
1091         
1092         
1093         /* Some locales like pt_BR need this to get the full window
1094            title shown */
1095         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
1096         
1097         /* Create the hbox */
1098         if (show_name) {
1099                 hbox = gtk_hbox_new (FALSE, 12);
1100                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
1101                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
1102                 
1103                 /* Add hbox to dialog */
1104                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1105                                     hbox, FALSE, FALSE, 0);
1106                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
1107         }
1108
1109         if (show_parent) {
1110                 hbox = gtk_hbox_new (FALSE, 12);
1111                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
1112                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
1113
1114                 /* Add hbox to dialog */
1115                 gtk_box_pack_start (GTK_BOX (top_vbox), 
1116                                     hbox, FALSE, FALSE, 0);
1117                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
1118         }
1119         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1120                                      GTK_WINDOW (dialog), parent_window);
1121
1122         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
1123         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
1124
1125         gtk_widget_show_all (GTK_WIDGET(dialog));
1126
1127         result = gtk_dialog_run (GTK_DIALOG(dialog));
1128         if (result == GTK_RESPONSE_ACCEPT) {
1129                 if (show_name)
1130                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1131                 if (show_parent) {
1132                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
1133                         if (*parent)
1134                                 g_object_ref (*parent);
1135                 }
1136         }
1137
1138         gtk_widget_destroy (dialog);
1139
1140         if (helper)
1141                 g_slice_free (FolderPickerHelper, helper);
1142
1143         while (gtk_events_pending ())
1144                 gtk_main_iteration ();
1145
1146         return result;
1147 }
1148
1149 gint
1150 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
1151                                        TnyFolderStore *suggested_folder,
1152                                        gchar *suggested_name,
1153                                        gchar **folder_name,
1154                                        TnyFolderStore **parent_folder)
1155 {
1156         gchar *real_suggested_name = NULL;
1157         gint result;
1158         ModestTnyAccountStore *acc_store;
1159         TnyAccount *account;
1160         gboolean do_free = FALSE;
1161
1162         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
1163                                                     suggested_folder);
1164
1165         /* In hildon 2.2 we always suggest the archive folder as parent */
1166         if (!suggested_folder) {
1167                 acc_store = modest_runtime_get_account_store ();
1168                 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
1169                 if (account) {
1170                         suggested_folder = (TnyFolderStore *)
1171                                 modest_tny_account_get_special_folder (account,
1172                                                                        TNY_FOLDER_TYPE_ARCHIVE);
1173                         g_object_unref (account);
1174                         account = NULL;
1175                 }
1176         }
1177
1178         /* If there is not archive folder then fallback to local folders account */
1179         if (!suggested_folder) {
1180                 do_free = TRUE;
1181                 suggested_folder = (TnyFolderStore *)
1182                         modest_tny_account_store_get_local_folders_account (acc_store);
1183         }
1184
1185         result = modest_platform_run_folder_common_dialog (parent_window,
1186                                                            suggested_folder,
1187                                                            _HL("ckdg_ti_new_folder"),
1188                                                            _FM("ckdg_fi_new_folder_name"),
1189                                                            real_suggested_name,
1190                                                            TRUE,
1191                                                            TRUE,
1192                                                            folder_name,
1193                                                            parent_folder);
1194
1195         if (do_free)
1196                 g_object_unref (suggested_folder);
1197
1198         g_free(real_suggested_name);
1199
1200         return result;
1201 }
1202
1203 gint
1204 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
1205                                           TnyFolderStore *parent_folder,
1206                                           const gchar *suggested_name,
1207                                           gchar **folder_name)
1208 {
1209         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
1210
1211         return modest_platform_run_folder_common_dialog (parent_window, 
1212                                                          parent_folder,
1213                                                          _HL("ckdg_ti_rename_folder"),
1214                                                          _HL("ckdg_fi_rename_name"),
1215                                                          suggested_name,
1216                                                          TRUE,
1217                                                          FALSE,
1218                                                          folder_name,
1219                                                          NULL);
1220 }
1221
1222
1223
1224 static void
1225 on_destroy_dialog (GtkWidget *dialog)
1226 {
1227         /* This could happen when the dialogs get programatically
1228            hidden or destroyed (for example when closing the
1229            application while a dialog is being shown) */
1230         if (!GTK_IS_WIDGET (dialog))
1231                 return;
1232
1233         gtk_widget_destroy (dialog);
1234
1235         if (gtk_events_pending ())
1236                 gtk_main_iteration ();
1237 }
1238
1239 gint
1240 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
1241                                          const gchar *message)
1242 {
1243         GtkWidget *dialog;
1244         gint response;
1245         
1246         dialog = hildon_note_new_confirmation (parent_window, message);
1247         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1248                                      GTK_WINDOW (dialog), parent_window);
1249
1250         response = gtk_dialog_run (GTK_DIALOG (dialog));
1251
1252         on_destroy_dialog (dialog);
1253
1254         return response;
1255 }
1256
1257 gint
1258 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1259                                                       const gchar *message,
1260                                                       const gchar *button_accept,
1261                                                       const gchar *button_cancel)
1262 {
1263         GtkWidget *dialog;
1264         gint response;
1265         
1266         dialog = hildon_note_new_confirmation_add_buttons (parent_window, message,
1267                                                            button_accept, GTK_RESPONSE_ACCEPT,
1268                                                            button_cancel, GTK_RESPONSE_CANCEL,
1269                                                            NULL);
1270
1271         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1272                                      GTK_WINDOW (dialog), parent_window);
1273
1274         response = gtk_dialog_run (GTK_DIALOG (dialog));
1275
1276         on_destroy_dialog (dialog);
1277
1278         return response;
1279 }
1280         
1281 void
1282 modest_platform_run_information_dialog (GtkWindow *parent_window,
1283                                         const gchar *message,
1284                                         gboolean block)
1285 {
1286         GtkWidget *note;
1287         
1288         note = hildon_note_new_information (parent_window, message);
1289         if (block)
1290                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1291                                              GTK_WINDOW (note), parent_window);
1292         
1293         if (block) {
1294                 gtk_dialog_run (GTK_DIALOG (note));
1295         
1296                 on_destroy_dialog (note);
1297         } else {
1298                 g_signal_connect_swapped (note,
1299                                           "response", 
1300                                           G_CALLBACK (on_destroy_dialog),
1301                                           note);
1302
1303                 gtk_widget_show_all (note);
1304         }
1305 }
1306
1307 typedef struct _ConnectAndWaitData {
1308         GMutex *mutex;
1309         GMainLoop *wait_loop;
1310         gboolean has_callback;
1311         gulong handler;
1312 } ConnectAndWaitData;
1313
1314
1315 static void
1316 quit_wait_loop (TnyAccount *account,
1317                 ConnectAndWaitData *data) 
1318 {
1319         /* Set the has_callback to TRUE (means that the callback was
1320            executed and wake up every code waiting for cond to be
1321            TRUE */
1322         g_mutex_lock (data->mutex);
1323         data->has_callback = TRUE;
1324         if (data->wait_loop)
1325                 g_main_loop_quit (data->wait_loop);
1326         g_mutex_unlock (data->mutex);
1327 }
1328
1329 static void
1330 on_connection_status_changed (TnyAccount *account, 
1331                               TnyConnectionStatus status,
1332                               gpointer user_data)
1333 {
1334         TnyConnectionStatus conn_status;
1335         ConnectAndWaitData *data;
1336                         
1337         /* Ignore if reconnecting or disconnected */
1338         conn_status = tny_account_get_connection_status (account);
1339         if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1340             conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1341                 return;
1342
1343         /* Remove the handler */
1344         data = (ConnectAndWaitData *) user_data;
1345         g_signal_handler_disconnect (account, data->handler);
1346
1347         /* Quit from wait loop */
1348         quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1349 }
1350
1351 static void
1352 on_tny_camel_account_set_online_cb (TnyCamelAccount *account, 
1353                                     gboolean canceled, 
1354                                     GError *err, 
1355                                     gpointer user_data)
1356 {
1357         /* Quit from wait loop */
1358         quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1359 }
1360
1361 gboolean 
1362 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1363                                   TnyAccount *account)
1364 {
1365         ConnectAndWaitData *data = NULL;
1366         gboolean device_online;
1367         TnyDevice *device;
1368         TnyConnectionStatus conn_status;
1369         gboolean user_requested;
1370         
1371         device = modest_runtime_get_device();
1372         device_online = tny_device_is_online (device);
1373
1374         /* Whether the connection is user requested or automatically
1375            requested, for example via D-Bus */
1376         user_requested = (parent_window) ? TRUE : FALSE;
1377
1378         /* If there is no account check only the device status */
1379         if (!account) {
1380                 if (device_online)
1381                         return TRUE;
1382                 else
1383                         return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1384                                                                NULL, user_requested);
1385         }
1386
1387         /* Return if the account is already connected */
1388         conn_status = tny_account_get_connection_status (account);
1389         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1390                 return TRUE;
1391
1392         /* Create the helper */
1393         data = g_slice_new0 (ConnectAndWaitData);
1394         data->mutex = g_mutex_new ();
1395         data->has_callback = FALSE;
1396
1397         /* Connect the device */
1398         if (!device_online) {
1399                 /* Track account connection status changes */
1400                 data->handler = g_signal_connect (account, "connection-status-changed",
1401                                                   G_CALLBACK (on_connection_status_changed),
1402                                                   data);
1403                 /* Try to connect the device */
1404                 device_online = tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), 
1405                                                                 NULL, user_requested);
1406
1407                 /* If the device connection failed then exit */
1408                 if (!device_online && data->handler)
1409                         goto frees;
1410         } else {
1411                 /* Force a reconnection of the account */
1412                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
1413                                               on_tny_camel_account_set_online_cb, data);
1414         }
1415
1416         /* Wait until the callback is executed */
1417         g_mutex_lock (data->mutex);
1418         if (!data->has_callback) {
1419                 data->wait_loop = g_main_loop_new (g_main_context_new (), FALSE);
1420                 gdk_threads_leave ();
1421                 g_mutex_unlock (data->mutex);
1422                 g_main_loop_run (data->wait_loop);
1423                 g_mutex_lock (data->mutex);
1424                 gdk_threads_enter ();
1425         }
1426         g_mutex_unlock (data->mutex);
1427
1428  frees:
1429         if (g_signal_handler_is_connected (account, data->handler))
1430                 g_signal_handler_disconnect (account, data->handler);
1431         g_mutex_free (data->mutex);
1432         g_main_loop_unref (data->wait_loop);
1433         g_slice_free (ConnectAndWaitData, data);
1434
1435         conn_status = tny_account_get_connection_status (account);
1436         return (conn_status == TNY_CONNECTION_STATUS_CONNECTED) ? TRUE: FALSE;
1437 }
1438
1439 gboolean 
1440 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1441 {
1442         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1443                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1444                         /* This must be a maildir account, which does not require a connection: */
1445                         return TRUE;
1446                 }
1447         }
1448
1449         return modest_platform_connect_and_wait (parent_window, account);
1450 }
1451
1452 gboolean 
1453 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1454 {
1455         if (!folder_store)
1456                 return TRUE; /* Maybe it is something local. */
1457                 
1458         gboolean result = TRUE;
1459         if (TNY_IS_FOLDER (folder_store)) {
1460                 /* Get the folder's parent account: */
1461                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1462                 if (account != NULL) {
1463                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1464                         g_object_unref (account);
1465                 }
1466         } else if (TNY_IS_ACCOUNT (folder_store)) {
1467                 /* Use the folder store as an account: */
1468                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1469         }
1470
1471         return result;
1472 }
1473
1474 GtkWidget *
1475 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1476 {
1477         GtkWidget *dialog;
1478
1479         dialog = modest_hildon2_sort_dialog_new (parent_window);
1480
1481         return dialog;
1482 }
1483
1484
1485 gboolean 
1486 modest_platform_set_update_interval (guint minutes)
1487 {
1488 #ifdef MODEST_HAVE_LIBALARM
1489
1490         cookie_t alarm_cookie, *alarm_cookies;
1491         ModestConf *conf = modest_runtime_get_conf ();
1492         if (!conf)
1493                 return FALSE;
1494
1495         if (minutes > 0) {
1496                 GSList *acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1497                 if (!acc_names) {
1498                         minutes = 0;
1499                 } else {
1500                         modest_account_mgr_free_account_names (acc_names);
1501                 }
1502         }
1503
1504         /* cookie_t alarm_cookie = modest_conf_get_int (conf, MODEST_CONF_ALARM_ID, NULL); */
1505
1506         /* Delete any existing alarm, because we will replace it: */
1507         alarm_cookies = alarmd_event_query (0,0, 0,0, MODEST_ALARMD_APPID);
1508         if (alarm_cookies) {
1509                 /* alarmd_event_query returns a zero terminated array */
1510                 for (; *alarm_cookies != 0; alarm_cookies++) {
1511                         alarmd_event_del (*alarm_cookies);
1512                 }
1513                 modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, 0, NULL);
1514         }
1515
1516         /* 0 means no updates: */
1517         if (minutes == 0)
1518                 return TRUE;
1519
1520         /* Register alarm: */
1521
1522         /* Set the interval in alarm_event_t structure: */
1523         alarm_event_t *event = alarm_event_create ();
1524         alarm_event_add_actions (event, 1);
1525         alarm_action_t *action = alarm_event_get_action (event, 0);
1526         alarm_event_set_alarm_appid (event, MODEST_ALARMD_APPID);
1527         event->alarm_time = minutes * 60; /* seconds */
1528
1529         /* Set recurrence every few minutes: */
1530         event->recur_secs = minutes*60;
1531         event->recur_count = -1; /* Means infinite */
1532
1533         /* Specify what should happen when the alarm happens:
1534          * It should call this D-Bus method: */
1535
1536         action->dbus_path = g_strdup(MODEST_DBUS_OBJECT);
1537         action->dbus_interface = g_strdup (MODEST_DBUS_IFACE);
1538         action->dbus_service = g_strdup (MODEST_DBUS_SERVICE);
1539         action->dbus_name = g_strdup (MODEST_DBUS_METHOD_SEND_RECEIVE);
1540         action->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_TYPE_DBUS | ALARM_ACTION_DBUS_USE_ACTIVATION;
1541
1542         /* Use ALARM_EVENT_NO_DIALOG: Otherwise, a dialog will be shown if 
1543          * exec_name or dbus_path is NULL, even though we have specified no dialog text.
1544          * Also use ALARM_EVENT_ACTIVATION so that modest is started (without UI) to get emails 
1545          * This is why we want to use the Alarm API instead of just g_timeout_add().
1546          * (The old maemo email-client did this, though it isn't specified in the UI spec.)
1547          * ALARM_EVENT_CONNECTED will prevent the alarm from being called in case that the device is offline
1548          */
1549         event->flags = ALARM_EVENT_CONNECTED | ALARM_EVENT_RUN_DELAYED;
1550
1551         alarm_cookie = alarmd_event_add (event);
1552
1553         /* now, free it */
1554         alarm_event_delete (event);
1555
1556         /* Store the alarm ID in GConf, so we can remove it later:
1557          * This is apparently valid between application instances. */
1558         modest_conf_set_int (conf, MODEST_CONF_ALARM_ID, alarm_cookie, NULL);
1559
1560         if (!alarm_cookie) {
1561             /* Error */
1562             g_warning ("Error setting alarm event. \n");
1563
1564             return FALSE;
1565         }
1566 #endif /* MODEST_HAVE_LIBALARM */
1567         return TRUE;
1568 }
1569
1570 void
1571 modest_platform_push_email_notification(void)
1572 {
1573         gboolean screen_on, app_in_foreground;
1574
1575         /* Get the window status */
1576         app_in_foreground = hildon_program_get_is_topmost (hildon_program_get_instance ());
1577
1578         screen_on = modest_window_mgr_screen_is_on (modest_runtime_get_window_mgr ());
1579
1580         /* If the screen is on and the app is in the
1581            foreground we don't show anything */
1582         if (!(screen_on && app_in_foreground)) {
1583
1584                 modest_platform_play_email_tone ();
1585
1586                 /* Activate LED. This must be deactivated by
1587                    modest_platform_remove_new_mail_notifications */
1588 #ifdef MODEST_HAVE_MCE
1589                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1590                                      MCE_SERVICE,
1591                                      MCE_REQUEST_PATH,
1592                                      MCE_REQUEST_IF,
1593                                      MCE_ACTIVATE_LED_PATTERN,
1594                                      NULL,
1595                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1596                                      DBUS_TYPE_INVALID);
1597 #endif
1598         }
1599 }
1600
1601 void
1602 modest_platform_on_new_headers_received (GList *URI_list,
1603                                          gboolean show_visual)
1604 {
1605         if (g_list_length (URI_list) == 0)
1606                 return;
1607
1608 #ifdef MODEST_HAVE_HILDON_NOTIFY
1609         /* For any other case issue a notification */
1610         HildonNotification *notification;
1611         ModestMsgNotificationData *data;
1612         gint notif_id;
1613         gchar *from;
1614         TnyAccountStore *acc_store;
1615         TnyAccount *account;
1616
1617         data = (ModestMsgNotificationData *) URI_list->data;
1618
1619         /* String is changed in-place. There is no need to
1620            actually dup the data->from string but we just do
1621            it in order not to modify the original contents */
1622         from = g_strdup (data->from);
1623         modest_text_utils_get_display_address (from);
1624
1625         /* Create notification */
1626         notification = hildon_notification_new (from,
1627                                                 data->subject,
1628                                                 "qgn_list_messagin",
1629                                                 MODEST_NOTIFICATION_CATEGORY);
1630         g_free (from);
1631
1632         /* Add DBus action */
1633         hildon_notification_add_dbus_action(notification,
1634                                             "default",
1635                                             "Cancel",
1636                                             MODEST_DBUS_SERVICE,
1637                                             MODEST_DBUS_OBJECT,
1638                                             MODEST_DBUS_IFACE,
1639                                             MODEST_DBUS_METHOD_OPEN_MESSAGE,
1640                                             G_TYPE_STRING, data->uri,
1641                                             -1);
1642
1643         /* Set the led pattern */
1644         if (data->time)
1645                 notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1646                                                     "time", data->time);
1647
1648         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1649                                             "dialog-type", 4);
1650         notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1651                                             "led-pattern",
1652                                             MODEST_NEW_MAIL_LIGHTING_PATTERN);
1653
1654         /* Make the notification persistent */
1655         notify_notification_set_hint_byte (NOTIFY_NOTIFICATION (notification),
1656                                            "persistent", TRUE);
1657
1658         /* Set the number of new notifications */
1659         notify_notification_set_hint_int32 (NOTIFY_NOTIFICATION (notification),
1660                                             "amount", g_list_length (URI_list));
1661
1662         /* Set the account of the headers */
1663         acc_store = (TnyAccountStore *) modest_runtime_get_account_store ();
1664         account = tny_account_store_find_account (acc_store, data->uri);
1665         if (account) {
1666                 const gchar *acc_name;
1667                 acc_name =
1668                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1669                 notify_notification_set_hint_string(NOTIFY_NOTIFICATION (notification),
1670                                                     "email-account",
1671                                                     acc_name);
1672                 g_object_unref (account);
1673         }
1674
1675         if (notify_notification_show (NOTIFY_NOTIFICATION (notification), NULL)) {
1676                 GSList *notifications_list = NULL;
1677
1678                 /* Get previous notifications ids */
1679                 notifications_list = modest_conf_get_list (modest_runtime_get_conf (),
1680                                                            MODEST_CONF_NOTIFICATION_IDS,
1681                                                            MODEST_CONF_VALUE_INT, NULL);
1682
1683                 /* Save id in the list */
1684                 g_object_get(G_OBJECT (notification), "id", &notif_id, NULL);
1685                 notifications_list = g_slist_prepend (notifications_list, GINT_TO_POINTER(notif_id));
1686
1687                 /* We don't listen for the "closed" signal, because we
1688                    don't care about if the notification was removed or
1689                    not to store the list in gconf */
1690
1691                 /* Save the ids */
1692                 modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS,
1693                                       notifications_list, MODEST_CONF_VALUE_INT, NULL);
1694
1695                 g_slist_free (notifications_list);
1696         } else {
1697                 g_warning ("Failed to send notification");
1698         }
1699
1700 #endif /*MODEST_HAVE_HILDON_NOTIFY*/
1701 }
1702
1703 void
1704 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1705 {
1706         if (only_visuals) {
1707 #ifdef MODEST_HAVE_MCE
1708                 osso_rpc_run_system (modest_maemo_utils_get_osso_context (),
1709                                      MCE_SERVICE,
1710                                      MCE_REQUEST_PATH,
1711                                      MCE_REQUEST_IF,
1712                                      MCE_DEACTIVATE_LED_PATTERN,
1713                                      NULL,
1714                                      DBUS_TYPE_STRING, MODEST_NEW_MAIL_LIGHTING_PATTERN,
1715                                      DBUS_TYPE_INVALID);
1716 #endif
1717                 return;
1718         }
1719
1720 #ifdef MODEST_HAVE_HILDON_NOTIFY
1721         GSList *notif_list = NULL;
1722
1723         /* Get previous notifications ids */
1724         notif_list = modest_conf_get_list (modest_runtime_get_conf (), 
1725                                            MODEST_CONF_NOTIFICATION_IDS, 
1726                                            MODEST_CONF_VALUE_INT, NULL);
1727
1728         while (notif_list) {
1729                 gint notif_id;
1730                 NotifyNotification *notif;
1731
1732                 /* Nasty HACK to remove the notifications, set the id
1733                    of the existing ones and then close them */
1734                 notif_id = GPOINTER_TO_INT(notif_list->data);
1735                 notif = notify_notification_new("dummy", NULL, NULL, NULL);
1736                 g_object_set(G_OBJECT(notif), "id", notif_id, NULL);
1737
1738                 /* Close the notification, note that some ids could be
1739                    already invalid, but we don't care because it does
1740                    not fail */
1741                 notify_notification_close(notif, NULL);
1742                 g_object_unref(notif);
1743
1744                 /* Delete the link, it's like going to the next */
1745                 notif_list = g_slist_delete_link (notif_list, notif_list);
1746         }
1747
1748         /* Save the ids */
1749         modest_conf_set_list (modest_runtime_get_conf (), MODEST_CONF_NOTIFICATION_IDS, 
1750                               notif_list, MODEST_CONF_VALUE_INT, NULL);
1751
1752         g_slist_free (notif_list);
1753
1754 #endif /* MODEST_HAVE_HILDON_NOTIFY */
1755 }
1756
1757
1758
1759 GtkWidget * 
1760 modest_platform_get_global_settings_dialog ()
1761 {
1762         return modest_hildon2_global_settings_dialog_new ();
1763 }
1764
1765 void
1766 modest_platform_show_help (GtkWindow *parent_window, 
1767                            const gchar *help_id)
1768 {
1769         return;
1770 }
1771
1772 void 
1773 modest_platform_show_search_messages (GtkWindow *parent_window)
1774 {
1775         osso_return_t result = OSSO_ERROR;
1776         
1777         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1778                                              "osso_global_search",
1779                                              "search_email", NULL, DBUS_TYPE_INVALID);
1780
1781         if (result != OSSO_OK) {
1782                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1783         }
1784 }
1785
1786 void 
1787 modest_platform_show_addressbook (GtkWindow *parent_window)
1788 {
1789         osso_return_t result = OSSO_ERROR;
1790
1791         result = osso_rpc_run_with_defaults (modest_maemo_utils_get_osso_context(),
1792                                              "osso_addressbook",
1793                                              "top_application", NULL, DBUS_TYPE_INVALID);
1794
1795         if (result != OSSO_OK) {
1796                 g_warning ("%s: osso_rpc_run_with_defaults() failed.\n", __FUNCTION__);
1797         }
1798 }
1799
1800 static GtkWidget *
1801 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1802 {
1803         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1804
1805         /* Show one account by default */
1806         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1807                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1808
1809         return widget;
1810 }
1811
1812 GtkWidget *
1813 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1814 {
1815         return modest_platform_create_folder_view_full (query, TRUE);
1816 }
1817
1818 void
1819 banner_finish (gpointer data, GObject *object)
1820 {
1821         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1822         modest_window_mgr_unregister_banner (mgr);
1823         g_object_unref (mgr);
1824 }
1825
1826 void 
1827 modest_platform_information_banner (GtkWidget *parent,
1828                                     const gchar *icon_name,
1829                                     const gchar *text)
1830 {
1831         GtkWidget *banner_parent = NULL;
1832         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1833
1834         if (modest_window_mgr_get_num_windows (mgr) == 0)
1835                 return;
1836
1837         if (parent && GTK_IS_WINDOW (parent)) {
1838                 /* If the window is the active one then show the
1839                    banner on top of this window */
1840                 if (gtk_window_is_active (GTK_WINDOW (parent)))
1841                         banner_parent = parent;
1842                 /* If the window is not the topmost but it's visible
1843                    (it's minimized for example) then show the banner
1844                    with no parent */ 
1845                 else if (GTK_WIDGET_VISIBLE (parent))
1846                         banner_parent = NULL;
1847                 /* If the window is hidden (like the main window when
1848                    running in the background) then do not show
1849                    anything */
1850                 else 
1851                         return;
1852         }
1853
1854         modest_platform_system_banner (banner_parent, icon_name, text);
1855 }
1856
1857 void 
1858 modest_platform_system_banner (GtkWidget *parent,
1859                                const gchar *icon_name,
1860                                const gchar *text)
1861 {
1862         GtkWidget *banner = NULL;
1863         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1864
1865         if (parent && GTK_IS_WINDOW (parent)) {
1866                 if (!gtk_window_is_active (GTK_WINDOW (parent)))
1867                         parent = NULL;
1868         }
1869
1870         banner = hildon_banner_show_information (parent, icon_name, text);
1871
1872         modest_window_mgr_register_banner (mgr);
1873         g_object_ref (mgr);
1874         g_object_weak_ref ((GObject *) banner, banner_finish, mgr);
1875 }
1876
1877 void
1878 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1879                                                  const gchar *icon_name,
1880                                                  const gchar *text,
1881                                                  gint timeout)
1882 {
1883         GtkWidget *banner;
1884
1885         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1886                 return;
1887
1888         banner = hildon_banner_show_information (parent, icon_name, text);
1889         hildon_banner_set_timeout(HILDON_BANNER(banner), timeout);
1890 }
1891
1892 GtkWidget *
1893 modest_platform_animation_banner (GtkWidget *parent,
1894                                   const gchar *animation_name,
1895                                   const gchar *text)
1896 {
1897         GtkWidget *inf_note = NULL;
1898
1899         g_return_val_if_fail (text != NULL, NULL);
1900
1901         if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0)
1902                 return NULL;
1903
1904         /* If the parent is not visible then do not show */
1905         if (parent && !GTK_WIDGET_VISIBLE (parent))
1906                 return NULL;
1907
1908         inf_note = hildon_banner_show_animation (parent, animation_name, text);
1909
1910         return inf_note;
1911 }
1912
1913 typedef struct
1914 {
1915         GMainLoop* loop;
1916         TnyAccount *account;
1917         gboolean is_online;
1918         gint count_tries;
1919 } CheckAccountIdleData;
1920
1921 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1922
1923 static gboolean 
1924 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1925 {
1926         gboolean stop_trying = FALSE;
1927         g_return_val_if_fail (data && data->account, FALSE);
1928         
1929         printf ("DEBUG: %s: tny_account_get_connection_status()==%d\n", __FUNCTION__,
1930                 tny_account_get_connection_status (data->account));     
1931         
1932         if (data && data->account && 
1933                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1934                  * after which the account is likely to be usable, or never likely to be usable soon: */
1935                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1936         {
1937                 data->is_online = TRUE;
1938                 
1939                 stop_trying = TRUE;
1940         } else {
1941                 /* Give up if we have tried too many times: */
1942                 if (data->count_tries >= NUMBER_OF_TRIES) {
1943                         stop_trying = TRUE;
1944                 } else {
1945                         /* Wait for another timeout: */
1946                         ++(data->count_tries);
1947                 }
1948         }
1949         
1950         if (stop_trying) {
1951                 /* Allow the function that requested this idle callback to continue: */
1952                 if (data->loop)
1953                         g_main_loop_quit (data->loop);
1954                         
1955                 if (data->account)
1956                         g_object_unref (data->account);
1957                 
1958                 return FALSE; /* Don't call this again. */
1959         } else {
1960                 return TRUE; /* Call this timeout callback again. */
1961         }
1962 }
1963
1964 /* Return TRUE immediately if the account is already online,
1965  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1966  * soon as the account is online, or FALSE if the account does 
1967  * not become online in the NUMBER_OF_TRIES seconds.
1968  * This is useful when the D-Bus method was run immediately after 
1969  * the application was started (when using D-Bus activation), 
1970  * because the account usually takes a short time to go online.
1971  * The return value is maybe not very useful.
1972  */
1973 gboolean
1974 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1975 {
1976         gboolean is_online;
1977
1978         g_return_val_if_fail (account, FALSE);
1979
1980         if (!tny_device_is_online (modest_runtime_get_device())) {
1981                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1982                 return FALSE;
1983         }
1984
1985         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1986          * so we avoid wait unnecessarily: */
1987         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1988                 return TRUE;
1989
1990         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1991          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1992          * we want to avoid. */
1993         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1994                 return TRUE;
1995                 
1996         /* This blocks on the result: */
1997         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1998         data->is_online = FALSE;
1999         data->account = account;
2000         g_object_ref (data->account);
2001         data->count_tries = 0;
2002                 
2003         GMainContext *context = NULL; /* g_main_context_new (); */
2004         data->loop = g_main_loop_new (context, FALSE /* not running */);
2005
2006         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
2007
2008         /* This main loop will run until the idle handler has stopped it: */
2009         g_main_loop_run (data->loop);
2010
2011         g_main_loop_unref (data->loop);
2012         /* g_main_context_unref (context); */
2013
2014         is_online = data->is_online;
2015         g_slice_free (CheckAccountIdleData, data);
2016         
2017         return is_online;       
2018 }
2019
2020
2021
2022 static void
2023 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
2024 {
2025         /* GTK_RESPONSE_HELP means we need to show the certificate */
2026         if (response_id == GTK_RESPONSE_APPLY) {
2027                 GtkWidget *note;
2028                 gchar *msg;
2029                 
2030                 /* Do not close the dialog */
2031                 g_signal_stop_emission_by_name (dialog, "response");
2032
2033                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
2034                 note = hildon_note_new_information (NULL, msg);
2035                 gtk_dialog_run (GTK_DIALOG(note));
2036                 gtk_widget_destroy (note);
2037         }
2038 }
2039
2040
2041 gboolean
2042 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
2043                                                      const gchar *certificate)
2044 {
2045         GtkWidget *note;
2046         gint response;
2047         ModestWindow *win;
2048         HildonWindowStack *stack;
2049
2050         stack = hildon_window_stack_get_default ();
2051         win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2052
2053         if (!win) {
2054                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2055                          __FUNCTION__);
2056                 return FALSE;
2057         }
2058
2059         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
2060                                            server_name);
2061
2062         /* We use GTK_RESPONSE_APPLY because we want the button in the
2063            middle of OK and CANCEL the same as the browser does for
2064            example. With GTK_RESPONSE_HELP the view button is aligned
2065            to the left while the other two to the right */
2066         note = hildon_note_new_confirmation_add_buttons  (
2067                 (GtkWindow *) win,
2068                 question,
2069                 _HL("wdgt_bd_yes"),     GTK_RESPONSE_OK,
2070                 _HL("wdgt_bd_view"),          GTK_RESPONSE_APPLY,   /* abusing this... */
2071                 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
2072                 NULL, NULL);
2073
2074         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2075                                      (GtkWindow *) note, (GtkWindow *) win);
2076
2077         g_signal_connect (G_OBJECT(note), "response",
2078                           G_CALLBACK(on_cert_dialog_response),
2079                           (gpointer) certificate);
2080
2081         response = gtk_dialog_run(GTK_DIALOG(note));
2082
2083         on_destroy_dialog (note);
2084         g_free (question);
2085
2086         return response == GTK_RESPONSE_OK;
2087 }
2088
2089 gboolean
2090 modest_platform_run_alert_dialog (const gchar* prompt,
2091                                   gboolean is_question)
2092 {
2093         ModestWindow *top_win;
2094         HildonWindowStack *stack;
2095
2096         stack = hildon_window_stack_get_default ();
2097         top_win = MODEST_WINDOW (hildon_window_stack_peek (stack));
2098
2099         if (!top_win) {
2100                 g_debug ("%s: don't show dialogs if there's no window shown; assuming 'Cancel'",
2101                          __FUNCTION__);
2102                 return FALSE;
2103         }
2104
2105         gboolean retval = TRUE;
2106         if (is_question) {
2107                 /* The Tinymail documentation says that we should show Yes and No buttons,
2108                  * when it is a question.
2109                  * Obviously, we need tinymail to use more specific error codes instead,
2110                  * so we know what buttons to show. */
2111                 GtkWidget *dialog = GTK_WIDGET (hildon_note_new_confirmation (GTK_WINDOW (top_win), 
2112                                                                               prompt));
2113                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2114                                              GTK_WINDOW (dialog), GTK_WINDOW (top_win));
2115
2116                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
2117                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
2118
2119                 on_destroy_dialog (dialog);
2120         } else {
2121                 /* Just show the error text and use the default response: */
2122                 modest_platform_run_information_dialog (GTK_WINDOW (top_win), 
2123                                                         prompt, FALSE);
2124         }
2125         return retval;
2126 }
2127
2128 /***************/
2129 typedef struct {
2130         GtkWindow *parent_window;
2131         ModestConnectedPerformer callback;
2132         TnyAccount *account;
2133         gpointer user_data;
2134         gchar *iap;
2135         TnyDevice *device;
2136 } OnWentOnlineInfo;
2137  
2138 static void 
2139 on_went_online_info_free (OnWentOnlineInfo *info)
2140 {
2141         /* And if we cleanup, we DO cleanup  :-)  */
2142         
2143         if (info->device)
2144                 g_object_unref (info->device);
2145         if (info->iap)
2146                 g_free (info->iap);
2147         if (info->parent_window)
2148                 g_object_unref (info->parent_window);
2149         if (info->account)
2150                 g_object_unref (info->account);
2151         
2152         g_slice_free (OnWentOnlineInfo, info);
2153         
2154         /* We're done ... */
2155         
2156         return;
2157 }
2158  
2159 static void
2160 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
2161 {
2162         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2163  
2164         /* Now it's really time to callback to the caller. If going online didn't succeed,
2165          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
2166          * canceled will be set. Etcetera etcetera. */
2167         
2168         if (info->callback) {
2169                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2170         }
2171         
2172         /* This is our last call, we must cleanup here if we didn't yet do that */
2173         on_went_online_info_free (info);
2174         
2175         return;
2176 }
2177  
2178  
2179 static void
2180 on_conic_device_went_online (TnyMaemoConicDevice *device, const gchar* iap_id, gboolean canceled, GError *err, gpointer user_data)
2181 {
2182         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
2183         info->iap = g_strdup (iap_id);
2184         
2185         if (canceled || err || !info->account) {
2186         
2187                 /* If there's a problem or if there's no account (then that's it for us, we callback
2188                  * the caller's callback now. He'll have to handle err or canceled, of course.
2189                  * We are not really online, as the account is not really online here ... */    
2190                 
2191                 /* We'll use the err and the canceled of this cb. TnyMaemoConicDevice delivered us
2192                  * this info. We don't cleanup err, Tinymail does that! */
2193                 
2194                 if (info->callback) {
2195                         
2196                         /* info->account can be NULL here, this means that the user did not
2197                          * provide a nice account instance. We'll assume that the user knows
2198                          * what he's doing and is happy with just the device going online. 
2199                          * 
2200                          * We can't do magic, we don't know what account the user wants to
2201                          * see going online. So just the device goes online, end of story */
2202                         
2203                         info->callback (canceled, err, info->parent_window, info->account, info->user_data);
2204                 }
2205                 
2206         } else if (info->account) {
2207                 
2208                 /* If there's no problem and if we have an account, we'll put the account
2209                  * online too. When done, the callback of bringing the account online
2210                  * will callback the caller's callback. This is the most normal case. */
2211  
2212                 info->device = TNY_DEVICE (g_object_ref (device));
2213                 
2214                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (info->account), TRUE,
2215                                               on_account_went_online, info);
2216                 
2217                 /* The on_account_went_online cb frees up the info, go look if you
2218                  * don't believe me! (so we return here) */
2219                 
2220                 return;
2221         }
2222         
2223         /* We cleanup if we are not bringing the account online too */
2224         on_went_online_info_free (info);
2225  
2226         return; 
2227 }
2228         
2229 void 
2230 modest_platform_connect_and_perform (GtkWindow *parent_window, 
2231                                      gboolean force,
2232                                      TnyAccount *account, 
2233                                      ModestConnectedPerformer callback, 
2234                                      gpointer user_data)
2235 {
2236         gboolean device_online;
2237         TnyDevice *device;
2238         TnyConnectionStatus conn_status;
2239         OnWentOnlineInfo *info;
2240         
2241         device = modest_runtime_get_device();
2242         device_online = tny_device_is_online (device);
2243
2244         /* If there is no account check only the device status */
2245         if (!account) {
2246                 
2247                 if (device_online) {
2248  
2249                         /* We promise to instantly perform the callback, so ... */
2250                         if (callback) {
2251                                 callback (FALSE, NULL, parent_window, account, user_data);
2252                         }
2253                         
2254                 } else {
2255                         
2256                         info = g_slice_new0 (OnWentOnlineInfo);
2257                         
2258                         info->iap = NULL;
2259                         info->device = NULL;
2260                         info->account = NULL;
2261                 
2262                         if (parent_window)
2263                                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2264                         else
2265                                 info->parent_window = NULL;
2266                         info->user_data = user_data;
2267                         info->callback = callback;
2268                 
2269                         tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2270                                                               force, on_conic_device_went_online, 
2271                                                               info);
2272  
2273                         /* We'll cleanup in on_conic_device_went_online */
2274                 }
2275  
2276                 /* The other code has no more reason to run. This is all that we can do for the
2277                  * caller (he should have given us a nice and clean account instance!). We
2278                  * can't do magic, we don't know what account he intends to bring online. So
2279                  * we'll just bring the device online (and await his false bug report). */
2280                 
2281                 return;
2282         }
2283  
2284         
2285         /* Return if the account is already connected */
2286         
2287         conn_status = tny_account_get_connection_status (account);
2288         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
2289  
2290                 /* We promise to instantly perform the callback, so ... */
2291                 if (callback) {
2292                         callback (FALSE, NULL, parent_window, account, user_data);
2293                 }
2294                 
2295                 return;
2296         }
2297         
2298         /* Else, we are in a state that requires that we go online before we
2299          * call the caller's callback. */
2300         
2301         info = g_slice_new0 (OnWentOnlineInfo);
2302         
2303         info->device = NULL;
2304         info->iap = NULL;
2305         info->account = TNY_ACCOUNT (g_object_ref (account));
2306         
2307         if (parent_window)
2308                 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
2309         else
2310                 info->parent_window = NULL;
2311         
2312         /* So we'll put the callback away for later ... */
2313         
2314         info->user_data = user_data;
2315         info->callback = callback;
2316         
2317         if (!device_online) {
2318  
2319                 /* If also the device is offline, then we connect both the device 
2320                  * and the account */
2321                 
2322                 tny_maemo_conic_device_connect_async (TNY_MAEMO_CONIC_DEVICE (device), NULL,
2323                                                       force, on_conic_device_went_online, 
2324                                                       info);
2325                 
2326         } else {
2327                 
2328                 /* If the device is online, we'll just connect the account */
2329                 
2330                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE, 
2331                                               on_account_went_online, info);
2332         }
2333  
2334         /* The info gets freed by on_account_went_online or on_conic_device_went_online
2335          * in both situations, go look if you don't believe me! */
2336         
2337         return;
2338 }
2339
2340 void
2341 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window, 
2342                                                gboolean force,
2343                                                TnyFolderStore *folder_store, 
2344                                                ModestConnectedPerformer callback, 
2345                                                gpointer user_data)
2346 {
2347         TnyAccount *account = NULL;
2348
2349         if (!folder_store ||
2350             (TNY_IS_MERGE_FOLDER (folder_store) &&
2351              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
2352
2353                 /* We promise to instantly perform the callback, so ... */
2354                 if (callback) {
2355                         GError *error = NULL;
2356                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
2357                                      "Unable to move or not found folder");
2358                         callback (FALSE, error, parent_window, NULL, user_data);
2359                         g_error_free (error);
2360                 }
2361                 return;
2362
2363         } else if (TNY_IS_FOLDER (folder_store)) {
2364                 /* Get the folder's parent account: */
2365                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2366         } else if (TNY_IS_ACCOUNT (folder_store)) {
2367                 /* Use the folder store as an account: */
2368                 account = TNY_ACCOUNT (g_object_ref (folder_store));
2369         }
2370
2371         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
2372                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2373                         /* No need to connect a local account */
2374                         if (callback)
2375                                 callback (FALSE, NULL, parent_window, account, user_data);
2376
2377                         goto clean;
2378                 }
2379         }
2380         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
2381
2382  clean:
2383         if (account)
2384                 g_object_unref (account);
2385 }
2386
2387 static void
2388 src_account_connect_performer (gboolean canceled,
2389                                GError *err,
2390                                GtkWindow *parent_window,
2391                                TnyAccount *src_account,
2392                                gpointer user_data)
2393 {
2394         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
2395
2396         if (canceled || err) {
2397                 /* If there was any error call the user callback */
2398                 info->callback (canceled, err, parent_window, src_account, info->data);
2399         } else {
2400                 /* Connect the destination account */
2401                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
2402                                                                TNY_FOLDER_STORE (info->dst_account),
2403                                                                info->callback, info->data);
2404         }
2405
2406         /* Free the info object */
2407         g_object_unref (info->dst_account);
2408         g_slice_free (DoubleConnectionInfo, info);
2409 }
2410
2411
2412 void 
2413 modest_platform_double_connect_and_perform (GtkWindow *parent_window, 
2414                                             gboolean force,
2415                                             TnyFolderStore *folder_store,
2416                                             DoubleConnectionInfo *connect_info)
2417 {
2418         modest_platform_connect_if_remote_and_perform(parent_window, 
2419                                                       force,
2420                                                       folder_store, 
2421                                                       src_account_connect_performer, 
2422                                                       connect_info);
2423 }
2424
2425 GtkWidget *
2426 modest_platform_get_account_settings_wizard (void)
2427 {
2428         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
2429
2430         return GTK_WIDGET (dialog);
2431 }
2432
2433 ModestConnectedVia
2434 modest_platform_get_current_connection (void)
2435 {
2436         TnyDevice *device = NULL;
2437         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
2438         
2439         device = modest_runtime_get_device ();
2440
2441         if (!tny_device_is_online (device))
2442                 return MODEST_CONNECTED_VIA_ANY;
2443
2444 #ifdef MODEST_HAVE_CONIC
2445         /* Get iap id */
2446         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
2447         if (iap_id) {
2448                 ConIcIap *iap = tny_maemo_conic_device_get_iap (
2449                         TNY_MAEMO_CONIC_DEVICE (device), iap_id);
2450                 const gchar *bearer_type = con_ic_iap_get_bearer_type (iap);
2451                 if (bearer_type) {
2452                         if (!strcmp (bearer_type, CON_IC_BEARER_WLAN_INFRA) ||
2453                             !strcmp (bearer_type, CON_IC_BEARER_WLAN_ADHOC) ||
2454                             !strcmp (bearer_type, "WIMAX")) {
2455                                 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX;
2456                         } else {
2457                                 retval = MODEST_CONNECTED_VIA_ANY;
2458                         }
2459                 }       
2460                 g_object_unref (iap);
2461         }
2462 #else
2463         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
2464 #endif /* MODEST_HAVE_CONIC */
2465         return retval;
2466 }
2467
2468
2469
2470 gboolean
2471 modest_platform_check_memory_low (ModestWindow *win,
2472                                   gboolean visuals)
2473 {
2474         gboolean lowmem;
2475         
2476         /* are we in low memory state? */
2477         lowmem = osso_mem_in_lowmem_state () ? TRUE : FALSE;
2478         
2479         if (win && lowmem && visuals)
2480                 modest_platform_run_information_dialog (
2481                         GTK_WINDOW(win),
2482                         _KR("memr_ib_operation_disabled"),
2483                         TRUE);
2484
2485         if (lowmem)
2486                 g_debug ("%s: low memory reached. disallowing some operations",
2487                          __FUNCTION__);
2488
2489         return lowmem;
2490 }
2491
2492 void 
2493 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
2494                                            TnyFolder *folder)
2495 {
2496         GtkWidget *dialog;
2497         
2498         /* Create dialog */
2499         dialog = modest_hildon2_details_dialog_new_with_folder (parent_window, folder);
2500
2501         /* Run dialog */
2502         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2503                                      GTK_WINDOW (dialog), 
2504                                      parent_window);
2505         gtk_widget_show_all (dialog);
2506
2507         g_signal_connect_swapped (dialog, "response", 
2508                                   G_CALLBACK (gtk_widget_destroy),
2509                                   dialog);
2510 }
2511
2512 typedef struct _HeaderDetailsGetSizeInfo {
2513         GtkWidget *dialog;
2514         TnyMimePart *part;
2515         guint total;
2516 } HeaderDetailsGetSizeInfo;
2517
2518 static void 
2519 header_details_dialog_destroy (gpointer userdata,
2520                                GObject *object)
2521 {
2522         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2523
2524         info->dialog = NULL;
2525 }
2526
2527 static gboolean
2528 idle_get_mime_part_size_cb (gpointer userdata)
2529 {
2530         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
2531         gdk_threads_enter ();
2532
2533         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
2534                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
2535                                                         info->total);
2536         }
2537
2538         if (info->dialog) {
2539                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
2540                 info->dialog = NULL;
2541         }
2542         g_object_unref (info->part);
2543         g_slice_free (HeaderDetailsGetSizeInfo, info);
2544
2545         gdk_threads_leave ();
2546
2547         return FALSE;
2548 }
2549
2550 static gpointer
2551 get_mime_part_size_thread (gpointer thr_user_data)
2552 {
2553         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
2554         gssize result = 0;
2555         TnyStream *count_stream;
2556
2557         count_stream = modest_count_stream_new ();
2558         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
2559         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2560         if (info->total == 0) {
2561                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
2562                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
2563                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
2564         }
2565         
2566         /* if there was an error, don't set the size (this is pretty uncommon) */
2567         if (result < 0) {
2568                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
2569         }
2570         g_idle_add (idle_get_mime_part_size_cb, info);
2571
2572         return NULL;
2573 }
2574
2575 void
2576 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
2577                                            TnyHeader *header,
2578                                            gboolean async_get_size,
2579                                            TnyMsg *msg)
2580 {
2581         GtkWidget *dialog;
2582
2583         /* Create dialog */
2584         dialog = modest_hildon2_details_dialog_new_with_header (parent_window, header, !async_get_size);
2585
2586         if (async_get_size && msg && TNY_IS_MSG (msg)) {
2587                 HeaderDetailsGetSizeInfo *info;
2588                 info = g_slice_new (HeaderDetailsGetSizeInfo);
2589                 info->dialog = dialog;
2590                 info->total = 0;
2591                 info->part = TNY_MIME_PART (g_object_ref (msg));
2592
2593                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
2594                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
2595         }
2596
2597         /* Run dialog */
2598         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
2599                                      GTK_WINDOW (dialog),
2600                                      parent_window);
2601         gtk_widget_show_all (dialog);
2602
2603         g_signal_connect_swapped (dialog, "response", 
2604                                   G_CALLBACK (gtk_widget_destroy),
2605                                   dialog);
2606 }
2607
2608 osso_context_t *
2609 modest_platform_get_osso_context (void)
2610 {
2611         return modest_maemo_utils_get_osso_context ();
2612 }
2613
2614 static gfloat
2615 convert_volume_to_db (int linear_volume)
2616 {
2617     gfloat linear_converted = linear_volume / 100.0;
2618     gfloat db_vol = 0.0;
2619     
2620     db_vol = 20 * log10 (linear_converted);
2621     if (isinf (db_vol) != 0)
2622         return -60.0;
2623
2624     return db_vol;
2625 }
2626
2627 static void
2628 modest_platform_play_email_tone (void)
2629 {
2630         gchar *mail_tone;
2631         gint mail_volume_int;
2632         int ret;
2633         ca_proplist *pl = NULL;
2634         gfloat db_volume;
2635
2636 #ifdef MODEST_USE_PROFILE
2637         gchar *active_profile;
2638         gchar *mail_volume;
2639
2640         active_profile = profile_get_profile ();
2641         mail_tone = profile_get_value (active_profile, PROFILE_MAIL_TONE);
2642         mail_volume = profile_get_value (active_profile, PROFILE_MAIL_VOLUME);
2643         mail_volume_int = profile_parse_int (mail_volume);
2644         g_free (mail_volume);
2645         g_free (active_profile);
2646 #else
2647         mail_tone = g_strdup (MAIL_TONE);
2648         mail_volume_int = 100;
2649 #endif
2650
2651         if (mail_tone && !strstr (mail_tone, "/")) {
2652                 gchar *tmp;
2653
2654                 tmp = g_strconcat ("/usr/share/sounds", mail_tone, NULL);
2655                 g_free (mail_tone);
2656                 mail_tone = tmp;
2657         }
2658
2659         if (mail_volume_int > 0) {
2660
2661                 if (ca_con == NULL) {
2662                         if ((ret = ca_context_create (&ca_con)) != CA_SUCCESS) {
2663                                 g_warning("ca_context_create: %s\n", ca_strerror(ret));
2664                                 ca_con = NULL;
2665                                 return;
2666                         }
2667                         if ((ret = ca_context_set_driver (ca_con, "gstreamer")) != CA_SUCCESS) {
2668                                 g_warning ("ca_context_set_driver: %s\n", ca_strerror (ret));
2669                                 ca_con = NULL;
2670                                 return;
2671                         }
2672                 }
2673
2674                 if (!ca_con_opened) {
2675                         if ((ret = ca_context_open(ca_con)) != CA_SUCCESS) {
2676                                 g_warning("ca_context_open: %s\n", ca_strerror(ret));
2677                                 return;
2678                         } else {
2679                                 ca_con_opened = TRUE;
2680                         }
2681                 }
2682
2683                 ca_proplist_create(&pl);
2684                 ca_proplist_sets(pl, CA_PROP_MEDIA_FILENAME, mail_tone);
2685                 db_volume = convert_volume_to_db (mail_volume_int);
2686                 ca_proplist_setf(pl, CA_PROP_CANBERRA_VOLUME, "%f", db_volume);
2687
2688                 ret = ca_context_play_full(ca_con, 0, pl, NULL, NULL);
2689                 g_debug("ca_context_play_full (vol %f): %s\n", (gfloat) mail_volume_int, ca_strerror(ret));
2690
2691                 ca_proplist_destroy(pl);
2692         }
2693
2694         g_free (mail_tone);
2695 }
2696
2697 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
2698 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
2699 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
2700 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
2701 #define MOVE_TO_DIALOG_PANNABLE "pannable"
2702 #define MOVE_TO_FOLDER_SEPARATOR "/"
2703
2704 static void
2705 translate_path (gchar **path)
2706 {
2707         gchar **parts;
2708         gchar **current;
2709         GString *output;
2710         gboolean add_separator;
2711
2712         parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
2713         g_free (*path);
2714
2715         current = parts;
2716         output = g_string_new ("");
2717         add_separator = FALSE;
2718
2719         while (*current != NULL) {
2720                 TnyFolderType folder_type;
2721                 gchar *downcase;
2722
2723                 if (add_separator) {
2724                         output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
2725                 } else {
2726                         add_separator = TRUE;
2727                 }
2728
2729                 downcase = g_ascii_strdown (*current, -1);
2730                 folder_type = modest_local_folder_info_get_type (downcase);
2731                 if (strcmp (downcase, "inbox") == 0) {
2732                         output = g_string_append (output, _("mcen_me_folder_inbox"));
2733                 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
2734                     folder_type == TNY_FOLDER_TYPE_DRAFTS ||
2735                     folder_type == TNY_FOLDER_TYPE_SENT ||
2736                     folder_type == TNY_FOLDER_TYPE_OUTBOX) {
2737                         output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
2738                 } else {
2739                         output = g_string_append (output, *current);
2740                 }
2741                 g_free (downcase);
2742
2743                 current++;
2744         }
2745
2746         g_strfreev (parts);
2747         *path = g_string_free (output, FALSE);
2748 }
2749
2750 static void
2751 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
2752                                           TnyFolderStore *folder_store)
2753 {
2754         GtkWidget *action_button;
2755         GtkWidget *image = NULL;
2756         TnyAccount *account;
2757         gchar *account_name = NULL, *short_name = NULL;
2758
2759         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2760
2761         /* Get account name */
2762         if (TNY_IS_FOLDER (folder_store))
2763                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
2764         else
2765                 account = g_object_ref (folder_store);
2766
2767         if (modest_tny_account_is_virtual_local_folders (account))
2768                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
2769                                                        MODEST_CONF_DEVICE_NAME, NULL);
2770
2771         if (!account_name)
2772                 account_name = g_strdup (tny_account_get_name (account));
2773
2774         g_object_unref (account);
2775
2776         /* Set title of button: account or folder name */
2777         if (TNY_IS_FOLDER (folder_store))
2778                 short_name = folder_store_get_display_name (folder_store);
2779         else
2780                 short_name = g_strdup (account_name);
2781
2782         hildon_button_set_title (HILDON_BUTTON (action_button), short_name);
2783
2784         /* Set value of button, folder full name */
2785         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
2786                 const gchar *camel_full_name;
2787                 gchar *last_slash, *full_name;
2788
2789                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
2790                 last_slash = g_strrstr (camel_full_name, "/");
2791                 if (last_slash) {
2792                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
2793                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
2794                         g_free (prefix);
2795                 } else {
2796                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
2797                                                  short_name,
2798                                                  NULL);
2799                 }
2800                 translate_path (&full_name);
2801                 hildon_button_set_value (HILDON_BUTTON (action_button), full_name);
2802                 g_free (full_name);
2803         }
2804         g_free (account_name);
2805         g_free (short_name);
2806
2807         /* Set image for the button */
2808         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
2809         if (image)
2810                 hildon_button_set_image (HILDON_BUTTON (action_button), image);
2811 }
2812
2813 static void
2814 move_to_dialog_show_accounts (GtkWidget *dialog)
2815 {
2816         GtkWidget *back_button;
2817         GtkWidget *folder_view;
2818         GtkWidget *pannable;
2819         GtkWidget *action_button;
2820
2821         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2822         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2823         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2824         pannable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2825
2826         gtk_widget_set_sensitive (back_button, FALSE);
2827         gtk_widget_set_sensitive (action_button, FALSE);
2828
2829         /* Need to set this here, otherwise callbacks called because
2830            of filtering won't perform correctly */
2831         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
2832
2833         /* Reset action button */
2834         hildon_button_set_title (HILDON_BUTTON (action_button), NULL);
2835         hildon_button_set_value (HILDON_BUTTON (action_button), NULL);
2836         hildon_button_set_image (HILDON_BUTTON (action_button), NULL);
2837
2838         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
2839         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
2840         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
2841         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2842                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2843         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
2844                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2845         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
2846                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2847         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
2848                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2849         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2850 }
2851
2852 static void
2853 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
2854 {
2855         GtkWidget *back_button;
2856         GtkWidget *folder_view;
2857         TnyAccount *account;
2858         const gchar *account_id;
2859         GtkWidget *pannable;
2860         GtkWidget *action_button;
2861
2862         back_button =
2863                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2864         action_button =
2865                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2866         folder_view =
2867                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2868         pannable =
2869                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE));
2870
2871         gtk_widget_set_sensitive (back_button, TRUE);
2872         gtk_widget_set_sensitive (action_button, TRUE);
2873
2874         /* Need to set this here, otherwise callbacks called because
2875            of filtering won't perform correctly */
2876         g_object_set_data (G_OBJECT (dialog),
2877                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2878                            GINT_TO_POINTER (TRUE));
2879
2880         account = TNY_ACCOUNT (folder_store);
2881         if (modest_tny_account_is_virtual_local_folders (account)) {
2882                 account_id = tny_account_get_id (account);
2883                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2884                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2885         } else if (modest_tny_account_is_memory_card_account (account)) {
2886                 account_id = tny_account_get_id (account);
2887                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2888                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2889         } else {
2890                 account_id = tny_account_get_id (account);
2891                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2892                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2893                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2894                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2895         }
2896
2897         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2898         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2899                                                                      account_id);
2900
2901         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2902         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2903         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2904         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2905         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (pannable), 0, 0);
2906 }
2907
2908 static void
2909 on_move_to_dialog_back_clicked (GtkButton *button,
2910                                 gpointer userdata)
2911 {
2912         GtkWidget *dialog = (GtkWidget *) userdata;
2913
2914         /* Back to show accounts */
2915         move_to_dialog_show_accounts (dialog);
2916 }
2917
2918 static void
2919 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2920                                     GtkTreePath       *path,
2921                                     GtkTreeViewColumn *column,
2922                                     gpointer           user_data)
2923 {
2924         TnyFolderStore *selected = NULL;
2925         GtkWidget *dialog;
2926         GtkWidget *folder_view;
2927         gboolean showing_folders;
2928
2929         dialog = (GtkWidget *) user_data;
2930         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2931                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2932
2933         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2934                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2935
2936         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2937         if (!selected)
2938                 return;
2939
2940         if (!showing_folders) {
2941                 gboolean valid = TRUE;
2942
2943                 if (TNY_IS_ACCOUNT (selected) &&
2944                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2945                         ModestProtocolType protocol_type;
2946
2947                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2948                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2949                                 (modest_runtime_get_protocol_registry (),
2950                                  protocol_type,
2951                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2952                 }
2953                 if (valid)
2954                         move_to_dialog_show_folders (dialog, selected);
2955         } else {
2956                 move_to_dialog_set_selected_folder_store (dialog, selected);
2957         }
2958         g_object_unref (selected);
2959 }
2960
2961 static void
2962 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2963                                      gpointer          user_data)
2964 {
2965         gboolean showing_folders;
2966         GtkWidget *dialog;
2967
2968         dialog = (GtkWidget *) user_data;
2969         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2970         if (showing_folders) {
2971                 TnyFolderStore *selected;
2972                 GtkWidget *folder_view;
2973
2974                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2975                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2976
2977                 if (selected) {
2978                         move_to_dialog_set_selected_folder_store (dialog, selected);
2979                         g_object_unref (selected);
2980                 }
2981         }
2982 }
2983
2984 static void
2985 on_move_to_dialog_action_clicked (GtkButton *selection,
2986                                   gpointer   user_data)
2987 {
2988         GtkWidget *dialog;
2989         gboolean showing_folders;
2990
2991         dialog = (GtkWidget *) user_data;
2992         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2993         if (showing_folders) {
2994                 TnyFolderStore *selected;
2995                 GtkWidget *folder_view;
2996
2997                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2998                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2999
3000                 if (selected) {
3001                         /* It's not possible to select root folders as
3002                            targets unless they're the local account or
3003                            the memory card account */
3004                         if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
3005                             (TNY_IS_ACCOUNT (selected) &&
3006                              (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
3007                               modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
3008                                 gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
3009                         g_object_unref (selected);
3010                 }
3011         }
3012 }
3013
3014 static void
3015 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
3016 {
3017         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (dialog), activity?1:0);
3018 }
3019
3020 GtkWidget *
3021 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
3022                                        GtkWidget **folder_view)
3023 {
3024         GtkWidget *dialog, *folder_view_container;
3025         GtkWidget *align;
3026         GtkWidget *buttons_hbox;
3027         GtkWidget *back_button;
3028         GdkPixbuf *back_pixbuf;
3029         GtkWidget *top_vbox;
3030         GtkWidget *action_button;
3031         GtkTreeSelection *selection;
3032
3033         /* Create dialog. We cannot use a touch selector because we
3034            need to use here the folder view widget directly */
3035         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
3036                                               GTK_WINDOW (parent_window),
3037                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
3038                                               GTK_DIALOG_DESTROY_WITH_PARENT,
3039                                               _HL("wdgt_bd_new"), MODEST_GTK_RESPONSE_NEW_FOLDER,
3040                                               NULL);
3041
3042         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3043         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
3044         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
3045
3046         /* Create folder view */
3047         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
3048         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
3049                           dialog);
3050
3051         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
3052                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
3053         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
3054                                                FALSE);
3055         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
3056                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
3057
3058         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
3059         back_button = gtk_button_new ();
3060         back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
3061         if (back_pixbuf) {
3062                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
3063                 g_object_unref (back_pixbuf);
3064         }
3065
3066         action_button = hildon_button_new (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT,
3067                                            HILDON_BUTTON_ARRANGEMENT_VERTICAL);
3068         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
3069
3070         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
3071         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
3072         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
3073         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
3074         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
3075
3076         /* Create pannable and add it to the dialog */
3077         folder_view_container = hildon_pannable_area_new ();
3078         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
3079         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
3080
3081         gtk_container_add (GTK_CONTAINER (align), top_vbox);
3082         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
3083
3084         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
3085
3086         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
3087         gtk_widget_show (folder_view_container);
3088         gtk_widget_show (align);
3089         gtk_widget_show (top_vbox);
3090         gtk_widget_show (*folder_view);
3091         gtk_widget_show_all (back_button);
3092         gtk_widget_show (action_button);
3093         gtk_widget_show (buttons_hbox);
3094         gtk_widget_show (dialog);
3095
3096         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
3097         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
3098         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
3099         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_PANNABLE, folder_view_container);
3100
3101         /* Simulate the behaviour of a HildonPickerDialog by emitting
3102            a response when a folder is selected */
3103         g_signal_connect (*folder_view, "row-activated",
3104                           G_CALLBACK (on_move_to_dialog_row_activated),
3105                           dialog);
3106
3107         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
3108         g_signal_connect (selection, "changed",
3109                           G_CALLBACK (on_move_to_dialog_selection_changed),
3110                           dialog);
3111
3112         g_signal_connect (action_button, "clicked",
3113                           G_CALLBACK (on_move_to_dialog_action_clicked),
3114                           dialog);
3115
3116         g_signal_connect (back_button, "clicked",
3117                           G_CALLBACK (on_move_to_dialog_back_clicked),
3118                           dialog);
3119
3120         move_to_dialog_show_accounts (dialog);
3121
3122         return dialog;
3123 }
3124
3125 TnyList *
3126 modest_platform_get_list_to_move (ModestWindow *window)
3127 {
3128         TnyList *list = NULL;
3129
3130         if (MODEST_IS_HEADER_WINDOW (window)) {
3131                 ModestHeaderView *header_view;
3132
3133                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
3134                 list = modest_header_view_get_selected_headers (header_view);
3135         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
3136                 ModestFolderView *folder_view;
3137                 TnyFolderStore *selected_folder;
3138
3139                 list = TNY_LIST (tny_simple_list_new ());
3140                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
3141                 selected_folder = modest_folder_view_get_selected (folder_view);
3142                 if (selected_folder) {
3143                         tny_list_prepend (list, G_OBJECT (selected_folder));
3144                         g_object_unref (selected_folder);
3145                 }
3146                 return list;
3147         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
3148                 TnyHeader *header;
3149
3150                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
3151                 if (header) {
3152                         list = TNY_LIST (tny_simple_list_new ());
3153                         tny_list_prepend (list, G_OBJECT (header));
3154                         g_object_unref (header);
3155                 }
3156         } else {
3157                 g_return_val_if_reached (NULL);
3158         }
3159
3160         return list;
3161 }