Identity selector support for headless operation
authorKevin Wasserman <kevin@debian.(none)>
Wed, 20 Mar 2013 13:53:28 +0000 (09:53 -0400)
committerKevin Wasserman <kevin@debian.(none)>
Thu, 21 Mar 2013 17:38:18 +0000 (13:38 -0400)
Also fix bugs related to multiple requests.

src/moonshot-identities-manager.vala
src/moonshot-identity-management-view.vala
src/moonshot-identity-manager-app.vala
src/moonshot-identity-request.vala
src/moonshot-server.vala

index 86c731b..e0b1dd2 100644 (file)
@@ -1,6 +1,6 @@
 using Gee;
 
-class IdentityManagerModel : Object {
+public class IdentityManagerModel : Object {
     private const string FILE_NAME = "identities.txt";
 
     private IIdentityCardStore store;
index 7b93fdb..efc4a54 100644 (file)
@@ -1,7 +1,7 @@
 using Gee;
 using Gtk;
 
-class IdentityManagerView : Window {
+public class IdentityManagerView : Window {
     private const int WINDOW_WIDTH = 400;
     private const int WINDOW_HEIGHT = 500;
     protected IdentityManagerApp parent_app;
@@ -21,9 +21,8 @@ class IdentityManagerView : Window {
     private TreeModelFilter filter;
 
     public IdentityManagerModel identities_manager;
-    private SList<IdCard>    candidates;
+    private unowned SList<IdCard>    candidates;
 
-    private IdCard default_id_card;
     public GLib.Queue<IdentityRequest> request_queue;
 
     private HashTable<Gtk.Button, string> service_button_map;
@@ -72,11 +71,6 @@ class IdentityManagerView : Window {
         load_id_cards();
     }
     
-    public void add_candidate (IdCard idcard)
-    {
-        candidates.append (idcard);
-    }
-
     private bool visible_func (TreeModel model, TreeIter iter)
     {
         IdCard id_card;
@@ -195,7 +189,6 @@ class IdentityManagerView : Window {
         remove_id_card_widget((IdCardWidget)id_card_widget);
         }   
 
-        this.default_id_card = null;
         LinkedList<IdCard> card_list = identities_manager.get_card_list() ;
         if (card_list == null) {
             return;
@@ -205,10 +198,6 @@ class IdentityManagerView : Window {
             add_id_card_data (id_card);
             add_id_card_widget (id_card);
         }
-
-        if (card_list.size > 0){
-            this.default_id_card = card_list.first();
-        }
     }
     
     private void fill_details (IdCardWidget id_card_widget)
@@ -441,176 +430,26 @@ class IdentityManagerView : Window {
         dialog.destroy ();
     }
 
-    public void select_identity (IdentityRequest request)
+    public void queue_identity_request(IdentityRequest request)
     {
-        IdCard identity = null;
-
-        this.request_queue.push_tail (request);
-        
-        if (custom_vbox.current_idcard != null &&
-            custom_vbox.current_idcard.send_button != null)
-          custom_vbox.current_idcard.send_button.set_sensitive (true);
-
-        if (request.select_default)
-        {
-            identity = default_id_card;
-        }
-
-        if (identity == null)
-        {
-            bool has_nai = request.nai != null && request.nai != "";
-            bool has_srv = request.service != null && request.service != "";
-            bool confirm = false;
-            IdCard nai_provided = null;
-
-            foreach (IdCard id in identities_manager.get_card_list())
-            {
-                /* If NAI matches we add id card to the candidate list */
-                if (has_nai && request.nai == id.nai)
-                {
-                    nai_provided = id;
-                    add_candidate (id);
-                    continue;
-                }
-
-                /* If any service matches we add id card to the candidate list */
-                if (has_srv)
-                {
-                    foreach (string srv in id.services)
-                    {
-                        if (request.service == srv)
-                        {
-                            add_candidate (id);
-                            continue;
-                        }
-                    }
-                }
-            }
-
-            /* If more than one candidate we dissasociate service from all ids */
-            if (has_srv && candidates.length() > 1)
-            {
-                foreach (IdCard id in candidates)
-                {
-                    int i = 0;
-                    SList<string> services_list = null;
-                    bool has_service = false;
-
-                    foreach (string srv in id.services)
-                    {
-                        if (srv == request.service)
-                        {
-                            has_service = true;
-                            continue;
-                        }
-                        services_list.append (srv);
-                    }
-                    
-                    if (!has_service)
-                        continue;
-
-                    if (services_list.length () == 0)
-                    {
-                        id.services = {};
-                        continue;
-                    }
-
-                    string[] services = new string[services_list.length ()];
-                    foreach (string srv in services_list)
-                    {
-                        services[i] = srv;
-                        i++;
-                    }
-
-                    id.services = services;
-                }
-            }
-
-//            identities_manager.store_id_cards ();
-
-            /* If there are no candidates we use the service matching rules */
-            if (candidates.length () == 0)
-            {
-                foreach (IdCard id in identities_manager.get_card_list())
-                {
-                    foreach (Rule rule in id.rules)
-                    {
-                        if (!match_service_pattern (request.service, rule.pattern))
-                            continue;
-
-                        candidates.append (id);
-
-                        if (rule.always_confirm == "true")
-                            confirm = true;
-                    }
-                }
-            }
-            
-            if (candidates.length () > 1)
-            {
-                if (has_nai && nai_provided != null)
-                {
-                    identity = nai_provided;
-                    confirm = false;
-                }
-                else
-                    confirm = true;
-            }
-            else
-                identity = candidates.nth_data (0);
-
-            /* TODO: If candidate list empty return fail */
-            
-            if (confirm)
-            {
-                filter.refilter();
-                redraw_id_card_widgets ();
-                show ();
-                return;
-            }
+        if (this.request_queue.is_empty())
+        { /* setup widgets */
+            candidates = request.candidates;
+            filter.refilter();
+            redraw_id_card_widgets ();
+            show ();
         }
-        // Send back the identity (we can't directly run the
-        // callback because we may be being called from a 'yield')
-        Idle.add (() => { send_identity_cb (identity); return false; });
-        return;
-    }
-    
-    private bool match_service_pattern (string service, string pattern)
-    {
-        var pspec = new PatternSpec (pattern);
-        return pspec.match_string (service);
+        this.request_queue.push_tail (request);
     }
 
     public void send_identity_cb (IdCard identity)
     {
         return_if_fail (request_queue.length > 0);
 
+       candidates = null;
         var request = this.request_queue.pop_head ();
         bool reset_password = false;
 
-        if (request.service != null && request.service != "")
-        {
-            bool duplicate_service = false;
-
-            foreach (string service in identity.services)
-            {
-                if (service == request.service)
-                    duplicate_service = true;
-            }
-            if (duplicate_service == false)
-            {
-                string[] services = new string[identity.services.length + 1];
-
-                for (int i = 0; i < identity.services.length; i++)
-                    services[i] = identity.services[i];
-
-                services[identity.services.length] = request.service;
-                identity.services = services;
-
-                identities_manager.update_card (identity);
-            }
-        }
-
         if (identity.password == null)
         {
             var dialog = new AddPasswordDialog ();
@@ -630,17 +469,23 @@ class IdentityManagerView : Window {
         }
 
         if (this.request_queue.is_empty())
+        {
+            candidates = null;
             Gtk.main_quit ();
+        } else {
+            candidates = this.request_queue.peek_head().candidates;
+            filter.refilter();
+            redraw_id_card_widgets ();
+        }
 
         if (identity != null)
-            this.default_id_card = identity;
+            parent_app.default_id_card = identity;
 
         request.return_identity (identity);
 
         if (reset_password)
             identity.password = null;
 
-        candidates = null;
     }
 
     private void label_make_bold (Label label)
index 3989807..4bdc39a 100644 (file)
@@ -1,8 +1,10 @@
+using Gee;
 using Gtk;
 
 
-class IdentityManagerApp {
+public class IdentityManagerApp {
     public IdentityManagerModel model;
+    public IdCard default_id_card;
     private IdentityManagerView view;
     private MoonshotServer ipc_server;
 
@@ -23,12 +25,17 @@ class IdentityManagerApp {
     private const int WINDOW_WIDTH = 400;
     private const int WINDOW_HEIGHT = 500;
     public void show() {
-        view.show();    
+        if (view != null) view.show();    
     }
        
-    public IdentityManagerApp () {
+    public IdentityManagerApp (bool headless) {
         model = new IdentityManagerModel(this);
-        view = new IdentityManagerView(this);
+        if (!headless)
+            view = new IdentityManagerView(this);
+        LinkedList<IdCard> card_list = model.get_card_list() ;
+        if (card_list.size > 0)
+            this.default_id_card = card_list.first();
+
         init_ipc_server ();
 
 #if OS_MACOS
@@ -40,7 +47,144 @@ class IdentityManagerApp {
         Signal.connect(osxApp, "NSApplicationOpenFile", (GLib.Callback)(on_osx_open_files), this);
 
 #endif
-        view.show();
+        if (view != null) view.show();
+    }
+
+    public bool add_identity (IdCard id) {
+        /* TODO: add to store here irrespective of view's existence */
+        if (view != null) return view.add_identity(id);
+        return false;
+    }
+
+    public void select_identity (IdentityRequest request) {
+        IdCard identity = null;
+
+        if (request.select_default)
+        {
+            identity = default_id_card;
+        }
+
+        if (identity == null)
+        {
+            bool has_nai = request.nai != null && request.nai != "";
+            bool has_srv = request.service != null && request.service != "";
+            bool confirm = false;
+            IdCard nai_provided = null;
+
+            foreach (IdCard id in model.get_card_list())
+            {
+                /* If NAI matches we add id card to the candidate list */
+                if (has_nai && request.nai == id.nai)
+                {
+                    nai_provided = id;
+                    request.candidates.append (id);
+                    continue;
+                }
+
+                /* If any service matches we add id card to the candidate list */
+                if (has_srv)
+                {
+                    foreach (string srv in id.services)
+                    {
+                        if (request.service == srv)
+                        {
+                            request.candidates.append (id);
+                            continue;
+                        }
+                    }
+                }
+            }
+
+            /* If more than one candidate we dissasociate service from all ids */
+            if (has_srv && request.candidates.length() > 1)
+            {
+                foreach (IdCard id in request.candidates)
+                {
+                    int i = 0;
+                    SList<string> services_list = null;
+                    bool has_service = false;
+
+                    foreach (string srv in id.services)
+                    {
+                        if (srv == request.service)
+                        {
+                            has_service = true;
+                            continue;
+                        }
+                        services_list.append (srv);
+                    }
+                    
+                    if (!has_service)
+                        continue;
+
+                    if (services_list.length () == 0)
+                    {
+                        id.services = {};
+                        continue;
+                    }
+
+                    string[] services = new string[services_list.length ()];
+                    foreach (string srv in services_list)
+                    {
+                        services[i] = srv;
+                        i++;
+                    }
+
+                    id.services = services;
+                }
+            }
+
+//            model.store_id_cards ();
+
+            /* If there are no candidates we use the service matching rules */
+            if (request.candidates.length () == 0)
+            {
+                foreach (IdCard id in model.get_card_list())
+                {
+                    foreach (Rule rule in id.rules)
+                    {
+                        if (!match_service_pattern (request.service, rule.pattern))
+                            continue;
+
+                        request.candidates.append (id);
+
+                        if (rule.always_confirm == "true")
+                            confirm = true;
+                    }
+                }
+            }
+            
+            if (request.candidates.length () > 1)
+            {
+                if (has_nai && nai_provided != null)
+                {
+                    identity = nai_provided;
+                    confirm = false;
+                }
+                else
+                    confirm = true;
+            }
+            if (identity == null)
+                identity = request.candidates.nth_data (0);
+
+            /* TODO: If candidate list empty return fail */
+            
+            if (confirm && (view != null))
+            {
+               view.queue_identity_request(request);
+                return;
+            }
+        }
+        // Send back the identity (we can't directly run the
+        // callback because we may be being called from a 'yield')
+        Idle.add (() => { request.return_identity (identity); return false; });
+        return;
+    }
+
+    private bool match_service_pattern (string service, string pattern)
+    {
+        var pspec = new PatternSpec (pattern);
+        return pspec.match_string (service);
     }   
     
 #if IPC_MSRPC
@@ -66,7 +210,7 @@ class IdentityManagerApp {
             uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
             assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
 
-            this.ipc_server = new MoonshotServer (this.view);
+            this.ipc_server = new MoonshotServer (this);
             conn.register_object ("/org/janet/moonshot", ipc_server);
         }
         catch (DBus.Error e)
@@ -88,7 +232,7 @@ class IdentityManagerApp {
 
     private void init_ipc_server ()
     {
-        this.ipc_server = new MoonshotServer (this.view);
+        this.ipc_server = new MoonshotServer (this);
         GLib.Bus.own_name (GLib.BusType.SESSION,
                            "org.janet.Moonshot",
                            GLib.BusNameOwnerFlags.NONE,
@@ -103,7 +247,13 @@ class IdentityManagerApp {
 
 
 public static int main(string[] args){
-        Gtk.init(ref args);
+#if IPC_DBUS_GLIB
+        bool headless = GLib.Environment.get_variable("DISPLAY") != null;
+#else
+       bool headless = false;
+#endif
+        if (!headless)
+            Gtk.init(ref args);
 
 #if OS_WIN32
         // Force specific theme settings on Windows without requiring a gtkrc file
@@ -117,11 +267,18 @@ public static int main(string[] args){
         Intl.textdomain (Config.GETTEXT_PACKAGE);
        
           
-        var app = new IdentityManagerApp();
+        var app = new IdentityManagerApp(headless);
         
         app.show();
 
-        Gtk.main();
+        if (headless) {
+#if IPC_DBUS_GLIB
+            MainLoop loop = new MainLoop();
+            loop.run();
+#endif
+        } else {
+            Gtk.main();
+        }
 
         return 0;
     }
index bb67997..3646edf 100644 (file)
@@ -1,31 +1,32 @@
-delegate void ReturnIdentityCallback (IdentityRequest request);
+public delegate void ReturnIdentityCallback (IdentityRequest request);
 
-class IdentityRequest : Object {
+public class IdentityRequest : Object {
     public IdCard? id_card = null;
     public bool complete = false;
     public bool select_default = false;
 
-    private IdentityManagerView main_window;
+    private IdentityManagerApp parent_app;
     public string nai;
     public string password;
     public string service;
+    public SList<IdCard> candidates;
 
     ReturnIdentityCallback callback = null;
 
-    public IdentityRequest (IdentityManagerView                   main_window,
+    public IdentityRequest (IdentityManagerApp           app,
                             string                       nai,
                             string                       password,
                             string                       service)
     {
-        this.main_window = main_window;
+        this.parent_app = app;
         this.nai = nai;
         this.password = password;
         this.service = service;
     }
 
-    public IdentityRequest.default (IdentityManagerView main_window)
+    public IdentityRequest.default (IdentityManagerApp app)
     {
-        this.main_window = main_window;
+        this.parent_app = app;
         this.select_default = true;
     }
 
@@ -39,7 +40,7 @@ class IdentityRequest : Object {
     }
 
     public bool execute () {
-        main_window.select_identity (this);
+        parent_app.select_identity (this);
 
         /* This function works as a GSourceFunc, so it can be passed to
          * the main loop from other threads
@@ -48,11 +49,34 @@ class IdentityRequest : Object {
     }
 
     public void return_identity (IdCard? id_card) {
-        return_if_fail (callback != null);
-
         this.id_card = id_card;
         this.complete = true;
 
+        /* update id_card service list */
+        if (id_card != null && this.service != null && this.service != "")
+        {
+            bool duplicate_service = false;
+
+            foreach (string service in id_card.services)
+            {
+                if (service == this.service)
+                    duplicate_service = true;
+            }
+            if (duplicate_service == false)
+            {
+                string[] services = new string[id_card.services.length + 1];
+
+                for (int i = 0; i < id_card.services.length; i++)
+                    services[i] = id_card.services[i];
+
+                services[id_card.services.length] = this.service;
+                id_card.services = services;
+
+                this.parent_app.model.update_card (id_card);
+            }
+        }
+
+        return_if_fail (callback != null);
         callback (this);
     }
 
index c581860..267b670 100644 (file)
@@ -3,11 +3,11 @@
 [DBus (name = "org.janet.Moonshot")]
 public class MoonshotServer : Object {
 
-    private IdentityManagerView main_window;
+    private IdentityManagerApp parent_app;
 
-    public MoonshotServer (Gtk.Window window)
+    public MoonshotServer (IdentityManagerApp app)
     {
-        this.main_window = (IdentityManagerView) window;
+        this.parent_app = app;
     }
 
     public async bool get_identity (string nai,
@@ -20,7 +20,7 @@ public class MoonshotServer : Object {
                                     out string subject_name_constraint,
                                     out string subject_alt_name_constraint)
     {
-        var request = new IdentityRequest (main_window,
+        var request = new IdentityRequest (parent_app,
                                            nai,
                                            password,
                                            service);
@@ -72,7 +72,7 @@ public class MoonshotServer : Object {
                                             out string subject_name_constraint,
                                             out string subject_alt_name_constraint)
     {
-        var request = new IdentityRequest.default (main_window);
+        var request = new IdentityRequest.default (parent_app);
         request.set_callback ((IdentityRequest) => get_default_identity.callback());
         request.execute ();
         yield;
@@ -148,7 +148,7 @@ public class MoonshotServer : Object {
         }
       }
 
-      return main_window.add_identity (idcard);
+      return parent_app.add_identity (idcard);
     }