diff options
Diffstat (limited to '')
-rw-r--r-- | etc.c | 1989 |
1 files changed, 1989 insertions, 0 deletions
@@ -0,0 +1,1989 @@ +/* $Id: etc.c,v 1.78 2004/04/16 18:47:19 ukai Exp $ */ +#include "fm.h" +#include <pwd.h> +#include "myctype.h" +#include "html.h" +#include "local.h" +#include "hash.h" + +#include <fcntl.h> +#include <sys/types.h> +#include <time.h> +#if defined(HAVE_WAITPID) || defined(HAVE_WAIT3) +#include <sys/wait.h> +#endif +#include <signal.h> + +#ifdef __WATT32__ +#define read(a,b,c) read_s(a,b,c) +#define close(x) close_s(x) +#endif /* __WATT32__ */ + +struct auth_pass { + int bad; + int is_proxy; + Str host; + int port; +/* Str file; */ + Str realm; + Str uname; + Str pwd; + struct auth_pass *next; +}; + +struct auth_pass *passwords = NULL; + +int +columnSkip(Buffer *buf, int offset) +{ + int i, maxColumn; + int column = buf->currentColumn + offset; + int nlines = buf->LINES + 1; + Line *l; + + maxColumn = 0; + for (i = 0, l = buf->topLine; i < nlines && l != NULL; i++, l = l->next) { + if (l->width < 0) + l->width = COLPOS(l, l->len); + if (l->width - 1 > maxColumn) + maxColumn = l->width - 1; + } + maxColumn -= buf->COLS - 1; + if (column < maxColumn) + maxColumn = column; + if (maxColumn < 0) + maxColumn = 0; + + if (buf->currentColumn == maxColumn) + return 0; + buf->currentColumn = maxColumn; + return 1; +} + +int +columnPos(Line *line, int column) +{ + int i; + + for (i = 1; i < line->len; i++) { + if (COLPOS(line, i) > column) + break; + } +#ifdef USE_M17N + for (i--; i > 0 && line->propBuf[i] & PC_WCHAR2; i--) ; + return i; +#else + return i - 1; +#endif +} + +Line * +lineSkip(Buffer *buf, Line *line, int offset, int last) +{ + int i; + Line *l; + + l = currentLineSkip(buf, line, offset, last); + if (!nextpage_topline) + for (i = buf->LINES - 1 - (buf->lastLine->linenumber - l->linenumber); + i > 0 && l->prev != NULL; i--, l = l->prev) ; + return l; +} + +Line * +currentLineSkip(Buffer *buf, Line *line, int offset, int last) +{ + int i, n; + Line *l = line; + + if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { + n = line->linenumber + offset + buf->LINES; + if (buf->lastLine->linenumber < n) + getNextPage(buf, n - buf->lastLine->linenumber); + while ((last || (buf->lastLine->linenumber < n)) && + (getNextPage(buf, 1) != NULL)) ; + if (last) + l = buf->lastLine; + } + + if (offset == 0) + return l; + if (offset > 0) + for (i = 0; i < offset && l->next != NULL; i++, l = l->next) ; + else + for (i = 0; i < -offset && l->prev != NULL; i++, l = l->prev) ; + return l; +} + +#define MAX_CMD_LEN 128 + +int +gethtmlcmd(char **s) +{ + extern Hash_si tagtable; + char cmdstr[MAX_CMD_LEN]; + char *p = cmdstr; + char *save = *s; + int cmd; + + (*s)++; + /* first character */ + if (IS_ALNUM(**s) || **s == '_' || **s == '/') { + *(p++) = TOLOWER(**s); + (*s)++; + } + else + return HTML_UNKNOWN; + if (p[-1] == '/') + SKIP_BLANKS(*s); + while ((IS_ALNUM(**s) || **s == '_') && p - cmdstr < MAX_CMD_LEN) { + *(p++) = TOLOWER(**s); + (*s)++; + } + if (p - cmdstr == MAX_CMD_LEN) { + /* buffer overflow: perhaps caused by bad HTML source */ + *s = save + 1; + return HTML_UNKNOWN; + } + *p = '\0'; + + /* hash search */ + cmd = getHash_si(&tagtable, cmdstr, HTML_UNKNOWN); + while (**s && **s != '>') + (*s)++; + if (**s == '>') + (*s)++; + return cmd; +} + +#ifdef USE_ANSI_COLOR +static int +parse_ansi_color(char **str, Lineprop *effect, Linecolor *color) +{ + char *p = *str, *q; + Lineprop e = *effect; + Linecolor c = *color; + int i; + + if (*p != ESC_CODE || *(p + 1) != '[') + return 0; + p += 2; + for (q = p; IS_DIGIT(*q) || *q == ';'; q++) ; + if (*q != 'm') + return 0; + *str = q + 1; + while (1) { + if (*p == 'm') { + e = PE_NORMAL; + c = 0; + break; + } + if (IS_DIGIT(*p)) { + q = p; + for (p++; IS_DIGIT(*p); p++) ; + i = atoi(allocStr(q, p - q)); + switch (i) { + case 0: + e = PE_NORMAL; + c = 0; + break; + case 1: + case 5: + e = PE_BOLD; + break; + case 4: + e = PE_UNDER; + break; + case 7: + e = PE_STAND; + break; + case 100: /* for EWS4800 kterm */ + c = 0; + break; + case 39: + c &= 0xf0; + break; + case 49: + c &= 0x0f; + break; + default: + if (i >= 30 && i <= 37) + c = (c & 0xf0) | (i - 30) | 0x08; + else if (i >= 40 && i <= 47) + c = (c & 0x0f) | ((i - 40) << 4) | 0x80; + break; + } + if (*p == 'm') + break; + } + else { + e = PE_NORMAL; + c = 0; + break; + } + p++; /* *p == ';' */ + } + *effect = e; + *color = c; + return 1; +} +#endif +/* + * Check character type + */ + +Str +checkType(Str s, Lineprop **oprop, Linecolor **ocolor) +{ + Lineprop mode; + Lineprop effect = PE_NORMAL; + Lineprop *prop; + static Lineprop *prop_buffer = NULL; + static int prop_size = 0; + char *str = s->ptr, *endp = &s->ptr[s->length], *bs = NULL; +#ifdef USE_ANSI_COLOR + Lineprop ceffect = PE_NORMAL; + Linecolor cmode = 0; + int check_color = FALSE; + Linecolor *color = NULL; + static Linecolor *color_buffer = NULL; + static int color_size = 0; + char *es = NULL; +#endif + int do_copy = FALSE; + int i; + int plen = 0, clen; + + if (prop_size < s->length) { + prop_size = (s->length > LINELEN) ? s->length : LINELEN; + prop_buffer = New_Reuse(Lineprop, prop_buffer, prop_size); + } + prop = prop_buffer; + + if (ShowEffect) { + bs = memchr(str, '\b', s->length); +#ifdef USE_ANSI_COLOR + if (ocolor) { + es = memchr(str, ESC_CODE, s->length); + if (es) { + if (color_size < s->length) { + color_size = (s->length > LINELEN) ? s->length : LINELEN; + color_buffer = New_Reuse(Linecolor, color_buffer, + color_size); + } + color = color_buffer; + } + } +#endif + if ((bs != NULL) +#ifdef USE_ANSI_COLOR + || (es != NULL) +#endif + ) { + char *sp = str, *ep; + s = Strnew_size(s->length); + do_copy = TRUE; + ep = bs ? (bs - 2) : endp; +#ifdef USE_ANSI_COLOR + if (es && ep > es - 2) + ep = es - 2; +#endif + for (; str < ep && IS_ASCII(*str); str++) { + *(prop++) = PE_NORMAL | (IS_CNTRL(*str) ? PC_CTRL : PC_ASCII); +#ifdef USE_ANSI_COLOR + if (color) + *(color++) = 0; +#endif + } + Strcat_charp_n(s, sp, (int)(str - sp)); + } + } + if (!do_copy) { + for (; str < endp && IS_ASCII(*str); str++) + *(prop++) = PE_NORMAL | (IS_CNTRL(*str) ? PC_CTRL : PC_ASCII); + } + + while (str < endp) { + if (prop - prop_buffer >= prop_size) + break; + if (bs != NULL) { +#ifdef USE_M17N + if (str == bs - 2 && !strncmp(str, "__\b\b", 4)) { + str += 4; + effect = PE_UNDER; + if (str < endp) + bs = memchr(str, '\b', endp - str); + continue; + } + else +#endif + if (str == bs - 1 && *str == '_') { + str += 2; + effect = PE_UNDER; + if (str < endp) + bs = memchr(str, '\b', endp - str); + continue; + } + else if (str == bs) { + if (*(str + 1) == '_') { + if (s->length) { + str += 2; +#ifdef USE_M17N + for (i = 1; i <= plen; i++) + *(prop - i) |= PE_UNDER; +#else + *(prop - 1) |= PE_UNDER; +#endif + } + else { + str++; + } + } +#ifdef USE_M17N + else if (!strncmp(str + 1, "\b__", 3)) { + if (s->length) { + str += (plen == 1) ? 3 : 4; + for (i = 1; i <= plen; i++) + *(prop - i) |= PE_UNDER; + } + else { + str += 2; + } + } + else if (*(str + 1) == '\b') { + if (s->length) { + clen = get_mclen(str + 2); + if (plen == clen && + !strncmp(str - plen, str + 2, plen)) { + for (i = 1; i <= plen; i++) + *(prop - i) |= PE_BOLD; + str += 2 + clen; + } + else { + Strshrink(s, plen); + prop -= plen; + str += 2; + } + } + else { + str += 2; + } + } +#endif + else { + if (s->length) { +#ifdef USE_M17N + clen = get_mclen(str + 1); + if (plen == clen && + !strncmp(str - plen, str + 1, plen)) { + for (i = 1; i <= plen; i++) + *(prop - i) |= PE_BOLD; + str += 1 + clen; + } + else { + Strshrink(s, plen); + prop -= plen; + str++; + } +#else + if (*(str - 1) == *(str + 1)) { + *(prop - 1) |= PE_BOLD; + str += 2; + } + else { + Strshrink(s, 1); + prop--; + str++; + } +#endif + } + else { + str++; + } + } + if (str < endp) + bs = memchr(str, '\b', endp - str); + continue; + } +#ifdef USE_ANSI_COLOR + else if (str > bs) + bs = memchr(str, '\b', endp - str); +#endif + } +#ifdef USE_ANSI_COLOR + if (es != NULL) { + if (str == es) { + int ok = parse_ansi_color(&str, &ceffect, &cmode); + if (str < endp) + es = memchr(str, ESC_CODE, endp - str); + if (ok) { + if (cmode) + check_color = TRUE; + continue; + } + } + else if (str > es) + es = memchr(str, ESC_CODE, endp - str); + } +#endif + + plen = get_mclen(str); + mode = get_mctype(str) | effect; +#ifdef USE_ANSI_COLOR + if (color) { + *(color++) = cmode; + mode |= ceffect; + } +#endif + *(prop++) = mode; +#ifdef USE_M17N + if (plen > 1) { + mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; + for (i = 1; i < plen; i++) { + *(prop++) = mode; +#ifdef USE_ANSI_COLOR + if (color) + *(color++) = cmode; +#endif + } + if (do_copy) + Strcat_charp_n(s, (char *)str, plen); + str += plen; + } + else +#endif + { + if (do_copy) + Strcat_char(s, (char)*str); + str++; + } + effect = PE_NORMAL; + } + *oprop = prop_buffer; +#ifdef USE_ANSI_COLOR + if (ocolor) + *ocolor = check_color ? color_buffer : NULL; +#endif + return s; +} + +static int +nextColumn(int n, char *p, Lineprop *pr) +{ + if (*pr & PC_CTRL) { + if (*p == '\t') + return (n + Tabstop) / Tabstop * Tabstop; + else if (*p == '\n') + return n + 1; + else if (*p != '\r') + return n + 2; + return n; + } +#ifdef USE_M17N + if (*pr & PC_UNKNOWN) + return n + 4; + return n + wtf_width((wc_uchar *) p); +#else + return n + 1; +#endif +} + +int +calcPosition(char *l, Lineprop *pr, int len, int pos, int bpos, int mode) +{ + static int *realColumn = NULL; + static int size = 0; + static char *prevl = NULL; + int i, j; + + if (l == NULL || len == 0) + return bpos; + if (l == prevl && mode == CP_AUTO) { + if (pos <= len) + return realColumn[pos]; + } + if (size < len + 1) { + size = (len + 1 > LINELEN) ? (len + 1) : LINELEN; + realColumn = New_N(int, size); + } + prevl = l; + i = 0; + j = bpos; +#ifdef USE_M17N + if (pr[i] & PC_WCHAR2) { + for (; i < len && pr[i] & PC_WCHAR2; i++) + realColumn[i] = j; + if (i > 0 && pr[i - 1] & PC_KANJI && WcOption.use_wide) + j++; + } +#endif + while (1) { + realColumn[i] = j; + if (i == len) + break; + j = nextColumn(j, &l[i], &pr[i]); + i++; +#ifdef USE_M17N + for (; i < len && pr[i] & PC_WCHAR2; i++) + realColumn[i] = realColumn[i - 1]; +#endif + } + if (pos >= i) + return j; + return realColumn[pos]; +} + +int +columnLen(Line *line, int column) +{ + int i, j; + + for (i = 0, j = 0; i < line->len;) { + j = nextColumn(j, &line->lineBuf[i], &line->propBuf[i]); + if (j > column) + return i; + i++; +#ifdef USE_M17N + while (i < line->len && line->propBuf[i] & PC_WCHAR2) + i++; +#endif + } + return line->len; +} + +char * +lastFileName(char *path) +{ + char *p, *q; + + p = q = path; + while (*p != '\0') { + if (*p == '/') + q = p + 1; + p++; + } + + return allocStr(q, -1); +} + +#ifdef USE_INCLUDED_SRAND48 +static unsigned long R1 = 0x1234abcd; +static unsigned long R2 = 0x330e; +#define A1 0x5deec +#define A2 0xe66d +#define C 0xb + +void +srand48(long seed) +{ + R1 = (unsigned long)seed; + R2 = 0x330e; +} + +long +lrand48(void) +{ + R1 = (A1 * R1 << 16) + A1 * R2 + A2 * R1 + ((A2 * R2 + C) >> 16); + R2 = (A2 * R2 + C) & 0xffff; + return (long)(R1 >> 1); +} +#endif + +char * +mybasename(char *s) +{ + char *p = s; + while (*p) + p++; + while (s <= p && *p != '/') + p--; + if (*p == '/') + p++; + else + p = s; + return allocStr(p, -1); +} + +char * +mydirname(char *s) +{ + char *p = s; + while (*p) + p++; + if (s != p) + p--; + while (s != p && *p == '/') + p--; + while (s != p && *p != '/') + p--; + if (*p != '/') + return "."; + while (s != p && *p == '/') + p--; + return allocStr(s, strlen(s) - strlen(p) + 1); +} + +#ifndef HAVE_STRERROR +char * +strerror(int errno) +{ + extern char *sys_errlist[]; + return sys_errlist[errno]; +} +#endif /* not HAVE_STRERROR */ + +#ifndef HAVE_SYS_ERRLIST +char **sys_errlist; + +prepare_sys_errlist() +{ + int i, n; + + i = 1; + while (strerror(i) != NULL) + i++; + n = i; + sys_errlist = New_N(char *, n); + sys_errlist[0] = ""; + for (i = 1; i < n; i++) + sys_errlist[i] = strerror(i); +} +#endif /* not HAVE_SYS_ERRLIST */ + +int +next_status(char c, int *status) +{ + switch (*status) { + case R_ST_NORMAL: + if (c == '<') { + *status = R_ST_TAG0; + return 0; + } + else if (c == '&') { + *status = R_ST_AMP; + return 1; + } + else + return 1; + break; + case R_ST_TAG0: + if (c == '!') { + *status = R_ST_CMNT1; + return 0; + } + *status = R_ST_TAG; + /* continues to next case */ + case R_ST_TAG: + if (c == '>') + *status = R_ST_NORMAL; + else if (c == '=') + *status = R_ST_EQL; + return 0; + case R_ST_EQL: + if (c == '"') + *status = R_ST_DQUOTE; + else if (c == '\'') + *status = R_ST_QUOTE; + else if (IS_SPACE(c)) + *status = R_ST_EQL; + else if (c == '>') + *status = R_ST_NORMAL; + else + *status = R_ST_VALUE; + return 0; + case R_ST_QUOTE: + if (c == '\'') + *status = R_ST_TAG; + return 0; + case R_ST_DQUOTE: + if (c == '"') + *status = R_ST_TAG; + return 0; + case R_ST_VALUE: + if (c == '>') + *status = R_ST_NORMAL; + else if (IS_SPACE(c)) + *status = R_ST_TAG; + return 0; + case R_ST_AMP: + if (c == ';') { + *status = R_ST_NORMAL; + return 0; + } + else if (c != '#' && !IS_ALNUM(c) && c != '_') { + /* something's wrong! */ + *status = R_ST_NORMAL; + return 0; + } + else + return 0; + case R_ST_CMNT1: + switch (c) { + case '-': + *status = R_ST_CMNT2; + break; + case '>': + *status = R_ST_NORMAL; + break; + default: + *status = R_ST_IRRTAG; + } + return 0; + case R_ST_CMNT2: + switch (c) { + case '-': + *status = R_ST_CMNT; + break; + case '>': + *status = R_ST_NORMAL; + break; + default: + *status = R_ST_IRRTAG; + } + return 0; + case R_ST_CMNT: + if (c == '-') + *status = R_ST_NCMNT1; + return 0; + case R_ST_NCMNT1: + if (c == '-') + *status = R_ST_NCMNT2; + else + *status = R_ST_CMNT; + return 0; + case R_ST_NCMNT2: + switch (c) { + case '>': + *status = R_ST_NORMAL; + break; + case '-': + *status = R_ST_NCMNT2; + break; + default: + if (IS_SPACE(c)) + *status = R_ST_NCMNT3; + else + *status = R_ST_CMNT; + break; + } + break; + case R_ST_NCMNT3: + switch (c) { + case '>': + *status = R_ST_NORMAL; + break; + case '-': + *status = R_ST_NCMNT1; + break; + default: + if (IS_SPACE(c)) + *status = R_ST_NCMNT3; + else + *status = R_ST_CMNT; + break; + } + return 0; + case R_ST_IRRTAG: + if (c == '>') + *status = R_ST_NORMAL; + return 0; + } + /* notreached */ + return 0; +} + +int +read_token(Str buf, char **instr, int *status, int pre, int append) +{ + char *p; + int prev_status; + + if (!append) + Strclear(buf); + if (**instr == '\0') + return 0; + for (p = *instr; *p; p++) { + prev_status = *status; + next_status(*p, status); + switch (*status) { + case R_ST_NORMAL: + if (prev_status == R_ST_AMP && *p != ';') { + p--; + break; + } + if (prev_status == R_ST_NCMNT2 || prev_status == R_ST_NCMNT3 || + prev_status == R_ST_IRRTAG || prev_status == R_ST_CMNT1) { + if (prev_status == R_ST_CMNT1 && !append && !pre) + Strclear(buf); + if (pre) + Strcat_char(buf, *p); + p++; + goto proc_end; + } + Strcat_char(buf, (!pre && IS_SPACE(*p)) ? ' ' : *p); + if (ST_IS_REAL_TAG(prev_status)) { + *instr = p + 1; + if (buf->length < 2 || + buf->ptr[buf->length - 2] != '<' || + buf->ptr[buf->length - 1] != '>') + return 1; + Strshrink(buf, 2); + } + break; + case R_ST_TAG0: + case R_ST_TAG: + if (prev_status == R_ST_NORMAL && p != *instr) { + *instr = p; + *status = prev_status; + return 1; + } + if (*status == R_ST_TAG0 && !REALLY_THE_BEGINNING_OF_A_TAG(p)) { + /* it seems that this '<' is not a beginning of a tag */ + /* + * Strcat_charp(buf, "<"); + */ + Strcat_char(buf, '<'); + *status = R_ST_NORMAL; + } + else + Strcat_char(buf, *p); + break; + case R_ST_EQL: + case R_ST_QUOTE: + case R_ST_DQUOTE: + case R_ST_VALUE: + case R_ST_AMP: + Strcat_char(buf, *p); + break; + case R_ST_CMNT: + case R_ST_IRRTAG: + if (pre) + Strcat_char(buf, *p); + else if (!append) + Strclear(buf); + break; + case R_ST_CMNT1: + case R_ST_CMNT2: + case R_ST_NCMNT1: + case R_ST_NCMNT2: + case R_ST_NCMNT3: + /* do nothing */ + if (pre) + Strcat_char(buf, *p); + break; + } + } + proc_end: + *instr = p; + return 1; +} + +Str +correct_irrtag(int status) +{ + char c; + Str tmp = Strnew(); + + while (status != R_ST_NORMAL) { + switch (status) { + case R_ST_CMNT: /* required "-->" */ + case R_ST_NCMNT1: /* required "->" */ + c = '-'; + break; + case R_ST_NCMNT2: + case R_ST_NCMNT3: + case R_ST_IRRTAG: + case R_ST_CMNT1: + case R_ST_CMNT2: + case R_ST_TAG: + case R_ST_TAG0: + case R_ST_EQL: /* required ">" */ + case R_ST_VALUE: + c = '>'; + break; + case R_ST_QUOTE: + c = '\''; + break; + case R_ST_DQUOTE: + c = '"'; + break; + case R_ST_AMP: + c = ';'; + break; + default: + return tmp; + } + next_status(c, &status); + Strcat_char(tmp, c); + } + return tmp; +} + +/* + * RFC2617: 1.2 Access Authentication Framework + * + * The realm value (case-sensitive), in combination with the canonical root + * URL (the absoluteURI for the server whose abs_path is empty; see section + * 5.1.2 of RFC2616 ) of the server being accessed, defines the protection + * space. These realms allow the protected resources on a server to be + * partitioned into a set of protection spaces, each with its own + * authentication scheme and/or authorization database. + * + */ +static void +add_auth_pass_entry(const struct auth_pass *ent, int netrc, int override) +{ + if ((ent->host || netrc) /* netrc accept default (host == NULL) */ + &&(ent->is_proxy || ent->realm || netrc) + && ent->uname && ent->pwd) { + struct auth_pass *newent = New(struct auth_pass); + memcpy(newent, ent, sizeof(struct auth_pass)); + if (override) { + newent->next = passwords; + passwords = newent; + } + else { + if (passwords == NULL) + passwords = newent; + else if (passwords->next == NULL) + passwords->next = newent; + else { + struct auth_pass *ep = passwords; + for (; ep->next; ep = ep->next) ; + ep->next = newent; + } + } + } + /* ignore invalid entries */ +} + +static struct auth_pass * +find_auth_pass_entry(char *host, int port, char *realm, char *uname, + int is_proxy) +{ + struct auth_pass *ent; + for (ent = passwords; ent != NULL; ent = ent->next) { + if (ent->is_proxy == is_proxy + && (ent->bad != TRUE) + && (!ent->host || !Strcasecmp_charp(ent->host, host)) + && (!ent->port || ent->port == port) + && (!ent->uname || !uname || !Strcmp_charp(ent->uname, uname)) + && (!ent->realm || !realm || !Strcmp_charp(ent->realm, realm)) + ) + return ent; + } + return NULL; +} + +int +find_auth_user_passwd(ParsedURL *pu, char *realm, + Str *uname, Str *pwd, int is_proxy) +{ + struct auth_pass *ent; + + if (pu->user && pu->pass) { + *uname = Strnew_charp(pu->user); + *pwd = Strnew_charp(pu->pass); + return 1; + } + ent = find_auth_pass_entry(pu->host, pu->port, realm, pu->user, is_proxy); + if (ent) { + *uname = ent->uname; + *pwd = ent->pwd; + return 1; + } + return 0; +} + +void +add_auth_user_passwd(ParsedURL *pu, char *realm, Str uname, Str pwd, + int is_proxy) +{ + struct auth_pass ent; + memset(&ent, 0, sizeof(ent)); + + ent.is_proxy = is_proxy; + ent.host = Strnew_charp(pu->host); + ent.port = pu->port; + ent.realm = Strnew_charp(realm); + ent.uname = uname; + ent.pwd = pwd; + add_auth_pass_entry(&ent, 0, 1); +} + +void +invalidate_auth_user_passwd(ParsedURL *pu, char *realm, Str uname, Str pwd, + int is_proxy) +{ + struct auth_pass *ent; + ent = find_auth_pass_entry(pu->host, pu->port, realm, NULL, is_proxy); + if (ent) { + ent->bad = TRUE; + } + return; +} + +/* passwd */ +/* + * machine <host> + * host <host> + * port <port> + * proxy + * path <file> ; not used + * realm <realm> + * login <login> + * passwd <passwd> + * password <passwd> + */ + +static Str +next_token(Str arg) +{ + Str narg = NULL; + char *p, *q; + if (arg == NULL || arg->length == 0) + return NULL; + p = arg->ptr; + q = p; + SKIP_NON_BLANKS(q); + if (*q != '\0') { + *q++ = '\0'; + SKIP_BLANKS(q); + if (*q != '\0') + narg = Strnew_charp(q); + } + return narg; +} + +static void +parsePasswd(FILE * fp, int netrc) +{ + struct auth_pass ent; + Str line = NULL; + + bzero(&ent, sizeof(struct auth_pass)); + while (1) { + Str arg = NULL; + char *p; + + if (line == NULL || line->length == 0) + line = Strfgets(fp); + if (line->length == 0) + break; + Strchop(line); + Strremovefirstspaces(line); + p = line->ptr; + if (*p == '#' || *p == '\0') { + line = NULL; + continue; /* comment or empty line */ + } + arg = next_token(line); + + if (!strcmp(p, "machine") || !strcmp(p, "host") + || (netrc && !strcmp(p, "default"))) { + add_auth_pass_entry(&ent, netrc, 0); + bzero(&ent, sizeof(struct auth_pass)); + if (netrc) + ent.port = 21; /* XXX: getservbyname("ftp"); ? */ + if (strcmp(p, "default") != 0) { + line = next_token(arg); + ent.host = arg; + } + else { + line = arg; + } + } + else if (!netrc && !strcmp(p, "port") && arg) { + line = next_token(arg); + ent.port = atoi(arg->ptr); + } + else if (!netrc && !strcmp(p, "proxy")) { + ent.is_proxy = 1; + line = arg; + } + else if (!netrc && !strcmp(p, "path")) { + line = next_token(arg); + /* ent.file = arg; */ + } + else if (!netrc && !strcmp(p, "realm")) { + /* XXX: rest of line becomes arg for realm */ + line = NULL; + ent.realm = arg; + } + else if (!strcmp(p, "login")) { + line = next_token(arg); + ent.uname = arg; + } + else if (!strcmp(p, "password") || !strcmp(p, "passwd")) { + line = next_token(arg); + ent.pwd = arg; + } + else if (netrc && !strcmp(p, "machdef")) { + while ((line = Strfgets(fp))->length != 0) { + if (*line->ptr == '\n') + break; + } + line = NULL; + } + else if (netrc && !strcmp(p, "account")) { + /* ignore */ + line = next_token(arg); + } + else { + /* ignore rest of line */ + line = NULL; + } + } + add_auth_pass_entry(&ent, netrc, 0); +} + +/* FIXME: gettextize? */ +#define FILE_IS_READABLE_MSG "SECURITY NOTE: file %s must not be accessible by others" + +FILE * +openSecretFile(char *fname) +{ + char *efname; + struct stat st; + + if (fname == NULL) + return NULL; + efname = expandPath(fname); + if (stat(efname, &st) < 0) + return NULL; + + /* check permissions, if group or others readable or writable, + * refuse it, because it's insecure. + * + * XXX: disable_secret_security_check will introduce some + * security issues, but on some platform such as Windows + * it's not possible (or feasible) to disable group|other + * readable and writable. + * [w3m-dev 03368][w3m-dev 03369][w3m-dev 03370] + */ + if (disable_secret_security_check) + /* do nothing */ ; + else if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + if (fmInitialized) { + message(Sprintf(FILE_IS_READABLE_MSG, fname)->ptr, 0, 0); + refresh(); + } + else { + fputs(Sprintf(FILE_IS_READABLE_MSG, fname)->ptr, stderr); + fputc('\n', stderr); + } + sleep(2); + return NULL; + } + + return fopen(efname, "r"); +} + +void +loadPasswd(void) +{ + FILE *fp; + + passwords = NULL; + fp = openSecretFile(passwd_file); + if (fp != NULL) { + parsePasswd(fp, 0); + fclose(fp); + } + + /* for FTP */ + fp = openSecretFile("~/.netrc"); + if (fp != NULL) { + parsePasswd(fp, 1); + fclose(fp); + } + return; +} + +/* get last modified time */ +char * +last_modified(Buffer *buf) +{ + TextListItem *ti; + struct stat st; + + if (buf->document_header) { + for (ti = buf->document_header->first; ti; ti = ti->next) { + if (strncasecmp(ti->ptr, "Last-modified: ", 15) == 0) { + return ti->ptr + 15; + } + } + return "unknown"; + } + else if (buf->currentURL.scheme == SCM_LOCAL) { + if (stat(buf->currentURL.file, &st) < 0) + return "unknown"; + return ctime(&st.st_mtime); + } + return "unknown"; +} + +static char roman_num1[] = { + 'i', 'x', 'c', 'm', '*', +}; +static char roman_num5[] = { + 'v', 'l', 'd', '*', +}; + +static Str +romanNum2(int l, int n) +{ + Str s = Strnew(); + + switch (n) { + case 1: + case 2: + case 3: + for (; n > 0; n--) + Strcat_char(s, roman_num1[l]); + break; + case 4: + Strcat_char(s, roman_num1[l]); + Strcat_char(s, roman_num5[l]); + break; + case 5: + case 6: + case 7: + case 8: + Strcat_char(s, roman_num5[l]); + for (n -= 5; n > 0; n--) + Strcat_char(s, roman_num1[l]); + break; + case 9: + Strcat_char(s, roman_num1[l]); + Strcat_char(s, roman_num1[l + 1]); + break; + } + return s; +} + +Str +romanNumeral(int n) +{ + Str r = Strnew(); + + if (n <= 0) + return r; + if (n >= 4000) { + Strcat_charp(r, "**"); + return r; + } + Strcat(r, romanNum2(3, n / 1000)); + Strcat(r, romanNum2(2, (n % 1000) / 100)); + Strcat(r, romanNum2(1, (n % 100) / 10)); + Strcat(r, romanNum2(0, n % 10)); + + return r; +} + +Str +romanAlphabet(int n) +{ + Str r = Strnew(); + int l; + char buf[14]; + + if (n <= 0) + return r; + + l = 0; + while (n) { + buf[l++] = 'a' + (n - 1) % 26; + n = (n - 1) / 26; + } + l--; + for (; l >= 0; l--) + Strcat_char(r, buf[l]); + + return r; +} + +#ifndef SIGIOT +#define SIGIOT SIGABRT +#endif /* not SIGIOT */ + +static void +reset_signals(void) +{ + mySignal(SIGHUP, SIG_DFL); /* terminate process */ + mySignal(SIGINT, SIG_DFL); /* terminate process */ + mySignal(SIGQUIT, SIG_DFL); /* terminate process */ + mySignal(SIGTERM, SIG_DFL); /* terminate process */ + mySignal(SIGILL, SIG_DFL); /* create core image */ + mySignal(SIGIOT, SIG_DFL); /* create core image */ + mySignal(SIGFPE, SIG_DFL); /* create core image */ +#ifdef SIGBUS + mySignal(SIGBUS, SIG_DFL); /* create core image */ +#endif /* SIGBUS */ +#ifdef SIGCHLD + mySignal(SIGCHLD, SIG_IGN); +#endif +#ifdef SIGPIPE + mySignal(SIGPIPE, SIG_IGN); +#endif +} + +#ifndef FOPEN_MAX +#define FOPEN_MAX 1024 /* XXX */ +#endif + +static void +close_all_fds_except(int i, int f) +{ + switch (i) { /* fall through */ + case 0: + dup2(open(DEV_NULL_PATH, O_RDONLY), 0); + case 1: + dup2(open(DEV_NULL_PATH, O_WRONLY), 1); + case 2: + dup2(open(DEV_NULL_PATH, O_WRONLY), 2); + } + /* close all other file descriptors (socket, ...) */ + for (i = 3; i < FOPEN_MAX; i++) { + if (i != f) + close(i); + } +} + +void +setup_child(int child, int i, int f) +{ + reset_signals(); + mySignal(SIGINT, SIG_IGN); + if (!child) + SETPGRP(); + close_tty(); + close_all_fds_except(i, f); + QuietMessage = TRUE; + fmInitialized = FALSE; + TrapSignal = FALSE; +} + +pid_t +open_pipe_rw(FILE ** fr, FILE ** fw) +{ + int fdr[2]; + int fdw[2]; + pid_t pid; + + if (fr && pipe(fdr) < 0) + goto err0; + if (fw && pipe(fdw) < 0) + goto err1; + + flush_tty(); + pid = fork(); + if (pid < 0) + goto err2; + if (pid == 0) { + /* child */ + if (fr) { + close(fdr[0]); + dup2(fdr[1], 1); + } + if (fw) { + close(fdw[1]); + dup2(fdw[0], 0); + } + } + else { + if (fr) { + close(fdr[1]); + if (*fr == stdin) + dup2(fdr[0], 0); + else + *fr = fdopen(fdr[0], "r"); + } + if (fw) { + close(fdw[0]); + if (*fw == stdout) + dup2(fdw[1], 1); + else + *fw = fdopen(fdw[1], "w"); + } + } + return pid; + err2: + if (fw) { + close(fdw[0]); + close(fdw[1]); + } + err1: + if (fr) { + close(fdr[0]); + close(fdr[1]); + } + err0: + return (pid_t) - 1; +} + +void +myExec(char *command) +{ + mySignal(SIGINT, SIG_DFL); + execl("/bin/sh", "sh", "-c", command, NULL); + exit(127); +} + +void +mySystem(char *command, int background) +{ + if (background) { +#ifndef __EMX__ + flush_tty(); + if (!fork()) { + setup_child(FALSE, 0, -1); + myExec(command); + } +#else + Str cmd = Strnew_charp("start /f "); + Strcat_charp(cmd, command); + system(cmd->ptr); +#endif + } + else + system(command); +} + +Str +myExtCommand(char *cmd, char *arg, int redirect) +{ + Str tmp = NULL; + char *p; + int set_arg = FALSE; + + for (p = cmd; *p; p++) { + if (*p == '%' && *(p + 1) == 's' && !set_arg) { + if (tmp == NULL) + tmp = Strnew_charp_n(cmd, (int)(p - cmd)); + Strcat_charp(tmp, arg); + set_arg = TRUE; + p++; + } + else { + if (tmp) + Strcat_char(tmp, *p); + } + } + if (!set_arg) { + if (redirect) + tmp = Strnew_m_charp("(", cmd, ") < ", arg, NULL); + else + tmp = Strnew_m_charp(cmd, " ", arg, NULL); + } + return tmp; +} + +Str +myEditor(char *cmd, char *file, int line) +{ + Str tmp = NULL; + char *p; + int set_file = FALSE, set_line = FALSE; + + for (p = cmd; *p; p++) { + if (*p == '%' && *(p + 1) == 's' && !set_file) { + if (tmp == NULL) + tmp = Strnew_charp_n(cmd, (int)(p - cmd)); + Strcat_charp(tmp, file); + set_file = TRUE; + p++; + } + else if (*p == '%' && *(p + 1) == 'd' && !set_line && line > 0) { + if (tmp == NULL) + tmp = Strnew_charp_n(cmd, (int)(p - cmd)); + Strcat(tmp, Sprintf("%d", line)); + set_line = TRUE; + p++; + } + else { + if (tmp) + Strcat_char(tmp, *p); + } + } + if (!set_file) { + if (tmp == NULL) + tmp = Strnew_charp(cmd); + if (!set_line && line > 1 && strcasestr(cmd, "vi")) + Strcat(tmp, Sprintf(" +%d", line)); + Strcat_m_charp(tmp, " ", file, NULL); + } + return tmp; +} + +char * +expandName(char *name) +{ + char *p; + struct passwd *passent, *getpwnam(const char *); + Str extpath = NULL; + + if (name == NULL) + return NULL; + p = name; + if (*p == '/') { + if ((*(p + 1) == '~' && IS_ALPHA(*(p + 2))) + && personal_document_root) { + char *q; + p += 2; + q = strchr(p, '/'); + if (q) { /* /~user/dir... */ + passent = getpwnam(allocStr(p, q - p)); + p = q; + } + else { /* /~user */ + passent = getpwnam(p); + p = ""; + } + if (!passent) + goto rest; + extpath = Strnew_m_charp(passent->pw_dir, "/", + personal_document_root, NULL); + if (*personal_document_root == '\0' && *p == '/') + p++; + } + else + goto rest; + if (Strcmp_charp(extpath, "/") == 0 && *p == '/') + p++; + Strcat_charp(extpath, p); + return extpath->ptr; + } + else + return expandPath(p); + rest: + return name; +} + +char * +file_to_url(char *file) +{ + Str tmp; +#ifdef SUPPORT_DOS_DRIVE_PREFIX + char *drive = NULL; +#endif +#ifdef SUPPORT_NETBIOS_SHARE + char *host = NULL; +#endif + + file = expandPath(file); +#ifdef SUPPORT_NETBIOS_SHARE + if (file[0] == '/' && file[1] == '/') { + char *p; + file += 2; + if (*file) { + p = strchr(file, '/'); + if (p != NULL && p != file) { + host = allocStr(file, (p - file)); + file = p; + } + } + } +#endif +#ifdef SUPPORT_DOS_DRIVE_PREFIX + if (IS_ALPHA(file[0]) && file[1] == ':') { + drive = allocStr(file, 2); + file += 2; + } + else +#endif + if (file[0] != '/') { + tmp = Strnew_charp(CurrentDir); + if (Strlastchar(tmp) != '/') + Strcat_char(tmp, '/'); + Strcat_charp(tmp, file); + file = tmp->ptr; + } + tmp = Strnew_charp("file://"); +#ifdef SUPPORT_NETBIOS_SHARE + if (host) + Strcat_charp(tmp, host); +#endif +#ifdef SUPPORT_DOS_DRIVE_PREFIX + if (drive) + Strcat_charp(tmp, drive); +#endif + Strcat_charp(tmp, file_quote(cleanupName(file))); + return tmp->ptr; +} + +#ifdef USE_M17N +char * +url_unquote_conv(char *url, wc_ces charset) +#else +char * +url_unquote_conv0(char *url) +#endif +{ +#ifdef USE_M17N + wc_uint8 old_auto_detect = WcOption.auto_detect; +#endif + Str tmp; + tmp = Str_url_unquote(Strnew_charp(url), FALSE, TRUE); +#ifdef USE_M17N + if (!charset || charset == WC_CES_US_ASCII) + charset = SystemCharset; + WcOption.auto_detect = WC_OPT_DETECT_ON; + tmp = convertLine(NULL, tmp, RAW_MODE, &charset, charset); + WcOption.auto_detect = old_auto_detect; +#endif + return tmp->ptr; +} + +static char *tmpf_base[MAX_TMPF_TYPE] = { + "tmp", "src", "frame", "cache", "cookie", +}; +static unsigned int tmpf_seq[MAX_TMPF_TYPE]; + +Str +tmpfname(int type, char *ext) +{ + Str tmpf; + tmpf = Sprintf("%s/w3m%s%d-%d%s", + tmp_dir, + tmpf_base[type], + CurrentPid, tmpf_seq[type]++, (ext) ? ext : ""); + pushText(fileToDelete, tmpf->ptr); + return tmpf; +} + +static char *monthtbl[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static int +get_day(char **s) +{ + Str tmp = Strnew(); + int day; + char *ss = *s; + + if (!**s) + return -1; + + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + + day = atoi(tmp->ptr); + + if (day < 1 || day > 31) { + *s = ss; + return -1; + } + return day; +} + +static int +get_month(char **s) +{ + Str tmp = Strnew(); + int mon; + char *ss = *s; + + if (!**s) + return -1; + + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + if (tmp->length > 0) { + mon = atoi(tmp->ptr); + } + else { + while (**s && IS_ALPHA(**s)) + Strcat_char(tmp, *((*s)++)); + for (mon = 1; mon <= 12; mon++) { + if (strncmp(tmp->ptr, monthtbl[mon - 1], 3) == 0) + break; + } + } + if (mon < 1 || mon > 12) { + *s = ss; + return -1; + } + return mon; +} + +static int +get_year(char **s) +{ + Str tmp = Strnew(); + int year; + char *ss = *s; + + if (!**s) + return -1; + + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + if (tmp->length != 2 && tmp->length != 4) { + *s = ss; + return -1; + } + + year = atoi(tmp->ptr); + if (tmp->length == 2) { + if (year >= 70) + year += 1900; + else + year += 2000; + } + return year; +} + +static int +get_time(char **s, int *hour, int *min, int *sec) +{ + Str tmp = Strnew(); + char *ss = *s; + + if (!**s) + return -1; + + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + if (**s != ':') { + *s = ss; + return -1; + } + *hour = atoi(tmp->ptr); + + (*s)++; + Strclear(tmp); + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + if (**s != ':') { + *s = ss; + return -1; + } + *min = atoi(tmp->ptr); + + (*s)++; + Strclear(tmp); + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + *sec = atoi(tmp->ptr); + + if (*hour < 0 || *hour >= 24 || + *min < 0 || *min >= 60 || *sec < 0 || *sec >= 60) { + *s = ss; + return -1; + } + return 0; +} + +static int +get_zone(char **s, int *z_hour, int *z_min) +{ + Str tmp = Strnew(); + int zone; + char *ss = *s; + + if (!**s) + return -1; + + if (**s == '+' || **s == '-') + Strcat_char(tmp, *((*s)++)); + while (**s && IS_DIGIT(**s)) + Strcat_char(tmp, *((*s)++)); + if (!(tmp->length == 4 && IS_DIGIT(*ss)) && + !(tmp->length == 5 && (*ss == '+' || *ss == '-'))) { + *s = ss; + return -1; + } + + zone = atoi(tmp->ptr); + *z_hour = zone / 100; + *z_min = zone - (zone / 100) * 100; + return 0; +} + +/* RFC 1123 or RFC 850 or ANSI C asctime() format string -> time_t */ +time_t +mymktime(char *timestr) +{ + char *s; + int day, mon, year, hour, min, sec, z_hour = 0, z_min = 0; + + if (!(timestr && *timestr)) + return -1; + s = timestr; + +#ifdef DEBUG + fprintf(stderr, "mktime: %s\n", timestr); +#endif /* DEBUG */ + + while (*s && IS_ALPHA(*s)) + s++; + while (*s && !IS_ALNUM(*s)) + s++; + + if (IS_DIGIT(*s)) { + /* RFC 1123 or RFC 850 format */ + if ((day = get_day(&s)) == -1) + return -1; + + while (*s && !IS_ALNUM(*s)) + s++; + if ((mon = get_month(&s)) == -1) + return -1; + + while (*s && !IS_DIGIT(*s)) + s++; + if ((year = get_year(&s)) == -1) + return -1; + + while (*s && !IS_DIGIT(*s)) + s++; + if (!*s) { + hour = 0; + min = 0; + sec = 0; + } + else { + if (get_time(&s, &hour, &min, &sec) == -1) + return -1; + while (*s && !IS_DIGIT(*s) && *s != '+' && *s != '-') + s++; + get_zone(&s, &z_hour, &z_min); + } + } + else { + /* ANSI C asctime() format. */ + while (*s && !IS_ALNUM(*s)) + s++; + if ((mon = get_month(&s)) == -1) + return -1; + + while (*s && !IS_DIGIT(*s)) + s++; + if ((day = get_day(&s)) == -1) + return -1; + + while (*s && !IS_DIGIT(*s)) + s++; + if (get_time(&s, &hour, &min, &sec) == -1) + return -1; + + while (*s && !IS_DIGIT(*s)) + s++; + if ((year = get_year(&s)) == -1) + return -1; + } +#ifdef DEBUG + fprintf(stderr, + "year=%d month=%d day=%d hour:min:sec=%d:%d:%d zone=%d:%d\n", year, + mon, day, hour, min, sec, z_hour, z_min); +#endif /* DEBUG */ + + mon -= 3; + if (mon < 0) { + mon += 12; + year--; + } + day += (year - 1968) * 1461 / 4; + day += ((((mon * 153) + 2) / 5) - 672); + hour -= z_hour; + min -= z_min; + return (time_t) ((day * 60 * 60 * 24) + + (hour * 60 * 60) + (min * 60) + sec); +} + +#ifdef USE_COOKIE +#ifdef INET6 +#include <sys/socket.h> +#endif /* INET6 */ +#include <netdb.h> +char * +FQDN(char *host) +{ + char *p; +#ifndef INET6 + struct hostent *entry; +#else /* INET6 */ + int *af; +#endif /* INET6 */ + + if (host == NULL) + return NULL; + + if (strcasecmp(host, "localhost") == 0) + return host; + + for (p = host; *p && *p != '.'; p++) ; + + if (*p == '.') + return host; + +#ifndef INET6 + if (!(entry = gethostbyname(host))) + return NULL; + + return allocStr(entry->h_name, -1); +#else /* INET6 */ + for (af = ai_family_order_table[DNS_order];; af++) { + int error; + struct addrinfo hints; + struct addrinfo *res, *res0; + char *namebuf; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = *af; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + if (*af == PF_UNSPEC) { + /* all done */ + break; + } + /* try next address family */ + continue; + } + for (res = res0; res != NULL; res = res->ai_next) { + if (res->ai_canonname) { + /* found */ + namebuf = strdup(res->ai_canonname); + freeaddrinfo(res0); + return namebuf; + } + } + freeaddrinfo(res0); + if (*af == PF_UNSPEC) { + break; + } + } + /* all failed */ + return NULL; +#endif /* INET6 */ +} + +#endif /* USE_COOKIE */ + +void (*mySignal(int signal_number, void (*action) (int))) (int) { +#ifdef SA_RESTART + struct sigaction new_action, old_action; + + sigemptyset(&new_action.sa_mask); + new_action.sa_handler = action; + if (signal_number == SIGALRM) { +#ifdef SA_INTERRUPT + new_action.sa_flags = SA_INTERRUPT; +#else + new_action.sa_flags = 0; +#endif + } + else { + new_action.sa_flags = SA_RESTART; + } + sigaction(signal_number, &new_action, &old_action); + return (old_action.sa_handler); +#else + return (signal(signal_number, action)); +#endif +} |