aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-proxy-editor.c
blob: 5f7933709439ab5641426b855493687000971076 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                   


                                                                           
  



                                                                             
  

                                                                           






































                                                                         

                                




















































































                                                                       






                                                        









                                                      



















                                                                      




























































































                                                                       












                                                                        












































                                                                              








                                                                           



















                                                                            




















































































































































































































                                                                              





                                                                        












                                                                       
                                                       





























                                                             


                                                                






















































































































































































                                                                               
/*
 * e-proxy-editor.c
 *
 * 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.
 *
 * 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 Lesser General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * SECTION: e-proxy-editor
 * @include: e-util/e-util.h
 * @short_description: Edit proxy profile details
 *
 * #EProxyEditor is an editing widget for proxy profiles, as described by
 * #ESource instances with an #ESourceProxy extension.
 *
 * The editor defaults to showing the built-in proxy profile returned by
 * e_source_registry_ref_builtin_proxy(), but that can be overridden with
 * e_proxy_editor_set_source().
 **/

#include "e-proxy-editor.h"

#include <config.h>
#include <glib/gi18n-lib.h>

#define E_PROXY_EDITOR_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE \
    ((obj), E_TYPE_PROXY_EDITOR, EProxyEditorPrivate))

struct _EProxyEditorPrivate {
    ESourceRegistry *registry;
    ESource *source;

    /* The widgets are not referenced. */
    GtkWidget *method_combo_box;
    GtkWidget *http_host_entry;
    GtkWidget *http_port_spin_button;
    GtkWidget *https_host_entry;
    GtkWidget *https_port_spin_button;
    GtkWidget *socks_host_entry;
    GtkWidget *socks_port_spin_button;
    GtkWidget *ignore_hosts_entry;
    GtkWidget *autoconfig_url_entry;

    gchar *gcc_program_path;
};

enum {
    PROP_0,
    PROP_REGISTRY,
    PROP_SOURCE
};

G_DEFINE_TYPE (
    EProxyEditor,
    e_proxy_editor,
    GTK_TYPE_GRID)

static void
proxy_editor_load (EProxyEditor *editor)
{
    ESource *source;
    ESourceProxy *extension;
    GEnumClass *enum_class;
    GEnumValue *enum_value;
    EProxyMethod method;
    const gchar *extension_name;
    gchar *autoconfig_url;
    gchar *joined_hosts;
    gchar **ignore_hosts;
    gchar *host;
    guint16 port;

    source = e_proxy_editor_ref_source (editor);
    g_return_if_fail (source != NULL);

    extension_name = E_SOURCE_EXTENSION_PROXY;
    extension = e_source_get_extension (source, extension_name);

    enum_class = g_type_class_ref (E_TYPE_PROXY_METHOD);
    method = e_source_proxy_get_method (extension);
    enum_value = g_enum_get_value (enum_class, method);
    if (enum_value != NULL)
        gtk_combo_box_set_active_id (
            GTK_COMBO_BOX (editor->priv->method_combo_box),
            enum_value->value_nick);
    g_type_class_unref (enum_class);

    autoconfig_url = e_source_proxy_dup_autoconfig_url (extension);
    gtk_entry_set_text (
        GTK_ENTRY (editor->priv->autoconfig_url_entry),
        (autoconfig_url != NULL) ? autoconfig_url : "");
    g_free (autoconfig_url);

    ignore_hosts = e_source_proxy_dup_ignore_hosts (extension);
    if (ignore_hosts != NULL)
        joined_hosts = g_strjoinv (", ", ignore_hosts);
    else
        joined_hosts = NULL;
    gtk_entry_set_text (
        GTK_ENTRY (editor->priv->ignore_hosts_entry),
        (joined_hosts != NULL) ? joined_hosts : "");
    g_strfreev (ignore_hosts);
    g_free (joined_hosts);

    host = e_source_proxy_dup_http_host (extension);
    gtk_entry_set_text (
        GTK_ENTRY (editor->priv->http_host_entry),
        (host != NULL) ? host : "");
    g_free (host);

    port = e_source_proxy_get_http_port (extension);
    gtk_spin_button_set_value (
        GTK_SPIN_BUTTON (editor->priv->http_port_spin_button),
        (gdouble) port);

    host = e_source_proxy_dup_https_host (extension);
    gtk_entry_set_text (
        GTK_ENTRY (editor->priv->https_host_entry),
        (host != NULL) ? host : "");
    g_free (host);

    port = e_source_proxy_get_https_port (extension);
    gtk_spin_button_set_value (
        GTK_SPIN_BUTTON (editor->priv->https_port_spin_button),
        (gdouble) port);

    g_object_unref (source);
}

static void
proxy_editor_combo_box_changed_cb (GtkComboBox *widget,
                                   EProxyEditor *editor)
{
    e_proxy_editor_save (editor);
}

static gboolean
proxy_editor_focus_out_event_cb (GtkWidget *widget,
                                 GdkEvent *event,
                                 EProxyEditor *editor)
{
    e_proxy_editor_save (editor);

    return FALSE;  /* propagate the event */
}

static void
proxy_editor_open_desktop_settings_cb (GtkButton *button,
                                       EProxyEditor *editor)
{
    gchar *command_line;
    GError *local_error = NULL;

    g_return_if_fail (editor->priv->gcc_program_path != NULL);

    command_line = g_strdup_printf (
        "%s network", editor->priv->gcc_program_path);
    g_spawn_command_line_async (command_line, &local_error);
    g_free (command_line);

    if (local_error != NULL) {
        g_warning ("%s: %s", G_STRFUNC, local_error->message);
        g_error_free (local_error);
    }
}

static gboolean
proxy_editor_active_id_to_visible (GBinding *binding,
                                   const GValue *source_value,
                                   GValue *target_value,
                                   gpointer user_data)
{
    const gchar *value_nick = user_data;
    const gchar *active_id;
    gboolean visible;

    active_id = g_value_get_string (source_value);
    visible = (g_strcmp0 (active_id, value_nick) == 0);
    g_value_set_boolean (target_value, visible);

    return TRUE;
}

static void
proxy_editor_set_registry (EProxyEditor *editor,
                           ESourceRegistry *registry)
{
    g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
    g_return_if_fail (editor->priv->registry == NULL);

    editor->priv->registry = g_object_ref (registry);
}

static void
proxy_editor_set_property (GObject *object,
                           guint property_id,
                           const GValue *value,
                           GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_REGISTRY:
            proxy_editor_set_registry (
                E_PROXY_EDITOR (object),
                g_value_get_object (value));
            return;

        case PROP_SOURCE:
            e_proxy_editor_set_source (
                E_PROXY_EDITOR (object),
                g_value_get_object (value));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
proxy_editor_get_property (GObject *object,
                           guint property_id,
                           GValue *value,
                           GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_REGISTRY:
            g_value_set_object (
                value,
                e_proxy_editor_get_registry (
                E_PROXY_EDITOR (object)));
            return;

        case PROP_SOURCE:
            g_value_take_object (
                value,
                e_proxy_editor_ref_source (
                E_PROXY_EDITOR (object)));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
proxy_editor_dispose (GObject *object)
{
    EProxyEditorPrivate *priv;

    priv = E_PROXY_EDITOR_GET_PRIVATE (object);

    if (priv->source != NULL)
        e_proxy_editor_save (E_PROXY_EDITOR (object));

    g_clear_object (&priv->registry);
    g_clear_object (&priv->source);

    /* Chain up to parent's dispose() method. */
    G_OBJECT_CLASS (e_proxy_editor_parent_class)->dispose (object);
}

static void
proxy_editor_finalize (GObject *object)
{
    EProxyEditorPrivate *priv;

    priv = E_PROXY_EDITOR_GET_PRIVATE (object);

    g_free (priv->gcc_program_path);

    /* Chain up to parent's finalize() method. */
    G_OBJECT_CLASS (e_proxy_editor_parent_class)->finalize (object);
}

static void
proxy_editor_constructed (GObject *object)
{
    EProxyEditor *editor;
    ESourceRegistry *registry;
    GtkLabel *label;
    GtkWidget *widget;
    GtkWidget *container;
    GtkSizeGroup *size_group;
    GEnumClass *enum_class;
    GEnumValue *enum_value;
    gint row = 0;

    /* Chain up to parent's constructed() method. */
    G_OBJECT_CLASS (e_proxy_editor_parent_class)->constructed (object);

    editor = E_PROXY_EDITOR (object);
    registry = e_proxy_editor_get_registry (editor);

    enum_class = g_type_class_ref (E_TYPE_PROXY_METHOD);

    /* Default to the built-in proxy profile source. */
    editor->priv->source = e_source_registry_ref_builtin_proxy (registry);

    gtk_grid_set_row_spacing (GTK_GRID (editor), 6);
    gtk_grid_set_column_spacing (GTK_GRID (editor), 6);

    /* This keeps all (visible) mnemonic labels the same width. */
    size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
    gtk_size_group_set_ignore_hidden (size_group, TRUE);

    widget = gtk_label_new_with_mnemonic (_("_Method:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (editor), widget, 0, 0, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_combo_box_text_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (editor), widget, 1, 0, 1, 1);
    editor->priv->method_combo_box = widget;  /* do not reference */
    gtk_widget_show (widget);

    /*** Defer to Desktop Settings ***/

    enum_value = g_enum_get_value (enum_class, E_PROXY_METHOD_DEFAULT);
    g_return_if_fail (enum_value != NULL);

    gtk_combo_box_text_append (
        GTK_COMBO_BOX_TEXT (editor->priv->method_combo_box),
        enum_value->value_nick, _("Defer to Desktop Settings"));

    if (editor->priv->gcc_program_path != NULL) {
        widget = gtk_button_new_with_mnemonic (
            _("_Open Desktop Settings"));
        gtk_widget_set_halign (widget, GTK_ALIGN_START);
        gtk_grid_attach (GTK_GRID (editor), widget, 1, ++row, 2, 1);

        g_signal_connect (
            widget, "clicked",
            G_CALLBACK (proxy_editor_open_desktop_settings_cb),
            editor);

        g_object_bind_property_full (
            editor->priv->method_combo_box, "active-id",
            widget, "visible",
            G_BINDING_DEFAULT,
            proxy_editor_active_id_to_visible,
            NULL,
            (gpointer) enum_value->value_nick,
            (GDestroyNotify) NULL);
    }

    /*** Manual ***/

    enum_value = g_enum_get_value (enum_class, E_PROXY_METHOD_MANUAL);
    g_return_if_fail (enum_value != NULL);

    gtk_combo_box_text_append (
        GTK_COMBO_BOX_TEXT (editor->priv->method_combo_box),
        enum_value->value_nick, _("Manual"));

    widget = gtk_grid_new ();
    gtk_widget_set_valign (widget, GTK_ALIGN_START);
    gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
    gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
    gtk_grid_attach (GTK_GRID (editor), widget, 0, ++row, 2, 1);

    g_object_bind_property_full (
        editor->priv->method_combo_box, "active-id",
        widget, "visible",
        G_BINDING_DEFAULT,
        proxy_editor_active_id_to_visible,
        NULL,
        (gpointer) enum_value->value_nick,
        (GDestroyNotify) NULL);

    container = widget;

    widget = gtk_label_new_with_mnemonic (_("_HTTP Proxy:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 1, 1);
    editor->priv->http_host_entry = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_spin_button_new_with_range (0, G_MAXUINT16, 1);
    gtk_spin_button_set_update_policy (
        GTK_SPIN_BUTTON (widget), GTK_UPDATE_IF_VALID);
    gtk_widget_set_size_request (widget, 100, -1);
    gtk_grid_attach (GTK_GRID (container), widget, 2, 0, 1, 1);
    editor->priv->http_port_spin_button = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_label_new_with_mnemonic (_("H_TTPS Proxy:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 1, 1);
    editor->priv->https_host_entry = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_spin_button_new_with_range (0, G_MAXUINT16, 1);
    gtk_spin_button_set_update_policy (
        GTK_SPIN_BUTTON (widget), GTK_UPDATE_IF_VALID);
    gtk_widget_set_size_request (widget, 100, -1);
    gtk_grid_attach (GTK_GRID (container), widget, 2, 1, 1, 1);
    editor->priv->https_port_spin_button = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_label_new_with_mnemonic (_("_Socks Proxy:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (container), widget, 0, 2, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (container), widget, 1, 2, 1, 1);
    editor->priv->socks_host_entry = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_spin_button_new_with_range (0, G_MAXUINT16, 1);
    gtk_spin_button_set_update_policy (
        GTK_SPIN_BUTTON (widget), GTK_UPDATE_IF_VALID);
    gtk_widget_set_size_request (widget, 100, -1);
    gtk_grid_attach (GTK_GRID (container), widget, 2, 2, 1, 1);
    editor->priv->socks_port_spin_button = widget;
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    widget = gtk_label_new_with_mnemonic (_("_Ignore Hosts:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (container), widget, 0, 3, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (container), widget, 1, 3, 2, 1);
    editor->priv->ignore_hosts_entry = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    /*** Automatic ***/

    enum_value = g_enum_get_value (enum_class, E_PROXY_METHOD_AUTO);
    g_return_if_fail (enum_value != NULL);

    gtk_combo_box_text_append (
        GTK_COMBO_BOX_TEXT (editor->priv->method_combo_box),
        enum_value->value_nick, _("Automatic"));

    widget = gtk_grid_new ();
    gtk_widget_set_valign (widget, GTK_ALIGN_START);
    gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
    gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
    gtk_grid_attach (GTK_GRID (editor), widget, 0, ++row, 2, 1);

    g_object_bind_property_full (
        editor->priv->method_combo_box, "active-id",
        widget, "visible",
        G_BINDING_DEFAULT,
        proxy_editor_active_id_to_visible,
        NULL,
        (gpointer) enum_value->value_nick,
        (GDestroyNotify) NULL);

    container = widget;

    widget = gtk_label_new_with_mnemonic (_("Configuration _URL:"));
    gtk_size_group_add_widget (size_group, widget);
    gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
    gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 1, 1);
    editor->priv->autoconfig_url_entry = widget;  /* do not reference */
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "focus-out-event",
        G_CALLBACK (proxy_editor_focus_out_event_cb), editor);

    /*** None ***/

    enum_value = g_enum_get_value (enum_class, E_PROXY_METHOD_NONE);
    g_return_if_fail (enum_value != NULL);

    gtk_combo_box_text_append (
        GTK_COMBO_BOX_TEXT (editor->priv->method_combo_box),
        enum_value->value_nick, _("None"));

    widget = gtk_label_new (
        _("Use a direct connection, no proxying required."));
    gtk_widget_set_hexpand (widget, TRUE);
    gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
    gtk_grid_attach (GTK_GRID (editor), widget, 1, ++row, 2, 1);
    gtk_widget_show (widget);

    g_object_bind_property_full (
        editor->priv->method_combo_box, "active-id",
        widget, "visible",
        G_BINDING_DEFAULT,
        proxy_editor_active_id_to_visible,
        NULL,
        (gpointer) enum_value->value_nick,
        (GDestroyNotify) NULL);
    g_object_unref (size_group);
    g_type_class_unref (enum_class);

    /* Populate the widgets. */
    proxy_editor_load (editor);

    /* Connect to this signal after the initial load. */
    g_signal_connect (
        editor->priv->method_combo_box, "changed",
        G_CALLBACK (proxy_editor_combo_box_changed_cb), editor);

}

static void
e_proxy_editor_class_init (EProxyEditorClass *class)
{
    GObjectClass *object_class;

    g_type_class_add_private (class, sizeof (EProxyEditorPrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = proxy_editor_set_property;
    object_class->get_property = proxy_editor_get_property;
    object_class->dispose = proxy_editor_dispose;
    object_class->finalize = proxy_editor_finalize;
    object_class->constructed = proxy_editor_constructed;

    g_object_class_install_property (
        object_class,
        PROP_REGISTRY,
        g_param_spec_object (
            "registry",
            "Registry",
            "Data source registry",
            E_TYPE_SOURCE_REGISTRY,
            G_PARAM_READWRITE |
            G_PARAM_CONSTRUCT_ONLY |
            G_PARAM_STATIC_STRINGS));

    g_object_class_install_property (
        object_class,
        PROP_SOURCE,
        g_param_spec_object (
            "source",
            "Source",
            "The data source being edited",
            E_TYPE_SOURCE,
            G_PARAM_READWRITE |
            G_PARAM_STATIC_STRINGS));
}

static void
e_proxy_editor_init (EProxyEditor *editor)
{
    editor->priv = E_PROXY_EDITOR_GET_PRIVATE (editor);

    editor->priv->gcc_program_path =
        g_find_program_in_path ("gnome-control-center");
}

/**
 * e_proxy_editor_new:
 * @registry: an #ESourceRegistry
 *
 * Creates a new #EProxyEditor widget, initially showing details of the
 * built-in proxy profile returned by e_source_registry_ref_builtin_proxy().
 *
 * Returns: a new #EProxyEditor
 **/
GtkWidget *
e_proxy_editor_new (ESourceRegistry *registry)
{
    g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);

    return g_object_new (
        E_TYPE_PROXY_EDITOR,
        "registry", registry, NULL);
}

/**
 * e_proxy_editor_save:
 * @editor: an #EProxyEditor
 *
 * Writes the proxy settings displayed in the @editor to the #ESource
 * being edited.
 *
 * This function is called automatically when the editing widgets lose input
 * focus, but it may sometimes need to be called explicitly such as when the
 * top-level window is closing.
 **/
void
e_proxy_editor_save (EProxyEditor *editor)
{
    ESource *source;
    ESourceProxy *extension;
    GEnumClass *enum_class;
    GEnumValue *enum_value;
    const gchar *active_id;
    const gchar *entry_text;
    const gchar *extension_name;
    gint spin_button_value;
    gchar **strv;

    g_return_if_fail (E_IS_PROXY_EDITOR (editor));

    source = e_proxy_editor_ref_source (editor);
    g_return_if_fail (source != NULL);

    extension_name = E_SOURCE_EXTENSION_PROXY;
    extension = e_source_get_extension (source, extension_name);

    enum_class = g_type_class_ref (E_TYPE_PROXY_METHOD);
    active_id = gtk_combo_box_get_active_id (
        GTK_COMBO_BOX (editor->priv->method_combo_box));
    enum_value = g_enum_get_value_by_nick (enum_class, active_id);
    if (enum_value != NULL)
        e_source_proxy_set_method (extension, enum_value->value);
    g_type_class_unref (enum_class);

    entry_text = gtk_entry_get_text (
        GTK_ENTRY (editor->priv->autoconfig_url_entry));
    if (entry_text != NULL && *entry_text == '\0')
        entry_text = NULL;
    e_source_proxy_set_autoconfig_url (extension, entry_text);

    entry_text = gtk_entry_get_text (
        GTK_ENTRY (editor->priv->ignore_hosts_entry));
    strv = g_strsplit (entry_text, ",", -1);
    if (strv != NULL) {
        guint length, ii;

        /* Strip leading and trailing whitespace from each element
         * to avoid a changed notification storm between the entry
         * (which adds a space after each comma) and ESourceProxy. */
        length = g_strv_length (strv);
        for (ii = 0; ii < length; ii++)
            g_strstrip (strv[ii]);
    }
    e_source_proxy_set_ignore_hosts (
        extension, (const gchar * const *) strv);
    g_strfreev (strv);

    entry_text = gtk_entry_get_text (
        GTK_ENTRY (editor->priv->http_host_entry));
    if (entry_text != NULL && *entry_text == '\0')
        entry_text = NULL;
    e_source_proxy_set_http_host (extension, entry_text);

    spin_button_value = gtk_spin_button_get_value_as_int (
        GTK_SPIN_BUTTON (editor->priv->http_port_spin_button));
    e_source_proxy_set_http_port (extension, (guint16) spin_button_value);

    entry_text = gtk_entry_get_text (
        GTK_ENTRY (editor->priv->https_host_entry));
    if (entry_text != NULL && *entry_text == '\0')
        entry_text = NULL;
    e_source_proxy_set_https_host (extension, entry_text);

    spin_button_value = gtk_spin_button_get_value_as_int (
        GTK_SPIN_BUTTON (editor->priv->https_port_spin_button));
    e_source_proxy_set_https_port (extension, (guint16) spin_button_value);

    entry_text = gtk_entry_get_text (
        GTK_ENTRY (editor->priv->socks_host_entry));
    if (entry_text != NULL && *entry_text == '\0')
        entry_text = NULL;
    e_source_proxy_set_socks_host (extension, entry_text);

    spin_button_value = gtk_spin_button_get_value_as_int (
        GTK_SPIN_BUTTON (editor->priv->socks_port_spin_button));
    e_source_proxy_set_socks_port (extension, (guint16) spin_button_value);

    g_object_unref (source);
}

/**
 * e_proxy_editor_get_registry:
 * @editor: an #EProxyEditor
 *
 * Returns the #ESourceRegistry passed to e_proxy_editor_get_registry().
 *
 * Returns: an #ESourceRegistry
 **/
ESourceRegistry *
e_proxy_editor_get_registry (EProxyEditor *editor)
{
    g_return_val_if_fail (E_IS_PROXY_EDITOR (editor), NULL);

    return editor->priv->registry;
}

/**
 * e_proxy_editor_ref_source:
 * @editor: an #EProxyEditor
 *
 * Returns the network proxy profile #ESource being edited.
 *
 * The returned #ESource is referenced for thread-safety and must be
 * unreferenced with g_object_unref() when finished with it.
 *
 * Returns: an #ESource
 **/
ESource *
e_proxy_editor_ref_source (EProxyEditor *editor)
{
    g_return_val_if_fail (E_IS_PROXY_EDITOR (editor), NULL);

    return g_object_ref (editor->priv->source);
}

/**
 * e_proxy_editor_set_source:
 * @editor: an #EProxyEditor
 * @source: an #ESource
 *
 * Sets the network proxy profile #ESource to edit.
 *
 * This first writes the displayed proxy settings to the previous #ESource,
 * then displays the proxy details for @source.  If @source is already being
 * edited then nothing happens.
 **/
void
e_proxy_editor_set_source (EProxyEditor *editor,
                           ESource *source)
{
    g_return_if_fail (E_IS_PROXY_EDITOR (editor));
    g_return_if_fail (E_IS_SOURCE (source));

    if (e_source_equal (source, editor->priv->source))
        return;

    e_proxy_editor_save (editor);

    g_clear_object (&editor->priv->source);
    editor->priv->source = g_object_ref (source);

    proxy_editor_load (editor);

    g_object_notify (G_OBJECT (editor), "source");
}