diff options
author | Jorge Arellano Cid <jcid@dillo.org> | 2008-12-20 17:19:27 -0300 |
---|---|---|
committer | Jorge Arellano Cid <jcid@dillo.org> | 2008-12-20 17:19:27 -0300 |
commit | 9b532026d3fc5c379827351c4da8b219012cb1c7 (patch) | |
tree | 87880cdd0fe5b27745b68002e7c308367b3bb87e /src | |
parent | 2950e1945283baeffea46480d14f32e21b294a44 (diff) |
Added basic authentication!
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/http.c | 14 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/auth.c | 514 | ||||
-rw-r--r-- | src/auth.h | 19 | ||||
-rw-r--r-- | src/bw.h | 1 | ||||
-rw-r--r-- | src/cache.c | 67 | ||||
-rw-r--r-- | src/dialog.cc | 79 | ||||
-rw-r--r-- | src/dialog.hh | 4 | ||||
-rw-r--r-- | src/dillo.cc | 2 |
9 files changed, 697 insertions, 5 deletions
diff --git a/src/IO/http.c b/src/IO/http.c index 2c50e829..9deb961a 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -33,6 +33,7 @@ #include "../dns.h" #include "../web.hh" #include "../cookies.h" +#include "../auth.h" #include "../prefs.h" #include "../misc.h" @@ -196,7 +197,7 @@ Dstr *Http_make_content_type(const DilloUrl *url) */ Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) { - char *ptr, *cookies, *referer; + char *ptr, *cookies, *auth, *referer; Dstr *query = dStr_new(""), *full_path = dStr_new(""), *proxy_auth = dStr_new(""); @@ -219,6 +220,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) } cookies = a_Cookies_get_query(url); + auth = a_Auth_get_auth_str(url); referer = Http_get_referer(url); if (URL_FLAGS(url) & URL_Post) { Dstr *content_type = Http_make_content_type(url); @@ -228,15 +230,16 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) "Connection: close\r\n" "Accept-Charset: utf-8,*;q=0.8\r\n" "Accept-Encoding: gzip\r\n" + "%s" /* auth */ "Host: %s\r\n" "%s" "%s" "User-Agent: Dillo/%s\r\n" "Content-Length: %ld\r\n" "Content-Type: %s\r\n" - "%s" + "%s" /* cookies */ "\r\n", - full_path->str, URL_AUTHORITY(url), + full_path->str, auth ? auth : "", URL_AUTHORITY(url), proxy_auth->str, referer, VERSION, URL_DATA(url)->len, content_type->str, cookies); @@ -250,16 +253,17 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) "Connection: close\r\n" "Accept-Charset: utf-8,*;q=0.8\r\n" "Accept-Encoding: gzip\r\n" + "%s" /* auth */ "Host: %s\r\n" "%s" "%s" "User-Agent: Dillo/%s\r\n" - "%s" + "%s" /* cookies */ "\r\n", full_path->str, (URL_FLAGS(url) & URL_E2EQuery) ? "Cache-Control: no-cache\r\nPragma: no-cache\r\n" : "", - URL_AUTHORITY(url), + auth ? auth : "", URL_AUTHORITY(url), proxy_auth->str, referer, VERSION, cookies); } dFree(referer); diff --git a/src/Makefile.am b/src/Makefile.am index d4d03eea..8da631ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,8 @@ dillo_SOURCES = \ bw.c \ cookies.c \ cookies.h \ + auth.c \ + auth.h \ colors.c \ colors.h \ binaryconst.h \ diff --git a/src/auth.c b/src/auth.c new file mode 100644 index 00000000..81e97188 --- /dev/null +++ b/src/auth.c @@ -0,0 +1,514 @@ +/* + * File: auth.c + * + * Copyright 2008 Jeremy Henty <onepoint@starurchin.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + */ + +/* Handling of HTTP AUTH takes place here. + * This implementation aims to follow RFC 2617: + * http://www.ietf.org/rfc/rfc2617.txt + */ + + +#include <ctype.h> /* for parsing */ +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "auth.h" +#include "msg.h" +#include "misc.h" +#include "dialog.hh" +#include "IO/Url.h" +#include "../dlib/dlib.h" + + +typedef struct { + int ok; + const char *realm; +} AuthParse_t; + +typedef struct { + char *name; + Dlist *paths; /* stripped of any trailing '/', so the root path is "" */ + char *authorization; /* the authorization request header */ +} AuthRealm_t; + +typedef struct { + char *scheme; + char *authority; + Dlist *realms; +} AuthHost_t; + +typedef struct { + const char *realm_name; + const DilloUrl *url; +} AuthDialogData_t; + +/* + * Local data + */ +static Dlist *auth_hosts; + +/* + * Initialize the auth module. + */ +void a_Auth_init(void) +{ + auth_hosts = dList_new(1); +} + +static AuthParse_t *Auth_parse_new() +{ + AuthParse_t *auth_parse = dNew(AuthParse_t, 1); + auth_parse->ok = 0; + auth_parse->realm = NULL; + return auth_parse; +} + +static void Auth_parse_free(AuthParse_t *auth_parse) +{ + if (auth_parse) { + dFree((void *) auth_parse->realm); + } +} + +static int Auth_path_is_inside(const char *path1, const char *path2, int len) +{ + /* + * path2 is effectively truncated to length len. Typically len will be + * strlen(path2), or 1 less when we want to ignore a trailing '/'. + */ + return + strncmp(path1, path2, len) == 0 && + (path1[len] == '\0' || path1[len] == '/'); +} + +/* + * Check valid chars. + * Return: 0 if invalid, 1 otherwise. + */ +static int Auth_is_token_char(char c) +{ + const char *invalid = "\"()<>@,;:\\[]¿?=/{} \t"; + return (strchr(invalid, c) || iscntrl(c)) ? 0 : 1; +} + +static void Auth_parse_auth_basic(AuthParse_t *auth_parse, char *auth) +{ + int token_value_pairs_found; + char *realm = NULL; + static const char realm_token[] = "realm"; + + /* parse comma-separated token-value pairs */ + token_value_pairs_found = 0; + while (1) { + char *token, *value; + int token_size, value_size; + + /* skip host and comma characters */ + while (*auth == ' ' || *auth == ',') + auth++; + + /* end of string? */ + if (!*auth) + goto end_parse; + + /* parse a token */ + token = auth; + token_size = 0; + while (Auth_is_token_char(*auth)) { + auth++; + token_size++; + } + if (token_size == 0) { + MSG("auth.c: Auth_parse_auth_basic: " + "missing Basic auth token\n"); + goto end_parse; + } + + /* skip space characters */ + while (*auth == ' ') + auth++; + + /* parse the '=' */ + switch (*auth++) { + case '=': + break; + case '\0': + case ',': + MSG("auth.c: Auth_parse_auth_basic: " + "missing Basic auth token value\n"); + goto end_parse; + break; + default: + MSG("auth.c: Auth_parse_auth_basic: " + "garbage after Basic auth token\n"); + goto end_parse; + break; + } + + /* skip space characters */ + while (*auth == ' ') + auth++; + + /* parse a quoted string */ + + /* parse a '"' */ + switch (*auth++) { + case '"': + break; + case '\0': + case ',': + MSG("auth.c: Auth_parse_auth_basic: " + "missing Basic auth token value after '='\n"); + goto end_parse; + break; + default: + MSG("auth.c: Auth_parse_auth_basic: " + "garbage in Basic auth after '='\n"); + goto end_parse; + break; + } + + /* parse the rest of a quoted string */ + value = auth; + value_size = 0; + while (1) { + switch (*auth++) { + case '"': + goto end_quoted_string; + break; + case '\0': + MSG("auth.c: Auth_parse_auth_basic: " + "auth string ended inside quoted string value\n"); + goto end_parse; + break; + case '\\': + /* end of string? */ + if (!*auth++) { + MSG("auth.c: Auth_parse_auth_basic: " + "auth string ended inside quoted string value " + "immediately after \\\n"); + goto end_parse; + } + /* fall through to the next case */ + default: + value_size++; + break; + } + } /* parse quoted string */ + end_quoted_string: + + token_value_pairs_found = 1; + + if (realm == NULL && + strncasecmp(realm_token,token,token_size) == 0 && + strlen(realm_token) == token_size) { + /* unquote and save the value */ + char c, *value_ptr, *realm_ptr; + realm = dNew(char, value_size + 1); + value_ptr = value; + realm_ptr = realm; + while ((c = *value_ptr++) != '"') + *realm_ptr++ = (c == '\\') ? *value_ptr++ : c; + *realm_ptr = '\0'; + auth_parse->ok = 1; + auth_parse->realm = realm; + _MSG("auth.c: Auth_parse_auth_basic: realm: '%s'\n", realm); + return; + } + } + end_parse: + + if (!token_value_pairs_found) { + MSG("auth.c: Auth_parse_auth_basic: " + "missing Basic auth token-value pairs\n"); + return; + } + + if (!realm) { + MSG("auth.c: Auth_parse_auth_basic: " + "missing Basic auth realm\n"); + return; + } +} + +static void Auth_parse_auth(AuthParse_t *auth_parse, char *auth) +{ + _MSG("auth.c: Auth_parse_auth: auth = '%s'\n", auth); + if (strncasecmp(auth, "Basic ", 6) == 0) { + Auth_parse_auth_basic(auth_parse, auth + 6); + } else { + MSG("auth.c: Auth_parse_auth: " + "unknown authorization scheme: auth = {%s}\n", + auth); + } +} + +/* + * Return the host that contains a URL, or NULL if there is no such host. + */ +static AuthHost_t *Auth_host_by_url(const DilloUrl *url) +{ + AuthHost_t *host; + int i; + + for (i = 0; (host = dList_nth_data(auth_hosts, i)); i++) + if (((dStrcasecmp(URL_SCHEME(url), host->scheme) == 0) && + (dStrcasecmp(URL_AUTHORITY(url), host->authority) == 0))) + return host; + + return NULL; +} + +/* + * Search all realms for the one with the given name. + */ +static AuthRealm_t *Auth_realm_by_name(const AuthHost_t *host, + const char *name) +{ + AuthRealm_t *realm; + int i; + + for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) + if (strcmp(realm->name,name) == 0) + return realm; + + return NULL; +} + +/* + * Search all realms for the one with the best-matching path. + */ +static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host, + const char *path) +{ + AuthRealm_t *realm_best, *realm; + int i, j; + int match_length; + + realm_best = NULL; + for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) { + char *realm_path; + + for (j = 0; (realm_path = dList_nth_data(realm->paths, j)); j++) { + int realm_path_length; + + realm_path_length = strlen(realm_path); + if (Auth_path_is_inside(path, realm_path, realm_path_length) && + !(realm_best && match_length >= realm_path_length)) { + realm_best = realm; + match_length = realm_path_length; + } + } /* for (j = 0; (path = ... */ + } /* for (i = 0; (realm = ... */ + + return realm_best; +} + +static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path) +{ + int i; + char *realm_path; + + for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++) + if (Auth_path_is_inside(path, realm_path, strlen(realm_path))) + return 1; + + return 0; +} + +static void Auth_realm_add_path(AuthRealm_t *realm, const char *path) +{ + int len, i; + char *realm_path, *n_path; + + n_path = strdup(path); + len = strlen(n_path); + + /* remove trailing '/' */ + if (len && n_path[len - 1] == '/') + n_path[--len] = 0; + + /* delete existing paths that are inside the new one */ + for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++) { + if (Auth_path_is_inside(realm_path, path, len)) { + dList_remove_fast(realm->paths, realm_path); + dFree(realm_path); + i--; /* reconsider this slot */ + } + } + + dList_append(realm->paths, n_path); +} + +/* + * Return the authorization header for an HTTP query. + */ +char *a_Auth_get_auth_str(const DilloUrl *url) +{ + AuthHost_t *host; + AuthRealm_t *realm; + + return + ((host = Auth_host_by_url(url)) && + (realm = Auth_realm_by_path(host, URL_PATH(url)))) ? + realm->authorization : NULL; +} + +/* + * Determine whether the user needs to authenticate. + */ +static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url) +{ + /* + * TO DO: I dislike the way that this code must decide whether we + * sent authentication during the request and trust us to resend it + * after the reload. Could it be more robust if every DilloUrl + * recorded its authentication, and whether it was accepted? (JCH) + */ + + AuthHost_t *host; + AuthRealm_t *realm; + + /* + * The size of the following comments reflects the concerns in the + * TO DO at the top of this function. It should not be so hard to + * explain why code is correct! (JCH) + */ + + /* + * If we have authentication but did not send it (because we did + * not know this path was in the realm) then we update the realm. + * We do not re-authenticate because our authentication is probably + * OK. Thanks to the updated realm the forthcoming reload will + * make us send the authentication. If our authentication is not + * OK the server will challenge us again after the reload and then + * we will re-authenticate. + */ + if ((host = Auth_host_by_url(url)) && + (realm = Auth_realm_by_name(host, realm_name)) && + (!Auth_realm_includes_path(realm, URL_PATH(url)))) { + _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n", + realm_name, URL_STR(url)); + Auth_realm_add_path(realm, URL_PATH(url)); + return 0; + } + + /* + * Either we had no authentication or we sent it and the server + * rejected it, so we must re-authenticate. + */ + return 1; +} + +static void Auth_do_auth_dialog_cb(const char *user, const char *password, + void *vData) +{ + AuthDialogData_t *data; + AuthHost_t *host; + AuthRealm_t *realm; + char *user_password, *response, *authorization, *authorization_old; + + data = (AuthDialogData_t *)vData; + + /* find or create the host */ + if (!(host = Auth_host_by_url(data->url))) { + /* create a new host */ + host = dNew(AuthHost_t, 1); + host->scheme = dStrdup(URL_SCHEME(data->url)); + host->authority = dStrdup(URL_AUTHORITY(data->url)); + host->realms = dList_new(1); + dList_append(auth_hosts, host); + } + + /* find or create the realm */ + if (!(realm = Auth_realm_by_name(host, data->realm_name))) { + /* create a new realm */ + realm = dNew(AuthRealm_t, 1); + realm->name = dStrdup(data->realm_name); + realm->paths = dList_new(1); + realm->authorization = NULL; + dList_append(host->realms, realm); + } + + Auth_realm_add_path(realm, URL_PATH(data->url)); + + /* create and set the authorization */ + user_password = dStrconcat(user, ":", password, NULL); + response = a_Misc_encode_base64(user_password); + authorization = + dStrconcat("Authorization: Basic ", response, "\r\n", NULL); + authorization_old = realm->authorization; + realm->authorization = authorization; + dFree(authorization_old); + dFree(user_password); + dFree(response); +} + +static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url) +{ + int ret; + char *message; + AuthDialogData_t *data; + + _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", realm); + message = dStrconcat("Enter a user and password for \"", + realm, "\".", NULL); + data = dNew(AuthDialogData_t, 1); + data->realm_name = dStrdup(realm); + data->url = a_Url_dup(url); + ret = a_Dialog_user_password(message, Auth_do_auth_dialog_cb, data); + dFree(message); + dFree((void*)data->realm_name); + a_Url_free((void*)data->url); + dFree(data); + return ret; +} + +/* + * Do authorization for an auth string. + */ +static int Auth_do_auth(char *auth, const DilloUrl *url) +{ + int reload; + AuthParse_t *auth_parse; + + _MSG("auth.c: Auth_do_auth: auth={%s}\n", auth); + reload = 0; + auth_parse = Auth_parse_new(); + Auth_parse_auth(auth_parse, auth); + if (auth_parse->ok) + reload = + Auth_do_auth_required(auth_parse->realm, url) ? + Auth_do_auth_dialog(auth_parse->realm, url) + : 1; + Auth_parse_free(auth_parse); + + return reload; +} + +/* + * Do authorization for a set of auth strings. + */ +int a_Auth_do_auth(Dlist *auths, const DilloUrl *url) +{ + int reload, i; + char *auth; + + reload = 0; + for (i = 0; (auth = dList_nth_data(auths, i)); ++i) + if (Auth_do_auth(auth, url)) + reload = 1; + + return reload; +} + diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 00000000..8813fc37 --- /dev/null +++ b/src/auth.h @@ -0,0 +1,19 @@ +#ifndef __AUTH_H__ +#define __AUTH_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "url.h" + + +char *a_Auth_get_auth_str(const DilloUrl *request_url); +int a_Auth_do_auth(Dlist *auth_string, const DilloUrl *url); +void a_Auth_init(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* !__AUTH_H__ */ @@ -84,6 +84,7 @@ void a_Bw_remove_doc(BrowserWindow *bw, void *vdoc); void a_Bw_add_url(BrowserWindow *bw, const DilloUrl *Url); void a_Bw_cleanup(BrowserWindow *bw); +typedef void (*BwCallback_t)(BrowserWindow *bw, const void *data); #ifdef __cplusplus } diff --git a/src/cache.c b/src/cache.c index a6342da1..831ad411 100644 --- a/src/cache.c +++ b/src/cache.c @@ -32,6 +32,7 @@ #include "misc.h" #include "capi.h" #include "decode.h" +#include "auth.h" #include "timeout.hh" #include "uicmd.hh" @@ -54,6 +55,7 @@ typedef struct { char *TypeMeta; /* MIME type string from META HTTP-EQUIV */ Dstr *Header; /* HTTP header */ const DilloUrl *Location; /* New URI for redirects */ + Dlist *Auth; /* Authentication fields */ Dstr *Data; /* Pointer to raw data */ Dstr *UTF8Data; /* Data after charset translation */ int DataRefcount; /* Reference count */ @@ -87,6 +89,7 @@ static uint_t DelayedQueueIdleId = 0; */ static void Cache_process_queue(CacheEntry_t *entry); static void Cache_delayed_process_queue(CacheEntry_t *entry); +static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw); /* @@ -206,6 +209,7 @@ static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url) NewEntry->TypeMeta = NULL; NewEntry->Header = dStr_new(""); NewEntry->Location = NULL; + NewEntry->Auth = NULL; NewEntry->Data = dStr_sized_new(8*1024); NewEntry->UTF8Data = NULL; NewEntry->DataRefcount = 0; @@ -288,6 +292,18 @@ void a_Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds) } /* + * Free Authentication fields. + */ +static void Cache_auth_free(Dlist *auth) +{ + int i; + void *auth_field; + for (i = 0; (auth_field = dList_nth_data(auth, i)); ++i) + dFree(auth_field); + dList_free(auth); +} + +/* * Free the components of a CacheEntry_t struct. */ static void Cache_entry_free(CacheEntry_t *entry) @@ -298,6 +314,7 @@ static void Cache_entry_free(CacheEntry_t *entry) dFree(entry->TypeMeta); dStr_free(entry->Header, TRUE); a_Url_free((DilloUrl *)entry->Location); + Cache_auth_free(entry->Auth); dStr_free(entry->Data, 1); dStr_free(entry->UTF8Data, 1); if (entry->CharsetDecoder) @@ -655,6 +672,9 @@ static void Cache_parse_header(CacheEntry_t *entry) } dFree(location_str); + } else if (strncmp(header + 9, "401", 3) == 0) { + entry->Auth = + Cache_parse_multiple_fields(header, "WWW-Authenticate"); } else if (strncmp(header + 9, "404", 3) == 0) { entry->Flags |= CA_NotFound; } @@ -927,6 +947,50 @@ static int Cache_redirect(CacheEntry_t *entry, int Flags, BrowserWindow *bw) return 0; } +typedef struct { + Dlist *auth; + DilloUrl *url; + BrowserWindow *bw; +} CacheAuthData_t; + +/* + * Ask for user/password and reload the page. + */ +static void Cache_auth_callback(void *vdata) +{ + CacheAuthData_t *data = (CacheAuthData_t *)vdata; + if (a_Auth_do_auth(data->auth, data->url)) + a_Nav_reload(data->bw); + Cache_auth_free(data->auth); + a_Url_free(data->url); + dFree(data); + Cache_auth_entry(NULL, NULL); + a_Timeout_remove(); +} + +/* + * Set a timeout function to ask for user/password. + */ +static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw) +{ + static int busy = 0; + CacheAuthData_t *data; + + if (!entry) { + busy = 0; + } else if (busy) { + MSG_WARN("Cache_auth_entry: caught busy!\n"); + } else if (entry->Auth) { + busy = 1; + data = dNew(CacheAuthData_t, 1); + data->auth = entry->Auth; + data->url = a_Url_dup(entry->Url); + data->bw = bw; + entry->Auth = NULL; + a_Timeout_add(0.0, Cache_auth_callback, data); + } +} + /* * Check whether a URL scheme is downloadable. * Return: 1 enabled, 0 disabled. @@ -1114,6 +1178,9 @@ static void Cache_process_queue(CacheEntry_t *entry) a_UIcmd_save_link(Client_bw, url); } a_Url_free(url); + + } else if (entry->Auth && (entry->Flags & CA_GotData)) { + Cache_auth_entry(entry, Client_bw); } /* Trigger cleanup when there are no cache clients */ diff --git a/src/dialog.cc b/src/dialog.cc index 8408782f..ca457c40 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -20,6 +20,9 @@ #include <fltk/ReturnButton.h> #include <fltk/TextDisplay.h> #include <fltk/HighlightButton.h> +#include <fltk/WordwrapOutput.h> +#include <fltk/Input.h> +#include <fltk/SecretInput.h> #include "msg.h" #include "dialog.hh" @@ -227,3 +230,79 @@ int a_Dialog_choice5(const char *QuestionTxt, return choice5_answer; } + +/*--------------------------------------------------------------------------*/ +static int ok_answer = 1, cancel_answer = 0; +static void Dialog_user_password_cb(Widget *button, void *vIntPtr) +{ + int ok = VOIDP2INT(vIntPtr); + _MSG("Dialog_user_password_cb: %d\n", ok); + button->window()->make_exec_return(ok); +} + +/* + * Make a user/password dialog. + * Call the callback with the result (OK or not) and the given user and + * password if OK. + */ +int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp) +{ + int ok, + window_w = 300, window_h = 280, + input_x = 80, input_w = 200, input_h = 30, + button_y = 230, button_h = 30; + + Window *window = + new Window(window_w,window_h,"User/Password"); + window->begin(); + + /* message */ + WordwrapOutput *message_output = + new WordwrapOutput(20,20,window_w-40,100); + message_output->box(DOWN_BOX); + message_output->text(message); + message_output->textfont(HELVETICA_BOLD_ITALIC); + message_output->textsize(14); + + /* inputs */ + Input *user_input = + new Input(input_x,140,input_w,input_h,"User"); + user_input->labelsize(14); + user_input->textsize(14); + SecretInput *password_input = + new SecretInput(input_x,180,input_w,input_h,"Password"); + password_input->labelsize(14); + password_input->textsize(14); + + /* "OK" button */ + Button *ok_button = + new Button(200,button_y,50,button_h,"OK"); + ok_button->labelsize(14); + ok_button->callback(Dialog_user_password_cb); + ok_button->user_data(&ok_answer); + + /* "Cancel" button */ + Button *cancel_button = + new Button(50,button_y,100,button_h,"Cancel"); + cancel_button->labelsize(14); + cancel_button->callback(Dialog_user_password_cb); + cancel_button->user_data(&cancel_answer); + + window->end(); + window->size_range(window_w,window_h,window_w,window_h); + window->resizable(window); + + if ((ok = window->exec())) { + /* call the callback */ + const char *user, *password; + user = user_input->value(); + password = password_input->value(); + _MSG("a_Dialog_user_passwd: ok = %d\n", ok); + (*cb)(user, password, vp); + } + + delete window; + + return ok; +} + diff --git a/src/dialog.hh b/src/dialog.hh index 17c326cb..d82eb0cc 100644 --- a/src/dialog.hh +++ b/src/dialog.hh @@ -5,12 +5,16 @@ extern "C" { #endif /* __cplusplus */ +typedef void (*UserPasswordCB)(const char *user, const char *password, + void *vp); + void a_Dialog_msg(const char *msg); int a_Dialog_choice3(const char *msg, const char *b0, const char *b1, const char *b2); int a_Dialog_choice5(const char *QuestionTxt, const char *alt1, const char *alt2, const char *alt3, const char *alt4, const char *alt5); +int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp); const char *a_Dialog_input(const char *msg); const char *a_Dialog_passwd(const char *msg); const char *a_Dialog_save_file(const char *msg, diff --git a/src/dillo.cc b/src/dillo.cc index c20d1f02..10430f29 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -45,6 +45,7 @@ #include "capi.h" #include "dicache.h" #include "cookies.h" +#include "auth.h" /* @@ -102,6 +103,7 @@ int main(int argc, char **argv) a_Dicache_init(); a_Bw_init(); a_Cookies_init(); + a_Auth_init(); // Sets WM_CLASS hint on X11 fltk::Window::xclass("dillo"); |