Пример #1
0
/*	Binary string comparison
**	------------------------
** On entry,
**	s	Points to one bstring
**	t	points to the other.
** On exit,
**	returns YES if the strings are equivalent
**		NO if they differ.
*/
PRIVATE BOOL HTBEquivalent ARGS2(
	CONST bstring *,	s,
	CONST bstring *,	t)
{
    if (s && t && BStrLen(s) == BStrLen(t)) {
	int j;
	int len = BStrLen(s);
	for (j = 0; j < len; ++j) {
	    if (!HT_EQUIV(BStrData(s)[j], BStrData(t)[j])) {
		return(NO);
	    }
	}
	return(YES);
    } else {
	return(s == t);		/* Two NULLs are equivalent, aren't they ? */
    }
}
Пример #2
0
// checked
uint8_t
XTDBLoadIndexes(XTDBHandle* h) {
    void* idxList = NULL;
    BinaryStr bStr,out;
    uint8_t rv;

    h->descDB = DBInit(STR(&h->descName),BDBOCREAT|BDBOWRITER);
    if (!h->descDB) {
        h->error = XTDB_NO_MEM;
        return False;
    }
    rv = DBOpen(h->descDB,BDBOCREAT|BDBOWRITER|BDBOTSYNC);
    if (!rv) {
        // XXX revisit
        h->error = DBGetLastError(h->descDB);
        if (h->error == XTDB_FILE_NOT_FOUND) {
            h->error = XTDB_DESC_NOT_FOUND;
        }
        return False;
    }

    StrToBStr(IDXFIELDNAME,&bStr);

    if (DBGetList(h->descDB,&bStr,&idxList)) {
        int idxLen = DBListLen(h->descDB,idxList);
        int i;
        for (i=0; i<idxLen; i++) {
            DBListVal(h->descDB,idxList,i,&out);
            char* idxName = BStrData(&out);
            //printf("IDX in descriptor %s\n",idxName);
            if (!XTDBAddIndex(h,idxName)) {
                return False;
            }
            assert(XTDBGetIndex(h,idxName));

        }
        DBListFree(h->descDB,idxList);
    }
    return True;
}
Пример #3
0
/*
 * LYShowInfo prints a page of info about the current file and the link that
 * the cursor is on.
 */
int LYShowInfo(DocInfo *doc,
	       DocInfo *newdoc,
	       char *owner_address)
{
    static char tempfile[LY_MAXPATH] = "\0";

    int url_type;
    FILE *fp0;
    char *Title = NULL;
    const char *cp;
    char *temp = NULL;
    char *buffer = NULL;

    BOOLEAN LYInfoAdvanced = (BOOL) (user_mode == ADVANCED_MODE);

#ifdef DIRED_SUPPORT
    struct stat dir_info;
    const char *name;
#endif /* DIRED_SUPPORT */

    if (LYReuseTempfiles) {
	fp0 = LYOpenTempRewrite(tempfile, HTML_SUFFIX, "w");
    } else {
	(void) LYRemoveTemp(tempfile);
	fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w");
    }
    if (fp0 == NULL) {
	HTAlert(CANNOT_OPEN_TEMP);
	return (-1);
    }

    /*
     * Point the address pointer at this Url
     */
    LYLocalFileToURL(&newdoc->address, tempfile);

    if (nlinks > 0 && links[doc->link].lname != NULL &&
	(url_type = is_url(links[doc->link].lname)) != 0 &&
	(url_type == LYNXEXEC_URL_TYPE ||
	 url_type == LYNXPROG_URL_TYPE)) {
	char *last_slash = strrchr(links[doc->link].lname, '/');
	int next_to_last = (int) strlen(links[doc->link].lname) - 1;

	if ((last_slash - links[doc->link].lname) == next_to_last) {
	    links[doc->link].lname[next_to_last] = '\0';
	}
    }

    label_columns = 9;

    WriteInternalTitle(fp0, SHOWINFO_TITLE);

    fprintf(fp0, "<h1>%s %s (%s) (<a href=\"%s\">%s</a>)",
	    LYNX_NAME, LYNX_VERSION,
	    LYVersionDate(),
	    (LYVersionIsRelease()? LYNX_WWW_HOME : LYNX_WWW_DIST),
	    LYVersionStatus());

    fprintf(fp0, "</h1>\n");	/* don't forget to close <h1> */

#ifdef DIRED_SUPPORT
    if (lynx_edit_mode && nlinks > 0) {

	BEGIN_DL(gettext("Directory that you are currently viewing"));

	temp = HTfullURL_toFile(doc->address);
	ADD_SS(gettext("Name:"), temp);
	FREE(temp);

	dt_URL(fp0, doc->address);

	END_DL();

	temp = HTfullURL_toFile(links[doc->link].lname);

	if (lstat(temp, &dir_info) == -1) {
	    CTRACE((tfp, "lstat(%s) failed, errno=%d\n", temp, errno));
	    HTAlert(CURRENT_LINK_STATUS_FAILED);
	} else {
	    char modes[80];

	    label_columns = 16;
	    if (S_ISDIR(dir_info.st_mode)) {
		BEGIN_DL(gettext("Directory that you have currently selected"));
	    } else if (S_ISREG(dir_info.st_mode)) {
		BEGIN_DL(gettext("File that you have currently selected"));
#ifdef S_IFLNK
	    } else if (S_ISLNK(dir_info.st_mode)) {
		BEGIN_DL(gettext("Symbolic link that you have currently selected"));
#endif
	    } else {
		BEGIN_DL(gettext("Item that you have currently selected"));
	    }
	    ADD_SS(gettext("Full name:"), temp);
#ifdef S_IFLNK
	    if (S_ISLNK(dir_info.st_mode)) {
		char buf[MAX_LINE];
		int buf_size;
		size_t limit = sizeof(buf) - 1;

		if ((buf_size = (int) readlink(temp, buf, limit)) != -1) {
		    if (buf_size > (int) limit)
			buf_size = (int) limit;
		    buf[buf_size] = '\0';
		} else {
		    sprintf(buf, "%.*s", (int) limit,
			    gettext("Unable to follow link"));
		}
		ADD_SS(gettext("Points to file:"), buf);
	    }
#endif
	    name = HTAA_UidToName((int) dir_info.st_uid);
	    if (*name)
		ADD_SS(gettext("Name of owner:"), name);
	    name = HTAA_GidToName((int) dir_info.st_gid);
	    if (*name)
		ADD_SS(gettext("Group name:"), name);
	    if (S_ISREG(dir_info.st_mode)) {
		ADD_NN(gettext("File size:"),
		       (long) dir_info.st_size,
		       gettext("(bytes)"));
	    }
	    /*
	     * Include date and time information.
	     */
	    ADD_SS(gettext("Creation date:"),
		   ctime(&dir_info.st_ctime));

	    ADD_SS(gettext("Last modified:"),
		   ctime(&dir_info.st_mtime));

	    ADD_SS(gettext("Last accessed:"),
		   ctime(&dir_info.st_atime));

	    END_DL();

	    label_columns = 9;
	    BEGIN_DL(gettext("Access Permissions"));
	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IRUSR))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWUSR))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXUSR)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
		    if ((dir_info.st_mode & S_ISUID))
			strcat(modes, ", setuid");
		}
	    }
	    ADD_SS(gettext("Owner:"), &modes[2]);

	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IRGRP))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWGRP))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXGRP)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
		    if ((dir_info.st_mode & S_ISGID))
			strcat(modes, ", setgid");
		}
	    }
	    ADD_SS(gettext("Group:"), &modes[2]);

	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IROTH))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWOTH))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXOTH)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
#ifdef S_ISVTX
		    if ((dir_info.st_mode & S_ISVTX))
			strcat(modes, ", sticky");
#endif
		}
	    }
	    ADD_SS(gettext("World:"), &modes[2]);
	    END_DL();
	}
	FREE(temp);
    } else {
#endif /* DIRED_SUPPORT */

	BEGIN_DL(gettext("File that you are currently viewing"));

	LYformTitle(&Title, doc->title);
	HTSprintf(&temp, "%s%s",
		  LYEntifyTitle(&buffer, Title),
		  ((doc->isHEAD &&
		    !strstr(Title, " (HEAD)") &&
		    !strstr(Title, " - HEAD")) ? " (HEAD)" : ""));
	ADD_SS(gettext("Linkname:"), temp);
	FREE(temp);

	dt_URL(fp0, doc->address);

	if (HTLoadedDocumentCharset()) {
	    ADD_SS(gettext("Charset:"),
		   HTLoadedDocumentCharset());
	} else {
	    LYUCcharset *p_in = HTAnchor_getUCInfoStage(HTMainAnchor,
							UCT_STAGE_PARSER);

	    if (!p_in || isEmpty(p_in->MIMEname) ||
		HTAnchor_getUCLYhndl(HTMainAnchor, UCT_STAGE_PARSER) < 0) {
		p_in = HTAnchor_getUCInfoStage(HTMainAnchor, UCT_STAGE_MIME);
	    }
	    if (p_in && non_empty(p_in->MIMEname) &&
		HTAnchor_getUCLYhndl(HTMainAnchor, UCT_STAGE_MIME) >= 0) {
		HTSprintf(&temp, "%s %s",
			  LYEntifyTitle(&buffer, p_in->MIMEname),
			  gettext("(assumed)"));
		ADD_SS(gettext("Charset:"), p_in->MIMEname);
		FREE(temp);
	    }
	}

	if ((cp = HText_getServer()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Server:"), cp);

	if ((cp = HText_getDate()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Date:"), cp);

	if ((cp = HText_getLastModified()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Last Mod:"), cp);

	if (LYInfoAdvanced) {
	    if (HTMainAnchor && HTMainAnchor->expires) {
		ADD_SS(gettext("Expires:"), HTMainAnchor->expires);
	    }
	    if (HTMainAnchor && HTMainAnchor->cache_control) {
		ADD_SS(gettext("Cache-Control:"), HTMainAnchor->cache_control);
	    }
	    if (HTMainAnchor && HTMainAnchor->content_length > 0) {
		ADD_NN(gettext("Content-Length:"),
		       HTMainAnchor->content_length,
		       gettext("bytes"));
	    } else {
		ADD_NN(gettext("Length:"),
		       HText_getNumOfBytes(),
		       gettext("bytes"));
	    }
	    if (HTMainAnchor && HTMainAnchor->content_language) {
		ADD_SS(gettext("Language:"), HTMainAnchor->content_language);
	    }
	}

	if (doc->post_data) {
	    fprintf(fp0, "<dt><em>%s</em> <xmp>%.*s</xmp>\n",
		    LYEntifyTitle(&buffer, gettext("Post Data:")),
		    BStrLen(doc->post_data),
		    BStrData(doc->post_data));
	    ADD_SS(gettext("Post Content Type:"), doc->post_content_type);
	}

	ADD_SS(gettext("Owner(s):"),
	       (owner_address
		? owner_address
		: NO_NOTHING));

	ADD_NN(gettext("size:"),
	       HText_getNumOfLines(),
	       gettext("lines"));

	StrAllocCopy(temp,
		     ((lynx_mode == FORMS_LYNX_MODE)
		      ? gettext("forms mode")
		      : (HTisDocumentSource()
			 ? gettext("source")
			 : gettext("normal"))));
	if (doc->safe)
	    StrAllocCat(temp, gettext(", safe"));
	if (doc->internal_link)
	    StrAllocCat(temp, gettext(", via internal link"));

	if (LYInfoAdvanced) {
	    if (HText_hasNoCacheSet(HTMainText))
		StrAllocCat(temp, gettext(", no-cache"));
	    if (HTAnchor_isISMAPScript((HTAnchor *) HTMainAnchor))
		StrAllocCat(temp, gettext(", ISMAP script"));
	    if (doc->bookmark)
		StrAllocCat(temp, gettext(", bookmark file"));
	}

	ADD_SS(gettext("mode:"), temp);
	FREE(temp);

	END_DL();

	if (nlinks > 0) {
	    BEGIN_DL(gettext("Link that you currently have selected"));
	    ADD_SS(gettext("Linkname:"),
		   LYGetHiliteStr(doc->link, 0));
	    if (lynx_mode == FORMS_LYNX_MODE &&
		links[doc->link].type == WWW_FORM_LINK_TYPE) {
		if (links[doc->link].l_form->submit_method) {
		    int method = links[doc->link].l_form->submit_method;
		    char *enctype = links[doc->link].l_form->submit_enctype;

		    ADD_SS(gettext("Method:"),
			   ((method == URL_POST_METHOD) ? "POST" :
			    ((method == URL_MAIL_METHOD) ? "(email)" :
			     "GET")));
		    ADD_SS(gettext("Enctype:"),
			   (non_empty(enctype)
			    ? enctype
			    : "application/x-www-form-urlencoded"));
		}
		if (links[doc->link].l_form->submit_action) {
		    ADD_SS(gettext("Action:"),
			   links[doc->link].l_form->submit_action);
		}
		if (!(links[doc->link].l_form->submit_method &&
		      links[doc->link].l_form->submit_action)) {
		    fprintf(fp0, "<dt>&nbsp;%s\n",
			    LYEntifyTitle(&buffer, gettext("(Form field)")));
		}
	    } else {
		dt_URL(fp0, NonNull(links[doc->link].lname));
	    }
	    END_DL();

	} else {
	    fprintf(fp0, "<h2>%s</h2>",
		    LYEntifyTitle(&buffer,
				  gettext("No Links on the current page")));
	}

	if ((cp = HText_getHttpHeaders()) != 0) {
	    fprintf(fp0, "<h2>%s</h2>",
		    LYEntifyTitle(&buffer, gettext("Server Headers:")));
	    fprintf(fp0, "<pre>%s</pre>",
		    LYEntifyTitle(&buffer, cp));
	}
#ifdef DIRED_SUPPORT
    }
#endif /* DIRED_SUPPORT */
    EndInternalPage(fp0);

    LYrefresh();

    LYCloseTemp(tempfile);
    FREE(Title);
    FREE(buffer);

    return (0);
}
Пример #4
0
static int LYLoadCGI(const char *arg,
		     HTParentAnchor *anAnchor,
		     HTFormat format_out,
		     HTStream *sink)
{
    int status = 0;

#ifdef LYNXCGI_LINKS
#ifndef VMS
    char *cp;
    struct stat stat_buf;
    char *pgm = NULL;		/* executable */
    char *pgm_args = NULL;	/* and its argument(s) */
    int statrv;
    char *orig_pgm = NULL;	/* Path up to ? as given, URL-escaped */
    char *document_root = NULL;	/* Corrected value of DOCUMENT_ROOT  */
    char *path_info = NULL;	/* PATH_INFO extracted from pgm      */
    char *pgm_buff = NULL;	/* PATH_INFO extraction buffer       */
    char *path_translated;	/* From document_root/path_info      */

    if (isEmpty(arg) || strlen(arg) <= 8) {
	HTAlert(BAD_REQUEST);
	status = -2;
	return (status);

    } else {
	if (StrNCmp(arg, "lynxcgi://localhost", 19) == 0) {
	    StrAllocCopy(pgm, arg + 19);
	} else {
	    StrAllocCopy(pgm, arg + 8);
	}
	if ((cp = StrChr(pgm, '?')) != NULL) {	/* Need to terminate executable */
	    *cp++ = '\0';
	    pgm_args = cp;
	}
    }

    StrAllocCopy(orig_pgm, pgm);
    if (trimPoundSelector(pgm) != NULL) {
	/*
	 * Strip a #fragment from path.  In this case any pgm_args found above
	 * will also be bogus, since the '?' came after the '#' and is part of
	 * the fragment.  Note that we don't handle the case where a '#'
	 * appears after a '?' properly according to URL rules.  - kw
	 */
	pgm_args = NULL;
    }
    HTUnEscape(pgm);

    /* BEGIN WebSter Mods */
    /* If pgm is not stat-able, see if PATH_INFO data is at the end of pgm */
    if ((statrv = stat(pgm, &stat_buf)) < 0) {
	StrAllocCopy(pgm_buff, pgm);
	while (statrv < 0 || (statrv = stat(pgm_buff, &stat_buf)) < 0) {
	    if ((cp = strrchr(pgm_buff, '/')) != NULL) {
		*cp = '\0';
		statrv = 1;	/* force new stat()  - kw */
	    } else {
		PERROR("strrchr(pgm_buff, '/') returned NULL");
		break;
	    }
	}

	if (statrv < 0) {
	    /* Did not find PATH_INFO data */
	    PERROR("stat() of pgm_buff failed");
	} else {
	    /* Found PATH_INFO data.  Strip it off of pgm and into path_info. */
	    StrAllocCopy(path_info, pgm + strlen(pgm_buff));
	    /* The following is safe since pgm_buff was derived from pgm
	       by stripping stuff off its end and by HTUnEscaping, so we
	       know we have enough memory allocated for pgm.  Note that
	       pgm_args may still point into that memory, so we cannot
	       reallocate pgm here. - kw */
	    strcpy(pgm, pgm_buff);
	    CTRACE((tfp,
		    "LYNXCGI: stat() of %s succeeded, path_info=\"%s\".\n",
		    pgm_buff, path_info));
	}
	FREE(pgm_buff);
    }
    /* END WebSter Mods */

    if (statrv != 0) {
	/*
	 * Neither the path as given nor any components examined by backing up
	 * were stat()able.  - kw
	 */
	HTAlert(gettext("Unable to access cgi script"));
	PERROR("stat() failed");
	status = -4;

    } else
#ifdef _WINDOWS			/* 1998/01/14 (Wed) 09:16:04 */
#define isExecutable(mode) (mode & (S_IXUSR))
#else
#define isExecutable(mode) (mode & (S_IXUSR|S_IXGRP|S_IXOTH))
#endif
    if (!(S_ISREG(stat_buf.st_mode) && isExecutable(stat_buf.st_mode))) {
	/*
	 * Not a runnable file, See if we can load it using "file:" code.
	 */
	char *new_arg = NULL;

	/*
	 * But try "file:" only if the file we are looking at is the path as
	 * given (no path_info was extracted), otherwise it will be to
	 * confusing to know just what file is loaded.  - kw
	 */
	if (path_info) {
	    CTRACE((tfp,
		    "%s is not a file and %s not an executable, giving up.\n",
		    orig_pgm, pgm));
	    FREE(path_info);
	    FREE(pgm);
	    FREE(orig_pgm);
	    status = -4;
	    return (status);
	}

	LYLocalFileToURL(&new_arg, orig_pgm);

	CTRACE((tfp, "%s is not an executable file, passing the buck.\n", arg));
	status = HTLoadFile(new_arg, anAnchor, format_out, sink);
	FREE(new_arg);

    } else if (path_info &&
	       anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       HTUnEscape(orig_pgm) &&
	       !can_exec_cgi(orig_pgm, "")) {
	/*
	 * If we have extra path info and are not just reloading the current,
	 * check the full file path (after unescaping) now to catch forbidden
	 * segments.  - kw
	 */
	status = HT_NOT_LOADED;

    } else if (no_lynxcgi) {
	HTUserMsg(CGI_DISABLED);
	status = HT_NOT_LOADED;

    } else if (no_bookmark_exec &&
	       anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       HTLoadedDocumentBookmark()) {
	/*
	 * If we are reloading a lynxcgi document that had already been loaded,
	 * the various checks above should allow it even if no_bookmark_exec is
	 * TRUE an we are not now coming from a bookmark page.  - kw
	 */
	HTUserMsg(BOOKMARK_EXEC_DISABLED);
	status = HT_NOT_LOADED;

    } else if (anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       !can_exec_cgi(pgm, pgm_args)) {
	/*
	 * If we are reloading a lynxcgi document that had already been loaded,
	 * the various checks above should allow it even if exec_ok() would
	 * reject it because we are not now coming from a document with a URL
	 * allowed by TRUSTED_LYNXCGI rules.  - kw
	 */
	status = HT_NOT_LOADED;

    } else {
	HTFormat format_in;
	HTStream *target = NULL;	/* Unconverted data */
	int fd1[2], fd2[2];
	char buf[MAX_LINE];
	int pid;

#ifdef HAVE_TYPE_UNIONWAIT
	union wait wstatus;

#else
	int wstatus;
#endif

	fd1[0] = -1;
	fd1[1] = -1;
	fd2[0] = -1;
	fd2[1] = -1;

	if (anAnchor->isHEAD || keep_mime_headers) {

	    /* Show output as plain text */
	    format_in = WWW_PLAINTEXT;
	} else {

	    /* Decode full HTTP response */
	    format_in = HTAtom_for("www/mime");
	}

	target = HTStreamStack(format_in,
			       format_out,
			       sink, anAnchor);

	if (!target || target == NULL) {
	    char *tmp = 0;

	    HTSprintf0(&tmp, CANNOT_CONVERT_I_TO_O,
		       HTAtom_name(format_in),
		       HTAtom_name(format_out));
	    HTAlert(tmp);
	    FREE(tmp);
	    status = HT_NOT_LOADED;

	} else if (anAnchor->post_data && pipe(fd1) < 0) {
	    HTAlert(CONNECT_SET_FAILED);
	    PERROR("pipe() failed");
	    status = -3;

	} else if (pipe(fd2) < 0) {
	    HTAlert(CONNECT_SET_FAILED);
	    PERROR("pipe() failed");
	    close(fd1[0]);
	    close(fd1[1]);
	    status = -3;

	} else {
	    static BOOL first_time = TRUE;	/* One time setup flag */

	    if (first_time) {	/* Set up static environment variables */
		first_time = FALSE;	/* Only once */

		add_environment_value("REMOTE_HOST=localhost");
		add_environment_value("REMOTE_ADDR=127.0.0.1");

		HTSprintf0(&user_agent, "HTTP_USER_AGENT=%s/%s libwww/%s",
			   LYNX_NAME, LYNX_VERSION, HTLibraryVersion);
		add_environment_value(user_agent);

		HTSprintf0(&server_software, "SERVER_SOFTWARE=%s/%s",
			   LYNX_NAME, LYNX_VERSION);
		add_environment_value(server_software);
	    }
	    fflush(stdout);
	    fflush(stderr);
	    CTRACE_FLUSH(tfp);

	    if ((pid = fork()) > 0) {	/* The good, */
		ssize_t chars;
		off_t total_chars;

		close(fd2[1]);

		if (anAnchor->post_data) {
		    ssize_t written;
		    int remaining, total_written = 0;

		    close(fd1[0]);

		    /* We have form data to push across the pipe */
		    if (TRACE) {
			CTRACE((tfp,
				"LYNXCGI: Doing post, content-type '%s'\n",
				anAnchor->post_content_type));
			CTRACE((tfp, "LYNXCGI: Writing:\n"));
			trace_bstring(anAnchor->post_data);
			CTRACE((tfp, "----------------------------------\n"));
		    }
		    remaining = BStrLen(anAnchor->post_data);
		    while ((written = write(fd1[1],
					    BStrData(anAnchor->post_data) + total_written,
					    (size_t) remaining)) != 0) {
			if (written < 0) {
#ifdef EINTR
			    if (errno == EINTR)
				continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
			    if (errno == ERESTARTSYS)
				continue;
#endif /* ERESTARTSYS */
			    PERROR("write() of POST data failed");
			    break;
			}
			CTRACE((tfp, "LYNXCGI: Wrote %d bytes of POST data.\n",
				(int) written));
			total_written += (int) written;
			remaining -= (int) written;
			if (remaining == 0)
			    break;
		    }
		    if (remaining != 0) {
			CTRACE((tfp, "LYNXCGI: %d bytes remain unwritten!\n",
				remaining));
		    }
		    close(fd1[1]);
		}

		HTReadProgress(total_chars = 0, (off_t) 0);
		while ((chars = read(fd2[0], buf, sizeof(buf))) != 0) {
		    if (chars < 0) {
#ifdef EINTR
			if (errno == EINTR)
			    continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
			if (errno == ERESTARTSYS)
			    continue;
#endif /* ERESTARTSYS */
			PERROR("read() of CGI output failed");
			break;
		    }
		    total_chars += (int) chars;
		    HTReadProgress(total_chars, (off_t) 0);
		    CTRACE((tfp, "LYNXCGI: Rx: %.*s\n", (int) chars, buf));
		    (*target->isa->put_block) (target, buf, (int) chars);
		}

		if (chars < 0 && total_chars == 0) {
		    status = HT_NOT_LOADED;
		    (*target->isa->_abort) (target, NULL);
		    target = NULL;
		} else if (chars != 0) {
		    status = HT_PARTIAL_CONTENT;
		} else {
		    status = HT_LOADED;
		}

#ifndef HAVE_WAITPID
		while (wait(&wstatus) != pid) ;		/* do nothing */
#else
		while (-1 == waitpid(pid, &wstatus, 0)) {	/* wait for child */
#ifdef EINTR
		    if (errno == EINTR)
			continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
		    if (errno == ERESTARTSYS)
			continue;
#endif /* ERESTARTSYS */
		    break;
		}
#endif /* !HAVE_WAITPID */
		close(fd2[0]);

	    } else if (pid == 0) {	/* The Bad, */
		char **argv = NULL;
		int argv_cnt = 3;	/* name, one arg and terminator */
		char **cur_argv = NULL;
		int exec_errno;

		/* Set up output pipe */
		close(fd2[0]);
		dup2(fd2[1], fileno(stdout));	/* Should check success code */
		dup2(fd2[1], fileno(stderr));
		close(fd2[1]);

		if (non_empty(language)) {
		    HTSprintf0(&accept_language, "HTTP_ACCEPT_LANGUAGE=%s", language);
		    add_environment_value(accept_language);
		}

		if (non_empty(pref_charset)) {
		    cp = NULL;
		    StrAllocCopy(cp, "HTTP_ACCEPT_CHARSET=");
		    StrAllocCat(cp, pref_charset);
		    add_environment_value(cp);
		}

		if (anAnchor->post_data &&
		    anAnchor->post_content_type) {
		    cp = NULL;
		    StrAllocCopy(cp, "CONTENT_TYPE=");
		    StrAllocCat(cp, anAnchor->post_content_type);
		    add_environment_value(cp);
		}

		if (anAnchor->post_data) {	/* post script, read stdin */
		    close(fd1[1]);
		    dup2(fd1[0], fileno(stdin));
		    close(fd1[0]);

		    /* Build environment variables */

		    add_environment_value("REQUEST_METHOD=POST");

		    HTSprintf0(&post_len, "CONTENT_LENGTH=%d",
			       BStrLen(anAnchor->post_data));
		    add_environment_value(post_len);
		} else {
		    close(fileno(stdin));

		    if (anAnchor->isHEAD) {
			add_environment_value("REQUEST_METHOD=HEAD");
		    }
		}

		/*
		 * Set up argument line, mainly for <index> scripts
		 */
		if (pgm_args != NULL) {
		    for (cp = pgm_args; *cp != '\0'; cp++) {
			if (*cp == '+') {
			    argv_cnt++;
			}
		    }
		}

		argv = (char **) malloc((unsigned) argv_cnt * sizeof(char *));

		if (argv == NULL) {
		    outofmem(__FILE__, "LYCgi");
		}
		assert(argv != NULL);

		cur_argv = argv + 1;	/* For argv[0] */
		if (pgm_args != NULL) {
		    char *cr;

		    /* Data for a get/search form */
		    if (is_www_index) {
			add_environment_value("REQUEST_METHOD=SEARCH");
		    } else if (!anAnchor->isHEAD && !anAnchor->post_data) {
			add_environment_value("REQUEST_METHOD=GET");
		    }

		    cp = NULL;
		    StrAllocCopy(cp, "QUERY_STRING=");
		    StrAllocCat(cp, pgm_args);
		    add_environment_value(cp);

		    /*
		     * Split up arguments into argv array
		     */
		    cp = pgm_args;
		    cr = cp;
		    while (1) {
			if (*cp == '\0') {
			    *(cur_argv++) = HTUnEscape(cr);
			    break;

			} else if (*cp == '+') {
			    *cp++ = '\0';
			    *(cur_argv++) = HTUnEscape(cr);
			    cr = cp;
			}
			cp++;
		    }
		} else if (!anAnchor->isHEAD && !anAnchor->post_data) {
		    add_environment_value("REQUEST_METHOD=GET");
		}
		*cur_argv = NULL;	/* Terminate argv */
		argv[0] = pgm;

		/* Begin WebSter Mods  -jkt */
		if (LYCgiDocumentRoot != NULL) {
		    /* Add DOCUMENT_ROOT to env */
		    cp = NULL;
		    StrAllocCopy(cp, "DOCUMENT_ROOT=");
		    StrAllocCat(cp, LYCgiDocumentRoot);
		    add_environment_value(cp);
		}
		if (path_info != NULL) {
		    /* Add PATH_INFO to env */
		    cp = NULL;
		    StrAllocCopy(cp, "PATH_INFO=");
		    StrAllocCat(cp, path_info);
		    add_environment_value(cp);
		}
		if (LYCgiDocumentRoot != NULL && path_info != NULL) {
		    /* Construct and add PATH_TRANSLATED to env */
		    StrAllocCopy(document_root, LYCgiDocumentRoot);
		    LYTrimHtmlSep(document_root);
		    path_translated = document_root;
		    StrAllocCat(path_translated, path_info);
		    cp = NULL;
		    StrAllocCopy(cp, "PATH_TRANSLATED=");
		    StrAllocCat(cp, path_translated);
		    add_environment_value(cp);
		    FREE(path_translated);
		}
		/* End WebSter Mods  -jkt */

		execve(argv[0], argv, env);
		exec_errno = errno;
		PERROR("execve failed");
		printf("Content-Type: text/plain\r\n\r\n");
		if (!anAnchor->isHEAD) {
		    printf("exec of %s failed", pgm);
		    printf(": %s.\r\n", LYStrerror(exec_errno));
		}
		fflush(stdout);
		fflush(stderr);
		_exit(1);

	    } else {		/* and the Ugly */
		HTAlert(CONNECT_FAILED);
		PERROR("fork() failed");
		close(fd1[0]);
		close(fd1[1]);
		close(fd2[0]);
		close(fd2[1]);
		status = -1;
	    }

	}
	if (target != NULL) {
	    (*target->isa->_free) (target);
	}
    }
    FREE(path_info);
    FREE(pgm);
    FREE(orig_pgm);
#else /* VMS */
    HTStream *target;
    char *buf = 0;

    target = HTStreamStack(WWW_HTML,
			   format_out,
			   sink, anAnchor);

    HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
	       gettext("Good Advice"));
    PUTS(buf);

    HTSprintf0(&buf, "<h1>%s</h1>\n", gettext("Good Advice"));
    PUTS(buf);

    HTSprintf0(&buf, "%s <a\n",
	       gettext("An excellent http server for VMS is available via"));
    PUTS(buf);

    HTSprintf0(&buf,
	       "href=\"http://www.ecr6.ohio-state.edu/www/doc/serverinfo.html\"\n");
    PUTS(buf);

    HTSprintf0(&buf, ">%s</a>.\n", gettext("this link"));
    PUTS(buf);

    HTSprintf0(&buf, "<p>%s\n",
	       gettext("It provides state of the art CGI script support.\n"));
    PUTS(buf);

    HTSprintf0(&buf, "</body>\n</html>\n");
    PUTS(buf);

    (*target->isa->_free) (target);
    FREE(buf);
    status = HT_LOADED;
#endif /* VMS */
#else /* LYNXCGI_LINKS */
    HTUserMsg(CGI_NOT_COMPILED);
    status = HT_NOT_LOADED;
#endif /* LYNXCGI_LINKS */

    (void) arg;
    (void) anAnchor;
    (void) format_out;
    (void) sink;

    return (status);
}