#include <libsoup/soup.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
struct _KatzeHttpAuth
{
GObject parent_instance;
+ gchar* filename;
+ GHashTable* logins;
};
struct _KatzeHttpAuthClass
GObjectClass parent_class;
};
+typedef struct
+{
+ KatzeHttpAuth* http_auth;
+ SoupAuth* auth;
+ gchar* username;
+ gchar* password;
+} KatzeHttpAuthSave;
+
+typedef struct
+{
+ gchar* username;
+ gchar* password;
+} KatzeHttpAuthLogin;
+
static void
katze_http_auth_session_feature_iface_init (SoupSessionFeatureInterface *iface,
gpointer data);
G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
katze_http_auth_session_feature_iface_init));
-#ifdef HAVE_LIBSOUP_2_27_91
+enum
+{
+ PROP_0,
+
+ PROP_FILENAME
+};
+
+static void
+katze_http_auth_set_property (GObject* object,
+ guint prop_id,
+ const GValue* value,
+ GParamSpec* pspec);
+
+static void
+katze_http_auth_get_property (GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec);
+
static void
-authentication_message_got_headers_cb (SoupMessage* msg,
- SoupAuth* auth)
+katze_http_auth_finalize (GObject* object);
+
+static gchar*
+katze_http_auth_soup_auth_get_hash (SoupAuth* auth)
+{
+ return g_strdup_printf ("%s:%s:%s",
+ soup_auth_get_host (auth),
+ soup_auth_get_scheme_name (auth),
+ soup_auth_get_realm (auth));
+}
+
+static void
+authentication_message_got_headers_cb (SoupMessage* msg,
+ KatzeHttpAuthSave* save)
{
/* Anything but 401 and 5xx means the password was accepted */
if (msg->status_code != 401 && msg->status_code < 500)
{
- gchar* username = g_object_get_data (G_OBJECT (msg), "username");
- gchar* password = g_object_get_data (G_OBJECT (msg), "password");
- soup_auth_save_password (auth, username, password);
+ gchar* opaque_info;
+ FILE* file;
+
+ opaque_info = katze_http_auth_soup_auth_get_hash (save->auth);
+
+ if (!g_hash_table_lookup (save->http_auth->logins, opaque_info))
+ {
+ KatzeHttpAuthLogin* login;
+ login = g_new (KatzeHttpAuthLogin, 1);
+ login->username = save->username;
+ login->password = save->password;
+ g_hash_table_insert (save->http_auth->logins, opaque_info, login);
+
+ if ((file = g_fopen (save->http_auth->filename, "a")))
+ {
+ fprintf (file, "%s\t%s\t%s\n", opaque_info,
+ login->username, login->password);
+ fclose (file);
+ }
+ }
+ else
+ {
+ /* FIXME g_free (save->username);
+ g_free (save->password); */
+ }
+ }
+ else
+ {
+ /* FIXME g_free (save->username);
+ g_free (save->password); */
}
+
+ /* FIXME g_object_unref (save->auth); */
+ /* FIXME g_free (save); */
+ g_signal_handlers_disconnect_by_func (msg,
+ authentication_message_got_headers_cb, save);
}
-#endif
static void
-authentication_dialog_response_cb (GtkWidget* dialog,
- gint response,
- SoupAuth* auth)
+authentication_dialog_response_cb (GtkWidget* dialog,
+ gint response,
+ KatzeHttpAuthSave* save)
{
- GtkWidget* username;
- GtkWidget* password;
SoupSession* session;
SoupMessage* msg;
if (response == GTK_RESPONSE_OK)
{
+ GtkEntry* username = g_object_get_data (G_OBJECT (dialog), "username");
+ GtkEntry* password = g_object_get_data (G_OBJECT (dialog), "password");
+
+ soup_auth_authenticate (save->auth,
+ gtk_entry_get_text (username), gtk_entry_get_text (password));
- username = g_object_get_data (G_OBJECT (dialog), "username");
- password = g_object_get_data (G_OBJECT (dialog), "password");
-
- soup_auth_authenticate (auth,
- gtk_entry_get_text (GTK_ENTRY (username)),
- gtk_entry_get_text (GTK_ENTRY (password)));
- #ifdef HAVE_LIBSOUP_2_27_91
- g_object_set_data_full (G_OBJECT (msg), "username",
- g_strdup (gtk_entry_get_text (GTK_ENTRY (username))), g_free);
- g_object_set_data_full (G_OBJECT (msg), "password",
- g_strdup (gtk_entry_get_text (GTK_ENTRY (password))), g_free);
- g_signal_connect (msg, "got-headers",
- G_CALLBACK (authentication_message_got_headers_cb), auth);
- #endif
+ if (save->http_auth->filename)
+ {
+ save->username = g_strdup (gtk_entry_get_text (username));
+ save->password = g_strdup (gtk_entry_get_text (password));
+ g_signal_connect (msg, "got-headers",
+ G_CALLBACK (authentication_message_got_headers_cb), save);
+ }
+ else
+ {
+ g_object_unref (save->auth);
+ g_free (save);
+ }
}
session = g_object_get_data (G_OBJECT (dialog), "session");
- gtk_widget_destroy (dialog);
if (g_object_get_data (G_OBJECT (msg), "paused"))
soup_session_unpause_message (session, msg);
- g_object_unref (auth);
+ gtk_widget_destroy (dialog);
+ g_object_unref (msg);
}
static void
-katze_http_auth_session_authenticate_cb (SoupSession* session,
- SoupMessage* msg,
- SoupAuth* auth,
- gboolean retrying)
+katze_http_auth_session_authenticate_cb (SoupSession* session,
+ SoupMessage* msg,
+ SoupAuth* auth,
+ gboolean retrying,
+ KatzeHttpAuth* http_auth)
{
+ gchar* opaque_info;
+ KatzeHttpAuthLogin* login;
GtkWidget* dialog;
GtkSizeGroup* sizegroup;
GtkWidget* hbox;
GtkWidget* label;
GtkWidget* align;
GtkWidget* entry;
- #ifdef HAVE_LIBSOUP_2_27_91
- GSList* users;
- #endif
+ KatzeHttpAuthSave* save;
/* We want to ask for authentication exactly once, so we
enforce this with a tag. There might be a better way. */
if (!retrying && g_object_get_data (G_OBJECT (msg), "katze-session-tag"))
return;
- if (soup_message_is_keepalive (msg))
+ if (1)
{
/* We use another tag to indicate whether a message is paused.
There doesn't seem to be API in libSoup to find that out. */
- soup_session_pause_message (session, msg);
+ soup_session_pause_message (session, g_object_ref (msg));
g_object_set_data (G_OBJECT (msg), "paused", (void*)1);
}
g_object_set_data (G_OBJECT (msg), "katze-session-tag", (void*)1);
+ opaque_info = katze_http_auth_soup_auth_get_hash (auth);
+ login = g_hash_table_lookup (http_auth->logins, opaque_info);
+ g_free (opaque_info);
+
dialog = gtk_dialog_new_with_buttons (_("Authentication Required"),
NULL,
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
gtk_size_group_add_widget (sizegroup, align);
gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
entry = gtk_entry_new ();
- #ifdef HAVE_LIBSOUP_2_27_91
- users = soup_auth_get_saved_users (auth);
- if (users)
- gtk_entry_set_text (GTK_ENTRY (entry), users->data);
- #endif
+ if (login)
+ gtk_entry_set_text (GTK_ENTRY (entry), login->username);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
g_object_set_data (G_OBJECT (dialog), "username", entry);
gtk_size_group_add_widget (sizegroup, align);
gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
entry = gtk_entry_new_with_max_length (32);
- #ifdef HAVE_LIBSOUP_2_27_91
- if (users)
- {
- gtk_entry_set_text (GTK_ENTRY (entry),
- soup_auth_get_saved_password (auth, users->data));
- g_slist_free (users);
- }
- #endif
+ if (login)
+ gtk_entry_set_text (GTK_ENTRY (entry), login->password);
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
g_object_set_data (G_OBJECT (dialog), "session", session);
g_object_set_data (G_OBJECT (dialog), "msg", msg);
+
+ save = g_new (KatzeHttpAuthSave, 1);
+ save->http_auth = http_auth;
+ save->auth = g_object_ref (auth);
g_signal_connect (dialog, "response",
- G_CALLBACK (authentication_dialog_response_cb), g_object_ref (auth));
+ G_CALLBACK (authentication_dialog_response_cb), save);
gtk_widget_show (dialog);
}
static void
-katze_http_auth_session_request_queued_cb (SoupSession* session,
- SoupMessage* msg,
- gpointer data)
+katze_http_auth_session_request_queued_cb (SoupSession* session,
+ SoupMessage* msg,
+ KatzeHttpAuth* http_auth)
{
/* WebKit has its own authentication dialog in recent versions.
We want only one, and we choose our own to have localization. */
soup_session_remove_feature_by_type (session, type);
g_signal_connect (session, "authenticate",
- G_CALLBACK (katze_http_auth_session_authenticate_cb), NULL);
+ G_CALLBACK (katze_http_auth_session_authenticate_cb), http_auth);
g_signal_handlers_disconnect_by_func (session,
katze_http_auth_session_request_queued_cb, NULL);
}
SoupSession* session)
{
g_signal_connect (session, "request-queued",
- G_CALLBACK (katze_http_auth_session_request_queued_cb), NULL);
+ G_CALLBACK (katze_http_auth_session_request_queued_cb), feature);
}
static void
static void
katze_http_auth_class_init (KatzeHttpAuthClass* class)
{
- /* Nothing to do. */
+ GObjectClass* gobject_class;
+ GParamFlags flags;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = katze_http_auth_finalize;
+ gobject_class->set_property = katze_http_auth_set_property;
+ gobject_class->get_property = katze_http_auth_get_property;
+
+ flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+ /**
+ * KatzeHttpAuth:filename:
+ *
+ * An absolute path and name of a file for storing logins.
+ *
+ * Since: 0.1.10
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_FILENAME,
+ g_param_spec_string (
+ "filename",
+ "Filename",
+ "An absolute path and name of a file for storing logins",
+ NULL,
+ flags));
+}
+
+static void
+katze_http_auth_login_free (KatzeHttpAuthLogin* login)
+{
+ g_free (login->username);
+ g_free (login->password);
+ g_free (login);
+}
+
+static void
+katze_http_auth_set_filename (KatzeHttpAuth* http_auth,
+ const gchar* filename)
+{
+ FILE* file;
+
+ katze_assign (http_auth->filename, g_strdup (filename));
+
+ g_hash_table_remove_all (http_auth->logins);
+
+ if ((file = g_fopen (filename, "r")))
+ {
+ gchar line[255];
+ guint number = 0;
+
+ while (fgets (line, 255, file))
+ {
+ gchar** parts = g_strsplit (line, "\t", 3);
+ if (parts && parts[0] && parts[1] && parts[2])
+ {
+ KatzeHttpAuthLogin* login;
+ gint length;
+
+ login = g_new (KatzeHttpAuthLogin, 1);
+ login->username = parts[1];
+ length = strlen (parts[2]);
+ if (parts[2][length - 1] == '\n')
+ length--;
+ login->password = g_strndup (parts[2], length);
+ g_hash_table_insert (http_auth->logins, parts[0], login);
+ g_free (parts);
+ }
+ else
+ {
+ g_strfreev (parts);
+ g_warning ("Error in line %d in HTTP Auth file", number);
+ }
+ number++;
+ }
+ fclose (file);
+ }
}
static void
katze_http_auth_init (KatzeHttpAuth* http_auth)
{
- /* Nothing to do. */
+ http_auth->filename = NULL;
+
+ http_auth->logins = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free, (GDestroyNotify)katze_http_auth_login_free);
+}
+
+static void
+katze_http_auth_finalize (GObject* object)
+{
+ KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+ g_free (http_auth->filename);
+
+ g_hash_table_unref (http_auth->logins);
+
+ G_OBJECT_CLASS (katze_http_auth_parent_class)->finalize (object);
+}
+
+static void
+katze_http_auth_set_property (GObject* object,
+ guint prop_id,
+ const GValue* value,
+ GParamSpec* pspec)
+{
+ KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ katze_http_auth_set_filename (http_auth, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+katze_http_auth_get_property (GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec)
+{
+ KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ g_value_set_string (value, http_auth->filename);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}