int map_scanner_string(struct scanner *scanner, unsigned char *ident, unsigned char *end, int base_type) { const struct scanner_string_mapping *mappings = scanner->info->mappings; int length = end - ident; for (; mappings->name; mappings++) { if (mappings->base_type == base_type && !c_strlcasecmp(mappings->name, -1, ident, length)) return mappings->type; } return base_type; }
/** Checks whether a host name matches a pattern that may contain * wildcards. * * @param[in] hostname * The host name to which the user wanted to connect. * Should be in UTF-8 and need not be null-terminated. * @param[in] hostname_length * The length of @a hostname, in bytes. * @param[in] pattern * A pattern that the host name might match. * Should be in UTF-8 and need not be null-terminated. * The pattern may contain wildcards, as specified in * RFC 2818 section 3.1. * @param[in] pattern_length * The length of @a pattern, in bytes. * * @return * Nonzero if the host name matches. Zero if it doesn't. * * According to RFC 2818 section 3.1, '*' matches any number of * characters except '.'. For example, "*r*.example.org" matches * "random.example.org" or "history.example.org" but not * "frozen.fruit.example.org". * * This function does not allocate memory, and consumes at most * O(@a hostname_length * @a pattern_length) time. */ int match_hostname_pattern(const unsigned char *hostname, size_t hostname_length, const unsigned char *pattern, size_t pattern_length) { const unsigned char *const hostname_end = hostname + hostname_length; const unsigned char *const pattern_end = pattern + pattern_length; assert(hostname <= hostname_end); assert(pattern <= pattern_end); if_assert_failed return 0; while (pattern < pattern_end) { if (*pattern == '*') { const unsigned char *next_wildcard; size_t literal_length; ++pattern; next_wildcard = memchr(pattern, '*', pattern_end - pattern); if (next_wildcard == NULL) literal_length = pattern_end - pattern; else literal_length = next_wildcard - pattern; for (;;) { size_t hostname_left = hostname_end - hostname; unicode_val_T uni; if (hostname_left < literal_length) return 0; /* If next_wildcard == NULL, then the * literal string is at the end of the * pattern, so anchor the match to the * end of the hostname. The end of * this function can then easily * verify that the whole hostname was * matched. * * But do not jump directly there; * first verify that there are no '.' * characters in between. */ if ((next_wildcard != NULL || hostname_left == literal_length) && !c_strlcasecmp(pattern, literal_length, hostname, literal_length)) break; /* The literal string doesn't match here. * Skip one character of the hostname and * retry. If the skipped character is '.' * or one of the equivalent characters * listed in RFC 3490 section 3.1 * requirement 1, then return 0, because * '*' must not match such characters. * Do the same if invalid UTF-8 is found. * Cast away const. */ uni = utf8_to_unicode((unsigned char **) hostname, hostname_end); if (uni == 0x002E || uni == 0x3002 || uni == 0xFF0E || uni == 0xFF61 || uni == UCS_NO_CHAR) return 0; } pattern += literal_length; hostname += literal_length; } else { if (hostname == hostname_end) return 0; if (c_toupper(*pattern) != c_toupper(*hostname)) return 0; ++pattern; ++hostname; } } return hostname == hostname_end; }
void html_textarea(struct html_context *html_context, unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end) { struct form_control *fc; unsigned char *p, *t_name, *wrap_attr; int t_namelen; int cols, rows; int i; html_focusable(html_context, attr); while (html < eof && (*html == '\n' || *html == '\r')) html++; p = html; while (p < eof && *p != '<') { pp: p++; } if (p >= eof) { *end = eof; return; } if (parse_element(p, eof, &t_name, &t_namelen, NULL, end)) goto pp; if (c_strlcasecmp(t_name, t_namelen, (const unsigned char *)"/TEXTAREA", 9)) goto pp; fc = init_form_control(FC_TEXTAREA, attr, html_context); if (!fc) return; fc->id = get_attr_val(attr, (unsigned char *)"id", html_context->doc_cp); fc->name = get_attr_val(attr, (unsigned char *)"name", html_context->doc_cp); fc->default_value = convert_string(NULL, html, p - html, html_context->doc_cp, CSM_DEFAULT, NULL, NULL, NULL); for (p = fc->default_value; p && p[0]; p++) { /* FIXME: We don't cope well with entities here. Bugzilla uses * inside of textarea and we fail miserably upon that * one. --pasky */ if (p[0] == '\r') { if (p[1] == '\n' || (p > fc->default_value && p[-1] == '\n')) { memmove(p, p + 1, strlen((const char *)p)); p--; } else { p[0] = '\n'; } } } cols = get_num(attr, (unsigned char *)"cols", html_context->doc_cp); if (cols <= 0) cols = html_context->options->default_form_input_size; cols++; /* Add 1 column, other browsers may have different behavior here (mozilla adds 2) --Zas */ if (cols > html_context->options->box.width) cols = html_context->options->box.width; fc->cols = cols; rows = get_num(attr, (unsigned char *)"rows", html_context->doc_cp); if (rows <= 0) rows = 1; if (rows > html_context->options->box.height) rows = html_context->options->box.height; fc->rows = rows; html_context->options->needs_height = 1; wrap_attr = get_attr_val(attr, (unsigned char *)"wrap", html_context->doc_cp); if (wrap_attr) { if (!c_strcasecmp((const char *)wrap_attr, "hard") || !c_strcasecmp((const char *)wrap_attr, "physical")) { fc->wrap = FORM_WRAP_HARD; } else if (!c_strcasecmp((const char *)wrap_attr, "soft") || !c_strcasecmp((const char *)wrap_attr, "virtual")) { fc->wrap = FORM_WRAP_SOFT; } else if (!c_strcasecmp((const char *)wrap_attr, "none") || !c_strcasecmp((const char *)wrap_attr, "off")) { fc->wrap = FORM_WRAP_NONE; } mem_free(wrap_attr); } else if (has_attr(attr, (unsigned char *)"nowrap", html_context->doc_cp)) { fc->wrap = FORM_WRAP_NONE; } else { fc->wrap = FORM_WRAP_SOFT; } fc->maxlength = get_num(attr, (unsigned char *)"maxlength", html_context->doc_cp); if (fc->maxlength == -1) fc->maxlength = INT_MAX; if (rows > 1) ln_break(html_context, 1); else put_chrs(html_context, (unsigned char *)" ", 1); html_stack_dup(html_context, ELEMENT_KILLABLE); format.form = fc; format.style.attr |= AT_BOLD; for (i = 0; i < rows; i++) { int j; for (j = 0; j < cols; j++) put_chrs(html_context, (unsigned char *)"_", 1); if (i < rows - 1) ln_break(html_context, 1); } pop_html_element(html_context); if (rows > 1) ln_break(html_context, 1); else put_chrs(html_context, (unsigned char *)" ", 1); html_context->special_f(html_context, SP_CONTROL, fc); }
void html_option(struct html_context *html_context, unsigned char *a, unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5) { struct form_control *fc; unsigned char *val; if (!format.select) return; val = get_attr_val(a, (unsigned char *)"value", html_context->doc_cp); if (!val) { struct string str; unsigned char *p, *r; unsigned char *name; int namelen; for (p = a - 1; *p != '<'; p--); if (!init_string(&str)) goto end_parse; if (parse_element(p, html_context->eoff, NULL, NULL, NULL, &p)) { INTERNAL("parse element failed"); val = str.source; goto end_parse; } se: while (p < html_context->eoff && isspace(*p)) p++; while (p < html_context->eoff && !isspace(*p) && *p != '<') { sp: add_char_to_string(&str, *p ? *p : ' '), p++; } r = p; val = str.source; /* Has to be before the possible 'goto end_parse' */ while (r < html_context->eoff && isspace(*r)) r++; if (r >= html_context->eoff) goto end_parse; if (r - 2 <= html_context->eoff && (r[1] == '!' || r[1] == '?')) { p = skip_comment(r, html_context->eoff); goto se; } if (parse_element(r, html_context->eoff, &name, &namelen, NULL, &p)) goto sp; if (namelen < 6) goto se; if (name[0] == '/') name++, namelen--; if (c_strlcasecmp(name, namelen, (const unsigned char *)"OPTION", 6) && c_strlcasecmp(name, namelen, (const unsigned char *)"SELECT", 6) && c_strlcasecmp(name, namelen, (const unsigned char *)"OPTGROUP", 8)) goto se; } end_parse: fc = init_form_control(FC_CHECKBOX, a, html_context); if (!fc) { mem_free_if(val); return; } fc->id = get_attr_val(a, (unsigned char *)"id", html_context->doc_cp); fc->name = null_or_stracpy(format.select); fc->default_value = val; fc->default_state = has_attr(a, (unsigned char *)"selected", html_context->doc_cp); fc->mode = has_attr(a, (unsigned char *)"disabled", html_context->doc_cp) ? FORM_MODE_DISABLED : format.select_disabled; put_chrs(html_context, (unsigned char *)" ", 1); html_stack_dup(html_context, ELEMENT_KILLABLE); format.form = fc; format.style.attr |= AT_BOLD; put_chrs(html_context, (unsigned char *)"[ ]", 3); pop_html_element(html_context); put_chrs(html_context, (unsigned char *)" ", 1); html_context->special_f(html_context, SP_CONTROL, fc); }
static void do_html_select(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, struct html_context *html_context) { struct conv_table *ct = (struct conv_table *)html_context->special_f(html_context, SP_TABLE, NULL); struct form_control *fc; struct string lbl = NULL_STRING, orig_lbl = NULL_STRING; unsigned char **values = NULL; unsigned char **labels; unsigned char *name, *t_attr, *en; int namelen; int nnmi = 0; int order = 0; int preselect = -1; int group = 0; int i, max_width; int closing_tag; html_focusable(html_context, attr); init_menu(&lnk_menu); se: en = html; see: html = en; while (html < eof && *html != '<') html++; if (html >= eof) { abort: *end = html; if (lbl.source) done_string(&lbl); if (orig_lbl.source) done_string(&orig_lbl); if (values) { int j; for (j = 0; j < order; j++) mem_free_if(values[j]); mem_free(values); } destroy_menu(&lnk_menu); *end = en; return; } if (lbl.source) { unsigned char *q, *s = en; int l = html - en; while (l && isspace(s[0])) s++, l--; while (l && isspace(s[l-1])) l--; q = convert_string(ct, s, l, html_context->options->cp, CSM_DEFAULT, NULL, NULL, NULL); if (q) add_to_string(&lbl, q), mem_free(q); add_bytes_to_string(&orig_lbl, s, l); } if (html + 2 <= eof && (html[1] == '!' || html[1] == '?')) { html = skip_comment(html, eof); goto se; } if (parse_element(html, eof, &name, &namelen, &t_attr, &en)) { html++; goto se; } if (!namelen) goto see; if (name[0] == '/') { namelen--; if (!namelen) goto see; name++; closing_tag = 1; } else { closing_tag = 0; } if (closing_tag && !c_strlcasecmp(name, namelen, (const unsigned char *)"SELECT", 6)) { add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi); goto end_parse; } if (!c_strlcasecmp(name, namelen, (const unsigned char *)"OPTION", 6)) { add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi); if (!closing_tag) { unsigned char *value, *label; if (has_attr(t_attr, (unsigned char *)"disabled", html_context->doc_cp)) goto see; if (preselect == -1 && has_attr(t_attr, (unsigned char *)"selected", html_context->doc_cp)) preselect = order; value = get_attr_val(t_attr, (unsigned char *)"value", html_context->doc_cp); if (!mem_align_alloc(&values, order, order + 1, 0xFF)) goto abort; values[order++] = value; label = get_attr_val(t_attr, (unsigned char *)"label", html_context->doc_cp); if (label) new_menu_item(&lnk_menu, label, order - 1, 0); if (!value || !label) { init_string(&lbl); init_string(&orig_lbl); nnmi = !!label; } } goto see; } if (!c_strlcasecmp(name, namelen, (const unsigned char *)"OPTGROUP", 8)) { add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi); if (group) new_menu_item(&lnk_menu, NULL, -1, 0), group = 0; if (!closing_tag) { unsigned char *label; label = get_attr_val(t_attr, (unsigned char *)"label", html_context->doc_cp); if (!label) { label = stracpy((const unsigned char *)""); if (!label) goto see; } new_menu_item(&lnk_menu, label, -1, 0); group = 1; } } goto see; end_parse: *end = en; if (!order) goto abort; labels = (unsigned char **)mem_calloc(order, sizeof(unsigned char *)); if (!labels) goto abort; fc = init_form_control(FC_SELECT, attr, html_context); if (!fc) { mem_free(labels); goto abort; } fc->id = get_attr_val(attr, (unsigned char *)"id", html_context->doc_cp); fc->name = get_attr_val(attr, (unsigned char *)"name", html_context->doc_cp); fc->default_state = preselect < 0 ? 0 : preselect; fc->default_value = order ? stracpy(values[fc->default_state]) : stracpy((const unsigned char *)""); fc->nvalues = order; fc->values = values; fc->menu = detach_menu(&lnk_menu); fc->labels = labels; menu_labels(fc->menu, (unsigned char *)"", labels); put_chrs(html_context, (unsigned char *)"[", 1); html_stack_dup(html_context, ELEMENT_KILLABLE); format.form = fc; format.style.attr |= AT_BOLD; max_width = 0; for (i = 0; i < order; i++) { if (!labels[i]) continue; #ifdef CONFIG_UTF8 if (html_context->options->utf8) int_lower_bound(&max_width, utf8_ptr2cells(labels[i], NULL)); else #endif /* CONFIG_UTF8 */ int_lower_bound(&max_width, strlen((const char *)labels[i])); } for (i = 0; i < max_width; i++) put_chrs(html_context, (unsigned char *)"_", 1); pop_html_element(html_context); put_chrs(html_context, (unsigned char *)"]", 1); html_context->special_f(html_context, SP_CONTROL, fc); }
void html_script(struct html_context *html_context, unsigned char *a, unsigned char *html, unsigned char *eof, unsigned char **end) { #ifdef CONFIG_ECMASCRIPT /* TODO: <noscript> processing. Well, same considerations apply as to * CSS property display: none processing. */ /* TODO: Charsets for external scripts. */ unsigned char *type, *language, *src; int in_comment = 0; #endif html_skip(html_context, a); #ifdef CONFIG_ECMASCRIPT /* We try to process nested <script> if we didn't process the parent * one. That's why's all the fuzz. */ /* Ref: * http://www.ietf.org/internet-drafts/draft-hoehrmann-script-types-03.txt */ type = get_attr_val(a, (unsigned char *)"type", html_context->doc_cp); if (type) { unsigned char *pos = type; if (!c_strncasecmp((const char *)type, "text/", 5)) { pos += 5; } else if (!c_strncasecmp((const char *)type, "application/", 12)) { pos += 12; } else { mem_free(type); not_processed: /* Permit nested scripts and retreat. */ html_top->invisible++; return; } if (!c_strncasecmp((const char *)pos, "javascript", 10)) { int len = strlen((const char *)pos); if (len > 10 && !isdigit(pos[10])) { mem_free(type); goto not_processed; } } else if (c_strcasecmp((const char *)pos, "ecmascript") && c_strcasecmp((const char *)pos, "jscript") && c_strcasecmp((const char *)pos, "livescript") && c_strcasecmp((const char *)pos, "x-javascript") && c_strcasecmp((const char *)pos, "x-ecmascript")) { mem_free(type); goto not_processed; } mem_free(type); } /* Check that the script content is ecmascript. The value of the * language attribute can be JavaScript with optional version digits * postfixed (like: ``JavaScript1.1''). * That attribute is deprecated in favor of type by HTML 4.01 */ language = get_attr_val(a, (unsigned char *)"language", html_context->doc_cp); if (language) { int languagelen = strlen((const char *)language); if (languagelen < 10 || (languagelen > 10 && !isdigit(language[10])) || c_strncasecmp((const char *)language, "javascript", 10)) { mem_free(language); html_top->invisible++; return; //goto not_processed; } mem_free(language); } if (html_context->part->document && (src = get_attr_val(a, (unsigned char *)"src", html_context->doc_cp))) { /* External reference. */ unsigned char *import_url; struct uri *uri; if (!get_opt_bool((const unsigned char *)"ecmascript.enable", NULL)) { mem_free(src); html_top->invisible++; return; //goto not_processed; } /* HTML <head> urls should already be fine but we can.t detect them. */ import_url = join_urls(html_context->base_href, src); mem_free(src); if (!import_url) goto imported; uri = get_uri(import_url, URI_BASE); if (!uri) goto imported; /* Request the imported script as part of the document ... */ html_context->special_f(html_context, SP_SCRIPT, uri); done_uri(uri); /* Create URL reference onload snippet. */ insert_in_string(&import_url, 0, (const unsigned char *)"^", 1); add_to_string_list(&html_context->part->document->onload_snippets, import_url, -1); imported: /* Retreat. Do not permit nested scripts, tho'. */ if (import_url) mem_free(import_url); return; } /* Positive, grab the rest and interpret it. */ /* First position to the real script start. */ while (html < eof && *html <= ' ') html++; if (eof - html > 4 && !strncmp((const char *)html, "<!--", 4)) { in_comment = 1; /* We either skip to the end of line or to -->. */ for (; *html != '\n' && *html != '\r' && eof - html >= 3; html++) { if (!strncmp((const char *)html, "-->", 3)) { /* This means the document is probably broken. * We will now try to process the rest of * <script> contents, which is however likely * to be empty. Should we try to process the * comment too? Currently it seems safer but * less tolerant to broken pages, if there are * any like this. */ html += 3; in_comment = 0; break; } } } *end = html; /* Now look ahead for the script end. The <script> contents is raw * CDATA, so we just look for the ending tag and need not care for * any quote marks counting etc - YET, we are more tolerant and permit * </script> stuff inside of the script if the whole <script> element * contents is wrapped in a comment. See i.e. Mozilla bug 26857 for fun * reading regarding this. */ for (; *end < eof; (*end)++) { unsigned char *name; int namelen; if (in_comment) { /* TODO: If we ever get some standards-quirk mode * distinction, this should be disabled in the * standards mode (and we should just look for CDATA * end, which is "</"). --pasky */ if (eof - *end >= 3 && !strncmp((const char *)*end, "-->", 3)) { /* Next iteration will jump passed the ending '>' */ (*end) += 2; in_comment = 0; } continue; /* XXX: Scan for another comment? That's admittelly * already stretching things a little bit to an * extreme ;-). */ } if (**end != '<') continue; /* We want to land before the closing element, that's why we * don't pass @end also as the appropriate parse_element() * argument. */ if (parse_element(*end, eof, &name, &namelen, NULL, NULL)) continue; if (c_strlcasecmp(name, namelen, (const unsigned char *)"/script", 7)) continue; /* We have won! */ break; } if (*end >= eof) { /* Either the document is not completely loaded yet or it's * broken. At any rate, run away screaming. */ *end = eof; /* Just for sanity. */ return; } if (html_context->part->document && *html != '^') { add_to_string_list(&html_context->part->document->onload_snippets, html, *end - html); } #endif }