summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastian Geerken <devnull@localhost>2012-09-14 11:34:19 +0200
committerSebastian Geerken <devnull@localhost>2012-09-14 11:34:19 +0200
commite4367b16dc131f34936bbb8fd09557b5aa5acbd7 (patch)
tree487a35941bf20bbc95a3d0b1dee420b00771f5b6 /src
parentabd446c2eebe1f96764b6d95f1c6c61ae9bc40b2 (diff)
parent94e451ffa5ece79a3b071ee553650bf8bd869a46 (diff)
Merge of <http://hg.dillo.org/dillo>.
Diffstat (limited to 'src')
-rw-r--r--src/IO/about.c69
-rw-r--r--src/IO/http.c35
-rw-r--r--src/IO/mime.c4
-rw-r--r--src/Makefile.am4
-rw-r--r--src/auth.c542
-rw-r--r--src/auth.h23
-rw-r--r--src/binaryconst.h5
-rw-r--r--src/cache.c42
-rw-r--r--src/capi.c23
-rw-r--r--src/colors.c4
-rw-r--r--src/cookies.c16
-rw-r--r--src/css.cc258
-rw-r--r--src/css.hh35
-rw-r--r--src/cssparser.cc77
-rw-r--r--src/decode.c29
-rw-r--r--src/dialog.cc24
-rw-r--r--src/digest.c204
-rw-r--r--src/digest.h16
-rw-r--r--src/dillo.cc5
-rw-r--r--src/dns.c89
-rw-r--r--src/form.cc118
-rw-r--r--src/form.hh1
-rw-r--r--src/html.cc554
-rw-r--r--src/html_common.hh7
-rw-r--r--src/keys.cc14
-rw-r--r--src/keysrc2
-rw-r--r--src/list.h4
-rw-r--r--src/md5.c390
-rw-r--r--src/md5.h100
-rw-r--r--src/menu.cc17
-rw-r--r--src/misc.c55
-rw-r--r--src/nav.c7
-rw-r--r--src/png.c2
-rw-r--r--src/prefsparser.cc14
-rw-r--r--src/styleengine.cc117
-rw-r--r--src/styleengine.hh2
-rw-r--r--src/table.cc94
-rw-r--r--src/table.hh4
-rw-r--r--src/ui.cc8
-rw-r--r--src/uicmd.cc4
-rw-r--r--src/url.c18
-rw-r--r--src/web.cc2
42 files changed, 2035 insertions, 1003 deletions
diff --git a/src/IO/about.c b/src/IO/about.c
index 77af318f..78cf086e 100644
--- a/src/IO/about.c
+++ b/src/IO/about.c
@@ -121,10 +121,6 @@ const char *const AboutSplash=
" <tr>\n"
" <td>&nbsp;&nbsp;\n"
" <td>\n"
-" <a href='http://www.linux.org.uk/Portaloo.cs'>Linux.org.uk</a>\n"
-" <tr>\n"
-" <td>&nbsp;&nbsp;\n"
-" <td>\n"
" <a href='http://www.commondreams.org/'>C.&nbsp;Dreams</a>\n"
" <tr>\n"
" <td>&nbsp;&nbsp;\n"
@@ -156,7 +152,7 @@ const char *const AboutSplash=
" <td><a href='http://www.gutenberg.org/'>P.&nbsp;Gutenberg</a>\n"
" <tr>\n"
" <td>&nbsp;&nbsp;\n"
-" <td><a href='http://freshmeat.net/'>FreshMeat</a>\n"
+" <td><a href='http://freecode.com/'>Freecode</a>\n"
" <tr>\n"
" <td>&nbsp;&nbsp;\n"
" <td><a href='http://www.gnu.org/gnu/thegnuproject.html'>GNU\n"
@@ -211,8 +207,8 @@ const char *const AboutSplash=
" <td bgcolor='#FFFFFF'>\n"
" <table border='0' cellspacing='0' cellpadding='5'><tr><td>\n"
" <p>\n"
-" Dillo is Free Software under the terms of version 3 of the\n"
-" <a href='http://www.gnu.org/licenses/gpl.html'>GPL</a>.\n"
+" The Dillo web browser is Free Software under the terms of version 3 of\n"
+" the <a href='http://www.gnu.org/licenses/gpl.html'>GPL</a>.\n"
" This means you have four basic freedoms:\n"
" <ul>\n"
" <li>Freedom to use the program any way you see fit.\n"
@@ -234,25 +230,24 @@ const char *const AboutSplash=
"<tr>\n"
" <td bgcolor='#CCCCCC'>\n"
" <h4>Release overview</h4>\n"
-" September 06, 2011\n"
+" December 05, 2011\n"
"<tr>\n"
" <td bgcolor='#FFFFFF'>\n"
" <table border='0' cellspacing='0' cellpadding='5'>\n"
" <tr>\n"
" <td>\n"
"<p>\n"
-"Dillo-3.0 is a port to FLTK-1.3, which is big news because FLTK-1.3.0 was\n"
-"<a href='http://fltk.org/articles.php?L1086'>released</a>\n"
-"in June, clearing the way for Dillo to return to those distributions\n"
-"which had excluded Dillo2 due to FLTK2 never being officially released.\n"
+"dillo-3.0.2 brings you some new bits and pieces, as listed below :)\n"
"<p>\n"
-"Dillo-3.0 also has plenty of improvements and bugfixes.\n"
-"<p>\n"
-"After this release, the core team will focus on implementing the CSS\n"
+"After this release, the core team plans to focus on implementing the CSS\n"
"feature of floating elements. This will <em>greatly</em> improve dillo's\n"
"web page rendering since many sites have adopted floats instead of tables.\n"
"<p>\n"
-"The new dillo3 has shown excellent stability in our experience.\n"
+"Dillo3 uses the FLTK GUI toolkit's 1.3.x series. In June, fltk-1.3.0 was\n"
+"<a href='http://fltk.org/articles.php?L1086'>released</a>,\n"
+"clearing the way for Dillo to return to those distributions\n"
+"which had excluded Dillo2 due to FLTK2 never being officially released.\n"
+"<p>\n"
"The core team welcomes developers willing to join our workforce.\n"
"<p>\n"
" </table>\n"
@@ -275,39 +270,11 @@ const char *const AboutSplash=
" <tr>\n"
" <td>\n"
"<ul>\n"
-"<li>Ported Dillo to FLTK-1.3.\n"
-"<li>Native build on OSX.\n"
-"<li>Default binding for close-all changed from Alt-q to Ctrl-q.\n"
-"<li>Default binding for close-tab changed from Ctrl-q to Ctrl-w.\n"
-"<li>Default binding for left-tab changed to Shift-Ctrl-Tab.\n"
-"<li>Rewrote the User Interface: much simpler design and event handling.\n"
-"<li>Added on-the-fly panel resize (tiny/small/medium and normal/small icons).\n"
-"<li>'hide-panels' key action now hides the findbar if present,\n"
-" and toggles display of the control panels otherwise.\n"
-"<li>Allow multiple search engines to be set in dillorc, with a menu\n"
-" in the web search dialog to select between them.\n"
-"<li>Added an optional label to dillorc's search_url.\n"
-" Format: \"[&lt;label&gt; ]&lt;url&gt;\"\n"
-"<li>Add right_click_closes_tab preference (default is middle click).\n"
-"<li>Allow binding to non-ASCII keys and multimedia keys.\n"
-"<li>Avoid a certificate dialog storm on some HTTPS sites (BUG#868).\n"
-"<li>Enable line wrapping for &lt;textarea&gt;. (BUG#903)\n"
-"<li>Avoid double render after going Back or Forward\n"
-" (it takes half the time now!)\n"
-"<li>Implemented a custom tabs handler (to allow fine control of it).\n"
-"<li>Rewrote dw's crossing-events dispatcher (avoids redundant events).\n"
-"<li>Fixed a years old bug: stamped tooltips when scrolling with keyboard.\n"
-"<li>Fixed a border case in URL resolver: empty path + {query|fragment}\n"
-" (BUG#948)\n"
-"<li>Cancel the expected URL after offering a download (BUG#982)\n"
-"<li>Eliminated a pack of 22 compiler warnings (gcc-4.6.1 amd64)\n"
-"<li>Removed 'large' option of panel_size preference.\n"
-"<li>Removed --enable-ansi configure option.\n"
-"<li>Limit saved cookie size.\n"
-"<li>Wrap image alt text.\n"
-"<li>Added support for CSS adjacent sibling selectors.\n"
-"<li>Fix redraw loops and reenabled limit_text_width dillorc option.\n"
-"<li>Collapse parent's and first child's top margin.\n"
+"<li>Digest authentication.\n"
+"<li>Rework line breaking and fix white-space:nowrap handling.\n"
+"<li>text-transform property.\n"
+"<li>Locale-independent ASCII character case handling (fixes Turkic locales).\n"
+"<li>Bind Ctrl-{PageUp,PageDown} to tab-{previous,next}.\n"
"</ul>\n"
" </table>\n"
"</table>\n"
@@ -328,12 +295,12 @@ const char *const AboutSplash=
"<ul>\n"
" <li> There's a\n"
" <a href='http://www.dillo.org/dillorc'>dillorc</a>\n"
-" (readable config) file within the tarball; It is well-commented\n"
+" (readable config) file inside the tarball. It is well-commented\n"
" and has plenty of options to customize dillo, so <STRONG>copy\n"
" it</STRONG> to your <STRONG>~/.dillo/</STRONG> directory, and\n"
" modify it to your taste.\n"
" <li> Documentation for developers is in the <CODE>/doc</CODE>\n"
-" dir within the tarball; you can find directions on everything\n"
+" dir inside the tarball; you can find directions on everything\n"
" else at the home page.\n"
" <li> The right mouse button brings up a context-sensitive menu\n"
" (available on pages, links, images, forms, the Back and Forward buttons,\n"
diff --git a/src/IO/http.c b/src/IO/http.c
index 41ee137a..3e87f912 100644
--- a/src/IO/http.c
+++ b/src/IO/http.c
@@ -171,10 +171,11 @@ static void Http_connect_queued_sockets(HostConnection_t *hc)
} else if (a_Web_valid(sd->web)) {
/* start connecting the socket */
if (Http_connect_socket(sd->Info) < 0) {
+ ChainLink *Info = sd->Info;
MSG_BW(sd->web, 1, "ERROR: %s", dStrerror(sd->Err));
- a_Chain_bfcb(OpAbort, sd->Info, NULL, "Both");
- dFree(sd->Info);
- Http_socket_free(VOIDP2INT(sd->Info->LocalKey));
+ a_Chain_bfcb(OpAbort, Info, NULL, "Both");
+ Http_socket_free(VOIDP2INT(Info->LocalKey)); /* free sd */
+ dFree(Info);
} else {
sd->connected_to = hc->host;
hc->active_connections++;
@@ -202,7 +203,7 @@ static void Http_socket_free(int SKey)
Http_connect_queued_sockets(hc);
if (hc->active_connections == 0)
Http_host_connection_remove(hc);
- }
+ }
dFree(S);
}
}
@@ -274,23 +275,22 @@ static Dstr *Http_make_content_type(const DilloUrl *url)
Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
bool_t use_proxy)
{
- const char *auth;
- char *ptr, *cookies, *referer;
+ char *ptr, *cookies, *referer, *auth;
Dstr *query = dStr_new(""),
- *full_path = dStr_new(""),
+ *request_uri = dStr_new(""),
*proxy_auth = dStr_new("");
if (use_proxy) {
- dStr_sprintfa(full_path, "%s%s",
+ dStr_sprintfa(request_uri, "%s%s",
URL_STR(url),
(URL_PATH_(url) || URL_QUERY_(url)) ? "" : "/");
- if ((ptr = strrchr(full_path->str, '#')))
- dStr_truncate(full_path, ptr - full_path->str);
+ if ((ptr = strrchr(request_uri->str, '#')))
+ dStr_truncate(request_uri, ptr - request_uri->str);
if (HTTP_Proxy_Auth_base64)
dStr_sprintf(proxy_auth, "Proxy-Authorization: Basic %s\r\n",
HTTP_Proxy_Auth_base64);
} else {
- dStr_sprintfa(full_path, "%s%s%s%s",
+ dStr_sprintfa(request_uri, "%s%s%s%s",
URL_PATH(url),
URL_QUERY_(url) ? "?" : "",
URL_QUERY(url),
@@ -298,7 +298,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
}
cookies = a_Cookies_get_query(url, requester);
- auth = a_Auth_get_auth_str(url);
+ auth = a_Auth_get_auth_str(url, request_uri->str);
referer = Http_get_referer(url);
if (URL_FLAGS(url) & URL_Post) {
Dstr *content_type = Http_make_content_type(url);
@@ -319,7 +319,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
"Content-Type: %s\r\n"
"%s" /* cookies */
"\r\n",
- full_path->str, HTTP_Language_hdr, auth ? auth : "",
+ request_uri->str, HTTP_Language_hdr, auth ? auth : "",
URL_AUTHORITY(url), proxy_auth->str, referer, prefs.http_user_agent,
(long)URL_DATA(url)->len, content_type->str,
cookies);
@@ -342,7 +342,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
"User-Agent: %s\r\n"
"%s" /* cookies */
"\r\n",
- full_path->str,
+ request_uri->str,
(URL_FLAGS(url) & URL_E2EQuery) ?
"Cache-Control: no-cache\r\nPragma: no-cache\r\n" : "",
HTTP_Language_hdr, auth ? auth : "", URL_AUTHORITY(url),
@@ -350,8 +350,9 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
}
dFree(referer);
dFree(cookies);
+ dFree(auth);
- dStr_free(full_path, TRUE);
+ dStr_free(request_uri, TRUE);
dStr_free(proxy_auth, TRUE);
_MSG("Query: {%s}\n", dStr_printable(query, 8192));
return query;
@@ -479,7 +480,7 @@ static int Http_must_use_proxy(const DilloUrl *url)
for (p = np; (tok = dStrsep(&p, " ")); ) {
int start = host_len - strlen(tok);
- if (start >= 0 && dStrcasecmp(host + start, tok) == 0) {
+ if (start >= 0 && dStrAsciiCasecmp(host + start, tok) == 0) {
/* no_proxy token is suffix of host string */
ret = 0;
break;
@@ -718,7 +719,7 @@ static HostConnection_t *Http_host_connection_get(const char *host)
for (i = 0; i < dList_length(host_connections); i++) {
hc = (HostConnection_t*) dList_nth_data(host_connections, i);
- if (dStrcasecmp(host, hc->host) == 0)
+ if (dStrAsciiCasecmp(host, hc->host) == 0)
return hc;
}
diff --git a/src/IO/mime.c b/src/IO/mime.c
index 19dc601a..3606d23c 100644
--- a/src/IO/mime.c
+++ b/src/IO/mime.c
@@ -67,7 +67,7 @@ static Viewer_t Mime_minor_type_fetch(const char *Key, uint_t Size)
if (Size) {
for ( i = 0; i < MimeMinItemsSize; ++i )
- if (dStrncasecmp(Key, MimeMinItems[i].Name, Size) == 0)
+ if (dStrnAsciiCasecmp(Key, MimeMinItems[i].Name, Size) == 0)
return MimeMinItems[i].Data;
}
return NULL;
@@ -83,7 +83,7 @@ static Viewer_t Mime_major_type_fetch(const char *Key, uint_t Size)
if (Size) {
for ( i = 0; i < MimeMajItemsSize; ++i )
- if (dStrncasecmp(Key, MimeMajItems[i].Name, Size) == 0)
+ if (dStrnAsciiCasecmp(Key, MimeMajItems[i].Name, Size) == 0)
return MimeMajItems[i].Data;
}
return NULL;
diff --git a/src/Makefile.am b/src/Makefile.am
index 9de7eed5..5e887d2c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,10 @@ dillo_SOURCES = \
cookies.h \
auth.c \
auth.h \
+ md5.c \
+ md5.h \
+ digest.c \
+ digest.h \
colors.c \
colors.h \
binaryconst.h \
diff --git a/src/auth.c b/src/auth.c
index 8943c3fd..d6ff081b 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -2,6 +2,7 @@
* File: auth.c
*
* Copyright 2008 Jeremy Henty <onepoint@starurchin.org>
+ * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de>
*
* 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
@@ -20,28 +21,29 @@
#include "msg.h"
#include "misc.h"
#include "dialog.hh"
+#include "digest.h"
#include "../dlib/dlib.h"
-
typedef struct {
int ok;
+ enum AuthParseHTTPAuthType_t type;
const char *realm;
+ const char *nonce;
+ const char *opaque;
+ int stale;
+ enum AuthParseDigestAlgorithm_t algorithm;
+ const char *domain;
+ enum AuthParseDigestQOP_t qop;
} 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 AuthParse_t *auth_parse;
const DilloUrl *url;
} AuthDialogData_t;
@@ -62,7 +64,14 @@ static AuthParse_t *Auth_parse_new()
{
AuthParse_t *auth_parse = dNew(AuthParse_t, 1);
auth_parse->ok = 0;
+ auth_parse->type = TYPENOTSET;
auth_parse->realm = NULL;
+ auth_parse->nonce = NULL;
+ auth_parse->opaque = NULL;
+ auth_parse->stale = 0;
+ auth_parse->algorithm = ALGORITHMNOTSET;
+ auth_parse->domain = NULL;
+ auth_parse->qop = QOPNOTSET;
return auth_parse;
}
@@ -70,6 +79,9 @@ static void Auth_parse_free(AuthParse_t *auth_parse)
{
if (auth_parse) {
dFree((void *)auth_parse->realm);
+ dFree((void *)auth_parse->nonce);
+ dFree((void *)auth_parse->opaque);
+ dFree((void *)auth_parse->domain);
dFree(auth_parse);
}
}
@@ -92,191 +104,250 @@ static int Auth_path_is_inside(const char *path1, const char *path2, int len)
static int Auth_is_token_char(char c)
{
const char *invalid = "\"()<>@,;:\\[]?=/{} \t";
- return (strchr(invalid, c) || iscntrl((uchar_t)c)) ? 0 : 1;
+ return (!isascii(c) || strchr(invalid, c) || iscntrl((uchar_t)c)) ? 0 : 1;
}
/*
- * Unquote the content of a quoted string.
+ * Unquote the content of a (potentially) quoted string.
* Return: newly allocated unquoted content.
*
* Arguments:
- * quoted: pointer to the first char *after* the initial double quote.
- * size: the number of chars in the result, *not* including a final '\0'.
+ * valuep: pointer to a pointer to the first char.
*
* Preconditions:
- * quoted points to a correctly quoted and escaped string.
- * size is the number of characters in the quoted string, *after*
- * removing escape characters.
+ * *valuep points to a correctly quoted and escaped string.
+ *
+ * Postconditions:
+ * *valuep points to the first not processed char.
*
*/
-static const char *Auth_unquote_value(const char *quoted, int size)
+static Dstr *Auth_unquote_value(char **valuep)
{
- char c, *value, *value_ptr;
- value_ptr = value = dNew(char, size + 1);
- while ((c = *quoted++) != '"')
- *value_ptr++ = (c == '\\') ? *quoted++ : c;
- *value_ptr = '\0';
- return value;
+ char c, quoted;
+ char *value = *valuep;
+ Dstr *result;
+
+ while (*value == ' ' || *value == '\t')
+ value++;
+
+ if ((quoted = *value == '"'))
+ value++;
+
+ result = dStr_new(NULL);
+ while ((c = *value) &&
+ (( quoted && c != '"') ||
+ (!quoted && Auth_is_token_char(c)))) {
+ dStr_append_c(result, (c == '\\' && value[1]) ? *++value : c);
+ value++;
+ }
+
+ if (quoted && *value == '\"')
+ value++;
+ *valuep = value;
+ return result;
}
+typedef int (Auth_parse_token_value_callback_t)(AuthParse_t *auth_parse,
+ char *token,
+ const char *value);
+
+
/*
- * Parse a quoted string. Save the result as the auth realm if required.
+ * Parse authentication challenge into token-value pairs
+ * and feed them into the callback function.
+ *
+ * The parsing is aborted should the callback function return 0.
+ *
* Return: 1 if the parse succeeds, 0 otherwise.
*/
-static int Auth_parse_quoted_string(AuthParse_t *auth_parse, int set_realm,
- char **auth)
+static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth,
+ Auth_parse_token_value_callback_t *callback)
{
- char *value;
- int size;
-
- /* parse the '"' */
- switch (*(*auth)++) {
- case '"':
- break;
- case '\0':
- case ',':
- MSG("auth.c: missing Basic auth token value after '='\n");
- return 0;
- break;
- default:
- MSG("auth.c: garbage in Basic auth after '='\n");
- return 0;
- break;
- }
+ char keep_going, expect_quoted;
+ char *token, *beyond_token;
+ Dstr *value;
+ size_t *token_size;
- /* parse the rest */
- value = *auth;
- size = 0;
- while (1) {
+ while (**auth) {
+ _MSG("Auth_parse_token_value: remaining: %s\n", *auth);
+
+ /* parse a token */
+ token = *auth;
+
+ token_size = 0;
+ while (Auth_is_token_char(**auth)) {
+ (*auth)++;
+ token_size++;
+ }
+ if (token_size == 0) {
+ MSG("Auth_parse_token_value: missing auth token\n");
+ return 0;
+ }
+ beyond_token = *auth;
+ /* skip linear whitespace characters */
+ while (**auth == ' ' || **auth == '\t')
+ (*auth)++;
+
+ /* parse the '=' */
switch (*(*auth)++) {
- case '"':
- if (set_realm) {
- dFree((void *)auth_parse->realm);
- auth_parse->realm = Auth_unquote_value(value, size);
- auth_parse->ok = 1;
- }
- return 1;
+ case '=':
+ *beyond_token = '\0';
break;
case '\0':
- MSG("auth.c: auth string ended inside quoted string value\n");
+ case ',':
+ MSG("Auth_parse_token_value: missing auth token value\n");
return 0;
break;
- case '\\':
- /* end of string? */
- if (!*(*auth)++) {
- MSG("auth.c: "
- "auth string ended inside quoted string value "
- "immediately after \\\n");
- return 0;
- }
- /* fall through to the next case */
default:
- size++;
+ MSG("Auth_parse_token_value: garbage after auth token\n");
+ return 0;
break;
}
- }
-}
-/*
- * Parse a token-value pair.
- * Return: 1 if the parse succeeds, 0 otherwise.
- */
-static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth)
-{
- char *token;
- int token_size, set_realm;
- static const char realm_token[] = "realm";
-
- /* 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_token_value: "
- "missing Basic auth token\n");
- return 0;
- }
+ value = Auth_unquote_value(auth);
+ expect_quoted = !(strcmp(token, "stale") == 0 ||
+ strcmp(token, "algorithm") == 0);
- /* skip space characters */
- while (**auth == ' ')
- (*auth)++;
-
- /* parse the '=' */
- switch (*(*auth)++) {
- case '=':
- break;
- case '\0':
- case ',':
- MSG("auth.c: Auth_parse_token_value: "
- "missing Basic auth token value\n");
- return 0;
- break;
- default:
- MSG("auth.c: Auth_parse_token_value: "
- "garbage after Basic auth token\n");
- return 0;
- break;
- }
+ if (((*auth)[-1] == '"') != expect_quoted)
+ MSG_WARN("Auth_parse_token_value: "
+ "Values for key %s should%s be quoted.\n",
+ token, expect_quoted ? "" : " not");
- /* skip space characters */
- while (**auth == ' ')
- (*auth)++;
+ keep_going = callback(auth_parse, token, value->str);
+ dStr_free(value, 1);
+ if (!keep_going)
+ break;
- /* is this value the realm? */
- set_realm =
- auth_parse->realm == NULL &&
- dStrncasecmp(realm_token,token,token_size) == 0 &&
- strlen(realm_token) == (size_t)token_size;
+ /* skip ' ' and ',' */
+ while ((**auth == ' ') || (**auth == ','))
+ (*auth)++;
+ }
+ return 1;
+}
- return Auth_parse_quoted_string(auth_parse, set_realm, auth);
+static int Auth_parse_basic_challenge_cb(AuthParse_t *auth_parse, char *token,
+ const char *value)
+{
+ if (dStrAsciiCasecmp("realm", token) == 0) {
+ if (!auth_parse->realm)
+ auth_parse->realm = strdup(value);
+ return 0; /* end parsing */
+ } else
+ MSG("Auth_parse_basic_challenge_cb: Ignoring unknown parameter: %s = "
+ "'%s'\n", token, value);
+ return 1;
}
-static void Auth_parse_auth_basic(AuthParse_t *auth_parse, char **auth)
+static int Auth_parse_digest_challenge_cb(AuthParse_t *auth_parse, char *token,
+ const char *value)
{
- int token_value_pairs_found;
+ const char *const fn = "Auth_parse_digest_challenge_cb";
+
+ if (!dStrAsciiCasecmp("realm", token) && !auth_parse->realm)
+ auth_parse->realm = strdup(value);
+ else if (!strcmp("domain", token) && !auth_parse->domain)
+ auth_parse->domain = strdup(value);
+ else if (!strcmp("nonce", token) && !auth_parse->nonce)
+ auth_parse->nonce = strdup(value);
+ else if (!strcmp("opaque", token) && !auth_parse->opaque)
+ auth_parse->opaque = strdup(value);
+ else if (strcmp("stale", token) == 0) {
+ if (dStrAsciiCasecmp("true", value) == 0)
+ auth_parse->stale = 1;
+ else if (dStrAsciiCasecmp("false", value) == 0)
+ auth_parse->stale = 0;
+ else {
+ MSG("%s: Invalid stale value: %s\n", fn, value);
+ return 0;
+ }
+ } else if (strcmp("algorithm", token) == 0) {
+ if (strcmp("MD5", value) == 0)
+ auth_parse->algorithm = MD5;
+ else if (strcmp("MD5-sess", value) == 0) {
+ /* auth_parse->algorithm = MD5SESS; */
+ MSG("%s: MD5-sess algorithm disabled (not tested because 'not "
+ "correctly implemented yet' in Apache 2.2)\n", fn);
+ return 0;
+ } else {
+ MSG("%s: Unknown algorithm: %s\n", fn, value);
+ return 0;
+ }
+ } else if (strcmp("qop", token) == 0) {
+ while (*value) {
+ int len = strcspn(value, ", \t");
+ if (len == 4 && strncmp("auth", value, 4) == 0) {
+ auth_parse->qop = AUTH;
+ break;
+ }
+ if (len == 8 && strncmp("auth-int", value, 8) == 0) {
+ /* auth_parse->qop = AUTHINT; */
+ /* Keep searching; maybe we'll find an "auth" yet. */
+ MSG("%s: auth-int qop disabled (not tested because 'not "
+ "implemented yet' in Apache 2.2)\n", fn);
+ } else {
+ MSG("%s: Unknown qop value in %s\n", fn, value);
+ }
+ value += len;
+ while (*value == ' ' || *value == '\t')
+ value++;
+ if (*value == ',')
+ value++;
+ while (*value == ' ' || *value == '\t')
+ value++;
+ }
+ } else {
+ MSG("%s: Ignoring unknown parameter: %s = '%s'\n", fn, token, value);
+ }
+ return 1;
+}
+static void Auth_parse_challenge_args(AuthParse_t *auth_parse,
+ char **challenge,
+ Auth_parse_token_value_callback_t *cb)
+{
/* parse comma-separated token-value pairs */
- token_value_pairs_found = 0;
while (1) {
/* skip space and comma characters */
- while (**auth == ' ' || **auth == ',')
- (*auth)++;
+ while (**challenge == ' ' || **challenge == ',')
+ (*challenge)++;
/* end of string? */
- if (!**auth)
+ if (!**challenge)
break;
/* parse token-value pair */
- if (!Auth_parse_token_value(auth_parse, auth))
+ if (!Auth_parse_token_value(auth_parse, challenge, cb))
break;
- token_value_pairs_found = 1;
}
- if (!token_value_pairs_found) {
- MSG("auth.c: Auth_parse_auth_basic: "
- "missing Basic auth token-value pairs\n");
- return;
- }
-
- if (!auth_parse->realm) {
- MSG("auth.c: Auth_parse_auth_basic: "
- "missing Basic auth realm\n");
- return;
+ if (auth_parse->type == BASIC) {
+ if (auth_parse->realm) {
+ auth_parse->ok = 1;
+ } else {
+ MSG("Auth_parse_challenge_args: missing Basic auth realm\n");
+ return;
+ }
+ } else if (auth_parse->type == DIGEST) {
+ if (auth_parse->realm && auth_parse->nonce) {
+ auth_parse->ok = 1;
+ } else {
+ MSG("Auth_parse_challenge_args: Digest challenge incomplete\n");
+ return;
+ }
}
}
-static void Auth_parse_auth(AuthParse_t *auth_parse, char *auth)
+static void Auth_parse_challenge(AuthParse_t *auth_parse, char *challenge)
{
- _MSG("auth.c: Auth_parse_auth: auth = '%s'\n", auth);
- if (dStrncasecmp(auth, "Basic ", 6) == 0) {
- auth += 6;
- Auth_parse_auth_basic(auth_parse, &auth);
+ Auth_parse_token_value_callback_t *cb;
+
+ MSG("auth.c: Auth_parse_challenge: challenge = '%s'\n", challenge);
+ if (auth_parse->type == DIGEST) {
+ challenge += 7;
+ cb = Auth_parse_digest_challenge_cb;
} else {
- MSG("auth.c: Auth_parse_auth: "
- "unknown authorization scheme: auth = {%s}\n",
- auth);
+ challenge += 6;
+ cb = Auth_parse_basic_challenge_cb;
}
+ Auth_parse_challenge_args(auth_parse, &challenge, cb);
}
/*
@@ -288,8 +359,8 @@ static AuthHost_t *Auth_host_by_url(const DilloUrl *url)
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)))
+ if (((dStrAsciiCasecmp(URL_SCHEME(url), host->scheme) == 0) &&
+ (dStrAsciiCasecmp(URL_AUTHORITY(url), host->authority) == 0)))
return host;
return NULL;
@@ -305,7 +376,7 @@ static AuthRealm_t *Auth_realm_by_name(const AuthHost_t *host,
int i;
for (i = 0; (realm = dList_nth_data(host->realms, i)); i++)
- if (strcmp(realm->name,name) == 0)
+ if (strcmp(realm->name, name) == 0)
return realm;
return NULL;
@@ -319,9 +390,8 @@ static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host,
{
AuthRealm_t *realm_best, *realm;
int i, j;
- int match_length;
+ int match_length = 0;
- match_length = 0;
realm_best = NULL;
for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) {
char *realm_path;
@@ -339,6 +409,24 @@ static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host,
return realm_best;
}
+static void Auth_realm_delete(AuthRealm_t *realm)
+{
+ int i;
+
+ MSG("Auth_realm_delete: \"%s\"\n", realm->name);
+ for (i = dList_length(realm->paths) - 1; i >= 0; i--)
+ dFree(dList_nth_data(realm->paths, i));
+ dList_free(realm->paths);
+ dFree(realm->name);
+ dFree(realm->username);
+ dFree(realm->authorization);
+ dFree(realm->cnonce);
+ dFree(realm->nonce);
+ dFree(realm->opaque);
+ dFree(realm->domain);
+ dFree(realm);
+}
+
static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path)
{
int i;
@@ -377,22 +465,33 @@ static void Auth_realm_add_path(AuthRealm_t *realm, const char *path)
/*
* Return the authorization header for an HTTP query.
+ * request_uri is a separate argument because we want it precisely as
+ * formatted in the request.
*/
-const char *a_Auth_get_auth_str(const DilloUrl *url)
+char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri)
{
+ char *ret = NULL;
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;
+ if ((host = Auth_host_by_url(url)) &&
+ (realm = Auth_realm_by_path(host, URL_PATH(url)))) {
+ if (realm->type == BASIC)
+ ret = dStrdup(realm->authorization);
+ else if (realm->type == DIGEST)
+ ret = a_Digest_authorization_hdr(realm, url, request_uri);
+ else
+ MSG("a_Auth_get_auth_str() got an unknown realm type: %i.\n",
+ realm->type);
+ }
+ return ret;
}
/*
* Determine whether the user needs to authenticate.
*/
-static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url)
+static int Auth_do_auth_required(const AuthParse_t *auth_parse,
+ const DilloUrl *url)
{
/*
* TO DO: I dislike the way that this code must decide whether we
@@ -420,12 +519,20 @@ static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url)
* 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;
+ (realm = Auth_realm_by_name(host, auth_parse->realm))) {
+ if (!Auth_realm_includes_path(realm, URL_PATH(url))) {
+ _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n",
+ auth_parse->realm, URL_STR(url));
+ Auth_realm_add_path(realm, URL_PATH(url));
+ return 0;
+ }
+
+ if (auth_parse->type == DIGEST && auth_parse->stale) {
+ /* we do have valid credentials but our nonce is old */
+ dFree((void *)realm->nonce);
+ realm->nonce = dStrdup(auth_parse->nonce);
+ return 0;
+ }
}
/*
@@ -441,7 +548,6 @@ static void Auth_do_auth_dialog_cb(const char *user, const char *password,
AuthDialogData_t *data;
AuthHost_t *host;
AuthRealm_t *realm;
- char *user_password, *response, *authorization, *authorization_old;
data = (AuthDialogData_t *)vData;
@@ -456,45 +562,78 @@ static void Auth_do_auth_dialog_cb(const char *user, const char *password,
}
/* 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);
+ if (!(realm = Auth_realm_by_name(host, data->auth_parse->realm))) {
+ realm = dNew0(AuthRealm_t, 1);
+ realm->name = dStrdup(data->auth_parse->realm);
realm->paths = dList_new(1);
- realm->authorization = NULL;
dList_append(host->realms, realm);
}
+ realm->type = data->auth_parse->type;
+ dFree(realm->authorization);
+ realm->authorization = NULL;
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);
+ if (realm->type == BASIC) {
+ char *user_password = dStrconcat(user, ":", password, NULL);
+ char *response = a_Misc_encode_base64(user_password);
+ char *authorization =
+ dStrconcat("Authorization: Basic ", response, "\r\n", NULL);
+ dFree(realm->authorization);
+ realm->authorization = authorization;
+ dFree(response);
+ dStrshred(user_password);
+ dFree(user_password);
+ } else if (realm->type == DIGEST) {
+ dFree(realm->username);
+ realm->username = dStrdup(user);
+ realm->nonce_count = 0;
+ dFree(realm->nonce);
+ realm->nonce = dStrdup(data->auth_parse->nonce);
+ dFree(realm->opaque);
+ realm->opaque = dStrdup(data->auth_parse->opaque);
+ realm->algorithm = data->auth_parse->algorithm;
+ dFree(realm->domain);
+ realm->domain = dStrdup(data->auth_parse->domain);
+ realm->qop = data->auth_parse->qop;
+ dFree(realm->cnonce);
+ if (realm->qop != QOPNOTSET)
+ realm->cnonce = a_Digest_create_cnonce();
+ if (!a_Digest_compute_digest(realm, user, password)) {
+ MSG("Auth_do_auth_dialog_cb: a_Digest_compute_digest failed.\n");
+ dList_remove_fast(host->realms, realm);
+ Auth_realm_delete(realm);
+ }
+ } else {
+ MSG("Auth_do_auth_dialog_cb: Unknown auth type: %i\n",
+ realm->type);
+ }
+ dStrshred((char *)password);
}
-static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url)
+/*
+ * Return: Nonzero if we got new credentials from the user and everything
+ * seems fine.
+ */
+static int Auth_do_auth_dialog(const AuthParse_t *auth_parse,
+ const DilloUrl *url)
{
int ret;
char *message;
AuthDialogData_t *data;
+ const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic";
+
+ _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm);
- _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", realm);
message = dStrconcat("The server at ", URL_HOST(url), " requires a username"
- " and password for \"", realm, "\".", NULL);
+ " and password for \"", auth_parse->realm, "\".\n\n"
+ "Authentication scheme: ", typestr, NULL);
data = dNew(AuthDialogData_t, 1);
- data->realm_name = dStrdup(realm);
+ data->auth_parse = auth_parse;
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);
+ a_Url_free((void *)data->url);
dFree(data);
return ret;
}
@@ -502,19 +641,20 @@ static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url)
/*
* Do authorization for an auth string.
*/
-static int Auth_do_auth(char *auth, const DilloUrl *url)
+static int Auth_do_auth(char *challenge, enum AuthParseHTTPAuthType_t type,
+ const DilloUrl *url)
{
- int reload;
AuthParse_t *auth_parse;
+ int reload = 0;
- _MSG("auth.c: Auth_do_auth: auth={%s}\n", auth);
- reload = 0;
+ _MSG("auth.c: Auth_do_auth: challenge={%s}\n", challenge);
auth_parse = Auth_parse_new();
- Auth_parse_auth(auth_parse, auth);
+ auth_parse->type = type;
+ Auth_parse_challenge(auth_parse, challenge);
if (auth_parse->ok)
reload =
- Auth_do_auth_required(auth_parse->realm, url) ?
- Auth_do_auth_dialog(auth_parse->realm, url)
+ Auth_do_auth_required(auth_parse, url) ?
+ Auth_do_auth_dialog(auth_parse, url)
: 1;
Auth_parse_free(auth_parse);
@@ -522,18 +662,24 @@ static int Auth_do_auth(char *auth, const DilloUrl *url)
}
/*
- * Do authorization for a set of auth strings.
+ * Given authentication challenge(s), prepare authorization.
+ * Return: 0 on failure
+ * nonzero on success. A new query will be sent to the server.
*/
-int a_Auth_do_auth(Dlist *auths, const DilloUrl *url)
+int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
{
- int reload, i;
- char *auth;
+ int i;
+ char *chal;
- reload = 0;
- for (i = 0; (auth = dList_nth_data(auths, i)); ++i)
- if (Auth_do_auth(auth, url))
- reload = 1;
+ for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
+ if (!dStrnAsciiCasecmp(chal, "Digest ", 7))
+ if (Auth_do_auth(chal, DIGEST, url))
+ return 1;
+ for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
+ if (!dStrnAsciiCasecmp(chal, "Basic ", 6))
+ if (Auth_do_auth(chal, BASIC, url))
+ return 1;
- return reload;
+ return 0;
}
diff --git a/src/auth.h b/src/auth.h
index 5f96f642..f78eb59b 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -7,8 +7,29 @@ extern "C" {
#include "url.h"
+enum AuthParseHTTPAuthType_t { TYPENOTSET, BASIC, DIGEST };
+enum AuthParseDigestAlgorithm_t { ALGORITHMNOTSET, MD5, MD5SESS };
+enum AuthParseDigestQOP_t { QOPNOTSET, AUTH, AUTHINT };
-const char *a_Auth_get_auth_str(const DilloUrl *request_url);
+typedef struct {
+ enum AuthParseHTTPAuthType_t type;
+ char *name;
+ Dlist *paths; /* stripped of any trailing '/', so the root path is "" */
+ char *authorization; /* BASIC: the authorization request header */
+ /* DIGEST: the hexdigest of A1 */
+ /* digest state ahead */
+ char *username;
+ char *cnonce;
+ unsigned int nonce_count;
+ char *nonce;
+ char *opaque;
+ enum AuthParseDigestAlgorithm_t algorithm;
+ char *domain; /* NOT USED */
+ enum AuthParseDigestQOP_t qop;
+} AuthRealm_t;
+
+
+char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri);
int a_Auth_do_auth(Dlist *auth_string, const DilloUrl *url);
void a_Auth_init(void);
diff --git a/src/binaryconst.h b/src/binaryconst.h
index b5b9735b..09d4e7fa 100644
--- a/src/binaryconst.h
+++ b/src/binaryconst.h
@@ -1,6 +1,11 @@
#ifndef __BINARYCONST_H__
#define __BINARYCONST_H__
+/* binaryconst.h was integrated into the Dillo project in April 2004, and
+ * presumably comes from the ancestor of the code found at
+ * http://cprog.tomsweb.net/binconst.txt
+ */
+
/* Macros for allowing binary constants in C
* By Tom Torfs - donated to the public domain */
diff --git a/src/cache.c b/src/cache.c
index 6094a8d5..ea9d9a1f 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -13,9 +13,9 @@
* Dillo's cache module
*/
-#include <ctype.h> /* for tolower */
#include <sys/types.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -143,7 +143,9 @@ static int Cache_client_enqueue(const DilloUrl *Url, DilloWeb *Web,
static int ClientKey = 0; /* Provide a primary key for each client */
CacheClient_t *NewClient;
- if (++ClientKey <= 0)
+ if (ClientKey < INT_MAX) /* check for integer overflow */
+ ClientKey++;
+ else
ClientKey = 1;
NewClient = dNew(CacheClient_t, 1);
@@ -521,7 +523,7 @@ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype,
/* META only gives charset; use detected MIME type too */
entry->TypeNorm = dStrconcat(entry->TypeDet, ctype, NULL);
} else if (*from == 'm' &&
- !dStrncasecmp(ctype, "text/xhtml", 10)) {
+ !dStrnAsciiCasecmp(ctype, "text/xhtml", 10)) {
/* WORKAROUND: doxygen uses "text/xhtml" in META */
entry->TypeNorm = dStrdup(entry->TypeDet);
}
@@ -584,7 +586,7 @@ static char *Cache_parse_field(const char *header, const char *fieldname)
for (i = 0; header[i]; i++) {
/* Search fieldname */
for (j = 0; fieldname[j]; j++)
- if (tolower(fieldname[j]) != tolower(header[i + j]))
+ if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j]))
break;
if (fieldname[j]) {
/* skip to next line */
@@ -620,7 +622,7 @@ static Dlist *Cache_parse_multiple_fields(const char *header,
for (i = 0; header[i]; i++) {
/* Search fieldname */
for (j = 0; fieldname[j]; j++)
- if (tolower(fieldname[j]) != tolower(header[i + j]))
+ if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j]))
break;
if (fieldname[j]) {
/* skip to next line */
@@ -675,21 +677,27 @@ static void Cache_parse_header(CacheEntry_t *entry)
entry->Header = dStr_new("");
return;
}
- if (header[9] == '3' && header[10] == '0') {
+ if (header[9] == '3' && header[10] == '0' &&
+ (location_str = Cache_parse_field(header, "Location"))) {
/* 30x: URL redirection */
- if ((location_str = Cache_parse_field(header, "Location"))) {
- DilloUrl *location_url;
-
+ DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url));
+
+ if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN &&
+ !a_Url_same_organization(entry->Url, location_url)) {
+ /* don't redirect; just show body like usual (if any) */
+ MSG("Redirection not followed from %s to %s\n",
+ URL_HOST(entry->Url), URL_STR(location_url));
+ a_Url_free(location_url);
+ } else {
entry->Flags |= CA_Redirect;
if (header[11] == '1')
entry->Flags |= CA_ForceRedirect; /* 301 Moved Permanently */
else if (header[11] == '2')
entry->Flags |= CA_TempRedirect; /* 302 Temporary Redirect */
- location_url = a_Url_new(location_str, URL_STR_(entry->Url));
if (URL_FLAGS(location_url) & (URL_Post + URL_Get) &&
- dStrcasecmp(URL_SCHEME(location_url), "dpi") == 0 &&
- dStrcasecmp(URL_SCHEME(entry->Url), "dpi") != 0) {
+ dStrAsciiCasecmp(URL_SCHEME(location_url), "dpi") == 0 &&
+ dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0) {
/* Forbid dpi GET and POST from non dpi-generated urls */
MSG("Redirection Denied! '%s' -> '%s'\n",
URL_STR(entry->Url), URL_STR(location_url));
@@ -697,8 +705,8 @@ static void Cache_parse_header(CacheEntry_t *entry)
} else {
entry->Location = location_url;
}
- dFree(location_str);
}
+ dFree(location_str);
} else if (strncmp(header + 9, "401", 3) == 0) {
entry->Auth =
Cache_parse_multiple_fields(header, "WWW-Authenticate");
@@ -728,7 +736,7 @@ static void Cache_parse_header(CacheEntry_t *entry)
* If Transfer-Encoding is present, Content-Length must be ignored.
* If the Transfer-Encoding is non-identity, it is an error.
*/
- if (dStrcasecmp(encoding, "identity"))
+ if (dStrAsciiCasecmp(encoding, "identity"))
MSG_HTTP("Content-Length and non-identity Transfer-Encoding "
"headers both present.\n");
} else {
@@ -1039,9 +1047,9 @@ static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw)
*/
int a_Cache_download_enabled(const DilloUrl *url)
{
- if (!dStrcasecmp(URL_SCHEME(url), "http") ||
- !dStrcasecmp(URL_SCHEME(url), "https") ||
- !dStrcasecmp(URL_SCHEME(url), "ftp"))
+ if (!dStrAsciiCasecmp(URL_SCHEME(url), "http") ||
+ !dStrAsciiCasecmp(URL_SCHEME(url), "https") ||
+ !dStrAsciiCasecmp(URL_SCHEME(url), "ftp"))
return 1;
return 0;
}
diff --git a/src/capi.c b/src/capi.c
index bcec07bf..6db7484c 100644
--- a/src/capi.c
+++ b/src/capi.c
@@ -229,17 +229,17 @@ int a_Capi_dpi_verify_request(BrowserWindow *bw, DilloUrl *url)
const DilloUrl *referer;
int allow = FALSE;
- if (dStrcasecmp(URL_SCHEME(url), "dpi") == 0) {
+ if (dStrAsciiCasecmp(URL_SCHEME(url), "dpi") == 0) {
if (!(URL_FLAGS(url) & (URL_Post + URL_Get))) {
allow = TRUE;
} else if (!(URL_FLAGS(url) & URL_Post) &&
- strncmp(URL_STR(url), "dpi:/vsource/", 13) == 0) {
+ strncmp(URL_PATH(url), "/vsource/", 9) == 0) {
allow = TRUE;
} else {
/* only allow GET&POST dpi-requests from dpi-generated urls */
if (a_Nav_stack_size(bw)) {
referer = a_History_get_url(NAV_TOP_UIDX(bw));
- if (dStrcasecmp(URL_SCHEME(referer), "dpi") == 0) {
+ if (dStrAsciiCasecmp(URL_SCHEME(referer), "dpi") == 0) {
allow = TRUE;
}
}
@@ -266,10 +266,10 @@ static int Capi_url_uses_dpi(DilloUrl *url, char **server_ptr)
char *p, *server = NULL, *url_str = URL_STR(url);
Dstr *tmp;
- if ((dStrncasecmp(url_str, "http:", 5) == 0) ||
- (dStrncasecmp(url_str, "about:", 6) == 0)) {
+ if ((dStrnAsciiCasecmp(url_str, "http:", 5) == 0) ||
+ (dStrnAsciiCasecmp(url_str, "about:", 6) == 0)) {
/* URL doesn't use dpi (server = NULL) */
- } else if (dStrncasecmp(url_str, "dpi:/", 5) == 0) {
+ } else if (dStrnAsciiCasecmp(url_str, "dpi:/", 5) == 0) {
/* dpi prefix, get this server's name */
if ((p = strchr(url_str + 5, '/')) != NULL) {
server = dStrndup(url_str + 5, (uint_t)(p - url_str - 5));
@@ -388,7 +388,8 @@ static bool_t Capi_filters_test(const DilloUrl *wanted,
*want_host = URL_HOST(wanted);
if (want_host[0] == '\0') {
ret = (req_host[0] == '\0' ||
- !dStrcasecmp(URL_SCHEME(wanted), "data")) ? TRUE : FALSE;
+ !dStrAsciiCasecmp(URL_SCHEME(wanted), "data"))
+ ? TRUE : FALSE;
} else {
/* This will regard "www.dillo.org" and "www.dillo.org." as
* different, but it doesn't seem worth caring about.
@@ -454,9 +455,9 @@ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData)
} else if (Capi_url_uses_dpi(web->url, &server)) {
/* dpi request */
if ((safe = a_Capi_dpi_verify_request(web->bw, web->url))) {
- if (dStrcasecmp(scheme, "dpi") == 0) {
+ if (dStrAsciiCasecmp(scheme, "dpi") == 0) {
if (strcmp(server, "vsource") == 0) {
- /* don't reload the "view source" page */
+ /* allow "view source" reload upon user request */
} else {
/* make the other "dpi:/" prefixed urls always reload. */
a_Url_set_flags(web->url, URL_FLAGS(web->url) | URL_E2EQuery);
@@ -478,7 +479,7 @@ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData)
}
dFree(server);
- } else if (!dStrcasecmp(scheme, "http")) {
+ } else if (!dStrAsciiCasecmp(scheme, "http")) {
/* http request */
if (reload) {
a_Capi_conn_abort_by_url(web->url);
@@ -491,7 +492,7 @@ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData)
}
use_cache = 1;
- } else if (!dStrcasecmp(scheme, "about")) {
+ } else if (!dStrAsciiCasecmp(scheme, "about")) {
/* internal request */
use_cache = 1;
}
diff --git a/src/colors.c b/src/colors.c
index 5b647bb2..dcb147e3 100644
--- a/src/colors.c
+++ b/src/colors.c
@@ -201,7 +201,7 @@ static const struct key {
#endif
};
-#define NCOLORS (sizeof(color_keyword) / sizeof(struct key))
+#define NCOLORS (sizeof(color_keyword) / sizeof(color_keyword[0]))
/*
* Parse a color in hex (RRGGBB) or (RGB)
@@ -262,7 +262,7 @@ int32_t a_Color_parse (const char *subtag, int32_t default_color, int *err)
high = NCOLORS - 1;
while (low <= high) {
mid = (low + high) / 2;
- if ((ret = dStrcasecmp(cp, color_keyword[mid].key)) < 0)
+ if ((ret = dStrAsciiCasecmp(cp, color_keyword[mid].key)) < 0)
high = mid - 1;
else if (ret > 0)
low = mid + 1;
diff --git a/src/cookies.c b/src/cookies.c
index d1451dc1..0a1e94ff 100644
--- a/src/cookies.c
+++ b/src/cookies.c
@@ -197,8 +197,8 @@ char *a_Cookies_get_query(const DilloUrl *query_url, const DilloUrl *requester)
if (requester == NULL) {
/* request made by user */
} else if (!a_Url_same_organization(query_url, requester)) {
- MSG("Cookies: No cookies sent for third-party request by '%s' for "
- "'%s'\n", URL_HOST(requester), URL_STR(query_url));
+ MSG("Cookies: not sent for request by '%s' for '%s'\n",
+ URL_HOST(requester), URL_HOST(query_url));
return dStrdup("");
}
@@ -284,11 +284,11 @@ static int Cookie_control_init(void)
rule[j++] = line[i++];
rule[j] = '\0';
- if (dStrcasecmp(rule, "ACCEPT") == 0)
+ if (dStrAsciiCasecmp(rule, "ACCEPT") == 0)
cc.action = COOKIE_ACCEPT;
- else if (dStrcasecmp(rule, "ACCEPT_SESSION") == 0)
+ else if (dStrAsciiCasecmp(rule, "ACCEPT_SESSION") == 0)
cc.action = COOKIE_ACCEPT_SESSION;
- else if (dStrcasecmp(rule, "DENY") == 0)
+ else if (dStrAsciiCasecmp(rule, "DENY") == 0)
cc.action = COOKIE_DENY;
else {
MSG("Cookies: rule '%s' for domain '%s' is not recognised.\n",
@@ -297,7 +297,7 @@ static int Cookie_control_init(void)
}
cc.domain = dStrdup(domain);
- if (dStrcasecmp(cc.domain, "DEFAULT") == 0) {
+ if (dStrAsciiCasecmp(cc.domain, "DEFAULT") == 0) {
/* Set the default action */
default_action = cc.action;
dFree(cc.domain);
@@ -338,13 +338,13 @@ static CookieControlAction Cookies_control_check_domain(const char *domain)
if (ccontrol[i].domain[0] == '.') {
diff = strlen(domain) - strlen(ccontrol[i].domain);
if (diff >= 0) {
- if (dStrcasecmp(domain + diff, ccontrol[i].domain) != 0)
+ if (dStrAsciiCasecmp(domain + diff, ccontrol[i].domain) != 0)
continue;
} else {
continue;
}
} else {
- if (dStrcasecmp(domain, ccontrol[i].domain) != 0)
+ if (dStrAsciiCasecmp(domain, ccontrol[i].domain) != 0)
continue;
}
diff --git a/src/css.cc b/src/css.cc
index a1d51da1..8cf1c8eb 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -11,11 +11,9 @@
#include <stdio.h>
#include "../dlib/dlib.h"
-#include "misc.h"
#include "msg.h"
#include "html_common.hh"
#include "css.hh"
-#include "cssparser.hh"
using namespace dw::core::style;
@@ -29,6 +27,7 @@ CssPropertyList::CssPropertyList (const CssPropertyList &p, bool deep) :
lout::misc::SimpleVector <CssProperty> (p)
{
refCount = 0;
+ safe = p.safe;
if (deep) {
for (int i = 0; i < size (); i++) {
CssProperty *p = getRef(i);
@@ -60,6 +59,9 @@ void CssPropertyList::set (CssPropertyName name, CssValueType type,
CssPropertyValue value) {
CssProperty *prop;
+ if (name == CSS_PROPERTY_DISPLAY || name == CSS_PROPERTY_BACKGROUND_IMAGE)
+ safe = false;
+
for (int i = 0; i < size (); i++) {
prop = getRef (i);
@@ -104,7 +106,7 @@ CssSelector::CssSelector () {
cs = selectorList->getRef (selectorList->size () - 1);
cs->notMatchingBefore = -1;
- cs->combinator = CHILD;
+ cs->combinator = COMB_NONE;
cs->selector = new CssSimpleSelector ();
};
@@ -117,55 +119,47 @@ CssSelector::~CssSelector () {
/**
* \brief Return whether selector matches at a given node in the document tree.
*/
-bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) {
- CssSimpleSelector *sel;
- Combinator comb = CHILD;
- int *notMatchingBefore;
- const DoctreeNode *n;
-
- for (int i = selectorList->size () - 1; i >= 0; i--) {
- struct CombinatorAndSelector *cs = selectorList->getRef (i);
+bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
+ int i, Combinator comb) {
+ assert (node);
- sel = cs->selector;
- notMatchingBefore = &cs->notMatchingBefore;
-
- if (node == NULL)
- return false;
+ if (i < 0)
+ return true;
- switch (comb) {
- case CHILD:
- case ADJACENT_SIBLING:
- if (!sel->match (node))
- return false;
- break;
- case DESCENDANT:
- n = node;
-
- while (true) {
- if (node == NULL || node->num <= *notMatchingBefore) {
- *notMatchingBefore = n->num;
- return false;
- }
+ struct CombinatorAndSelector *cs = selectorList->getRef (i);
+ CssSimpleSelector *sel = cs->selector;
- if (sel->match (node))
- break;
+ switch (comb) {
+ case COMB_NONE:
+ break;
+ case COMB_CHILD:
+ node = docTree->parent (node);
+ break;
+ case COMB_ADJACENT_SIBLING:
+ node = docTree->sibling (node);
+ break;
+ case COMB_DESCENDANT:
+ node = docTree->parent (node);
- node = docTree->parent (node);
- }
- break;
- default:
- return false; // \todo implement other combinators
- }
+ for (const DoctreeNode *n = node;
+ n && n->num > cs->notMatchingBefore; n = docTree->parent (n))
+ if (sel->match (n) && match (docTree, n, i - 1, cs->combinator))
+ return true;
- comb = cs->combinator;
+ if (node) // remember that it didn't match to avoid future tests
+ cs->notMatchingBefore = node->num;
- if (comb == ADJACENT_SIBLING)
- node = docTree->sibling (node);
- else
- node = docTree->parent (node);
+ return false;
+ break;
+ default:
+ return false; // \todo implement other combinators
}
- return true;
+ if (!node || !sel->match (node))
+ return false;
+
+ // tail recursion should be optimized by the compiler
+ return match (docTree, node, i - 1, cs->combinator);
}
void CssSelector::addSimpleSelector (Combinator c) {
@@ -179,6 +173,13 @@ void CssSelector::addSimpleSelector (Combinator c) {
cs->selector = new CssSimpleSelector ();
}
+bool CssSelector::checksPseudoClass () {
+ for (int i = 0; i < selectorList->size (); i++)
+ if (selectorList->getRef (i)->selector->getPseudoClass ())
+ return true;
+ return false;
+}
+
/**
* \brief Return the specificity of the selector.
*
@@ -200,13 +201,13 @@ void CssSelector::print () {
if (i < selectorList->size () - 1) {
switch (selectorList->getRef (i + 1)->combinator) {
- case CHILD:
+ case COMB_CHILD:
fprintf (stderr, "> ");
break;
- case DESCENDANT:
+ case COMB_DESCENDANT:
fprintf (stderr, "\" \" ");
break;
- case ADJACENT_SIBLING:
+ case COMB_ADJACENT_SIBLING:
fprintf (stderr, "+ ");
break;
default:
@@ -262,19 +263,20 @@ void CssSimpleSelector::setSelect (SelectType t, const char *v) {
* the document tree.
*/
bool CssSimpleSelector::match (const DoctreeNode *n) {
+ assert (n);
if (element != ELEMENT_ANY && element != n->element)
return false;
if (pseudo != NULL &&
- (n->pseudo == NULL || dStrcasecmp (pseudo, n->pseudo) != 0))
+ (n->pseudo == NULL || dStrAsciiCasecmp (pseudo, n->pseudo) != 0))
return false;
- if (id != NULL && (n->id == NULL || dStrcasecmp (id, n->id) != 0))
+ if (id != NULL && (n->id == NULL || dStrAsciiCasecmp (id, n->id) != 0))
return false;
if (klass != NULL) {
for (int i = 0; i < klass->size (); i++) {
bool found = false;
if (n->klass != NULL) {
for (int j = 0; j < n->klass->size (); j++) {
- if (dStrcasecmp (klass->get(i), n->klass->get(j)) == 0) {
+ if (dStrAsciiCasecmp (klass->get(i), n->klass->get(j)) == 0) {
found = true;
break;
}
@@ -364,23 +366,6 @@ void CssStyleSheet::RuleList::insert (CssRule *rule) {
*getRef (i) = rule;
}
-CssStyleSheet::CssStyleSheet () {
- for (int i = 0; i < ntags; i++)
- elementTable[i] = new RuleList ();
-
- idTable = new RuleMap ();
- classTable = new RuleMap ();
- anyTable = new RuleList ();
-}
-
-CssStyleSheet::~CssStyleSheet () {
- for (int i = 0; i < ntags; i++)
- delete elementTable[i];
- delete idTable;
- delete classTable;
- delete anyTable;
-}
-
/**
* \brief Insert a rule into CssStyleSheet.
*
@@ -394,26 +379,26 @@ void CssStyleSheet::addRule (CssRule *rule) {
if (top->getId ()) {
string = new lout::object::ConstString (top->getId ());
- ruleList = idTable->get (string);
+ ruleList = idTable.get (string);
if (ruleList == NULL) {
ruleList = new RuleList ();
- idTable->put (string, ruleList);
+ idTable.put (string, ruleList);
} else {
delete string;
}
} else if (top->getClass () && top->getClass ()->size () > 0) {
string = new lout::object::ConstString (top->getClass ()->get (0));
- ruleList = classTable->get (string);
+ ruleList = classTable.get (string);
if (ruleList == NULL) {
ruleList = new RuleList;
- classTable->put (string, ruleList);
+ classTable.put (string, ruleList);
} else {
delete string;
}
} else if (top->getElement () >= 0 && top->getElement () < ntags) {
- ruleList = elementTable[top->getElement ()];
+ ruleList = &elementTable[top->getElement ()];
} else if (top->getElement () == CssSimpleSelector::ELEMENT_ANY) {
- ruleList = anyTable;
+ ruleList = &anyTable;
}
if (ruleList) {
@@ -439,7 +424,7 @@ void CssStyleSheet::apply (CssPropertyList *props,
if (node->id) {
lout::object::ConstString idString (node->id);
- ruleList[numLists] = idTable->get (&idString);
+ ruleList[numLists] = idTable.get (&idString);
if (ruleList[numLists])
numLists++;
}
@@ -453,17 +438,17 @@ void CssStyleSheet::apply (CssPropertyList *props,
lout::object::ConstString classString (node->klass->get (i));
- ruleList[numLists] = classTable->get (&classString);
+ ruleList[numLists] = classTable.get (&classString);
if (ruleList[numLists])
numLists++;
}
}
- ruleList[numLists] = elementTable[node->element];
+ ruleList[numLists] = &elementTable[node->element];
if (ruleList[numLists])
numLists++;
- ruleList[numLists] = anyTable;
+ ruleList[numLists] = &anyTable;
if (ruleList[numLists])
numLists++;
@@ -477,13 +462,15 @@ void CssStyleSheet::apply (CssPropertyList *props,
int minSpecIndex = -1;
for (int i = 0; i < numLists; i++) {
- if (ruleList[i] && ruleList[i]->size () > index[i] &&
- (ruleList[i]->get(index[i])->specificity () < minSpec ||
- (ruleList[i]->get(index[i])->specificity () == minSpec &&
- ruleList[i]->get(index[i])->position () < minPos))) {
+ RuleList *rl = ruleList[i];
+
+ if (rl && rl->size () > index[i] &&
+ (rl->get(index[i])->specificity () < minSpec ||
+ (rl->get(index[i])->specificity () == minSpec &&
+ rl->get(index[i])->position () < minPos))) {
- minSpec = ruleList[i]->get(index[i])->specificity ();
- minPos = ruleList[i]->get(index[i])->position ();
+ minSpec = rl->get(index[i])->specificity ();
+ minPos = rl->get(index[i])->position ();
minSpecIndex = i;
}
}
@@ -500,19 +487,6 @@ void CssStyleSheet::apply (CssPropertyList *props,
CssContext::CssContext () {
pos = 0;
-
- memset (sheet, 0, sizeof(sheet));
- sheet[CSS_PRIMARY_USER_AGENT] = new CssStyleSheet ();
- sheet[CSS_PRIMARY_USER] = new CssStyleSheet ();
- sheet[CSS_PRIMARY_USER_IMPORTANT] = new CssStyleSheet ();
-
- buildUserAgentStyle ();
- buildUserStyle ();
-}
-
-CssContext::~CssContext () {
- for (int o = CSS_PRIMARY_USER_AGENT; o < CSS_PRIMARY_LAST; o++)
- delete sheet[o];
}
/**
@@ -528,29 +502,24 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree,
DoctreeNode *node,
CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant,
CssPropertyList *nonCssHints) {
- if (sheet[CSS_PRIMARY_USER_AGENT])
- sheet[CSS_PRIMARY_USER_AGENT]->apply (props, docTree, node);
- if (sheet[CSS_PRIMARY_USER])
- sheet[CSS_PRIMARY_USER]->apply (props, docTree, node);
+ sheet[CSS_PRIMARY_USER_AGENT].apply (props, docTree, node);
+ sheet[CSS_PRIMARY_USER].apply (props, docTree, node);
if (nonCssHints)
nonCssHints->apply (props);
- if (sheet[CSS_PRIMARY_AUTHOR])
- sheet[CSS_PRIMARY_AUTHOR]->apply (props, docTree, node);
+ sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node);
if (tagStyle)
tagStyle->apply (props);
- if (sheet[CSS_PRIMARY_AUTHOR_IMPORTANT])
- sheet[CSS_PRIMARY_AUTHOR_IMPORTANT]->apply (props, docTree, node);
+ sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node);
if (tagStyleImportant)
tagStyleImportant->apply (props);
- if (sheet[CSS_PRIMARY_USER_IMPORTANT])
- sheet[CSS_PRIMARY_USER_IMPORTANT]->apply (props, docTree, node);
+ sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node);
}
void CssContext::addRule (CssSelector *sel, CssPropertyList *props,
@@ -559,74 +528,13 @@ void CssContext::addRule (CssSelector *sel, CssPropertyList *props,
if (props->size () > 0) {
CssRule *rule = new CssRule (sel, props, pos++);
- if (sheet[order] == NULL)
- sheet[order] = new CssStyleSheet ();
-
- sheet[order]->addRule (rule);
- }
-}
-
-/**
- * \brief Create the user agent style.
- *
- * The user agent style defines how dillo renders HTML in the absence of
- * author or user styles.
- */
-void CssContext::buildUserAgentStyle () {
- const char *cssBuf =
- "body {margin: 5px}"
- "big {font-size: 1.17em}"
- "blockquote, dd {margin-left: 40px; margin-right: 40px}"
- "center {text-align: center}"
- "dt {font-weight: bolder}"
- ":link {color: blue; text-decoration: underline; cursor: pointer}"
- ":visited {color: #800080; text-decoration: underline; cursor: pointer}"
- "h1, h2, h3, h4, h5, h6, b, strong {font-weight: bolder}"
- "i, em, cite, address, var {font-style: italic}"
- ":link img, :visited img {border: 1px solid}"
- "frameset, ul, ol, dir {margin-left: 40px}"
- "h1 {font-size: 2em; margin-top: .67em; margin-bottom: 0}"
- "h2 {font-size: 1.5em; margin-top: .75em; margin-bottom: 0}"
- "h3 {font-size: 1.17em; margin-top: .83em; margin-bottom: 0}"
- "h4 {margin-top: 1.12em; margin-bottom: 0}"
- "h5 {font-size: 0.83em; margin-top: 1.5em; margin-bottom: 0}"
- "h6 {font-size: 0.75em; margin-top: 1.67em; margin-bottom: 0}"
- "hr {width: 100%; border: 1px inset}"
- "li {margin-top: 0.1em}"
- "pre {white-space: pre}"
- "ol {list-style-type: decimal}"
- "ul {list-style-type: disc}"
- "ul ul {list-style-type: circle}"
- "ul ul ul {list-style-type: square}"
- "ul ul ul ul {list-style-type: disc}"
- "u {text-decoration: underline}"
- "small, sub, sup {font-size: 0.83em}"
- "sub {vertical-align: sub}"
- "sup {vertical-align: super}"
- "s, strike, del {text-decoration: line-through}"
- "table {border-spacing: 2px}"
- "td, th {padding: 2px}"
- "thead, tbody, tfoot {vertical-align: middle}"
- "th {font-weight: bolder; text-align: center}"
- "code, tt, pre, samp, kbd {font-family: monospace}"
- /* WORKAROUND: Reset font properties in tables as some
- * some pages rely on it (e.g. gmail).
- * http://developer.mozilla.org/En/Fixing_Table_Inheritance_in_Quirks_Mode
- * has a detailed description of the issue.
- */
- "table, caption {font-size: medium; font-weight: normal}";
-
- CssParser::parse (NULL, NULL, this, cssBuf, strlen (cssBuf),
- CSS_ORIGIN_USER_AGENT);
-}
-
-void CssContext::buildUserStyle () {
- Dstr *style;
- char *filename = dStrconcat(dGethomedir(), "/.dillo/style.css", NULL);
-
- if ((style = a_Misc_file2dstr(filename))) {
- CssParser::parse (NULL,NULL,this,style->str, style->len,CSS_ORIGIN_USER);
- dStr_free (style, 1);
+ if ((order == CSS_PRIMARY_AUTHOR ||
+ order == CSS_PRIMARY_AUTHOR_IMPORTANT) &&
+ !rule->isSafe ()) {
+ MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n");
+ delete rule;
+ } else {
+ sheet[order].addRule (rule);
+ }
}
- dFree (filename);
}
diff --git a/src/css.hh b/src/css.hh
index 20935dfd..e81fde62 100644
--- a/src/css.hh
+++ b/src/css.hh
@@ -223,6 +223,7 @@ typedef enum {
CSS_PROPERTY_X_COLSPAN,
CSS_PROPERTY_X_ROWSPAN,
PROPERTY_X_LINK,
+ PROPERTY_X_LANG,
PROPERTY_X_IMG,
PROPERTY_X_TOOLTIP,
CSS_PROPERTY_LAST
@@ -297,11 +298,13 @@ class CssProperty {
class CssPropertyList : public lout::misc::SimpleVector <CssProperty> {
int refCount;
bool ownerOfStrings;
+ bool safe;
public:
inline CssPropertyList(bool ownerOfStrings = false) :
lout::misc::SimpleVector <CssProperty> (1) {
refCount = 0;
+ safe = true;
this->ownerOfStrings = ownerOfStrings;
};
CssPropertyList(const CssPropertyList &p, bool deep = false);
@@ -310,6 +313,7 @@ class CssPropertyList : public lout::misc::SimpleVector <CssProperty> {
void set (CssPropertyName name, CssValueType type,
CssPropertyValue value);
void apply (CssPropertyList *props);
+ bool isSafe () { return safe; };
void print ();
inline void ref () { refCount++; }
inline void unref () { if (--refCount == 0) delete this; }
@@ -355,9 +359,10 @@ class CssSimpleSelector {
class CssSelector {
public:
typedef enum {
- DESCENDANT,
- CHILD,
- ADJACENT_SIBLING,
+ COMB_NONE,
+ COMB_DESCENDANT,
+ COMB_CHILD,
+ COMB_ADJACENT_SIBLING,
} Combinator;
private:
@@ -370,6 +375,8 @@ class CssSelector {
int refCount;
lout::misc::SimpleVector <struct CombinatorAndSelector> *selectorList;
+ bool match (Doctree *dt, const DoctreeNode *node, int i, Combinator comb);
+
public:
CssSelector ();
~CssSelector ();
@@ -378,8 +385,11 @@ class CssSelector {
return selectorList->getRef (selectorList->size () - 1)->selector;
};
inline int size () { return selectorList->size (); };
- bool match (Doctree *dt, const DoctreeNode *node);
+ inline bool match (Doctree *dt, const DoctreeNode *node) {
+ return match (dt, node, selectorList->size () - 1, COMB_NONE);
+ };
int specificity ();
+ bool checksPseudoClass ();
void print ();
inline void ref () { refCount++; }
inline void unref () { if (--refCount == 0) delete this; }
@@ -403,6 +413,9 @@ class CssRule {
void apply (CssPropertyList *props,
Doctree *docTree, const DoctreeNode *node);
+ inline bool isSafe () {
+ return !selector->checksPseudoClass () || props->isSafe ();
+ };
inline int specificity () { return spec; };
inline int position () { return pos; };
void print ();
@@ -439,15 +452,11 @@ class CssStyleSheet {
};
static const int ntags = 90; // \todo replace 90
- RuleList *elementTable[ntags];
- RuleMap *idTable;
- RuleMap *classTable;
- RuleList *anyTable;
+ RuleList elementTable[ntags], anyTable;
+ RuleMap idTable, classTable;
public:
- CssStyleSheet();
- ~CssStyleSheet();
void addRule (CssRule *rule);
void apply (CssPropertyList *props,
Doctree *docTree, const DoctreeNode *node);
@@ -458,15 +467,11 @@ class CssStyleSheet {
*/
class CssContext {
private:
- CssStyleSheet *sheet[CSS_PRIMARY_USER_IMPORTANT + 1];
+ CssStyleSheet sheet[CSS_PRIMARY_USER_IMPORTANT + 1];
int pos;
- void buildUserAgentStyle ();
- void buildUserStyle ();
-
public:
CssContext ();
- ~CssContext ();
void addRule (CssSelector *sel, CssPropertyList *props,
CssPrimaryOrder order);
diff --git a/src/cssparser.cc b/src/cssparser.cc
index f6e60731..bd065234 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -71,8 +71,8 @@ static const char *const Css_cursor_enum_vals[] = {
};
static const char *const Css_display_enum_vals[] = {
- "block", "inline", "list-item", "none", "table", "table-row-group",
- "table-header-group", "table-footer-group", "table-row",
+ "block", "inline", "inline-block", "list-item", "none", "table",
+ "table-row-group", "table-header-group", "table-footer-group", "table-row",
"table-cell", NULL
};
@@ -125,6 +125,10 @@ static const char *const Css_text_decoration_enum_vals[] = {
"underline", "overline", "line-through", "blink", NULL
};
+static const char *const Css_text_transform_enum_vals[] = {
+ "none", "capitalize", "uppercase", "lowercase", NULL
+};
+
static const char *const Css_vertical_align_vals[] = {
"top", "bottom", "middle", "baseline", "sub", "super", "text-top",
"text-bottom", NULL
@@ -232,7 +236,8 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
Css_text_decoration_enum_vals},
{"text-indent", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
{"text-shadow", {CSS_TYPE_UNUSED}, NULL},
- {"text-transform", {CSS_TYPE_UNUSED}, NULL},
+ {"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
+ Css_text_transform_enum_vals},
{"top", {CSS_TYPE_UNUSED}, NULL},
{"unicode-bidi", {CSS_TYPE_UNUSED}, NULL},
{"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals},
@@ -411,7 +416,7 @@ static const CssShorthandInfo Css_shorthand_info[] = {
};
#define CSS_SHORTHAND_NUM \
- (sizeof(Css_shorthand_info) / sizeof(CssShorthandInfo))
+ (sizeof(Css_shorthand_info) / sizeof(Css_shorthand_info[0]))
/* ----------------------------------------------------------------------
* Parsing
@@ -673,7 +678,7 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
case CSS_TYPE_ENUM:
if (ttype == CSS_TK_SYMBOL) {
for (i = 0; Css_property_info[prop].enum_symbols[i]; i++)
- if (dStrcasecmp(tval,
+ if (dStrAsciiCasecmp(tval,
Css_property_info[prop].enum_symbols[i]) == 0)
return true;
}
@@ -681,11 +686,11 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
case CSS_TYPE_MULTI_ENUM:
if (ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(tval, "none") == 0) {
+ if (dStrAsciiCasecmp(tval, "none") == 0) {
return true;
} else {
for (i = 0; Css_property_info[prop].enum_symbols[i]; i++) {
- if (dStrcasecmp(tval,
+ if (dStrAsciiCasecmp(tval,
Css_property_info[prop].enum_symbols[i]) == 0)
return true;
}
@@ -702,14 +707,14 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
case CSS_TYPE_SIGNED_LENGTH:
if (ttype == CSS_TK_DECINT ||
ttype == CSS_TK_FLOAT ||
- (ttype == CSS_TK_SYMBOL && dStrcasecmp(tval, "auto") == 0))
+ (ttype == CSS_TK_SYMBOL && dStrAsciiCasecmp(tval, "auto") == 0))
return true;
break;
case CSS_TYPE_COLOR:
if ((ttype == CSS_TK_COLOR ||
ttype == CSS_TK_SYMBOL) &&
- (dStrcasecmp(tval, "rgb") == 0 ||
+ (dStrAsciiCasecmp(tval, "rgb") == 0 ||
a_Color_parse(tval, -1, &err) != -1))
return true;
break;
@@ -837,7 +842,7 @@ bool CssParser::parseValue(CssPropertyName prop,
case CSS_TYPE_ENUM:
if (ttype == CSS_TK_SYMBOL) {
for (i = 0; Css_property_info[prop].enum_symbols[i]; i++)
- if (dStrcasecmp(tval,
+ if (dStrAsciiCasecmp(tval,
Css_property_info[prop].enum_symbols[i]) == 0) {
val->intVal = i;
ret = true;
@@ -852,10 +857,10 @@ bool CssParser::parseValue(CssPropertyName prop,
ret = true;
while (ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(tval, "none") != 0) {
+ if (dStrAsciiCasecmp(tval, "none") != 0) {
for (i = 0, found = false;
!found && Css_property_info[prop].enum_symbols[i]; i++) {
- if (dStrcasecmp(tval,
+ if (dStrAsciiCasecmp(tval,
Css_property_info[prop].enum_symbols[i]) == 0)
val->intVal |= (1 << i);
}
@@ -876,32 +881,32 @@ bool CssParser::parseValue(CssPropertyName prop,
if (!spaceSeparated && ttype == CSS_TK_SYMBOL) {
ret = true;
- if (dStrcasecmp(tval, "px") == 0) {
+ if (dStrAsciiCasecmp(tval, "px") == 0) {
lentype = CSS_LENGTH_TYPE_PX;
nextToken();
- } else if (dStrcasecmp(tval, "mm") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "mm") == 0) {
lentype = CSS_LENGTH_TYPE_MM;
nextToken();
- } else if (dStrcasecmp(tval, "cm") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "cm") == 0) {
lentype = CSS_LENGTH_TYPE_MM;
fval *= 10;
nextToken();
- } else if (dStrcasecmp(tval, "in") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "in") == 0) {
lentype = CSS_LENGTH_TYPE_MM;
fval *= 25.4;
nextToken();
- } else if (dStrcasecmp(tval, "pt") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "pt") == 0) {
lentype = CSS_LENGTH_TYPE_MM;
fval *= (25.4 / 72);
nextToken();
- } else if (dStrcasecmp(tval, "pc") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "pc") == 0) {
lentype = CSS_LENGTH_TYPE_MM;
fval *= (25.4 / 6);
nextToken();
- } else if (dStrcasecmp(tval, "em") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "em") == 0) {
lentype = CSS_LENGTH_TYPE_EM;
nextToken();
- } else if (dStrcasecmp(tval, "ex") == 0) {
+ } else if (dStrAsciiCasecmp(tval, "ex") == 0) {
lentype = CSS_LENGTH_TYPE_EX;
nextToken();
} else {
@@ -926,7 +931,7 @@ bool CssParser::parseValue(CssPropertyName prop,
ret = true;
val->intVal = CSS_CREATE_LENGTH(fval, lentype);
- } else if (ttype == CSS_TK_SYMBOL && dStrcasecmp(tval, "auto") == 0) {
+ } else if (ttype == CSS_TK_SYMBOL && !dStrAsciiCasecmp(tval, "auto")) {
ret = true;
val->intVal = CSS_LENGTH_TYPE_AUTO;
nextToken();
@@ -942,7 +947,7 @@ bool CssParser::parseValue(CssPropertyName prop,
ret = true;
nextToken();
} else if (ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(tval, "rgb") == 0) {
+ if (dStrAsciiCasecmp(tval, "rgb") == 0) {
nextToken();
if (parseRgbColor(&val->intVal))
ret = true;
@@ -1021,7 +1026,7 @@ bool CssParser::parseWeight()
if (ttype == CSS_TK_CHAR && tval[0] == '!') {
nextToken();
if (ttype == CSS_TK_SYMBOL &&
- dStrcasecmp(tval, "important") == 0) {
+ dStrAsciiCasecmp(tval, "important") == 0) {
nextToken();
return true;
}
@@ -1035,7 +1040,7 @@ bool CssParser::parseWeight()
*/
static int Css_property_info_cmp(const void *a, const void *b)
{
- return dStrcasecmp(((CssPropertyInfo *) a)->symbol,
+ return dStrAsciiCasecmp(((CssPropertyInfo *) a)->symbol,
((CssPropertyInfo *) b)->symbol);
}
@@ -1045,7 +1050,7 @@ static int Css_property_info_cmp(const void *a, const void *b)
*/
static int Css_shorthand_info_cmp(const void *a, const void *b)
{
- return dStrcasecmp(((CssShorthandInfo *) a)->symbol,
+ return dStrAsciiCasecmp(((CssShorthandInfo *) a)->symbol,
((CssShorthandInfo *) b)->symbol);
}
@@ -1291,13 +1296,13 @@ CssSelector *CssParser::parseSelector()
(tval[0] == ',' || tval[0] == '{')) {
break;
} else if (ttype == CSS_TK_CHAR && tval[0] == '>') {
- selector->addSimpleSelector (CssSelector::CHILD);
+ selector->addSimpleSelector (CssSelector::COMB_CHILD);
nextToken();
} else if (ttype == CSS_TK_CHAR && tval[0] == '+') {
- selector->addSimpleSelector (CssSelector::ADJACENT_SIBLING);
+ selector->addSimpleSelector (CssSelector::COMB_ADJACENT_SIBLING);
nextToken();
} else if (ttype != CSS_TK_END && spaceSeparated) {
- selector->addSimpleSelector (CssSelector::DESCENDANT);
+ selector->addSimpleSelector (CssSelector::COMB_DESCENDANT);
} else {
delete selector;
selector = NULL;
@@ -1390,7 +1395,7 @@ char * CssParser::parseUrl()
Dstr *urlStr = NULL;
if (ttype != CSS_TK_SYMBOL ||
- dStrcasecmp(tval, "url") != 0)
+ dStrAsciiCasecmp(tval, "url") != 0)
return NULL;
nextToken();
@@ -1436,7 +1441,7 @@ void CssParser::parseImport(DilloHtml *html, DilloUrl *baseUrl)
nextToken();
if (ttype == CSS_TK_SYMBOL &&
- dStrcasecmp(tval, "url") == 0)
+ dStrAsciiCasecmp(tval, "url") == 0)
urlStr = parseUrl();
else if (ttype == CSS_TK_STRING)
urlStr = dStrdup (tval);
@@ -1448,8 +1453,8 @@ void CssParser::parseImport(DilloHtml *html, DilloUrl *baseUrl)
mediaSyntaxIsOK = false;
mediaIsSelected = false;
while (ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(tval, "all") == 0 ||
- dStrcasecmp(tval, "screen") == 0)
+ if (dStrAsciiCasecmp(tval, "all") == 0 ||
+ dStrAsciiCasecmp(tval, "screen") == 0)
mediaIsSelected = true;
nextToken();
if (ttype == CSS_TK_CHAR && tval[0] == ',') {
@@ -1490,8 +1495,8 @@ void CssParser::parseMedia()
/* parse a comma-separated list of media */
while (ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(tval, "all") == 0 ||
- dStrcasecmp(tval, "screen") == 0)
+ if (dStrAsciiCasecmp(tval, "all") == 0 ||
+ dStrAsciiCasecmp(tval, "screen") == 0)
mediaIsSelected = true;
nextToken();
if (ttype == CSS_TK_CHAR && tval[0] == ',') {
@@ -1577,11 +1582,11 @@ void CssParser::parse(DilloHtml *html, DilloUrl *url, CssContext * context,
parser.tval[0] == '@') {
parser.nextToken();
if (parser.ttype == CSS_TK_SYMBOL) {
- if (dStrcasecmp(parser.tval, "import") == 0 &&
+ if (dStrAsciiCasecmp(parser.tval, "import") == 0 &&
html != NULL &&
importsAreAllowed) {
parser.parseImport(html, url);
- } else if (dStrcasecmp(parser.tval, "media") == 0) {
+ } else if (dStrAsciiCasecmp(parser.tval, "media") == 0) {
parser.parseMedia();
} else {
parser.ignoreStatement();
diff --git a/src/decode.c b/src/decode.c
index 24067318..7ea3dc25 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -190,7 +190,7 @@ Decode *a_Decode_transfer_init(const char *format)
{
Decode *dc = NULL;
- if (format && !dStrcasecmp(format, "chunked")) {
+ if (format && !dStrAsciiCasecmp(format, "chunked")) {
int *chunk_remaining = dNew(int, 1);
*chunk_remaining = 0;
dc = dNew(Decode, 1);
@@ -215,7 +215,8 @@ Decode *a_Decode_content_init(const char *format)
Decode *dc = NULL;
if (format && *format) {
- if (!dStrcasecmp(format, "gzip") || !dStrcasecmp(format, "x-gzip")) {
+ if (!dStrAsciiCasecmp(format, "gzip") ||
+ !dStrAsciiCasecmp(format, "x-gzip")) {
z_stream *zs;
_MSG("gzipped data!\n");
@@ -245,17 +246,17 @@ Decode *a_Decode_content_init(const char *format)
*/
static int Decode_is_ascii(const char *str)
{
- return (!(dStrcasecmp(str, "ASCII") &&
- dStrcasecmp(str, "US-ASCII") &&
- dStrcasecmp(str, "us") &&
- dStrcasecmp(str, "IBM367") &&
- dStrcasecmp(str, "cp367") &&
- dStrcasecmp(str, "csASCII") &&
- dStrcasecmp(str, "ANSI_X3.4-1968") &&
- dStrcasecmp(str, "iso-ir-6") &&
- dStrcasecmp(str, "ANSI_X3.4-1986") &&
- dStrcasecmp(str, "ISO_646.irv:1991") &&
- dStrcasecmp(str, "ISO646-US")));
+ return (!(dStrAsciiCasecmp(str, "ASCII") &&
+ dStrAsciiCasecmp(str, "US-ASCII") &&
+ dStrAsciiCasecmp(str, "us") &&
+ dStrAsciiCasecmp(str, "IBM367") &&
+ dStrAsciiCasecmp(str, "cp367") &&
+ dStrAsciiCasecmp(str, "csASCII") &&
+ dStrAsciiCasecmp(str, "ANSI_X3.4-1968") &&
+ dStrAsciiCasecmp(str, "iso-ir-6") &&
+ dStrAsciiCasecmp(str, "ANSI_X3.4-1986") &&
+ dStrAsciiCasecmp(str, "ISO_646.irv:1991") &&
+ dStrAsciiCasecmp(str, "ISO646-US")));
}
/*
@@ -271,7 +272,7 @@ Decode *a_Decode_charset_init(const char *format)
if (format &&
strlen(format) &&
- dStrcasecmp(format,"UTF-8") &&
+ dStrAsciiCasecmp(format,"UTF-8") &&
!Decode_is_ascii(format)) {
iconv_t ic = iconv_open("UTF-8", format);
diff --git a/src/dialog.cc b/src/dialog.cc
index 15e5d7a9..f830f2d3 100644
--- a/src/dialog.cc
+++ b/src/dialog.cc
@@ -95,6 +95,24 @@ public:
};
};
+class EnterButton : public Fl_Button {
+public:
+ EnterButton (int x,int y,int w,int h, const char* label = 0) :
+ Fl_Button (x,y,w,h,label) {};
+ int handle(int e);
+};
+
+int EnterButton::handle(int e)
+{
+ if (e == FL_KEYBOARD && Fl::focus() == this && Fl::event_key() == FL_Enter){
+ set_changed();
+ simulate_key_action();
+ do_callback();
+ return 1;
+ }
+ return Fl_Button::handle(e);
+}
+
//----------------------------------------------------------------------------
@@ -354,7 +372,7 @@ int a_Dialog_choice5(const char *QuestionTxt,
bw = (ww - gap)/nb - gap;
xpos += gap;
for (int i=1; i <= nb; ++i) {
- b = new Fl_Button(xpos, wh-bh, bw, bh, txt[i]);
+ b = new EnterButton(xpos, wh-bh, bw, bh, txt[i]);
b->align(FL_ALIGN_WRAP|FL_ALIGN_CLIP);
b->box(FL_UP_BOX);
b->callback(choice5_cb, INT2VOIDP(i));
@@ -426,14 +444,14 @@ int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp)
/* "OK" button */
y += input_h + 20;
- Fl_Button *ok_button = new Fl_Button(200, y, 50, button_h, "OK");
+ Fl_Button *ok_button = new EnterButton(200, y, 50, button_h, "OK");
ok_button->labelsize(14);
ok_button->callback(Dialog_user_password_cb);
window->add(ok_button);
/* "Cancel" button */
Fl_Button *cancel_button =
- new Fl_Button(50, y, 100, button_h, "Cancel");
+ new EnterButton(50, y, 100, button_h, "Cancel");
cancel_button->labelsize(14);
cancel_button->callback(Dialog_user_password_cb);
window->add(cancel_button);
diff --git a/src/digest.c b/src/digest.c
new file mode 100644
index 00000000..d5461950
--- /dev/null
+++ b/src/digest.c
@@ -0,0 +1,204 @@
+/*
+ * File: digest.c
+ *
+ * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de>
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include "digest.h"
+#include "md5.h"
+#include "msg.h"
+#include "../dlib/dlib.h"
+
+static const char *ALGORITHM2STR[] = { NULL, "MD5", "MD5-sess" };
+static const char *QOP2STR[] = { NULL, "auth", "auth-int" };
+static const char hexchars[] = "0123456789abcdef";
+
+static Dstr *md5hexdigest(const Dstr *data)
+{
+ md5_state_t state;
+ md5_byte_t digest[16];
+ Dstr *result = dStr_sized_new(33);
+ int i;
+
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t *)data->str, data->len);
+ md5_finish(&state, digest);
+
+ for (i = 0; i < 16; i++)
+ dStr_sprintfa(result, "%02x", digest[i]);
+ return result;
+}
+
+/*
+ * Returns a pointer to a newly allocated string containing a cnonce
+ */
+char *a_Digest_create_cnonce(void)
+{
+ int i;
+ char *result = dNew(char, 33);
+ for (i = 0; i < 32; i++)
+ result[i] = hexchars[rand() % 16];
+ result[32] = 0;
+ return result;
+}
+
+/*
+ * This portion only has to be calculated once.
+ */
+int a_Digest_compute_digest(AuthRealm_t *realm, const char *username,
+ const char *passwd)
+{
+ Dstr *a1;
+ Dstr *digest;
+
+ if (realm->algorithm == MD5 || realm->algorithm == ALGORITHMNOTSET) {
+ /* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */
+ a1 = dStr_new(NULL);
+ dStr_sprintf(a1, "%s:%s:%s", username, realm->name, passwd);
+ } else if (realm->algorithm == MD5SESS) {
+ /* A1 = H( unq(username-value) ":" unq(realm-value)
+ ** ":" passwd )
+ ** ":" unq(nonce-value) ":" unq(cnonce-value)
+ */
+ Dstr *a0 = dStr_new(NULL);
+ dStr_sprintf(a0, "%s:%s:%s", username, realm->name, passwd);
+ Dstr *ha0 = md5hexdigest(a0);
+ a1 = dStr_new(NULL);
+ dStr_sprintf(a1, "%s:%s:%s", ha0, realm->nonce, realm->cnonce);
+ dStr_free(a0, 1);
+ dStr_free(ha0, 1);
+ } else {
+ MSG("a_Digest_create_auth: Unknown algorithm.\n");
+ return 0;
+ }
+
+ digest = md5hexdigest(a1);
+ realm->authorization = digest->str;
+ dStr_shred(a1);
+ dStr_free(a1, 1);
+ dStr_free(digest, 0);
+ return 1;
+}
+
+/*
+ * This portion is calculatd for each request.
+ */
+static Dstr *Digest_create_response(AuthRealm_t *realm, const char *method,
+ const char *digest_uri,
+ const Dstr *entity_body)
+{
+ Dstr *ha2;
+ Dstr *result;
+
+ if (realm->qop == QOPNOTSET || realm->qop == AUTH) {
+ /* A2 = Method ":" digest-uri-value */
+ Dstr *a2 = dStr_new(NULL);
+ dStr_sprintf(a2, "%s:%s", method, digest_uri);
+ ha2 = md5hexdigest(a2);
+ dStr_free(a2, 1);
+ } else if (realm->qop == AUTHINT) {
+ /* A2 = Method ":" digest-uri-value ":" H(entity-body) */
+ Dstr *hentity = md5hexdigest(entity_body);
+ Dstr *a2 = dStr_new(NULL);
+ dStr_sprintf(a2, "%s:%s:%s", method, digest_uri, hentity->str);
+ ha2 = md5hexdigest(a2);
+ dStr_free(hentity, 1);
+ dStr_free(a2, 1);
+ } else {
+ MSG("a_Digest_create_auth: Unknown qop value.\n");
+ return NULL;
+ }
+ result = dStr_new(NULL);
+
+ if (realm->qop == AUTH || realm->qop == AUTHINT) {
+ dStr_sprintf(result,
+ "%s:%s:%08x:%s:%s:%s",
+ realm->authorization,
+ realm->nonce,
+ realm->nonce_count,
+ realm->cnonce,
+ QOP2STR[realm->qop],
+ ha2->str);
+ } else {
+ dStr_sprintf(result,
+ "%s:%s:%s",
+ realm->authorization,
+ realm->nonce,
+ ha2->str);
+ }
+
+ Dstr *request_digest = md5hexdigest(result);
+ dStr_free(result, 1);
+ dStr_free(ha2, 1);
+ return request_digest;
+}
+
+static void Digest_Dstr_append_token_value(Dstr *str, int delimiter,
+ const char *token,
+ const char *value, int quoted)
+{
+ char c;
+ dStr_sprintfa(str, "%s%s=", (delimiter ? ", " : ""), token);
+ if (quoted) {
+ dStr_append_c(str, '"');
+ while ((c = *value++)) {
+ if (c == '"')
+ dStr_append_c(str, '\\');
+ dStr_append_c(str, c);
+ }
+ dStr_append_c(str, '"');
+ } else {
+ dStr_append(str, value);
+ }
+}
+
+/*
+ * Construct Digest Authorization header.
+ *
+ * Field ordering: furaisanjin reports that his DVD recorder requires the
+ * order that IE happens to use: "username, realm, nonce, uri, cnonce, nc,
+ * algorithm, response, qop". It apparently doesn't use "opaque", so that's
+ * been left where it already was.
+ */
+char *a_Digest_authorization_hdr(AuthRealm_t *realm, const DilloUrl *url,
+ const char *digest_uri)
+{
+ char *ret;
+ Dstr *response, *result;
+ const char *method = URL_FLAGS(url) & URL_Post ? "POST" : "GET";
+
+ realm->nonce_count++;
+ response = Digest_create_response(realm, method, digest_uri, URL_DATA(url));
+ if (!response)
+ return NULL;
+ result = dStr_new("Authorization: Digest ");
+ Digest_Dstr_append_token_value(result, 0, "username", realm->username, 1);
+ Digest_Dstr_append_token_value(result, 1, "realm", realm->name, 1);
+ Digest_Dstr_append_token_value(result, 1, "nonce", realm->nonce, 1);
+ Digest_Dstr_append_token_value(result, 1, "uri", digest_uri, 1);
+ if (realm->qop != QOPNOTSET) {
+ Digest_Dstr_append_token_value(result, 1, "cnonce", realm->cnonce, 1);
+ dStr_sprintfa(result, ", nc=%08x", realm->nonce_count);
+ }
+ if (realm->algorithm != ALGORITHMNOTSET) {
+ Digest_Dstr_append_token_value(result, 1, "algorithm",
+ ALGORITHM2STR[realm->algorithm], 0);
+ }
+ Digest_Dstr_append_token_value(result, 1, "response", response->str, 1);
+ if (realm->opaque)
+ Digest_Dstr_append_token_value(result, 1, "opaque", realm->opaque, 1);
+ if (realm->qop != QOPNOTSET)
+ Digest_Dstr_append_token_value(result, 1, "qop", QOP2STR[realm->qop], 1);
+ dStr_sprintfa(result, "\r\n");
+
+ dStr_free(response, 1);
+ ret = result->str;
+ dStr_free(result, 0);
+ return ret;
+}
diff --git a/src/digest.h b/src/digest.h
new file mode 100644
index 00000000..2723c645
--- /dev/null
+++ b/src/digest.h
@@ -0,0 +1,16 @@
+#ifndef __DIGEST_H__
+#define __DIGEST_H__
+
+#include "auth.h"
+#include "../dlib/dlib.h"
+
+
+char *a_Digest_create_cnonce(void);
+int a_Digest_compute_digest(AuthRealm_t *realm,
+ const char *username,
+ const char *passwd);
+char *a_Digest_authorization_hdr(AuthRealm_t *realm,
+ const DilloUrl *url,
+ const char *uri);
+
+#endif /* !__DIGEST_H__ */
diff --git a/src/dillo.cc b/src/dillo.cc
index b05cb16a..7552676d 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -410,8 +410,9 @@ int main(int argc, char **argv)
if (idx == argc) {
/* No URLs/files on cmdline. Send startup screen */
- if (strcmp(URL_STR(prefs.start_page), "about:blank") == 0)
- a_UIcmd_open_url(bw, NULL);
+ if (dStrAsciiCasecmp(URL_SCHEME(prefs.start_page), "about") == 0 &&
+ strcmp(URL_PATH(prefs.start_page), "blank") == 0)
+ a_UIcmd_open_url(bw, NULL); // NULL URL focuses location
else
a_UIcmd_open_url(bw, prefs.start_page);
} else {
diff --git a/src/dns.c b/src/dns.c
index 980586c6..3989701d 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -24,11 +24,13 @@
#endif
+#include <assert.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
@@ -38,7 +40,7 @@
#include "msg.h"
#include "dns.h"
#include "list.h"
-#include "timeout.hh"
+#include "IO/iowatch.hh"
/* Maximum dns resolving threads */
@@ -48,13 +50,17 @@
# define D_DNS_MAX_SERVERS 1
#endif
+typedef enum {
+ DNS_SERVER_IDLE,
+ DNS_SERVER_PROCESSING,
+ DNS_SERVER_RESOLVED,
+} DnsServerState_t;
typedef struct {
int channel; /* Index of this channel [0 based] */
- bool_t in_use; /* boolean to tell if server is doing a lookup */
- bool_t ip_ready; /* boolean: is IP lookup done? */
+ DnsServerState_t state;
Dlist *addr_list; /* IP address */
- char *hostname; /* Adress to resolve */
+ char *hostname; /* Address to resolve */
int status; /* errno code for resolving function */
#ifdef D_DNS_THREADED
pthread_t th1; /* Thread id */
@@ -77,7 +83,7 @@ typedef struct {
/*
* Forward declarations
*/
-static void Dns_timeout_client(void *data);
+static void Dns_timeout_client(int fd, void *data);
/*
* Local Data
@@ -88,6 +94,7 @@ static GDnsCache *dns_cache;
static int dns_cache_size, dns_cache_size_max;
static GDnsQueue *dns_queue;
static int dns_queue_size, dns_queue_size_max;
+static int dns_notify_pipe[2];
/* ----------------------------------------------------------------------
@@ -113,7 +120,7 @@ static int Dns_queue_find(const char *hostname)
int i;
for (i = 0; i < dns_queue_size; i++)
- if (!strcmp(hostname, dns_queue[i].hostname))
+ if (!dStrAsciiCasecmp(hostname, dns_queue[i].hostname))
return i;
return -1;
@@ -169,7 +176,7 @@ static void Dns_cache_add(char *hostname, Dlist *addr_list)
*/
void a_Dns_init(void)
{
- int i;
+ int res, i;
#ifdef D_DNS_THREADED
MSG("dillo_dns_init: Here we go! (threaded)\n");
@@ -187,11 +194,15 @@ void a_Dns_init(void)
num_servers = D_DNS_MAX_SERVERS;
+ res = pipe(dns_notify_pipe);
+ assert(res == 0);
+ fcntl(dns_notify_pipe[0], F_SETFL, O_NONBLOCK);
+ a_IOwatch_add_fd(dns_notify_pipe[0], DIO_READ, Dns_timeout_client, NULL);
+
/* Initialize servers data */
for (i = 0; i < num_servers; ++i) {
dns_server[i].channel = i;
- dns_server[i].in_use = FALSE;
- dns_server[i].ip_ready = FALSE;
+ dns_server[i].state = DNS_SERVER_IDLE;
dns_server[i].addr_list = NULL;
dns_server[i].hostname = NULL;
dns_server[i].status = 0;
@@ -323,7 +334,9 @@ static void *Dns_server(void *data)
MSG(" (nil)\n");
}
dns_server[channel].addr_list = hosts;
- dns_server[channel].ip_ready = TRUE;
+ dns_server[channel].state = DNS_SERVER_RESOLVED;
+
+ write(dns_notify_pipe[1], ".", 1);
return NULL; /* (avoids a compiler warning) */
}
@@ -339,16 +352,11 @@ static void Dns_server_req(int channel, const char *hostname)
static int thrATTRInitialized = 0;
#endif
- dns_server[channel].in_use = TRUE;
- dns_server[channel].ip_ready = FALSE;
+ dns_server[channel].state = DNS_SERVER_PROCESSING;
dFree(dns_server[channel].hostname);
dns_server[channel].hostname = dStrdup(hostname);
- /* Let's set a timeout client to poll the server channel (5 times/sec) */
- a_Timeout_add(0.2,Dns_timeout_client,
- INT2VOIDP(dns_server[channel].channel));
-
#ifdef D_DNS_THREADED
/* set the thread attribute to the detached state */
if (!thrATTRInitialized) {
@@ -377,7 +385,7 @@ void a_Dns_resolve(const char *hostname, DnsCallback_t cb_func, void *cb_data)
/* check for cache hit. */
for (i = 0; i < dns_cache_size; i++)
- if (!strcmp(hostname, dns_cache[i].hostname))
+ if (!dStrAsciiCasecmp(hostname, dns_cache[i].hostname))
break;
if (i < dns_cache_size) {
@@ -393,7 +401,7 @@ void a_Dns_resolve(const char *hostname, DnsCallback_t cb_func, void *cb_data)
/* Find a channel we can send the request to */
for (channel = 0; channel < num_servers; channel++)
- if (!dns_server[channel].in_use)
+ if (dns_server[channel].state == DNS_SERVER_IDLE)
break;
if (channel < num_servers) {
/* Found a free channel! */
@@ -422,8 +430,6 @@ static void Dns_serve_channel(int channel)
--i;
}
}
- /* set current channel free */
- srv->in_use = FALSE;
}
/*
@@ -434,7 +440,7 @@ static void Dns_assign_channels(void)
int ch, i, j;
for (ch = 0; ch < num_servers; ++ch) {
- if (dns_server[ch].in_use == FALSE) {
+ if (dns_server[ch].state == DNS_SERVER_IDLE) {
/* Find the next query in the queue (we're a FIFO) */
for (i = 0; i < dns_queue_size; i++)
if (dns_queue[i].channel == -2)
@@ -445,8 +451,10 @@ static void Dns_assign_channels(void)
* with the same hostname*/
for (j = i; j < dns_queue_size; j++)
if (dns_queue[j].channel == -2 &&
- !strcmp(dns_queue[j].hostname, dns_queue[i].hostname))
+ !dStrAsciiCasecmp(dns_queue[j].hostname,
+ dns_queue[i].hostname)) {
dns_queue[j].channel = ch;
+ }
Dns_server_req(ch, dns_queue[i].hostname);
} else
return;
@@ -455,27 +463,29 @@ static void Dns_assign_channels(void)
}
/*
- * This is a timeout function that
- * reads the DNS results and resumes the stopped jobs.
+ * This function is called on the main thread and
+ * reads the DNS results.
*/
-static void Dns_timeout_client(void *data)
+static void Dns_timeout_client(int fd, void *data)
{
- int channel = VOIDP2INT(data);
- DnsServer *srv = &dns_server[channel];
+ int i;
+ char buf[16];
- if (srv->ip_ready) {
- if (srv->addr_list != NULL) {
- /* DNS succeeded, let's cache it */
- Dns_cache_add(srv->hostname, srv->addr_list);
- }
- Dns_serve_channel(channel);
- Dns_assign_channels();
- a_Timeout_remove(); /* Done! */
+ while (read(dns_notify_pipe[0], buf, sizeof(buf)) > 0);
- } else {
- /* IP not already resolved, keep on trying... */
- a_Timeout_repeat(0.2, Dns_timeout_client, data);
+ for (i = 0; i < num_servers; ++i) {
+ DnsServer *srv = &dns_server[i];
+
+ if (srv->state == DNS_SERVER_RESOLVED) {
+ if (srv->addr_list != NULL) {
+ /* DNS succeeded, let's cache it */
+ Dns_cache_add(srv->hostname, srv->addr_list);
+ }
+ Dns_serve_channel(i);
+ srv->state = DNS_SERVER_IDLE;
+ }
}
+ Dns_assign_channels();
}
@@ -495,6 +505,9 @@ void a_Dns_freeall(void)
dFree(dList_nth_data(dns_cache[i].addr_list, j));
dList_free(dns_cache[i].addr_list);
}
+ a_IOwatch_remove_fd(dns_notify_pipe[0], DIO_READ);
+ close(dns_notify_pipe[0]);
+ close(dns_notify_pipe[1]);
dFree(dns_cache);
}
diff --git a/src/form.cc b/src/form.cc
index f70bea8c..8275c12b 100644
--- a/src/form.cc
+++ b/src/form.cc
@@ -271,7 +271,7 @@ static DilloHtmlInput *Html_get_radio_input(DilloHtml *html, const char *name)
for (int idx = 0; idx < inputs->size(); idx++) {
DilloHtmlInput *input = inputs->get(idx);
if (input->type == DILLO_HTML_INPUT_RADIO &&
- input->name && !dStrcasecmp(input->name, name))
+ input->name && !dStrAsciiCasecmp(input->name, name))
return input;
}
}
@@ -279,8 +279,7 @@ static DilloHtmlInput *Html_get_radio_input(DilloHtml *html, const char *name)
}
/*
- * Get the current input.
- * Note that this _assumes_ that there _is_ a current input.
+ * Get the current input if available.
*/
static DilloHtmlInput *Html_get_current_input(DilloHtml *html)
{
@@ -291,7 +290,8 @@ static DilloHtmlInput *Html_get_current_input(DilloHtml *html)
else
inputs = html->inputs_outside_form;
- return inputs->get (inputs->size() - 1);
+ return (inputs && inputs->size() > 0) ?
+ inputs->get (inputs->size() - 1) : NULL;
}
/*
@@ -318,9 +318,9 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
method = DILLO_HTML_METHOD_GET;
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "method"))) {
- if (!dStrcasecmp(attrbuf, "post")) {
+ if (!dStrAsciiCasecmp(attrbuf, "post")) {
method = DILLO_HTML_METHOD_POST;
- } else if (dStrcasecmp(attrbuf, "get")) {
+ } else if (dStrAsciiCasecmp(attrbuf, "get")) {
BUG_MSG("Unknown form submission method \"%s\"\n", attrbuf);
}
}
@@ -333,7 +333,7 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
content_type = DILLO_HTML_ENC_URLENCODED;
if ((method == DILLO_HTML_METHOD_POST) &&
((attrbuf = a_Html_get_attr(html, tag, tagsize, "enctype")))) {
- if (!dStrcasecmp(attrbuf, "multipart/form-data"))
+ if (!dStrAsciiCasecmp(attrbuf, "multipart/form-data"))
content_type = DILLO_HTML_ENC_MULTIPART;
}
charset = NULL;
@@ -343,9 +343,9 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
char *ptr = first = dStrdup(attrbuf);
while (ptr && !charset) {
char *curr = dStrsep(&ptr, " ,");
- if (!dStrcasecmp(curr, "utf-8")) {
+ if (!dStrAsciiCasecmp(curr, "utf-8")) {
charset = curr;
- } else if (!dStrcasecmp(curr, "UNKNOWN")) {
+ } else if (!dStrAsciiCasecmp(curr, "UNKNOWN")) {
/* defined to be whatever encoding the document is in */
charset = html->charset;
}
@@ -441,18 +441,18 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
init_str = NULL;
inp_type = DILLO_HTML_INPUT_UNKNOWN;
- if (!dStrcasecmp(type, "password")) {
+ if (!dStrAsciiCasecmp(type, "password")) {
inp_type = DILLO_HTML_INPUT_PASSWORD;
attrbuf = a_Html_get_attr(html, tag, tagsize, "size");
int size = Html_input_get_size(html, attrbuf);
resource = factory->createEntryResource (size, true, NULL);
init_str = value;
- } else if (!dStrcasecmp(type, "checkbox")) {
+ } else if (!dStrAsciiCasecmp(type, "checkbox")) {
inp_type = DILLO_HTML_INPUT_CHECKBOX;
resource = factory->createCheckButtonResource(false);
init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL);
init_str = (value) ? value : dStrdup("on");
- } else if (!dStrcasecmp(type, "radio")) {
+ } else if (!dStrAsciiCasecmp(type, "radio")) {
inp_type = DILLO_HTML_INPUT_RADIO;
RadioButtonResource *rb_r = NULL;
DilloHtmlInput *input = Html_get_radio_input(html, name);
@@ -461,22 +461,22 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
resource = factory->createRadioButtonResource(rb_r, false);
init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL);
init_str = value;
- } else if (!dStrcasecmp(type, "hidden")) {
+ } else if (!dStrAsciiCasecmp(type, "hidden")) {
inp_type = DILLO_HTML_INPUT_HIDDEN;
init_str = value;
int size = Html_input_get_size(html, NULL);
resource = factory->createEntryResource(size, false, name);
- } else if (!dStrcasecmp(type, "submit")) {
+ } else if (!dStrAsciiCasecmp(type, "submit")) {
inp_type = DILLO_HTML_INPUT_SUBMIT;
init_str = (value) ? value : dStrdup("submit");
resource = factory->createLabelButtonResource(init_str);
// gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */
- } else if (!dStrcasecmp(type, "reset")) {
+ } else if (!dStrAsciiCasecmp(type, "reset")) {
inp_type = DILLO_HTML_INPUT_RESET;
init_str = (value) ? value : dStrdup("Reset");
resource = factory->createLabelButtonResource(init_str);
// gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */
- } else if (!dStrcasecmp(type, "image")) {
+ } else if (!dStrAsciiCasecmp(type, "image")) {
if (URL_FLAGS(html->base_url) & URL_SpamSafe) {
/* Don't request the image; make a text submit button instead */
inp_type = DILLO_HTML_INPUT_SUBMIT;
@@ -491,7 +491,7 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
embed = Html_input_image(html, tag, tagsize);
init_str = value;
}
- } else if (!dStrcasecmp(type, "file")) {
+ } else if (!dStrAsciiCasecmp(type, "file")) {
bool valid = true;
if (html->InFlags & IN_FORM) {
DilloHtmlForm *form = html->getCurrentForm();
@@ -512,24 +512,22 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
init_str = dStrdup("File selector");
resource = factory->createLabelButtonResource(init_str);
}
- } else if (!dStrcasecmp(type, "button")) {
+ } else if (!dStrAsciiCasecmp(type, "button")) {
inp_type = DILLO_HTML_INPUT_BUTTON;
if (value) {
init_str = value;
resource = factory->createLabelButtonResource(init_str);
}
- } else if (!dStrcasecmp(type, "text") || !*type) {
+ } else {
/* Text input, which also is the default */
inp_type = DILLO_HTML_INPUT_TEXT;
+ if (*type && dStrAsciiCasecmp(type, "text"))
+ BUG_MSG("Unknown input type: \"%s\"\n", type);
attrbuf = a_Html_get_attr(html, tag, tagsize, "size");
int size = Html_input_get_size(html, attrbuf);
resource = factory->createEntryResource(size, false, NULL);
init_str = value;
- } else {
- /* Unknown input type */
- BUG_MSG("Unknown input type: \"%s\"\n", type);
}
-
if (resource)
embed = new Embed (resource);
@@ -609,17 +607,8 @@ void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
html->InFlags &= ~IN_FORM;
}
-/*
- * The textarea tag
- */
void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
{
- const int MAX_COLS=1024, MAX_ROWS=10000;
-
- char *name;
- const char *attrbuf;
- int cols, rows;
-
if (html->InFlags & IN_TEXTAREA) {
BUG_MSG("nested <textarea>\n");
html->ReqTagClose = TRUE;
@@ -631,6 +620,19 @@ void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
}
html->InFlags |= IN_TEXTAREA;
+}
+
+/*
+ * The textarea tag
+ */
+void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize)
+{
+ const int MAX_COLS=1024, MAX_ROWS=10000;
+
+ char *name;
+ const char *attrbuf;
+ int cols, rows;
+
a_Html_stash_init(html);
S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM;
@@ -684,7 +686,7 @@ void Html_tag_close_textarea(DilloHtml *html, int TagIdx)
DilloHtmlInput *input;
int i;
- if (html->InFlags & IN_TEXTAREA) {
+ if (html->InFlags & IN_TEXTAREA && !S_TOP(html)->display_none) {
/* Remove the line ending that follows the opening tag */
if (html->Stash->str[0] == '\r')
dStr_erase(html->Stash, 0, 1);
@@ -705,8 +707,10 @@ void Html_tag_close_textarea(DilloHtml *html, int TagIdx)
/* The HTML3.2 spec says it can have "text and character entities". */
str = a_Html_parse_entities(html, html->Stash->str, html->Stash->len);
input = Html_get_current_input(html);
- input->init_str = str;
- ((MultiLineTextResource *)input->embed->getResource ())->setText(str);
+ if (input) {
+ input->init_str = str;
+ ((MultiLineTextResource *)input->embed->getResource ())->setText(str);
+ }
html->InFlags &= ~IN_TEXTAREA;
}
@@ -833,11 +837,11 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize)
type = a_Html_get_attr_wdef(html, tag, tagsize, "type", "");
- if (!dStrcasecmp(type, "button")) {
+ if (!dStrAsciiCasecmp(type, "button")) {
inp_type = DILLO_HTML_INPUT_BUTTON;
- } else if (!dStrcasecmp(type, "reset")) {
+ } else if (!dStrAsciiCasecmp(type, "reset")) {
inp_type = DILLO_HTML_INPUT_BUTTON_RESET;
- } else if (!dStrcasecmp(type, "submit") || !*type) {
+ } else if (!dStrAsciiCasecmp(type, "submit") || !*type) {
/* submit button is the default */
inp_type = DILLO_HTML_INPUT_BUTTON_SUBMIT;
} else {
@@ -1036,7 +1040,7 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit)
char *boundary = NULL;
iconv_t char_encoder = (iconv_t) -1;
- if (submit_charset && dStrcasecmp(submit_charset, "UTF-8")) {
+ if (submit_charset && dStrAsciiCasecmp(submit_charset, "UTF-8")) {
char_encoder = iconv_open(submit_charset, "UTF-8");
if (char_encoder == (iconv_t) -1) {
MSG_WARN("Cannot convert to character encoding '%s'\n",
@@ -1310,8 +1314,8 @@ void DilloHtmlForm::filesInputMultipartAppend(Dstr* data,
(void)a_Misc_get_content_type_from_data(file->str, file->len, &ctype);
/* Heuristic: text/plain with ".htm[l]" extension -> text/html */
if ((ext = strrchr(filename, '.')) &&
- !dStrcasecmp(ctype, "text/plain") &&
- (!dStrcasecmp(ext, ".html") || !dStrcasecmp(ext, ".htm"))) {
+ !dStrAsciiCasecmp(ctype, "text/plain") &&
+ (!dStrAsciiCasecmp(ext, ".html") || !dStrAsciiCasecmp(ext, ".htm"))){
ctype = "text/html";
}
@@ -1476,7 +1480,7 @@ DilloHtmlInput *DilloHtmlForm::getRadioInput (const char *name)
for (int idx = 0; idx < inputs->size(); idx++) {
DilloHtmlInput *input = inputs->get(idx);
if (input->type == DILLO_HTML_INPUT_RADIO &&
- input->name && !dStrcasecmp(input->name, name))
+ input->name && !dStrAsciiCasecmp(input->name, name))
return input;
}
return NULL;
@@ -1904,29 +1908,21 @@ DilloHtmlOption::~DilloHtmlOption ()
*/
static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize)
{
- const char *attrbuf;
DilloImage *Image;
Embed *button = NULL;
- DilloUrl *url = NULL;
-
- if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "src")) &&
- (url = a_Html_url_new(html, attrbuf, NULL, 0))) {
- html->styleEngine->setPseudoLink ();
-
- /* create new image and add it to the button */
- if ((Image = a_Html_image_new(html, tag, tagsize, url))) {
- IM2DW(Image)->setStyle (html->styleEngine->backgroundStyle ());
- ResourceFactory *factory = HT2LT(html)->getResourceFactory();
- ComplexButtonResource *complex_b_r =
- factory->createComplexButtonResource(IM2DW(Image), false);
- button = new Embed(complex_b_r);
- HT2TB(html)->addWidget (button, html->styleEngine->style ());
-// gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */
+ html->styleEngine->setPseudoLink ();
- } else {
- a_Url_free(url);
- }
+ /* create new image and add it to the button */
+ a_Html_image_attrs(html, tag, tagsize);
+ if ((Image = a_Html_image_new(html, tag, tagsize))) {
+ IM2DW(Image)->setStyle (html->styleEngine->backgroundStyle ());
+ ResourceFactory *factory = HT2LT(html)->getResourceFactory();
+ ComplexButtonResource *complex_b_r =
+ factory->createComplexButtonResource(IM2DW(Image), false);
+ button = new Embed(complex_b_r);
+ HT2TB(html)->addWidget (button, html->styleEngine->style ());
+// gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */
}
if (!button)
MSG("Html_input_image: unable to create image submit.\n");
diff --git a/src/form.hh b/src/form.hh
index a54cde56..cd04543f 100644
--- a/src/form.hh
+++ b/src/form.hh
@@ -52,6 +52,7 @@ void Html_tag_close_form(DilloHtml *html, int TagIdx);
void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize);
+void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_close_textarea(DilloHtml *html, int TagIdx);
void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_close_select(DilloHtml *html, int TagIdx);
diff --git a/src/html.cc b/src/html.cc
index 98fe7b8b..d3c9f383 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -16,7 +16,7 @@
/*-----------------------------------------------------------------------------
* Includes
*---------------------------------------------------------------------------*/
-#include <ctype.h> /* for isspace and tolower */
+#include <ctype.h> /* for isspace */
#include <string.h> /* for memcpy and memmove */
#include <stdlib.h>
#include <stdio.h> /* for sprintf */
@@ -119,6 +119,7 @@ typedef struct {
char EndTag; /* Is it Required, Optional or Forbidden */
uchar_t TagLevel; /* Used to heuristically parse bad HTML */
TagOpenFunct open; /* Open function */
+ TagOpenFunct content; /* Content function */
TagCloseFunct close; /* Close function */
} TagInfo;
extern const TagInfo Tags[];
@@ -284,23 +285,6 @@ static int Html_set_new_link(DilloHtml *html, DilloUrl **url)
}
/*
- * Add a new image to our list.
- * image is NULL if dillo will try to load the image immediately.
- */
-static void Html_add_new_htmlimage(DilloHtml *html,
- DilloUrl **url, DilloImage *image)
-{
- DilloHtmlImage *hi = dNew(DilloHtmlImage, 1);
- hi->url = *url;
- hi->image = image;
- a_Image_ref(image);
-
- int n = html->images->size();
- html->images->increase();
- html->images->set(n, hi);
-}
-
-/*
* Evaluates the ALIGN attribute (left|center|right|justify) and
* sets the style at the top of the stack.
*/
@@ -311,16 +295,16 @@ void a_Html_tag_set_align_attr(DilloHtml *html, const char *tag, int tagsize)
if ((align = a_Html_get_attr(html, tag, tagsize, "align"))) {
TextAlignType textAlignType = TEXT_ALIGN_LEFT;
- if (dStrcasecmp (align, "left") == 0)
+ if (dStrAsciiCasecmp (align, "left") == 0)
textAlignType = TEXT_ALIGN_LEFT;
- else if (dStrcasecmp (align, "right") == 0)
+ else if (dStrAsciiCasecmp (align, "right") == 0)
textAlignType = TEXT_ALIGN_RIGHT;
- else if (dStrcasecmp (align, "center") == 0)
+ else if (dStrAsciiCasecmp (align, "center") == 0)
textAlignType = TEXT_ALIGN_CENTER;
- else if (dStrcasecmp (align, "justify") == 0)
+ else if (dStrAsciiCasecmp (align, "justify") == 0)
textAlignType = TEXT_ALIGN_JUSTIFY;
#if 0
- else if (dStrcasecmp (align, "char") == 0) {
+ else if (dStrAsciiCasecmp (align, "char") == 0) {
/* TODO: Actually not supported for <p> etc. */
v.textAlign = TEXT_ALIGN_STRING;
if ((charattr = a_Html_get_attr(html, tag, tagsize, "char"))) {
@@ -352,11 +336,11 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize)
VAlignType valign;
if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) {
- if (dStrcasecmp (attr, "top") == 0)
+ if (dStrAsciiCasecmp (attr, "top") == 0)
valign = VALIGN_TOP;
- else if (dStrcasecmp (attr, "bottom") == 0)
+ else if (dStrAsciiCasecmp (attr, "bottom") == 0)
valign = VALIGN_BOTTOM;
- else if (dStrcasecmp (attr, "baseline") == 0)
+ else if (dStrAsciiCasecmp (attr, "baseline") == 0)
valign = VALIGN_BASELINE;
else
valign = VALIGN_MIDDLE;
@@ -435,6 +419,7 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url,
stack->getRef(0)->table_mode = DILLO_HTML_TABLE_MODE_NONE;
stack->getRef(0)->table_border_mode = DILLO_HTML_TABLE_BORDER_SEPARATE;
stack->getRef(0)->cell_text_align_set = false;
+ stack->getRef(0)->display_none = false;
stack->getRef(0)->list_type = HTML_LIST_NONE;
stack->getRef(0)->list_number = 0;
stack->getRef(0)->tag_idx = -1; /* MUST not be used */
@@ -662,12 +647,14 @@ void DilloHtml::loadImages (const DilloUrl *pattern)
const DilloUrl *requester = pattern ? NULL : this->page_url;
for (int i = 0; i < images->size(); i++) {
- if (images->get(i)->image) {
- if ((!pattern) || (!a_Url_cmp(images->get(i)->url, pattern))) {
- if (Html_load_image(bw, images->get(i)->url, requester,
- images->get(i)->image)) {
- a_Image_unref (images->get(i)->image);
- images->get(i)->image = NULL; // web owns it now
+ DilloHtmlImage *hi = images->get(i);
+
+ if (hi->image) {
+ assert(hi->url);
+ if ((!pattern) || (!a_Url_cmp(hi->url, pattern))) {
+ if (Html_load_image(bw, hi->url, requester, hi->image)) {
+ a_Image_unref (hi->image);
+ hi->image = NULL; // web owns it now
}
}
}
@@ -1063,7 +1050,9 @@ static void Html_process_space(DilloHtml *html, const char *space,
int i, offset;
DilloHtmlParseMode parse_mode = S_TOP(html)->parse_mode;
- if (parse_mode == DILLO_HTML_PARSE_MODE_STASH) {
+ if (S_TOP(html)->display_none) {
+ /* do nothing */
+ } else if (parse_mode == DILLO_HTML_PARSE_MODE_STASH) {
html->StashSpace = (html->Stash->len > 0);
} else if (parse_mode == DILLO_HTML_PARSE_MODE_VERBATIM) {
@@ -1112,6 +1101,8 @@ static void Html_process_space(DilloHtml *html, const char *space,
}
if (spaceCnt) {
+ // add break possibility for the white-space:pre-wrap case
+ HT2TB(html)->addBreakOption (html->styleEngine->wordStyle ());
spc = dStrnfill(spaceCnt, ' ');
HT2TB(html)->addText (spc, spaceCnt, html->styleEngine->wordStyle ());
dFree(spc);
@@ -1146,6 +1137,9 @@ static void Html_process_word(DilloHtml *html, const char *word, int size)
char *Pword;
DilloHtmlParseMode parse_mode = S_TOP(html)->parse_mode;
+ if (S_TOP(html)->display_none)
+ return;
+
if (parse_mode == DILLO_HTML_PARSE_MODE_STASH ||
parse_mode == DILLO_HTML_PARSE_MODE_STASH_AND_BODY) {
if (html->StashSpace) {
@@ -1213,10 +1207,12 @@ static void Html_process_word(DilloHtml *html, const char *word, int size)
Html_process_space(html, word2 + start, i - start);
} else if (!strncmp(word2+i, utf8_zero_width_space, 3)) {
i += 3;
+ HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ());
} else if (a_Utf8_ideographic(word2+i, beyond_word2, &len)) {
i += len;
HT2TB(html)->addText(word2 + start, i - start,
html->styleEngine->wordStyle ());
+ HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ());
} else {
do {
i += len;
@@ -1241,7 +1237,7 @@ static bool Html_match_tag(const char *tagstr, char *tag, int tagsize)
int i;
for (i = 0; i < tagsize && tagstr[i] != '\0'; i++) {
- if (tolower(tagstr[i]) != tolower(tag[i]))
+ if (D_ASCII_TOLOWER(tagstr[i]) != D_ASCII_TOLOWER(tag[i]))
return false;
}
/* The test for '/' is for xml compatibility: "empty/>" will be matched. */
@@ -1315,7 +1311,8 @@ static void Html_tag_cleanup_to_idx(DilloHtml *html, int idx)
if (s_sz > idx + 1 && toptag.EndTag != 'O')
BUG_MSG(" - forcing close of open tag: <%s>\n", toptag.name);
_MSG("Close: %*s%s\n", size," ", toptag.name);
- toptag.close(html, toptag_idx);
+ if (toptag.close)
+ toptag.close(html, toptag_idx);
Html_real_pop_tag(html);
}
}
@@ -1463,10 +1460,10 @@ static int
int i;
for (i = 0; val[i]; ++i)
- if (!(isalnum(val[i]) || strchr(":_.-", val[i])))
+ if (!isascii(val[i]) || !(isalnum(val[i]) || strchr(":_.-", val[i])))
break;
- if (val[i] || !isalpha(val[0]))
+ if (val[i] || !(isascii(val[0]) && isalpha(val[0])))
BUG_MSG("'%s' value is not of the form "
"[A-Za-z][A-Za-z0-9:_.-]*\n", attrname);
@@ -1531,18 +1528,18 @@ static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize)
_MSG("New: {%s}\n", ntag);
/* The default DT_NONE type is TagSoup */
- if (!dStrncasecmp(ntag, HTML_SGML_sig, strlen(HTML_SGML_sig))) {
+ if (!dStrnAsciiCasecmp(ntag, HTML_SGML_sig, strlen(HTML_SGML_sig))) {
p = ntag + strlen(HTML_SGML_sig) + 1;
if (!strncmp(p, HTML401, strlen(HTML401)) &&
- dStristr(p + strlen(HTML401), HTML401_url)) {
+ dStriAsciiStr(p + strlen(HTML401), HTML401_url)) {
html->DocType = DT_HTML;
html->DocTypeVersion = 4.01f;
} else if (!strncmp(p, XHTML1, strlen(XHTML1)) &&
- dStristr(p + strlen(XHTML1), XHTML1_url)) {
+ dStriAsciiStr(p + strlen(XHTML1), XHTML1_url)) {
html->DocType = DT_XHTML;
html->DocTypeVersion = 1.0f;
} else if (!strncmp(p, XHTML11, strlen(XHTML11)) &&
- dStristr(p + strlen(XHTML11), XHTML11_url)) {
+ dStriAsciiStr(p + strlen(XHTML11), XHTML11_url)) {
html->DocType = DT_XHTML;
html->DocTypeVersion = 1.1f;
} else if (!strncmp(p, HTML40, strlen(HTML40))) {
@@ -1555,7 +1552,7 @@ static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize)
html->DocType = DT_HTML;
html->DocTypeVersion = 2.0f;
}
- } else if (!dStrcasecmp(ntag, HTML5_sig)) {
+ } else if (!dStrAsciiCasecmp(ntag, HTML5_sig)) {
BUG_MSG("Document follows HTML5 working draft; treating as HTML4.\n");
html->DocType = DT_HTML;
html->DocTypeVersion = 5.0f;
@@ -1688,11 +1685,11 @@ static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize)
if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) {
BUG_MSG("type attribute is required for <style>\n");
- } else if (dStrcasecmp(attrbuf, "text/css")) {
+ } else if (dStrAsciiCasecmp(attrbuf, "text/css")) {
html->loadCssFromStash = false;
}
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) &&
- dStrcasecmp(attrbuf, "all") && !dStristr(attrbuf, "screen")) {
+ dStrAsciiCasecmp(attrbuf, "all") && !dStriAsciiStr(attrbuf, "screen")) {
/* HTML 4.01 sec. 6.13 says that media descriptors are case-sensitive,
* but sec. 14.2.3 says that the attribute is case-insensitive.
* TODO can be a comma-separated list.
@@ -1816,8 +1813,6 @@ static void Html_tag_open_p(DilloHtml *html, const char *tag, int tagsize)
CssPropertyList props;
a_Html_tag_set_align_attr (html, tag, tagsize);
- html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
}
/*
@@ -1828,22 +1823,15 @@ static void Html_tag_open_p(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize)
{
const char *attrbuf;
- char *src;
DilloUrl *url;
- Textblock *textblock;
- Widget *bullet;
CssPropertyList props;
- textblock = HT2TB(html);
-
if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src")))
return;
if (!(url = a_Html_url_new(html, attrbuf, NULL, 0)))
return;
- src = dStrdup(attrbuf);
-
if (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached) {
/* visited frame */
html->styleEngine->setPseudoVisited ();
@@ -1854,6 +1842,21 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize)
html->styleEngine->setNonCssHint (PROPERTY_X_LINK, CSS_TYPE_INTEGER,
Html_set_new_link(html,&url));
+}
+
+static void Html_tag_content_frame (DilloHtml *html, const char *tag, int tagsize)
+{
+ const char *attrbuf;
+ char *src;
+ Textblock *textblock;
+ Widget *bullet;
+
+ textblock = HT2TB(html);
+
+ if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src")))
+ return;
+
+ src = dStrdup(attrbuf);
textblock->addParbreak (5, html->styleEngine->wordStyle ());
@@ -1861,7 +1864,7 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize)
textblock->addWidget(bullet, html->styleEngine->wordStyle ());
textblock->addSpace(html->styleEngine->wordStyle ());
- if (tolower(tag[1]) == 'i') {
+ if (D_ASCII_TOLOWER(tag[1]) == 'i') {
/* IFRAME usually comes with very long advertising/spying URLS,
* to not break rendering we will force name="IFRAME" */
textblock->addText ("IFRAME", html->styleEngine->wordStyle ());
@@ -1886,7 +1889,7 @@ static void Html_tag_open_frame (DilloHtml *html, const char *tag, int tagsize)
* TODO: This is just a temporary fix while real frame support
* isn't finished. Imitates lynx/w3m's frames.
*/
-static void Html_tag_open_frameset (DilloHtml *html,
+static void Html_tag_content_frameset (DilloHtml *html,
const char *tag, int tagsize)
{
HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
@@ -1899,11 +1902,8 @@ static void Html_tag_open_frameset (DilloHtml *html,
*/
static void Html_tag_open_h(DilloHtml *html, const char *tag, int tagsize)
{
- html->styleEngine->inheritBackgroundColor ();
a_Html_tag_set_align_attr (html, tag, tagsize);
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
-
a_Html_stash_init(html);
S_TOP(html)->parse_mode =
DILLO_HTML_PARSE_MODE_STASH_AND_BODY;
@@ -1912,7 +1912,7 @@ static void Html_tag_open_h(DilloHtml *html, const char *tag, int tagsize)
/*
* <BR>
*/
-static void Html_tag_open_br(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_content_br(DilloHtml *html, const char *tag, int tagsize)
{
HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ());
}
@@ -1965,56 +1965,23 @@ static void Html_tag_open_abbr(DilloHtml *html, const char *tag, int tagsize)
}
/*
- * <CENTER>
- */
-static void Html_tag_open_center(DilloHtml *html, const char *tag, int tagsize)
-{
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
-}
-
-/*
- * </CENTER>, also used for </TABLE>
- */
-static void Html_tag_close_center(DilloHtml *html, int TagIdx)
-{
- HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
-}
-
-/*
- * <ADDRESS>
- */
-static void Html_tag_open_address(DilloHtml *html,
- const char *tag, int tagsize)
-{
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
-}
-
-/*
* Read image-associated tag attributes and create new image.
*/
-DilloImage *a_Html_image_new(DilloHtml *html, const char *tag,
- int tagsize, DilloUrl *url)
+void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize)
{
- DilloImage *Image;
- char *width_ptr, *height_ptr, *alt_ptr;
+ char *width_ptr, *height_ptr;
const char *attrbuf;
CssLength l_w = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
CssLength l_h = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO);
int space, border, w = 0, h = 0;
- bool load_now;
if (prefs.show_tooltip &&
(attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) {
html->styleEngine->setNonCssHint(PROPERTY_X_TOOLTIP, CSS_TYPE_STRING,
attrbuf);
}
- alt_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "alt", NULL);
- if ((!alt_ptr || !*alt_ptr) && !prefs.load_images) {
- dFree(alt_ptr);
- alt_ptr = dStrdup("[IMG]"); // Place holder for img_off mode
- }
width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", NULL);
height_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "height", NULL);
// Check for malicious values
@@ -2044,7 +2011,7 @@ DilloImage *a_Html_image_new(DilloHtml *html, const char *tag,
dFree(width_ptr);
dFree(height_ptr);
width_ptr = height_ptr = NULL;
- MSG("a_Html_image_new: suspicious image size request %d x %d\n", w, h);
+ MSG("a_Html_image_attrs: suspicious image size request %d x %d\n", w, h);
} else {
if (CSS_LENGTH_TYPE(l_w) != CSS_LENGTH_TYPE_AUTO)
html->styleEngine->setNonCssHint (CSS_PROPERTY_WIDTH,
@@ -2111,27 +2078,58 @@ DilloImage *a_Html_image_new(DilloHtml *html, const char *tag,
}
/* x_img is an index to a list of {url,image} pairs.
- * We know Html_add_new_htmlimage() will use size() as its next index */
+ * We know a_Html_image_new() will use size() as its next index */
html->styleEngine->setNonCssHint (PROPERTY_X_IMG, CSS_TYPE_INTEGER,
html->images->size());
- /* Add a new image widget to this page */
- Image = a_Image_new(alt_ptr, 0);
+
+ dFree(width_ptr);
+ dFree(height_ptr);
+}
+
+DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize)
+{
+ bool load_now;
+ char *alt_ptr;
+ const char *attrbuf;
+ DilloUrl *url;
+ DilloImage *image;
+
+ if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src")) ||
+ !(url = a_Html_url_new(html, attrbuf, NULL, 0)))
+ return NULL;
+
+ alt_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "alt", NULL);
+ if ((!alt_ptr || !*alt_ptr) && !prefs.load_images) {
+ dFree(alt_ptr);
+ alt_ptr = dStrdup("[IMG]"); // Place holder for img_off mode
+ }
+
+ image = a_Image_new(alt_ptr, 0);
+
if (HT2TB(html)->getBgColor())
- Image->bg_color = HT2TB(html)->getBgColor()->getColor();
+ image->bg_color = HT2TB(html)->getBgColor()->getColor();
+
+ DilloHtmlImage *hi = dNew(DilloHtmlImage, 1);
+ hi->url = url;
+ html->images->increase();
+ html->images->set(html->images->size() - 1, hi);
load_now = prefs.load_images ||
- !dStrcasecmp(URL_SCHEME(url), "data") ||
+ !dStrAsciiCasecmp(URL_SCHEME(url), "data") ||
(a_Capi_get_flags_with_redirection(url) & CAPI_IsCached);
- bool loading = false;
- if (load_now)
- loading = Html_load_image(html->bw, url, html->page_url, Image);
- Html_add_new_htmlimage(html, &url, loading ? NULL : Image);
- dFree(width_ptr);
- dFree(height_ptr);
+ if (load_now && Html_load_image(html->bw, url, html->page_url, image)) {
+ // hi->image is NULL if dillo tries to load the image immediately
+ hi->image = NULL;
+ } else {
+ // otherwise a reference is kept in html->images
+ hi->image = image;
+ a_Image_ref(image);
+ }
+
dFree(alt_ptr);
- return Image;
+ return image;
}
/*
@@ -2155,23 +2153,28 @@ static bool Html_load_image(BrowserWindow *bw, DilloUrl *url,
return ClientKey != 0;
}
+static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize)
+{
+ a_Html_image_attrs(html, tag, tagsize);
+}
+
/*
* Create a new Image struct and request the image-url to the cache
* (If it either hits or misses, is not relevant here; that's up to the
* cache functions)
*/
-static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_content_img(DilloHtml *html, const char *tag, int tagsize)
{
DilloImage *Image;
- DilloUrl *url, *usemap_url;
+ DilloUrl *usemap_url;
const char *attrbuf;
/* This avoids loading images. Useful for viewing suspicious HTML email. */
if (URL_FLAGS(html->base_url) & URL_SpamSafe)
return;
- if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src")) ||
- !(url = a_Html_url_new(html, attrbuf, NULL, 0)))
+ Image = a_Html_image_new(html, tag, tagsize);
+ if (!Image)
return;
usemap_url = NULL;
@@ -2179,7 +2182,6 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize)
/* TODO: usemap URLs outside of the document are not used. */
usemap_url = a_Html_url_new(html, attrbuf, NULL, 0);
- Image = a_Html_image_new(html, tag, tagsize, url);
HT2TB(html)->addWidget((Widget*)Image->dw, html->styleEngine->style());
/* Image maps */
@@ -2203,7 +2205,7 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize)
/*
* <map>
*/
-static void Html_tag_open_map(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_content_map(DilloHtml *html, const char *tag, int tagsize)
{
char *hash_name;
const char *attrbuf;
@@ -2277,7 +2279,7 @@ misc::SimpleVector<int> *Html_read_coords(DilloHtml *html, const char *str)
/*
* <AREA>
*/
-static void Html_tag_open_area(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_content_area(DilloHtml *html, const char *tag, int tagsize)
{
enum types {UNKNOWN, RECTANGLE, CIRCLE, POLYGON, BACKGROUND};
types type;
@@ -2293,15 +2295,15 @@ static void Html_tag_open_area(DilloHtml *html, const char *tag, int tagsize)
}
attrbuf = a_Html_get_attr(html, tag, tagsize, "shape");
- if (!attrbuf || !*attrbuf || !dStrcasecmp(attrbuf, "rect")) {
+ if (!attrbuf || !*attrbuf || !dStrAsciiCasecmp(attrbuf, "rect")) {
/* the default shape is a rectangle */
type = RECTANGLE;
- } else if (dStrcasecmp(attrbuf, "default") == 0) {
+ } else if (dStrAsciiCasecmp(attrbuf, "default") == 0) {
/* "default" is the background */
type = BACKGROUND;
- } else if (dStrcasecmp(attrbuf, "circle") == 0) {
+ } else if (dStrAsciiCasecmp(attrbuf, "circle") == 0) {
type = CIRCLE;
- } else if (dStrncasecmp(attrbuf, "poly", 4) == 0) {
+ } else if (dStrnAsciiCasecmp(attrbuf, "poly", 4) == 0) {
type = POLYGON;
} else {
BUG_MSG("<area> unknown shape: \"%s\"\n", attrbuf);
@@ -2395,7 +2397,7 @@ static const char* Html_get_javascript_link(DilloHtml *html)
char ch, *p1, *p2;
Dstr *Buf = html->attr_data;
- if (dStrncasecmp("javascript", Buf->str, 10) == 0) {
+ if (dStrnAsciiCasecmp("javascript", Buf->str, 10) == 0) {
i = strcspn(Buf->str, "'\"");
ch = Buf->str[i];
if ((ch == '"' || ch == '\'') &&
@@ -2437,11 +2439,11 @@ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize)
/* TODO: add support for MAP with A HREF */
if (html->InFlags & IN_MAP)
- Html_tag_open_area(html, tag, tagsize);
+ Html_tag_content_area(html, tag, tagsize);
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "href"))) {
/* if it's a javascript link, extract the reference. */
- if (tolower(attrbuf[0]) == 'j')
+ if (D_ASCII_TOLOWER(attrbuf[0]) == 'j')
attrbuf = Html_get_javascript_link(html);
url = a_Html_url_new(html, attrbuf, NULL, 0);
@@ -2549,11 +2551,11 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize)
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) {
/* list_style_type explicitly defined */
- if (dStrcasecmp(attrbuf, "disc") == 0)
+ if (dStrAsciiCasecmp(attrbuf, "disc") == 0)
list_style_type = LIST_STYLE_TYPE_DISC;
- else if (dStrcasecmp(attrbuf, "circle") == 0)
+ else if (dStrAsciiCasecmp(attrbuf, "circle") == 0)
list_style_type = LIST_STYLE_TYPE_CIRCLE;
- else if (dStrcasecmp(attrbuf, "square") == 0)
+ else if (dStrAsciiCasecmp(attrbuf, "square") == 0)
list_style_type = LIST_STYLE_TYPE_SQUARE;
else
/* invalid value */
@@ -2563,8 +2565,6 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize)
CSS_TYPE_ENUM, list_style_type);
}
- Html_add_textblock(html, 9);
-
S_TOP(html)->list_type = HTML_LIST_UNORDERED;
S_TOP(html)->list_number = 0;
S_TOP(html)->ref_list_item = NULL;
@@ -2621,8 +2621,6 @@ static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize)
CSS_TYPE_ENUM, listStyleType);
}
- Html_add_textblock(html, 9);
-
S_TOP(html)->list_type = HTML_LIST_ORDERED;
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "start")) &&
@@ -2640,12 +2638,8 @@ static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize)
{
Style *style = html->styleEngine->style ();
- Style *wordStyle = html->styleEngine->wordStyle ();
- Widget **ref_list_item;
- ListItem *list_item;
int *list_number;
const char *attrbuf;
- char buf[16];
if (S_TOP(html)->list_type == HTML_LIST_NONE)
BUG_MSG("<li> outside <ul> or <ol>\n");
@@ -2654,30 +2648,14 @@ static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize)
/* Get our parent tag's variables (used as state storage) */
list_number = &html->stack->getRef(html->stack->size()-2)->list_number;
- ref_list_item = &html->stack->getRef(html->stack->size()-2)->ref_list_item;
-
- HT2TB(html)->addParbreak (0, wordStyle);
- list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width);
- HT2TB(html)->addWidget (list_item, style);
- HT2TB(html)->addParbreak (0, wordStyle);
- *ref_list_item = list_item;
- S_TOP(html)->textblock = html->dw = list_item;
-
- if (style->listStyleType == LIST_STYLE_TYPE_NONE) {
- // none
- } else if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) {
+ if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) {
// ordered
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "value")) &&
(*list_number = strtol(attrbuf, NULL, 10)) < 0) {
BUG_MSG("illegal negative LIST VALUE attribute; Starting from 0\n");
*list_number = 0;
}
- numtostr((*list_number)++, buf, 16, style->listStyleType);
- list_item->initWithText (buf, wordStyle);
- } else {
- // unordered
- list_item->initWithWidget (new Bullet(), wordStyle);
}
}
@@ -2695,7 +2673,6 @@ static void Html_tag_close_li(DilloHtml *html, int TagIdx)
*/
static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize)
{
- Widget *hruler;
char *width_ptr;
const char *attrbuf;
int32_t size = 0;
@@ -2743,6 +2720,11 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize)
size_bottom);
}
+}
+
+static void Html_tag_content_hr(DilloHtml *html, const char *tag, int tagsize)
+{
+ Widget *hruler;
HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
hruler = new Ruler();
@@ -2795,7 +2777,6 @@ static void Html_tag_open_pre(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_close_pre(DilloHtml *html, int TagIdx)
{
html->InFlags &= ~IN_PRE;
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
}
/*
@@ -2854,7 +2835,7 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize)
}
if ((equiv = a_Html_get_attr(html, tag, tagsize, "http-equiv"))) {
- if (!dStrcasecmp(equiv, "refresh") &&
+ if (!dStrAsciiCasecmp(equiv, "refresh") &&
(content = a_Html_get_attr(html, tag, tagsize, "content"))) {
/* Get delay, if present, and make a message with it */
@@ -2906,7 +2887,7 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize)
a_Url_free(new_url);
dFree(mr_url);
- } else if (!dStrcasecmp(equiv, "content-type") &&
+ } else if (!dStrAsciiCasecmp(equiv, "content-type") &&
(content = a_Html_get_attr(html, tag, tagsize, "content"))) {
_MSG("Html_tag_open_meta: content={%s}\n", content);
/* Cannot ask cache whether the content type was changed, as
@@ -3011,14 +2992,14 @@ static void Html_tag_open_link(DilloHtml *html, const char *tag, int tagsize)
dReturn_if_fail (prefs.load_stylesheets);
/* CSS stylesheet link */
if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "rel")) ||
- dStrcasecmp(attrbuf, "stylesheet"))
+ dStrAsciiCasecmp(attrbuf, "stylesheet"))
return;
/* IMPLIED attributes? */
if (((attrbuf = a_Html_get_attr(html, tag, tagsize, "type")) &&
- dStrcasecmp(attrbuf, "text/css")) ||
+ dStrAsciiCasecmp(attrbuf, "text/css")) ||
((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) &&
- !dStristr(attrbuf, "screen") && dStrcasecmp(attrbuf, "all")))
+ !dStriAsciiStr(attrbuf, "screen") && dStrAsciiCasecmp(attrbuf, "all")))
return;
if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "href")) ||
@@ -3085,14 +3066,6 @@ static void Html_tag_open_default(DilloHtml *html,const char *tag,int tagsize)
static void Html_tag_open_div(DilloHtml *html, const char *tag, int tagsize)
{
a_Html_tag_set_align_attr (html, tag, tagsize);
- Html_add_textblock(html, 0);
-}
-
-/*
- * Default close for most tags.
- */
-static void Html_tag_close_default(DilloHtml *html, int TagIdx)
-{
}
/*
@@ -3105,8 +3078,13 @@ static void Html_tag_close_par(DilloHtml *html, int TagIdx)
/*
- * Function index for the open and close functions for each tag
- * (Alphabetically sorted for a binary search)
+ * Function index for the open, content, and close functions for each tag
+ * (Alphabetically sorted for a binary search).
+ * The open and close functions are always called. They are used for style
+ * handling and HTML bug reporting.
+ * Content creation (e.g. adding new widgets or text) is done in the content
+ * function, which is not called in the display:none case.
+ * Note, that many tags don't need a content function (e.g. <div>, <span>, ...).
*
* Explanation for the 'Flags' field:
*
@@ -3124,101 +3102,112 @@ static void Html_tag_close_par(DilloHtml *html, int TagIdx)
* (flow have both set)
*/
-
const TagInfo Tags[] = {
- {"a", B8(010101),'R',2, Html_tag_open_a, Html_tag_close_a},
- {"abbr", B8(010101),'R',2, Html_tag_open_abbr, Html_tag_close_default},
+ {"a", B8(010101),'R',2, Html_tag_open_a, NULL, Html_tag_close_a},
+ {"abbr", B8(010101),'R',2, Html_tag_open_abbr, NULL, NULL},
/* acronym 010101 */
- {"address", B8(010110),'R',2, Html_tag_open_address, Html_tag_close_par},
- {"area", B8(010001),'F',0, Html_tag_open_area, Html_tag_close_default},
- {"b", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"base", B8(100001),'F',0, Html_tag_open_base, Html_tag_close_default},
+ {"address", B8(010110),'R',2, Html_tag_open_default, NULL, Html_tag_close_par},
+ {"area", B8(010001),'F',0, Html_tag_open_default, Html_tag_content_area,
+ NULL},
+ {"b", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"base", B8(100001),'F',0, Html_tag_open_base, NULL, NULL},
/* basefont 010001 */
/* bdo 010101 */
- {"big", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"blockquote", B8(011110),'R',2, Html_tag_open_blockquote,
- Html_tag_close_default},
- {"body", B8(011110),'O',1, Html_tag_open_body, Html_tag_close_body},
- {"br", B8(010001),'F',0, Html_tag_open_br, Html_tag_close_default},
- {"button", B8(011101),'R',2, Html_tag_open_button, Html_tag_close_button},
+ {"big", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"blockquote", B8(011110),'R',2, Html_tag_open_blockquote, NULL,
+ NULL},
+ {"body", B8(011110),'O',1, Html_tag_open_body, NULL, Html_tag_close_body},
+ {"br", B8(010001),'F',0, Html_tag_open_default, Html_tag_content_br,
+ NULL},
+ {"button", B8(011101),'R',2, Html_tag_open_button, NULL, Html_tag_close_button},
/* caption */
- {"center", B8(011110),'R',2, Html_tag_open_center, Html_tag_close_center},
- {"cite", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"code", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"center", B8(011110),'R',2, Html_tag_open_default, NULL, NULL},
+ {"cite", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"code", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
/* col 010010 'F' */
/* colgroup */
- {"dd", B8(011110),'O',1, Html_tag_open_dd, Html_tag_close_default},
- {"del", B8(011101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"dfn", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"dir", B8(011010),'R',2, Html_tag_open_dir, Html_tag_close_par},
+ {"dd", B8(011110),'O',1, Html_tag_open_dd, NULL, NULL},
+ {"del", B8(011101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"dfn", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"dir", B8(011010),'R',2, Html_tag_open_dir, NULL, Html_tag_close_par},
/* TODO: complete <div> support! */
- {"div", B8(011110),'R',2, Html_tag_open_div, Html_tag_close_default},
- {"dl", B8(011010),'R',2, Html_tag_open_dl, Html_tag_close_par},
- {"dt", B8(010110),'O',1, Html_tag_open_dt, Html_tag_close_par},
- {"em", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"div", B8(011110),'R',2, Html_tag_open_div, NULL, NULL},
+ {"dl", B8(011010),'R',2, Html_tag_open_dl, NULL, Html_tag_close_par},
+ {"dt", B8(010110),'O',1, Html_tag_open_dt, NULL, Html_tag_close_par},
+ {"em", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
/* fieldset */
- {"font", B8(010101),'R',2, Html_tag_open_font, Html_tag_close_default},
- {"form", B8(011110),'R',2, Html_tag_open_form, Html_tag_close_form},
- {"frame", B8(010010),'F',0, Html_tag_open_frame, Html_tag_close_default},
- {"frameset", B8(011110),'R',2,Html_tag_open_frameset, Html_tag_close_default},
- {"h1", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"h2", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"h3", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"h4", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"h5", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"h6", B8(010110),'R',2, Html_tag_open_h, Html_tag_close_par},
- {"head", B8(101101),'O',1, Html_tag_open_head, Html_tag_close_head},
- {"hr", B8(010010),'F',0, Html_tag_open_hr, Html_tag_close_default},
- {"html", B8(001110),'O',1, Html_tag_open_html, Html_tag_close_html},
- {"i", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"iframe", B8(011110),'R',2, Html_tag_open_frame, Html_tag_close_default},
- {"img", B8(010001),'F',0, Html_tag_open_img, Html_tag_close_default},
- {"input", B8(010001),'F',0, Html_tag_open_input, Html_tag_close_default},
+ {"font", B8(010101),'R',2, Html_tag_open_font, NULL, NULL},
+ {"form", B8(011110),'R',2, Html_tag_open_form, NULL, Html_tag_close_form},
+ {"frame", B8(010010),'F',0, Html_tag_open_frame, Html_tag_content_frame,
+ NULL},
+ {"frameset", B8(011110),'R',2, Html_tag_open_default, Html_tag_content_frameset,
+ NULL},
+ {"h1", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"h2", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"h3", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"h4", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"h5", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"h6", B8(010110),'R',2, Html_tag_open_h, NULL, NULL},
+ {"head", B8(101101),'O',1, Html_tag_open_head, NULL, Html_tag_close_head},
+ {"hr", B8(010010),'F',0, Html_tag_open_hr, Html_tag_content_hr,
+ NULL},
+ {"html", B8(001110),'O',1, Html_tag_open_html, NULL, Html_tag_close_html},
+ {"i", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"iframe", B8(011110),'R',2, Html_tag_open_frame, NULL, NULL},
+ {"img", B8(010001),'F',0, Html_tag_open_img, Html_tag_content_img,
+ NULL},
+ {"input", B8(010001),'F',0, Html_tag_open_input, NULL, NULL},
/* ins */
- {"isindex", B8(110001),'F',0, Html_tag_open_isindex, Html_tag_close_default},
- {"kbd", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
+ {"isindex", B8(110001),'F',0, Html_tag_open_isindex, NULL, NULL},
+ {"kbd", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
/* label 010101 */
/* legend 01?? */
- {"li", B8(011110),'O',1, Html_tag_open_li, Html_tag_close_li},
- {"link", B8(100001),'F',0, Html_tag_open_link, Html_tag_close_default},
- {"map", B8(011001),'R',2, Html_tag_open_map, Html_tag_close_map},
+ {"li", B8(011110),'O',1, Html_tag_open_li, NULL, Html_tag_close_li},
+ {"link", B8(100001),'F',0, Html_tag_open_link, NULL, NULL},
+ {"map", B8(011001),'R',2, Html_tag_open_default, Html_tag_content_map,
+ Html_tag_close_map},
/* menu 1010 -- TODO: not exactly 1010, it can contain LI and inline */
- {"menu", B8(011010),'R',2, Html_tag_open_menu, Html_tag_close_par},
- {"meta", B8(100001),'F',0, Html_tag_open_meta, Html_tag_close_default},
+ {"menu", B8(011010),'R',2, Html_tag_open_menu, NULL, Html_tag_close_par},
+ {"meta", B8(100001),'F',0, Html_tag_open_meta, NULL, NULL},
/* noframes 1011 */
/* noscript 1011 */
- {"object", B8(111101),'R',2, Html_tag_open_object, Html_tag_close_default},
- {"ol", B8(011010),'R',2, Html_tag_open_ol, Html_tag_close_default},
+ {"object", B8(111101),'R',2, Html_tag_open_object, NULL, NULL},
+ {"ol", B8(011010),'R',2, Html_tag_open_ol, NULL, NULL},
/* optgroup */
- {"option", B8(010001),'O',1, Html_tag_open_option, Html_tag_close_default},
- {"p", B8(010110),'O',1, Html_tag_open_p, Html_tag_close_par},
+ {"option", B8(010001),'O',1, Html_tag_open_option, NULL, NULL},
+ {"p", B8(010110),'O',1, Html_tag_open_p, NULL, NULL},
/* param 010001 'F' */
- {"pre", B8(010110),'R',2, Html_tag_open_pre, Html_tag_close_pre},
- {"q", B8(010101),'R',2, Html_tag_open_q, Html_tag_close_q},
- {"s", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"samp", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"script", B8(111001),'R',2, Html_tag_open_script, Html_tag_close_script},
- {"select", B8(010101),'R',2, Html_tag_open_select, Html_tag_close_select},
- {"small", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"span", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"strike", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"strong", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"style", B8(100101),'R',2, Html_tag_open_style, Html_tag_close_style},
- {"sub", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"sup", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"table", B8(011010),'R',5, Html_tag_open_table, Html_tag_close_center},
+ {"pre", B8(010110),'R',2, Html_tag_open_pre, NULL, Html_tag_close_pre},
+ {"q", B8(010101),'R',2, Html_tag_open_q, NULL, Html_tag_close_q},
+ {"s", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"samp", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"script", B8(111001),'R',2, Html_tag_open_script, NULL, Html_tag_close_script},
+ {"select", B8(010101),'R',2, Html_tag_open_select, NULL, Html_tag_close_select},
+ {"small", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"span", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"strike", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"strong", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"style", B8(100101),'R',2, Html_tag_open_style, NULL, Html_tag_close_style},
+ {"sub", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"sup", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"table", B8(011010),'R',5, Html_tag_open_table, Html_tag_content_table,
+ NULL},
/* tbody */
- {"td", B8(011110),'O',3, Html_tag_open_td, Html_tag_close_default},
- {"textarea", B8(010101),'R',2,Html_tag_open_textarea,Html_tag_close_textarea},
+ {"td", B8(011110),'O',3, Html_tag_open_td, Html_tag_content_td,
+ NULL},
+ {"textarea", B8(010101),'R',2,Html_tag_open_textarea, Html_tag_content_textarea,
+ Html_tag_close_textarea},
/* tfoot */
- {"th", B8(011110),'O',1, Html_tag_open_th, Html_tag_close_default},
+ {"th", B8(011110),'O',1, Html_tag_open_th, Html_tag_content_th,
+ NULL},
/* thead */
- {"title", B8(100101),'R',2, Html_tag_open_title, Html_tag_close_title},
- {"tr", B8(011010),'O',4, Html_tag_open_tr, Html_tag_close_default},
- {"tt", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"u", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default},
- {"ul", B8(011010),'R',2, Html_tag_open_ul, Html_tag_close_default},
- {"var", B8(010101),'R',2, Html_tag_open_default, Html_tag_close_default}
+ {"title", B8(100101),'R',2, Html_tag_open_title, NULL, Html_tag_close_title},
+ {"tr", B8(011010),'O',4, Html_tag_open_tr, Html_tag_content_tr,
+ NULL},
+ {"tt", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"u", B8(010101),'R',2, Html_tag_open_default, NULL, NULL},
+ {"ul", B8(011010),'R',2, Html_tag_open_ul, NULL, NULL},
+ {"var", B8(010101),'R',2, Html_tag_open_default, NULL, NULL}
};
#define NTAGS (sizeof(Tags)/sizeof(Tags[0]))
@@ -3232,8 +3221,8 @@ const TagInfo Tags[] = {
static int Html_tag_compare(const char *p1, const char *p2)
{
while ( *p2 ) {
- if (tolower(*p1) != *p2)
- return(tolower(*p1) - *p2);
+ if (D_ASCII_TOLOWER(*p1) != *p2)
+ return(D_ASCII_TOLOWER(*p1) - *p2);
++p1;
++p2;
}
@@ -3456,6 +3445,53 @@ static void Html_parse_common_attrs(DilloHtml *html, char *tag, int tagsize)
html->styleEngine->setStyle (attrbuf);
}
+ if (tagsize >= 10) { /* TODO prefs.hyphenate? */
+ /* length of "<t lang=i>" */
+ attrbuf = Html_get_attr2(html, tag, tagsize, "lang",
+ HTML_LeftTrim | HTML_RightTrim);
+ if (attrbuf)
+ html->styleEngine->setNonCssHint(PROPERTY_X_LANG, CSS_TYPE_STRING,
+ attrbuf);
+ }
+}
+
+static void Html_display_block(DilloHtml *html)
+{
+ //HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
+ Html_add_textblock(html, 0);
+}
+
+static void Html_display_listitem(DilloHtml *html)
+{
+ Style *style = html->styleEngine->style ();
+ Style *wordStyle = html->styleEngine->wordStyle ();
+ Widget **ref_list_item;
+ ListItem *list_item;
+ int *list_number;
+ char buf[16];
+
+ /* Get our parent tag's variables (used as state storage) */
+ list_number = &html->stack->getRef(html->stack->size()-2)->list_number;
+ ref_list_item = &html->stack->getRef(html->stack->size()-2)->ref_list_item;
+
+ HT2TB(html)->addParbreak (0, wordStyle);
+
+ list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width);
+ HT2TB(html)->addWidget (list_item, style);
+ HT2TB(html)->addParbreak (0, wordStyle);
+ *ref_list_item = list_item;
+ S_TOP(html)->textblock = html->dw = list_item;
+
+ if (style->listStyleType == LIST_STYLE_TYPE_NONE) {
+ // none
+ } else if (style->listStyleType >= LIST_STYLE_TYPE_DECIMAL) {
+ // ordered
+ numtostr((*list_number)++, buf, 16, style->listStyleType);
+ list_item->initWithText (buf, wordStyle);
+ } else {
+ // unordered
+ list_item->initWithWidget (new Bullet(), wordStyle);
+ }
}
/*
@@ -3475,7 +3511,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize)
if (ni == -1) {
/* TODO: doctype parsing is a bit fuzzy, but enough for the time being */
if (!(html->InFlags & IN_HTML)) {
- if (tagsize > 9 && !dStrncasecmp(tag, "<!doctype", 9))
+ if (tagsize > 9 && !dStrnAsciiCasecmp(tag, "<!doctype", 9))
Html_parse_doctype(html, tag, tagsize);
}
/* Ignore unknown tags */
@@ -3514,6 +3550,29 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize)
/* Call the open function for this tag */
_MSG("Open : %s\n", Tags[ni].name);
Tags[ni].open (html, tag, tagsize);
+
+ if (! S_TOP(html)->display_none) {
+ switch (html->styleEngine->style ()->display) {
+ case DISPLAY_BLOCK:
+ Html_display_block(html);
+ break;
+ case DISPLAY_LIST_ITEM:
+ Html_display_listitem(html);
+ break;
+ case DISPLAY_NONE:
+ S_TOP(html)->display_none = true;
+ break;
+ case DISPLAY_INLINE:
+ case DISPLAY_INLINE_BLOCK: // TODO: implement inline-block
+ default:
+ break;
+ }
+
+ if (Tags[ni].content && ! S_TOP(html)->display_none) {
+ Tags[ni].content (html, tag, tagsize);
+ }
+ }
+
if (html->stop_parser)
break;
@@ -3592,8 +3651,11 @@ static const char *Html_get_attr2(DilloHtml *html,
(tag[i] == '=' || isspace(tag[i]) || tag[i] == '>')))) {
state = SEEK_TOKEN_START;
--i;
- } else if (tolower(tag[i]) != tolower(attrname[attr_pos++]))
- state = SEEK_ATTR_START;
+ } else {
+ if (D_ASCII_TOLOWER(tag[i]) != D_ASCII_TOLOWER(attrname[attr_pos]))
+ state = SEEK_ATTR_START;
+ attr_pos++;
+ }
break;
case SEEK_TOKEN_START:
diff --git a/src/html_common.hh b/src/html_common.hh
index cf5c8114..726fbd0e 100644
--- a/src/html_common.hh
+++ b/src/html_common.hh
@@ -34,6 +34,7 @@
html->bugMessage(__VA_ARGS__); \
} D_STMT_END
+
/*
* Typedefs
*/
@@ -103,7 +104,7 @@ struct _DilloHtmlState {
DilloHtmlTableMode table_mode;
DilloHtmlTableBorderMode table_border_mode;
bool cell_text_align_set;
-
+ bool display_none;
DilloHtmlListMode list_type;
int list_number;
@@ -238,8 +239,8 @@ DilloUrl *a_Html_url_new(DilloHtml *html,
const char *url_str, const char *base_url,
int use_base_url);
-DilloImage *a_Html_image_new(DilloHtml *html, const char *tag,
- int tagsize, DilloUrl *url);
+void a_Html_image_attrs(DilloHtml *html, const char *tag, int tagsize);
+DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize);
char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize);
void a_Html_pop_tag(DilloHtml *html, int TagIdx);
diff --git a/src/keys.cc b/src/keys.cc
index bd78fd5f..08d50306 100644
--- a/src/keys.cc
+++ b/src/keys.cc
@@ -103,7 +103,9 @@ static const KeyBinding_t default_keys[] = {
{ "new-tab" , KEYS_NEW_TAB , FL_CTRL , 't' },
{ "left-tab" , KEYS_LEFT_TAB , FL_CTRL |
FL_SHIFT , FL_Tab },
+ { "left-tab" , KEYS_LEFT_TAB , FL_CTRL , FL_Page_Up },
{ "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Tab },
+ { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Page_Down },
{ "close-tab" , KEYS_CLOSE_TAB , FL_CTRL , 'w' },
{ "find" , KEYS_FIND , FL_CTRL , 'f' },
{ "websearch" , KEYS_WEBSEARCH , FL_CTRL , 's' },
@@ -147,7 +149,7 @@ void Keys::init()
// Fill our key bindings list
bindings = dList_new(32);
- for (uint_t i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) {
+ for (uint_t i = 0; i < sizeof(default_keys) / sizeof(default_keys[0]); i++) {
if (default_keys[i].key) {
node = dNew(KeyBinding_t, 1);
node->name = dStrdup(default_keys[i].name);
@@ -242,8 +244,8 @@ void Keys::delKeyCmd(int key, int mod)
int Keys::getKeyCode(char *keyName)
{
uint_t i;
- for (i = 0; i < sizeof(keyNames) / sizeof(Mapping_t); i++) {
- if (!dStrcasecmp(keyNames[i].name, keyName)) {
+ for (i = 0; i < sizeof(keyNames) / sizeof(keyNames[0]); i++) {
+ if (!dStrAsciiCasecmp(keyNames[i].name, keyName)) {
return keyNames[i].value;
}
}
@@ -260,7 +262,7 @@ KeysCommand_t Keys::getCmdCode(const char *commandName)
uint_t i;
for (i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) {
- if (!dStrcasecmp(default_keys[i].name, commandName))
+ if (!dStrAsciiCasecmp(default_keys[i].name, commandName))
return default_keys[i].cmd;
}
return KEYS_INVALID;
@@ -273,8 +275,8 @@ KeysCommand_t Keys::getCmdCode(const char *commandName)
int Keys::getModifier(char *modifierName)
{
uint_t i;
- for (i = 0; i < sizeof(modifierNames) / sizeof(Mapping_t); i++) {
- if (!dStrcasecmp(modifierNames[i].name, modifierName)) {
+ for (i = 0; i < sizeof(modifierNames) / sizeof(modifierNames[0]); i++) {
+ if (!dStrAsciiCasecmp(modifierNames[i].name, modifierName)) {
return modifierNames[i].value;
}
}
diff --git a/src/keysrc b/src/keysrc
index 706917df..e0c488f9 100644
--- a/src/keysrc
+++ b/src/keysrc
@@ -40,7 +40,9 @@
# "left-tab" and "right-tab" switch to the left/right of the current tab.
# <ctrl><shift>tab = left-tab
+# <ctrl>PageUp = left-tab
# <ctrl>tab = right-tab
+# <ctrl>PageDown = right-tab
# "back" and "forward" move back/forward through the browser history.
#backspace = back
diff --git a/src/list.h b/src/list.h
index 8623bf09..f98661d1 100644
--- a/src/list.h
+++ b/src/list.h
@@ -16,12 +16,12 @@
*/
#define a_List_resize(list,num_items,alloc_step) \
if (!list) { \
- list = dMalloc(alloc_step * sizeof((*list))); \
+ list = dMalloc(alloc_step * sizeof(*list)); \
} \
if (num_items >= alloc_step){ \
while ( num_items >= alloc_step ) \
alloc_step <<= 1; \
- list = dRealloc(list, alloc_step * sizeof((*list))); \
+ list = dRealloc(list, alloc_step * sizeof(*list)); \
}
diff --git a/src/md5.c b/src/md5.c
new file mode 100644
index 00000000..bd1ffb16
--- /dev/null
+++ b/src/md5.c
@@ -0,0 +1,390 @@
+/*
+ * md5.c was taken from "RFC1321-based (RSA-free) MD5 library" by L. Peter
+ * Deutsch at http://sourceforge.net/projects/libmd5-rfc/ in October 2011.
+ *
+ * The code was not modified when integrated into the Dillo project, but you
+ * should check the source repository to be sure that there have not been
+ * modifications since this notice.
+ */
+
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/src/md5.h b/src/md5.h
new file mode 100644
index 00000000..184a14b7
--- /dev/null
+++ b/src/md5.h
@@ -0,0 +1,100 @@
+/*
+ * md5.h was taken from "RFC1321-based (RSA-free) MD5 library" by L. Peter
+ * Deutsch at http://sourceforge.net/projects/libmd5-rfc/ in October 2011.
+ *
+ * The code was not modified when integrated into the Dillo project, but you
+ * should check the source repository to be sure that there have not been
+ * modifications since this notice.
+ */
+
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/src/menu.cc b/src/menu.cc
index 658b89bc..fe8ff139 100644
--- a/src/menu.cc
+++ b/src/menu.cc
@@ -207,8 +207,20 @@ static void Menu_form_hiddens_cb(Fl_Widget*, void *user_data)
static void Menu_stylesheet_cb(Fl_Widget*, void *vUrl)
{
+ int mb = Fl::event_button();
const DilloUrl *url = (const DilloUrl *) vUrl;
- a_UIcmd_open_url(popup_bw, url);
+
+ if (mb == 1) {
+ a_UIcmd_open_url(popup_bw, url);
+ } else if (mb == 2) {
+ if (prefs.middle_click_opens_new_tab) {
+ int focus = prefs.focus_new_tab ? 1 : 0;
+ if (Fl::event_state(FL_SHIFT)) focus = !focus;
+ a_UIcmd_open_url_nt(popup_bw, url, focus);
+ } else {
+ a_UIcmd_open_url_nw(popup_bw, url);
+ }
+ }
}
/*
@@ -315,7 +327,8 @@ void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url,
has_bugs == TRUE ? pm[1].activate() : pm[1].deactivate();
- if (strncmp(URL_STR(url), "dpi:/vsource/", 13) == 0)
+ if (dStrAsciiCasecmp(URL_SCHEME(url), "dpi") == 0 &&
+ strncmp(URL_PATH(url), "/vsource/", 9) == 0)
pm[0].deactivate();
else
pm[0].activate();
diff --git a/src/misc.c b/src/misc.c
index 2abfb988..0181a125 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -141,23 +141,23 @@ int a_Misc_get_content_type_from_data(void *Data, size_t Size, const char **PT)
/* HTML try */
for (i = 0; i < Size && dIsspace(p[i]); ++i);
- if ((Size - i >= 5 && !dStrncasecmp(p+i, "<html", 5)) ||
- (Size - i >= 5 && !dStrncasecmp(p+i, "<head", 5)) ||
- (Size - i >= 6 && !dStrncasecmp(p+i, "<title", 6)) ||
- (Size - i >= 14 && !dStrncasecmp(p+i, "<!doctype html", 14)) ||
+ if ((Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<html", 5)) ||
+ (Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<head", 5)) ||
+ (Size - i >= 6 && !dStrnAsciiCasecmp(p+i, "<title", 6)) ||
+ (Size - i >= 14 && !dStrnAsciiCasecmp(p+i, "<!doctype html", 14)) ||
/* this line is workaround for FTP through the Squid proxy */
- (Size - i >= 17 && !dStrncasecmp(p+i, "<!-- HTML listing", 17))) {
+ (Size - i >= 17 && !dStrnAsciiCasecmp(p+i, "<!-- HTML listing", 17))) {
Type = DT_TEXT_HTML;
st = 0;
/* Images */
- } else if (Size >= 4 && !dStrncasecmp(p, "GIF8", 4)) {
+ } else if (Size >= 4 && !strncmp(p, "GIF8", 4)) {
Type = DT_IMAGE_GIF;
st = 0;
- } else if (Size >= 4 && !dStrncasecmp(p, "\x89PNG", 4)) {
+ } else if (Size >= 4 && !strncmp(p, "\x89PNG", 4)) {
Type = DT_IMAGE_PNG;
st = 0;
- } else if (Size >= 2 && !dStrncasecmp(p, "\xff\xd8", 2)) {
+ } else if (Size >= 2 && !strncmp(p, "\xff\xd8", 2)) {
/* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking
* at the character representation should be machine independent. */
Type = DT_IMAGE_JPG;
@@ -221,20 +221,20 @@ void a_Misc_parse_content_type(const char *type, char **major, char **minor,
if (!(str = type))
return;
- for (s = str; *s && !iscntrl((uchar_t)*s) && !strchr(tspecials_space, *s);
- s++) ;
+ for (s = str; *s && isascii((uchar_t)*s) && !iscntrl((uchar_t)*s) &&
+ !strchr(tspecials_space, *s); s++) ;
if (major)
*major = dStrndup(str, s - str);
if (*s == '/') {
- for (str = ++s;
- *s && !iscntrl((uchar_t)*s) && !strchr(tspecials_space, *s); s++) ;
+ for (str = ++s; *s && isascii((uchar_t)*s) && !iscntrl((uchar_t)*s) &&
+ !strchr(tspecials_space, *s); s++) ;
if (minor)
*minor = dStrndup(str, s - str);
}
if (charset && *s &&
- (dStrncasecmp(type, "text/", 5) == 0 ||
- dStrncasecmp(type, "application/xhtml+xml", 21) == 0)) {
+ (dStrnAsciiCasecmp(type, "text/", 5) == 0 ||
+ dStrnAsciiCasecmp(type, "application/xhtml+xml", 21) == 0)) {
/* "charset" parameter defined for text media type in RFC 2046,
* application/xhtml+xml in RFC 3236.
*
@@ -246,7 +246,7 @@ void a_Misc_parse_content_type(const char *type, char **major, char **minor,
const char terminators[] = " ;\t";
const char key[] = "charset";
- if ((s = dStristr(str, key)) &&
+ if ((s = dStriAsciiStr(str, key)) &&
(s == str || strchr(terminators, s[-1]))) {
s += sizeof(key) - 1;
for ( ; *s == ' ' || *s == '\t'; ++s);
@@ -283,12 +283,12 @@ int a_Misc_content_type_cmp(const char *ct1, const char *ct2)
a_Misc_parse_content_type(ct1, &major1, &minor1, &charset1);
a_Misc_parse_content_type(ct2, &major2, &minor2, &charset2);
- if (major1 && major2 && !dStrcasecmp(major1, major2) &&
- minor1 && minor2 && !dStrcasecmp(minor1, minor2) &&
+ if (major1 && major2 && !dStrAsciiCasecmp(major1, major2) &&
+ minor1 && minor2 && !dStrAsciiCasecmp(minor1, minor2) &&
((!charset1 && !charset2) ||
- (charset1 && charset2 && !dStrcasecmp(charset1, charset2)) ||
- (!charset1 && charset2 && !dStrcasecmp(charset2, "UTF-8")) ||
- (charset1 && !charset2 && !dStrcasecmp(charset1, "UTF-8")))) {
+ (charset1 && charset2 && !dStrAsciiCasecmp(charset1, charset2)) ||
+ (!charset1 && charset2 && !dStrAsciiCasecmp(charset2, "UTF-8")) ||
+ (charset1 && !charset2 && !dStrAsciiCasecmp(charset1, "UTF-8")))) {
ret = 0;
} else {
ret = 1;
@@ -328,22 +328,23 @@ int a_Misc_content_type_check(const char *EntryType, const char *DetectedType)
return 0; /* there's no mismatch without server type */
for (i = 1; MimeTypes[i].str; ++i)
- if (dStrncasecmp(EntryType, MimeTypes[i].str, MimeTypes[i].len) == 0)
+ if (dStrnAsciiCasecmp(EntryType, MimeTypes[i].str, MimeTypes[i].len) ==0)
break;
if (!MimeTypes[i].str) {
/* type not found, no mismatch */
st = 0;
- } else if (dStrncasecmp(EntryType, "image/", 6) == 0 &&
- !dStrncasecmp(DetectedType,MimeTypes[i].str,MimeTypes[i].len)){
+ } else if (dStrnAsciiCasecmp(EntryType, "image/", 6) == 0 &&
+ !dStrnAsciiCasecmp(DetectedType, MimeTypes[i].str,
+ MimeTypes[i].len)){
/* An image, and there's an exact match */
st = 0;
- } else if (dStrncasecmp(EntryType, "text/", 5) ||
- dStrncasecmp(DetectedType, "application/", 12)) {
+ } else if (dStrnAsciiCasecmp(EntryType, "text/", 5) ||
+ dStrnAsciiCasecmp(DetectedType, "application/", 12)) {
/* Not an application sent as text */
st = 0;
- } else if (dStrncasecmp(EntryType, "application/xhtml+xml", 21) &&
- dStrncasecmp(DetectedType, "text/html", 9)) {
+ } else if (dStrnAsciiCasecmp(EntryType, "application/xhtml+xml", 21) &&
+ dStrnAsciiCasecmp(DetectedType, "text/html", 9)) {
/* XML version of HTML */
st = 0;
}
diff --git a/src/nav.c b/src/nav.c
index bea90dd3..7a567710 100644
--- a/src/nav.c
+++ b/src/nav.c
@@ -481,9 +481,10 @@ static void Nav_reload_callback(void *data)
a_Nav_cancel_expect(bw);
if (a_Nav_stack_size(bw)) {
h_url = a_History_get_url(NAV_TOP_UIDX(bw));
- if (strncmp(URL_STR(h_url), "dpi:/vsource/", 13) == 0) {
- /* disable reload for view source dpi */
- confirmed = 0;
+ if (dStrAsciiCasecmp(URL_SCHEME(h_url), "dpi") == 0 &&
+ strncmp(URL_PATH(h_url), "/vsource/", 9) == 0) {
+ /* allow reload for view source dpi */
+ confirmed = 1;
} else if (URL_FLAGS(h_url) & URL_Post) {
/* Attempt to repost data, let's confirm... */
choice = a_Dialog_choice5("Repost form data?",
diff --git a/src/png.c b/src/png.c
index bf9de2ef..bf34a8d5 100644
--- a/src/png.c
+++ b/src/png.c
@@ -98,8 +98,6 @@ struct _DilloPng {
} DilloPng;
#define DATASIZE (png->ipbufsize - png->ipbufstart)
-#define BLACK 0
-#define WHITE 255
static
diff --git a/src/prefsparser.cc b/src/prefsparser.cc
index efe64a0e..e74b5a6f 100644
--- a/src/prefsparser.cc
+++ b/src/prefsparser.cc
@@ -113,7 +113,7 @@ int PrefsParser::parseOption(char *name, char *value)
};
node = NULL;
- for (i = 0; i < sizeof(symbols) / sizeof(SymNode_t); i++) {
+ for (i = 0; i < sizeof(symbols) / sizeof(symbols[0]); i++) {
if (!strcmp(symbols[i].name, name)) {
node = & (symbols[i]);
break;
@@ -127,8 +127,8 @@ int PrefsParser::parseOption(char *name, char *value)
switch (node->type) {
case PREFS_BOOL:
- *(bool_t *)node->pref = (!dStrcasecmp(value, "yes") ||
- !dStrcasecmp(value, "true"));
+ *(bool_t *)node->pref = (!dStrAsciiCasecmp(value, "yes") ||
+ !dStrAsciiCasecmp(value, "true"));
break;
case PREFS_COLOR:
*(int32_t *)node->pref = a_Color_parse(value, *(int32_t*)node->pref,&st);
@@ -167,18 +167,18 @@ int PrefsParser::parseOption(char *name, char *value)
&prefs.width, &prefs.height);
break;
case PREFS_FILTER:
- if (!dStrcasecmp(value, "same_domain"))
+ if (!dStrAsciiCasecmp(value, "same_domain"))
prefs.filter_auto_requests = PREFS_FILTER_SAME_DOMAIN;
else {
- if (dStrcasecmp(value, "allow_all"))
+ if (dStrAsciiCasecmp(value, "allow_all"))
MSG_WARN("prefs: unrecognized value for filter_auto_requests\n");
prefs.filter_auto_requests = PREFS_FILTER_ALLOW_ALL;
}
break;
case PREFS_PANEL_SIZE:
- if (!dStrcasecmp(value, "tiny"))
+ if (!dStrAsciiCasecmp(value, "tiny"))
prefs.panel_size = P_tiny;
- else if (!dStrcasecmp(value, "small"))
+ else if (!dStrAsciiCasecmp(value, "small"))
prefs.panel_size = P_small;
else /* default to "medium" */
prefs.panel_size = P_medium;
diff --git a/src/styleengine.cc b/src/styleengine.cc
index a4c31ccb..ed272269 100644
--- a/src/styleengine.cc
+++ b/src/styleengine.cc
@@ -12,6 +12,7 @@
#include "../dlib/dlib.h"
#include "msg.h"
#include "prefs.h"
+#include "misc.h"
#include "html_common.hh"
#include "styleengine.hh"
@@ -25,6 +26,8 @@ StyleEngine::StyleEngine (dw::core::Layout *layout) {
doctree = new Doctree ();
stack = new lout::misc::SimpleVector <Node> (1);
cssContext = new CssContext ();
+ buildUserAgentStyle ();
+ buildUserStyle ();
this->layout = layout;
importDepth = 0;
@@ -103,7 +106,7 @@ void StyleEngine::setId (const char *id) {
DoctreeNode *dn = doctree->top ();
assert (dn->id == NULL);
dn->id = dStrdup (id);
-};
+}
/**
* \brief split a string at sep chars and return a SimpleVector of strings
@@ -134,7 +137,7 @@ void StyleEngine::setClass (const char *klass) {
DoctreeNode *dn = doctree->top ();
assert (dn->klass == NULL);
dn->klass = splitStr (klass, ' ');
-};
+}
void StyleEngine::setStyle (const char *styleAttr) {
Node *n = stack->getRef (stack->size () - 1);
@@ -148,7 +151,7 @@ void StyleEngine::setStyle (const char *styleAttr) {
n->styleAttrProperties,
n->styleAttrPropertiesImportant);
}
-};
+}
/**
* \brief Instruct StyleEngine to use the nonCssHints from parent element
@@ -303,15 +306,15 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
*c = '\0';
dStrstrip(p->value.strVal);
- if (strcmp (p->value.strVal, "serif") == 0)
+ if (dStrAsciiCasecmp (p->value.strVal, "serif") == 0)
fontName = prefs.font_serif;
- else if (strcmp (p->value.strVal, "sans-serif") == 0)
+ else if (dStrAsciiCasecmp (p->value.strVal, "sans-serif") == 0)
fontName = prefs.font_sans_serif;
- else if (strcmp (p->value.strVal, "cursive") == 0)
+ else if (dStrAsciiCasecmp (p->value.strVal, "cursive") == 0)
fontName = prefs.font_cursive;
- else if (strcmp (p->value.strVal, "fantasy") == 0)
+ else if (dStrAsciiCasecmp (p->value.strVal, "fantasy") == 0)
fontName = prefs.font_fantasy;
- else if (strcmp (p->value.strVal, "monospace") == 0)
+ else if (dStrAsciiCasecmp (p->value.strVal, "monospace") == 0)
fontName = prefs.font_monospace;
else if (Font::exists(layout, p->value.strVal))
fontName = p->value.strVal;
@@ -331,30 +334,33 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
if (p->type == CSS_TYPE_ENUM) {
switch (p->value.intVal) {
case CSS_FONT_SIZE_XX_SMALL:
- fontAttrs.size = roundInt(11.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(8.1 * prefs.font_factor);
break;
case CSS_FONT_SIZE_X_SMALL:
- fontAttrs.size = roundInt(12.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(9.7 * prefs.font_factor);
break;
case CSS_FONT_SIZE_SMALL:
- fontAttrs.size = roundInt(13.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(11.7 * prefs.font_factor);
break;
case CSS_FONT_SIZE_MEDIUM:
fontAttrs.size = roundInt(14.0 * prefs.font_factor);
break;
case CSS_FONT_SIZE_LARGE:
+ fontAttrs.size = roundInt(16.8 * prefs.font_factor);
break;
case CSS_FONT_SIZE_X_LARGE:
- fontAttrs.size = roundInt(16.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(20.2 * prefs.font_factor);
break;
case CSS_FONT_SIZE_XX_LARGE:
- fontAttrs.size = roundInt(17.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(24.2 * prefs.font_factor);
break;
case CSS_FONT_SIZE_SMALLER:
- fontAttrs.size -= roundInt(1.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(fontAttrs.size * 0.83 *
+ prefs.font_factor);
break;
case CSS_FONT_SIZE_LARGER:
- fontAttrs.size += roundInt(1.0 * prefs.font_factor);
+ fontAttrs.size = roundInt(fontAttrs.size * 1.2 *
+ prefs.font_factor);
break;
default:
assert(false); // invalid font-size enum
@@ -565,6 +571,9 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
case CSS_PROPERTY_TEXT_INDENT:
computeLength (&attrs->textIndent, p->value.intVal, attrs->font);
break;
+ case CSS_PROPERTY_TEXT_TRANSFORM:
+ attrs->textTransform = (TextTransform) p->value.intVal;
+ break;
case CSS_PROPERTY_VERTICAL_ALIGN:
attrs->valign = (VAlignType) p->value.intVal;
break;
@@ -595,6 +604,13 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
case PROPERTY_X_LINK:
attrs->x_link = p->value.intVal;
break;
+ case PROPERTY_X_LANG:
+ attrs->x_lang[0] = tolower (p->value.strVal[0]);
+ if (attrs->x_lang[0])
+ attrs->x_lang[1] = tolower (p->value.strVal[1]);
+ else
+ attrs->x_lang[1] = 0;
+ break;
case PROPERTY_X_IMG:
attrs->x_img = p->value.intVal;
break;
@@ -804,3 +820,74 @@ void StyleEngine::parse (DilloHtml *html, DilloUrl *url, const char *buf,
CssParser::parse (html, url, cssContext, buf, buflen, origin);
importDepth--;
}
+
+/**
+ * \brief Create the user agent style.
+ *
+ * The user agent style defines how dillo renders HTML in the absence of
+ * author or user styles.
+ */
+void StyleEngine::buildUserAgentStyle () {
+ const char *cssBuf =
+ "body {margin: 5px}"
+ "big {font-size: 1.17em}"
+ "blockquote, dd {margin-left: 40px; margin-right: 40px}"
+ "center {text-align: center}"
+ "dt {font-weight: bolder}"
+ ":link {color: blue; text-decoration: underline; cursor: pointer}"
+ ":visited {color: #800080; text-decoration: underline; cursor: pointer}"
+ "h1, h2, h3, h4, h5, h6, b, strong {font-weight: bolder}"
+ "address, center, div, h1, h2, h3, h4, h5, h6, ol, p, ul, pre {display: block}"
+ "i, em, cite, address, var {font-style: italic}"
+ ":link img, :visited img {border: 1px solid}"
+ "frameset, ul, ol, dir {margin-left: 40px}"
+ /* WORKAROUND: It should be margin: 1em 0
+ * but as we don't collapse these margins yet, it
+ * look better like this.
+ */
+ "p {margin: 0.5em 0}"
+ "h1 {font-size: 2em; margin-top: .67em; margin-bottom: 0}"
+ "h2 {font-size: 1.5em; margin-top: .75em; margin-bottom: 0}"
+ "h3 {font-size: 1.17em; margin-top: .83em; margin-bottom: 0}"
+ "h4 {margin-top: 1.12em; margin-bottom: 0}"
+ "h5 {font-size: 0.83em; margin-top: 1.5em; margin-bottom: 0}"
+ "h6 {font-size: 0.75em; margin-top: 1.67em; margin-bottom: 0}"
+ "hr {width: 100%; border: 1px inset}"
+ "li {margin-top: 0.1em; display: list-item}"
+ "pre {white-space: pre}"
+ "ol {list-style-type: decimal}"
+ "ul {list-style-type: disc}"
+ "ul ul {list-style-type: circle}"
+ "ul ul ul {list-style-type: square}"
+ "ul ul ul ul {list-style-type: disc}"
+ "u {text-decoration: underline}"
+ "small, sub, sup {font-size: 0.83em}"
+ "sub {vertical-align: sub}"
+ "sup {vertical-align: super}"
+ "s, strike, del {text-decoration: line-through}"
+ "table {border-spacing: 2px}"
+ "td, th {padding: 2px}"
+ "thead, tbody, tfoot {vertical-align: middle}"
+ "th {font-weight: bolder; text-align: center}"
+ "code, tt, pre, samp, kbd {font-family: monospace}"
+ /* WORKAROUND: Reset font properties in tables as some
+ * pages rely on it (e.g. gmail).
+ * http://developer.mozilla.org/En/Fixing_Table_Inheritance_in_Quirks_Mode
+ * has a detailed description of the issue.
+ */
+ "table, caption {font-size: medium; font-weight: normal}";
+
+ CssParser::parse (NULL, NULL, cssContext, cssBuf, strlen (cssBuf),
+ CSS_ORIGIN_USER_AGENT);
+}
+
+void StyleEngine::buildUserStyle () {
+ Dstr *style;
+ char *filename = dStrconcat(dGethomedir(), "/.dillo/style.css", NULL);
+
+ if ((style = a_Misc_file2dstr(filename))) {
+ CssParser::parse (NULL,NULL,cssContext,style->str, style->len,CSS_ORIGIN_USER);
+ dStr_free (style, 1);
+ }
+ dFree (filename);
+}
diff --git a/src/styleengine.hh b/src/styleengine.hh
index b73a8b5f..7cca1475 100644
--- a/src/styleengine.hh
+++ b/src/styleengine.hh
@@ -36,6 +36,8 @@ class StyleEngine {
Doctree *doctree;
int importDepth;
+ void buildUserAgentStyle ();
+ void buildUserStyle ();
dw::core::style::Style *style0 (int i);
dw::core::style::Style *wordStyle0 ();
inline void setNonCssHint(CssPropertyName name, CssValueType type,
diff --git a/src/table.cc b/src/table.cc
index d48a0c45..d66b32b0 100644
--- a/src/table.cc
+++ b/src/table.cc
@@ -30,14 +30,15 @@ using namespace dw::core::style;
static void Html_tag_open_table_cell(DilloHtml *html,
const char *tag, int tagsize,
- dw::core::style::TextAlignType text_align);
+ dw::core::style::TextAlignType text_align);
+static void Html_tag_content_table_cell(DilloHtml *html,
+ const char *tag, int tagsize);
/*
* <TABLE>
*/
void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize)
{
- dw::core::Widget *table;
const char *attrbuf;
int32_t border = -1, cellspacing = -1, cellpadding = -1, bgcolor = -1;
CssLength cssLength;
@@ -81,13 +82,13 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize)
a_Html_parse_length (html, attrbuf));
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) {
- if (dStrcasecmp (attrbuf, "left") == 0)
+ if (dStrAsciiCasecmp (attrbuf, "left") == 0)
html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN,
CSS_TYPE_ENUM, TEXT_ALIGN_LEFT);
- else if (dStrcasecmp (attrbuf, "right") == 0)
+ else if (dStrAsciiCasecmp (attrbuf, "right") == 0)
html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN,
CSS_TYPE_ENUM, TEXT_ALIGN_RIGHT);
- else if (dStrcasecmp (attrbuf, "center") == 0)
+ else if (dStrAsciiCasecmp (attrbuf, "center") == 0)
html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN,
CSS_TYPE_ENUM, TEXT_ALIGN_CENTER);
}
@@ -99,7 +100,7 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize)
CSS_TYPE_COLOR, bgcolor);
}
- HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
+ html->styleEngine->style (); // evaluate now, so we can build non-css hints for the cells
/* The style for the cells */
html->styleEngine->clearNonCssHints ();
@@ -135,13 +136,21 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize)
CSS_TYPE_LENGTH_PERCENTAGE, cssLength);
}
+}
+void Html_tag_content_table(DilloHtml *html, const char *tag, int tagsize)
+{
+ dw::core::Widget *table;
+
+ HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
table = new dw::Table(prefs.limit_text_width);
HT2TB(html)->addWidget (table, html->styleEngine->style ());
+ HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
S_TOP(html)->table_mode = DILLO_HTML_TABLE_MODE_TOP;
S_TOP(html)->table_border_mode = DILLO_HTML_TABLE_BORDER_SEPARATE;
S_TOP(html)->cell_text_align_set = FALSE;
S_TOP(html)->table = table;
+
}
/*
@@ -177,8 +186,6 @@ void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize)
html->styleEngine->inheritBackgroundColor ();
- ((dw::Table*)S_TOP(html)->table)->addRow (html->styleEngine->style ());
-
if (bgcolor != -1) {
html->styleEngine->setNonCssHint(CSS_PROPERTY_BACKGROUND_COLOR,
CSS_TYPE_COLOR, bgcolor);
@@ -188,6 +195,20 @@ void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize)
default:
break;
}
+}
+
+void Html_tag_content_tr(DilloHtml *html, const char *tag, int tagsize)
+{
+ switch (S_TOP(html)->table_mode) {
+ case DILLO_HTML_TABLE_MODE_NONE:
+ return;
+ case DILLO_HTML_TABLE_MODE_TOP:
+ case DILLO_HTML_TABLE_MODE_TR:
+ case DILLO_HTML_TABLE_MODE_TD:
+ ((dw::Table*)S_TOP(html)->table)->addRow (html->styleEngine->style ());
+ default:
+ break;
+ }
S_TOP(html)->table_mode = DILLO_HTML_TABLE_MODE_TR;
}
@@ -201,6 +222,11 @@ void Html_tag_open_td(DilloHtml *html, const char *tag, int tagsize)
dw::core::style::TEXT_ALIGN_LEFT);
}
+void Html_tag_content_td(DilloHtml *html, const char *tag, int tagsize)
+{
+ Html_tag_content_table_cell (html, tag, tagsize);
+}
+
/*
* <TH>
*/
@@ -210,6 +236,11 @@ void Html_tag_open_th(DilloHtml *html, const char *tag, int tagsize)
dw::core::style::TEXT_ALIGN_CENTER);
}
+void Html_tag_content_th(DilloHtml *html, const char *tag, int tagsize)
+{
+ Html_tag_content_table_cell (html, tag, tagsize);
+}
+
/*
* Utilities
*/
@@ -311,8 +342,6 @@ static void Html_tag_open_table_cell(DilloHtml *html,
const char *tag, int tagsize,
dw::core::style::TextAlignType text_align)
{
- Widget *col_tb;
- int colspan = 1, rowspan = 1;
const char *attrbuf;
int32_t bgcolor;
@@ -329,16 +358,6 @@ static void Html_tag_open_table_cell(DilloHtml *html,
/* continues */
case DILLO_HTML_TABLE_MODE_TR:
case DILLO_HTML_TABLE_MODE_TD:
- if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "colspan"))) {
- char *invalid;
- colspan = strtol(attrbuf, &invalid, 10);
- if ((colspan < 0) || (attrbuf == invalid))
- colspan = 1;
- }
- /* TODO: check errors? */
- if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "rowspan")))
- rowspan = MAX(1, strtol (attrbuf, NULL, 10));
-
/* text style */
if (!S_TOP(html)->cell_text_align_set) {
html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN,
@@ -347,9 +366,6 @@ static void Html_tag_open_table_cell(DilloHtml *html,
if (a_Html_get_attr(html, tag, tagsize, "nowrap"))
html->styleEngine->setNonCssHint(CSS_PROPERTY_WHITE_SPACE,
CSS_TYPE_ENUM, WHITE_SPACE_NOWRAP);
- else
- html->styleEngine->setNonCssHint(CSS_PROPERTY_WHITE_SPACE,
- CSS_TYPE_ENUM, WHITE_SPACE_NORMAL);
a_Html_tag_set_align_attr (html, tag, tagsize);
@@ -368,6 +384,38 @@ static void Html_tag_open_table_cell(DilloHtml *html,
CSS_TYPE_COLOR, bgcolor);
}
+ default:
+ /* compiler happiness */
+ break;
+ }
+}
+
+static void Html_tag_content_table_cell(DilloHtml *html,
+ const char *tag, int tagsize)
+{
+ int colspan = 1, rowspan = 1;
+ const char *attrbuf;
+ Widget *col_tb;
+
+ switch (S_TOP(html)->table_mode) {
+ case DILLO_HTML_TABLE_MODE_NONE:
+ return;
+
+ case DILLO_HTML_TABLE_MODE_TOP:
+ BUG_MSG("<td> or <th> outside <tr>\n");
+ /* a_Dw_table_add_cell takes care that dillo does not crash. */
+ /* continues */
+ case DILLO_HTML_TABLE_MODE_TR:
+ case DILLO_HTML_TABLE_MODE_TD:
+ if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "colspan"))) {
+ char *invalid;
+ colspan = strtol(attrbuf, &invalid, 10);
+ if ((colspan < 0) || (attrbuf == invalid))
+ colspan = 1;
+ }
+ /* TODO: check errors? */
+ if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "rowspan")))
+ rowspan = MAX(1, strtol (attrbuf, NULL, 10));
if (html->styleEngine->style ()->textAlign
== TEXT_ALIGN_STRING)
col_tb = new dw::TableCell (
diff --git a/src/table.hh b/src/table.hh
index aca717ba..5417f681 100644
--- a/src/table.hh
+++ b/src/table.hh
@@ -12,8 +12,12 @@ class DilloHtml;
*/
void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize);
+void Html_tag_content_table(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize);
+void Html_tag_content_tr(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_open_td(DilloHtml *html, const char *tag, int tagsize);
+void Html_tag_content_td(DilloHtml *html, const char *tag, int tagsize);
void Html_tag_open_th(DilloHtml *html, const char *tag, int tagsize);
+void Html_tag_content_th(DilloHtml *html, const char *tag, int tagsize);
#endif /* __TABLE_HH__ */
diff --git a/src/ui.cc b/src/ui.cc
index afa88073..ce7a2a8a 100644
--- a/src/ui.cc
+++ b/src/ui.cc
@@ -739,10 +739,6 @@ int UI::handle(int event)
a_UIcmd_search_dialog(a_UIcmd_get_bw_by_widget(this));
ret = 1;
} else if (cmd == KEYS_GOTO) {
- if (Panelmode == UI_HIDDEN) {
- panels_toggle();
- temporaryPanels(true);
- }
focus_location();
ret = 1;
} else if (cmd == KEYS_HIDE_PANELS) {
@@ -819,6 +815,10 @@ void UI::set_location(const char *str)
*/
void UI::focus_location()
{
+ if (Panelmode == UI_HIDDEN) {
+ panels_toggle();
+ temporaryPanels(true);
+ }
Location->take_focus();
// Make text selected when already focused.
Location->position(Location->size(), 0);
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 38225047..6ca98280 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -597,7 +597,7 @@ void a_UIcmd_open_urlstr(void *vbw, const char *urlstr)
/* Filter URL string */
new_urlstr = a_Url_string_strip_delimiters(urlstr);
- if (!dStrncasecmp(new_urlstr, "file:", 5)) {
+ if (!dStrnAsciiCasecmp(new_urlstr, "file:", 5)) {
/* file URI */
ch = new_urlstr[5];
if (!ch || ch == '.') {
@@ -1177,7 +1177,7 @@ void a_UIcmd_scroll(BrowserWindow *bw, int icmd)
};
KeysCommand_t keycmd = (KeysCommand_t)icmd;
- for (uint_t i = 0; i < (sizeof(map)/sizeof(mapping_t)); i++) {
+ for (uint_t i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
if (keycmd == map[i].keys_cmd) {
layout->scroll(map[i].dw_cmd);
break;
diff --git a/src/url.c b/src/url.c
index 78f717cf..4c7ea356 100644
--- a/src/url.c
+++ b/src/url.c
@@ -54,7 +54,7 @@ static const char *HEX = "0123456789ABCDEF";
#define URL_STR_FIELD_CMP(s1,s2) \
(s1) && (s2) ? strcmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1
#define URL_STR_FIELD_I_CMP(s1,s2) \
- (s1) && (s2) ? dStrcasecmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1
+ (s1) && (s2) ? dStrAsciiCasecmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1
/*
* Return the url as a string.
@@ -586,8 +586,7 @@ char *a_Url_encode_hex_str(const char *str)
newstr = dNew(char, 6*strlen(str)+1);
for (c = newstr; *str; str++)
- if ((dIsalnum(*str) && !(*str & 0x80)) || strchr(verbatim, *str))
- /* we really need isalnum for the "C" locale */
+ if ((dIsalnum(*str) && isascii(*str)) || strchr(verbatim, *str))
*c++ = *str;
else if (*str == ' ')
*c++ = '+';
@@ -652,10 +651,10 @@ static bool_t Url_host_is_ip(const char *host)
_MSG("an IPv4 address\n");
return TRUE;
}
- if (*host == '[' &&
- (len == strspn(host, "0123456789abcdefABCDEF:.[]"))) {
+ if (strchr(host, ':') &&
+ (len == strspn(host, "0123456789abcdefABCDEF:."))) {
/* The precise format is shown in section 3.2.2 of rfc 3986 */
- _MSG("an IPv6 address\n");
+ MSG("an IPv6 address\n");
return TRUE;
}
return FALSE;
@@ -702,7 +701,7 @@ static uint_t Url_host_public_internal_dots(const char *host)
for (i = 0; i < tld_num; i++) {
if (strlen(tlds[i]) == (uint_t) tld_len &&
- !dStrncasecmp(tlds[i], host + start, tld_len)) {
+ !dStrnAsciiCasecmp(tlds[i], host + start, tld_len)) {
_MSG("TLD code matched %s\n", tlds[i]);
ret++;
break;
@@ -759,6 +758,7 @@ bool_t a_Url_same_organization(const DilloUrl *u1, const DilloUrl *u2)
if (!u1 || !u2)
return FALSE;
- return dStrcasecmp(Url_host_find_public_suffix(URL_HOST(u1)),
- Url_host_find_public_suffix(URL_HOST(u2))) ? FALSE :TRUE;
+ return dStrAsciiCasecmp(Url_host_find_public_suffix(URL_HOST(u1)),
+ Url_host_find_public_suffix(URL_HOST(u2)))
+ ? FALSE : TRUE;
}
diff --git a/src/web.cc b/src/web.cc
index 74851f2b..48c368be 100644
--- a/src/web.cc
+++ b/src/web.cc
@@ -95,7 +95,7 @@ int a_Web_dispatch_by_type (const char *Type, DilloWeb *Web,
} else {
/* A non-RootUrl. At this moment we only handle image-children */
- if (!dStrncasecmp(Type, "image/", 6)) {
+ if (!dStrnAsciiCasecmp(Type, "image/", 6)) {
dw = (Widget*) a_Mime_set_viewer(Type, Web, Call, Data);
} else {
MSG_HTTP("'%s' cannot be displayed as image; has media type '%s'\n",