Beispiel #1
0
/*
 * Parse an external acl helper line.
 *
 * Squid can be configured to pass various formats, we assume something
 * similar to the normal redirector format:
 *
 *   %URI %SRC %LOGIN
 *
 * For example:
 *   external_acl_type foo ttl=60 children=1 %URI %SRC %LOGIN /path/to/sg
 */
int parseAuthzLine(char *line, struct SquidInfo *s)
{
	char *field = NULL;

	sgLogDebug("got authz line %s", line);

	resetSquidInfo(s);

	/* get the URL and parse */
	if ((field = strtok(line, "\t ")) == NULL)
		return 0;

	HTUnEscape(field);
	if (!parseUrl(field, s))
		return 0;

	/* get the source address and parse */
	if ((field = strtok(NULL, " \t\n")) == NULL)
		return 0;

	HTUnEscape(field);      /* just in case, IPs should not need escaping */
	strcpy(s->src, field);

	/* get the login and parse */
	if ((field = strtok(NULL, " \t\n")) == NULL)
		return 0;

	if (!parseIdent(field,s))
		return 0;

	sgLogDebug("parsed authz line: furl='%s' domain='%s' surl='%s' src=%s ident='%s'",
		   s->furl, s->domain, s->surl, s->src, s->ident);

	return 1;
}
Beispiel #2
0
/*      Output parent directory entry
**
**    This gives the TITLE and H1 header, and also a link
**    to the parent directory if appropriate.
*/
PUBLIC void HTDirTitles ARGS2(HTStructured *, target,
		 HTAnchor * , anchor)

{
    char * logical = HTAnchor_address(anchor);
    char * path = HTParse(logical, "", PARSE_PATH + PARSE_PUNCTUATION);
    char * current;

    current = strrchr(path, '/');	/* last part or "" */
    free(logical);

    {
      char * printable = NULL;
      StrAllocCopy(printable, (current + 1));
      HTUnEscape(printable);
      START(HTML_TITLE);
      PUTS(*printable ? printable : "Welcome ");
      PUTS(" directory");
      END(HTML_TITLE);    
    
      START(HTML_H1);
      PUTS(*printable ? printable : "Welcome");
      END(HTML_H1);
      free(printable);
    }

    /*  Make link back to parent directory
     */

    if (current && current[1]) {   /* was a slash AND something else too */
        char * parent;
	char * relative;
	*current++ = 0;
      parent = strrchr(path, '/');  /* penultimate slash */

	relative = (char*) malloc(strlen(current) + 4);
	if (relative == NULL) outofmem(__FILE__, "DirRead");
	sprintf(relative, "%s/..", current);
        PUTS ("<A HREF=\"");
        PUTS (relative);
        PUTS ("\">");
	free(relative);

	PUTS("Up to ");
	if (parent) {
	  char * printable = NULL;
	  StrAllocCopy(printable, parent + 1);
	  HTUnEscape(printable);
	  PUTS(printable);
	  free(printable);
	} else {
	  PUTS("/");
	}

        PUTS("</A>");
      }
    free(path);
}
Beispiel #3
0
static int parseIdent(char *field, struct SquidInfo *s)
{
	char *p = NULL;

	HTUnEscape(field);

	if (strcmp(field, "-") != 0) {
		strcpy(s->ident, field);
		for (p = s->ident; *p != '\0'; p++) /* convert ident to lowercase chars */
			*p = tolower(*p);

		if (stripRealm && (p = strrchr(s->ident,'@'))) {
			if (realm) {
				if (strcmp(p, realm) == 0)
					*p = 0;
			} else {
				*p = 0;
			}
		}
	} else {
		s->ident[0] = '\0';
	}

	return 1;
}
Beispiel #4
0
/*
 * Wrapper for exec_ok(), confirming with user if the link text is not visible
 * in the status line.
 */
static BOOL can_exec_cgi(const char *linktext, const char *linkargs)
{
    const char *format = gettext("Do you want to execute \"%s\"?");
    char *message = NULL;
    char *command = NULL;
    char *p;
    BOOL result = TRUE;

    if (!exec_ok(HTLoadedDocumentURL(), linktext, CGI_PATH)) {
	/* exec_ok gives out msg. */
	result = FALSE;
    } else {
	StrAllocCopy(command, linktext);
	if (non_empty(linkargs)) {
	    HTSprintf(&command, " %s", linkargs);
	}
	HTUnEscape(command);
	for (p = command; *p; ++p)
	    if (*p == '+')
		*p = ' ';
	HTSprintf0(&message, format, command);
	result = HTConfirm(message);
	FREE(message);
	FREE(command);
    }
    return result;
}
Beispiel #5
0
/*
 * Parse a redirector input line, format is:
 *
 *   URL ip-address/fqdn ident method
 *
 * for example
 *    http://www.example.com/page1.html 192.168.2.3/- andi GET
 */
int parseLine(char *line, struct SquidInfo *s)
{
	char *field = NULL;
	char *p = NULL;

	sgLogDebug("got redirector line %s", line);

	resetSquidInfo(s);

	/* get the URL and parse */
	if ((field = strtok(line, "\t ")) == NULL)
		return 0;

	HTUnEscape(field);
	if (!parseUrl(field, s))
		return 0;

	/* get the source address and parse */
	if ((field = strtok(NULL, " \t\n")) == NULL)
		return 0;

	if ((p = strchr(field, '/')) != NULL) {
		*p = 0;
		strcpy(s->src, field);
		strcpy(s->srcDomain, p + 1);
		if (s->srcDomain[0] == '-' && s->srcDomain[1] == 0)
			s->srcDomain[0] = 0;
	} else {
		strcpy(s->src, field);
	}

	/* get the identity */
	if ((field = strtok(NULL, " \t\n")) == NULL)
		return 0;

	if (!parseIdent(field,s))
		return 0;

	/* get the method */
	if ((field = strtok(NULL, " \t\n")) == NULL)
		return 0;

	strcpy(s->method, field);
	if (s->method[0] == '\0')
		return 0;

	sgLogDebug("parsed redirector line: furl='%s' domain='%s' surl='%s' src=%s ident='%s'",
		   s->furl, s->domain, s->surl, s->src, s->ident);

	return 1;
}
Beispiel #6
0
static int HTUnEscape_tcl(ClientData clientData, Tcl_Interp *interp, 
			  int argc, char **argv) {
  if (argc == 2) {
    char *str      = argv[1];
    if (str) {
      char *result = HTUnEscape(str);
      Tcl_AppendResult(interp, result, NULL);
      return TCL_OK;
    }
    Tcl_AppendResult(interp, bad_vars, NULL);
    return TCL_ERROR;
  }
  else {
    Tcl_AppendResult(interp, err_string, argv[0], " string", NULL);
    return TCL_ERROR;
  }
}
Beispiel #7
0
/*	NewsPost_start
**	--------------
**	NNTP needs two extra headers: "From" and "Newsgroups".
**	Take the newsgroups from the Postweb model as destinations for this
**	anchor.
**	Return YES if OK else NO
*/
PRIVATE BOOL NewsPost_start (HTStream * me, HTRequest * request)
{
    char linebuf[128];		/* @@@ */
    HTChunk *header = me->buffer;
    HTUserProfile * up = HTRequest_userProfile(request);
    const char * mailaddress = HTUserProfile_email(up);
    if (mailaddress) {
	sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
	HTChunk_puts(header, linebuf);
    }

    /*
    **	Find all the newsgroups we are posting to by looking at all the
    **  destinations from the source of this request.
    ** 	First the main link and then the sub links
    */
    HTChunk_puts(header, "Newsgroups :");    
    if (HTRequest_isDestination(request)) {
	HTRequest *src_req = HTRequest_source(request);
	HTParentAnchor *src_anchor = HTRequest_anchor(src_req);
	HTLink *link = HTAnchor_mainLink((HTAnchor *) src_anchor);
	HTAnchor *dest = HTLink_destination(link);
	HTMethod method = HTLink_method(link);
	if (link && method == METHOD_POST &&
	    HTLink_result(link) == HT_LINK_NONE) {
	    char *desturl = HTAnchor_physical((HTParentAnchor *) dest);
	    char *access = HTParse(desturl, "", PARSE_ACCESS);
	    if (!strcasecomp(access, "news") || !strcasecomp(access, "nntp")) {
		char *newsgroup = HTParse(desturl, "", PARSE_PATH);
		HTUnEscape(newsgroup);
		HTCleanTelnetString(newsgroup);
		HTChunk_puts(header, newsgroup);
		HT_FREE(newsgroup);
	    }
	    HT_FREE(access);
	}

	/* DO FOR ALL SUB ANCHOR DESTINATION S AS WELL */
	
    }
    HTTRACE(PROT_TRACE, "News Tx..... %s" _ HTChunk_data(header));
    return YES;
}
static void dt_URL(FILE *fp0, const char *address)
{
    if (address == NULL)
	address = "";
    ADD_WW(gettext("URL:"), address);

    /*
     * If the display handles UTF-8, and if the address uses %xy formatted
     * characters, show the decoded URL on the next line.
     */
    if (LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
	char *working = NULL;

	StrAllocCopy(working, address);
	if (strcmp(HTUnEscape(working), address)) {
	    fprintf(fp0, "\n<br>%s\n", working);
	}
	free(working);
    }
}
Beispiel #9
0
/* HTUnEscape with control-code nuking */
PRIVATE void SafeHTUnEscape ARGS1(
    char *,	string)
{
     int i;
     int flg = FALSE;

     HTUnEscape(string);
     for (i=0; string[i] != '\0'; i++)
     {
	/* FIXME: this is no longer explicitly 7-bit ASCII,
	   but are there portability problems? */
	if ((!LYIsASCII(string[i])) || !isprint(UCH(string[i])))
	{
	   string[i] = '?';
	   flg = TRUE;
	}
     }
     if (flg)
	HTAlert(MAILTO_SQUASH_CTL);
}
Beispiel #10
0
/*	Convert filenames between local and WWW formats
**	-----------------------------------------------
** On exit,
**	returns	a malloc'ed string which must be freed by the caller.
*/
PUBLIC char * HTLocalName ARGS1(WWW_CONST char *,name)
{
  char * access = HTParse(name, "", PARSE_ACCESS);
  char * host = HTParse(name, "", PARSE_HOST);
  char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
  
  HTUnEscape(path);	/* Interpret % signs */
  
  if (0==strcmp(access, "file")) 
    {
      free(access);	
      if (!host || !*host || (0==my_strcasecmp(host, HTHostName())) ||
          (0==my_strcasecmp(host, "localhost"))) 
        {
          if (host)
            free(host);
#ifndef DISABLE_TRACE
          if (www2Trace) 
            fprintf(stderr, "Node `%s' means path `%s'\n", name, path);
#endif
          return(path);
        }
      else
        {
          free (host);
          if (path)
            free (path);
          return NULL;
        }
    }
  
  /* not file */
  if (host)
    free (host);
  free (access);
  if (path)
    free (path);
  return NULL;
}
Beispiel #11
0
/*
===============
inspired from http://www.w3.org/Library/Examples/LoadToFile.c
setup the download, return once we have a connection
===============
*/
int DL_BeginDownload( const char *localName, const char *remoteName, int debug )
{
	char *access = NULL;
	char *url = NULL;
	char *login = NULL;
	char *path = NULL;
	char *ptr = NULL;

	if ( dl_running )
	{
		Com_Printf(_( "ERROR: DL_BeginDownload called with a download request already active\n" ));
		return 0;
	}

	terminate_status = HT_UNDEF;

#ifdef HTDEBUG

	if ( debug )
	{
		WWWTRACE = SHOW_ALL_TRACE;
	}

#endif

	if ( !localName || !remoteName )
	{
		Com_DPrintf( "Empty download URL or empty local file name\n" );
		return 0;
	}

	DL_InitDownload();

	/* need access for ftp behaviour and HTTP Basic Auth */
	access = HTParse( remoteName, "", PARSE_ACCESS );

	/*
	   Set the timeout for how long we are going to wait for a response
	   This needs to be set and reset to 0 after dl each time
	   idcvs/2003-January/000449.html
	   http://lists.w3.org/Archives/Public/www-lib/2003AprJun/0033.html
	   In case of ftp download, we leave no timeout during connect phase cause of libwww bugs
	   show_bug.cgi?id=605
	 */
	if ( !Q_stricmp( access, "ftp" ) )
	{
		dl_is_ftp = 1;
		HTHost_setEventTimeout( -1 );
	}
	else
	{
		dl_is_ftp = 0;
		HTHost_setEventTimeout( 30000 );
	}

	dl_request = HTRequest_new();

	/* HTTP Basic Auth */
	if ( !Q_stricmp( access, "http" ) )
	{
		HTBasic *basic;

		login = HTParse( remoteName, "", PARSE_HOST );
		path = HTParse( remoteName, "", PARSE_PATH + PARSE_PUNCTUATION );
		ptr = strchr( login, '@' );

		if ( ptr )
		{
			/* Uid and/or passwd specified */
			char *passwd;

			*ptr = '\0';
			passwd = strchr( login, ':' );

			if ( passwd )
			{
				/* Passwd specified */
				*passwd++ = '\0';
				HTUnEscape( passwd );
			}

			HTUnEscape( login );
			/* proactively set the auth */
			basic = HTBasic_new();
			StrAllocCopy( basic->uid, login );
			StrAllocCopy( basic->pw, passwd );
			basic_credentials( dl_request, basic );
			HTBasic_delete( basic );
			/* correct the HTTP */
			url = HT_MALLOC( 7 + strlen( ptr + 1 ) + strlen( path ) + 1 );
			sprintf( url, "http://%s%s", ptr + 1, path );
			Com_DPrintf( "HTTP Basic Auth – %s %s %s\n", login, passwd, url );
			HT_FREE( login );
			HT_FREE( path );
		}
		else
		{
			StrAllocCopy( url, remoteName );
		}
	}
	else
	{
		StrAllocCopy( url, remoteName );
	}

	HT_FREE( access );

	FS_CreatePath( localName );

	/* Start the load */
	if ( HTLoadToFile( url, dl_request, localName ) != YES )
	{
		Com_DPrintf( "HTLoadToFile failed\n" );
		HT_FREE( url );
		HTProfile_delete();
		return 0;
	}

	HT_FREE( url );

	/* remove possible login/pass part for the ui */
	access = HTParse( remoteName, "", PARSE_ACCESS );
	login = HTParse( remoteName, "", PARSE_HOST );
	path = HTParse( remoteName, "", PARSE_PATH + PARSE_PUNCTUATION );
	ptr = strchr( login, '@' );

	if ( ptr )
	{
		/* Uid and/or passwd specified */
		Cvar_Set( "cl_downloadName", va( "%s://*:*%s%s", access, ptr, path ) );
	}
	else
	{
		Cvar_Set( "cl_downloadName", remoteName );
	}

	HT_FREE( path );
	HT_FREE( login );
	HT_FREE( access );

	if ( dl_is_ftp )
	{
		HTHost_setEventTimeout( 30000 );
	}

	/* Go into the event loop... */
	HTEventList_init( dl_request );

	dl_running = 1;

	return 1;
}
Beispiel #12
0
/*	Determine the content of an file name
**	-------------------------------------
**  Use the set of bindings to find the combination of language,
**  media type, encoding, and transfer encoding  of a given anchor.
**  If more than one suffix is found they are all searched. The last suffix
**  has highest priority, the first one lowest. See also HTBind_getBindings()
**  Either of format, encoding, or language can be NULL
**  Returns the format, encoding, and language found
*/
PUBLIC BOOL HTBind_getFormat (const char *	filename,
			      HTFormat *	format,
			      HTEncoding *	enc,
			      HTEncoding *	cte,
			      HTLanguage *	lang,
			      double *		quality)
{
    int sufcnt=0;
    char *file=NULL;
#ifdef HT_REENTRANT
    char *lasts;					     /* For strtok_r */
#endif
    if (!HTBindings) HTBind_init();
    if (*quality < HT_EPSILON)
	*quality = 1.0;			           /* Set to a neutral value */
    StrAllocCopy(file, filename);
    HTUnEscape(file);				   /* Unescape the file name */
#ifdef HT_REENTRANT
    if (strtok_r(file, HTDelimiters, &lasts)) {	 /* Do we have any suffixes? */
#else
    if (strtok(file, HTDelimiters)) { 		 /* Do we have any suffixes? */
#endif /* HT_REENTRANT */
	char *suffix;
#ifdef HT_REENTRANT
	while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
#else
	while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
#endif /* HT_REENTRANT */
	    HTBind *suff=NULL;
	    int hash;
	    unsigned char * p;
	    HTTRACE(BIND_TRACE, "Get Binding. Look for '%s\' " _ suffix);
	    sufcnt++;

	    /* Select list from hash table */
	    for (p=suffix, hash=0; *p; p++) {
		hash = (hash * 3 + TOLOWER(*p)) % HT_L_HASH_SIZE;
	    }

	    /* Now search list for entries (case or non case sensitive) */
	    if (HTBindings[hash]) {
		HTList *cur = HTBindings[hash];
		while ((suff = (HTBind *) HTList_nextObject(cur))) {
		    if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
			!strcasecomp(suff->suffix, suffix)) {
			HTTRACE(BIND_TRACE, "Found!\n");
			if (suff->type && format) *format = suff->type;
			if (suff->encoding && enc) *enc = suff->encoding;
			if (suff->transfer && cte) *cte = suff->transfer;
			if (suff->language && lang) *lang = suff->language;
			if (suff->quality > HT_EPSILON)
			    *quality *= suff->quality;
			break;
		    }
		}
	    }
	    if (!suff) {	/* We don't have this suffix - use default */
		HTTRACE(BIND_TRACE, "Not found - use default for \'*.*\'\n");
		if (format) *format = unknown_suffix.type;
		if (enc) *enc = unknown_suffix.encoding;
		if (cte) *cte = unknown_suffix.transfer;
		if (lang) *lang = unknown_suffix.language;
		*quality = unknown_suffix.quality;
	    }
	} /* while we still have suffixes */
    }
    if (!sufcnt) {		/* No suffix so use default value */
	HTTRACE(BIND_TRACE, "Get Binding. No suffix found - using default '%s\'\n" _ filename);
	if (format) *format = no_suffix.type;
	if (enc) *enc = no_suffix.encoding;
	if (cte) *cte = no_suffix.transfer;
	if (lang) *lang = no_suffix.language;
	*quality = no_suffix.quality;
    }
    HTTRACE(BIND_TRACE, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', cte='%s\', language='%s\' with quality %.2f\n" _ 
		filename _ 
		(format && *format) ? HTAtom_name(*format) : "unknown" _ 
		(enc && *enc) ? HTAtom_name(*enc) : "unknown" _ 
		(cte && *cte) ? HTAtom_name(*cte) : "unknown" _ 
		(lang && *lang) ? HTAtom_name(*lang) : "unknown" _ 
		*quality);
    HT_FREE(file);
    return YES;
}
Beispiel #13
0
/*
 * Seek and handle body=foo fields.  - FM
 */
PRIVATE void extract_body ARGS2(
    char **,	dst,
    char *,	src)
{
    CONST char *keyword = "body=";
    int len = strlen(keyword);
    int i;
    char *cp, *cp0, *cp1, *temp = 0;

    cp = (src + 1);
    while (*cp != '\0') {
	if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
	    !strncasecomp(cp, keyword, len)) {
	    cp += len;
	    if ((cp1 = strchr(cp, '&')) != NULL) {
		*cp1 = '\0';
	    }
	    if (*cp) {
		/*
		 *  Break up the value into lines with
		 *  a maximum length of 78. - FM
		 */
		StrAllocCopy(temp, cp);
		HTUnEscape(temp);
		cp0 = temp;
		while((cp = strchr(cp0, '\n')) != NULL) {
		    *cp = '\0';
		    if (cp > cp0) {
			if (*(cp - 1) == '\r') {
			    *(cp - 1) = '\0';
			}
		    }
		    i = 0;
		    len = strlen(cp0);
		    while (len > 78) {
			HTSprintf(dst, "%.78s\n", &cp0[i]);
			i += 78;
			len = strlen(&cp0[i]);
		    }
		    HTSprintf(dst, "%s\n", &cp0[i]);
		    cp0 = (cp + 1);
		}
		i = 0;
		len = strlen(cp0);
		while (len > 78) {
		    HTSprintf(dst, "%.78s\n", &cp0[i]);
		    i += 78;
		    len = strlen(&cp0[i]);
		}
		if (len) {
		    HTSprintf(dst, "%s\n", &cp0[i]);
		}
		FREE(temp);
	    }
	    if (cp1) {
		*cp1 = '&';
		cp = cp1;
		cp1 = NULL;
	    } else {
		break;
	    }
	}
	cp++;
    }
    CTRACE((tfp, "extract_body(%s) = '%s'\n", keyword, NONNULL(*dst)));
}
Beispiel #14
0
/*		Load by name					HTLoadFinger
 *		============
 */
int HTLoadFinger(const char *arg,
		 HTParentAnchor *anAnchor,
		 HTFormat format_out,
		 HTStream *stream)
{
    static char empty[1];

    char *username, *sitename;	/* Fields extracted from URL */
    char *slash, *at_sign;	/* Fields extracted from URL */
    char *command, *str, *param;	/* Buffers */
    int port;			/* Port number from URL */
    int status;			/* tcp return */
    int result = HT_LOADED;
    BOOL IsGopherURL = FALSE;
    const char *p1 = arg;

    CTRACE((tfp, "HTFinger: Looking for %s\n", (arg ? arg : "NULL")));

    if (!(arg && *arg)) {
	HTAlert(COULD_NOT_LOAD_DATA);
	return HT_NOT_LOADED;	/* Ignore if no name */
    }

    if (!initialized)
	initialized = initialize();
    if (!initialized) {
	HTAlert(gettext("Could not set up finger connection."));
	return HT_NOT_LOADED;	/* FAIL */
    }

    /*  Set up the host and command fields.
     */
    if (!strncasecomp(arg, "finger://", 9)) {
	p1 = arg + 9;		/* Skip "finger://" prefix */
    } else if (!strncasecomp(arg, "gopher://", 9)) {
	p1 = arg + 9;		/* Skip "gopher://" prefix */
	IsGopherURL = TRUE;
    }

    param = 0;
    sitename = StrAllocCopy(param, p1);
    if (param == 0) {
	HTAlert(COULD_NOT_LOAD_DATA);
	return HT_NOT_LOADED;
    } else if ((slash = StrChr(sitename, '/')) != NULL) {
	*slash++ = '\0';
	HTUnEscape(slash);
	if (IsGopherURL) {
	    if (*slash != '0') {
		HTAlert(COULD_NOT_LOAD_DATA);
		return HT_NOT_LOADED;	/* FAIL */
	    }
	    *slash++ = '\0';
	}
    }

    if ((at_sign = StrChr(sitename, '@')) != NULL) {
	if (IsGopherURL) {
	    HTAlert(COULD_NOT_LOAD_DATA);
	    return HT_NOT_LOADED;	/* FAIL */
	} else {
	    *at_sign++ = '\0';
	    username = sitename;
	    sitename = at_sign;
	    HTUnEscape(username);
	}
    } else if (slash) {
	username = slash;
    } else {
	username = empty;
    }

    if (*sitename == '\0') {
	HTAlert(gettext("Could not load data (no sitename in finger URL)"));
	result = HT_NOT_LOADED;	/* Ignore if no name */
    } else if (HTParsePort(sitename, &port) != NULL) {
	if (port != 79) {
	    HTAlert(gettext("Invalid port number - will only use port 79!"));
	    result = HT_NOT_LOADED;	/* Ignore if wrong port */
	}
    }

    if (result == HT_LOADED) {
	/* Load the string for making a connection/
	 */
	str = 0;
	HTSprintf0(&str, "lose://%s/", sitename);

	/* Load the command for the finger server.
	 */
	command = 0;
	if (at_sign && slash) {
	    if (*slash == 'w' || *slash == 'W') {
		HTSprintf0(&command, "/w %s%c%c", username, CR, LF);
	    } else {
		HTSprintf0(&command, "%s%c%c", username, CR, LF);
	    }
	} else if (at_sign) {
	    HTSprintf0(&command, "%s%c%c", username, CR, LF);
	} else if (*username == '/') {
	    if ((slash = StrChr((username + 1), '/')) != NULL) {
		*slash = ' ';
	    }
	    HTSprintf0(&command, "%s%c%c", username, CR, LF);
	} else if ((*username == 'w' || *username == 'W') &&
		   *(username + 1) == '/') {
	    if (*username + 2 != '\0') {
		*(username + 1) = ' ';
	    } else {
		*(username + 1) = '\0';
	    }
	    HTSprintf0(&command, "/%s%c%c", username, CR, LF);
	} else if ((*username == 'w' || *username == 'W') &&
		   *(username + 1) == '\0') {
	    HTSprintf0(&command, "/%s%c%c", username, CR, LF);
	} else if ((slash = StrChr(username, '/')) != NULL) {
	    *slash++ = '\0';
	    if (*slash == 'w' || *slash == 'W') {
		HTSprintf0(&command, "/w %s%c%c", username, CR, LF);
	    } else {
		HTSprintf0(&command, "%s%c%c", username, CR, LF);
	    }
	} else {
	    HTSprintf0(&command, "%s%c%c", username, CR, LF);
	}

	/* Now, let's get a stream setup up from the FingerHost:
	 * CONNECTING to finger host
	 */
	CTRACE((tfp, "HTFinger: doing HTDoConnect on '%s'\n", str));
	status = HTDoConnect(str, "finger", FINGER_PORT, &finger_fd);
	CTRACE((tfp, "HTFinger: Done DoConnect; status %d\n", status));

	if (status == HT_INTERRUPTED) {
	    /* Interrupt cleanly */
	    CTRACE((tfp,
		    "HTFinger: Interrupted on connect; recovering cleanly.\n"));
	    HTProgress(CONNECTION_INTERRUPTED);
	    result = HT_NOT_LOADED;
	} else if (status < 0) {
	    NETCLOSE(finger_fd);
	    finger_fd = -1;
	    CTRACE((tfp, "HTFinger: Unable to connect to finger host.\n"));
	    HTAlert(gettext("Could not access finger host."));
	    result = HT_NOT_LOADED;	/* FAIL */
	} else {
	    CTRACE((tfp, "HTFinger: Connected to finger host '%s'.\n", str));

	    /* Send the command, and process response if successful.
	     */
	    if (response(command, sitename, anAnchor, format_out, stream) != 0) {
		HTAlert(gettext("No response from finger server."));
		result = HT_NOT_LOADED;
	    }
	}
	FREE(str);
	FREE(command);
    }
    FREE(param);
    return result;
}
Beispiel #15
0
void LYDownload(char *line)
{
    char *Line = NULL, *method, *file, *sug_file = NULL;
    int method_number;
    int count;
    char *the_command = 0;
    bstring *buffer = NULL;
    bstring *command = NULL;
    char *cp;
    lynx_list_item_type *download_command = 0;
    int ch;
    RecallType recall;
    int FnameTotal;
    int FnameNum;
    BOOLEAN FirstRecall = TRUE;
    BOOLEAN SecondS = FALSE;

#ifdef VMS
    LYDidRename = FALSE;
#endif /* VMS */

    /*
     * Make sure we have a valid download file comparison string loaded via the
     * download options menu.  - FM
     */
    if (LYValidDownloadFile[0] == '\0') {
	goto failed;
    }

    /*
     * Make a copy of the LYNXDOWNLOAD internal URL for parsing.  - FM
     */
    StrAllocCopy(Line, line);

    /*
     * Parse out the File, sug_file, and the Method.
     */
    if ((file = strstr(Line, "/File=")) == NULL)
	goto failed;
    *file = '\0';
    /*
     * Go past "File=".
     */
    file += 6;

    if ((sug_file = strstr(file + 1, "/SugFile=")) != NULL) {
	*sug_file = '\0';
	/*
	 * Go past "SugFile=".
	 */
	sug_file += 9;
	HTUnEscape(sug_file);
    }

    /*
     * Make sure that the file string is the one from the last displayed
     * download options menu.  - FM
     */
    if (strcmp(file, LYValidDownloadFile)) {
	goto failed;
    }
#if defined(DIRED_SUPPORT)
    /* FIXME: use HTLocalName */
    if (!StrNCmp(file, "file://localhost", 16)) {
#ifdef __DJGPP__
	if (!StrNCmp(file + 16, "/dev/", 5))
	    file += 16;
	else {
	    file += 17;
	    file = HTDOS_name(file);
	}
#else
	file += 16;
#endif /* __DJGPP__ */
    } else if (isFILE_URL(file))
	file += LEN_FILE_URL;
    HTUnEscape(file);
#else
#if defined(_WINDOWS)		/* 1997/10/15 (Wed) 16:27:38 */
    if (!StrNCmp(file, "file://localhost/", 17))
	file += 17;
    else if (!StrNCmp(file, "file:/", 6))
	file += 6;
    HTUnEscape(file);
#endif /* _WINDOWS */
#endif /* DIRED_SUPPORT */

    if ((method = strstr(Line, "Method=")) == NULL)
	goto failed;
    /*
     * Go past "Method=".
     */
    method += 7;
    method_number = atoi(method);

    /*
     * Set up the sug_filenames recall buffer.
     */
    FnameTotal = (sug_filenames ? HTList_count(sug_filenames) : 0);
    recall = ((FnameTotal >= 1) ? RECALL_URL : NORECALL);
    FnameNum = FnameTotal;

    if (method_number < 0) {
	/*
	 * Write to local file.
	 */
	_statusline(FILENAME_PROMPT);
      retry:
	if (sug_file) {
	    BStrCopy0(buffer, sug_file);
	} else {
	    BStrCopy0(buffer, "");
	}

      check_recall:
	if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 ||
	    isBEmpty(buffer) ||
	    ch == UPARROW_KEY ||
	    ch == DNARROW_KEY) {

	    if (recall && ch == UPARROW_KEY) {
		if (FirstRecall) {
		    FirstRecall = FALSE;
		    /*
		     * Use the last Fname in the list.  - FM
		     */
		    FnameNum = 0;
		} else {
		    /*
		     * Go back to the previous Fname in the list.  - FM
		     */
		    FnameNum++;
		}
		if (FnameNum >= FnameTotal) {
		    /*
		     * Reset the FirstRecall flag, and use sug_file or a blank.
		     * - FM
		     */
		    FirstRecall = TRUE;
		    FnameNum = FnameTotal;
		    _statusline(FILENAME_PROMPT);
		    goto retry;
		} else if ((cp = (char *) HTList_objectAt(sug_filenames,
							  FnameNum)) != NULL) {
		    BStrCopy0(buffer, cp);
		    if (FnameTotal == 1) {
			_statusline(EDIT_THE_PREV_FILENAME);
		    } else {
			_statusline(EDIT_A_PREV_FILENAME);
		    }
		    goto check_recall;
		}
	    } else if (recall && ch == DNARROW_KEY) {
		if (FirstRecall) {
		    FirstRecall = FALSE;
		    /*
		     * Use the first Fname in the list.  - FM
		     */
		    FnameNum = FnameTotal - 1;
		} else {
		    /*
		     * Advance to the next Fname in the list.  - FM
		     */
		    FnameNum--;
		}
		if (FnameNum < 0) {
		    /*
		     * Set the FirstRecall flag, and use sug_file or a blank.
		     * - FM
		     */
		    FirstRecall = TRUE;
		    FnameNum = FnameTotal;
		    _statusline(FILENAME_PROMPT);
		    goto retry;
		} else if ((cp = (char *) HTList_objectAt(sug_filenames,
							  FnameNum)) != NULL) {
		    BStrCopy0(buffer, cp);
		    if (FnameTotal == 1) {
			_statusline(EDIT_THE_PREV_FILENAME);
		    } else {
			_statusline(EDIT_A_PREV_FILENAME);
		    }
		    goto check_recall;
		}
	    }

	    /*
	     * Save cancelled.
	     */
	    goto cancelled;
	}

	BStrCopy(command, buffer);
	if (!LYValidateFilename(&buffer, &command))
	    goto cancelled;
#ifdef HAVE_POPEN
	else if (LYIsPipeCommand(buffer->str)) {
	    /* I don't know how to download to a pipe */
	    HTAlert(CANNOT_WRITE_TO_FILE);
	    _statusline(NEW_FILENAME_PROMPT);
	    FirstRecall = TRUE;
	    FnameNum = FnameTotal;
	    goto retry;
	}
#endif

	/*
	 * See if it already exists.
	 */
	switch (LYValidateOutput(buffer->str)) {
	case 'Y':
	    break;
	case 'N':
	    _statusline(NEW_FILENAME_PROMPT);
	    FirstRecall = TRUE;
	    FnameNum = FnameTotal;
	    goto retry;
	default:
	    goto cleanup;
	}

	/*
	 * See if we can write to it.
	 */
	CTRACE((tfp, "LYDownload: filename is %s\n", buffer->str));

	SecondS = TRUE;

	HTInfoMsg(SAVING);
#ifdef VMS
	/*
	 * Try rename() first.  - FM
	 */
	CTRACE((tfp, "command: rename(%s, %s)\n", file, buffer->str));
	if (rename(file, buffer->str)) {
	    /*
	     * Failed.  Use spawned COPY_COMMAND.  - FM
	     */
	    CTRACE((tfp, "         FAILED!\n"));
	    LYCopyFile(file, buffer->str);
	} else {
	    /*
	     * We don't have the temporary file (it was renamed to a permanent
	     * file), so set a flag to pop out of the download menu.  - FM
	     */
	    LYDidRename = TRUE;
	}
	chmod(buffer->str, HIDE_CHMOD);
#else /* Unix: */

	LYCopyFile(file, buffer->str);
	LYRelaxFilePermissions(buffer->str);
#endif /* VMS */

    } else {
	/*
	 * Use configured download commands.
	 */
	BStrCopy0(buffer, "");
	for (count = 0, download_command = downloaders;
	     count < method_number;
	     count++, download_command = download_command->next) ;	/* null body */

	/*
	 * Commands have the form "command %s [etc]" where %s is the filename.
	 */
	if (download_command->command != NULL) {
	    /*
	     * Check for two '%s' and ask for the local filename if there is.
	     */
	    if (HTCountCommandArgs(download_command->command) >= 2) {
		_statusline(FILENAME_PROMPT);

	      again:
		if (sug_file) {
		    BStrCopy0(buffer, sug_file);
		} else {
		    BStrCopy0(buffer, "");
		}

	      check_again:
		if ((ch = LYgetBString(&buffer, FALSE, 0, recall)) < 0 ||
		    isBEmpty(buffer) ||
		    ch == UPARROW_KEY ||
		    ch == DNARROW_KEY) {

		    if (recall && ch == UPARROW_KEY) {
			if (FirstRecall) {
			    FirstRecall = FALSE;
			    /*
			     * Use the last Fname in the list.  - FM
			     */
			    FnameNum = 0;
			} else {
			    /*
			     * Go back to the previous Fname in the list.  - FM
			     */
			    FnameNum++;
			}
			if (FnameNum >= FnameTotal) {
			    /*
			     * Reset the FirstRecall flag, and use sug_file or
			     * a blank.  - FM
			     */
			    FirstRecall = TRUE;
			    FnameNum = FnameTotal;
			    _statusline(FILENAME_PROMPT);
			    goto again;
			} else if ((cp = (char *) HTList_objectAt(sug_filenames,
								  FnameNum))
				   != NULL) {
			    BStrCopy0(buffer, cp);
			    if (FnameTotal == 1) {
				_statusline(EDIT_THE_PREV_FILENAME);
			    } else {
				_statusline(EDIT_A_PREV_FILENAME);
			    }
			    goto check_again;
			}
		    } else if (recall && ch == DNARROW_KEY) {
			if (FirstRecall) {
			    FirstRecall = FALSE;
			    /*
			     * Use the first Fname in the list.  - FM
			     */
			    FnameNum = FnameTotal - 1;
			} else {
			    /*
			     * Advance to the next Fname in the list.  - FM
			     */
			    FnameNum--;
			}
			if (FnameNum < 0) {
			    /*
			     * Set the FirstRecall flag, and use sug_file or a
			     * blank.  - FM
			     */
			    FirstRecall = TRUE;
			    FnameNum = FnameTotal;
			    _statusline(FILENAME_PROMPT);
			    goto again;
			} else if ((cp = (char *) HTList_objectAt(sug_filenames,
								  FnameNum))
				   != NULL) {
			    BStrCopy0(buffer, cp);
			    if (FnameTotal == 1) {
				_statusline(EDIT_THE_PREV_FILENAME);
			    } else {
				_statusline(EDIT_A_PREV_FILENAME);
			    }
			    goto check_again;
			}
		    }

		    /*
		     * Download cancelled.
		     */
		    goto cancelled;
		}

		if (no_dotfiles || !show_dotfiles) {
		    if (*LYPathLeaf(buffer->str) == '.') {
			HTAlert(FILENAME_CANNOT_BE_DOT);
			_statusline(NEW_FILENAME_PROMPT);
			goto again;
		    }
		}
		/*
		 * Cancel if the user entered "/dev/null" on Unix, or an "nl:"
		 * path on VMS.  - FM
		 */
		if (LYIsNullDevice(buffer->str)) {
		    goto cancelled;
		}
		SecondS = TRUE;
	    }

	    /*
	     * The following is considered a bug by the community.  If the
	     * command only takes one argument on the command line, then the
	     * suggested file name is not used.  It actually is not a bug at
	     * all and does as it should, putting both names on the command
	     * line.
	     */
	    count = 1;
	    HTAddParam(&the_command, download_command->command, count, file);
	    if (HTCountCommandArgs(download_command->command) > 1)
		HTAddParam(&the_command, download_command->command, ++count, buffer->str);
	    HTEndParam(&the_command, download_command->command, count);

	} else {
	    HTAlert(MISCONF_DOWNLOAD_COMMAND);
	    goto failed;
	}

	CTRACE((tfp, "command: %s\n", the_command));
	stop_curses();
	LYSystem(the_command);
	FREE(the_command);
	start_curses();
	/* don't remove(file); */
    }

    if (SecondS == TRUE) {
#ifdef VMS
	if (0 == strncasecomp(buffer->str, "sys$disk:", 9)) {
	    if (0 == StrNCmp((buffer->str + 9), "[]", 2)) {
		HTAddSugFilename(buffer->str + 11);
	    } else {
		HTAddSugFilename(buffer->str + 9);
	    }
	} else {
	    HTAddSugFilename(buffer->str);
	}
#else
	HTAddSugFilename(buffer->str);
#endif /* VMS */
    }
    goto cleanup;

  failed:
    HTAlert(CANNOT_DOWNLOAD_FILE);
    goto cleanup;

  cancelled:
    HTInfoMsg(CANCELLING);

  cleanup:
    FREE(Line);
    BStrFree(buffer);
    return;
}
Beispiel #16
0
/*	HTDir_new
**	---------
**    	Creates a structured stream object and sets up the initial HTML stuff
**	Returns the dir object if OK, else NULL
*/
PUBLIC HTDir * HTDir_new (HTRequest * request, HTDirShow show, HTDirKey key)
{    
    HTDir *dir;
    char *title = NULL;
    if (!request) return NULL;

    /* Create object */
    if ((dir = (HTDir *) HT_CALLOC(1, sizeof (HTDir))) == NULL ||
	(dir->fnbuf = (char *) HT_MALLOC(MaxFileW+HT_DLEN_SPACE)) == NULL)
	HT_OUTOFMEM("HTDir_new");
    dir->target = HTMLGenerator(request, NULL, WWW_HTML,
			       HTRequest_outputFormat(request),
			       HTRequest_outputStream(request));
    HTRequest_setOutputConnected(request, YES);
    HTAnchor_setFormat(HTRequest_anchor(request), WWW_HTML);
    dir->request = request;
    dir->show = show;
    dir->key = key;
    if (key==HT_DK_NONE)
	dir->curfw = MaxFileW;
    else {
	dir->curfw = MinFileW;
	dir->array = HTArray_new(256);
    }

    /* We're all OK */
    HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0, "HTDir_new");

    /* Find the length of the fields */
    {
	int len = HT_DLEN_SPACE+1;
	if (show & HT_DS_SIZE) len += (HT_DLEN_SIZE+HT_DLEN_SPACE);
	if (show & HT_DS_DATE) len += (HT_DLEN_DATE+HT_DLEN_SPACE);
	if (show & HT_DS_DES) len += HT_DLEN_DES;
	if ((dir->lnbuf = (char *) HT_MALLOC(len)) == NULL)
	    HT_OUTOFMEM("HTDir_new");
    }

    /* Find the title and the base URL */
    {
	char *addr = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
	char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
	char *ptr;
	if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
	    *ptr = '\0';
	StrAllocCopy(title, path);
	HTUnEscape(title);				 	    /* Title */
	if((ptr=strrchr(path, '/')) && (ptr<path+strlen(path)-1 || ptr==path)){
	    StrAllocCopy(dir->base, ++ptr);
	    StrAllocCat(dir->base, "/");
	}
	HTTRACE(PROT_TRACE, "HTDir_new... base is `%s\'\n" _ dir->base ? dir->base : "");
	HT_FREE(addr);
	HT_FREE(path);
    }

    /* Start the HTML stuff */
    {
	HTStructured *target = dir->target;
	START(HTML_HTML);
	START(HTML_HEAD);
	START(HTML_TITLE);
	PUTS("Current index is ");
	PUTS(title);
	END(HTML_TITLE);
	END(HTML_HEAD);
	START(HTML_BODY);
	START(HTML_H1);
	PUTS("Index of ");
	PUTS(title);
	END(HTML_H1);
    }
    HT_FREE(title);
    return dir;
}
Beispiel #17
0
/*
 *  This function is called from HTLoadNews() to have the user
 *  create a file with news headers and a body for posting of
 *  a new message (based on a newspost://nntp_host/newsgroups
 *  or snewspost://secure_nntp_host/newsgroups URL), or to post
 *  a followup (based on a newsreply://nntp_host/newsgroups or
 *  snewsreply://secure_nntp_host/newsgroups URL). The group
 *  or comma-separated list of newsgroups is passed without
 *  a lead slash, and followup is TRUE for newsreply or
 *  snewsreply URLs.  - FM
 */
char *LYNewsPost(char *newsgroups,
		 BOOLEAN followup)
{
    char user_input[MAX_LINE];
    char CJKinput[MAX_LINE];
    char *cp = NULL;
    const char *kp = NULL;
    int c = 0;			/* user input */
    int len;
    FILE *fd = NULL;
    char my_tempfile[LY_MAXPATH];
    FILE *fc = NULL;
    char CJKfile[LY_MAXPATH];
    char *postfile = NULL;
    char *NewsGroups = NULL;
    char *References = NULL;
    char *org = NULL;
    FILE *fp = NULL;
    BOOLEAN nonempty = FALSE;
    BOOLEAN nonspaces = FALSE;

    /*
     * Make sure a non-zero length newspost, newsreply, snewspost or snewsreply
     * path was sent to us.  - FM
     */
    if (isEmpty(newsgroups))
	return (postfile);

    /*
     * Return immediately if we do get called, maybe by some quirk of HTNews.c,
     * when we shouldn't.  - kw
     */
    if (no_newspost)
	return (postfile);

    /*
     * Open a temporary file for the headers and message body.  - FM
     */
#ifdef __DJGPP__
    if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, BIN_W)) == NULL)
#else
    if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, "w")) == NULL)
#endif /* __DJGPP__ */
    {
	HTAlert(CANNOT_OPEN_TEMP);
	return (postfile);
    }

    /*
     * If we're using a Japanese display character set, open a temporary file
     * for a conversion to JIS.  - FM
     */
    CJKfile[0] = '\0';
    if (current_char_set == UCGetLYhndl_byMIME("euc-jp") ||
	current_char_set == UCGetLYhndl_byMIME("shift_jis")) {
	if ((fc = LYOpenTemp(CJKfile, HTML_SUFFIX, "w")) == NULL) {
	    HTAlert(CANNOT_OPEN_TEMP);
	    LYRemoveTemp(my_tempfile);
	    return (postfile);
	}
    }

    /*
     * The newsgroups could be a comma-seperated list.  It need not have
     * spaces, but deal with any that may also have been hex escaped.  - FM
     */
    StrAllocCopy(NewsGroups, newsgroups);
    if ((cp = strstr(NewsGroups, ";ref="))) {
	*cp = '\0';
	cp += 5;
	if (*cp == '<') {
	    StrAllocCopy(References, cp);
	} else {
	    StrAllocCopy(References, "<");
	    StrAllocCat(References, cp);
	    StrAllocCat(References, ">");
	}
	HTUnEscape(References);
	if (!((cp = strchr(References, '@')) && cp > References + 1 &&
	      isalnum(UCH(cp[1])))) {
	    FREE(References);
	}
    }
    HTUnEscape(NewsGroups);
    if (!*NewsGroups) {
	LYCloseTempFP(fd);	/* Close the temp file. */
	goto cleanup;
    }

    /*
     * Allow ^C to cancel the posting, i.e., don't let SIGINTs exit Lynx.
     */
    signal(SIGINT, terminate_message);
    term_message = FALSE;

    /*
     * Show the list of newsgroups.  - FM
     */
    LYclear();
    LYmove(2, 0);
    scrollok(LYwin, TRUE);	/* Enable scrolling. */
    LYaddstr(gettext("You will be posting to:"));
    LYaddstr("\n\t");
    LYaddstr(NewsGroups);
    LYaddch('\n');

    /*
     * Get the mail address for the From header, offering personal_mail_address
     * as default.
     */
    LYaddstr(gettext("\n\n Please provide your mail address for the From: header\n"));
    sprintf(user_input, "From: %.*s", (int) sizeof(user_input) - 8,
	    NonNull(personal_mail_address));
    if (LYgetstr(user_input, VISIBLE,
		 sizeof(user_input), NORECALL) < 0 ||
	term_message) {
	HTInfoMsg(NEWS_POST_CANCELLED);
	LYCloseTempFP(fd);	/* Close the temp file. */
	scrollok(LYwin, FALSE);	/* Stop scrolling.      */
	goto cleanup;
    }
    fprintf(fd, "%s\n", user_input);

    /*
     * Get the Subject header, offering the current document's title as the
     * default if this is a followup rather than a new post.  - FM
     */
    LYaddstr(gettext("\n\n Please provide or edit the Subject: header\n"));
    strcpy(user_input, "Subject: ");
    if ((followup == TRUE && nhist > 0) &&
	(kp = HText_getTitle()) != NULL) {
	/*
	 * Add the default subject.
	 */
	kp = LYSkipCBlanks(kp);
#ifdef CJK_EX			/* 1998/05/15 (Fri) 09:10:38 */
	if (HTCJK == JAPANESE) {
	    CJKinput[0] = '\0';
	    switch (kanji_code) {
	    case EUC:
		TO_EUC((const unsigned char *) kp, (unsigned char *) CJKinput);
		kp = CJKinput;
		break;
	    case SJIS:
		TO_SJIS((const unsigned char *) kp, (unsigned char *) CJKinput);
		kp = CJKinput;
		break;
	    default:
		break;
	    }
	}
#endif
	if (strncasecomp(kp, "Re:", 3)) {
	    strcat(user_input, "Re: ");
	}
	len = (int) strlen(user_input);
	LYstrncpy(user_input + len, kp, (int) sizeof(user_input) - len - 1);
    }
    cp = NULL;
    if (LYgetstr(user_input, VISIBLE,
		 sizeof(user_input), NORECALL) < 0 ||
	term_message) {
	HTInfoMsg(NEWS_POST_CANCELLED);
	LYCloseTempFP(fd);	/* Close the temp file. */
	scrollok(LYwin, FALSE);	/* Stop scrolling.      */
	goto cleanup;
    }
    fprintf(fd, "%s\n", user_input);

    /*
     * Add Organization:  header.
     */
    StrAllocCopy(cp, "Organization: ");
    if ((org = LYGetEnv("ORGANIZATION")) != NULL) {
	StrAllocCat(cp, org);
    } else if ((org = LYGetEnv("NEWS_ORGANIZATION")) != NULL) {
	StrAllocCat(cp, org);
    }
#ifdef UNIX
    else if ((fp = fopen("/etc/organization", TXT_R)) != NULL) {
	char *buffer = 0;

	if (LYSafeGets(&buffer, fp) != NULL) {
	    if (user_input[0] != '\0') {
		LYTrimNewline(buffer);
		StrAllocCat(cp, buffer);
	    }
	}
	FREE(buffer);
	LYCloseInput(fp);
    }
#else
#ifdef _WINDOWS			/* 1998/05/14 (Thu) 17:47:01 */
    else {
	char *p, fname[LY_MAXPATH];

	strcpy(fname, LynxSigFile);
	p = strrchr(fname, '/');
	if (p != 0 && (p - fname) < sizeof(fname) - 15) {
	    strcpy(p + 1, "LYNX_ETC.TXT");
	    if ((fp = fopen(fname, TXT_R)) != NULL) {
		if (fgets(user_input, sizeof(user_input), fp) != NULL) {
		    if ((org = strchr(user_input, '\n')) != NULL) {
			*org = '\0';
		    }
		    if (user_input[0] != '\0') {
			StrAllocCat(cp, user_input);
		    }
		}
		LYCloseInput(fp);
	    }
	}
    }
#endif /* _WINDOWS */
#endif /* !UNIX */
    LYstrncpy(user_input, cp, (sizeof(user_input) - 16));
    FREE(cp);
    LYaddstr(gettext("\n\n Please provide or edit the Organization: header\n"));
    if (LYgetstr(user_input, VISIBLE,
		 sizeof(user_input), NORECALL) < 0 ||
	term_message) {
	HTInfoMsg(NEWS_POST_CANCELLED);
	LYCloseTempFP(fd);	/* Close the temp file. */
	scrollok(LYwin, FALSE);	/* Stop scrolling.      */
	goto cleanup;
    }
    fprintf(fd, "%s\n", user_input);

    if (References) {
	fprintf(fd, "References: %s\n", References);
    }
    /*
     * Add Newsgroups Summary and Keywords headers.
     */
    fprintf(fd, "Newsgroups: %s\nSummary: \nKeywords: \n\n", NewsGroups);

    /*
     * Have the user create the message body.
     */
    if (!no_editor && non_empty(editor)) {

	if (followup && nhist > 0) {
	    /*
	     * Ask if the user wants to include the original message.
	     */
	    if (term_message) {
		_statusline(INC_ORIG_MSG_PROMPT);
	    } else if (HTConfirm(INC_ORIG_MSG_PROMPT) == YES) {
		/*
		 * The 'TRUE' will add the reply ">" in front of every line. 
		 * We're assuming that if the display character set is Japanese
		 * and the document did not have a CJK charset, any non-EUC or
		 * non-SJIS 8-bit characters in it where converted to 7-bit
		 * equivalents.  - FM
		 */
		print_wwwfile_to_fd(fd, FALSE, TRUE);
	    }
	}
	LYCloseTempFP(fd);	/* Close the temp file. */
	scrollok(LYwin, FALSE);	/* Stop scrolling.      */
	if (term_message || LYCharIsINTERRUPT(c))
	    goto cleanup;

	/*
	 * Spawn the user's editor on the news file.
	 */
	edit_temporary_file(my_tempfile, "", SPAWNING_EDITOR_FOR_NEWS);

	nonempty = message_has_content(my_tempfile, &nonspaces);

    } else {
	/*
	 * Use the built in line editior.
	 */
	LYaddstr(gettext("\n\n Please enter your message below."));
	LYaddstr(gettext("\n When you are done, press enter and put a single period (.)"));
	LYaddstr(gettext("\n on a line and press enter again."));
	LYaddstr("\n\n");
	LYrefresh();
	*user_input = '\0';
	if (LYgetstr(user_input, VISIBLE,
		     sizeof(user_input), NORECALL) < 0 ||
	    term_message) {
	    HTInfoMsg(NEWS_POST_CANCELLED);
	    LYCloseTempFP(fd);	/* Close the temp file. */
	    scrollok(LYwin, FALSE);	/* Stop scrolling.      */
	    goto cleanup;
	}
	while (!STREQ(user_input, ".") && !term_message) {
	    LYaddch('\n');
	    fprintf(fd, "%s\n", user_input);
	    if (!nonempty && strlen(user_input))
		nonempty = TRUE;
	    *user_input = '\0';
	    if (LYgetstr(user_input, VISIBLE,
			 sizeof(user_input), NORECALL) < 0) {
		HTInfoMsg(NEWS_POST_CANCELLED);
		LYCloseTempFP(fd);	/* Close the temp file. */
		scrollok(LYwin, FALSE);		/* Stop scrolling.      */
		goto cleanup;
	    }
	}
	fprintf(fd, "\n");
	LYCloseTempFP(fd);	/* Close the temp file. */
	scrollok(LYwin, FALSE);	/* Stop scrolling.      */
    }

    if (nonempty) {
	/*
	 * Confirm whether to post, and if so, whether to append the sig file. 
	 * - FM
	 */
	LYStatusLine = (LYlines - 1);
	c = HTConfirm(POST_MSG_PROMPT);
	LYStatusLine = -1;
	if (c != YES) {
	    LYclear();		/* clear the screen */
	    goto cleanup;
	}
    } else {
	HTAlert(gettext("Message has no original text!"));
	if (!nonspaces
	    || HTConfirmDefault(POST_MSG_PROMPT, NO) != YES)
	    goto cleanup;
    }
    if ((LynxSigFile != NULL) && (fp = fopen(LynxSigFile, TXT_R)) != NULL) {
	char *msg = NULL;

	HTSprintf0(&msg, APPEND_SIG_FILE, LynxSigFile);

	LYStatusLine = (LYlines - 1);
	if (term_message) {
	    _user_message(APPEND_SIG_FILE, LynxSigFile);
	} else if (HTConfirm(msg) == YES) {
	    if ((fd = LYAppendToTxtFile(my_tempfile)) != NULL) {
		char *buffer = NULL;

		fputs("-- \n", fd);
		while (LYSafeGets(&buffer, fp) != NULL) {
		    fputs(buffer, fd);
		}
		LYCloseOutput(fd);
	    }
	}
	LYCloseInput(fp);
	FREE(msg);
	LYStatusLine = -1;
    }
    LYclear();			/* clear the screen */

    /*
     * If we are using a Japanese display character set, convert the contents
     * of the temp file to JIS (nothing should change if it does not, in fact,
     * contain EUC or SJIS di-bytes).  Otherwise, use the temp file as is.  -
     * FM
     */
    if (CJKfile[0] != '\0') {
	if ((fd = fopen(my_tempfile, TXT_R)) != NULL) {
	    char *buffer = NULL;

	    while (LYSafeGets(&buffer, fd) != NULL) {
		TO_JIS((unsigned char *) buffer,
		       (unsigned char *) CJKinput);
		fputs(CJKinput, fc);
	    }
	    LYCloseTempFP(fc);
	    StrAllocCopy(postfile, CJKfile);
	    LYCloseInput(fd);
	    LYRemoveTemp(my_tempfile);
	    strcpy(my_tempfile, CJKfile);
	    CJKfile[0] = '\0';
	} else {
	    StrAllocCopy(postfile, my_tempfile);
	}
    } else {
	StrAllocCopy(postfile, my_tempfile);
    }
    if (!followup) {
	/*
	 * If it's not a followup, the current document most likely is the
	 * group listing, so force a to have the article show up in the list
	 * after the posting.  Note, that if it's a followup via a link in a
	 * news article, the user must do a reload manually on returning to the
	 * group listing.  - FM
	 */
	LYforce_no_cache = TRUE;
    }
    LYStatusLine = (LYlines - 1);
    HTUserMsg(POSTING_TO_NEWS);
    LYStatusLine = -1;

    /*
     * Come here to cleanup and exit.
     */
  cleanup:
#ifndef VMS
    signal(SIGINT, cleanup_sig);
#endif /* !VMS */
    term_message = FALSE;
    if (!postfile)
	LYRemoveTemp(my_tempfile);
    LYRemoveTemp(CJKfile);
    FREE(NewsGroups);
    FREE(References);

    return (postfile);
}
Beispiel #18
0
/*	Convert file URLs into a local representation
**	---------------------------------------------
**	The URL has already been translated through the rules in get_physical
**	in HTAccess.c and all we need to do now is to map the path to a local
**	representation, for example if must translate '/' to the ones that
**	turn the wrong way ;-)
**	Returns:
**		OK:	local file (that must be freed by caller)
**		Error:	NULL
*/
PUBLIC char * HTWWWToLocal (const char * url, const char * base,
                            HTUserProfile * up)
{
    if (url) {
        char * access = HTParse(url, base, PARSE_ACCESS);
        char * host = HTParse(url, base, PARSE_HOST);
        char * path = HTParse(url, base, PARSE_PATH+PARSE_PUNCTUATION);
        const char * myhost = HTUserProfile_fqdn(up);

        /* Find out if this is a reference to the local file system */
        if ((*access && strcmp(access, "file") && strcmp(access, "cache")) ||
                (*host && strcasecomp(host, "localhost") &&
                 myhost && strcmp(host, myhost))) {
            HTTRACE(CORE_TRACE, "LocalName... Not on local file system\n");
            HT_FREE(access);
            HT_FREE(host);
            HT_FREE(path);
            return NULL;
        } else {
            char *ptr;
            if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
                *ptr = '\0';

            /*
            ** Do whatever translation is required here in order to fit your
            ** platform _before_ the path is unescaped.
            */
#ifdef VMS
            HTVMS_checkDecnet(path);
#endif
#ifdef WWW_MSWINDOWS
            /* An absolute pathname with logical drive */
            if (*path == '/' && path[2] == ':') {
                char *orig=path, *dest=path+1;
                while((*orig++ = *dest++));

                /* A network host */
            } else if (*host && strcasecomp(host, "localhost")) {
                char * newpath = NULL;
                StrAllocMCopy(&newpath, "//", host, path, NULL);
                HT_FREE(path);
                path = newpath;
            }

            /* Convert '/' to '\' */
            {
                char *p = path;
                while (*p) {
                    if (*p=='/') *p='\\';
                    p++;
                }
            }
#endif

            HTUnEscape(path);		  /* Take out the escaped characters */
            HTTRACE(CORE_TRACE, "Node........ `%s' means path `%s'\n" _ url _ path);
            HT_FREE(access);
            HT_FREE(host);
            return path;
        }
    }
    return NULL;
}
Beispiel #19
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);
}
Beispiel #20
0
/*
 *  In edit mode invoke the given (or default) editor to display and edit the
 *  current file.  For editors listed in 'editor_can_position()', Lynx
 *  will open the file to the same line that the screen cursor is on (or
 *  close...) when editing is invoked.
 *
 *  Returns FALSE if file is uneditable.
 */
PUBLIC int edit_current_file ARGS3(
	char *,		newfile,
	int,		cur,
	int,		lineno)
{
    int result = FALSE;
    char *filename = NULL;
#if !(defined(VMS) || defined(USE_DOS_DRIVES))
    char *colon;
#endif
    char *number_sign;
    char position[80];
#if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES)
    FILE *fp;
#endif

    CTRACE((tfp, "edit_current_file(newfile=%s, cur=%d, lineno=%d)\n",
		 newfile, cur, lineno));

    /*
     *  If it's a remote file then we can't edit it.
     */
    if (!LYisLocalFile(newfile)) {
	HTUserMsg(CANNOT_EDIT_REMOTE_FILES);
	return FALSE;
    }

    /*
     *  If there's a fragment, trim it. - FM
     */
    number_sign = trimPoundSelector(newfile);

    /*
     *  On Unix, first try to open it as a completely referenced file,
     *  then via the path alone.
     *
     * On VMS, only try the path.
     */
#if defined (VMS) || defined (USE_DOS_DRIVES)
    filename = HTParse(newfile, "", PARSE_PATH+PARSE_PUNCTUATION);
    HTUnEscape(filename);
    StrAllocCopy(filename, HTSYS_name(filename));
    if (!LYCanReadFile(filename)) {
#ifdef SH_EX
	HTUserMsg2(COULD_NOT_EDIT_FILE, filename);
#else
	HTAlert(COULD_NOT_ACCESS_FILE);
#endif
	CTRACE((tfp, "filename: '%s'\n", filename));
	goto done;
    }
#else	/* something like UNIX */
    if (strncmp(newfile, "file://localhost/", 16) == 0)
	colon = newfile + 16;
    else
	colon = strchr(newfile, ':');
    StrAllocCopy(filename, (colon + 1));
    HTUnEscape(filename);
    if (!LYCanReadFile(filename)) {
	FREE(filename);
	filename = HTParse(newfile, "", PARSE_PATH+PARSE_PUNCTUATION);
	HTUnEscape(filename);
	if (!LYCanReadFile(HTSYS_name(filename))) {
	    HTAlert(COULD_NOT_ACCESS_FILE);
	    goto done;
	}
    }
#endif

#if defined(VMS) || defined(CANT_EDIT_UNWRITABLE_FILES)
    /*
     *  Don't allow editing if user lacks append access.
     */
    if ((fp = fopen(filename, TXT_A)) == NULL)
    {
	HTUserMsg(NOAUTH_TO_EDIT_FILE);
	goto done;
    }
    fclose(fp);
#endif /* VMS || CANT_EDIT_UNWRITABLE_FILES */

    /*
     *  Make sure cur is at least zero. - FM
     */
    if (cur < 0) {
	cur = 0;
    }

    /*
     *  Set up the command for the editor. - FM
     */
    *position = 0;
#ifdef VMS
    lineno--;
#endif
    lineno += (nlinks ? links[cur].ly : 0);
    if (lineno > 0)
	sprintf(position, "%d", lineno);

    edit_temporary_file(filename, position, NULL);
    result = TRUE;

done:
    /*
     *  Restore the fragment if there was one. - FM
     */
    restorePoundSelector(number_sign);

    FREE(filename);
    CTRACE((tfp, "edit_current_file returns %d\n", result));
    return (result);
}
Beispiel #21
0
PRIVATE int NewsEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    news_info *news = (news_info *)pVoid;
    int status = HT_ERROR;
    HTNet * net = news->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * url = HTAnchor_physical(anchor);
    HTHost * host = HTNet_host(net);
    
    /*
    ** Initiate a new nntp structure and bind to request structure
    ** This is actually state NNTP_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {			      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadHTTP");
	HTNewsCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    } else
	news = (news_info *) HTNet_context(net);		/* Get existing copy */

    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
        switch (news->state) {
          case NEWS_BEGIN:
	    news->state = (!strchr(url, '@') && strchr(url, '*')) ?
		NEWS_SEEK_CACHE : NEWS_NEED_CONNECTION;
	    break;

	case NEWS_SEEK_CACHE:
	    if (HTNewsCache_before(request, NULL, 0) == HT_LOADED)
		news->state = NEWS_SUCCESS;
	    else
		news->state = NEWS_NEED_CONNECTION;
	    break;

	  case NEWS_NEED_CONNECTION: 		/* Let's set up a connection */
	    if (!strncasecomp(url, "news:", 5)) {
		HTUserProfile * up = HTRequest_userProfile(request);
		char * newshost = HTUserProfile_news(up);
		StrAllocCopy(news->name, url+5);
		if (newshost) {
		    char *newshack = NULL;    /* Then we can use HTParse :-) */
		    StrAllocCopy(newshack, "news://");
		    StrAllocCat(newshack, newshost);
		    status = HTHost_connect(host, net, (char *) newshack);
		    host = HTNet_host(net);
		    HT_FREE(newshack);
		} else
		    news->state = NEWS_ERROR;
	    } else if (!strncasecomp(url, "nntp:", 5)) {
		news->name = HTParse(url, "", PARSE_PATH);
		status = HTHost_connect(host, net, url);
		host = HTNet_host(net);
	    } else {
		HTTRACE(PROT_TRACE, "News........ Huh?");
		news->state = NEWS_ERROR;
            }
            if (status == HT_OK) {
		BOOL greeting = NO;

		/* Set up the persistent connection */
		if (!HTNet_persistent(net)) {
		    HTNet_setPersistent(net, YES, HT_TP_SINGLE);
		    greeting = YES;
		}

		/*
		** Check the protocol class to see if we have connected to a
		** the right class of server, in this case HTTP.
		*/
		{
		    HTHost * host = HTNet_host(net);
		    char * s_class = HTHost_class(host);
		    if (s_class && strcasecomp(s_class, "nntp")) {
			HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS,
					   NULL, 0, "HTLoadNews");
			news->state = NEWS_ERROR;
			break;
		    }
		    HTHost_setClass(host, "nntp");
		}

		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTNewsStatus_new(request, news, host);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		news->state = greeting ? NEWS_NEED_GREETING : NEWS_NEED_SWITCH;

	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_GREETING:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED) {
		if (news->repcode/100 == 2)
		    news->state = NEWS_NEED_SWITCH;
		else
		    news->state = NEWS_ERROR;
	    } else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_SWITCH:
	  {
	      HTMethod method = HTRequest_method(request);
	      /*
	      ** Find out what to ask the news server. Syntax of address is
	      **	xxx@yyy		Article
	      **	<xxx@yyy>	Same article
	      **	xxxxx		News group (no "@")
	      */
	      if (method == METHOD_GET) {
		  if (strchr(url, '@')) {				  /* ARTICLE */
		      if (*(news->name) != '<') {		  /* Add '<' and '>' */
			  char *newart;
			  if ((newart = (char  *) HT_MALLOC(strlen(news->name)+3)) == NULL)
			      HT_OUTOFMEM("HTLoadNews");
			  sprintf(newart, "<%s>", news->name);
			  HT_FREE(news->name);
			  news->name = newart;
		      }
		      news->state = NEWS_NEED_ARTICLE;
		  } else if (strchr(url, '*'))
		      news->state = NEWS_NEED_LIST;
		  else
		      news->state = NEWS_NEED_GROUP;
	      } else if (method == METHOD_POST)
		  news->state = NEWS_NEED_POST;
	      else {
		  HTRequest_addError(request, ERR_FATAL, NO,
				     HTERR_NOT_IMPLEMENTED,NULL, 0,"HTLoadNews");
		  news->state = NEWS_ERROR;
	      }
	      HTUnEscape(news->name);
	      HTCleanTelnetString(news->name);
	  }
	  break;

	  case NEWS_NEED_ARTICLE:
	    if (!news->sent) {
		status = SendCommand(request, news, "ARTICLE", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_MIME;

		/*
		** Set the default content type to plain text as news servers
		** almost never send any useful information about the length
		** of the body or the type - the success of MIME!
		*/
		HTAnchor_setFormat(anchor, WWW_PLAINTEXT);
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

#if HT_LISTGROUP
	  case NEWS_NEED_LGRP:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", "NEWSGROUPS");
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
 		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_NEED_LIST;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;
#endif /* HT_LISTGROUP */

	  case NEWS_NEED_LIST:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", NULL);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_GROUP:
	    if (!news->sent) {
		status = SendCommand(request, news, "GROUP", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (sscanf(news->reply, "%d%d%d", &news->total,
				   &news->first, &news->last) == 3) {
			    if (MaxArt && news->total>MaxArt)
				news->last = news->first-MaxArt;
			    news->current = news->first;

			    /* If no content in this group */
			    if (news->first == news->last) {
				HTRequest_addError(request, ERR_FATAL, NO,
						   HTERR_NO_CONTENT,
						   NULL, 0, "HTLoadNews");
				news->state = NEWS_NO_DATA;
				break;
			    }
			    news->state = NEWS_NEED_XOVER;
			} else
			    news->state = NEWS_ERROR;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_XOVER:
	    if (!news->sent) {
		char buf[20];
		sprintf(buf, "%d-%d", news->first, news->last);
		status = SendCommand(request, news, "XOVER", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_OVER;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2)
			news->state = NEWS_SUCCESS;
		    else {
			news->format = WWW_NNTP_HEAD;
			news->state = NEWS_NEED_HEAD;
		    }
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_HEAD:
	    if (!news->sent) {
		char buf[10];
		sprintf(buf, "%d", news->current++);
		status = SendCommand(request, news, "HEAD", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (news->current > news->last)
			    news->state = NEWS_SUCCESS;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_POST:
	  {
	      HTStream * oldinput = HTRequest_inputStream(request);
	      HTStream * newinput =
		  HTNewsPost_new(request, HTBuffer_new(oldinput, request,512));
	      HTRequest_setInputStream(request, newinput);
	      
	      /* Remember to convert to CRLF */

	  }
	  news->state = NEWS_NEED_BODY;
	  break;

          case NEWS_NEED_BODY:
            if (type == HTEvent_WRITE || type == HTEvent_BEGIN) {
		if (HTRequest_isDestination(request)) {
		    HTRequest * source = HTRequest_source(request);
		    HTNet * srcnet = HTRequest_net(source);
		    if (srcnet) {
			HTHost_register(HTNet_host(srcnet), srcnet, HTEvent_READ);
			HTHost_unregister(HTNet_host(srcnet), srcnet, HTEvent_WRITE);
		    }
		    return HT_OK;
		}

		/*
		**  Should we use the input stream directly or call the post
		**  callback function to send data down to the network?
		*/
		{
		    HTStream * input = HTRequest_inputStream(request);
		    HTPostCallback * pcbf = HTRequest_postCallback(request);
		    if (pcbf) {
			status = pcbf(request, input);
			if (status == HT_PAUSE || status == HT_LOADED)
			    type = HTEvent_READ;
		    } else {
			status = (*input->isa->flush)(input);
			type = HTEvent_READ;
		    }
		    if (status == HT_WOULD_BLOCK) return HT_OK;
		}
		status = request->PostCallback ?
                    request->PostCallback(request, request->input_stream) :
			(*request->input_stream->isa->flush)(request->input_stream);
 		if (status == HT_WOULD_BLOCK)
                    return HT_OK;
                else 	
                    type = HTEvent_READ;	  /* Trick to ensure that we do READ */
	    } else if (type == HTEvent_READ) {
                status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
                else if (status == HT_LOADED)
		    news->state = NEWS_SUCCESS;
		else
		    news->state = NEWS_ERROR;
	    } else {
		news->state = NEWS_ERROR;
	    }
	    break;
		
	  case NEWS_SUCCESS:
	    HTNewsCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	case NEWS_NO_DATA:
	    HTNewsCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case NEWS_ERROR:
	    HTNewsCleanup(request, HT_NOT_FOUND);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}
Beispiel #22
0
/*							HTVMSBrowseDir()
**
**	This function generates a directory listing as an HTML-object
**	for local file URL's.  It assumes the first two elements of
**	of the path are a device followed by a directory:
**
**		file://localhost/device/directory[/[foo]]
**
**	Will not accept 000000 as a directory name.
**	Will offer links to parent through the top directory, unless
**	a terminal slash was included in the calling URL.
**
**	Returns HT_LOADED on success, HTLoadError() messages on error.
**
**	Developed for Lynx by Foteos Macrides ([email protected]).
*/
PUBLIC int HTVMSBrowseDir ARGS4(
	CONST char *,		address,
	HTParentAnchor *,	anchor,
	HTFormat,		format_out,
	HTStream *,		sink
)
{
    HTStructured* target;
    HTStructuredClass targetClass;
    char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION);
    char *tail = NULL;
    char *title = NULL;
    char *header = NULL;
    char *parent = NULL;
    char *relative = NULL;
    char *cp, *cp1;
    int  pathend, len;
    DIR *dp;
    struct stat file_info;
    time_t NowTime;
    static char ThisYear[8];
    VMSEntryInfo *entry_info = 0;
    char string_buffer[64];

    HTUnEscape(pathname);
    CTRACE((tfp,"HTVMSBrowseDir: Browsing `%s\'\n", pathname));

    /*
     *  Require at least two elements (presumably a device and directory)
     *  and disallow the device root (000000 directory).  Symbolic paths
     *  (e.g., sys$help) should have been translated and expanded (e.g.,
     *  to /sys$sysroot/syshlp) before calling this routine.
     */
    if (((*pathname != '/') ||
	 (cp = strchr(pathname+1, '/')) == NULL ||
	 *(cp + 1) == '\0' ||
	 0 == strncmp((cp + 1), "000000", 6)) ||
	(dp = HTVMSopendir(pathname)) == NULL) {
	FREE(pathname);
	return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR);
    }

    /*
     *  Set up the output stream.
     */
    _HTProgress (BUILDING_DIR_LIST);
    if (UCLYhndl_HTFile_for_unspec >= 0) {
	HTAnchor_setUCInfoStage(anchor,
				UCLYhndl_HTFile_for_unspec,
				UCT_STAGE_PARSER,
				UCT_SETBY_DEFAULT);
    }
    target = HTML_new(anchor, format_out, sink);
    targetClass = *(target->isa);

    /*
     *  Set up the offset string of the anchor reference,
     *  and strings for the title and header.
     */
    cp = strrchr(pathname, '/');  /* find lastslash */
    StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */
    if (*tail != '\0') {
	StrAllocCopy(title, tail);
	*cp = '\0';
	if ((cp1=strrchr(pathname, '/')) != NULL &&
	    cp1 != pathname &&
	    strncmp((cp1+1), "000000", 6))
	    StrAllocCopy(parent, (cp1+1));
	*cp = '/';
    } else {
	pathname[strlen(pathname)-1] = '\0';
	cp = strrchr(pathname, '/');
	StrAllocCopy(title, (cp+1));
	pathname[strlen(pathname)] = '/';
    }
    StrAllocCopy(header, pathname);

    /*
     *  Initialize path name for HTStat().
     */
    pathend = strlen(pathname);
    if (*(pathname+pathend-1) != '/') {
	StrAllocCat(pathname, "/");
	pathend++;
    }

    /*
     *  Output the title and header.
     */
    START(HTML_HTML);
    PUTC('\n');
    START(HTML_HEAD);
    PUTC('\n');
    HTUnEscape(title);
    START(HTML_TITLE);
    PUTS(title);
    PUTS(" directory");
    END(HTML_TITLE);
    PUTC('\n');
    FREE(title);
    END(HTML_HEAD);
    PUTC('\n');
    START(HTML_BODY);
    PUTC('\n');
    HTUnEscape(header);
    START(HTML_H1);
    PUTS(header);
    END(HTML_H1);
    PUTC('\n');
    if (HTDirReadme == HT_DIR_README_TOP) {
	FILE * fp;
	if (header[strlen(header)-1] != '/')
	    StrAllocCat(header, "/");
	StrAllocCat(header, HT_DIR_README_FILE);
	if ((fp = fopen(header,	 "r")) != NULL) {
	    START(HTML_PRE);
	    for(;;) {
		char c = fgetc(fp);
		if (c == (char)EOF)
		    break;
#ifdef NOTDEFINED
		switch (c) {
		    case '&':
		    case '<':
		    case '>':
			PUTC('&');
			PUTC('#');
			PUTC((char)(c / 10));
			PUTC((char) (c % 10));
			PUTC(';');
			break;
		    default:
			PUTC(c);
		}
#else
		PUTC(c);
#endif /* NOTDEFINED */
	    }
	    END(HTML_PRE);
	    fclose(fp);
	}
    }
    FREE(header);
    if (parent) {
	HTSprintf0(&relative, "%s/..", tail);
	HTStartAnchor(target, "", relative);
	PUTS("Up to ");
	HTUnEscape(parent);
	PUTS(parent);
	END(HTML_A);
	START(HTML_P);
	PUTC('\n');
	FREE(relative);
	FREE(parent);
    }

    /*
     *  Set up the date comparison.
     */
    NowTime = time(NULL);
    strcpy(ThisYear, (char *)ctime(&NowTime)+20);
    ThisYear[4] = '\0';

    /*
     * Now, generate the Btree and put it out to the output stream.
     */
    {
	char dottest = 2;	/* To avoid two strcmp() each time */
	STRUCT_DIRENT *dirbuf;
	HTBTree *bt;

	/* Set up sort key and initialize BTree */
	bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs);

	/* Build tree */
	while ((dirbuf = HTVMSreaddir(dp))) {
	    HTAtom *encoding = NULL;
	    HTFormat format;

	    /* Skip if not used */
	    if (!dirbuf->d_ino)	{
		continue;
	    }

	    /* Current and parent directories are never shown in list */
	    if (dottest && (!strcmp(dirbuf->d_name, ".") ||
			    !strcmp(dirbuf->d_name, ".."))) {
		dottest--;
		continue;
	    }

	    /* Don't show the selective enabling file
	     * unless version numbers are included */
	    if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) {
		continue;
	    }

	    /* Skip files beginning with a dot? */
	    if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') {
		continue;
	    }

	    /* OK, make an lstat() and get a key ready. */
	    *(pathname+pathend) = '\0';
	    StrAllocCat(pathname, dirbuf->d_name);
	    if (HTStat(pathname, &file_info)) {
		/* for VMS the failure here means the file is not readable...
		   we however continue to browse through the directory... */
		continue;
	    }
	    entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo));
	    if (entry_info == NULL)
		outofmem(__FILE__, "HTVMSBrowseDir");
	    entry_info->type = 0;
	    entry_info->size = 0;
	    entry_info->date = 0;
	    entry_info->filename = 0;
	    entry_info->display = TRUE;

	    /* Get the type */
	    format = HTFileFormat(dirbuf->d_name, &encoding,
				  (CONST char **)&cp);
	    if (!cp) {
		if(!strncmp(HTAtom_name(format), "application",11))
		{
		    cp = HTAtom_name(format) + 12;
		    if(!strncmp(cp,"x-", 2))
			cp += 2;
		}
		else
		    cp = HTAtom_name(format);
	    }
	    StrAllocCopy(entry_info->type, cp);

	    StrAllocCopy(entry_info->filename, dirbuf->d_name);
	    if (S_ISDIR(file_info.st_mode)) {
		/* strip .DIR part... */
		char *dot;
		dot = strstr(entry_info->filename, ".DIR");
		if (dot)
		   *dot = '\0';
		LYLowerCase(entry_info->filename);
		StrAllocCopy(entry_info->type, "Directory");
	    } else {
		if ((cp = strstr(entry_info->filename, "READ")) == NULL) {
		    cp = entry_info->filename;
		} else {
		    cp += 4;
		    if (!strncmp(cp, "ME", 2)) {
			cp += 2;
			while (cp && *cp && *cp != '.') {
			    cp++;
			}
		    } else if (!strncmp(cp, ".ME", 3)) {
			cp = (entry_info->filename +
			      strlen(entry_info->filename));
		    } else {
			cp = entry_info->filename;
		    }
		}
		LYLowerCase(cp);
		if (((len = strlen(entry_info->filename)) > 2) &&
		    entry_info->filename[len-1] == 'z') {
		    if (entry_info->filename[len-2] == '.' ||
			entry_info->filename[len-2] == '_')
			entry_info->filename[len-1] = 'Z';
		}
	    }

	    /* Get the date */
	    {
		char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime);
		*(t+24) = '\0';

		StrAllocCopy(entry_info->date, (t+4));
		*((entry_info->date)+7) = '\0';
		if ((atoi((t+19))) < atoi(ThisYear))
		    StrAllocCat(entry_info->date,  (t+19));
		else {
		    StrAllocCat(entry_info->date, (t+11));
		    *((entry_info->date)+12) = '\0';
		}
	    }

	    /* Get the size */
	    if (!S_ISDIR(file_info.st_mode))
		entry_info->size = (unsigned int)file_info.st_size;
	    else
		entry_info->size = 0;

	    /* Now, update the BTree etc. */
	    if(entry_info->display)
	      {
		 CTRACE((tfp,"Adding file to BTree: %s\n",
						      entry_info->filename));
		 HTBTree_add(bt, entry_info);
	      }

	} /* End while HTVMSreaddir() */

	FREE(pathname);
	HTVMSclosedir(dp);

	START(HTML_PRE);
	/*
	 * Run through the BTree printing out in order
	 */
	{
	    HTBTElement * ele;
	    int i;
	    for (ele = HTBTree_next(bt, NULL);
		 ele != NULL;
		 ele = HTBTree_next(bt, ele))
	    {
		entry_info = (VMSEntryInfo *)HTBTree_object(ele);

		/* Output the date */
		if(entry_info->date)
		       {
			     PUTS(entry_info->date);
			     PUTS("  ");
		       }
		else
			PUTS("     * ");

		/* Output the type */
		if(entry_info->type)
		  {
		    for(i = 0; entry_info->type[i] != '\0' && i < 15; i++)
			PUTC(entry_info->type[i]);
		    for(; i < 17; i++)
			PUTC(' ');

		  }

		/* Output the link for the name */
		HTDirEntry(target, tail, entry_info->filename);
		PUTS(entry_info->filename);
		END(HTML_A);

		/* Output the size */
		if(entry_info->size)
		  {
			  if(entry_info->size < 1024)
			      sprintf(string_buffer,"  %d bytes",
							entry_info->size);
			  else
			      sprintf(string_buffer,"  %dKb",
							entry_info->size/1024);
			  PUTS(string_buffer);
		  }

		PUTC('\n'); /* end of this entry */

		free_VMSEntryInfo_contents(entry_info);
	    }
	}

	HTBTreeAndObject_free(bt);

    } /* End of both BTree loops */

    /*
     *  Complete the output stream.
     */
    END(HTML_PRE);
    PUTC('\n');
    END(HTML_BODY);
    PUTC('\n');
    END(HTML_HTML);
    PUTC('\n');
    FREE(tail);
    FREE_TARGET;

    return HT_LOADED;

} /* End of directory reading section */