Set close button and proper size to change folder dialog.
[modest] / src / gtk / 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-scrollable.h>
36 #include <modest-runtime.h>
37 #include <modest-main-window.h>
38 #include <modest-header-view.h>
39 #include "modest-widget-memory.h"
40 #include <modest-utils.h>
41 #include <tny-camel-folder.h>
42 #include <tny-simple-list.h>
43 #include <tny-merge-folder.h>
44 #include <tny-error.h>
45 #include <tny-folder.h>
46 #include <tny-account-store-view.h>
47 #include <tny-gnome-device.h>
48 #include <gtk/gtk.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
52 #include <string.h>
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "widgets/modest-window-mgr.h"
57 #include <modest-datetime-formatter.h>
58 #include "modest-header-window.h"
59 #include <modest-folder-window.h>
60 #include <modest-account-mgr.h>
61 #include <modest-account-mgr-helpers.h>
62 #include <modest-ui-constants.h>
63 #include <modest-icon-names.h>
64 #include <modest-count-stream.h>
65 #include <modest-gtk-details-dialog.h>
66 #include <modest-default-global-settings-dialog.h>
67 #include <math.h>
68 #include "widgets/modest-toolkit-utils.h"
69 #include <modest-shell-banner.h>
70
71 #define HILDON_OSSO_URI_ACTION "uri-action"
72 #define URI_ACTION_COPY "copy:"
73 #define MODEST_NOTIFICATION_CATEGORY "email-message"
74 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
75
76 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
77 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
78 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
79 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
80
81 static void     
82 on_modest_conf_update_interval_changed (ModestConf* self, 
83                                         const gchar *key, 
84                                         ModestConfEvent event,
85                                         ModestConfNotificationId id, 
86                                         gpointer user_data)
87 {
88         g_return_if_fail (key);
89         
90         if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
91                 const guint update_interval_minutes = 
92                         modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
93                 modest_platform_set_update_interval (update_interval_minutes);
94         }
95 }
96
97
98
99 static gboolean
100 check_required_files (void)
101 {
102 #if 0
103         FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
104
105         if (!mcc_file) {
106                 g_printerr ("modest: check for mcc file (for LANG) failed\n");
107                 return FALSE;
108         } else {
109                 fclose (mcc_file);
110         }
111
112         if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
113             access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
114                 g_printerr ("modest: cannot find providers data\n");
115                 return FALSE;
116         }
117 #endif
118         return TRUE;
119 }
120
121
122 /* the gpointer here is the osso_context. */
123 gboolean
124 modest_platform_init (int argc, char *argv[])
125 {
126         GSList *acc_names;
127
128         if (!check_required_files ()) {
129                 g_printerr ("modest: missing required files\n");
130                 return FALSE;
131         }
132
133         /* Make sure that the update interval is changed whenever its gconf key 
134          * is changed */
135         /* CAUTION: we're not using here the
136            modest_conf_listen_to_namespace because we know that there
137            are other parts of Modest listening for this namespace, so
138            we'll receive the notifications anyway. We basically do not
139            use it because there is no easy way to do the
140            modest_conf_forget_namespace */
141         ModestConf *conf = modest_runtime_get_conf ();
142         g_signal_connect (G_OBJECT(conf),
143                           "key_changed",
144                           G_CALLBACK (on_modest_conf_update_interval_changed), 
145                           NULL);
146
147         /* only force the setting of the default interval, if there are actually
148          * any accounts */
149         acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
150         if (acc_names) {
151                 /* Get the initial update interval from gconf: */
152                 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
153                                                        MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
154                 modest_account_mgr_free_account_names (acc_names);
155         }
156         
157         return TRUE;
158 }
159
160 gboolean
161 modest_platform_uninit (void)
162 {
163         return TRUE;
164 }
165
166
167
168
169 TnyDevice*
170 modest_platform_get_new_device (void)
171 {
172         return TNY_DEVICE (tny_gnome_device_new ());
173 }
174
175 gchar*
176 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
177                                     gchar **effective_mime_type)
178 {
179         gchar *icon_name  = NULL;
180         gchar *content_type;
181         GIcon *icon;
182         gchar **icon_names, **cursor;
183         
184         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) 
185                 content_type = g_content_type_guess (name, NULL, 0, NULL);
186         else {
187                 content_type = g_content_type_from_mime_type (mime_type);
188         }
189
190         if (!content_type) {
191                 content_type = g_content_type_from_mime_type ("application/octet-stream");
192         }
193         icon = g_content_type_get_icon (content_type);
194         if (!G_THEMED_ICON (icon))
195                 return NULL;
196
197         g_object_get (G_OBJECT (icon), "names", &icon_names, NULL);
198
199         for (cursor = icon_names; cursor; ++cursor) {
200                 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
201                     !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
202                         icon_name = g_strdup ("stock_message-display");
203                         break;
204                 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
205                         icon_name = g_strdup (*cursor);
206                         break;
207                 }
208         }
209         g_strfreev (icon_names);
210
211         return icon_name;
212
213 }
214
215
216
217 gboolean 
218 modest_platform_activate_uri (const gchar *uri)
219 {
220         GAppLaunchContext *al_context;
221         gboolean retval;
222
223         al_context = gdk_app_launch_context_new ();
224         retval =  g_app_info_launch_default_for_uri (uri, al_context, NULL);
225         g_object_unref (al_context);
226
227         return retval;
228
229 }
230
231 gboolean 
232 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
233 {
234         gchar *content_type;
235         gboolean retval;
236         GAppInfo *app_info;
237         GList *list;
238         GFile *file;
239         GAppLaunchContext *al_context;
240
241         content_type = g_content_type_from_mime_type (mime_type);
242         if (!content_type)
243                 return FALSE;
244
245         app_info = g_app_info_get_default_for_type (content_type, FALSE);
246         g_free (content_type);
247         if (!app_info) {
248                 content_type = g_content_type_guess (path, NULL, 0, NULL);
249                 if (!content_type)
250                         return FALSE;
251
252                 app_info = g_app_info_get_default_for_type (content_type, FALSE);
253                 g_free (content_type);
254
255                 if (!app_info)
256                         return FALSE;
257
258         }
259
260         file = g_file_new_for_path (path);
261         list = g_list_prepend (NULL, file);
262         al_context = gdk_app_launch_context_new ();
263         retval = g_app_info_launch (app_info, list, al_context, NULL);
264         g_object_unref (al_context);
265
266         g_list_free (list);
267         g_object_unref (file);
268
269         return retval;
270 }
271
272 gboolean
273 modest_platform_show_uri_popup (const gchar *uri)
274 {
275         g_warning ("Not implemented %s", __FUNCTION__);
276
277         return FALSE;
278 }
279
280
281 GdkPixbuf*
282 modest_platform_get_icon (const gchar *name, guint icon_size)
283 {
284         return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
285                                          name,
286                                          icon_size,
287                                          0,
288                                          NULL);
289 }
290
291 const gchar*
292 modest_platform_get_app_name (void)
293 {
294         return _("mcen_ap_name");
295 }
296
297 static void
298 entry_insert_text (GtkEditable *editable,
299                    const gchar *text,
300                    gint         length,
301                    gint        *position,
302                    gpointer     data)
303 {
304         gchar *chars;
305         gint chars_length;
306
307         chars = gtk_editable_get_chars (editable, 0, -1);
308         chars_length = g_utf8_strlen (chars, -1);
309         g_free (chars);
310
311         /* Show WID-INF036 */
312         if (chars_length >= 20) {
313                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
314                                                    _CS_MAXIMUM_CHARACTERS_REACHED);
315         } else {
316                 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
317                         /* Show an error */
318                         gchar *tmp, *msg;
319
320                         tmp = g_strndup (folder_name_forbidden_chars,
321                                          FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
322                         msg = g_strdup_printf (_CS_ILLEGAL_CHARACTERS_ENTERED, tmp);
323                         modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)),
324                                                              NULL, msg);
325                         g_free (msg);
326                         g_free (tmp);
327                 } else {
328                         if (length >= 20) {
329                                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
330                                                                      _CS_MAXIMUM_CHARACTERS_REACHED);
331                         }
332                         /* Write the text in the entry if it's valid */
333                         g_signal_handlers_block_by_func (editable,
334                                                          (gpointer) entry_insert_text, data);
335                         gtk_editable_insert_text (editable, text, length, position);
336                         g_signal_handlers_unblock_by_func (editable,
337                                                            (gpointer) entry_insert_text, data);
338                 }
339         }
340         /* Do not allow further processing */
341         g_signal_stop_emission_by_name (editable, "insert_text");
342 }
343
344 static void
345 entry_changed (GtkEditable *editable,
346                gpointer     user_data)
347 {
348         gchar *chars;
349         GtkWidget *ok_button;
350         GList *buttons;
351
352         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
353         ok_button = GTK_WIDGET (buttons->data);
354
355         chars = gtk_editable_get_chars (editable, 0, -1);
356         g_return_if_fail (chars != NULL);
357
358
359         if (g_utf8_strlen (chars,-1) >= 20) {
360                 modest_platform_information_banner  (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
361                                                      _CS_MAXIMUM_CHARACTERS_REACHED);
362         }
363         gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
364
365         /* Free */
366         g_list_free (buttons);
367         g_free (chars);
368 }
369
370
371
372 static void
373 on_response (GtkDialog *dialog,
374              gint response,
375              gpointer user_data)
376 {
377         GtkWidget *entry, *picker;
378         TnyFolderStore *parent;
379         const gchar *new_name;
380         gboolean exists;
381
382         if (response != GTK_RESPONSE_ACCEPT)
383                 return;
384
385         /* Get entry */
386         entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
387         picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
388
389         parent = TNY_FOLDER_STORE (user_data);
390         new_name = gtk_entry_get_text (GTK_ENTRY (entry));
391         exists = FALSE;
392
393         if (picker != NULL)
394                 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
395
396         /* Look for another folder with the same name */
397         if (!TNY_IS_MERGE_FOLDER (parent) &&
398             modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
399                 exists = TRUE;
400
401         if (!exists) {
402                 if (TNY_IS_ACCOUNT (parent) &&
403                     modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
404                     modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
405                                                                          new_name)) {
406                         exists = TRUE;
407                 }
408         }
409
410         if (exists) {
411                 /* Show an error */
412                 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)), 
413                                                     NULL, _CS_FOLDER_ALREADY_EXISTS);
414                 /* Select the text */
415                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
416                 gtk_widget_grab_focus (entry);
417                 /* Do not close the dialog */
418                 g_signal_stop_emission_by_name (dialog, "response");
419         }
420 }
421
422 typedef struct _FolderChooserData {
423         TnyFolderStore *store;
424         GtkWidget *dialog;
425 } FolderChooserData;
426
427 static void
428 folder_chooser_activated (ModestFolderView *folder_view,
429                           TnyFolderStore *folder,
430                           FolderChooserData *userdata)
431 {
432         userdata->store = folder;
433         gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
434 }
435
436 static TnyFolderStore *
437 folder_chooser_dialog_run (ModestFolderView *original,
438                            TnyFolderStore *current,
439                            GtkButton *picker)
440 {
441         GtkWidget *folder_view;
442         FolderChooserData userdata = {NULL, NULL};
443         GtkWidget *scrollable;
444         const gchar *visible_id = NULL;
445
446         userdata.dialog = gtk_dialog_new ();
447
448         gtk_widget_set_size_request (GTK_WIDGET (userdata.dialog), 
449                                      MODEST_DIALOG_WINDOW_MAX_WIDTH,
450                                      MODEST_DIALOG_WINDOW_MAX_HEIGHT);
451
452         gtk_dialog_add_button (GTK_DIALOG (userdata.dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
453
454         scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
455         folder_view = modest_platform_create_folder_view (NULL);
456
457         gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM_CHANGE_FOLDER);
458
459         modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
460                                        MODEST_FOLDER_VIEW (folder_view));
461
462         if (TNY_IS_ACCOUNT (current)) {
463                 /* Local folders and MMC account are always shown
464                    along with the currently visible server account */
465                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
466                     modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
467                         visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
468                 else
469                         visible_id = tny_account_get_id (TNY_ACCOUNT (current));
470         } else if (TNY_IS_FOLDER (current)) {
471                 TnyAccount *account;
472                 account = modest_tny_folder_get_account ((TnyFolder *) current);
473                 if (account) {
474                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
475                             modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
476                                 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
477                         } else {
478                                 visible_id = tny_account_get_id (account);
479                         }
480                         g_object_unref (account);
481                 }
482         } else {
483                 visible_id =
484                         modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
485         }
486
487         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
488                                                                      visible_id);
489
490         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
491         gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
492         gtk_widget_set_size_request (scrollable, -1, 320);
493
494         gtk_widget_show (folder_view);
495         gtk_widget_show (scrollable);
496         gtk_widget_show (userdata.dialog);
497         g_signal_connect (G_OBJECT (folder_view), "folder-activated", 
498                           G_CALLBACK (folder_chooser_activated), 
499                           (gpointer) &userdata);
500
501         gtk_dialog_run (GTK_DIALOG (userdata.dialog));
502         gtk_widget_destroy (userdata.dialog);
503
504         return userdata.store;
505 }
506
507 static gchar *
508 folder_store_get_display_name (TnyFolderStore *store)
509 {
510         if (TNY_IS_ACCOUNT (store)) {
511                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
512                         return modest_conf_get_string (modest_runtime_get_conf(),
513                                                        MODEST_CONF_DEVICE_NAME, NULL);
514                 else
515                         return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
516         } else {
517                 gchar *fname;
518                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
519
520                 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
521                 type = tny_folder_get_folder_type (TNY_FOLDER (store));
522                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
523                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
524                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
525                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
526                                 g_free (fname);
527                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
528                         }
529                 } else {
530                         /* Sometimes an special folder is reported by the server as
531                            NORMAL, like some versions of Dovecot */
532                         if (type == TNY_FOLDER_TYPE_NORMAL ||
533                             type == TNY_FOLDER_TYPE_UNKNOWN) {
534                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
535                         }
536                 }
537
538                 if (type == TNY_FOLDER_TYPE_INBOX) {
539                         g_free (fname);
540                         fname = g_strdup (_("mcen_me_folder_inbox"));
541                 }
542                 return fname;
543         }
544 }
545
546 GtkWidget *
547 get_image_for_folder_store (TnyFolderStore *store,
548                             gint size)
549 {
550         GdkPixbuf *pixbuf;
551         const gchar *icon_name = NULL;
552         GtkWidget *image = NULL;
553
554         if (TNY_IS_ACCOUNT (store)) {
555                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
556                         icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
557                 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
558                         icon_name = MODEST_FOLDER_ICON_MMC;
559                 else
560                         icon_name = MODEST_FOLDER_ICON_ACCOUNT;
561         } else {
562                 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
563                 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
564                         switch (type) {
565                         case TNY_FOLDER_TYPE_INBOX:
566                                 icon_name = MODEST_FOLDER_ICON_INBOX;
567                                 break;
568                         default:
569                                 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
570                         }
571                 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
572                         switch (type) {
573                         case TNY_FOLDER_TYPE_OUTBOX:
574                                 icon_name = MODEST_FOLDER_ICON_OUTBOX;
575                                 break;
576                         case TNY_FOLDER_TYPE_DRAFTS:
577                                 icon_name = MODEST_FOLDER_ICON_DRAFTS;
578                                 break;
579                         case TNY_FOLDER_TYPE_SENT:
580                                 icon_name = MODEST_FOLDER_ICON_SENT;
581                                 break;
582                         default:
583                                 icon_name = MODEST_FOLDER_ICON_NORMAL;
584                         }
585                 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
586                         icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
587                 }
588         }
589
590         /* Set icon */
591         pixbuf = modest_platform_get_icon (icon_name, size);
592
593         if (pixbuf) {
594                 image = gtk_image_new_from_pixbuf (pixbuf);
595                 g_object_unref (pixbuf);
596         }
597
598         return image;
599 }
600
601 static void
602 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
603 {
604         gchar *name;
605
606         if (store == NULL) {
607                 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
608         } else {
609                 GtkWidget *image;
610
611                 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
612                                         g_object_ref (store),
613                                         (GDestroyNotify) g_object_unref);
614                 name = folder_store_get_display_name (store);
615                 gtk_button_set_label (GTK_BUTTON (button), name);
616                 g_free (name);
617
618                 /* Select icon */
619                 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
620                 if (image)
621                         gtk_button_set_image (GTK_BUTTON (button), image);
622         }
623 }
624
625 /* Always returns DUPs so you must free the returned value */
626 static gchar *
627 get_next_folder_name (const gchar *suggested_name, 
628                       TnyFolderStore *suggested_folder)
629 {
630         const gchar *default_name = _FM_NEW_FOLDER_NAME_STUB;
631         unsigned int i;
632         gchar *real_suggested_name;
633
634         if (suggested_name !=NULL) {
635                 return g_strdup (suggested_name);
636         }
637
638         for(i = 0; i < 100; ++ i) {
639                 gboolean exists = FALSE;
640
641                 if (i == 0)
642                         real_suggested_name = g_strdup (default_name);
643                 else
644                         real_suggested_name = g_strdup_printf ("%s(%d)",
645                                                                _FM_NEW_FOLDER_NAME_STUB,
646                                                                i);
647                 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
648                                                                     real_suggested_name,
649                                                                     TRUE);
650
651                 if (!exists)
652                         break;
653
654                 g_free (real_suggested_name);
655         }
656
657         /* Didn't find a free number */
658         if (i == 100)
659                 real_suggested_name = g_strdup (default_name);
660
661         return real_suggested_name;
662 }
663
664 typedef struct {
665         ModestFolderView *folder_view;
666         GtkEntry *entry;
667 } FolderPickerHelper;
668
669 static void
670 folder_picker_clicked (GtkButton *button,
671                        FolderPickerHelper *helper)
672 {
673         TnyFolderStore *store, *current;
674
675         current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
676
677         store = folder_chooser_dialog_run (helper->folder_view, current, button);
678         if (store) {
679                 const gchar *current_name;
680                 gboolean exists = FALSE;
681
682                 folder_picker_set_store (GTK_BUTTON (button), store);
683
684                 /* Update the name of the folder */
685                 current_name = gtk_entry_get_text (helper->entry);
686
687                 if (TNY_IS_FOLDER_STORE (store))
688                         exists = modest_tny_folder_has_subfolder_with_name (store,
689                                                                             current_name,
690                                                                             TRUE);
691                 if (exists) {
692                         gchar *new_name = get_next_folder_name (NULL, store);
693                         gtk_entry_set_text (helper->entry, new_name);
694                         g_free (new_name);
695                 }
696         }
697 }
698
699 static GtkWidget *
700 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
701 {
702         GtkWidget *button;
703         const gchar *acc_id = NULL;
704
705         button = gtk_button_new ();
706
707         gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
708
709         if (suggested) {
710
711                 folder_picker_set_store (GTK_BUTTON (button), suggested);
712
713                 if (TNY_IS_ACCOUNT (suggested)) {
714                         if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
715                             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
716                                 acc_id = tny_account_get_id ((TnyAccount *) suggested);
717                 } else {
718                         TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
719                         if (account) {
720                                 acc_id = tny_account_get_id ((TnyAccount *) account);
721                                 g_object_unref (account);
722                         }
723                 }
724         }
725
726         if (!acc_id)
727                 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
728
729         g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
730                                 g_strdup (acc_id), (GDestroyNotify) g_free);
731
732
733         g_signal_connect (G_OBJECT (button), "clicked",
734                           G_CALLBACK (folder_picker_clicked),
735                           helper);
736
737         return button;
738 }
739
740
741 static gint
742 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
743                                           TnyFolderStore *suggested_parent,
744                                           const gchar *dialog_title,
745                                           const gchar *label_text,
746                                           const gchar *suggested_name,
747                                           gboolean show_name,
748                                           gboolean show_parent,
749                                           gchar **folder_name,
750                                           TnyFolderStore **parent)
751 {
752         GtkWidget *accept_btn = NULL;
753         GtkWidget *dialog, *entry = NULL, *label_entry = NULL,  *label_location = NULL, *hbox;
754         GtkWidget *account_picker = NULL;
755         GList *buttons = NULL;
756         gint result;
757         GtkSizeGroup *sizegroup;
758         ModestFolderView *folder_view;
759         ModestWindow *folder_window;
760         ModestWindowMgr *window_mgr;
761         FolderPickerHelper *helper = NULL;
762         GtkWidget *top_vbox, *top_align;
763
764         window_mgr = modest_runtime_get_window_mgr ();
765         folder_window = modest_window_mgr_get_folder_window (window_mgr);
766         g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
767         
768         folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
769         
770         top_vbox = gtk_vbox_new (FALSE, 0);
771         top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
772         gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
773         
774         /* Ask the user for the folder name */
775         dialog = gtk_dialog_new_with_buttons (dialog_title,
776                                               parent_window,
777                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
778                                               GTK_STOCK_CANCEL,
779                                               GTK_RESPONSE_CANCEL,
780                                               _FM_NEW_FOLDER_DIALOG_OK,
781                                               GTK_RESPONSE_ACCEPT,
782                                               NULL);
783
784         /* Add accept button (with unsensitive handler) */
785         buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
786         accept_btn = GTK_WIDGET (buttons->data);
787
788         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
789
790         if (show_name) {
791                 label_entry = gtk_label_new (label_text);
792                 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
793                 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
794
795                 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
796                 gtk_size_group_add_widget (sizegroup, label_entry);
797                 
798                 if (suggested_name)
799                   gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
800                 else
801                         gtk_entry_set_text (GTK_ENTRY (entry), _FM_NEW_FOLDER_NAME_STUB);
802                 gtk_entry_set_width_chars (GTK_ENTRY (entry),
803                                            MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
804                                                 g_utf8_strlen (_FM_NEW_FOLDER_NAME_STUB, -1)));
805                 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
806         }
807         
808         if (show_parent) {
809           
810                 label_location = gtk_label_new (_FM_NEW_FOLDER_LOCATION);
811
812                 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
813                 gtk_size_group_add_widget (sizegroup, label_location);
814
815                 helper = g_slice_new0 (FolderPickerHelper);
816                 helper->folder_view = folder_view;
817                 helper->entry = (GtkEntry *) entry;
818
819                 account_picker = folder_picker_new (suggested_parent, helper);
820         }
821
822         g_object_unref (sizegroup);
823         
824         /* Connect to the response method to avoid closing the dialog
825            when an invalid name is selected*/
826         g_signal_connect (dialog,
827                           "response",
828                           G_CALLBACK (on_response),
829                           suggested_parent);
830         
831         if (show_name) {
832                 /* Track entry changes */
833                 g_signal_connect (entry,
834                                   "insert-text",
835                                   G_CALLBACK (entry_insert_text),
836                                   dialog);
837                 g_signal_connect (entry,
838                                   "changed",
839                                   G_CALLBACK (entry_changed),
840                                   dialog);
841         }
842         
843         
844         /* Some locales like pt_BR need this to get the full window
845            title shown */
846         gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
847         
848         /* Create the hbox */
849         if (show_name) {
850                 hbox = gtk_hbox_new (FALSE, 12);
851                 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
852                 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
853                 
854                 /* Add hbox to dialog */
855                 gtk_box_pack_start (GTK_BOX (top_vbox), 
856                                     hbox, FALSE, FALSE, 0);
857                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
858         }
859
860         if (show_parent) {
861                 hbox = gtk_hbox_new (FALSE, 12);
862                 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
863                 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
864
865                 /* Add hbox to dialog */
866                 gtk_box_pack_start (GTK_BOX (top_vbox), 
867                                     hbox, FALSE, FALSE, 0);
868                 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
869         }
870         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
871                                      GTK_WINDOW (dialog), parent_window);
872
873         gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
874         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
875
876         gtk_widget_show_all (GTK_WIDGET(dialog));
877
878         result = gtk_dialog_run (GTK_DIALOG(dialog));
879         if (result == GTK_RESPONSE_ACCEPT) {
880                 if (show_name)
881                         *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
882                 if (show_parent) {
883                         *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
884                         if (*parent)
885                                 g_object_ref (*parent);
886                 }
887         }
888
889         gtk_widget_destroy (dialog);
890
891         if (helper)
892                 g_slice_free (FolderPickerHelper, helper);
893
894         while (gtk_events_pending ())
895                 gtk_main_iteration ();
896
897         return result;
898 }
899
900 gint
901 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
902                                        TnyFolderStore *suggested_folder,
903                                        gchar *suggested_name,
904                                        gchar **folder_name,
905                                        TnyFolderStore **parent_folder)
906 {
907         gchar *real_suggested_name = NULL;
908         gint result;
909         ModestTnyAccountStore *acc_store;
910         TnyAccount *account;
911         gboolean do_free = FALSE;
912
913         real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
914                                                     suggested_folder);
915
916         /* In hildon 2.2 we always suggest the archive folder as parent */
917         if (!suggested_folder) {
918                 acc_store = modest_runtime_get_account_store ();
919                 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
920                 if (account) {
921                         suggested_folder = (TnyFolderStore *)
922                                 modest_tny_account_get_special_folder (account,
923                                                                        TNY_FOLDER_TYPE_ARCHIVE);
924                         g_object_unref (account);
925                         account = NULL;
926                 }
927         }
928
929         /* If there is not archive folder then fallback to local folders account */
930         if (!suggested_folder) {
931                 do_free = TRUE;
932                 suggested_folder = (TnyFolderStore *)
933                         modest_tny_account_store_get_local_folders_account (acc_store);
934         }
935
936         result = modest_platform_run_folder_common_dialog (parent_window,
937                                                            suggested_folder,
938                                                            _HL_TITLE_NEW_FOLDER,
939                                                            _FM_NEW_FOLDER_NAME,
940                                                            real_suggested_name,
941                                                            TRUE,
942                                                            TRUE,
943                                                            folder_name,
944                                                            parent_folder);
945
946         if (do_free)
947                 g_object_unref (suggested_folder);
948
949         g_free(real_suggested_name);
950
951         return result;
952 }
953
954 gint
955 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
956                                           TnyFolderStore *parent_folder,
957                                           const gchar *suggested_name,
958                                           gchar **folder_name)
959 {
960         GtkWindow *toplevel;
961
962         g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
963
964         toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (parent_window));
965         return modest_platform_run_folder_common_dialog (toplevel,
966                                                          parent_folder,
967                                                          _HL_TITLE_RENAME_FOLDER,
968                                                          _HL_RENAME_NAME,
969                                                          suggested_name,
970                                                          TRUE,
971                                                          FALSE,
972                                                          folder_name,
973                                                          NULL);
974 }
975
976
977
978 static void
979 on_destroy_dialog (GtkWidget *dialog)
980 {
981         /* This could happen when the dialogs get programatically
982            hidden or destroyed (for example when closing the
983            application while a dialog is being shown) */
984         if (!GTK_IS_WIDGET (dialog))
985                 return;
986
987         gtk_widget_destroy (dialog);
988
989         if (gtk_events_pending ())
990                 gtk_main_iteration ();
991 }
992
993 gint
994 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
995                                          const gchar *message)
996 {
997         GtkWidget *dialog;
998         gint response;
999
1000         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1001                                          GTK_MESSAGE_QUESTION,
1002                                          GTK_BUTTONS_OK_CANCEL,
1003                                          message);
1004         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1005                                      GTK_WINDOW (dialog), parent_window);
1006
1007         response = gtk_dialog_run (GTK_DIALOG (dialog));
1008
1009         on_destroy_dialog (dialog);
1010
1011         return response;
1012 }
1013
1014 gint
1015 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1016                                                       const gchar *message,
1017                                                       const gchar *button_accept,
1018                                                       const gchar *button_cancel)
1019 {
1020         GtkWidget *dialog;
1021         gint response;
1022         
1023         dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1024                                          GTK_MESSAGE_QUESTION,
1025                                          GTK_BUTTONS_NONE,
1026                                          message);
1027         gtk_dialog_add_buttons (GTK_DIALOG (dialog),
1028                                 button_accept, GTK_RESPONSE_ACCEPT,
1029                                 button_cancel, GTK_RESPONSE_CANCEL,
1030                                 NULL);
1031
1032         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1033                                      GTK_WINDOW (dialog), parent_window);
1034
1035         response = gtk_dialog_run (GTK_DIALOG (dialog));
1036
1037         on_destroy_dialog (dialog);
1038
1039         return response;
1040 }
1041         
1042 void
1043 modest_platform_run_information_dialog (GtkWindow *parent_window,
1044                                         const gchar *message,
1045                                         gboolean block)
1046 {
1047         GtkWidget *note;
1048         
1049         note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1050                                        GTK_MESSAGE_INFO,
1051                                        GTK_BUTTONS_OK,
1052                                        message);
1053         if (block)
1054                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1055                                              GTK_WINDOW (note), parent_window);
1056         
1057         if (block) {
1058                 gtk_dialog_run (GTK_DIALOG (note));
1059         
1060                 on_destroy_dialog (note);
1061         } else {
1062                 g_signal_connect_swapped (note,
1063                                           "response", 
1064                                           G_CALLBACK (on_destroy_dialog),
1065                                           note);
1066
1067                 gtk_widget_show_all (note);
1068         }
1069 }
1070
1071 typedef struct _ConnectAndWaitData {
1072         GMutex *mutex;
1073         GMainLoop *wait_loop;
1074         gboolean has_callback;
1075         gulong handler;
1076 } ConnectAndWaitData;
1077
1078
1079 gboolean 
1080 modest_platform_connect_and_wait (GtkWindow *parent_window, 
1081                                   TnyAccount *account)
1082 {
1083         gboolean device_online;
1084         TnyDevice *device;
1085         TnyConnectionStatus conn_status;
1086         gboolean user_requested;
1087         
1088         device = modest_runtime_get_device();
1089         device_online = tny_device_is_online (device);
1090
1091         /* Whether the connection is user requested or automatically
1092            requested, for example via D-Bus */
1093         user_requested = (parent_window) ? TRUE : FALSE;
1094
1095         /* If there is no account check only the device status */
1096         if (!account) {
1097                 if (device_online)
1098                         return TRUE;
1099                 else
1100                         /* TODO: should show connection dialog through gnome device */
1101                         return FALSE;
1102         }
1103
1104         /* Return if the account is already connected */
1105         conn_status = tny_account_get_connection_status (account);
1106         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1107                 return TRUE;
1108
1109         return FALSE;
1110 }
1111
1112 gboolean 
1113 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1114 {
1115         if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1116                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1117                         /* This must be a maildir account, which does not require a connection: */
1118                         return TRUE;
1119                 }
1120         }
1121
1122         return modest_platform_connect_and_wait (parent_window, account);
1123 }
1124
1125 gboolean 
1126 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1127 {
1128         if (!folder_store)
1129                 return TRUE; /* Maybe it is something local. */
1130                 
1131         gboolean result = TRUE;
1132         if (TNY_IS_FOLDER (folder_store)) {
1133                 /* Get the folder's parent account: */
1134                 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1135                 if (account != NULL) {
1136                         result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1137                         g_object_unref (account);
1138                 }
1139         } else if (TNY_IS_ACCOUNT (folder_store)) {
1140                 /* Use the folder store as an account: */
1141                 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1142         }
1143
1144         return result;
1145 }
1146
1147 GtkWidget *
1148 modest_platform_create_sort_dialog       (GtkWindow *parent_window)
1149 {
1150         return NULL;
1151
1152 }
1153
1154
1155 gboolean 
1156 modest_platform_set_update_interval (guint minutes)
1157 {
1158         return TRUE;
1159 }
1160
1161 void
1162 modest_platform_push_email_notification(void)
1163 {
1164         return;
1165 }
1166
1167 void
1168 modest_platform_on_new_headers_received (GList *URI_list,
1169                                          gboolean show_visual)
1170 {
1171         return;
1172 }
1173
1174 void
1175 modest_platform_remove_new_mail_notifications (gboolean only_visuals) 
1176 {
1177         return;
1178 }
1179
1180
1181
1182 GtkWidget * 
1183 modest_platform_get_global_settings_dialog ()
1184 {
1185         return modest_default_global_settings_dialog_new ();
1186 }
1187
1188 void
1189 modest_platform_show_help (GtkWindow *parent_window, 
1190                            const gchar *help_id)
1191 {
1192         return;
1193 }
1194
1195 void 
1196 modest_platform_show_search_messages (GtkWindow *parent_window)
1197 {
1198         return;
1199 }
1200
1201 void 
1202 modest_platform_show_addressbook (GtkWindow *parent_window)
1203 {
1204         return;
1205 }
1206
1207 static GtkWidget *
1208 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1209 {
1210         GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1211
1212         /* Show one account by default */
1213         modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1214                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1215
1216         return widget;
1217 }
1218
1219 GtkWidget *
1220 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1221 {
1222         return modest_platform_create_folder_view_full (query, TRUE);
1223 }
1224
1225 void
1226 banner_finish (gpointer data, GObject *object)
1227 {
1228         ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1229         modest_window_mgr_unregister_banner (mgr);
1230         g_object_unref (mgr);
1231 }
1232
1233 void 
1234 modest_platform_information_banner (GtkWidget *parent,
1235                                     const gchar *icon_name,
1236                                     const gchar *text)
1237 {
1238         GtkWidget *banner;
1239
1240         banner = modest_shell_banner_new (parent);
1241         modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1242         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1243
1244         return;
1245 }
1246
1247 void 
1248 modest_platform_system_banner (GtkWidget *parent,
1249                                const gchar *icon_name,
1250                                const gchar *text)
1251 {
1252         modest_platform_information_banner (parent, icon_name, text);
1253 }
1254
1255 void
1256 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1257                                                  const gchar *icon_name,
1258                                                  const gchar *text,
1259                                                  gint timeout)
1260 {
1261         GtkWidget *banner;
1262
1263         banner = modest_shell_banner_new_with_timeout (parent, timeout);
1264         modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1265         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1266
1267         return;
1268 }
1269
1270 GtkWidget *
1271 modest_platform_animation_banner (GtkWidget *parent,
1272                                   const gchar *animation_name,
1273                                   const gchar *text)
1274 {
1275         GtkWidget *banner;
1276
1277         banner = modest_shell_banner_new_with_timeout (parent, 0);
1278         modest_shell_banner_set_animation (MODEST_SHELL_BANNER (banner), animation_name);
1279         modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1280
1281         return banner;
1282 }
1283
1284 typedef struct
1285 {
1286         GMainLoop* loop;
1287         TnyAccount *account;
1288         gboolean is_online;
1289         gint count_tries;
1290 } CheckAccountIdleData;
1291
1292 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1293
1294 static gboolean 
1295 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1296 {
1297         gboolean stop_trying = FALSE;
1298         g_return_val_if_fail (data && data->account, FALSE);
1299
1300         if (data && data->account && 
1301                 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1302                  * after which the account is likely to be usable, or never likely to be usable soon: */
1303                 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1304         {
1305                 data->is_online = TRUE;
1306
1307                 stop_trying = TRUE;
1308         } else {
1309                 /* Give up if we have tried too many times: */
1310                 if (data->count_tries >= NUMBER_OF_TRIES) {
1311                         stop_trying = TRUE;
1312                 } else {
1313                         /* Wait for another timeout: */
1314                         ++(data->count_tries);
1315                 }
1316         }
1317
1318         if (stop_trying) {
1319                 /* Allow the function that requested this idle callback to continue: */
1320                 if (data->loop)
1321                         g_main_loop_quit (data->loop);
1322
1323                 if (data->account)
1324                         g_object_unref (data->account);
1325
1326                 return FALSE; /* Don't call this again. */
1327         } else {
1328                 return TRUE; /* Call this timeout callback again. */
1329         }
1330 }
1331
1332 /* Return TRUE immediately if the account is already online,
1333  * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as 
1334  * soon as the account is online, or FALSE if the account does 
1335  * not become online in the NUMBER_OF_TRIES seconds.
1336  * This is useful when the D-Bus method was run immediately after 
1337  * the application was started (when using D-Bus activation), 
1338  * because the account usually takes a short time to go online.
1339  * The return value is maybe not very useful.
1340  */
1341 gboolean
1342 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1343 {
1344         gboolean is_online;
1345
1346         g_return_val_if_fail (account, FALSE);
1347
1348         if (!tny_device_is_online (modest_runtime_get_device())) {
1349                 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1350                 return FALSE;
1351         }
1352
1353         /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1354          * so we avoid wait unnecessarily: */
1355         if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1356                 return TRUE;
1357
1358         /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED, 
1359          * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that 
1360          * we want to avoid. */
1361         if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1362                 return TRUE;
1363                 
1364         /* This blocks on the result: */
1365         CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1366         data->is_online = FALSE;
1367         data->account = account;
1368         g_object_ref (data->account);
1369         data->count_tries = 0;
1370                 
1371         GMainContext *context = NULL; /* g_main_context_new (); */
1372         data->loop = g_main_loop_new (context, FALSE /* not running */);
1373
1374         g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1375
1376         /* This main loop will run until the idle handler has stopped it: */
1377         g_main_loop_run (data->loop);
1378
1379         g_main_loop_unref (data->loop);
1380         /* g_main_context_unref (context); */
1381
1382         is_online = data->is_online;
1383         g_slice_free (CheckAccountIdleData, data);
1384         
1385         return is_online;       
1386 }
1387
1388
1389
1390 static void
1391 on_cert_dialog_response (GtkDialog *dialog, gint response_id,  const gchar* cert)
1392 {
1393         /* GTK_RESPONSE_HELP means we need to show the certificate */
1394         if (response_id == GTK_RESPONSE_APPLY) {
1395                 gchar *msg;
1396                 
1397                 /* Do not close the dialog */
1398                 g_signal_stop_emission_by_name (dialog, "response");
1399
1400                 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);    
1401                 modest_platform_run_information_dialog (NULL, msg, TRUE);
1402         }
1403 }
1404
1405
1406 gboolean
1407 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1408                                                      const gchar *certificate)
1409 {
1410         GtkWidget *note;
1411         gint response;
1412
1413         
1414         gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1415                                            server_name);
1416
1417         /* We use GTK_RESPONSE_APPLY because we want the button in the
1418            middle of OK and CANCEL the same as the browser does for
1419            example. With GTK_RESPONSE_HELP the view button is aligned
1420            to the left while the other two to the right */
1421         note = gtk_message_dialog_new  (
1422                 NULL,
1423                 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1424                 GTK_MESSAGE_QUESTION,
1425                 GTK_BUTTONS_NONE,
1426                 question);
1427         gtk_dialog_add_buttons (GTK_DIALOG (note),
1428                                 _HL_YES,     GTK_RESPONSE_OK,
1429                                 _HL_VIEW,          GTK_RESPONSE_APPLY,   /* abusing this... */
1430                                 _HL_NO, GTK_RESPONSE_CANCEL,
1431                                 NULL, NULL);
1432
1433         g_signal_connect (G_OBJECT(note), "response",
1434                           G_CALLBACK(on_cert_dialog_response),
1435                           (gpointer) certificate);
1436
1437         response = gtk_dialog_run(GTK_DIALOG(note));
1438
1439         on_destroy_dialog (note);
1440         g_free (question);
1441
1442         return response == GTK_RESPONSE_OK;
1443 }
1444
1445 gboolean
1446 modest_platform_run_alert_dialog (const gchar* prompt,
1447                                   gboolean is_question)
1448 {
1449
1450         gboolean retval = TRUE;
1451         if (is_question) {
1452                 GtkWidget *dialog;
1453                 /* The Tinymail documentation says that we should show Yes and No buttons,
1454                  * when it is a question.
1455                  * Obviously, we need tinymail to use more specific error codes instead,
1456                  * so we know what buttons to show. */
1457                 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1458                                                  GTK_MESSAGE_QUESTION,
1459                                                  GTK_BUTTONS_YES_NO,
1460                                                  prompt);
1461
1462                 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1463                 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1464
1465                 on_destroy_dialog (dialog);
1466         } else {
1467                 /* Just show the error text and use the default response: */
1468                 modest_platform_run_information_dialog (NULL, 
1469                                                         prompt, FALSE);
1470         }
1471         return retval;
1472 }
1473
1474 /***************/
1475 typedef struct {
1476         ModestWindow *parent_window;
1477         ModestConnectedPerformer callback;
1478         TnyAccount *account;
1479         gpointer user_data;
1480         gchar *iap;
1481         TnyDevice *device;
1482 } OnWentOnlineInfo;
1483  
1484 static void 
1485 on_went_online_info_free (OnWentOnlineInfo *info)
1486 {
1487         /* And if we cleanup, we DO cleanup  :-)  */
1488         
1489         if (info->device)
1490                 g_object_unref (info->device);
1491         if (info->iap)
1492                 g_free (info->iap);
1493         if (info->parent_window)
1494                 g_object_unref (info->parent_window);
1495         if (info->account)
1496                 g_object_unref (info->account);
1497         
1498         g_slice_free (OnWentOnlineInfo, info);
1499         
1500         /* We're done ... */
1501         
1502         return;
1503 }
1504  
1505 static void
1506 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1507 {
1508         OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1509  
1510         /* Now it's really time to callback to the caller. If going online didn't succeed,
1511          * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1512          * canceled will be set. Etcetera etcetera. */
1513         
1514         if (info->callback) {
1515                 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1516         }
1517         
1518         /* This is our last call, we must cleanup here if we didn't yet do that */
1519         on_went_online_info_free (info);
1520         
1521         return;
1522 }
1523  
1524 void 
1525 modest_platform_connect_and_perform (ModestWindow *parent_window,
1526                                      gboolean force,
1527                                      TnyAccount *account, 
1528                                      ModestConnectedPerformer callback, 
1529                                      gpointer user_data)
1530 {
1531         gboolean device_online;
1532         TnyDevice *device;
1533         TnyConnectionStatus conn_status;
1534         
1535         device = modest_runtime_get_device();
1536         device_online = tny_device_is_online (device);
1537
1538         /* If there is no account check only the device status */
1539         if (!account) {
1540                 
1541                 if (device_online) {
1542  
1543                         /* We promise to instantly perform the callback, so ... */
1544                         if (callback) {
1545                                 callback (FALSE, NULL, parent_window, account, user_data);
1546                         }
1547                         
1548                 } else {
1549                         
1550                 }
1551  
1552                 /* The other code has no more reason to run. This is all that we can do for the
1553                  * caller (he should have given us a nice and clean account instance!). We
1554                  * can't do magic, we don't know what account he intends to bring online. So
1555                  * we'll just bring the device online (and await his false bug report). */
1556                 
1557                 return;
1558         }
1559  
1560         
1561         /* Return if the account is already connected */
1562         
1563         conn_status = tny_account_get_connection_status (account);
1564         if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1565
1566                 /* We promise to instantly perform the callback, so ... */
1567                 if (callback) {
1568                         callback (FALSE, NULL, parent_window, account, user_data);
1569                 }
1570
1571                 return;
1572         }
1573
1574         if (!device_online) {
1575                 OnWentOnlineInfo *info = NULL;
1576
1577                 info = g_slice_new0 (OnWentOnlineInfo);
1578
1579                 info->device = NULL;
1580                 info->iap = NULL;
1581                 info->account = TNY_ACCOUNT (g_object_ref (account));
1582
1583                 if (parent_window)
1584                         info->parent_window = (ModestWindow *) g_object_ref (parent_window);
1585                 else
1586                         info->parent_window = NULL;
1587
1588                 /* So we'll put the callback away for later ... */
1589                 info->user_data = user_data;
1590                 info->callback = callback;
1591
1592                 /* If the device is online, we'll just connect the account */
1593                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1594                                               on_account_went_online, info);
1595         }
1596
1597         /* The info gets freed by on_account_went_online or on_conic_device_went_online
1598          * in both situations, go look if you don't believe me! */
1599 }
1600
1601 void
1602 modest_platform_connect_if_remote_and_perform (ModestWindow *parent_window,
1603                                                gboolean force,
1604                                                TnyFolderStore *folder_store, 
1605                                                ModestConnectedPerformer callback, 
1606                                                gpointer user_data)
1607 {
1608         TnyAccount *account = NULL;
1609
1610         if (!folder_store ||
1611             (TNY_IS_MERGE_FOLDER (folder_store) &&
1612              (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1613
1614                 /* We promise to instantly perform the callback, so ... */
1615                 if (callback) {
1616                         GError *error = NULL;
1617                         g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1618                                      "Unable to move or not found folder");
1619                         callback (FALSE, error, parent_window, NULL, user_data);
1620                         g_error_free (error);
1621                 }
1622                 return;
1623
1624         } else if (TNY_IS_FOLDER (folder_store)) {
1625                 /* Get the folder's parent account: */
1626                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1627         } else if (TNY_IS_ACCOUNT (folder_store)) {
1628                 /* Use the folder store as an account: */
1629                 account = TNY_ACCOUNT (g_object_ref (folder_store));
1630         }
1631
1632         if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1633                 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1634                         /* No need to connect a local account */
1635                         if (callback)
1636                                 callback (FALSE, NULL, parent_window, account, user_data);
1637
1638                         goto clean;
1639                 }
1640         }
1641         modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1642
1643  clean:
1644         if (account)
1645                 g_object_unref (account);
1646 }
1647
1648 static void
1649 src_account_connect_performer (gboolean canceled,
1650                                GError *err,
1651                                ModestWindow *parent_window,
1652                                TnyAccount *src_account,
1653                                gpointer user_data)
1654 {
1655         DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1656
1657         if (canceled || err) {
1658                 /* If there was any error call the user callback */
1659                 info->callback (canceled, err, parent_window, src_account, info->data);
1660         } else {
1661                 /* Connect the destination account */
1662                 modest_platform_connect_if_remote_and_perform (parent_window, TRUE, 
1663                                                                TNY_FOLDER_STORE (info->dst_account),
1664                                                                info->callback, info->data);
1665         }
1666
1667         /* Free the info object */
1668         g_object_unref (info->dst_account);
1669         g_slice_free (DoubleConnectionInfo, info);
1670 }
1671
1672
1673 void 
1674 modest_platform_double_connect_and_perform (ModestWindow *parent_window,
1675                                             gboolean force,
1676                                             TnyFolderStore *folder_store,
1677                                             DoubleConnectionInfo *connect_info)
1678 {
1679         modest_platform_connect_if_remote_and_perform(parent_window,
1680                                                       force,
1681                                                       folder_store, 
1682                                                       src_account_connect_performer, 
1683                                                       connect_info);
1684 }
1685
1686 GtkWidget *
1687 modest_platform_get_account_settings_wizard (void)
1688 {
1689         ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1690
1691         return GTK_WIDGET (dialog);
1692 }
1693
1694 ModestConnectedVia
1695 modest_platform_get_current_connection (void)
1696 {
1697         TnyDevice *device = NULL;
1698         ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1699         
1700         device = modest_runtime_get_device ();
1701
1702         if (!tny_device_is_online (device))
1703                 return MODEST_CONNECTED_VIA_ANY;
1704
1705         retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */  
1706         return retval;
1707 }
1708
1709
1710
1711 gboolean
1712 modest_platform_check_memory_low (ModestWindow *win,
1713                                   gboolean visuals)
1714 {
1715         return FALSE;
1716         
1717 }
1718
1719 void 
1720 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1721                                            TnyFolder *folder)
1722 {
1723         GtkWidget *dialog;
1724         
1725         /* Create dialog */
1726         dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1727                                                                            parent_window, folder);
1728
1729         /* Run dialog */
1730         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
1731                                      GTK_WINDOW (dialog), 
1732                                      parent_window);
1733         gtk_widget_show_all (dialog);
1734
1735         g_signal_connect_swapped (dialog, "response", 
1736                                   G_CALLBACK (gtk_widget_destroy),
1737                                   dialog);
1738 }
1739
1740 typedef struct _HeaderDetailsGetSizeInfo {
1741         GtkWidget *dialog;
1742         TnyMimePart *part;
1743         guint total;
1744 } HeaderDetailsGetSizeInfo;
1745
1746 static void 
1747 header_details_dialog_destroy (gpointer userdata,
1748                                GObject *object)
1749 {
1750         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1751
1752         info->dialog = NULL;
1753 }
1754
1755 static gboolean
1756 idle_get_mime_part_size_cb (gpointer userdata)
1757 {
1758         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1759         gdk_threads_enter ();
1760
1761         if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1762                 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1763                                                         info->total);
1764         }
1765
1766         if (info->dialog) {
1767                 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1768                 info->dialog = NULL;
1769         }
1770         g_object_unref (info->part);
1771         g_slice_free (HeaderDetailsGetSizeInfo, info);
1772
1773         gdk_threads_leave ();
1774
1775         return FALSE;
1776 }
1777
1778 static gpointer
1779 get_mime_part_size_thread (gpointer thr_user_data)
1780 {
1781         HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1782         gssize result = 0;
1783         TnyStream *count_stream;
1784
1785         count_stream = modest_count_stream_new ();
1786         result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1787         info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1788         if (info->total == 0) {
1789                 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1790                 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1791                 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1792         }
1793         
1794         /* if there was an error, don't set the size (this is pretty uncommon) */
1795         if (result < 0) {
1796                 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1797         }
1798         g_idle_add (idle_get_mime_part_size_cb, info);
1799
1800         return NULL;
1801 }
1802
1803 void
1804 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1805                                            TnyHeader *header,
1806                                            gboolean async_get_size,
1807                                            TnyMsg *msg)
1808 {
1809         GtkWidget *dialog;
1810
1811         /* Create dialog */
1812         dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1813                                                                            parent_window, header, !async_get_size);
1814
1815         if (async_get_size && msg && TNY_IS_MSG (msg)) {
1816                 HeaderDetailsGetSizeInfo *info;
1817                 info = g_slice_new (HeaderDetailsGetSizeInfo);
1818                 info->dialog = dialog;
1819                 info->total = 0;
1820                 info->part = TNY_MIME_PART (g_object_ref (msg));
1821
1822                 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1823                 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1824         }
1825
1826         /* Run dialog */
1827         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1828                                      GTK_WINDOW (dialog),
1829                                      parent_window);
1830         gtk_widget_show_all (dialog);
1831
1832         g_signal_connect_swapped (dialog, "response", 
1833                                   G_CALLBACK (gtk_widget_destroy),
1834                                   dialog);
1835 }
1836
1837 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1838 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1839 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1840 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1841 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1842 #define MOVE_TO_FOLDER_SEPARATOR "/"
1843
1844 static void
1845 translate_path (gchar **path)
1846 {
1847         gchar **parts;
1848         gchar **current;
1849         GString *output;
1850         gboolean add_separator;
1851
1852         parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1853         g_free (*path);
1854
1855         current = parts;
1856         output = g_string_new ("");
1857         add_separator = FALSE;
1858
1859         while (*current != NULL) {
1860                 TnyFolderType folder_type;
1861                 gchar *downcase;
1862
1863                 if (add_separator) {
1864                         output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1865                 } else {
1866                         add_separator = TRUE;
1867                 }
1868
1869                 downcase = g_ascii_strdown (*current, -1);
1870                 folder_type = modest_local_folder_info_get_type (downcase);
1871                 if (strcmp (downcase, "inbox") == 0) {
1872                         output = g_string_append (output, _("mcen_me_folder_inbox"));
1873                 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1874                     folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1875                     folder_type == TNY_FOLDER_TYPE_SENT ||
1876                     folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1877                         output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1878                 } else {
1879                         output = g_string_append (output, *current);
1880                 }
1881                 g_free (downcase);
1882
1883                 current++;
1884         }
1885
1886         g_strfreev (parts);
1887         *path = g_string_free (output, FALSE);
1888 }
1889
1890 static void
1891 move_to_dialog_set_selected_folder_store (GtkWidget *dialog, 
1892                                           TnyFolderStore *folder_store)
1893 {
1894         GtkWidget *action_button;
1895         GtkWidget *image = NULL;
1896         TnyAccount *account;
1897         gchar *account_name = NULL, *short_name = NULL;
1898
1899         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1900
1901         /* Get account name */
1902         if (TNY_IS_FOLDER (folder_store))
1903                 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1904         else
1905                 account = g_object_ref (folder_store);
1906
1907         if (modest_tny_account_is_virtual_local_folders (account))
1908                 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1909                                                        MODEST_CONF_DEVICE_NAME, NULL);
1910
1911         if (!account_name)
1912                 account_name = g_strdup (tny_account_get_name (account));
1913
1914         g_object_unref (account);
1915
1916         /* Set title of button: account or folder name */
1917         if (TNY_IS_FOLDER (folder_store))
1918                 short_name = folder_store_get_display_name (folder_store);
1919         else
1920                 short_name = g_strdup (account_name);
1921
1922         gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1923
1924         /* Set value of button, folder full name */
1925         if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1926                 const gchar *camel_full_name;
1927                 gchar *last_slash, *full_name;
1928
1929                 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1930                 last_slash = g_strrstr (camel_full_name, "/");
1931                 if (last_slash) {
1932                         gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1933                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1934                         g_free (prefix);
1935                 } else {
1936                         full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1937                                                  short_name,
1938                                                  NULL);
1939                 }
1940                 translate_path (&full_name);
1941                 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1942                 g_free (full_name);
1943         }
1944         g_free (account_name);
1945         g_free (short_name);
1946
1947         /* Set image for the button */
1948         image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1949         if (image)
1950                 gtk_button_set_image (GTK_BUTTON (action_button), image);
1951 }
1952
1953 static void
1954 move_to_dialog_show_accounts (GtkWidget *dialog)
1955 {
1956         GtkWidget *back_button;
1957         GtkWidget *folder_view;
1958         GtkWidget *scrollable;
1959         GtkWidget *action_button;
1960
1961         back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1962         action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1963         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1964         scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1965
1966         gtk_widget_set_sensitive (back_button, FALSE);
1967         gtk_widget_set_sensitive (action_button, FALSE);
1968
1969         /* Need to set this here, otherwise callbacks called because
1970            of filtering won't perform correctly */
1971         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1972
1973         /* Reset action button */
1974         gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1975         gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1976
1977         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1978         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1979         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1980         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1981                                          MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1982         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1983                                        MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1984         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), 
1985                                          MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1986         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), 
1987                                        MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1988         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1989 }
1990
1991 static void
1992 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1993 {
1994         GtkWidget *back_button;
1995         GtkWidget *folder_view;
1996         TnyAccount *account;
1997         const gchar *account_id;
1998         GtkWidget *scrollable;
1999         GtkWidget *action_button;
2000
2001         back_button =
2002                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
2003         action_button =
2004                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
2005         folder_view =
2006                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2007         scrollable =
2008                 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
2009
2010         gtk_widget_set_sensitive (back_button, TRUE);
2011         gtk_widget_set_sensitive (action_button, TRUE);
2012
2013         /* Need to set this here, otherwise callbacks called because
2014            of filtering won't perform correctly */
2015         g_object_set_data (G_OBJECT (dialog),
2016                            MOVE_TO_DIALOG_SHOWING_FOLDERS,
2017                            GINT_TO_POINTER (TRUE));
2018
2019         account = TNY_ACCOUNT (folder_store);
2020         if (modest_tny_account_is_virtual_local_folders (account)) {
2021                 account_id = tny_account_get_id (account);
2022                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2023                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2024         } else if (modest_tny_account_is_memory_card_account (account)) {
2025                 account_id = tny_account_get_id (account);
2026                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2027                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2028         } else {
2029                 account_id = tny_account_get_id (account);
2030                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2031                                                MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2032                 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2033                                                MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2034         }
2035
2036         move_to_dialog_set_selected_folder_store (dialog, folder_store);
2037         modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2038                                                                      account_id);
2039
2040         modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2041         modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2042         modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2043         modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2044         modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
2045 }
2046
2047 static void
2048 on_move_to_dialog_back_clicked (GtkButton *button,
2049                                 gpointer userdata)
2050 {
2051         GtkWidget *dialog = (GtkWidget *) userdata;
2052
2053         /* Back to show accounts */
2054         move_to_dialog_show_accounts (dialog);
2055 }
2056
2057 static void
2058 on_move_to_dialog_row_activated (GtkTreeView       *tree_view,
2059                                     GtkTreePath       *path,
2060                                     GtkTreeViewColumn *column,
2061                                     gpointer           user_data)
2062 {
2063         TnyFolderStore *selected = NULL;
2064         GtkWidget *dialog;
2065         GtkWidget *folder_view;
2066         gboolean showing_folders;
2067
2068         dialog = (GtkWidget *) user_data;
2069         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), 
2070                                                               MOVE_TO_DIALOG_SHOWING_FOLDERS));
2071
2072         folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), 
2073                                                      MOVE_TO_DIALOG_FOLDER_VIEW));
2074
2075         selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2076         if (!selected)
2077                 return;
2078
2079         if (!showing_folders) {
2080                 gboolean valid = TRUE;
2081
2082                 if (TNY_IS_ACCOUNT (selected) &&
2083                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2084                         ModestProtocolType protocol_type;
2085
2086                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2087                         valid  = !modest_protocol_registry_protocol_type_has_tag 
2088                                 (modest_runtime_get_protocol_registry (),
2089                                  protocol_type,
2090                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2091                 }
2092                 if (valid)
2093                         move_to_dialog_show_folders (dialog, selected);
2094         } else {
2095                 move_to_dialog_set_selected_folder_store (dialog, selected);
2096         }
2097         g_object_unref (selected);
2098 }
2099
2100 static void
2101 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2102                                      gpointer          user_data)
2103 {
2104         gboolean showing_folders;
2105         GtkWidget *dialog;
2106
2107         dialog = (GtkWidget *) user_data;
2108         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2109         if (showing_folders) {
2110                 TnyFolderStore *selected;
2111                 GtkWidget *folder_view;
2112
2113                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2114                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2115
2116                 if (selected) {
2117                         move_to_dialog_set_selected_folder_store (dialog, selected);
2118                         g_object_unref (selected);
2119                 }
2120         }
2121 }
2122
2123 static void
2124 on_move_to_dialog_action_clicked (GtkButton *selection,
2125                                   gpointer   user_data)
2126 {
2127         GtkWidget *dialog;
2128         gboolean showing_folders;
2129
2130         dialog = (GtkWidget *) user_data;
2131         showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2132         if (showing_folders) {
2133                 TnyFolderStore *selected;
2134                 GtkWidget *folder_view;
2135
2136                 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2137                 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2138
2139                 if (selected) {
2140                         /* It's not possible to select root folders as
2141                            targets unless they're the local account or
2142                            the memory card account */
2143                         if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2144                             (TNY_IS_ACCOUNT (selected) &&
2145                              (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2146                               modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2147                                 gtk_dialog_response  (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2148                         g_object_unref (selected);
2149                 }
2150         }
2151 }
2152
2153 static void
2154 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2155 {
2156 }
2157
2158 GtkWidget *
2159 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2160                                        GtkWidget **folder_view)
2161 {
2162         GtkWidget *dialog, *folder_view_container;
2163         GtkWidget *align;
2164         GtkWidget *buttons_hbox;
2165         GtkWidget *back_button;
2166         GdkPixbuf *back_pixbuf;
2167         GtkWidget *top_vbox;
2168         GtkWidget *action_button;
2169         GtkTreeSelection *selection;
2170
2171         /* Create dialog. We cannot use a touch selector because we
2172            need to use here the folder view widget directly */
2173         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2174                                               GTK_WINDOW (parent_window),
2175                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2176                                               GTK_DIALOG_DESTROY_WITH_PARENT,
2177                                               _FM_CHANGE_FOLDER_NEW_FOLDER,
2178                                               MODEST_GTK_RESPONSE_NEW_FOLDER,
2179                                               NULL);
2180
2181         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2182         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2183         top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2184
2185         /* Create folder view */
2186         *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2187         g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2188                           dialog);
2189
2190         modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2191                                            MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2192         modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2193                                                FALSE);
2194         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2195                                                   (TnyAccountStore *) modest_runtime_get_account_store ());
2196
2197         buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2198         back_button = gtk_button_new ();
2199         back_pixbuf = modest_platform_get_icon (_FM_FOLDER_UP, MODEST_ICON_SIZE_BIG);
2200         if (back_pixbuf) {
2201                 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2202                 g_object_unref (back_pixbuf);
2203         }
2204
2205         action_button = gtk_button_new ();
2206         gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2207
2208         gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2209         gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2210         gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2211         gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2212         gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2213
2214         /* Create scrollable and add it to the dialog */
2215         folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2216         gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2217         gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2218
2219         gtk_container_add (GTK_CONTAINER (align), top_vbox);
2220         gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2221
2222         gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2223
2224         gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2225         gtk_widget_show (folder_view_container);
2226         gtk_widget_show (align);
2227         gtk_widget_show (top_vbox);
2228         gtk_widget_show (*folder_view);
2229         gtk_widget_show_all (back_button);
2230         gtk_widget_show (action_button);
2231         gtk_widget_show (buttons_hbox);
2232         gtk_widget_show (dialog);
2233
2234         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2235         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2236         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2237         g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2238
2239         /* Simulate the behaviour of a HildonPickerDialog by emitting
2240            a response when a folder is selected */
2241         g_signal_connect (*folder_view, "row-activated",
2242                           G_CALLBACK (on_move_to_dialog_row_activated),
2243                           dialog);
2244
2245         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2246         g_signal_connect (selection, "changed",
2247                           G_CALLBACK (on_move_to_dialog_selection_changed),
2248                           dialog);
2249
2250         g_signal_connect (action_button, "clicked",
2251                           G_CALLBACK (on_move_to_dialog_action_clicked),
2252                           dialog);
2253
2254         g_signal_connect (back_button, "clicked",
2255                           G_CALLBACK (on_move_to_dialog_back_clicked),
2256                           dialog);
2257
2258         move_to_dialog_show_accounts (dialog);
2259
2260         return dialog;
2261 }
2262
2263 TnyList *
2264 modest_platform_get_list_to_move (ModestWindow *window)
2265 {
2266         TnyList *list = NULL;
2267
2268         if (MODEST_IS_HEADER_WINDOW (window)) {
2269                 ModestHeaderView *header_view;
2270
2271                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2272                 list = modest_header_view_get_selected_headers (header_view);
2273         } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2274                 ModestFolderView *folder_view;
2275                 TnyFolderStore *selected_folder;
2276
2277                 list = TNY_LIST (tny_simple_list_new ());
2278                 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2279                 selected_folder = modest_folder_view_get_selected (folder_view);
2280                 if (selected_folder) {
2281                         tny_list_prepend (list, G_OBJECT (selected_folder));
2282                         g_object_unref (selected_folder);
2283                 }
2284                 return list;
2285         } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2286                 TnyHeader *header;
2287
2288                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2289                 if (header) {
2290                         list = TNY_LIST (tny_simple_list_new ());
2291                         tny_list_prepend (list, G_OBJECT (header));
2292                         g_object_unref (header);
2293                 }
2294         } else {
2295                 g_return_val_if_reached (NULL);
2296         }
2297
2298         return list;
2299 }