:, [if test $os_win32 = yes; then with_gnome=no; else with_gnome=yes; fi])
AC_MSG_RESULT($with_gnome)
+if test $with_gnome != no; then
+ PKG_CHECK_MODULES(GNOME_KEYRING, gnome-keyring-1, :,
+ AC_MSG_ERROR(
+[Could not find gnome-keyring devel files.
+Configure with --without-gnome if you wish to build only libsoup
+without GNOME-specific features.]))
+fi
+AC_SUBST(GNOME_KEYRING_CFLAGS)
+AC_SUBST(GNOME_KEYRING_LIBS)
+
AM_CONDITIONAL(BUILD_LIBSOUP_GNOME, test $with_gnome != no)
if test $with_gnome != no; then
$(GCONF_CFLAGS) \
$(LIBPROXY_CFLAGS) \
$(SQLITE_CFLAGS) \
+ $(GNOME_KEYRING_CFLAGS) \
$(LIBGCRYPT_CFLAGS) \
$(LIBGNUTLS_CFLAGS)
soup-method.h \
soup-misc.h \
soup-multipart.h \
+ soup-password-manager.h \
soup-portability.h \
soup-proxy-resolver.h \
soup-proxy-uri-resolver.h \
soup-misc.c \
soup-multipart.c \
soup-nossl.c \
+ soup-password-manager.c \
soup-path-map.h \
soup-path-map.c \
soup-proxy-resolver.c \
libsoupgnomeinclude_HEADERS = \
soup-cookie-jar-sqlite.h\
soup-gnome.h \
- soup-gnome-features.h
+ soup-gnome-features.h \
+ soup-password-manager-gnome.h
lib_LTLIBRARIES += libsoup-gnome-2.4.la
$(GLIB_LIBS) \
$(GCONF_LIBS) \
$(LIBPROXY_LIBS) \
- $(SQLITE_LIBS)
+ $(SQLITE_LIBS) \
+ $(GNOME_KEYRING_LIBS)
libsoup_gnome_2_4_la_SOURCES = \
soup-cookie-jar-sqlite.c \
soup-gnome-features.c \
soup-proxy-resolver-gnome.h \
- soup-proxy-resolver-gnome.c
+ soup-proxy-resolver-gnome.c \
+ soup-password-manager-gnome.h \
+ soup-password-manager-gnome.c
endif
} SoupAuthManagerNTLMClass;
+#define SOUP_AUTH_MANAGER_NTLM_USE_NTLM "use-ntlm"
+
GType soup_auth_manager_ntlm_get_type (void);
G_END_DECLS
SoupAuth *auth, gboolean retrying);
} SoupAuthManagerClass;
-#define SOUP_AUTH_MANAGER_NTLM_USE_NTLM "use-ntlm"
-
GType soup_auth_manager_get_type (void);
void soup_auth_manager_add_type (SoupAuthManager *manager,
#include "soup-auth-basic.h"
#include "soup-auth-digest.h"
#include "soup-headers.h"
+#include "soup-marshal.h"
#include "soup-uri.h"
/**
gboolean proxy;
char *host;
+ GHashTable *saved_passwords;
} SoupAuthPrivate;
#define SOUP_AUTH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH, SoupAuthPrivate))
G_DEFINE_TYPE (SoupAuth, soup_auth, G_TYPE_OBJECT)
enum {
+ SAVE_PASSWORD,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
PROP_0,
PROP_SCHEME_NAME,
g_free (auth->realm);
g_free (priv->host);
+ if (priv->saved_passwords)
+ g_hash_table_destroy (priv->saved_passwords);
G_OBJECT_CLASS (soup_auth_parent_class)->finalize (object);
}
object_class->set_property = set_property;
object_class->get_property = get_property;
+ /**
+ * SoupAuth::save-password:
+ * @auth: the auth
+ * @username: the username to save
+ * @password: the password to save
+ *
+ * Emitted to request that the @username/@password pair be
+ * saved. If the session supports password-saving, it will
+ * connect to this signal before emitting
+ * #SoupSession::authenticate, so that it record the password
+ * if requested by the caller.
+ *
+ * Since: 2.28
+ **/
+ signals[SAVE_PASSWORD] =
+ g_signal_new ("save-password",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ soup_marshal_NONE__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
/* properties */
/**
* SOUP_AUTH_SCHEME_NAME:
*
* Call this on an auth to authenticate it; normally this will cause
* the auth's message to be requeued with the new authentication info.
+ *
+ * This does not cause the password to be saved to persistent storage;
+ * see soup_auth_save_password() for that.
**/
void
soup_auth_authenticate (SoupAuth *auth, const char *username, const char *password)
g_free (s->data);
g_slist_free (space);
}
+
+/**
+ * soup_auth_get_saved_users:
+ * @auth: a #SoupAuth
+ *
+ * Gets a list of usernames for which a saved password is available.
+ * (If the session is not configured to save passwords, this will
+ * always be %NULL.)
+ *
+ * Return value: the list of usernames. You must free the list with
+ * g_slist_free(), but do not free or modify the contents.
+ *
+ * Since: 2.28
+ **/
+GSList *
+soup_auth_get_saved_users (SoupAuth *auth)
+{
+ SoupAuthPrivate *priv;
+ GSList *users;
+
+ g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
+
+ priv = SOUP_AUTH_GET_PRIVATE (auth);
+ users = NULL;
+
+ if (priv->saved_passwords) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, priv->saved_passwords);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ users = g_slist_prepend (users, key);
+ }
+ return users;
+}
+
+/**
+ * soup_auth_get_saved_password:
+ * @auth: a #SoupAuth
+ * @user: a username from the list returned from
+ * soup_auth_get_saved_users().
+ *
+ * Given a username for which @auth has a saved password, this returns
+ * that password. If @auth doesn't have a passwords saved for @user, it
+ * returns %NULL.
+ *
+ * Return value: the saved password, or %NULL.
+ *
+ * Since: 2.28
+ **/
+const char *
+soup_auth_get_saved_password (SoupAuth *auth, const char *user)
+{
+ SoupAuthPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
+ g_return_val_if_fail (user != NULL, NULL);
+
+ priv = SOUP_AUTH_GET_PRIVATE (auth);
+ if (!priv->saved_passwords)
+ return NULL;
+ return g_hash_table_lookup (priv->saved_passwords, user);
+}
+
+static void
+free_password (gpointer password)
+{
+ memset (password, 0, strlen (password));
+ g_free (password);
+}
+
+static inline void
+init_saved_passwords (SoupAuthPrivate *priv)
+{
+ priv->saved_passwords = g_hash_table_new_full (
+ g_str_hash, g_str_equal, g_free, free_password);
+}
+
+/**
+ * soup_auth_has_saved_password:
+ * @auth: a #SoupAuth
+ * @username: a username
+ * @password: a password
+ *
+ * Updates @auth to be aware of an already-saved username/password
+ * combination. This method <emphasis>does not</emphasis> cause the
+ * given @username and @password to be saved; use
+ * soup_auth_save_password() for that. (soup_auth_has_saved_password()
+ * is an internal method, which is used by the code that actually
+ * saves and restores the passwords.)
+ *
+ * Since: 2.28
+ **/
+void
+soup_auth_has_saved_password (SoupAuth *auth, const char *username,
+ const char *password)
+{
+ SoupAuthPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_AUTH (auth));
+ g_return_if_fail (username != NULL);
+ g_return_if_fail (password != NULL);
+
+ priv = SOUP_AUTH_GET_PRIVATE (auth);
+
+ if (!priv->saved_passwords)
+ init_saved_passwords (priv);
+ g_hash_table_insert (priv->saved_passwords,
+ g_strdup (username), g_strdup (password));
+}
+
+/**
+ * soup_auth_save_password:
+ * @auth: a #SoupAuth
+ * @username: the username provided by the user or client
+ * @password: the password provided by the user or client
+ *
+ * Requests that the username/password pair be saved to whatever form
+ * of persistent password storage the session supports.
+ *
+ * Since: 2.28
+ **/
+void
+soup_auth_save_password (SoupAuth *auth, const char *username,
+ const char *password)
+{
+ g_return_if_fail (SOUP_IS_AUTH (auth));
+ g_return_if_fail (username != NULL);
+ g_return_if_fail (password != NULL);
+
+ g_signal_emit (auth, signals[SAVE_PASSWORD], 0,
+ username, password);
+}
const char *soup_auth_get_realm (SoupAuth *auth);
char *soup_auth_get_info (SoupAuth *auth);
+GSList *soup_auth_get_saved_users (SoupAuth *auth);
+const char *soup_auth_get_saved_password (SoupAuth *auth,
+ const char *user);
+void soup_auth_save_password (SoupAuth *auth,
+ const char *username,
+ const char *password);
+
void soup_auth_authenticate (SoupAuth *auth,
const char *username,
const char *password);
void soup_auth_free_protection_space (SoupAuth *auth,
GSList *space);
+void soup_auth_has_saved_password (SoupAuth *auth,
+ const char *username,
+ const char *password);
+
G_END_DECLS
#endif /* SOUP_AUTH_H */
#include <libsoup/soup-cookie-jar-sqlite.h>
#include <libsoup/soup-gnome-features.h>
+#include <libsoup/soup-password-manager-gnome.h>
#endif /* SOUP_GNOME_H */
NONE:BOXED,BOXED
NONE:OBJECT,OBJECT,BOOLEAN
NONE:STRING,BOXED
+NONE:STRING,STRING
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-password-manager-gnome.c: GNOME-keyring-based password manager
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-password-manager-gnome.h"
+#include "soup-auth.h"
+#include "soup-session-feature.h"
+#include "soup-uri.h"
+
+#include <gnome-keyring.h>
+
+static void soup_password_manager_gnome_interface_init (SoupPasswordManagerInterface *password_manager_interface);
+
+G_DEFINE_TYPE_EXTENDED (SoupPasswordManagerGNOME, soup_password_manager_gnome, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_PASSWORD_MANAGER, soup_password_manager_gnome_interface_init))
+
+static void get_passwords_async (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupPasswordManagerCallback callback,
+ gpointer user_data);
+static void get_passwords_sync (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ GCancellable *cancellable);
+
+static void
+soup_password_manager_gnome_init (SoupPasswordManagerGNOME *manager_gnome)
+{
+}
+
+static void
+soup_password_manager_gnome_class_init (SoupPasswordManagerGNOMEClass *gnome_class)
+{
+}
+
+static void
+soup_password_manager_gnome_interface_init (SoupPasswordManagerInterface *password_manager_interface)
+{
+ password_manager_interface->get_passwords_async = get_passwords_async;
+ password_manager_interface->get_passwords_sync = get_passwords_sync;
+}
+
+SoupPasswordManager *
+soup_password_manager_gnome_new (void)
+{
+ return g_object_new (SOUP_TYPE_PASSWORD_MANAGER_GNOME, NULL);
+}
+
+
+static void
+save_password_callback (GnomeKeyringResult result, guint32 val, gpointer data)
+{
+}
+
+static void
+async_save_password (SoupAuth *auth, const char *username,
+ const char *password, gpointer user_data)
+{
+ SoupURI *uri = user_data;
+
+ gnome_keyring_set_network_password (
+ NULL, /* use default keyring */
+ username,
+ soup_auth_get_realm (auth),
+ uri->host,
+ NULL,
+ uri->scheme,
+ soup_auth_get_scheme_name (auth),
+ uri->port,
+ password,
+ save_password_callback, NULL, NULL);
+}
+
+static void
+sync_save_password (SoupAuth *auth, const char *username,
+ const char *password, gpointer user_data)
+{
+ SoupURI *uri = user_data;
+ guint32 item_id;
+
+ gnome_keyring_set_network_password_sync (
+ NULL, /* use default keyring */
+ username,
+ soup_auth_get_realm (auth),
+ uri->host,
+ NULL,
+ uri->scheme,
+ soup_auth_get_scheme_name (auth),
+ uri->port,
+ password,
+ &item_id);
+}
+
+static void
+update_auth_for_passwords (SoupAuth *auth, SoupMessage *msg,
+ GList *passwords, gboolean async)
+{
+ GnomeKeyringNetworkPasswordData *pdata;
+ SoupURI *uri;
+
+ while (passwords) {
+ pdata = passwords->data;
+ soup_auth_has_saved_password (auth, pdata->user,
+ pdata->password);
+ passwords = passwords->next;
+ }
+
+ uri = soup_uri_copy (soup_message_get_uri (msg));
+ g_signal_connect (auth, "save_password",
+ G_CALLBACK (async ? async_save_password : sync_save_password),
+ uri);
+ g_object_set_data_full (G_OBJECT (auth),
+ "SoupPasswordManagerGNOME-save_password-uri",
+ uri, (GDestroyNotify)soup_uri_free);
+}
+
+typedef struct {
+ SoupPasswordManager *password_manager;
+ SoupMessage *msg;
+ SoupAuth *auth;
+ gboolean retrying;
+
+ SoupPasswordManagerCallback callback;
+ gpointer user_data;
+
+ gpointer request;
+} SoupPasswordManagerGNOMEAuthData;
+
+static void
+find_password_callback (GnomeKeyringResult result, GList *list,
+ gpointer user_data)
+{
+ SoupPasswordManagerGNOMEAuthData *auth_data = user_data;
+
+ /* FIXME: check result? */
+
+ update_auth_for_passwords (auth_data->auth, auth_data->msg, list, TRUE);
+ auth_data->callback (auth_data->password_manager,
+ auth_data->msg, auth_data->auth,
+ auth_data->retrying, auth_data->user_data);
+
+ /* gnome-keyring will call free_auth_data to clean up for us. */
+}
+
+static void
+free_auth_data (gpointer data)
+{
+ SoupPasswordManagerGNOMEAuthData *auth_data = data;
+
+ g_object_unref (auth_data->auth);
+ g_object_unref (auth_data->msg);
+ g_slice_free (SoupPasswordManagerGNOMEAuthData, auth_data);
+}
+
+static void
+get_passwords_async (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupPasswordManagerCallback callback,
+ gpointer user_data)
+{
+ SoupPasswordManagerGNOMEAuthData *auth_data;
+ SoupURI *uri = soup_message_get_uri (msg);
+
+ auth_data = g_slice_new (SoupPasswordManagerGNOMEAuthData);
+ auth_data->password_manager = password_manager;
+ auth_data->msg = g_object_ref (msg);
+ auth_data->auth = g_object_ref (auth);
+ auth_data->retrying = retrying;
+
+ /* FIXME: async_context, cancellable */
+
+ auth_data->callback = callback;
+ auth_data->user_data = user_data;
+
+ /* FIXME: should we be specifying protocol and port here, or
+ * leaving them NULL/0 and filtering results in the callback?
+ * We don't want to send https passwords to http, but the
+ * reverse might be OK (if that's how other clients tend to
+ * behave).
+ */
+ auth_data->request = gnome_keyring_find_network_password (
+ NULL, /* user -- accept any */
+ soup_auth_get_realm (auth), /* domain */
+ uri->host, /* server */
+ NULL, /* object -- unused */
+ uri->scheme, /* protocol */
+ soup_auth_get_scheme_name (auth), /* authtype */
+ uri->port, /* port */
+ find_password_callback, auth_data, free_auth_data);
+}
+
+static void
+get_passwords_sync (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ GCancellable *cancellable)
+{
+ SoupURI *uri = soup_message_get_uri (msg);
+ GList *results = NULL;
+
+ /* FIXME: cancellable */
+
+ gnome_keyring_find_network_password_sync (
+ NULL, /* user -- accept any */
+ soup_auth_get_realm (auth), /* domain */
+ uri->host, /* server */
+ NULL, /* object -- unused */
+ uri->scheme, /* protocol */
+ soup_auth_get_scheme_name (auth), /* authtype */
+ uri->port, /* port */
+ &results);
+
+ update_auth_for_passwords (auth, msg, results, FALSE);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef SOUP_PASSWORD_MANAGER_GNOME_H
+#define SOUP_PASSWORD_MANAGER_GNOME_H 1
+
+#include <libsoup/soup-password-manager.h>
+
+#define SOUP_TYPE_PASSWORD_MANAGER_GNOME (soup_password_manager_gnome_get_type ())
+#define SOUP_PASSWORD_MANAGER_GNOME(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PASSWORD_MANAGER_GNOME, SoupPasswordManagerGNOME))
+#define SOUP_PASSWORD_MANAGER_GNOME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PASSWORD_MANAGER_GNOME, SoupPasswordManagerGNOMEClass))
+#define SOUP_IS_PASSWORD_MANAGER_GNOME(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PASSWORD_MANAGER_GNOME))
+#define SOUP_IS_PASSWORD_MANAGER_GNOME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PASSWORD_MANAGER_GNOME))
+#define SOUP_PASSWORD_MANAGER_GNOME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_PASSWORD_MANAGER_GNOME, SoupPasswordManagerGNOMEClass))
+
+typedef struct {
+ GObject parent;
+
+} SoupPasswordManagerGNOME;
+
+typedef struct {
+ GObjectClass parent_class;
+
+} SoupPasswordManagerGNOMEClass;
+
+GType soup_password_manager_gnome_get_type (void);
+
+SoupPasswordManager *soup_password_manager_gnome_new (void);
+
+#endif /* SOUP_PASSWORD_MANAGER_GNOME_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-password-manager.c: HTTP auth password manager interface
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-password-manager.h"
+#include "soup-session-feature.h"
+
+GType
+soup_password_manager_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ GType g_define_type_id =
+ g_type_register_static_simple (G_TYPE_INTERFACE,
+ g_intern_static_string ("SoupPasswordManager"),
+ sizeof (SoupPasswordManagerInterface),
+ (GClassInitFunc)NULL,
+ 0,
+ (GInstanceInitFunc)NULL,
+ (GTypeFlags) 0);
+ g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
+ g_type_interface_add_prerequisite (g_define_type_id, SOUP_TYPE_SESSION_FEATURE);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+ return g_define_type_id__volatile;
+}
+
+/**
+ * soup_password_manager_get_passwords_async:
+ * @password_manager: the #SoupPasswordManager
+ * @msg: the #SoupMessage being authenticated
+ * @auth: the #SoupAuth being authenticated
+ * @retrying: whether or not this is a re-attempt to authenticate
+ * @async_context: the #GMainContext to invoke @callback in
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to invoke after fetching passwords
+ * @user_data: data for @callback
+ *
+ * Asynchronously attempts to look up saved passwords for @auth/@msg
+ * and then calls @callback after updating @auth with the information.
+ * Also registers @auth with @password_manager so that if the caller
+ * calls soup_auth_save_password() on it, the password will be saved.
+ *
+ * #SoupPasswordManager does not actually use the @retrying flag itself;
+ * it just passes its value on to @callback.
+ *
+ * If @cancellable is cancelled, @callback will still be invoked.
+ *
+ * Since: 2.28
+ **/
+void
+soup_password_manager_get_passwords_async (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupPasswordManagerCallback callback,
+ gpointer user_data)
+{
+ SOUP_PASSWORD_MANAGER_GET_CLASS (password_manager)->
+ get_passwords_async (password_manager, msg, auth, retrying,
+ async_context, cancellable,
+ callback, user_data);
+}
+
+/**
+ * soup_password_manager_get_passwords_sync:
+ * @password_manager: the #SoupPasswordManager
+ * @msg: the #SoupMessage being authenticated
+ * @auth: the #SoupAuth being authenticated
+ * @cancellable: a #GCancellable, or %NULL
+ *
+ * Synchronously attempts to look up saved passwords for @auth/@msg
+ * and updates @auth with the information. Also registers @auth with
+ * @password_manager so that if the caller calls
+ * soup_auth_save_password() on it, the password will be saved.
+ *
+ * Since: 2.28
+ **/
+void
+soup_password_manager_get_passwords_sync (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ GCancellable *cancellable)
+{
+ SOUP_PASSWORD_MANAGER_GET_CLASS (password_manager)->
+ get_passwords_sync (password_manager, msg, auth, cancellable);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef SOUP_PASSWORD_MANAGER_H
+#define SOUP_PASSWORD_MANAGER_H 1
+
+#include <libsoup/soup-types.h>
+#include <gio/gio.h>
+
+#define SOUP_TYPE_PASSWORD_MANAGER (soup_password_manager_get_type ())
+#define SOUP_PASSWORD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PASSWORD_MANAGER, SoupPasswordManager))
+#define SOUP_PASSWORD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PASSWORD_MANAGER, SoupPasswordManagerInterface))
+#define SOUP_IS_PASSWORD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PASSWORD_MANAGER))
+#define SOUP_IS_PASSWORD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PASSWORD_MANAGER))
+#define SOUP_PASSWORD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), SOUP_TYPE_PASSWORD_MANAGER, SoupPasswordManagerInterface))
+
+typedef struct _SoupPasswordManager SoupPasswordManager;
+
+typedef void (*SoupPasswordManagerCallback) (SoupPasswordManager *,
+ SoupMessage *, SoupAuth *,
+ gboolean retrying,
+ gpointer user_data);
+
+typedef struct {
+ GTypeInterface base;
+
+ /* virtual methods */
+ void (*get_passwords_async) (SoupPasswordManager *, SoupMessage *,
+ SoupAuth *, gboolean,
+ GMainContext *, GCancellable *,
+ SoupPasswordManagerCallback, gpointer);
+ void (*get_passwords_sync) (SoupPasswordManager *, SoupMessage *,
+ SoupAuth *, GCancellable *);
+
+} SoupPasswordManagerInterface;
+
+GType soup_password_manager_get_type (void);
+
+void soup_password_manager_get_passwords_async (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupPasswordManagerCallback callback,
+ gpointer user_data);
+
+void soup_password_manager_get_passwords_sync (SoupPasswordManager *password_manager,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ GCancellable *cancellable);
+
+#endif /* SOUP_PASSWORD_MANAGER_H */
#include "soup-address.h"
#include "soup-message-private.h"
#include "soup-misc.h"
+#include "soup-password-manager.h"
#include "soup-proxy-uri-resolver.h"
#include "soup-uri.h"
SoupSessionCallback callback, gpointer user_data);
static guint send_message (SoupSession *session, SoupMessage *req);
+static void auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying);
+
G_DEFINE_TYPE (SoupSessionAsync, soup_session_async, SOUP_TYPE_SESSION)
typedef struct {
/* virtual method override */
session_class->queue_message = queue_message;
session_class->send_message = send_message;
+ session_class->auth_required = auth_required;
object_class->finalize = finalize;
}
return req->status_code;
}
+
+static void
+got_passwords (SoupPasswordManager *password_manager, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying, gpointer session)
+{
+ soup_session_unpause_message (session, msg);
+ SOUP_SESSION_CLASS (soup_session_async_parent_class)->
+ auth_required (session, msg, auth, retrying);
+ g_object_unref (auth);
+}
+
+static void
+auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying)
+{
+ SoupSessionFeature *password_manager;
+
+ password_manager = soup_session_get_feature_for_message (
+ session, SOUP_TYPE_PASSWORD_MANAGER, msg);
+ if (password_manager) {
+ soup_session_pause_message (session, msg);
+ g_object_ref (auth);
+ soup_password_manager_get_passwords_async (
+ SOUP_PASSWORD_MANAGER (password_manager),
+ msg, auth, retrying,
+ soup_session_get_async_context (session),
+ NULL, /* FIXME cancellable */
+ got_passwords, session);
+ } else {
+ SOUP_SESSION_CLASS (soup_session_async_parent_class)->
+ auth_required (session, msg, auth, retrying);
+ }
+}
#include "soup-session-private.h"
#include "soup-address.h"
#include "soup-message-private.h"
-#include "soup-proxy-uri-resolver.h"
#include "soup-misc.h"
+#include "soup-password-manager.h"
+#include "soup-proxy-uri-resolver.h"
#include "soup-uri.h"
/**
static guint send_message (SoupSession *session, SoupMessage *msg);
static void cancel_message (SoupSession *session, SoupMessage *msg,
guint status_code);
+static void auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying);
G_DEFINE_TYPE (SoupSessionSync, soup_session_sync, SOUP_TYPE_SESSION)
session_class->queue_message = queue_message;
session_class->send_message = send_message;
session_class->cancel_message = cancel_message;
+ session_class->auth_required = auth_required;
object_class->finalize = finalize;
}
g_cond_broadcast (priv->cond);
}
+static void
+auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying)
+{
+ SoupSessionFeature *password_manager;
+
+ password_manager = soup_session_get_feature_for_message (
+ session, SOUP_TYPE_PASSWORD_MANAGER, msg);
+ if (password_manager) {
+ soup_password_manager_get_passwords_sync (
+ SOUP_PASSWORD_MANAGER (password_manager),
+ msg, auth, NULL); /* FIXME cancellable */
+ }
+
+ SOUP_SESSION_CLASS (soup_session_sync_parent_class)->
+ auth_required (session, msg, auth, retrying);
+}
static void requeue_message (SoupSession *session, SoupMessage *msg);
static void cancel_message (SoupSession *session, SoupMessage *msg,
guint status_code);
+static void auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying);
static void auth_manager_authenticate (SoupAuthManager *manager,
SoupMessage *msg, SoupAuth *auth,
session_class->queue_message = queue_message;
session_class->requeue_message = requeue_message;
session_class->cancel_message = cancel_message;
+ session_class->auth_required = auth_required;
/* virtual method override */
object_class->dispose = dispose;
}
static void
+auth_required (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying)
+{
+ g_signal_emit (session, signals[AUTHENTICATE], 0, msg, auth, retrying);
+}
+
+static void
auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
SoupAuth *auth, gboolean retrying,
gpointer session)
{
- g_signal_emit (session, signals[AUTHENTICATE], 0, msg, auth, retrying);
+ SOUP_SESSION_GET_CLASS (session)->auth_required (
+ session, msg, auth, retrying);
}
#define SOUP_METHOD_IS_SAFE(method) (method == SOUP_METHOD_GET || \
void (*cancel_message) (SoupSession *session, SoupMessage *msg,
guint status_code);
+ void (*auth_required) (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gboolean retrying);
+
+
/* Padding for future expansion */
- void (*_libsoup_reserved1) (void);
void (*_libsoup_reserved2) (void);
void (*_libsoup_reserved3) (void);
void (*_libsoup_reserved4) (void);
#include <libsoup/soup-method.h>
#include <libsoup/soup-misc.h>
#include <libsoup/soup-multipart.h>
+#include <libsoup/soup-password-manager.h>
#include <libsoup/soup-proxy-resolver.h>
#include <libsoup/soup-proxy-uri-resolver.h>
#include <libsoup/soup-server.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <termios.h>
#include <unistd.h>
#ifdef HAVE_GNOME
}
static void
+authenticate (SoupSession *session, SoupMessage *msg,
+ SoupAuth *auth, gpointer user_data)
+{
+ char *uri;
+ GSList *saved_users;
+ struct termios t;
+ int old_lflag;
+ char user[80], pwbuf[80];
+ const char *password;
+
+ if (tcgetattr (STDIN_FILENO, &t) != 0)
+ return;
+
+ uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+ fprintf (stderr, "Authentication required for %s:\n", uri);
+ g_free (uri);
+ fprintf (stderr, " Realm: %s, Auth type: %s\n",
+ soup_auth_get_realm (auth), soup_auth_get_scheme_name (auth));
+
+ saved_users = soup_auth_get_saved_users (auth);
+ if (saved_users) {
+ GSList *u;
+
+ fprintf (stderr, " Passwords saved for: ");
+ for (u = saved_users; u; u = u->next) {
+ if (u != saved_users)
+ fprintf (stderr, ", ");
+ fprintf (stderr, "%s", (char *)u->data);
+ }
+ fprintf (stderr, "\n");
+ }
+ g_slist_free (saved_users);
+
+ fprintf (stderr, " username: ");
+ fflush (stderr);
+
+ if (!fgets (user, sizeof (user), stdin) || user[0] == '\n')
+ return;
+ *strchr (user, '\n') = '\0';
+
+ password = soup_auth_get_saved_password (auth, user);
+ if (!password) {
+ fprintf (stderr, " password: ");
+ fflush (stderr);
+
+ old_lflag = t.c_lflag;
+ t.c_lflag = (t.c_lflag | ICANON | ECHONL) & ~ECHO;
+ tcsetattr (STDIN_FILENO, TCSANOW, &t);
+
+ /* For some reason, fgets can return EINTR on
+ * Linux if ECHO is false...
+ */
+ do
+ password = fgets (pwbuf, sizeof (pwbuf), stdin);
+ while (password == NULL && errno == EINTR);
+
+ t.c_lflag = old_lflag;
+ tcsetattr (STDIN_FILENO, TCSANOW, &t);
+
+ if (!password || pwbuf[0] == '\n')
+ return;
+ *strchr (pwbuf, '\n') = '\0';
+ }
+
+ soup_auth_authenticate (auth, user, password);
+ soup_auth_save_password (auth, user, password);
+}
+
+static void
usage (void)
{
fprintf (stderr, "Usage: get [-c CAfile] [-p proxy URL] [-h] [-d] URL\n");
g_thread_init (NULL);
g_type_init ();
+ g_set_application_name ("get");
method = SOUP_METHOD_GET;
SOUP_SESSION_SSL_CA_FILE, cafile,
#ifdef HAVE_GNOME
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_GNOME_FEATURES_2_26,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PASSWORD_MANAGER_GNOME,
#endif
SOUP_SESSION_USER_AGENT, "get ",
NULL);
SOUP_SESSION_SSL_CA_FILE, cafile,
#ifdef HAVE_GNOME
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_GNOME_FEATURES_2_26,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PASSWORD_MANAGER_GNOME,
#endif
SOUP_SESSION_USER_AGENT, "get ",
NULL);
}
+ g_signal_connect (session, "authenticate",
+ G_CALLBACK (authenticate), NULL);
/* Need to do this after creating the session, since adding
* SOUP_TYPE_GNOME_FEATURE_2_26 will add a proxy resolver, thereby