diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 2011-06-11 12:12:46 -0400 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 2011-06-11 12:12:46 -0400 |
commit | 279010bc0791556e63b4951d83a2c45252142b80 (patch) | |
tree | 2f0ca07764a555764bb1f5a628a3468e88bf0c59 /src/LYUtils.c | |
parent | 0b30d0d375231ff07227872f2d1d25f005e43e98 (diff) | |
download | lynx-snapshots-279010bc0791556e63b4951d83a2c45252142b80.tar.gz |
snapshot of project "lynx", label v2_8_8dev_9a
Diffstat (limited to 'src/LYUtils.c')
-rw-r--r-- | src/LYUtils.c | 7998 |
1 files changed, 0 insertions, 7998 deletions
diff --git a/src/LYUtils.c b/src/LYUtils.c deleted file mode 100644 index 7ea2472f..00000000 --- a/src/LYUtils.c +++ /dev/null @@ -1,7998 +0,0 @@ -/* - * $LynxId: LYUtils.c,v 1.211 2011/06/05 20:38:08 tom Exp $ - */ -#include <HTUtils.h> -#include <HTTCP.h> -#include <HTParse.h> -#include <HTAccess.h> -#include <HTCJK.h> -#include <HTAlert.h> - -#if defined(__MINGW32__) - -extern int kbhit(void); /* FIXME: use conio.h */ - -#undef UNIX - -#elif defined(_WINDOWS) - -#ifdef DONT_USE_GETTEXT -#undef gettext -#endif - -#include <conio.h> - -#ifdef DONT_USE_GETTEXT -#define gettext(s) s -#endif - -#if !defined(kbhit) && defined(_WCONIO_DEFINED) -#define kbhit() _kbhit() /* reasonably recent conio.h */ -#endif - -#endif /* __MINGW32__ */ - -#include <LYCurses.h> -#include <LYHistory.h> -#include <LYStrings.h> -#include <LYGlobalDefs.h> -#include <LYUtils.h> -#include <LYSignal.h> -#include <GridText.h> -#include <LYClean.h> -#include <LYCharSets.h> -#include <LYCharUtils.h> - -#include <LYMainLoop.h> -#include <LYKeymap.h> - -#ifdef __DJGPP__ -#include <go32.h> -#include <sys/exceptn.h> -#endif /* __DJGPP__ */ - -#ifndef NO_GROUPS -#include <HTFile.h> -#endif - -#ifdef _WINDOWS /* 1998/04/30 (Thu) 19:04:25 */ -#define GETPID() (unsigned) (getpid() & 0xffff) -#else -#define GETPID() (unsigned) getpid() -#endif /* _WINDOWS */ - -#ifdef FNAMES_8_3 -#define PID_FMT "%04x" -#else -#define PID_FMT "%u" -#endif - -#ifdef DJGPP_KEYHANDLER -#include <bios.h> -#endif /* DJGPP_KEYHANDLER */ - -#ifdef __EMX__ -# define BOOLEAN OS2_BOOLEAN /* Conflicts, but is used */ -# undef HT_ERROR /* Conflicts too */ -# define INCL_PM /* I want some PM functions.. */ -# define INCL_DOSPROCESS /* TIB PIB. */ -# include <os2.h> -# undef BOOLEAN -#endif - -#ifdef VMS -#include <descrip.h> -#include <libclidef.h> -#include <lib$routines.h> -#endif /* VMS */ - -#ifdef HAVE_UTMP -#include <pwd.h> -#ifdef UTMPX_FOR_UTMP -#include <utmpx.h> -#define utmp utmpx -#ifdef UTMPX_FILE -#ifdef UTMP_FILE -#undef UTMP_FILE -#endif /* UTMP_FILE */ -#define UTMP_FILE UTMPX_FILE -#else -#ifdef __UTMPX_FILE -#define UTMP_FILE __UTMPX_FILE /* at least in OS/390 S/390 -- gil -- 2100 */ -#else -#ifndef UTMP_FILE -#define UTMP_FILE "/var/adm/utmpx" /* Digital Unix 4.0 */ -#endif -#endif -#endif /* UTMPX_FILE */ -#else -#include <utmp.h> -#endif /* UTMPX_FOR_UTMP */ -#endif /* HAVE_UTMP */ - -#ifdef NEED_PTEM_H -/* they neglected to define struct winsize in termios.h -- it's only in - * termio.h and ptem.h (the former conflicts with other definitions). - */ -#include <sys/stream.h> -#include <sys/ptem.h> -#endif - -#include <LYLeaks.h> - -#ifdef USE_COLOR_STYLE -#include <AttrList.h> -#include <LYHash.h> -#include <LYStyle.h> -#endif - -#ifdef SVR4_BSDSELECT -extern int BSDselect(int nfds, fd_set * readfds, fd_set * writefds, - fd_set * exceptfds, struct timeval *timeout); - -#ifdef select -#undef select -#endif /* select */ -#define select BSDselect -#ifdef SOCKS -#ifdef Rselect -#undef Rselect -#endif /* Rselect */ -#define Rselect BSDselect -#endif /* SOCKS */ -#endif /* SVR4_BSDSELECT */ - -#ifdef __DJGPP__ -#undef select /* defined to select_s in www_tcp.h */ -#endif - -#ifndef UTMP_FILE -#if defined(__FreeBSD__) || defined(__bsdi__) -#define UTMP_FILE _PATH_UTMP -#else -#define UTMP_FILE "/etc/utmp" -#endif /* __FreeBSD__ || __bsdi__ */ -#endif /* !UTMP_FILE */ - -/* - * experimental - make temporary filenames random to make the scheme less - * obvious. However, as noted by KW, there are instances (such as the - * 'O'ption page, for which Lynx will store a temporary filename even when - * it no longer applies, since it will reuse that filename at a later time. - */ -#ifdef USE_RAND_TEMPNAME -#if defined(LYNX_RAND_MAX) -#define HAVE_RAND_TEMPNAME 1 -#define MAX_TEMPNAME 10000 -#ifndef BITS_PER_CHAR -#define BITS_PER_CHAR 8 -#endif -#endif -#endif - -#define COPY_COMMAND "%s %s %s" - -static HTList *localhost_aliases = NULL; /* Hosts to treat as local */ -static char *HomeDir = NULL; /* HOME directory */ - -HTList *sug_filenames = NULL; /* Suggested filenames */ - -/* - * Maintain a list of all of the temp-files we create so that we can remove - * them during the cleanup. - */ -typedef struct _LYTemp { - struct _LYTemp *next; - char *name; - BOOLEAN outs; - FILE *file; -} LY_TEMP; - -static LY_TEMP *ly_temp; - -static LY_TEMP *FindTempfileByName(const char *name) -{ - LY_TEMP *p; - - for (p = ly_temp; p != 0; p = p->next) { - if (!strcmp(p->name, name)) { - break; - } - } - return p; -} - -static LY_TEMP *FindTempfileByFP(FILE *fp) -{ - LY_TEMP *p; - - for (p = ly_temp; p != 0; p = p->next) { - if (p->file == fp) { - break; - } - } - return p; -} - -#if defined(_WIN32) -/* - * Use RegQueryValueExA() rather than RegQueryValueEx() for compatibility - * with non-Unicode winvile - */ -static int w32_get_reg_sz(HKEY hkey, const char *name, char *value, unsigned length) -{ - int result; - DWORD dwSzBuffer = length; - - CTRACE((tfp, "w32_get_reg_sz(%s)\n", name)); - result = RegQueryValueExA(hkey, - name, - NULL, - NULL, - (LPBYTE) value, - &dwSzBuffer); - if (result == ERROR_SUCCESS) { - value[dwSzBuffer] = 0; - CTRACE((tfp, "->%s\n", value)); - } - return result; -} -#endif - -/* - * Get an environment variable, rejecting empty strings - */ -char *LYGetEnv(const char *name) -{ - char *result = getenv(name); - -#if defined(_WIN32) - if (result == 0) { - static HKEY rootkeys[] = - {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; - - int j; - HKEY hkey; - char buffer[256]; - - for (j = 0; j < (int) TABLESIZE(rootkeys); ++j) { - if (RegOpenKeyEx(rootkeys[j], - LYNX_SUBKEY W32_STRING("\\Environment"), - 0, - KEY_READ, - &hkey) == ERROR_SUCCESS) { - if (w32_get_reg_sz(hkey, name, buffer, sizeof(buffer)) == ERROR_SUCCESS) { - - result = strdup(buffer); - (void) RegCloseKey(hkey); - break; - } - - (void) RegCloseKey(hkey); - } - } - } -#endif - return non_empty(result) ? result : 0; -} - -/* - * ascii versions of locale sensitive functions needed because in - * Turkish locales tolower("I") is not "i". That's fatal for case - * sensitive operations with charset names, HTML tags etc. - */ -#ifdef USE_ASCII_CTYPES -int ascii_tolower(int i) -{ - if (91 > i && i > 64) - return (i + 32); - else - return i; -} - -int ascii_toupper(int i) -{ - if (123 > i && i > 96) - return (i - 32); - else - return i; -} - -int ascii_isupper(int i) -{ - if (91 > i && i > 64) - return 1; - else - return 0; -} -#endif /* USE_ASCII_CTYPES */ - -/* - * Check for UTF-8 data, returning the length past the first character. - * Return zero if we found an ordinary character rather than UTF-8. - */ -size_t utf8_length(int utf_flag, - const char *data) -{ - size_t utf_extra = 0; - - if (utf_flag && is8bits(*data)) { - if ((*data & 0xe0) == 0xc0) { - utf_extra = 1; - } else if ((*data & 0xf0) == 0xe0) { - utf_extra = 2; - } else if ((*data & 0xf8) == 0xf0) { - utf_extra = 3; - } else if ((*data & 0xfc) == 0xf8) { - utf_extra = 4; - } else if ((*data & 0xfe) == 0xfc) { - utf_extra = 5; - } else { - /* - * Garbage. - */ - utf_extra = 0; - } - if (strlen(data + 1) < utf_extra) { - /* - * Shouldn't happen. - */ - utf_extra = 0; - } - } - return utf_extra; -} - -/* - * Free storage used for the link-highlighting. - */ -void LYFreeHilites(int first, int last) -{ - int i; - - for (i = first; i < last; i++) { - LYSetHilite(i, NULL); - FREE(links[i].lname); - } -} - -#define LXP (links[cur].lx) -#define LYP (links[cur].ly) - -/* - * Set the initial highlight information for a given link. - */ -void LYSetHilite(int cur, - const char *text) -{ - links[cur].list.hl_base.hl_text = (char *) text; - links[cur].list.hl_len = (short) ((text != NULL) ? 1 : 0); - FREE(links[cur].list.hl_info); -} - -/* - * Add highlight information for the next line of a link. - */ -void LYAddHilite(int cur, - char *text, - int x) -{ - HiliteList *list = &(links[cur].list); - HiliteInfo *have = list->hl_info; - size_t need = (unsigned) (list->hl_len - 1); - size_t want; - - list->hl_len = (short) (list->hl_len + 1); - want = (size_t) list->hl_len; - - if (have != NULL) { - have = typeRealloc(HiliteInfo, have, want); - } else { - have = typeMallocn(HiliteInfo, want); - } - list->hl_info = have; - have[need].hl_text = text; - have[need].hl_x = (short) x; -} - -/* - * Get the highlight text, counting from zero. - */ -const char *LYGetHiliteStr(int cur, - int count) -{ - const char *result; - - if (count >= links[cur].list.hl_len) - result = NULL; - else if (count > 0) - result = links[cur].list.hl_info[count - 1].hl_text; - else - result = links[cur].list.hl_base.hl_text; - return result; -} - -/* - * Get the X-ordinate at which to draw the corresponding highlight-text - */ -int LYGetHilitePos(int cur, - int count) -{ - int result; - - if (count >= links[cur].list.hl_len) - result = -1; - else if (count > 0) - result = links[cur].list.hl_info[count - 1].hl_x; - else - result = LXP; - return result; -} - -#ifdef SHOW_WHEREIS_TARGETS - -#define SKIP_GLYPHS(theFlag, theData, theOffset) \ - (theFlag \ - ? LYmbcs_skip_glyphs(theData, (theOffset), theFlag) \ - : (theData + (theOffset))) - -/* - * If we have an emphasized WHEREIS hit in the highlighted text, restore the - * emphasis. Note that we never emphasize the first and last characters of the - * highlighted text when we are making the link current, so the link attributes - * for the current link will persist at the beginning and end, providing an - * indication to the user that it has been made current. Also note that we use - * HText_getFirstTargetInLine() to determine if there's a hit in the HText - * structure line containing the link, and if so, get back a copy of the line - * starting at that first hit (which might be before or after our link), and - * with all IsSpecial characters stripped, so we don't need to deal with them - * here. -FM - */ -static BOOL show_whereis_targets(int flag, - int cur, - int count, - const char *target, - int TargetEmphasisON, - int utf_flag) -{ - const char *Data = NULL; - const char *cp; - char *theData = NULL; - char buffer[MAX_LINE]; - char tmp[7]; - int HitOffset; - int LenNeeded; - int Offset; - int tLen; - - tmp[0] = tmp[1] = tmp[2] = '\0'; - - if (non_empty(target) - && (links[cur].type & WWW_LINK_TYPE) - && non_empty(LYGetHiliteStr(cur, count)) - && LYP + count < display_lines - && HText_getFirstTargetInLine(HTMainText, - links[cur].anchor_line_num + count, - utf_flag, - &Offset, - &tLen, - &theData, - target)) { - int itmp, written, len, y, offset; - const char *data; - int tlen = (int) strlen(target); - int hlen, hLen; - int hLine = LYP + count; - int hoffset = LYGetHilitePos(cur, count); - size_t utf_extra = 0; - - /* - * Copy into the buffer only what will fit up to the right border of - * the screen. -FM - */ - LYmbcsstrncpy(buffer, - NonNull(LYGetHiliteStr(cur, count)), - (int) (sizeof(buffer) - 1), - (LYcolLimit - LYGetHilitePos(cur, count)), - utf_flag); - hlen = (int) strlen(buffer); - hLen = ((IS_CJK_TTY || utf_flag) ? - LYmbcsstrlen(buffer, utf_flag, YES) : hlen); - - /* - * Break out if the first hit in the line starts after this link. -FM - */ - if (Offset < (hoffset + hLen)) { - /* - * Recursively skip hits that end before this link, and break out - * if there is no hit beyond those. -FM - */ - Data = theData; - while ((Offset < hoffset) && - ((Offset + tLen) <= hoffset)) { - data = (Data + tlen); - offset = (Offset + tLen); - if (((cp = LYno_attr_mb_strstr(data, - target, - utf_flag, YES, - &HitOffset, - &LenNeeded)) != NULL) - && (offset + LenNeeded) < LYcols) { - Data = cp; - Offset = (offset + HitOffset); - } else { - goto highlight_search_done; - } - } - data = buffer; - offset = hoffset; - - /* - * If the hit starts before the hightext, and ends in or beyond the - * hightext, restore the emphasis, skipping the first and last - * characters of the hightext if we're making the link current. - * -FM - */ - if ((Offset < offset) && - ((Offset + tLen) > offset)) { - itmp = 0; - written = 0; - len = (tlen - (offset - Offset)); - - /* - * Go to the start of the hightext and handle its first - * character. -FM - */ - LYmove(hLine, offset); - tmp[0] = data[itmp]; - utf_extra = utf8_length(utf_flag, data + itmp); - if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); - itmp += (int) utf_extra; - /* - * Start emphasis immediately if we are making the link - * non-current. -FM - */ - if (flag != ON) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 1)); - } - tmp[1] = '\0'; - written += (int) (utf_extra + 1); - } else if (IS_CJK_TTY && is8bits(tmp[0])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - tmp[1] = data[++itmp]; - /* - * Start emphasis immediately if we are making the link - * non-current. -FM - */ - if (flag != ON) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 1)); - } - tmp[1] = '\0'; - written += 2; - } else { - /* - * Start emphasis immediately if we are making the link - * non-current. -FM - */ - if (flag != ON) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 1)); - } - written++; - } - itmp++; - /* - * Start emphasis after the first character if we are making - * the link current and this is not the last character. -FM - */ - if (!TargetEmphasisON && - data[itmp] != '\0') { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - } - - /* - * Handle the remaining characters. -FM - */ - for (; - written < len && (tmp[0] = data[itmp]) != '\0'; - itmp++) { - /* - * Print all the other target chars, except the last - * character if it is also the last character of hightext - * and we are making the link current. -FM - */ - utf_extra = utf8_length(utf_flag, data + itmp); - if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); - itmp += (int) utf_extra; - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += (int) (utf_extra + 1); - } else if (IS_CJK_TTY && is8bits(tmp[0])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - tmp[1] = data[++itmp]; - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += 2; - } else { - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - written++; - } - } - - /* - * Stop the emphasis if we haven't already, then reset the - * offset to our current position in the line, and if that is - * beyond the link, or or we are making the link current and it - * is the last character of the hightext, we are done. -FM - */ - if (TargetEmphasisON) { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - } - LYGetYX(y, offset); - if (offset < (hoffset + (flag == ON ? (hLen - 1) : hLen)) - /* - * See if we have another hit that starts within the - * hightext. -FM - */ - && ((cp = - LYno_attr_mb_strstr(data = SKIP_GLYPHS(utf_flag, - Data, - offset - Offset), - target, - utf_flag, YES, - &HitOffset, - &LenNeeded)) != NULL) - && (offset + LenNeeded) < LYcols - /* - * If the hit starts after the end of the hightext, or we - * are making the link current and the hit starts at its - * last character, we are done. -FM - */ - && (HitOffset + offset) < - (hoffset + - (flag == ON ? (hLen - 1) : hLen))) { - /* - * Set up the data and offset for the hit, and let the code - * for within hightext hits handle it. -FM - */ - Data = cp; - Offset = (offset + HitOffset); - data = buffer; - offset = hoffset; - goto highlight_hit_within_hightext; - } - goto highlight_search_done; - } - - highlight_hit_within_hightext: - /* - * If we get to here, the hit starts within the hightext. If we - * are making the link current and it's the last character in the - * hightext, we are done. Otherwise, move there and start - * restoring the emphasis. -FM - */ - if ((Offset - offset) <= (flag == ON ? (hLen - 1) : hLen)) { - data = SKIP_GLYPHS(utf_flag, data, Offset - offset); - if (utf_flag) { - LYrefresh(); - } - offset = Offset; - itmp = 0; - written = 0; - len = tlen; - - /* - * Go to the start of the hit and handle its first character. - * -FM - */ - LYmove(hLine, offset); - tmp[0] = data[itmp]; - utf_extra = utf8_length(utf_flag, data + itmp); - if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); - itmp += (int) utf_extra; - /* - * Start emphasis immediately if we are making the link - * non-current, or we are making it current but this is not - * the first or last character of the hightext. -FM - */ - if (flag != ON || - (offset > hoffset && data[itmp + 1] != '\0')) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 1)); - } - tmp[1] = '\0'; - written += (int) (utf_extra + 1); - } else if (IS_CJK_TTY && is8bits(tmp[0])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - tmp[1] = data[++itmp]; - /* - * Start emphasis immediately if we are making the link - * non-current, or we are making it current but this is not - * the first or last character of the hightext. -FM - */ - if (flag != ON || - (offset > hoffset && data[itmp + 1] != '\0')) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 2)); - } - tmp[1] = '\0'; - written += 2; - } else { - /* - * Start emphasis immediately if we are making the link - * non-current, or we are making it current but this is not - * the first or last character of the hightext. -FM - */ - if (flag != ON || - (offset > hoffset && data[itmp + 1] != '\0')) { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - LYaddstr(tmp); - } else { - LYmove(hLine, (offset + 1)); - } - written++; - } - itmp++; - /* - * Start emphasis after the first character if we are making - * the link current and this is not the last character. -FM - */ - if (!TargetEmphasisON && - data[itmp] != '\0') { - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - } - - for (; - written < len && (tmp[0] = data[itmp]) != '\0'; - itmp++) { - /* - * Print all the other target chars, except the last - * character if it is also the last character of hightext - * and we are making the link current. -FM - */ - utf_extra = utf8_length(utf_flag, data + itmp); - if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); - itmp += (int) utf_extra; - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += (int) (utf_extra + 1); - } else if (IS_CJK_TTY && is8bits(tmp[0])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - tmp[1] = data[++itmp]; - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += 2; - } else { - /* - * Make sure we don't restore emphasis to the last - * character of hightext if we are making the link - * current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - written++; - } - } - - /* - * Stop the emphasis if we haven't already, then reset the - * offset to our current position in the line, and if that is - * beyond the link, or we are making the link current and it is - * the last character in the hightext, we are done. -FM - */ - if (TargetEmphasisON) { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - } - LYGetYX(y, offset); - if (offset < (hoffset + (flag == ON ? (hLen - 1) : hLen)) - /* - * See if we have another hit that starts within the - * hightext. -FM - */ - && ((cp = - LYno_attr_mb_strstr(data = SKIP_GLYPHS(utf_flag, - Data, - offset - Offset), - target, - utf_flag, YES, - &HitOffset, - &LenNeeded)) != NULL) - && (offset + LenNeeded) < LYcols - /* - * If the hit starts after the end of the hightext, or we - * are making the link current and the hit starts at its - * last character, we are done. -FM - */ - && (HitOffset + offset) < - (hoffset + (flag == ON ? (hLen - 1) : hLen))) { - /* - * If the target extends beyond our buffer, emphasize - * everything in the hightext starting at this hit. - * Otherwise, set up the data and offsets, and loop back. - * -FM - */ - if ((HitOffset + (offset + tLen)) >= (hoffset + hLen)) { - offset = (HitOffset + offset); - data = SKIP_GLYPHS(utf_flag, Data, offset - hoffset); - if (utf_flag) { - LYrefresh(); - } - LYmove(hLine, offset); - itmp = 0; - written = 0; - len = (int) strlen(data); - - /* - * Turn the emphasis back on. -FM - */ - LYstartTargetEmphasis(); - TargetEmphasisON = TRUE; - for (; - written < len && (tmp[0] = data[itmp]) != '\0'; - itmp++) { - /* - * Print all the other target chars, except the - * last character if it is also the last character - * of hightext and we are making the link current. - * -FM - */ - utf_extra = utf8_length(utf_flag, data + itmp); - if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); - itmp += (int) utf_extra; - /* - * Make sure we don't restore emphasis to the - * last character of hightext if we are making - * the link current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - LYGetYX(y, offset); - LYmove(hLine, (offset + 1)); - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += (int) (utf_extra + 1); - } else if (IS_CJK_TTY && is8bits(tmp[0])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - tmp[1] = data[++itmp]; - /* - * Make sure we don't restore emphasis to the - * last character of hightext if we are making - * the link current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - } else { - LYaddstr(tmp); - } - tmp[1] = '\0'; - written += 2; - } else { - /* - * Make sure we don't restore emphasis to the - * last character of hightext if we are making - * the link current. -FM - */ - if (flag == ON && data[(itmp + 1)] == '\0') { - LYstopTargetEmphasis(); - TargetEmphasisON = FALSE; - } else { - LYaddstr(tmp); - } - written++; - } - } - /* - * Turn off the emphasis if we haven't already, and - * then we're done. -FM - */ - if (TargetEmphasisON) { - LYstopTargetEmphasis(); - } - } else { - Data = cp; - Offset = (offset + HitOffset); - data = buffer; - offset = hoffset; - goto highlight_hit_within_hightext; - } - } - } - } - } - highlight_search_done: - FREE(theData); - return (BOOLEAN) TargetEmphasisON; -} -#endif /* SHOW_WHEREIS_TARGETS */ - -#ifdef USE_COLOR_STYLE -static int find_cached_style(int cur, - int flag) -{ - int s = s_alink; - -#ifdef TEXTFIELDS_MAY_NEED_ACTIVATION - if (textfields_need_activation - && links[cur].type == WWW_FORM_LINK_TYPE - && F_TEXTLIKE(links[cur].l_form->type)) - s = s_curedit; -#endif - - if (flag != ON) { - int x; - - /* - * This is where we try to restore the original style when a link is - * unhighlighted. The cached styles array saves the original style - * just for this case. If it doesn't have a color change saved at just - * the right position, we look at preceding positions in the same line - * until we find one. - */ - if (ValidCachedStyle(LYP, LXP)) { - CTRACE2(TRACE_STYLE, - (tfp, "STYLE.highlight.off: cached style @(%d,%d): ", - LYP, LXP)); - s = (int) GetCachedStyle(LYP, LXP); - if (s == 0) { - for (x = LXP - 1; x >= 0; x--) { - s = (int) GetCachedStyle(LYP, x); - if (s != 0) { - SetCachedStyle(LYP, LXP, (unsigned) s); - CTRACE2(TRACE_STYLE, - (tfp, "found %d, x_offset=%d.\n", s, x - LXP)); - break; - } - } - if (s == 0) { - CTRACE2(TRACE_STYLE, (tfp, "not found, assume <a>.\n")); - s = s_a; - } - } else { - CTRACE2(TRACE_STYLE, (tfp, "found %d.\n", s)); - } - } else { - CTRACE2(TRACE_STYLE, - (tfp, "STYLE.highlight.off: can't use cache.\n")); - s = s_a; - } - } else { - CTRACE2(TRACE_STYLE, (tfp, "STYLE.highlight.on: @(%d,%d).\n", LYP, LXP)); - } - return s; -} -#endif /* USE_COLOR_STYLE */ - -/* - * Highlight (or unhighlight) a given link. - */ -void LYhighlight(int flag, - int cur, - const char *target) -{ - char buffer[MAX_LINE]; - int i; - int hi_count; - int hi_offset; - int title_adjust = (no_title ? -TITLE_LINES : 0); - char tmp[7]; - const char *hi_string; - -#ifdef SHOW_WHEREIS_TARGETS - BOOL TargetEmphasisON = FALSE; - BOOL target1_drawn = NO; -#endif - BOOL utf_flag = (BOOL) IS_UTF8_TTY; - BOOL hl1_drawn = NO; - -#ifdef USE_COLOR_STYLE - BOOL hl2_drawn = FALSE; /* whether links[cur].l_hightext2 is already drawn - - properly */ -#endif - tmp[0] = tmp[1] = tmp[2] = '\0'; - - /* - * Bugs in the history code might cause -1 to be sent for cur, which yields - * a crash when LYStrNCpy() is called with a nonsense pointer. As far as I - * know, such bugs have been squashed, but if they should reappear, this - * works around them. -FM - */ - if (cur < 0) { - CTRACE((tfp, "LYhighlight cur %d (bug workaround)\n", cur)); - cur = 0; - } - - CTRACE((tfp, "LYhighlight at(%2d,%2d) %s %d [%d]:%s\n", - links[cur].ly, links[cur].lx, - (flag - ? "on" - : "off"), - cur, - links[cur].anchor_number, - NONNULL(target))); - -#if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH) - if (flag == OFF) - textinput_redrawn = FALSE; -#endif - - if (nlinks > 0) { -#ifdef USE_COLOR_STYLE - if (flag == ON || links[cur].type == WWW_FORM_LINK_TYPE) { - LYmove(LYP + title_adjust, LXP); - LynxChangeStyle(find_cached_style(cur, flag), STACK_ON); - } -#else - if (links[cur].type == WWW_FORM_LINK_TYPE - || LYGetHiliteStr(cur, 0) == NULL) { - LYMoveToLink(cur, target, NULL, - flag, links[cur].inUnderline, utf_flag); - lynx_start_link_color(flag == ON, links[cur].inUnderline); - } else { - LYMoveToLink(cur, target, LYGetHiliteStr(cur, 0), - flag, links[cur].inUnderline, utf_flag); - hl1_drawn = YES; -#ifdef SHOW_WHEREIS_TARGETS - target1_drawn = YES; -#endif - } -#endif - - if (links[cur].type == WWW_FORM_LINK_TYPE) { - int len; - int avail_space = (LYcolLimit - LXP) + (LYcolLimit * (LYlines - LYP)); - const char *text = LYGetHiliteStr(cur, 0); - - if (text == 0) - text = ""; - - if (avail_space > links[cur].l_form->size) - avail_space = links[cur].l_form->size; - - len = (int) (LYmbcs_skip_cells(text, avail_space, utf_flag) - text); - LYwaddnstr(LYwin, text, (size_t) len); - while (len++ < avail_space) - LYaddch('_'); - -#ifdef USE_COLOR_STYLE - } else if (flag == OFF) { - hl2_drawn = TRUE; - redraw_lines_of_link(cur); - CTRACE2(TRACE_STYLE, - (tfp, "STYLE.highlight.off: NOFIX branch @(%d,%d).\n", - LYP, LXP)); -#endif - } else if (!hl1_drawn) { - /* - * Copy into the buffer only what will fit within the width of the - * screen. - */ - LYmbcsstrncpy(buffer, - NonNull(LYGetHiliteStr(cur, 0)), - (int) (sizeof(buffer) - 1), - (LYcolLimit - LXP), - utf_flag); - LYaddstr(buffer); - } - - /* - * Display a second line as well. - */ -#ifdef USE_COLOR_STYLE - if (hl2_drawn == FALSE) -#endif - { - for (hi_count = 1; - (hi_string = LYGetHiliteStr(cur, hi_count)) != NULL - && LYP + hi_count <= display_lines; - ++hi_count) { - int row = LYP + hi_count + title_adjust; - - hi_offset = LYGetHilitePos(cur, hi_count); - lynx_stop_link_color(flag == ON, links[cur].inUnderline); - LYmove(row, hi_offset); - -#ifdef USE_COLOR_STYLE - CTRACE2(TRACE_STYLE, - (tfp, "STYLE.highlight.line2: @(%d,%d), style=%d.\n", - row, hi_offset, - flag == ON ? s_alink : s_a)); - LynxChangeStyle(flag == ON ? s_alink : s_a, ABS_ON); -#else - lynx_start_link_color(flag == ON, links[cur].inUnderline); -#endif - - for (i = 0; (tmp[0] = hi_string[i]) != '\0' - && (i + hi_offset) < LYcols; i++) { - if (!IsSpecialAttrChar(hi_string[i])) { - /* - * For CJK strings, by Masanobu Kimura. - */ - if (IS_CJK_TTY && is8bits(tmp[0])) { - tmp[1] = hi_string[++i]; - LYaddstr(tmp); - tmp[1] = '\0'; - } else { - LYaddstr(tmp); - } - } - } - } - lynx_stop_link_color(flag == ON, links[cur].inUnderline); - } -#ifdef SHOW_WHEREIS_TARGETS - for (hi_count = target1_drawn ? 1 : 0; - LYGetHiliteStr(cur, hi_count) != NULL; - hi_count++) { - TargetEmphasisON = show_whereis_targets(flag, - cur, - hi_count, - target, - TargetEmphasisON, - utf_flag); - } - - if (!LYShowCursor) - /* - * Get cursor out of the way. - */ - LYHideCursor(); - else -#endif /* SHOW_WHEREIS_TARGETS */ - /* - * Never hide the cursor if there's no FANCY CURSES or SLANG. - */ - LYmove(LYP + title_adjust, ((LXP > 0) ? (LXP - 1) : 0)); - - if (flag) - LYrefresh(); - } - return; -} - -/* - * free_and_clear will free a pointer if it is non-zero and then set it to - * zero. - */ -void free_and_clear(char **pointer) -{ - if (*pointer) { - FREE(*pointer); - *pointer = 0; - } - return; -} - -/* - * Convert single or serial newlines to single spaces throughout a string - * (ignore newlines if the preceding character is a space) and convert tabs to - * single spaces. Don't ignore any explicit tabs or spaces if the condense - * argument is FALSE, otherwise, condense any serial spaces or tabs to one - * space. - FM - */ -void convert_to_spaces(char *string, - int condense) -{ - char *s = string; - char *ns; - BOOL last_is_space = FALSE; - - if (!s) - return; - - s = LYSkipNonBlanks(s); - ns = s; - - while (*s) { - switch (*s) { - case ' ': - case '\t': - if (!(condense && last_is_space)) - *(ns++) = ' '; - last_is_space = TRUE; - break; - - case '\r': - case '\n': - if (!last_is_space) { - *(ns++) = ' '; - last_is_space = TRUE; - } - break; - - default: - *(ns++) = *s; - last_is_space = FALSE; - break; - } - s++; - } - *ns = '\0'; - return; -} - -/* - * Strip trailing slashes from directory paths. - */ -char *strip_trailing_slash(char *dirname) -{ - int i; - - i = (int) strlen(dirname) - 1; - while (i >= 0 && dirname[i] == '/') - dirname[i--] = '\0'; - return (dirname); -} - -/* - * Remove most blanks, but restore one trailing blank to make prompts nicer. - */ -static void remove_most_blanks(char *buffer) -{ - int length = (int) strlen(buffer); - BOOL trailing = (BOOL) ((length != 0) && (buffer[length - 1] == ' ')); - - LYReduceBlanks(buffer); - if (trailing) - strcat(buffer, " "); -} - -/* - * Display (or hide) the status line. - */ -BOOLEAN mustshow = FALSE; - -void statusline(const char *text) -{ - char buffer[MAX_LINE]; - unsigned char *temp = NULL; - int max_length, len, i, j; - int at_lineno; - unsigned char k; - char *p; - char text_buff[MAX_LINE]; - - if (text == NULL) - return; - - /* - * Don't print statusline messages if dumping to stdout. - */ - if (dump_output_immediately) - return; - - /* - * Don't print statusline message if turned off. - */ - if (mustshow != TRUE) { - if (no_statusline == TRUE) { - return; - } - } - mustshow = FALSE; - - /* "LYNXDOWNLOAD://Method=-1/File=%s/SugFile=%s%s\">Save to disk</a>\n" */ - LYStrNCpy(text_buff, text, sizeof(text_buff) - 1); - p = strchr(text_buff, '\n'); - if (p) - *p = '\0'; - - /* - * Deal with any CJK escape sequences and Kanji if we have a CJK character - * set selected, otherwise, strip any escapes. Also, make sure text is not - * longer than the statusline window. - FM - */ - max_length = (((LYcolLimit - 1) < (int) sizeof(buffer)) - ? (LYcolLimit - 1) - : (int) sizeof(buffer) - 1); - if ((text_buff[0] != '\0') && - (LYHaveCJKCharacterSet)) { - /* - * Translate or filter any escape sequences. - FM - */ - if ((temp = typecallocn(unsigned char, strlen(text_buff) + 1)) == NULL) - outofmem(__FILE__, "statusline"); - - assert(temp != NULL); - - if (kanji_code == EUC) { - TO_EUC((const unsigned char *) text_buff, temp); - } else if (kanji_code == SJIS) { -#ifdef KANJI_CODE_OVERRIDE - if (!LYRawMode || last_kcode == SJIS) - strcpy(temp, text_buff); - else - TO_SJIS((const unsigned char *) text_buff, temp); -#else - strcpy((char *) temp, text_buff); -#endif - } else { - for (i = 0, j = 0; text_buff[i]; i++) { - if (text_buff[i] != CH_ESC) { /* S/390 -- gil -- 2119 */ - temp[j++] = UCH(text_buff[i]); - } - } - temp[j] = '\0'; - } - - /* - * Deal with any newlines or tabs in the string. - FM - */ - remove_most_blanks((char *) temp); - - /* - * Handle the Kanji, making sure the text is not longer than the - * statusline window. - FM - */ - for (i = 0, j = 0, len = 0, k = '\0'; - temp[i] != '\0' && len < max_length; i++) { - if (k != '\0') { - buffer[j++] = (char) k; - buffer[j++] = (char) temp[i]; - k = '\0'; - len += 2; - } else if ((temp[i] & 0200) != 0) { - k = temp[i]; - } else { - buffer[j++] = (char) temp[i]; - len++; - } - } - buffer[j] = '\0'; - FREE(temp); - } else { - /* - * Deal with any newlines or tabs in the string. - FM - */ - remove_most_blanks(text_buff); -#ifdef WIDEC_CURSES - len = (int) strlen(text_buff); - if (len >= (int) (sizeof(buffer) - 1)) - len = (int) (sizeof(buffer) - 1); - StrNCpy(buffer, text_buff, len)[len] = '\0'; - /* FIXME: a binary search might be faster */ - while (len > 0 && LYstrExtent(buffer, len, len) > max_length) - buffer[--len] = '\0'; -#else - /* - * Strip any escapes, and shorten text if necessary. Note that we - * don't deal with the possibility of UTF-8 characters in the string. - * This is unlikely, but if strings with such characters are used in - * LYMessages_en.h, a compilation symbol of HAVE_UTF8_STATUSLINES could - * be added there, and code added here for determining the displayed - * string length, as we do above for CJK. - FM - */ - for (i = 0, len = 0; text_buff[i] != '\0' && len < max_length; i++) { - if (text_buff[i] != CH_ESC) { /* S/390 -- gil -- 2119 */ - buffer[len++] = text_buff[i]; - } - } - buffer[len] = '\0'; -#endif - } - - /* - * Move to the desired statusline window and output the text highlighted. - * - FM - */ - if (LYStatusLine >= 0) { - if (LYStatusLine < LYlines - 1) { - at_lineno = LYStatusLine; - } else { - at_lineno = LYlines - 1; - } - } else if (user_mode == NOVICE_MODE) { - at_lineno = LYlines - 3; - } else { - at_lineno = LYlines - 1; - } - LYmove(at_lineno, 0); - LYclrtoeol(); - - if (buffer[0] != '\0') { - BOOLEAN has_CJK = FALSE; - - if (IS_CJK_TTY) { - for (i = 0; buffer[i] != '\0'; i++) { - if (buffer[i] & 0x80) { - has_CJK = TRUE; - break; - } - } - } - - if (has_CJK -#ifdef HAVE_UTF8_STATUSLINES - || IS_UTF8_TTY -#endif - ) { - LYrefresh(); - } -#ifndef USE_COLOR_STYLE - lynx_start_status_color(); - LYaddstr(buffer); - lynx_stop_status_color(); -#else - /* draw the status bar in the STATUS style */ - { - int y, x; - int a = ((StrNCmp(buffer, ALERT_FORMAT, ALERT_PREFIX_LEN) - || !hashStyles[s_alert].name) - ? s_status - : s_alert); - - LynxChangeStyle(a, STACK_ON); - LYaddstr(buffer); - wbkgdset(LYwin, - ((lynx_has_color && LYShowColor >= SHOW_COLOR_ON) - ? (chtype) hashStyles[a].color - : A_NORMAL) | ' '); - LYGetYX(y, x); - if (y == at_lineno) { - LYclrtoeol(); - } - if (!(lynx_has_color && LYShowColor >= SHOW_COLOR_ON)) - wbkgdset(LYwin, A_NORMAL | ' '); - else if (s_normal != NOSTYLE) - wbkgdset(LYwin, (chtype) (hashStyles[s_normal].color | ' ')); - else - wbkgdset(LYwin, (chtype) (displayStyles[DSTYLE_NORMAL].color | ' ')); - LynxChangeStyle(a, STACK_OFF); - } -#endif - } - LYrefresh(); - - return; -} - -static const char *novice_lines(int lineno) -{ - switch (lineno) { - case 0: - return NOVICE_LINE_TWO_A; - case 1: - return NOVICE_LINE_TWO_B; - case 2: - return NOVICE_LINE_TWO_C; - default: - return ""; - } -} - -static int lineno = 0; - -void toggle_novice_line(void) -{ - lineno++; - if (*novice_lines(lineno) == '\0') - lineno = 0; - return; -} - -void noviceline(int more_flag GCC_UNUSED) -{ - if (dump_output_immediately) - return; - - LYmove(LYlines - 2, 0); - LYclrtoeol(); - LYaddstr(NOVICE_LINE_ONE); - - LYmove(LYlines - 1, 0); - LYclrtoeol(); -#if defined(DIRED_SUPPORT ) && defined(OK_OVERRIDE) - if (lynx_edit_mode && !no_dired_support) - LYaddstr(DIRED_NOVICELINE); - else -#endif /* DIRED_SUPPORT && OK_OVERRIDE */ - - if (LYUseNoviceLineTwo) - LYaddstr(NOVICE_LINE_TWO); - else - LYaddstr(novice_lines(lineno)); - - LYrefresh(); - return; -} - -#if defined(MISC_EXP) || defined(TTY_DEVICE) || defined(HAVE_TTYNAME) -/* - * If the standard input is not a tty, and Lynx is really reading from the - * standard input, attempt to reopen it, pointing to a real tty. Normally - * this would happen if the user pipes data to Lynx and wants to run - * interactively after that. - * - * Returns: - * 1 if successfully reopened - * -1 if we cannot reopen - * 0 if we do not have to reopen - */ -int LYReopenInput(void) -{ - int result = 0; - int fd; - - if ((fd = fileno(stdin)) == 0 - && !isatty(fd) - && LYConsoleInputFD(FALSE) == fd) { - const char *term_name = NULL; - int new_fd = -1; - -#ifdef HAVE_TTYNAME - if (isatty(fileno(stdout)) && - (term_name = ttyname(fileno(stdout))) != NULL) - new_fd = open(term_name, O_RDONLY); - - if (new_fd == -1 && - isatty(fileno(stderr)) && - (term_name = ttyname(fileno(stderr))) != NULL) - new_fd = open(term_name, O_RDONLY); -#endif - -#ifdef HAVE_CTERMID - if (new_fd == -1 && - (term_name = ctermid(NULL)) != NULL) - new_fd = open(term_name, O_RDONLY); -#endif - -#ifdef TTY_DEVICE - if (new_fd == -1) - new_fd = open(term_name = TTY_DEVICE, O_RDONLY); -#endif - - CTRACE((tfp, "LYReopenInput open(%s) returned %d.\n", term_name, new_fd)); - if (new_fd >= 0) { - FILE *frp; - - close(new_fd); - frp = freopen(term_name, "r", stdin); - CTRACE((tfp, - "LYReopenInput freopen(%s,\"r\",stdin) returned %p, stdin is now %p with fd %d.\n", - term_name, (void *) frp, (void *) stdin, fileno(stdin))); - result = 1; - } else { - result = -1; - } - } - return result; -} -#endif - -#if defined(NSL_FORK) || defined(MISC_EXP) || defined (TTY_DEVICE) || defined(HAVE_TTYNAME) -/* - * Returns the file descriptor from which keyboard input is expected, or INVSOC - * (-1) if not available. If need_selectable is true, returns non-INVSOC fd - * only if select() is possible - actually, currently only checks if fd is - * connected to a tty. - kw - */ -int LYConsoleInputFD(int need_selectable) -{ - int fd = INVSOC; - -#ifdef USE_SLANG - if (!LYCursesON) - fd = fileno(stdin); -#if ((SLANG_VERSION >= 9919) && defined(REAL_UNIX_SYSTEM) && !defined(__CYGWIN__)) - /* SLang_TT_Read_FD introduced in slang 0.99.19, from its changelog: - * SLang_TT_Read_FD variable is now available for unix. This is the file - * descriptor used by SLang_getkey. */ - else - fd = SLang_TT_Read_FD; -#endif /* SLANG_VERSION >= 9919 */ -#else /* !USE_SLANG */ - fd = fileno(stdin); -#endif /* !USE_SLANG */ - - if (need_selectable && fd != INVSOC) { - if (isatty(fd)) { - return fd; - } else { - return INVSOC; - } - } - return fd; -} -#endif /* NSL_FORK || MISC_EXP */ - -static int fake_zap = 0; - -void LYFakeZap(int set) -{ - if (set && fake_zap < 1) { - CTRACE((tfp, "\r *** Set simulated 'Z'")); - if (fake_zap) - CTRACE((tfp, ", %d pending", fake_zap)); - CTRACE((tfp, " ***\n")); - fake_zap++; - } else if (!set && fake_zap) { - CTRACE((tfp, "\r *** Unset simulated 'Z'")); - CTRACE((tfp, ", %d pending", fake_zap)); - CTRACE((tfp, " ***\n")); - fake_zap = 0; - } - -} - -static int DontCheck(void) -{ - static long last; - long next; - - /** Curses or slang setup was not invoked **/ - if (dump_output_immediately) - return (TRUE); - - if (LYHaveCmdScript()) /* we may be running from a script */ - return (TRUE); - -#ifdef MISC_EXP - if (LYNoZapKey) - return (TRUE); -#endif - /* - * Avoid checking interrupts more than one per second, since it is a slow - * and expensive operation - TD - */ -#ifdef HAVE_GETTIMEOFDAY -#undef timezone /* U/Win defines a conflicting macro */ - { - struct timeval tv; - - gettimeofday(&tv, (struct timezone *) 0); - next = tv.tv_usec / 100000L; /* 0.1 seconds is a compromise */ - } -#else - next = time((time_t *) 0); -#endif - if (next == last) - return (TRUE); - - last = next; - return FALSE; -} - -int HTCheckForInterrupt(void) -{ - int c; - int cmd; - - if (fake_zap > 0) { - fake_zap--; - CTRACE((tfp, "\r *** Got simulated 'Z' ***\n")); - CTRACE_FLUSH(tfp); - CTRACE_SLEEP(AlertSecs); - return ((int) TRUE); - } - - /** Curses or slang setup was not invoked **/ - if (DontCheck()) - return ((int) FALSE); - -#ifndef VMS /* UNIX stuff: */ - -#if !defined(_WINDOWS) || defined(__MINGW32__) - - /* - * First, check if there is a character. - */ -#ifdef USE_SLANG - /** No keystroke was entered - Note that this isn't taking possible SOCKSification - and the socks_flag into account, and may fail on the - slang library's select() when SOCKSified. - FM **/ -#ifdef DJGPP_KEYHANDLER - if (0 == _bios_keybrd(_NKEYBRD_READY)) - return (FALSE); -#else - if (0 == SLang_input_pending(0)) - return (FALSE); -#endif /* DJGPP_KEYHANDLER */ - -#else /* Unix curses: */ - { - struct timeval socket_timeout; - int ret = 0; - fd_set readfds; - - socket_timeout.tv_sec = 0; - socket_timeout.tv_usec = 0; - FD_ZERO(&readfds); - FD_SET(0, &readfds); -#ifdef SOCKS - if (socks_flag) - ret = Rselect(1, &readfds, NULL, NULL, &socket_timeout); - else -#endif /* SOCKS */ - ret = select(1, &readfds, NULL, NULL, &socket_timeout); - - /** Suspended? **/ - if ((ret == -1) && (SOCKET_ERRNO == EINTR)) - return ((int) FALSE); - - /** No keystroke was entered? **/ - if (!FD_ISSET(0, &readfds)) - return ((int) FALSE); - } -#endif /* USE_SLANG */ - -#endif /* !_WINDOWS */ - - /* - * Now, read the character. - */ -#if defined(USE_CURSES_NODELAY) - nodelay(LYwin, TRUE); - c = LYgetch(); - nodelay(LYwin, FALSE); -#elif defined(USE_SLANG) && defined(_WINDOWS) - if (!SLang_input_pending(0)) - return ((int) FALSE); - c = LYgetch(); -#else - c = LYgetch(); -#endif - -#else /* VMS: */ - extern int typeahead(void); - - /** Control-C or Control-Y and a 'N'o reply to exit query **/ - if (HadVMSInterrupt) { - HadVMSInterrupt = FALSE; - return ((int) TRUE); - } - - c = typeahead(); - -#endif /* !VMS */ - - /* - * 'c' contains whatever character we're able to read from keyboard - */ - - /** Keyboard 'Z' or 'z', or Control-G or Control-C **/ - if (LYCharIsINTERRUPT(c)) - return ((int) TRUE); - - /* There is a subset of mainloop() actions available at this stage: no new - * getfile() cycle is possible until the previous finished. Currently we - * have scrolling in partial mode, toggling of trace log, and pasting. - * User search now in progress... - */ - cmd = (LKC_TO_LAC(keymap, c)); - switch (cmd) { - case LYK_TRACE_TOGGLE: /* Toggle TRACE mode. */ - handle_LYK_TRACE_TOGGLE(); - break; -#ifdef CAN_CUT_AND_PASTE - case LYK_TO_CLIPBOARD:{ /* ^S */ - const char *s = LYDownLoadAddress(); - - if (!s || !*s || put_clip(s)) - HTInfoMsg(gettext("Copy to clipboard failed.")); - else - HTInfoMsg(gettext("Download document URL put to clipboard.")); - break; - } -#endif /* defined CAN_CUT_AND_PASTE */ - default: -#ifdef DISP_PARTIAL - /* OK, we got several lines from new document and want to scroll... */ - if (display_partial && (NumOfLines_partial > 2)) { - BOOLEAN do_refresh; - int res; - int Newline_partial = LYGetNewline(); - - switch (cmd) { - case LYK_WHEREIS: /* search within the document */ - case LYK_NEXT: /* search for the next occurrence in the document */ - case LYK_PREV: /* search for the previous occurrence in the document */ - handle_LYK_WHEREIS(cmd, &do_refresh); - if (www_search_result != -1) { - Newline_partial = www_search_result; - www_search_result = -1; /* reset */ - } - break; - - case LYK_FASTBACKW_LINK: - if (Newline_partial <= (display_lines) + 1) { - Newline_partial -= display_lines; - } else if ((res = - HTGetLinkOrFieldStart(-1, - &Newline_partial, NULL, - -1, TRUE)) == LINK_LINE_FOUND) { - Newline_partial++; - } else if (res == LINK_DO_ARROWUP) { - Newline_partial -= display_lines; - } - break; - case LYK_FASTFORW_LINK: - if (HText_canScrollDown()) { - /* This is not an exact science... - kw */ - if (HTGetLinkOrFieldStart(HText_LinksInLines(HTMainText, - Newline_partial, - display_lines) - - 1, - &Newline_partial, NULL, - 1, TRUE) == LINK_LINE_FOUND) { - Newline_partial++; - } - } - break; - case LYK_PREV_PAGE: - if (Newline_partial > 1) - Newline_partial -= display_lines; - break; - case LYK_NEXT_PAGE: - if (HText_canScrollDown()) - Newline_partial += display_lines; - break; - case LYK_UP_HALF: - if (Newline_partial > 1) - Newline_partial -= (display_lines / 2); - break; - case LYK_DOWN_HALF: - if (HText_canScrollDown()) - Newline_partial += (display_lines / 2); - break; - case LYK_UP_TWO: - if (Newline_partial > 1) - Newline_partial -= 2; - break; - case LYK_DOWN_TWO: - if (HText_canScrollDown()) - Newline_partial += 2; - break; - case LYK_HOME: - if (Newline_partial > 1) - Newline_partial = 1; - break; - case LYK_END: - if (HText_canScrollDown()) - Newline_partial = HText_getNumOfLines() - display_lines + 1; - /* calculate for "current" bottom value */ - break; - case LYK_REFRESH: - break; - default: - /** Other or no keystrokes **/ - return ((int) FALSE); - } /* end switch */ - if (Newline_partial < 1) - Newline_partial = 1; - if (LYMainLoop_pageDisplay(Newline_partial)) - NumOfLines_partial = HText_getNumOfLines(); - } -#endif /* DISP_PARTIAL */ - break; - } /* end switch */ - /** Other or no keystrokes **/ - return ((int) FALSE); -} - -/* - * Check if the given filename looks like it's an absolute pathname, i.e., - * references a directory. - */ -BOOLEAN LYisAbsPath(const char *path) -{ - BOOLEAN result = FALSE; - - if (non_empty(path)) { -#ifdef VMS - result = TRUE; -#else -#if defined(USE_DOS_DRIVES) - result = (BOOLEAN) (LYIsPathSep(path[0]) - || (LYIsDosDrive(path) - && LYIsPathSep(path[2]))); -#else - result = (BOOLEAN) (LYIsPathSep(path[0])); -#endif /* USE_DOS_DRIVES */ -#endif - } - return result; -} - -/* - * Check if the given filename is the root path, e.g., "/" on Unix. - */ -BOOLEAN LYisRootPath(const char *path) -{ -#if defined(USE_DOS_DRIVES) - if (strlen(path) == 3 - && LYIsDosDrive(path) - && LYIsPathSep(path[2])) - return TRUE; -#endif - return (BOOL) ((strlen(path) == 1) && LYIsPathSep(path[0])); -} - -/* - * A file URL for a remote host is an obsolete ftp URL. - * Return YES only if we're certain it's a local file. - FM - */ -BOOLEAN LYisLocalFile(const char *filename) -{ - char *host = NULL; - char *acc_method = NULL; - char *cp; - - if (!filename) - return NO; - if (!(host = HTParse(filename, "", PARSE_HOST))) - return NO; - if (!*host) { - FREE(host); - return NO; - } - - if ((cp = strchr(host, ':')) != NULL) - *cp = '\0'; - - if ((acc_method = HTParse(filename, "", PARSE_ACCESS))) { - if (0 == strcmp("file", acc_method) && - (0 == strcmp(host, "localhost") || - LYSameFilename(host, HTHostName()))) { - FREE(host); - FREE(acc_method); - return YES; - } - } - - FREE(host); - FREE(acc_method); - return NO; -} - -/* - * Utility for checking URLs with a host field. Return YES only if we're - * certain it's the local host. - FM - */ -BOOLEAN LYisLocalHost(const char *filename) -{ - char *host = NULL; - char *cp; - - if (!filename) - return NO; - if (!(host = HTParse(filename, "", PARSE_HOST))) - return NO; - if (!*host) { - FREE(host); - return NO; - } - - if ((cp = strchr(host, ':')) != NULL) - *cp = '\0'; - - if ((LYSameFilename(host, "localhost") || - LYSameFilename(host, LYHostName) || - LYSameFilename(host, HTHostName()))) { - FREE(host); - return YES; - } - - FREE(host); - return NO; -} - -/* - * Free an HTList that contains strings. - */ -void LYFreeStringList(HTList *list) -{ - if (list != NULL) { - char *argument; - HTList *cur = list; - - while (NULL != (argument = (char *) HTList_nextObject(cur))) { - FREE(argument); - } - HTList_delete(list); - } -} - -/* - * Utility for freeing the list of local host aliases. - FM - */ -void LYLocalhostAliases_free(void) -{ - LYFreeStringList(localhost_aliases); - localhost_aliases = NULL; -} - -/* - * Utility for listing hosts to be treated as local aliases. - FM - */ -void LYAddLocalhostAlias(char *alias) -{ - char *LocalAlias = NULL; - - if (!non_empty(alias)) - return; - - if (!localhost_aliases) { - localhost_aliases = HTList_new(); -#ifdef LY_FIND_LEAKS - atexit(LYLocalhostAliases_free); -#endif - } - - StrAllocCopy(LocalAlias, alias); - HTList_addObject(localhost_aliases, LocalAlias); - - return; -} - -/* - * Utility for checking URLs with a host field. Return YES only if we've - * listed the host as a local alias. - FM - */ -BOOLEAN LYisLocalAlias(const char *filename) -{ - char *host = NULL; - char *alias; - char *cp; - HTList *cur = localhost_aliases; - - if (!cur || !filename) - return NO; - if (!(host = HTParse(filename, "", PARSE_HOST))) - return NO; - if (!(*host)) { - FREE(host); - return NO; - } - - if ((cp = strchr(host, ':')) != NULL) - *cp = '\0'; - - while (NULL != (alias = (char *) HTList_nextObject(cur))) { - if (LYSameFilename(host, alias)) { - FREE(host); - return YES; - } - } - - FREE(host); - return NO; -} - -/* - * This function checks for a URL with an unknown scheme, - * but for which proxying has been set up, and if so, - * returns PROXY_URL_TYPE. - FM - * - * If a colon is present but the string segment which - * precedes it is not being proxied, and we can be sure - * that what follows the colon is not a port field, - * it returns UNKNOWN_URL_TYPE. Otherwise, it returns - * 0 (not a URL). - FM - */ -UrlTypes LYCheckForProxyURL(char *filename) -{ - char *cp = filename; - char *cp1; - char *cp2 = NULL; - - /* - * Don't crash on an empty argument. - */ - if (isEmpty(cp)) - return (NOT_A_URL_TYPE); - - /* kill beginning spaces */ - cp = LYSkipBlanks(cp); - - /* - * Check for a colon, and if present, - * see if we have proxying set up. - */ - if ((cp1 = strchr((cp + 1), ':')) != NULL) { - if ((cp2 = strchr((cp + 1), '/')) != NULL && cp2 < cp1) - return (NOT_A_URL_TYPE); - *cp1 = '\0'; - cp2 = NULL; - StrAllocCopy(cp2, cp); - *cp1 = ':'; - StrAllocCat(cp2, "_proxy"); - if (LYGetEnv(cp2) != NULL) { - FREE(cp2); - return (PROXY_URL_TYPE); - } - FREE(cp2); -#if defined (USE_DOS_DRIVES) - if (LYIsDosDrive(cp)) - return (NOT_A_URL_TYPE); -#endif - cp1++; - if (!*cp) { - return (NOT_A_URL_TYPE); - } else if (isdigit(UCH(*cp1))) { - while (*cp1 && isdigit(UCH(*cp1))) - cp1++; - if (*cp1 && !LYIsHtmlSep(*cp1)) - return (UNKNOWN_URL_TYPE); - } else { - return (UNKNOWN_URL_TYPE); - } - } - - return (NOT_A_URL_TYPE); -} - -/* - * Compare a "type:" string, replacing it by the comparison-string if it - * matches (and return true in that case). - */ -static BOOLEAN compare_type(char *tst, - const char *cmp, - size_t len) -{ - if (!strncasecomp(tst, cmp, (int) len)) { - if (StrNCmp(tst, cmp, len)) { - size_t i; - - for (i = 0; i < len; i++) - tst[i] = cmp[i]; - } - return TRUE; - } - return FALSE; -} -#define CompareType(tst,cmp,len) compare_type((tst),(cmp),(size_t)(len)) - -#define DoubleHtmlSep(s) (LYIsHtmlSep((s)[0]) && LYIsHtmlSep((s)[1])) -#define compare_two(tst,cmp,len,limit) \ - ((len + 2) <= limit \ - && DoubleHtmlSep(tst + len) \ - && CompareType(tst, cmp, len)) - -/* - * Must recognize a URL and return the type. - * If recognized, based on a case-insensitive - * analysis of the scheme field, ensures that - * the scheme field has the expected case. - * - * Returns 0 (not a URL) for a NULL argument, - * one which lacks a colon. - * - * Chains to LYCheckForProxyURL() if a colon - * is present but the type is not recognized. - */ -UrlTypes is_url(char *filename) -{ - char *cp = filename; - char *cp1; - UrlTypes result = NOT_A_URL_TYPE; - int limit; - - /* - * Don't crash on an empty argument. - */ - if (isEmpty(cp)) - return (result); - - /* - * Can't be a URL if it lacks a colon and if it starts with '[' it's - * probably IPv6 adress. - */ - if (NULL == strchr(cp, ':') || cp[0] == '[') - return (result); - - /* - * Kill beginning spaces. - */ - cp = LYSkipBlanks(cp); - - /* - * Can't be a URL if it starts with a slash. So return immediately for - * this common case, also to avoid false positives if there was a colon - * later in the string. Also can't be a URL if it starts with a colon. - - * KW - */ - if (*cp == ':' || LYIsHtmlSep(*cp)) { - result = NOT_A_URL_TYPE; - - } else { - limit = (int) strlen(cp); - switch (*cp) { - case 'L': - case 'l': - /* - * Lynx internal pages ("LYNXfoo:" or "lynxfoo:") start with 'l' or - * 'L', other URLs aren't. - */ - if (CompareType(cp, STR_LYNXEXEC, LEN_LYNXEXEC)) { - /* - * Special External Lynx type to handle execution of commands - * or scripts which require a pause to read the screen upon - * completion. - */ - result = LYNXEXEC_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXPROG, LEN_LYNXPROG)) { - /* - * Special External Lynx type to handle execution of commands, - * scripts or programs with do not require a pause to read - * screen upon completion. - */ - result = LYNXPROG_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXCGI, LEN_LYNXCGI)) { - /* - * Special External Lynx type to handle cgi scripts. - */ - result = LYNXCGI_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXPRINT, LEN_LYNXPRINT)) { - /* - * Special Internal Lynx type. - */ - result = LYNXPRINT_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXOPTIONS, LEN_LYNXOPTIONS)) { - /* - * Special Internal Lynx type. - */ - result = LYNXOPTIONS_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXCFG, LEN_LYNXCFG)) { - /* - * Special Internal Lynx type. - */ - result = LYNXCFG_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXMESSAGES, LEN_LYNXMESSAGES)) { - /* - * Special Internal Lynx type. - */ - result = LYNXMESSAGES_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXCFLAGS, LEN_LYNXCFLAGS)) { - /* - * Special Internal Lynx type. - */ - result = LYNXCOMPILE_OPTS_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXDOWNLOAD, LEN_LYNXDOWNLOAD)) { - /* - * Special Internal Lynx type. - */ - result = LYNXDOWNLOAD_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXDIRED, LEN_LYNXDIRED)) { - /* - * Special Internal Lynx type. - */ - result = LYNXDIRED_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXHIST, LEN_LYNXHIST)) { - /* - * Special Internal Lynx type. - */ - result = LYNXHIST_URL_TYPE; - -#ifdef USE_CACHEJAR - } else if (CompareType(cp, STR_LYNXCACHE, LEN_LYNXCACHE)) { - /* - * Special Internal Lynx type. - */ - result = LYNXCACHE_URL_TYPE; -#endif - - } else if (CompareType(cp, STR_LYNXKEYMAP, LEN_LYNXKEYMAP)) { - /* - * Special Internal Lynx type. - */ - result = LYNXKEYMAP_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXIMGMAP, LEN_LYNXIMGMAP)) { - /* - * Special Internal Lynx type. - */ - /* force lower/uppercase of next part */ - (void) is_url(&cp[LEN_LYNXIMGMAP]); - result = LYNXIMGMAP_URL_TYPE; - - } else if (CompareType(cp, STR_LYNXCOOKIE, LEN_LYNXCOOKIE)) { - /* - * Special Internal Lynx type. - */ - result = LYNXCOOKIE_URL_TYPE; - } - break; -#ifndef DISABLE_NEWS - /* - * NEWSfoo: schemes - - */ - case 'N': - case 'n': - if (CompareType(cp, STR_NEWS_URL, LEN_NEWS_URL)) { - result = NEWS_URL_TYPE; - - } else if (CompareType(cp, STR_NNTP_URL, LEN_NNTP_URL)) { - result = NNTP_URL_TYPE; - - } else if (CompareType(cp, "newspost:", 9)) { - /* - * Special Lynx type to handle news posts. - */ - result = NEWSPOST_URL_TYPE; - - } else if (CompareType(cp, "newsreply:", 10)) { - /* - * Special Lynx type to handle news replies (followups). - */ - result = NEWSREPLY_URL_TYPE; - } - break; - - /* - * SNEWSfoo: schemes - - */ - case 'S': - case 's': - if (CompareType(cp, STR_SNEWS_URL, LEN_SNEWS_URL)) { - result = SNEWS_URL_TYPE; - - } else if (CompareType(cp, "snewspost:", 10)) { - /* - * Special Lynx type to handle snews posts. - */ - result = NEWSPOST_URL_TYPE; - - } else if (CompareType(cp, "snewsreply:", 11)) { - /* - * Special Lynx type to handle snews replies (followups). - */ - result = NEWSREPLY_URL_TYPE; - } - break; -#endif - case 'M': - case 'm': - if (CompareType(cp, STR_MAILTO_URL, LEN_MAILTO_URL)) { - result = MAILTO_URL_TYPE; - } - break; - - case 'F': - case 'f': - if (CompareType(cp, STR_FILE_URL, LEN_FILE_URL)) { - if (LYisLocalFile(cp)) { - result = FILE_URL_TYPE; - } else if (DoubleHtmlSep(cp + LEN_FILE_URL)) { - result = FTP_URL_TYPE; - } - } -#ifndef DISABLE_FTP - else if (compare_two(cp, STR_FTP_URL, LEN_FTP_URL, limit)) { - result = FTP_URL_TYPE; - } -#endif -#ifndef DISABLE_FINGER - else if (compare_two(cp, STR_FINGER_URL, LEN_FINGER_URL, limit)) { - result = FINGER_URL_TYPE; - } -#endif - break; - - case 'B': - case 'b': -#ifndef DISABLE_BIBP - if (CompareType(cp, STR_BIBP_URL, LEN_BIBP_URL)) { - result = BIBP_URL_TYPE; - } -#endif - break; - - case 'D': - case 'd': - if (CompareType(cp, "data:", 5)) { - result = DATA_URL_TYPE; - } - break; - - default: - if (limit >= 3 - && ((cp1 = strchr(cp + 3, ':')) == NULL - || !DoubleHtmlSep(cp1 + 1))) { - /* - * If it doesn't contain "://", and it's not one of the the - * above, it can't be a URL with a scheme we know, so check if - * it's an unknown scheme for which proxying has been set up. - * - FM - */ - if (cp1 != NULL - && (cp1 - cp) > 1 /* exclude DOS-style device:/path */ - && LYisAbsPath(cp1 + 1)) { - result = NCFTP_URL_TYPE; - } - - } else { - switch (*cp) { - case 'H': - case 'h': - if (CompareType(cp, STR_HTTP_URL, LEN_HTTP_URL)) { - result = HTTP_URL_TYPE; - - } else if (CompareType(cp, STR_HTTPS_URL, LEN_HTTPS_URL)) { - result = HTTPS_URL_TYPE; - } - break; - -#ifndef DISABLE_GOPHER - case 'G': - case 'g': - if (CompareType(cp, STR_GOPHER_URL, LEN_GOPHER_URL)) { - if (strlen(cp) >= 11 - && (cp1 = strchr(cp + 11, '/')) != NULL) { - - if (TOUPPER(*(cp1 + 1)) == 'H' || *(cp1 + 1) == 'w') - /* if this is a gopher html type */ - result = HTML_GOPHER_URL_TYPE; - else if (*(cp1 + 1) == 'T' || *(cp1 + 1) == '8') - result = TELNET_GOPHER_URL_TYPE; - else if (*(cp1 + 1) == '7') - result = INDEX_GOPHER_URL_TYPE; - else - result = GOPHER_URL_TYPE; - } else { - result = GOPHER_URL_TYPE; - } - } - break; -#endif - case 'W': - case 'w': - if (CompareType(cp, STR_WAIS_URL, LEN_WAIS_URL)) { - result = WAIS_URL_TYPE; - } - break; - - case 'T': - case 't': - if (CompareType(cp, STR_TELNET_URL, LEN_TELNET_URL)) { - result = TELNET_URL_TYPE; - - } else if (CompareType(cp, STR_TN3270_URL, LEN_TN3270_URL)) { - result = TN3270_URL_TYPE; - } - break; - - case 'R': - case 'r': - if (CompareType(cp, STR_RLOGIN_URL, LEN_RLOGIN_URL)) { - result = RLOGIN_URL_TYPE; - } - break; - - case 'C': - case 'c': - if (CompareType(cp, STR_CSO_URL, LEN_CSO_URL)) { - result = CSO_URL_TYPE; - } - break; - - case 'A': - case 'a': - if (CompareType(cp, "afs:", 4)) { - result = AFS_URL_TYPE; - } - break; - - case 'P': - case 'p': - if (CompareType(cp, "prospero:", 9)) { - result = PROSPERO_URL_TYPE; - } - break; - } - } - } - /* - * Check if it is an unknown scheme for which proxying has been set up. - */ - if (result == NOT_A_URL_TYPE) - result = LYCheckForProxyURL(filename); - } - return result; -} - -/* - * Sometimes it is just expected that curses is on when an alert or other - * statusline message needs to be shown and we are not just dumping - * immediately. Calling this will 'fix' it, but may not always be appropriate. - * - kw - */ -void LYFixCursesOn(const char *reason) -{ - if (dump_output_immediately || LYCursesON) - return; - if (reason) { - CTRACE((tfp, "Forcing curses on to %s\n", reason)); - } - start_curses(); -} - -/* - * Most protocol modules called through HTLoad* expect that curses is on unless - * dump_output_immediately is set, so that statusline messages can be shown. - * Some protocols expect the opposite, namely telnet and friends. This - * function should be called after the 'physical' URL for accessing addr has - * been established. It does the right thing to the degree that curses is - * turned on for known problem cases. In any normal circumstances this should - * never apply, but proxying or rule substitution is not prevented for - * telnet-like URLs, and this 'fix' avoids some crashes that can otherwise - * occur. - kw - */ -BOOLEAN LYFixCursesOnForAccess(const char *addr, - const char *physical) -{ - /* - * If curses is off when maybe it shouldn't... - */ - if (!dump_output_immediately && !LYCursesON && physical) { - char *cp1; - - /* - * If requested resource wants to be accessed with curses off, and - * getfile() would indeed have turned curses off for it... - */ - if (strstr(addr, "://") != NULL && - (isTELNET_URL(addr) || - isRLOGIN_URL(addr) || - isTN3270_URL(addr) || - (!isGOPHER_URL(addr) && - (cp1 = strchr(addr + 11, '/')) != NULL && - (*(cp1 + 1) == 'T' || *(cp1 + 1) == '8')))) { - /* - * If actual access that will be done is ok with curses off, then - * do nothing special, else force curses on. - kw - */ - if (!isTELNET_URL(physical) && - !isRLOGIN_URL(physical) && - !isTN3270_URL(physical)) { - start_curses(); - HTAlert(gettext("Unexpected access protocol for this URL scheme.")); - return TRUE; - } - } - } - return FALSE; -} - -/* - * Determine whether we allow HEAD and related flags for a URL. - kw - */ -BOOLEAN LYCanDoHEAD(const char *address) -{ - char *temp0 = NULL; - int isurl; - - if (!non_empty(address)) - return FALSE; - if (!StrNCmp(address, "http", 4)) - return TRUE; - /* Make copy for is_url() since caller may not care for case changes */ - StrAllocCopy(temp0, address); - isurl = is_url(temp0); - if (!isurl) { - FREE(temp0); - return FALSE; - } - if (isurl == LYNXCGI_URL_TYPE) { - FREE(temp0); -#if defined(LYNXCGI_LINKS) && !defined(VMS) - return TRUE; -#else - return FALSE; -#endif - } - /* - * The idea of the following is to allow HEAD for news URLs that identify - * single articles, not those that identify ranges of articles or groups or - * a list of groups. - kw - */ - if (isurl == NEWS_URL_TYPE || isurl == NNTP_URL_TYPE) { - char *temp = HTParse(address, "", PARSE_PATH); - char *cp = strrchr(temp, '/'); - - if (strchr((cp ? cp : temp), '@') != NULL) { - FREE(temp0); - FREE(temp); - return TRUE; - } - if (cp && isdigit(UCH(cp[1])) && strchr(cp, '-') == NULL) { - FREE(temp0); - FREE(temp); - return TRUE; - } - FREE(temp); - } -#define ALLOW_PROXY_HEAD -/* If defined, also allow head requests for URLs proxied through the "http" or - * "lynxcgi" protocols, which understand HEAD. Only the proxy environment - * variables are checked, not the HTRules system. - kw - */ -#ifdef ALLOW_PROXY_HEAD - if (isurl != FILE_URL_TYPE) { - char *acc_method = HTParse(temp0, "", PARSE_ACCESS); - - if (non_empty(acc_method)) { - char *proxy; - - StrAllocCat(acc_method, "_proxy"); - proxy = LYGetEnv(acc_method); - if (proxy && (isHTTP_URL(proxy) || - isLYNXCGI(proxy)) && - !override_proxy(temp0)) { - FREE(temp0); - FREE(acc_method); - return TRUE; - } - } - FREE(acc_method); - } -#endif /* ALLOW_PROXY_HEAD */ - - FREE(temp0); - return FALSE; -} - -/* - * Close an input file. - */ -BOOLEAN LYCloseInput(FILE *fp) -{ - int result = FALSE; - - if (fp != 0) { - int err = ferror(fp); - LY_TEMP *p = FindTempfileByFP(fp); - - fclose(fp); - if (p != 0) { - p->file = 0; - } - if (!err) { - result = TRUE; - } - } - return (BOOLEAN) result; -} - -/* - * Close an output file, reporting any problems with writing to it. - */ -BOOLEAN LYCloseOutput(FILE *fp) -{ - int result = FALSE; - - if (fp != 0) { - int err = ferror(fp); - LY_TEMP *p = FindTempfileByFP(fp); - - fclose(fp); - if (p != 0) { - p->file = 0; - } - if (!err) { - result = TRUE; - } - } - if (!result) { - HTAlert(CANNOT_WRITE_TO_FILE); - } - return (BOOLEAN) result; -} - -/* - * Test if we'll be able to write a file. If not, warn the user. - */ -BOOLEAN LYCanWriteFile(const char *filename) -{ - if (LYCloseOutput(fopen(filename, "w"))) { - remove(filename); - return TRUE; - } else { - _statusline(NEW_FILENAME_PROMPT); - return FALSE; - } -} - -/* - * Test if we'll be able to read a file. - */ -BOOLEAN LYCanReadFile(const char *filename) -{ - FILE *fp; - - if (non_empty(filename)) { - if ((fp = fopen(filename, "r")) != 0) { - return LYCloseInput(fp); - } - } - return FALSE; -} - -/* - * Remove backslashes from any string. - */ -void remove_backslashes(char *buf) -{ - char *cp; - - for (cp = buf; *cp != '\0'; cp++) { - - if (*cp != '\\') { /* don't print slashes */ - *buf = *cp; - buf++; - } else if (*cp == '\\' && /* print one slash if there */ - *(cp + 1) == '\\') { /* are two in a row */ - *buf = *cp; - buf++; - } - } - *buf = '\0'; - return; -} - -/* - * Checks to see if the current process is attached via a terminal in the local - * domain. - */ -BOOLEAN inlocaldomain(void) -{ - BOOLEAN result = TRUE; - -#ifdef HAVE_UTMP - int n; - FILE *fp; - struct utmp me; - char *cp, *mytty = NULL; - - if ((cp = ttyname(0))) - mytty = LYLastPathSep(cp); - - result = FALSE; - if (mytty && (fp = fopen(UTMP_FILE, "r")) != NULL) { - mytty++; - do { - n = (int) fread((char *) &me, sizeof(struct utmp), (size_t) 1, fp); - } while (n > 0 && !STREQ(me.ut_line, mytty)); - (void) LYCloseInput(fp); - - if (n > 0) { - if (strlen(me.ut_host) > strlen(LYLocalDomain) && - STREQ(LYLocalDomain, - me.ut_host + strlen(me.ut_host) - strlen(LYLocalDomain))) { - result = TRUE; - } -#ifdef LINUX - /* Linux fix to check for local user. J.Cullen 11Jul94 */ - else if (strlen(me.ut_host) == 0) { - result = TRUE; - } -#endif /* LINUX */ - } - - } else { - CTRACE((tfp, - "Could not get ttyname (returned %s) or open UTMP file %s\n", - NONNULL(cp), UTMP_FILE)); - } -#else - CTRACE((tfp, "LYUtils: inlocaldomain() not supported.\n")); -#endif /* HAVE_UTMP */ - return (result); -} - -#ifdef HAVE_SIGACTION -/* - * An extended alternative for calling signal(), sets some flags for signal - * handler as we want them if that functionality is available. (We don't - * return anything from this function since the return value would currently be - * ignored anyway.) - kw - */ -void LYExtSignal(int sig, - LYSigHandlerFunc_t *handler) -{ -#ifdef SIGWINCH - /* add more cases to if(condition) if required... */ - if (sig == SIGWINCH && LYNonRestartingSIGWINCH) { - struct sigaction act; - - act.sa_handler = handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_RESTART - if (sig != SIGWINCH) - act.sa_flags |= SA_RESTART; -#endif /* SA_RESTART */ - sigaction(sig, &act, NULL); - } else -#endif /* defined(SIGWINCH) */ - signal(sig, handler); -} -#endif /* HAVE_SIGACTION */ - -#if defined(SIGTSTP) && !defined(USE_SLANG) -#ifdef HAVE_SIGACTION -/* - * For switching a signal's handling between SIG_DFL and something (possibly) - * different that may have been set up by lynx code or e.g. by curses library. - * Uses sigaction to preserve / restore as much state as possible. - * - * Second arg is where to save or restore from. - * - * Third arg to_dfl specifies what to do: - * 1 Save current state in where, set handling to SIG_DFL - * 0 Restore current state to previously saved one in where - * - * Currently only used for SIGTSTP without SLANG, to prevent (n)curses signal - * handler from running while lynx is waiting in system() for an interactive - * command like an editor. - kw - */ -static BOOLEAN LYToggleSigDfl(int sig, - struct sigaction *where, - int to_dfl) -{ - int rv = -1; - struct sigaction oact; - - if (to_dfl == 1) { - rv = sigaction(sig, NULL, &oact); - if (rv == 0) { - if (oact.sa_handler != SIG_DFL) { - oact.sa_handler = SIG_DFL; - rv = sigaction(sig, &oact, where); - } else if (where) { - memcpy(where, &oact, sizeof(oact)); - rv = 0; - } - } - } else { - rv = sigaction(sig, where, NULL); - } - if (rv != 0) { - CTRACE((tfp, "Error in LYToggleSigDfl: %s\n", LYStrerror(errno))); - return FALSE; - } else - return TRUE; -} -#endif /* HAVE_SIGACTION */ -#endif /* SIGTSTP && !USE_SLANG */ - -/************** - * This bit of code catches window size change signals - */ - -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -/* For systems that have both, but both can't be included, duh (or neither) */ -/* FIXME: this whole chunk may be redundant */ -#ifdef TERMIO_AND_CURSES -# ifdef TERMIO_AND_TERMIOS -# include <termio.h> -# else -# ifdef HAVE_TERMIOS_H -# include <termios.h> -# else -# ifdef HAVE_TERMIO_H -# include <termio.h> -# endif /* HAVE_TERMIO_H */ -# endif /* HAVE_TERMIOS_H */ -# endif /* TERMIO_AND_TERMIOS */ -#endif /* TERMIO_AND_CURSES */ - -void size_change(int sig GCC_UNUSED) -{ - int old_lines = LYlines; - int old_cols = LYcols; - -#ifdef USE_SLANG -#if defined(VMS) || defined(UNIX) - SLtt_get_screen_size(); -#endif /* VMS || UNIX */ - LYlines = SLtt_Screen_Rows; - LYcols = SLtt_Screen_Cols; -#ifdef SLANG_MBCS_HACK - PHYSICAL_SLtt_Screen_Cols = LYcols; -#ifdef SLANG_NO_LIMIT /* define this if slang has been fixed */ - SLtt_Screen_Cols = LYcolLimit * 6; -#else - /* Needs to be limited: fixed buffer bugs in slang can cause crash, - see slang's SLtt_smart_puts - kw */ - SLtt_Screen_Cols = HTMIN(LYcolLimit * 6, 255); -#endif -#endif /* SLANG_MBCS_HACK */ - if (sig == 0) - /* - * Called from start_curses(). - */ - return; -#else /* Curses: */ -#ifdef HAVE_SIZECHANGE -#ifdef TIOCGSIZE - struct ttysize win; - -#else -#ifdef TIOCGWINSZ - struct winsize win; -#endif /* TIOCGWINSZ */ -#endif /* TIOCGSIZE */ - -#ifdef TIOCGSIZE - if (ioctl(0, TIOCGSIZE, &win) == 0) { - if (win.ts_lines != 0) { - LYlines = win.ts_lines; - } - if (win.ts_cols != 0) { - LYcols = win.ts_cols; - } - } -#else -#ifdef TIOCGWINSZ - if (ioctl(0, (long) TIOCGWINSZ, &win) == 0) { - if (win.ws_row != 0) { - LYlines = win.ws_row; - } - if (win.ws_col != 0) { - LYcols = win.ws_col; - } - } -#endif /* TIOCGWINSZ */ -#endif /* TIOCGSIZE */ -#endif /* HAVE_SIZECHANGE */ - -#ifdef __EMX__ - { - int scrsize[2]; - - _scrsize(scrsize); - LYcols = scrsize[0]; - LYlines = scrsize[1]; - } -#endif - - if (LYlines <= 0) - LYlines = DFT_ROWS; - if (LYcols <= 0) - LYcols = DFT_COLS; -#endif /* USE_SLANG */ - - /* - * Check if the screen size has actually changed. - AJL - */ - if (LYlines != old_lines || LYcols != old_cols) { - recent_sizechange = TRUE; - CTRACE((tfp, "Window size changed from (%d,%d) to (%d,%d)\n", - old_lines, old_cols, LYlines, LYcols)); -#if defined(CAN_SWITCH_DISPLAY_CHARSET) && defined(CAN_AUTODETECT_DISPLAY_CHARSET) - /* May need to reload the font due to different char-box size */ - if (current_char_set != auto_display_charset) - Switch_Display_Charset(current_char_set, SWITCH_DISPLAY_CHARSET_RESIZE); -#endif - } -#ifdef SIGWINCH - LYExtSignal(SIGWINCH, size_change); -#endif /* SIGWINCH */ - - return; -} - -/* - * Utility for freeing the list of previous suggested filenames. - FM - */ -void HTSugFilenames_free(void) -{ - LYFreeStringList(sug_filenames); - sug_filenames = NULL; -} - -/* - * Utility for listing suggested filenames, making any repeated filenames the - * most current in the list. - FM - */ -void HTAddSugFilename(char *fname) -{ - char *tmp = NULL; - char *old; - HTList *cur; - - if (!non_empty(fname)) - return; - - StrAllocCopy(tmp, fname); - - if (!sug_filenames) { - sug_filenames = HTList_new(); -#ifdef LY_FIND_LEAKS - atexit(HTSugFilenames_free); -#endif - HTList_addObject(sug_filenames, tmp); - return; - } - - cur = sug_filenames; - while (NULL != (old = (char *) HTList_nextObject(cur))) { - if (!strcmp(old, tmp)) { - HTList_removeObject(sug_filenames, old); - FREE(old); - break; - } - } - HTList_addObject(sug_filenames, tmp); - - return; -} - -/* - * CHANGE_SUG_FILENAME -- Foteos Macrides 29-Dec-1993 Upgraded for use with - * Lynx2.2 - FM 17-Jan-1994 - */ -void change_sug_filename(char *fname) -{ - const char *cp2; - char *temp = 0, *cp, *cp1, *end; - -#ifdef VMS - char *dot; - int j, k; -#endif /* VMS */ - - /* - * Establish the current end of fname. - */ - end = fname + strlen(fname); - - /* - * Unescape fname. - */ - HTUnEscape(fname); - - /* - * Rename any temporary files. - */ - cp2 = wwwName(lynx_temp_space); - if (LYIsHtmlSep(*cp2)) { - HTSprintf0(&temp, "file://localhost%s" PID_FMT, cp2, GETPID()); - } else { - HTSprintf0(&temp, "file://localhost/%s" PID_FMT, cp2, GETPID()); - } - if (!StrNCmp(fname, temp, strlen(temp))) { - cp = strrchr(fname, '.'); - if (strlen(cp) > (strlen(temp) - 4)) - cp = NULL; - StrAllocCopy(temp, NonNull(cp)); - sprintf(fname, "temp%.*s", LY_MAXPATH - 10, temp); - } - FREE(temp); - - if (fname[strlen(fname) - 1] == '/') - /* - * Hmm... we have a directory name. It is annoying to see a - * scheme+host+path name as a suggested one, let's remove the - * last_slash and go ahead like we have a file name. - LP - */ - fname[strlen(fname) - 1] = '\0'; - - /* - * Remove everything up the the last_slash if there is one. - */ - if ((cp = strrchr(fname, '/')) != NULL && strlen(cp) > 1) { - cp1 = fname; - /* - * Go past the slash. - */ - cp++; - for (; *cp != '\0'; cp++, cp1++) { - *cp1 = *cp; - } - *cp1 = '\0'; - } -#ifdef _WINDOWS /* 1998/05/05 (Tue) 10:08:05 */ - if ((cp = strrchr(fname, '=')) != NULL && strlen(cp) > 1) { - cp1 = fname; - /* - * Go past the '='. - */ - cp++; - for (; *cp != '\0'; cp++, cp1++) { - *cp1 = *cp; - } - *cp1 = '\0'; - } -#endif - - /* - * Trim off date-size suffix, if present. - */ - if ((*(end - 1) == ']') && ((cp = strrchr(fname, '[')) != NULL) && - (cp > fname) && *(--cp) == ' ') { - while (*cp == ' ') { - *(cp--) = '\0'; - } - } -#ifdef VMS - /* - * Trim off VMS device and/or directory specs, if present. - */ - if ((cp = strchr(fname, '[')) != NULL && - (cp1 = strrchr(cp, ']')) != NULL && strlen(cp1) > 1) { - cp1++; - for (cp = fname; *cp1 != '\0'; cp1++) { - *(cp++) = *cp1; - } - *cp = '\0'; - } - /* - * Replace illegal or problem characters. - */ - dot = fname + strlen(fname); - for (cp = fname; cp < dot; cp++) { - /* - * Replace with underscores. - */ - if (*cp == ' ' || *cp == '/' || *cp == ':' || - *cp == '[' || *cp == ']' || *cp == '&') { - *cp = '_'; - /* - * Replace with dashes. - */ - } else if (*cp == '!' || *cp == '?' || *cp == '\'' || - *cp == ',' || *cp == ':' || *cp == '"' || - *cp == '+' || *cp == '@' || *cp == '\\' || - *cp == '(' || *cp == ')' || *cp == '=' || - *cp == '<' || *cp == '>' || *cp == '#' || - *cp == '%' || *cp == '*' || *cp == '`' || - *cp == '~' || *cp == '^' || *cp == '|' || - *cp < ' ' || (UCH(*cp)) > 126) { - *cp = '-'; - } - } - - /* - * Collapse any serial underscores. - */ - cp = fname + 1; - j = 0; - while (cp < dot) { - if (fname[j] == '_' && *cp == '_') { - cp++; - } else { - fname[++j] = *cp++; - } - } - fname[++j] = '\0'; - - /* - * Collapse any serial dashes. - */ - dot = fname + (strlen(fname)); - cp = fname + 1; - j = 0; - while (cp < dot) { - if (fname[j] == '-' && *cp == '-') { - cp++; - } else { - fname[++j] = *cp++; - } - } - fname[++j] = '\0'; - - /* - * Trim any trailing or leading underscores or dashes. - */ - cp = fname + (strlen(fname)) - 1; - while (*cp == '_' || *cp == '-') { - *cp-- = '\0'; - } - if (fname[0] == '_' || fname[0] == '-') { - dot = fname + (strlen(fname)); - cp = fname; - while ((*cp == '_' || *cp == '-') && cp < dot) { - cp++; - } - j = 0; - while (cp < dot) { - fname[j++] = *cp++; - } - fname[j] = '\0'; - } - - /* - * Replace all but the last period with _'s, or second to last if last is - * followed by a terminal Z or z, or GZ or gz, - * e.g., convert foo.tar.Z to foo.tar_Z - * or, convert foo.tar.gz to foo.tar-gz - */ - j = strlen(fname) - 1; - if ((dot = strrchr(fname, '.')) != NULL) { - if (TOUPPER(fname[j]) == 'Z') { - if ((fname[j - 1] == '.') && - (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { - *dot = '_'; - dot = strrchr(fname, '.'); - } else if (((TOUPPER(fname[j - 1]) == 'G') && - fname[j - 2] == '.') && - (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { - *dot = '-'; - dot = strrchr(fname, '.'); - } - } - cp = fname; - while ((cp = strchr(cp, '.')) != NULL && cp < dot) { - *cp = '_'; - } - - /* - * But if the root is > 39 characters, move the period appropriately to - * the left. - */ - while (dot - fname > 39) { - *dot = '\0'; - if ((cp = strrchr(fname, '_')) != NULL) { - *cp = '.'; - *dot = '_'; - } else if ((cp = strrchr(fname, '-')) != NULL) { - *cp = '.'; - *dot = '_'; - } else if (*(dot + 1) == '\0') { - j = strlen(fname); - while (j > 39) { - fname[j] = fname[j - 1]; - j--; - } - fname[j] = '.'; - } else { - *dot = '.'; - j = 39; - k = 0; - while (dot[k] != '\0') { - fname[j++] = dot[k++]; - } - fname[j] = '\0'; - } - dot = strrchr(fname, '.'); - } - - /* - * Make sure the extension is < 40 characters. - */ - if ((fname + strlen(fname) - dot) > 39) { - *(dot + 40) = '\0'; - } - - /* - * Trim trailing dashes or underscores. - */ - j = (strlen(fname) - 1); - while (fname[j] == '_' || fname[j] == '-') { - fname[j--] = '\0'; - } - } else { - /* - * No period, so put one on the end, or after the 39th character, - * trimming trailing dashes or underscores. - */ - if (strlen(fname) > 39) { - fname[39] = '\0'; - } - j = (strlen(fname) - 1); - while ((fname[j] == '_') || (fname[j] == '-')) { - j--; - } - fname[++j] = '.'; - fname[++j] = '\0'; - } - -#else /* Not VMS (UNIX): */ - - /* - * Replace problem characters. - */ - for (cp = fname; *cp != '\0'; cp++) { - switch (*cp) { - case '\'': - case '"': - case '/': - case ' ': - *cp = '-'; - } - } -#endif /* VMS (UNIX) */ - - /* - * Make sure the rest of the original string in nulled. - */ - cp = fname + strlen(fname); - while (cp < end) { - *cp++ = '\0'; - } - - return; -} - -/* - * Construct a temporary-filename. Assumes result is LY_MAXPATH chars long. - */ -static int fmt_tempname(char *result, - const char *prefix, - const char *suffix) -{ - int code; - -#ifdef HAVE_RAND_TEMPNAME -#define SIZE_TEMPNAME ((MAX_TEMPNAME / BITS_PER_CHAR) + 1) - static BOOL first = TRUE; - static int names_used = 0; - static unsigned char used_tempname[SIZE_TEMPNAME]; - unsigned offset, mask; -#endif - static unsigned counter; - char leaf[LY_MAXPATH]; - - if (prefix == 0) - prefix = ""; - if (suffix == 0) - suffix = ""; - /* - * Prefer a random value rather than a counter. - */ -#ifdef HAVE_RAND_TEMPNAME - if (first) { - lynx_srand((unsigned) ((long) time((time_t *) 0) + (long) result)); - first = FALSE; - } - - /* We don't really need all of the bits from rand(). The high-order bits - * are the more-random portion in any case, but limiting the width of the - * generated name is done partly to avoid problems on systems that may not - * support long filenames. - */ - counter = MAX_TEMPNAME; - if (names_used < MAX_TEMPNAME) { - long get_rand = lynx_rand(); - long max_rand = LYNX_RAND_MAX; - - counter = (unsigned) (((float) MAX_TEMPNAME * (float) get_rand) / - (float) max_rand + 1); - /* - * Avoid reusing a temporary name, since there are places in the code - * which can refer to a temporary filename even after it has been - * closed and removed from the filesystem. - */ - do { - counter %= MAX_TEMPNAME; - offset = counter / BITS_PER_CHAR; - mask = (unsigned) (1 << (counter % BITS_PER_CHAR)); - if ((used_tempname[offset] & mask) == 0) { - names_used++; - used_tempname[offset] |= UCH(mask); - break; - } - } while ((used_tempname[offset] & mask) == 0); - } - if (names_used >= MAX_TEMPNAME) - HTAlert(gettext("Too many tempfiles")); -#else - counter++; -#endif - -#ifdef FNAMES_8_3 - /* - * The 'lynx_temp_space' string ends with a '/' or '\\', so we only have to - * limit the length of the leaf. As received (e.g., from HTCompressed), - * the suffix may contain more than a ".htm", e.g., "-txt.gz", so we trim - * off from the filename portion to make room. - */ - sprintf(leaf, PID_FMT PID_FMT, counter, GETPID()); - if (strlen(leaf) > 8) - leaf[8] = 0; - if (strlen(suffix) > 4 || *suffix != '.') { - const char *tail = strchr(suffix, '.'); - - if (tail == 0) - tail = suffix + strlen(suffix); - if (8 - (tail - suffix) >= 0) - leaf[8 - (tail - suffix)] = 0; - } - strcat(leaf, suffix); -#else - sprintf(leaf, "L" PID_FMT "-%uTMP%s", GETPID(), counter, suffix); -#endif - /* - * Someone could have configured the temporary pathname to be too long. - */ - if ((strlen(prefix) + strlen(leaf)) < LY_MAXPATH) { - sprintf(result, "%s%s", prefix, leaf); - code = TRUE; - } else { - sprintf(result, "%.*s", LY_MAXPATH - 1, leaf); - code = FALSE; - } - CTRACE((tfp, "-> '%s'\n", result)); - return (code); -} - -/* - * Convert 4, 6, 2, 8 to left, right, down, up, etc. - */ -int number2arrows(int number) -{ - switch (number) { - case '1': - number = END_KEY; - break; - case '2': - number = DNARROW; - break; - case '3': - number = PGDOWN; - break; - case '4': - number = LTARROW; - break; - case '5': - number = DO_NOTHING; - break; - case '6': - number = RTARROW; - break; - case '7': - number = HOME; - break; - case '8': - number = UPARROW; - break; - case '9': - number = PGUP; - break; - } - - return (number); -} - -/* - * parse_restrictions takes a string of comma-separated restrictions and sets - * the corresponding flags to restrict the facilities available. - */ -/* The first two are special: we want to record whether "default" or "all" - * restrictions were applied, in addition to the detailed effects of those - * options. - kw - */ -/* skip the special flags when processing "all" and "default": */ -#define N_SPECIAL_RESTRICT_OPTIONS 2 -/* *INDENT-OFF* */ -static const struct { - const char *name; - BOOLEAN *flag; - BOOLEAN can; -} restrictions[] = { - { "default", &had_restrictions_default, TRUE }, - { "all", &had_restrictions_all, TRUE }, - { "inside_telnet", &no_inside_telnet, CAN_ANONYMOUS_INSIDE_DOMAIN_TELNET }, - { "outside_telnet", &no_outside_telnet, CAN_ANONYMOUS_OUTSIDE_DOMAIN_TELNET }, - { "telnet_port", &no_telnet_port, CAN_ANONYMOUS_GOTO_TELNET_PORT }, - { "inside_ftp", &no_inside_ftp, CAN_ANONYMOUS_INSIDE_DOMAIN_FTP }, - { "outside_ftp", &no_outside_ftp, CAN_ANONYMOUS_OUTSIDE_DOMAIN_FTP }, - { "inside_rlogin", &no_inside_rlogin, CAN_ANONYMOUS_INSIDE_DOMAIN_RLOGIN }, - { "outside_rlogin", &no_outside_rlogin, CAN_ANONYMOUS_OUTSIDE_DOMAIN_RLOGIN }, - { "suspend", &no_suspend, FALSE }, - { "editor", &no_editor, FALSE }, - { "shell", &no_shell, FALSE }, - { "bookmark", &no_bookmark, FALSE }, - { "multibook", &no_multibook, FALSE }, - { "bookmark_exec", &no_bookmark_exec, FALSE }, - { "option_save", &no_option_save, FALSE }, - { "print", &no_print, CAN_ANONYMOUS_PRINT }, - { "download", &no_download, FALSE }, - { "disk_save", &no_disk_save, FALSE }, -#if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) - { "exec", &no_exec, LOCAL_EXECUTION_LINKS_ALWAYS_OFF_FOR_ANONYMOUS }, -#endif - { "lynxcgi", &no_lynxcgi, FALSE }, - { "exec_frozen", &exec_frozen, FALSE }, - { "goto", &no_goto, CAN_ANONYMOUS_GOTO }, - { "jump", &no_jump, CAN_ANONYMOUS_JUMP }, - { "file_url", &no_file_url, FALSE }, -#ifndef DISABLE_NEWS - { "news_post", &no_newspost, FALSE }, - { "inside_news", &no_inside_news, CAN_ANONYMOUS_INSIDE_DOMAIN_READ_NEWS }, - { "outside_news", &no_outside_news, CAN_ANONYMOUS_OUTSIDE_DOMAIN_READ_NEWS }, -#endif - { "mail", &no_mail, CAN_ANONYMOUS_MAIL }, - { "dotfiles", &no_dotfiles, FALSE }, - { "useragent", &no_useragent, FALSE }, -#ifdef SUPPORT_CHDIR - { "chdir", &no_chdir, FALSE }, -#endif -#ifdef DIRED_SUPPORT - { "dired_support", &no_dired_support, FALSE }, -#ifdef OK_PERMIT - { "change_exec_perms", &no_change_exec_perms, FALSE }, -#endif /* OK_PERMIT */ -#endif /* DIRED_SUPPORT */ -#ifdef USE_EXTERNALS - { "externals", &no_externals, FALSE }, -#endif - { "lynxcfg_info", &no_lynxcfg_info, CAN_ANONYMOUS_VIEW_LYNXCFG_INFO }, -#ifndef NO_CONFIG_INFO - { "lynxcfg_xinfo", &no_lynxcfg_xinfo, CAN_ANONYMOUS_VIEW_LYNXCFG_EXTENDED_INFO }, -#ifdef HAVE_CONFIG_H - { "compileopts_info", &no_compileopts_info, CAN_ANONYMOUS_VIEW_COMPILEOPTS_INFO }, -#endif -#endif - /* put "goto" restrictions on the end, since they are a refinement */ -#ifndef DISABLE_BIBP - { "goto_bibp", &no_goto_bibp, CAN_ANONYMOUS_GOTO_BIBP }, -#endif -#ifdef HAVE_CONFIG_H -#ifndef NO_CONFIG_INFO - { "goto_configinfo", &no_goto_configinfo, CAN_ANONYMOUS_GOTO_CONFIGINFO }, -#endif -#endif - { "goto_cso", &no_goto_cso, CAN_ANONYMOUS_GOTO_CSO }, - { "goto_file", &no_goto_file, CAN_ANONYMOUS_GOTO_FILE }, -#ifndef DISABLE_FINGER - { "goto_finger", &no_goto_finger, CAN_ANONYMOUS_GOTO_FINGER }, -#endif - { "goto_ftp", &no_goto_ftp, CAN_ANONYMOUS_GOTO_FTP }, -#ifndef DISABLE_GOPHER - { "goto_gopher", &no_goto_gopher, CAN_ANONYMOUS_GOTO_GOPHER }, -#endif - { "goto_http", &no_goto_http, CAN_ANONYMOUS_GOTO_HTTP }, - { "goto_https", &no_goto_https, CAN_ANONYMOUS_GOTO_HTTPS }, - { "goto_lynxcgi", &no_goto_lynxcgi, CAN_ANONYMOUS_GOTO_LYNXCGI }, - { "goto_lynxexec", &no_goto_lynxexec, CAN_ANONYMOUS_GOTO_LYNXEXEC }, - { "goto_lynxprog", &no_goto_lynxprog, CAN_ANONYMOUS_GOTO_LYNXPROG }, - { "goto_mailto", &no_goto_mailto, CAN_ANONYMOUS_GOTO_MAILTO }, -#ifndef DISABLE_NEWS - { "goto_news", &no_goto_news, CAN_ANONYMOUS_GOTO_NEWS }, - { "goto_nntp", &no_goto_nntp, CAN_ANONYMOUS_GOTO_NNTP }, -#endif - { "goto_rlogin", &no_goto_rlogin, CAN_ANONYMOUS_GOTO_RLOGIN }, -#ifndef DISABLE_NEWS - { "goto_snews", &no_goto_snews, CAN_ANONYMOUS_GOTO_SNEWS }, -#endif - { "goto_telnet", &no_goto_telnet, CAN_ANONYMOUS_GOTO_TELNET }, - { "goto_tn3270", &no_goto_tn3270, CAN_ANONYMOUS_GOTO_TN3270 }, - { "goto_wais", &no_goto_wais, CAN_ANONYMOUS_GOTO_WAIS }, -}; -/* *INDENT-ON* */ - -/* This will make no difference between '-' and '_'. It does only in/equality - * compare. It assumes that p2 can't contain dashes, but p1 can. This - * function is also used (if macro OPTNAME_ALLOW_DASHES doesn't have value of - * zero) for compare of commandline options -VH - */ -BOOL strn_dash_equ(const char *p1, - const char *p2, - int len) -{ - while (len--) { - if (!*p2) - return 0; /* canonical name is shorter */ - switch (*p1) { - case 0: - return 0; - case '-': - case '_': - if (*p2 != '_') - return 0; - else - break; - default: - if (*p1 != *p2) - return 0; - } - ++p1; - ++p2; - } - return 1; -} - -/* Uncomment following lines to allow only exact string matching */ -/* #define RESTRICT_NM_ALLOW_DASHES 0 */ - -#ifndef RESTRICT_NM_ALLOW_DASHES -# define RESTRICT_NM_ALLOW_DASHES 1 -#endif - -#if RESTRICT_NM_ALLOW_DASHES -# define RESTRICT_NM_EQU(a,b,len) strn_dash_equ(a,b,len) -#else -# define RESTRICT_NM_EQU(a,b,len) STRNEQ(a,b,len) -#endif - -/* - * Returns the inx'th name from the restrictions table, or null if inx is - * out of range. - */ -const char *index_to_restriction(unsigned inx) -{ - if (inx < TABLESIZE(restrictions)) - return restrictions[inx].name; - return NULL; -} - -/* - * Returns the value TRUE/FALSE of a given restriction, or -1 if it is not - * one that we recognize. - */ -int find_restriction(const char *name, - int len) -{ - unsigned i; - - if (len < 0) - len = (int) strlen(name); - for (i = 0; i < TABLESIZE(restrictions); i++) { - if (RESTRICT_NM_EQU(name, restrictions[i].name, len)) { - return (*restrictions[i].flag); - } - } - return -1; -} - -void parse_restrictions(const char *s) -{ - const char *p; - const char *word; - unsigned i; - BOOLEAN found; - - p = s; - while (*p) { - p = LYSkipCBlanks(p); - if (*p == '\0') - break; - word = p; - while (*p != ',' && *p != '\0') - p++; - - found = FALSE; - if (RESTRICT_NM_EQU(word, "all", (int) (p - word))) { - found = TRUE; - for (i = N_SPECIAL_RESTRICT_OPTIONS; - i < TABLESIZE(restrictions); - i++) - *(restrictions[i].flag) = TRUE; - } else if (RESTRICT_NM_EQU(word, "default", (int) (p - word))) { - found = TRUE; - for (i = N_SPECIAL_RESTRICT_OPTIONS; - i < TABLESIZE(restrictions); - i++) - *(restrictions[i].flag) = (BOOLEAN) !restrictions[i].can; - } else { - for (i = 0; i < TABLESIZE(restrictions); i++) { - if (RESTRICT_NM_EQU(word, restrictions[i].name, (int) (p - word))) { - *(restrictions[i].flag) = TRUE; - found = TRUE; - break; - } - } - } - if (!found) { - printf("%s: %.*s\n", gettext("unknown restriction"), - (int) (p - word), word); - exit_immediately(EXIT_FAILURE); - } - if (*p) - p++; - } - - /* - * If shell is restricted, set restrictions on related topics. - */ - if (no_shell) { - no_goto_lynxexec = TRUE; - no_goto_lynxprog = TRUE; - no_goto_lynxcgi = TRUE; -#ifdef EXEC_LINKS - local_exec_on_local_files = TRUE; -#endif - } -} - -void print_restrictions_to_fd(FILE *fp) -{ - unsigned i, count = 0; - - for (i = 0; i < TABLESIZE(restrictions); i++) { - if (*(restrictions[i].flag) == TRUE) { - count++; - } - } - if (!count) { - fprintf(fp, gettext("No restrictions set.\n")); - return; - } - fprintf(fp, gettext("Restrictions set:\n")); - for (i = 0; i < TABLESIZE(restrictions); i++) { - if (*(restrictions[i].flag) == TRUE) { - /* if "goto" is restricted, don't bother tell about its - * refinements - */ - if (StrNCmp(restrictions[i].name, "goto_", 5) - || !no_goto) - fprintf(fp, " %s\n", restrictions[i].name); - } - } -} - -#ifdef VMS -#include <jpidef.h> -#include <maildef.h> -#include <starlet.h> - -typedef struct _VMSMailItemList { - short buffer_length; - short item_code; - void *buffer_address; - long *return_length_address; -} VMSMailItemList; - -void LYCheckMail(void) -{ - static BOOL firsttime = TRUE, failure = FALSE; - static char user[13], dir[252]; - static long userlen = 0, dirlen; - static time_t lastcheck = 0; - time_t now; - static short new, lastcount; - long ucontext = 0, status; - short flags = MAIL$M_NEWMSG; - /* *INDENT-OFF* */ - VMSMailItemList - null_list[] = {{0,0,0,0}}, - jpi_list[] = {{sizeof(user) - 1,JPI$_USERNAME,(void *)user,&userlen}, - {0,0,0,0}}, - uilist[] = {{0,MAIL$_USER_USERNAME,0,0}, - {0,0,0,0}}, - uolist[] = {{sizeof(new),MAIL$_USER_NEW_MESSAGES,&new,0}, - {sizeof(dir),MAIL$_USER_FULL_DIRECTORY,dir,&dirlen}, - {0,0,0,0}}; - /* *INDENT-ON* */ - - extern long mail$user_begin(); - extern long mail$user_get_info(); - extern long mail$user_end(); - - if (failure) - return; - - if (firsttime) { - firsttime = FALSE; - /* Get the username. */ - status = sys$getjpiw(0, 0, 0, jpi_list, 0, 0, 0); - if (!(status & 1)) { - failure = TRUE; - return; - } - user[userlen] = '\0'; - LYTrimTrailing(user); - } - - /* Minimum report interval is 60 sec. */ - time(&now); - if (now - lastcheck < 60) - return; - lastcheck = now; - - /* Get the current newmail count. */ - status = mail$user_begin(&ucontext, null_list, null_list); - if (!(status & 1)) { - failure = TRUE; - return; - } - uilist[0].buffer_length = strlen(user); - uilist[0].buffer_address = user; - status = mail$user_get_info(&ucontext, uilist, uolist); - if (!(status & 1)) { - failure = TRUE; - return; - } - - /* Should we report anything to the user? */ - if (new > 0) { - if (lastcount == 0) - /* Have newmail at startup of Lynx. */ - HTUserMsg(HAVE_UNREAD_MAIL_MSG); - else if (new > lastcount) - /* Have additional mail since last report. */ - HTUserMsg(HAVE_NEW_MAIL_MSG); - lastcount = new; - return; - } - lastcount = new; - - /* Clear the context */ - mail$user_end((long *) &ucontext, null_list, null_list); - return; -} -#else -void LYCheckMail(void) -{ - static BOOL firsttime = TRUE; - static char *mf; - static time_t lastcheck; - static time_t lasttime; - static long lastsize; - time_t now; - struct stat st; - - if (firsttime) { - mf = LYGetEnv("MAIL"); - firsttime = FALSE; - time(&lasttime); - } - - if (mf == NULL) - return; - - time(&now); - if (now - lastcheck < 60) - return; - lastcheck = now; - - if ((stat(mf, &st) < 0) - || !S_ISREG(st.st_mode)) { - mf = NULL; - return; - } - - if (st.st_size > 0) { - if (((lasttime != st.st_mtime) && (st.st_mtime > st.st_atime)) - || ((lastsize != 0) && (st.st_size > lastsize))) - HTUserMsg(HAVE_NEW_MAIL_MSG); - else if (lastsize == 0) - HTUserMsg(HAVE_MAIL_MSG); - } - lastsize = (long) st.st_size; - lasttime = st.st_mtime; - return; -} -#endif /* VMS */ - -/* - * This function ensures that an href will be - * converted to a fully resolved, absolute URL, - * with guessing of the host or expansions of - * lead tildes via LYConvertToURL() if needed, - * and tweaking/simplifying via HTParse(). It - * is used for LynxHome, startfile, homepage, - * and 'g'oto entries, after they have been - * passed to LYFillLocalFileURL(). - FM - * Such URLs have no `base' reference to which they - * could be resolved. LYLegitimizeHREF could not be used. - */ -void LYEnsureAbsoluteURL(char **href, - const char *name, - int fixit) -{ - char *temp = NULL; - - if (isEmpty(*href)) - return; - - /* - * Check whether to fill in localhost. - FM - */ - LYFillLocalFileURL(href, "file://localhost"); - - /* - * If it is not a URL then make it one. - */ - if (!strcasecomp(*href, STR_NEWS_URL)) { - StrAllocCat(*href, "*"); - } else if (!strcasecomp(*href, STR_SNEWS_URL)) { - StrAllocCat(*href, "/*"); - } - - if (!is_url(*href)) { - CTRACE((tfp, "%s%s'%s' is not a URL\n", - NonNull(name), (name ? " " : ""), *href)); - LYConvertToURL(href, fixit); - } - - temp = HTParse(*href, "", PARSE_ALL); - if (non_empty(temp)) - StrAllocCopy(*href, temp); - FREE(temp); -} - -/* - * Rewrite and reallocate a previously allocated string as a file URL if the - * string resolves to a file or directory on the local system, otherwise as an - * http URL. - FM - */ -void LYConvertToURL(char **AllocatedString, - int fixit) -{ - char *old_string = *AllocatedString; - char *temp = NULL; - char *cp = NULL; - -#ifndef VMS - struct stat st; -#endif /* !VMS */ - - if (isEmpty(old_string)) - return; - -#if defined(USE_DOS_DRIVES) - { - char *cp_url = *AllocatedString; - - for (; *cp_url != '\0'; cp_url++) - if (*cp_url == '\\') - *cp_url = '/'; - cp_url--; - if (LYIsDosDrive(*AllocatedString) && *cp_url == ':') - LYAddPathSep(AllocatedString); - } -#endif /* USE_DOS_DRIVES */ - - *AllocatedString = NULL; /* so StrAllocCopy doesn't free it */ - StrAllocCopy(*AllocatedString, "file://localhost"); - - if (*old_string != '/') { - char *fragment = NULL; - -#if defined(USE_DOS_DRIVES) - StrAllocCat(*AllocatedString, "/"); -#endif /* USE_DOS_DRIVES */ -#ifdef VMS - /* - * Not a SHELL pathspec. Get the full VMS spec and convert it. - */ - char *cur_dir = NULL; - static char url_file[LY_MAXPATH], file_name[LY_MAXPATH], dir_name[LY_MAXPATH]; - unsigned long context = 0; - - $DESCRIPTOR(url_file_dsc, url_file); - $DESCRIPTOR(file_name_dsc, file_name); - if (LYIsTilde(*old_string)) { - /* - * On VMS, we'll accept '~' on the command line as Home_Dir(), and - * assume the rest of the path, if any, has SHELL syntax. - */ - StrAllocCat(*AllocatedString, HTVMS_wwwName(Home_Dir())); - if ((cp = strchr(old_string, '/')) != NULL) { - /* - * Append rest of path, if present, skipping "user" if "~user" - * was entered, simplifying, and eliminating any residual - * relative elements. - FM - */ - StrAllocCopy(temp, cp); - LYTrimRelFromAbsPath(temp); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - } - goto have_VMS_URL; - } else { - fragment = trimPoundSelector(old_string); - LYStrNCpy(url_file, old_string, sizeof(url_file) - 1); - } - url_file_dsc.dsc$w_length = (short) strlen(url_file); - if (1 & lib$find_file(&url_file_dsc, &file_name_dsc, &context, - 0, 0, 0, 0)) { - /* - * We found the file. Convert to a URL pathspec. - */ - if ((cp = strchr(file_name, ';')) != NULL) { - *cp = '\0'; - } - LYLowerCase(file_name); - StrAllocCat(*AllocatedString, HTVMS_wwwName(file_name)); - if ((cp = strchr(old_string, ';')) != NULL) { - StrAllocCat(*AllocatedString, cp); - } - if (fragment != NULL) { - restorePoundSelector(fragment); - StrAllocCat(*AllocatedString, fragment); - fragment = NULL; - } - } else if ((NULL != getcwd(dir_name, sizeof(dir_name) - 1, 0)) && - 0 == chdir(old_string)) { - /* - * Probably a directory. Try converting that. - */ - StrAllocCopy(cur_dir, dir_name); - restorePoundSelector(fragment); - if (NULL != getcwd(dir_name, sizeof(dir_name) - 1, 0)) { - /* - * Yup, we got it! - */ - LYLowerCase(dir_name); - StrAllocCat(*AllocatedString, dir_name); - if (fragment != NULL) { - StrAllocCat(*AllocatedString, fragment); - fragment = NULL; - } - } else { - /* - * Nope. Assume it's an http URL with the "http://" defaulted, - * if we can't rule out a bad VMS path. - */ - fragment = NULL; - if (strchr(old_string, '[') || - ((cp = strchr(old_string, ':')) != NULL && - !isdigit(UCH(cp[1]))) || - !LYExpandHostForURL(&old_string, - URLDomainPrefixes, - URLDomainSuffixes)) { - /* - * Probably a bad VMS path (but can't be sure). Use - * original pathspec for the error message that will - * result. - */ - sprintf(url_file, "/%.*s", sizeof(url_file) - 2, old_string); - CTRACE((tfp, - "Can't find '%s' Will assume it's a bad path.\n", - old_string)); - StrAllocCat(*AllocatedString, url_file); - } else { - /* - * Assume a URL is wanted, so guess the scheme with - * "http://" as the default. - FM - */ - if (!LYAddSchemeForURL(&old_string, "http://")) { - StrAllocCopy(*AllocatedString, "http://"); - StrAllocCat(*AllocatedString, old_string); - } else { - StrAllocCopy(*AllocatedString, old_string); - } - } - } - } else { - /* - * Nothing found. Assume it's an http URL with the "http://" - * defaulted, if we can't rule out a bad VMS path. - */ - restorePoundSelector(fragment); - fragment = NULL; - - if (strchr(old_string, '[') || - ((cp = strchr(old_string, ':')) != NULL && - !isdigit(UCH(cp[1]))) || - !LYExpandHostForURL(&old_string, - URLDomainPrefixes, - URLDomainSuffixes)) { - /* - * Probably a bad VMS path (but can't be sure). Use original - * pathspec for the error message that will result. - */ - sprintf(url_file, "/%.*s", sizeof(url_file) - 2, old_string); - CTRACE((tfp, "Can't find '%s' Will assume it's a bad path.\n", - old_string)); - StrAllocCat(*AllocatedString, url_file); - } else { - /* - * Assume a URL is wanted, so guess the scheme with "http://" - * as the default. - FM - */ - if (!LYAddSchemeForURL(&old_string, "http://")) { - StrAllocCopy(*AllocatedString, "http://"); - StrAllocCat(*AllocatedString, old_string); - } else { - StrAllocCopy(*AllocatedString, old_string); - } - } - } - lib$find_file_end(&context); - FREE(cur_dir); - have_VMS_URL: - CTRACE((tfp, "Trying: '%s'\n", *AllocatedString)); -#else /* not VMS: */ -#if defined(USE_DOS_DRIVES) -#ifdef _WINDOWS - if (*old_string == '.') { - char fullpath[MAX_PATH + 1]; - char *filepart = NULL; - DWORD chk; - - chk = GetFullPathNameA(old_string, MAX_PATH + 1, - fullpath, &filepart); - if (chk != 0) { - StrAllocCopy(temp, wwwName(fullpath)); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - } else { - StrAllocCat(*AllocatedString, old_string); - } - } -#else - if (strlen(old_string) == 1 && *old_string == '.') { - /* - * They want . - */ - char curdir[LY_MAXPATH]; - - StrAllocCopy(temp, wwwName(Current_Dir(curdir))); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - } -#endif - else -#endif /* USE_DOS_DRIVES */ - if (LYIsTilde(*old_string)) { - /* - * On Unix, convert '~' to Home_Dir(). - */ - StrAllocCat(*AllocatedString, wwwName(Home_Dir())); - if ((cp = strchr(old_string, '/')) != NULL) { - /* - * Append rest of path, if present, skipping "user" if "~user" - * was entered, simplifying, and eliminating any residual - * relative elements. - FM - */ - StrAllocCopy(temp, cp); - LYTrimRelFromAbsPath(temp); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - } - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - } else { - /* - * Create a full path to the current default directory. - */ - char curdir[LY_MAXPATH]; - char *temp2 = NULL; - BOOL is_local = FALSE; - - Current_Dir(curdir); - /* - * Concatenate and simplify, trimming any residual relative - * elements. - FM - */ -#if defined (USE_DOS_DRIVES) - if (old_string[1] != ':' && old_string[1] != '|') { - StrAllocCopy(temp, wwwName(curdir)); - LYAddHtmlSep(&temp); - LYStrNCpy(curdir, temp, (sizeof(curdir) - 1)); - StrAllocCat(temp, old_string); - } else { - curdir[0] = '\0'; - /* 1998/01/13 (Tue) 12:24:33 */ - if (old_string[1] == '|') - old_string[1] = ':'; - StrAllocCopy(temp, old_string); - - if (strlen(temp) == 2 && LYIsDosDrive(temp)) - LYAddPathSep(&temp); - } -#else - StrAllocCopy(temp, curdir); - StrAllocCat(temp, "/"); - StrAllocCat(temp, old_string); -#endif /* USE_DOS_DRIVES */ - LYTrimRelFromAbsPath(temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", old_string, temp)); - if ((stat(temp, &st) > -1) || - LYCanReadFile(temp)) { - /* - * It is a subdirectory or file on the local system. - */ -#if defined (USE_DOS_DRIVES) - /* Don't want to see DOS local paths like c: escaped */ - /* especially when we really have file://localhost/ */ - /* at the beginning. To avoid any confusion we allow */ - /* escaping the path if URL specials % or # present. */ - if (strchr(temp, '#') == NULL && strchr(temp, '%') == NULL) - StrAllocCopy(cp, temp); - else - cp = HTEscape(temp, URL_PATH); -#else - cp = HTEscape(temp, URL_PATH); -#endif /* USE_DOS_DRIVES */ - StrAllocCat(*AllocatedString, cp); - FREE(cp); - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - is_local = TRUE; - } else { - char *cp2 = NULL; - - StrAllocCopy(temp2, curdir); - LYAddPathSep(&temp2); - StrAllocCopy(cp, old_string); - fragment = trimPoundSelector(cp); - HTUnEscape(cp); /* unescape given path without fragment */ - StrAllocCat(temp2, cp); /* append to current dir */ - StrAllocCopy(cp2, temp2); /* keep a copy in cp2 */ - LYTrimRelFromAbsPath(temp2); -#ifdef WIN_EX /* 1998/07/31 (Fri) 09:09:03 */ - HTUnEscape(temp2); /* for LFN */ -#endif - - if (strcmp(temp2, temp) != 0 && - ((stat(temp2, &st) > -1) || - LYCanReadFile(temp2))) { - /* - * It is a subdirectory or file on the local system with - * escaped characters and/or a fragment to be appended to - * the URL. - FM - */ - - FREE(temp); - if (strcmp(cp2, temp2) == 0) { - /* - * LYTrimRelFromAbsPath did nothing, use old_string as - * given. - kw - */ - temp = HTEscape(curdir, URL_PATH); - LYAddHtmlSep(&temp); - StrAllocCat(temp, old_string); - } else { - temp = HTEscape(temp2, URL_PATH); - if (fragment != NULL) { - restorePoundSelector(fragment); - StrAllocCat(temp, fragment); - } - } - StrAllocCat(*AllocatedString, temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - is_local = TRUE; - - } else if (strchr(curdir, '#') != NULL || - strchr(curdir, '%') != NULL) { - /* - * If PWD has some unusual characters, construct a filename - * in temp where those are escaped. This is mostly to - * prevent this function from returning with some weird URL - * if the LYExpandHostForURL tests further down fail. - kw - */ - FREE(temp); - if (strcmp(cp2, temp2) == 0) { - /* - * LYTrimRelFromAbsPath did nothing, use old_string as - * given. - kw - */ - temp = HTEscape(curdir, URL_PATH); - LYAddHtmlSep(&temp); - StrAllocCat(temp, old_string); - } else { - temp = HTEscape(temp2, URL_PATH); - if (fragment != NULL) { - restorePoundSelector(fragment); - StrAllocCat(temp, fragment); - } - } - } - FREE(cp); - FREE(cp2); - } - if (is_local == FALSE) { - /* - * It's not an accessible subdirectory or file on the local - * system, so assume it's a URL request and guess the scheme - * with "http://" as the default. - */ - CTRACE((tfp, "Can't stat() or fopen() '%s'\n", - temp2 ? temp2 : temp)); -#ifdef WIN_EX /* 1998/01/13 (Tue) 09:07:37 */ - { - const char *p, *q; - char buff[LY_MAXPATH + 128]; - - p = Home_Dir(); - q = temp2 ? temp2 : temp; - - if (strlen(q) == 3 && LYIsDosDrive(q)) { - sprintf(buff, - "'%s' not exist, Goto LynxHome '%s'.", q, p); - _statusline(buff); - LYSleepAlert(); - FREE(temp); - StrAllocCat(*AllocatedString, p); - goto Retry; - } - } -#endif - if (LYExpandHostForURL(&old_string, - URLDomainPrefixes, - URLDomainSuffixes)) { - if (!LYAddSchemeForURL(&old_string, "http://")) { - StrAllocCopy(*AllocatedString, "http://"); - StrAllocCat(*AllocatedString, old_string); - } else { - StrAllocCopy(*AllocatedString, old_string); - } - } else if (fixit) { - /* RW 1998Mar16 Restore AllocatedString to 'old_string' */ - StrAllocCopy(*AllocatedString, old_string); - } else { - /* Return file URL for the file that does not exist */ - StrAllocCat(*AllocatedString, temp); - } -#ifdef WIN_EX - Retry: -#endif - CTRACE((tfp, "Trying: '%s'\n", *AllocatedString)); - } - FREE(temp); - FREE(temp2); - } -#endif /* VMS */ - } else { - /* - * Path begins with a slash. Simplify and use it. - */ - if (old_string[1] == '\0') { - /* - * Request for root. Respect it on Unix, but on VMS we treat that - * as a listing of the login directory. - FM - */ -#ifdef VMS - StrAllocCat(*AllocatedString, HTVMS_wwwName(Home_Dir())); -#else - StrAllocCat(*AllocatedString, "/"); - } else if ((stat(old_string, &st) > -1) || - LYCanReadFile(old_string)) { - /* - * It is an absolute directory or file on the local system. - KW - */ - StrAllocCopy(temp, old_string); - LYTrimRelFromAbsPath(temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", old_string, temp)); - cp = HTEscape(temp, URL_PATH); - StrAllocCat(*AllocatedString, cp); - FREE(cp); - FREE(temp); - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); -#endif /* VMS */ - } else if (LYIsTilde(old_string[1])) { - /* - * Has a Home_Dir() reference. Handle it as if there weren't a - * lead slash. - FM - */ - StrAllocCat(*AllocatedString, wwwName(Home_Dir())); - if ((cp = strchr((old_string + 1), '/')) != NULL) { - /* - * Append rest of path, if present, skipping "user" if "~user" - * was entered, simplifying, and eliminating any residual - * relative elements. - FM - */ - StrAllocCopy(temp, cp); - LYTrimRelFromAbsPath(temp); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - } - } else { - /* - * Normal absolute path. Simplify, trim any residual relative - * elements, and append it. - FM - */ - StrAllocCopy(temp, old_string); - LYTrimRelFromAbsPath(temp); - StrAllocCat(*AllocatedString, temp); - FREE(temp); - } - CTRACE((tfp, "Converted '%s' to '%s'\n", - old_string, *AllocatedString)); - } - FREE(old_string); - /* Pause so we can read the messages before invoking curses */ - CTRACE_SLEEP(AlertSecs); -} - -#if defined(_WINDOWS) /* 1998/06/23 (Tue) 16:45:20 */ - -int win32_check_interrupt(void) -{ - int c; - - if (kbhit()) { - c = LYgetch(); - /** Keyboard 'Z' or 'z', or Control-G or Control-C **/ - if (LYCharIsINTERRUPT(c) || c == 0x1b) { - return TRUE; - } - } - return FALSE; -} - -void sleep(unsigned sec) -{ - unsigned int i, j; - int c; - - for (j = 0; j < sec; j++) { - for (i = 0; i < 10; i++) { - Sleep(100); - if (kbhit()) { - c = LYgetch(); - return; - } - } - } -} -#endif - -/* - * This function rewrites and reallocates a previously allocated string so that - * the first element is a confirmed Internet host, and returns TRUE, otherwise - * it does not modify the string and returns FALSE. It first tries the element - * as is, then, if the element does not end with a dot, it adds prefixes from - * the (comma separated) prefix list argument, and, if the element does not - * begin with a dot, suffixes from the (comma separated) suffix list arguments - * (e.g., www.host.com, then www.host,edu, then www.host.net, then - * www.host.org). The remaining path, if one is present, will be appended to - * the expanded host. It also takes into account whether a colon is in the - * element or suffix, and includes that and what follows as a port field for - * the expanded host field (e.g, wfbr:8002/dir/lynx should yield - * www.wfbr.edu:8002/dir/lynx). The calling function should prepend the scheme - * field (e.g., http://), or pass the string to LYAddSchemeForURL(), if this - * function returns TRUE. - FM - */ -BOOLEAN LYExpandHostForURL(char **AllocatedString, - char *prefix_list, - char *suffix_list) -{ - char *DomainPrefix = NULL; - const char *StartP, *EndP; - char *DomainSuffix = NULL; - const char *StartS, *EndS; - char *Str = NULL, *StrColon = NULL, *MsgStr = NULL; - char *Host = NULL, *HostColon = NULL, *host = NULL; - char *Path = NULL; - char *Fragment = NULL; - BOOLEAN GotHost = FALSE; - BOOLEAN Startup = (BOOL) (helpfilepath == NULL); - -#ifdef INET6 - struct addrinfo hints, *res; - int error; - char *begin; - char *end = NULL; -#endif /* INET6 */ - - /* - * If it's a NULL or zero-length string, or if it begins with a slash or - * hash, don't continue pointlessly. - FM - */ - if (!(*AllocatedString) || *AllocatedString[0] == '\0' || - *AllocatedString[0] == '/' || *AllocatedString[0] == '#') { - return GotHost; - } - - /* - * If it's a partial or relative path, don't continue pointlessly. - FM - */ - if (!StrNCmp(*AllocatedString, "..", 2) || - !StrNCmp(*AllocatedString, "./", 2)) { - return GotHost; - } - - /* - * Make a clean copy of the string, and trim off the path if one is - * present, but save the information so we can restore the path after - * filling in the Host[:port] field. - FM - */ - StrAllocCopy(Str, *AllocatedString); - if ((Path = strchr(Str, '/')) != NULL) { - /* - * Have a path. Any fragment should already be included in Path. - FM - */ - *Path = '\0'; - } else { - /* - * No path, so check for a fragment and trim that, to be restored after - * filling in the Host[:port] field. - FM - */ - Fragment = trimPoundSelector(Str); - } - - /* - * If the potential host string has a colon, assume it begins a port field, - * and trim it off, but save the information so we can restore the port - * field after filling in the host field. - FM - */ - if ((StrColon = strrchr(Str, ':')) != NULL && - isdigit(UCH(StrColon[1])) && strchr(StrColon, ']') == NULL) { - if (StrColon == Str) { - goto cleanup; - } - *StrColon = '\0'; - } - - /* - * Do a DNS test on the potential host field as presently trimmed. - FM - */ - StrAllocCopy(host, Str); - HTUnEscape(host); - if (LYCursesON) { - StrAllocCopy(MsgStr, WWW_FIND_MESSAGE); - StrAllocCat(MsgStr, host); - StrAllocCat(MsgStr, FIRST_SEGMENT); - HTProgress(MsgStr); - } else if (Startup && !dump_output_immediately) { - fprintf(stdout, "%s '%s'%s\r\n", WWW_FIND_MESSAGE, host, FIRST_SEGMENT); - } -#ifdef INET6 - begin = host; - if (host[0] == '[' && ((end = strrchr(host, ']')))) { - /* - * cut '[' and ']' from the IPv6 address, e.g. [::1] - */ - begin = host + 1; - *end = '\0'; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(begin, "80", &hints, &res); - if (end) - *end = ']'; - - if (!error && res) -#else - if (LYGetHostByName(host) != NULL) -#endif /* INET6 */ - { - /* - * Clear any residual interrupt. - FM - */ - if (LYCursesON && HTCheckForInterrupt()) { - CTRACE((tfp, - "LYExpandHostForURL: Ignoring interrupt because '%s' resolved.\n", - host)); - } - - /* - * Return success. - FM - */ - GotHost = TRUE; - goto cleanup; - } else if (LYCursesON && (lynx_nsl_status == HT_INTERRUPTED)) { - /* - * Give the user chance to interrupt lookup cycles. - KW & FM - */ - CTRACE((tfp, - "LYExpandHostForURL: Interrupted while '%s' failed to resolve.\n", - host)); - - /* - * Return failure. - FM - */ - goto cleanup; - } - - /* - * Set the first prefix, making it a zero-length string if the list is NULL - * or if the potential host field ends with a dot. - FM - */ - StartP = ((prefix_list && Str[strlen(Str) - 1] != '.') - ? prefix_list - : ""); - /* - * If we have a prefix, but the allocated string is one of the common host - * prefixes, make our prefix a zero-length string. - FM - */ - if (*StartP && *StartP != '.') { - if (!strncasecomp(*AllocatedString, "www.", 4) || - !strncasecomp(*AllocatedString, "ftp.", 4) || - !strncasecomp(*AllocatedString, "gopher.", 7) || - !strncasecomp(*AllocatedString, "wais.", 5) || - !strncasecomp(*AllocatedString, "cso.", 4) || - !strncasecomp(*AllocatedString, "ns.", 3) || - !strncasecomp(*AllocatedString, "ph.", 3) || - !strncasecomp(*AllocatedString, "finger.", 7) || - !strncasecomp(*AllocatedString, "news.", 5) || - !strncasecomp(*AllocatedString, "nntp.", 5)) { - StartP = ""; - } - } - while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) { - StartP++; /* Skip whitespace and separators */ - } - EndP = StartP; - while (*EndP && !WHITE(*EndP) && *EndP != ',') { - EndP++; /* Find separator */ - } - StrAllocCopy(DomainPrefix, StartP); - DomainPrefix[EndP - StartP] = '\0'; - - /* - * Test each prefix with each suffix. - FM - */ - do { - /* - * Set the first suffix, making it a zero-length string if the list is - * NULL or if the potential host field begins with a dot. - FM - */ - StartS = ((suffix_list && *Str != '.') - ? suffix_list - : ""); - while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) { - StartS++; /* Skip whitespace and separators */ - } - EndS = StartS; - while (*EndS && !WHITE(*EndS) && *EndS != ',') { - EndS++; /* Find separator */ - } - StrAllocCopy(DomainSuffix, StartS); - DomainSuffix[EndS - StartS] = '\0'; - - /* - * Create domain names and do DNS tests. - FM - */ - do { - StrAllocCopy(Host, DomainPrefix); - StrAllocCat(Host, ((*Str == '.') ? (Str + 1) : Str)); - if (Host[strlen(Host) - 1] == '.') { - Host[strlen(Host) - 1] = '\0'; - } - StrAllocCat(Host, DomainSuffix); - if ((HostColon = strrchr(Host, ':')) != NULL && - isdigit(UCH(HostColon[1]))) { - *HostColon = '\0'; - } - StrAllocCopy(host, Host); - HTUnEscape(host); - if (LYCursesON) { - StrAllocCopy(MsgStr, WWW_FIND_MESSAGE); - StrAllocCat(MsgStr, host); - StrAllocCat(MsgStr, GUESSING_SEGMENT); - HTProgress(MsgStr); - } else if (Startup && !dump_output_immediately) { - fprintf(stdout, "%s '%s'%s\n", WWW_FIND_MESSAGE, host, GUESSING_SEGMENT); - } - GotHost = (BOOL) (LYGetHostByName(host) != NULL); - if (HostColon != NULL) { - *HostColon = ':'; - } - if (GotHost == FALSE) { - /* - * Give the user chance to interrupt lookup cycles. - KW - */ - if (LYCursesON && (lynx_nsl_status == HT_INTERRUPTED)) { - CTRACE((tfp, - "LYExpandHostForURL: Interrupted while '%s' failed to resolve.\n", - host)); - goto cleanup; /* We didn't find a valid name. */ - } - - /* - * Advance to the next suffix, or end of suffix list. - FM - */ - StartS = ((*EndS == '\0') ? EndS : (EndS + 1)); - while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) { - StartS++; /* Skip whitespace and separators */ - } - EndS = StartS; - while (*EndS && !WHITE(*EndS) && *EndS != ',') { - EndS++; /* Find separator */ - } - LYStrNCpy(DomainSuffix, StartS, (EndS - StartS)); - } - } while ((GotHost == FALSE) && (*DomainSuffix != '\0')); - - if (GotHost == FALSE) { - /* - * Advance to the next prefix, or end of prefix list. - FM - */ - StartP = ((*EndP == '\0') ? EndP : (EndP + 1)); - while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) { - StartP++; /* Skip whitespace and separators */ - } - EndP = StartP; - while (*EndP && !WHITE(*EndP) && *EndP != ',') { - EndP++; /* Find separator */ - } - LYStrNCpy(DomainPrefix, StartP, (EndP - StartP)); - } - } while ((GotHost == FALSE) && (*DomainPrefix != '\0')); - - /* - * If a test passed, restore the port field if we had one and there is no - * colon in the expanded host, and the path if we had one, and reallocate - * the original string with the expanded Host[:port] field included. - FM - */ - if (GotHost) { - if (StrColon && strchr(Host, ':') == NULL) { - *StrColon = ':'; - StrAllocCat(Host, StrColon); - } - if (Path) { - *Path = '/'; - StrAllocCat(Host, Path); - } else if (Fragment) { - StrAllocCat(Host, "/"); - restorePoundSelector(Fragment); - StrAllocCat(Host, Fragment); - } - StrAllocCopy(*AllocatedString, Host); - } - - /* - * Clear any residual interrupt. - FM - */ - if (LYCursesON && HTCheckForInterrupt()) { - CTRACE((tfp, - "LYExpandHostForURL: Ignoring interrupt because '%s' %s.\n", - host, - (GotHost ? "resolved" : "timed out"))); - } - - /* - * Clean up and return the last test result. - FM - */ - cleanup: - FREE(DomainPrefix); - FREE(DomainSuffix); - FREE(Str); - FREE(MsgStr); - FREE(Host); - FREE(host); - return GotHost; -} - -/* - * This function rewrites and reallocates a previously allocated string that - * begins with an Internet host name so that the string begins with its guess - * of the scheme based on the first field of the host name, or the default - * scheme if no guess was made, and returns TRUE, otherwise it does not modify - * the string and returns FALSE. It also returns FALSE without modifying the - * string if the default_scheme argument was NULL or zero-length and no guess - * was made. - FM - */ -BOOLEAN LYAddSchemeForURL(char **AllocatedString, - const char *default_scheme) -{ - char *Str = NULL; - BOOLEAN GotScheme = FALSE; - - /* - * If we were passed a NULL or zero-length string, don't continue - * pointlessly. - FM - */ - if (!(*AllocatedString) || *AllocatedString[0] == '\0') { - return GotScheme; - } - - /* - * Try to guess the appropriate scheme. - FM - */ - if (0 == strncasecomp(*AllocatedString, "www", 3)) { - /* - * This could be either http or https, so check the default and - * otherwise use "http". - FM - */ - if (default_scheme != NULL && - NULL != strstr(default_scheme, "http")) { - StrAllocCopy(Str, default_scheme); - } else { - StrAllocCopy(Str, "http://"); - } - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "ftp", 3)) { - StrAllocCopy(Str, "ftp://"); - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "gopher", 6)) { - StrAllocCopy(Str, "gopher://"); - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "wais", 4)) { - StrAllocCopy(Str, "wais://"); - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "cso", 3) || - 0 == strncasecomp(*AllocatedString, "ns.", 3) || - 0 == strncasecomp(*AllocatedString, "ph.", 3)) { - StrAllocCopy(Str, "cso://"); - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "finger", 6)) { - StrAllocCopy(Str, "finger://"); - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "news", 4)) { - /* - * This could be either news, snews, or nntp, so check the default, and - * otherwise use news. - FM - */ - if ((default_scheme != NULL) && - (NULL != strstr(default_scheme, "news") || - NULL != strstr(default_scheme, "nntp"))) { - StrAllocCopy(Str, default_scheme); - } else { - StrAllocCopy(Str, "news://"); - } - GotScheme = TRUE; - - } else if (0 == strncasecomp(*AllocatedString, "nntp", 4)) { - StrAllocCopy(Str, "nntp://"); - GotScheme = TRUE; - - } - - /* - * If we've make a guess, use it. Otherwise, if we were passed a default - * scheme prefix, use that. - FM - */ - if (GotScheme == TRUE) { - StrAllocCat(Str, *AllocatedString); - StrAllocCopy(*AllocatedString, Str); - FREE(Str); - return GotScheme; - - } else if (non_empty(default_scheme)) { - StrAllocCopy(Str, default_scheme); - GotScheme = TRUE; - StrAllocCat(Str, *AllocatedString); - StrAllocCopy(*AllocatedString, Str); - FREE(Str); - return GotScheme; - } - - return GotScheme; -} - -/* - * This function expects an absolute Unix or VMS SHELL path spec as an - * allocated string, simplifies it, and trims out any residual relative - * elements. It also checks whether the path had a terminal slash, and if it - * didn't, makes sure that the simplified path doesn't either. If it's a - * directory, our convention is to exclude "Up to parent" links when a terminal - * slash is present. - FM - */ -void LYTrimRelFromAbsPath(char *path) -{ - char *cp; - int i; - BOOL TerminalSlash; - - /* - * Make sure we have a pointer to an absolute path. - FM - */ - if (path == NULL || !LYIsPathSep(*path)) - return; - - /* - * Check whether the path has a terminal slash. - FM - */ - TerminalSlash = (BOOL) (LYIsPathSep(path[(strlen(path) - 1)])); - - /* - * Simplify the path and then do any necessary trimming. - FM - */ - HTSimplify(path); - cp = path; - while (cp[1] == '.') { - if (cp[2] == '\0') { - /* - * Eliminate trailing dot. - FM - */ - cp[1] = '\0'; - } else if (LYIsPathSep(cp[2])) { - /* - * Skip over the "/." of a "/./". - FM - */ - cp += 2; - } else if (cp[2] == '.' && cp[3] == '\0') { - /* - * Eliminate trailing dotdot. - FM - */ - cp[1] = '\0'; - } else if (cp[2] == '.' && cp[3] == '/') { - /* - * Skip over the "/.." of a "/../". - FM - */ - cp += 3; - } else { - /* - * Done trimming. - FM - */ - break; - } - } - - /* - * Load any shifts into path, and eliminate any terminal slash created by - * HTSimplify() or our walk, but not present originally. - FM - */ - if (cp > path) { - for (i = 0; cp[i] != '\0'; i++) - path[i] = cp[i]; - path[i] = '\0'; - } - if (TerminalSlash == FALSE) { - LYTrimPathSep(path); - } -} - -/* - * Example Client-Side Include interface. - * - * This is called from SGML.c and simply returns markup for reporting the URL - * of the document being loaded if a comment begins with "<!--#lynxCSI". The - * markup will be included as if it were in the document. Move this function - * to a separate module for doing this kind of thing seriously, someday. - FM - */ -void LYDoCSI(char *url, - const char *comment, - char **csi) -{ - const char *cp = comment; - - if (cp == NULL) - return; - - if (StrNCmp(cp, "!--#", 4)) - return; - - cp += 4; - if (!strncasecomp(cp, "lynxCSI", 7)) { - StrAllocCat(*csi, "\n<p align=\"center\">URL: "); - StrAllocCat(*csi, url); - StrAllocCat(*csi, "</p>\n\n"); - } - - return; -} - -#ifdef VMS -/* - * Define_VMSLogical -- Fote Macrides 04-Apr-1995 - * Define VMS logicals in the process table. - */ -void Define_VMSLogical(char *LogicalName, - char *LogicalValue) -{ - $DESCRIPTOR(lname, ""); - $DESCRIPTOR(lvalue, ""); - $DESCRIPTOR(ltable, "LNM$PROCESS"); - - if (isEmpty(LogicalName)) - return; - - lname.dsc$w_length = strlen(LogicalName); - lname.dsc$a_pointer = LogicalName; - - if (isEmpty(LogicalValue)) { - lib$delete_logical(&lname, <able); - return; - } - - lvalue.dsc$w_length = strlen(LogicalValue); - lvalue.dsc$a_pointer = LogicalValue; - lib$set_logical(&lname, &lvalue, <able, 0, 0); - return; -} -#endif /* VMS */ - -#ifdef LY_FIND_LEAKS -static void LYHomeDir_free(void) -{ - FREE(HomeDir); -} -#endif /* LY_FIND_LEAKS */ - -char *Current_Dir(char *pathname) -{ - char *result; - -#ifdef HAVE_GETCWD - result = getcwd(pathname, (size_t) LY_MAXPATH); -#else - result = getwd(pathname); -#endif /* NO_GETCWD */ - if (result == 0) - strcpy(pathname, "."); - return pathname; -} - -/* - * Verify that the given path refers to an existing directory, returning the - * string if the directory exists. If not, return null. - */ -static char *CheckDir(char *path) -{ - struct stat stat_info; - - if (!LYisAbsPath(path) - || (HTStat(path, &stat_info) < 0 - || !S_ISDIR(stat_info.st_mode))) { - path = NULL; - } - return path; -} - -/* - * Lookup various possibilities for $HOME, and check that the directory exists. - */ -static char *HomeEnv(void) -{ - char *result = CheckDir(LYGetEnv("HOME")); - -#if defined (USE_DOS_DRIVES) - if (result == 0) { - char *head; - char *leaf; - static char *temp = NULL; - - /* Windows 2000 */ - if ((result = LYGetEnv("USERPROFILE")) != 0) { - HTSprintf0(&temp, "%s%sMy Documents", result, PATHSEP_STR); - result = CheckDir(temp); - } - /* NT4 */ - if (result == 0) { - if ((head = LYGetEnv("HOMEDRIVE")) != 0) { - if ((leaf = LYGetEnv("HOMEPATH")) != 0) { - HTSprintf0(&temp, "%s%s%s", head, PATHSEP_STR, leaf); - result = CheckDir(temp); - } - } - } - /* General M$ */ -#ifdef USE_PROGRAM_DIR - if (result == 0) - result = CheckDir(program_dir); -#endif - if (result == 0) - result = CheckDir(LYGetEnv("TEMP")); - if (result == 0) - result = CheckDir(LYGetEnv("TMP")); - if (result == 0) { - if ((head = LYGetEnv("SystemDrive")) != 0) { - HTSprintf0(&temp, "%s%s", head, PATHSEP_STR); - result = CheckDir(temp); - } - } - if (result == 0) - result = CheckDir("C:" PATHSEP_STR); - } -#endif - - return result; -} - -const char *Home_Dir(void) -{ - static const char *homedir = NULL; - char *cp = NULL; - - if (homedir == NULL) { - if ((cp = HomeEnv()) == NULL) { -#ifdef VMS - if ((cp = LYGetEnv("SYS$LOGIN")) == NULL - && (cp = LYGetEnv("SYS$SCRATCH")) == NULL) { - cp = "sys$scratch:"; - } - StrAllocCopy(HomeDir, cp); -#else -#ifdef UNIX -#ifdef HAVE_UTMP - /* - * One could use getlogin() and getpwnam() here instead. - */ - struct passwd *pw = getpwuid(geteuid()); - - if (pw && pw->pw_dir) { - StrAllocCopy(HomeDir, pw->pw_dir); - } else -#endif - { - /* - * Use /tmp; it should be writable. - */ - StrAllocCopy(HomeDir, "/tmp"); - } -#endif -#endif /* VMS */ - } else { - StrAllocCopy(HomeDir, cp); - } - homedir = (const char *) HomeDir; -#ifdef LY_FIND_LEAKS - atexit(LYHomeDir_free); -#endif - } - if (homedir == NULL) { - printf("%s\n", gettext("Cannot find HOME directory")); - exit_immediately(EXIT_FAILURE); - } - return homedir; -} - -/* - * Return a pointer to the final leaf of the given pathname, If no pathname - * separators are found, returns the original pathname. The leaf may be - * empty. - */ -char *LYPathLeaf(char *pathname) -{ - char *leaf; - -#ifdef UNIX - if ((leaf = strrchr(pathname, '/')) != 0) { - leaf++; - } -#else -#ifdef VMS - if ((leaf = strrchr(pathname, ']')) == 0) - leaf = strrchr(pathname, ':'); - if (leaf != 0) - leaf++; -#else - int n; - - for (leaf = 0, n = strlen(pathname) - 1; n >= 0; n--) { - if (strchr("\\/:", pathname[n]) != 0) { - leaf = pathname + n + 1; - break; - } - } -#endif -#endif - return (leaf != 0) ? leaf : pathname; -} - -/* - * This function checks the acceptability of file paths that are intended to be - * off the home directory. The file path should be passed in fbuffer, together - * with the size of the buffer. The function simplifies the file path, and if - * it is acceptable, loads it into fbuffer and returns TRUE. Otherwise, it - * does not modify fbuffer and returns FALSE. If a subdirectory is present and - * the path does not begin with "./", that is prefixed to make the situation - * clear. - FM - */ -BOOLEAN LYPathOffHomeOK(char *fbuffer, - size_t fbuffer_size) -{ - char *file = NULL; - char *cp, *cp1; - - /* - * Make sure we have an fbuffer and a string in it. - FM - */ - if (fbuffer_size < 2 || isEmpty(fbuffer)) { - return (FALSE); - } - StrAllocCopy(file, fbuffer); - cp = file; - - /* - * Check for an inappropriate reference to the home directory, and correct - * it if we can. - FM - */ -#ifdef VMS - if (!strncasecomp(cp, "sys$login", 9)) { - if (*(cp + 9) == '\0') { - /* - * Reject "sys$login". - FM - */ - FREE(file); - return (FALSE); - } - if (*(cp + 9) == ':') { - cp += 10; - if (*cp == '\0') { - /* - * Reject "sys$login:". Otherwise, we have converted - * "sys$login:file" to "file", or have left a strange path for - * VMS as it was originally. - FM - */ - FREE(file); - return (FALSE); - } - } - } -#endif /* VMS */ - if (LYIsTilde(cp[0])) { - if (LYIsPathSep(cp[1])) { - if (cp[2] != '\0') { - if (strchr((cp + 2), '/') != NULL) { - /* - * Convert "~/subdir(s)/file" to "./subdir(s)/file". - FM - */ - *cp = '.'; - } else { - /* - * Convert "~/file" to "file". - FM - */ - cp += 2; - } - } else { - /* - * Reject "~/". - FM - */ - FREE(file); - return (FALSE); - } - } else if ((*(cp + 1) != '\0') && - (cp1 = strchr((cp + 1), '/')) != NULL) { - cp = (cp1 - 1); - if (*(cp + 2) != '\0') { - if (strchr((cp + 2), '/') != NULL) { - /* - * Convert "~user/subdir(s)/file" to "./subdir(s)/file". - * If user is someone else, we covered a spoof. Otherwise, - * we simplified. - FM - */ - *cp = '.'; - } else { - /* - * Convert "~user/file" to "file". - FM - */ - cp += 2; - } - } else { - /* - * Reject "~user/". - FM - */ - FREE(file); - return (FALSE); - } - } else { - /* - * Reject "~user". - FM - */ - FREE(file); - return (FALSE); - } - } -#ifdef VMS - /* - * Check for VMS path specs, and reject if still present. - FM - */ - if (strchr(cp, ':') != NULL || strchr(cp, ']') != NULL) { - FREE(file); - return (FALSE); - } -#endif /* VMS */ - - /* - * Check for a URL or absolute path, and reject if present. - FM - */ - if (is_url(cp) || LYIsPathSep(*cp)) { - FREE(file); - return (FALSE); - } - - /* - * Simplify it. - FM - */ - HTSimplify(cp); - - /* - * Check if it has a pointless "./". - FM - */ - if (!StrNCmp(cp, "./", 2)) { - if (strchr((cp + 2), '/') == NULL) { - cp += 2; - } - } - - /* - * Check for spoofing. - FM - */ - if (*cp == '\0' - || LYIsPathSep(*cp) - || LYIsPathSep(cp[(strlen(cp) - 1)]) - || strstr(cp, "..") != NULL - || !strcmp(cp, ".")) { - FREE(file); - return (FALSE); - } - - /* - * Load what we have at this point into fbuffer, trimming if too long, and - * claim it's OK. - FM - */ - if (fbuffer_size > 3 && StrNCmp(cp, "./", 2) && strchr(cp, '/')) { - /* - * We have a subdirectory and no lead "./", so prefix it to make the - * situation clear. - FM - */ - strcpy(fbuffer, "./"); - if (strlen(cp) > (fbuffer_size - 3)) - cp[(fbuffer_size - 3)] = '\0'; - strcat(fbuffer, cp); - } else { - if (strlen(cp) > (fbuffer_size - 1)) - cp[(fbuffer_size - 1)] = '\0'; - strcpy(fbuffer, cp); - } - FREE(file); - return (TRUE); -} - -/* - * Search for a leading tilde, optionally embedded. If found, return a pointer - * to the tilde. If not found, return the original parameter. - */ -static char *FindLeadingTilde(char *pathname, int embedded) -{ - char *result = pathname; - - if (pathname != NULL) { - if (embedded) { - while (pathname[0] != '\0') { - if (LYIsPathSep(pathname[0])) { - if (LYIsTilde(pathname[1])) { - ++pathname; - break; - } - } - ++pathname; - } - } - if (LYIsTilde(*pathname)) - result = pathname; - } - return result; -} - -/* - * Convert a non-absolute path to one which is off the home directory. Expand - * tildes as a side-effect. Return a pointer to the converted result. - */ -char *LYAbsOrHomePath(char **fname) -{ - if (!LYisAbsPath(*fname)) { - if (LYIsTilde((*fname)[0])) { - LYTildeExpand(fname, FALSE); - } else { - char temp[LY_MAXPATH]; - - LYAddPathToHome(temp, sizeof(temp), *fname); - StrAllocCopy(*fname, temp); - } - } - return *fname; -} - -/* - * Expand a "leading" tilde into the user's home directory in WWW format. If - * "embedded" is true, allow that "leading" tilde to follow a path separator. - */ -char *LYTildeExpand(char **pathname, - int embedded) -{ - char *temp = FindLeadingTilde(*pathname, embedded); - - if (LYIsTilde(temp[0])) { - - CTRACE((tfp, "LYTildeExpand %s\n", *pathname)); - if (LYIsPathSep(temp[1])) { - char *first = NULL; - char *second = NULL; - - StrAllocCopy(first, *pathname); - first[temp - *pathname] = '\0'; - - StrAllocCopy(second, temp + 2); - - StrAllocCopy(*pathname, first); - StrAllocCat(*pathname, wwwName(Home_Dir())); - LYAddPathSep(pathname); - StrAllocCat(*pathname, second); - - FREE(first); - FREE(second); - } else if (temp[1] == '\0') { - StrAllocCopy(*pathname, wwwName(Home_Dir())); - } - CTRACE((tfp, "expanded path %s\n", *pathname)); - } - return *pathname; -} - -/* - * This function appends fname to the home path and returns the full path and - * filename. The fname string can be just a filename (e.g., - * "lynx_bookmarks.html"), or include a subdirectory off the home directory, in - * which case fname should begin with "./" (e.g., ./BM/lynx_bookmarks.html) Use - * LYPathOffHomeOK() to check and/or fix up fname before calling this function. - * On VMS, the resultant full path and filename are converted to VMS syntax. - - * FM - */ -void LYAddPathToHome(char *fbuffer, - size_t fbuffer_size, - const char *fname) -{ - char *home = NULL; - const char *file = fname; - int len; - - /* - * Make sure we have a buffer. - FM - */ - if (!fbuffer) - return; - if (fbuffer_size < 2) { - fbuffer[0] = '\0'; - return; - } - fbuffer[(fbuffer_size - 1)] = '\0'; - - /* - * Make sure we have a file name. - FM - */ - if (!file) - file = ""; - - /* - * Set up home string and length. - FM - */ - StrAllocCopy(home, Home_Dir()); - -#ifdef VMS -#define NO_HOMEPATH "Error:" -#else -#define NO_HOMEPATH "/error" -#endif /* VMS */ - if (!non_empty(home)) - /* - * Home_Dir() has a bug if this ever happens. - FM - */ - StrAllocCopy(home, NO_HOMEPATH); - - len = (int) fbuffer_size - ((int) strlen(home) + 1); - if (len <= 0) { - /* - * Buffer is smaller than or only big enough for the home path. Load - * what fits of the home path and return. This will fail, but we need - * something in the buffer. - FM - */ - LYStrNCpy(fbuffer, home, (fbuffer_size - 1)); - FREE(home); - return; - } -#ifdef VMS - /* - * Check whether we have a subdirectory path or just a filename. - FM - */ - if (!StrNCmp(file, "./", 2)) { - /* - * We have a subdirectory path. - FM - */ - if (home[strlen(home) - 1] == ']') { - /* - * We got the home directory, so convert it to SHELL syntax and - * append subdirectory path, then convert that to VMS syntax. - FM - */ - char *temp = NULL; - - HTSprintf0(&temp, "%s%s", HTVMS_wwwName(home), (file + 1)); - sprintf(fbuffer, "%.*s", - (fbuffer_size - 1), HTVMS_name("", temp)); - FREE(temp); - } else { - /* - * This will fail, but we need something in the buffer. - FM - */ - sprintf(fbuffer, "%s%.*s", home, len, file); - } - } else { - /* - * We have a file in the home directory. - FM - */ - sprintf(fbuffer, "%s%.*s", home, len, file); - } -#else - /* - * Check whether we have a subdirectory path or just a filename. - FM - */ - sprintf(fbuffer, "%s/%.*s", home, len, - (StrNCmp(file, "./", 2) ? file : (file + 2))); -#endif /* VMS */ - FREE(home); -} - -/* - * Given a filename, concatenate it to the save-space pathname, unless it is - * an absolute pathname. If there is no save-space defined, use the home - * directory. Return a new string with the result. - */ -char *LYAddPathToSave(char *fname) -{ - char *result = NULL; - - if (LYisAbsPath(fname)) { - StrAllocCopy(result, fname); - } else { - if (lynx_save_space != NULL) { - StrAllocCopy(result, lynx_save_space); - } else { - char temp[LY_MAXPATH]; - - LYAddPathToHome(temp, sizeof(temp), fname); - StrAllocCopy(result, temp); - } - } - return result; -} - -#if !defined(HAVE_PUTENV) && !defined(_WINDOWS) -/* - * No putenv on the NeXT so we use this code instead! - */ - -/* Copyright (C) 1991 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#if defined(STDC_HEADERS) || defined(USG) -#include <string.h> -#else /* Not (STDC_HEADERS or USG): */ -#include <strings.h> -#endif /* STDC_HEADERS or USG */ - -#ifndef NULL -#define NULL 0 -#endif /* !NULL */ - -extern char **environ; - -/* - * Put STRING, which is of the form "NAME=VALUE", in the environment. - */ -int putenv(const char *string) -{ - char *name_end = strchr(string, '='); - register size_t size; - register char **ep; - - if (name_end == NULL) { - /* Remove the variable from the environment. */ - size = strlen(string); - for (ep = environ; *ep != NULL; ++ep) - if (!StrNCmp(*ep, string, size) && (*ep)[size] == '=') { - while (ep[1] != NULL) { - ep[0] = ep[1]; - ++ep; - } - *ep = NULL; - return 0; - } - } - - size = 0; - for (ep = environ; *ep != NULL; ++ep) - if (!StrNCmp(*ep, string, name_end - string) && - (*ep)[name_end - string] == '=') - break; - else - ++size; - - if (*ep == NULL) { - static char **last_environ = NULL; - char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); - - if (new_environ == NULL) - return -1; - (void) memcpy((char *) new_environ, (char *) environ, size * sizeof(char *)); - - new_environ[size] = (char *) string; - new_environ[size + 1] = NULL; - if (last_environ != NULL) - FREE(last_environ); - last_environ = new_environ; - environ = new_environ; - } else - *ep = (char *) string; - - return 0; -} -#endif /* !HAVE_PUTENV */ - -#ifdef NEED_REMOVE -int remove(char *name) -{ - return unlink(name); -} -#endif - -#if defined(MULTI_USER_UNIX) - -#if defined(HAVE_LSTAT) && defined(S_IFLNK) -/* - * If IsOurFile() is checking a symbolic link, ensure that the target - * points to the user's file as well. - */ -static BOOL IsOurSymlink(const char *name) -{ - BOOL result = FALSE; - int size = LY_MAXPATH; - int used; - char *buffer = typeMallocn(char, (unsigned) size); - - if (buffer != 0) { - while ((used = (int) readlink(name, buffer, (size_t) (size - 1))) == size - - 1) { - buffer = typeRealloc(char, buffer, (unsigned) (size *= 2)); - - if (buffer == 0) - break; - } - if (buffer != 0) { - if (used > 0) { - buffer[used] = '\0'; - } else { - FREE(buffer); - } - } - } - if (buffer != 0) { - if (!LYisAbsPath(buffer)) { - char *cutoff = LYLastPathSep(name); - char *clone = NULL; - - if (cutoff != 0) { - HTSprintf0(&clone, "%.*s%s%s", - (int) (cutoff - name), - name, PATHSEP_STR, buffer); - FREE(buffer); - buffer = clone; - } - } - CTRACE2(TRACE_CFG, (tfp, "IsOurSymlink(%s -> %s)\n", name, buffer)); - result = IsOurFile(buffer); - FREE(buffer); - } - return result; -} -#endif - -/* - * Verify if this is really a file, not accessed by a link, except for the - * special case of its directory being pointed to by a link from a directory - * owned by root and not writable by other users. - */ -BOOL IsOurFile(const char *name) -{ - BOOL result = FALSE; - struct stat data; - - if (!LYIsTilde(name[0]) - && lstat(name, &data) == 0 - && ((S_ISREG(data.st_mode) - && (data.st_mode & (S_IWOTH | S_IWGRP)) == 0 - && data.st_nlink == 1 - && data.st_uid == getuid()) -#if defined(HAVE_LSTAT) && defined(S_IFLNK) - || (S_ISLNK(data.st_mode) && IsOurSymlink(name)) -#endif - )) { - int linked = FALSE; - - /* - * ( If this is not a single-user system, the other user is presumed by - * some people busy trying to use a symlink attack on our files ;-) - */ -#if defined(HAVE_LSTAT) - char *path = 0; - char *leaf; - - StrAllocCopy(path, name); - do { - if ((leaf = LYPathLeaf(path)) != path) - *--leaf = '\0'; /* write a null on the '/' */ - if (lstat(*path ? path : "/", &data) != 0) { - break; - } - /* - * If we find a symbolic link, it has to be in a directory that's - * protected. Otherwise someone could have switched it to point - * to one of the real user's files. - */ - if (S_ISLNK(data.st_mode)) { - linked = TRUE; /* could be link-to-link; doesn't matter */ - } else if (S_ISDIR(data.st_mode)) { - if (linked) { - linked = FALSE; - /* - * We assume that a properly-configured system has the - * unwritable directories owned by root. This is not - * necessarily so (bin, news, etc., may), but the only - * uid we can count on is 0. It would be nice to add a - * check for the gid also, but that wouldn't be - * portable. - */ - if (data.st_uid != 0 - || (data.st_mode & S_IWOTH) != 0) { - linked = TRUE; /* force an error-return */ - break; - } - } - } else if (linked) { - break; - } - } while (leaf != path); - FREE(path); -#endif - result = (BOOLEAN) !linked; - } - CTRACE2(TRACE_CFG, (tfp, "IsOurFile(%s) %d\n", name, result)); - return result; -} - -/* - * Open a file that we don't want other users to see. - */ -static FILE *OpenHiddenFile(const char *name, const char *mode) -{ - FILE *fp = 0; - struct stat data; - BOOLEAN binary = (BOOLEAN) (strchr(mode, 'b') != 0); - -#if defined(O_CREAT) && defined(O_EXCL) /* we have fcntl.h or kindred? */ - /* - * This is the preferred method for creating new files, since it ensures - * that no one has an existing file or link that they happen to own. - */ - if (*mode == 'w') { - int fd = open(name, O_CREAT | O_EXCL | O_WRONLY, HIDE_CHMOD); - - if (fd < 0 - && errno == EEXIST - && IsOurFile(name)) { - remove(name); - /* FIXME: there's a race at this point if directory is open */ - fd = open(name, O_CREAT | O_EXCL | O_WRONLY, HIDE_CHMOD); - } - if (fd >= 0) { -#if defined(O_BINARY) && defined(__CYGWIN__) - if (binary) - setmode(fd, O_BINARY); -#endif - fp = fdopen(fd, mode); - } - } else -#endif - if (*mode == 'a') { - if (IsOurFile(name) - && chmod(name, HIDE_CHMOD) == 0) - fp = fopen(name, mode); - else if (lstat(name, &data) != 0) - fp = OpenHiddenFile(name, binary ? BIN_W : TXT_W); - /* - * This is less stringent, but reasonably portable. For new files, the - * umask will suffice; however if the file already exists we'll change - * permissions first, before opening it. If the chmod fails because of - * some reason other than a non-existent file, there's no point in trying - * to open it. - * - * This won't work properly if the user is root, since the chmod succeeds. - */ - } else if (*mode != 'a') { - mode_t save = umask(HIDE_UMASK); - - if (chmod(name, HIDE_CHMOD) == 0 || errno == ENOENT) - fp = fopen(name, mode); - umask(save); - } - return fp; -} -#else -#define OpenHiddenFile(name, mode) fopen(name, mode) -#endif /* MULTI_USER_UNIX */ - -FILE *LYNewBinFile(const char *name) -{ -#ifdef VMS - FILE *fp = fopen(name, BIN_W, "mbc=32"); - - chmod(name, HIDE_CHMOD); -#else - FILE *fp = OpenHiddenFile(name, BIN_W); -#endif - return fp; -} - -FILE *LYNewTxtFile(const char *name) -{ - FILE *fp; - -#ifdef VMS - fp = fopen(name, TXT_W, "shr=get"); - chmod(name, HIDE_CHMOD); -#else - SetDefaultMode(O_TEXT); - - fp = OpenHiddenFile(name, TXT_W); - - SetDefaultMode(O_BINARY); -#endif - - return fp; -} - -FILE *LYAppendToTxtFile(const char *name) -{ - FILE *fp; - -#ifdef VMS - fp = fopen(name, TXT_A, "shr=get"); - chmod(name, HIDE_CHMOD); -#else - SetDefaultMode(O_TEXT); - - fp = OpenHiddenFile(name, TXT_A); - - SetDefaultMode(O_BINARY); -#endif - return fp; -} - -#if defined(MULTI_USER_UNIX) -/* - * Restore normal permissions to a copy of a file that we have created with - * temp file restricted permissions. The normal umask should apply for user - * files. - kw - */ -void LYRelaxFilePermissions(const char *name) -{ - mode_t mode; - struct stat stat_buf; - - if (stat(name, &stat_buf) == 0 && - S_ISREG(stat_buf.st_mode) && - (mode = (stat_buf.st_mode & 0777)) == HIDE_CHMOD) { - /* - * It looks plausible that this is a file we created with temp file - * paranoid permissions (and the umask wasn't even more restrictive - * when it was copied). - kw - */ - mode_t save = umask(HIDE_UMASK); - - mode = ((mode & 0700) | 0066) & ~save; - umask(save); - chmod(name, mode); - } -} -#endif - -/* - * Check if the given anchor has an associated file-cache. - */ -BOOLEAN LYCachedTemp(char *result, - char **cached) -{ - if (*cached) { - LYStrNCpy(result, *cached, LY_MAXPATH); - FREE(*cached); - if (LYCanReadFile(result)) { - remove(result); - } - return TRUE; - } - return FALSE; -} - -#ifndef HAVE_MKDTEMP -#define mkdtemp(path) ((mktemp(path) != 0) && (mkdir(path, 0700) == 0)) -#endif - -/* - * Open a temp-file, ensuring that it is unique, and not readable by other - * users. - * - * The mode can be one of: "w", "a", "wb". - */ -FILE *LYOpenTemp(char *result, - const char *suffix, - const char *mode) -{ - FILE *fp = 0; - BOOL txt = TRUE; - char wrt = 'r'; - LY_TEMP *p; - - CTRACE((tfp, "LYOpenTemp(,%s,%s)\n", suffix, mode)); - if (result == 0) - return 0; - - while (*mode != '\0') { - switch (*mode++) { - case 'w': - wrt = 'w'; - break; - case 'a': - wrt = 'a'; - break; - case 'b': - txt = FALSE; - break; - default: - CTRACE((tfp, "%s @%d: BUG\n", __FILE__, __LINE__)); - return 0; - } - } - - /* - * Verify if the given space looks secure enough. Otherwise, make a - * secure subdirectory of that. - */ -#if defined(MULTI_USER_UNIX) && (defined(HAVE_MKTEMP) || defined(HAVE_MKDTEMP)) - if (lynx_temp_subspace == 0) { - BOOL make_it = FALSE; - struct stat sb; - - if (lstat(lynx_temp_space, &sb) == 0 - && S_ISDIR(sb.st_mode)) { - if (sb.st_uid != getuid() - || (sb.st_mode & (S_IWOTH | S_IWGRP)) != 0) { - make_it = TRUE; - CTRACE((tfp, - "lynx_temp_space is not our directory %s owner %d mode %03o\n", - lynx_temp_space, (int) sb.st_uid, (int) sb.st_mode & 0777)); - } - } else { - make_it = TRUE; - CTRACE((tfp, "lynx_temp_space is not a directory %s\n", lynx_temp_space)); - } - if (make_it) { - mode_t old_mask = umask(HIDE_UMASK); - - StrAllocCat(lynx_temp_space, "lynxXXXXXXXXXX"); - if (mkdtemp(lynx_temp_space) == 0) { - printf("%s: %s\n", lynx_temp_space, LYStrerror(errno)); - exit_immediately(EXIT_FAILURE); - } - umask(old_mask); - lynx_temp_subspace = 1; - StrAllocCat(lynx_temp_space, "/"); - CTRACE((tfp, "made subdirectory %s\n", lynx_temp_space)); - } else { - lynx_temp_subspace = -1; - } - } -#endif - - do { - if (!fmt_tempname(result, lynx_temp_space, suffix)) - return 0; - if (txt) { - switch (wrt) { - case 'w': - fp = LYNewTxtFile(result); - break; - case 'a': - fp = LYAppendToTxtFile(result); - break; - } - } else { - fp = LYNewBinFile(result); - } - /* - * If we get a failure to make a temporary file, don't bother to try a - * different name unless the failure was because the file already - * exists. - */ -#ifdef EEXIST /* FIXME (need a better test) in fcntl.h or unistd.h */ - if ((fp == 0) && (errno != EEXIST)) { - CTRACE((tfp, "... LYOpenTemp(%s) failed: %s\n", - result, LYStrerror(errno))); - return 0; - } -#endif - } while (fp == 0); - - if ((p = typecalloc(LY_TEMP)) != 0) { - p->next = ly_temp; - StrAllocCopy((p->name), result); - p->file = fp; - p->outs = (BOOLEAN) (wrt != 'r'); - ly_temp = p; - } else { - outofmem(__FILE__, "LYOpenTemp"); - } - - CTRACE((tfp, "... LYOpenTemp(%s)\n", result)); - return fp; -} - -/* - * Reopen a temporary file - */ -FILE *LYReopenTemp(char *name) -{ - LY_TEMP *p; - FILE *fp = 0; - - LYCloseTemp(name); - if ((p = FindTempfileByName(name)) != 0) { - fp = p->file = LYAppendToTxtFile(name); - } - return fp; -} - -/* - * Open a temp-file for writing, possibly re-using a previously used - * name and file. - * If a non-empty fname is given, it is reused if it indicates a file - * previously registered as a temp file and, in case the file still - * exists, if it looks like we can write to it safely. Otherwise a - * new temp file (with new name) will be generated and returned in fname. - * - * File permissions are set so that the file is not readable by unprivileged - * other users. - * - * Suffix is only used if fname is not being reused. - * The mode should be "w", others are possible (they may be passed on) - * but probably don't make sense. - kw - */ -FILE *LYOpenTempRewrite(char *fname, - const char *suffix, - const char *mode) -{ - FILE *fp = 0; - BOOL txt = TRUE; - char wrt = 'r'; - BOOL registered = NO; - BOOL writable_exists = NO; - BOOL is_ours = NO; - BOOL still_open = NO; - LY_TEMP *p; - struct stat stat_buf; - - CTRACE((tfp, "LYOpenTempRewrite(%s,%s,%s)\n", fname, suffix, mode)); - if (*fname == '\0') /* first time, no filename yet */ - return (LYOpenTemp(fname, suffix, mode)); - - if ((p = FindTempfileByName(fname)) != 0) { - registered = YES; - if (p->file != 0) - still_open = YES; - CTRACE((tfp, "...used before%s\n", still_open ? ", still open!" : ".")); - } - - if (registered) { -#ifndef NO_GROUPS - writable_exists = HTEditable(fname); /* existing, can write */ -#define CTRACE_EXISTS "exists and is writable, " -#else - writable_exists = (BOOL) (stat(fname, &stat_buf) == 0); /* existing, assume can write */ -#define CTRACE_EXISTS "exists, " -#endif - - if (writable_exists) { - is_ours = IsOurFile(fname); - } - CTRACE((tfp, "...%s%s\n", - writable_exists ? CTRACE_EXISTS : "", - is_ours ? "is our file." : "is NOT our file.")); - } - - /* - * Note that in cases where LYOpenTemp is called as fallback below, we - * don't call LYRemoveTemp first. That may be appropriate in some cases, - * but not trying to remove a weird existing file seems safer and could - * help diagnose an unusual situation. (They may be removed anyway later.) - */ - if (still_open) { - /* - * This should probably not happen. Make a new one. - */ - return (LYOpenTemp(fname, suffix, mode)); - } else if (!registered) { - /* - * Not registered. It should have been registered at one point though, - * otherwise we wouldn't be called like this. - */ - return (LYOpenTemp(fname, suffix, mode)); - } else if (writable_exists && !is_ours) { - /* - * File exists, writable if we checked, but something is wrong with it. - */ - return (LYOpenTemp(fname, suffix, mode)); -#ifndef NO_GROUPS - } else if (!is_ours && (lstat(fname, &stat_buf) == 0)) { - /* - * Exists but not writable, and something is wrong with it. - */ - return (LYOpenTemp(fname, suffix, mode)); -#endif - } - - while (*mode != '\0') { - switch (*mode++) { - case 'w': - wrt = 'w'; - break; - case 'a': - wrt = 'a'; - break; - case 'b': - txt = FALSE; - break; - default: - CTRACE((tfp, "%s @%d: BUG\n", __FILE__, __LINE__)); - return fp; - } - } - - if (is_ours) { - /* - * Yes, it exists, is writable if we checked, and everything looks ok - * so far. This should be the most regular case. - kw - */ -#ifdef HAVE_TRUNCATE - if (txt == TRUE) { /* limitation of LYReopenTemp. shrug */ - /* - * We truncate and then append, this avoids having a small window - * in which the file doesn't exist. - kw - */ - if (truncate(fname, (off_t) 0) != 0) { - CTRACE((tfp, "... truncate(%s,0) failed: %s\n", - fname, LYStrerror(errno))); - return (LYOpenTemp(fname, suffix, mode)); - } else { - return (LYReopenTemp(fname)); - } - } -#endif - remove(fname); - - } - - /* We come here in two cases: either the file existed and was ours and we - * just got rid of it. Or the file did and does not exist, but is - * registered as a temp file. It must have been removed by some means - * other than LYRemoveTemp. In both cases, reuse the name! - kw - */ - - if (txt) { - switch (wrt) { - case 'w': - fp = LYNewTxtFile(fname); - break; - case 'a': - fp = LYAppendToTxtFile(fname); - break; - } - } else { - fp = LYNewBinFile(fname); - } - p->file = fp; - - CTRACE((tfp, "... LYOpenTempRewrite(%s), %s\n", fname, - (fp) ? "ok" : "failed")); - /* - * We could fall back to trying LYOpenTemp() here in case of failure. - * After all the checks already done above a filure here should be pretty - * unusual though, so maybe it's better to let the user notice that - * something went wrong, and not try to fix it up. - kw - */ - return fp; -} - -/* - * Special case of LYOpenTemp, used for manipulating bookmark file, i.e., with - * renaming. - */ -FILE *LYOpenScratch(char *result, - const char *prefix) -{ - FILE *fp; - LY_TEMP *p; - - if (!fmt_tempname(result, prefix, HTML_SUFFIX)) - return 0; - - if ((fp = LYNewTxtFile(result)) != 0) { - if ((p = typecalloc(LY_TEMP)) != 0) { - p->next = ly_temp; - StrAllocCopy((p->name), result); - p->file = fp; - ly_temp = p; - } else { - outofmem(__FILE__, "LYOpenScratch"); - } - } - CTRACE((tfp, "LYOpenScratch(%s)\n", result)); - return fp; -} - -static void LY_close_temp(LY_TEMP * p) -{ - if (p->file != 0) { - if (p->outs) { - LYCloseOutput(p->file); - } else { - LYCloseInput(p->file); - } - p->file = 0; - } -} - -/* - * Close a temp-file, given its name - */ -void LYCloseTemp(char *name) -{ - LY_TEMP *p; - - CTRACE((tfp, "LYCloseTemp(%s)\n", name)); - if ((p = FindTempfileByName(name)) != 0) { - CTRACE((tfp, "...LYCloseTemp(%s)%s\n", name, - (p->file != 0) ? ", closed" : "")); - LY_close_temp(p); - } -} - -/* - * Close a temp-file, given its file-pointer - */ -void LYCloseTempFP(FILE *fp) -{ - LY_TEMP *p; - - CTRACE((tfp, "LYCloseTempFP\n")); - if ((p = FindTempfileByFP(fp)) != 0) { - LY_close_temp(p); - CTRACE((tfp, "...LYCloseTempFP(%s)\n", p->name)); - } -} - -/* - * Close a temp-file, removing it. - */ -int LYRemoveTemp(char *name) -{ - LY_TEMP *p, *q; - int code = -1; - - if (non_empty(name)) { - CTRACE((tfp, "LYRemoveTemp(%s)\n", name)); - for (p = ly_temp, q = 0; p != 0; q = p, p = p->next) { - if (!strcmp(name, p->name)) { - if (q != 0) { - q->next = p->next; - } else { - ly_temp = p->next; - } - LY_close_temp(p); - code = HTSYS_remove(name); - CTRACE((tfp, "...LYRemoveTemp done(%d)%s\n", code, - (p->file != 0) ? ", closed" : "")); - CTRACE_FLUSH(tfp); - FREE(p->name); - FREE(p); - break; - } - } - } - return code; -} - -/* - * Remove all of the temp-files. Note that this assumes that they are closed, - * since some systems will not allow us to remove a file which is open. - */ -void LYCleanupTemp(void) -{ - while (ly_temp != 0) { - LYRemoveTemp(ly_temp->name); - } -#if defined(MULTI_USER_UNIX) - if (lynx_temp_subspace > 0) { - char result[LY_MAXPATH]; - - LYStrNCpy(result, lynx_temp_space, sizeof(result) - 1); - LYTrimPathSep(result); - CTRACE((tfp, "LYCleanupTemp removing %s\n", result)); - rmdir(result); - lynx_temp_subspace = -1; - } -#endif -} - -/* - * We renamed a temporary file. Keep track so we can remove it on exit. - */ -void LYRenamedTemp(char *oldname, - char *newname) -{ - LY_TEMP *p; - - CTRACE((tfp, "LYRenamedTemp(old=%s, new=%s)\n", oldname, newname)); - if ((p = FindTempfileByName(oldname)) != 0) { - StrAllocCopy((p->name), newname); - } -} - -#ifndef DISABLE_BIBP -/* - * Check that bibhost defines the BibP icon. - */ -void LYCheckBibHost(void) -{ - DocAddress bibhostIcon; - BOOLEAN saveFlag; - - bibhostIcon.address = NULL; - StrAllocCopy(bibhostIcon.address, BibP_bibhost); - StrAllocCat(bibhostIcon.address, "bibp1.0/bibpicon.jpg"); - bibhostIcon.post_data = NULL; - bibhostIcon.post_content_type = NULL; - bibhostIcon.bookmark = FALSE; - bibhostIcon.isHEAD = FALSE; - bibhostIcon.safe = FALSE; - saveFlag = traversal; - traversal = TRUE; /* Hack to force error response. */ - BibP_bibhost_available = (BOOLEAN) (HTLoadAbsolute(&bibhostIcon) == YES); - traversal = saveFlag; - BibP_bibhost_checked = TRUE; -} -#endif /* !DISABLE_BIBP */ - -/* - * Management of User Interface Pages. - kw - * - * These are mostly temp files. Pages which can be recognized by their special - * URL (after having been loaded) need not be tracked here. - * - * First some private stuff: - */ -typedef struct uipage_entry { - UIP_t type; - unsigned flags; - char *url; - HTList *alturls; - char *file; -} uip_entry; - -#define UIP_F_MULTI 0x0001 /* flag: track multiple instances */ -#define UIP_F_LIMIT 0x0002 /* flag: limit size of alturls list */ -#define UIP_F_LMULTI (UIP_F_MULTI | UIP_F_LIMIT) -/* *INDENT-OFF* */ -static uip_entry ly_uip[] = -{ - { UIP_HISTORY , UIP_F_LMULTI, NULL, NULL, NULL } - , { UIP_DOWNLOAD_OPTIONS , 0 , NULL, NULL, NULL } - , { UIP_PRINT_OPTIONS , 0 , NULL, NULL, NULL } - , { UIP_SHOWINFO , UIP_F_LMULTI, NULL, NULL, NULL } - , { UIP_LIST_PAGE , UIP_F_LMULTI, NULL, NULL, NULL } - , { UIP_VLINKS , UIP_F_LMULTI, NULL, NULL, NULL } -#if !defined(NO_OPTION_FORMS) - , { UIP_OPTIONS_MENU , UIP_F_LMULTI, NULL, NULL, NULL } -#endif -#ifdef DIRED_SUPPORT - , { UIP_DIRED_MENU , 0 , NULL, NULL, NULL } - , { UIP_PERMIT_OPTIONS , 0 , NULL, NULL, NULL } - , { UIP_UPLOAD_OPTIONS , UIP_F_LMULTI, NULL, NULL, NULL } -#endif -#ifdef USE_ADDRLIST_PAGE - , { UIP_ADDRLIST_PAGE , UIP_F_LMULTI, NULL, NULL, NULL } -#endif - , { UIP_LYNXCFG , UIP_F_LMULTI, NULL, NULL, NULL } -#if !defined(NO_CONFIG_INFO) - , { UIP_CONFIG_DEF , UIP_F_LMULTI, NULL, NULL, NULL } -#endif -/* The following are not generated tempfiles: */ - , { UIP_TRACELOG , 0 , NULL, NULL, NULL } -#if defined(DIRED_SUPPORT) && defined(OK_INSTALL) - , { UIP_INSTALL , 0 , NULL, NULL, NULL } -#endif - -}; -/* *INDENT-ON* */ - -/* Public entry points for User Interface Page management: */ - -BOOL LYIsUIPage3(const char *url, - UIP_t type, - int flagparam) -{ - unsigned int i; - size_t l; - - if (!url) - return NO; - for (i = 0; i < TABLESIZE(ly_uip); i++) { - if (ly_uip[i].type == type) { - if (!ly_uip[i].url) { - return NO; - } else if ((flagparam & UIP_P_FRAG) ? - (!StrNCmp(ly_uip[i].url, url, (l = strlen(ly_uip[i].url))) - && (url[l] == '\0' || url[l] == '#')) : - !strcmp(ly_uip[i].url, url)) { - return YES; - } else if (ly_uip[i].flags & UIP_F_MULTI) { - char *p; - HTList *l0 = ly_uip[i].alturls; - - while ((p = (char *) HTList_nextObject(l0)) != NULL) { - if ((flagparam & UIP_P_FRAG) ? - (!StrNCmp(p, url, (l = strlen(p))) - && (url[l] == '\0' || url[l] == '#')) : - !strcmp(p, url)) - return YES; - } - } - return NO; - } - } - return NO; -} - -void LYRegisterUIPage(const char *url, - UIP_t type) -{ - unsigned int i; - - for (i = 0; i < TABLESIZE(ly_uip); i++) { - if (ly_uip[i].type == type) { - if (ly_uip[i].url && url && - !strcmp(ly_uip[i].url, url)) { - - } else if (!ly_uip[i].url || !url || - !(ly_uip[i].flags & UIP_F_MULTI)) { - StrAllocCopy(ly_uip[i].url, url); - - } else { - char *p; - int n = 0; - HTList *l0 = ly_uip[i].alturls; - - while ((p = (char *) HTList_nextObject(l0)) != NULL) { - if (!strcmp(p, url)) - return; - if (!strcmp(p, ly_uip[i].url)) { - StrAllocCopy(ly_uip[i].url, url); - return; - } - n++; - } - if (!ly_uip[i].alturls) - ly_uip[i].alturls = HTList_new(); - - if (n >= HTCacheSize && (ly_uip[i].flags & UIP_F_LIMIT)) - HTList_removeFirstObject(ly_uip[i].alturls); - HTList_addObject(ly_uip[i].alturls, ly_uip[i].url); - ly_uip[i].url = NULL; - StrAllocCopy(ly_uip[i].url, url); - } - - return; - } - } -} - -void LYUIPages_free(void) -{ - unsigned int i; - - for (i = 0; i < TABLESIZE(ly_uip); i++) { - FREE(ly_uip[i].url); - FREE(ly_uip[i].file); - LYFreeStringList(ly_uip[i].alturls); - ly_uip[i].alturls = NULL; - } -} - -/* - * Convert local pathname to www name - * (do not bother about file://localhost prefix at this point). - */ -const char *wwwName(const char *pathname) -{ - const char *cp = NULL; - -#if defined(USE_DOS_DRIVES) - cp = HTDOS_wwwName(pathname); -#else -#ifdef VMS - cp = HTVMS_wwwName(pathname); -#else - cp = pathname; -#endif /* VMS */ -#endif - - return cp; -} - -/* - * Given a user-specified filename, e.g., for download or print, validate and - * expand it. Expand home-directory expressions in the given string. Only - * allow pipes if the user can spawn shell commands. - * - * Both strings are fixed buffer sizes, LY_MAXPATH. - */ -BOOLEAN LYValidateFilename(char *result, - char *given) -{ - BOOLEAN code = TRUE; - char *cp = NULL; - const char *cp2 = NULL; - - /* - * Cancel if the user entered "/dev/null" on Unix, or an "nl:" path on VMS. - * - FM - */ - if (LYIsNullDevice(given)) { - /* just ignore it */ - code = FALSE; -#ifdef HAVE_POPEN - } else if (LYIsPipeCommand(given)) { - if (no_shell) { - HTUserMsg(SPAWNING_DISABLED); - code = FALSE; - } else { - LYStrNCpy(result, given, LY_MAXPATH); - } -#endif - } else { - if ((cp = FindLeadingTilde(given, TRUE)) != 0 - && (cp2 = wwwName(Home_Dir())) != 0 - && strlen(cp2) + strlen(given) < LY_MAXPATH) { - if (LYIsTilde(cp[0]) && LYIsPathSep(cp[1])) { - *(cp++) = '\0'; - strcpy(result, given); - LYTrimPathSep(result); - strcat(result, cp2); - strcat(result, cp); - strcpy(given, result); - } - } -#ifdef VMS - if (strchr(given, '/') != NULL) { - strcpy(result, HTVMS_name("", given)); - strcpy(given, result); - } - if (given[0] != '/' - && strchr(given, ':') == NULL - && strlen(given) < LY_MAXPATH - 13) { - strcpy(result, "sys$disk:"); - if (strchr(given, ']') == NULL) - strcat(result, "[]"); - strcat(result, given); - } else { - strcpy(result, given); - } -#else - -#ifndef __EMX__ - if (!LYisAbsPath(given)) { -#if defined(__DJGPP__) || defined(_WINDOWS) - if (strchr(result, ':') != NULL) - cp = NULL; - else -#endif /* __DJGPP__ || _WINDOWS */ - { -#ifdef SUPPORT_CHDIR - static char buf[LY_MAXPATH]; - - cp = Current_Dir(buf); -#else - cp = original_dir; -#endif - } - } else -#endif /* __EMX__ */ - cp = NULL; - - *result = 0; - if (cp) { - LYTrimPathSep(cp); - if (strlen(cp) >= LY_MAXPATH - 2) { - code = FALSE; - } else { - sprintf(result, "%s/", cp); - } - } - if (code) { - cp = HTSYS_name(given); - if (strlen(result) + strlen(cp) >= LY_MAXPATH - 1) { - code = FALSE; - } else { - strcat(result, cp); - } - } -#endif /* VMS */ - } - return code; -} - -/* - * Given a valid filename, check if it exists. If so, we'll have to worry - * about overwriting it. - * - * Returns: - * 'Y' (yes/success) - * 'N' (no/retry) - * 3 (cancel) - */ -int LYValidateOutput(char *filename) -{ - int c; - - /* - * Assume we can write to a pipe - */ -#ifdef HAVE_POPEN - if (LYIsPipeCommand(filename)) - return 'Y'; -#endif - - if (no_dotfiles || !show_dotfiles) { - if (*LYPathLeaf(filename) == '.') { - HTAlert(FILENAME_CANNOT_BE_DOT); - return 'N'; - } - } - - /* - * See if it already exists. - */ - if (LYCanReadFile(filename)) { -#ifdef VMS - c = HTConfirm(FILE_EXISTS_HPROMPT); -#else - c = HTConfirm(FILE_EXISTS_OPROMPT); -#endif /* VMS */ - if (HTLastConfirmCancelled()) { - HTInfoMsg(SAVE_REQUEST_CANCELLED); - return 3; - } else if (c == NO) { - return 'N'; - } - } - return 'Y'; -} - -/* - * Convert a local filename to a URL - */ -void LYLocalFileToURL(char **target, - const char *source) -{ - const char *leaf; - - StrAllocCopy(*target, "file://localhost"); - - leaf = wwwName(source); - - if (!LYisAbsPath(source)) { - char temp[LY_MAXPATH]; - - Current_Dir(temp); - if (!LYIsHtmlSep(*temp)) - LYAddHtmlSep(target); - StrAllocCat(*target, temp); - } - if (!LYIsHtmlSep(*leaf)) - LYAddHtmlSep(target); - StrAllocCat(*target, leaf); -} - -/* - * Open a temporary file for internal-pages, optionally reusing an existing - * filename. - */ -FILE *InternalPageFP(char *filename, - int reuse_flag) -{ - FILE *fp; - - if (LYReuseTempfiles && reuse_flag) { - fp = LYOpenTempRewrite(filename, HTML_SUFFIX, BIN_W); - } else { - LYRemoveTemp(filename); - fp = LYOpenTemp(filename, HTML_SUFFIX, BIN_W); - } - if (fp == NULL) { - HTAlert(CANNOT_OPEN_TEMP); - } - return fp; -} - -/* - * This part is shared by all internal pages. - */ -void WriteInternalTitle(FILE *fp0, const char *Title) -{ - fprintf(fp0, - "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"); - - fprintf(fp0, "<html>\n<head>\n"); - LYAddMETAcharsetToFD(fp0, -1); - if (LYIsListpageTitle(Title)) { - if (strchr(HTLoadedDocumentURL(), '"') == NULL) { - char *Address = NULL; - - /* - * Insert a BASE tag so there is some way to relate the List Page - * file to its underlying document after we are done. It won't be - * actually used for resolving relative URLs. - kw - */ - StrAllocCopy(Address, HTLoadedDocumentURL()); - LYEntify(&Address, FALSE); - fprintf(fp0, "<base href=\"%s\">\n", Address); - FREE(Address); - } - } - fprintf(fp0, "<title>%s</title>\n</head>\n<body>\n", Title); -} - -/* - * This is used to start most internal pages, except for special cases where - * the embedded HREF's in the title differ. - */ -void BeginInternalPage(FILE *fp0, const char *Title, - const char *HelpURL) -{ - WriteInternalTitle(fp0, Title); - - if ((user_mode == NOVICE_MODE) - && LYwouldPush(Title, NULL) - && (HelpURL != 0)) { - fprintf(fp0, "<h1>%s (%s%s%s), <a href=\"%s%s\">help</a></h1>\n", - Title, LYNX_NAME, VERSION_SEGMENT, LYNX_VERSION, - helpfilepath, HelpURL); - } else { - fprintf(fp0, "<h1>%s (%s%s%s)</h1>\n", - Title, LYNX_NAME, VERSION_SEGMENT, LYNX_VERSION); - } -} - -void EndInternalPage(FILE *fp0) -{ - fprintf(fp0, "</body>\n</html>"); -} - -char *trimPoundSelector(char *address) -{ - char *pound = findPoundSelector(address); - - if (pound != 0) - *pound = '\0'; - return pound; -} - -/* - * Trim a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to local filesystems. - */ -void LYTrimPathSep(char *path) -{ - size_t len; - - if (path != 0 - && (len = strlen(path)) != 0 - && LYIsPathSep(path[len - 1])) - path[len - 1] = 0; -} - -/* - * Add a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to local filesystems. - */ -void LYAddPathSep(char **path) -{ - size_t len; - char *temp; - - if ((path != 0) - && ((temp = *path) != 0) - && (len = strlen(temp)) != 0 - && !LYIsPathSep(temp[len - 1])) { - StrAllocCat(*path, PATHSEP_STR); - } -} - -/* - * Add a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to local filesystems. - */ -void LYAddPathSep0(char *path) -{ - size_t len; - - if ((path != 0) - && (len = strlen(path)) != 0 - && (len < LY_MAXPATH - 2) - && !LYIsPathSep(path[len - 1])) { - strcat(path, PATHSEP_STR); - } -} - -/* - * Check if a given string contains a path separator - */ -char *LYLastPathSep(const char *path) -{ - char *result; - -#if defined(USE_DOS_DRIVES) - if ((result = strrchr(path, '\\')) == 0) - result = strrchr(path, '/'); -#else - result = strrchr(path, '/'); -#endif - return result; -} - -/* - * Trim a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to HTML paths. - */ -void LYTrimHtmlSep(char *path) -{ - size_t len; - - if (path != 0 - && (len = strlen(path)) != 0 - && LYIsHtmlSep(path[len - 1])) - path[len - 1] = 0; -} - -/* - * Add a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to HTML paths. - */ -void LYAddHtmlSep(char **path) -{ - size_t len; - char *temp; - - if ((path != 0) - && ((temp = *path) != 0) - && (len = strlen(temp)) != 0 - && !LYIsHtmlSep(temp[len - 1])) { - StrAllocCat(*path, "/"); - } -} - -/* - * Add a trailing path-separator to avoid confusing other programs when we concatenate - * to it. This only applies to HTML paths. - */ -void LYAddHtmlSep0(char *path) -{ - size_t len; - - if ((path != 0) - && (len = strlen(path)) != 0 - && (len < LY_MAXPATH - 2) - && !LYIsHtmlSep(path[len - 1])) { - strcat(path, "/"); - } -} - -/* - * Copy a file - */ -int LYCopyFile(char *src, - char *dst) -{ - int code; - const char *program; - - if ((program = HTGetProgramPath(ppCOPY)) != NULL) { - char *the_command = 0; - - HTAddParam(&the_command, COPY_COMMAND, 1, program); - HTAddParam(&the_command, COPY_COMMAND, 2, src); - HTAddParam(&the_command, COPY_COMMAND, 3, dst); - HTEndParam(&the_command, COPY_COMMAND, 3); - - CTRACE((tfp, "command: %s\n", the_command)); - stop_curses(); - code = LYSystem(the_command); - start_curses(); - - FREE(the_command); - } else { - FILE *fin, *fout; - unsigned char buff[BUFSIZ]; - size_t len; - - code = EOF; - if ((fin = fopen(src, BIN_R)) != 0) { - if ((fout = fopen(dst, BIN_W)) != 0) { - code = 0; - while ((len = fread(buff, (size_t) 1, sizeof(buff), fin)) != 0) { - if (fwrite(buff, (size_t) 1, len, fout) < len - || ferror(fout)) { - code = EOF; - break; - } - } - LYCloseOutput(fout); - } - LYCloseInput(fin); - } - CTRACE((tfp, "builtin copy ->%d\n\tsource=%s\n\ttarget=%s\n", - code, src, dst)); - } - - if (code) { - HTAlert(CANNOT_WRITE_TO_FILE); - } - return code; -} - -#ifdef __DJGPP__ -static char *escape_backslashes(char *source) -{ - char *result = 0; - int count = 0; - int n; - - for (n = 0; source[n] != '\0'; ++n) { - if (source[n] == '\\') - ++count; - } - if (count != 0) { - result = malloc(count + n + 1); - if (result != 0) { - int ch; - char *target = result; - - while ((ch = *source++) != '\0') { - if (ch == '\\') - *target++ = ch; - *target++ = ch; - } - *target = '\0'; - } - } - return result; -} -#endif /* __DJGPP__ */ -/* - * Invoke a shell command, return nonzero on error. - */ -int LYSystem(char *command) -{ - int code; - int do_free = 0; - -#if defined(HAVE_SIGACTION) && defined(SIGTSTP) && !defined(USE_SLANG) - struct sigaction saved_sigtstp_act; - BOOLEAN sigtstp_saved = FALSE; -#endif - int saved_errno = 0; - -#ifdef __EMX__ - int scrsize[4]; -#endif - - fflush(stdout); - fflush(stderr); - CTRACE((tfp, "LYSystem(%s)\n", command)); - CTRACE_FLUSH(tfp); - -#ifdef __DJGPP__ - __djgpp_set_ctrl_c(0); - _go32_want_ctrl_break(1); -#endif /* __DJGPP__ */ - -#ifdef VMS - code = DCLsystem(command); -#else -# ifdef __EMX__ /* FIXME: Should be LY_CONVERT_SLASH? */ - /* Configure writes commands which contain direct slashes. - Native command-(non)-shell will not tolerate this. */ - { - char *space = command, *slash = command; - - _scrsize(scrsize); - while (*space && *space != ' ' && *space != '\t') - space++; - while (slash < space && *slash != '/') - slash++; - if (slash != space) { - char *old = command; - - command = NULL; - StrAllocCopy(command, old); - do_free = 1; - slash = (slash - old) + command - 1; - space = (space - old) + command; - while (++slash < space) - if (*slash == '/') - *slash = '\\'; - } - } -# endif - - /* - * This chunk of code does not work, for two reasons: - * a) the Cygwin system() function edits out the backslashes - * b) it does not account for more than one parameter, e.g., +number - */ -#if defined(__CYGWIN__) && defined(DOSPATH) /* 1999/02/26 (Fri) */ - { - char cmd[LY_MAXPATH]; - char win32_name[LY_MAXPATH]; - char new_cmd[LY_MAXPATH]; - char new_command[LY_MAXPATH * 2 + 10]; - char *p, *q; - - p = command; - q = cmd; - while (*p) { - if (*p == ' ') - break; - else - *q = *p; - p++; - q++; - } - *q = '\0'; - - if (cmd[0] == '/') - cygwin_conv_to_full_posix_path(cmd, new_cmd); - else - strcpy(new_cmd, cmd); - - while (*p == ' ') - p++; - - if (strchr(p, '\\') == NULL) { - /* for Windows Application */ - cygwin_conv_to_full_win32_path(p, win32_name); - sprintf(new_command, "%.*s \"%.*s\"", - LY_MAXPATH, new_cmd, LY_MAXPATH, win32_name); - } else { - /* for DOS like editor */ - q = win32_name; - while (*p) { - if (*p == '\\') { - if (*(p + 1) == '\\') - p++; - } - *q = *p; - q++, p++; - } - *q = '\0'; - sprintf(new_command, "%.*s %.*s", LY_MAXPATH, new_cmd, LY_MAXPATH, win32_name); - } - command = new_command; - } -#endif - -#ifdef __DJGPP__ - if (dj_is_bash) { - char *new_command = escape_backslashes(command); - - if (new_command != 0) { - if (do_free) - free(command); - command = new_command; - } - } -#endif /* __DJGPP__ */ - -#ifdef _WIN_CC - code = exec_command(command, TRUE); /* Wait exec */ -#else /* !_WIN_CC */ -#ifdef SIGPIPE - if (restore_sigpipe_for_children) - signal(SIGPIPE, SIG_DFL); /* Some commands expect the default */ -#endif -#if defined(HAVE_SIGACTION) && defined(SIGTSTP) && !defined(USE_SLANG) - if (!dump_output_immediately && !LYCursesON && !no_suspend) - sigtstp_saved = LYToggleSigDfl(SIGTSTP, &saved_sigtstp_act, 1); -#endif - code = system(command); - saved_errno = errno; -#if defined(HAVE_SIGACTION) && defined(SIGTSTP) && !defined(USE_SLANG) - if (sigtstp_saved) - LYToggleSigDfl(SIGTSTP, &saved_sigtstp_act, 0); -#endif -#ifdef SIGPIPE - if (restore_sigpipe_for_children) - signal(SIGPIPE, SIG_IGN); /* Ignore it again - kw */ -#endif -#endif -#endif - -#ifdef __DJGPP__ - __djgpp_set_ctrl_c(1); - _go32_want_ctrl_break(0); -#endif /* __DJGPP__ */ - - fflush(stdout); - fflush(stderr); - - if (do_free) - FREE(command); -#if !defined(UCX) || !defined(VAXC) /* errno not modifiable ?? */ - set_errno(saved_errno); /* may have been clobbered */ -#endif -#ifdef __EMX__ /* Check whether the screen size changed */ - size_change(0); -#endif - return code; -} - -/* - * Return a string which can be used in LYSystem() for spawning a subshell - */ -#if defined(__CYGWIN__) /* 1999/02/26 (Fri) */ -int Cygwin_Shell(void) -{ - char *shell; - int code; - STARTUPINFO startUpInfo; - PROCESS_INFORMATION procInfo; - SECURITY_ATTRIBUTES sa; - - /* Set up security attributes to allow inheritance of the file handle */ - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - /* Init a startup structure */ - GetStartupInfo(&startUpInfo); - - shell = LYGetEnv("COMSPEC"); - - /* Create the child process, specifying - inherited handles. Pass the value of the - handle as a command line parameter */ - code = 0; - if (shell) { - code = CreateProcess(0, shell, 0, 0, - TRUE, 0, - 0, 0, &startUpInfo, &procInfo); - - if (!code) { - printf("shell = [%s], code = %ld\n", shell, GetLastError()); - } - - /* wait for the child to return (this is not a requirement - since the child is its own independent process) */ - WaitForSingleObject(procInfo.hProcess, INFINITE); - } - - return code; -} -#endif - -#ifdef WIN_EX -/* - * Quote the path to make it safe for shell command processing. - * We always quote it not only includes spaces in it. - * At least we should quote paths which include "&". - */ -char *quote_pathname(char *pathname) -{ - char *result = NULL; - - HTSprintf0(&result, "\"%s\"", pathname); - return result; -} -#endif - -const char *LYSysShell(void) -{ - const char *shell = 0; - -#ifdef DOSPATH -#ifdef WIN_EX - shell = LYGetEnv("SHELL"); - if (shell) { - if (access(shell, 0) != 0) - shell = LYGetEnv("COMSPEC"); - } else { - shell = LYGetEnv("COMSPEC"); - } - if (shell == NULL) { - if (system_is_NT) - shell = "cmd.exe"; - else - shell = "command.com"; - } -#else - shell = LYGetEnv("SHELL"); - if (shell == NULL) { - shell = LYGetEnv("COMSPEC"); - } - if (shell == NULL) { - shell = "command.com"; - } -#endif /* WIN_EX */ -#else -#ifdef __EMX__ - if (LYGetEnv("SHELL") != NULL) { - shell = LYGetEnv("SHELL"); - } else { - shell = (LYGetEnv("COMSPEC") == NULL) ? "cmd.exe" : LYGetEnv("COMSPEC"); - } -#else -#ifdef VMS - shell = ""; -#else - shell = "exec $SHELL"; -#endif /* __EMX__ */ -#endif /* VMS */ -#endif /* DOSPATH */ - return shell; -} - -#ifdef VMS -#define DISPLAY "DECW$DISPLAY" -#else -#define DISPLAY "DISPLAY" -#endif /* VMS */ - -/* - * Return the X-Window $DISPLAY string if it is nonnull/nonempty - */ -char *LYgetXDisplay(void) -{ - return LYGetEnv(DISPLAY); -} - -/* - * Set the value of the X-Window $DISPLAY variable (yes it leaks memory, but - * that is putenv's fault). - */ -void LYsetXDisplay(char *new_display) -{ - if (new_display != 0) { -#ifdef VMS - LYUpperCase(new_display); - Define_VMSLogical(DISPLAY, new_display); -#else - static char *display_putenv_command; - - HTSprintf0(&display_putenv_command, "DISPLAY=%s", new_display); - putenv(display_putenv_command); -#endif /* VMS */ - if ((new_display = LYgetXDisplay()) != 0) { - StrAllocCopy(x_display, new_display); - } - } -} - -#ifdef CAN_CUT_AND_PASTE -#ifdef __EMX__ - -static int proc_type = -1; -static PPIB pib; -static HAB hab; -static HMQ hmq; - -static void morph_PM(void) -{ - PTIB tib; - int first = 0; - - if (proc_type == -1) { - DosGetInfoBlocks(&tib, &pib); - proc_type = pib->pib_ultype; - first = 1; - } - if (pib->pib_ultype != 3) /* 2 is VIO */ - pib->pib_ultype = 3; /* 3 is PM */ - if (first) - hab = WinInitialize(0); - /* 64 messages if before OS/2 3.0, ignored otherwise */ - hmq = WinCreateMsgQueue(hab, 64); - WinCancelShutdown(hmq, 1); /* Do not inform us on shutdown */ -} - -static void unmorph_PM(void) -{ - WinDestroyMsgQueue(hmq); - pib->pib_ultype = proc_type; -} - -int size_clip(void) -{ - return 8192; -} - -/* Code partially stolen from FED editor. */ - -int put_clip(const char *s) -{ - int sz = strlen(s) + 1; - int ret = EOF, nl = 0; - char *pByte = 0, *s1 = s, c, *t; - - while ((c = *s1++)) { - if (c == '\r' && *s1 == '\n') - s1++; - else if (c == '\n') - nl++; - } - if (DosAllocSharedMem((PPVOID) & pByte, 0, sz + nl, - PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE | OBJ_GETTABLE)) - return ret; - - if (!nl) - memcpy(pByte, s, sz); - else { - t = pByte; - while ((c = *t++ = *s++)) - if (c == '\n' && (t == pByte + 1 || t[-2] != '\r')) - t[-1] = '\r', *t++ = '\n'; - } - - morph_PM(); - if (!hab) - goto fail; - - WinOpenClipbrd(hab); - WinEmptyClipbrd(hab); - if (WinSetClipbrdData(hab, (ULONG) pByte, CF_TEXT, CFI_POINTER)) - ret = 0; - WinCloseClipbrd(hab); - unmorph_PM(); - if (ret == 0) - return 0; - fail: - DosFreeMem((PPVOID) & pByte); - return EOF; -} - -static int clip_open; - -/* get_clip_grab() returns a pointer to the string in the system area. - get_clip_release() should be called ASAP after this. */ - -char *get_clip_grab(void) -{ - char *ClipData; - ULONG ulFormat; - int sz; - - morph_PM(); - if (!hab) - return 0; - if (clip_open) - get_clip_release(); - - WinQueryClipbrdFmtInfo(hab, CF_TEXT, &ulFormat); - if (ulFormat != CFI_POINTER) { - unmorph_PM(); - return 0; - } - WinOpenClipbrd(hab); - clip_open = 1; - ClipData = (char *) WinQueryClipbrdData(hab, CF_TEXT); - sz = strlen(ClipData); - if (!ClipData || !sz) { - get_clip_release(); - return 0; - } - return ClipData; -} - -void get_clip_release(void) -{ - if (!clip_open) - return; - WinCloseClipbrd(hab); - clip_open = 0; - unmorph_PM(); -} - -#else /* !( defined __EMX__ ) */ - -# if !defined(WIN_EX) && defined(HAVE_POPEN) - -static FILE *paste_handle = 0; -static char *paste_buf = NULL; - -void get_clip_release(void) -{ - if (paste_handle != 0) - pclose(paste_handle); - if (paste_buf) - FREE(paste_buf); -} - -static int clip_grab(void) -{ - char *cmd = LYGetEnv("RL_PASTE_CMD"); - - if (paste_handle) - pclose(paste_handle); - if (!cmd) - return 0; - - paste_handle = popen(cmd, TXT_R); - if (!paste_handle) - return 0; - return 1; -} - -#define PASTE_BUFFER 1008 -#define CF_TEXT 0 /* Not used */ - -char *get_clip_grab(void) -{ - int len; - unsigned size = PASTE_BUFFER; - int off = 0; - - if (!clip_grab()) - return NULL; - if (!paste_handle) - return NULL; - if (paste_buf) - FREE(paste_buf); - paste_buf = typeMallocn(char, PASTE_BUFFER); - - while (1) { - len = (int) fread(paste_buf + off, - (size_t) 1, - (size_t) PASTE_BUFFER - 1, - paste_handle); - paste_buf[off + len] = '\0'; - if (len < PASTE_BUFFER - 1) - break; - if (strchr(paste_buf + off, '\r') - || strchr(paste_buf + off, '\n')) - break; - paste_buf = typeRealloc(char, paste_buf, size += PASTE_BUFFER - 1); - - off += len; - } - return paste_buf; -} - -int put_clip(const char *s) -{ - char *cmd = LYGetEnv("RL_CLCOPY_CMD"); - FILE *fh; - size_t l = strlen(s), res; - - if (!cmd) - return -1; - - fh = popen(cmd, TXT_W); - if (!fh) - return -1; - res = fwrite(s, (size_t) 1, l, fh); - if (pclose(fh) != 0 || res != l) - return -1; - return 0; -} - -# endif /* !defined(WIN_EX) && defined(HAVE_POPEN) */ - -#endif /* __EMX__ */ - -/* - * Sleep for a number of milli-sec. - */ -void LYmsec_delay(unsigned msec) -{ -#if defined(_WINDOWS) - Sleep(msec); - -#elif defined(HAVE_NAPMS) - napms((int) msec); - -#elif defined(DJGPP) || defined(HAVE_USLEEP) - usleep(1000 * msec); - -#else - struct timeval tv; - unsigned long usec = 1000UL * msec; - - tv.tv_sec = usec / 1000000UL; - tv.tv_usec = usec % 1000000UL; - select(0, NULL, NULL, NULL, &tv); -#endif -} - -#if defined(WIN_EX) /* 1997/10/16 (Thu) 20:13:28 */ - -int put_clip(const char *szBuffer) -{ - HANDLE hWnd; - HANDLE m_hLogData; - LPTSTR pLogData; - HANDLE hClip; - int len; - - if (szBuffer == NULL) - return EOF; - - len = strlen(szBuffer); - if (len == 0) - return EOF; - else - len++; - - m_hLogData = GlobalAlloc(GHND, len); - if (m_hLogData == NULL) { - return EOF; - } - - hWnd = NULL; - if (!OpenClipboard(hWnd)) { - return EOF; - } - /* Remove the current Clipboard contents */ - if (!EmptyClipboard()) { - GlobalFree(m_hLogData); - return EOF; - } - - /* Lock the global memory while we write to it. */ - pLogData = (LPTSTR) GlobalLock(m_hLogData); - - lstrcpy((LPTSTR) pLogData, szBuffer); - GlobalUnlock(m_hLogData); - - /* If there were any lines at all then copy them to clipboard. */ - hClip = SetClipboardData(CF_TEXT, m_hLogData); - if (!hClip) { - /* If we couldn't clip the data then free the global handle. */ - GlobalFree(m_hLogData); - } - - CloseClipboard(); - return 0; -} - -static HANDLE m_hLogData; -static int m_locked; - -/* get_clip_grab() returns a pointer to the string in the system area. - get_clip_release() should be called ASAP after this. */ - -char *get_clip_grab() -{ - HANDLE hWnd; - LPTSTR pLogData; - - hWnd = NULL; - if (!OpenClipboard(hWnd)) { - return 0; - } - - m_hLogData = GetClipboardData(CF_TEXT); - - if (m_hLogData == NULL) { - CloseClipboard(); - m_locked = 0; - return 0; - } - pLogData = (LPTSTR) GlobalLock(m_hLogData); - - m_locked = 1; - return pLogData; -} - -void get_clip_release() -{ - if (!m_locked) - return; - GlobalUnlock(m_hLogData); - CloseClipboard(); - m_locked = 0; -} -#endif /* WIN_EX */ -#endif /* CAN_CUT_AND_PASTE */ - -#if defined(WIN_EX) - -#ifndef WSABASEERR -#define WSABASEERR 10000 -#endif - -#ifdef ENABLE_IPV6 -#define WSOCK_NAME "ws2_32" -#else -#define WSOCK_NAME "wsock32" -#endif - -/* - * Description: the windows32 version of perror() - * - * Returns: a pointer to a static error - * - * Notes/Dependencies: I got this from - * comp.os.ms-windows.programmer.win32 - */ -char *w32_strerror(DWORD ercode) -{ -/* __declspec(thread) necessary if you will use multiple threads */ -#ifdef __CYGWIN__ - static char msg_buff[256]; - -#else - __declspec(thread) static char msg_buff[256]; -#endif - HMODULE hModule; - int i, msg_type; - unsigned char *p, *q, tmp_buff[256]; - DWORD rc; - - hModule = NULL; - msg_type = FORMAT_MESSAGE_FROM_SYSTEM; - /* Fill message buffer with a default message in - * case FormatMessage fails - */ - wsprintf(msg_buff, "Error %ld", ercode); - - /* - * Special code for winsock error handling. - */ - if (ercode > WSABASEERR) { - hModule = GetModuleHandle(WSOCK_NAME); - if (hModule) - msg_type = FORMAT_MESSAGE_FROM_HMODULE; - } - /* - * message handling. If not found in module, retry from system. - */ - rc = FormatMessage(msg_type, hModule, ercode, LANG_NEUTRAL, - msg_buff, sizeof(msg_buff), NULL); - - if (rc == 0 && msg_type == FORMAT_MESSAGE_FROM_HMODULE) { - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ercode, - LANG_NEUTRAL, msg_buff, sizeof(msg_buff), NULL); - } - - strcpy((char *) tmp_buff, msg_buff); - p = q = tmp_buff; - i = 0; - while (*p) { - if (!(*p == '\n' || *p == '\r')) - msg_buff[i++] = *p; - p++; - } - msg_buff[i] = '\0'; - - return msg_buff; -} - -#endif - -#if defined(SYSLOG_REQUESTED_URLS) -/* - * syslog() interface - */ -void LYOpenlog(const char *banner) -{ - if (syslog_requested_urls) { - CTRACE((tfp, "LYOpenlog(%s)\n", NONNULL(banner))); -#if defined(DJGPP) - openlog("lynx", LOG_PID | LOG_NDELAY, LOG_LOCAL5); -#else - openlog("lynx", LOG_PID, LOG_LOCAL5); -#endif - - if (banner) { - syslog(LOG_INFO, "Session start:%s", banner); - } else { - syslog(LOG_INFO, "Session start"); - } - } -} - -static BOOLEAN looks_like_password(char *first, - char *last) -{ - BOOLEAN result = FALSE; - - while (first <= last) { - if (*first == '/' - || *first == ':') { - result = FALSE; - break; - } - result = TRUE; - first++; - } - return result; -} - -void LYSyslog(char *arg) -{ - char *colon1; - char *colon2; - char *atsign; - - if (syslog_requested_urls) { - - CTRACE((tfp, "LYSyslog %s\n", arg)); - - if (is_url(arg)) { /* proto://user:password@host/path:port */ - /* ^this colon */ - if ((colon1 = strchr(arg, ':')) != 0 - && !StrNCmp(colon1, "://", 3) - && (colon2 = strchr(colon1 + 3, ':')) != 0 - && (atsign = strchr(colon1, '@')) != 0 - && (colon2 < atsign) - && looks_like_password(colon2 + 1, atsign - 1)) { - char *buf = NULL; - - StrAllocCopy(buf, arg); - buf[colon2 - arg + 1] = 0; - StrAllocCat(buf, "******"); - StrAllocCat(buf, atsign); - syslog(LOG_INFO | LOG_LOCAL5, "%s", buf); - CTRACE((tfp, "...alter %s\n", buf)); - FREE(buf); - return; - } - } - syslog(LOG_INFO | LOG_LOCAL5, "%s", NONNULL(arg)); - } -} - -void LYCloselog(void) -{ - if (syslog_requested_urls) { - syslog(LOG_INFO, "Session over"); - closelog(); - } -} - -#endif /* SYSLOG_REQUESTED_URLS */ - -#if defined(WIN_EX) || defined(__CYGWIN__) /* 2000/03/07 (Tue) 17:17:46 */ - -#define IS_SEP(p) ((p == '\\') || (p == '/') || (p == ':')) - -static char *black_list[] = -{ - "con", - "prn", - "clock$", - "config$", - NULL -}; - -static int is_device(char *fname) -{ - HANDLE fileHandle; - DWORD val; - int i; - - i = 0; - while (black_list[i] != NULL) { - if (stricmp(fname, black_list[i]) == 0) { - return 1; /* device file */ - } - i++; - } - - fileHandle = CreateFile(fname, 0, 0, 0, OPEN_EXISTING, 0, 0); - - if (fileHandle == INVALID_HANDLE_VALUE) { - return 0; /* normal file */ - } else { - val = GetFileType(fileHandle); - switch (val) { - case 1: - val = 0; - break; - case 2: - val = 1; /* device file */ - break; - default: - val = 0; - break; - } - - CloseHandle(fileHandle); - } - return val; -} - -static char *device_list[] = -{ - "con", - "nul", - "aux", - "prn", - NULL -}; - -#define IS_SJIS_HI1(hi) ((0x81<=hi)&&(hi<=0x9F)) /* 1st lev. */ -#define IS_SJIS_HI2(hi) ((0xE0<=hi)&&(hi<=0xEF)) /* 2nd lev. */ - -int unsafe_filename(const char *fname) -{ - int i, len, sum; - unsigned char *cp; - char *save; - - i = 0; - while (device_list[i] != NULL) { - if (stricmp(fname, device_list[i]) == 0) { - return 0; /* device file (open OK) */ - } - i++; - } - - save = cp = strdup(fname); - - while (*cp) { - if (IS_SJIS_HI1(*cp) || IS_SJIS_HI2(*cp)) - cp += 2; /* KANJI skip */ - if (IS_SEP(*cp)) { - *cp = '\0'; - } - cp++; - } - - sum = 0; - cp = save; - len = strlen(fname); - while (cp < (save + len)) { - if (*cp == '\0') { - cp++; - } else { - char *q; - - q = strchr(cp, '.'); - if (q) - *q = '\0'; - if (is_device(cp)) { - sum++; - break; - } - if (q) - cp = q + 1; - while (*cp) - cp++; - } - } - free(save); - - if (sum != 0) - return 1; - else - return 0; -} - -FILE *safe_fopen(const char *fname, const char *mode) -{ - if (unsafe_filename(fname)) { - return (FILE *) NULL; - } else { - return fopen(fname, mode); - } -} - -#endif /* defined(WIN_EX) || defined(__CYGWIN__) */ |