/* * $LynxId: LYUtils.c,v 1.274 2015/03/22 15:38:23 tom Exp $ */ #include #include #include #include #include #include #if defined(__MINGW32__) extern int kbhit(void); /* FIXME: use conio.h */ #undef UNIX #elif defined(_WINDOWS) #ifdef DONT_USE_GETTEXT #undef gettext #elif defined(HAVE_GETTEXT) #undef gettext #define gettext conio_gettext #else #undef gettext #endif #include #ifdef DONT_USE_GETTEXT #define gettext(s) s #elif defined(HAVE_GETTEXT) #undef gettext #ifdef _INTL_REDIRECT_MACROS #define gettext libintl_gettext /* restore definition from libintl.h */ #endif #else #undef gettext #define gettext(s) s #endif #if !defined(kbhit) && defined(_WCONIO_DEFINED) #define kbhit() _kbhit() /* reasonably recent conio.h */ #endif #elif defined(__minix) #include /* for struct winsize */ #endif /* __MINGW32__ */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __DJGPP__ #include #include #endif /* __DJGPP__ */ #ifndef NO_GROUPS #include #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 #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 # undef BOOLEAN #endif #ifdef VMS #include #include #include #endif /* VMS */ #ifdef HAVE_UTMP #include #ifdef UTMPX_FOR_UTMP #include #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 #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 #include #endif #include #ifdef USE_COLOR_STYLE #include #include #include #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; } static char *w32_get_shell_folder(const char *name) { static HKEY rootkey = HKEY_CURRENT_USER; char *result = 0; HKEY hkey; char buffer[LY_MAXPATH]; if (RegOpenKeyEx(rootkey, W32_STRING("Software" "\\Microsoft" "\\Windows" "\\CurrentVersion" "\\Explorer" "\\Shell Folders"), 0, KEY_READ, &hkey) == ERROR_SUCCESS) { if (w32_get_reg_sz(hkey, name, buffer, sizeof(buffer)) == ERROR_SUCCESS) { result = strdup(buffer); (void) RegCloseKey(hkey); } (void) RegCloseKey(hkey); } return non_empty(result) ? result : 0; } #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(ro
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 022div.cc</title>
<meta name="Generator" content="Vim/8.1">
<meta name="plugin-version" content="vim8.1_v1">
<meta name="syntax" content="cpp">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.LineNr { }
.SpecialChar { color: #d70000; }
.Comment { color: #005faf; }
.Delimiter { color: #c000c0; }
.Identifier { color: #af5f00; }
.Constant { color: #008787; }
.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  var lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/022div.cc'>https://github.com/akkartik/mu/blob/master/022div.cc</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="Comment">//: helper for division operations: sign-extend EAX into EDX</span>
<span id="L2" class="LineNr"> 2 </span>
<span id="L3" class="LineNr"> 3 </span><span class="Delimiter">:(before &quot;End Initialize Op Names&quot;)</span>
<span id="L4" class="LineNr"> 4 </span><a href='001help.cc.html#L235'>put_new</a><span class="Delimiter">(</span><span class="SpecialChar"><a href='010vm.cc.html#L355'>Name</a></span><span class="Delimiter">,</span> <span class="Constant">&quot;99&quot;</span><span class="Delimiter">,</span> <span class="Constant">&quot;sign-extend <a href='010vm.cc.html#L10'>EAX</a> into <a href='010vm.cc.html#L12'>EDX</a> (cdq)&quot;</span><span class="Delimiter">);</span>
<span id="L5" class="LineNr"> 5 </span>
<span id="L6" class="LineNr"> 6 </span><span class="Delimiter">:(code)</span>
<span id="L7" class="LineNr"> 7 </span><span class="Normal">void</span> <a href='022div.cc.html#L7'>test_cdq</a><span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span id="L8" class="LineNr"> 8 </span>  <span class="SpecialChar"><a href='010vm.cc.html#L25'>Reg</a></span>[EAX]<span class="Delimiter">.</span>i = <span class="Constant">10</span><span class="Delimiter">;</span>
<span id="L9" class="LineNr"> 9 </span>  <a href='011run.cc.html#L82'>run</a><span class="Delimiter">(</span>
<span id="L10" class="LineNr">10 </span>      <span class="Constant">&quot;== code 0x1\n&quot;</span>
<span id="L11" class="LineNr">11 </span>      <span class="Constant">&quot;99\n&quot;</span>
<span id="L12" class="LineNr">12 </span>  <span class="Delimiter">);</span>
<span id="L13" class="LineNr">13 </span>  <a href='003trace.cc.html#L290'>CHECK_TRACE_CONTENTS</a><span class="Delimiter">(</span>
<span id="L14" class="LineNr">14 </span>      <span class="Constant">&quot;run: sign-extend <a href='010vm.cc.html#L10'>EAX</a> into EDX\n&quot;</span>
<span id="L15" class="LineNr">15 </span>      <span class="Constant">&quot;run: <a href='010vm.cc.html#L12'>EDX</a> is now 0x00000000\n&quot;</span>
<span id="L16" class="LineNr">16 </span>  <span class="Delimiter">);</span>
<span id="L17" class="LineNr">17 </span><span class="Delimiter">}</span>
<span id="L18" class="LineNr">18 </span>
<span id="L19" class="LineNr">19 </span><span class="Delimiter">:(before &quot;End Single-Byte Opcodes&quot;)</span>
<span id="L20" class="LineNr">20 </span><span class="Normal">case</span> <span class="Constant">0x99</span>: <span class="Delimiter">{</span>  <span class="Comment">// sign-extend EAX into EDX</span>
<span id="L21" class="LineNr">21 </span>  <a href='003trace.cc.html#L96'>trace</a><span class="Delimiter">(</span><span class="SpecialChar">Callstack_depth</span>+<span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;sign-extend <a href='010vm.cc.html#L10'>EAX</a> into EDX&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
<span id="L22" class="LineNr">22 </span>  <span class="SpecialChar"><a href='010vm.cc.html#L25'>Reg</a></span>[EDX]<span class="Delimiter">.</span>i = <span class="Delimiter">(</span><span class="SpecialChar"><a href='010vm.cc.html#L25'>Reg</a></span>[EAX]<span class="Delimiter">.</span>i &lt; <span class="Constant">0</span><span class="Delimiter">)</span> ? -<span class="Constant">1</span> : <span class="Constant">0</span><span class="Delimiter">;</span>
<span id="L23" class="LineNr">23 </span>  <a href='003trace.cc.html#L96'>trace</a><span class="Delimiter">(</span><span class="SpecialChar">Callstack_depth</span>+<span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;EDX is now 0x&quot;</span> &lt;&lt; <a href='010vm.cc.html#L408'>HEXWORD</a> &lt;&lt; <span class="SpecialChar"><a href='010vm.cc.html#L25'>Reg</a></span>[EDX]<span class="Delimiter">.</span>u &lt;&lt; end<span class="Delimiter">();</span>
<span id="L24" class="LineNr">24 </span>  <span class="Identifier">break</span><span class="Delimiter">;</span>
<span id="L25" class="LineNr">25 </span><span class="Delimiter">}</span>
<span id="L26" class="LineNr">26 </span>
<span id="L27" class="LineNr">27 </span><span class="Delimiter">:(code)</span>
<span id="L28" class="LineNr">28 </span><span class="Normal">void</span> <a href='022div.cc.html#L28'>test_cdq_negative</a><span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span id="L29" class="LineNr">29 </span>  <span class="SpecialChar"><a href='010vm.cc.html#L25'>Reg</a></span>[EAX]<span class="Delimiter">.</span>i = -<span class="Constant">10</span><span class="Delimiter">;</span>
<span id="L30" class="LineNr">30 </span>  <a href='011run.cc.html#L82'>run</a><span class="Delimiter">(</span>
<span id="L31" class="LineNr">31 </span>      <span class="Constant">&quot;== code 0x1\n&quot;</span>
<span id="L32" class="LineNr">32 </span>      <span class="Constant">&quot;99\n&quot;</span>
<span id="L33" class="LineNr">33 </span>  <span class="Delimiter">);</span>
<span id="L34" class="LineNr">34 </span>  <a href='003trace.cc.html#L290'>CHECK_TRACE_CONTENTS</a><span class="Delimiter">(</span>
<span id="L35" class="LineNr">35 </span>      <span class="Constant">&quot;run: sign-extend <a href='010vm.cc.html#L10'>EAX</a> into EDX\n&quot;</span>
<span id="L36" class="LineNr">36 </span>      <span class="Constant">&quot;run: <a href='010vm.cc.html#L12'>EDX</a> is now 0xffffffff\n&quot;</span>
<span id="L37" class="LineNr">37 </span>  <span class="Delimiter">);</span>
<span id="L38" class="LineNr">38 </span><span class="Delimiter">}</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
* 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) { BOOLEAN result = FALSE; if (LYCloseOutput(fopen(filename, "w"))) { if (remove(filename) == 0) { result = TRUE; } } else { _statusline(NEW_FILENAME_PROMPT); } return result; } /* * Test if we'll be able to read a file. */ BOOLEAN LYCanReadFile(const char *filename) { FILE *fp; BOOLEAN result = FALSE; if (non_empty(filename)) { if ((fp = fopen(filename, "r")) != 0) { result = LYCloseInput(fp); } } return result; } char *LYFindConfigFile(const char *nominal, const char *dftfile) { char *result = 0; char *path = 0; char *head = 0; char *leaf; char *item; if (non_empty(nominal)) { StrAllocCopy(result, nominal); /* * Look for it in as-is - first expanding any tilde. */ LYTildeExpand(&result, TRUE); if (!LYCanReadFile(result)) { const char *cfg_path; char *list = 0; BOOLEAN found = FALSE; /* * Now try in the config-path. */ if ((cfg_path = LYGetEnv("LYNX_CFG_PATH")) == NULL) cfg_path = LYNX_CFG_PATH; StrAllocCopy(list, cfg_path); path = list; while ((item = LYstrsep(&path, PATH_SEPARATOR)) != 0) { if (isEmpty(item)) continue; FREE(result); HTSprintf0(&result, "%s%s%s", item, FILE_SEPARATOR, nominal); LYTildeExpand(&result, TRUE); if (LYCanReadFile(result)) { found = TRUE; break; } } FREE(list); if (!found) { /* * If not found, try finding it in the same directory as the * compiled-in location of the default file. */ StrAllocCopy(head, dftfile); if (strcmp(nominal, dftfile) && (leaf = LYPathLeaf(head)) != head) { head[leaf - head] = '\0'; StrAllocCopy(result, head); StrAllocCat(result, nominal); if (!LYCanReadFile(result)) { FREE(result); } } #ifdef USE_PROGRAM_DIR else { /* * Finally, try in the same directory as the executable. */ StrAllocCopy(result, program_dir); LYAddPathSep(&result); StrAllocCat(result, nominal); LYTildeExpand(&result, TRUE); if (!LYCanReadFile(result)) { FREE(result); } } #endif } } } FREE(head); return result; } /* * 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; 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 #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 # else # ifdef HAVE_TERMIOS_H # include # else # ifdef HAVE_TERMIO_H # include # 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))) { if ((cp = strrchr(fname, '.')) != 0) { 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 *) NULL) + (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_KEY; break; case '3': number = PGDOWN_KEY; break; case '4': number = LTARROW_KEY; break; case '5': number = DO_NOTHING; break; case '6': number = RTARROW_KEY; break; case '7': number = HOME_KEY; break; case '8': number = UPARROW_KEY; break; case '9': number = PGUP_KEY; 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 #include #include 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)) { char *his_home = NULL; StrAllocCopy(his_home, old_string); LYTildeExpand(&his_home, FALSE); StrAllocCat(*AllocatedString, his_home); FREE(his_home); 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; } #if (!defined(__MINGW32__) && !defined(sleep)) || (defined(__MINGW32__) && !defined(HAVE_SLEEP)) void sleep(unsigned sec) { unsigned int i, j; for (j = 0; j < sec; j++) { for (i = 0; i < 10; i++) { Sleep(100); if (kbhit()) { (void) LYgetch(); return; } } } } #endif /* !__MINGW32__ */ #endif /* _WINDOWS */ /* * 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); /* * 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 if (HTGetAddrInfo(host, 80) != NULL) #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 "