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