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