[seahorse] pgp: Make PgpBackend responsible for handling keyservers



commit bc26f2bf5cb3035f0f94c412f3e675d2071b1ed4
Author: Anukul Sangwan <anukulsangwan icloud com>
Date:   Fri Feb 19 18:59:31 2021 +0000

    pgp: Make PgpBackend responsible for handling keyservers
    
    That way, we don't need to fiddle around with the `GSettings` keys (and
    its special values format) in several places, and we can just expose
    what we need. With a bit of luck, it allows us to also get rid of the
    `SeahorsePgpSettings` singleton which is strewn around in several
    places.

 common/config.vapi                  |  11 +-
 common/meson.build                  |   3 +-
 common/pgp-settings.vala            |  71 ++++++++++---
 common/prefs-keyservers.vala        | 138 ++++++++++++++++++++++++
 common/prefs.vala                   | 205 +-----------------------------------
 common/seahorse-prefs-keyservers.ui | 137 ++++++++++++++++++++++++
 common/seahorse-prefs.ui            | 152 --------------------------
 data/seahorse.gresource.xml         |   1 +
 pgp/seahorse-discovery.c            |  11 +-
 pgp/seahorse-pgp-backend.c          |  74 +++++++------
 pgp/seahorse-pgp-backend.h          |   6 +-
 po/POTFILES.in                      |   2 +
 12 files changed, 394 insertions(+), 417 deletions(-)
---
diff --git a/common/config.vapi b/common/config.vapi
index f408170e..37017d1b 100644
--- a/common/config.vapi
+++ b/common/config.vapi
@@ -47,12 +47,17 @@ namespace Progress {
 }
 
 [CCode (cheader_filename = "pgp/seahorse-pgp-backend.h")]
-namespace Pgp.Backend {
-       public void initialize();
+public class Pgp.Backend : GLib.Object, Gcr.Collection, Place {
+    public static void initialize();
+    public static unowned Pgp.Backend get();
+
+    public unowned GLib.ListModel get_remotes();
+    public void add_remote(string uri, bool persist);
+    public void remove_remote(string uri);
 }
 
 [CCode (cheader_filename = "pgp/seahorse-server-source.h")]
-public class ServerSource {
+public class ServerSource : GLib.Object, Gcr.Collection, Place {
 }
 
 #if WITH_LDAP
diff --git a/common/meson.build b/common/meson.build
index 849af26b..0b520dcd 100644
--- a/common/meson.build
+++ b/common/meson.build
@@ -36,10 +36,11 @@ common_deps = [
 ]
 
 common_vala_args = [
+  '--gresources', resources_xml,
 ]
 
 if get_option('keyservers-support')
-  common_sources += 'keyserver-control.vala'
+  common_sources += ['keyserver-control.vala', 'prefs-keyservers.vala']
   common_vala_args += [ '-D', 'WITH_KEYSERVER' ]
 endif
 
diff --git a/common/pgp-settings.vala b/common/pgp-settings.vala
index ef07a6e7..0ae94e46 100644
--- a/common/pgp-settings.vala
+++ b/common/pgp-settings.vala
@@ -60,32 +60,71 @@ public class Seahorse.PgpSettings : GLib.Settings {
         ServerCategory.init();
     }
 
-       private static PgpSettings? _instance = null;
-       public static PgpSettings instance() {
-               if (_instance == null)
-                       _instance = new PgpSettings();
-               return _instance;
-       }
+    private static PgpSettings? _instance = null;
+    public static PgpSettings instance() {
+        if (_instance == null)
+            _instance = new PgpSettings();
+        return _instance;
+    }
 
     [CCode (array_null_terminated = true, array_length = false)]
     public string[] get_uris() {
-        // The values are 'uri name', remove the name part
         string[] uris = {};
-        foreach (string server in this.keyservers)
-            uris += server.strip().split(" ", 2)[0];
-
+        foreach (unowned string server in this.keyservers)
+            uris += get_uri_for_keyserver_entry (server);
         return uris;
     }
 
     [CCode (array_null_terminated = true, array_length = false)]
     public string[] get_names() {
         string[] names = {};
-        foreach (string server in this.keyservers) {
-            // The values are 'uri' or 'uri name', remove the name part if there
-            string[] split = server._strip().split(" ", 2);
-            names += (split.length == 1)? split[0] : split[1];
-        }
-
+        foreach (unowned string server in this.keyservers)
+            names += get_name_for_keyserver_entry (server);
         return names;
     }
+
+    public void add_keyserver(string uri, string? name) {
+        string[] servers = {};
+
+        if (uri in this.keyservers)
+            return;
+
+        debug("Adding key server URL '%s'", uri);
+        foreach (unowned string keyserver in this.keyservers)
+            servers += keyserver;
+
+        if (name != null)
+            servers += "%s %s".printf(uri, name);
+        else
+            servers += uri;
+        servers += null;
+
+        this.keyservers = servers;
+    }
+
+    public void remove_keyserver(string uri) {
+        string[] servers = {};
+
+        if (!(uri in this.keyservers))
+            return;
+
+        debug("Removing key server URL '%s'", uri);
+        foreach (unowned string keyserver in this.keyservers)
+            if (get_uri_for_keyserver_entry(keyserver) != uri)
+                servers += keyserver;
+        servers += null;
+
+        this.keyservers = servers;
+    }
+
+    private string? get_uri_for_keyserver_entry(string keyserver) {
+        // The values are "uri" or "uri name", so remove the name part (if any)
+        return keyserver.strip().split(" ", 2)[0];
+    }
+
+    private string? get_name_for_keyserver_entry(string keyserver) {
+        // The values are "uri" or "uri name", so fallback to uri if no name
+        string[] split = keyserver.strip().split(" ", 2);
+        return (split.length == 1)? split[0] : split[1];
+    }
 }
diff --git a/common/prefs-keyservers.vala b/common/prefs-keyservers.vala
new file mode 100644
index 00000000..89d101b8
--- /dev/null
+++ b/common/prefs-keyservers.vala
@@ -0,0 +1,138 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2004-2005 Stefan Walter
+ * Copyright (C) 2017 Niels De Graef
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+[GtkTemplate (ui = "/org/gnome/Seahorse/seahorse-prefs-keyservers.ui")]
+public class Seahorse.PrefsKeyservers : Gtk.Box {
+
+    [GtkChild]
+    public unowned Gtk.Grid keyserver_tab;
+    [GtkChild]
+    private unowned Gtk.ListBox keyservers_list;
+    [GtkChild]
+    private unowned Gtk.Box keyserver_publish;
+    [GtkChild]
+    private unowned Gtk.Label keyserver_publish_to_label;
+    [GtkChild]
+    private unowned Gtk.CheckButton auto_retrieve;
+    [GtkChild]
+    private unowned Gtk.CheckButton auto_sync;
+
+    public PrefsKeyservers(Gtk.Window? parent) {
+        var model = Pgp.Backend.get().get_remotes();
+        this.keyservers_list.bind_model(model, (item) => {
+            return new KeyServerRow(item as ServerSource);
+        });
+
+        KeyserverControl skc = new KeyserverControl("server-publish-to",
+                                                    _("None: Don’t publish keys"));
+        this.keyserver_publish.add(skc);
+        this.keyserver_publish.show_all();
+
+        this.keyserver_publish_to_label.set_mnemonic_widget(skc);
+
+        AppSettings.instance().bind("server-auto-retrieve", this.auto_retrieve, "active",
+                                    SettingsBindFlags.DEFAULT);
+        AppSettings.instance().bind("server-auto-publish", this.auto_sync, "active",
+                                    SettingsBindFlags.DEFAULT);
+    }
+
+    private class KeyServerRow : Gtk.ListBoxRow {
+
+        private unowned ServerSource server;
+        private Gtk.Label label;
+        private Gtk.Entry entry;
+
+        public KeyServerRow(ServerSource server) {
+            this.server = server;
+
+            var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 2);
+            box.margin = 6;
+            add(box);
+
+            this.label = new Gtk.Label(server.uri);
+            box.pack_start(this.label, false);
+
+            this.entry = new Gtk.Entry();
+            this.entry.set_no_show_all(true);
+            this.entry.hide();
+            this.entry.activate.connect(on_entry_activated);
+            box.pack_start(this.entry);
+
+            var remove_button = new Gtk.Button.from_icon_name("list-remove-symbolic");
+            remove_button.get_style_context().add_class("flat");
+            remove_button.clicked.connect(on_remove_button_clicked);
+            box.pack_end(remove_button, false);
+
+            var edit_button = new Gtk.Button.from_icon_name("document-edit-symbolic");
+            edit_button.get_style_context().add_class("flat");
+            edit_button.clicked.connect(on_edit_button_clicked);
+            box.pack_end(edit_button, false);
+
+            show_all();
+        }
+
+        private void on_edit_button_clicked(Gtk.Button edit_button) {
+            this.label.hide();
+            this.entry.set_text(this.label.get_text());
+            this.entry.show_now();
+            this.entry.grab_focus();
+        }
+
+        private void on_remove_button_clicked(Gtk.Button remove_button) {
+            Pgp.Backend.get().remove_remote(this.server.uri);
+        }
+
+        private void on_entry_activated(Gtk.Entry entry) {
+            var uri = this.entry.get_text();
+
+            // If nothing changed, just go away
+            if (uri == server.uri) {
+                this.entry.hide();
+                return;
+            }
+
+            // Before doing anything, make sure we have a valid thing going on
+            if (!ServerCategory.is_valid_uri(uri)) {
+                this.entry.get_style_context().add_class("error");
+                return;
+            }
+
+            // We don't really have a way of ediing a remote, so simulate an edit
+            // by adding and removing one
+            Pgp.Backend.get().remove_remote(this.server.uri);
+            Pgp.Backend.get().add_remote(uri, true);
+            this.entry.hide();
+        }
+    }
+
+    [GtkCallback]
+    private void on_add_button_clicked(Gtk.Button button) {
+        AddKeyserverDialog dialog = new AddKeyserverDialog(get_toplevel() as Gtk.Window);
+
+        if (dialog.run() == Gtk.ResponseType.OK) {
+            string? result = dialog.calculate_keyserver_uri();
+
+            if (result != null)
+                Pgp.Backend.get().add_remote(result, true);
+        }
+
+        dialog.destroy();
+    }
+}
diff --git a/common/prefs.vala b/common/prefs.vala
index bab3a714..e1b681ab 100644
--- a/common/prefs.vala
+++ b/common/prefs.vala
@@ -20,17 +20,7 @@
 
 public class Seahorse.Prefs : Gtk.Dialog {
 
-    private bool updating_model;
-
     private Gtk.Notebook notebook;
-    private Gtk.Grid keyserver_tab;
-    private Gtk.TreeView keyservers;
-    private Gtk.Box keyserver_publish;
-    private Gtk.Label keyserver_publish_to_label;
-    private Gtk.Button keyserver_remove;
-    private Gtk.Button keyserver_add;
-    private Gtk.CheckButton auto_retrieve;
-    private Gtk.CheckButton auto_sync;
 
     /**
      * Create a new preferences window.
@@ -43,9 +33,8 @@ public class Seahorse.Prefs : Gtk.Dialog {
             transient_for: parent,
             modal: true
         );
-        this.updating_model = false;
 
-        Gtk.Builder builder = new Gtk.Builder();
+        var builder = new Gtk.Builder();
         try {
             string path = "/org/gnome/Seahorse/seahorse-prefs.ui";
             builder.add_from_resource(path);
@@ -56,22 +45,11 @@ public class Seahorse.Prefs : Gtk.Dialog {
         get_content_area().border_width = 0;
         get_content_area().add(content);
         this.notebook = (Gtk.Notebook) builder.get_object("notebook");
-        this.keyserver_tab = (Gtk.Grid) builder.get_object("keyserver-tab");
-        this.keyservers = (Gtk.TreeView) builder.get_object("keyservers");
-        this.keyserver_publish = (Gtk.Box) builder.get_object("keyserver-publish");
-        this.keyserver_publish_to_label = (Gtk.Label) builder.get_object("keyserver-publish-to-label");
-        this.keyserver_remove = (Gtk.Button) builder.get_object("keyserver_remove");
-        this.keyserver_add = (Gtk.Button) builder.get_object("keyserver_add");
-        this.auto_retrieve = (Gtk.CheckButton) builder.get_object("auto_retrieve");
-        this.auto_sync = (Gtk.CheckButton) builder.get_object("auto_sync");
-
-        this.keyserver_remove.clicked.connect(on_prefs_keyserver_remove_clicked);
-        this.keyserver_add.clicked.connect(on_prefs_keyserver_add_clicked);
 
 #if WITH_KEYSERVER
-        setup_keyservers();
-#else
-        remove_tab(this.keyserver_tab);
+        var keyservers = new PrefsKeyservers(this);
+        var label = new Gtk.Label("Keyservers");
+        add_tab(label, keyservers);
 #endif
 
         if (tabid != null) {
@@ -121,179 +99,4 @@ public class Seahorse.Prefs : Gtk.Dialog {
         if (pos != -1)
             this.notebook.remove_page(pos);
     }
-
-#if WITH_KEYSERVER
-
-    private enum Columns {
-        KEYSERVER,
-        N_COLUMNS
-    }
-
-    // Perform keyserver page initialization
-    private void setup_keyservers () {
-        string[] keyservers = PgpSettings.instance().get_uris();
-        populate_keyservers(keyservers);
-
-        Gtk.TreeModel model = this.keyservers.get_model();
-        model.row_changed.connect(keyserver_row_changed);
-        model.row_deleted.connect(keyserver_row_deleted);
-
-        Gtk.TreeSelection selection = this.keyservers.get_selection();
-        selection.set_mode(Gtk.SelectionMode.SINGLE);
-        selection.changed.connect(keyserver_sel_changed);
-
-        PgpSettings.instance().changed["keyserver"].connect((settings, key) => {
-            populate_keyservers(settings.get_strv(key));
-        });
-
-        KeyserverControl skc = new KeyserverControl("server-publish-to",
-                                                    _("None: Don’t publish keys"));
-        this.keyserver_publish.add(skc);
-        this.keyserver_publish.show_all();
-
-        this.keyserver_publish_to_label.set_mnemonic_widget(skc);
-
-        AppSettings.instance().bind("server-auto-retrieve", this.auto_retrieve, "active",
-                                    SettingsBindFlags.DEFAULT);
-        AppSettings.instance().bind("server-auto-publish", this.auto_sync, "active",
-                                    SettingsBindFlags.DEFAULT);
-    }
-
-    // Called when a cell has completed being edited
-    private void keyserver_cell_edited (Gtk.CellRendererText cell, string? path, string? text, Gtk.TreeStore 
store) {
-        if (!ServerCategory.is_valid_uri(text)) {
-            Util.show_error (null,
-                             _("Not a valid Key Server address."),
-                             _("For help contact your system administrator or the administrator of the key 
server." ));
-            return;
-        }
-
-        Gtk.TreeIter iter;
-        warn_if_fail(store.get_iter_from_string(out iter, path));
-        store.set(iter, Columns.KEYSERVER, text, -1);
-    }
-
-    // The selection changed on the tree
-    private void keyserver_sel_changed (Gtk.TreeSelection selection) {
-        this.keyserver_remove.sensitive = (selection.count_selected_rows() > 0);
-    }
-
-    // User wants to remove selected rows
-    private void on_prefs_keyserver_remove_clicked (Gtk.Widget? button) {
-        this.keyservers.get_selection().selected_foreach((model, path, iter) => {
-            ((Gtk.TreeStore) model).remove(ref iter);
-        });
-    }
-
-    // Write key server list to settings
-    private void save_keyservers (Gtk.TreeModel model) {
-        string[] values = {};
-        Gtk.TreeIter iter;
-        if (model.get_iter_first(out iter)) {
-            do {
-                string? keyserver = null;
-                model.get(iter, Columns.KEYSERVER, out keyserver, -1);
-                if (keyserver == null)
-                    return;
-                values += keyserver;
-            } while (model.iter_next(ref iter));
-        }
-
-        PgpSettings.instance().keyservers = values;
-    }
-
-    private void keyserver_row_changed (Gtk.TreeModel model, Gtk.TreePath arg1, Gtk.TreeIter arg2) {
-        // If currently updating (see populate_keyservers) ignore
-        if (this.updating_model)
-            return;
-
-        save_keyservers(model);
-    }
-
-    private void keyserver_row_deleted (Gtk.TreeModel model, Gtk.TreePath arg1) {
-        // If currently updating (see populate_keyservers) ignore
-        if (this.updating_model)
-            return;
-
-        save_keyservers(model);
-    }
-
-    private void populate_keyservers(string[] keyservers) {
-        Gtk.TreeStore store = (Gtk.TreeStore) this.keyservers.get_model();
-
-        // This is our first time so create a store
-        if (store == null) {
-            store = new Gtk.TreeStore(1, typeof(string));
-            this.keyservers.set_model(store);
-
-            // Make the column
-            Gtk.CellRendererText renderer = new Gtk.CellRendererText();
-            renderer.editable = true;
-            renderer.edited.connect((cell, path, text) => {
-                keyserver_cell_edited(cell, path, text, store);
-            });
-            Gtk.TreeViewColumn column = new Gtk.TreeViewColumn.with_attributes(
-                                                _("URL"), renderer,
-                                                "text", Columns.KEYSERVER,
-                                                null);
-            this.keyservers.append_column(column);
-        }
-
-        // Mark this so we can ignore events
-        this.updating_model = true;
-
-        // We try and be inteligent about updating so we don't throw
-        // away selections and stuff like that
-        uint i = 0;
-        Gtk.TreeIter iter;
-        if (store.get_iter_first(out iter)) {
-            bool cont = false;
-            do {
-                string? val;
-                store.get(iter, Columns.KEYSERVER, out val, -1);
-                if (keyservers[i] != null
-                        && val != null
-                        && keyservers[i].collate(val) == 0) {
-                    cont = store.iter_next(ref iter);
-                    i++;
-                } else {
-                    cont = store.remove(ref iter);
-                }
-            } while (cont);
-        }
-
-        // Any remaining extra rows
-        for ( ; keyservers[i] != null; i++) {
-            store.append(out iter, null);
-            store.set(iter, Columns.KEYSERVER, keyservers[i], -1);
-        }
-
-        // Done updating
-        this.updating_model = false;
-    }
-
-    private void on_prefs_keyserver_add_clicked (Gtk.Button button) {
-        AddKeyserverDialog dialog = new AddKeyserverDialog(this);
-
-        if (dialog.run() == Gtk.ResponseType.OK) {
-            string? result = dialog.calculate_keyserver_uri();
-
-            if (result != null) {
-                Gtk.TreeStore store = (Gtk.TreeStore) this.keyservers.get_model();
-                Gtk.TreeIter iter;
-                store.append(out iter, null);
-                store.set(iter, Columns.KEYSERVER, result, -1);
-            }
-        }
-
-        dialog.destroy();
-    }
-
-#else
-
-    private void on_prefs_keyserver_add_clicked (Gtk.Button? button) { }
-    void on_prefs_keyserver_remove_clicked (Gtk.Widget? button) { }
-
-#endif
-
 }
diff --git a/common/seahorse-prefs-keyservers.ui b/common/seahorse-prefs-keyservers.ui
new file mode 100644
index 00000000..40860fd9
--- /dev/null
+++ b/common/seahorse-prefs-keyservers.ui
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="3.24"/>
+  <template class="SeahorsePrefsKeyservers" parent="GtkBox">
+    <property name="visible">True</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="border_width">12</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="orientation">horizontal</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="hexpand">true</property>
+                <property name="label" translatable="yes">Keyservers</property>
+                <property name="use_underline">True</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="keyserver_add_button">
+                <property name="visible">True</property>
+                <property name="halign">end</property>
+                <property name="tooltip-text" translatable="yes">Add a new keyserver</property>
+                <signal name="clicked" handler="on_add_button_clicked"/>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="icon-name">list-add-symbolic</property>
+                  </object>
+                </child>
+                <style>
+                  <class name="image-button"/>
+                  <class name="flat"/>
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkGrid" id="keyserver_tab">
+            <property name="visible">True</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">12</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="min-content-height">200</property>
+                <child>
+                  <object class="GtkListBox" id="keyservers_list">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hexpand">True</property>
+                    <style>
+                      <class name="content"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="top_attach">0</property>
+                <property name="left_attach">0</property>
+                <property name="width">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="keyserver_publish_to_label">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">_Publish keys to:</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="left_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="keyserver_publish">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="left_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="auto_retrieve">
+                <property name="label" translatable="yes">Automatically retrieve keys from _key 
servers</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="left_attach">0</property>
+                <property name="width">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="auto_sync">
+                <property name="label" translatable="yes">Automatically synchronize _modified keys with key 
servers</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="left_attach">0</property>
+                <property name="width">2</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/common/seahorse-prefs.ui b/common/seahorse-prefs.ui
index 8076ef03..0ef73dfd 100644
--- a/common/seahorse-prefs.ui
+++ b/common/seahorse-prefs.ui
@@ -16,158 +16,6 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="vexpand">True</property>
-            <child>
-              <object class="GtkGrid" id="keyserver-tab">
-                <property name="visible">True</property>
-                <property name="border_width">12</property>
-                <property name="column_spacing">12</property>
-                <property name="row_spacing">12</property>
-                <child>
-                  <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">11</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">_Find keys via:</property>
-                        <property name="use_underline">True</property>
-                        <property name="mnemonic_widget">scrolledwindow1</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkButton" id="keyserver_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">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>
-                    <child>
-                      <object class="GtkButton" id="keyserver_remove">
-                        <property name="label">gtk-remove</property>
-                        <property name="visible">True</property>
-                        <property name="sensitive">False</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_stock">True</property>
-                        <signal name="clicked" handler="on_prefs_keyserver_remove_clicked"/>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">2</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="hscrollbar_policy">never</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="keyservers">
-                        <property name="height_request">130</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="top_attach">0</property>
-                    <property name="left_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="keyserver-publish-to-label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">_Publish keys to:</property>
-                    <property name="use_underline">True</property>
-                  </object>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="left_attach">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkBox" id="keyserver-publish">
-                    <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="left_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkCheckButton" id="auto_retrieve">
-                    <property name="label" translatable="yes">Automatically retrieve keys from _key 
servers</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </object>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="left_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkCheckButton" id="auto_sync">
-                    <property name="label" translatable="yes">Automatically synchronize _modified keys with 
key servers</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="draw_indicator">True</property>
-                  </object>
-                  <packing>
-                    <property name="top_attach">3</property>
-                    <property name="left_attach">1</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">Key Servers</property>
-              </object>
-              <packing>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
-            <child>
-              <placeholder/>
-            </child>
-            <child type="tab">
-              <placeholder/>
-            </child>
           </object>
           <packing>
             <property name="position">1</property>
diff --git a/data/seahorse.gresource.xml b/data/seahorse.gresource.xml
index 7c9ac10d..6156a971 100644
--- a/data/seahorse.gresource.xml
+++ b/data/seahorse.gresource.xml
@@ -8,6 +8,7 @@
     <!-- Common -->
     <file alias="seahorse-add-keyserver.ui" 
preprocess="xml-stripblanks">../common/seahorse-add-keyserver.ui</file>
     <file alias="seahorse-prefs.ui" preprocess="xml-stripblanks">../common/seahorse-prefs.ui</file>
+    <file alias="seahorse-prefs-keyservers.ui" 
preprocess="xml-stripblanks">../common/seahorse-prefs-keyservers.ui</file>
 
     <!-- Seahorse -->
     <file alias="seahorse-change-passphrase.ui" 
preprocess="xml-stripblanks">../src/seahorse-change-passphrase.ui</file>
diff --git a/pgp/seahorse-discovery.c b/pgp/seahorse-discovery.c
index 2020442b..9622328b 100644
--- a/pgp/seahorse-discovery.c
+++ b/pgp/seahorse-discovery.c
@@ -156,13 +156,10 @@ resolve_callback (AvahiServiceResolver *resolver, AvahiIfIndex iface, AvahiProto
                g_hash_table_replace (self->services, service_name, service_uri);
                g_signal_emit (self, signals[ADDED], 0, service_name);
 
-               /* Add it to the context */
-               if (!seahorse_pgp_backend_lookup_remote (NULL, service_uri)) {
-                       SeahorseServerSource *ssrc = seahorse_server_category_create_server (service_uri);
-                       g_return_if_fail (ssrc != NULL);
-                       seahorse_pgp_backend_add_remote (NULL, service_uri, ssrc);
-                       g_object_unref (ssrc);
-               }
+        /* Add it to the context */
+        if (!seahorse_pgp_backend_lookup_remote (NULL, service_uri)) {
+            seahorse_pgp_backend_add_remote (NULL, service_uri, FALSE);
+        }
 
                g_debug ("added: %s %s\n", service_name, service_uri);
                break;
diff --git a/pgp/seahorse-pgp-backend.c b/pgp/seahorse-pgp-backend.c
index d19685c9..c08b26dc 100644
--- a/pgp/seahorse-pgp-backend.c
+++ b/pgp/seahorse-pgp-backend.c
@@ -51,6 +51,7 @@ struct _SeahorsePgpBackend {
     GObject parent;
 
     SeahorseGpgmeKeyring *keyring;
+    SeahorsePgpSettings *pgp_settings;
     SeahorseDiscovery *discovery;
     SeahorseUnknownSource *unknown;
     GListModel *remotes;
@@ -73,6 +74,7 @@ seahorse_pgp_backend_init (SeahorsePgpBackend *self)
     g_return_if_fail (pgp_backend == NULL);
     pgp_backend = self;
 
+    self->pgp_settings = seahorse_pgp_settings_instance ();
     self->remotes = G_LIST_MODEL (g_list_store_new (SEAHORSE_TYPE_SERVER_SOURCE));
     self->actions = seahorse_pgp_backend_actions_instance ();
 }
@@ -96,7 +98,7 @@ on_settings_keyservers_changed (GSettings  *settings,
 
         remote = g_list_model_get_item (self->remotes, i);
         uri = seahorse_place_get_uri (SEAHORSE_PLACE (remote));
-        g_ptr_array_add (check, uri);
+        g_ptr_array_add (check, g_steal_pointer (&uri));
     }
 
     /* Load and strip names from keyserver list */
@@ -107,17 +109,13 @@ on_settings_keyservers_changed (GSettings  *settings,
         gboolean found;
         guint index;
 
-        /* If we don't have a keysource then add it */
         found = g_ptr_array_find_with_equal_func (check, uri, g_str_equal, &index);
         if (found) {
             /* Mark this one as present */
             g_ptr_array_remove_index (check, index);
         } else {
-            g_autoptr(SeahorseServerSource) source = NULL;
-
-            source = seahorse_server_category_create_server (uri);
-            if (source != NULL)
-                seahorse_pgp_backend_add_remote (self, uri, source);
+            /* If we don't have a keysource then add it */
+            seahorse_pgp_backend_add_remote (self, uri, FALSE);
         }
     }
 
@@ -168,11 +166,11 @@ seahorse_pgp_backend_constructed (GObject *obj)
        self->unknown = seahorse_unknown_source_new ();
 
 #ifdef WITH_KEYSERVER
-    g_signal_connect (seahorse_pgp_settings_instance (), "changed::keyservers",
+    g_signal_connect (self->pgp_settings, "changed::keyservers",
                       G_CALLBACK (on_settings_keyservers_changed), self);
 
     /* Initial loading */
-    on_settings_keyservers_changed (G_SETTINGS (seahorse_pgp_settings_instance ()),
+    on_settings_keyservers_changed (G_SETTINGS (self->pgp_settings),
                                     "keyservers",
                                     self);
 #endif
@@ -247,7 +245,7 @@ seahorse_pgp_backend_finalize (GObject *obj)
     SeahorsePgpBackend *self = SEAHORSE_PGP_BACKEND (obj);
 
 #ifdef WITH_KEYSERVER
-    g_signal_handlers_disconnect_by_func (seahorse_pgp_settings_instance (),
+    g_signal_handlers_disconnect_by_func (self->pgp_settings,
                                           on_settings_keyservers_changed, self);
 #endif
 
@@ -362,28 +360,25 @@ seahorse_pgp_backend_get_default_keyring (SeahorsePgpBackend *self)
 SeahorsePgpKey *
 seahorse_pgp_backend_get_default_key (SeahorsePgpBackend *self)
 {
-       SeahorsePgpKey *key = NULL;
-       SeahorsePgpSettings *settings;
-       const gchar *keyid;
-       gchar *value;
+    SeahorsePgpKey *key = NULL;
+    g_autofree char *value = NULL;
 
-       self = self ? self : seahorse_pgp_backend_get ();
-       g_return_val_if_fail (SEAHORSE_PGP_IS_BACKEND (self), NULL);
+    self = self ? self : seahorse_pgp_backend_get ();
+    g_return_val_if_fail (SEAHORSE_PGP_IS_BACKEND (self), NULL);
 
-       settings = seahorse_pgp_settings_instance ();
-       if (settings != NULL) {
-               value = seahorse_pgp_settings_get_default_key (settings);
-               if (value != NULL && value[0]) {
-                       if (g_str_has_prefix (value, "openpgp:"))
-                               keyid = value + strlen ("openpgp:");
-                       else
-                               keyid = value;
-                       key = SEAHORSE_PGP_KEY (seahorse_gpgme_keyring_lookup (self->keyring, keyid));
-               }
-               g_free (value);
-       }
+    value = seahorse_pgp_settings_get_default_key (self->pgp_settings);
+    if (value && *value) {
+        const char *keyid;
+
+        if (g_str_has_prefix (value, "openpgp:"))
+            keyid = value + strlen ("openpgp:");
+        else
+            keyid = value;
 
-       return key;
+        key = SEAHORSE_PGP_KEY (seahorse_gpgme_keyring_lookup (self->keyring, keyid));
+    }
+
+    return key;
 }
 
 #ifdef WITH_KEYSERVER
@@ -437,14 +432,21 @@ seahorse_pgp_backend_lookup_remote (SeahorsePgpBackend *self,
 void
 seahorse_pgp_backend_add_remote (SeahorsePgpBackend   *self,
                                  const char           *uri,
-                                 SeahorseServerSource *source)
+                                 gboolean              persist)
 {
-    self = self ? self : seahorse_pgp_backend_get ();
     g_return_if_fail (SEAHORSE_PGP_IS_BACKEND (self));
-    g_return_if_fail (SEAHORSE_IS_SERVER_SOURCE (source));
     g_return_if_fail (seahorse_pgp_backend_lookup_remote (self, uri) == NULL);
 
-    g_list_store_append (G_LIST_STORE (self->remotes), source);
+    if (persist) {
+        /* Add to the PGP settings. That's all we need to do, since we're
+         * subscribed to the "changed" callback */
+        seahorse_pgp_settings_add_keyserver (self->pgp_settings, uri, NULL);
+    } else {
+        /* Don't persist, so just immediately create a ServerSource */
+        g_autoptr(SeahorseServerSource) ssrc = NULL;
+        ssrc = seahorse_server_category_create_server (uri);
+        g_list_store_append (G_LIST_STORE (self->remotes), ssrc);
+    }
 }
 
 void
@@ -455,6 +457,8 @@ seahorse_pgp_backend_remove_remote (SeahorsePgpBackend *self,
     g_return_if_fail (SEAHORSE_PGP_IS_BACKEND (self));
     g_return_if_fail (uri && *uri);
 
+    g_debug ("Removing remote %s", uri);
+
     for (guint i = 0; i < g_list_model_get_n_items (self->remotes); i++) {
         g_autoptr(SeahorseServerSource) ssrc = NULL;
         g_autofree char *src_uri = NULL;
@@ -465,6 +469,8 @@ seahorse_pgp_backend_remove_remote (SeahorsePgpBackend *self,
         if (g_ascii_strcasecmp (uri, src_uri) == 0)
             g_list_store_remove (G_LIST_STORE (self->remotes), i);
     }
+
+    seahorse_pgp_settings_remove_keyserver (self->pgp_settings, uri);
 }
 
 typedef struct {
@@ -520,7 +526,7 @@ seahorse_pgp_backend_search_remote_async (SeahorsePgpBackend *self,
     g_return_if_fail (SEAHORSE_PGP_IS_BACKEND (self));
 
     /* Get a list of all selected key servers */
-    names = g_settings_get_strv (G_SETTINGS (seahorse_app_settings_instance ()), "last-search-servers");
+    names = g_settings_get_strv (G_SETTINGS (self->pgp_settings), "last-search-servers");
     if (names != NULL && names[0] != NULL) {
         servers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
         for (guint i = 0; names[i] != NULL; i++)
diff --git a/pgp/seahorse-pgp-backend.h b/pgp/seahorse-pgp-backend.h
index 9008de46..5a877e5b 100644
--- a/pgp/seahorse-pgp-backend.h
+++ b/pgp/seahorse-pgp-backend.h
@@ -59,11 +59,11 @@ SeahorseServerSource * seahorse_pgp_backend_lookup_remote        (SeahorsePgpBac
                                                                   const gchar *uri);
 
 void                   seahorse_pgp_backend_add_remote           (SeahorsePgpBackend *self,
-                                                                  const gchar *uri,
-                                                                  SeahorseServerSource *source);
+                                                                  const char         *uri,
+                                                                  gboolean            persist);
 
 void                   seahorse_pgp_backend_remove_remote        (SeahorsePgpBackend *self,
-                                                                  const gchar *uri);
+                                                                  const char         *uri);
 
 void                   seahorse_pgp_backend_search_remote_async  (SeahorsePgpBackend *self,
                                                                   const gchar *search,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6f448c92..682d6e7a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,8 +9,10 @@ common/interaction.vala
 common/passphrase-prompt.vala
 common/place.vala
 common/prefs.vala
+common/prefs-keyservers.vala
 common/seahorse-add-keyserver.ui
 common/seahorse-prefs.ui
+common/seahorse-prefs-keyservers.ui
 common/util.vala
 common/validity.vala
 data/gtk/help-overlay.ui


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