1563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/*
2563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Copyright (C) 2009 Igalia S.L.
3563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
4563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * This library is free software; you can redistribute it and/or
5563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * modify it under the terms of the GNU Library General Public
6563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * License as published by the Free Software Foundation; either
7563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * version 2 of the License, or (at your option) any later version.
8563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
9563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * This library is distributed in the hope that it will be useful,
10563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * but WITHOUT ANY WARRANTY; without even the implied warranty of
11563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Library General Public License for more details.
13563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark *
14563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * You should have received a copy of the GNU Library General Public License
15563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * along with this library; see the file COPYING.LIB.  If not, write to
16563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Boston, MA 02110-1301, USA.
18563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */
19563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
20563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "config.h"
21563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
22231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#define LIBSOUP_I_HAVE_READ_BUG_594377_AND_KNOW_SOUP_PASSWORD_MANAGER_MIGHT_GO_AWAY
23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <glib/gi18n-lib.h>
25563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <gtk/gtk.h>
26563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <libsoup/soup.h>
27563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
28ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block#include "GtkVersioning.h"
29563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "webkitmarshal.h"
30563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "webkitsoupauthdialog.h"
31563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch/**
330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * SECTION:webkitsoupauthdialog
34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * @short_description: A #SoupSessionFeature to provide a simple
350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * authentication dialog for HTTP basic auth support.
360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *
37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * #WebKitSoupAuthDialog is a #SoupSessionFeature that you can attach to your
38231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * #SoupSession to provide a simple authentication dialog while
39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * handling HTTP basic auth. It is built as a simple C-only module
40231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * to ease reuse.
410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch */
420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
43563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void webkit_soup_auth_dialog_session_feature_init(SoupSessionFeatureInterface* feature_interface, gpointer interface_data);
44563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void attach(SoupSessionFeature* manager, SoupSession* session);
45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void detach(SoupSessionFeature* manager, SoupSession* session);
46563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
47563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkenum {
48563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    CURRENT_TOPLEVEL,
49563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    LAST_SIGNAL
50563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark};
51563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
52563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic guint signals[LAST_SIGNAL] = { 0 };
53563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
54563af33bc48281d19dce701398dbb88cb54fd7ecCary ClarkG_DEFINE_TYPE_WITH_CODE(WebKitSoupAuthDialog, webkit_soup_auth_dialog, G_TYPE_OBJECT,
55563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                        G_IMPLEMENT_INTERFACE(SOUP_TYPE_SESSION_FEATURE,
56563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                                              webkit_soup_auth_dialog_session_feature_init))
57563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
58563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void webkit_soup_auth_dialog_class_init(WebKitSoupAuthDialogClass* klass)
59563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
60563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GObjectClass* object_class = G_OBJECT_CLASS(klass);
61563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
62a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    /**
63a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * WebKitSoupAuthDialog::current-toplevel:
64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * @authDialog: the object on which the signal is emitted
65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * @message: the #SoupMessage being used in the authentication process
66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     *
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * This signal is emitted by the @authDialog when it needs to know
68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * the current toplevel widget in order to correctly set the
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * transiency for the authentication dialog.
70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     *
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * Return value: (transfer none): the current toplevel #GtkWidget or %NULL if there's none
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     *
73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     * Since: 1.1.1
74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch     */
75563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    signals[CURRENT_TOPLEVEL] =
76563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark      g_signal_new("current-toplevel",
77563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   G_OBJECT_CLASS_TYPE(object_class),
78563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   G_SIGNAL_RUN_LAST,
79563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   G_STRUCT_OFFSET(WebKitSoupAuthDialogClass, current_toplevel),
80563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   NULL, NULL,
81563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   webkit_marshal_OBJECT__OBJECT,
82563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   GTK_TYPE_WIDGET, 1,
83563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                   SOUP_TYPE_MESSAGE);
84563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
85563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
86563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void webkit_soup_auth_dialog_init(WebKitSoupAuthDialog* instance)
87563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
88563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
89563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
90563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void webkit_soup_auth_dialog_session_feature_init(SoupSessionFeatureInterface *feature_interface,
91563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                                                         gpointer interface_data)
92563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
93563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    feature_interface->attach = attach;
94563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    feature_interface->detach = detach;
95563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
96563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
97563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarktypedef struct _WebKitAuthData {
98563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupMessage* msg;
99563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupAuth* auth;
100563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupSession* session;
101563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupSessionFeature* manager;
102563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* loginEntry;
103563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* passwordEntry;
104563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* checkButton;
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    char *username;
1060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    char *password;
107563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark} WebKitAuthData;
108563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
109563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void free_authData(WebKitAuthData* authData)
110563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
111563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_object_unref(authData->msg);
1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    g_free(authData->username);
1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    g_free(authData->password);
114563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_slice_free(WebKitAuthData, authData);
115563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
116563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
117231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#ifdef SOUP_TYPE_PASSWORD_MANAGER
1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic void save_password_callback(SoupMessage* msg, WebKitAuthData* authData)
119563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
120231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    /* Anything but 401 and 5xx means the password was accepted */
121231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (msg->status_code != 401 && msg->status_code < 500)
122231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        soup_auth_save_password(authData->auth, authData->username, authData->password);
123231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
124231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    /* Disconnect the callback. If the authentication succeeded we are
125231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block     * done, and if it failed we'll create a new authData and we'll
126231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block     * connect to 'got-headers' again in response_callback */
127231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    g_signal_handlers_disconnect_by_func(msg, save_password_callback, authData);
128231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    free_authData(authData);
1300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
131563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#endif
132563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic void response_callback(GtkDialog* dialog, gint response_id, WebKitAuthData* authData)
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
135231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    gboolean freeAuthData = TRUE;
136231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
137231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (response_id == GTK_RESPONSE_OK) {
1380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        authData->username = g_strdup(gtk_entry_get_text(GTK_ENTRY(authData->loginEntry)));
1390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        authData->password = g_strdup(gtk_entry_get_text(GTK_ENTRY(authData->passwordEntry)));
140231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        soup_auth_authenticate(authData->auth, authData->username, authData->password);
142563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
143231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#ifdef SOUP_TYPE_PASSWORD_MANAGER
144231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (authData->checkButton &&
145231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(authData->checkButton))) {
1460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            g_signal_connect(authData->msg, "got-headers", G_CALLBACK(save_password_callback), authData);
147231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            freeAuthData = FALSE;
148231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
149563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#endif
150563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    }
151563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
152563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    soup_session_unpause_message(authData->session, authData->msg);
153231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (freeAuthData)
154231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        free_authData(authData);
155563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_widget_destroy(GTK_WIDGET(dialog));
156563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
157563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
158563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic GtkWidget *
159231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktable_add_entry(GtkWidget*  table,
160231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                int         row,
161231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                const char* label_text,
162231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                const char* value,
163231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                gpointer    user_data)
164563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
165563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* entry;
166563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* label;
167563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
168563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    label = gtk_label_new(label_text);
169563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
170563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
171563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    entry = gtk_entry_new();
172563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
173563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
174563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (value)
175563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        gtk_entry_set_text(GTK_ENTRY(entry), value);
176563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
177563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_table_attach(GTK_TABLE(table), label,
178563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                     0, 1, row, row + 1,
179563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                     GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
180563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_table_attach_defaults(GTK_TABLE(table), entry,
181563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                              1, 2, row, row + 1);
182563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
183563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    return entry;
184563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
185563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
186231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic gboolean session_can_save_passwords(SoupSession* session)
187231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
188231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#ifdef SOUP_TYPE_PASSWORD_MANAGER
189231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return soup_session_get_feature(session, SOUP_TYPE_PASSWORD_MANAGER) != NULL;
190231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#else
191231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return FALSE;
192231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
193231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
194231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
195563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void show_auth_dialog(WebKitAuthData* authData, const char* login, const char* password)
196563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
197563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* toplevel;
198563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* widget;
199563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkDialog* dialog;
200563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWindow* window;
201563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* entryContainer;
202563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* hbox;
203563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* mainVBox;
204563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* vbox;
205563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* icon;
206563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* table;
207dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    GtkWidget* serverMessageDescriptionLabel;
208dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    GtkWidget* serverMessageLabel;
209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    GtkWidget* descriptionLabel;
210dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    char* description;
211dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const char* realm;
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    gboolean hasRealm;
213563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupURI* uri;
214563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* rememberBox;
215563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    GtkWidget* checkButton;
216563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
217563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* From GTK+ gtkmountoperation.c, modified and simplified. LGPL 2 license */
218563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
219563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    widget = gtk_dialog_new();
220563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    window = GTK_WINDOW(widget);
221563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    dialog = GTK_DIALOG(widget);
222563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
223563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_dialog_add_buttons(dialog,
224563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
225563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                           GTK_STOCK_OK, GTK_RESPONSE_OK,
226563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                           NULL);
227563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
228563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* Set the dialog up with HIG properties */
229231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
230ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(dialog)), 2); /* 2 * 5 + 2 = 12 */
231ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_action_area(dialog)), 5);
232ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_action_area(dialog)), 6);
233563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
234563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_window_set_resizable(window, FALSE);
235563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_window_set_title(window, "");
236563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_window_set_icon_name(window, GTK_STOCK_DIALOG_AUTHENTICATION);
237563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
238563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
239563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
240563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* Get the current toplevel */
241563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_signal_emit(authData->manager, signals[CURRENT_TOPLEVEL], 0, authData->msg, &toplevel);
242563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
243563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (toplevel)
244563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        gtk_window_set_transient_for(window, GTK_WINDOW(toplevel));
245563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
246563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* Build contents */
247563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    hbox = gtk_hbox_new(FALSE, 12);
248563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
249ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(dialog)), hbox, TRUE, TRUE, 0);
250563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
251563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION,
252563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                                    GTK_ICON_SIZE_DIALOG);
253563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
254563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0);
255563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
256563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
257563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    mainVBox = gtk_vbox_new(FALSE, 18);
258563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_box_pack_start(GTK_BOX(hbox), mainVBox, TRUE, TRUE, 0);
259563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
260563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    uri = soup_message_get_uri(authData->msg);
261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    description = g_strdup_printf(_("A username and password are being requested by the site %s"), uri->host);
262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    descriptionLabel = gtk_label_new(description);
263dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    g_free(description);
264dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0.0, 0.5);
265dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE);
266dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    gtk_box_pack_start(GTK_BOX(mainVBox), GTK_WIDGET(descriptionLabel),
267563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                       FALSE, FALSE, 0);
268563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
269563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    vbox = gtk_vbox_new(FALSE, 6);
270231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    gtk_box_pack_start(GTK_BOX(mainVBox), vbox, FALSE, FALSE, 0);
271563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
272563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* The table that holds the entries */
273563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    entryContainer = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
274563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
275563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_alignment_set_padding(GTK_ALIGNMENT(entryContainer),
276563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                              0, 0, 0, 0);
277563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
278563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_box_pack_start(GTK_BOX(vbox), entryContainer,
279563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                       FALSE, FALSE, 0);
280563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    realm = soup_auth_get_realm(authData->auth);
282dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Checking that realm is not an empty string
283dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    hasRealm = (realm && (strlen(realm) > 0));
284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    table = gtk_table_new(hasRealm ? 3 : 2, 2, FALSE);
286231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    gtk_table_set_col_spacings(GTK_TABLE(table), 12);
287231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    gtk_table_set_row_spacings(GTK_TABLE(table), 6);
288563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_container_add(GTK_CONTAINER(entryContainer), table);
289563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
290dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (hasRealm) {
291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        serverMessageDescriptionLabel = gtk_label_new(_("Server message:"));
292dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        serverMessageLabel = gtk_label_new(realm);
293dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_misc_set_alignment(GTK_MISC(serverMessageDescriptionLabel), 0.0, 0.5);
294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_label_set_line_wrap(GTK_LABEL(serverMessageDescriptionLabel), TRUE);
295dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_misc_set_alignment(GTK_MISC(serverMessageLabel), 0.0, 0.5);
296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_label_set_line_wrap(GTK_LABEL(serverMessageLabel), TRUE);
297dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
298dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_table_attach_defaults(GTK_TABLE(table), serverMessageDescriptionLabel,
299dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                  0, 1, 0, 1);
300dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        gtk_table_attach_defaults(GTK_TABLE(table), serverMessageLabel,
301dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                  1, 2, 0, 1);
302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
303dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
304dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    authData->loginEntry = table_add_entry(table, hasRealm ? 1 : 0, _("Username:"),
305563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                                           login, NULL);
306dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    authData->passwordEntry = table_add_entry(table, hasRealm ? 2 : 1, _("Password:"),
307563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark                                              password, NULL);
308563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
309563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_entry_set_visibility(GTK_ENTRY(authData->passwordEntry), FALSE);
310563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (session_can_save_passwords(authData->session)) {
312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        rememberBox = gtk_vbox_new(FALSE, 6);
313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        gtk_box_pack_start(GTK_BOX(vbox), rememberBox,
314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                           FALSE, FALSE, 0);
315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        checkButton = gtk_check_button_new_with_mnemonic(_("_Remember password"));
316231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (login && password)
317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkButton), TRUE);
318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        gtk_label_set_line_wrap(GTK_LABEL(gtk_bin_get_child(GTK_BIN(checkButton))), TRUE);
319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        gtk_box_pack_start(GTK_BOX(rememberBox), checkButton, FALSE, FALSE, 0);
320231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        authData->checkButton = checkButton;
321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
322563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
323563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_signal_connect(dialog, "response", G_CALLBACK(response_callback), authData);
324563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    gtk_widget_show_all(widget);
325563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
326563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
327563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void session_authenticate(SoupSession* session, SoupMessage* msg, SoupAuth* auth, gboolean retrying, gpointer user_data)
328563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
329563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupURI* uri;
330563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    WebKitAuthData* authData;
331563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    SoupSessionFeature* manager = (SoupSessionFeature*)user_data;
332231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#ifdef SOUP_TYPE_PASSWORD_MANAGER
333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    GSList* users;
334231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
335231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    const char *login, *password;
336563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
337563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    soup_session_pause_message(session, msg);
338563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    /* We need to make sure the message sticks around when pausing it */
339563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_object_ref(msg);
340563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
341563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    uri = soup_message_get_uri(msg);
342231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    authData = g_slice_new0(WebKitAuthData);
343563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    authData->msg = msg;
344563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    authData->auth = auth;
345563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    authData->session = session;
346563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    authData->manager = manager;
347563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
348231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    login = password = NULL;
349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#ifdef SOUP_TYPE_PASSWORD_MANAGER
351231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    users = soup_auth_get_saved_users(auth);
352231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (users) {
353231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        login = users->data;
354231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        password = soup_auth_get_saved_password(auth, login);
355231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        g_slist_free(users);
356231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
357563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#endif
358231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
359231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    show_auth_dialog(authData, login, password);
360563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
361563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
362563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void attach(SoupSessionFeature* manager, SoupSession* session)
363563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
364563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_signal_connect(session, "authenticate", G_CALLBACK(session_authenticate), manager);
365563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
366563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
367563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic void detach(SoupSessionFeature* manager, SoupSession* session)
368563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{
369563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    g_signal_handlers_disconnect_by_func(session, session_authenticate, manager);
370563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark}
371563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
372563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark
373