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