[seahorse] gkr: Port the gnome-keyring/libsecret stuff to vala



commit 7b202f99b4f66f4b13ae610be4159382cb98ec59
Author: Stef Walter <stefw gnome org>
Date:   Thu Jun 20 17:09:39 2013 +0200

    gkr: Port the gnome-keyring/libsecret stuff to vala

 gkr/Makefile.am                       |   35 +-
 gkr/gkr-backend.vala                  |  274 ++++++++++
 gkr/gkr-dialogs.vala                  |    4 +-
 gkr/gkr-item-add.vala                 |  121 +++++
 gkr/gkr-item-properties.vala          |  299 +++++++++++
 gkr/gkr-item.vala                     |  540 ++++++++++++++++++++
 gkr/gkr-keyring-add.vala              |   78 +++
 gkr/gkr-keyring-properties.vala       |   81 +++
 gkr/gkr-keyring.vala                  |  275 ++++++++++
 gkr/gkr-module.vala                   |    4 +-
 gkr/seahorse-add-keyring.xml          |   63 +---
 gkr/seahorse-gkr-actions.c            |  304 -----------
 gkr/seahorse-gkr-actions.h            |   34 --
 gkr/seahorse-gkr-add-item.c           |  188 -------
 gkr/seahorse-gkr-add-item.xml         |   73 +---
 gkr/seahorse-gkr-add-keyring.c        |  170 -------
 gkr/seahorse-gkr-backend.c            |  530 -------------------
 gkr/seahorse-gkr-backend.h            |   69 ---
 gkr/seahorse-gkr-dialogs.h            |   41 --
 gkr/seahorse-gkr-item-deleter.c       |  243 ---------
 gkr/seahorse-gkr-item-deleter.h       |   42 --
 gkr/seahorse-gkr-item-properties.c    |  567 ---------------------
 gkr/seahorse-gkr-item-properties.xml  |   71 +---
 gkr/seahorse-gkr-item.c               |  899 ---------------------------------
 gkr/seahorse-gkr-item.h               |   94 ----
 gkr/seahorse-gkr-keyring-deleter.c    |  182 -------
 gkr/seahorse-gkr-keyring-deleter.h    |   42 --
 gkr/seahorse-gkr-keyring-properties.c |  109 ----
 gkr/seahorse-gkr-keyring.c            |  525 -------------------
 gkr/seahorse-gkr-keyring.h            |   56 --
 gkr/seahorse-gkr-keyring.xml          |   16 +-
 src/seahorse-sidebar.c                |   13 +-
 32 files changed, 1697 insertions(+), 4345 deletions(-)
---
diff --git a/gkr/Makefile.am b/gkr/Makefile.am
index 029ecf4..ba3d781 100644
--- a/gkr/Makefile.am
+++ b/gkr/Makefile.am
@@ -10,13 +10,13 @@ INCLUDES = -I$(top_builddir) \
        -I$(top_srcdir)/libseahorse \
        $(SEAHORSE_CFLAGS) \
        -DSEAHORSE_UIDIR=\""$(uidir)/"\" \
+       -DUIDIR=\""$(uidir)/"\" \
        -DLOCALEDIR=\"$(localedir)\" \
        -DEXECDIR=\""$(seahorselibexecbindir)"\" \
        -DGETTEXT_PACKAGE=\""seahorse\"" \
        -DSECRET_API_SUBJECT_TO_CHANGE
 
 noinst_LTLIBRARIES = \
-       libvala-code.la \
        libseahorse-gkr.la
 
 AM_VALAFLAGS = \
@@ -25,37 +25,32 @@ AM_VALAFLAGS = \
        --header=seahorse-gkr.h \
        --vapidir $(top_builddir)/common \
        --pkg common \
+       --pkg config \
        --pkg gtk+-3.0 \
        --pkg gcr-3 \
+       --pkg gcr-ui-3 \
        --pkg libsecret-1 \
+       --pkg libsecret-unstable \
        $(NULL)
 
-libvala_code_la_SOURCES = \
+libseahorse_gkr_la_CFLAGS = \
+       -include config.h -w
+
+libseahorse_gkr_la_SOURCES = \
+       gkr-backend.vala \
        gkr-dialogs.vala \
        gkr-module.vala \
+       gkr-item.vala \
+       gkr-item-add.vala \
+       gkr-item-properties.vala \
+       gkr-keyring.vala \
+       gkr-keyring-add.vala \
+       gkr-keyring-properties.vala \
        $(NULL)
 
-libvala_code_la_CFLAGS = \
-       -include config.h -w \
-       $(NULL)
-
-libseahorse_gkr_la_SOURCES = \
-       seahorse-gkr-actions.c seahorse-gkr-actions.h \
-       seahorse-gkr-add-item.c \
-       seahorse-gkr-add-keyring.c \
-       seahorse-gkr-backend.c seahorse-gkr-backend.h \
-       seahorse-gkr-dialogs.h \
-       seahorse-gkr-item.c seahorse-gkr-item.h \
-       seahorse-gkr-item-deleter.c seahorse-gkr-item-deleter.h \
-       seahorse-gkr-item-properties.c \
-       seahorse-gkr-keyring.c seahorse-gkr-keyring.h \
-       seahorse-gkr-keyring-deleter.c seahorse-gkr-keyring-deleter.h \
-       seahorse-gkr-keyring-properties.c
-
 libseahorse_gkr_la_LIBADD = \
        $(top_builddir)/common/libcommon.la \
        $(top_builddir)/libseahorse/libseahorse.la \
-       libvala-code.la \
        $(NULL)
 
 ui_DATA = \
diff --git a/gkr/gkr-backend.vala b/gkr/gkr-backend.vala
new file mode 100644
index 0000000..abc062d
--- /dev/null
+++ b/gkr/gkr-backend.vala
@@ -0,0 +1,274 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+private class MyService : Secret.Service {
+       public override GLib.Type get_collection_gtype() {
+               return typeof(Keyring);
+       }
+
+       public override GLib.Type get_item_gtype() {
+               return typeof(Item);
+       }
+}
+
+public class Backend: GLib.Object , Gcr.Collection, Seahorse.Backend {
+       public string name {
+               get { return NAME; }
+       }
+
+       public string label {
+               get { return _("Passwords"); }
+       }
+
+       public string description {
+               get { return _("Stored personal passwords, credentials and secrets"); }
+       }
+
+       public Gtk.ActionGroup actions {
+               owned get { return this._actions; }
+       }
+
+       public GLib.HashTable<string, string> aliases {
+               get { return this._aliases; }
+       }
+
+       public Secret.Service? service {
+               get { return this._service; }
+       }
+
+       private static Backend? _instance = null;
+       private Secret.Service _service;
+       private GLib.HashTable<string, Keyring> _keyrings;
+       private GLib.HashTable<string, string> _aliases;
+       private Gtk.ActionGroup _actions;
+
+       construct {
+               return_if_fail(_instance == null);
+               Backend._instance = this;
+
+               this._actions = BackendActions.instance(this);
+               this._keyrings = new GLib.HashTable<string, Keyring>(GLib.str_hash, GLib.str_equal);
+               this._aliases = new GLib.HashTable<string, string>(GLib.str_hash, GLib.str_equal);
+
+               Secret.Service.open.begin(typeof(MyService), null,
+                                         Secret.ServiceFlags.OPEN_SESSION, null, (obj, res) => {
+                       try {
+                               this._service = Secret.Service.open.end(res);
+                               this._service.notify.connect((pspec) => {
+                                       if (pspec.name == "collections")
+                                               refresh_collections();
+                               });
+                               this._service.load_collections.begin(null, (obj, res) => {
+                                       refresh_collections();
+                               });
+                               refresh_aliases();
+                       } catch (GLib.Error err) {
+                               GLib.warning("couldn't connect to secret service: %s", err.message);
+                       }
+                       notify_property("service");
+               });
+       }
+
+       public override void dispose() {
+               this._aliases.remove_all();
+               this._keyrings.remove_all();
+               this._actions.sensitive = false;
+               base.dispose();
+       }
+
+       public void refresh_collections() {
+               var seen = new GLib.HashTable<string, weak string>(GLib.str_hash, GLib.str_equal);
+               var keyrings = this._service.get_collections();
+
+               string object_path;
+               foreach (var keyring in keyrings) {
+                       object_path = keyring.get_object_path();
+
+                       /* Don't list the session keyring */
+                       if (this._aliases.lookup("session") == object_path)
+                               continue;
+
+                       seen.add(object_path);
+                       if (this._keyrings.lookup(object_path) == null) {
+                               this._keyrings.insert(object_path, (Keyring)keyring);
+                               emit_added(keyring);
+                       }
+               }
+
+               /* Remove any that we didn't find */
+               var iter = GLib.HashTableIter<string, Keyring>(this._keyrings);
+               while (iter.next(out object_path, null)) {
+                       if (seen.lookup(object_path) == null) {
+                               var keyring = this._keyrings.lookup(object_path);
+                               iter.remove();
+                               emit_removed(keyring);
+                       }
+               }
+       }
+
+       public uint get_length() {
+               return this._keyrings.size();
+       }
+
+       public GLib.List<weak GLib.Object> get_objects() {
+               return get_keyrings();
+       }
+
+       public bool contains(GLib.Object object) {
+               if (object is Keyring) {
+                       var keyring = (Keyring)object;
+                       return this._keyrings.lookup(keyring.uri) == keyring;
+               }
+               return false;
+       }
+
+       public Place lookup_place(string uri) {
+               return this._keyrings.lookup(uri);
+       }
+
+       public static void initialize() {
+               return_if_fail(Backend._instance == null);
+               (new Backend()).register();
+               return_if_fail(Backend._instance != null);
+       }
+
+       public static Backend instance() {
+               return_if_fail(Backend._instance != null);
+               return Backend._instance;
+       }
+
+       public GLib.List<weak Keyring> get_keyrings() {
+               return this._keyrings.get_values();
+       }
+
+       private void read_alias(string name) {
+               if (this._service == null)
+                       return;
+               this._service.read_alias_dbus_path.begin(name, null, (obj, res) => {
+                       try {
+                               var object_path = this._service.read_alias_dbus_path.end(res);
+                               if (object_path != null) {
+                                       this._aliases.insert(name, object_path);
+                                       notify_property("aliases");
+                               }
+                       } catch (GLib.Error err) {
+                               GLib.warning("Couldn't read secret service alias %s: %s", name, err.message);
+                       }
+               });
+
+       }
+
+       private void refresh_aliases() {
+               read_alias("default");
+               read_alias("session");
+               read_alias("login");
+       }
+
+       public void refresh() {
+               refresh_aliases();
+               refresh_collections();
+       }
+       public bool has_alias(string alias,
+                             Keyring keyring) {
+               string object_path = keyring.get_object_path();
+               return this._aliases.lookup(alias) == object_path;
+       }
+}
+
+public class BackendActions : Seahorse.Actions {
+       public Backend backend { construct; get; }
+       private static WeakRef _instance;
+       private bool _initialized;
+
+       construct {
+               this._initialized = false;
+               this.set_translation_domain(Config.GETTEXT_PACKAGE);
+
+               this.backend.notify.connect_after((pspec) => {
+                       if (pspec.name == "service")
+                               return;
+                       if (this._initialized)
+                               return;
+                       if (this.backend.service == null)
+                                       return;
+
+                       this._initialized = true;
+                       this.add_actions(BACKEND_ACTIONS, null);
+                       this.register_definition(BACKEND_UI);
+
+                       /* Register another set of actions as a generator */
+                       var actions = new Gtk.ActionGroup("gkr-generate");
+                       actions.set_translation_domain(Config.GETTEXT_PACKAGE);
+                       actions.add_actions(ENTRIES_NEW, null);
+                       Registry.register_object(actions, "generator");
+               });
+
+               this.backend.notify_property("service");
+       }
+
+       private BackendActions(Backend backend) {
+               GLib.Object(name: "KeyringBackend", backend: backend);
+       }
+
+       private static void on_new_keyring(Gtk.Action action) {
+               new KeyringAdd(Action.get_window(action));
+       }
+
+       private static void on_new_item(Gtk.Action action) {
+               new ItemAdd(Action.get_window(action));
+       }
+
+       private static const Gtk.ActionEntry[] BACKEND_ACTIONS = {
+               { "keyring-new", null, N_("New password keyring"), "",
+                 N_("Used to store application and network passwords"), on_new_keyring },
+               { "keyring-item-new", null, N_("New password..."), "",
+                 N_("Safely store a password or secret."), on_new_item },
+       };
+
+       private static const Gtk.ActionEntry[] ENTRIES_NEW = {
+               { "keyring-new", "folder", N_("Password Keyring"), "",
+                 N_("Used to store application and network passwords"), on_new_keyring },
+               { "keyring-item-new", Gcr.ICON_PASSWORD, N_("Stored Password"), "",
+                 N_("Safely store a password or secret."), on_new_item }
+       };
+
+       private static const string BACKEND_UI =
+               """"<ui>
+                       <popup name='SeahorseGkrBackend'>
+                               <menuitem action='keyring-new'/>
+                       </popup>
+               </ui>""";
+
+       public static Gtk.ActionGroup instance(Backend backend) {
+               BackendActions? actions = (BackendActions?)_instance.get();
+               if (actions != null)
+                       return actions;
+               actions = new BackendActions(backend);
+               _instance.set(actions);
+               return actions;
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-dialogs.vala b/gkr/gkr-dialogs.vala
index 94f2ea3..651673d 100644
--- a/gkr/gkr-dialogs.vala
+++ b/gkr/gkr-dialogs.vala
@@ -20,8 +20,9 @@
  */
 
 namespace Seahorse {
+namespace Gkr {
 
-public class GkrDialog {
+public class Dialog {
 
        private static void update_wait_cursor(Gtk.Widget widget) {
                GLib.Cancellable? cancellable = widget.get_data("gkr-request");
@@ -81,3 +82,4 @@ public class GkrDialog {
 }
 
 }
+}
\ No newline at end of file
diff --git a/gkr/gkr-item-add.vala b/gkr/gkr-item-add.vala
new file mode 100644
index 0000000..173c484
--- /dev/null
+++ b/gkr/gkr-item-add.vala
@@ -0,0 +1,121 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public class ItemAdd : Gtk.Dialog {
+       construct {
+               this.title = _("Add Password");
+               this.modal = true;
+               this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
+               this.border_width = 5;
+
+               var builder = Util.load_built_contents(this, "gkr-add-item");
+               this.add_buttons(Gtk.Stock.OK, Gtk.ResponseType.ACCEPT,
+                                Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL);
+
+               /* Load up a list of all the keyrings, and select the default */
+               var combo = (Gtk.ComboBox)builder.get_object("item-keyring");
+               var store = new Gtk.ListStore(2, typeof(string), typeof(Secret.Collection));
+               combo.set_model(store);
+
+               var cell = new Gtk.CellRendererText();
+               combo.pack_start(cell, true);
+               combo.add_attribute(cell, "text", 0);
+
+               foreach (var keyring in Backend.instance().get_keyrings()) {
+                       Gtk.TreeIter iter;
+                       store.append(out iter);
+                       store.set(iter,
+                                 0, keyring.label,
+                                 1, keyring,
+                                 -1);
+                       if (keyring.is_default)
+                               combo.set_active_iter(iter);
+               }
+
+               var label = (Gtk.Entry)builder.get_object("item-label");
+               this.set_response_sensitive(Gtk.ResponseType.ACCEPT, false);
+               label.changed.connect((editable) => {
+                       var value = label.get_text();
+                       this.set_response_sensitive(Gtk.ResponseType.ACCEPT, value != "");
+               });
+
+               var area = (Gtk.Container)builder.get_object("password-area");
+               var buffer = new Gcr.SecureEntryBuffer();
+               var entry = new Gtk.Entry.with_buffer(buffer);
+               entry.visibility = false;
+               area.add(entry);
+               entry.show();
+
+               var check = (Gtk.ToggleButton)builder.get_object("show-password");
+               check.toggled.connect(() => {
+                       entry.visibility = check.active;
+               });
+
+               this.response.connect((resp) => {
+                       if (resp != Gtk.ResponseType.ACCEPT) {
+                               this.destroy();
+                               return;
+                       }
+
+                       Gtk.TreeIter iter;
+                       if (!combo.get_active_iter(out iter))
+                               return;
+
+                       Secret.Collection collection;
+                       combo.model.get(iter, 1, out collection, -1);
+
+                       var secret = new Secret.Value(entry.get_text(), -1, "text/plain");
+                       var cancellable = Dialog.begin_request(this);
+                       var attributes = new GLib.HashTable<string, string>(GLib.str_hash, GLib.str_equal);
+
+                       /* TODO: Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=697681 */
+                       var schema = new Secret.Schema("org.gnome.keyring.Note", Secret.SchemaFlags.NONE);
+
+                       Secret.Item.create.begin(collection, schema, attributes,
+                                                label.get_text(), secret, Secret.ItemCreateFlags.NONE,
+                                                cancellable, (obj, res) => {
+                               try {
+                                       /* Clear the operation without cancelling it since it is complete */
+                                       Dialog.complete_request(this, false);
+
+                                       Secret.Item.create.end(res);
+                               } catch (GLib.Error err) {
+                                       Util.show_error(this, _("Couldn't add item"), err.message);
+                               }
+
+                               this.destroy();
+                       });
+
+               });
+       }
+
+       public ItemAdd(Gtk.Window? parent) {
+               GLib.Object(transient_for: parent);
+               this.show();
+               this.present();
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-item-properties.vala b/gkr/gkr-item-properties.vala
new file mode 100644
index 0000000..0c3e447
--- /dev/null
+++ b/gkr/gkr-item-properties.vala
@@ -0,0 +1,299 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2006 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public class ItemProperties : Gtk.Dialog {
+       public Item item { construct; get; }
+
+       private Gtk.Builder _builder;
+       private Gtk.Entry _password_entry;
+       private Gtk.Expander _password_expander;
+       private bool _password_changed;
+       private bool _updating_password;
+       private bool _updating_description;
+
+       construct {
+               this._builder = new Gtk.Builder();
+               try {
+                       string path = GLib.Path.build_filename(Config.UIDIR, 
"seahorse-gkr-item-properties.xml");
+                       this._builder.add_from_file(path);
+               } catch (GLib.Error err) {
+                       GLib.critical ("%s", err.message);
+               }
+
+               this.add_button(Gtk.Stock.CLOSE, Gtk.ResponseType.CLOSE);
+               var content = (Gtk.Widget)this._builder.get_object("gkr-item-properties");
+               ((Gtk.Container)this.get_content_area()).add(content);
+               content.show();
+
+               this.response.connect((response) => {
+                       this.destroy();
+               });
+
+               /* Setup the image properly */
+               this.item.bind_property ("icon", this._builder.get_object("key-image"), "gicon",
+                                        GLib.BindingFlags.SYNC_CREATE);
+
+               /* Setup the label properly */
+               Gtk.Entry description = (Gtk.Entry)this._builder.get_object("description-field");
+               this.item.bind_property("label", description, "text", GLib.BindingFlags.SYNC_CREATE);
+               description.activate.connect(() => {
+                       description_activate(description);
+               });
+               description.focus_out_event.connect_after(() => {
+                       description_activate(description);
+                       return false;
+               });
+
+               /* The expander for showing password */
+               this._password_expander = (Gtk.Expander)this._builder.get_object("password-expander");
+               this._password_expander.activate.connect_after(expander_activate);
+
+               /* The check button for password visibility */
+               Gtk.CheckButton check = (Gtk.CheckButton)this._builder.get_object("show-password-check");
+               check.toggled.connect(() => {
+                       this._password_entry.visibility = check.active;
+               });
+
+               /* Window title */
+               this.item.bind_property ("label", this, "title", GLib.BindingFlags.SYNC_CREATE);
+
+               /* Update as appropriate */
+               this.item.notify.connect((pspec) => {
+                       switch(pspec.name) {
+                       case "use":
+                               update_use();
+                               update_type();
+                               update_visibility();
+                               break;
+                       case "attributes":
+                               update_details();
+                               update_server();
+                               update_user();
+                               break;
+                       case "has-secret":
+                               password_display();
+                               break;
+                       }
+               });
+
+               /* Create the password entry */
+               var buffer = new Gcr.SecureEntryBuffer();
+               this._password_entry = new Gtk.Entry.with_buffer(buffer);
+               Gtk.Box box = (Gtk.Box)this._builder.get_object("password-box-area");
+               box.add(this._password_entry);
+               this._password_entry.visibility = false;
+               this._password_entry.show();
+               this._password_changed = false;
+               this._updating_password = false;
+
+               /* Now watch for changes in the password */
+               this._password_entry.activate.connect(password_activate);
+               this._password_entry.changed.connect(() => {
+                       this._password_changed = true;
+               });
+               this._password_entry.focus_out_event.connect_after(() => {
+                       password_activate ();
+                       return false;
+               });
+
+               /* Sensitivity of the password entry */
+               this.item.bind_property("has-secret", this._password_entry, "sensitive");
+       }
+
+       public ItemProperties(Item item,
+                             Gtk.Window? parent) {
+               GLib.Object (
+                       item: item,
+                       transient_for: parent
+               );
+
+               item.refresh();
+       }
+
+       private void update_use() {
+               Gtk.Label use = (Gtk.Label)this._builder.get_object("use-field");
+               switch (this.item.use) {
+               case Use.NETWORK:
+                       use.label = _("Access a network share or resource");
+                       break;
+               case Use.WEB:
+                       use.label = _("Access a website");
+                       break;
+               case Use.PGP:
+                       use.label = _("Unlocks a PGP key");
+                       break;
+               case Use.SSH:
+                       use.label = _("Unlocks a Secure Shell key");
+                       break;
+               case Use.OTHER:
+                       use.label = _("Saved password or login");
+                       break;
+               default:
+                       use.label = "";
+                       break;
+               };
+       }
+
+       private void update_type() {
+               Gtk.Label type = (Gtk.Label)this._builder.get_object("type-field");
+               switch (item.use) {
+               case Use.NETWORK:
+               case Use.WEB:
+                       type.label = _("Network Credentials");
+                       break;
+               case Use.PGP:
+               case Use.SSH:
+               case Use.OTHER:
+                       type.label = _("Password");
+                       break;
+               default:
+                       type.label = "";
+                       break;
+               };
+       }
+
+       private void update_visibility() {
+               var use = this.item.use;
+               bool visible = use == Use.NETWORK || use == Use.WEB;
+               this._builder.get_object("server-label").set("visible", visible);
+               this._builder.get_object("server-field").set("visible", visible);
+               this._builder.get_object("login-label").set("visible", visible);
+               this._builder.get_object("login-field").set("visible", visible);
+       }
+
+       private void update_server() {
+               Gtk.Label server = (Gtk.Label)this._builder.get_object("server-label");
+               var value = this.item.get_attribute("server");
+               if (value == null)
+                       value = "";
+               server.label = value;
+       }
+
+       private void update_user() {
+               Gtk.Label login = (Gtk.Label)this._builder.get_object("login-label");
+               var value = this.item.get_attribute("user");
+               if (value == null)
+                       value = "";
+               login.label = value;
+       }
+
+       private void update_details() {
+               var contents = new GLib.StringBuilder();
+               var attrs = this.item.attributes;
+               var iter = GLib.HashTableIter<string, string>(attrs);
+               string key, value;
+               while (iter.next(out key, out value)) {
+                       if (key.has_prefix("gkr:") || key.has_prefix("xdg:"))
+                               continue;
+                       contents.append_printf("<b>%s</b>: %s\n",
+                                              GLib.Markup.escape_text(key),
+                                              GLib.Markup.escape_text(value));
+               }
+               Gtk.Label details = (Gtk.Label)this._builder.get_object("details-box");
+               details.use_markup = true;
+               details.label = contents.str;
+       }
+
+       private void password_activate()
+       {
+               if (!this._password_expander.expanded)
+                       return;
+               if (!this._password_changed)
+                       return;
+               if (this._updating_password)
+                       return;
+
+               this._updating_password = true;
+               this._password_expander.sensitive = false;
+
+               var value = new Secret.Value(this._password_entry.text, -1, "text/plain");
+               this.item.set_secret.begin(value, null, (obj, res) => {
+                       try {
+                               this.item.set_secret.end(res);
+                               password_display();
+                       } catch (GLib.Error err) {
+                               DBusError.strip_remote_error(err);
+                               Util.show_error (this, _("Couldn't change password."), err.message);
+                       }
+
+                       this._password_expander.sensitive = true;
+                       this._updating_password = false;
+               });
+       }
+
+       private void password_display() {
+               if (this._password_expander.expanded) {
+                       var secret = this.item.get_secret();
+                       if (secret != null) {
+                               unowned string? password = secret.get_text();
+                               if (password != null) {
+                                       this._password_entry.set_text(password);
+                                       this._password_changed = false;
+                                       return;
+                               }
+                       }
+               }
+               this._password_entry.set_text("");
+               this._password_changed = false;
+       }
+
+       private void description_activate(Gtk.Entry description)
+       {
+               if (this._updating_description)
+                       return;
+
+               this._updating_description = true;
+               description.sensitive = false;
+
+               this.item.set_label.begin(description.text, null, (obj, res) => {
+                       try {
+                               this.item.set_label.end(res);
+                       } catch (GLib.Error err) {
+                               description.text = this.item.label;
+                               DBusError.strip_remote_error(err);
+                               Util.show_error (this, _("Couldn't set description."), err.message);
+                       }
+
+                       description.sensitive = true;
+                       this._updating_description = false;
+               });
+       }
+
+       private void expander_activate (Gtk.Expander expander)
+       {
+               if (!expander.expanded)
+                       return;
+
+               /* Always have a hidden password when opening box */
+               Gtk.CheckButton check = (Gtk.CheckButton)this._builder.get_object("show-password-check");
+               check.set_active (false);
+
+               /* Make sure to trigger retrieving the secret */
+               password_display ();
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-item.vala b/gkr/gkr-item.vala
new file mode 100644
index 0000000..b179871
--- /dev/null
+++ b/gkr/gkr-item.vala
@@ -0,0 +1,540 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2006 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public enum Use {
+       OTHER,
+       NETWORK,
+       WEB,
+       PGP,
+       SSH,
+}
+
+private struct DisplayInfo {
+       string? item_type;
+       string? label;
+       string? details;
+       string? description;
+}
+
+[CCode (has_target = false)]
+private delegate void DisplayCustom(string label,
+                                    GLib.HashTable<string, string> item_attrs,
+                                    ref DisplayInfo info);
+
+private struct DisplayEntry {
+       string item_type;
+       string description;
+       DisplayCustom? custom_func;
+}
+
+public class Item : Secret.Item, Deletable, Viewable {
+       public string description {
+               owned get {
+                       ensure_display_info ();
+                       return this._info.description;
+               }
+       }
+
+       public Use use {
+               get {
+                       var schema_name = get_attribute("xdg:schema");
+                       if (schema_name != null && schema_name == NETWORK_PASSWORD)
+                               return Use.NETWORK;
+                       return Use.OTHER;
+               }
+       }
+
+       public bool has_secret {
+               get { return _item_secret != null; }
+       }
+
+       public Keyring place {
+               owned get { return (Keyring)_place.get(); }
+               set { _place.set(value); }
+       }
+
+       public Flags object_flags {
+               get { return Flags.DELETABLE | Flags.PERSONAL; }
+       }
+
+       public GLib.Icon icon {
+               owned get { return new GLib.ThemedIcon (Gcr.ICON_PASSWORD); }
+       }
+
+       public new string label {
+               owned get {
+                       ensure_display_info ();
+                       return this._info.label;
+               }
+       }
+
+       public string markup {
+               owned get {
+                       ensure_display_info ();
+                       var result = new GLib.StringBuilder("");
+                       result.append(GLib.Markup.escape_text(this._info.label));
+                       result.append("<span size='small' rise='0' foreground='#555555'>\n");
+                       result.append(this._info.details);
+                       result.append("</span>");
+                       return result.str;
+               }
+       }
+
+       public Usage usage {
+               get { return Usage.CREDENTIALS; }
+       }
+
+       public Gtk.ActionGroup? actions {
+               get { return null; }
+       }
+
+       public bool deletable {
+               get { return true; }
+       }
+
+       private Secret.Value? _item_secret = null;
+       private DisplayInfo? _info = null;
+       private GLib.WeakRef _place;
+       private GLib.Cancellable? _req_secret = null;
+
+       construct {
+               g_properties_changed.connect((changed_properties, invalidated_properties) => {
+                       this._info = null;
+                       freeze_notify();
+                       notify_property("has-secret");
+                       notify_property("use");
+                       notify_property("label");
+                       notify_property("icon");
+                       notify_property("markup");
+                       notify_property("description");
+                       notify_property("object-flags");
+                       thaw_notify();
+               });
+       }
+
+       public override void dispose() {
+               if (this._req_secret != null)
+                       this._req_secret.cancel();
+               this._req_secret = null;
+               base.dispose();
+       }
+
+       public Deleter create_deleter() {
+               return new ItemDeleter(this);
+       }
+
+       public Gtk.Window? create_viewer(Gtk.Window? parent) {
+               return new ItemProperties(this, parent);
+       }
+
+       private void ensure_display_info() {
+               if (this._info != null)
+                       return;
+
+               this._info = DisplayInfo();
+
+               var attrs = this.attributes;
+               var item_type = get_attribute_string (attrs, "xdg:schema");
+               item_type = map_item_type_to_specific (item_type, attrs);
+               assert (item_type != null);
+               this._info.item_type = item_type;
+
+               var label = base.get_label();
+               foreach (var entry in DISPLAY_ENTRIES) {
+                       if (entry.item_type == item_type) {
+                               if (entry.custom_func != null)
+                                       entry.custom_func(label, attrs, ref this._info);
+                               if (this._info.description == null)
+                                       this._info.description = entry.description;
+                               break;
+                       }
+               }
+
+               if (this._info.label == null)
+                       this._info.label = label;
+               if (this._info.label == null)
+                       this._info.label = "";
+               if (this._info.details == null)
+                       this._info.details = "";
+       }
+
+       private void load_item_secret() {
+               if (this._req_secret == null) {
+                       this._req_secret = new GLib.Cancellable();
+                       load_secret.begin(this._req_secret, (obj, res) => {
+                               try {
+                                       this._req_secret = null;
+                                       load_secret.end(res);
+                                       this._item_secret = base.get_secret();
+                                       notify_property("has-secret");
+                               } catch (GLib.Error err) {
+                                       GLib.warning("Couldn't retrieve secret: %s", err.message);
+                               }
+                       });
+               }
+       }
+
+
+       public new void refresh() {
+               base.refresh();
+               if (this._item_secret != null)
+                       load_item_secret ();
+       }
+
+       public new Secret.Value? get_secret() {
+               if (this._item_secret == null)
+                       load_item_secret ();
+               return this._item_secret;
+       }
+
+       public string? get_attribute(string name) {
+               if (this.attributes == null)
+                       return null;
+               return this.attributes.lookup(name);
+       }
+
+       public new async bool set_secret(Secret.Value value,
+                                        GLib.Cancellable? cancellable) throws GLib.Error {
+               yield base.set_secret(value, cancellable);
+               _item_secret = value;
+               notify_property("has-secret");
+               return true;
+       }
+}
+
+private const string GENERIC_SECRET = "org.freedesktop.Secret.Generic";
+private const string NETWORK_PASSWORD = "org.gnome.keyring.NetworkPassword";
+private const string KEYRING_NOTE = "org.gnome.keyring.Note";
+private const string CHAINED_KEYRING = "org.gnome.keyring.ChainedKeyring";
+private const string ENCRYPTION_KEY = "org.gnome.keyring.EncryptionKey";
+private const string PK_STORAGE = "org.gnome.keyring.PkStorage";
+private const string CHROME_PASSWORD = "x.internal.Chrome";
+private const string GOA_PASSWORD = "org.gnome.OnlineAccounts";
+private const string TELEPATHY_PASSWORD = "org.freedesktop.Telepathy";
+private const string EMPATHY_PASSWORD = "org.freedesktop.Empathy";
+private const string NETWORK_MANAGER_SECRET = "org.freedesktop.NetworkManager";
+
+private string? get_attribute_string(GLib.HashTable<string, string>? attrs,
+                                     string name) {
+       if (attrs == null)
+               return null;
+       return attrs.lookup(name);
+}
+
+private int get_attribute_int(GLib.HashTable<string, string>? attrs,
+                              string name)
+{
+       if (attrs == null)
+               return 0;
+
+       var value = attrs.lookup(name);
+       if (value != null)
+               return int.parse(value);
+
+       return 0;
+}
+
+private bool is_network_item(GLib.HashTable<string, string>? attrs,
+                             string match)
+{
+       var protocol = get_attribute_string (attrs, "protocol");
+       return protocol != null && protocol.ascii_casecmp(match) == 0;
+}
+
+private bool is_custom_network_label(string? server,
+                                     string? user,
+                                     string? object,
+                                     int port,
+                                     string? display)
+{
+       /*
+        * For network passwords gnome-keyring generates in a funky looking display
+        * name that's generated from login credentials. We simulate that generating
+        * here and return FALSE if it matches. This allows us to display user
+        * customized display names and ignore the generated ones.
+        */
+
+       if (server == null)
+               return true;
+
+       var generated = new GLib.StringBuilder("");
+       if (user != null)
+               generated.append_printf("%s@", user);
+       generated.append(server);
+       if (port != 0)
+               generated.append_printf(":%d", port);
+       if (object != null)
+               generated.append_printf ("/%s", object);
+
+       return (generated.str == display);
+}
+
+private string? calc_network_label(GLib.HashTable<string, string>? attrs,
+                                   bool always)
+{
+       /* HTTP usually has a the realm as the "object" display that */
+       if (is_network_item (attrs, "http") && attrs != null) {
+               var val = get_attribute_string (attrs, "object");
+               if (val != null && val != "")
+                       return val;
+
+               /* Display the server name as a last resort */
+               if (always) {
+                       val = get_attribute_string (attrs, "server");
+                       if (val != null && val != "")
+                               return val;
+               }
+       }
+
+       return null;
+}
+
+private void network_custom(string? display,
+                            GLib.HashTable<string, string>? attrs,
+                            ref DisplayInfo info)
+{
+       var server = get_attribute_string (attrs, "server");
+       var protocol = get_attribute_string (attrs, "protocol");
+       var object = get_attribute_string (attrs, "object");
+       var user = get_attribute_string (attrs, "user");
+       var port = get_attribute_int (attrs, "port");
+
+       if (protocol == null)
+               return;
+
+       /* If it's customized by the application or user then display that */
+       if (!is_custom_network_label (server, user, object, port, display))
+               info.label = calc_network_label (attrs, true);
+       if (info.label == null)
+               info.label = display;
+
+       string symbol = "@";
+       if (user == null) {
+               user = "";
+               symbol = "";
+       }
+
+       if (object == null)
+               object = "";
+
+       if (server != null && protocol != null) {
+               info.details = GLib.Markup.printf_escaped("%s://%s%s%s/%s",
+                                                         protocol, user, symbol,
+                                                         server, object);
+       }
+}
+
+private void chrome_custom(string? display,
+                           GLib.HashTable<string, string>? attrs,
+                           ref DisplayInfo info)
+{
+       var origin = get_attribute_string (attrs, "origin_url");
+
+       /* A brain dead url, parse */
+       if (display != null && display == origin) {
+               try {
+                       var regex = new GLib.Regex("[a-z]+://([^/]+)/", GLib.RegexCompileFlags.CASELESS, 0);
+                       GLib.MatchInfo match;
+                       if (regex.match(display, GLib.RegexMatchFlags.ANCHORED, out match)) {
+                               if (match.matches())
+                                       info.label = match.fetch(1);
+                       }
+               } catch (GLib.RegexError err) {
+                       GLib.critical("%s", err.message);
+                       return;
+               }
+
+       }
+
+       if (info.label == null)
+               info.label = display;
+       if (origin != null)
+               info.details = GLib.Markup.escape_text(origin);
+       else
+               info.details = "";
+}
+
+private string? decode_telepathy_id(string account) {
+       account.replace("_", "%");
+       return GLib.Uri.unescape_string(account);
+}
+
+private void empathy_custom(string? display,
+                            GLib.HashTable<string, string>? attrs,
+                            ref DisplayInfo info)
+{
+       var account = get_attribute_string(attrs, "account-id");
+
+       /* Translators: This should be the same as the string in empathy */
+       var prefix = _("IM account password for ");
+
+       if (display != null && display.has_prefix(prefix)) {
+               var len = prefix.length;
+               var pos = display.index_of_char ('(', (int)len);
+               if (pos != -1)
+                       info.label = display.slice(len, pos);
+
+               try {
+                       var regex = new GLib.Regex("^.+/.+/(.+)$", GLib.RegexCompileFlags.CASELESS, 0);
+                       GLib.MatchInfo match;
+                       if (regex.match(account, GLib.RegexMatchFlags.ANCHORED, out match)) {
+                               if (match.matches())
+                                       info.details = decode_telepathy_id (match.fetch(1));
+                       }
+               } catch (GLib.RegexError err) {
+                       GLib.critical("%s", err.message);
+                       return;
+               }
+       }
+
+       if (info.label == null)
+               info.label = display;
+       if (info.details == null)
+               info.details = GLib.Markup.escape_text (account);
+}
+
+private void telepathy_custom(string? display,
+                              GLib.HashTable<string, string>? attrs,
+                              ref DisplayInfo info)
+{
+       var account = get_attribute_string (attrs, "account");
+       if (account != null && display != null && display.index_of(account) != -1) {
+               try {
+                       var regex = new GLib.Regex("^.+/.+/(.+)$", GLib.RegexCompileFlags.CASELESS, 0);
+                       GLib.MatchInfo match;
+                       if (regex.match(account, GLib.RegexMatchFlags.ANCHORED, out match)) {
+                               if (match.matches()) {
+                                       var identifier = match.fetch(1);
+                                       info.label = decode_telepathy_id(identifier);
+                               }
+                       }
+               } catch (GLib.RegexError err) {
+                       GLib.critical("%s", err.message);
+                       return;
+               }
+       }
+
+       if(info.label == null)
+               info.label = display;
+       if(account != null)
+               info.details = GLib.Markup.escape_text(account);
+}
+
+
+private const DisplayEntry[] DISPLAY_ENTRIES = {
+       { GENERIC_SECRET, N_("Password or secret"), null},
+       { NETWORK_PASSWORD, N_("Network password"), network_custom },
+       { KEYRING_NOTE, N_("Stored note"), null },
+       { CHAINED_KEYRING, N_("Keyring password"), null },
+       { ENCRYPTION_KEY, N_("Encryption key password"), null },
+       { PK_STORAGE, N_("Key storage password"), null },
+       { CHROME_PASSWORD, N_("Google Chrome password"), chrome_custom },
+       { GOA_PASSWORD, N_("Gnome Online Accounts password"), null },
+       { TELEPATHY_PASSWORD, N_("Telepathy password"), telepathy_custom },
+       { EMPATHY_PASSWORD, N_("Instant messaging password"), empathy_custom },
+       { NETWORK_MANAGER_SECRET, N_("Network Manager secret"), null },
+};
+
+private struct MappingEntry {
+       string item_type;
+       string mapped_type;
+       string match_attribute;
+       string? match_pattern;
+}
+
+private const MappingEntry[] MAPPING_ENTRIES = {
+       { GENERIC_SECRET, CHROME_PASSWORD, "application", "chrome*" },
+       { GENERIC_SECRET, GOA_PASSWORD, "goa-identity", null },
+       { GENERIC_SECRET, TELEPATHY_PASSWORD, "account", "*/*/*" },
+       { GENERIC_SECRET, EMPATHY_PASSWORD, "account-id", "*/*/*" },
+       /* Network secret for Auto anna/802-11-wireless-security/psk */
+       { GENERIC_SECRET, NETWORK_MANAGER_SECRET, "connection-uuid", null },
+};
+
+private string map_item_type_to_specific(string? item_type,
+                                         GLib.HashTable<string, string>? attrs)
+{
+
+       if (item_type == null)
+               return GENERIC_SECRET;
+       if (attrs == null)
+               return item_type;
+
+       foreach (var mapping in MAPPING_ENTRIES) {
+               if (item_type == mapping.item_type) {
+                       var value = get_attribute_string (attrs, mapping.match_attribute);
+                       if (value != null && mapping.match_pattern != null) {
+                               if (GLib.PatternSpec.match_simple(mapping.match_pattern, value))
+                                       return mapping.mapped_type;
+                       } else if (value != null) {
+                               return mapping.mapped_type;
+                       }
+               }
+       }
+
+       return item_type;
+}
+
+class ItemDeleter : Deleter {
+       private GLib.List<Item> _items;
+
+       public override Gtk.Dialog create_confirm(Gtk.Window? parent) {
+               var num = this._items.length();
+               if (num == 1) {
+                       var label = ((Secret.Item)_items.data).label;
+                       return new DeleteDialog(parent, _("Are you sure you want to delete the password 
'%s'?"), label);
+               } else {
+                       return new DeleteDialog(parent, GLib.ngettext ("Are you sure you want to delete %d 
password?",
+                                                                      "Are you sure you want to delete %d 
passwords?", num), num);
+               }
+       }
+
+       public ItemDeleter(Item item) {
+               if (!add_object(item))
+                       GLib.assert_not_reached();
+       }
+
+       public override unowned GLib.List<weak GLib.Object> get_objects() {
+               return this._items;
+       }
+
+       public override bool add_object (GLib.Object obj) {
+               if (obj is Item) {
+                       this._items.append((Item)obj);
+                       return true;
+               }
+               return false;
+       }
+
+       public override async bool delete(GLib.Cancellable? cancellable) throws GLib.Error {
+               var items = _items.copy();
+               foreach (var item in items)
+                       yield item.delete(cancellable);
+               return true;
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-keyring-add.vala b/gkr/gkr-keyring-add.vala
new file mode 100644
index 0000000..54c66e4
--- /dev/null
+++ b/gkr/gkr-keyring-add.vala
@@ -0,0 +1,78 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public class KeyringAdd : Gtk.Dialog {
+       construct {
+               this.title = _("Add Password Keyring");
+               this.modal = true;
+               this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
+               this.border_width = 5;
+
+               var builder = Util.load_built_contents(this, "add-keyring");
+               this.add_buttons(Gtk.Stock.OK, Gtk.ResponseType.ACCEPT,
+                                Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL);
+
+               var entry = (Gtk.Entry)builder.get_object("keyring-name");
+               this.set_response_sensitive(Gtk.ResponseType.ACCEPT, false);
+               entry.changed.connect((editable) => {
+                       var name = entry.get_text();
+                       this.set_response_sensitive(Gtk.ResponseType.ACCEPT, name != "");
+               });
+
+               this.response.connect((resp) => {
+                       if (resp == Gtk.ResponseType.ACCEPT) {
+                               var name = entry.get_text();
+                               var cancellable = Dialog.begin_request(this);
+                               var service = Backend.instance().service;
+                               Secret.Collection.create.begin(service, name, null,
+                                                              
Secret.CollectionCreateFlags.COLLECTION_CREATE_NONE,
+                                                              cancellable, (obj, res) => {
+                                       /* Clear the operation without cancelling it since it is complete */
+                                       Dialog.complete_request(this, false);
+
+                                       try {
+                                               Secret.Collection.create.end(res);
+                                       } catch (GLib.Error err) {
+                                               Util.show_error(this, _("Couldn't add keyring"), err.message);
+                                       }
+
+                                       this.destroy();
+                               });
+                       } else {
+                               this.destroy();
+                       }
+               });
+
+       }
+
+       public KeyringAdd(Gtk.Window? parent) {
+               GLib.Object(transient_for: parent);
+               this.show();
+               this.present();
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-keyring-properties.vala b/gkr/gkr-keyring-properties.vala
new file mode 100644
index 0000000..7fc5190
--- /dev/null
+++ b/gkr/gkr-keyring-properties.vala
@@ -0,0 +1,81 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public class KeyringProperties : Gtk.Dialog {
+       public Keyring keyring { construct; get; }
+
+       private Gtk.Builder _builder;
+
+       construct {
+               this._builder = new Gtk.Builder();
+               try {
+                       string path = GLib.Path.build_filename(Config.UIDIR, "seahorse-gkr-keyring.xml");
+                       this._builder.add_from_file(path);
+               } catch (GLib.Error err) {
+                       GLib.critical ("%s", err.message);
+               }
+
+               this.add_button(Gtk.Stock.CLOSE, Gtk.ResponseType.CLOSE);
+               var content = (Gtk.Widget)this._builder.get_object("gkr-item-properties");
+               ((Gtk.Container)this.get_content_area()).add(content);
+               content.show();
+
+               this.response.connect((response) => {
+                       this.destroy();
+               });
+
+               /* Setup the image properly */
+               this.keyring.bind_property ("icon", this._builder.get_object("keyring-image"), "gicon",
+                                           GLib.BindingFlags.SYNC_CREATE);
+
+               /* The window title */
+               this.keyring.bind_property ("label", this, "title", GLib.BindingFlags.SYNC_CREATE);
+
+               /* Setup the label properly */
+               var name = (Gtk.Label)this._builder.get_object("name-field");
+               this.keyring.bind_property ("label", name, "label", GLib.BindingFlags.SYNC_CREATE);
+
+               /* The date field */
+               this.keyring.notify.connect((pspec) => {
+                       switch(pspec.name) {
+                       case "created":
+                               var created = (Gtk.Label)this._builder.get_object("created-field");
+                               created.label = Util.get_display_date_string((long)this.keyring.created);
+                               break;
+                       }
+               });
+       }
+
+       public KeyringProperties(Keyring keyring,
+                                Gtk.Window? parent) {
+               GLib.Object (
+                       keyring: keyring,
+                       transient_for: parent
+               );
+       }
+
+}
+
+}
+}
diff --git a/gkr/gkr-keyring.vala b/gkr/gkr-keyring.vala
new file mode 100644
index 0000000..2c76aec
--- /dev/null
+++ b/gkr/gkr-keyring.vala
@@ -0,0 +1,275 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+namespace Seahorse {
+namespace Gkr {
+
+public class Keyring : Secret.Collection, Gcr.Collection, Place, Deletable, Lockable, Viewable {
+       public string description {
+               owned get {
+                       if (Backend.instance().has_alias ("login", this))
+                               return _("A keyring that is automatically unlocked on login");
+                       return _("A keyring used to store passwords");
+               }
+       }
+
+       public string uri {
+               owned get {
+                       var object_path = base.get_object_path ();
+                       return "secret-service://%s".printf(object_path);
+               }
+       }
+
+       public GLib.Icon icon {
+               owned get { return new GLib.ThemedIcon("folder"); }
+       }
+       public Gtk.ActionGroup actions {
+               owned get {
+                       if (this._actions == null)
+                               this._actions = create_actions();
+                       return this._actions;
+               }
+       }
+
+       public bool is_default {
+               get { return Backend.instance().has_alias ("default", this); }
+       }
+
+       public bool lockable {
+               get { return !get_locked(); }
+       }
+
+       public bool unlockable {
+               get { return get_locked(); }
+       }
+
+       public bool deletable {
+               get { return true; }
+       }
+
+       private GLib.HashTable<string, Item> _items;
+       private Gtk.ActionGroup? _actions;
+
+       construct {
+               this._items = new GLib.HashTable<string, Item>(GLib.str_hash, GLib.str_equal);
+               this.notify.connect((pspec) => {
+                       if (pspec.name == "items" || pspec.name == "locked")
+                               refresh_collection();
+               });
+               Backend.instance().notify.connect((pspec) => {
+                       notify_property ("is-default");
+                       notify_property ("description");
+               });
+       }
+
+       public uint get_length() {
+               return _items.size();
+       }
+
+       public GLib.List<weak GLib.Object> get_objects() {
+               return _items.get_values();
+       }
+
+       public bool contains(GLib.Object obj) {
+               if (obj is Item)
+                       return _items.lookup(((Item)obj).get_object_path()) != null;
+               return false;
+       }
+
+       public Gtk.Window? create_viewer(Gtk.Window? parent) {
+               return new KeyringProperties(this, parent);
+       }
+
+       public Deleter create_deleter() {
+               return new KeyringDeleter(this);
+       }
+
+       public async bool lock(GLib.TlsInteraction? interaction,
+                       GLib.Cancellable? cancellable) throws GLib.Error {
+               var objects = new GLib.List<GLib.DBusProxy>();
+               objects.prepend(this);
+
+               var service = get_service();
+               GLib.List<GLib.DBusProxy> locked;
+               yield service.lock(objects, cancellable, out locked);
+               refresh_collection ();
+               return locked.length() > 0;
+       }
+
+       public async bool unlock(GLib.TlsInteraction? interaction,
+                                GLib.Cancellable? cancellable) throws GLib.Error {
+               var objects = new GLib.List<GLib.DBusProxy>();
+               objects.prepend(this);
+
+               var service = get_service();
+               GLib.List<GLib.DBusProxy> unlocked;
+               yield service.unlock(objects, cancellable, out unlocked);
+               refresh_collection ();
+               return unlocked.length() > 0;
+       }
+
+       public async bool load(GLib.Cancellable? cancellable) throws GLib.Error {
+               refresh_collection();
+               return true;
+       }
+
+       private void refresh_collection() {
+               var seen = new GLib.HashTable<string, weak string>(GLib.str_hash, GLib.str_equal);
+
+               GLib.List<Secret.Item> items = null;
+               if (!get_locked())
+                       items = get_items();
+
+               foreach (var item in items) {
+                       var object_path = item.get_object_path();
+                       seen.add(object_path);
+
+                       if (_items.lookup(object_path) == null) {
+                               item.set("place", this);
+                               _items.insert(object_path, (Item)item);
+                               emit_added(item);
+                       }
+               }
+
+               /* Remove any that we didn't find */
+               var iter = GLib.HashTableIter<string, Item>(_items);
+               string object_path;
+               while (iter.next (out object_path, null)) {
+                       if (seen.lookup(object_path) == null) {
+                               var item = _items.lookup(object_path);
+                               item.set("place", null);
+                               iter.remove();
+                               emit_removed (item);
+                       }
+               }
+       }
+
+       [CCode (instance_pos = -1)]
+       private void on_keyring_default(Gtk.Action action) {
+               var parent = Action.get_window(action);
+               var service = this.service;
+
+               service.set_alias.begin("default", this, null, (obj, res) => {
+                       try {
+                               service.set_alias.end(res);
+                               Backend.instance().refresh();
+                       } catch (GLib.Error err) {
+                               Util.show_error(parent, _("Couldn't set default keyring"), err.message);
+                       }
+               });
+       }
+
+       [CCode (instance_pos = -1)]
+       private void on_keyring_password (Gtk.Action action) {
+               var parent = Action.get_window(action);
+               var service = this.service;
+               service.get_connection().call.begin(service.get_name(),
+                                                   service.get_object_path(),
+                                                   
"org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface",
+                                                   "ChangeWithPrompt",
+                                                   new GLib.Variant("(o)", this.get_object_path()),
+                                                   new GLib.VariantType("(o)"),
+                                                   GLib.DBusCallFlags.NONE, -1, null, (obj, res) => {
+                       try {
+                               var retval = service.get_connection().call.end(res);
+                               string prompt_path;
+                               retval.get("(o)", out prompt_path);
+                               service.prompt_at_dbus_path.begin(prompt_path, null, null, (obj, res) => {
+                                       try {
+                                               service.prompt_at_dbus_path.end(res);
+                                       } catch (GLib.Error err) {
+                                               Util.show_error(parent, _("Couldn't change keyring 
password"), err.message);
+                                       }
+                                       Backend.instance().refresh();
+                               });
+                       } catch (GLib.Error err) {
+                               Util.show_error(parent, _("Couldn't change keyring password"), err.message);
+                       }
+               });
+       }
+
+       private static const Gtk.ActionEntry[] KEYRING_ACTIONS = {
+               { "keyring-default", null, N_("_Set as default"), null,
+                 N_("Applications usually store new passwords in the default keyring."), on_keyring_default 
},
+               { "keyring-password", null, N_("Change _Password"), null,
+                 N_("Change the unlock password of the password storage keyring"), on_keyring_password },
+       };
+
+       private Gtk.ActionGroup create_actions() {
+               Gtk.ActionGroup actions = new Gtk.ActionGroup("KeyringActions");
+
+               /* Add these actions, but none of them are visible until cloned */
+               actions.set_translation_domain(Config.GETTEXT_PACKAGE);
+               actions.add_actions(KEYRING_ACTIONS, this);
+
+               var action = actions.get_action("keyring-default");
+               this.bind_property("is-default", action, "sensitive",
+                                  GLib.BindingFlags.INVERT_BOOLEAN | GLib.BindingFlags.SYNC_CREATE);
+
+               return actions;
+       }
+
+}
+
+class KeyringDeleter : Deleter {
+       private Keyring? _keyring;
+       private GLib.List<GLib.Object> _objects;
+
+       public override Gtk.Dialog create_confirm(Gtk.Window? parent) {
+               var dialog = new DeleteDialog(parent,
+                                             _("Are you sure you want to delete the password keyring '%s'?"),
+                                             this._keyring.label);
+
+               dialog.check_label = _("I understand that all items will be permanently deleted.");
+               dialog.check_require = true;
+
+               return dialog;
+       }
+
+       public KeyringDeleter(Keyring keyring) {
+               if (!add_object(keyring))
+                       GLib.assert_not_reached();
+       }
+
+       public override unowned GLib.List<weak GLib.Object> get_objects() {
+               return this._objects;
+       }
+
+       public override bool add_object (GLib.Object obj) {
+               if (this._keyring != null)
+                       return false;
+               if (obj is Keyring) {
+                       this._keyring = (Keyring)obj;
+                       this._objects.append(obj);
+                       return true;
+               }
+               return false;
+       }
+
+       public override async bool delete(GLib.Cancellable? cancellable) throws GLib.Error {
+               yield this._keyring.delete(cancellable);
+               return true;
+       }
+}
+
+}
+}
diff --git a/gkr/gkr-module.vala b/gkr/gkr-module.vala
index 6f3ed1e..a01346c 100644
--- a/gkr/gkr-module.vala
+++ b/gkr/gkr-module.vala
@@ -22,7 +22,9 @@
  */
 
 namespace Seahorse {
+namespace Gkr {
 
-public const string GKR_NAME = "gkr";
+public const string NAME = "gkr";
 
+}
 }
\ No newline at end of file
diff --git a/gkr/seahorse-add-keyring.xml b/gkr/seahorse-add-keyring.xml
index 42a88f6..743e489 100644
--- a/gkr/seahorse-add-keyring.xml
+++ b/gkr/seahorse-add-keyring.xml
@@ -2,17 +2,7 @@
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkDialog" id="add-keyring">
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Add Password Keyring</property>
-    <property name="modal">True</property>
-    <property name="window_position">center-on-parent</property>
-    <property name="type_hint">dialog</property>
-    <property name="skip_taskbar_hint">True</property>
-    <property name="skip_pager_hint">True</property>
-    <signal name="response" handler="on_add_keyring_properties_response"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
+      <object class="GtkVBox" id="add-keyring">
         <property name="visible">True</property>
         <property name="spacing">2</property>
         <child>
@@ -76,56 +66,5 @@
             <property name="position">1</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_widget_closed"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="ok">
-                <property name="label">gtk-add</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can_focus">True</property>
-                <property name="has_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
       </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-6">cancel</action-widget>
-      <action-widget response="-3">ok</action-widget>
-    </action-widgets>
-  </object>
 </interface>
diff --git a/gkr/seahorse-gkr-add-item.xml b/gkr/seahorse-gkr-add-item.xml
index 55ea6bd..8677f3b 100644
--- a/gkr/seahorse-gkr-add-item.xml
+++ b/gkr/seahorse-gkr-add-item.xml
@@ -2,21 +2,7 @@
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkDialog" id="gkr-add-item">
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Add Password</property>
-    <property name="modal">True</property>
-    <property name="window_position">center-on-parent</property>
-    <property name="type_hint">dialog</property>
-    <property name="skip_taskbar_hint">True</property>
-    <property name="skip_pager_hint">True</property>
-    <signal name="response" handler="on_add_item_response"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
-        <property name="visible">True</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkVBox" id="vbox1">
+          <object class="GtkVBox" id="gkr-add-item">
             <property name="visible">True</property>
             <property name="border_width">5</property>
             <property name="spacing">6</property>
@@ -129,61 +115,4 @@
               </packing>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="cancel">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_widget_closed"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="ok">
-                <property name="label">gtk-add</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can_focus">True</property>
-                <property name="has_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-6">cancel</action-widget>
-      <action-widget response="-3">ok</action-widget>
-    </action-widgets>
-  </object>
 </interface>
diff --git a/gkr/seahorse-gkr-item-properties.xml b/gkr/seahorse-gkr-item-properties.xml
index 3f4733a..e2fadd0 100644
--- a/gkr/seahorse-gkr-item-properties.xml
+++ b/gkr/seahorse-gkr-item-properties.xml
@@ -2,18 +2,7 @@
 <interface>
   <requires lib="gtk+" version="3.0"/>
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkDialog" id="gkr-item-properties">
-    <property name="visible">True</property>
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Key Properties</property>
-    <property name="type_hint">dialog</property>
-    <signal name="delete_event" handler="on_widget_delete_event"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
-        <property name="visible">True</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkNotebook" id="notebook">
+          <object class="GtkNotebook" id="gkr-item-properties">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="border_width">5</property>
@@ -65,8 +54,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="activates_default">True</property>
-                            <signal name="focus_out_event" handler="on_item_description_focus_out"/>
-                            <signal name="activate" handler="on_item_description_activate"/>
                           </object>
                           <packing>
                             <property name="left_attach">1</property>
@@ -213,7 +200,6 @@
                   <object class="GtkExpander" id="password-expander">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <signal name="activate" handler="on_item_password_expander_activate" after="yes"/>
                     <child>
                       <object class="GtkAlignment" id="alignment45">
                         <property name="visible">True</property>
@@ -243,7 +229,6 @@
                                 <property name="receives_default">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="draw_indicator">True</property>
-                                <signal name="toggled" handler="on_item_show_password_toggled"/>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
@@ -355,58 +340,4 @@
               </packing>
             </child>
           </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="helpbutton1">
-                <property name="label">gtk-help</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_widget_help"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="closebutton1">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-                <signal name="clicked" handler="on_widget_closed"/>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-11">helpbutton1</action-widget>
-      <action-widget response="-7">closebutton1</action-widget>
-    </action-widgets>
-  </object>
 </interface>
diff --git a/gkr/seahorse-gkr-keyring.xml b/gkr/seahorse-gkr-keyring.xml
index e9a6c03..83def2b 100644
--- a/gkr/seahorse-gkr-keyring.xml
+++ b/gkr/seahorse-gkr-keyring.xml
@@ -2,15 +2,7 @@
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkDialog" id="gkr-keyring">
-    <property name="visible">True</property>
-    <property name="border_width">5</property>
-    <property name="title" translatable="yes">Keyring Properties</property>
-    <property name="type_hint">dialog</property>
-    <signal name="response" handler="on_keyring_properties_response"/>
-    <signal name="delete_event" handler="on_widget_delete_event"/>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
+      <object class="GtkVBox" id="gkr-keyring">
         <property name="visible">True</property>
         <property name="spacing">2</property>
         <child>
@@ -184,10 +176,4 @@
           </packing>
         </child>
       </object>
-    </child>
-    <action-widgets>
-      <action-widget response="-11">helpbutton1</action-widget>
-      <action-widget response="-7">closebutton1</action-widget>
-    </action-widgets>
-  </object>
 </interface>
diff --git a/src/seahorse-sidebar.c b/src/seahorse-sidebar.c
index 19991d0..d206662 100644
--- a/src/seahorse-sidebar.c
+++ b/src/seahorse-sidebar.c
@@ -27,11 +27,6 @@
 #include "seahorse-interaction.h"
 #include "seahorse-util.h"
 
-#include "gkr/seahorse-gkr.h"
-#include "pgp/seahorse-pgp.h"
-#include "pkcs11/seahorse-pkcs11.h"
-#include "ssh/seahorse-ssh.h"
-
 #include <glib/gi18n.h>
 
 struct _SeahorseSidebar {
@@ -745,13 +740,13 @@ order_from_backend (GObject *backend)
 
        if (name == NULL)
                order = 10;
-       else if (g_str_equal (name, SEAHORSE_GKR_NAME))
+       else if (g_str_equal (name, "gkr"))
                order = 0;
-       else if (g_str_equal (name, SEAHORSE_PGP_NAME))
+       else if (g_str_equal (name, "pgp"))
                order = 1;
-       else if (g_str_equal (name, SEAHORSE_PKCS11_NAME))
+       else if (g_str_equal (name, "pkcs11"))
                order = 2;
-       else if (g_str_equal (name, SEAHORSE_SSH_NAME))
+       else if (g_str_equal (name, "ssh"))
                order = 3;
        else
                order = 10;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]