1/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
2 *
3 * Copyright (C) 2011,2012 Canonical Ltd
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Robert Ancell <robert.ancell@canonical.com>
18 *          Michael Terry <michael.terry@canonical.com>
19 */
20
21int remote_server_field_sort_function (RemoteServerField? item1, RemoteServerField? item2)
22{
23    string[] sorted_fields = { "domain", "username", "email", "password" };
24    foreach (var field in sorted_fields)
25    {
26        if (item1.type == field)
27            return -1;
28        if (item2.type == field)
29            return 1;
30    }
31
32    return (item1.type < item2.type) ? -1 : 0;
33}
34
35public class UserList : GreeterList
36{
37    private bool _offer_guest = false;
38    public bool offer_guest
39    {
40        get { return _offer_guest; }
41        set
42        {
43            _offer_guest = value;
44            if (value)
45                add_user ("*guest", _("Guest Session"));
46            else
47                remove_entry ("*guest");
48        }
49    }
50
51    private Gdk.Pixbuf message_pixbuf;
52
53    private uint change_background_timeout = 0;
54
55    private uint remote_login_service_watch;
56    private RemoteLoginService remote_login_service;
57    private List<RemoteServer?> remote_directory_server_list = new List<RemoteServer?> ();
58    private List<RemoteServer?> remote_login_server_list = new List<RemoteServer?> ();
59    private HashTable<string, Gtk.Widget> current_remote_fields;
60    private string currently_browsing_server_url;
61    private string currently_browsing_server_email;
62    private EmailAutocompleter remote_server_email_field_autocompleter;
63
64    /* User to authenticate against */
65    private string ?authenticate_user = null;
66
67    private bool show_hidden_users_ = false;
68    public bool show_hidden_users
69    {
70        set
71        {
72            show_hidden_users_ = value;
73
74            if (SlickGreeter.singleton.test_mode)
75            {
76                if (value)
77                    add_user ("hidden", "Hidden User", null, false, false, null);
78                else
79                    remove_entry ("hidden");
80                return;
81            }
82
83            var hidden_users = UGSettings.get_strv (UGSettings.KEY_HIDDEN_USERS);
84            if (!value)
85            {
86                foreach (var username in hidden_users)
87                    remove_entry (username);
88                return;
89            }
90
91            var users = LightDM.UserList.get_instance ();
92            foreach (var user in users.users)
93            {
94                foreach (var username in hidden_users)
95                {
96                    if (user.name == username)
97                    {
98                        debug ("Showing hidden user %s", username);
99                        user_added_cb (user);
100                    }
101                }
102            }
103        }
104
105        get
106        {
107            return show_hidden_users_;
108        }
109    }
110
111    private string _default_session = "gnome";
112    public string default_session
113    {
114        get
115        {
116            return _default_session;
117        }
118        set
119        {
120            _default_session = value;
121            if (selected_entry != null)
122                selected_entry.set_options_image (get_badge ());
123        }
124    }
125
126    private string? _session = null;
127    public string? session
128    {
129        get
130        {
131            return _session;
132        }
133        set
134        {
135            _session = value;
136            if (selected_entry != null)
137                selected_entry.set_options_image (get_badge ());
138        }
139    }
140
141    public UserList (Background bg, MenuBar mb)
142    {
143        Object (background: bg, menubar: mb);
144    }
145
146    construct
147    {
148        menubar.notify["high-contrast"].connect (() => { change_background (); });
149        entry_displayed_start.connect (() => { change_background (); });
150        entry_displayed_done.connect (() => { change_background (); });
151
152        try
153        {
154            message_pixbuf = new Gdk.Pixbuf.from_file (Path.build_filename (Config.PKGDATADIR, "message.png", null));
155        }
156        catch (Error e)
157        {
158            debug ("Error loading message image: %s", e.message);
159        }
160
161        fill_list ();
162
163        entry_selected.connect (entry_selected_cb);
164
165        connect_to_lightdm ();
166
167        if (!SlickGreeter.singleton.test_mode &&
168            SlickGreeter.singleton.show_remote_login_hint ())
169            remote_login_service_watch = Bus.watch_name (BusType.SESSION,
170                                            "com.canonical.RemoteLogin",
171                                            BusNameWatcherFlags.AUTO_START,
172                                            on_remote_login_service_appeared,
173                                            on_remote_login_service_vanished);
174
175    }
176
177    private void remove_remote_servers ()
178    {
179        remote_directory_server_list = new List<RemoteServer?> ();
180        remote_login_server_list = new List<RemoteServer?> ();
181        remove_entries_with_prefix ("*remote");
182    }
183
184    private void remove_remote_login_servers ()
185    {
186        remote_login_server_list = new List<RemoteServer?> ();
187        remove_entries_with_prefix ("*remote_login");
188
189        /* If we have no entries at all, we should show manual */
190        if (!always_show_manual)
191            add_manual_entry ();
192    }
193
194    private async void query_directory_servers ()
195    {
196        try
197        {
198            RemoteServer[] server_list;
199            yield remote_login_service.get_servers (out server_list);
200            set_remote_directory_servers (server_list);
201        }
202        catch (Error e)
203        {
204            debug ("Calling GetServers on com.canonical.RemoteLogin dbus service failed. Error: %s", e.message);
205            remove_remote_servers ();
206        }
207    }
208
209    private string user_list_name_for_remote_directory_server (RemoteServer remote_server)
210    {
211        return "*remote_directory*" + remote_server.url;
212    }
213
214    private string username_from_remote_server_fields(RemoteServer remote_server)
215    {
216        var username = "";
217        foreach (var f in remote_server.fields)
218        {
219            if (f.type == "username" && f.default_value != null)
220            {
221                username = f.default_value.get_string ();
222                break;
223            }
224        }
225        return username;
226     }
227
228    private string user_list_name_for_remote_login_server (RemoteServer remote_server)
229    {
230        var username = username_from_remote_server_fields (remote_server);
231        return "*remote_login*" + remote_server.url + "*" + username;
232    }
233
234    private string url_from_remote_loding_server_list_name (string remote_server_list_name)
235    {
236        return remote_server_list_name.split ("*")[2];
237    }
238
239    private string username_from_remote_loding_server_list_name (string remote_server_list_name)
240    {
241        return remote_server_list_name.split ("*")[3];
242    }
243
244    private void set_remote_directory_servers (RemoteServer[] server_list)
245    {
246        /* Add new servers */
247        foreach (var remote_server in server_list)
248        {
249            var list_name = user_list_name_for_remote_directory_server (remote_server);
250            if (find_entry (list_name) == null)
251            {
252                var e = new PromptBox (list_name);
253                e.label = remote_server.name;
254                e.respond.connect (remote_directory_respond_cb);
255                e.show_options.connect (show_remote_account_dialog);
256                add_entry (e);
257
258                remote_directory_server_list.append (remote_server);
259            }
260        }
261
262        /* Remove gone servers */
263        unowned List<RemoteServer?> it = remote_directory_server_list;
264        while (it != null)
265        {
266            var remote_server = it.data;
267            var found = false;
268            for (int i = 0; !found && i < server_list.length; i++)
269            {
270                found = remote_server.url == server_list[i].url;
271            }
272            if (!found)
273            {
274                if (remote_server.url == currently_browsing_server_url)
275                {
276                    /* The server we where "browsing" disappeared, so kill its children */
277                    remove_remote_login_servers ();
278                    currently_browsing_server_url = "";
279                    currently_browsing_server_email = "";
280                }
281                remove_entry (user_list_name_for_remote_directory_server (remote_server));
282                unowned List<RemoteServer?> newIt = it.next;
283                remote_directory_server_list.delete_link (it);
284                it = newIt;
285            }
286            else
287            {
288                it = it.next;
289            }
290        }
291
292        /* Remove manual option unless specified */
293        if (remote_directory_server_list.length() > 0 && !always_show_manual) {
294            debug ("removing manual login since we have a remote login entry");
295            remove_entry ("*other");
296        }
297    }
298
299    private PromptBox create_prompt_for_login_server (RemoteServer remote_server)
300    {
301        var e = new PromptBox (user_list_name_for_remote_login_server (remote_server));
302        e.label = remote_server.name;
303        e.respond.connect (remote_login_respond_cb);
304        add_entry (e);
305        remote_login_server_list.append (remote_server);
306
307        return e;
308    }
309
310    private void remote_login_servers_updated (string url, string email_address, string data_type, RemoteServer[] server_list)
311    {
312        if (currently_browsing_server_url == url && currently_browsing_server_email == email_address)
313        {
314            /* Add new servers */
315            foreach (var remote_server in server_list)
316            {
317                var list_name = user_list_name_for_remote_login_server (remote_server);
318                if (find_entry (list_name) == null)
319                    create_prompt_for_login_server (remote_server);
320            }
321
322            /* Remove gone servers */
323            unowned List<RemoteServer?> it = remote_login_server_list;
324            while (it != null)
325            {
326                RemoteServer remote_server = it.data;
327                var found = false;
328                for (var i = 0; !found && i < server_list.length; i++)
329                    found = remote_server.url == server_list[i].url;
330                if (!found)
331                {
332                    remove_entry (user_list_name_for_remote_login_server (remote_server));
333                    unowned List<RemoteServer?> newIt = it.next;
334                    remote_login_server_list.delete_link (it);
335                    it = newIt;
336                }
337                else
338                {
339                    it = it.next;
340                }
341            }
342        }
343    }
344
345    private void remote_login_changed (string url, string email_address)
346    {
347        if (currently_browsing_server_url == url && currently_browsing_server_email == email_address)
348        {
349            /* Something happened and we are being asked for re-authentication by the remote-login-service */
350            remove_remote_login_servers ();
351            currently_browsing_server_url = "";
352            currently_browsing_server_email = "";
353
354            var directory_list_name = "*remote_directory*" + url;
355            set_active_entry (directory_list_name);
356        }
357    }
358
359    private void on_remote_login_service_appeared (DBusConnection conn, string name)
360    {
361        Bus.get_proxy.begin<RemoteLoginService> (BusType.SESSION,
362            "com.canonical.RemoteLogin",
363            "/com/canonical/RemoteLogin",
364            0,
365            null,
366            (obj, res) => {
367                try
368                {
369                    remote_login_service = Bus.get_proxy.end<RemoteLoginService> (res);
370                    remote_login_service.servers_updated.connect (set_remote_directory_servers);
371                    remote_login_service.login_servers_updated.connect (remote_login_servers_updated);
372                    remote_login_service.login_changed.connect (remote_login_changed);
373                    query_directory_servers.begin ();
374                }
375                catch (IOError e)
376                {
377                    debug ("Getting the com.canonical.RemoteLogin dbus service failed. Error: %s", e.message);
378                    remove_remote_servers ();
379                    remote_login_service = null;
380                }
381            }
382        );
383    }
384
385    private void on_remote_login_service_vanished (DBusConnection conn, string name)
386    {
387        remove_remote_servers ();
388        remote_login_service = null;
389
390        /* provide a fallback manual login option */
391        if (SlickGreeter.singleton.hide_users_hint ()) {
392            add_manual_entry();
393            set_active_entry ("*other");
394        }
395    }
396
397    private async void remote_directory_respond_cb ()
398    {
399        remove_remote_login_servers ();
400        currently_browsing_server_url = "";
401        currently_browsing_server_email = "";
402
403        var password_field = current_remote_fields.get ("password") as DashEntry;
404        var email_field = current_remote_fields.get ("email") as Gtk.Entry;
405        if (password_field == null)
406        {
407            debug ("Something wrong happened in remote_directory_respond_cb. There was no password field");
408            return;
409        }
410        if (email_field == null)
411        {
412            debug ("Something wrong happened in remote_directory_respond_cb. There was no email field");
413            return;
414        }
415
416        RemoteServer[] server_list = {};
417        var email = email_field.text;
418        var email_valid = false;
419        try
420        {
421            /* Check email address is valid
422             * Using the html5 definition of a valid e-mail address
423             * http://www.w3.org/TR/html5/states-of-the-type-attribute.html#valid-e-mail-address */
424            var re = new Regex ("[a-zA-Z0-9.!#$%&'\\*\\+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*");
425            MatchInfo info;
426            email_valid = re.match_all (email, 0, out info);
427            email_valid = email_valid && info.get_match_count () > 0 && info.fetch (0) == email;
428        }
429        catch (RegexError e)
430        {
431            debug ("Calling email regex match failed. Error: %s", e.message);
432        }
433
434        selected_entry.reset_messages ();
435        if (!email_valid)
436        {
437            will_clear = true;
438            show_message (_("Please enter a complete e-mail address"), true);
439            create_remote_fields_for_current_item.begin (remote_directory_server_list);
440        }
441        else
442        {
443            var login_success = false;
444            try
445            {
446                var url = url_from_remote_loding_server_list_name (selected_entry.id);
447                if (SlickGreeter.singleton.test_mode)
448                {
449                    if (password_field.text == "password")
450                    {
451                        test_fill_remote_login_servers (out server_list);
452                        login_success = true;
453                    }
454                    else if (password_field.text == "delay1")
455                    {
456                        test_fill_remote_login_servers (out server_list);
457                        login_success = true;
458                        Timeout.add (5000, () => { test_call_set_remote_directory_servers (); return false; });
459                    }
460                    else if (password_field.text == "delay2")
461                    {
462                        test_fill_remote_login_servers (out server_list);
463                        login_success = true;
464                        Timeout.add (5000, () => { test_call_remote_login_servers_updated (); return false; });
465                    }
466                    else if (password_field.text == "delay3")
467                    {
468                        test_fill_remote_login_servers (out server_list);
469                        login_success = true;
470                        Timeout.add (5000, () => { remote_login_changed (currently_browsing_server_url, currently_browsing_server_email); return false; });
471                    }
472                    else if (password_field.text == "duplicate")
473                    {
474                        test_fill_remote_login_servers_duplicate_entries (out server_list);
475                        login_success = true;
476                    }
477                }
478                else
479                {
480                    string data_type;
481                    bool allowcache = true;
482                    // If we had an error and are retrying the same user and server, do not use the cache on R-L-S
483                    if (selected_entry.has_errors && currently_browsing_server_email == email && currently_browsing_server_url == url)
484                        allowcache = false;
485                    yield remote_login_service.get_servers_for_login (url, email, password_field.text, allowcache, out login_success, out data_type, out server_list);
486                }
487                currently_browsing_server_url = url;
488                currently_browsing_server_email = email;
489            }
490            catch (Error e)
491            {
492                debug ("Calling get_servers in com.canonical.RemoteLogin dbus service failed. Error: %s", e.message);
493            }
494
495            if (login_success)
496            {
497                password_field.did_respond = false;
498                if (server_list.length == 0)
499                    show_remote_account_dialog ();
500                else
501                {
502                    var last_used_server_list_name = "";
503                    foreach (var remote_server in server_list)
504                    {
505                        var e = create_prompt_for_login_server (remote_server);
506                        if (remote_server.last_used_server)
507                            last_used_server_list_name = e.id;
508                    }
509                    if (last_used_server_list_name != "")
510                        set_active_entry (last_used_server_list_name);
511                    else
512                        set_active_first_entry_with_prefix ("*remote_login");
513                }
514            }
515            else
516            {
517                will_clear = true;
518                show_message (_("Incorrect e-mail address or password"), true);
519                create_remote_fields_for_current_item.begin (remote_directory_server_list);
520            }
521        }
522    }
523
524    private void remote_login_respond_cb ()
525    {
526        sensitive = false;
527        will_clear = true;
528        greeter_authenticating_user = selected_entry.id;
529        if (SlickGreeter.singleton.test_mode)
530        {
531            Gtk.Entry field = current_remote_fields.get ("password") as Gtk.Entry;
532            test_is_authenticated = field.text == "password";
533            if (field.text == "delay")
534                Timeout.add (5000, () => { authentication_complete_cb (); return false; });
535            else
536                authentication_complete_cb ();
537        }
538        else
539        {
540            SlickGreeter.singleton.authenticate_remote (get_lightdm_session (), null);
541            remote_login_service.set_last_used_server.begin (currently_browsing_server_url, url_from_remote_loding_server_list_name (selected_entry.id));
542        }
543    }
544
545    private void show_remote_account_dialog ()
546    {
547        var dialog = new Gtk.MessageDialog (null, 0, Gtk.MessageType.OTHER, Gtk.ButtonsType.NONE, "");
548        dialog.set_position (Gtk.WindowPosition.CENTER_ALWAYS);
549        dialog.secondary_text = _("If you have an account on an RDP or Citrix server, Remote Login lets you run applications from that server.");
550        // For 12.10 we still don't support Citrix
551        dialog.secondary_text = _("If you have an account on an RDP server, Remote Login lets you run applications from that server.");
552        if (offer_guest)
553        {
554            dialog.add_button (_("Cancel"), 0);
555            var b = dialog.add_button (_("Set Up..."), 1);
556            b.grab_focus ();
557            dialog.text = _("You need an Ubuntu Remote Login account to use this service. Would you like to set up an account now?");
558        }
559        else
560        {
561            dialog.add_button (_("OK"), 0);
562            dialog.text = _("You need an Ubuntu Remote Login account to use this service. Visit uccs.canonical.com to set up an account.");
563        }
564
565        dialog.show_all ();
566        dialog.response.connect ((id) =>
567        {
568            if (id == 1)
569            {
570                var config_session = "uccsconfigure";
571                if (is_supported_remote_session (config_session))
572                {
573                    greeter_authenticating_user = selected_entry.id;
574                    SlickGreeter.singleton.authenticate_remote (config_session, null);
575                }
576            }
577            dialog.destroy ();
578        });
579        dialog.run ();
580    }
581
582    private bool change_background_timeout_cb ()
583    {
584        string? new_background_file = null;
585        if (menubar.high_contrast || !UGSettings.get_boolean (UGSettings.KEY_DRAW_USER_BACKGROUNDS))
586            new_background_file = null;
587        else if (selected_entry is UserPromptBox)
588            new_background_file = (selected_entry as UserPromptBox).background;
589
590        background.current_background = new_background_file;
591
592        change_background_timeout = 0;
593        return false;
594    }
595
596    private void change_background ()
597    {
598        if (background.current_background != null)
599        {
600            if (change_background_timeout == 0)
601                change_background_timeout = Idle.add (change_background_timeout_cb);
602        }
603        else
604        {
605            change_background_timeout_cb ();
606        }
607    }
608
609    protected static int user_list_compare_entry (PromptBox a, PromptBox b)
610    {
611        if (a.id.has_prefix ("*remote_directory") && !b.id.has_prefix ("*remote_directory"))
612            return 1;
613        if (a.id.has_prefix ("*remote_login") && !b.id.has_prefix ("*remote_login"))
614            return 1;
615
616        /* Fall back to default behaviour of the GreeterList sorter */
617        return GreeterList.compare_entry (a, b);
618    }
619
620    protected override void insert_entry (PromptBox entry)
621    {
622        entries.insert_sorted (entry, user_list_compare_entry);
623    }
624
625    protected override void setup_prompt_box (bool fade = true)
626    {
627        base.setup_prompt_box (fade);
628        var userbox = selected_entry as UserPromptBox;
629        if (userbox != null)
630            selected_entry.set_is_active (userbox.is_active);
631    }
632
633    private void entry_selected_cb (string? username)
634    {
635        SlickGreeter.singleton.set_state ("last-user", username);
636        if (selected_entry is UserPromptBox)
637            session = (selected_entry as UserPromptBox).session;
638        else
639            session = null;
640        selected_entry.clear ();
641
642        /* Reset this variable so it can be freed */
643        remote_server_email_field_autocompleter = null;
644
645        start_authentication ();
646    }
647
648    protected override void start_authentication ()
649    {
650        sensitive = true;
651        greeter_authenticating_user = "";
652        if (selected_entry.id.has_prefix ("*remote_directory"))
653        {
654            prompted = true;
655            create_remote_fields_for_current_item.begin (remote_directory_server_list);
656        }
657        else if (selected_entry.id.has_prefix ("*remote_login"))
658        {
659            prompted = true;
660            create_remote_fields_for_current_item.begin (remote_login_server_list);
661        }
662        else
663            base.start_authentication ();
664    }
665
666    private async void create_remote_fields_for_current_item (List<RemoteServer?> server_list)
667    {
668        current_remote_fields = new HashTable<string, Gtk.Widget> (str_hash, str_equal);
669        var url = url_from_remote_loding_server_list_name (selected_entry.id);
670        var username = username_from_remote_loding_server_list_name (selected_entry.id);
671
672        foreach (var remote_server in server_list)
673        {
674            var remote_username = username_from_remote_server_fields (remote_server);
675            if (remote_server.url == url && (username == null || username == remote_username))
676            {
677                if (selected_entry.id.has_prefix ("*remote_login"))
678                {
679                    if (!is_supported_remote_session (remote_server.type))
680                    {
681                        show_message (_("Server type not supported."), true);
682                    }
683                }
684
685                var fields = new List<RemoteServerField?> ();
686                foreach (var field in remote_server.fields)
687                    fields.append (field);
688                fields.sort (remote_server_field_sort_function);
689                foreach (var field in fields)
690                {
691                    Gtk.Widget? widget = null;
692                    var default_value = "";
693                    if (field.default_value != null && field.default_value.is_of_type (VariantType.STRING))
694                        default_value = field.default_value.get_string ();
695                    if (field.type == "username")
696                    {
697                        var entry = add_prompt (_("Username:"));
698                        entry.text = default_value;
699                        widget = entry;
700                    }
701                    else if (field.type == "password")
702                    {
703                        var entry = add_prompt (_("Password:"), true);
704                        entry.text = default_value;
705                        widget = entry;
706                    }
707                    else if (field.type == "domain")
708                    {
709                        string[] domainsArray = {};
710                        if (field.properties != null && field.properties.contains ("domains") && field.properties.get ("domains").is_of_type (VariantType.ARRAY))
711                            domainsArray = field.properties.get ("domains").dup_strv ();
712                        var domains = new GenericArray<string> ();
713                        for (var i = 0; i < domainsArray.length; i++)
714                            domains.add (domainsArray[i]);
715
716                        var read_only = field.properties != null &&
717                                        field.properties.contains ("read-only") &&
718                                        field.properties.get ("read-only").is_of_type (VariantType.BOOLEAN) &&
719                                        field.properties.get ("read-only").get_boolean ();
720                        if (domains.length == 0 || (domains.length == 1 && (domains[0] == default_value || default_value.length == 0)))
721                        {
722                            var prompt = add_prompt (_("Domain:"));
723                            prompt.text = domains.length == 1 ? domains[0] : default_value;
724                            prompt.sensitive = !read_only;
725                            widget = prompt;
726                        }
727                        else
728                        {
729                            if (default_value.length > 0)
730                            {
731                                /* Make sure the domain list contains the default value */
732                                var found = false;
733                                for (var i = 0; !found && i < domains.length; i++)
734                                    found = default_value == domains[i];
735
736                                if (!found)
737                                    domains.add (default_value);
738                            }
739
740                            /* Sort domains alphabetically */
741                            domains.sort (strcmp);
742                            var combo = add_combo (domains, read_only);
743
744                            if (default_value.length > 0)
745                            {
746                                if (read_only)
747                                {
748                                    for (var i = 0; i < domains.length; i++)
749                                    {
750                                        if (default_value == domains[i])
751                                        {
752                                            combo.active = i;
753                                            break;
754                                        }
755                                    }
756                                }
757                                else
758                                {
759                                    var entry = combo.get_child () as Gtk.Entry;
760                                    entry.text = default_value;
761                                }
762                            }
763
764                            widget = combo;
765                        }
766                    }
767                    else if (field.type == "email")
768                    {
769                        string[] email_domains;
770                        try
771                        {
772                            if (SlickGreeter.singleton.test_mode)
773                                email_domains = { "canonical.com", "ubuntu.org", "candy.com", "urban.net" };
774                            else
775                                yield remote_login_service.get_cached_domains_for_server (url, out email_domains);
776                        }
777                        catch (Error e)
778                        {
779                            email_domains.resize (0);
780                            debug ("Calling get_cached_domains_for_server in com.canonical.RemoteLogin dbus service failed. Error: %s", e.message);
781                        }
782
783                        var entry = add_prompt (_("Email address:"));
784                        entry.text = default_value;
785                        widget = entry;
786                        if (email_domains.length > 0)
787                            remote_server_email_field_autocompleter = new EmailAutocompleter (entry, email_domains);
788                    }
789                    else
790                    {
791                        debug ("Found field of type %s, don't know what to do with it", field.type);
792                        continue;
793                    }
794                    current_remote_fields.insert (field.type, widget);
795                }
796                break;
797            }
798        }
799    }
800
801    public override void focus_prompt ()
802    {
803        if (selected_entry.id.has_prefix ("*remote_login"))
804        {
805            var url = url_from_remote_loding_server_list_name(selected_entry.id);
806            foreach (var remote_server in remote_login_server_list)
807            {
808                if (remote_server.url == url)
809                {
810                    if (!is_supported_remote_session (remote_server.type))
811                    {
812                        selected_entry.sensitive = false;
813                        return;
814                    }
815                }
816            }
817        }
818
819        base.focus_prompt ();
820    }
821
822    public override void show_authenticated (bool successful = true)
823    {
824        if (successful)
825        {
826            /* 'Log In' here is the button for logging in. */
827            selected_entry.add_button (_("Log In"),
828                                       _("Login as %s").printf (selected_entry.label));
829        }
830        else
831        {
832            selected_entry.add_button (_("Retry"),
833                                       _("Retry as %s").printf (selected_entry.label));
834        }
835
836        if (mode != Mode.SCROLLING)
837            selected_entry.show_prompts ();
838
839        focus_prompt ();
840        redraw_greeter_box ();
841    }
842
843    public void add_user (string name, string label, string? background = null, bool is_active = false, bool has_messages = false, string? session = null)
844    {
845        var e = find_entry (name) as UserPromptBox;
846        if (e == null)
847        {
848            e = new UserPromptBox (name);
849            e.respond.connect (prompt_box_respond_cb);
850            e.login.connect (prompt_box_login_cb);
851            e.show_options.connect (prompt_box_show_options_cb);
852            e.label = label; /* Do this before adding for sorting purposes */
853            add_entry (e);
854        }
855        e.background = background;
856        e.is_active = is_active;
857        if ( session == null)
858        {
859            session = default_session;
860        }
861        e.session = SlickGreeter.validate_session (session);
862        e.label = label;
863        e.set_show_message_icon (has_messages);
864        e.set_is_active (is_active);
865
866        /* Remove manual option when have users */
867        if (have_entries () && !always_show_manual)
868            remove_entry ("*other");
869    }
870
871    protected override void add_manual_entry ()
872    {
873        var text = manual_name;
874        if (text == null)
875            text = _("Login");
876        add_user ("*other", text);
877    }
878
879    protected void prompt_box_respond_cb (string[] responses)
880    {
881        selected_entry.sensitive = false;
882        will_clear = true;
883        unacknowledged_messages = false;
884
885        foreach (var response in responses)
886        {
887            if (SlickGreeter.singleton.test_mode)
888                test_respond (response);
889            else
890                SlickGreeter.singleton.respond (response);
891        }
892    }
893
894    private void prompt_box_login_cb ()
895    {
896        debug ("Start session for %s", selected_entry.id);
897
898        unacknowledged_messages = false;
899        var is_authenticated = false;
900        if (SlickGreeter.singleton.test_mode)
901            is_authenticated = test_is_authenticated;
902        else
903            is_authenticated = SlickGreeter.singleton.is_authenticated();
904
905        /* Finish authentication (again) or restart it */
906        if (is_authenticated)
907            authentication_complete_cb ();
908        else
909        {
910            selected_entry.clear ();
911            start_authentication ();
912        }
913    }
914
915    private void prompt_box_show_options_cb ()
916    {
917        var session_chooser = new SessionList (background, menubar, session, default_session);
918        session_chooser.session_clicked.connect (session_clicked_cb);
919        SlickGreeter.singleton.push_list (session_chooser);
920    }
921
922    private void session_clicked_cb (string session)
923    {
924        this.session = session;
925        SlickGreeter.singleton.pop_list ();
926    }
927
928    private bool should_show_session_badge ()
929    {
930        if (SlickGreeter.singleton.test_mode)
931            return get_selected_id () != "no-badge";
932        else
933            return LightDM.get_sessions ().length () > 1;
934    }
935
936    private Gdk.Pixbuf? get_badge ()
937    {
938        if (selected_entry is UserPromptBox)
939        {
940            if (!should_show_session_badge ())
941                return null;
942            else if (session == null)
943                return SessionList.get_badge (default_session);
944            else
945                return SessionList.get_badge (session);
946        }
947        else
948        {
949            if (selected_entry.id.has_prefix ("*remote_directory"))
950                return SessionList.get_badge ("remote-login");
951            else
952                return null;
953        }
954    }
955
956    private bool is_supported_remote_session (string session_internal_name)
957    {
958        if (SlickGreeter.singleton.test_mode)
959            return session_internal_name == "rdp";
960
961        var found = false;
962        foreach (var session in LightDM.get_remote_sessions ())
963        {
964            if (session.key == session_internal_name)
965            {
966                found = true;
967                break;
968            }
969        }
970        return found;
971    }
972
973    protected override string get_lightdm_session ()
974    {
975        if (selected_entry.id.has_prefix ("*remote_login"))
976        {
977            var url = url_from_remote_loding_server_list_name (selected_entry.id);
978            unowned List<RemoteServer?> it = remote_login_server_list;
979
980            var answer = "";
981            while (answer == "" && it != null)
982            {
983                RemoteServer remote_server = it.data;
984                if (remote_server.url == url)
985                    answer = remote_server.type;
986                it = it.next;
987            }
988
989            if (is_supported_remote_session (answer))
990                return answer;
991            else
992                return "";
993        }
994        else
995            return session;
996    }
997
998    private void fill_list ()
999    {
1000        if (SlickGreeter.singleton.test_mode)
1001            test_fill_list ();
1002        else
1003        {
1004            default_session = SlickGreeter.singleton.default_session_hint ();
1005            always_show_manual = SlickGreeter.singleton.show_manual_login_hint ();
1006            if (!SlickGreeter.singleton.hide_users_hint ())
1007            {
1008                var users = LightDM.UserList.get_instance ();
1009                users.user_added.connect (user_added_cb);
1010                users.user_changed.connect (user_added_cb);
1011                users.user_removed.connect (user_removed_cb);
1012                foreach (var user in users.users)
1013                    user_added_cb (user);
1014            }
1015
1016            if (SlickGreeter.singleton.has_guest_account_hint ())
1017            {
1018                debug ("Adding guest account entry");
1019                offer_guest = true;
1020            }
1021
1022            /* If we have no entries at all, we should show manual */
1023            if (!have_entries ())
1024                add_manual_entry ();
1025
1026            var last_user = SlickGreeter.singleton.get_state ("last-user");
1027            if (SlickGreeter.singleton.select_user_hint () != null)
1028                set_active_entry (SlickGreeter.singleton.select_user_hint ());
1029            else if (last_user != null)
1030                set_active_entry (last_user);
1031        }
1032    }
1033
1034    private void user_added_cb (LightDM.User user)
1035    {
1036        debug ("Adding/updating user %s (%s)", user.name, user.real_name);
1037
1038        if (!show_hidden_users)
1039        {
1040            var hidden_users = UGSettings.get_strv (UGSettings.KEY_HIDDEN_USERS);
1041            foreach (var username in hidden_users)
1042                if (username == user.name)
1043                    return;
1044        }
1045
1046        if (!filter_group (user.name))
1047            return;
1048
1049        var label = user.real_name;
1050        if (user.real_name == "")
1051            label = user.name;
1052
1053        add_user (user.name, label, user.background, user.logged_in, user.has_messages, user.session);
1054    }
1055
1056    private bool filter_group (string user_name)
1057    {
1058        var group_filter = UGSettings.get_strv (UGSettings.KEY_GROUP_FILTER);
1059
1060        /* Empty list means do not filter by group */
1061        if (group_filter.length == 0)
1062            return true;
1063
1064        foreach (var group_name in group_filter)
1065            if (in_group (group_name, user_name))
1066                return true;
1067
1068        return false;
1069    }
1070
1071    private bool in_group (string group_name, string user_name)
1072    {
1073        unowned Posix.Group? group = Posix.getgrnam (group_name);
1074        if (group == null)
1075            return false;
1076
1077        foreach (var name in group.gr_mem)
1078            if (name == user_name)
1079                return true;
1080
1081        return false;
1082    }
1083
1084    private void user_removed_cb (LightDM.User user)
1085    {
1086        debug ("Removing user %s", user.name);
1087        remove_entry (user.name);
1088    }
1089
1090    protected override void show_prompt_cb (string text, LightDM.PromptType type)
1091    {
1092        if (selected_entry.id.has_prefix ("*remote_login"))
1093        {
1094            if (text == "remote login:")
1095            {
1096                Gtk.Entry field = current_remote_fields.get ("username") as Gtk.Entry;
1097                var answer = field != null ? field.text : "";
1098                SlickGreeter.singleton.respond (answer);
1099            }
1100            else if (text == "password:")
1101            {
1102                Gtk.Entry field = current_remote_fields.get ("password") as Gtk.Entry;
1103                var answer = field != null ? field.text : "";
1104                SlickGreeter.singleton.respond (answer);
1105            }
1106            else if (text == "remote host:")
1107            {
1108                var answer = url_from_remote_loding_server_list_name (selected_entry.id);
1109                SlickGreeter.singleton.respond (answer);
1110            }
1111            else if (text == "domain:")
1112            {
1113                Gtk.Entry field = current_remote_fields.get ("domain") as Gtk.Entry;
1114                var answer = field != null ? field.text : "";
1115                SlickGreeter.singleton.respond (answer);
1116            }
1117        }
1118        else
1119            base.show_prompt_cb (text, type);
1120    }
1121
1122    /* A lot of test code below here */
1123
1124    private struct TestEntry
1125    {
1126        string username;
1127        string real_name;
1128        string? background;
1129        bool is_active;
1130        bool has_messages;
1131        string? session;
1132    }
1133
1134    private const TestEntry[] test_entries =
1135    {
1136        { "has-password",       "Has Password",      "*" },
1137        { "different-prompt",   "Different Prompt",  "*" },
1138        { "no-password",        "No Password",       "*" },
1139        { "change-password",    "Change Password",   "*" },
1140        { "auth-error",         "Auth Error",        "*" },
1141        { "two-factor",         "Two Factor",        "*" },
1142        { "two-prompts",        "Two Prompts",       "*" },
1143        { "info-prompt",        "Info Prompt",       "*" },
1144        { "long-info-prompt",   "Long Info Prompt",  "*" },
1145        { "wide-info-prompt",   "Wide Info Prompt",  "*" },
1146        { "multi-info-prompt",  "Multi Info Prompt", "*" },
1147        { "very-very-long-name",    "Long name (far far too long to fit)", "*" },
1148        { "long-name-and-messages", "Long name and messages (too long to fit)", "*", false, true },
1149        { "active",             "Active Account",    "*", true },
1150        { "has-messages",       "Has Messages",      "*", false, true },
1151        { "gnome",              "GNOME",             "*", false, false, "gnome" },
1152        { "locked",             "Locked Account",    "*" },
1153        { "color-background",   "Color Background",  "#dd4814" },
1154        { "white-background",   "White Background",  "#ffffff" },
1155        { "black-background",   "Black Background",  "#000000" },
1156        { "no-background",      "No Background",     null },
1157        { "unicode",            "가나다라마",         "*" },
1158        { "no-response",        "No Response",       "*" },
1159        { "no-badge",           "No Badge",          "*" },
1160        { "messages-after-login", "Messages After Login", "*" },
1161        { "" }
1162    };
1163    private List<string> test_backgrounds;
1164    private int n_test_entries = 0;
1165    private bool test_prompted_sso = false;
1166    private string test_two_prompts_first = null;
1167    private bool test_request_new_password = false;
1168    private string? test_new_password = null;
1169
1170    private void test_fill_list ()
1171    {
1172        test_backgrounds = new List<string> ();
1173        try
1174        {
1175            var dir = Dir.open ("/usr/local/share/backgrounds/");
1176            while (true)
1177            {
1178                var bg = dir.read_name ();
1179                if (bg == null)
1180                    break;
1181                test_backgrounds.append ("/usr/local/share/backgrounds/" + bg);
1182            }
1183        }
1184        catch (FileError e)
1185        {
1186        }
1187
1188        if (!SlickGreeter.singleton.hide_users_hint())
1189            while (add_test_entry ());
1190
1191        /* add a manual entry if the list of entries is empty initially */
1192        if (n_test_entries <= 0)
1193        {
1194            add_manual_entry();
1195            set_active_entry ("*other");
1196            n_test_entries++;
1197        }
1198
1199        offer_guest = SlickGreeter.singleton.has_guest_account_hint();
1200        always_show_manual = SlickGreeter.singleton.show_manual_login_hint();
1201
1202        key_press_event.connect (test_key_press_cb);
1203
1204        if (SlickGreeter.singleton.show_remote_login_hint())
1205            Timeout.add (1000, () =>
1206            {
1207                RemoteServer[] test_server_list = {};
1208                RemoteServer remote_server = RemoteServer ();
1209                remote_server.type = "uccs";
1210                remote_server.name = "Remote Login";
1211                remote_server.url = "http://crazyurl.com";
1212                remote_server.last_used_server = false;
1213                remote_server.fields = {};
1214                RemoteServerField field1 = RemoteServerField ();
1215                field1.type = "email";
1216                RemoteServerField field2 = RemoteServerField ();
1217                field2.type = "password";
1218                remote_server.fields = {field1, field2};
1219
1220                test_server_list += remote_server;
1221                set_remote_directory_servers (test_server_list);
1222
1223                return false;
1224            });
1225
1226        var last_user = SlickGreeter.singleton.get_state ("last-user");
1227        if (last_user != null)
1228            set_active_entry (last_user);
1229
1230    }
1231
1232    private void test_call_set_remote_directory_servers ()
1233    {
1234        RemoteServer[] test_server_list = {};
1235        RemoteServer remote_server = RemoteServer ();
1236        remote_server.type = "uccs";
1237        remote_server.name = "Corporate Remote Login";
1238        remote_server.url = "http://internalcompayserver.com";
1239        remote_server.last_used_server = false;
1240        remote_server.fields = {};
1241        RemoteServerField field1 = RemoteServerField ();
1242        field1.type = "email";
1243        RemoteServerField field2 = RemoteServerField ();
1244        field2.type = "password";
1245        remote_server.fields = {field1, field2};
1246
1247        test_server_list += remote_server;
1248        set_remote_directory_servers (test_server_list);
1249    }
1250
1251    private void test_call_remote_login_servers_updated ()
1252    {
1253        RemoteServer[] server_list = {};
1254        RemoteServer remote_server1 = RemoteServer ();
1255        remote_server1.type = "rdp";
1256        remote_server1.name = "Cool RDP server";
1257        remote_server1.url = "http://coolrdpserver.com";
1258        remote_server1.last_used_server = false;
1259        remote_server1.fields = {};
1260        RemoteServerField field1 = RemoteServerField ();
1261        field1.type = "username";
1262        RemoteServerField field2 = RemoteServerField ();
1263        field2.type = "password";
1264        RemoteServerField field3 = RemoteServerField ();
1265        field3.type = "domain";
1266        remote_server1.fields = {field1, field2, field3};
1267
1268        RemoteServer remote_server2 = RemoteServer ();
1269        remote_server2.type = "rdp";
1270        remote_server2.name = "MegaCool RDP server";
1271        remote_server2.url = "http://megacoolrdpserver.com";
1272        remote_server2.last_used_server = false;
1273        remote_server2.fields = {};
1274        RemoteServerField field21 = RemoteServerField ();
1275        field21.type = "username";
1276        RemoteServerField field22 = RemoteServerField ();
1277        field22.type = "password";
1278        remote_server2.fields = {field21, field22};
1279
1280        server_list.resize (2);
1281        server_list[0] = remote_server1;
1282        server_list[1] = remote_server2;
1283
1284        remote_login_servers_updated (currently_browsing_server_url, currently_browsing_server_email, "", server_list);
1285    }
1286
1287    private void test_fill_remote_login_servers (out RemoteServer[] server_list)
1288    {
1289        string[] domains = { "SCANNERS", "PRINTERS", "ROUTERS" };
1290
1291        server_list = {};
1292        RemoteServer remote_server1 = RemoteServer ();
1293        remote_server1.type = "rdp";
1294        remote_server1.name = "Cool RDP server";
1295        remote_server1.url = "http://coolrdpserver.com";
1296        remote_server1.last_used_server = false;
1297        remote_server1.fields = {};
1298        RemoteServerField field1 = RemoteServerField ();
1299        field1.type = "username";
1300        RemoteServerField field2 = RemoteServerField ();
1301        field2.type = "password";
1302        RemoteServerField field3 = RemoteServerField ();
1303        field3.type = "domain";
1304        remote_server1.fields = {field1, field2, field3};
1305
1306        RemoteServer remote_server2 = RemoteServer ();
1307        remote_server2.type = "rdp";
1308        remote_server2.name = "RDP server with default username, and editable domain";
1309        remote_server2.url = "http://rdpdefaultusername.com";
1310        remote_server2.last_used_server = false;
1311        remote_server2.fields = {};
1312        RemoteServerField field21 = RemoteServerField ();
1313        field21.type = "username";
1314        field21.default_value = new Variant.string ("alowl");
1315        RemoteServerField field22 = RemoteServerField ();
1316        field22.type = "password";
1317        RemoteServerField field23 = RemoteServerField ();
1318        field23.type = "domain";
1319        field23.default_value = new Variant.string ("PRINTERS");
1320        field23.properties = new HashTable<string, Variant> (str_hash, str_equal);
1321        field23.properties["domains"] = domains;
1322        remote_server2.fields = {field21, field22, field23};
1323
1324        RemoteServer remote_server3 = RemoteServer ();
1325        remote_server3.type = "rdp";
1326        remote_server3.name = "RDP server with default username, and non editable domain";
1327        remote_server3.url = "http://rdpdefaultusername2.com";
1328        remote_server3.last_used_server = true;
1329        remote_server3.fields = {};
1330        RemoteServerField field31 = RemoteServerField ();
1331        field31.type = "username";
1332        field31.default_value = new Variant.string ("lwola");
1333        RemoteServerField field32 = RemoteServerField ();
1334        field32.type = "password";
1335        RemoteServerField field33 = RemoteServerField ();
1336        field33.type = "domain";
1337        field33.default_value = new Variant.string ("PRINTERS");
1338        field33.properties = new HashTable<string, Variant> (str_hash, str_equal);
1339        field33.properties["domains"] = domains;
1340        field33.properties["read-only"] = true;
1341
1342        remote_server3.fields = {field31, field32, field33};
1343
1344        RemoteServer remote_server4 = RemoteServer ();
1345        remote_server4.type = "notsupported";
1346        remote_server4.name = "Not supported server";
1347        remote_server4.url = "http://notsupportedserver.com";
1348        remote_server4.fields = {};
1349        RemoteServerField field41 = RemoteServerField ();
1350        field41.type = "username";
1351        RemoteServerField field42 = RemoteServerField ();
1352        field42.type = "password";
1353        RemoteServerField field43 = RemoteServerField ();
1354        field43.type = "domain";
1355
1356        remote_server4.fields = {field41, field42, field43};
1357
1358        server_list.resize (4);
1359        server_list[0] = remote_server1;
1360        server_list[1] = remote_server2;
1361        server_list[2] = remote_server3;
1362        server_list[3] = remote_server4;
1363    }
1364
1365    private void test_fill_remote_login_servers_duplicate_entries (out RemoteServer[] server_list)
1366    {
1367        /* Create two remote servers with same url but different username and domain. */
1368        server_list = {};
1369
1370        RemoteServer remote_server2 = RemoteServer ();
1371        remote_server2.type = "rdp";
1372        remote_server2.name = "RDP server with default username, and editable domain";
1373        remote_server2.url = "http://rdpdefaultusername.com";
1374        remote_server2.last_used_server = false;
1375        remote_server2.fields = {};
1376        RemoteServerField field21 = RemoteServerField ();
1377        field21.type = "username";
1378        field21.default_value = new Variant.string ("alowl1");
1379        RemoteServerField field22 = RemoteServerField ();
1380        field22.type = "password";
1381        field22.default_value = new Variant.string ("duplicate1");
1382        RemoteServerField field23 = RemoteServerField ();
1383        field23.type = "domain";
1384        field23.default_value = new Variant.string ("SCANNERS");
1385        remote_server2.fields = {field21, field22, field23};
1386
1387        RemoteServer remote_server5 = RemoteServer ();
1388        remote_server5.type = "rdp";
1389        remote_server5.name = "RDP server with default username, and editable domain";
1390        remote_server5.url = "http://rdpdefaultusername.com";
1391        remote_server5.last_used_server = false;
1392        remote_server5.fields = {};
1393        RemoteServerField field51 = RemoteServerField ();
1394        field51.type = "username";
1395        field51.default_value = new Variant.string ("alowl2");
1396        RemoteServerField field52 = RemoteServerField ();
1397        field52.type = "password";
1398        field52.default_value = new Variant.string ("duplicate2");
1399        RemoteServerField field53 = RemoteServerField ();
1400        field53.type = "domain";
1401        field53.default_value = new Variant.string ("PRINTERS");
1402        remote_server5.fields = {field51, field52, field53};
1403
1404        server_list.resize (2);
1405        server_list[0] = remote_server2;
1406        server_list[1] = remote_server5;
1407    }
1408
1409    private bool test_key_press_cb (Gdk.EventKey event)
1410    {
1411        if ((event.state & Gdk.ModifierType.CONTROL_MASK) == 0)
1412            return false;
1413
1414        switch (event.keyval)
1415        {
1416        case Gdk.Key.plus:
1417            add_test_entry ();
1418            break;
1419        case Gdk.Key.minus:
1420            remove_test_entry ();
1421            break;
1422        case Gdk.Key.@0:
1423            while (remove_test_entry ());
1424            offer_guest = false;
1425            break;
1426        case Gdk.Key.equal:
1427            while (add_test_entry ());
1428            offer_guest = true;
1429            break;
1430        case Gdk.Key.g:
1431            offer_guest = false;
1432            break;
1433        case Gdk.Key.G:
1434            offer_guest = true;
1435            break;
1436        case Gdk.Key.m:
1437            always_show_manual = false;
1438            break;
1439        case Gdk.Key.M:
1440            always_show_manual = true;
1441            break;
1442        }
1443
1444        return false;
1445    }
1446
1447    private bool add_test_entry ()
1448    {
1449        var e = test_entries[n_test_entries];
1450        if (e.username == "")
1451            return false;
1452
1453        var background = e.background;
1454        if (background == "*")
1455        {
1456            var background_index = 0;
1457            for (var i = 0; i < n_test_entries; i++)
1458            {
1459                if (test_entries[i].background == "*")
1460                    background_index++;
1461            }
1462            if (test_backgrounds.length () > 0)
1463                background = test_backgrounds.nth_data (background_index % test_backgrounds.length ());
1464        }
1465        add_user (e.username, e.real_name, background, e.is_active, e.has_messages, e.session);
1466        n_test_entries++;
1467
1468        return true;
1469    }
1470
1471    private bool remove_test_entry ()
1472    {
1473        if (n_test_entries == 0)
1474            return false;
1475
1476        remove_entry (test_entries[n_test_entries - 1].username);
1477        n_test_entries--;
1478
1479        return true;
1480    }
1481
1482    private void test_respond (string text)
1483    {
1484        debug ("response %s", text);
1485        switch (get_selected_id ())
1486        {
1487        case "*other":
1488            if (test_username == null)
1489            {
1490                debug ("username=%s", text);
1491                test_username = text;
1492                show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1493            }
1494            else
1495            {
1496                test_is_authenticated = text == "password";
1497                authentication_complete_cb ();
1498            }
1499            break;
1500        case "two-factor":
1501            if (!test_prompted_sso)
1502            {
1503                if (text == "password")
1504                {
1505                    debug ("prompt otp");
1506                    test_prompted_sso = true;
1507                    show_prompt_cb ("OTP:", LightDM.PromptType.QUESTION);
1508                }
1509                else
1510                {
1511                    test_is_authenticated = false;
1512                    authentication_complete_cb ();
1513                }
1514            }
1515            else
1516            {
1517                test_is_authenticated = text == "otp";
1518                authentication_complete_cb ();
1519            }
1520            break;
1521        case "two-prompts":
1522            if (test_two_prompts_first == null)
1523                test_two_prompts_first = text;
1524            else
1525            {
1526                test_is_authenticated = test_two_prompts_first == "blue" && text == "password";
1527                authentication_complete_cb ();
1528            }
1529            break;
1530        case "change-password":
1531            if (test_new_password != null)
1532            {
1533                test_is_authenticated = text == test_new_password;
1534                authentication_complete_cb ();
1535            }
1536            else if (test_request_new_password)
1537            {
1538                test_new_password = text;
1539                show_prompt_cb ("Retype new UNIX password: ", LightDM.PromptType.SECRET);
1540            }
1541            else
1542            {
1543                if (text != "password")
1544                {
1545                    test_is_authenticated = false;
1546                    authentication_complete_cb ();
1547                }
1548                else
1549                {
1550                    test_request_new_password = true;
1551                    show_message_cb ("You are required to change your password immediately (root enforced)", LightDM.MessageType.ERROR);
1552                    show_prompt_cb ("Enter new UNIX password: ", LightDM.PromptType.SECRET);
1553                }
1554            }
1555            break;
1556        case "no-response":
1557            break;
1558        case "locked":
1559            test_is_authenticated = false;
1560            show_message_cb ("Account is locked", LightDM.MessageType.ERROR);
1561            authentication_complete_cb ();
1562            break;
1563        case "messages-after-login":
1564            test_is_authenticated = text == "password";
1565            if (test_is_authenticated)
1566                show_message_cb ("Congratulations on logging in!", LightDM.MessageType.INFO);
1567            authentication_complete_cb ();
1568            break;
1569        default:
1570            test_is_authenticated = text == "password";
1571            authentication_complete_cb ();
1572            break;
1573        }
1574    }
1575
1576    protected override void test_start_authentication ()
1577    {
1578        test_username = null;
1579        test_is_authenticated = false;
1580        test_prompted_sso = false;
1581        test_two_prompts_first = null;
1582        test_request_new_password = false;
1583        test_new_password = null;
1584
1585        switch (get_selected_id ())
1586        {
1587        case "*other":
1588            if (authenticate_user != null)
1589            {
1590                test_username = authenticate_user;
1591                authenticate_user = null;
1592                show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1593            }
1594            else
1595                show_prompt_cb ("Username:", LightDM.PromptType.QUESTION);
1596            break;
1597        case "*guest":
1598            test_is_authenticated = true;
1599            authentication_complete_cb ();
1600            break;
1601        case "different-prompt":
1602            show_prompt_cb ("Secret word", LightDM.PromptType.SECRET);
1603            break;
1604        case "no-password":
1605            test_is_authenticated = true;
1606            authentication_complete_cb ();
1607            break;
1608        case "auth-error":
1609            show_message_cb ("Authentication Error", LightDM.MessageType.ERROR);
1610            test_is_authenticated = false;
1611            authentication_complete_cb ();
1612            break;
1613        case "info-prompt":
1614            show_message_cb ("Welcome to Slick Greeter", LightDM.MessageType.INFO);
1615            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1616            break;
1617        case "long-info-prompt":
1618            show_message_cb ("Welcome to Slick Greeter\n\nWe like to annoy you with long messages.\nLike this one\n\nThis is the last line of a multiple line message.", LightDM.MessageType.INFO);
1619            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1620            break;
1621        case "wide-info-prompt":
1622            show_message_cb ("Welcome to Slick Greeter, the greeteriest greeter that ever did appear in these fine lands", LightDM.MessageType.INFO);
1623            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1624            break;
1625        case "multi-info-prompt":
1626            show_message_cb ("Welcome to Slick Greeter", LightDM.MessageType.INFO);
1627            show_message_cb ("This is an error", LightDM.MessageType.ERROR);
1628            show_message_cb ("You should have seen three messages", LightDM.MessageType.INFO);
1629            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1630            break;
1631        case "two-prompts":
1632            show_prompt_cb ("Favorite Color (blue):", LightDM.PromptType.QUESTION);
1633            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1634            break;
1635        default:
1636            show_prompt_cb ("Password:", LightDM.PromptType.SECRET);
1637            break;
1638        }
1639    }
1640}
1641