Merge commit 'upstream/3.0.2_rc1'
Axel Beckert
12 years ago
73 | 73 | |
74 | 74 | Contributions are always welcome! |
75 | 75 | |
76 | ||
77 | ||
78 | --------------- | |
79 | Non-Dillo code: | |
80 | --------------- | |
81 | ||
82 | * dw/fltkcomplexbutton.(cc|hh) contain code from the FLTK project whose | |
83 | copyright is held by Bill Spitzak and others. | |
84 | * src/binaryconst.h contains code by Tom Torfs that the author placed in the | |
85 | public domain. | |
86 | * src/md5.[ch] contain code by L. Peter Deutsch whose copyright is held by | |
87 | Aladdin Enterprises. |
0 | 0 | ============================================================================= |
1 | 1 | Dillo project |
2 | 2 | ============================================================================= |
3 | ||
4 | Here we list changes that are relatively significant and/or visible to the | |
5 | user. For a history of changes in full detail, see our Mercurial repository | |
6 | at http://hg.dillo.org/dillo | |
7 | ||
8 | ||
9 | dillo-3.0.2 [December 05, 2011] | |
10 | ||
11 | +- Digest authentication | |
12 | Patch: Justus Winter, corvid | |
13 | +- text-transform property | |
14 | - If not following redirection, show body of redirecting page. | |
15 | - Middle click on stylesheet menu item opens in new tab/window. | |
16 | - Improve handling of combining characters. | |
17 | - Locale-independent ASCII character case handling (fixes Turkic locales). | |
18 | Patches: corvid | |
19 | +- Rework line breaking and fix white-space:nowrap handling. | |
20 | Patch: Johannes Hofmann | |
21 | +- Bind Ctrl-{PageUp,PageDown} to tab-{previous,next}. | |
22 | Patch: Jeremy Henty | |
23 | ||
24 | ----------------------------------------------------------------------------- | |
3 | 25 | |
4 | 26 | dillo-3.0.1 [September 21, 2011] |
5 | 27 | |
51 | 73 | Patch: Johannes Hofmann |
52 | 74 | +- Default binding for left-tab changed to Shift-Ctrl-Tab. |
53 | 75 | Patch: Jeremy Henty |
54 | ||
55 | Note: these are user-visible changes. The full Changelog is kept | |
56 | in our Mercurial repository at http://hg.dillo.org/dillo | |
57 | ||
58 | 76 | |
59 | 77 | ----------------------------------------------------------------------------- |
60 | 78 |
1 | 1 | Dillo web browser |
2 | 2 | =================== |
3 | 3 | |
4 | Dillo-3.0 is the first release of the newest branch, which is | |
5 | based on the already released fltk-1.3 toolkit. This is big news | |
6 | because it clears the way for Dillo to return to those | |
7 | distributions which had excluded Dillo2 due to FLTK2 never | |
8 | being officially released. | |
4 | Dillo is a multi-platform graphical web browser, known for its | |
5 | speed and small footprint, that is developed with a focus on | |
6 | personal security and privacy. | |
9 | 7 | |
10 | The development effort shifted to the dillo-3.x branch long ago, | |
11 | and it became the active one; dillo-2.x received less and less | |
12 | attention, and dillo-2.2.1 became the last of its series. | |
8 | The dillo3 series uses version 1.3.x of the FLTK GUI toolkit | |
9 | (http://fltk.org). | |
13 | 10 | |
14 | The core team will focus on implementing the CSS feature of | |
15 | floating elements. This will greatly improve dillo's web page | |
16 | rendering since many sites have adopted floats instead of tables. | |
17 | ||
18 | The new dillo3 has shown excellent stability. | |
11 | The core team currently plans to focus on implementing the CSS | |
12 | feature of floating elements. This will greatly improve | |
13 | dillo's web page rendering since many sites have adopted floats | |
14 | instead of tables. | |
19 | 15 | |
20 | 16 | The core team welcomes developers willing to join our workforce. |
21 | 17 | |
22 | 18 | |
23 | 19 | NOTE: With FLTK-1.3, when running on X with Xft enabled (the |
24 | default), font naming is more restricted than it was with FLTK2. | |
25 | If your font_* preferences are no longer working well, please try | |
26 | the fc-list command as given in dillorc. | |
20 | default), font naming is more restricted than it was with FLTK2 | |
21 | as used by dillo2. If your font_* preferences are no longer | |
22 | working well, please try the fc-list command as it is shown in | |
23 | dillorc. | |
27 | 24 | |
28 | 25 | |
29 | 26 | Here's a list of some old well-known problems of dillo: |
33 | 30 | |
34 | 31 | |
35 | 32 | ------- |
36 | FLTK1.3 | |
33 | FLTK-1.3 | |
37 | 34 | ------- |
38 | 35 | |
39 | 36 | You can get FLTK-1.3 here: |
58 | 55 | |
59 | 56 | 2.- Then dillo3: |
60 | 57 | |
61 | tar jxvf dillo-3.0.1.tar.bz2 | |
62 | cd dillo-3.0.1 | |
58 | tar jxvf dillo-3.0.2.tar.bz2 | |
59 | cd dillo-3.0.2 | |
63 | 60 | ./configure; make |
64 | 61 | sudo make install-strip |
65 | 62 |
0 | 0 | #! /bin/sh |
1 | 1 | # Attempt to guess a canonical system name. |
2 | 2 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
3 | # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 | |
3 | # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | |
4 | 4 | # Free Software Foundation, Inc. |
5 | 5 | |
6 | timestamp='2009-12-30' | |
6 | timestamp='2009-11-20' | |
7 | 7 | |
8 | 8 | # This file is free software; you can redistribute it and/or modify it |
9 | 9 | # under the terms of the GNU General Public License as published by |
55 | 55 | GNU config.guess ($timestamp) |
56 | 56 | |
57 | 57 | Originally written by Per Bothner. |
58 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, | |
59 | 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free | |
60 | Software Foundation, Inc. | |
58 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, | |
59 | 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. | |
61 | 60 | |
62 | 61 | This is free software; see the source for copying conditions. There is NO |
63 | 62 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." |
0 | 0 | #! /bin/sh |
1 | 1 | # Configuration validation subroutine script. |
2 | 2 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
3 | # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 | |
3 | # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | |
4 | 4 | # Free Software Foundation, Inc. |
5 | 5 | |
6 | timestamp='2009-12-31' | |
6 | timestamp='2009-11-20' | |
7 | 7 | |
8 | 8 | # This file is (in principle) common to ALL GNU software. |
9 | 9 | # The presence of a machine in this file suggests that SOME GNU software |
74 | 74 | version="\ |
75 | 75 | GNU config.sub ($timestamp) |
76 | 76 | |
77 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, | |
78 | 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free | |
79 | Software Foundation, Inc. | |
77 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, | |
78 | 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. | |
80 | 79 | |
81 | 80 | This is free software; see the source for copying conditions. There is NO |
82 | 81 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." |
1435 | 1434 | -dicos*) |
1436 | 1435 | os=-dicos |
1437 | 1436 | ;; |
1438 | -nacl*) | |
1439 | ;; | |
1440 | 1437 | -none) |
1441 | 1438 | ;; |
1442 | 1439 | *) |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.68 for dillo 3.0.1. | |
2 | # Generated by GNU Autoconf 2.68 for dillo 3.0.2. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
556 | 556 | # Identity of this package. |
557 | 557 | PACKAGE_NAME='dillo' |
558 | 558 | PACKAGE_TARNAME='dillo' |
559 | PACKAGE_VERSION='3.0.1' | |
560 | PACKAGE_STRING='dillo 3.0.1' | |
559 | PACKAGE_VERSION='3.0.2' | |
560 | PACKAGE_STRING='dillo 3.0.2' | |
561 | 561 | PACKAGE_BUGREPORT='' |
562 | 562 | PACKAGE_URL='' |
563 | 563 | |
1286 | 1286 | # Omit some internal or obsolete options to make the list less imposing. |
1287 | 1287 | # This message is too long to be a string in the A/UX 3.1 sh. |
1288 | 1288 | cat <<_ACEOF |
1289 | \`configure' configures dillo 3.0.1 to adapt to many kinds of systems. | |
1289 | \`configure' configures dillo 3.0.2 to adapt to many kinds of systems. | |
1290 | 1290 | |
1291 | 1291 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1292 | 1292 | |
1357 | 1357 | |
1358 | 1358 | if test -n "$ac_init_help"; then |
1359 | 1359 | case $ac_init_help in |
1360 | short | recursive ) echo "Configuration of dillo 3.0.1:";; | |
1360 | short | recursive ) echo "Configuration of dillo 3.0.2:";; | |
1361 | 1361 | esac |
1362 | 1362 | cat <<\_ACEOF |
1363 | 1363 | |
1463 | 1463 | test -n "$ac_init_help" && exit $ac_status |
1464 | 1464 | if $ac_init_version; then |
1465 | 1465 | cat <<\_ACEOF |
1466 | dillo configure 3.0.1 | |
1466 | dillo configure 3.0.2 | |
1467 | 1467 | generated by GNU Autoconf 2.68 |
1468 | 1468 | |
1469 | 1469 | Copyright (C) 2010 Free Software Foundation, Inc. |
2171 | 2171 | This file contains any messages produced by compilers while |
2172 | 2172 | running configure, to aid debugging if configure makes a mistake. |
2173 | 2173 | |
2174 | It was created by dillo $as_me 3.0.1, which was | |
2174 | It was created by dillo $as_me 3.0.2, which was | |
2175 | 2175 | generated by GNU Autoconf 2.68. Invocation command line was |
2176 | 2176 | |
2177 | 2177 | $ $0 $@ |
3098 | 3098 | |
3099 | 3099 | # Define the identity of the package. |
3100 | 3100 | PACKAGE='dillo' |
3101 | VERSION='3.0.1' | |
3101 | VERSION='3.0.2' | |
3102 | 3102 | |
3103 | 3103 | |
3104 | 3104 | cat >>confdefs.h <<_ACEOF |
6983 | 6983 | # report actual input values of CONFIG_FILES etc. instead of their |
6984 | 6984 | # values after options handling. |
6985 | 6985 | ac_log=" |
6986 | This file was extended by dillo $as_me 3.0.1, which was | |
6986 | This file was extended by dillo $as_me 3.0.2, which was | |
6987 | 6987 | generated by GNU Autoconf 2.68. Invocation command line was |
6988 | 6988 | |
6989 | 6989 | CONFIG_FILES = $CONFIG_FILES |
7049 | 7049 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
7050 | 7050 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
7051 | 7051 | ac_cs_version="\\ |
7052 | dillo config.status 3.0.1 | |
7052 | dillo config.status 3.0.2 | |
7053 | 7053 | configured by $0, generated by GNU Autoconf 2.68, |
7054 | 7054 | with options \\"\$ac_cs_config\\" |
7055 | 7055 |
0 | 0 | dnl Process this file with aclocal, autoconf and automake. |
1 | 1 | |
2 | AC_INIT([dillo], [3.0.1]) | |
2 | AC_INIT([dillo], [3.0.2]) | |
3 | 3 | |
4 | 4 | dnl Detect the canonical target build environment |
5 | 5 | AC_CANONICAL_TARGET |
46 | 46 | dnl |
47 | 47 | AC_CHECK_SIZEOF(char) |
48 | 48 | AC_CHECK_SIZEOF(short) |
49 | AC_CHECK_SIZEOF(long) | |
50 | AC_CHECK_SIZEOF(int) | |
49 | AC_CHECK_SIZEOF(long) | |
50 | AC_CHECK_SIZEOF(int) | |
51 | 51 | AC_CHECK_SIZEOF(void *) |
52 | 52 | |
53 | 53 | AC_TYPE_INT16_T |
303 | 303 | |
304 | 304 | dnl ---------------------- |
305 | 305 | dnl Check if we need to |
306 | dnl support the old | |
306 | dnl support the old | |
307 | 307 | dnl iconv interface |
308 | 308 | dnl ---------------------- |
309 | 309 | if test "x$iconv_ok" = "xyes"; then |
369 | 369 | else |
370 | 370 | AC_MSG_RESULT(no. Now we will try some libraries.) |
371 | 371 | |
372 | AC_SEARCH_LIBS(pthread_create, pthread, | |
373 | LIBPTHREADS_LIBS="-lpthread", | |
374 | AC_SEARCH_LIBS(pthread_create, pthreads, | |
372 | AC_SEARCH_LIBS(pthread_create, pthread, | |
373 | LIBPTHREADS_LIBS="-lpthread", | |
374 | AC_SEARCH_LIBS(pthread_create, pthreads, | |
375 | 375 | LIBPTHREADS_LIBS="-lpthreads", |
376 | 376 | AC_SEARCH_LIBS(pthread_create, c_r, |
377 | 377 | LIBPTHREADS_LIBS="-lc_r", thread_ok=no))) |
164 | 164 | # |
165 | 165 | # See http://zytrax.com/tech/web/browser_ids.htm for a compilation of strings. |
166 | 166 | # |
167 | # http_user_agent="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" | |
168 | # http_user_agent="Wget/1.11.4" | |
169 | #The default is Dillo/(current version number) | |
167 | # http_user_agent="Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1" | |
168 | # http_user_agent="Wget/1.12 (linux-gnu)" | |
169 | #The default is "Dillo/"+current_version_number | |
170 | 170 | |
171 | 171 | #------------------------------------------------------------------------- |
172 | 172 | # COLORS SECTION |
239 | 239 | |
240 | 240 | # A mouse's middle click over a tab closes the Tab. |
241 | 241 | # With mousewheel mouses, right click feels way better (set to YES). |
242 | #right_click_closes_tab=NO | |
242 | #right_click_closes_tab=NO | |
243 | 243 | |
244 | 244 | # Mouse middle click by default drives drag-scrolling. |
245 | 245 | # To paste an URL into the window instead of scrolling, set it to NO. |
133 | 133 | } |
134 | 134 | |
135 | 135 | /* |
136 | * Clear the contents of the string | |
137 | */ | |
138 | void dStrshred(char *s) | |
139 | { | |
140 | if (s) | |
141 | memset(s, 0, strlen(s)); | |
142 | } | |
143 | ||
144 | /* | |
136 | 145 | * Return a new string of length 'len' filled with 'c' characters |
137 | 146 | */ |
138 | 147 | char *dStrnfill(size_t len, char c) |
163 | 172 | } |
164 | 173 | |
165 | 174 | /* |
175 | * ASCII functions to avoid the case difficulties introduced by I/i in | |
176 | * Turkic locales. | |
177 | */ | |
178 | ||
179 | /* | |
166 | 180 | * Case insensitive strstr |
167 | 181 | */ |
168 | char *dStristr(const char *haystack, const char *needle) | |
182 | char *dStriAsciiStr(const char *haystack, const char *needle) | |
169 | 183 | { |
170 | 184 | int i, j; |
171 | 185 | char *ret = NULL; |
172 | 186 | |
173 | 187 | if (haystack && needle) { |
174 | 188 | for (i = 0, j = 0; haystack[i] && needle[j]; ++i) |
175 | if (tolower(haystack[i]) == tolower(needle[j])) { | |
189 | if (D_ASCII_TOLOWER(haystack[i]) == D_ASCII_TOLOWER(needle[j])) { | |
176 | 190 | ++j; |
177 | 191 | } else if (j) { |
178 | 192 | i -= j; |
184 | 198 | return ret; |
185 | 199 | } |
186 | 200 | |
201 | int dStrAsciiCasecmp(const char *s1, const char *s2) | |
202 | { | |
203 | int ret = 0; | |
204 | ||
205 | while ((*s1 || *s2) && | |
206 | !(ret = D_ASCII_TOLOWER(*s1) - D_ASCII_TOLOWER(*s2))) { | |
207 | s1++; | |
208 | s2++; | |
209 | } | |
210 | return ret; | |
211 | } | |
212 | ||
213 | int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n) | |
214 | { | |
215 | int ret = 0; | |
216 | ||
217 | while (n-- && (*s1 || *s2) && | |
218 | !(ret = D_ASCII_TOLOWER(*s1) - D_ASCII_TOLOWER(*s2))) { | |
219 | s1++; | |
220 | s2++; | |
221 | } | |
222 | return ret; | |
223 | } | |
187 | 224 | |
188 | 225 | /* |
189 | 226 | *- dStr ---------------------------------------------------------------------- |
332 | 369 | ds->str[len] = 0; |
333 | 370 | ds->len = len; |
334 | 371 | } |
372 | } | |
373 | ||
374 | /* | |
375 | * Clear a Dstr. | |
376 | */ | |
377 | void dStr_shred (Dstr *ds) | |
378 | { | |
379 | if (ds && ds->sz > 0) | |
380 | memset(ds->str, '\0', ds->sz); | |
335 | 381 | } |
336 | 382 | |
337 | 383 | /* |
4 | 4 | #include <stddef.h> /* for size_t */ |
5 | 5 | #include <stdarg.h> /* for va_list */ |
6 | 6 | #include <string.h> /* for strerror */ |
7 | #include <strings.h> /* for strcasecmp, strncasecmp (POSIX 2001) */ | |
8 | 7 | |
9 | 8 | #include "d_size.h" |
10 | 9 | |
33 | 32 | #define dIsspace(c) isspace((uchar_t)(c)) |
34 | 33 | #define dIsalnum(c) isalnum((uchar_t)(c)) |
35 | 34 | |
35 | #define D_ASCII_TOUPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c)) | |
36 | #define D_ASCII_TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + 0x20 : (c)) | |
36 | 37 | /* |
37 | 38 | *-- Casts ------------------------------------------------------------------- |
38 | 39 | */ |
85 | 86 | char *dStrstrip(char *s); |
86 | 87 | char *dStrnfill(size_t len, char c); |
87 | 88 | char *dStrsep(char **orig, const char *delim); |
88 | char *dStristr(const char *haystack, const char *needle); | |
89 | void dStrshred(char *s); | |
90 | char *dStriAsciiStr(const char *haystack, const char *needle); | |
91 | int dStrAsciiCasecmp(const char *s1, const char *s2); | |
92 | int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n); | |
89 | 93 | |
90 | /* these are in POSIX 2001. Could be implemented if a port requires it */ | |
91 | #define dStrcasecmp strcasecmp | |
92 | #define dStrncasecmp strncasecmp | |
93 | 94 | #define dStrerror strerror |
94 | 95 | |
95 | 96 | /* |
113 | 114 | void dStr_insert (Dstr *ds, int pos_0, const char *s); |
114 | 115 | void dStr_insert_l (Dstr *ds, int pos_0, const char *s, int l); |
115 | 116 | void dStr_truncate (Dstr *ds, int len); |
117 | void dStr_shred (Dstr *ds); | |
116 | 118 | void dStr_erase (Dstr *ds, int pos_0, int len); |
117 | 119 | void dStr_vsprintfa (Dstr *ds, const char *format, va_list argp); |
118 | 120 | void dStr_vsprintf (Dstr *ds, const char *format, va_list argp); |
0 | .TH dillo 1 "August 5, 2010" "version 2.2" "USER COMMANDS" | |
0 | .TH dillo 1 "October 13, 2011" "" "USER COMMANDS" | |
1 | 1 | .SH NAME |
2 | 2 | dillo \- web browser |
3 | 3 | .SH SYNOPSIS |
16 | 16 | downloader. |
17 | 17 | .PP |
18 | 18 | Dillo displays HTML, text, PNG, JPEG, and GIF files. |
19 | It handles cookies, basic authentication, proxying, and some CSS. | |
19 | It handles cookies, HTTP authentication (basic and digest), proxying (basic), | |
20 | and some CSS. | |
20 | 21 | .PP |
21 | 22 | Framesets are displayed as links to frames, and there is currently |
22 | 23 | no support for javascript or video. |
2 | 2 | |
3 | 3 | <head> |
4 | 4 | <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
5 | <title> Dillo Web Browser :: | |
5 | <title> Dillo Web Browser :: | |
6 | 6 | |
7 | 7 | Help for New Users |
8 | 8 | |
53 | 53 | </ul> |
54 | 54 | </td></tr> |
55 | 55 | </table> |
56 | ||
56 | ||
57 | 57 | <table WIDTH="100%" BORDER=1 CELLSPACING=0 CELLPADDING=3> |
58 | 58 | <tr ALIGN=LEFT VALIGN=TOP><td bgcolor="wheat"> |
59 | 59 | <h4><font color="green">Usage:</font></h4> |
76 | 76 | <li> <b>Configuration:</b> If you want to change Dillo's |
77 | 77 | appearance or behaviour, look at the options in your |
78 | 78 | <b><font color="#5040a0">dillorc</font></b> |
79 | file (if you don't have a copy in your ~/.dillo/ directory, get it | |
80 | <a href='http://www.dillo.org/dillorc'>here</a>). | |
79 | file (if you don't have a copy in your ~/.dillo/ directory, get it | |
80 | <a href='http://www.dillo.org/dillorc'>here</a>). | |
81 | 81 | |
82 | 82 | <li> Clicking the "Reload" button always requests an end-to-end reload |
83 | 83 | of the page currently viewed, but it will *not* reload embedded |
194 | 194 | That is, if you just compile and use dillo, it will reject |
195 | 195 | every single cookie sent to it! |
196 | 196 | <p> |
197 | If you want to enable cookies in dillo, please read | |
197 | If you want to enable cookies in dillo, please read | |
198 | 198 | <a href="Cookies.txt">Cookies.txt</a>. It's very easy -- |
199 | 199 | just a matter of setting up a <code>cookiesrc</code> file). |
200 | 200 | </td></tr> |
251 | 251 | (<a href='http://www.dillo.org/dpi1.html'>dpi</a>) framework. |
252 | 252 | This should be transparent to the end user. Please note that: |
253 | 253 | <ul> |
254 | <li>It is a good idea to keep a backup of your | |
254 | <li>It is a good idea to keep a backup of your | |
255 | 255 | <code>~/.dillo/bm.txt</code> |
256 | 256 | <li>The server will stay alive after closing dillo. |
257 | 257 | <li>You can stop the server by sending it a KILL signal. Dillo |
307 | 307 | <tr><td>Back or "<b>,</b>" <td>< <td>previous page |
308 | 308 | <tr><td>Shift-Back or "<b>.</b>" <td>> <td>next page |
309 | 309 | <tr><td>Alt-F <td>File <td>file menu |
310 | <tr><td>Ctrl-TabKey <td>TabKey <td>Next tab | |
311 | <tr><td>Ctrl-Shift-TabKey <td>TabKey <td>Previous tab | |
310 | <tr><td>Ctrl-TabKey or | |
311 | Ctrl-PageDown <td>TabKey <td>Next tab | |
312 | <tr><td>Ctrl-Shift-TabKey or | |
313 | Ctrl-PageUp <td>TabKey <td>Previous tab | |
312 | 314 | <tr><td>Esc <td>escape <td>close dialog, |
313 | 315 | close findbar,<br> |
314 | 316 | Hide/show control panels |
441 | 441 | if (*e == '+') { |
442 | 442 | *p = ' '; |
443 | 443 | } else if (*e == '%') { |
444 | if (dStrncasecmp(e, "%0D%0A", 6) == 0) { | |
444 | if (dStrnAsciiCasecmp(e, "%0D%0A", 6) == 0) { | |
445 | 445 | *p = '\n'; |
446 | 446 | e += 5; |
447 | 447 | } else { |
1625 | 1625 | dFree(cmd); |
1626 | 1626 | url = a_Dpip_get_attr_l(Buf, BufSize, "url"); |
1627 | 1627 | |
1628 | if (strcmp(url, "dpi:/bm/modify") == 0) { | |
1629 | st = Bmsrv_send_modify_answer(sh, url); | |
1630 | dFree(url); | |
1631 | return st; | |
1632 | ||
1633 | } else if (strncmp(url, "dpi:/bm/modify?", 15) == 0) { | |
1634 | /* process request */ | |
1635 | st = Bmsrv_process_modify_request(sh, url); | |
1636 | dFree(url); | |
1637 | return st; | |
1628 | if (dStrnAsciiCasecmp(url, "dpi:", 4) == 0) { | |
1629 | if (strcmp(url+4, "/bm/modify") == 0) { | |
1630 | st = Bmsrv_send_modify_answer(sh, url); | |
1631 | dFree(url); | |
1632 | return st; | |
1633 | } else if (strncmp(url+4, "/bm/modify?", 11) == 0) { | |
1634 | /* process request */ | |
1635 | st = Bmsrv_process_modify_request(sh, url); | |
1636 | dFree(url); | |
1637 | return st; | |
1638 | } | |
1638 | 1639 | } |
1639 | 1640 | |
1640 | 1641 |
157 | 157 | { |
158 | 158 | const DomainNode *n1 = v1, *n2 = v2; |
159 | 159 | |
160 | return dStrcasecmp(n1->domain, n2->domain); | |
160 | return dStrAsciiCasecmp(n1->domain, n2->domain); | |
161 | 161 | } |
162 | 162 | |
163 | 163 | /* |
168 | 168 | const DomainNode *node = v1; |
169 | 169 | const char *domain = v2; |
170 | 170 | |
171 | return dStrcasecmp(node->domain, domain); | |
171 | return dStrAsciiCasecmp(node->domain, domain); | |
172 | 172 | } |
173 | 173 | |
174 | 174 | /* |
467 | 467 | int i; |
468 | 468 | |
469 | 469 | for (i = 0; i < 12; i++) { |
470 | if (!dStrncasecmp(months[i], month_name, 3)) | |
470 | if (!dStrnAsciiCasecmp(months[i], month_name, 3)) | |
471 | 471 | return i; |
472 | 472 | } |
473 | 473 | return -1; |
820 | 820 | cookie->expires_at = mktime(tm); |
821 | 821 | if (cookie->expires_at == (time_t) -1) |
822 | 822 | cookie->expires_at = cookies_future_time; |
823 | } else if (dStrcasecmp(attr, "Path") == 0) { | |
823 | } else if (dStrAsciiCasecmp(attr, "Path") == 0) { | |
824 | 824 | value = Cookies_parse_value(&str); |
825 | 825 | dFree(cookie->path); |
826 | 826 | cookie->path = value; |
827 | } else if (dStrcasecmp(attr, "Domain") == 0) { | |
827 | } else if (dStrAsciiCasecmp(attr, "Domain") == 0) { | |
828 | 828 | value = Cookies_parse_value(&str); |
829 | 829 | dFree(cookie->domain); |
830 | 830 | cookie->domain = value; |
831 | } else if (dStrcasecmp(attr, "Max-Age") == 0) { | |
831 | } else if (dStrAsciiCasecmp(attr, "Max-Age") == 0) { | |
832 | 832 | value = Cookies_parse_value(&str); |
833 | 833 | if (isdigit(*value) || *value == '-') { |
834 | 834 | time_t now = time(NULL); |
844 | 844 | expires = max_age = TRUE; |
845 | 845 | } |
846 | 846 | dFree(value); |
847 | } else if (dStrcasecmp(attr, "Expires") == 0) { | |
847 | } else if (dStrAsciiCasecmp(attr, "Expires") == 0) { | |
848 | 848 | if (!max_age) { |
849 | 849 | value = Cookies_parse_value(&str); |
850 | 850 | Cookies_unquote_string(value); |
869 | 869 | } else { |
870 | 870 | Cookies_eat_value(&str); |
871 | 871 | } |
872 | } else if (dStrcasecmp(attr, "Secure") == 0) { | |
872 | } else if (dStrAsciiCasecmp(attr, "Secure") == 0) { | |
873 | 873 | cookie->secure = TRUE; |
874 | 874 | Cookies_eat_value(&str); |
875 | } else if (dStrcasecmp(attr, "HttpOnly") == 0) { | |
875 | } else if (dStrAsciiCasecmp(attr, "HttpOnly") == 0) { | |
876 | 876 | Cookies_eat_value(&str); |
877 | 877 | } else { |
878 | 878 | MSG("Cookie contains unknown attribute: '%s'\n", attr); |
919 | 919 | _MSG("an IPv4 address\n"); |
920 | 920 | return TRUE; |
921 | 921 | } |
922 | if (*domain == '[' && | |
923 | (len == strspn(domain, "0123456789abcdefABCDEF:.[]"))) { | |
922 | if (strchr(domain, ':') && | |
923 | (len == strspn(domain, "0123456789abcdefABCDEF:."))) { | |
924 | 924 | /* The precise format is shown in section 3.2.2 of rfc 3986 */ |
925 | _MSG("an IPv6 address\n"); | |
925 | MSG("an IPv6 address\n"); | |
926 | 926 | return TRUE; |
927 | 927 | } |
928 | 928 | return FALSE; |
991 | 991 | * don't, so: No. |
992 | 992 | */ |
993 | 993 | |
994 | if (!dStrcasecmp(A, B)) | |
994 | if (!dStrAsciiCasecmp(A, B)) | |
995 | 995 | return TRUE; |
996 | 996 | |
997 | 997 | if (Cookies_domain_is_ip(B)) |
1001 | 1001 | |
1002 | 1002 | if (diff > 0) { |
1003 | 1003 | /* B is the tail of A, and the match is preceded by a '.' */ |
1004 | return (dStrcasecmp(A + diff, B) == 0 && A[diff - 1] == '.'); | |
1004 | return (dStrAsciiCasecmp(A + diff, B) == 0 && A[diff - 1] == '.'); | |
1005 | 1005 | } else { |
1006 | 1006 | return FALSE; |
1007 | 1007 | } |
1049 | 1049 | |
1050 | 1050 | for (i = 0; i < tld_num; i++) { |
1051 | 1051 | if (strlen(tlds[i]) == (uint_t) tld_len && |
1052 | !dStrncasecmp(tlds[i], host + start, tld_len)) { | |
1052 | !dStrnAsciiCasecmp(tlds[i], host + start, tld_len)) { | |
1053 | 1053 | _MSG("TLD code matched %s\n", tlds[i]); |
1054 | 1054 | ret++; |
1055 | 1055 | break; |
1220 | 1220 | matching_cookies = dList_new(8); |
1221 | 1221 | |
1222 | 1222 | /* Check if the protocol is secure or not */ |
1223 | is_ssl = (!dStrcasecmp(url_scheme, "https")); | |
1223 | is_ssl = (!dStrAsciiCasecmp(url_scheme, "https")); | |
1224 | 1224 | |
1225 | 1225 | is_ip_addr = Cookies_domain_is_ip(url_host); |
1226 | 1226 | |
1349 | 1349 | rule[j++] = line[i++]; |
1350 | 1350 | rule[j] = '\0'; |
1351 | 1351 | |
1352 | if (dStrcasecmp(rule, "ACCEPT") == 0) | |
1352 | if (dStrAsciiCasecmp(rule, "ACCEPT") == 0) | |
1353 | 1353 | cc.action = COOKIE_ACCEPT; |
1354 | else if (dStrcasecmp(rule, "ACCEPT_SESSION") == 0) | |
1354 | else if (dStrAsciiCasecmp(rule, "ACCEPT_SESSION") == 0) | |
1355 | 1355 | cc.action = COOKIE_ACCEPT_SESSION; |
1356 | else if (dStrcasecmp(rule, "DENY") == 0) | |
1356 | else if (dStrAsciiCasecmp(rule, "DENY") == 0) | |
1357 | 1357 | cc.action = COOKIE_DENY; |
1358 | 1358 | else { |
1359 | 1359 | MSG("Cookies: rule '%s' for domain '%s' is not recognised.\n", |
1362 | 1362 | } |
1363 | 1363 | |
1364 | 1364 | cc.domain = dStrdup(domain); |
1365 | if (dStrcasecmp(cc.domain, "DEFAULT") == 0) { | |
1365 | if (dStrAsciiCasecmp(cc.domain, "DEFAULT") == 0) { | |
1366 | 1366 | /* Set the default action */ |
1367 | 1367 | default_action = cc.action; |
1368 | 1368 | dFree(cc.domain); |
1403 | 1403 | if (ccontrol[i].domain[0] == '.') { |
1404 | 1404 | diff = strlen(domain) - strlen(ccontrol[i].domain); |
1405 | 1405 | if (diff >= 0) { |
1406 | if (dStrcasecmp(domain + diff, ccontrol[i].domain) != 0) | |
1406 | if (dStrAsciiCasecmp(domain + diff, ccontrol[i].domain) != 0) | |
1407 | 1407 | continue; |
1408 | 1408 | } else { |
1409 | 1409 | continue; |
1410 | 1410 | } |
1411 | 1411 | } else { |
1412 | if (dStrcasecmp(domain, ccontrol[i].domain) != 0) | |
1412 | if (dStrAsciiCasecmp(domain, ccontrol[i].domain) != 0) | |
1413 | 1413 | continue; |
1414 | 1414 | } |
1415 | 1415 |
43 | 43 | MSG("len=%d{%s}\n", strlen((char*)str), str); |
44 | 44 | |
45 | 45 | for (p = s; (*p = *s); ++s) { |
46 | if (isalnum(*p) || strchr("+/=", *p)) | |
46 | if (isascii(*p) && (isalnum(*p) || strchr("+/=", *p))) | |
47 | 47 | ++p; |
48 | 48 | } |
49 | 49 | |
225 | 225 | char *mime_type = NULL, *p; |
226 | 226 | size_t len = 0; |
227 | 227 | |
228 | if (dStrncasecmp(url, "data:", 5) == 0) { | |
228 | if (dStrnAsciiCasecmp(url, "data:", 5) == 0) { | |
229 | 229 | if ((p = strchr(url, ',')) && p - url < 256) { |
230 | 230 | url += 5; |
231 | 231 | len = p - url; |
232 | 232 | strncpy(buf, url, len); |
233 | 233 | buf[len] = 0; |
234 | 234 | /* strip ";base64" */ |
235 | if (len >= 7 && dStrcasecmp(buf + len - 7, ";base64") == 0) { | |
235 | if (len >= 7 && dStrAsciiCasecmp(buf + len - 7, ";base64") == 0) { | |
236 | 236 | len -= 7; |
237 | 237 | buf[len] = 0; |
238 | 238 | } |
241 | 241 | /* that's it, now handle omitted types */ |
242 | 242 | if (len == 0) { |
243 | 243 | mime_type = dStrdup("text/plain;charset=US-ASCII"); |
244 | } else if (!dStrncasecmp(buf, "charset", 7)) { | |
244 | } else if (!dStrnAsciiCasecmp(buf, "charset", 7)) { | |
245 | 245 | mime_type = dStrconcat("text/plain", buf, NULL); |
246 | 246 | } else { |
247 | 247 | mime_type = dStrdup(buf); |
261 | 261 | unsigned char *data = NULL; |
262 | 262 | |
263 | 263 | if ((p = strchr(url, ',')) && p - url >= 12 && /* "data:;base64" */ |
264 | dStrncasecmp(p - 7, ";base64", 7) == 0) { | |
264 | dStrnAsciiCasecmp(p - 7, ";base64", 7) == 0) { | |
265 | 265 | is_base64 = 1; |
266 | 266 | } |
267 | 267 |
326 | 326 | /* escape "'" character for the shell. Is it necessary? */ |
327 | 327 | esc_url = Escape_uri_str(url, "'"); |
328 | 328 | /* avoid malicious SMTP relaying with FTP urls */ |
329 | if (dStrncasecmp(esc_url, "ftp:/", 5) == 0) | |
329 | if (dStrnAsciiCasecmp(esc_url, "ftp:/", 5) == 0) | |
330 | 330 | Filter_smtp_hack(esc_url); |
331 | 331 | dl_argv = new char*[8]; |
332 | 332 | int i = 0; |
353 | 353 | gw = 400, gh = 70; |
354 | 354 | group = new Fl_Group(0,0,gw,gh); |
355 | 355 | group->begin(); |
356 | prTitle = new Fl_Box(24, 7, 290, 23); | |
357 | prTitle->box(FL_RSHADOW_BOX); | |
358 | prTitle->color(FL_WHITE); | |
359 | prTitle->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); | |
360 | prTitle->copy_label(shortname); | |
361 | // Attach this 'log_text' to the tooltip | |
362 | log_text_add("Target File: ", 13); | |
363 | log_text_add(fullname, strlen(fullname)); | |
364 | log_text_add("\n\n", 2); | |
365 | ||
366 | prBar = new ProgressBar(24, 40, 92, 20); | |
367 | prBar->box(FL_THIN_UP_BOX); | |
368 | prBar->tooltip("Progress Status"); | |
369 | ||
370 | int ix = 122, iy = 37, iw = 50, ih = 14; | |
371 | Fl_Widget *o = new Fl_Box(ix,iy,iw,ih, "Got"); | |
372 | o->box(FL_RFLAT_BOX); | |
373 | o->color(FL_DARK2); | |
374 | o->labelsize(12); | |
375 | o->tooltip("Downloaded Size"); | |
376 | prGot = new Fl_Box(ix,iy+14,iw,ih, "0KB"); | |
377 | prGot->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
378 | prGot->labelcolor(FL_BLUE); | |
379 | prGot->labelsize(12); | |
380 | prGot->box(FL_NO_BOX); | |
381 | ||
382 | ix += iw; | |
383 | o = new Fl_Box(ix,iy,iw,ih, "Size"); | |
384 | o->box(FL_RFLAT_BOX); | |
385 | o->color(FL_DARK2); | |
386 | o->labelsize(12); | |
387 | o->tooltip("Total Size"); | |
388 | prSize = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
389 | prSize->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
390 | prSize->labelsize(12); | |
391 | prSize->box(FL_NO_BOX); | |
392 | ||
393 | ix += iw; | |
394 | o = new Fl_Box(ix,iy,iw,ih, "Rate"); | |
395 | o->box(FL_RFLAT_BOX); | |
396 | o->color(FL_DARK2); | |
397 | o->labelsize(12); | |
398 | o->tooltip("Current transfer Rate (KBytes/sec)"); | |
399 | prRate = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
400 | prRate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
401 | prRate->labelsize(12); | |
402 | prRate->box(FL_NO_BOX); | |
403 | ||
404 | ix += iw; | |
405 | o = new Fl_Box(ix,iy,iw,ih, "~Rate"); | |
406 | o->box(FL_RFLAT_BOX); | |
407 | o->color(FL_DARK2); | |
408 | o->labelsize(12); | |
409 | o->tooltip("Average transfer Rate (KBytes/sec)"); | |
410 | pr_Rate = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
411 | pr_Rate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
412 | pr_Rate->labelsize(12); | |
413 | pr_Rate->box(FL_NO_BOX); | |
414 | ||
415 | ix += iw; | |
416 | prETAt = o = new Fl_Box(ix,iy,iw,ih, "ETA"); | |
417 | o->box(FL_RFLAT_BOX); | |
418 | o->color(FL_DARK2); | |
419 | o->labelsize(12); | |
420 | o->tooltip("Estimated Time of Arrival"); | |
421 | prETA = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
422 | prETA->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
423 | prETA->labelsize(12); | |
424 | prETA->box(FL_NO_BOX); | |
425 | ||
426 | prButton = new Fl_Button(326, 9, 44, 19, "Stop"); | |
427 | prButton->tooltip("Stop this transfer"); | |
428 | prButton->box(FL_UP_BOX); | |
429 | prButton->clear_visible_focus(); | |
430 | prButton->callback(prButton_scb, this); | |
356 | prTitle = new Fl_Box(24, 7, 290, 23); | |
357 | prTitle->box(FL_RSHADOW_BOX); | |
358 | prTitle->color(FL_WHITE); | |
359 | prTitle->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); | |
360 | prTitle->copy_label(shortname); | |
361 | // Attach this 'log_text' to the tooltip | |
362 | log_text_add("Target File: ", 13); | |
363 | log_text_add(fullname, strlen(fullname)); | |
364 | log_text_add("\n\n", 2); | |
365 | ||
366 | prBar = new ProgressBar(24, 40, 92, 20); | |
367 | prBar->box(FL_THIN_UP_BOX); | |
368 | prBar->tooltip("Progress Status"); | |
369 | ||
370 | int ix = 122, iy = 37, iw = 50, ih = 14; | |
371 | Fl_Widget *o = new Fl_Box(ix,iy,iw,ih, "Got"); | |
372 | o->box(FL_RFLAT_BOX); | |
373 | o->color(FL_DARK2); | |
374 | o->labelsize(12); | |
375 | o->tooltip("Downloaded Size"); | |
376 | prGot = new Fl_Box(ix,iy+14,iw,ih, "0KB"); | |
377 | prGot->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
378 | prGot->labelcolor(FL_BLUE); | |
379 | prGot->labelsize(12); | |
380 | prGot->box(FL_NO_BOX); | |
381 | ||
382 | ix += iw; | |
383 | o = new Fl_Box(ix,iy,iw,ih, "Size"); | |
384 | o->box(FL_RFLAT_BOX); | |
385 | o->color(FL_DARK2); | |
386 | o->labelsize(12); | |
387 | o->tooltip("Total Size"); | |
388 | prSize = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
389 | prSize->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
390 | prSize->labelsize(12); | |
391 | prSize->box(FL_NO_BOX); | |
392 | ||
393 | ix += iw; | |
394 | o = new Fl_Box(ix,iy,iw,ih, "Rate"); | |
395 | o->box(FL_RFLAT_BOX); | |
396 | o->color(FL_DARK2); | |
397 | o->labelsize(12); | |
398 | o->tooltip("Current transfer Rate (KBytes/sec)"); | |
399 | prRate = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
400 | prRate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
401 | prRate->labelsize(12); | |
402 | prRate->box(FL_NO_BOX); | |
403 | ||
404 | ix += iw; | |
405 | o = new Fl_Box(ix,iy,iw,ih, "~Rate"); | |
406 | o->box(FL_RFLAT_BOX); | |
407 | o->color(FL_DARK2); | |
408 | o->labelsize(12); | |
409 | o->tooltip("Average transfer Rate (KBytes/sec)"); | |
410 | pr_Rate = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
411 | pr_Rate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
412 | pr_Rate->labelsize(12); | |
413 | pr_Rate->box(FL_NO_BOX); | |
414 | ||
415 | ix += iw; | |
416 | prETAt = o = new Fl_Box(ix,iy,iw,ih, "ETA"); | |
417 | o->box(FL_RFLAT_BOX); | |
418 | o->color(FL_DARK2); | |
419 | o->labelsize(12); | |
420 | o->tooltip("Estimated Time of Arrival"); | |
421 | prETA = new Fl_Box(ix,iy+14,iw,ih, "??"); | |
422 | prETA->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); | |
423 | prETA->labelsize(12); | |
424 | prETA->box(FL_NO_BOX); | |
425 | ||
426 | prButton = new Fl_Button(326, 9, 44, 19, "Stop"); | |
427 | prButton->tooltip("Stop this transfer"); | |
428 | prButton->box(FL_UP_BOX); | |
429 | prButton->clear_visible_focus(); | |
430 | prButton->callback(prButton_scb, this); | |
431 | 431 | |
432 | 432 | group->box(FL_ROUNDED_BOX); |
433 | 433 | group->end(); |
1086 | 1086 | } |
1087 | 1087 | |
1088 | 1088 | /* |
1089 | * A Scroll class that resizes its resizable widget to its width. | |
1090 | * see http://seriss.com/people/erco/fltk/#ScrollableWidgetBrowser | |
1091 | */ | |
1092 | class DlScroll : public Fl_Scroll | |
1093 | { | |
1094 | public: | |
1095 | void resize(int x_, int y_, int w_, int h_) | |
1096 | { | |
1097 | Fl_Widget *resizable_ = resizable(); | |
1098 | if (resizable_) | |
1099 | resizable_->resize(resizable_->x(), | |
1100 | resizable_->y(), | |
1101 | w() - scrollbar_size(), | |
1102 | resizable_->h()); | |
1103 | Fl_Scroll::resize(x_, y_, w_, h_); | |
1104 | } | |
1105 | DlScroll(int x, int y, int w, int h, const char *l = 0) | |
1106 | : Fl_Scroll(x, y, w, h, l) | |
1107 | { | |
1108 | } | |
1109 | }; | |
1110 | ||
1111 | /* | |
1089 | 1112 | * Create the main window and an empty list of requests. |
1090 | 1113 | */ |
1091 | 1114 | DLWin::DLWin(int ww, int wh) { |
1096 | 1119 | // Create the empty main window |
1097 | 1120 | mWin = new Fl_Window(ww, wh, "Downloads:"); |
1098 | 1121 | mWin->begin(); |
1099 | mScroll = new Fl_Scroll(0,0,ww,wh); | |
1100 | mScroll->begin(); | |
1101 | mPG = new Fl_Pack(0,0,ww-18,wh); | |
1102 | mPG->end(); | |
1103 | mScroll->end(); | |
1104 | mScroll->type(Fl_Scroll::VERTICAL); | |
1122 | mScroll = new DlScroll(0,0,ww,wh); | |
1123 | mScroll->begin(); | |
1124 | mPG = new Fl_Pack(0,0,ww-18,wh); | |
1125 | mPG->end(); | |
1126 | mScroll->end(); | |
1127 | mScroll->type(Fl_Scroll::VERTICAL); | |
1128 | mScroll->resizable(mPG); | |
1105 | 1129 | mWin->end(); |
1106 | 1130 | mWin->resizable(mScroll); |
1107 | 1131 | mWin->callback(dlwin_esc_cb, NULL); |
67 | 67 | if (strchr(s, '%')) { |
68 | 68 | for (p = buf; (*p = *s); ++s, ++p) { |
69 | 69 | if (*p == '%' && isxdigit(s[1]) && isxdigit(s[2])) { |
70 | *p = (isdigit(s[1]) ? (s[1] - '0') : toupper(s[1]) - 'A' + 10)*16; | |
71 | *p += isdigit(s[2]) ? (s[2] - '0') : toupper(s[2]) - 'A' + 10; | |
70 | *p = (isdigit(s[1]) ? (s[1] - '0') | |
71 | : D_ASCII_TOUPPER(s[1]) - 'A' + 10) * 16; | |
72 | *p += isdigit(s[2]) ? (s[2] - '0') | |
73 | : D_ASCII_TOUPPER(s[2]) - 'A' + 10; | |
72 | 74 | s += 2; |
73 | 75 | } |
74 | 76 | } |
120 | 122 | for (i = 0, j = 0; str[i]; ++i) { |
121 | 123 | if (str[i] == '&') { |
122 | 124 | for (k = 0; k < 5; ++k) { |
123 | if (!dStrncasecmp(str + i, unsafe_rep[k], unsafe_rep_len[k])) { | |
125 | if (!dStrnAsciiCasecmp(str + i, unsafe_rep[k], unsafe_rep_len[k])) { | |
124 | 126 | i += unsafe_rep_len[k] - 1; |
125 | 127 | break; |
126 | 128 | } |
153 | 155 | memmove(url + i, url + i + 1, strlen(url + i)); |
154 | 156 | --i; |
155 | 157 | } else if (c == '%' && url[i+1] == '0' && |
156 | (tolower(url[i+2]) == 'a' || tolower(url[i+2]) == 'd')) { | |
158 | (D_ASCII_TOLOWER(url[i+2]) == 'a' || | |
159 | D_ASCII_TOLOWER(url[i+2]) == 'd')) { | |
157 | 160 | memmove(url + i, url + i + 3, strlen(url + i + 2)); |
158 | 161 | --i; |
159 | 162 | } |
14 | 14 | * With new HTML layout. |
15 | 15 | */ |
16 | 16 | |
17 | #include <ctype.h> /* for tolower */ | |
17 | #include <ctype.h> /* for isspace */ | |
18 | 18 | #include <errno.h> /* for errno */ |
19 | 19 | #include <stdio.h> |
20 | 20 | #include <stdlib.h> |
141 | 141 | |
142 | 142 | /* HTML try */ |
143 | 143 | for (i = 0; i < Size && dIsspace(p[i]); ++i); |
144 | if ((Size - i >= 5 && !dStrncasecmp(p+i, "<html", 5)) || | |
145 | (Size - i >= 5 && !dStrncasecmp(p+i, "<head", 5)) || | |
146 | (Size - i >= 6 && !dStrncasecmp(p+i, "<title", 6)) || | |
147 | (Size - i >= 14 && !dStrncasecmp(p+i, "<!doctype html", 14)) || | |
144 | if ((Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<html", 5)) || | |
145 | (Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<head", 5)) || | |
146 | (Size - i >= 6 && !dStrnAsciiCasecmp(p+i, "<title", 6)) || | |
147 | (Size - i >= 14 && !dStrnAsciiCasecmp(p+i, "<!doctype html", 14)) || | |
148 | 148 | /* this line is workaround for FTP through the Squid proxy */ |
149 | (Size - i >= 17 && !dStrncasecmp(p+i, "<!-- HTML listing", 17))) { | |
149 | (Size - i >= 17 && !dStrnAsciiCasecmp(p+i, "<!-- HTML listing", 17))) { | |
150 | 150 | |
151 | 151 | Type = 1; |
152 | 152 | |
153 | 153 | /* Images */ |
154 | } else if (Size >= 4 && !dStrncasecmp(p, "GIF8", 4)) { | |
154 | } else if (Size >= 4 && !strncmp(p, "GIF8", 4)) { | |
155 | 155 | Type = 3; |
156 | } else if (Size >= 4 && !dStrncasecmp(p, "\x89PNG", 4)) { | |
156 | } else if (Size >= 4 && !strncmp(p, "\x89PNG", 4)) { | |
157 | 157 | Type = 4; |
158 | } else if (Size >= 2 && !dStrncasecmp(p, "\xff\xd8", 2)) { | |
158 | } else if (Size >= 2 && !strncmp(p, "\xff\xd8", 2)) { | |
159 | 159 | /* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking |
160 | 160 | * at the character representation should be machine independent. */ |
161 | 161 | Type = 5; |
501 | 501 | |
502 | 502 | e++; |
503 | 503 | |
504 | if (!dStrcasecmp(e, "gif")) { | |
504 | if (!dStrAsciiCasecmp(e, "gif")) { | |
505 | 505 | return "image/gif"; |
506 | } else if (!dStrcasecmp(e, "jpg") || | |
507 | !dStrcasecmp(e, "jpeg")) { | |
506 | } else if (!dStrAsciiCasecmp(e, "jpg") || | |
507 | !dStrAsciiCasecmp(e, "jpeg")) { | |
508 | 508 | return "image/jpeg"; |
509 | } else if (!dStrcasecmp(e, "png")) { | |
509 | } else if (!dStrAsciiCasecmp(e, "png")) { | |
510 | 510 | return "image/png"; |
511 | } else if (!dStrcasecmp(e, "html") || | |
512 | !dStrcasecmp(e, "htm") || | |
513 | !dStrcasecmp(e, "shtml")) { | |
511 | } else if (!dStrAsciiCasecmp(e, "html") || | |
512 | !dStrAsciiCasecmp(e, "htm") || | |
513 | !dStrAsciiCasecmp(e, "shtml")) { | |
514 | 514 | return "text/html"; |
515 | } else if (!dStrcasecmp(e, "txt")) { | |
515 | } else if (!dStrAsciiCasecmp(e, "txt")) { | |
516 | 516 | return "text/plain"; |
517 | 517 | } else { |
518 | 518 | return NULL; |
711 | 711 | |
712 | 712 | /* Check for gzipped file */ |
713 | 713 | namelen = strlen(client->filename); |
714 | if (namelen > 3 && !dStrcasecmp(client->filename + namelen - 3, ".gz")) { | |
714 | if (namelen > 3 && | |
715 | !dStrAsciiCasecmp(client->filename + namelen - 3, ".gz")) { | |
715 | 716 | gzipped = TRUE; |
716 | 717 | namelen -= 3; |
717 | 718 | } |
798 | 799 | dReturn_val_if (orig == NULL, ret); |
799 | 800 | |
800 | 801 | /* Make sure the string starts with "file:/" */ |
801 | if (strncmp(str, "file:/", 5) != 0) | |
802 | if (dStrnAsciiCasecmp(str, "file:/", 5) != 0) | |
802 | 803 | return ret; |
803 | 804 | str += 5; |
804 | 805 | |
805 | 806 | /* Skip "localhost" */ |
806 | if (dStrncasecmp(str, "//localhost/", 12) == 0) | |
807 | if (dStrnAsciiCasecmp(str, "//localhost/", 12) == 0) | |
807 | 808 | str += 11; |
808 | 809 | |
809 | 810 | /* Skip packed slashes, and leave just one */ |
940 | 941 | DPIBYE = 1; |
941 | 942 | MSG("(pid %d): Got DpiBye.\n", (int)getpid()); |
942 | 943 | client->flags |= FILE_DONE; |
943 | } else if (url && strcmp(url, "dpi:/file/toggle") == 0) { | |
944 | } else if (url && dStrnAsciiCasecmp(url, "dpi:", 4) == 0 && | |
945 | strcmp(url+4, "/file/toggle") == 0) { | |
944 | 946 | File_toggle_html_style(client); |
945 | 947 | } else if (path) { |
946 | 948 | File_get(client, path, url); |
97 | 97 | |
98 | 98 | /* HTML try */ |
99 | 99 | for (i = 0; i < Size && dIsspace(p[i]); ++i); |
100 | if ((Size - i >= 5 && !dStrncasecmp(p+i, "<html", 5)) || | |
101 | (Size - i >= 5 && !dStrncasecmp(p+i, "<head", 5)) || | |
102 | (Size - i >= 6 && !dStrncasecmp(p+i, "<title", 6)) || | |
103 | (Size - i >= 14 && !dStrncasecmp(p+i, "<!doctype html", 14)) || | |
100 | if ((Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<html", 5)) || | |
101 | (Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<head", 5)) || | |
102 | (Size - i >= 6 && !dStrnAsciiCasecmp(p+i, "<title", 6)) || | |
103 | (Size - i >= 14 && !dStrnAsciiCasecmp(p+i, "<!doctype html", 14)) || | |
104 | 104 | /* this line is workaround for FTP through the Squid proxy */ |
105 | (Size - i >= 17 && !dStrncasecmp(p+i, "<!-- HTML listing", 17))) { | |
105 | (Size - i >= 17 && !dStrnAsciiCasecmp(p+i, "<!-- HTML listing", 17))) { | |
106 | 106 | |
107 | 107 | Type = 1; |
108 | 108 | st = 0; |
109 | 109 | /* Images */ |
110 | } else if (Size >= 4 && !dStrncasecmp(p, "GIF8", 4)) { | |
110 | } else if (Size >= 4 && !strncmp(p, "GIF8", 4)) { | |
111 | 111 | Type = 3; |
112 | 112 | st = 0; |
113 | } else if (Size >= 4 && !dStrncasecmp(p, "\x89PNG", 4)) { | |
113 | } else if (Size >= 4 && !strncmp(p, "\x89PNG", 4)) { | |
114 | 114 | Type = 4; |
115 | 115 | st = 0; |
116 | } else if (Size >= 2 && !dStrncasecmp(p, "\xff\xd8", 2)) { | |
116 | } else if (Size >= 2 && !strncmp(p, "\xff\xd8", 2)) { | |
117 | 117 | /* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking |
118 | 118 | * at the character representation should be machine independent. */ |
119 | 119 | Type = 5; |
359 | 359 | char * url_look_up = NULL; |
360 | 360 | |
361 | 361 | /*Determine how much of url we chop off as unneeded*/ |
362 | if (dStrncasecmp(url, "https://", 8) == 0){ | |
362 | if (dStrnAsciiCasecmp(url, "https://", 8) == 0){ | |
363 | 363 | url_offset = 8; |
364 | } else if (dStrncasecmp(url, "http://", 7) == 0) { | |
364 | } else if (dStrnAsciiCasecmp(url, "http://", 7) == 0) { | |
365 | 365 | url_offset = 7; |
366 | 366 | portnum = 80; |
367 | 367 | } |
100 | 100 | int bytes_read = 0, old_line = 0, line = 1; |
101 | 101 | char *p, *q, *src_str, line_str[128]; |
102 | 102 | |
103 | if (strncmp(url, "dpi:/vsource/:", 14) == 0) | |
103 | if (dStrnAsciiCasecmp(url, "dpi:", 4) == 0 && | |
104 | strncmp(url+4, "/vsource/:", 10) == 0) | |
104 | 105 | url += 14; |
105 | 106 | |
106 | 107 | /* Send HTTP header for plain text MIME type */ |
844 | 844 | if (A->name[A_len - 1] == '*') |
845 | 845 | len = A_len - 1; |
846 | 846 | |
847 | return(dStrncasecmp(A->name, B, len)); | |
847 | return(dStrnAsciiCasecmp(A->name, B, len)); | |
848 | 848 | } |
849 | 849 | |
850 | 850 | /*! |
0 | // fltkcomplexbutton.cc contains code from FLTK 1.3's src/Fl_Button.cxx | |
1 | // that is Copyright 1998-2010 by Bill Spitzak and others. | |
0 | // fltkcomplexbutton.cc is derived from src/Fl_Button.cxx from FLTK's 1.3 | |
1 | // branch at http://fltk.org in early 2011. | |
2 | // src/Fl_Button.cxx is Copyright 1998-2010 by Bill Spitzak and others. | |
2 | 3 | |
3 | 4 | /* |
4 | 5 | * This program is free software; you can redistribute it and/or modify |
107 | 108 | return 1; |
108 | 109 | } else return 0; |
109 | 110 | case FL_KEYBOARD : |
110 | if (Fl::focus() == this && Fl::event_key() == ' ' && | |
111 | if (Fl::focus() == this && | |
112 | (Fl::event_key() == ' ' || Fl::event_key() == FL_Enter) && | |
111 | 113 | !(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) { |
112 | 114 | set_changed(); |
113 | 115 | Fl_Widget_Tracker wp(this); |
0 | 0 | |
1 | // fltkcomplexbutton.hh contains code from FLTK 1.3's FL/Fl_Button.H | |
2 | // that is Copyright 1998-2010 by Bill Spitzak and others. | |
1 | // fltkcomplexbutton.hh is derived from FL/Fl_Button.H from FLTK's 1.3 branch | |
2 | // at http://fltk.org in early 2011. | |
3 | // FL/Fl_Button.H is Copyright 1998-2010 by Bill Spitzak and others. | |
3 | 4 | |
4 | 5 | /* |
5 | 6 | * This program is free software; you can redistribute it and/or modify |
140 | 140 | static void strstrip(char *big, const char *little) |
141 | 141 | { |
142 | 142 | if (strlen(big) >= strlen(little) && |
143 | strcasecmp(big + strlen(big) - strlen(little), little) == 0) | |
143 | misc::AsciiStrcasecmp(big + strlen(big) - strlen(little), little) == 0) | |
144 | 144 | *(big + strlen(big) - strlen(little)) = '\0'; |
145 | 145 | } |
146 | 146 | |
524 | 524 | if ((cu = fl_toupper(c)) == c) { |
525 | 525 | /* already uppercase, just draw the character */ |
526 | 526 | fl_font(ff->font, ff->size); |
527 | width += font->letterSpacing; | |
528 | width += (int)fl_width(text + curr, next - curr); | |
527 | if (fl_nonspacing(cu) == 0) { | |
528 | width += font->letterSpacing; | |
529 | width += (int)fl_width(text + curr, next - curr); | |
530 | } | |
529 | 531 | } else { |
530 | 532 | /* make utf8 string for converted char */ |
531 | 533 | nb = fl_utf8encode(cu, chbuf); |
532 | 534 | fl_font(ff->font, sc_fontsize); |
533 | width += font->letterSpacing; | |
534 | width += (int)fl_width(chbuf, nb); | |
535 | if (fl_nonspacing(cu) == 0) { | |
536 | width += font->letterSpacing; | |
537 | width += (int)fl_width(chbuf, nb); | |
538 | } | |
535 | 539 | } |
536 | 540 | } |
537 | 541 | } else { |
543 | 547 | |
544 | 548 | while (next < len) { |
545 | 549 | next = nextGlyph(text, curr); |
546 | width += font->letterSpacing; | |
550 | c = fl_utf8decode(text + curr, text + next, &nb); | |
551 | if (fl_nonspacing(c) == 0) | |
552 | width += font->letterSpacing; | |
547 | 553 | curr = next; |
548 | 554 | } |
549 | 555 | } |
550 | 556 | } |
551 | 557 | |
552 | 558 | return width; |
559 | } | |
560 | ||
561 | char *FltkPlatform::textToUpper (const char *text, int len) | |
562 | { | |
563 | char *newstr = NULL; | |
564 | ||
565 | if (len > 0) { | |
566 | int newlen; | |
567 | ||
568 | newstr = (char*) malloc(3 * len + 1); | |
569 | newlen = fl_utf_toupper((const unsigned char*)text, len, newstr); | |
570 | assert(newlen <= 3 * len); | |
571 | newstr[newlen] = '\0'; | |
572 | } | |
573 | return newstr; | |
574 | } | |
575 | ||
576 | char *FltkPlatform::textToLower (const char *text, int len) | |
577 | { | |
578 | char *newstr = NULL; | |
579 | ||
580 | if (len > 0) { | |
581 | int newlen; | |
582 | ||
583 | newstr = (char*) malloc(3 * len + 1); | |
584 | newlen = fl_utf_tolower((const unsigned char*)text, len, newstr); | |
585 | assert(newlen <= 3 * len); | |
586 | newstr[newlen] = '\0'; | |
587 | } | |
588 | return newstr; | |
553 | 589 | } |
554 | 590 | |
555 | 591 | int FltkPlatform::nextGlyph (const char *text, int idx) |
152 | 152 | void detachView (core::View *view); |
153 | 153 | |
154 | 154 | int textWidth (core::style::Font *font, const char *text, int len); |
155 | char *textToUpper (const char *text, int len); | |
156 | char *textToLower (const char *text, int len); | |
155 | 157 | int nextGlyph (const char *text, int idx); |
156 | 158 | int prevGlyph (const char *text, int idx); |
157 | 159 | float dpiX (); |
265 | 265 | |
266 | 266 | // ---------------------------------------------------------------------- |
267 | 267 | |
268 | class EnterButton : public Fl_Button { | |
269 | public: | |
270 | EnterButton (int x,int y,int w,int h, const char* label = 0) : | |
271 | Fl_Button (x,y,w,h,label) {}; | |
272 | int handle(int e); | |
273 | }; | |
274 | ||
275 | int EnterButton::handle(int e) | |
276 | { | |
277 | if (e == FL_KEYBOARD && Fl::focus() == this && Fl::event_key() == FL_Enter){ | |
278 | set_changed(); | |
279 | simulate_key_action(); | |
280 | do_callback(); | |
281 | return 1; | |
282 | } | |
283 | return Fl_Button::handle(e); | |
284 | } | |
285 | ||
268 | 286 | FltkLabelButtonResource::FltkLabelButtonResource (FltkPlatform *platform, |
269 | 287 | const char *label): |
270 | 288 | FltkSpecificResource <dw::core::ui::LabelButtonResource> (platform) |
282 | 300 | *allocation) |
283 | 301 | { |
284 | 302 | Fl_Button *button = |
285 | new Fl_Button (allocation->x, allocation->y, allocation->width, | |
286 | allocation->ascent + allocation->descent, label); | |
303 | new EnterButton (allocation->x, allocation->y, allocation->width, | |
304 | allocation->ascent + allocation->descent, label); | |
287 | 305 | button->callback (widgetCallback, this); |
288 | 306 | button->when (FL_WHEN_RELEASE); |
289 | 307 | return button; |
547 | 547 | viewY = translateCanvasYToViewY (Y); |
548 | 548 | int curr = 0, next = 0, nb; |
549 | 549 | char chbuf[4]; |
550 | int c, cu; | |
550 | int c, cu, width; | |
551 | 551 | |
552 | 552 | if (font->fontVariant == core::style::FONT_VARIANT_SMALL_CAPS) { |
553 | 553 | int sc_fontsize = lout::misc::roundInt(ff->size * 0.78); |
557 | 557 | if ((cu = fl_toupper(c)) == c) { |
558 | 558 | /* already uppercase, just draw the character */ |
559 | 559 | fl_font(ff->font, ff->size); |
560 | width = (int)fl_width(text + curr, next - curr); | |
561 | if (curr && width) | |
562 | viewX += font->letterSpacing; | |
560 | 563 | fl_draw(text + curr, next - curr, viewX, viewY); |
561 | viewX += font->letterSpacing; | |
562 | viewX += (int)fl_width(text + curr, next - curr); | |
564 | viewX += width; | |
563 | 565 | } else { |
564 | 566 | /* make utf8 string for converted char */ |
565 | 567 | nb = fl_utf8encode(cu, chbuf); |
566 | 568 | fl_font(ff->font, sc_fontsize); |
569 | width = (int)fl_width(chbuf, nb); | |
570 | if (curr && width) | |
571 | viewX += font->letterSpacing; | |
567 | 572 | fl_draw(chbuf, nb, viewX, viewY); |
568 | viewX += font->letterSpacing; | |
569 | viewX += (int)fl_width(chbuf, nb); | |
573 | viewX += width; | |
570 | 574 | } |
571 | 575 | } |
572 | 576 | } else { |
573 | 577 | while (next < len) { |
574 | 578 | next = theLayout->nextGlyph(text, curr); |
579 | width = (int)fl_width(text + curr, next - curr); | |
580 | if (curr && width) | |
581 | viewX += font->letterSpacing; | |
575 | 582 | fl_draw(text + curr, next - curr, viewX, viewY); |
576 | viewX += font->letterSpacing + | |
577 | (int)fl_width(text + curr,next - curr); | |
583 | viewX += width; | |
578 | 584 | curr = next; |
579 | 585 | } |
580 | 586 | } |
296 | 296 | return platform->textWidth (font, text, len); |
297 | 297 | } |
298 | 298 | |
299 | inline char *textToUpper (const char *text, int len) | |
300 | { | |
301 | return platform->textToUpper (text, len); | |
302 | } | |
303 | ||
304 | inline char *textToLower (const char *text, int len) | |
305 | { | |
306 | return platform->textToLower (text, len); | |
307 | } | |
308 | ||
299 | 309 | inline int nextGlyph (const char *text, int idx) |
300 | 310 | { |
301 | 311 | return platform->nextGlyph (text, idx); |
55 | 55 | * \brief Return the width of a text, with a given length and font. |
56 | 56 | */ |
57 | 57 | virtual int textWidth (style::Font *font, const char *text, int len) = 0; |
58 | ||
59 | /** | |
60 | * \brief Return the string resulting from transforming text to uppercase. | |
61 | */ | |
62 | virtual char *textToUpper (const char *text, int len) = 0; | |
63 | ||
64 | /** | |
65 | * \brief Return the string resulting from transforming text to lowercase. | |
66 | */ | |
67 | virtual char *textToLower (const char *text, int len) = 0; | |
58 | 68 | |
59 | 69 | /** |
60 | 70 | * \brief Return the index of the next glyph in string text. |
41 | 41 | textDecoration = TEXT_DECORATION_NONE; |
42 | 42 | textAlign = TEXT_ALIGN_LEFT; |
43 | 43 | textAlignChar = '.'; |
44 | textTransform = TEXT_TRANSFORM_NONE; | |
44 | 45 | listStylePosition = LIST_STYLE_POSITION_OUTSIDE; |
45 | 46 | listStyleType = LIST_STYLE_TYPE_DISC; |
46 | 47 | valign = VALIGN_BASELINE; |
116 | 117 | textAlign == otherAttrs->textAlign && |
117 | 118 | valign == otherAttrs->valign && |
118 | 119 | textAlignChar == otherAttrs->textAlignChar && |
120 | textTransform == otherAttrs->textTransform && | |
119 | 121 | hBorderSpacing == otherAttrs->hBorderSpacing && |
120 | 122 | vBorderSpacing == otherAttrs->vBorderSpacing && |
121 | 123 | wordSpacing == otherAttrs->wordSpacing && |
153 | 155 | textAlign + |
154 | 156 | valign + |
155 | 157 | textAlignChar + |
158 | textTransform + | |
156 | 159 | hBorderSpacing + |
157 | 160 | vBorderSpacing + |
158 | 161 | wordSpacing + |
243 | 246 | textAlign = attrs->textAlign; |
244 | 247 | valign = attrs->valign; |
245 | 248 | textAlignChar = attrs->textAlignChar; |
249 | textTransform = attrs->textTransform; | |
246 | 250 | hBorderSpacing = attrs->hBorderSpacing; |
247 | 251 | vBorderSpacing = attrs->vBorderSpacing; |
248 | 252 | wordSpacing = attrs->wordSpacing; |
884 | 888 | *const roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" }, |
885 | 889 | *const roman_I3[] = { "","M","MM","MMM","MMMM" }; |
886 | 890 | |
887 | static void strtolower (char *s) | |
891 | static void strAsciiTolower (char *s) | |
888 | 892 | { |
889 | 893 | for ( ; *s; s++) |
890 | *s = tolower (*s); | |
894 | *s = misc::AsciiTolower (*s); | |
891 | 895 | } |
892 | 896 | |
893 | 897 | /** |
942 | 946 | buf[buflen - 1] = '\0'; |
943 | 947 | |
944 | 948 | if (low) |
945 | strtolower(buf); | |
949 | strAsciiTolower(buf); | |
946 | 950 | |
947 | 951 | } |
948 | 952 |
244 | 244 | VALIGN_SUPER, |
245 | 245 | VALIGN_TEXT_TOP, |
246 | 246 | VALIGN_TEXT_BOTTOM, |
247 | }; | |
248 | ||
249 | enum TextTransform { | |
250 | TEXT_TRANSFORM_NONE, | |
251 | TEXT_TRANSFORM_CAPITALIZE, | |
252 | TEXT_TRANSFORM_UPPERCASE, | |
253 | TEXT_TRANSFORM_LOWERCASE, | |
247 | 254 | }; |
248 | 255 | |
249 | 256 | /** |
440 | 447 | TextAlignType textAlign; |
441 | 448 | VAlignType valign; |
442 | 449 | char textAlignChar; /* In future, strings will be supported. */ |
450 | TextTransform textTransform; | |
443 | 451 | |
444 | 452 | int hBorderSpacing, vBorderSpacing, wordSpacing; |
445 | 453 | Length width, height, lineHeight, textIndent; |
269 | 269 | |
270 | 270 | void Table::addCell (Widget *widget, int colspan, int rowspan) |
271 | 271 | { |
272 | const int maxspan = 100; | |
272 | 273 | Child *child; |
273 | 274 | int colspanEff; |
274 | 275 | |
275 | // We limit the values for colspan and rowspan to 50, to avoid | |
276 | // We limit the values for colspan and rowspan to avoid | |
276 | 277 | // attacks by malicious web pages. |
277 | if (colspan > 50 || colspan < 0) { | |
278 | MSG_WARN("colspan = %d is set to 50.\n", colspan); | |
279 | colspan = 50; | |
280 | } | |
281 | if (rowspan > 50 || rowspan <= 0) { | |
282 | MSG_WARN("rowspan = %d is set to 50.\n", rowspan); | |
283 | rowspan = 50; | |
278 | if (colspan > maxspan || colspan < 0) { | |
279 | MSG_WARN("colspan = %d is set to %d.\n", colspan, maxspan); | |
280 | colspan = maxspan; | |
281 | } | |
282 | if (rowspan > maxspan || rowspan <= 0) { | |
283 | MSG_WARN("rowspan = %d is set to %d.\n", rowspan, maxspan); | |
284 | rowspan = maxspan; | |
284 | 285 | } |
285 | 286 | |
286 | 287 | if (numRows == 0) { |
69 | 69 | words = new misc::SimpleVector <Word> (1); |
70 | 70 | anchors = new misc::SimpleVector <Anchor> (1); |
71 | 71 | |
72 | //DBG_OBJ_SET_NUM(page, "num_lines", num_lines); | |
72 | //DBG_OBJ_SET_NUM(this, "num_lines", num_lines); | |
73 | 73 | |
74 | 74 | lastLineWidth = 0; |
75 | lastLineParMin = 0; | |
76 | 75 | lastLineParMax = 0; |
77 | 76 | wrapRef = -1; |
78 | 77 | |
79 | //DBG_OBJ_SET_NUM(page, "last_line_width", last_line_width); | |
80 | //DBG_OBJ_SET_NUM(page, "last_line_par_min", last_line_par_min); | |
81 | //DBG_OBJ_SET_NUM(page, "last_line_par_max", last_line_par_max); | |
82 | //DBG_OBJ_SET_NUM(page, "wrap_ref", wrap_ref); | |
78 | //DBG_OBJ_SET_NUM(this, "last_line_width", last_line_width); | |
79 | //DBG_OBJ_SET_NUM(this, "last_line_par_min", last_line_par_min); | |
80 | //DBG_OBJ_SET_NUM(this, "last_line_par_max", last_line_par_max); | |
81 | //DBG_OBJ_SET_NUM(this, "wrap_ref", wrap_ref); | |
83 | 82 | |
84 | 83 | hoverLink = -1; |
85 | 84 | |
128 | 127 | parent class destructor. (???) */ |
129 | 128 | words = NULL; |
130 | 129 | |
131 | //DBG_OBJ_SET_NUM(page, "num_lines", page->num_lines); | |
130 | //DBG_OBJ_SET_NUM(this, "num_lines", lines->size ()); | |
132 | 131 | } |
133 | 132 | |
134 | 133 | /** |
201 | 200 | { |
202 | 201 | core::Extremes wordExtremes; |
203 | 202 | Line *line; |
204 | Word *word; | |
203 | Word *word, *prevWord = NULL; | |
205 | 204 | int wordIndex, lineIndex; |
206 | int parMin, parMax; | |
207 | bool nowrap; | |
208 | ||
209 | //DBG_MSG (widget, "extremes", 0, "Dw_page_get_extremes"); | |
205 | int parMax; | |
206 | ||
207 | //DBG_MSG (widget, "extremes", 0, "getExtremesImpl"); | |
210 | 208 | //DBG_MSG_START (widget); |
211 | 209 | |
212 | 210 | if (lines->size () == 0) { |
216 | 214 | } else if (wrapRef == -1) { |
217 | 215 | /* no rewrap necessary -> values in lines are up to date */ |
218 | 216 | line = lines->getRef (lines->size () - 1); |
219 | /* Historical note: The former distinction between lines with and without | |
220 | * words[first_word]->nowrap set is no longer necessary, since | |
221 | * Dw_page_real_word_wrap sets max_word_min to the correct value in any | |
222 | * case. */ | |
223 | extremes->minWidth = line->maxWordMin; | |
217 | extremes->minWidth = line->maxParMin; | |
224 | 218 | extremes->maxWidth = misc::max (line->maxParMax, lastLineParMax); |
225 | 219 | //DBG_MSG (widget, "extremes", 0, "simple case"); |
226 | 220 | } else { |
231 | 225 | if (wrapRef == 0) { |
232 | 226 | extremes->minWidth = 0; |
233 | 227 | extremes->maxWidth = 0; |
234 | parMin = 0; | |
235 | 228 | parMax = 0; |
236 | 229 | } else { |
237 | 230 | line = lines->getRef (wrapRef); |
238 | extremes->minWidth = line->maxWordMin; | |
231 | extremes->minWidth = line->maxParMin; | |
239 | 232 | extremes->maxWidth = line->maxParMax; |
240 | parMin = line->parMin; | |
241 | 233 | parMax = line->parMax; |
242 | 234 | |
243 | 235 | //DBG_MSGF (widget, "extremes", 0, "parMin = %d", parMin); |
249 | 241 | for (lineIndex = wrapRef; lineIndex < lines->size (); lineIndex++) { |
250 | 242 | //DBG_MSGF (widget, "extremes", 0, "line %d", lineIndex); |
251 | 243 | //DBG_MSG_START (widget); |
252 | core::style::WhiteSpace ws; | |
244 | int parMin = 0; | |
253 | 245 | |
254 | 246 | line = lines->getRef (lineIndex); |
255 | ws = words->getRef(line->firstWord)->style->whiteSpace; | |
256 | nowrap = ws == core::style::WHITE_SPACE_PRE || | |
257 | ws == core::style::WHITE_SPACE_NOWRAP; | |
258 | ||
259 | //DEBUG_MSG (DEBUG_SIZE_LEVEL, " line %d (of %d), nowrap = %d\n", | |
260 | // lineIndex, page->num_lines, nowrap); | |
261 | 247 | |
262 | 248 | for (wordIndex = line->firstWord; wordIndex <= line->lastWord; |
263 | 249 | wordIndex++) { |
268 | 254 | wordExtremes.minWidth += line1OffsetEff; |
269 | 255 | wordExtremes.maxWidth += line1OffsetEff; |
270 | 256 | //DEBUG_MSG (DEBUG_SIZE_LEVEL + 1, |
271 | // " (next plus %d)\n", page->line1_offset); | |
257 | // " (next plus %d)\n", line1OffsetEff); | |
272 | 258 | } |
273 | 259 | |
274 | if (nowrap) { | |
275 | parMin += prevWordSpace + wordExtremes.minWidth; | |
276 | //DBG_MSGF (widget, "extremes", 0, "parMin = %d", parMin); | |
277 | } else { | |
278 | if (extremes->minWidth < wordExtremes.minWidth) | |
279 | extremes->minWidth = wordExtremes.minWidth; | |
280 | } | |
260 | ||
261 | if (extremes->minWidth < wordExtremes.minWidth) | |
262 | extremes->minWidth = wordExtremes.minWidth; | |
281 | 263 | |
282 | 264 | _MSG("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n", |
283 | 265 | parMax, wordExtremes.maxWidth, prevWordSpace); |
284 | 266 | if (word->content.type != core::Content::BREAK) |
285 | 267 | parMax += prevWordSpace; |
286 | 268 | parMax += wordExtremes.maxWidth; |
269 | ||
270 | if (prevWord && !canBreakAfter(prevWord)) { | |
271 | parMin += prevWordSpace + wordExtremes.minWidth; | |
272 | } else { | |
273 | parMin = wordExtremes.minWidth; | |
274 | } | |
275 | ||
276 | if (extremes->minWidth < parMin) { | |
277 | extremes->minWidth = parMin; | |
278 | } | |
279 | ||
287 | 280 | prevWordSpace = word->origSpace; |
281 | prevWord = word; | |
288 | 282 | |
289 | 283 | //DEBUG_MSG (DEBUG_SIZE_LEVEL + 1, |
290 | 284 | // " word %s: maxWidth = %d\n", |
291 | // a_Dw_content_text (&word->content), | |
285 | // word->content.text, | |
292 | 286 | // word_extremes.maxWidth); |
293 | 287 | } |
294 | 288 | |
299 | 293 | //DEBUG_MSG (DEBUG_SIZE_LEVEL + 2, |
300 | 294 | // " parMax = %d, after word %d (%s)\n", |
301 | 295 | // parMax, line->last_word - 1, |
302 | // a_Dw_content_text (&word->content)); | |
296 | // word->content.text); | |
303 | 297 | |
304 | 298 | if (extremes->maxWidth < parMax) |
305 | 299 | extremes->maxWidth = parMax; |
306 | 300 | |
307 | if (nowrap) { | |
308 | //DBG_MSGF (widget, "extremes", 0, "parMin = %d", parMin); | |
309 | if (extremes->minWidth < parMin) | |
310 | extremes->minWidth = parMin; | |
311 | ||
312 | //DEBUG_MSG (DEBUG_SIZE_LEVEL + 2, | |
313 | // " parMin = %d, after word %d (%s)\n", | |
314 | // parMin, line->last_word - 1, | |
315 | // a_Dw_content_text (&word->content)); | |
316 | } | |
317 | ||
318 | 301 | prevWordSpace = 0; |
319 | parMin = 0; | |
320 | 302 | parMax = 0; |
321 | 303 | } |
322 | 304 | |
328 | 310 | } |
329 | 311 | |
330 | 312 | //DBG_MSGF (widget, "extremes", 0, "width difference: %d + %d", |
331 | // page->inner_padding, p_Dw_style_box_diff_width (widget->style)); | |
313 | // innerPadding, getStyle()->boxDiffWidth ()); | |
332 | 314 | |
333 | 315 | int diff = innerPadding + getStyle()->boxDiffWidth (); |
334 | 316 | extremes->minWidth += diff; |
479 | 461 | void Textblock::markChange (int ref) |
480 | 462 | { |
481 | 463 | if (ref != -1) { |
482 | //DBG_MSGF (page, "wrap", 0, "Dw_page_mark_size_change (ref = %d)", ref); | |
464 | //DBG_MSGF (page, "wrap", 0, "markChange (ref = %d)", ref); | |
483 | 465 | |
484 | 466 | if (wrapRef == -1) |
485 | 467 | wrapRef = ref; |
486 | 468 | else |
487 | 469 | wrapRef = misc::min (wrapRef, ref); |
488 | 470 | |
489 | //DBG_OBJ_SET_NUM (page, "wrap_ref", page->wrap_ref); | |
471 | //DBG_OBJ_SET_NUM (this, "wrap_ref", wrapRef); | |
490 | 472 | } |
491 | 473 | } |
492 | 474 | |
493 | 475 | void Textblock::setWidth (int width) |
494 | 476 | { |
495 | /* If limitTextWidth is set to YES, a queue_resize may also be | |
477 | /* If limitTextWidth is set to YES, a queueResize() may also be | |
496 | 478 | * necessary. */ |
497 | 479 | if (availWidth != width || limitTextWidth) { |
498 | 480 | //DEBUG_MSG(DEBUG_REWRAP_LEVEL, |
499 | // "Dw_page_set_width: Calling p_Dw_widget_queue_resize, " | |
481 | // "setWidth: Calling queueResize, " | |
500 | 482 | // "in page with %d word(s)\n", |
501 | // page->num_words); | |
483 | // words->size()); | |
502 | 484 | |
503 | 485 | availWidth = width; |
504 | 486 | queueResize (0, false); |
511 | 493 | { |
512 | 494 | if (availAscent != ascent) { |
513 | 495 | //DEBUG_MSG(DEBUG_REWRAP_LEVEL, |
514 | // "Dw_page_set_ascent: Calling p_Dw_widget_queue_resize, " | |
496 | // "setAscent: Calling queueResize, " | |
515 | 497 | // "in page with %d word(s)\n", |
516 | // page->num_words); | |
498 | // words->size()); | |
517 | 499 | |
518 | 500 | availAscent = ascent; |
519 | 501 | queueResize (0, false); |
525 | 507 | { |
526 | 508 | if (availDescent != descent) { |
527 | 509 | //DEBUG_MSG(DEBUG_REWRAP_LEVEL, |
528 | // "Dw_page_set_descent: Calling p_Dw_widget_queue_resize, " | |
510 | // "setDescent: Calling queueResize, " | |
529 | 511 | // "in page with %d word(s)\n", |
530 | // page->num_words); | |
512 | // words->size()); | |
531 | 513 | |
532 | 514 | availDescent = descent; |
533 | 515 | queueResize (0, false); |
620 | 602 | core::MousePositionEvent *event) |
621 | 603 | { |
622 | 604 | core::Iterator *it; |
623 | Line *line, *lastLine; | |
624 | int nextWordStartX, wordStartX, wordX, nextWordX, yFirst, yLast; | |
625 | int charPos = 0, link = -1, prevPos, wordIndex, lineIndex; | |
626 | Word *word; | |
627 | bool found, r; | |
605 | int wordIndex; | |
606 | int charPos = 0, link = -1; | |
607 | bool r; | |
628 | 608 | |
629 | 609 | if (words->size () == 0) { |
630 | 610 | wordIndex = -1; |
631 | 611 | } else { |
632 | lastLine = lines->getRef (lines->size () - 1); | |
633 | yFirst = lineYOffsetCanvasI (0); | |
634 | yLast = lineYOffsetCanvas (lastLine) + lastLine->boxAscent + | |
635 | lastLine->boxDescent; | |
612 | Line *lastLine = lines->getRef (lines->size () - 1); | |
613 | int yFirst = lineYOffsetCanvasI (0); | |
614 | int yLast = lineYOffsetCanvas (lastLine) + lastLine->boxAscent + | |
615 | lastLine->boxDescent; | |
636 | 616 | if (event->yCanvas < yFirst) { |
637 | 617 | // Above the first line: take the first word. |
638 | 618 | wordIndex = 0; |
639 | charPos = 0; | |
640 | 619 | } else if (event->yCanvas >= yLast) { |
641 | 620 | // Below the last line: take the last word. |
642 | 621 | wordIndex = words->size () - 1; |
643 | word = words->getRef (wordIndex); | |
644 | charPos = word->content.type == core::Content::TEXT ? | |
645 | strlen (word->content.text) : 0; | |
622 | charPos = core::SelectionState::END_OF_WORD; | |
646 | 623 | } else { |
647 | lineIndex = findLineIndex (event->yWidget); | |
648 | line = lines->getRef (lineIndex); | |
624 | Line *line = lines->getRef (findLineIndex (event->yWidget)); | |
649 | 625 | |
650 | 626 | // Pointer within the break space? |
651 | 627 | if (event->yWidget > |
652 | 628 | (lineYOffsetWidget (line) + line->boxAscent + line->boxDescent)) { |
653 | 629 | // Choose this break. |
654 | 630 | wordIndex = line->lastWord; |
655 | charPos = 0; | |
631 | charPos = core::SelectionState::END_OF_WORD; | |
656 | 632 | } else if (event->xWidget < lineXOffsetWidget (line)) { |
657 | 633 | // Left of the first word in the line. |
658 | 634 | wordIndex = line->firstWord; |
659 | charPos = 0; | |
660 | 635 | } else { |
661 | nextWordStartX = lineXOffsetWidget (line); | |
662 | found = false; | |
636 | int nextWordStartX = lineXOffsetWidget (line); | |
637 | ||
663 | 638 | for (wordIndex = line->firstWord; |
664 | !found && wordIndex <= line->lastWord; | |
639 | wordIndex <= line->lastWord; | |
665 | 640 | wordIndex++) { |
666 | word = words->getRef (wordIndex); | |
667 | wordStartX = nextWordStartX; | |
641 | Word *word = words->getRef (wordIndex); | |
642 | int wordStartX = nextWordStartX; | |
643 | ||
668 | 644 | nextWordStartX += word->size.width + word->effSpace; |
669 | 645 | |
670 | 646 | if (event->xWidget >= wordStartX && |
671 | 647 | event->xWidget < nextWordStartX) { |
672 | 648 | // We have found the word. |
673 | if (word->content.type == core::Content::TEXT) { | |
674 | // Search the character the mouse pointer is in. | |
675 | // nextWordX is the right side of this character. | |
676 | charPos = 0; | |
677 | while ((nextWordX = wordStartX + | |
678 | layout->textWidth (word->style->font, | |
679 | word->content.text, charPos)) | |
680 | <= event->xWidget) | |
681 | charPos = layout->nextGlyph (word->content.text, | |
682 | charPos); | |
683 | // The left side of this character. | |
684 | prevPos = layout->prevGlyph (word->content.text, charPos); | |
685 | wordX = wordStartX + layout->textWidth (word->style->font, | |
686 | word->content.text, | |
687 | prevPos); | |
688 | ||
689 | // If the mouse pointer is left from the middle, use the | |
690 | // left position, otherwise, use the right one. | |
691 | if (event->xWidget <= (wordX + nextWordX) / 2) | |
692 | charPos = prevPos; | |
649 | int yWidgetBase = lineYOffsetWidget (line) + line->boxAscent; | |
650 | ||
651 | if (event->xWidget >= nextWordStartX - word->effSpace) { | |
652 | charPos = core::SelectionState::END_OF_WORD; | |
653 | if (wordIndex < line->lastWord && | |
654 | (words->getRef(wordIndex + 1)->content.type != | |
655 | core::Content::BREAK) && | |
656 | (event->yWidget <= | |
657 | yWidgetBase + word->spaceStyle->font->descent) && | |
658 | (event->yWidget > | |
659 | yWidgetBase - word->spaceStyle->font->ascent)) { | |
660 | link = word->spaceStyle->x_link; | |
661 | } | |
693 | 662 | } else { |
694 | // Depends on whether the pointer is within the left or | |
695 | // right half of the (non-text) word. | |
696 | if (event->xWidget >= | |
697 | (wordStartX + nextWordStartX) / 2) | |
698 | charPos = core::SelectionState::END_OF_WORD; | |
699 | else | |
700 | charPos = 0; | |
663 | if (event->yWidget <= yWidgetBase + word->size.descent && | |
664 | event->yWidget > yWidgetBase - word->size.ascent) { | |
665 | link = word->style->x_link; | |
666 | } | |
667 | if (word->content.type == core::Content::TEXT) { | |
668 | int glyphX = wordStartX; | |
669 | ||
670 | while (1) { | |
671 | int nextCharPos = | |
672 | layout->nextGlyph (word->content.text, charPos); | |
673 | int glyphWidth = | |
674 | textWidth (word->content.text, charPos, | |
675 | nextCharPos - charPos, word->style); | |
676 | if (event->xWidget > glyphX + glyphWidth) { | |
677 | glyphX += glyphWidth; | |
678 | charPos = nextCharPos; | |
679 | continue; | |
680 | } else if (event->xWidget >= glyphX + glyphWidth/2){ | |
681 | // On the right half of a character; | |
682 | // now just look for combining chars | |
683 | charPos = nextCharPos; | |
684 | while (word->content.text[charPos]) { | |
685 | nextCharPos = | |
686 | layout->nextGlyph (word->content.text, | |
687 | charPos); | |
688 | if (textWidth (word->content.text, charPos, | |
689 | nextCharPos - charPos, | |
690 | word->style)) | |
691 | break; | |
692 | charPos = nextCharPos; | |
693 | } | |
694 | } | |
695 | break; | |
696 | } | |
697 | } else { | |
698 | // Depends on whether the pointer is within the left or | |
699 | // right half of the (non-text) word. | |
700 | if (event->xWidget >= (wordStartX + nextWordStartX) /2) | |
701 | charPos = core::SelectionState::END_OF_WORD; | |
702 | } | |
701 | 703 | } |
702 | ||
703 | found = true; | |
704 | link = word->style ? word->style->x_link : -1; | |
705 | 704 | break; |
706 | 705 | } |
707 | 706 | } |
708 | ||
709 | if (!found) { | |
707 | if (wordIndex > line->lastWord) { | |
710 | 708 | // No word found in this line (i.e. we are on the right side), |
711 | 709 | // take the last of this line. |
712 | 710 | wordIndex = line->lastWord; |
713 | if (wordIndex >= words->size ()) | |
714 | wordIndex--; | |
715 | word = words->getRef (wordIndex); | |
716 | charPos = word->content.type == core::Content::TEXT ? | |
717 | strlen (word->content.text) : | |
718 | (int)core::SelectionState::END_OF_WORD; | |
711 | charPos = core::SelectionState::END_OF_WORD; | |
719 | 712 | } |
720 | 713 | } |
721 | 714 | } |
769 | 762 | |
770 | 763 | words->getRef(i)->effSpace = words->getRef(i)->origSpace + |
771 | 764 | (effSpaceDiffCum - lastEffSpaceDiffCum); |
772 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.eff_space", i, | |
773 | // page->words[i].eff_space); | |
765 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.effSpace", i, | |
766 | // words->getRef(i)->effSpace); | |
774 | 767 | |
775 | 768 | lastEffSpaceDiffCum = effSpaceDiffCum; |
776 | 769 | } |
782 | 775 | { |
783 | 776 | Line *lastLine; |
784 | 777 | |
785 | //DBG_MSG (page, "wrap", 0, "Dw_page_add_line"); | |
778 | //DBG_MSG (page, "wrap", 0, "addLine"); | |
786 | 779 | //DBG_MSG_START (page); |
787 | 780 | |
788 | 781 | lines->increase (); |
789 | //DBG_OBJ_SET_NUM(page, "num_lines", page->num_lines); | |
782 | //DBG_OBJ_SET_NUM(this, "num_lines", lines->size ()); | |
790 | 783 | |
791 | 784 | //DEBUG_MSG (DEBUG_REWRAP_LEVEL, "--- new line %d in %p, with word %d of %d" |
792 | // "\n", page->num_lines - 1, page, word_ind, page->num_words); | |
785 | // "\n", lines->size () - 1, page, word_ind, words->size()); | |
793 | 786 | |
794 | 787 | lastLine = lines->getRef (lines->size () - 1); |
795 | 788 | |
796 | 789 | if (lines->size () == 1) { |
797 | 790 | lastLine->top = 0; |
798 | 791 | lastLine->maxLineWidth = line1OffsetEff; |
799 | lastLine->maxWordMin = 0; | |
792 | lastLine->maxParMin = 0; | |
800 | 793 | lastLine->maxParMax = 0; |
801 | 794 | } else { |
802 | 795 | Line *prevLine = lines->getRef (lines->size () - 2); |
804 | 797 | lastLine->top = prevLine->top + prevLine->boxAscent + |
805 | 798 | prevLine->boxDescent + prevLine->breakSpace; |
806 | 799 | lastLine->maxLineWidth = prevLine->maxLineWidth; |
807 | lastLine->maxWordMin = prevLine->maxWordMin; | |
800 | lastLine->maxParMin = prevLine->maxParMin; | |
808 | 801 | lastLine->maxParMax = prevLine->maxParMax; |
809 | 802 | } |
810 | 803 | |
811 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.top", page->num_lines - 1, | |
804 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.top", lines->size () - 1, | |
812 | 805 | // lastLine->top); |
813 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.maxLineWidth", page->num_lines - 1, | |
806 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.maxLineWidth", lines->size () - 1, | |
814 | 807 | // lastLine->maxLineWidth); |
815 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.maxWordMin", page->num_lines - 1, | |
816 | // lastLine->maxWordMin); | |
817 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.maxParMax", page->num_lines - 1, | |
808 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.maxParMin", lines->size () - 1, | |
809 | // lastLine->maxParMin); | |
810 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.maxParMax", lines->size () - 1, | |
818 | 811 | // lastLine->maxParMax); |
819 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.parMin", page->num_lines - 1, | |
812 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.parMin", lines->size () - 1, | |
820 | 813 | // lastLine->parMin); |
821 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.parMax", page->num_lines - 1, | |
814 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.parMax", lines->size () - 1, | |
822 | 815 | // lastLine->parMax); |
823 | 816 | |
824 | 817 | lastLine->firstWord = wordIndex; |
828 | 821 | lastLine->breakSpace = 0; |
829 | 822 | lastLine->leftOffset = 0; |
830 | 823 | |
831 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.ascent", page->num_lines - 1, | |
824 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.ascent", lines->size () - 1, | |
832 | 825 | // lastLine->boxAscent); |
833 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.descent", page->num_lines - 1, | |
826 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.descent", lines->size () - 1, | |
834 | 827 | // lastLine->boxDescent); |
835 | 828 | |
836 | 829 | /* update values in line */ |
843 | 836 | |
844 | 837 | if (newPar) { |
845 | 838 | lastLine->maxParMax = misc::max (lastLine->maxParMax, lastLineParMax); |
846 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.maxParMax", page->num_lines - 1, | |
839 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.maxParMax", lines->size () - 1, | |
847 | 840 | // lastLine->maxParMax); |
848 | 841 | |
849 | /* The following code looks questionable (especially since the values | |
850 | * will be overwritten). In any case, line1OffsetEff is probably | |
851 | * supposed to go into lastLinePar*, not lastLine->par*. | |
852 | */ | |
853 | 842 | if (lines->size () > 1) { |
854 | lastLine->parMin = 0; | |
855 | lastLine->parMax = 0; | |
843 | lastLineParMax = 0; | |
856 | 844 | } else { |
857 | lastLine->parMin = line1OffsetEff; | |
858 | lastLine->parMax = line1OffsetEff; | |
859 | } | |
860 | lastLineParMin = 0; | |
861 | lastLineParMax = 0; | |
862 | ||
863 | //DBG_OBJ_SET_NUM(page, "lastLineParMin", page->lastLineParMin); | |
864 | //DBG_OBJ_SET_NUM(page, "lastLineParMax", page->lastLineParMax); | |
865 | } | |
866 | ||
867 | lastLine->parMin = lastLineParMin; | |
845 | lastLineParMax = line1OffsetEff; | |
846 | } | |
847 | ||
848 | //DBG_OBJ_SET_NUM(this, "lastLineParMax", lastLineParMax); | |
849 | } | |
850 | ||
868 | 851 | lastLine->parMax = lastLineParMax; |
869 | 852 | |
870 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.parMin", page->num_lines - 1, | |
853 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.parMin", lines->size () - 1, | |
871 | 854 | // lastLine->parMin); |
872 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.parMax", page->num_lines - 1, | |
855 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.parMax", lines->size () - 1, | |
873 | 856 | // lastLine->parMax); |
874 | 857 | |
875 | 858 | //DBG_MSG_END (page); |
886 | 869 | Line *lastLine; |
887 | 870 | Word *word; |
888 | 871 | int availWidth, lastSpace, leftOffset, len; |
889 | bool newLine = false, newPar = false; | |
872 | bool newLine = false, newPar = false, canBreakBefore = true; | |
890 | 873 | core::Extremes wordExtremes; |
891 | 874 | |
892 | //DBG_MSGF (page, "wrap", 0, "Dw_page_real_word_wrap (%d): %s, width = %d", | |
893 | // word_ind, a_Dw_content_html (&page->words[word_ind].content), | |
894 | // page->words[word_ind].size.width); | |
875 | //DBG_MSGF (page, "wrap", 0, "wordWrap (%d): %s, width = %d", | |
876 | // wordIndex, words->getRef(wordIndex)->content.text), | |
877 | // words->getRef(wordIndex)->size.width); | |
895 | 878 | //DBG_MSG_START (page); |
896 | 879 | |
897 | 880 | availWidth = this->availWidth - getStyle()->boxDiffWidth() - innerPadding; |
941 | 924 | /* previous word is a break */ |
942 | 925 | newLine = true; |
943 | 926 | newPar = true; |
944 | } else if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP || | |
945 | word->style->whiteSpace == core::style::WHITE_SPACE_PRE) { | |
946 | //DBG_MSGF (page, "wrap", 0, "no wrap (white_space = %d)", | |
947 | // word->style->white_space); | |
927 | } else if (!canBreakAfter (prevWord)) { | |
928 | canBreakBefore = false; | |
929 | // no break within nowrap | |
948 | 930 | newLine = false; |
949 | 931 | newPar = false; |
932 | if (lastLineWidth + prevWord->origSpace + word->size.width > | |
933 | availWidth) | |
934 | markChange (lines->size () - 1); | |
950 | 935 | } else if (lastLine->firstWord != wordIndex) { |
951 | /* Does new word fit into the last line? */ | |
952 | //DBG_MSGF (page, "wrap", 0, | |
953 | // "word %d (%s) fits? (%d + %d + %d <= %d)...", | |
954 | // word_ind, a_Dw_content_html (&word->content), | |
955 | // page->lastLine_width, prevWord->orig_space, | |
956 | // word->size.width, availWidth); | |
957 | newLine = lastLineWidth + prevWord->origSpace + word->size.width > | |
958 | availWidth; | |
959 | //DBG_MSGF (page, "wrap", 0, "... %s.", | |
960 | // newLine ? "No" : "Yes"); | |
936 | // check if we need to break because nowrap sequence is following | |
937 | newLine = false; | |
938 | int lineWidthNeeded = lastLineWidth + prevWord->origSpace; | |
939 | for (int i = wordIndex; i < words->size (); i++) { | |
940 | Word *w = words->getRef (i); | |
941 | ||
942 | if (w->content.type == core::Content::BREAK || | |
943 | (word->content.type == core::Content::WIDGET && | |
944 | word->content.widget->blockLevel())) | |
945 | break; | |
946 | ||
947 | lineWidthNeeded += w->size.width; | |
948 | ||
949 | if (lineWidthNeeded > availWidth) { | |
950 | newLine = true; | |
951 | break; | |
952 | } else if (canBreakAfter (w)) { | |
953 | break; | |
954 | } | |
955 | ||
956 | lineWidthNeeded += w->origSpace; | |
957 | } | |
961 | 958 | } |
962 | 959 | } |
963 | 960 | |
983 | 980 | len += word->style->font->ascent / 3; |
984 | 981 | lastLine->contentDescent = misc::max (lastLine->contentDescent, len); |
985 | 982 | |
986 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.ascent", page->num_lines - 1, | |
983 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.ascent", lines->size () - 1, | |
987 | 984 | // lastLine->boxAscent); |
988 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.descent", page->num_lines - 1, | |
985 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.descent", lines->size () - 1, | |
989 | 986 | // lastLine->boxDescent); |
990 | 987 | |
991 | 988 | if (word->content.type == core::Content::WIDGET) { |
1000 | 997 | word->content.widget->blockLevel () && |
1001 | 998 | getStyle ()->borderWidth.top == 0 && |
1002 | 999 | getStyle ()->padding.top == 0) { |
1003 | // collapse top margin of parent element with top margin of first child | |
1000 | // collapse top margins of parent element and its first child | |
1004 | 1001 | // see: http://www.w3.org/TR/CSS21/box.html#collapsing-margins |
1005 | 1002 | collapseMarginTop = getStyle ()->margin.top; |
1006 | 1003 | } |
1028 | 1025 | if (!newLine) |
1029 | 1026 | lastLineWidth += lastSpace; |
1030 | 1027 | if (!newPar) { |
1031 | lastLineParMin += lastSpace; | |
1032 | 1028 | lastLineParMax += lastSpace; |
1033 | 1029 | } |
1034 | 1030 | |
1035 | 1031 | lastLineWidth += word->size.width; |
1036 | 1032 | |
1037 | 1033 | getWordExtremes (word, &wordExtremes); |
1038 | lastLineParMin += wordExtremes.maxWidth; /* Why maxWidth? */ | |
1039 | 1034 | lastLineParMax += wordExtremes.maxWidth; |
1040 | 1035 | |
1041 | if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP || | |
1042 | word->style->whiteSpace == core::style::WHITE_SPACE_PRE) { | |
1043 | lastLine->parMin += wordExtremes.minWidth + lastSpace; | |
1036 | if (!canBreakBefore) { | |
1037 | lastLineParMin += wordExtremes.minWidth + lastSpace; | |
1044 | 1038 | /* This may also increase the accumulated minimum word width. */ |
1045 | lastLine->maxWordMin = | |
1046 | misc::max (lastLine->maxWordMin, lastLine->parMin); | |
1047 | /* NOTE: Most code relies on that all values of nowrap are equal for all | |
1048 | * words within one line. */ | |
1039 | lastLine->maxParMin = misc::max (lastLine->maxParMin, lastLineParMin); | |
1049 | 1040 | } else { |
1050 | lastLine->maxWordMin = | |
1051 | misc::max (lastLine->maxWordMin, wordExtremes.minWidth); | |
1052 | } | |
1053 | ||
1054 | //DBG_OBJ_SET_NUM(page, "lastLine_par_min", page->lastLine_par_min); | |
1055 | //DBG_OBJ_SET_NUM(page, "lastLine_par_max", page->lastLine_par_max); | |
1056 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.par_min", page->num_lines - 1, | |
1041 | lastLineParMin = wordExtremes.minWidth; | |
1042 | lastLine->maxParMin = | |
1043 | misc::max (lastLine->maxParMin, wordExtremes.minWidth); | |
1044 | } | |
1045 | ||
1046 | //DBG_OBJ_SET_NUM(this, "lastLine_par_min", lastLineParMin); | |
1047 | //DBG_OBJ_SET_NUM(this, "lastLine_par_max", lastLineParMax); | |
1048 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.par_min", lines->size () - 1, | |
1057 | 1049 | // lastLine->par_min); |
1058 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.par_max", page->num_lines - 1, | |
1050 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.par_max", lines->size () - 1, | |
1059 | 1051 | // lastLine->par_max); |
1060 | //DBG_OBJ_ARRSET_NUM (page, "lines.%d.max_word_min", page->num_lines - 1, | |
1052 | //DBG_OBJ_ARRSET_NUM (this, "lines.%d.max_word_min", lines->size () - 1, | |
1061 | 1053 | // lastLine->max_word_min); |
1062 | 1054 | |
1063 | 1055 | /* Align the line. |
1086 | 1078 | if (leftOffset < 0) |
1087 | 1079 | leftOffset = 0; |
1088 | 1080 | |
1089 | if (hasListitemValue && lastLine == lines->getRef (0)) { | |
1090 | /* List item markers are always on the left. */ | |
1091 | lastLine->leftOffset = 0; | |
1092 | words->getRef(0)->effSpace = words->getRef(0)->origSpace + leftOffset; | |
1093 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.eff_space", 0, | |
1094 | // page->words[0].eff_space); | |
1095 | } else { | |
1096 | lastLine->leftOffset = leftOffset; | |
1097 | } | |
1081 | lastLine->leftOffset = leftOffset; | |
1098 | 1082 | } |
1099 | 1083 | mustQueueResize = true; |
1100 | 1084 | |
1176 | 1160 | return; |
1177 | 1161 | |
1178 | 1162 | //DBG_MSGF (page, "wrap", 0, |
1179 | // "Dw_page_rewrap: page->wrap_ref = %d, in page with %d word(s)", | |
1180 | // page->wrap_ref, page->num_words); | |
1163 | // "rewrap: wrapRef = %d, in page with %d word(s)", | |
1164 | // wrapRef, words->size()); | |
1181 | 1165 | //DBG_MSG_START (page); |
1182 | 1166 | |
1183 | /* All lines up from page->wrap_ref will be rebuild from the word list, | |
1167 | /* All lines up from wrapRef will be rebuild from the word list, | |
1184 | 1168 | * the line list up from this position is rebuild. */ |
1185 | 1169 | lines->setSize (wrapRef); |
1186 | 1170 | lastLineWidth = 0; |
1187 | //DBG_OBJ_SET_NUM(page, "num_lines", page->num_lines); | |
1188 | //DBG_OBJ_SET_NUM(page, "lastLine_width", page->lastLine_width); | |
1171 | lastLineParMin = 0; | |
1172 | //DBG_OBJ_SET_NUM(this, "num_lines", lines->size ()); | |
1173 | //DBG_OBJ_SET_NUM(this, "lastLine_width", lastLineWidth); | |
1189 | 1174 | |
1190 | 1175 | /* In the word list, start at the last word plus one in the line before. */ |
1191 | 1176 | if (wrapRef > 0) { |
1192 | /* Note: In this case, Dw_page_real_word_wrap will immediately find | |
1193 | * the need to rewrap the line, since we start with the last one (plus | |
1194 | * one). This is also the reason, why page->lastLine_width is set | |
1177 | /* Note: In this case, wordWrap() will immediately find the need | |
1178 | * to rewrap the line, since we start with the last one (plus one). | |
1179 | * This is also the reason, why lastLineWidth is set | |
1195 | 1180 | * to the length of the line. */ |
1196 | 1181 | lastLine = lines->getRef (lines->size () - 1); |
1197 | 1182 | |
1198 | lastLineParMin = lastLine->parMin; | |
1199 | 1183 | lastLineParMax = lastLine->parMax; |
1200 | 1184 | |
1201 | 1185 | wordIndex = lastLine->lastWord + 1; |
1204 | 1188 | words->getRef(i)->origSpace); |
1205 | 1189 | lastLineWidth += words->getRef(lastLine->lastWord)->size.width; |
1206 | 1190 | } else { |
1207 | lastLineParMin = 0; | |
1208 | 1191 | lastLineParMax = 0; |
1209 | 1192 | |
1210 | 1193 | wordIndex = 0; |
1226 | 1209 | //DEBUG_MSG(DEBUG_REWRAP_LEVEL, |
1227 | 1210 | // "Assigning parent_ref = %d to rewrapped word %d, " |
1228 | 1211 | // "in page with %d word(s)\n", |
1229 | // page->num_lines - 1, wordIndex, page->num_words); | |
1212 | // lines->size () - 1, wordIndex, words->size()); | |
1230 | 1213 | |
1231 | 1214 | /* todo_refactoring: |
1232 | 1215 | if (word->content.type == DW_CONTENT_ANCHOR) |
1233 | 1216 | p_Dw_gtk_viewport_change_anchor |
1234 | 1217 | (widget, word->content.anchor, |
1235 | 1218 | Dw_page_line_total_y_offset (page, |
1236 | &page->lines[page->num_lines - 1])); | |
1219 | &page->lines[lines->size () - 1])); | |
1237 | 1220 | */ |
1238 | 1221 | } |
1239 | 1222 | |
1269 | 1252 | } |
1270 | 1253 | |
1271 | 1254 | /* |
1255 | * Draw a string of text | |
1256 | */ | |
1257 | void Textblock::drawText(core::View *view, core::style::Style *style, | |
1258 | core::style::Color::Shading shading, int x, int y, | |
1259 | const char *text, int start, int len) | |
1260 | { | |
1261 | if (len > 0) { | |
1262 | char *str = NULL; | |
1263 | ||
1264 | switch (style->textTransform) { | |
1265 | case core::style::TEXT_TRANSFORM_NONE: | |
1266 | default: | |
1267 | break; | |
1268 | case core::style::TEXT_TRANSFORM_UPPERCASE: | |
1269 | str = layout->textToUpper(text + start, len); | |
1270 | break; | |
1271 | case core::style::TEXT_TRANSFORM_LOWERCASE: | |
1272 | str = layout->textToLower(text + start, len); | |
1273 | break; | |
1274 | case core::style::TEXT_TRANSFORM_CAPITALIZE: | |
1275 | { | |
1276 | /* \bug No way to know about non-ASCII punctuation. */ | |
1277 | bool initial_seen = false; | |
1278 | ||
1279 | for (int i = 0; i < start; i++) | |
1280 | if (!ispunct(text[i])) | |
1281 | initial_seen = true; | |
1282 | if (initial_seen) | |
1283 | break; | |
1284 | ||
1285 | int after = 0; | |
1286 | text += start; | |
1287 | while (ispunct(text[after])) | |
1288 | after++; | |
1289 | if (text[after]) | |
1290 | after = layout->nextGlyph(text, after); | |
1291 | if (after > len) | |
1292 | after = len; | |
1293 | ||
1294 | char *initial = layout->textToUpper(text, after); | |
1295 | int newlen = strlen(initial) + len-after; | |
1296 | str = (char *)malloc(newlen + 1); | |
1297 | strcpy(str, initial); | |
1298 | strncpy(str + strlen(str), text+after, len-after); | |
1299 | str[newlen] = '\0'; | |
1300 | free(initial); | |
1301 | break; | |
1302 | } | |
1303 | } | |
1304 | view->drawText(style->font, style->color, shading, x, y, | |
1305 | str ? str : text + start, str ? strlen(str) : len); | |
1306 | if (str) | |
1307 | free(str); | |
1308 | } | |
1309 | } | |
1310 | ||
1311 | /* | |
1272 | 1312 | * Draw a word of text. |
1273 | 1313 | */ |
1274 | void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area, | |
1314 | void Textblock::drawWord(int wordIndex, core::View *view,core::Rectangle *area, | |
1275 | 1315 | int xWidget, int yWidgetBase) |
1276 | 1316 | { |
1277 | 1317 | Word *word = words->getRef(wordIndex); |
1287 | 1327 | } |
1288 | 1328 | yWorldBase = yWidgetBase + allocation.y; |
1289 | 1329 | |
1290 | view->drawText (style->font, style->color, | |
1291 | core::style::Color::SHADING_NORMAL, xWorld, yWorldBase, | |
1292 | word->content.text, strlen (word->content.text)); | |
1330 | drawText (view, style, core::style::Color::SHADING_NORMAL, xWorld, | |
1331 | yWorldBase, word->content.text, 0, strlen (word->content.text)); | |
1293 | 1332 | |
1294 | 1333 | if (style->textDecoration) |
1295 | 1334 | decorateText(view, style, core::style::Color::SHADING_NORMAL, xWorld, |
1311 | 1350 | |
1312 | 1351 | xStart = xWorld; |
1313 | 1352 | if (firstCharIdx) |
1314 | xStart += layout->textWidth (style->font, word->content.text, | |
1315 | firstCharIdx); | |
1353 | xStart += textWidth (word->content.text, 0, firstCharIdx, style); | |
1316 | 1354 | if (firstCharIdx == 0 && lastCharIdx == wordLen) |
1317 | 1355 | width = word->size.width; |
1318 | 1356 | else |
1319 | width = layout->textWidth (style->font, | |
1320 | word->content.text + firstCharIdx, | |
1321 | lastCharIdx - firstCharIdx); | |
1357 | width = textWidth (word->content.text, firstCharIdx, | |
1358 | lastCharIdx - firstCharIdx, style); | |
1322 | 1359 | if (width > 0) { |
1323 | 1360 | /* Highlight text */ |
1324 | 1361 | core::style::Color *wordBgColor; |
1333 | 1370 | style->font->ascent + style->font->descent); |
1334 | 1371 | |
1335 | 1372 | /* Highlight the text. */ |
1336 | view->drawText (style->font, style->color, | |
1337 | core::style::Color::SHADING_INVERSE, xStart, | |
1338 | yWorldBase, word->content.text + firstCharIdx, | |
1339 | lastCharIdx - firstCharIdx); | |
1373 | drawText (view, style, core::style::Color::SHADING_INVERSE, xStart, | |
1374 | yWorldBase, word->content.text, firstCharIdx, | |
1375 | lastCharIdx - firstCharIdx); | |
1340 | 1376 | |
1341 | 1377 | if (style->textDecoration) |
1342 | 1378 | decorateText(view, style, core::style::Color::SHADING_INVERSE, |
1434 | 1470 | yWidgetBase - line->boxAscent, word->size.width, |
1435 | 1471 | line->boxAscent + line->boxDescent, false); |
1436 | 1472 | } |
1437 | drawText(wordIndex, view, area, xWidget, yWidgetBase); | |
1473 | drawWord(wordIndex, view, area, xWidget, yWidgetBase); | |
1438 | 1474 | } |
1439 | 1475 | } |
1440 | 1476 | if (word->effSpace > 0 && wordIndex < line->lastWord && |
1534 | 1570 | word = words->getRef (wordIndex); |
1535 | 1571 | lastXCursor = xCursor; |
1536 | 1572 | xCursor += word->size.width + word->effSpace; |
1537 | if (lastXCursor <= x && xCursor > x && | |
1538 | y > yWidgetBase - word->size.ascent && | |
1539 | y <= yWidgetBase + word->size.descent) { | |
1540 | *inSpace = x >= xCursor - word->effSpace; | |
1541 | return word; | |
1573 | if (lastXCursor <= x && xCursor > x) { | |
1574 | if (x >= xCursor - word->effSpace) { | |
1575 | if (wordIndex < line->lastWord && | |
1576 | (words->getRef(wordIndex + 1)->content.type != | |
1577 | core::Content::BREAK) && | |
1578 | y > yWidgetBase - word->spaceStyle->font->ascent && | |
1579 | y <= yWidgetBase + word->spaceStyle->font->descent) { | |
1580 | *inSpace = true; | |
1581 | return word; | |
1582 | } | |
1583 | } else { | |
1584 | if (y > yWidgetBase - word->size.ascent && | |
1585 | y <= yWidgetBase + word->size.descent) | |
1586 | return word; | |
1587 | } | |
1588 | break; | |
1542 | 1589 | } |
1543 | 1590 | } |
1544 | 1591 | |
1580 | 1627 | word->origSpace = 0; |
1581 | 1628 | word->effSpace = 0; |
1582 | 1629 | word->content.space = false; |
1583 | ||
1584 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.size.width", page->num_words - 1, | |
1630 | word->content.breakType = core::Content::BREAK_NO; | |
1631 | ||
1632 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.size.width", words->size() - 1, | |
1585 | 1633 | // word->size.width); |
1586 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.size.descent", page->num_words - 1, | |
1634 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.size.descent", words->size() - 1, | |
1587 | 1635 | // word->size.descent); |
1588 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.size.ascent", page->num_words - 1, | |
1636 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.size.ascent", words->size() - 1, | |
1589 | 1637 | // word->size.ascent); |
1590 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.orig_space", page->num_words - 1, | |
1638 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.orig_space", words->size() - 1, | |
1591 | 1639 | // word->orig_space); |
1592 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.eff_space", page->num_words - 1, | |
1640 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.effSpace", words->size() - 1, | |
1593 | 1641 | // word->eff_space); |
1594 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.content.space", page->num_words - 1, | |
1642 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.content.space", words->size() - 1, | |
1595 | 1643 | // word->content.space); |
1596 | 1644 | |
1597 | 1645 | word->style = style; |
1602 | 1650 | return word; |
1603 | 1651 | } |
1604 | 1652 | |
1653 | /* | |
1654 | * Get the width of a string of text. | |
1655 | */ | |
1656 | int Textblock::textWidth(const char *text, int start, int len, | |
1657 | core::style::Style *style) | |
1658 | { | |
1659 | int ret = 0; | |
1660 | ||
1661 | if (len > 0) { | |
1662 | char *str = NULL; | |
1663 | ||
1664 | switch (style->textTransform) { | |
1665 | case core::style::TEXT_TRANSFORM_NONE: | |
1666 | default: | |
1667 | ret = layout->textWidth(style->font, text+start, len); | |
1668 | break; | |
1669 | case core::style::TEXT_TRANSFORM_UPPERCASE: | |
1670 | str = layout->textToUpper(text+start, len); | |
1671 | ret = layout->textWidth(style->font, str, strlen(str)); | |
1672 | break; | |
1673 | case core::style::TEXT_TRANSFORM_LOWERCASE: | |
1674 | str = layout->textToLower(text+start, len); | |
1675 | ret = layout->textWidth(style->font, str, strlen(str)); | |
1676 | break; | |
1677 | case core::style::TEXT_TRANSFORM_CAPITALIZE: | |
1678 | { | |
1679 | /* \bug No way to know about non-ASCII punctuation. */ | |
1680 | bool initial_seen = false; | |
1681 | ||
1682 | for (int i = 0; i < start; i++) | |
1683 | if (!ispunct(text[i])) | |
1684 | initial_seen = true; | |
1685 | if (initial_seen) { | |
1686 | ret = layout->textWidth(style->font, text+start, len); | |
1687 | } else { | |
1688 | int after = 0; | |
1689 | ||
1690 | text += start; | |
1691 | while (ispunct(text[after])) | |
1692 | after++; | |
1693 | if (text[after]) | |
1694 | after = layout->nextGlyph(text, after); | |
1695 | if (after > len) | |
1696 | after = len; | |
1697 | str = layout->textToUpper(text, after); | |
1698 | ret = layout->textWidth(style->font, str, strlen(str)) + | |
1699 | layout->textWidth(style->font, text+after, len-after); | |
1700 | } | |
1701 | break; | |
1702 | } | |
1703 | } | |
1704 | if (str) | |
1705 | free(str); | |
1706 | } | |
1707 | return ret; | |
1708 | } | |
1709 | ||
1605 | 1710 | /** |
1606 | 1711 | * Calculate the size of a text word. |
1607 | 1712 | */ |
1609 | 1714 | core::style::Style *style, |
1610 | 1715 | core::Requisition *size) |
1611 | 1716 | { |
1612 | size->width = layout->textWidth (style->font, text, len); | |
1717 | size->width = textWidth (text, 0, len, style); | |
1613 | 1718 | size->ascent = style->font->ascent; |
1614 | 1719 | size->descent = style->font->descent; |
1615 | 1720 | |
1668 | 1773 | word->content.type = core::Content::TEXT; |
1669 | 1774 | word->content.text = layout->textZone->strndup(text, len); |
1670 | 1775 | |
1671 | //DBG_OBJ_ARRSET_STR (page, "words.%d.content.text", page->num_words - 1, | |
1776 | //DBG_OBJ_ARRSET_STR (page, "words.%d.content.text", words->size() - 1, | |
1672 | 1777 | // word->content.text); |
1673 | 1778 | |
1674 | 1779 | wordWrap (words->size () - 1); |
1697 | 1802 | word->content.type = core::Content::WIDGET; |
1698 | 1803 | word->content.widget = widget; |
1699 | 1804 | |
1700 | //DBG_OBJ_ARRSET_PTR (page, "words.%d.content.widget", page->num_words - 1, | |
1805 | //DBG_OBJ_ARRSET_PTR (page, "words.%d.content.widget", words->size() - 1, | |
1701 | 1806 | // word->content.widget); |
1702 | 1807 | |
1703 | 1808 | wordWrap (words->size () - 1); |
1708 | 1813 | //DEBUG_MSG(DEBUG_REWRAP_LEVEL, |
1709 | 1814 | // "Assigning parent_ref = %d to added word %d, " |
1710 | 1815 | // "in page with %d word(s)\n", |
1711 | // page->num_lines - 1, page->num_words - 1, page->num_words); | |
1712 | } | |
1713 | ||
1816 | // lines->size () - 1, words->size() - 1, words->size()); | |
1817 | } | |
1714 | 1818 | |
1715 | 1819 | /** |
1716 | 1820 | * Add an anchor to the page. "name" is copied, so no strdup is necessary for |
1763 | 1867 | if (wordIndex >= 0) { |
1764 | 1868 | Word *word = words->getRef(wordIndex); |
1765 | 1869 | |
1870 | // According to http://www.w3.org/TR/CSS2/text.html#white-space-model: | |
1871 | // "line breaking opportunities are determined based on the text prior | |
1872 | // to the white space collapsing steps". | |
1873 | // So we call addBreakOption () for each Textblock::addSpace () call. | |
1874 | // This is important e.g. to be able to break between foo and bar in: | |
1875 | // <span style="white-space:nowrap">foo </span> bar | |
1876 | addBreakOption (style); | |
1877 | ||
1766 | 1878 | if (!word->content.space) { |
1767 | 1879 | word->content.space = true; |
1768 | 1880 | word->effSpace = word->origSpace = style->font->spaceWidth + |
1769 | 1881 | style->wordSpacing; |
1770 | 1882 | |
1771 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.orig_space", nw, | |
1772 | // page->words[nw].orig_space); | |
1773 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.eff_space", nw, | |
1774 | // page->words[nw].eff_space); | |
1775 | //DBG_OBJ_ARRSET_NUM (page, "words.%d.content.space", nw, | |
1776 | // page->words[nw].content.space); | |
1883 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.origSpace", wordIndex, | |
1884 | // word->origSpace); | |
1885 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.effSpace", wordIndex, | |
1886 | // word->effSpace); | |
1887 | //DBG_OBJ_ARRSET_NUM (this, "words.%d.content.space", wordIndex, | |
1888 | // word->content.space); | |
1777 | 1889 | word->spaceStyle->unref (); |
1778 | 1890 | word->spaceStyle = style; |
1779 | 1891 | style->ref (); |
1780 | 1892 | } |
1781 | 1893 | } |
1782 | 1894 | } |
1783 | ||
1784 | 1895 | |
1785 | 1896 | /** |
1786 | 1897 | * Cause a paragraph break |
1941 | 2052 | } |
1942 | 2053 | |
1943 | 2054 | /* |
1944 | * Any words added by a_Dw_page_add_... are not immediately (queued to | |
2055 | * Any words added by addWord() are not immediately (queued to | |
1945 | 2056 | * be) drawn, instead, this function must be called. This saves some |
1946 | * calls to p_Dw_widget_queue_resize. | |
2057 | * calls to queueResize(). | |
1947 | 2058 | * |
1948 | 2059 | */ |
1949 | 2060 | void Textblock::flush () |
2184 | 2295 | allocation->x += w->size.width + w->effSpace; |
2185 | 2296 | } |
2186 | 2297 | if (start > 0 && word->content.type == core::Content::TEXT) { |
2187 | allocation->x += textblock->layout->textWidth (word->style->font, | |
2188 | word->content.text, | |
2189 | start); | |
2298 | allocation->x += textblock->textWidth (word->content.text, 0, start, | |
2299 | word->style); | |
2190 | 2300 | } |
2191 | 2301 | allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent - |
2192 | 2302 | word->size.ascent; |
2198 | 2308 | if (start > 0 || end < wordEnd) { |
2199 | 2309 | end = misc::min(end, wordEnd); /* end could be INT_MAX */ |
2200 | 2310 | allocation->width = |
2201 | textblock->layout->textWidth (word->style->font, | |
2202 | word->content.text + start, | |
2203 | end - start); | |
2311 | textblock->textWidth (word->content.text, start, end - start, | |
2312 | word->style); | |
2204 | 2313 | } |
2205 | 2314 | } |
2206 | 2315 | allocation->ascent = word->size.ascent; |
147 | 147 | /* The following members contain accumulated values, from the top |
148 | 148 | * down to the line before. */ |
149 | 149 | int maxLineWidth; /* maximum of all line widths */ |
150 | int maxWordMin; /* maximum of all word minima */ | |
150 | int maxParMin; /* maximum of all paragraph minima */ | |
151 | 151 | int maxParMax; /* maximum of all paragraph maxima */ |
152 | int parMin; /* the minimal total width down from the last | |
153 | * paragraph start, to the *beginning* of the | |
154 | * line */ | |
155 | 152 | int parMax; /* the maximal total width down from the last |
156 | 153 | * paragraph start, to the *beginning* of the |
157 | 154 | * line */ |
239 | 236 | int availWidth, availAscent, availDescent; |
240 | 237 | |
241 | 238 | int lastLineWidth; |
242 | int lastLineParMin; | |
239 | int lastLineParMin; /* width of the current non-breakable word sequence | |
240 | * used by wordWrap () */ | |
243 | 241 | int lastLineParMax; |
244 | 242 | int wrapRef; /* [0 based] */ |
245 | 243 | |
255 | 253 | |
256 | 254 | void queueDrawRange (int index1, int index2); |
257 | 255 | void getWordExtremes (Word *word, core::Extremes *extremes); |
256 | inline bool canBreakAfter (Word *word) | |
257 | { | |
258 | return word->content.breakType == core::Content::BREAK_OK; | |
259 | } | |
258 | 260 | void markChange (int ref); |
259 | 261 | void justifyLine (Line *line, int availWidth); |
260 | 262 | Line *addLine (int wordInd, bool newPar); |
263 | 265 | void decorateText(core::View *view, core::style::Style *style, |
264 | 266 | core::style::Color::Shading shading, |
265 | 267 | int x, int yBase, int width); |
266 | void drawText(int wordIndex, core::View *view, core::Rectangle *area, | |
268 | void drawText(core::View *view, core::style::Style *style, | |
269 | core::style::Color::Shading shading, int x, int y, | |
270 | const char *text, int start, int len); | |
271 | void drawWord(int wordIndex, core::View *view, core::Rectangle *area, | |
267 | 272 | int xWidget, int yWidgetBase); |
268 | 273 | void drawSpace(int wordIndex, core::View *view, core::Rectangle *area, |
269 | 274 | int xWidget, int yWidgetBase); |
274 | 279 | |
275 | 280 | Word *addWord (int width, int ascent, int descent, |
276 | 281 | core::style::Style *style); |
282 | int textWidth (const char *text, int start, int len, | |
283 | core::style::Style *style); | |
277 | 284 | void calcTextSize (const char *text, size_t len, core::style::Style *style, |
278 | 285 | core::Requisition *size); |
279 | ||
280 | 286 | |
281 | 287 | /** |
282 | 288 | * \brief Returns the x offset (the indentation plus any offset needed for |
381 | 387 | void addWidget (core::Widget *widget, core::style::Style *style); |
382 | 388 | bool addAnchor (const char *name, core::style::Style *style); |
383 | 389 | void addSpace(core::style::Style *style); |
390 | inline void addBreakOption (core::style::Style *style) | |
391 | { | |
392 | int wordIndex = words->size () - 1; | |
393 | if (wordIndex >= 0 && | |
394 | style->whiteSpace != core::style::WHITE_SPACE_NOWRAP && | |
395 | style->whiteSpace != core::style::WHITE_SPACE_PRE) | |
396 | words->getRef(wordIndex)->content.breakType = core::Content::BREAK_OK; | |
397 | } | |
384 | 398 | void addParbreak (int space, core::style::Style *style); |
385 | 399 | void addLinebreak (core::style::Style *style); |
386 | 400 |
193 | 193 | REAL_CONTENT = 0xff ^ (START | END), |
194 | 194 | SELECTION_CONTENT = TEXT | WIDGET | BREAK |
195 | 195 | }; |
196 | enum BreakType { | |
197 | BREAK_NO, | |
198 | BREAK_OK | |
199 | }; | |
196 | 200 | /* Content is embedded in struct Word therefore we |
197 | 201 | * try to be space efficient. |
198 | 202 | */ |
199 | 203 | short type; |
200 | 204 | bool space; |
205 | unsigned char breakType; | |
201 | 206 | union { |
202 | 207 | const char *text; |
203 | 208 | Widget *widget; |
0 | 0 | #!/bin/sh |
1 | # | |
2 | # $NetBSD: install-sh.in,v 1.5 2010/10/08 19:57:05 tez Exp $ | |
3 | # This script now also installs multiple files, but might choke on installing | |
4 | # multiple files with spaces in the file names. | |
5 | # | |
6 | 1 | # install - install a program, script, or datafile |
7 | # This comes from X11R5 (mit/util/scripts/install.sh). | |
8 | # | |
9 | # Copyright 1991 by the Massachusetts Institute of Technology | |
10 | # | |
11 | # Permission to use, copy, modify, distribute, and sell this software and its | |
12 | # documentation for any purpose is hereby granted without fee, provided that | |
13 | # the above copyright notice appear in all copies and that both that | |
14 | # copyright notice and this permission notice appear in supporting | |
15 | # documentation, and that the name of M.I.T. not be used in advertising or | |
16 | # publicity pertaining to distribution of the software without specific, | |
17 | # written prior permission. M.I.T. makes no representations about the | |
18 | # suitability of this software for any purpose. It is provided "as is" | |
19 | # without express or implied warranty. | |
2 | ||
3 | scriptversion=2009-04-28.21; # UTC | |
4 | ||
5 | # This originates from X11R5 (mit/util/scripts/install.sh), which was | |
6 | # later released in X11R6 (xc/config/util/install.sh) with the | |
7 | # following copyright and license. | |
8 | # | |
9 | # Copyright (C) 1994 X Consortium | |
10 | # | |
11 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
12 | # of this software and associated documentation files (the "Software"), to | |
13 | # deal in the Software without restriction, including without limitation the | |
14 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
15 | # sell copies of the Software, and to permit persons to whom the Software is | |
16 | # furnished to do so, subject to the following conditions: | |
17 | # | |
18 | # The above copyright notice and this permission notice shall be included in | |
19 | # all copies or substantial portions of the Software. | |
20 | # | |
21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
24 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |
25 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- | |
26 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
27 | # | |
28 | # Except as contained in this notice, the name of the X Consortium shall not | |
29 | # be used in advertising or otherwise to promote the sale, use or other deal- | |
30 | # ings in this Software without prior written authorization from the X Consor- | |
31 | # tium. | |
32 | # | |
33 | # | |
34 | # FSF changes to this file are in the public domain. | |
20 | 35 | # |
21 | 36 | # Calling this script install-sh is preferred over install.sh, to prevent |
22 | 37 | # `make' implicit rules from creating a file called install from it |
25 | 40 | # This script is compatible with the BSD install script, but was written |
26 | 41 | # from scratch. |
27 | 42 | |
43 | nl=' | |
44 | ' | |
45 | IFS=" "" $nl" | |
46 | ||
28 | 47 | # set DOITPROG to echo to test this script |
29 | 48 | |
30 | 49 | # Don't use :- since 4.3BSD and earlier shells don't like it. |
31 | doit="${DOITPROG-}" | |
32 | ||
33 | ||
34 | # put in absolute paths if you don't have them in your path; or use env. vars. | |
35 | ||
36 | awkprog="${AWKPROG-awk}" | |
37 | mvprog="${MVPROG-mv}" | |
38 | cpprog="${CPPROG-cp}" | |
39 | chmodprog="${CHMODPROG-chmod}" | |
40 | chownprog="${CHOWNPROG-chown}" | |
41 | chgrpprog="${CHGRPPROG-chgrp}" | |
42 | stripprog="${STRIPPROG-strip}" | |
43 | rmprog="${RMPROG-rm}" | |
44 | mkdirprog="${MKDIRPROG-mkdir}" | |
45 | ||
46 | instcmd="$cpprog" | |
47 | pathcompchmodcmd="$chmodprog 755" | |
48 | chmodcmd="$chmodprog 755" | |
49 | chowncmd="" | |
50 | chgrpcmd="" | |
51 | stripcmd="" | |
52 | stripflags="" | |
50 | doit=${DOITPROG-} | |
51 | if test -z "$doit"; then | |
52 | doit_exec=exec | |
53 | else | |
54 | doit_exec=$doit | |
55 | fi | |
56 | ||
57 | # Put in absolute file names if you don't have them in your path; | |
58 | # or use environment vars. | |
59 | ||
60 | chgrpprog=${CHGRPPROG-chgrp} | |
61 | chmodprog=${CHMODPROG-chmod} | |
62 | chownprog=${CHOWNPROG-chown} | |
63 | cmpprog=${CMPPROG-cmp} | |
64 | cpprog=${CPPROG-cp} | |
65 | mkdirprog=${MKDIRPROG-mkdir} | |
66 | mvprog=${MVPROG-mv} | |
67 | rmprog=${RMPROG-rm} | |
68 | stripprog=${STRIPPROG-strip} | |
69 | ||
70 | posix_glob='?' | |
71 | initialize_posix_glob=' | |
72 | test "$posix_glob" != "?" || { | |
73 | if (set -f) 2>/dev/null; then | |
74 | posix_glob= | |
75 | else | |
76 | posix_glob=: | |
77 | fi | |
78 | } | |
79 | ' | |
80 | ||
81 | posix_mkdir= | |
82 | ||
83 | # Desired mode of installed file. | |
84 | mode=0755 | |
85 | ||
86 | chgrpcmd= | |
87 | chmodcmd=$chmodprog | |
88 | chowncmd= | |
89 | mvcmd=$mvprog | |
53 | 90 | rmcmd="$rmprog -f" |
54 | mvcmd="$mvprog" | |
55 | src="" | |
56 | msrc="" | |
57 | dst="" | |
58 | dir_arg="" | |
59 | suffix="" | |
60 | suffixfmt="" | |
61 | ||
62 | while [ x"$1" != x ]; do | |
63 | case $1 in | |
64 | -b) suffix=".old" | |
65 | shift | |
66 | continue;; | |
67 | ||
68 | -B) suffixfmt="$2" | |
69 | shift | |
70 | shift | |
71 | continue;; | |
72 | ||
73 | -c) instcmd="$cpprog" | |
74 | shift | |
75 | continue;; | |
76 | ||
77 | -d) dir_arg=true | |
78 | shift | |
79 | continue;; | |
80 | ||
81 | -m) chmodcmd="$chmodprog $2" | |
82 | shift | |
83 | shift | |
84 | continue;; | |
85 | ||
86 | -o) chowncmd="$chownprog $2" | |
87 | shift | |
88 | shift | |
89 | continue;; | |
90 | ||
91 | -g) chgrpcmd="$chgrpprog $2" | |
92 | shift | |
93 | shift | |
94 | continue;; | |
95 | ||
96 | -s) stripcmd="$stripprog" | |
97 | shift | |
98 | continue;; | |
99 | ||
100 | -S) stripcmd="$stripprog" | |
101 | stripflags="-S $2 $stripflags" | |
102 | shift | |
103 | shift | |
104 | continue;; | |
105 | ||
106 | *) if [ x"$msrc" = x ] | |
91 | stripcmd= | |
92 | ||
93 | src= | |
94 | dst= | |
95 | dir_arg= | |
96 | dst_arg= | |
97 | ||
98 | copy_on_change=false | |
99 | no_target_directory= | |
100 | ||
101 | usage="\ | |
102 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | |
103 | or: $0 [OPTION]... SRCFILES... DIRECTORY | |
104 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... | |
105 | or: $0 [OPTION]... -d DIRECTORIES... | |
106 | ||
107 | In the 1st form, copy SRCFILE to DSTFILE. | |
108 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | |
109 | In the 4th, create DIRECTORIES. | |
110 | ||
111 | Options: | |
112 | --help display this help and exit. | |
113 | --version display version info and exit. | |
114 | ||
115 | -c (ignored) | |
116 | -C install only if different (preserve the last data modification time) | |
117 | -d create directories instead of installing files. | |
118 | -g GROUP $chgrpprog installed files to GROUP. | |
119 | -m MODE $chmodprog installed files to MODE. | |
120 | -o USER $chownprog installed files to USER. | |
121 | -s $stripprog installed files. | |
122 | -t DIRECTORY install into DIRECTORY. | |
123 | -T report an error if DSTFILE is a directory. | |
124 | ||
125 | Environment variables override the default commands: | |
126 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG | |
127 | RMPROG STRIPPROG | |
128 | " | |
129 | ||
130 | while test $# -ne 0; do | |
131 | case $1 in | |
132 | -c) ;; | |
133 | ||
134 | -C) copy_on_change=true;; | |
135 | ||
136 | -d) dir_arg=true;; | |
137 | ||
138 | -g) chgrpcmd="$chgrpprog $2" | |
139 | shift;; | |
140 | ||
141 | --help) echo "$usage"; exit $?;; | |
142 | ||
143 | -m) mode=$2 | |
144 | case $mode in | |
145 | *' '* | *' '* | *' | |
146 | '* | *'*'* | *'?'* | *'['*) | |
147 | echo "$0: invalid mode: $mode" >&2 | |
148 | exit 1;; | |
149 | esac | |
150 | shift;; | |
151 | ||
152 | -o) chowncmd="$chownprog $2" | |
153 | shift;; | |
154 | ||
155 | -s) stripcmd=$stripprog;; | |
156 | ||
157 | -t) dst_arg=$2 | |
158 | shift;; | |
159 | ||
160 | -T) no_target_directory=true;; | |
161 | ||
162 | --version) echo "$0 $scriptversion"; exit $?;; | |
163 | ||
164 | --) shift | |
165 | break;; | |
166 | ||
167 | -*) echo "$0: invalid option: $1" >&2 | |
168 | exit 1;; | |
169 | ||
170 | *) break;; | |
171 | esac | |
172 | shift | |
173 | done | |
174 | ||
175 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then | |
176 | # When -d is used, all remaining arguments are directories to create. | |
177 | # When -t is used, the destination is already specified. | |
178 | # Otherwise, the last argument is the destination. Remove it from $@. | |
179 | for arg | |
180 | do | |
181 | if test -n "$dst_arg"; then | |
182 | # $@ is not empty: it contains at least $arg. | |
183 | set fnord "$@" "$dst_arg" | |
184 | shift # fnord | |
185 | fi | |
186 | shift # arg | |
187 | dst_arg=$arg | |
188 | done | |
189 | fi | |
190 | ||
191 | if test $# -eq 0; then | |
192 | if test -z "$dir_arg"; then | |
193 | echo "$0: no input file specified." >&2 | |
194 | exit 1 | |
195 | fi | |
196 | # It's OK to call `install-sh -d' without argument. | |
197 | # This can happen when creating conditional directories. | |
198 | exit 0 | |
199 | fi | |
200 | ||
201 | if test -z "$dir_arg"; then | |
202 | trap '(exit $?); exit' 1 2 13 15 | |
203 | ||
204 | # Set umask so as not to create temps with too-generous modes. | |
205 | # However, 'strip' requires both read and write access to temps. | |
206 | case $mode in | |
207 | # Optimize common cases. | |
208 | *644) cp_umask=133;; | |
209 | *755) cp_umask=22;; | |
210 | ||
211 | *[0-7]) | |
212 | if test -z "$stripcmd"; then | |
213 | u_plus_rw= | |
214 | else | |
215 | u_plus_rw='% 200' | |
216 | fi | |
217 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; | |
218 | *) | |
219 | if test -z "$stripcmd"; then | |
220 | u_plus_rw= | |
221 | else | |
222 | u_plus_rw=,u+rw | |
223 | fi | |
224 | cp_umask=$mode$u_plus_rw;; | |
225 | esac | |
226 | fi | |
227 | ||
228 | for src | |
229 | do | |
230 | # Protect names starting with `-'. | |
231 | case $src in | |
232 | -*) src=./$src;; | |
233 | esac | |
234 | ||
235 | if test -n "$dir_arg"; then | |
236 | dst=$src | |
237 | dstdir=$dst | |
238 | test -d "$dstdir" | |
239 | dstdir_status=$? | |
240 | else | |
241 | ||
242 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command | |
243 | # might cause directories to be created, which would be especially bad | |
244 | # if $src (and thus $dsttmp) contains '*'. | |
245 | if test ! -f "$src" && test ! -d "$src"; then | |
246 | echo "$0: $src does not exist." >&2 | |
247 | exit 1 | |
248 | fi | |
249 | ||
250 | if test -z "$dst_arg"; then | |
251 | echo "$0: no destination specified." >&2 | |
252 | exit 1 | |
253 | fi | |
254 | ||
255 | dst=$dst_arg | |
256 | # Protect names starting with `-'. | |
257 | case $dst in | |
258 | -*) dst=./$dst;; | |
259 | esac | |
260 | ||
261 | # If destination is a directory, append the input filename; won't work | |
262 | # if double slashes aren't ignored. | |
263 | if test -d "$dst"; then | |
264 | if test -n "$no_target_directory"; then | |
265 | echo "$0: $dst_arg: Is a directory" >&2 | |
266 | exit 1 | |
267 | fi | |
268 | dstdir=$dst | |
269 | dst=$dstdir/`basename "$src"` | |
270 | dstdir_status=0 | |
271 | else | |
272 | # Prefer dirname, but fall back on a substitute if dirname fails. | |
273 | dstdir=` | |
274 | (dirname "$dst") 2>/dev/null || | |
275 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | |
276 | X"$dst" : 'X\(//\)[^/]' \| \ | |
277 | X"$dst" : 'X\(//\)$' \| \ | |
278 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || | |
279 | echo X"$dst" | | |
280 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ | |
281 | s//\1/ | |
282 | q | |
283 | } | |
284 | /^X\(\/\/\)[^/].*/{ | |
285 | s//\1/ | |
286 | q | |
287 | } | |
288 | /^X\(\/\/\)$/{ | |
289 | s//\1/ | |
290 | q | |
291 | } | |
292 | /^X\(\/\).*/{ | |
293 | s//\1/ | |
294 | q | |
295 | } | |
296 | s/.*/./; q' | |
297 | ` | |
298 | ||
299 | test -d "$dstdir" | |
300 | dstdir_status=$? | |
301 | fi | |
302 | fi | |
303 | ||
304 | obsolete_mkdir_used=false | |
305 | ||
306 | if test $dstdir_status != 0; then | |
307 | case $posix_mkdir in | |
308 | '') | |
309 | # Create intermediate dirs using mode 755 as modified by the umask. | |
310 | # This is like FreeBSD 'install' as of 1997-10-28. | |
311 | umask=`umask` | |
312 | case $stripcmd.$umask in | |
313 | # Optimize common cases. | |
314 | *[2367][2367]) mkdir_umask=$umask;; | |
315 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; | |
316 | ||
317 | *[0-7]) | |
318 | mkdir_umask=`expr $umask + 22 \ | |
319 | - $umask % 100 % 40 + $umask % 20 \ | |
320 | - $umask % 10 % 4 + $umask % 2 | |
321 | `;; | |
322 | *) mkdir_umask=$umask,go-w;; | |
323 | esac | |
324 | ||
325 | # With -d, create the new directory with the user-specified mode. | |
326 | # Otherwise, rely on $mkdir_umask. | |
327 | if test -n "$dir_arg"; then | |
328 | mkdir_mode=-m$mode | |
329 | else | |
330 | mkdir_mode= | |
331 | fi | |
332 | ||
333 | posix_mkdir=false | |
334 | case $umask in | |
335 | *[123567][0-7][0-7]) | |
336 | # POSIX mkdir -p sets u+wx bits regardless of umask, which | |
337 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. | |
338 | ;; | |
339 | *) | |
340 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ | |
341 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 | |
342 | ||
343 | if (umask $mkdir_umask && | |
344 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 | |
107 | 345 | then |
108 | msrc="$dst" | |
346 | if test -z "$dir_arg" || { | |
347 | # Check for POSIX incompatibilities with -m. | |
348 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | |
349 | # other-writeable bit of parent directory when it shouldn't. | |
350 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | |
351 | ls_ld_tmpdir=`ls -ld "$tmpdir"` | |
352 | case $ls_ld_tmpdir in | |
353 | d????-?r-*) different_mode=700;; | |
354 | d????-?--*) different_mode=755;; | |
355 | *) false;; | |
356 | esac && | |
357 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { | |
358 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` | |
359 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" | |
360 | } | |
361 | } | |
362 | then posix_mkdir=: | |
363 | fi | |
364 | rmdir "$tmpdir/d" "$tmpdir" | |
109 | 365 | else |
110 | msrc="$msrc $dst" | |
366 | # Remove any dirs left behind by ancient mkdir implementations. | |
367 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null | |
111 | 368 | fi |
112 | src="$dst" | |
113 | dst="$1" | |
114 | shift | |
115 | continue;; | |
369 | trap '' 0;; | |
370 | esac;; | |
116 | 371 | esac |
372 | ||
373 | if | |
374 | $posix_mkdir && ( | |
375 | umask $mkdir_umask && | |
376 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" | |
377 | ) | |
378 | then : | |
379 | else | |
380 | ||
381 | # The umask is ridiculous, or mkdir does not conform to POSIX, | |
382 | # or it failed possibly due to a race condition. Create the | |
383 | # directory the slow way, step by step, checking for races as we go. | |
384 | ||
385 | case $dstdir in | |
386 | /*) prefix='/';; | |
387 | -*) prefix='./';; | |
388 | *) prefix='';; | |
389 | esac | |
390 | ||
391 | eval "$initialize_posix_glob" | |
392 | ||
393 | oIFS=$IFS | |
394 | IFS=/ | |
395 | $posix_glob set -f | |
396 | set fnord $dstdir | |
397 | shift | |
398 | $posix_glob set +f | |
399 | IFS=$oIFS | |
400 | ||
401 | prefixes= | |
402 | ||
403 | for d | |
404 | do | |
405 | test -z "$d" && continue | |
406 | ||
407 | prefix=$prefix$d | |
408 | if test -d "$prefix"; then | |
409 | prefixes= | |
410 | else | |
411 | if $posix_mkdir; then | |
412 | (umask=$mkdir_umask && | |
413 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break | |
414 | # Don't fail if two instances are running concurrently. | |
415 | test -d "$prefix" || exit 1 | |
416 | else | |
417 | case $prefix in | |
418 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; | |
419 | *) qprefix=$prefix;; | |
420 | esac | |
421 | prefixes="$prefixes '$qprefix'" | |
422 | fi | |
423 | fi | |
424 | prefix=$prefix/ | |
425 | done | |
426 | ||
427 | if test -n "$prefixes"; then | |
428 | # Don't fail if two instances are running concurrently. | |
429 | (umask $mkdir_umask && | |
430 | eval "\$doit_exec \$mkdirprog $prefixes") || | |
431 | test -d "$dstdir" || exit 1 | |
432 | obsolete_mkdir_used=true | |
433 | fi | |
434 | fi | |
435 | fi | |
436 | ||
437 | if test -n "$dir_arg"; then | |
438 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && | |
439 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && | |
440 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || | |
441 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 | |
442 | else | |
443 | ||
444 | # Make a couple of temp file names in the proper directory. | |
445 | dsttmp=$dstdir/_inst.$$_ | |
446 | rmtmp=$dstdir/_rm.$$_ | |
447 | ||
448 | # Trap to clean up those temp files at exit. | |
449 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | |
450 | ||
451 | # Copy the file name to the temp name. | |
452 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && | |
453 | ||
454 | # and set any options; do chmod last to preserve setuid bits. | |
455 | # | |
456 | # If any of these fail, we abort the whole thing. If we want to | |
457 | # ignore errors from any of these, just make sure not to ignore | |
458 | # errors from the above "$doit $cpprog $src $dsttmp" command. | |
459 | # | |
460 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && | |
461 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && | |
462 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && | |
463 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | |
464 | ||
465 | # If -C, don't bother to copy if it wouldn't change the file. | |
466 | if $copy_on_change && | |
467 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && | |
468 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && | |
469 | ||
470 | eval "$initialize_posix_glob" && | |
471 | $posix_glob set -f && | |
472 | set X $old && old=:$2:$4:$5:$6 && | |
473 | set X $new && new=:$2:$4:$5:$6 && | |
474 | $posix_glob set +f && | |
475 | ||
476 | test "$old" = "$new" && | |
477 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 | |
478 | then | |
479 | rm -f "$dsttmp" | |
480 | else | |
481 | # Rename the file to the real destination. | |
482 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || | |
483 | ||
484 | # The rename failed, perhaps because mv can't rename something else | |
485 | # to itself, or perhaps because mv is so ancient that it does not | |
486 | # support -f. | |
487 | { | |
488 | # Now remove or move aside any old file at destination location. | |
489 | # We try this two ways since rm can't unlink itself on some | |
490 | # systems and the destination file might be busy for other | |
491 | # reasons. In this case, the final cleanup might fail but the new | |
492 | # file should still install successfully. | |
493 | { | |
494 | test ! -f "$dst" || | |
495 | $doit $rmcmd -f "$dst" 2>/dev/null || | |
496 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && | |
497 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } | |
498 | } || | |
499 | { echo "$0: cannot unlink or rename $dst" >&2 | |
500 | (exit 1); exit 1 | |
501 | } | |
502 | } && | |
503 | ||
504 | # Now rename the file to the real destination. | |
505 | $doit $mvcmd "$dsttmp" "$dst" | |
506 | } | |
507 | fi || exit 1 | |
508 | ||
509 | trap '' 0 | |
510 | fi | |
117 | 511 | done |
118 | 512 | |
119 | if [ x"$dir_arg" = x ] | |
120 | then | |
121 | dstisfile="" | |
122 | if [ ! -d "$dst" ] | |
123 | then | |
124 | if [ x"$msrc" = x"$src" ] | |
125 | then | |
126 | dstisfile=true | |
127 | else | |
128 | echo "install: destination is not a directory" | |
129 | exit 1 | |
130 | fi | |
131 | fi | |
132 | else | |
133 | msrc="$msrc $dst" | |
134 | fi | |
135 | ||
136 | if [ x"$msrc" = x ] | |
137 | then | |
138 | echo "install: no destination specified" | |
139 | exit 1 | |
140 | fi | |
141 | ||
142 | for srcarg in $msrc; do | |
143 | ||
144 | if [ x"$dir_arg" != x ]; then | |
145 | ||
146 | dstarg="$srcarg" | |
147 | else | |
148 | dstarg="$dst" | |
149 | ||
150 | # Waiting for this to be detected by the "$instcmd $srcarg $dsttmp" command | |
151 | # might cause directories to be created, which would be especially bad | |
152 | # if $src (and thus $dsttmp) contains '*'. | |
153 | ||
154 | if [ -f "$srcarg" ] | |
155 | then | |
156 | doinst="$instcmd" | |
157 | elif [ -d "$srcarg" ] | |
158 | then | |
159 | echo "install: $srcarg: not a regular file" | |
160 | exit 1 | |
161 | elif [ "$srcarg" = "/dev/null" ] | |
162 | then | |
163 | doinst="$cpprog" | |
164 | else | |
165 | echo "install: $srcarg does not exist" | |
166 | exit 1 | |
167 | fi | |
168 | ||
169 | # If destination is a directory, append the input filename; if your system | |
170 | # does not like double slashes in filenames, you may need to add some logic | |
171 | ||
172 | if [ -d "$dstarg" ] | |
173 | then | |
174 | dstarg="$dstarg"/`basename "$srcarg"` | |
175 | fi | |
176 | fi | |
177 | ||
178 | ## this sed command emulates the dirname command | |
179 | dstdir=`echo "$dstarg" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | |
180 | ||
181 | # Make sure that the destination directory exists. | |
182 | # this part is taken from Noah Friedman's mkinstalldirs script | |
183 | ||
184 | # Skip lots of stat calls in the usual case. | |
185 | if [ ! -d "$dstdir" ]; then | |
186 | defaultIFS=' | |
187 | ' | |
188 | IFS="${IFS-${defaultIFS}}" | |
189 | ||
190 | oIFS="${IFS}" | |
191 | # Some sh's can't handle IFS=/ for some reason. | |
192 | IFS='%' | |
193 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` | |
194 | IFS="${oIFS}" | |
195 | ||
196 | pathcomp='' | |
197 | ||
198 | while [ $# -ne 0 ] ; do | |
199 | pathcomp="${pathcomp}${1}" | |
200 | shift | |
201 | ||
202 | if [ ! -d "${pathcomp}" ] ; | |
203 | then | |
204 | $doit $mkdirprog "${pathcomp}" | |
205 | if [ x"$chowncmd" != x ]; then $doit $chowncmd "${pathcomp}"; else true ; fi && | |
206 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "${pathcomp}"; else true ; fi && | |
207 | if [ x"$pathcompchmodcmd" != x ]; then $doit $pathcompchmodcmd "${pathcomp}"; else true ; fi | |
208 | ||
209 | else | |
210 | true | |
211 | fi | |
212 | ||
213 | pathcomp="${pathcomp}/" | |
214 | done | |
215 | fi | |
216 | ||
217 | if [ x"$dir_arg" != x ] | |
218 | then | |
219 | if [ -d "$dstarg" ]; then | |
220 | true | |
221 | else | |
222 | $doit $mkdirprog "$dstarg" && | |
223 | ||
224 | if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dstarg"; else true ; fi && | |
225 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dstarg"; else true ; fi && | |
226 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dstarg"; else true ; fi | |
227 | fi | |
228 | else | |
229 | ||
230 | if [ x"$dstisfile" = x ] | |
231 | then | |
232 | file=$srcarg | |
233 | else | |
234 | file=$dst | |
235 | fi | |
236 | ||
237 | dstfile=`basename "$file"` | |
238 | dstfinal="$dstdir/$dstfile" | |
239 | ||
240 | # Make a temp file name in the proper directory. | |
241 | ||
242 | dsttmp=$dstdir/#inst.$$# | |
243 | ||
244 | # Make a backup file name in the proper directory. | |
245 | case x$suffixfmt in | |
246 | *%*) suffix=`echo x | | |
247 | $awkprog -v bname="$dstfinal" -v fmt="$suffixfmt" ' | |
248 | { cnt = 0; | |
249 | do { | |
250 | sfx = sprintf(fmt, cnt++); | |
251 | name = bname sfx; | |
252 | } while (system("test -f " name) == 0); | |
253 | print sfx; }' -`;; | |
254 | x) ;; | |
255 | *) suffix="$suffixfmt";; | |
256 | esac | |
257 | dstbackup="$dstfinal$suffix" | |
258 | ||
259 | # Move or copy the file name to the temp name | |
260 | ||
261 | $doit $doinst $srcarg "$dsttmp" && | |
262 | ||
263 | trap "rm -f ${dsttmp}" 0 && | |
264 | ||
265 | # and set any options; do chmod last to preserve setuid bits | |
266 | ||
267 | # If any of these fail, we abort the whole thing. If we want to | |
268 | # ignore errors from any of these, just make sure not to ignore | |
269 | # errors from the above "$doit $instcmd $src $dsttmp" command. | |
270 | ||
271 | if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else true;fi && | |
272 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else true;fi && | |
273 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripflags "$dsttmp"; else true;fi && | |
274 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else true;fi && | |
275 | ||
276 | # Now rename the file to the real destination. | |
277 | ||
278 | if [ x"$suffix" != x ] && [ -f "$dstfinal" ] | |
279 | then | |
280 | $doit $mvcmd "$dstfinal" "$dstbackup" | |
281 | else | |
282 | $doit $rmcmd -f "$dstfinal" | |
283 | fi && | |
284 | $doit $mvcmd "$dsttmp" "$dstfinal" | |
285 | fi | |
286 | ||
287 | done && | |
288 | ||
289 | ||
290 | exit 0 | |
513 | # Local variables: | |
514 | # eval: (add-hook 'write-file-hooks 'time-stamp) | |
515 | # time-stamp-start: "scriptversion=" | |
516 | # time-stamp-format: "%:y-%02m-%02d.%02H" | |
517 | # time-stamp-time-zone: "UTC" | |
518 | # time-stamp-end: "; # UTC" | |
519 | # End: |
6 | 6 | * \brief This namespace contains a framework for container classes, which |
7 | 7 | * members are instances of object::Object. |
8 | 8 | * |
9 | * A common problem in languanges without garbage collection is, where the | |
9 | * A common problem in languages without garbage collection is, where the | |
10 | 10 | * children belong to, and so, who is responsible to delete them (instantiation |
11 | 11 | * is always done by the caller). This information is here told to the |
12 | 12 | * collections, each container has a constructor with the parameter |
40 | 40 | inline int roundInt(double d) |
41 | 41 | { |
42 | 42 | return (int) ((d > 0) ? (d + 0.5) : (d - 0.5)); |
43 | } | |
44 | ||
45 | inline int AsciiTolower(char c) | |
46 | { | |
47 | return ((c >= 'A' && c <= 'Z') ? c + 0x20 : c); | |
48 | } | |
49 | ||
50 | inline int AsciiToupper(char c) | |
51 | { | |
52 | return ((c >= 'a' && c <= 'z') ? c - 0x20 : c); | |
53 | } | |
54 | ||
55 | inline int AsciiStrcasecmp(const char *s1, const char *s2) | |
56 | { | |
57 | int ret = 0; | |
58 | ||
59 | while ((*s1 || *s2) && !(ret = AsciiTolower(*s1) - AsciiTolower(*s2))) { | |
60 | s1++; | |
61 | s2++; | |
62 | } | |
63 | return ret; | |
43 | 64 | } |
44 | 65 | |
45 | 66 | /** |
155 | 155 | " <td><a href='http://www.gutenberg.org/'>P. Gutenberg</a>\n" |
156 | 156 | " <tr>\n" |
157 | 157 | " <td> \n" |
158 | " <td><a href='http://freshmeat.net/'>FreshMeat</a>\n" | |
158 | " <td><a href='http://freecode.com/'>Freecode</a>\n" | |
159 | 159 | " <tr>\n" |
160 | 160 | " <td> \n" |
161 | 161 | " <td><a href='http://www.gnu.org/gnu/thegnuproject.html'>GNU\n" |
210 | 210 | " <td bgcolor='#FFFFFF'>\n" |
211 | 211 | " <table border='0' cellspacing='0' cellpadding='5'><tr><td>\n" |
212 | 212 | " <p>\n" |
213 | " Dillo is Free Software under the terms of version 3 of the\n" | |
214 | " <a href='http://www.gnu.org/licenses/gpl.html'>GPL</a>.\n" | |
213 | " The Dillo web browser is Free Software under the terms of version 3 of\n" | |
214 | " the <a href='http://www.gnu.org/licenses/gpl.html'>GPL</a>.\n" | |
215 | 215 | " This means you have four basic freedoms:\n" |
216 | 216 | " <ul>\n" |
217 | 217 | " <li>Freedom to use the program any way you see fit.\n" |
233 | 233 | "<tr>\n" |
234 | 234 | " <td bgcolor='#CCCCCC'>\n" |
235 | 235 | " <h4>Release overview</h4>\n" |
236 | " September 21, 2011\n" | |
236 | " December 05, 2011\n" | |
237 | 237 | "<tr>\n" |
238 | 238 | " <td bgcolor='#FFFFFF'>\n" |
239 | 239 | " <table border='0' cellspacing='0' cellpadding='5'>\n" |
240 | 240 | " <tr>\n" |
241 | 241 | " <td>\n" |
242 | 242 | "<p>\n" |
243 | "The dillo-3.0.1 release brings improved privacy and some new options for\n" | |
244 | "configuring the user interface.\n" | |
245 | "<p>\n" | |
246 | "Dillo3 is a port to FLTK-1.3, which is big news because FLTK-1.3.0 was\n" | |
247 | "<a href='http://fltk.org/articles.php?L1086'>released</a>\n" | |
248 | "in June, clearing the way for Dillo to return to those distributions\n" | |
249 | "which had excluded Dillo2 due to FLTK2 never being officially released.\n" | |
250 | "<p>\n" | |
251 | "After this release, the core team will focus on implementing the CSS\n" | |
243 | "dillo-3.0.2 brings you some new bits and pieces, as listed below :)\n" | |
244 | "<p>\n" | |
245 | "After this release, the core team plans to focus on implementing the CSS\n" | |
252 | 246 | "feature of floating elements. This will <em>greatly</em> improve dillo's\n" |
253 | 247 | "web page rendering since many sites have adopted floats instead of tables.\n" |
254 | 248 | "<p>\n" |
255 | "The new dillo3 has shown excellent stability in our experience.\n" | |
249 | "Dillo3 uses the FLTK GUI toolkit's 1.3.x series. In June, fltk-1.3.0 was\n" | |
250 | "<a href='http://fltk.org/articles.php?L1086'>released</a>,\n" | |
251 | "clearing the way for Dillo to return to those distributions\n" | |
252 | "which had excluded Dillo2 due to FLTK2 never being officially released.\n" | |
253 | "<p>\n" | |
256 | 254 | "The core team welcomes developers willing to join our workforce.\n" |
257 | 255 | "<p>\n" |
258 | 256 | " </table>\n" |
274 | 272 | " <table border='0' cellspacing='0' cellpadding='5'>\n" |
275 | 273 | " <tr>\n" |
276 | 274 | " <td>\n" |
277 | "dillo-3.0.1:\n" | |
278 | 275 | "<ul>\n" |
279 | "<li>Privacy -- never send cookies when making third-party requests, and\n" | |
280 | " never accept cookies in the responses to these requests.\n" | |
281 | "<li>Add preference for UI theme.\n" | |
282 | "<li>Allow key bindings for paging left/right.\n" | |
283 | "<li>Add show_quit_dialog dillorc option.\n" | |
284 | "</ul>\n" | |
285 | "dillo-3.0:\n" | |
286 | "<ul>\n" | |
287 | "<li>Ported Dillo to FLTK-1.3.\n" | |
288 | "<li>Native build on OSX.\n" | |
289 | "<li>Default binding for close-all changed from Alt-q to Ctrl-q.\n" | |
290 | "<li>Default binding for close-tab changed from Ctrl-q to Ctrl-w.\n" | |
291 | "<li>Default binding for left-tab changed to Shift-Ctrl-Tab.\n" | |
292 | "<li>Rewrote the User Interface: much simpler design and event handling.\n" | |
293 | "<li>Added on-the-fly panel resize (tiny/small/medium and normal/small icons).\n" | |
294 | "<li>'hide-panels' key action now hides the findbar if present,\n" | |
295 | " and toggles display of the control panels otherwise.\n" | |
296 | "<li>Allow multiple search engines to be set in dillorc, with a menu\n" | |
297 | " in the web search dialog to select between them.\n" | |
298 | "<li>Added an optional label to dillorc's search_url.\n" | |
299 | " Format: \"[<label> ]<url>\"\n" | |
300 | "<li>Add right_click_closes_tab preference (default is middle click).\n" | |
301 | "<li>Allow binding to non-ASCII keys and multimedia keys.\n" | |
302 | "<li>Avoid a certificate dialog storm on some HTTPS sites (BUG#868).\n" | |
303 | "<li>Enable line wrapping for <textarea>. (BUG#903)\n" | |
304 | "<li>Avoid double render after going Back or Forward\n" | |
305 | " (it takes half the time now!)\n" | |
306 | "<li>Implemented a custom tabs handler (to allow fine control of it).\n" | |
307 | "<li>Rewrote dw's crossing-events dispatcher (avoids redundant events).\n" | |
308 | "<li>Fixed a years old bug: stamped tooltips when scrolling with keyboard.\n" | |
309 | "<li>Fixed a border case in URL resolver: empty path + {query|fragment}\n" | |
310 | " (BUG#948)\n" | |
311 | "<li>Cancel the expected URL after offering a download (BUG#982)\n" | |
312 | "<li>Eliminated a pack of 22 compiler warnings (gcc-4.6.1 amd64)\n" | |
313 | "<li>Removed 'large' option of panel_size preference.\n" | |
314 | "<li>Removed --enable-ansi configure option.\n" | |
315 | "<li>Limit saved cookie size.\n" | |
316 | "<li>Wrap image alt text.\n" | |
317 | "<li>Added support for CSS adjacent sibling selectors.\n" | |
318 | "<li>Fix redraw loops and reenabled limit_text_width dillorc option.\n" | |
319 | "<li>Collapse parent's and first child's top margin.\n" | |
276 | "<li>Digest authentication.\n" | |
277 | "<li>Rework line breaking and fix white-space:nowrap handling.\n" | |
278 | "<li>text-transform property.\n" | |
279 | "<li>Locale-independent ASCII character case handling (fixes Turkic locales).\n" | |
280 | "<li>Bind Ctrl-{PageUp,PageDown} to tab-{previous,next}.\n" | |
320 | 281 | "</ul>\n" |
321 | 282 | " </table>\n" |
322 | 283 | "</table>\n" |
337 | 298 | "<ul>\n" |
338 | 299 | " <li> There's a\n" |
339 | 300 | " <a href='http://www.dillo.org/dillorc'>dillorc</a>\n" |
340 | " (readable config) file within the tarball; It is well-commented\n" | |
301 | " (readable config) file inside the tarball. It is well-commented\n" | |
341 | 302 | " and has plenty of options to customize dillo, so <STRONG>copy\n" |
342 | 303 | " it</STRONG> to your <STRONG>~/.dillo/</STRONG> directory, and\n" |
343 | 304 | " modify it to your taste.\n" |
344 | 305 | " <li> Documentation for developers is in the <CODE>/doc</CODE>\n" |
345 | " dir within the tarball; you can find directions on everything\n" | |
306 | " dir inside the tarball; you can find directions on everything\n" | |
346 | 307 | " else at the home page.\n" |
347 | 308 | " <li> The right mouse button brings up a context-sensitive menu\n" |
348 | 309 | " (available on pages, links, images, forms, the Back and Forward buttons,\n" |
170 | 170 | } else if (a_Web_valid(sd->web)) { |
171 | 171 | /* start connecting the socket */ |
172 | 172 | if (Http_connect_socket(sd->Info) < 0) { |
173 | ChainLink *Info = sd->Info; | |
173 | 174 | MSG_BW(sd->web, 1, "ERROR: %s", dStrerror(sd->Err)); |
174 | a_Chain_bfcb(OpAbort, sd->Info, NULL, "Both"); | |
175 | dFree(sd->Info); | |
176 | Http_socket_free(VOIDP2INT(sd->Info->LocalKey)); | |
175 | a_Chain_bfcb(OpAbort, Info, NULL, "Both"); | |
176 | Http_socket_free(VOIDP2INT(Info->LocalKey)); /* free sd */ | |
177 | dFree(Info); | |
177 | 178 | } else { |
178 | 179 | sd->connected_to = hc->host; |
179 | 180 | hc->active_connections++; |
201 | 202 | Http_connect_queued_sockets(hc); |
202 | 203 | if (hc->active_connections == 0) |
203 | 204 | Http_host_connection_remove(hc); |
204 | } | |
205 | } | |
205 | 206 | dFree(S); |
206 | 207 | } |
207 | 208 | } |
273 | 274 | Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, |
274 | 275 | bool_t use_proxy) |
275 | 276 | { |
276 | const char *auth; | |
277 | char *ptr, *cookies, *referer; | |
277 | char *ptr, *cookies, *referer, *auth; | |
278 | 278 | Dstr *query = dStr_new(""), |
279 | *full_path = dStr_new(""), | |
279 | *request_uri = dStr_new(""), | |
280 | 280 | *proxy_auth = dStr_new(""); |
281 | 281 | |
282 | 282 | if (use_proxy) { |
283 | dStr_sprintfa(full_path, "%s%s", | |
283 | dStr_sprintfa(request_uri, "%s%s", | |
284 | 284 | URL_STR(url), |
285 | 285 | (URL_PATH_(url) || URL_QUERY_(url)) ? "" : "/"); |
286 | if ((ptr = strrchr(full_path->str, '#'))) | |
287 | dStr_truncate(full_path, ptr - full_path->str); | |
286 | if ((ptr = strrchr(request_uri->str, '#'))) | |
287 | dStr_truncate(request_uri, ptr - request_uri->str); | |
288 | 288 | if (HTTP_Proxy_Auth_base64) |
289 | 289 | dStr_sprintf(proxy_auth, "Proxy-Authorization: Basic %s\r\n", |
290 | 290 | HTTP_Proxy_Auth_base64); |
291 | 291 | } else { |
292 | dStr_sprintfa(full_path, "%s%s%s%s", | |
292 | dStr_sprintfa(request_uri, "%s%s%s%s", | |
293 | 293 | URL_PATH(url), |
294 | 294 | URL_QUERY_(url) ? "?" : "", |
295 | 295 | URL_QUERY(url), |
297 | 297 | } |
298 | 298 | |
299 | 299 | cookies = a_Cookies_get_query(url, requester); |
300 | auth = a_Auth_get_auth_str(url); | |
300 | auth = a_Auth_get_auth_str(url, request_uri->str); | |
301 | 301 | referer = Http_get_referer(url); |
302 | 302 | if (URL_FLAGS(url) & URL_Post) { |
303 | 303 | Dstr *content_type = Http_make_content_type(url); |
318 | 318 | "Content-Type: %s\r\n" |
319 | 319 | "%s" /* cookies */ |
320 | 320 | "\r\n", |
321 | full_path->str, HTTP_Language_hdr, auth ? auth : "", | |
321 | request_uri->str, HTTP_Language_hdr, auth ? auth : "", | |
322 | 322 | URL_AUTHORITY(url), proxy_auth->str, referer, prefs.http_user_agent, |
323 | 323 | (long)URL_DATA(url)->len, content_type->str, |
324 | 324 | cookies); |
341 | 341 | "User-Agent: %s\r\n" |
342 | 342 | "%s" /* cookies */ |
343 | 343 | "\r\n", |
344 | full_path->str, | |
344 | request_uri->str, | |
345 | 345 | (URL_FLAGS(url) & URL_E2EQuery) ? |
346 | 346 | "Cache-Control: no-cache\r\nPragma: no-cache\r\n" : "", |
347 | 347 | HTTP_Language_hdr, auth ? auth : "", URL_AUTHORITY(url), |
349 | 349 | } |
350 | 350 | dFree(referer); |
351 | 351 | dFree(cookies); |
352 | ||
353 | dStr_free(full_path, TRUE); | |
352 | dFree(auth); | |
353 | ||
354 | dStr_free(request_uri, TRUE); | |
354 | 355 | dStr_free(proxy_auth, TRUE); |
355 | 356 | _MSG("Query: {%s}\n", dStr_printable(query, 8192)); |
356 | 357 | return query; |
478 | 479 | for (p = np; (tok = dStrsep(&p, " ")); ) { |
479 | 480 | int start = host_len - strlen(tok); |
480 | 481 | |
481 | if (start >= 0 && dStrcasecmp(host + start, tok) == 0) { | |
482 | if (start >= 0 && dStrAsciiCasecmp(host + start, tok) == 0) { | |
482 | 483 | /* no_proxy token is suffix of host string */ |
483 | 484 | ret = 0; |
484 | 485 | break; |
717 | 718 | for (i = 0; i < dList_length(host_connections); i++) { |
718 | 719 | hc = (HostConnection_t*) dList_nth_data(host_connections, i); |
719 | 720 | |
720 | if (dStrcasecmp(host, hc->host) == 0) | |
721 | if (dStrAsciiCasecmp(host, hc->host) == 0) | |
721 | 722 | return hc; |
722 | 723 | } |
723 | 724 |
66 | 66 | |
67 | 67 | if (Size) { |
68 | 68 | for ( i = 0; i < MimeMinItemsSize; ++i ) |
69 | if (dStrncasecmp(Key, MimeMinItems[i].Name, Size) == 0) | |
69 | if (dStrnAsciiCasecmp(Key, MimeMinItems[i].Name, Size) == 0) | |
70 | 70 | return MimeMinItems[i].Data; |
71 | 71 | } |
72 | 72 | return NULL; |
82 | 82 | |
83 | 83 | if (Size) { |
84 | 84 | for ( i = 0; i < MimeMajItemsSize; ++i ) |
85 | if (dStrncasecmp(Key, MimeMajItems[i].Name, Size) == 0) | |
85 | if (dStrnAsciiCasecmp(Key, MimeMajItems[i].Name, Size) == 0) | |
86 | 86 | return MimeMajItems[i].Data; |
87 | 87 | } |
88 | 88 | return NULL; |
34 | 34 | cookies.h \ |
35 | 35 | auth.c \ |
36 | 36 | auth.h \ |
37 | md5.c \ | |
38 | md5.h \ | |
39 | digest.c \ | |
40 | digest.h \ | |
37 | 41 | colors.c \ |
38 | 42 | colors.h \ |
39 | 43 | binaryconst.h \ |
50 | 50 | PROGRAMS = $(bin_PROGRAMS) |
51 | 51 | am_dillo_OBJECTS = dillo.$(OBJEXT) paths.$(OBJEXT) ui.$(OBJEXT) \ |
52 | 52 | uicmd.$(OBJEXT) bw.$(OBJEXT) cookies.$(OBJEXT) auth.$(OBJEXT) \ |
53 | colors.$(OBJEXT) misc.$(OBJEXT) history.$(OBJEXT) \ | |
54 | prefs.$(OBJEXT) prefsparser.$(OBJEXT) keys.$(OBJEXT) \ | |
55 | url.$(OBJEXT) bitvec.$(OBJEXT) klist.$(OBJEXT) chain.$(OBJEXT) \ | |
56 | utf8.$(OBJEXT) timeout.$(OBJEXT) dialog.$(OBJEXT) \ | |
57 | web.$(OBJEXT) nav.$(OBJEXT) cache.$(OBJEXT) decode.$(OBJEXT) \ | |
58 | dicache.$(OBJEXT) capi.$(OBJEXT) css.$(OBJEXT) \ | |
59 | cssparser.$(OBJEXT) styleengine.$(OBJEXT) plain.$(OBJEXT) \ | |
60 | html.$(OBJEXT) form.$(OBJEXT) table.$(OBJEXT) \ | |
53 | md5.$(OBJEXT) digest.$(OBJEXT) colors.$(OBJEXT) misc.$(OBJEXT) \ | |
54 | history.$(OBJEXT) prefs.$(OBJEXT) prefsparser.$(OBJEXT) \ | |
55 | keys.$(OBJEXT) url.$(OBJEXT) bitvec.$(OBJEXT) klist.$(OBJEXT) \ | |
56 | chain.$(OBJEXT) utf8.$(OBJEXT) timeout.$(OBJEXT) \ | |
57 | dialog.$(OBJEXT) web.$(OBJEXT) nav.$(OBJEXT) cache.$(OBJEXT) \ | |
58 | decode.$(OBJEXT) dicache.$(OBJEXT) capi.$(OBJEXT) \ | |
59 | css.$(OBJEXT) cssparser.$(OBJEXT) styleengine.$(OBJEXT) \ | |
60 | plain.$(OBJEXT) html.$(OBJEXT) form.$(OBJEXT) table.$(OBJEXT) \ | |
61 | 61 | bookmark.$(OBJEXT) dns.$(OBJEXT) gif.$(OBJEXT) jpeg.$(OBJEXT) \ |
62 | 62 | png.$(OBJEXT) imgbuf.$(OBJEXT) image.$(OBJEXT) menu.$(OBJEXT) \ |
63 | 63 | dpiapi.$(OBJEXT) findbar.$(OBJEXT) xembed.$(OBJEXT) |
295 | 295 | cookies.h \ |
296 | 296 | auth.c \ |
297 | 297 | auth.h \ |
298 | md5.c \ | |
299 | md5.h \ | |
300 | digest.c \ | |
301 | digest.h \ | |
298 | 302 | colors.c \ |
299 | 303 | colors.h \ |
300 | 304 | binaryconst.h \ |
474 | 478 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode.Po@am__quote@ |
475 | 479 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dialog.Po@am__quote@ |
476 | 480 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dicache.Po@am__quote@ |
481 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/digest.Po@am__quote@ | |
477 | 482 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dillo.Po@am__quote@ |
478 | 483 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Po@am__quote@ |
479 | 484 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dpiapi.Po@am__quote@ |
487 | 492 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jpeg.Po@am__quote@ |
488 | 493 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Po@am__quote@ |
489 | 494 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/klist.Po@am__quote@ |
495 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ | |
490 | 496 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/menu.Po@am__quote@ |
491 | 497 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@ |
492 | 498 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nav.Po@am__quote@ |
1 | 1 | * File: auth.c |
2 | 2 | * |
3 | 3 | * Copyright 2008 Jeremy Henty <onepoint@starurchin.org> |
4 | * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de> | |
4 | 5 | * |
5 | 6 | * This program is free software; you can redistribute it and/or modify |
6 | 7 | * it under the terms of the GNU General Public License as published by |
19 | 20 | #include "msg.h" |
20 | 21 | #include "misc.h" |
21 | 22 | #include "dialog.hh" |
23 | #include "digest.h" | |
22 | 24 | #include "../dlib/dlib.h" |
23 | ||
24 | 25 | |
25 | 26 | typedef struct { |
26 | 27 | int ok; |
28 | enum AuthParseHTTPAuthType_t type; | |
27 | 29 | const char *realm; |
30 | const char *nonce; | |
31 | const char *opaque; | |
32 | int stale; | |
33 | enum AuthParseDigestAlgorithm_t algorithm; | |
34 | const char *domain; | |
35 | enum AuthParseDigestQOP_t qop; | |
28 | 36 | } AuthParse_t; |
29 | ||
30 | typedef struct { | |
31 | char *name; | |
32 | Dlist *paths; /* stripped of any trailing '/', so the root path is "" */ | |
33 | char *authorization; /* the authorization request header */ | |
34 | } AuthRealm_t; | |
35 | 37 | |
36 | 38 | typedef struct { |
37 | 39 | char *scheme; |
40 | 42 | } AuthHost_t; |
41 | 43 | |
42 | 44 | typedef struct { |
43 | const char *realm_name; | |
45 | const AuthParse_t *auth_parse; | |
44 | 46 | const DilloUrl *url; |
45 | 47 | } AuthDialogData_t; |
46 | 48 | |
61 | 63 | { |
62 | 64 | AuthParse_t *auth_parse = dNew(AuthParse_t, 1); |
63 | 65 | auth_parse->ok = 0; |
66 | auth_parse->type = TYPENOTSET; | |
64 | 67 | auth_parse->realm = NULL; |
68 | auth_parse->nonce = NULL; | |
69 | auth_parse->opaque = NULL; | |
70 | auth_parse->stale = 0; | |
71 | auth_parse->algorithm = ALGORITHMNOTSET; | |
72 | auth_parse->domain = NULL; | |
73 | auth_parse->qop = QOPNOTSET; | |
65 | 74 | return auth_parse; |
66 | 75 | } |
67 | 76 | |
69 | 78 | { |
70 | 79 | if (auth_parse) { |
71 | 80 | dFree((void *)auth_parse->realm); |
81 | dFree((void *)auth_parse->nonce); | |
82 | dFree((void *)auth_parse->opaque); | |
83 | dFree((void *)auth_parse->domain); | |
72 | 84 | dFree(auth_parse); |
73 | 85 | } |
74 | 86 | } |
91 | 103 | static int Auth_is_token_char(char c) |
92 | 104 | { |
93 | 105 | const char *invalid = "\"()<>@,;:\\[]?=/{} \t"; |
94 | return (strchr(invalid, c) || iscntrl((uchar_t)c)) ? 0 : 1; | |
95 | } | |
96 | ||
97 | /* | |
98 | * Unquote the content of a quoted string. | |
106 | return (!isascii(c) || strchr(invalid, c) || iscntrl((uchar_t)c)) ? 0 : 1; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Unquote the content of a (potentially) quoted string. | |
99 | 111 | * Return: newly allocated unquoted content. |
100 | 112 | * |
101 | 113 | * Arguments: |
102 | * quoted: pointer to the first char *after* the initial double quote. | |
103 | * size: the number of chars in the result, *not* including a final '\0'. | |
114 | * valuep: pointer to a pointer to the first char. | |
104 | 115 | * |
105 | 116 | * Preconditions: |
106 | * quoted points to a correctly quoted and escaped string. | |
107 | * size is the number of characters in the quoted string, *after* | |
108 | * removing escape characters. | |
109 | * | |
110 | */ | |
111 | static const char *Auth_unquote_value(const char *quoted, int size) | |
112 | { | |
113 | char c, *value, *value_ptr; | |
114 | value_ptr = value = dNew(char, size + 1); | |
115 | while ((c = *quoted++) != '"') | |
116 | *value_ptr++ = (c == '\\') ? *quoted++ : c; | |
117 | *value_ptr = '\0'; | |
118 | return value; | |
119 | } | |
120 | ||
121 | /* | |
122 | * Parse a quoted string. Save the result as the auth realm if required. | |
117 | * *valuep points to a correctly quoted and escaped string. | |
118 | * | |
119 | * Postconditions: | |
120 | * *valuep points to the first not processed char. | |
121 | * | |
122 | */ | |
123 | static Dstr *Auth_unquote_value(char **valuep) | |
124 | { | |
125 | char c, quoted; | |
126 | char *value = *valuep; | |
127 | Dstr *result; | |
128 | ||
129 | while (*value == ' ' || *value == '\t') | |
130 | value++; | |
131 | ||
132 | if ((quoted = *value == '"')) | |
133 | value++; | |
134 | ||
135 | result = dStr_new(NULL); | |
136 | while ((c = *value) && | |
137 | (( quoted && c != '"') || | |
138 | (!quoted && Auth_is_token_char(c)))) { | |
139 | dStr_append_c(result, (c == '\\' && value[1]) ? *++value : c); | |
140 | value++; | |
141 | } | |
142 | ||
143 | if (quoted && *value == '\"') | |
144 | value++; | |
145 | *valuep = value; | |
146 | return result; | |
147 | } | |
148 | ||
149 | typedef int (Auth_parse_token_value_callback_t)(AuthParse_t *auth_parse, | |
150 | char *token, | |
151 | const char *value); | |
152 | ||
153 | ||
154 | /* | |
155 | * Parse authentication challenge into token-value pairs | |
156 | * and feed them into the callback function. | |
157 | * | |
158 | * The parsing is aborted should the callback function return 0. | |
159 | * | |
123 | 160 | * Return: 1 if the parse succeeds, 0 otherwise. |
124 | 161 | */ |
125 | static int Auth_parse_quoted_string(AuthParse_t *auth_parse, int set_realm, | |
126 | char **auth) | |
127 | { | |
128 | char *value; | |
129 | int size; | |
130 | ||
131 | /* parse the '"' */ | |
132 | switch (*(*auth)++) { | |
133 | case '"': | |
134 | break; | |
135 | case '\0': | |
136 | case ',': | |
137 | MSG("auth.c: missing Basic auth token value after '='\n"); | |
138 | return 0; | |
139 | break; | |
140 | default: | |
141 | MSG("auth.c: garbage in Basic auth after '='\n"); | |
142 | return 0; | |
143 | break; | |
144 | } | |
145 | ||
146 | /* parse the rest */ | |
147 | value = *auth; | |
148 | size = 0; | |
149 | while (1) { | |
162 | static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth, | |
163 | Auth_parse_token_value_callback_t *callback) | |
164 | { | |
165 | char keep_going, expect_quoted; | |
166 | char *token, *beyond_token; | |
167 | Dstr *value; | |
168 | size_t *token_size; | |
169 | ||
170 | while (**auth) { | |
171 | _MSG("Auth_parse_token_value: remaining: %s\n", *auth); | |
172 | ||
173 | /* parse a token */ | |
174 | token = *auth; | |
175 | ||
176 | token_size = 0; | |
177 | while (Auth_is_token_char(**auth)) { | |
178 | (*auth)++; | |
179 | token_size++; | |
180 | } | |
181 | if (token_size == 0) { | |
182 | MSG("Auth_parse_token_value: missing auth token\n"); | |
183 | return 0; | |
184 | } | |
185 | beyond_token = *auth; | |
186 | /* skip linear whitespace characters */ | |
187 | while (**auth == ' ' || **auth == '\t') | |
188 | (*auth)++; | |
189 | ||
190 | /* parse the '=' */ | |
150 | 191 | switch (*(*auth)++) { |
151 | case '"': | |
152 | if (set_realm) { | |
153 | dFree((void *)auth_parse->realm); | |
154 | auth_parse->realm = Auth_unquote_value(value, size); | |
155 | auth_parse->ok = 1; | |
156 | } | |
157 | return 1; | |
192 | case '=': | |
193 | *beyond_token = '\0'; | |
158 | 194 | break; |
159 | 195 | case '\0': |
160 | MSG("auth.c: auth string ended inside quoted string value\n"); | |
196 | case ',': | |
197 | MSG("Auth_parse_token_value: missing auth token value\n"); | |
161 | 198 | return 0; |
162 | 199 | break; |
163 | case '\\': | |
164 | /* end of string? */ | |
165 | if (!*(*auth)++) { | |
166 | MSG("auth.c: " | |
167 | "auth string ended inside quoted string value " | |
168 | "immediately after \\\n"); | |
169 | return 0; | |
200 | default: | |
201 | MSG("Auth_parse_token_value: garbage after auth token\n"); | |
202 | return 0; | |
203 | break; | |
204 | } | |
205 | ||
206 | value = Auth_unquote_value(auth); | |
207 | expect_quoted = !(strcmp(token, "stale") == 0 || | |
208 | strcmp(token, "algorithm") == 0); | |
209 | ||
210 | if (((*auth)[-1] == '"') != expect_quoted) | |
211 | MSG_WARN("Auth_parse_token_value: " | |
212 | "Values for key %s should%s be quoted.\n", | |
213 | token, expect_quoted ? "" : " not"); | |
214 | ||
215 | keep_going = callback(auth_parse, token, value->str); | |
216 | dStr_free(value, 1); | |
217 | if (!keep_going) | |
218 | break; | |
219 | ||
220 | /* skip ' ' and ',' */ | |
221 | while ((**auth == ' ') || (**auth == ',')) | |
222 | (*auth)++; | |
223 | } | |
224 | return 1; | |
225 | } | |
226 | ||
227 | static int Auth_parse_basic_challenge_cb(AuthParse_t *auth_parse, char *token, | |
228 | const char *value) | |
229 | { | |
230 | if (dStrAsciiCasecmp("realm", token) == 0) { | |
231 | if (!auth_parse->realm) | |
232 | auth_parse->realm = strdup(value); | |
233 | return 0; /* end parsing */ | |
234 | } else | |
235 | MSG("Auth_parse_basic_challenge_cb: Ignoring unknown parameter: %s = " | |
236 | "'%s'\n", token, value); | |
237 | return 1; | |
238 | } | |
239 | ||
240 | static int Auth_parse_digest_challenge_cb(AuthParse_t *auth_parse, char *token, | |
241 | const char *value) | |
242 | { | |
243 | const char *const fn = "Auth_parse_digest_challenge_cb"; | |
244 | ||
245 | if (!dStrAsciiCasecmp("realm", token) && !auth_parse->realm) | |
246 | auth_parse->realm = strdup(value); | |
247 | else if (!strcmp("domain", token) && !auth_parse->domain) | |
248 | auth_parse->domain = strdup(value); | |
249 | else if (!strcmp("nonce", token) && !auth_parse->nonce) | |
250 | auth_parse->nonce = strdup(value); | |
251 | else if (!strcmp("opaque", token) && !auth_parse->opaque) | |
252 | auth_parse->opaque = strdup(value); | |
253 | else if (strcmp("stale", token) == 0) { | |
254 | if (dStrAsciiCasecmp("true", value) == 0) | |
255 | auth_parse->stale = 1; | |
256 | else if (dStrAsciiCasecmp("false", value) == 0) | |
257 | auth_parse->stale = 0; | |
258 | else { | |
259 | MSG("%s: Invalid stale value: %s\n", fn, value); | |
260 | return 0; | |
261 | } | |
262 | } else if (strcmp("algorithm", token) == 0) { | |
263 | if (strcmp("MD5", value) == 0) | |
264 | auth_parse->algorithm = MD5; | |
265 | else if (strcmp("MD5-sess", value) == 0) { | |
266 | /* auth_parse->algorithm = MD5SESS; */ | |
267 | MSG("%s: MD5-sess algorithm disabled (not tested because 'not " | |
268 | "correctly implemented yet' in Apache 2.2)\n", fn); | |
269 | return 0; | |
270 | } else { | |
271 | MSG("%s: Unknown algorithm: %s\n", fn, value); | |
272 | return 0; | |
273 | } | |
274 | } else if (strcmp("qop", token) == 0) { | |
275 | while (*value) { | |
276 | int len = strcspn(value, ", \t"); | |
277 | if (len == 4 && strncmp("auth", value, 4) == 0) { | |
278 | auth_parse->qop = AUTH; | |
279 | break; | |
170 | 280 | } |
171 | /* fall through to the next case */ | |
172 | default: | |
173 | size++; | |
174 | break; | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
179 | /* | |
180 | * Parse a token-value pair. | |
181 | * Return: 1 if the parse succeeds, 0 otherwise. | |
182 | */ | |
183 | static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth) | |
184 | { | |
185 | char *token; | |
186 | int token_size, set_realm; | |
187 | static const char realm_token[] = "realm"; | |
188 | ||
189 | /* parse a token */ | |
190 | token = *auth; | |
191 | token_size = 0; | |
192 | while (Auth_is_token_char(**auth)) { | |
193 | (*auth)++; | |
194 | token_size++; | |
195 | } | |
196 | if (token_size == 0) { | |
197 | MSG("auth.c: Auth_parse_token_value: " | |
198 | "missing Basic auth token\n"); | |
199 | return 0; | |
200 | } | |
201 | ||
202 | /* skip space characters */ | |
203 | while (**auth == ' ') | |
204 | (*auth)++; | |
205 | ||
206 | /* parse the '=' */ | |
207 | switch (*(*auth)++) { | |
208 | case '=': | |
209 | break; | |
210 | case '\0': | |
211 | case ',': | |
212 | MSG("auth.c: Auth_parse_token_value: " | |
213 | "missing Basic auth token value\n"); | |
214 | return 0; | |
215 | break; | |
216 | default: | |
217 | MSG("auth.c: Auth_parse_token_value: " | |
218 | "garbage after Basic auth token\n"); | |
219 | return 0; | |
220 | break; | |
221 | } | |
222 | ||
223 | /* skip space characters */ | |
224 | while (**auth == ' ') | |
225 | (*auth)++; | |
226 | ||
227 | /* is this value the realm? */ | |
228 | set_realm = | |
229 | auth_parse->realm == NULL && | |
230 | dStrncasecmp(realm_token,token,token_size) == 0 && | |
231 | strlen(realm_token) == (size_t)token_size; | |
232 | ||
233 | return Auth_parse_quoted_string(auth_parse, set_realm, auth); | |
234 | } | |
235 | ||
236 | static void Auth_parse_auth_basic(AuthParse_t *auth_parse, char **auth) | |
237 | { | |
238 | int token_value_pairs_found; | |
239 | ||
281 | if (len == 8 && strncmp("auth-int", value, 8) == 0) { | |
282 | /* auth_parse->qop = AUTHINT; */ | |
283 | /* Keep searching; maybe we'll find an "auth" yet. */ | |
284 | MSG("%s: auth-int qop disabled (not tested because 'not " | |
285 | "implemented yet' in Apache 2.2)\n", fn); | |
286 | } else { | |
287 | MSG("%s: Unknown qop value in %s\n", fn, value); | |
288 | } | |
289 | value += len; | |
290 | while (*value == ' ' || *value == '\t') | |
291 | value++; | |
292 | if (*value == ',') | |
293 | value++; | |
294 | while (*value == ' ' || *value == '\t') | |
295 | value++; | |
296 | } | |
297 | } else { | |
298 | MSG("%s: Ignoring unknown parameter: %s = '%s'\n", fn, token, value); | |
299 | } | |
300 | return 1; | |
301 | } | |
302 | ||
303 | static void Auth_parse_challenge_args(AuthParse_t *auth_parse, | |
304 | char **challenge, | |
305 | Auth_parse_token_value_callback_t *cb) | |
306 | { | |
240 | 307 | /* parse comma-separated token-value pairs */ |
241 | token_value_pairs_found = 0; | |
242 | 308 | while (1) { |
243 | 309 | /* skip space and comma characters */ |
244 | while (**auth == ' ' || **auth == ',') | |
245 | (*auth)++; | |
310 | while (**challenge == ' ' || **challenge == ',') | |
311 | (*challenge)++; | |
246 | 312 | /* end of string? */ |
247 | if (!**auth) | |
313 | if (!**challenge) | |
248 | 314 | break; |
249 | 315 | /* parse token-value pair */ |
250 | if (!Auth_parse_token_value(auth_parse, auth)) | |
316 | if (!Auth_parse_token_value(auth_parse, challenge, cb)) | |
251 | 317 | break; |
252 | token_value_pairs_found = 1; | |
253 | } | |
254 | ||
255 | if (!token_value_pairs_found) { | |
256 | MSG("auth.c: Auth_parse_auth_basic: " | |
257 | "missing Basic auth token-value pairs\n"); | |
258 | return; | |
259 | } | |
260 | ||
261 | if (!auth_parse->realm) { | |
262 | MSG("auth.c: Auth_parse_auth_basic: " | |
263 | "missing Basic auth realm\n"); | |
264 | return; | |
265 | } | |
266 | } | |
267 | ||
268 | static void Auth_parse_auth(AuthParse_t *auth_parse, char *auth) | |
269 | { | |
270 | _MSG("auth.c: Auth_parse_auth: auth = '%s'\n", auth); | |
271 | if (dStrncasecmp(auth, "Basic ", 6) == 0) { | |
272 | auth += 6; | |
273 | Auth_parse_auth_basic(auth_parse, &auth); | |
318 | } | |
319 | ||
320 | if (auth_parse->type == BASIC) { | |
321 | if (auth_parse->realm) { | |
322 | auth_parse->ok = 1; | |
323 | } else { | |
324 | MSG("Auth_parse_challenge_args: missing Basic auth realm\n"); | |
325 | return; | |
326 | } | |
327 | } else if (auth_parse->type == DIGEST) { | |
328 | if (auth_parse->realm && auth_parse->nonce) { | |
329 | auth_parse->ok = 1; | |
330 | } else { | |
331 | MSG("Auth_parse_challenge_args: Digest challenge incomplete\n"); | |
332 | return; | |
333 | } | |
334 | } | |
335 | } | |
336 | ||
337 | static void Auth_parse_challenge(AuthParse_t *auth_parse, char *challenge) | |
338 | { | |
339 | Auth_parse_token_value_callback_t *cb; | |
340 | ||
341 | MSG("auth.c: Auth_parse_challenge: challenge = '%s'\n", challenge); | |
342 | if (auth_parse->type == DIGEST) { | |
343 | challenge += 7; | |
344 | cb = Auth_parse_digest_challenge_cb; | |
274 | 345 | } else { |
275 | MSG("auth.c: Auth_parse_auth: " | |
276 | "unknown authorization scheme: auth = {%s}\n", | |
277 | auth); | |
278 | } | |
346 | challenge += 6; | |
347 | cb = Auth_parse_basic_challenge_cb; | |
348 | } | |
349 | Auth_parse_challenge_args(auth_parse, &challenge, cb); | |
279 | 350 | } |
280 | 351 | |
281 | 352 | /* |
287 | 358 | int i; |
288 | 359 | |
289 | 360 | for (i = 0; (host = dList_nth_data(auth_hosts, i)); i++) |
290 | if (((dStrcasecmp(URL_SCHEME(url), host->scheme) == 0) && | |
291 | (dStrcasecmp(URL_AUTHORITY(url), host->authority) == 0))) | |
361 | if (((dStrAsciiCasecmp(URL_SCHEME(url), host->scheme) == 0) && | |
362 | (dStrAsciiCasecmp(URL_AUTHORITY(url), host->authority) == 0))) | |
292 | 363 | return host; |
293 | 364 | |
294 | 365 | return NULL; |
304 | 375 | int i; |
305 | 376 | |
306 | 377 | for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) |
307 | if (strcmp(realm->name,name) == 0) | |
378 | if (strcmp(realm->name, name) == 0) | |
308 | 379 | return realm; |
309 | 380 | |
310 | 381 | return NULL; |
318 | 389 | { |
319 | 390 | AuthRealm_t *realm_best, *realm; |
320 | 391 | int i, j; |
321 | int match_length; | |
322 | ||
323 | match_length = 0; | |
392 | int match_length = 0; | |
393 | ||
324 | 394 | realm_best = NULL; |
325 | 395 | for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) { |
326 | 396 | char *realm_path; |
338 | 408 | return realm_best; |
339 | 409 | } |
340 | 410 | |
411 | static void Auth_realm_delete(AuthRealm_t *realm) | |
412 | { | |
413 | int i; | |
414 | ||
415 | MSG("Auth_realm_delete: \"%s\"\n", realm->name); | |
416 | for (i = dList_length(realm->paths) - 1; i >= 0; i--) | |
417 | dFree(dList_nth_data(realm->paths, i)); | |
418 | dList_free(realm->paths); | |
419 | dFree(realm->name); | |
420 | dFree(realm->username); | |
421 | dFree(realm->authorization); | |
422 | dFree(realm->cnonce); | |
423 | dFree(realm->nonce); | |
424 | dFree(realm->opaque); | |
425 | dFree(realm->domain); | |
426 | dFree(realm); | |
427 | } | |
428 | ||
341 | 429 | static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path) |
342 | 430 | { |
343 | 431 | int i; |
376 | 464 | |
377 | 465 | /* |
378 | 466 | * Return the authorization header for an HTTP query. |
379 | */ | |
380 | const char *a_Auth_get_auth_str(const DilloUrl *url) | |
381 | { | |
467 | * request_uri is a separate argument because we want it precisely as | |
468 | * formatted in the request. | |
469 | */ | |
470 | char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri) | |
471 | { | |
472 | char *ret = NULL; | |
382 | 473 | AuthHost_t *host; |
383 | 474 | AuthRealm_t *realm; |
384 | 475 | |
385 | return | |
386 | ((host = Auth_host_by_url(url)) && | |
387 | (realm = Auth_realm_by_path(host, URL_PATH(url)))) ? | |
388 | realm->authorization : NULL; | |
476 | if ((host = Auth_host_by_url(url)) && | |
477 | (realm = Auth_realm_by_path(host, URL_PATH(url)))) { | |
478 | if (realm->type == BASIC) | |
479 | ret = dStrdup(realm->authorization); | |
480 | else if (realm->type == DIGEST) | |
481 | ret = a_Digest_authorization_hdr(realm, url, request_uri); | |
482 | else | |
483 | MSG("a_Auth_get_auth_str() got an unknown realm type: %i.\n", | |
484 | realm->type); | |
485 | } | |
486 | return ret; | |
389 | 487 | } |
390 | 488 | |
391 | 489 | /* |
392 | 490 | * Determine whether the user needs to authenticate. |
393 | 491 | */ |
394 | static int Auth_do_auth_required(const char *realm_name, const DilloUrl *url) | |
492 | static int Auth_do_auth_required(const AuthParse_t *auth_parse, | |
493 | const DilloUrl *url) | |
395 | 494 | { |
396 | 495 | /* |
397 | 496 | * TO DO: I dislike the way that this code must decide whether we |
419 | 518 | * we will re-authenticate. |
420 | 519 | */ |
421 | 520 | if ((host = Auth_host_by_url(url)) && |
422 | (realm = Auth_realm_by_name(host, realm_name)) && | |
423 | (!Auth_realm_includes_path(realm, URL_PATH(url)))) { | |
424 | _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n", | |
425 | realm_name, URL_STR(url)); | |
426 | Auth_realm_add_path(realm, URL_PATH(url)); | |
427 | return 0; | |
521 | (realm = Auth_realm_by_name(host, auth_parse->realm))) { | |
522 | if (!Auth_realm_includes_path(realm, URL_PATH(url))) { | |
523 | _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n", | |
524 | auth_parse->realm, URL_STR(url)); | |
525 | Auth_realm_add_path(realm, URL_PATH(url)); | |
526 | return 0; | |
527 | } | |
528 | ||
529 | if (auth_parse->type == DIGEST && auth_parse->stale) { | |
530 | /* we do have valid credentials but our nonce is old */ | |
531 | dFree((void *)realm->nonce); | |
532 | realm->nonce = dStrdup(auth_parse->nonce); | |
533 | return 0; | |
534 | } | |
428 | 535 | } |
429 | 536 | |
430 | 537 | /* |
440 | 547 | AuthDialogData_t *data; |
441 | 548 | AuthHost_t *host; |
442 | 549 | AuthRealm_t *realm; |
443 | char *user_password, *response, *authorization, *authorization_old; | |
444 | 550 | |
445 | 551 | data = (AuthDialogData_t *)vData; |
446 | 552 | |
455 | 561 | } |
456 | 562 | |
457 | 563 | /* find or create the realm */ |
458 | if (!(realm = Auth_realm_by_name(host, data->realm_name))) { | |
459 | /* create a new realm */ | |
460 | realm = dNew(AuthRealm_t, 1); | |
461 | realm->name = dStrdup(data->realm_name); | |
564 | if (!(realm = Auth_realm_by_name(host, data->auth_parse->realm))) { | |
565 | realm = dNew0(AuthRealm_t, 1); | |
566 | realm->name = dStrdup(data->auth_parse->realm); | |
462 | 567 | realm->paths = dList_new(1); |
463 | realm->authorization = NULL; | |
464 | 568 | dList_append(host->realms, realm); |
465 | 569 | } |
570 | realm->type = data->auth_parse->type; | |
571 | dFree(realm->authorization); | |
572 | realm->authorization = NULL; | |
466 | 573 | |
467 | 574 | Auth_realm_add_path(realm, URL_PATH(data->url)); |
468 | 575 | |
469 | /* create and set the authorization */ | |
470 | user_password = dStrconcat(user, ":", password, NULL); | |
471 | response = a_Misc_encode_base64(user_password); | |
472 | authorization = | |
473 | dStrconcat("Authorization: Basic ", response, "\r\n", NULL); | |
474 | authorization_old = realm->authorization; | |
475 | realm->authorization = authorization; | |
476 | dFree(authorization_old); | |
477 | dFree(user_password); | |
478 | dFree(response); | |
479 | } | |
480 | ||
481 | static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url) | |
576 | if (realm->type == BASIC) { | |
577 | char *user_password = dStrconcat(user, ":", password, NULL); | |
578 | char *response = a_Misc_encode_base64(user_password); | |
579 | char *authorization = | |
580 | dStrconcat("Authorization: Basic ", response, "\r\n", NULL); | |
581 | dFree(realm->authorization); | |
582 | realm->authorization = authorization; | |
583 | dFree(response); | |
584 | dStrshred(user_password); | |
585 | dFree(user_password); | |
586 | } else if (realm->type == DIGEST) { | |
587 | dFree(realm->username); | |
588 | realm->username = dStrdup(user); | |
589 | realm->nonce_count = 0; | |
590 | dFree(realm->nonce); | |
591 | realm->nonce = dStrdup(data->auth_parse->nonce); | |
592 | dFree(realm->opaque); | |
593 | realm->opaque = dStrdup(data->auth_parse->opaque); | |
594 | realm->algorithm = data->auth_parse->algorithm; | |
595 | dFree(realm->domain); | |
596 | realm->domain = dStrdup(data->auth_parse->domain); | |
597 | realm->qop = data->auth_parse->qop; | |
598 | dFree(realm->cnonce); | |
599 | if (realm->qop != QOPNOTSET) | |
600 | realm->cnonce = a_Digest_create_cnonce(); | |
601 | if (!a_Digest_compute_digest(realm, user, password)) { | |
602 | MSG("Auth_do_auth_dialog_cb: a_Digest_compute_digest failed.\n"); | |
603 | dList_remove_fast(host->realms, realm); | |
604 | Auth_realm_delete(realm); | |
605 | } | |
606 | } else { | |
607 | MSG("Auth_do_auth_dialog_cb: Unknown auth type: %i\n", | |
608 | realm->type); | |
609 | } | |
610 | dStrshred((char *)password); | |
611 | } | |
612 | ||
613 | /* | |
614 | * Return: Nonzero if we got new credentials from the user and everything | |
615 | * seems fine. | |
616 | */ | |
617 | static int Auth_do_auth_dialog(const AuthParse_t *auth_parse, | |
618 | const DilloUrl *url) | |
482 | 619 | { |
483 | 620 | int ret; |
484 | 621 | char *message; |
485 | 622 | AuthDialogData_t *data; |
486 | ||
487 | _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", realm); | |
623 | const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic"; | |
624 | ||
625 | _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm); | |
626 | ||
488 | 627 | message = dStrconcat("The server at ", URL_HOST(url), " requires a username" |
489 | " and password for \"", realm, "\".", NULL); | |
628 | " and password for \"", auth_parse->realm, "\".\n\n" | |
629 | "Authentication scheme: ", typestr, NULL); | |
490 | 630 | data = dNew(AuthDialogData_t, 1); |
491 | data->realm_name = dStrdup(realm); | |
631 | data->auth_parse = auth_parse; | |
492 | 632 | data->url = a_Url_dup(url); |
493 | 633 | ret = a_Dialog_user_password(message, Auth_do_auth_dialog_cb, data); |
494 | 634 | dFree(message); |
495 | dFree((void*)data->realm_name); | |
496 | a_Url_free((void*)data->url); | |
635 | a_Url_free((void *)data->url); | |
497 | 636 | dFree(data); |
498 | 637 | return ret; |
499 | 638 | } |
501 | 640 | /* |
502 | 641 | * Do authorization for an auth string. |
503 | 642 | */ |
504 | static int Auth_do_auth(char *auth, const DilloUrl *url) | |
505 | { | |
506 | int reload; | |
643 | static int Auth_do_auth(char *challenge, enum AuthParseHTTPAuthType_t type, | |
644 | const DilloUrl *url) | |
645 | { | |
507 | 646 | AuthParse_t *auth_parse; |
508 | ||
509 | _MSG("auth.c: Auth_do_auth: auth={%s}\n", auth); | |
510 | reload = 0; | |
647 | int reload = 0; | |
648 | ||
649 | _MSG("auth.c: Auth_do_auth: challenge={%s}\n", challenge); | |
511 | 650 | auth_parse = Auth_parse_new(); |
512 | Auth_parse_auth(auth_parse, auth); | |
651 | auth_parse->type = type; | |
652 | Auth_parse_challenge(auth_parse, challenge); | |
513 | 653 | if (auth_parse->ok) |
514 | 654 | reload = |
515 | Auth_do_auth_required(auth_parse->realm, url) ? | |
516 | Auth_do_auth_dialog(auth_parse->realm, url) | |
655 | Auth_do_auth_required(auth_parse, url) ? | |
656 | Auth_do_auth_dialog(auth_parse, url) | |
517 | 657 | : 1; |
518 | 658 | Auth_parse_free(auth_parse); |
519 | 659 | |
521 | 661 | } |
522 | 662 | |
523 | 663 | /* |
524 | * Do authorization for a set of auth strings. | |
525 | */ | |
526 | int a_Auth_do_auth(Dlist *auths, const DilloUrl *url) | |
527 | { | |
528 | int reload, i; | |
529 | char *auth; | |
530 | ||
531 | reload = 0; | |
532 | for (i = 0; (auth = dList_nth_data(auths, i)); ++i) | |
533 | if (Auth_do_auth(auth, url)) | |
534 | reload = 1; | |
535 | ||
536 | return reload; | |
537 | } | |
538 | ||
664 | * Given authentication challenge(s), prepare authorization. | |
665 | * Return: 0 on failure | |
666 | * nonzero on success. A new query will be sent to the server. | |
667 | */ | |
668 | int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url) | |
669 | { | |
670 | int i; | |
671 | char *chal; | |
672 | ||
673 | for (i = 0; (chal = dList_nth_data(challenges, i)); ++i) | |
674 | if (!dStrnAsciiCasecmp(chal, "Digest ", 7)) | |
675 | if (Auth_do_auth(chal, DIGEST, url)) | |
676 | return 1; | |
677 | for (i = 0; (chal = dList_nth_data(challenges, i)); ++i) | |
678 | if (!dStrnAsciiCasecmp(chal, "Basic ", 6)) | |
679 | if (Auth_do_auth(chal, BASIC, url)) | |
680 | return 1; | |
681 | ||
682 | return 0; | |
683 | } | |
684 |
6 | 6 | |
7 | 7 | #include "url.h" |
8 | 8 | |
9 | enum AuthParseHTTPAuthType_t { TYPENOTSET, BASIC, DIGEST }; | |
10 | enum AuthParseDigestAlgorithm_t { ALGORITHMNOTSET, MD5, MD5SESS }; | |
11 | enum AuthParseDigestQOP_t { QOPNOTSET, AUTH, AUTHINT }; | |
9 | 12 | |
10 | const char *a_Auth_get_auth_str(const DilloUrl *request_url); | |
13 | typedef struct { | |
14 | enum AuthParseHTTPAuthType_t type; | |
15 | char *name; | |
16 | Dlist *paths; /* stripped of any trailing '/', so the root path is "" */ | |
17 | char *authorization; /* BASIC: the authorization request header */ | |
18 | /* DIGEST: the hexdigest of A1 */ | |
19 | /* digest state ahead */ | |
20 | char *username; | |
21 | char *cnonce; | |
22 | unsigned int nonce_count; | |
23 | char *nonce; | |
24 | char *opaque; | |
25 | enum AuthParseDigestAlgorithm_t algorithm; | |
26 | char *domain; /* NOT USED */ | |
27 | enum AuthParseDigestQOP_t qop; | |
28 | } AuthRealm_t; | |
29 | ||
30 | ||
31 | char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri); | |
11 | 32 | int a_Auth_do_auth(Dlist *auth_string, const DilloUrl *url); |
12 | 33 | void a_Auth_init(void); |
13 | 34 |
0 | 0 | #ifndef __BINARYCONST_H__ |
1 | 1 | #define __BINARYCONST_H__ |
2 | ||
3 | /* binaryconst.h was integrated into the Dillo project in April 2004, and | |
4 | * presumably comes from the ancestor of the code found at | |
5 | * http://cprog.tomsweb.net/binconst.txt | |
6 | */ | |
2 | 7 | |
3 | 8 | /* Macros for allowing binary constants in C |
4 | 9 | * By Tom Torfs - donated to the public domain */ |
12 | 12 | * Dillo's cache module |
13 | 13 | */ |
14 | 14 | |
15 | #include <ctype.h> /* for tolower */ | |
16 | 15 | #include <sys/types.h> |
17 | 16 | |
18 | 17 | #include <stdlib.h> |
520 | 519 | /* META only gives charset; use detected MIME type too */ |
521 | 520 | entry->TypeNorm = dStrconcat(entry->TypeDet, ctype, NULL); |
522 | 521 | } else if (*from == 'm' && |
523 | !dStrncasecmp(ctype, "text/xhtml", 10)) { | |
522 | !dStrnAsciiCasecmp(ctype, "text/xhtml", 10)) { | |
524 | 523 | /* WORKAROUND: doxygen uses "text/xhtml" in META */ |
525 | 524 | entry->TypeNorm = dStrdup(entry->TypeDet); |
526 | 525 | } |
583 | 582 | for (i = 0; header[i]; i++) { |
584 | 583 | /* Search fieldname */ |
585 | 584 | for (j = 0; fieldname[j]; j++) |
586 | if (tolower(fieldname[j]) != tolower(header[i + j])) | |
585 | if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j])) | |
587 | 586 | break; |
588 | 587 | if (fieldname[j]) { |
589 | 588 | /* skip to next line */ |
619 | 618 | for (i = 0; header[i]; i++) { |
620 | 619 | /* Search fieldname */ |
621 | 620 | for (j = 0; fieldname[j]; j++) |
622 | if (tolower(fieldname[j]) != tolower(header[i + j])) | |
621 | if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j])) | |
623 | 622 | break; |
624 | 623 | if (fieldname[j]) { |
625 | 624 | /* skip to next line */ |
674 | 673 | entry->Header = dStr_new(""); |
675 | 674 | return; |
676 | 675 | } |
677 | if (header[9] == '3' && header[10] == '0') { | |
676 | if (header[9] == '3' && header[10] == '0' && | |
677 | (location_str = Cache_parse_field(header, "Location"))) { | |
678 | 678 | /* 30x: URL redirection */ |
679 | if ((location_str = Cache_parse_field(header, "Location"))) { | |
680 | DilloUrl *location_url; | |
681 | ||
679 | DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url)); | |
680 | ||
681 | if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN && | |
682 | !a_Url_same_organization(entry->Url, location_url)) { | |
683 | /* don't redirect; just show body like usual (if any) */ | |
684 | MSG("Redirection not followed from %s to %s\n", | |
685 | URL_HOST(entry->Url), URL_STR(location_url)); | |
686 | a_Url_free(location_url); | |
687 | } else { | |
682 | 688 | entry->Flags |= CA_Redirect; |
683 | 689 | if (header[11] == '1') |
684 | 690 | entry->Flags |= CA_ForceRedirect; /* 301 Moved Permanently */ |
685 | 691 | else if (header[11] == '2') |
686 | 692 | entry->Flags |= CA_TempRedirect; /* 302 Temporary Redirect */ |
687 | 693 | |
688 | location_url = a_Url_new(location_str, URL_STR_(entry->Url)); | |
689 | 694 | if (URL_FLAGS(location_url) & (URL_Post + URL_Get) && |
690 | dStrcasecmp(URL_SCHEME(location_url), "dpi") == 0 && | |
691 | dStrcasecmp(URL_SCHEME(entry->Url), "dpi") != 0) { | |
695 | dStrAsciiCasecmp(URL_SCHEME(location_url), "dpi") == 0 && | |
696 | dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0) { | |
692 | 697 | /* Forbid dpi GET and POST from non dpi-generated urls */ |
693 | 698 | MSG("Redirection Denied! '%s' -> '%s'\n", |
694 | 699 | URL_STR(entry->Url), URL_STR(location_url)); |
696 | 701 | } else { |
697 | 702 | entry->Location = location_url; |
698 | 703 | } |
699 | dFree(location_str); | |
700 | } | |
704 | } | |
705 | dFree(location_str); | |
701 | 706 | } else if (strncmp(header + 9, "401", 3) == 0) { |
702 | 707 | entry->Auth = |
703 | 708 | Cache_parse_multiple_fields(header, "WWW-Authenticate"); |
727 | 732 | * If Transfer-Encoding is present, Content-Length must be ignored. |
728 | 733 | * If the Transfer-Encoding is non-identity, it is an error. |
729 | 734 | */ |
730 | if (dStrcasecmp(encoding, "identity")) | |
735 | if (dStrAsciiCasecmp(encoding, "identity")) | |
731 | 736 | MSG_HTTP("Content-Length and non-identity Transfer-Encoding " |
732 | 737 | "headers both present.\n"); |
733 | 738 | } else { |
1038 | 1043 | */ |
1039 | 1044 | int a_Cache_download_enabled(const DilloUrl *url) |
1040 | 1045 | { |
1041 | if (!dStrcasecmp(URL_SCHEME(url), "http") || | |
1042 | !dStrcasecmp(URL_SCHEME(url), "https") || | |
1043 | !dStrcasecmp(URL_SCHEME(url), "ftp")) | |
1046 | if (!dStrAsciiCasecmp(URL_SCHEME(url), "http") || | |
1047 | !dStrAsciiCasecmp(URL_SCHEME(url), "https") || | |
1048 | !dStrAsciiCasecmp(URL_SCHEME(url), "ftp")) | |
1044 | 1049 | return 1; |
1045 | 1050 | return 0; |
1046 | 1051 | } |
228 | 228 | const DilloUrl *referer; |
229 | 229 | int allow = FALSE; |
230 | 230 | |
231 | if (dStrcasecmp(URL_SCHEME(url), "dpi") == 0) { | |
231 | if (dStrAsciiCasecmp(URL_SCHEME(url), "dpi") == 0) { | |
232 | 232 | if (!(URL_FLAGS(url) & (URL_Post + URL_Get))) { |
233 | 233 | allow = TRUE; |
234 | 234 | } else if (!(URL_FLAGS(url) & URL_Post) && |
235 | strncmp(URL_STR(url), "dpi:/vsource/", 13) == 0) { | |
235 | strncmp(URL_PATH(url), "/vsource/", 9) == 0) { | |
236 | 236 | allow = TRUE; |
237 | 237 | } else { |
238 | 238 | /* only allow GET&POST dpi-requests from dpi-generated urls */ |
239 | 239 | if (a_Nav_stack_size(bw)) { |
240 | 240 | referer = a_History_get_url(NAV_TOP_UIDX(bw)); |
241 | if (dStrcasecmp(URL_SCHEME(referer), "dpi") == 0) { | |
241 | if (dStrAsciiCasecmp(URL_SCHEME(referer), "dpi") == 0) { | |
242 | 242 | allow = TRUE; |
243 | 243 | } |
244 | 244 | } |
265 | 265 | char *p, *server = NULL, *url_str = URL_STR(url); |
266 | 266 | Dstr *tmp; |
267 | 267 | |
268 | if ((dStrncasecmp(url_str, "http:", 5) == 0) || | |
269 | (dStrncasecmp(url_str, "about:", 6) == 0)) { | |
268 | if ((dStrnAsciiCasecmp(url_str, "http:", 5) == 0) || | |
269 | (dStrnAsciiCasecmp(url_str, "about:", 6) == 0)) { | |
270 | 270 | /* URL doesn't use dpi (server = NULL) */ |
271 | } else if (dStrncasecmp(url_str, "dpi:/", 5) == 0) { | |
271 | } else if (dStrnAsciiCasecmp(url_str, "dpi:/", 5) == 0) { | |
272 | 272 | /* dpi prefix, get this server's name */ |
273 | 273 | if ((p = strchr(url_str + 5, '/')) != NULL) { |
274 | 274 | server = dStrndup(url_str + 5, (uint_t)(p - url_str - 5)); |
387 | 387 | *want_host = URL_HOST(wanted); |
388 | 388 | if (want_host[0] == '\0') { |
389 | 389 | ret = (req_host[0] == '\0' || |
390 | !dStrcasecmp(URL_SCHEME(wanted), "data")) ? TRUE : FALSE; | |
390 | !dStrAsciiCasecmp(URL_SCHEME(wanted), "data")) | |
391 | ? TRUE : FALSE; | |
391 | 392 | } else { |
392 | 393 | /* This will regard "www.dillo.org" and "www.dillo.org." as |
393 | 394 | * different, but it doesn't seem worth caring about. |
453 | 454 | } else if (Capi_url_uses_dpi(web->url, &server)) { |
454 | 455 | /* dpi request */ |
455 | 456 | if ((safe = a_Capi_dpi_verify_request(web->bw, web->url))) { |
456 | if (dStrcasecmp(scheme, "dpi") == 0) { | |
457 | if (dStrAsciiCasecmp(scheme, "dpi") == 0) { | |
457 | 458 | if (strcmp(server, "vsource") == 0) { |
458 | /* don't reload the "view source" page */ | |
459 | /* allow "view source" reload upon user request */ | |
459 | 460 | } else { |
460 | 461 | /* make the other "dpi:/" prefixed urls always reload. */ |
461 | 462 | a_Url_set_flags(web->url, URL_FLAGS(web->url) | URL_E2EQuery); |
477 | 478 | } |
478 | 479 | dFree(server); |
479 | 480 | |
480 | } else if (!dStrcasecmp(scheme, "http")) { | |
481 | } else if (!dStrAsciiCasecmp(scheme, "http")) { | |
481 | 482 | /* http request */ |
482 | 483 | if (reload) { |
483 | 484 | a_Capi_conn_abort_by_url(web->url); |
490 | 491 | } |
491 | 492 | use_cache = 1; |
492 | 493 | |
493 | } else if (!dStrcasecmp(scheme, "about")) { | |
494 | } else if (!dStrAsciiCasecmp(scheme, "about")) { | |
494 | 495 | /* internal request */ |
495 | 496 | use_cache = 1; |
496 | 497 | } |
261 | 261 | high = NCOLORS - 1; |
262 | 262 | while (low <= high) { |
263 | 263 | mid = (low + high) / 2; |
264 | if ((ret = dStrcasecmp(cp, color_keyword[mid].key)) < 0) | |
264 | if ((ret = dStrAsciiCasecmp(cp, color_keyword[mid].key)) < 0) | |
265 | 265 | high = mid - 1; |
266 | 266 | else if (ret > 0) |
267 | 267 | low = mid + 1; |
283 | 283 | rule[j++] = line[i++]; |
284 | 284 | rule[j] = '\0'; |
285 | 285 | |
286 | if (dStrcasecmp(rule, "ACCEPT") == 0) | |
286 | if (dStrAsciiCasecmp(rule, "ACCEPT") == 0) | |
287 | 287 | cc.action = COOKIE_ACCEPT; |
288 | else if (dStrcasecmp(rule, "ACCEPT_SESSION") == 0) | |
288 | else if (dStrAsciiCasecmp(rule, "ACCEPT_SESSION") == 0) | |
289 | 289 | cc.action = COOKIE_ACCEPT_SESSION; |
290 | else if (dStrcasecmp(rule, "DENY") == 0) | |
290 | else if (dStrAsciiCasecmp(rule, "DENY") == 0) | |
291 | 291 | cc.action = COOKIE_DENY; |
292 | 292 | else { |
293 | 293 | MSG("Cookies: rule '%s' for domain '%s' is not recognised.\n", |
296 | 296 | } |
297 | 297 | |
298 | 298 | cc.domain = dStrdup(domain); |
299 | if (dStrcasecmp(cc.domain, "DEFAULT") == 0) { | |
299 | if (dStrAsciiCasecmp(cc.domain, "DEFAULT") == 0) { | |
300 | 300 | /* Set the default action */ |
301 | 301 | default_action = cc.action; |
302 | 302 | dFree(cc.domain); |
337 | 337 | if (ccontrol[i].domain[0] == '.') { |
338 | 338 | diff = strlen(domain) - strlen(ccontrol[i].domain); |
339 | 339 | if (diff >= 0) { |
340 | if (dStrcasecmp(domain + diff, ccontrol[i].domain) != 0) | |
340 | if (dStrAsciiCasecmp(domain + diff, ccontrol[i].domain) != 0) | |
341 | 341 | continue; |
342 | 342 | } else { |
343 | 343 | continue; |
344 | 344 | } |
345 | 345 | } else { |
346 | if (dStrcasecmp(domain, ccontrol[i].domain) != 0) | |
346 | if (dStrAsciiCasecmp(domain, ccontrol[i].domain) != 0) | |
347 | 347 | continue; |
348 | 348 | } |
349 | 349 |
264 | 264 | if (element != ELEMENT_ANY && element != n->element) |
265 | 265 | return false; |
266 | 266 | if (pseudo != NULL && |
267 | (n->pseudo == NULL || dStrcasecmp (pseudo, n->pseudo) != 0)) | |
267 | (n->pseudo == NULL || dStrAsciiCasecmp (pseudo, n->pseudo) != 0)) | |
268 | 268 | return false; |
269 | if (id != NULL && (n->id == NULL || dStrcasecmp (id, n->id) != 0)) | |
269 | if (id != NULL && (n->id == NULL || dStrAsciiCasecmp (id, n->id) != 0)) | |
270 | 270 | return false; |
271 | 271 | if (klass != NULL) { |
272 | 272 | for (int i = 0; i < klass->size (); i++) { |
273 | 273 | bool found = false; |
274 | 274 | if (n->klass != NULL) { |
275 | 275 | for (int j = 0; j < n->klass->size (); j++) { |
276 | if (dStrcasecmp (klass->get(i), n->klass->get(j)) == 0) { | |
276 | if (dStrAsciiCasecmp (klass->get(i), n->klass->get(j)) == 0) { | |
277 | 277 | found = true; |
278 | 278 | break; |
279 | 279 | } |
609 | 609 | "th {font-weight: bolder; text-align: center}" |
610 | 610 | "code, tt, pre, samp, kbd {font-family: monospace}" |
611 | 611 | /* WORKAROUND: Reset font properties in tables as some |
612 | * some pages rely on it (e.g. gmail). | |
612 | * pages rely on it (e.g. gmail). | |
613 | 613 | * http://developer.mozilla.org/En/Fixing_Table_Inheritance_in_Quirks_Mode |
614 | 614 | * has a detailed description of the issue. |
615 | 615 | */ |
118 | 118 | |
119 | 119 | static const char *const Css_text_decoration_enum_vals[] = { |
120 | 120 | "underline", "overline", "line-through", "blink", NULL |
121 | }; | |
122 | ||
123 | static const char *const Css_text_transform_enum_vals[] = { | |
124 | "none", "capitalize", "uppercase", "lowercase", NULL | |
121 | 125 | }; |
122 | 126 | |
123 | 127 | static const char *const Css_vertical_align_vals[] = { |
227 | 231 | Css_text_decoration_enum_vals}, |
228 | 232 | {"text-indent", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, |
229 | 233 | {"text-shadow", {CSS_TYPE_UNUSED}, NULL}, |
230 | {"text-transform", {CSS_TYPE_UNUSED}, NULL}, | |
234 | {"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, | |
235 | Css_text_transform_enum_vals}, | |
231 | 236 | {"top", {CSS_TYPE_UNUSED}, NULL}, |
232 | 237 | {"unicode-bidi", {CSS_TYPE_UNUSED}, NULL}, |
233 | 238 | {"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals}, |
668 | 673 | case CSS_TYPE_ENUM: |
669 | 674 | if (ttype == CSS_TK_SYMBOL) { |
670 | 675 | for (i = 0; Css_property_info[prop].enum_symbols[i]; i++) |
671 | if (dStrcasecmp(tval, | |
676 | if (dStrAsciiCasecmp(tval, | |
672 | 677 | Css_property_info[prop].enum_symbols[i]) == 0) |
673 | 678 | return true; |
674 | 679 | } |
676 | 681 | |
677 | 682 | case CSS_TYPE_MULTI_ENUM: |
678 | 683 | if (ttype == CSS_TK_SYMBOL) { |
679 | if (dStrcasecmp(tval, "none") == 0) { | |
684 | if (dStrAsciiCasecmp(tval, "none") == 0) { | |
680 | 685 | return true; |
681 | 686 | } else { |
682 | 687 | for (i = 0; Css_property_info[prop].enum_symbols[i]; i++) { |
683 | if (dStrcasecmp(tval, | |
688 | if (dStrAsciiCasecmp(tval, | |
684 | 689 | Css_property_info[prop].enum_symbols[i]) == 0) |
685 | 690 | return true; |
686 | 691 | } |
697 | 702 | case CSS_TYPE_SIGNED_LENGTH: |
698 | 703 | if (ttype == CSS_TK_DECINT || |
699 | 704 | ttype == CSS_TK_FLOAT || |
700 | (ttype == CSS_TK_SYMBOL && dStrcasecmp(tval, "auto") == 0)) | |
705 | (ttype == CSS_TK_SYMBOL && dStrAsciiCasecmp(tval, "auto") == 0)) | |
701 | 706 | return true; |
702 | 707 | break; |
703 | 708 | |
704 | 709 | case CSS_TYPE_COLOR: |
705 | 710 | if ((ttype == CSS_TK_COLOR || |
706 | 711 | ttype == CSS_TK_SYMBOL) && |
707 | (dStrcasecmp(tval, "rgb") == 0 || | |
712 | (dStrAsciiCasecmp(tval, "rgb") == 0 || | |
708 | 713 | a_Color_parse(tval, -1, &err) != -1)) |
709 | 714 | return true; |
710 | 715 | break; |
832 | 837 | case CSS_TYPE_ENUM: |
833 | 838 | if (ttype == CSS_TK_SYMBOL) { |
834 | 839 | for (i = 0; Css_property_info[prop].enum_symbols[i]; i++) |
835 | if (dStrcasecmp(tval, | |
840 | if (dStrAsciiCasecmp(tval, | |
836 | 841 | Css_property_info[prop].enum_symbols[i]) == 0) { |
837 | 842 | val->intVal = i; |
838 | 843 | ret = true; |
847 | 852 | ret = true; |
848 | 853 | |
849 | 854 | while (ttype == CSS_TK_SYMBOL) { |
850 | if (dStrcasecmp(tval, "none") != 0) { | |
855 | if (dStrAsciiCasecmp(tval, "none") != 0) { | |
851 | 856 | for (i = 0, found = false; |
852 | 857 | !found && Css_property_info[prop].enum_symbols[i]; i++) { |
853 | if (dStrcasecmp(tval, | |
858 | if (dStrAsciiCasecmp(tval, | |
854 | 859 | Css_property_info[prop].enum_symbols[i]) == 0) |
855 | 860 | val->intVal |= (1 << i); |
856 | 861 | } |
871 | 876 | if (!spaceSeparated && ttype == CSS_TK_SYMBOL) { |
872 | 877 | ret = true; |
873 | 878 | |
874 | if (dStrcasecmp(tval, "px") == 0) { | |
879 | if (dStrAsciiCasecmp(tval, "px") == 0) { | |
875 | 880 | lentype = CSS_LENGTH_TYPE_PX; |
876 | 881 | nextToken(); |
877 | } else if (dStrcasecmp(tval, "mm") == 0) { | |
882 | } else if (dStrAsciiCasecmp(tval, "mm") == 0) { | |
878 | 883 | lentype = CSS_LENGTH_TYPE_MM; |
879 | 884 | nextToken(); |
880 | } else if (dStrcasecmp(tval, "cm") == 0) { | |
885 | } else if (dStrAsciiCasecmp(tval, "cm") == 0) { | |
881 | 886 | lentype = CSS_LENGTH_TYPE_MM; |
882 | 887 | fval *= 10; |
883 | 888 | nextToken(); |
884 | } else if (dStrcasecmp(tval, "in") == 0) { | |
889 | } else if (dStrAsciiCasecmp(tval, "in") == 0) { | |
885 | 890 | lentype = CSS_LENGTH_TYPE_MM; |
886 | 891 | fval *= 25.4; |
887 | 892 | nextToken(); |
888 | } else if (dStrcasecmp(tval, "pt") == 0) { | |
893 | } else if (dStrAsciiCasecmp(tval, "pt") == 0) { | |
889 | 894 | lentype = CSS_LENGTH_TYPE_MM; |
890 | 895 | fval *= (25.4 / 72); |
891 | 896 | nextToken(); |
892 | } else if (dStrcasecmp(tval, "pc") == 0) { | |
897 | } else if (dStrAsciiCasecmp(tval, "pc") == 0) { | |
893 | 898 | lentype = CSS_LENGTH_TYPE_MM; |
894 | 899 | fval *= (25.4 / 6); |
895 | 900 | nextToken(); |
896 | } else if (dStrcasecmp(tval, "em") == 0) { | |
901 | } else if (dStrAsciiCasecmp(tval, "em") == 0) { | |
897 | 902 | lentype = CSS_LENGTH_TYPE_EM; |
898 | 903 | nextToken(); |
899 | } else if (dStrcasecmp(tval, "ex") == 0) { | |
904 | } else if (dStrAsciiCasecmp(tval, "ex") == 0) { | |
900 | 905 | lentype = CSS_LENGTH_TYPE_EX; |
901 | 906 | nextToken(); |
902 | 907 | } else { |
921 | 926 | ret = true; |
922 | 927 | |
923 | 928 | val->intVal = CSS_CREATE_LENGTH(fval, lentype); |
924 | } else if (ttype == CSS_TK_SYMBOL && dStrcasecmp(tval, "auto") == 0) { | |
929 | } else if (ttype == CSS_TK_SYMBOL && !dStrAsciiCasecmp(tval, "auto")) { | |
925 | 930 | ret = true; |
926 | 931 | val->intVal = CSS_LENGTH_TYPE_AUTO; |
927 | 932 | nextToken(); |
937 | 942 | ret = true; |
938 | 943 | nextToken(); |
939 | 944 | } else if (ttype == CSS_TK_SYMBOL) { |
940 | if (dStrcasecmp(tval, "rgb") == 0) { | |
945 | if (dStrAsciiCasecmp(tval, "rgb") == 0) { | |
941 | 946 | nextToken(); |
942 | 947 | if (parseRgbColor(&val->intVal)) |
943 | 948 | ret = true; |
1016 | 1021 | if (ttype == CSS_TK_CHAR && tval[0] == '!') { |
1017 | 1022 | nextToken(); |
1018 | 1023 | if (ttype == CSS_TK_SYMBOL && |
1019 | dStrcasecmp(tval, "important") == 0) { | |
1024 | dStrAsciiCasecmp(tval, "important") == 0) { | |
1020 | 1025 | nextToken(); |
1021 | 1026 | return true; |
1022 | 1027 | } |
1030 | 1035 | */ |
1031 | 1036 | static int Css_property_info_cmp(const void *a, const void *b) |
1032 | 1037 | { |
1033 | return dStrcasecmp(((CssPropertyInfo *) a)->symbol, | |
1038 | return dStrAsciiCasecmp(((CssPropertyInfo *) a)->symbol, | |
1034 | 1039 | ((CssPropertyInfo *) b)->symbol); |
1035 | 1040 | } |
1036 | 1041 | |
1040 | 1045 | */ |
1041 | 1046 | static int Css_shorthand_info_cmp(const void *a, const void *b) |
1042 | 1047 | { |
1043 | return dStrcasecmp(((CssShorthandInfo *) a)->symbol, | |
1048 | return dStrAsciiCasecmp(((CssShorthandInfo *) a)->symbol, | |
1044 | 1049 | ((CssShorthandInfo *) b)->symbol); |
1045 | 1050 | } |
1046 | 1051 | |
1385 | 1390 | Dstr *urlStr = NULL; |
1386 | 1391 | |
1387 | 1392 | if (ttype != CSS_TK_SYMBOL || |
1388 | dStrcasecmp(tval, "url") != 0) | |
1393 | dStrAsciiCasecmp(tval, "url") != 0) | |
1389 | 1394 | return NULL; |
1390 | 1395 | |
1391 | 1396 | nextToken(); |
1431 | 1436 | nextToken(); |
1432 | 1437 | |
1433 | 1438 | if (ttype == CSS_TK_SYMBOL && |
1434 | dStrcasecmp(tval, "url") == 0) | |
1439 | dStrAsciiCasecmp(tval, "url") == 0) | |
1435 | 1440 | urlStr = parseUrl(); |
1436 | 1441 | else if (ttype == CSS_TK_STRING) |
1437 | 1442 | urlStr = dStrdup (tval); |
1443 | 1448 | mediaSyntaxIsOK = false; |
1444 | 1449 | mediaIsSelected = false; |
1445 | 1450 | while (ttype == CSS_TK_SYMBOL) { |
1446 | if (dStrcasecmp(tval, "all") == 0 || | |
1447 | dStrcasecmp(tval, "screen") == 0) | |
1451 | if (dStrAsciiCasecmp(tval, "all") == 0 || | |
1452 | dStrAsciiCasecmp(tval, "screen") == 0) | |
1448 | 1453 | mediaIsSelected = true; |
1449 | 1454 | nextToken(); |
1450 | 1455 | if (ttype == CSS_TK_CHAR && tval[0] == ',') { |
1485 | 1490 | |
1486 | 1491 | /* parse a comma-separated list of media */ |
1487 | 1492 | while (ttype == CSS_TK_SYMBOL) { |
1488 | if (dStrcasecmp(tval, "all") == 0 || | |
1489 | dStrcasecmp(tval, "screen") == 0) | |
1493 | if (dStrAsciiCasecmp(tval, "all") == 0 || | |
1494 | dStrAsciiCasecmp(tval, "screen") == 0) | |
1490 | 1495 | mediaIsSelected = true; |
1491 | 1496 | nextToken(); |
1492 | 1497 | if (ttype == CSS_TK_CHAR && tval[0] == ',') { |
1572 | 1577 | parser.tval[0] == '@') { |
1573 | 1578 | parser.nextToken(); |
1574 | 1579 | if (parser.ttype == CSS_TK_SYMBOL) { |
1575 | if (dStrcasecmp(parser.tval, "import") == 0 && | |
1580 | if (dStrAsciiCasecmp(parser.tval, "import") == 0 && | |
1576 | 1581 | html != NULL && |
1577 | 1582 | importsAreAllowed) { |
1578 | 1583 | parser.parseImport(html, url); |
1579 | } else if (dStrcasecmp(parser.tval, "media") == 0) { | |
1584 | } else if (dStrAsciiCasecmp(parser.tval, "media") == 0) { | |
1580 | 1585 | parser.parseMedia(); |
1581 | 1586 | } else { |
1582 | 1587 | parser.ignoreStatement(); |
189 | 189 | { |
190 | 190 | Decode *dc = NULL; |
191 | 191 | |
192 | if (format && !dStrcasecmp(format, "chunked")) { | |
192 | if (format && !dStrAsciiCasecmp(format, "chunked")) { | |
193 | 193 | int *chunk_remaining = dNew(int, 1); |
194 | 194 | *chunk_remaining = 0; |
195 | 195 | dc = dNew(Decode, 1); |
214 | 214 | Decode *dc = NULL; |
215 | 215 | |
216 | 216 | if (format && *format) { |
217 | if (!dStrcasecmp(format, "gzip") || !dStrcasecmp(format, "x-gzip")) { | |
217 | if (!dStrAsciiCasecmp(format, "gzip") || | |
218 | !dStrAsciiCasecmp(format, "x-gzip")) { | |
218 | 219 | z_stream *zs; |
219 | 220 | _MSG("gzipped data!\n"); |
220 | 221 | |
244 | 245 | */ |
245 | 246 | static int Decode_is_ascii(const char *str) |
246 | 247 | { |
247 | return (!(dStrcasecmp(str, "ASCII") && | |
248 | dStrcasecmp(str, "US-ASCII") && | |
249 | dStrcasecmp(str, "us") && | |
250 | dStrcasecmp(str, "IBM367") && | |
251 | dStrcasecmp(str, "cp367") && | |
252 | dStrcasecmp(str, "csASCII") && | |
253 | dStrcasecmp(str, "ANSI_X3.4-1968") && | |
254 | dStrcasecmp(str, "iso-ir-6") && | |
255 | dStrcasecmp(str, "ANSI_X3.4-1986") && | |
256 | dStrcasecmp(str, "ISO_646.irv:1991") && | |
257 | dStrcasecmp(str, "ISO646-US"))); | |
248 | return (!(dStrAsciiCasecmp(str, "ASCII") && | |
249 | dStrAsciiCasecmp(str, "US-ASCII") && | |
250 | dStrAsciiCasecmp(str, "us") && | |
251 | dStrAsciiCasecmp(str, "IBM367") && | |
252 | dStrAsciiCasecmp(str, "cp367") && | |
253 | dStrAsciiCasecmp(str, "csASCII") && | |
254 | dStrAsciiCasecmp(str, "ANSI_X3.4-1968") && | |
255 | dStrAsciiCasecmp(str, "iso-ir-6") && | |
256 | dStrAsciiCasecmp(str, "ANSI_X3.4-1986") && | |
257 | dStrAsciiCasecmp(str, "ISO_646.irv:1991") && | |
258 | dStrAsciiCasecmp(str, "ISO646-US"))); | |
258 | 259 | } |
259 | 260 | |
260 | 261 | /* |
270 | 271 | |
271 | 272 | if (format && |
272 | 273 | strlen(format) && |
273 | dStrcasecmp(format,"UTF-8") && | |
274 | dStrAsciiCasecmp(format,"UTF-8") && | |
274 | 275 | !Decode_is_ascii(format)) { |
275 | 276 | |
276 | 277 | iconv_t ic = iconv_open("UTF-8", format); |
93 | 93 | return Fl_Choice::handle(e); |
94 | 94 | }; |
95 | 95 | }; |
96 | ||
97 | class EnterButton : public Fl_Button { | |
98 | public: | |
99 | EnterButton (int x,int y,int w,int h, const char* label = 0) : | |
100 | Fl_Button (x,y,w,h,label) {}; | |
101 | int handle(int e); | |
102 | }; | |
103 | ||
104 | int EnterButton::handle(int e) | |
105 | { | |
106 | if (e == FL_KEYBOARD && Fl::focus() == this && Fl::event_key() == FL_Enter){ | |
107 | set_changed(); | |
108 | simulate_key_action(); | |
109 | do_callback(); | |
110 | return 1; | |
111 | } | |
112 | return Fl_Button::handle(e); | |
113 | } | |
96 | 114 | |
97 | 115 | //---------------------------------------------------------------------------- |
98 | 116 | |
353 | 371 | bw = (ww - gap)/nb - gap; |
354 | 372 | xpos += gap; |
355 | 373 | for (int i=1; i <= nb; ++i) { |
356 | b = new Fl_Button(xpos, wh-bh, bw, bh, txt[i]); | |
374 | b = new EnterButton(xpos, wh-bh, bw, bh, txt[i]); | |
357 | 375 | b->align(FL_ALIGN_WRAP|FL_ALIGN_CLIP); |
358 | 376 | b->box(FL_UP_BOX); |
359 | 377 | b->callback(choice5_cb, INT2VOIDP(i)); |
425 | 443 | |
426 | 444 | /* "OK" button */ |
427 | 445 | y += input_h + 20; |
428 | Fl_Button *ok_button = new Fl_Button(200, y, 50, button_h, "OK"); | |
446 | Fl_Button *ok_button = new EnterButton(200, y, 50, button_h, "OK"); | |
429 | 447 | ok_button->labelsize(14); |
430 | 448 | ok_button->callback(Dialog_user_password_cb); |
431 | 449 | window->add(ok_button); |
432 | 450 | |
433 | 451 | /* "Cancel" button */ |
434 | 452 | Fl_Button *cancel_button = |
435 | new Fl_Button(50, y, 100, button_h, "Cancel"); | |
453 | new EnterButton(50, y, 100, button_h, "Cancel"); | |
436 | 454 | cancel_button->labelsize(14); |
437 | 455 | cancel_button->callback(Dialog_user_password_cb); |
438 | 456 | window->add(cancel_button); |
0 | /* | |
1 | * File: digest.c | |
2 | * | |
3 | * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | */ | |
10 | ||
11 | #include <stdlib.h> | |
12 | #include "digest.h" | |
13 | #include "md5.h" | |
14 | #include "msg.h" | |
15 | #include "../dlib/dlib.h" | |
16 | ||
17 | static const char *ALGORITHM2STR[] = { NULL, "MD5", "MD5-sess" }; | |
18 | static const char *QOP2STR[] = { NULL, "auth", "auth-int" }; | |
19 | static const char hexchars[] = "0123456789abcdef"; | |
20 | ||
21 | static Dstr *md5hexdigest(const Dstr *data) | |
22 | { | |
23 | md5_state_t state; | |
24 | md5_byte_t digest[16]; | |
25 | Dstr *result = dStr_sized_new(33); | |
26 | int i; | |
27 | ||
28 | md5_init(&state); | |
29 | md5_append(&state, (const md5_byte_t *)data->str, data->len); | |
30 | md5_finish(&state, digest); | |
31 | ||
32 | for (i = 0; i < 16; i++) | |
33 | dStr_sprintfa(result, "%02x", digest[i]); | |
34 | return result; | |
35 | } | |
36 | ||
37 | /* | |
38 | * Returns a pointer to a newly allocated string containing a cnonce | |
39 | */ | |
40 | char *a_Digest_create_cnonce(void) | |
41 | { | |
42 | int i; | |
43 | char *result = dNew(char, 33); | |
44 | for (i = 0; i < 32; i++) | |
45 | result[i] = hexchars[rand() % 16]; | |
46 | result[32] = 0; | |
47 | return result; | |
48 | } | |
49 | ||
50 | /* | |
51 | * This portion only has to be calculated once. | |
52 | */ | |
53 | int a_Digest_compute_digest(AuthRealm_t *realm, const char *username, | |
54 | const char *passwd) | |
55 | { | |
56 | Dstr *a1; | |
57 | Dstr *digest; | |
58 | ||
59 | if (realm->algorithm == MD5 || realm->algorithm == ALGORITHMNOTSET) { | |
60 | /* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */ | |
61 | a1 = dStr_new(NULL); | |
62 | dStr_sprintf(a1, "%s:%s:%s", username, realm->name, passwd); | |
63 | } else if (realm->algorithm == MD5SESS) { | |
64 | /* A1 = H( unq(username-value) ":" unq(realm-value) | |
65 | ** ":" passwd ) | |
66 | ** ":" unq(nonce-value) ":" unq(cnonce-value) | |
67 | */ | |
68 | Dstr *a0 = dStr_new(NULL); | |
69 | dStr_sprintf(a0, "%s:%s:%s", username, realm->name, passwd); | |
70 | Dstr *ha0 = md5hexdigest(a0); | |
71 | a1 = dStr_new(NULL); | |
72 | dStr_sprintf(a1, "%s:%s:%s", ha0, realm->nonce, realm->cnonce); | |
73 | dStr_free(a0, 1); | |
74 | dStr_free(ha0, 1); | |
75 | } else { | |
76 | MSG("a_Digest_create_auth: Unknown algorithm.\n"); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | digest = md5hexdigest(a1); | |
81 | realm->authorization = digest->str; | |
82 | dStr_shred(a1); | |
83 | dStr_free(a1, 1); | |
84 | dStr_free(digest, 0); | |
85 | return 1; | |
86 | } | |
87 | ||
88 | /* | |
89 | * This portion is calculatd for each request. | |
90 | */ | |
91 | static Dstr *Digest_create_response(AuthRealm_t *realm, const char *method, | |
92 | const char *digest_uri, | |
93 | const Dstr *entity_body) | |
94 | { | |
95 | Dstr *ha2; | |
96 | Dstr *result; | |
97 | ||
98 | if (realm->qop == QOPNOTSET || realm->qop == AUTH) { | |
99 | /* A2 = Method ":" digest-uri-value */ | |
100 | Dstr *a2 = dStr_new(NULL); | |
101 | dStr_sprintf(a2, "%s:%s", method, digest_uri); | |
102 | ha2 = md5hexdigest(a2); | |
103 | dStr_free(a2, 1); | |
104 | } else if (realm->qop == AUTHINT) { | |
105 | /* A2 = Method ":" digest-uri-value ":" H(entity-body) */ | |
106 | Dstr *hentity = md5hexdigest(entity_body); | |
107 | Dstr *a2 = dStr_new(NULL); | |
108 | dStr_sprintf(a2, "%s:%s:%s", method, digest_uri, hentity->str); | |
109 | ha2 = md5hexdigest(a2); | |
110 | dStr_free(hentity, 1); | |
111 | dStr_free(a2, 1); | |
112 | } else { | |
113 | MSG("a_Digest_create_auth: Unknown qop value.\n"); | |
114 | return NULL; | |
115 | } | |
116 | result = dStr_new(NULL); | |
117 | ||
118 | if (realm->qop == AUTH || realm->qop == AUTHINT) { | |
119 | dStr_sprintf(result, | |
120 | "%s:%s:%08x:%s:%s:%s", | |
121 | realm->authorization, | |
122 | realm->nonce, | |
123 | realm->nonce_count, | |
124 | realm->cnonce, | |
125 | QOP2STR[realm->qop], | |
126 | ha2->str); | |
127 | } else { | |
128 | dStr_sprintf(result, | |
129 | "%s:%s:%s", | |
130 | realm->authorization, | |
131 | realm->nonce, | |
132 | ha2->str); | |
133 | } | |
134 | ||
135 | Dstr *request_digest = md5hexdigest(result); | |
136 | dStr_free(result, 1); | |
137 | dStr_free(ha2, 1); | |
138 | return request_digest; | |
139 | } | |
140 | ||
141 | static void Digest_Dstr_append_token_value(Dstr *str, int delimiter, | |
142 | const char *token, | |
143 | const char *value, int quoted) | |
144 | { | |
145 | char c; | |
146 | dStr_sprintfa(str, "%s%s=", (delimiter ? ", " : ""), token); | |
147 | if (quoted) { | |
148 | dStr_append_c(str, '"'); | |
149 | while ((c = *value++)) { | |
150 | if (c == '"') | |
151 | dStr_append_c(str, '\\'); | |
152 | dStr_append_c(str, c); | |
153 | } | |
154 | dStr_append_c(str, '"'); | |
155 | } else { | |
156 | dStr_append(str, value); | |
157 | } | |
158 | } | |
159 | ||
160 | /* | |
161 | * Construct Digest Authorization header. | |
162 | * | |
163 | * Field ordering: furaisanjin reports that his DVD recorder requires the | |
164 | * order that IE happens to use: "username, realm, nonce, uri, cnonce, nc, | |
165 | * algorithm, response, qop". It apparently doesn't use "opaque", so that's | |
166 | * been left where it already was. | |
167 | */ | |
168 | char *a_Digest_authorization_hdr(AuthRealm_t *realm, const DilloUrl *url, | |
169 | const char *digest_uri) | |
170 | { | |
171 | char *ret; | |
172 | Dstr *response, *result; | |
173 | const char *method = URL_FLAGS(url) & URL_Post ? "POST" : "GET"; | |
174 | ||
175 | realm->nonce_count++; | |
176 | response = Digest_create_response(realm, method, digest_uri, URL_DATA(url)); | |
177 | if (!response) | |
178 | return NULL; | |
179 | result = dStr_new("Authorization: Digest "); | |
180 | Digest_Dstr_append_token_value(result, 0, "username", realm->username, 1); | |
181 | Digest_Dstr_append_token_value(result, 1, "realm", realm->name, 1); | |
182 | Digest_Dstr_append_token_value(result, 1, "nonce", realm->nonce, 1); | |
183 | Digest_Dstr_append_token_value(result, 1, "uri", digest_uri, 1); | |
184 | if (realm->qop != QOPNOTSET) { | |
185 | Digest_Dstr_append_token_value(result, 1, "cnonce", realm->cnonce, 1); | |
186 | dStr_sprintfa(result, ", nc=%08x", realm->nonce_count); | |
187 | } | |
188 | if (realm->algorithm != ALGORITHMNOTSET) { | |
189 | Digest_Dstr_append_token_value(result, 1, "algorithm", | |
190 | ALGORITHM2STR[realm->algorithm], 0); | |
191 | } | |
192 | Digest_Dstr_append_token_value(result, 1, "response", response->str, 1); | |
193 | if (realm->opaque) | |
194 | Digest_Dstr_append_token_value(result, 1, "opaque", realm->opaque, 1); | |
195 | if (realm->qop != QOPNOTSET) | |
196 | Digest_Dstr_append_token_value(result, 1, "qop", QOP2STR[realm->qop], 1); | |
197 | dStr_sprintfa(result, "\r\n"); | |
198 | ||
199 | dStr_free(response, 1); | |
200 | ret = result->str; | |
201 | dStr_free(result, 0); | |
202 | return ret; | |
203 | } |
0 | #ifndef __DIGEST_H__ | |
1 | #define __DIGEST_H__ | |
2 | ||
3 | #include "auth.h" | |
4 | #include "../dlib/dlib.h" | |
5 | ||
6 | ||
7 | char *a_Digest_create_cnonce(void); | |
8 | int a_Digest_compute_digest(AuthRealm_t *realm, | |
9 | const char *username, | |
10 | const char *passwd); | |
11 | char *a_Digest_authorization_hdr(AuthRealm_t *realm, | |
12 | const DilloUrl *url, | |
13 | const char *uri); | |
14 | ||
15 | #endif /* !__DIGEST_H__ */ |
409 | 409 | |
410 | 410 | if (idx == argc) { |
411 | 411 | /* No URLs/files on cmdline. Send startup screen */ |
412 | if (strcmp(URL_STR(prefs.start_page), "about:blank") == 0) | |
412 | if (dStrAsciiCasecmp(URL_SCHEME(prefs.start_page), "about") == 0 && | |
413 | strcmp(URL_PATH(prefs.start_page), "blank") == 0) | |
413 | 414 | a_UIcmd_open_url(bw, NULL); |
414 | 415 | else |
415 | 416 | a_UIcmd_open_url(bw, prefs.start_page); |
112 | 112 | int i; |
113 | 113 | |
114 | 114 | for (i = 0; i < dns_queue_size; i++) |
115 | if (!strcmp(hostname, dns_queue[i].hostname)) | |
115 | if (!dStrAsciiCasecmp(hostname, dns_queue[i].hostname)) | |
116 | 116 | return i; |
117 | 117 | |
118 | 118 | return -1; |
376 | 376 | |
377 | 377 | /* check for cache hit. */ |
378 | 378 | for (i = 0; i < dns_cache_size; i++) |
379 | if (!strcmp(hostname, dns_cache[i].hostname)) | |
379 | if (!dStrAsciiCasecmp(hostname, dns_cache[i].hostname)) | |
380 | 380 | break; |
381 | 381 | |
382 | 382 | if (i < dns_cache_size) { |
444 | 444 | * with the same hostname*/ |
445 | 445 | for (j = i; j < dns_queue_size; j++) |
446 | 446 | if (dns_queue[j].channel == -2 && |
447 | !strcmp(dns_queue[j].hostname, dns_queue[i].hostname)) | |
447 | !dStrAsciiCasecmp(dns_queue[j].hostname, | |
448 | dns_queue[i].hostname)) { | |
448 | 449 | dns_queue[j].channel = ch; |
450 | } | |
449 | 451 | Dns_server_req(ch, dns_queue[i].hostname); |
450 | 452 | } else |
451 | 453 | return; |
270 | 270 | for (int idx = 0; idx < inputs->size(); idx++) { |
271 | 271 | DilloHtmlInput *input = inputs->get(idx); |
272 | 272 | if (input->type == DILLO_HTML_INPUT_RADIO && |
273 | input->name && !dStrcasecmp(input->name, name)) | |
273 | input->name && !dStrAsciiCasecmp(input->name, name)) | |
274 | 274 | return input; |
275 | 275 | } |
276 | 276 | } |
317 | 317 | |
318 | 318 | method = DILLO_HTML_METHOD_GET; |
319 | 319 | if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "method"))) { |
320 | if (!dStrcasecmp(attrbuf, "post")) { | |
320 | if (!dStrAsciiCasecmp(attrbuf, "post")) { | |
321 | 321 | method = DILLO_HTML_METHOD_POST; |
322 | } else if (dStrcasecmp(attrbuf, "get")) { | |
322 | } else if (dStrAsciiCasecmp(attrbuf, "get")) { | |
323 | 323 | BUG_MSG("Unknown form submission method \"%s\"\n", attrbuf); |
324 | 324 | } |
325 | 325 | } |
332 | 332 | content_type = DILLO_HTML_ENC_URLENCODED; |
333 | 333 | if ((method == DILLO_HTML_METHOD_POST) && |
334 | 334 | ((attrbuf = a_Html_get_attr(html, tag, tagsize, "enctype")))) { |
335 | if (!dStrcasecmp(attrbuf, "multipart/form-data")) | |
335 | if (!dStrAsciiCasecmp(attrbuf, "multipart/form-data")) | |
336 | 336 | content_type = DILLO_HTML_ENC_MULTIPART; |
337 | 337 | } |
338 | 338 | charset = NULL; |
342 | 342 | char *ptr = first = dStrdup(attrbuf); |
343 | 343 | while (ptr && !charset) { |
344 | 344 | char *curr = dStrsep(&ptr, " ,"); |
345 | if (!dStrcasecmp(curr, "utf-8")) { | |
345 | if (!dStrAsciiCasecmp(curr, "utf-8")) { | |
346 | 346 | charset = curr; |
347 | } else if (!dStrcasecmp(curr, "UNKNOWN")) { | |
347 | } else if (!dStrAsciiCasecmp(curr, "UNKNOWN")) { | |
348 | 348 | /* defined to be whatever encoding the document is in */ |
349 | 349 | charset = html->charset; |
350 | 350 | } |
440 | 440 | |
441 | 441 | init_str = NULL; |
442 | 442 | inp_type = DILLO_HTML_INPUT_UNKNOWN; |
443 | if (!dStrcasecmp(type, "password")) { | |
443 | if (!dStrAsciiCasecmp(type, "password")) { | |
444 | 444 | inp_type = DILLO_HTML_INPUT_PASSWORD; |
445 | 445 | attrbuf = a_Html_get_attr(html, tag, tagsize, "size"); |
446 | 446 | int size = Html_input_get_size(html, attrbuf); |
447 | 447 | resource = factory->createEntryResource (size, true, NULL); |
448 | 448 | init_str = value; |
449 | } else if (!dStrcasecmp(type, "checkbox")) { | |
449 | } else if (!dStrAsciiCasecmp(type, "checkbox")) { | |
450 | 450 | inp_type = DILLO_HTML_INPUT_CHECKBOX; |
451 | 451 | resource = factory->createCheckButtonResource(false); |
452 | 452 | init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL); |
453 | 453 | init_str = (value) ? value : dStrdup("on"); |
454 | } else if (!dStrcasecmp(type, "radio")) { | |
454 | } else if (!dStrAsciiCasecmp(type, "radio")) { | |
455 | 455 | inp_type = DILLO_HTML_INPUT_RADIO; |
456 | 456 | RadioButtonResource *rb_r = NULL; |
457 | 457 | DilloHtmlInput *input = Html_get_radio_input(html, name); |
460 | 460 | resource = factory->createRadioButtonResource(rb_r, false); |
461 | 461 | init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL); |
462 | 462 | init_str = value; |
463 | } else if (!dStrcasecmp(type, "hidden")) { | |
463 | } else if (!dStrAsciiCasecmp(type, "hidden")) { | |
464 | 464 | inp_type = DILLO_HTML_INPUT_HIDDEN; |
465 | 465 | init_str = value; |
466 | 466 | int size = Html_input_get_size(html, NULL); |
467 | 467 | resource = factory->createEntryResource(size, false, name); |
468 | } else if (!dStrcasecmp(type, "submit")) { | |
468 | } else if (!dStrAsciiCasecmp(type, "submit")) { | |
469 | 469 | inp_type = DILLO_HTML_INPUT_SUBMIT; |
470 | 470 | init_str = (value) ? value : dStrdup("submit"); |
471 | 471 | resource = factory->createLabelButtonResource(init_str); |
472 | 472 | // gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */ |
473 | } else if (!dStrcasecmp(type, "reset")) { | |
473 | } else if (!dStrAsciiCasecmp(type, "reset")) { | |
474 | 474 | inp_type = DILLO_HTML_INPUT_RESET; |
475 | 475 | init_str = (value) ? value : dStrdup("Reset"); |
476 | 476 | resource = factory->createLabelButtonResource(init_str); |
477 | 477 | // gtk_widget_set_sensitive(widget, FALSE); /* Until end of FORM! */ |
478 | } else if (!dStrcasecmp(type, "image")) { | |
478 | } else if (!dStrAsciiCasecmp(type, "image")) { | |
479 | 479 | if (URL_FLAGS(html->base_url) & URL_SpamSafe) { |
480 | 480 | /* Don't request the image; make a text submit button instead */ |
481 | 481 | inp_type = DILLO_HTML_INPUT_SUBMIT; |
490 | 490 | embed = Html_input_image(html, tag, tagsize); |
491 | 491 | init_str = value; |
492 | 492 | } |
493 | } else if (!dStrcasecmp(type, "file")) { | |
493 | } else if (!dStrAsciiCasecmp(type, "file")) { | |
494 | 494 | bool valid = true; |
495 | 495 | if (html->InFlags & IN_FORM) { |
496 | 496 | DilloHtmlForm *form = html->getCurrentForm(); |
511 | 511 | init_str = dStrdup("File selector"); |
512 | 512 | resource = factory->createLabelButtonResource(init_str); |
513 | 513 | } |
514 | } else if (!dStrcasecmp(type, "button")) { | |
514 | } else if (!dStrAsciiCasecmp(type, "button")) { | |
515 | 515 | inp_type = DILLO_HTML_INPUT_BUTTON; |
516 | 516 | if (value) { |
517 | 517 | init_str = value; |
518 | 518 | resource = factory->createLabelButtonResource(init_str); |
519 | 519 | } |
520 | } else if (!dStrcasecmp(type, "text") || !*type) { | |
520 | } else { | |
521 | 521 | /* Text input, which also is the default */ |
522 | 522 | inp_type = DILLO_HTML_INPUT_TEXT; |
523 | if (*type && dStrAsciiCasecmp(type, "text")) | |
524 | BUG_MSG("Unknown input type: \"%s\"\n", type); | |
523 | 525 | attrbuf = a_Html_get_attr(html, tag, tagsize, "size"); |
524 | 526 | int size = Html_input_get_size(html, attrbuf); |
525 | 527 | resource = factory->createEntryResource(size, false, NULL); |
526 | 528 | init_str = value; |
527 | } else { | |
528 | /* Unknown input type */ | |
529 | BUG_MSG("Unknown input type: \"%s\"\n", type); | |
530 | } | |
531 | ||
529 | } | |
532 | 530 | if (resource) |
533 | 531 | embed = new Embed (resource); |
534 | 532 | |
832 | 830 | |
833 | 831 | type = a_Html_get_attr_wdef(html, tag, tagsize, "type", ""); |
834 | 832 | |
835 | if (!dStrcasecmp(type, "button")) { | |
833 | if (!dStrAsciiCasecmp(type, "button")) { | |
836 | 834 | inp_type = DILLO_HTML_INPUT_BUTTON; |
837 | } else if (!dStrcasecmp(type, "reset")) { | |
835 | } else if (!dStrAsciiCasecmp(type, "reset")) { | |
838 | 836 | inp_type = DILLO_HTML_INPUT_BUTTON_RESET; |
839 | } else if (!dStrcasecmp(type, "submit") || !*type) { | |
837 | } else if (!dStrAsciiCasecmp(type, "submit") || !*type) { | |
840 | 838 | /* submit button is the default */ |
841 | 839 | inp_type = DILLO_HTML_INPUT_BUTTON_SUBMIT; |
842 | 840 | } else { |
1035 | 1033 | char *boundary = NULL; |
1036 | 1034 | iconv_t char_encoder = (iconv_t) -1; |
1037 | 1035 | |
1038 | if (submit_charset && dStrcasecmp(submit_charset, "UTF-8")) { | |
1036 | if (submit_charset && dStrAsciiCasecmp(submit_charset, "UTF-8")) { | |
1039 | 1037 | char_encoder = iconv_open(submit_charset, "UTF-8"); |
1040 | 1038 | if (char_encoder == (iconv_t) -1) { |
1041 | 1039 | MSG_WARN("Cannot convert to character encoding '%s'\n", |
1309 | 1307 | (void)a_Misc_get_content_type_from_data(file->str, file->len, &ctype); |
1310 | 1308 | /* Heuristic: text/plain with ".htm[l]" extension -> text/html */ |
1311 | 1309 | if ((ext = strrchr(filename, '.')) && |
1312 | !dStrcasecmp(ctype, "text/plain") && | |
1313 | (!dStrcasecmp(ext, ".html") || !dStrcasecmp(ext, ".htm"))) { | |
1310 | !dStrAsciiCasecmp(ctype, "text/plain") && | |
1311 | (!dStrAsciiCasecmp(ext, ".html") || !dStrAsciiCasecmp(ext, ".htm"))){ | |
1314 | 1312 | ctype = "text/html"; |
1315 | 1313 | } |
1316 | 1314 | |
1475 | 1473 | for (int idx = 0; idx < inputs->size(); idx++) { |
1476 | 1474 | DilloHtmlInput *input = inputs->get(idx); |
1477 | 1475 | if (input->type == DILLO_HTML_INPUT_RADIO && |
1478 | input->name && !dStrcasecmp(input->name, name)) | |
1476 | input->name && !dStrAsciiCasecmp(input->name, name)) | |
1479 | 1477 | return input; |
1480 | 1478 | } |
1481 | 1479 | return NULL; |
15 | 15 | /*----------------------------------------------------------------------------- |
16 | 16 | * Includes |
17 | 17 | *---------------------------------------------------------------------------*/ |
18 | #include <ctype.h> /* for isspace and tolower */ | |
18 | #include <ctype.h> /* for isspace */ | |
19 | 19 | #include <string.h> /* for memcpy and memmove */ |
20 | 20 | #include <stdlib.h> |
21 | 21 | #include <stdio.h> /* for sprintf */ |
310 | 310 | if ((align = a_Html_get_attr(html, tag, tagsize, "align"))) { |
311 | 311 | TextAlignType textAlignType = TEXT_ALIGN_LEFT; |
312 | 312 | |
313 | if (dStrcasecmp (align, "left") == 0) | |
313 | if (dStrAsciiCasecmp (align, "left") == 0) | |
314 | 314 | textAlignType = TEXT_ALIGN_LEFT; |
315 | else if (dStrcasecmp (align, "right") == 0) | |
315 | else if (dStrAsciiCasecmp (align, "right") == 0) | |
316 | 316 | textAlignType = TEXT_ALIGN_RIGHT; |
317 | else if (dStrcasecmp (align, "center") == 0) | |
317 | else if (dStrAsciiCasecmp (align, "center") == 0) | |
318 | 318 | textAlignType = TEXT_ALIGN_CENTER; |
319 | else if (dStrcasecmp (align, "justify") == 0) | |
319 | else if (dStrAsciiCasecmp (align, "justify") == 0) | |
320 | 320 | textAlignType = TEXT_ALIGN_JUSTIFY; |
321 | 321 | #if 0 |
322 | else if (dStrcasecmp (align, "char") == 0) { | |
322 | else if (dStrAsciiCasecmp (align, "char") == 0) { | |
323 | 323 | /* TODO: Actually not supported for <p> etc. */ |
324 | 324 | v.textAlign = TEXT_ALIGN_STRING; |
325 | 325 | if ((charattr = a_Html_get_attr(html, tag, tagsize, "char"))) { |
351 | 351 | VAlignType valign; |
352 | 352 | |
353 | 353 | if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) { |
354 | if (dStrcasecmp (attr, "top") == 0) | |
354 | if (dStrAsciiCasecmp (attr, "top") == 0) | |
355 | 355 | valign = VALIGN_TOP; |
356 | else if (dStrcasecmp (attr, "bottom") == 0) | |
356 | else if (dStrAsciiCasecmp (attr, "bottom") == 0) | |
357 | 357 | valign = VALIGN_BOTTOM; |
358 | else if (dStrcasecmp (attr, "baseline") == 0) | |
358 | else if (dStrAsciiCasecmp (attr, "baseline") == 0) | |
359 | 359 | valign = VALIGN_BASELINE; |
360 | 360 | else |
361 | 361 | valign = VALIGN_MIDDLE; |
1106 | 1106 | } |
1107 | 1107 | |
1108 | 1108 | if (spaceCnt) { |
1109 | // add break possibility for the white-space:pre-wrap case | |
1110 | HT2TB(html)->addBreakOption (html->styleEngine->wordStyle ()); | |
1109 | 1111 | spc = dStrnfill(spaceCnt, ' '); |
1110 | 1112 | HT2TB(html)->addText (spc, spaceCnt, html->styleEngine->wordStyle ()); |
1111 | 1113 | dFree(spc); |
1207 | 1209 | Html_process_space(html, word2 + start, i - start); |
1208 | 1210 | } else if (!strncmp(word2+i, utf8_zero_width_space, 3)) { |
1209 | 1211 | i += 3; |
1212 | HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ()); | |
1210 | 1213 | } else if (a_Utf8_ideographic(word2+i, beyond_word2, &len)) { |
1211 | 1214 | i += len; |
1212 | 1215 | HT2TB(html)->addText(word2 + start, i - start, |
1213 | 1216 | html->styleEngine->wordStyle ()); |
1217 | HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ()); | |
1214 | 1218 | } else { |
1215 | 1219 | do { |
1216 | 1220 | i += len; |
1235 | 1239 | int i; |
1236 | 1240 | |
1237 | 1241 | for (i = 0; i < tagsize && tagstr[i] != '\0'; i++) { |
1238 | if (tolower(tagstr[i]) != tolower(tag[i])) | |
1242 | if (D_ASCII_TOLOWER(tagstr[i]) != D_ASCII_TOLOWER(tag[i])) | |
1239 | 1243 | return false; |
1240 | 1244 | } |
1241 | 1245 | /* The test for '/' is for xml compatibility: "empty/>" will be matched. */ |
1457 | 1461 | int i; |
1458 | 1462 | |
1459 | 1463 | for (i = 0; val[i]; ++i) |
1460 | if (!(isalnum(val[i]) || strchr(":_.-", val[i]))) | |
1464 | if (!isascii(val[i]) || !(isalnum(val[i]) || strchr(":_.-", val[i]))) | |
1461 | 1465 | break; |
1462 | 1466 | |
1463 | if (val[i] || !isalpha(val[0])) | |
1467 | if (val[i] || !(isascii(val[0]) && isalpha(val[0]))) | |
1464 | 1468 | BUG_MSG("'%s' value is not of the form " |
1465 | 1469 | "[A-Za-z][A-Za-z0-9:_.-]*\n", attrname); |
1466 | 1470 | |
1525 | 1529 | _MSG("New: {%s}\n", ntag); |
1526 | 1530 | |
1527 | 1531 | /* The default DT_NONE type is TagSoup */ |
1528 | if (!dStrncasecmp(ntag, HTML_SGML_sig, strlen(HTML_SGML_sig))) { | |
1532 | if (!dStrnAsciiCasecmp(ntag, HTML_SGML_sig, strlen(HTML_SGML_sig))) { | |
1529 | 1533 | p = ntag + strlen(HTML_SGML_sig) + 1; |
1530 | 1534 | if (!strncmp(p, HTML401, strlen(HTML401)) && |
1531 | dStristr(p + strlen(HTML401), HTML401_url)) { | |
1535 | dStriAsciiStr(p + strlen(HTML401), HTML401_url)) { | |
1532 | 1536 | html->DocType = DT_HTML; |
1533 | 1537 | html->DocTypeVersion = 4.01f; |
1534 | 1538 | } else if (!strncmp(p, XHTML1, strlen(XHTML1)) && |
1535 | dStristr(p + strlen(XHTML1), XHTML1_url)) { | |
1539 | dStriAsciiStr(p + strlen(XHTML1), XHTML1_url)) { | |
1536 | 1540 | html->DocType = DT_XHTML; |
1537 | 1541 | html->DocTypeVersion = 1.0f; |
1538 | 1542 | } else if (!strncmp(p, XHTML11, strlen(XHTML11)) && |
1539 | dStristr(p + strlen(XHTML11), XHTML11_url)) { | |
1543 | dStriAsciiStr(p + strlen(XHTML11), XHTML11_url)) { | |
1540 | 1544 | html->DocType = DT_XHTML; |
1541 | 1545 | html->DocTypeVersion = 1.1f; |
1542 | 1546 | } else if (!strncmp(p, HTML40, strlen(HTML40))) { |
1549 | 1553 | html->DocType = DT_HTML; |
1550 | 1554 | html->DocTypeVersion = 2.0f; |
1551 | 1555 | } |
1552 | } else if (!dStrcasecmp(ntag, HTML5_sig)) { | |
1556 | } else if (!dStrAsciiCasecmp(ntag, HTML5_sig)) { | |
1553 | 1557 | BUG_MSG("Document follows HTML5 working draft; treating as HTML4.\n"); |
1554 | 1558 | html->DocType = DT_HTML; |
1555 | 1559 | html->DocTypeVersion = 5.0f; |
1682 | 1686 | |
1683 | 1687 | if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { |
1684 | 1688 | BUG_MSG("type attribute is required for <style>\n"); |
1685 | } else if (dStrcasecmp(attrbuf, "text/css")) { | |
1689 | } else if (dStrAsciiCasecmp(attrbuf, "text/css")) { | |
1686 | 1690 | html->loadCssFromStash = false; |
1687 | 1691 | } |
1688 | 1692 | if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) && |
1689 | dStrcasecmp(attrbuf, "all") && !dStristr(attrbuf, "screen")) { | |
1693 | dStrAsciiCasecmp(attrbuf, "all") && !dStriAsciiStr(attrbuf, "screen")) { | |
1690 | 1694 | /* HTML 4.01 sec. 6.13 says that media descriptors are case-sensitive, |
1691 | 1695 | * but sec. 14.2.3 says that the attribute is case-insensitive. |
1692 | 1696 | * TODO can be a comma-separated list. |
1855 | 1859 | textblock->addWidget(bullet, html->styleEngine->wordStyle ()); |
1856 | 1860 | textblock->addSpace(html->styleEngine->wordStyle ()); |
1857 | 1861 | |
1858 | if (tolower(tag[1]) == 'i') { | |
1862 | if (D_ASCII_TOLOWER(tag[1]) == 'i') { | |
1859 | 1863 | /* IFRAME usually comes with very long advertising/spying URLS, |
1860 | 1864 | * to not break rendering we will force name="IFRAME" */ |
1861 | 1865 | textblock->addText ("IFRAME", html->styleEngine->wordStyle ()); |
2115 | 2119 | Image->bg_color = HT2TB(html)->getBgColor()->getColor(); |
2116 | 2120 | |
2117 | 2121 | load_now = prefs.load_images || |
2118 | !dStrcasecmp(URL_SCHEME(url), "data") || | |
2122 | !dStrAsciiCasecmp(URL_SCHEME(url), "data") || | |
2119 | 2123 | (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached); |
2120 | 2124 | bool loading = false; |
2121 | 2125 | if (load_now) |
2287 | 2291 | } |
2288 | 2292 | attrbuf = a_Html_get_attr(html, tag, tagsize, "shape"); |
2289 | 2293 | |
2290 | if (!attrbuf || !*attrbuf || !dStrcasecmp(attrbuf, "rect")) { | |
2294 | if (!attrbuf || !*attrbuf || !dStrAsciiCasecmp(attrbuf, "rect")) { | |
2291 | 2295 | /* the default shape is a rectangle */ |
2292 | 2296 | type = RECTANGLE; |
2293 | } else if (dStrcasecmp(attrbuf, "default") == 0) { | |
2297 | } else if (dStrAsciiCasecmp(attrbuf, "default") == 0) { | |
2294 | 2298 | /* "default" is the background */ |
2295 | 2299 | type = BACKGROUND; |
2296 | } else if (dStrcasecmp(attrbuf, "circle") == 0) { | |
2300 | } else if (dStrAsciiCasecmp(attrbuf, "circle") == 0) { | |
2297 | 2301 | type = CIRCLE; |
2298 | } else if (dStrncasecmp(attrbuf, "poly", 4) == 0) { | |
2302 | } else if (dStrnAsciiCasecmp(attrbuf, "poly", 4) == 0) { | |
2299 | 2303 | type = POLYGON; |
2300 | 2304 | } else { |
2301 | 2305 | BUG_MSG("<area> unknown shape: \"%s\"\n", attrbuf); |
2389 | 2393 | char ch, *p1, *p2; |
2390 | 2394 | Dstr *Buf = html->attr_data; |
2391 | 2395 | |
2392 | if (dStrncasecmp("javascript", Buf->str, 10) == 0) { | |
2396 | if (dStrnAsciiCasecmp("javascript", Buf->str, 10) == 0) { | |
2393 | 2397 | i = strcspn(Buf->str, "'\""); |
2394 | 2398 | ch = Buf->str[i]; |
2395 | 2399 | if ((ch == '"' || ch == '\'') && |
2435 | 2439 | |
2436 | 2440 | if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "href"))) { |
2437 | 2441 | /* if it's a javascript link, extract the reference. */ |
2438 | if (tolower(attrbuf[0]) == 'j') | |
2442 | if (D_ASCII_TOLOWER(attrbuf[0]) == 'j') | |
2439 | 2443 | attrbuf = Html_get_javascript_link(html); |
2440 | 2444 | |
2441 | 2445 | url = a_Html_url_new(html, attrbuf, NULL, 0); |
2543 | 2547 | if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { |
2544 | 2548 | |
2545 | 2549 | /* list_style_type explicitly defined */ |
2546 | if (dStrcasecmp(attrbuf, "disc") == 0) | |
2550 | if (dStrAsciiCasecmp(attrbuf, "disc") == 0) | |
2547 | 2551 | list_style_type = LIST_STYLE_TYPE_DISC; |
2548 | else if (dStrcasecmp(attrbuf, "circle") == 0) | |
2552 | else if (dStrAsciiCasecmp(attrbuf, "circle") == 0) | |
2549 | 2553 | list_style_type = LIST_STYLE_TYPE_CIRCLE; |
2550 | else if (dStrcasecmp(attrbuf, "square") == 0) | |
2554 | else if (dStrAsciiCasecmp(attrbuf, "square") == 0) | |
2551 | 2555 | list_style_type = LIST_STYLE_TYPE_SQUARE; |
2552 | 2556 | else |
2553 | 2557 | /* invalid value */ |
2848 | 2852 | } |
2849 | 2853 | |
2850 | 2854 | if ((equiv = a_Html_get_attr(html, tag, tagsize, "http-equiv"))) { |
2851 | if (!dStrcasecmp(equiv, "refresh") && | |
2855 | if (!dStrAsciiCasecmp(equiv, "refresh") && | |
2852 | 2856 | (content = a_Html_get_attr(html, tag, tagsize, "content"))) { |
2853 | 2857 | |
2854 | 2858 | /* Get delay, if present, and make a message with it */ |
2900 | 2904 | a_Url_free(new_url); |
2901 | 2905 | dFree(mr_url); |
2902 | 2906 | |
2903 | } else if (!dStrcasecmp(equiv, "content-type") && | |
2907 | } else if (!dStrAsciiCasecmp(equiv, "content-type") && | |
2904 | 2908 | (content = a_Html_get_attr(html, tag, tagsize, "content"))) { |
2905 | 2909 | _MSG("Html_tag_open_meta: content={%s}\n", content); |
2906 | 2910 | /* Cannot ask cache whether the content type was changed, as |
3005 | 3009 | dReturn_if_fail (prefs.load_stylesheets); |
3006 | 3010 | /* CSS stylesheet link */ |
3007 | 3011 | if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "rel")) || |
3008 | dStrcasecmp(attrbuf, "stylesheet")) | |
3012 | dStrAsciiCasecmp(attrbuf, "stylesheet")) | |
3009 | 3013 | return; |
3010 | 3014 | |
3011 | 3015 | /* IMPLIED attributes? */ |
3012 | 3016 | if (((attrbuf = a_Html_get_attr(html, tag, tagsize, "type")) && |
3013 | dStrcasecmp(attrbuf, "text/css")) || | |
3017 | dStrAsciiCasecmp(attrbuf, "text/css")) || | |
3014 | 3018 | ((attrbuf = a_Html_get_attr(html, tag, tagsize, "media")) && |
3015 | !dStristr(attrbuf, "screen") && dStrcasecmp(attrbuf, "all"))) | |
3019 | !dStriAsciiStr(attrbuf, "screen") && dStrAsciiCasecmp(attrbuf, "all"))) | |
3016 | 3020 | return; |
3017 | 3021 | |
3018 | 3022 | if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "href")) || |
3226 | 3230 | static int Html_tag_compare(const char *p1, const char *p2) |
3227 | 3231 | { |
3228 | 3232 | while ( *p2 ) { |
3229 | if (tolower(*p1) != *p2) | |
3230 | return(tolower(*p1) - *p2); | |
3233 | if (D_ASCII_TOLOWER(*p1) != *p2) | |
3234 | return(D_ASCII_TOLOWER(*p1) - *p2); | |
3231 | 3235 | ++p1; |
3232 | 3236 | ++p2; |
3233 | 3237 | } |
3469 | 3473 | if (ni == -1) { |
3470 | 3474 | /* TODO: doctype parsing is a bit fuzzy, but enough for the time being */ |
3471 | 3475 | if (!(html->InFlags & IN_HTML)) { |
3472 | if (tagsize > 9 && !dStrncasecmp(tag, "<!doctype", 9)) | |
3476 | if (tagsize > 9 && !dStrnAsciiCasecmp(tag, "<!doctype", 9)) | |
3473 | 3477 | Html_parse_doctype(html, tag, tagsize); |
3474 | 3478 | } |
3475 | 3479 | /* Ignore unknown tags */ |
3586 | 3590 | (tag[i] == '=' || isspace(tag[i]) || tag[i] == '>')))) { |
3587 | 3591 | state = SEEK_TOKEN_START; |
3588 | 3592 | --i; |
3589 | } else if (tolower(tag[i]) != tolower(attrname[attr_pos++])) | |
3590 | state = SEEK_ATTR_START; | |
3593 | } else { | |
3594 | if (D_ASCII_TOLOWER(tag[i]) != D_ASCII_TOLOWER(attrname[attr_pos])) | |
3595 | state = SEEK_ATTR_START; | |
3596 | attr_pos++; | |
3597 | } | |
3591 | 3598 | break; |
3592 | 3599 | |
3593 | 3600 | case SEEK_TOKEN_START: |
102 | 102 | { "new-tab" , KEYS_NEW_TAB , FL_CTRL , 't' }, |
103 | 103 | { "left-tab" , KEYS_LEFT_TAB , FL_CTRL | |
104 | 104 | FL_SHIFT , FL_Tab }, |
105 | { "left-tab" , KEYS_LEFT_TAB , FL_CTRL , FL_Page_Up }, | |
105 | 106 | { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Tab }, |
107 | { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Page_Down }, | |
106 | 108 | { "close-tab" , KEYS_CLOSE_TAB , FL_CTRL , 'w' }, |
107 | 109 | { "find" , KEYS_FIND , FL_CTRL , 'f' }, |
108 | 110 | { "websearch" , KEYS_WEBSEARCH , FL_CTRL , 's' }, |
242 | 244 | { |
243 | 245 | uint_t i; |
244 | 246 | for (i = 0; i < sizeof(keyNames) / sizeof(Mapping_t); i++) { |
245 | if (!dStrcasecmp(keyNames[i].name, keyName)) { | |
247 | if (!dStrAsciiCasecmp(keyNames[i].name, keyName)) { | |
246 | 248 | return keyNames[i].value; |
247 | 249 | } |
248 | 250 | } |
259 | 261 | uint_t i; |
260 | 262 | |
261 | 263 | for (i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) { |
262 | if (!dStrcasecmp(default_keys[i].name, commandName)) | |
264 | if (!dStrAsciiCasecmp(default_keys[i].name, commandName)) | |
263 | 265 | return default_keys[i].cmd; |
264 | 266 | } |
265 | 267 | return KEYS_INVALID; |
273 | 275 | { |
274 | 276 | uint_t i; |
275 | 277 | for (i = 0; i < sizeof(modifierNames) / sizeof(Mapping_t); i++) { |
276 | if (!dStrcasecmp(modifierNames[i].name, modifierName)) { | |
278 | if (!dStrAsciiCasecmp(modifierNames[i].name, modifierName)) { | |
277 | 279 | return modifierNames[i].value; |
278 | 280 | } |
279 | 281 | } |
39 | 39 | |
40 | 40 | # "left-tab" and "right-tab" switch to the left/right of the current tab. |
41 | 41 | # <ctrl><shift>tab = left-tab |
42 | # <ctrl>PageUp = left-tab | |
42 | 43 | # <ctrl>tab = right-tab |
44 | # <ctrl>PageDown = right-tab | |
43 | 45 | |
44 | 46 | # "back" and "forward" move back/forward through the browser history. |
45 | 47 | #backspace = back |
0 | /* | |
1 | * md5.c was taken from "RFC1321-based (RSA-free) MD5 library" by L. Peter | |
2 | * Deutsch at http://sourceforge.net/projects/libmd5-rfc/ in October 2011. | |
3 | * | |
4 | * The code was not modified when integrated into the Dillo project, but you | |
5 | * should check the source repository to be sure that there have not been | |
6 | * modifications since this notice. | |
7 | */ | |
8 | ||
9 | /* | |
10 | Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. | |
11 | ||
12 | This software is provided 'as-is', without any express or implied | |
13 | warranty. In no event will the authors be held liable for any damages | |
14 | arising from the use of this software. | |
15 | ||
16 | Permission is granted to anyone to use this software for any purpose, | |
17 | including commercial applications, and to alter it and redistribute it | |
18 | freely, subject to the following restrictions: | |
19 | ||
20 | 1. The origin of this software must not be misrepresented; you must not | |
21 | claim that you wrote the original software. If you use this software | |
22 | in a product, an acknowledgment in the product documentation would be | |
23 | appreciated but is not required. | |
24 | 2. Altered source versions must be plainly marked as such, and must not be | |
25 | misrepresented as being the original software. | |
26 | 3. This notice may not be removed or altered from any source distribution. | |
27 | ||
28 | L. Peter Deutsch | |
29 | ghost@aladdin.com | |
30 | ||
31 | */ | |
32 | /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ | |
33 | /* | |
34 | Independent implementation of MD5 (RFC 1321). | |
35 | ||
36 | This code implements the MD5 Algorithm defined in RFC 1321, whose | |
37 | text is available at | |
38 | http://www.ietf.org/rfc/rfc1321.txt | |
39 | The code is derived from the text of the RFC, including the test suite | |
40 | (section A.5) but excluding the rest of Appendix A. It does not include | |
41 | any code or documentation that is identified in the RFC as being | |
42 | copyrighted. | |
43 | ||
44 | The original and principal author of md5.c is L. Peter Deutsch | |
45 | <ghost@aladdin.com>. Other authors are noted in the change history | |
46 | that follows (in reverse chronological order): | |
47 | ||
48 | 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order | |
49 | either statically or dynamically; added missing #include <string.h> | |
50 | in library. | |
51 | 2002-03-11 lpd Corrected argument list for main(), and added int return | |
52 | type, in test program and T value program. | |
53 | 2002-02-21 lpd Added missing #include <stdio.h> in test program. | |
54 | 2000-07-03 lpd Patched to eliminate warnings about "constant is | |
55 | unsigned in ANSI C, signed in traditional"; made test program | |
56 | self-checking. | |
57 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. | |
58 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). | |
59 | 1999-05-03 lpd Original version. | |
60 | */ | |
61 | ||
62 | #include "md5.h" | |
63 | #include <string.h> | |
64 | ||
65 | #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ | |
66 | #ifdef ARCH_IS_BIG_ENDIAN | |
67 | # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) | |
68 | #else | |
69 | # define BYTE_ORDER 0 | |
70 | #endif | |
71 | ||
72 | #define T_MASK ((md5_word_t)~0) | |
73 | #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) | |
74 | #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) | |
75 | #define T3 0x242070db | |
76 | #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) | |
77 | #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) | |
78 | #define T6 0x4787c62a | |
79 | #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) | |
80 | #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) | |
81 | #define T9 0x698098d8 | |
82 | #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) | |
83 | #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) | |
84 | #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) | |
85 | #define T13 0x6b901122 | |
86 | #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) | |
87 | #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) | |
88 | #define T16 0x49b40821 | |
89 | #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) | |
90 | #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) | |
91 | #define T19 0x265e5a51 | |
92 | #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) | |
93 | #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) | |
94 | #define T22 0x02441453 | |
95 | #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) | |
96 | #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) | |
97 | #define T25 0x21e1cde6 | |
98 | #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) | |
99 | #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) | |
100 | #define T28 0x455a14ed | |
101 | #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) | |
102 | #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) | |
103 | #define T31 0x676f02d9 | |
104 | #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) | |
105 | #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) | |
106 | #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) | |
107 | #define T35 0x6d9d6122 | |
108 | #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) | |
109 | #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) | |
110 | #define T38 0x4bdecfa9 | |
111 | #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) | |
112 | #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) | |
113 | #define T41 0x289b7ec6 | |
114 | #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) | |
115 | #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) | |
116 | #define T44 0x04881d05 | |
117 | #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) | |
118 | #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) | |
119 | #define T47 0x1fa27cf8 | |
120 | #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) | |
121 | #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) | |
122 | #define T50 0x432aff97 | |
123 | #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) | |
124 | #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) | |
125 | #define T53 0x655b59c3 | |
126 | #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) | |
127 | #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) | |
128 | #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) | |
129 | #define T57 0x6fa87e4f | |
130 | #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) | |
131 | #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) | |
132 | #define T60 0x4e0811a1 | |
133 | #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) | |
134 | #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) | |
135 | #define T63 0x2ad7d2bb | |
136 | #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) | |
137 | ||
138 | ||
139 | static void | |
140 | md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) | |
141 | { | |
142 | md5_word_t | |
143 | a = pms->abcd[0], b = pms->abcd[1], | |
144 | c = pms->abcd[2], d = pms->abcd[3]; | |
145 | md5_word_t t; | |
146 | #if BYTE_ORDER > 0 | |
147 | /* Define storage only for big-endian CPUs. */ | |
148 | md5_word_t X[16]; | |
149 | #else | |
150 | /* Define storage for little-endian or both types of CPUs. */ | |
151 | md5_word_t xbuf[16]; | |
152 | const md5_word_t *X; | |
153 | #endif | |
154 | ||
155 | { | |
156 | #if BYTE_ORDER == 0 | |
157 | /* | |
158 | * Determine dynamically whether this is a big-endian or | |
159 | * little-endian machine, since we can use a more efficient | |
160 | * algorithm on the latter. | |
161 | */ | |
162 | static const int w = 1; | |
163 | ||
164 | if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ | |
165 | #endif | |
166 | #if BYTE_ORDER <= 0 /* little-endian */ | |
167 | { | |
168 | /* | |
169 | * On little-endian machines, we can process properly aligned | |
170 | * data without copying it. | |
171 | */ | |
172 | if (!((data - (const md5_byte_t *)0) & 3)) { | |
173 | /* data are properly aligned */ | |
174 | X = (const md5_word_t *)data; | |
175 | } else { | |
176 | /* not aligned */ | |
177 | memcpy(xbuf, data, 64); | |
178 | X = xbuf; | |
179 | } | |
180 | } | |
181 | #endif | |
182 | #if BYTE_ORDER == 0 | |
183 | else /* dynamic big-endian */ | |
184 | #endif | |
185 | #if BYTE_ORDER >= 0 /* big-endian */ | |
186 | { | |
187 | /* | |
188 | * On big-endian machines, we must arrange the bytes in the | |
189 | * right order. | |
190 | */ | |
191 | const md5_byte_t *xp = data; | |
192 | int i; | |
193 | ||
194 | # if BYTE_ORDER == 0 | |
195 | X = xbuf; /* (dynamic only) */ | |
196 | # else | |
197 | # define xbuf X /* (static only) */ | |
198 | # endif | |
199 | for (i = 0; i < 16; ++i, xp += 4) | |
200 | xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); | |
201 | } | |
202 | #endif | |
203 | } | |
204 | ||
205 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) | |
206 | ||
207 | /* Round 1. */ | |
208 | /* Let [abcd k s i] denote the operation | |
209 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ | |
210 | #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) | |
211 | #define SET(a, b, c, d, k, s, Ti)\ | |
212 | t = a + F(b,c,d) + X[k] + Ti;\ | |
213 | a = ROTATE_LEFT(t, s) + b | |
214 | /* Do the following 16 operations. */ | |
215 | SET(a, b, c, d, 0, 7, T1); | |
216 | SET(d, a, b, c, 1, 12, T2); | |
217 | SET(c, d, a, b, 2, 17, T3); | |
218 | SET(b, c, d, a, 3, 22, T4); | |
219 | SET(a, b, c, d, 4, 7, T5); | |
220 | SET(d, a, b, c, 5, 12, T6); | |
221 | SET(c, d, a, b, 6, 17, T7); | |
222 | SET(b, c, d, a, 7, 22, T8); | |
223 | SET(a, b, c, d, 8, 7, T9); | |
224 | SET(d, a, b, c, 9, 12, T10); | |
225 | SET(c, d, a, b, 10, 17, T11); | |
226 | SET(b, c, d, a, 11, 22, T12); | |
227 | SET(a, b, c, d, 12, 7, T13); | |
228 | SET(d, a, b, c, 13, 12, T14); | |
229 | SET(c, d, a, b, 14, 17, T15); | |
230 | SET(b, c, d, a, 15, 22, T16); | |
231 | #undef SET | |
232 | ||
233 | /* Round 2. */ | |
234 | /* Let [abcd k s i] denote the operation | |
235 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ | |
236 | #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) | |
237 | #define SET(a, b, c, d, k, s, Ti)\ | |
238 | t = a + G(b,c,d) + X[k] + Ti;\ | |
239 | a = ROTATE_LEFT(t, s) + b | |
240 | /* Do the following 16 operations. */ | |
241 | SET(a, b, c, d, 1, 5, T17); | |
242 | SET(d, a, b, c, 6, 9, T18); | |
243 | SET(c, d, a, b, 11, 14, T19); | |
244 | SET(b, c, d, a, 0, 20, T20); | |
245 | SET(a, b, c, d, 5, 5, T21); | |
246 | SET(d, a, b, c, 10, 9, T22); | |
247 | SET(c, d, a, b, 15, 14, T23); | |
248 | SET(b, c, d, a, 4, 20, T24); | |
249 | SET(a, b, c, d, 9, 5, T25); | |
250 | SET(d, a, b, c, 14, 9, T26); | |
251 | SET(c, d, a, b, 3, 14, T27); | |
252 | SET(b, c, d, a, 8, 20, T28); | |
253 | SET(a, b, c, d, 13, 5, T29); | |
254 | SET(d, a, b, c, 2, 9, T30); | |
255 | SET(c, d, a, b, 7, 14, T31); | |
256 | SET(b, c, d, a, 12, 20, T32); | |
257 | #undef SET | |
258 | ||
259 | /* Round 3. */ | |
260 | /* Let [abcd k s t] denote the operation | |
261 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ | |
262 | #define H(x, y, z) ((x) ^ (y) ^ (z)) | |
263 | #define SET(a, b, c, d, k, s, Ti)\ | |
264 | t = a + H(b,c,d) + X[k] + Ti;\ | |
265 | a = ROTATE_LEFT(t, s) + b | |
266 | /* Do the following 16 operations. */ | |
267 | SET(a, b, c, d, 5, 4, T33); | |
268 | SET(d, a, b, c, 8, 11, T34); | |
269 | SET(c, d, a, b, 11, 16, T35); | |
270 | SET(b, c, d, a, 14, 23, T36); | |
271 | SET(a, b, c, d, 1, 4, T37); | |
272 | SET(d, a, b, c, 4, 11, T38); | |
273 | SET(c, d, a, b, 7, 16, T39); | |
274 | SET(b, c, d, a, 10, 23, T40); | |
275 | SET(a, b, c, d, 13, 4, T41); | |
276 | SET(d, a, b, c, 0, 11, T42); | |
277 | SET(c, d, a, b, 3, 16, T43); | |
278 | SET(b, c, d, a, 6, 23, T44); | |
279 | SET(a, b, c, d, 9, 4, T45); | |
280 | SET(d, a, b, c, 12, 11, T46); | |
281 | SET(c, d, a, b, 15, 16, T47); | |
282 | SET(b, c, d, a, 2, 23, T48); | |
283 | #undef SET | |
284 | ||
285 | /* Round 4. */ | |
286 | /* Let [abcd k s t] denote the operation | |
287 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ | |
288 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) | |
289 | #define SET(a, b, c, d, k, s, Ti)\ | |
290 | t = a + I(b,c,d) + X[k] + Ti;\ | |
291 | a = ROTATE_LEFT(t, s) + b | |
292 | /* Do the following 16 operations. */ | |
293 | SET(a, b, c, d, 0, 6, T49); | |
294 | SET(d, a, b, c, 7, 10, T50); | |
295 | SET(c, d, a, b, 14, 15, T51); | |
296 | SET(b, c, d, a, 5, 21, T52); | |
297 | SET(a, b, c, d, 12, 6, T53); | |
298 | SET(d, a, b, c, 3, 10, T54); | |
299 | SET(c, d, a, b, 10, 15, T55); | |
300 | SET(b, c, d, a, 1, 21, T56); | |
301 | SET(a, b, c, d, 8, 6, T57); | |
302 | SET(d, a, b, c, 15, 10, T58); | |
303 | SET(c, d, a, b, 6, 15, T59); | |
304 | SET(b, c, d, a, 13, 21, T60); | |
305 | SET(a, b, c, d, 4, 6, T61); | |
306 | SET(d, a, b, c, 11, 10, T62); | |
307 | SET(c, d, a, b, 2, 15, T63); | |
308 | SET(b, c, d, a, 9, 21, T64); | |
309 | #undef SET | |
310 | ||
311 | /* Then perform the following additions. (That is increment each | |
312 | of the four registers by the value it had before this block | |
313 | was started.) */ | |
314 | pms->abcd[0] += a; | |
315 | pms->abcd[1] += b; | |
316 | pms->abcd[2] += c; | |
317 | pms->abcd[3] += d; | |
318 | } | |
319 | ||
320 | void | |
321 | md5_init(md5_state_t *pms) | |
322 | { | |
323 | pms->count[0] = pms->count[1] = 0; | |
324 | pms->abcd[0] = 0x67452301; | |
325 | pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; | |
326 | pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; | |
327 | pms->abcd[3] = 0x10325476; | |
328 | } | |
329 | ||
330 | void | |
331 | md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) | |
332 | { | |
333 | const md5_byte_t *p = data; | |
334 | int left = nbytes; | |
335 | int offset = (pms->count[0] >> 3) & 63; | |
336 | md5_word_t nbits = (md5_word_t)(nbytes << 3); | |
337 | ||
338 | if (nbytes <= 0) | |
339 | return; | |
340 | ||
341 | /* Update the message length. */ | |
342 | pms->count[1] += nbytes >> 29; | |
343 | pms->count[0] += nbits; | |
344 | if (pms->count[0] < nbits) | |
345 | pms->count[1]++; | |
346 | ||
347 | /* Process an initial partial block. */ | |
348 | if (offset) { | |
349 | int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); | |
350 | ||
351 | memcpy(pms->buf + offset, p, copy); | |
352 | if (offset + copy < 64) | |
353 | return; | |
354 | p += copy; | |
355 | left -= copy; | |
356 | md5_process(pms, pms->buf); | |
357 | } | |
358 | ||
359 | /* Process full blocks. */ | |
360 | for (; left >= 64; p += 64, left -= 64) | |
361 | md5_process(pms, p); | |
362 | ||
363 | /* Process a final partial block. */ | |
364 | if (left) | |
365 | memcpy(pms->buf, p, left); | |
366 | } | |
367 | ||
368 | void | |
369 | md5_finish(md5_state_t *pms, md5_byte_t digest[16]) | |
370 | { | |
371 | static const md5_byte_t pad[64] = { | |
372 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
373 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
374 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
375 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
376 | }; | |
377 | md5_byte_t data[8]; | |
378 | int i; | |
379 | ||
380 | /* Save the length before padding. */ | |
381 | for (i = 0; i < 8; ++i) | |
382 | data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); | |
383 | /* Pad to 56 bytes mod 64. */ | |
384 | md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); | |
385 | /* Append the length. */ | |
386 | md5_append(pms, data, 8); | |
387 | for (i = 0; i < 16; ++i) | |
388 | digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); | |
389 | } |
0 | /* | |
1 | * md5.h was taken from "RFC1321-based (RSA-free) MD5 library" by L. Peter | |
2 | * Deutsch at http://sourceforge.net/projects/libmd5-rfc/ in October 2011. | |
3 | * | |
4 | * The code was not modified when integrated into the Dillo project, but you | |
5 | * should check the source repository to be sure that there have not been | |
6 | * modifications since this notice. | |
7 | */ | |
8 | ||
9 | /* | |
10 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. | |
11 | ||
12 | This software is provided 'as-is', without any express or implied | |
13 | warranty. In no event will the authors be held liable for any damages | |
14 | arising from the use of this software. | |
15 | ||
16 | Permission is granted to anyone to use this software for any purpose, | |
17 | including commercial applications, and to alter it and redistribute it | |
18 | freely, subject to the following restrictions: | |
19 | ||
20 | 1. The origin of this software must not be misrepresented; you must not | |
21 | claim that you wrote the original software. If you use this software | |
22 | in a product, an acknowledgment in the product documentation would be | |
23 | appreciated but is not required. | |
24 | 2. Altered source versions must be plainly marked as such, and must not be | |
25 | misrepresented as being the original software. | |
26 | 3. This notice may not be removed or altered from any source distribution. | |
27 | ||
28 | L. Peter Deutsch | |
29 | ghost@aladdin.com | |
30 | ||
31 | */ | |
32 | /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ | |
33 | /* | |
34 | Independent implementation of MD5 (RFC 1321). | |
35 | ||
36 | This code implements the MD5 Algorithm defined in RFC 1321, whose | |
37 | text is available at | |
38 | http://www.ietf.org/rfc/rfc1321.txt | |
39 | The code is derived from the text of the RFC, including the test suite | |
40 | (section A.5) but excluding the rest of Appendix A. It does not include | |
41 | any code or documentation that is identified in the RFC as being | |
42 | copyrighted. | |
43 | ||
44 | The original and principal author of md5.h is L. Peter Deutsch | |
45 | <ghost@aladdin.com>. Other authors are noted in the change history | |
46 | that follows (in reverse chronological order): | |
47 | ||
48 | 2002-04-13 lpd Removed support for non-ANSI compilers; removed | |
49 | references to Ghostscript; clarified derivation from RFC 1321; | |
50 | now handles byte order either statically or dynamically. | |
51 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. | |
52 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); | |
53 | added conditionalization for C++ compilation from Martin | |
54 | Purschke <purschke@bnl.gov>. | |
55 | 1999-05-03 lpd Original version. | |
56 | */ | |
57 | ||
58 | #ifndef md5_INCLUDED | |
59 | # define md5_INCLUDED | |
60 | ||
61 | /* | |
62 | * This package supports both compile-time and run-time determination of CPU | |
63 | * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be | |
64 | * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is | |
65 | * defined as non-zero, the code will be compiled to run only on big-endian | |
66 | * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to | |
67 | * run on either big- or little-endian CPUs, but will run slightly less | |
68 | * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. | |
69 | */ | |
70 | ||
71 | typedef unsigned char md5_byte_t; /* 8-bit byte */ | |
72 | typedef unsigned int md5_word_t; /* 32-bit word */ | |
73 | ||
74 | /* Define the state of the MD5 Algorithm. */ | |
75 | typedef struct md5_state_s { | |
76 | md5_word_t count[2]; /* message length in bits, lsw first */ | |
77 | md5_word_t abcd[4]; /* digest buffer */ | |
78 | md5_byte_t buf[64]; /* accumulate block */ | |
79 | } md5_state_t; | |
80 | ||
81 | #ifdef __cplusplus | |
82 | extern "C" | |
83 | { | |
84 | #endif | |
85 | ||
86 | /* Initialize the algorithm. */ | |
87 | void md5_init(md5_state_t *pms); | |
88 | ||
89 | /* Append a string to the message. */ | |
90 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); | |
91 | ||
92 | /* Finish the message and return the digest. */ | |
93 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); | |
94 | ||
95 | #ifdef __cplusplus | |
96 | } /* end extern "C" */ | |
97 | #endif | |
98 | ||
99 | #endif /* md5_INCLUDED */ |
206 | 206 | |
207 | 207 | static void Menu_stylesheet_cb(Fl_Widget*, void *vUrl) |
208 | 208 | { |
209 | int mb = Fl::event_button(); | |
209 | 210 | const DilloUrl *url = (const DilloUrl *) vUrl; |
210 | a_UIcmd_open_url(popup_bw, url); | |
211 | ||
212 | if (mb == 1) { | |
213 | a_UIcmd_open_url(popup_bw, url); | |
214 | } else if (mb == 2) { | |
215 | if (prefs.middle_click_opens_new_tab) { | |
216 | int focus = prefs.focus_new_tab ? 1 : 0; | |
217 | if (Fl::event_state(FL_SHIFT)) focus = !focus; | |
218 | a_UIcmd_open_url_nt(popup_bw, url, focus); | |
219 | } else { | |
220 | a_UIcmd_open_url_nw(popup_bw, url); | |
221 | } | |
222 | } | |
211 | 223 | } |
212 | 224 | |
213 | 225 | /* |
314 | 326 | |
315 | 327 | has_bugs == TRUE ? pm[1].activate() : pm[1].deactivate(); |
316 | 328 | |
317 | if (strncmp(URL_STR(url), "dpi:/vsource/", 13) == 0) | |
329 | if (dStrAsciiCasecmp(URL_SCHEME(url), "dpi") == 0 && | |
330 | strncmp(URL_PATH(url), "/vsource/", 9) == 0) | |
318 | 331 | pm[0].deactivate(); |
319 | 332 | else |
320 | 333 | pm[0].activate(); |
140 | 140 | |
141 | 141 | /* HTML try */ |
142 | 142 | for (i = 0; i < Size && dIsspace(p[i]); ++i); |
143 | if ((Size - i >= 5 && !dStrncasecmp(p+i, "<html", 5)) || | |
144 | (Size - i >= 5 && !dStrncasecmp(p+i, "<head", 5)) || | |
145 | (Size - i >= 6 && !dStrncasecmp(p+i, "<title", 6)) || | |
146 | (Size - i >= 14 && !dStrncasecmp(p+i, "<!doctype html", 14)) || | |
143 | if ((Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<html", 5)) || | |
144 | (Size - i >= 5 && !dStrnAsciiCasecmp(p+i, "<head", 5)) || | |
145 | (Size - i >= 6 && !dStrnAsciiCasecmp(p+i, "<title", 6)) || | |
146 | (Size - i >= 14 && !dStrnAsciiCasecmp(p+i, "<!doctype html", 14)) || | |
147 | 147 | /* this line is workaround for FTP through the Squid proxy */ |
148 | (Size - i >= 17 && !dStrncasecmp(p+i, "<!-- HTML listing", 17))) { | |
148 | (Size - i >= 17 && !dStrnAsciiCasecmp(p+i, "<!-- HTML listing", 17))) { | |
149 | 149 | |
150 | 150 | Type = DT_TEXT_HTML; |
151 | 151 | st = 0; |
152 | 152 | /* Images */ |
153 | } else if (Size >= 4 && !dStrncasecmp(p, "GIF8", 4)) { | |
153 | } else if (Size >= 4 && !strncmp(p, "GIF8", 4)) { | |
154 | 154 | Type = DT_IMAGE_GIF; |
155 | 155 | st = 0; |
156 | } else if (Size >= 4 && !dStrncasecmp(p, "\x89PNG", 4)) { | |
156 | } else if (Size >= 4 && !strncmp(p, "\x89PNG", 4)) { | |
157 | 157 | Type = DT_IMAGE_PNG; |
158 | 158 | st = 0; |
159 | } else if (Size >= 2 && !dStrncasecmp(p, "\xff\xd8", 2)) { | |
159 | } else if (Size >= 2 && !strncmp(p, "\xff\xd8", 2)) { | |
160 | 160 | /* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking |
161 | 161 | * at the character representation should be machine independent. */ |
162 | 162 | Type = DT_IMAGE_JPG; |
220 | 220 | if (!(str = type)) |
221 | 221 | return; |
222 | 222 | |
223 | for (s = str; *s && !iscntrl((uchar_t)*s) && !strchr(tspecials_space, *s); | |
224 | s++) ; | |
223 | for (s = str; *s && isascii((uchar_t)*s) && !iscntrl((uchar_t)*s) && | |
224 | !strchr(tspecials_space, *s); s++) ; | |
225 | 225 | if (major) |
226 | 226 | *major = dStrndup(str, s - str); |
227 | 227 | |
228 | 228 | if (*s == '/') { |
229 | for (str = ++s; | |
230 | *s && !iscntrl((uchar_t)*s) && !strchr(tspecials_space, *s); s++) ; | |
229 | for (str = ++s; *s && isascii((uchar_t)*s) && !iscntrl((uchar_t)*s) && | |
230 | !strchr(tspecials_space, *s); s++) ; | |
231 | 231 | if (minor) |
232 | 232 | *minor = dStrndup(str, s - str); |
233 | 233 | } |
234 | 234 | if (charset && *s && |
235 | (dStrncasecmp(type, "text/", 5) == 0 || | |
236 | dStrncasecmp(type, "application/xhtml+xml", 21) == 0)) { | |
235 | (dStrnAsciiCasecmp(type, "text/", 5) == 0 || | |
236 | dStrnAsciiCasecmp(type, "application/xhtml+xml", 21) == 0)) { | |
237 | 237 | /* "charset" parameter defined for text media type in RFC 2046, |
238 | 238 | * application/xhtml+xml in RFC 3236. |
239 | 239 | * |
245 | 245 | const char terminators[] = " ;\t"; |
246 | 246 | const char key[] = "charset"; |
247 | 247 | |
248 | if ((s = dStristr(str, key)) && | |
248 | if ((s = dStriAsciiStr(str, key)) && | |
249 | 249 | (s == str || strchr(terminators, s[-1]))) { |
250 | 250 | s += sizeof(key) - 1; |
251 | 251 | for ( ; *s == ' ' || *s == '\t'; ++s); |
282 | 282 | a_Misc_parse_content_type(ct1, &major1, &minor1, &charset1); |
283 | 283 | a_Misc_parse_content_type(ct2, &major2, &minor2, &charset2); |
284 | 284 | |
285 | if (major1 && major2 && !dStrcasecmp(major1, major2) && | |
286 | minor1 && minor2 && !dStrcasecmp(minor1, minor2) && | |
285 | if (major1 && major2 && !dStrAsciiCasecmp(major1, major2) && | |
286 | minor1 && minor2 && !dStrAsciiCasecmp(minor1, minor2) && | |
287 | 287 | ((!charset1 && !charset2) || |
288 | (charset1 && charset2 && !dStrcasecmp(charset1, charset2)) || | |
289 | (!charset1 && charset2 && !dStrcasecmp(charset2, "UTF-8")) || | |
290 | (charset1 && !charset2 && !dStrcasecmp(charset1, "UTF-8")))) { | |
288 | (charset1 && charset2 && !dStrAsciiCasecmp(charset1, charset2)) || | |
289 | (!charset1 && charset2 && !dStrAsciiCasecmp(charset2, "UTF-8")) || | |
290 | (charset1 && !charset2 && !dStrAsciiCasecmp(charset1, "UTF-8")))) { | |
291 | 291 | ret = 0; |
292 | 292 | } else { |
293 | 293 | ret = 1; |
327 | 327 | return 0; /* there's no mismatch without server type */ |
328 | 328 | |
329 | 329 | for (i = 1; MimeTypes[i].str; ++i) |
330 | if (dStrncasecmp(EntryType, MimeTypes[i].str, MimeTypes[i].len) == 0) | |
330 | if (dStrnAsciiCasecmp(EntryType, MimeTypes[i].str, MimeTypes[i].len) ==0) | |
331 | 331 | break; |
332 | 332 | |
333 | 333 | if (!MimeTypes[i].str) { |
334 | 334 | /* type not found, no mismatch */ |
335 | 335 | st = 0; |
336 | } else if (dStrncasecmp(EntryType, "image/", 6) == 0 && | |
337 | !dStrncasecmp(DetectedType,MimeTypes[i].str,MimeTypes[i].len)){ | |
336 | } else if (dStrnAsciiCasecmp(EntryType, "image/", 6) == 0 && | |
337 | !dStrnAsciiCasecmp(DetectedType, MimeTypes[i].str, | |
338 | MimeTypes[i].len)){ | |
338 | 339 | /* An image, and there's an exact match */ |
339 | 340 | st = 0; |
340 | } else if (dStrncasecmp(EntryType, "text/", 5) || | |
341 | dStrncasecmp(DetectedType, "application/", 12)) { | |
341 | } else if (dStrnAsciiCasecmp(EntryType, "text/", 5) || | |
342 | dStrnAsciiCasecmp(DetectedType, "application/", 12)) { | |
342 | 343 | /* Not an application sent as text */ |
343 | 344 | st = 0; |
344 | } else if (dStrncasecmp(EntryType, "application/xhtml+xml", 21) && | |
345 | dStrncasecmp(DetectedType, "text/html", 9)) { | |
345 | } else if (dStrnAsciiCasecmp(EntryType, "application/xhtml+xml", 21) && | |
346 | dStrnAsciiCasecmp(DetectedType, "text/html", 9)) { | |
346 | 347 | /* XML version of HTML */ |
347 | 348 | st = 0; |
348 | 349 | } |
480 | 480 | a_Nav_cancel_expect(bw); |
481 | 481 | if (a_Nav_stack_size(bw)) { |
482 | 482 | h_url = a_History_get_url(NAV_TOP_UIDX(bw)); |
483 | if (strncmp(URL_STR(h_url), "dpi:/vsource/", 13) == 0) { | |
484 | /* disable reload for view source dpi */ | |
485 | confirmed = 0; | |
483 | if (dStrAsciiCasecmp(URL_SCHEME(h_url), "dpi") == 0 && | |
484 | strncmp(URL_PATH(h_url), "/vsource/", 9) == 0) { | |
485 | /* allow reload for view source dpi */ | |
486 | confirmed = 1; | |
486 | 487 | } else if (URL_FLAGS(h_url) & URL_Post) { |
487 | 488 | /* Attempt to repost data, let's confirm... */ |
488 | 489 | choice = a_Dialog_choice5("Repost form data?", |
126 | 126 | |
127 | 127 | switch (node->type) { |
128 | 128 | case PREFS_BOOL: |
129 | *(bool_t *)node->pref = (!dStrcasecmp(value, "yes") || | |
130 | !dStrcasecmp(value, "true")); | |
129 | *(bool_t *)node->pref = (!dStrAsciiCasecmp(value, "yes") || | |
130 | !dStrAsciiCasecmp(value, "true")); | |
131 | 131 | break; |
132 | 132 | case PREFS_COLOR: |
133 | 133 | *(int32_t *)node->pref = a_Color_parse(value, *(int32_t*)node->pref,&st); |
166 | 166 | &prefs.width, &prefs.height); |
167 | 167 | break; |
168 | 168 | case PREFS_FILTER: |
169 | if (!dStrcasecmp(value, "same_domain")) | |
169 | if (!dStrAsciiCasecmp(value, "same_domain")) | |
170 | 170 | prefs.filter_auto_requests = PREFS_FILTER_SAME_DOMAIN; |
171 | 171 | else { |
172 | if (dStrcasecmp(value, "allow_all")) | |
172 | if (dStrAsciiCasecmp(value, "allow_all")) | |
173 | 173 | MSG_WARN("prefs: unrecognized value for filter_auto_requests\n"); |
174 | 174 | prefs.filter_auto_requests = PREFS_FILTER_ALLOW_ALL; |
175 | 175 | } |
176 | 176 | break; |
177 | 177 | case PREFS_PANEL_SIZE: |
178 | if (!dStrcasecmp(value, "tiny")) | |
178 | if (!dStrAsciiCasecmp(value, "tiny")) | |
179 | 179 | prefs.panel_size = P_tiny; |
180 | else if (!dStrcasecmp(value, "small")) | |
180 | else if (!dStrAsciiCasecmp(value, "small")) | |
181 | 181 | prefs.panel_size = P_small; |
182 | 182 | else /* default to "medium" */ |
183 | 183 | prefs.panel_size = P_medium; |
302 | 302 | *c = '\0'; |
303 | 303 | dStrstrip(p->value.strVal); |
304 | 304 | |
305 | if (strcmp (p->value.strVal, "serif") == 0) | |
305 | if (dStrAsciiCasecmp (p->value.strVal, "serif") == 0) | |
306 | 306 | fontName = prefs.font_serif; |
307 | else if (strcmp (p->value.strVal, "sans-serif") == 0) | |
307 | else if (dStrAsciiCasecmp (p->value.strVal, "sans-serif") == 0) | |
308 | 308 | fontName = prefs.font_sans_serif; |
309 | else if (strcmp (p->value.strVal, "cursive") == 0) | |
309 | else if (dStrAsciiCasecmp (p->value.strVal, "cursive") == 0) | |
310 | 310 | fontName = prefs.font_cursive; |
311 | else if (strcmp (p->value.strVal, "fantasy") == 0) | |
311 | else if (dStrAsciiCasecmp (p->value.strVal, "fantasy") == 0) | |
312 | 312 | fontName = prefs.font_fantasy; |
313 | else if (strcmp (p->value.strVal, "monospace") == 0) | |
313 | else if (dStrAsciiCasecmp (p->value.strVal, "monospace") == 0) | |
314 | 314 | fontName = prefs.font_monospace; |
315 | 315 | else if (Font::exists(layout, p->value.strVal)) |
316 | 316 | fontName = p->value.strVal; |
330 | 330 | if (p->type == CSS_TYPE_ENUM) { |
331 | 331 | switch (p->value.intVal) { |
332 | 332 | case CSS_FONT_SIZE_XX_SMALL: |
333 | fontAttrs.size = roundInt(11.0 * prefs.font_factor); | |
333 | fontAttrs.size = roundInt(8.1 * prefs.font_factor); | |
334 | 334 | break; |
335 | 335 | case CSS_FONT_SIZE_X_SMALL: |
336 | fontAttrs.size = roundInt(12.0 * prefs.font_factor); | |
336 | fontAttrs.size = roundInt(9.7 * prefs.font_factor); | |
337 | 337 | break; |
338 | 338 | case CSS_FONT_SIZE_SMALL: |
339 | fontAttrs.size = roundInt(13.0 * prefs.font_factor); | |
339 | fontAttrs.size = roundInt(11.7 * prefs.font_factor); | |
340 | 340 | break; |
341 | 341 | case CSS_FONT_SIZE_MEDIUM: |
342 | 342 | fontAttrs.size = roundInt(14.0 * prefs.font_factor); |
343 | 343 | break; |
344 | 344 | case CSS_FONT_SIZE_LARGE: |
345 | fontAttrs.size = roundInt(16.8 * prefs.font_factor); | |
345 | 346 | break; |
346 | 347 | case CSS_FONT_SIZE_X_LARGE: |
347 | fontAttrs.size = roundInt(16.0 * prefs.font_factor); | |
348 | fontAttrs.size = roundInt(20.2 * prefs.font_factor); | |
348 | 349 | break; |
349 | 350 | case CSS_FONT_SIZE_XX_LARGE: |
350 | fontAttrs.size = roundInt(17.0 * prefs.font_factor); | |
351 | fontAttrs.size = roundInt(24.2 * prefs.font_factor); | |
351 | 352 | break; |
352 | 353 | case CSS_FONT_SIZE_SMALLER: |
353 | fontAttrs.size -= roundInt(1.0 * prefs.font_factor); | |
354 | fontAttrs.size = roundInt(fontAttrs.size * 0.83 * | |
355 | prefs.font_factor); | |
354 | 356 | break; |
355 | 357 | case CSS_FONT_SIZE_LARGER: |
356 | fontAttrs.size += roundInt(1.0 * prefs.font_factor); | |
358 | fontAttrs.size = roundInt(fontAttrs.size * 1.2 * | |
359 | prefs.font_factor); | |
357 | 360 | break; |
358 | 361 | default: |
359 | 362 | assert(false); // invalid font-size enum |
560 | 563 | break; |
561 | 564 | case CSS_PROPERTY_TEXT_INDENT: |
562 | 565 | computeLength (&attrs->textIndent, p->value.intVal, attrs->font); |
566 | break; | |
567 | case CSS_PROPERTY_TEXT_TRANSFORM: | |
568 | attrs->textTransform = (TextTransform) p->value.intVal; | |
563 | 569 | break; |
564 | 570 | case CSS_PROPERTY_VERTICAL_ALIGN: |
565 | 571 | attrs->valign = (VAlignType) p->value.intVal; |
80 | 80 | a_Html_parse_length (html, attrbuf)); |
81 | 81 | |
82 | 82 | if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) { |
83 | if (dStrcasecmp (attrbuf, "left") == 0) | |
83 | if (dStrAsciiCasecmp (attrbuf, "left") == 0) | |
84 | 84 | html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN, |
85 | 85 | CSS_TYPE_ENUM, TEXT_ALIGN_LEFT); |
86 | else if (dStrcasecmp (attrbuf, "right") == 0) | |
86 | else if (dStrAsciiCasecmp (attrbuf, "right") == 0) | |
87 | 87 | html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN, |
88 | 88 | CSS_TYPE_ENUM, TEXT_ALIGN_RIGHT); |
89 | else if (dStrcasecmp (attrbuf, "center") == 0) | |
89 | else if (dStrAsciiCasecmp (attrbuf, "center") == 0) | |
90 | 90 | html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN, |
91 | 91 | CSS_TYPE_ENUM, TEXT_ALIGN_CENTER); |
92 | 92 | } |
346 | 346 | if (a_Html_get_attr(html, tag, tagsize, "nowrap")) |
347 | 347 | html->styleEngine->setNonCssHint(CSS_PROPERTY_WHITE_SPACE, |
348 | 348 | CSS_TYPE_ENUM, WHITE_SPACE_NOWRAP); |
349 | else | |
350 | html->styleEngine->setNonCssHint(CSS_PROPERTY_WHITE_SPACE, | |
351 | CSS_TYPE_ENUM, WHITE_SPACE_NORMAL); | |
352 | 349 | |
353 | 350 | a_Html_tag_set_align_attr (html, tag, tagsize); |
354 | 351 |
596 | 596 | /* Filter URL string */ |
597 | 597 | new_urlstr = a_Url_string_strip_delimiters(urlstr); |
598 | 598 | |
599 | if (!dStrncasecmp(new_urlstr, "file:", 5)) { | |
599 | if (!dStrnAsciiCasecmp(new_urlstr, "file:", 5)) { | |
600 | 600 | /* file URI */ |
601 | 601 | ch = new_urlstr[5]; |
602 | 602 | if (!ch || ch == '.') { |
53 | 53 | #define URL_STR_FIELD_CMP(s1,s2) \ |
54 | 54 | (s1) && (s2) ? strcmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1 |
55 | 55 | #define URL_STR_FIELD_I_CMP(s1,s2) \ |
56 | (s1) && (s2) ? dStrcasecmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1 | |
56 | (s1) && (s2) ? dStrAsciiCasecmp(s1,s2) : !(s1) && !(s2) ? 0 : (s1) ? 1 : -1 | |
57 | 57 | |
58 | 58 | /* |
59 | 59 | * Return the url as a string. |
585 | 585 | newstr = dNew(char, 6*strlen(str)+1); |
586 | 586 | |
587 | 587 | for (c = newstr; *str; str++) |
588 | if ((dIsalnum(*str) && !(*str & 0x80)) || strchr(verbatim, *str)) | |
589 | /* we really need isalnum for the "C" locale */ | |
588 | if ((dIsalnum(*str) && isascii(*str)) || strchr(verbatim, *str)) | |
590 | 589 | *c++ = *str; |
591 | 590 | else if (*str == ' ') |
592 | 591 | *c++ = '+'; |
651 | 650 | _MSG("an IPv4 address\n"); |
652 | 651 | return TRUE; |
653 | 652 | } |
654 | if (*host == '[' && | |
655 | (len == strspn(host, "0123456789abcdefABCDEF:.[]"))) { | |
653 | if (strchr(host, ':') && | |
654 | (len == strspn(host, "0123456789abcdefABCDEF:."))) { | |
656 | 655 | /* The precise format is shown in section 3.2.2 of rfc 3986 */ |
657 | _MSG("an IPv6 address\n"); | |
656 | MSG("an IPv6 address\n"); | |
658 | 657 | return TRUE; |
659 | 658 | } |
660 | 659 | return FALSE; |
701 | 700 | |
702 | 701 | for (i = 0; i < tld_num; i++) { |
703 | 702 | if (strlen(tlds[i]) == (uint_t) tld_len && |
704 | !dStrncasecmp(tlds[i], host + start, tld_len)) { | |
703 | !dStrnAsciiCasecmp(tlds[i], host + start, tld_len)) { | |
705 | 704 | _MSG("TLD code matched %s\n", tlds[i]); |
706 | 705 | ret++; |
707 | 706 | break; |
758 | 757 | if (!u1 || !u2) |
759 | 758 | return FALSE; |
760 | 759 | |
761 | return dStrcasecmp(Url_host_find_public_suffix(URL_HOST(u1)), | |
762 | Url_host_find_public_suffix(URL_HOST(u2))) ? FALSE :TRUE; | |
763 | } | |
760 | return dStrAsciiCasecmp(Url_host_find_public_suffix(URL_HOST(u1)), | |
761 | Url_host_find_public_suffix(URL_HOST(u2))) | |
762 | ? FALSE : TRUE; | |
763 | } |
94 | 94 | |
95 | 95 | } else { |
96 | 96 | /* A non-RootUrl. At this moment we only handle image-children */ |
97 | if (!dStrncasecmp(Type, "image/", 6)) { | |
97 | if (!dStrnAsciiCasecmp(Type, "image/", 6)) { | |
98 | 98 | dw = (Widget*) a_Mime_set_viewer(Type, Web, Call, Data); |
99 | 99 | } else { |
100 | 100 | MSG_HTTP("'%s' cannot be displayed as image; has media type '%s'\n", |
917 | 917 | |
918 | 918 | /* SOME IP ADDRS */ |
919 | 919 | |
920 | a_Cookies_set("name=val", "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]", | |
920 | a_Cookies_set("name=val", "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", | |
921 | 921 | "/", NULL); |
922 | 922 | expect(__LINE__, "Cookie: name=val\r\n", "http", |
923 | "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]", "/"); | |
924 | ||
925 | a_Cookies_set("name=val", "[::FFFF:129.144.52.38]", "/", NULL); | |
926 | expect(__LINE__, "Cookie: name=val\r\n", "http", "[::FFFF:129.144.52.38]", | |
923 | "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", "/"); | |
924 | ||
925 | a_Cookies_set("name=val", "::FFFF:129.144.52.38", "/", NULL); | |
926 | expect(__LINE__, "Cookie: name=val\r\n", "http", "::FFFF:129.144.52.38", | |
927 | 927 | "/"); |
928 | 928 | |
929 | 929 | a_Cookies_set("name=val", "127.0.0.1", "/", NULL); |
68 | 68 | |
69 | 69 | char buf[16]; |
70 | 70 | strcpy (buf, numbers[textblockNo]); |
71 | buf[0] = toupper (buf[0]); | |
71 | buf[0] = lout::misc::AsciiToupper (buf[0]); | |
72 | 72 | topTextblock->addText (buf, headingStyle); |
73 | 73 | topTextblock->addParbreak (5, headingStyle); |
74 | 74 | |
75 | 75 | for (int i = 0; i < 30; i++) { |
76 | 76 | strcpy (buf, numbers[textblockNo]); |
77 | 77 | if (i == 0) |
78 | buf[0] = toupper (buf[0]); | |
78 | buf[0] = lout::misc::AsciiToupper (buf[0]); | |
79 | 79 | strcat (buf, i == 29 ? "." : ","); |
80 | 80 | |
81 | 81 | topTextblock->addText (buf, wordStyle); |
108 | 108 | for (int i = 0; i < 10; i++) { |
109 | 109 | char buf[16]; |
110 | 110 | strcpy (buf, numbers[i]); |
111 | buf[0] = toupper (buf[0]); | |
111 | buf[0] = lout::misc::AsciiToupper (buf[0]); | |
112 | 112 | buttonLabel[i] = strdup(buf); |
113 | 113 | Fl_Button *button = new Fl_Button(0, 20 * i, 50, 20, buttonLabel[i]); |
114 | 114 | button->callback (anchorCallback, (void*)(long)i); |