This commit is contained in:
Alan Dipert
2010-03-08 05:55:21 -05:00
commit 29c82be0c2
528 changed files with 159411 additions and 0 deletions

683
libwww2/CUkerb.c Normal file
View File

@@ -0,0 +1,683 @@
/* Ben Fried deserves credit for writing the code that upon which
* this source is based. ADC
*/
#include "../config.h"
#if defined(KRB4) || defined(KRB5)
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <pwd.h>
#include "HTAAUtil.h" /* for HTAA_KERBEROS_Vx defines */
#ifdef KRB4
#include <krb.h>
#define MAX_KDATA_LEN MAX_KTXT_LEN
static des_cblock session; /* Our session key */
static des_key_schedule schedule; /* Schedule for our session key */
int k4checksum;
#endif
#ifdef KRB5
#include <krb5.h>
#include <krb_err.h>
#ifndef MAX_KDATA_LEN
#define MAX_KDATA_LEN 1250
#endif
#define KRB5_DEFAULT_LIFE 60*60*8 /* 8 hours */
krb5_auth_context *k5auth_context;
krb5_context k5context = 0;
krb5_ccache k5ccache;
#endif
/* is all of this necessary? ADC */
char *getenv(), *getlogin(); /* *index(), *malloc(), *realloc(); */
struct passwd *getpwnam(), *getpwuid();
static char *envariables[] = { "USER", "LOGNAME" };
extern int useAFS; /* perhaps change name */
int doing_kerb_auth = 0;
char phost[1024];
char Hostname[1024];
#define NIL 0
#define T 1
/* Table for converting binary values to and from hexadecimal */
static char hex[] = "0123456789abcdef";
static char dec[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 37 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* '0' - '?' */
0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'P' - '_' */
0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'p' - DEL */
};
/****************************************************************************
* scheme_login -- lets user login for Kerberos TGT
*
* Returns 0 on success
* Returns 1 on failure (after reporting error to user)
***************************************************************************/
int scheme_login(scheme)
int scheme;
{
char *username, *password, buf[BUFSIZ], erbuf[BUFSIZ];
int code;
username = (char *) prompt_for_string("Kerberos Username:");
if (!username || !*username) {
application_user_info_wait("You did not enter a Username.\nCannot get Kerberos ticket-granting ticket\n");
return 1;
}
sprintf(buf, "Password for %s:", username);
password = (char *) prompt_for_password(buf);
if (!password || !*password) {
application_user_info_wait("You did not enter a Password.\nCannot obtain ticket-granting ticket\n");
return 1;
}
if (0) { /* just to get things started */
}
#ifdef KRB4
else if (scheme == HTAA_KERBEROS_V4) {
if (useAFS) {
code = AFSgetTGT(username, password, buf);
}
else {
code = k4getTGT(username, password, buf);
}
}
#endif
#ifdef KRB5
else if (scheme == HTAA_KERBEROS_V5) {
code = k5getTGT(username, password, buf);
}
#endif
memset(password, 0, sizeof(password));
if (code) {
sprintf(erbuf,"Kerberos login error:\n%s",buf);
application_user_info_wait(erbuf);
return 1;
}
return 0;
}
/****************************************************************************
* AFSgetTGT() -- Uses klog to get the K4 TGT
*
* Returns 1 if pipe open fails
* Returns 0 otherwise (even if klog fails!)
***************************************************************************/
int AFSgetTGT(username, password, err_string)
char *err_string, *username, *password;
{
char reason[256];
register int code;
FILE *fp;
char lngbuf[BUFSIZ*2],buf[BUFSIZ];
char stop=0;
int n;
sprintf(buf,"klog -tmp -pr %s -pa %s 2>&1",username,password);
if (!(fp=popen(buf,"r"))) {
application_user_info_wait("Error: Could not startup external klog command.\n");
return(1);
}
strcpy(buf," ");
strcpy(lngbuf," ");
n=1;
while (n>0) {
n=fread(buf,sizeof(char),BUFSIZ-1,fp);
if (n>0) {
if (!stop && (n+strlen(lngbuf))<BUFSIZ*2) {
buf[n]='\0';
strcat(lngbuf,buf);
}
else {
stop=1;
}
}
}
pclose(fp);
if (strlen(lngbuf)>1) {
application_user_info_wait(lngbuf);
}
return(0);
}
#ifdef KRB4
/****************************************************************************
* passwd_to_key -- convert users password to numeric key
*
* (cribbed from MIT's krb_get_in_tkt.c)
* this can probably be augmented to support Transarc's string-to-key
***************************************************************************/
static int passwd_to_key(user,instance,realm,passwd,key)
char *user, *instance, *realm, *passwd;
C_Block key;
{
string_to_key(passwd, key);
return (0);
}
/****************************************************************************
* k4getTGT() -- calls K4 libraries to get TGT (non-AFS)
*
* Returns 0 on success (err_string = "")
* Returns 1 on failure (err_string = something meaningful)
***************************************************************************/
int k4getTGT(username, password, err_string)
char *err_string, *username, *password;
{
char instance[INST_SZ], *sinstance;
char realm[REALM_SZ];
char pname[MAX_K_NAME_SZ];
int lifetime = DEFAULT_TKT_LIFE;
int code;
*instance = '\0'; /* assume client principal "user@realm" (no instance */
krb_get_lrealm(realm, 1); /* get local realm */
strcpy(pname, username);
strcat(pname, "@");
strncat(pname, realm, REALM_SZ);
sinstance = realm; /* assume tgt is for krbtgt.realm@realm */
in_tkt(pname, instance); /* to initialize ticket store */
code = krb_get_in_tkt(username, instance, realm, "krbtgt", sinstance,
lifetime, passwd_to_key , NULL, password);
if (code == INTK_BADPW) {
strcpy(err_string, "Wrong password");
return 1;
}
else if (code != INTK_OK) {
strcpy(err_string, krb_err_txt[code]);
return 1;
}
return 0;
}
#endif /* KRB4 */
#ifdef KRB5
/****************************************************************************
* k5getTGT() -- calls K5 libraries to get TGT (non-AFS)
* most of this was copied from the Krb5 kinit.c
*
* Returns 0 on success (err_string = "")
* Returns 1 on failure (err_string = something meaningful)
***************************************************************************/
int k5getTGT(username, password, err_string)
char *username, *password, *err_string;
{
int code, options = 0; /* KRB5_DEFAULT_OPTIONS = 0 */
krb5_creds my_creds;
krb5_timestamp now;
krb5_principal me, server;
krb5_preauthtype *preauth = NULL;
/* SWP -- For CodeCenter --
krb5_data tgtname = {
0,
KRB5_TGS_NAME_SIZE,
KRB5_TGS_NAME
};
*/
krb5_data tgtname;
tgtname.magic = 0;
tgtname.length = KRB5_TGS_NAME_SIZE;
tgtname.data = KRB5_TGS_NAME;
if (code = krb5_timeofday(k5context, &now)) {
sprintf(err_string,"Wouldn't tell you the time of day");
return 1;
}
if (code = krb5_parse_name(k5context, username, &me)) {
sprintf(err_string,"Couldn't find client principal name");
return 1;
}
if (code = krb5_cc_initialize (k5context, k5ccache, me)) {
sprintf(err_string,"Couldn't initialize credentials cache");
return 1;
}
memset((char *)&my_creds, 0, sizeof(my_creds));
my_creds.client = me;
if (code = krb5_build_principal_ext(k5context, &server,
krb5_princ_realm(k5context, me)->length,
krb5_princ_realm(k5context, me)->data,
tgtname.length, tgtname.data,
krb5_princ_realm(kcontext, me)->length,
krb5_princ_realm(kcontext, me)->data,
0)) {
sprintf(err_string,"Couldn't build server principal name");
return 1;
}
my_creds.server = server;
my_creds.times.starttime = 0;
my_creds.times.endtime = 0; /* now + KRB5_DEFAULT_LIFE; */
my_creds.times.renew_till = 0;
code = krb5_get_in_tkt_with_password(k5context, options, 0,
NULL, preauth, password, k5ccache, &my_creds, 0);
/* eytpyes = NULL means use default etype for decoding tgt */
/* addrs = 0 means use default local (client machine) address */
if (code) {
sprintf(err_string,"krb5_get_in_tkt error: %s", error_message(code));
return 1;
}
else {
return 0;
}
}
#endif
/*************************************************************************
* kdata_to_str -- convert 8-bit char array to ascii string
*
* Accepts: input array and length
* Returns: a pointer to the result, or null pointer on malloc failure
* The caller is responsible for freeing the returned value.
*
* Changed to accomodate general strings with length, due to conflict between
* KTEXT and krb5_data types ( 6/28/95 ADC)
************************************************************************/
static char *kdata_to_str(in_data, length)
char *in_data; /* char FAR ?? */
int length;
{
char *result, *p;
int i;
p = result = malloc(length*2+1);
if (!result) return (char *) NULL;
for (i=0; i < length; i++) {
*p++ = hex[(in_data[i]>>4)&0xf];
*p++ = hex[(in_data[i])&0xf];
}
*p++ = '\0';
return result;
}
/*************************************************************************
* str_to_kdata -- Converts ascii string to a (binary) char array
*
* Accepts: string to convert
* pointer to output array
* Returns: length of output array, NIL on failure
************************************************************************/
int str_to_kdata(in_str, out_str)
char *in_str;
char *out_str;
{
int inlen, outlen;
inlen = strlen(in_str);
if (inlen & 1) return NIL; /* must be even number, in this scheme */
inlen /= 2;
if (inlen > MAX_KDATA_LEN) return NIL;
for (outlen=0; *in_str; outlen++, in_str += 2) {
out_str[outlen] = (dec[in_str[0]]<<4) + dec[in_str[1]];
}
return outlen;
}
/****************************************************************************
* compose_kerberos_auth_string
*
* Accepts: scheme (one of the HTAA_KERBEROS values)
* hostname
* Returns: Authorization string (NULL, upon failure)
***************************************************************************/
char *compose_kerberos_auth_string(scheme, hostname)
HTAAScheme scheme;
char *hostname;
{
struct hostent *host_name;
char user[BUFSIZ], *inst, *pass, *tmp = 0;
int code, retval, firsttime = 1;
char buf[BUFSIZ], krb_err_str[BUFSIZ];
#ifdef KRB4
CREDENTIALS k4cr, k4c;
KTEXT_ST k4authent;
Key_schedule k4key_s;
char *krb_get_phost();
static char *better_err_str[] = { "Server principal unrecognized by KDC",
"System clocks out of sync" };
#endif
#ifdef KRB5
krb5_data k5ap_req;
krb5_principal k5clientp, k5serverp;
krb5_creds k5in_creds, *k5out_creds;
krb5_timestamp now;
#endif
while (code || firsttime) {
#ifdef KRB4
if (scheme == HTAA_KERBEROS_V4) {
k4checksum = time(0) ^ getpid();
strcpy(phost, krb_get_phost(hostname));
code = krb_mk_req(&k4authent, "khttp", phost,
krb_realmofhost(hostname), k4checksum);
if (!code) { /* check for ticket expired */
code = krb_get_cred("khttp",phost,krb_realmofhost(hostname),&k4c);
if (!code) {
k4c.issue_date += ((unsigned char) k4c.lifetime) * 5 * 60;
if (time(0) >= k4c.issue_date) {
code=26;
}
}
}
if (!code) {
strcpy(user,k4c.pname);
pass = kdata_to_str(k4authent.dat, k4authent.length);
}
else if (code == 1) { /* normally "Principal Expired" */
strcpy(krb_err_str, better_err_str[0]);
}
else if (code == RD_AP_TIME) {
strcpy(krb_err_str, better_err_str[1]);
}
else {
strcpy(krb_err_str, krb_err_txt[code]);
}
}
#endif
#ifdef KRB5
if (scheme == HTAA_KERBEROS_V5) {
krb_err_str[0] = '\0';
if (!k5context) {
krb5_init_context(&k5context);
if (code) {
sprintf(krb_err_str,"Error initializing Kerb5 context: %s\n",error_message(code));
application_user_info_wait(krb_err_str);
return (char *) NULL;
}
krb5_init_ets(k5context);
code = krb5_cc_default(k5context, &k5ccache);
if (code) {
sprintf(krb_err_str,"Error initializing Credentials Cache: %s\n",error_message(code));
application_user_info_wait(krb_err_str);
return (char *) NULL;
}
}
code = krb5_mk_req(k5context, &k5auth_context, AP_OPTS_USE_SESSION_KEY,
"khttp", hostname, NULL, k5ccache, &k5ap_req);
if (!code) {
/* get username from credentials cache */
code = krb5_cc_get_principal(k5context, k5ccache, &k5clientp);
if (code) {
sprintf(krb_err_str,"Error getting client principal: %s\n",error_message(code));
application_user_info_wait(krb_err_str);
return (char *) NULL;
}
strcpy(user, k5clientp->data->data);
/* get server credentials to check for expiration */
code = krb5_timeofday(k5context, &now);
if (code) {
sprintf(krb_err_str,"Couldn't give ya the time of day: %s\n",error_message(code));
application_user_info_wait(krb_err_str);
return (char *) NULL;
}
krb5_sname_to_principal(k5context, hostname, "khttp",
KRB5_NT_SRV_HST, &k5serverp);
memset((char *)&k5in_creds, 0, sizeof(k5in_creds));
k5in_creds.server = k5serverp;
k5in_creds.client = k5clientp;
k5in_creds.times.endtime = now + KRB5_DEFAULT_LIFE;
k5in_creds.keyblock.keytype = 0;
k5in_creds.authdata = NULL;
code = krb5_get_credentials(k5context,KRB5_GC_CACHED,k5ccache,&k5in_creds,&k5out_creds);
if ((code == KRB5_CC_NOTFOUND) || (now >= k5out_creds->times.endtime)) {
/* replace "Matching creds not found" */
sprintf(krb_err_str,"Kerberos ticket expired\n");
code = 666;
}
krb5_free_cred_contents(k5context, &k5in_creds);
krb5_free_cred_contents(k5context, &k5out_creds);
krb5_free_principal(k5context, k5clientp);
krb5_free_principal(k5context, k5serverp);
}
if (code) {
if (!krb_err_str[0]) {
sprintf(krb_err_str,"krb5_mk_req: %s\n",error_message(code));
}
}
else {
pass = kdata_to_str(k5ap_req.data, k5ap_req.length);
}
}
#endif
if (code) {
sprintf(buf,"Error: %s\n\nWould you like to attempt to login\nto obtain a ticket-granting ticket?\n",krb_err_str);
if (!prompt_for_yes_or_no(buf)) {
return (char *) NULL;
}
else {
if (scheme_login(scheme))
return (char *) NULL;
}
} /* if (code) */
firsttime = 0;
} /* while (code || firsttime) */
if (!pass) {
sprintf(buf,"Error: Couldn't convert kdata to string (out of memory)\nAborting...\n");
application_user_info_wait(buf);
return (char *) NULL;
}
if (!tmp)
tmp = malloc(strlen(pass)+strlen(user)+40);
else
tmp = realloc(tmp, strlen(pass)+strlen(user)+40);
if (!tmp) {
/* XXX out of memory */
fprintf(stderr,"out of memory!!\n");
fflush(stderr);
exit(1);
}
doing_kerb_auth = 1;
strcpy(Hostname, hostname);
sprintf(tmp, "%s %s", user, pass);
free(pass);
return tmp;
}
/*************************************************************************
* validate_kerberos_server_auth
* Accepts: scheme (one of the HTAA_KERBEROS values)
* the Authorization line from the request
* Returns: NIL on success, T on failure
(currently return value not used)
************************************************************************/
int validate_kerberos_server_auth(scheme, str)
HTAAScheme scheme;
char *str;
{
int retval;
char buf[256], *tmp;
if (!doing_kerb_auth) {
/* sprintf(buf, "Received kerberos credentials from server %s, but I'm not doing kerberos authentication!\n", Hostname);
application_user_info_wait(buf);
*/
return 1;
}
if (*str != '[') {
fprintf(stderr,"\n\nleft bracket not found: [%s]\n",str);
goto krb_server_validate_getout;
}
if (tmp = index(str, ' ')) *tmp = NULL;
tmp = str + strlen(str) - 1;
if (*tmp != ']') {
fprintf(stderr,"\n\nright bracket not found\n\n");
goto krb_server_validate_getout;
}
*tmp = 0; /* end string where right bracket was */
str++; /* get rid of left bracket */
if (0) { /* just to get things started */
}
#ifdef KRB4
else if (scheme == HTAA_KERBEROS_V4) {
retval = k4validate_kerberos_server_auth(str);
}
#endif
#ifdef KRB5
else if (scheme == HTAA_KERBEROS_V5) {
retval = k5validate_kerberos_server_auth(str);
}
#endif
else {
retval = 1;
}
/* Reset stupid global state variables for the next auth we do. */
krb_server_validate_getout:
if (retval) {
sprintf(buf, " Warning:\nAuthentication of server %s failed", Hostname);
application_user_info_wait(buf);
}
/*
bzero(Hostname, sizeof(Hostname));
bzero(phost, sizeof(phost));
*/
memset(Hostname,0,sizeof(Hostname));
memset(phost,0,sizeof(phost));
doing_kerb_auth = 0;
return retval;
}
/************************************************************************/
#ifdef KRB4
int k4validate_kerberos_server_auth(str)
char *str;
{
KTEXT_ST k4authent;
CREDENTIALS k4cr;
Key_schedule k4key_s;
char buf[256];
k4authent.length = str_to_kdata(str, k4authent.dat);
if (k4authent.length == 0 || k4authent.length != 8) {
fprintf(stderr,"\n\nbad length\n\n");
return 1;
}
if (krb_get_cred("khttp", phost, krb_realmofhost(Hostname),&k4cr)) {
fprintf(stderr,"\n\ncouldn't get credentials");
return 1;
}
des_key_sched(k4cr.session, k4key_s);
des_ecb_encrypt(k4authent.dat, k4authent.dat, k4key_s, 0);
if (ntohl(*(long *)k4authent.dat) != k4checksum + 1) {
fprintf(stderr,"\n\nchecksum just doesn't check out\n\n");
return 1;
}
return 0;
}
#endif
/************************************************************************/
#ifdef KRB5
int k5validate_kerberos_server_auth(instr)
char *instr;
{
int code;
char buf[256];
char tmpstr[MAX_KDATA_LEN];
krb5_data k5ap_rep;
krb5_ap_rep_enc_part *k5ap_rep_result;
k5ap_rep.length = str_to_kdata(instr, tmpstr);
if (k5ap_rep.length == 0)
return 1;
k5ap_rep.data = tmpstr;
code = krb5_rd_rep(k5context, k5auth_context, &k5ap_rep, &k5ap_rep_result);
krb5_free_ap_rep_enc_part(k5context, k5ap_rep_result);
if (code)
return 1;
return 0;
}
#endif /* KRB5 */
/************************************************************************/
#endif /* KRB4 or KRB5 */

1132
libwww2/HTAABrow.c Normal file

File diff suppressed because it is too large Load Diff

182
libwww2/HTAABrow.h Normal file
View File

@@ -0,0 +1,182 @@
/* BROWSER SIDE ACCESS AUTHORIZATION MODULE
This module is the browser side interface to Access Authorization (AA) package. It
contains code only for browser.
Important to know about memory allocation:
Routines in this module use dynamic allocation, but free automatically all the memory
reserved by them.
Therefore the caller never has to (and never should) free() any object returned by
these functions.
Therefore also all the strings returned by this package are only valid until the next
call to the same function is made. This approach is selected, because of the nature of
access authorization: no string returned by the package needs to be valid longer than
until the next call.
This also makes it easy to plug the AA package in: you don't have to ponder whether to
free()something here or is it done somewhere else (because it is always done somewhere
else).
The strings that the package needs to store are copied so the original strings given as
parameters to AA functions may be freed or modified with no side effects.
Also note:The AA package does not free() anything else than what it has itself
allocated.
*/
#ifndef HTAABROW_H
#define HTAABROW_H
#include "HTUtils.h" /* BOOL, PARAMS, ARGS */
#include "HTAAUtil.h" /* Common parts of AA */
#ifdef SHORT_NAMES
#define HTAAcoAu HTAA_composeAuth
#define HTAAsRWA HTAA_shouldRetryWithAuth
#define HTAA_TWA HTAA_TryWithAuth
#endif /*SHORT_NAMES*/
/*
Routines for Browser Side Recording of AA Info
Most of the browser-side AA is done by the following two functions (which are called
from file HTTP.c so the browsers using libwww only need to be linked with the new
library and not be changed at all):
HTAA_composeAuth() composes the Authorization: line contents, if the AA package
thinks that the given document is protected. Otherwise this function returns NULL.
This function also calls the functions HTPrompt(),HTPromptPassword() and HTConfirm()
to get the username, password and some confirmation from the user.
HTAA_shouldRetryWithAuth() determines whether to retry the request with AA or with a
new AA (in case username or password was misspelled).
HTAA_TryWithAuth() sets up everything for an automatic first try with authentication.
HTAA_ClearAuth() clears the currently allocated authentication record.
*/
/* PUBLIC HTAA_composeAuth()
**
** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE IF WE
** ALREADY KNOW, THAT THE HOST MIGHT REQUIRE AUTHORIZATION
**
** ON ENTRY:
** hostname is the hostname of the server.
** portnumber is the portnumber in which the server runs.
** docname is the pathname of the document (as in URL)
**
** ON EXIT:
** returns NULL, if no authorization seems to be needed, or
** if it is the entire Authorization: line, e.g.
**
** "Authorization: basic username:password"
**
** As usual, this string is automatically freed.
*/
PUBLIC char *HTAA_composeAuth PARAMS((WWW_CONST char * hostname,
WWW_CONST int portnumber,
WWW_CONST char * docname));
/* BROWSER PUBLIC HTAA_shouldRetryWithAuth()
**
** DETERMINES IF WE SHOULD RETRY THE SERVER
** WITH AUTHORIZATION
** (OR IF ALREADY RETRIED, WITH A DIFFERENT
** USERNAME AND/OR PASSWORD (IF MISSPELLED))
** ON ENTRY:
** start_of_headers is the first block already read from socket,
** but status line skipped; i.e. points to the
** start of the header section.
** length is the remaining length of the first block.
** soc is the socket to read the rest of server reply.
**
** This function should only be called when
** server has replied with a 401 (Unauthorized)
** status code.
** ON EXIT:
** returns YES, if connection should be retried.
** The node containing all the necessary
** information is
** * either constructed if it does not exist
** * or password is reset to NULL to indicate
** that username and password should be
** reprompted when composing Authorization:
** field (in function HTAA_composeAuth()).
** NO, otherwise.
*/
PUBLIC BOOL HTAA_shouldRetryWithAuth PARAMS((char * start_of_headers,
int length,
int soc));
#ifdef PEM_AUTH
/* BROWSER PUBLIC HTAA_TryWithAuth()
**
** SAYS WE KNOW WE SHOULD TRY THE SERVER
** WITH AUTHORIZATION RIGHT FROM THE START
** ON ENTRY:
** enctype is the string we were given to determine
** just what type of authorization we should ask for
** from the start.
** entity is the server identifier needed by some
** types of authorization.
** action is the url we are GETing or POSTing to.
**
** This function should only be called when
** when we are responding to a form with ENCTYPE set.
** ON EXIT:
** returns YES
** The node containing all the necessary
** information is constructed.
** NO
** Client can't do this encryption type.
*/
PUBLIC BOOL HTAA_TryWithAuth PARAMS((char * enctype,
char * entity,
char * action));
/*
*/
PUBLIC void HTAA_ClearAuth NOPARAMS;
#endif /* PEM_AUTH */
#ifdef PEM_AUTH
/*
* PUBLIC HTAA_makecommand()
*
* ENCRYPT AN HTTP REQUEST, AND ENCAPSULATE IT IN
* A NEW HTTP PEM AUTHORIZED REQUEST
*
* ON ENTRY:
* command the HTTP request
*
* ON EXIT:
* returns the new HTTP request with PEM
*
* Do not free this string. This function *requires* that the
* HTAA_composeAuth function has been called prior to it.
*
*/
PUBLIC char *HTAA_makecommand PARAMS((char * command, char **body, int *bl));
#endif /* PEM_AUTH */
PUBLIC void HTAAServer_clear ();
#endif /* NOT HTAABROW_H */
/*
End of file HTAABrow.h. */

199
libwww2/HTAAFile.c Normal file
View File

@@ -0,0 +1,199 @@
/* MODULE HTAAFile.c
** FILE ROUTINES FOR AUTHENTICATION
** (PASSWD AND GROUP FILES) AND
** ACCESS CONTROL LIST (.www_acl)
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <stdio.h> /* FILE */
#include <string.h>
#include "tcp.h" /* Macro FROMASCII() */
#include "HTAAUtil.h" /* Common utilities used in AA */
#include "HTAAFile.h" /* Implemented here */
#define SPACE ' '
#define TAB '\t'
/* PUBLIC HTAAFile_nextRec()
** GO TO THE BEGINNING OF THE NEXT RECORD
** ON ENTRY:
** fp is the file from which records are read from.
**
** ON EXIT:
** returns nothing. File read pointer is located at the beginning
** of the next record.
**
*/
PUBLIC void HTAAFile_nextRec ARGS1(FILE *, fp)
{
int ch = getc(fp);
while (ch != EOF && ch != CR && ch != LF)
ch = getc(fp); /* Skip until end-of-line */
while (ch != EOF &&
(ch == CR || ch == LF)) /*Skip carriage returns and linefeeds*/
ch = getc(fp);
if (ch != EOF)
ungetc(ch, fp);
}
/* PRIVATE read_item()
** READ AN ITEM FROM A PASSWORD, GROUP
** OR ACCESS CONTROL LIST FILE
** i.e. either a field, or a list item.
** ON ENTRY:
** fp is the file to read the characters from
** contents is the character array to put the characters
** reading_list if TRUE, read a list item (ends either in
** acomma or acolon),
** if FALSE, read a field (ends in acolon).
** max_len is the maximum number of characters that may
** be read (i.e. the size of dest minus one for
** terminating null).
** ON EXIT:
** returns the terminating character
** (i.e. either separator or CR or LF or EOF).
** contents contains a null-terminated string representing
** the read field.
** NOTE 1:
** Ignores leading and trailing blanks and tabs.
** NOTE 2:
** If the item is more than max_len characters
** long, the rest of the characters in that item
** are ignored. However, contents is always
** null-terminated!
*/
PRIVATE int read_item ARGS4(FILE *, fp,
char *, contents,
BOOL, reading_list,
int, max_len)
{
char * dest = contents;
char * end = contents;
int cnt = 0;
int ch = getc(fp);
while (SPACE == ch || TAB == ch) /* Skip spaces and tabs */
ch = getc(fp);
while (ch != FIELD_SEPARATOR &&
(!reading_list || ch != LIST_SEPARATOR) &&
ch != CR && ch != LF && ch != EOF && cnt < max_len) {
*(dest++) = ch;
cnt++;
if (ch != SPACE && ch != TAB)
end = dest;
ch = getc(fp);
} /* while not eol or eof or too many read */
/* Terminate the string, truncating trailing whitespace off.
** Otherwise (if whitespace would be included), here would
** be *dest='\0'; and cnt -= ... would be left out.
*/
*end = '\0';
cnt -= dest-end;
if (cnt == max_len) {
/* If the field was too long (or exactly maximum) ignore the rest */
while (ch != FIELD_SEPARATOR &&
(!reading_list || ch != LIST_SEPARATOR) &&
ch != CR && ch != LF && ch != EOF)
ch = getc(fp);
}
if (ch == CR || ch == LF)
ungetc(ch, fp); /* Push back the record separator (NL or LF) */
return ch; /* Return the terminating character */
}
/* PUBLIC HTAAFile_readField()
** READ A FIELD FROM A PASSWORD, GROUP
** OR ACCESS CONTROL LIST FILE
** i.e. an item terminated by colon,
** end-of-line, or end-of-file.
** ON ENTRY:
** fp is the file to read the characters from
** contents is the character array to put the characters
** max_len is the maximum number of characters that may
** be read (i.e. the size of dest minus one for
** terminating null).
** ON EXIT:
** returns the terminating character
** (i.e. either separator or CR or LF or EOF).
** contents contains a null-terminated string representing
** the read field.
** NOTE 1:
** Ignores leading and trailing blanks and tabs.
** NOTE 2:
** If the field is more than max_len characters
** long, the rest of the characters in that item
** are ignored. However, contents is always
** null-terminated!
*/
PUBLIC int HTAAFile_readField ARGS3(FILE *, fp,
char *, contents,
int, max_len)
{
return read_item(fp, contents, NO, max_len);
}
/* PUBLIC HTAAFile_readList()
**
** READ A LIST OF STRINGS SEPARATED BY COMMAS
** (FROM A GROUP OR ACCESS CONTROL LIST FILE)
** ON ENTRY:
** fp is a pointer to the input file.
** result is the list to which append the read items.
** max_len is the maximum number of characters in each
** list entry (extra characters are ignored).
** ON EXIT:
** returns the number of items read.
**
*/
PUBLIC int HTAAFile_readList ARGS3(FILE *, fp,
HTList *, result,
int, max_len)
{
char *item = NULL;
char terminator;
int cnt = 0;
do {
if (!item && !(item = (char*)malloc(max_len+1)))
outofmem(__FILE__, "HTAAFile_readList");
terminator = read_item(fp, item, YES, max_len);
if (strlen(item) > 0) {
cnt++;
HTList_addObject(result, (void*)item);
item = NULL;
}
} while (terminator != FIELD_SEPARATOR &&
terminator != CR && terminator != LF &&
terminator != EOF);
if (item) free(item); /* This was not needed */
return cnt;
}

124
libwww2/HTAAFile.h Normal file
View File

@@ -0,0 +1,124 @@
/* FILE ROUTINES FOR ACCESS AUTHORIZATION PACKAGE
This module implements the routines used for accessing (and parsing) the files used in
the access authorization:
password file
group file
access control list (ACL) file
*/
#ifndef HTAAFILE_H
#define HTAAFILE_H
#include <stdio.h> /* FILE */
#include "HTUtils.h" /* BOOL, PARAMS, ARGS */
#include "HTList.h" /* HTList */
#ifdef SHORT_NAMES
#define HTAAFnRe HTAAFile_nextRec
#define HTAAFrFi HTAAFile_readField
#define HTAAFrLi HTAAFile_readList
#endif /*SHORT_NAMES*/
/* Used field separators */
#define FIELD_SEPARATOR ':' /* Used to separate fields */
#define LIST_SEPARATOR ',' /* Used to separate items in a list */
/* in group and ALC files. */
/*
Naming conventions
Record is an entire line in file.
Field is an entity separated by colons and/or by end-of-line.
List is a field in which there are items separated by commas.
Record-oriented Read Routines
Password, group and ACL are internally read in by the following functions:
HTAAFile_nextRec() skips to the beginning of the next record (must be called even
after the last field of a record is read to proceed to the next
record).
HTAAFile_readField() reads a field (separated by colons).
HTAAFile_readList() reads a field containing a comma-separated list of items.
*/
/* PUBLIC HTAAFile_nextRec()
** GO TO THE BEGINNING OF THE NEXT RECORD
** ON ENTRY:
** fp is the file from which records are read from.
**
** ON EXIT:
** returns nothing. File read pointer is located at the beginning
** of the next record.
**
*/
PUBLIC void HTAAFile_nextRec PARAMS((FILE * fp));
/* PUBLIC HTAAFile_readField()
** READ A FIELD FROM A PASSWORD, GROUP
** OR ACCESS CONTROL LIST FILE
** i.e. an item terminated by colon,
** end-of-line, or end-of-file.
** ON ENTRY:
** fp is the file to read the characters from
** contents is the character array to put the characters
** max_len is the maximum number of characters that may
** be read (i.e. the size of dest minus one for
** terminating null).
** ON EXIT:
** returns the terminating character
** (i.e. either separator or CR or LF or EOF).
** contents contains a null-terminated string representing
** the read field.
** NOTE 1:
** Ignores leading and trailing blanks and tabs.
** NOTE 2:
** If the field is more than max_len characters
** long, the rest of the characters in that item
** are ignored. However, contents is always
** null-terminated!
*/
PUBLIC int HTAAFile_readField PARAMS((FILE * fp,
char * contents,
int max_len));
/* PUBLIC HTAAFile_readList()
**
** READ A LIST OF STRINGS SEPARATED BY COMMAS
** (FROM A GROUP OR ACCESS CONTROL LIST FILE)
** ON ENTRY:
** fp is a pointer to the input file.
** result is the list to which append the read items.
** max_len is the maximum number of characters in each
** list entry (extra characters are ignored).
** ON EXIT:
** returns the number of items read.
**
*/
PUBLIC int HTAAFile_readList PARAMS((FILE * fp,
HTList * result,
int max_len));
/*
*/
#endif /* not HTAAFILE_H */
/*
End of file HTAAFile.h. */

562
libwww2/HTAAProt.c Normal file
View File

@@ -0,0 +1,562 @@
/* MODULE HTAAProt.c
** PROTECTION FILE PARSING MODULE
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <string.h>
#include <pwd.h> /* Unix password file routine: getpwnam() */
#include <grp.h> /* Unix group file routine: getgrnam() */
#include "HTUtils.h"
#include "HTAAUtil.h"
#include "HTAAFile.h"
#include "HTLex.h" /* Lexical analysor */
#include "HTAssoc.h" /* Association list */
#include "HTAAProt.h" /* Implemented here */
#include "../libnut/str-tools.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/*
** Protection setup caching
*/
typedef struct {
char * prot_filename;
HTAAProt * prot;
} HTAAProtCache;
PRIVATE HTList * prot_cache = NULL; /* Protection setup cache. */
PRIVATE HTAAProt *default_prot = NULL; /* Default protection. */
PRIVATE HTAAProt *current_prot = NULL; /* Current protection mode */
/* which is set up by callbacks */
/* from the rule system when */
/* a "protect" rule is matched. */
/* PRIVATE isNumber()
** DOES A CHARACTER STRING REPRESENT A NUMBER
*/
PRIVATE BOOL isNumber ARGS1(WWW_CONST char *, s)
{
WWW_CONST char *cur = s;
if (!s || !*s) return NO;
while (*cur) {
if (*cur < '0' || *cur > '9')
return NO;
cur++;
}
return YES;
}
/* PUBLIC HTAA_getUid()
** GET THE USER ID TO CHANGE THE PROCESS UID TO
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns the uid number to give to setuid() system call.
** Default is 65534 (nobody).
*/
PUBLIC int HTAA_getUid NOARGS
{
struct passwd *pw = NULL;
if (current_prot && current_prot->uid_name) {
if (isNumber(current_prot->uid_name)) {
if (NULL != (pw = getpwuid(atoi(current_prot->uid_name)))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"%s(%s) returned (%s:%s:%d:%d:...)\n",
"HTAA_getUid: getpwuid",
current_prot->uid_name,
pw->pw_name, pw->pw_passwd,
pw->pw_uid, pw->pw_gid);
#endif
return pw->pw_uid;
}
}
else { /* User name (not a number) */
if (NULL != (pw = getpwnam(current_prot->uid_name))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s(\"%s\") %s (%s:%s:%d:%d:...)\n",
"HTAA_getUid: getpwnam",
current_prot->uid_name, "returned",
pw->pw_name, pw->pw_passwd,
pw->pw_uid, pw->pw_gid);
#endif
return pw->pw_uid;
}
}
}
return 65534; /* nobody */
}
/* PUBLIC HTAA_getGid()
** GET THE GROUP ID TO CHANGE THE PROCESS GID TO
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns the uid number to give to setgid() system call.
** Default is 65534 (nogroup).
*/
PUBLIC int HTAA_getGid NOARGS
{
struct group *gr = NULL;
if (current_prot && current_prot->gid_name) {
if (isNumber(current_prot->gid_name)) {
if (NULL != (gr = getgrgid(atoi(current_prot->gid_name)))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"%s(%s) returned (%s:%s:%d:...)\n",
"HTAA_getGid: getgrgid",
current_prot->gid_name,
gr->gr_name, gr->gr_passwd, gr->gr_gid);
#endif
return gr->gr_gid;
}
}
else { /* Group name (not number) */
if (NULL != (gr = getgrnam(current_prot->gid_name))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"%s(\"%s\") returned (%s:%s:%d:...)\n",
"HTAA_getGid: getgrnam",
current_prot->gid_name,
gr->gr_name, gr->gr_passwd, gr->gr_gid);
#endif
return gr->gr_gid;
}
}
}
return 65534; /* nogroup */
}
/* PRIVATE HTAA_setIds()
** SET UID AND GID (AS NAMES OR NUMBERS)
** TO HTAAProt STRUCTURE
** ON ENTRY:
** prot destination.
** ids is a string like "james.www" or "1422.69" etc.
** giving uid and gid.
**
** ON EXIT:
** returns nothing.
*/
PRIVATE void HTAA_setIds ARGS2(HTAAProt *, prot,
WWW_CONST char *, ids)
{
if (ids) {
char *local_copy = NULL;
char *point;
StrAllocCopy(local_copy, ids);
point = strchr(local_copy, '.');
if (point) {
*(point++) = (char)0;
StrAllocCopy(prot->gid_name, point);
}
else {
StrAllocCopy(prot->gid_name, "nogroup");
}
StrAllocCopy(prot->uid_name, local_copy);
FREE(local_copy);
}
else {
StrAllocCopy(prot->uid_name, "nobody");
StrAllocCopy(prot->gid_name, "nogroup");
}
}
/* PRIVATE HTAA_parseProtFile()
** PARSE A PROTECTION SETUP FILE AND
** PUT THE RESULT IN A HTAAProt STRUCTURE
** ON ENTRY:
** prot destination structure.
** fp open protection file.
**
** ON EXIT:
** returns nothing.
*/
PRIVATE void HTAA_parseProtFile ARGS2(HTAAProt *, prot,
FILE *, fp)
{
if (prot && fp) {
LexItem lex_item;
char *fieldname = NULL;
while (LEX_EOF != (lex_item = lex(fp))) {
while (lex_item == LEX_REC_SEP) /* Ignore empty lines */
lex_item = lex(fp);
if (lex_item == LEX_EOF) /* End of file */
break;
if (lex_item == LEX_ALPH_STR) { /* Valid setup record */
StrAllocCopy(fieldname, lex_buffer);
if (LEX_FIELD_SEP != (lex_item = lex(fp)))
unlex(lex_item); /* If someone wants to use colon */
/* after field name it's ok, but */
/* not required. Here we read it.*/
if (0==my_strncasecmp(fieldname, "Auth", 4)) {
lex_item = lex(fp);
while (lex_item == LEX_ALPH_STR) {
HTAAScheme scheme = HTAAScheme_enum(lex_buffer);
if (scheme != HTAA_UNKNOWN) {
if (!prot->valid_schemes)
prot->valid_schemes = HTList_new();
HTList_addObject(prot->valid_schemes,(void*)scheme);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s `%s'\n",
"HTAA_parseProtFile: valid",
"authentication scheme:",
HTAAScheme_name(scheme));
#endif
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "%s %s `%s'\n",
"HTAA_parseProtFile: unknown",
"authentication scheme:",
lex_buffer);
#endif
if (LEX_ITEM_SEP != (lex_item = lex(fp)))
break;
/*
** Here lex_item == LEX_ITEM_SEP; after item separator
** it is ok to have one or more newlines (LEX_REC_SEP)
** and they are ignored (continuation line).
*/
do {
lex_item = lex(fp);
} while (lex_item == LEX_REC_SEP);
} /* while items in list */
} /* if "Authenticate" */
else if (0==my_strncasecmp(fieldname, "mask", 4)) {
prot->mask_group = HTAA_parseGroupDef(fp);
lex_item=LEX_REC_SEP; /*groupdef parser read this already*/
#ifndef DISABLE_TRACE
if (www2Trace) {
if (prot->mask_group) {
fprintf(stderr,
"HTAA_parseProtFile: Mask group:\n");
HTAA_printGroupDef(prot->mask_group);
} else fprintf(stderr, "HTAA_parseProtFile: %s\n",
"Mask group syntax error");
}
#endif
} /* if "Mask" */
else { /* Just a name-value pair, put it to assoclist */
if (LEX_ALPH_STR == (lex_item = lex(fp))) {
if (!prot->values)
prot->values = HTAssocList_new();
HTAssocList_add(prot->values, fieldname, lex_buffer);
lex_item = lex(fp); /* Read record separator */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"%s `%s' bound to value `%s'\n",
"HTAA_parseProtFile: Name",
fieldname, lex_buffer);
#endif
}
} /* else name-value pair */
} /* if valid field */
if (lex_item != LEX_EOF && lex_item != LEX_REC_SEP) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s %d (that line ignored)\n",
"HTAA_parseProtFile: Syntax error",
"in protection setup file at line",
lex_line);
#endif
do {
lex_item = lex(fp);
} while (lex_item != LEX_EOF && lex_item != LEX_REC_SEP);
} /* if syntax error */
} /* while not end-of-file */
} /* if valid parameters */
}
/* PRIVATE HTAAProt_new()
** ALLOCATE A NEW HTAAProt STRUCTURE AND
** INITIALIZE IT FROM PROTECTION SETUP FILE
** ON ENTRY:
** cur_docname current filename after rule translations.
** prot_filename protection setup file name.
** If NULL, not an error.
** ids Uid and gid names or numbers,
** examples:
** james ( <=> james.nogroup)
** .www ( <=> nobody.www)
** james.www
** james.69
** 1422.69
** 1422.www
**
** May be NULL, defaults to nobody.nogroup.
** Should be NULL, if prot_file is NULL.
**
** ON EXIT:
** returns returns a new and initialized protection
** setup structure.
** If setup file is already read in (found
** in cache), only sets uid_name and gid
** fields, and returns that.
*/
PRIVATE HTAAProt *HTAAProt_new ARGS3(WWW_CONST char *, cur_docname,
WWW_CONST char *, prot_filename,
WWW_CONST char *, ids)
{
HTList *cur = prot_cache;
HTAAProtCache *cache_item = NULL;
HTAAProt *prot;
FILE *fp;
if (!prot_cache)
prot_cache = HTList_new();
while (NULL != (cache_item = (HTAAProtCache*)HTList_nextObject(cur))) {
if (!strcmp(cache_item->prot_filename, prot_filename))
break;
}
if (cache_item) {
prot = cache_item->prot;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s `%s' already in cache\n",
"HTAAProt_new: Protection file", prot_filename);
#endif
} else {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTAAProt_new: Loading protection file `%s'\n",
prot_filename);
#endif
if (!(prot = (HTAAProt*)malloc(sizeof(HTAAProt))))
outofmem(__FILE__, "HTAAProt_new");
prot->template = NULL;
prot->filename = NULL;
prot->uid_name = NULL;
prot->gid_name = NULL;
prot->valid_schemes = HTList_new();
prot->mask_group= NULL; /* Masking disabled by defaults */
prot->values = HTAssocList_new();
if (prot_filename && NULL != (fp = fopen(prot_filename, "r"))) {
HTAA_parseProtFile(prot, fp);
fclose(fp);
if (!(cache_item = (HTAAProtCache*)malloc(sizeof(HTAAProtCache))))
outofmem(__FILE__, "HTAAProt_new");
cache_item->prot = prot;
cache_item->prot_filename = NULL;
StrAllocCopy(cache_item->prot_filename, prot_filename);
HTList_addObject(prot_cache, (void*)cache_item);
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "HTAAProt_new: %s `%s'\n",
"Unable to open protection setup file",
(prot_filename ? prot_filename : "(null)"));
#endif
}
if (cur_docname)
StrAllocCopy(prot->filename, cur_docname);
HTAA_setIds(prot, ids);
return prot;
}
/* PUBLIC HTAA_setDefaultProtection()
** SET THE DEFAULT PROTECTION MODE
** (called by rule system when a
** "defprot" rule is matched)
** ON ENTRY:
** cur_docname is the current result of rule translations.
** prot_filename is the protection setup file (second argument
** for "defprot" rule, optional)
** ids contains user and group names separated by
** a dot, corresponding to the uid
** gid under which the server should run,
** default is "nobody.nogroup" (third argument
** for "defprot" rule, optional; can be given
** only if protection setup file is also given).
**
** ON EXIT:
** returns nothing.
** Sets the module-wide variable default_prot.
*/
PUBLIC void HTAA_setDefaultProtection ARGS3(WWW_CONST char *, cur_docname,
WWW_CONST char *, prot_filename,
WWW_CONST char *, ids)
{
default_prot = NULL; /* Not free()'d because this is in cache */
if (prot_filename) {
default_prot = HTAAProt_new(cur_docname, prot_filename, ids);
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "%s %s\n",
"HTAA_setDefaultProtection: ERROR: Protection file",
"not specified (obligatory for DefProt rule)!!\n");
#endif
}
/* PUBLIC HTAA_setCurrentProtection()
** SET THE CURRENT PROTECTION MODE
** (called by rule system when a
** "protect" rule is matched)
** ON ENTRY:
** cur_docname is the current result of rule translations.
** prot_filename is the protection setup file (second argument
** for "protect" rule, optional)
** ids contains user and group names separated by
** a dot, corresponding to the uid
** gid under which the server should run,
** default is "nobody.nogroup" (third argument
** for "protect" rule, optional; can be given
** only if protection setup file is also given).
**
** ON EXIT:
** returns nothing.
** Sets the module-wide variable current_prot.
*/
PUBLIC void HTAA_setCurrentProtection ARGS3(WWW_CONST char *, cur_docname,
WWW_CONST char *, prot_filename,
WWW_CONST char *, ids)
{
current_prot = NULL; /* Not free()'d because this is in cache */
if (prot_filename) {
current_prot = HTAAProt_new(cur_docname, prot_filename, ids);
} else {
if (default_prot) {
current_prot = default_prot;
HTAA_setIds(current_prot, ids);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s %s\n",
"HTAA_setCurrentProtection: Protection file",
"not specified for Protect rule",
"-- using default protection");
#endif
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "%s %s %s\n",
"HTAA_setCurrentProtection: ERROR: Protection",
"file not specified for Protect rule, and",
"default protection is not set!!");
#endif
}
}
/* PUBLIC HTAA_getCurrentProtection()
** GET CURRENT PROTECTION SETUP STRUCTURE
** (this is set up by callbacks made from
** the rule system when matching "protect"
** (and "defprot") rules)
** ON ENTRY:
** HTTranslate() must have been called before calling
** this function.
**
** ON EXIT:
** returns a HTAAProt structure representing the
** protection setup of the HTTranslate()'d file.
** This must not be free()'d.
*/
PUBLIC HTAAProt *HTAA_getCurrentProtection NOARGS
{
return current_prot;
}
/* PUBLIC HTAA_getDefaultProtection()
** GET DEFAULT PROTECTION SETUP STRUCTURE
** AND SET IT TO CURRENT PROTECTION
** (this is set up by callbacks made from
** the rule system when matching "defprot"
** rules)
** ON ENTRY:
** HTTranslate() must have been called before calling
** this function.
**
** ON EXIT:
** returns a HTAAProt structure representing the
** default protection setup of the HTTranslate()'d
** file (if HTAA_getCurrentProtection() returned
** NULL, i.e. if there is no "protect" rule
** but ACL exists, and we need to know default
** protection settings).
** This must not be free()'d.
** IMPORTANT:
** As a side-effect this tells the protection system that
** the file is in fact protected and sets the current
** protection mode to default.
*/
PUBLIC HTAAProt *HTAA_getDefaultProtection NOARGS
{
if (!current_prot) {
current_prot = default_prot;
default_prot = NULL;
}
return current_prot;
}
/* SERVER INTERNAL HTAA_clearProtections()
** CLEAR DOCUMENT PROTECTION MODE
** (ALSO DEFAULT PROTECTION)
** (called by the rule system)
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns nothing.
** Frees the memory used by protection information.
*/
PUBLIC void HTAA_clearProtections NOARGS
{
current_prot = NULL; /* These are not freed because */
default_prot = NULL; /* they are actually in cache. */
}

199
libwww2/HTAAProt.h Normal file
View File

@@ -0,0 +1,199 @@
/* PROTECTION SETUP FILE
*/
#ifndef HTAAPROT_H
#define HTAAPROT_H
#include "HTUtils.h"
#include "HTGroup.h"
#include "HTAssoc.h"
#ifdef SHORT_NAMES
#define HTAAgUid HTAA_getUid
#define HTAAgGid HTAA_getGid
#define HTAAgDPr HTAA_setDefaultProtection
#define HTAAsCPr HTAA_setCurrentProtection
#define HTAAgCPr HTAA_getCurrentProtection
#define HTAAgDPr HTAA_getDefaultProtection
#define HTAAclPr HTAA_clearProtections
#endif /*SHORT_NAMES*/
/*
Server's Representation of Document (Tree) Protections
*/
typedef struct {
char * template; /* Template for this protection */
char * filename; /* Current document file */
char * uid_name; /* Effective uid (name of it) */
char * gid_name; /* Effective gid (name of it) */
GroupDef * mask_group; /* Allowed users and IP addresses */
HTList * valid_schemes;/* Valid authentication schemes */
HTAssocList * values; /* Association list for scheme specific */
/* parameters. */
} HTAAProt;
/*
Callbacks for rule system
The following three functioncs are called by the rule system:
HTAA_clearProtections() when starting to translate a filename
HTAA_setDefaultProtection() when "defprot" rule is matched
HTAA_setCurrentProtection() when "protect" rule is matched
Protection setup files are cached by these functions.
*/
/* PUBLIC HTAA_setDefaultProtection()
** SET THE DEFAULT PROTECTION MODE
** (called by rule system when a
** "defprot" rule is matched)
** ON ENTRY:
** cur_docname is the current result of rule translations.
** prot_filename is the protection setup file (second argument
** for "defprot" rule, optional)
** eff_ids contains user and group names separated by
** a dot, corresponding to the effective uid
** gid under which the server should run,
** default is "nobody.nogroup" (third argument
** for "defprot" rule, optional; can be given
** only if protection setup file is also given).
**
** ON EXIT:
** returns nothing.
** Sets the module-wide variable default_prot.
*/
PUBLIC void HTAA_setDefaultProtection PARAMS((WWW_CONST char * cur_docname,
WWW_CONST char * prot_filename,
WWW_CONST char * eff_ids));
/* PUBLIC HTAA_setCurrentProtection()
** SET THE CURRENT PROTECTION MODE
** (called by rule system when a
** "protect" rule is matched)
** ON ENTRY:
** cur_docname is the current result of rule translations.
** prot_filename is the protection setup file (second argument
** for "protect" rule, optional)
** eff_ids contains user and group names separated by
** a dot, corresponding to the effective uid
** gid under which the server should run,
** default is "nobody.nogroup" (third argument
** for "protect" rule, optional; can be given
** only if protection setup file is also given).
**
** ON EXIT:
** returns nothing.
** Sets the module-wide variable current_prot.
*/
PUBLIC void HTAA_setCurrentProtection PARAMS((WWW_CONST char * cur_docname,
WWW_CONST char * prot_filename,
WWW_CONST char * eff_ids));
/* SERVER INTERNAL HTAA_clearProtections()
** CLEAR DOCUMENT PROTECTION MODE
** (ALSO DEFAULT PROTECTION)
** (called by the rule system)
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns nothing.
** Frees the memory used by protection information.
*/
PUBLIC void HTAA_clearProtections NOPARAMS;
/*
Getting Protection Settings
HTAA_getCurrentProtection() returns the current protection mode (if there was a
"protect" rule). NULL, if no "protect" rule has been matched.
HTAA_getDefaultProtection() sets the current protection mode to what it was set to
by "defprot" rule and also returns it (therefore after this call also
HTAA_getCurrentProtection() returns the same structure.
*/
/* PUBLIC HTAA_getCurrentProtection()
** GET CURRENT PROTECTION SETUP STRUCTURE
** (this is set up by callbacks made from
** the rule system when matching "protect"
** (and "defprot") rules)
** ON ENTRY:
** HTTranslate() must have been called before calling
** this function.
**
** ON EXIT:
** returns a HTAAProt structure representing the
** protection setup of the HTTranslate()'d file.
** This must not be free()'d.
*/
PUBLIC HTAAProt *HTAA_getCurrentProtection NOPARAMS;
/* PUBLIC HTAA_getDefaultProtection()
** GET DEFAULT PROTECTION SETUP STRUCTURE
** (this is set up by callbacks made from
** the rule system when matching "defprot"
** rules)
** ON ENTRY:
** HTTranslate() must have been called before calling
** this function.
**
** ON EXIT:
** returns a HTAAProt structure representing the
** default protection setup of the HTTranslate()'d
** file (if HTAA_getCurrentProtection() returned
** NULL, i.e. if there is no "protect" rule
** but ACL exists, and we need to know default
** protection settings).
** This must not be free()'d.
*/
PUBLIC HTAAProt *HTAA_getDefaultProtection NOPARAMS;
/*
Get User and Group IDs to Which Set to
*/
/* PUBLIC HTAA_getUid()
** GET THE USER ID TO CHANGE THE PROCESS UID TO
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns the uid number to give to setuid() system call.
** Default is 65534 (nobody).
*/
PUBLIC int HTAA_getUid NOPARAMS;
/* PUBLIC HTAA_getGid()
** GET THE GROUP ID TO CHANGE THE PROCESS GID TO
** ON ENTRY:
** No arguments.
**
** ON EXIT:
** returns the uid number to give to setgid() system call.
** Default is 65534 (nogroup).
*/
PUBLIC int HTAA_getGid NOPARAMS;
/*
*/
#endif /* not HTAAPROT_H */
/*
End of file HTAAProt.h. */

640
libwww2/HTAAServ.c Normal file
View File

@@ -0,0 +1,640 @@
/* MODULE HTAAServ.c
** SERVER SIDE ACCESS AUTHORIZATION MODULE
**
** Contains the means for checking the user access
** authorization for a file.
**
** IMPORTANT:
** Routines in this module use dynamic allocation, but free
** automatically all the memory reserved by them.
**
** Therefore the caller never has to (and never should)
** free() any object returned by these functions.
**
** Therefore also all the strings returned by this package
** are only valid until the next call to the same function
** is made. This approach is selected, because of the nature
** of access authorization: no string returned by the package
** needs to be valid longer than until the next call.
**
** This also makes it easy to plug the AA package in:
** you don't have to ponder whether to free() something
** here or is it done somewhere else (because it is always
** done somewhere else).
**
** The strings that the package needs to store are copied
** so the original strings given as parameters to AA
** functions may be freed or modified with no side effects.
**
** The AA package does not free() anything else than what
** it has itself allocated.
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <stdio.h> /* FILE */
#include <string.h> /* strchr() */
#include "HTUtils.h"
#include "HTString.h"
#include "HTAccess.h" /* HTSecure */
#include "HTFile.h" /* HTLocalName */
#include "HTRules.h" /* */
#include "HTParse.h" /* URL parsing function */
#include "HTList.h" /* HTList object */
#include "HTAAUtil.h" /* AA common parts */
#include "HTAuth.h" /* Authentication */
#include "HTACL.h" /* Access Control List */
#include "HTGroup.h" /* Group handling */
#include "HTAAProt.h" /* Protection file parsing */
#include "HTAAServ.h" /* Implemented here */
/*
** Global variables
*/
PUBLIC time_t theTime;
/*
** Module-wide global variables
*/
PRIVATE FILE * htaa_logfile = NULL; /* Log file */
PRIVATE HTAAUser *htaa_user = NULL; /* Authenticated user */
PRIVATE HTAAFailReasonType HTAAFailReason = HTAA_OK; /* AA fail reason */
/* SERVER PUBLIC HTAA_statusMessage()
** RETURN A STRING EXPLAINING ACCESS
** AUTHORIZATION FAILURE
** (Can be used in server reply status line
** with 401/403 replies.)
** ON EXIT:
** returns a string containing the error message
** corresponding to internal HTAAFailReason.
*/
PUBLIC char *HTAA_statusMessage NOARGS
{
switch (HTAAFailReason) {
/* 401 cases */
case HTAA_NO_AUTH:
return "Unauthorized -- authentication failed";
break;
case HTAA_NOT_MEMBER:
return "Unauthorized to access the document";
break;
/* 403 cases */
case HTAA_BY_RULE:
return "Forbidden -- by rule";
break;
case HTAA_IP_MASK:
return "Forbidden -- server refuses to serve to your IP address";
break;
case HTAA_NO_ACL:
case HTAA_NO_ENTRY:
return "Forbidden -- access to file is never allowed";
break;
case HTAA_SETUP_ERROR:
return "Forbidden -- server protection setup error";
break;
/* 404 cases */
case HTAA_NOT_FOUND:
return "Not found -- file doesn't exist or is read protected";
break;
/* Success */
case HTAA_OK:
return "AA: Access should be ok but something went wrong";
break;
/* Others */
default:
return "Access denied -- unable to specify reason (bug)";
} /* switch */
}
PRIVATE char *status_name ARGS1(HTAAFailReasonType, reason)
{
switch (HTAAFailReason) {
/* 401 cases */
case HTAA_NO_AUTH:
return "NO-AUTHENTICATION";
break;
case HTAA_NOT_MEMBER:
return "NOT-AUTHORIZED";
break;
/* 403 cases */
case HTAA_BY_RULE:
return "FORB-RULE";
break;
case HTAA_IP_MASK:
return "FORB-IP";
break;
case HTAA_NO_ACL:
return "NO-ACL-FILE";
break;
case HTAA_NO_ENTRY:
return "NO-ACL-ENTRY";
break;
case HTAA_SETUP_ERROR:
return "SETUP-ERROR";
break;
/* 404 cases */
case HTAA_NOT_FOUND:
return "NOT-FOUND";
break;
/* Success */
case HTAA_OK:
return "OK";
break;
/* Others */
default:
return "SERVER-BUG";
} /* switch */
}
/* PRIVATE check_uthorization()
** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
** ON ENTRY:
** pathname is the physical file pathname
** to access.
** method method, e.g. METHOD_GET, METHOD_PUT, ...
** scheme authentication scheme.
** scheme_specifics authentication string (or other
** scheme specific parameters, like
** Kerberos-ticket).
**
** ON EXIT:
** returns HTAA_OK on success.
** Otherwise the reason for failing.
** NOTE:
** This function does not check whether the file
** exists or not -- so the status 404 Not found
** must be returned from somewhere else (this is
** to avoid unnecessary overhead of opening the
** file twice).
*/
PRIVATE HTAAFailReasonType check_authorization ARGS4(WWW_CONST char *, pathname,
HTAAMethod, method,
HTAAScheme, scheme,
char *, scheme_specifics)
{
HTAAFailReasonType reason;
GroupDef *allowed_groups;
FILE *acl_file = NULL;
HTAAProt *prot = NULL; /* Protection mode */
htaa_user = NULL;
if (!pathname) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTAA_checkAuthorization: Forbidden by rule\n");
#endif
return HTAA_BY_RULE;
}
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s `%s' %s %s\n",
"HTAA_checkAuthorization: translated path:",
pathname, "method:", HTAAMethod_name(method));
#endif
/*
** Get protection setting (set up by callbacks from rule system)
** NULL, if not protected by a "protect" rule.
*/
prot = HTAA_getCurrentProtection();
/*
** Check ACL existence
*/
if (!(acl_file = HTAA_openAcl(pathname))) {
if (prot) { /* protect rule, but no ACL */
if (prot->mask_group) {
/*
** Only mask enabled, check that
*/
GroupDefList *group_def_list =
HTAA_readGroupFile(HTAssocList_lookup(prot->values,
"group"));
/*
** Authenticate if authentication info given
*/
if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) {
htaa_user = HTAA_authenticate(scheme,
scheme_specifics,
prot);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "Authentication returned: %s\n",
(htaa_user ? htaa_user->username
: "NOT-AUTHENTICATED"));
#endif
}
HTAA_resolveGroupReferences(prot->mask_group, group_def_list);
reason = HTAA_userAndInetInGroup(prot->mask_group,
htaa_user
? htaa_user->username : "",
HTClientHost,
NULL);
#ifndef DISABLE_TRACE
if (www2Trace) {
if (reason != HTAA_OK)
fprintf(stderr, "%s %s %s %s\n",
"HTAA_checkAuthorization: access denied",
"by mask (no ACL, only Protect rule)",
"host", HTClientHost);
else fprintf(stderr, "%s %s %s %s\n",
"HTAA_checkAuthorization: request from",
HTClientHost,
"accepted by only mask match (no ACL, only",
"Protect rule, and only mask enabled)");
}
#endif
return reason;
}
else { /* 403 Forbidden */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s\n",
"HTAA_checkAuthorization: Protected, but",
"no mask group nor ACL -- forbidden");
#endif
return HTAA_NO_ACL;
}
}
else { /* No protect rule and no ACL => OK 200 */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTAA_checkAuthorization: %s\n",
"no protect rule nor ACL -- ok\n");
#endif
return HTAA_OK;
}
}
/*
** Now we know that ACL exists
*/
if (!prot) { /* Not protected by "protect" rule */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTAA_checkAuthorization: default protection\n");
#endif
prot = HTAA_getDefaultProtection(); /* Also sets current protection */
if (!prot) { /* @@ Default protection not set ?? */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s\n",
"HTAA_checkAuthorization: default protection",
"not set (internal server error)!!");
#endif
return HTAA_SETUP_ERROR;
}
}
/*
** Now we know that document is protected and ACL exists.
** Check against ACL entry.
*/
{
GroupDefList *group_def_list =
HTAA_readGroupFile(HTAssocList_lookup(prot->values, "group"));
/*
** Authenticate now that we know protection mode
*/
if (scheme != HTAA_UNKNOWN && scheme != HTAA_NONE) {
htaa_user = HTAA_authenticate(scheme,
scheme_specifics,
prot);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "Authentication returned: %s\n",
(htaa_user
? htaa_user->username : "NOT-AUTHENTICATED"));
#endif
}
/*
** Check mask group
*/
if (prot->mask_group) {
HTAA_resolveGroupReferences(prot->mask_group, group_def_list);
reason=HTAA_userAndInetInGroup(prot->mask_group,
htaa_user ? htaa_user->username : "",
HTClientHost,
NULL);
if (reason != HTAA_OK) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s %s\n",
"HTAA_checkAuthorization: access denied",
"by mask, host:", HTClientHost);
#endif
return reason;
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "%s %s %s %s %s\n",
"HTAA_checkAuthorization: request from",
HTClientHost,
"accepted by just mask group match",
"(no ACL, only Protect rule, and only",
"mask enabled)");
#endif
/* And continue authorization checking */
}
/*
** Get ACL entries; get first one first, the loop others
** Remember, allowed_groups is automatically freed by
** HTAA_getAclEntry().
*/
allowed_groups = HTAA_getAclEntry(acl_file, pathname, method);
if (!allowed_groups) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s `%s' %s\n",
"No entry for file", pathname, "in ACL");
#endif
HTAA_closeAcl(acl_file);
return HTAA_NO_ENTRY; /* Forbidden -- no entry in the ACL */
}
else {
do {
HTAA_resolveGroupReferences(allowed_groups, group_def_list);
reason = HTAA_userAndInetInGroup(allowed_groups,
htaa_user
? htaa_user->username : "",
HTClientHost,
NULL);
if (reason == HTAA_OK) {
HTAA_closeAcl(acl_file);
return HTAA_OK; /* OK */
}
allowed_groups = HTAA_getAclEntry(acl_file, pathname, method);
} while (allowed_groups);
HTAA_closeAcl(acl_file);
return HTAA_NOT_MEMBER; /* Unauthorized */
}
}
}
/* PUBLIC HTAA_checkAuthorization()
** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
** ON ENTRY:
** url is the document to be accessed.
** method_name name of the method, e.g. "GET"
** scheme_name authentication scheme name.
** scheme_specifics authentication string (or other
** scheme specific parameters, like
** Kerberos-ticket).
**
** ON EXIT:
** returns status codes uniform with those of HTTP:
** 200 OK if file access is ok.
** 401 Unauthorized if user is not authorized to
** access the file.
** 403 Forbidden if there is no entry for the
** requested file in the ACL.
**
** NOTE:
** This function does not check whether the file
** exists or not -- so the status 404 Not found
** must be returned from somewhere else (this is
** to avoid unnecessary overhead of opening the
** file twice).
**
*/
PUBLIC int HTAA_checkAuthorization ARGS4(WWW_CONST char *, url,
WWW_CONST char *, method_name,
WWW_CONST char *, scheme_name,
char *, scheme_specifics)
{
static char *pathname = NULL;
char *local_copy = NULL;
HTAAMethod method = HTAAMethod_enum(method_name);
HTAAScheme scheme = HTAAScheme_enum(scheme_name);
/*
** Translate into absolute pathname, and
** check for "protect" and "defprot" rules.
*/
FREE(pathname); /* From previous call */
StrAllocCopy(local_copy, url);
{
char *keywords = strchr(local_copy, '?');
if (keywords) *keywords = (char)0; /* Chop off keywords */
}
HTSimplify(local_copy); /* Remove ".." etc. */
pathname = HTTranslate(local_copy);
if (!HTSecure) {
char *localname = HTLocalName(pathname);
free(pathname);
pathname = localname;
}
FREE(local_copy);
HTAAFailReason = check_authorization(pathname, method,
scheme, scheme_specifics);
if (htaa_logfile) {
time(&theTime);
fprintf(htaa_logfile, "%24.24s %s %s %s %s %s\n",
ctime(&theTime),
HTClientHost ? HTClientHost : "local",
method_name,
url,
status_name(HTAAFailReason),
htaa_user && htaa_user->username
? htaa_user->username : "");
fflush(htaa_logfile); /* Actually update it on disk */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "Log: %24.24s %s %s %s %s %s\n",
ctime(&theTime),
HTClientHost ? HTClientHost : "local",
method_name,
url,
status_name(HTAAFailReason),
htaa_user && htaa_user->username
? htaa_user->username : "");
#endif
}
switch (HTAAFailReason) {
case HTAA_NO_AUTH:
case HTAA_NOT_MEMBER:
return 401;
break;
case HTAA_BY_RULE:
case HTAA_IP_MASK:
case HTAA_NO_ACL:
case HTAA_NO_ENTRY:
case HTAA_SETUP_ERROR:
return 403;
break;
case HTAA_NOT_FOUND:
return 404;
break;
case HTAA_OK:
return 200;
break;
default:
return 500;
} /* switch */
}
/* PRIVATE compose_scheme_specifics()
** COMPOSE SCHEME-SPECIFIC PARAMETERS
** TO BE SENT ALONG WITH SERVER REPLY
** IN THE WWW-Authenticate: FIELD.
** ON ENTRY:
** scheme is the authentication scheme for which
** parameters are asked for.
** prot protection setup structure.
**
** ON EXIT:
** returns scheme specific parameters in an
** auto-freed string.
*/
PRIVATE char *compose_scheme_specifics ARGS2(HTAAScheme, scheme,
HTAAProt *, prot)
{
static char *result = NULL;
FREE(result); /* From previous call */
switch (scheme) {
case HTAA_BASIC:
{
char *realm = HTAssocList_lookup(prot->values, "server");
result = (char*)malloc(60);
sprintf(result, "realm=\"%s\"",
(realm ? realm : "UNKNOWN"));
return result;
}
break;
case HTAA_PUBKEY:
{
char *realm = HTAssocList_lookup(prot->values, "server");
result = (char*)malloc(200);
sprintf(result, "realm=\"%s\", key=\"%s\"",
(realm ? realm : "UNKNOWN"),
"PUBKEY-NOT-IMPLEMENTED");
return result;
}
break;
default:
return NULL;
}
}
/* SERVER PUBLIC HTAA_composeAuthHeaders()
** COMPOSE WWW-Authenticate: HEADER LINES
** INDICATING VALID AUTHENTICATION SCHEMES
** FOR THE REQUESTED DOCUMENT
** ON ENTRY:
** No parameters, but HTAA_checkAuthorization() must
** just before have failed because a wrong (or none)
** authentication scheme was used.
**
** ON EXIT:
** returns a buffer containing all the WWW-Authenticate:
** fields including CRLFs (this buffer is auto-freed).
** NULL, if authentication won't help in accessing
** the requested document.
**
*/
PUBLIC char *HTAA_composeAuthHeaders NOARGS
{
static char *result = NULL;
HTAAScheme scheme;
char *scheme_name;
char *scheme_params;
HTAAProt *prot = HTAA_getCurrentProtection();
if (!prot) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s\n",
"HTAA_composeAuthHeaders: Document not protected",
"-- why was this function called??");
#endif
return NULL;
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "HTAA_composeAuthHeaders: for file `%s'\n",
prot->filename);
#endif
FREE(result); /* From previous call */
if (!(result = (char*)malloc(4096))) /* @@ */
outofmem(__FILE__, "HTAA_composeAuthHeaders");
*result = (char)0;
for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
if (-1 < HTList_indexOf(prot->valid_schemes, (void*)scheme)) {
if ((scheme_name = HTAAScheme_name(scheme))) {
scheme_params = compose_scheme_specifics(scheme,prot);
strcat(result, "WWW-Authenticate: ");
strcat(result, scheme_name);
if (scheme_params) {
strcat(result, " ");
strcat(result, scheme_params);
}
strcat(result, "\r\n");
} /* scheme name found */
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "HTAA_composeAuthHeaders: %s %d\n",
"No name found for scheme number", scheme);
#endif
} /* scheme valid for requested document */
} /* for every scheme */
return result;
}
/* PUBLIC HTAA_startLogging()
** START UP ACCESS AUTHORIZATION LOGGING
** ON ENTRY:
** fp is the open log file.
**
*/
PUBLIC void HTAA_startLogging ARGS1(FILE *, fp)
{
htaa_logfile = fp;
}

144
libwww2/HTAAServ.h Normal file
View File

@@ -0,0 +1,144 @@
/* SERVER SIDE ACCESS AUTHORIZATION MODULE
This module is the server side interface to Access Authorization (AA) package. It
contains code only for server.
Important to know about memory allocation:
Routines in this module use dynamic allocation, but free automatically all the memory
reserved by them.
Therefore the caller never has to (and never should) free() any object returned by
these functions.
Therefore also all the strings returned by this package are only valid until the next
call to the same function is made. This approach is selected, because of the nature of
access authorization: no string returned by the package needs to be valid longer than
until the next call.
This also makes it easy to plug the AA package in: you don't have to ponder whether to
free()something here or is it done somewhere else (because it is always done somewhere
else).
The strings that the package needs to store are copied so the original strings given as
parameters to AA functions may be freed or modified with no side effects.
Also note:The AA package does not free() anything else than what it has itself
allocated.
*/
#ifndef HTAASERV_H
#define HTAASERV_H
#include <stdio.h> /* FILE */
#include "HTUtils.h" /* BOOL, PARAMS, ARGS */
#include "HTRules.h" /* This module interacts with rule system */
#include "HTAAUtil.h" /* Common parts of AA */
#include "HTAuth.h" /* Authentication */
#ifdef SHORT_NAMES
#define HTAAstMs HTAA_statusMessage
#define HTAAchAu HTAA_checkAuthorization
#define HTAAcoAH HTAA_composeAuthHeaders
#define HTAAsLog HTAA_startLogging
#endif /*SHORT_NAMES*/
/*
Check Access Authorization
HTAA_checkAuthorization() is the main access authorization function.
*/
/* PUBLIC HTAA_checkAuthorization()
** CHECK IF USER IS AUTHORIZED TO ACCESS A FILE
** ON ENTRY:
** url is the document to be accessed.
** method_name name of the method, e.g. "GET"
** scheme_name authentication scheme name.
** scheme_specifics authentication string (or other
** scheme specific parameters, like
** Kerberos-ticket).
**
** ON EXIT:
** returns status codes uniform with those of HTTP:
** 200 OK if file access is ok.
** 401 Unauthorized if user is not authorized to
** access the file.
** 403 Forbidden if there is no entry for the
** requested file in the ACL.
**
** NOTE:
** This function does not check whether the file
** exists or not -- so the status 404 Not found
** must be returned from somewhere else (this is
** to avoid unnecessary overhead of opening the
** file twice).
**
*/
PUBLIC int HTAA_checkAuthorization PARAMS((WWW_CONST char * url,
WWW_CONST char * method_name,
WWW_CONST char * scheme_name,
char * scheme_specifics));
/*
Compose Status Line Message
*/
/* SERVER PUBLIC HTAA_statusMessage()
** RETURN A STRING EXPLAINING ACCESS
** AUTHORIZATION FAILURE
** (Can be used in server reply status line
** with 401/403 replies.)
** ON EXIT:
** returns a string containing the error message
** corresponding to internal HTAAFailReason.
*/
PUBLIC char *HTAA_statusMessage NOPARAMS;
/*
Compose "Authenticate:" Header Lines for Server Reply
*/
/* SERVER PUBLIC HTAA_composeAuthHeaders()
** COMPOSE WWW-Authenticate: HEADER LINES
** INDICATING VALID AUTHENTICATION SCHEMES
** FOR THE REQUESTED DOCUMENT
** ON ENTRY:
** No parameters, but HTAA_checkAuthorization() must
** just before have failed because a wrong (or none)
** authentication scheme was used.
**
** ON EXIT:
** returns a buffer containing all the WWW-Authenticate:
** fields including CRLFs (this buffer is auto-freed).
** NULL, if authentication won't help in accessing
** the requested document.
*/
PUBLIC char *HTAA_composeAuthHeaders NOPARAMS;
/*
Start Access Authorization Logging
*/
/* PUBLIC HTAA_startLogging()
** START UP ACCESS AUTHORIZATION LOGGING
** ON ENTRY:
** fp is the open log file.
**
*/
PUBLIC void HTAA_startLogging PARAMS((FILE * fp));
/*
*/
#endif /* NOT HTAASERV_H */
/*
End of file HTAAServ.h. */

538
libwww2/HTAAUtil.c Normal file
View File

@@ -0,0 +1,538 @@
/* MODULE HTAAUtil.c
** COMMON PARTS OF ACCESS AUTHORIZATION MODULE
** FOR BOTH SERVER AND BROWSER
**
** IMPORTANT:
** Routines in this module use dynamic allocation, but free
** automatically all the memory reserved by them.
**
** Therefore the caller never has to (and never should)
** free() any object returned by these functions.
**
** Therefore also all the strings returned by this package
** are only valid until the next call to the same function
** is made. This approach is selected, because of the nature
** of access authorization: no string returned by the package
** needs to be valid longer than until the next call.
**
** This also makes it easy to plug the AA package in:
** you don't have to ponder whether to free() something
** here or is it done somewhere else (because it is always
** done somewhere else).
**
** The strings that the package needs to store are copied
** so the original strings given as parameters to AA
** functions may be freed or modified with no side effects.
**
** The AA package does not free() anything else than what
** it has itself allocated.
**
** AA (Access Authorization) package means modules which
** names start with HTAA.
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <string.h>
#include "HTUtils.h"
#include "tcp.h" /* NETREAD() etc. */
#include "HTAAUtil.h" /* Implemented here */
#include "HTAssoc.h" /* Assoc list */
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* PUBLIC HTAAScheme_enum()
** TRANSLATE SCHEME NAME INTO
** A SCHEME ENUMERATION
**
** ON ENTRY:
** name is a string representing the scheme name.
**
** ON EXIT:
** returns the enumerated constant for that scheme.
*/
PUBLIC HTAAScheme HTAAScheme_enum ARGS1(WWW_CONST char*, name)
{
static char *upcased = NULL;
char *cur;
if (!name) return HTAA_UNKNOWN;
StrAllocCopy(upcased, name);
cur = upcased;
while (*cur) {
*cur = TOUPPER(*cur);
cur++;
}
if (!strncmp(upcased, "NONE", 4))
return HTAA_NONE;
else if (!strncmp(upcased, "BASIC", 5))
return HTAA_BASIC;
else if (!strncmp(upcased, "PUBKEY", 6))
return HTAA_PUBKEY;
else if (!strncmp(upcased, "KERBEROSV4", 10))
return HTAA_KERBEROS_V4;
else if (!strncmp(upcased, "KERBEROSV5", 10))
return HTAA_KERBEROS_V5;
else if (!strncmp(upcased, "DIGEST", 6))
return HTAA_MD5; /* DXP */
else
return HTAA_UNKNOWN;
}
/* PUBLIC HTAAScheme_name()
** GET THE NAME OF A GIVEN SCHEME
** ON ENTRY:
** scheme is one of the scheme enum values:
** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ...
**
** ON EXIT:
** returns the name of the scheme, i.e.
** "None", "Basic", "Pubkey", ...
*/
PUBLIC char *HTAAScheme_name ARGS1(HTAAScheme, scheme)
{
switch (scheme) {
case HTAA_NONE: return "None"; break;
case HTAA_BASIC: return "Basic"; break;
case HTAA_PUBKEY: return "Pubkey"; break;
case HTAA_KERBEROS_V4: return "KerberosV4"; break;
case HTAA_KERBEROS_V5: return "KerberosV5"; break;
case HTAA_MD5: return "Digest"; break;
case HTAA_UNKNOWN: return "UNKNOWN"; break;
default: return "THIS-IS-A-BUG";
}
}
/* PUBLIC HTAAMethod_enum()
** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE
** ON ENTRY:
** name is the method name to translate.
**
** ON EXIT:
** returns HTAAMethod enumerated value corresponding
** to the given name.
*/
PUBLIC HTAAMethod HTAAMethod_enum ARGS1(WWW_CONST char *, name)
{
char tmp[MAX_METHODNAME_LEN+1];
WWW_CONST char *src = name;
char *dest = tmp;
if (!name) return METHOD_UNKNOWN;
while (*src) {
*dest = TOUPPER(*src);
dest++;
src++;
}
*dest = 0;
if (0==strcmp(tmp, "GET"))
return METHOD_GET;
else if (0==strcmp(tmp, "PUT"))
return METHOD_PUT;
else if (0==strcmp(tmp, "META"))
return METHOD_META;
else
return METHOD_UNKNOWN;
}
/* PUBLIC HTAAMethod_name()
** GET THE NAME OF A GIVEN METHOD
** ON ENTRY:
** method is one of the method enum values:
** METHOD_GET, METHOD_PUT, ...
**
** ON EXIT:
** returns the name of the scheme, i.e.
** "GET", "PUT", ...
*/
PUBLIC char *HTAAMethod_name ARGS1(HTAAMethod, method)
{
switch (method) {
case METHOD_GET: return "GET"; break;
case METHOD_PUT: return "PUT"; break;
case METHOD_META: return "META"; break;
case METHOD_UNKNOWN: return "UNKNOWN"; break;
default: return "THIS-IS-A-BUG";
}
}
/* PUBLIC HTAAMethod_inList()
** IS A METHOD IN A LIST OF METHOD NAMES
** ON ENTRY:
** method is the method to look for.
** list is a list of method names.
**
** ON EXIT:
** returns YES, if method was found.
** NO, if not found.
*/
PUBLIC BOOL HTAAMethod_inList ARGS2(HTAAMethod, method,
HTList *, list)
{
HTList *cur = list;
char *item;
while (NULL != (item = (char*)HTList_nextObject(cur))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, " %s", item);
#endif
if (method == HTAAMethod_enum(item))
return YES;
}
return NO; /* Not found */
}
/* PUBLIC HTAA_templateMatch()
** STRING COMPARISON FUNCTION FOR FILE NAMES
** WITH ONE WILDCARD * IN THE TEMPLATE
** NOTE:
** This is essentially the same code as in HTRules.c, but it
** cannot be used because it is embedded in between other code.
** (In fact, HTRules.c should use this routine, but then this
** routine would have to be more sophisticated... why is life
** sometimes so hard...)
**
** ON ENTRY:
** template is a template string to match the file name
** agaist, may contain a single wildcard
** character * which matches zero or more
** arbitrary characters.
** filename is the filename (or pathname) to be matched
** agaist the template.
**
** ON EXIT:
** returns YES, if filename matches the template.
** NO, otherwise.
*/
PUBLIC BOOL HTAA_templateMatch ARGS2(WWW_CONST char *, template,
WWW_CONST char *, filename)
{
WWW_CONST char *p = template;
WWW_CONST char *q = filename;
int m;
for( ; *p && *q && *p == *q; p++, q++) /* Find first mismatch */
; /* do nothing else */
if (!*p && !*q) return YES; /* Equally long equal strings */
else if ('*' == *p) { /* Wildcard */
p++; /* Skip wildcard character */
m = strlen(q) - strlen(p); /* Amount to match to wildcard */
if (m < 0) return NO; /* No match, filename too short */
else { /* Skip the matched characters and compare */
if (strcmp(p, q+m)) return NO; /* Tail mismatch */
else return YES; /* Tail match */
}
} /* if wildcard */
else return NO; /* Length or character mismatch */
}
/* PUBLIC HTAA_makeProtectionTemplate()
** CREATE A PROTECTION TEMPLATE FOR THE FILES
** IN THE SAME DIRECTORY AS THE GIVEN FILE
** (Used by server if there is no fancier way for
** it to tell the client, and by browser if server
** didn't send WWW-ProtectionTemplate: field)
** ON ENTRY:
** docname is the document pathname (from URL).
**
** ON EXIT:
** returns a template matching docname, and other files
** files in that directory.
**
** E.g. /foo/bar/x.html => /foo/bar/ *
** ^
** Space only to prevent it from
** being a comment marker here,
** there really isn't any space.
*/
PUBLIC char *HTAA_makeProtectionTemplate ARGS1(WWW_CONST char *, docname)
{
char *template = NULL;
char *slash = NULL;
if (docname) {
StrAllocCopy(template, docname);
slash = strrchr(template, '/');
if (slash) slash++;
else slash = template;
*slash = (char)0;
StrAllocCat(template, "*");
}
else StrAllocCopy(template, "*");
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"make_template: made template `%s' for file `%s'\n",
template, docname);
#endif
return template;
}
/*
** Skip leading whitespace from *s forward
*/
#define SKIPWS(s) while (*s==' ' || *s=='\t') s++;
/*
** Kill trailing whitespace starting from *(s-1) backwords
*/
#define KILLWS(s) {char *c=s-1; while (*c==' ' || *c=='\t') *(c--)=(char)0;}
/* PUBLIC HTAA_parseArgList()
** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD
** ON ENTRY:
** str is a comma-separated list:
**
** item, item, item
** where
** item ::= value
** | name=value
** | name="value"
**
** Leading and trailing whitespace is ignored
** everywhere except inside quotes, so the following
** examples are equal:
**
** name=value,foo=bar
** name="value",foo="bar"
** name = value , foo = bar
** name = "value" , foo = "bar"
**
** ON EXIT:
** returns a list of name-value pairs (actually HTAssocList*).
** For items with no name, just value, the name is
** the number of order number of that item. E.g.
** "1" for the first, etc.
*/
PUBLIC HTAssocList *HTAA_parseArgList ARGS1(char *, str)
{
HTAssocList *assoc_list = HTAssocList_new();
char *cur = NULL;
char *name = NULL;
int index = 0;
if (!str) return assoc_list;
while (*str) {
SKIPWS(str); /* Skip leading whitespace */
cur = str;
index++;
while (*cur && *cur != '=' && *cur != ',')
cur++; /* Find end of name (or lonely value without a name) */
KILLWS(cur); /* Kill trailing whitespace */
if (*cur == '=') { /* Name followed by a value */
*(cur++) = (char)0; /* Terminate name */
StrAllocCopy(name, str);
SKIPWS(cur); /* Skip WS leading the value */
str = cur;
if (*str == '"') { /* Quoted value */
str++;
cur = str;
while (*cur && *cur != '"') cur++;
if (*cur == '"')
*(cur++) = (char)0; /* Terminate value */
/* else it is lacking terminating quote */
SKIPWS(cur); /* Skip WS leading comma */
if (*cur == ',') cur++; /* Skip separating colon */
}
else { /* Unquoted value */
while (*cur && *cur != ',') cur++;
KILLWS(cur); /* Kill trailing whitespace */
if (*cur == ',')
*(cur++) = (char)0;
/* else *cur already NULL */
}
}
else { /* No name, just a value */
if (*cur == ',')
*(cur++) = (char)0; /* Terminate value */
/* else last value on line (already terminated by NULL) */
StrAllocCopy(name, "nnn"); /* Room for item order number */
sprintf(name, "%d", index); /* Item order number for name */
}
HTAssocList_add(assoc_list, name, str);
str = cur;
} /* while *str */
return assoc_list;
}
/************** HEADER LINE READER -- DOES UNFOLDING *************************/
#define BUFFER_SIZE 16384
PRIVATE char buffer[BUFFER_SIZE + 1];
PRIVATE char *start_pointer = buffer;
PRIVATE char *end_pointer = buffer;
PRIVATE int in_soc = -1;
/* PUBLIC HTAA_setupReader()
** SET UP HEADER LINE READER, i.e. give
** the already-read-but-not-yet-processed
** buffer of text to be read before more
** is read from the socket.
** ON ENTRY:
** start_of_headers is a pointer to a buffer containing
** the beginning of the header lines
** (rest will be read from a socket).
** length is the number of valid characters in
** 'start_of_headers' buffer.
** soc is the socket to use when start_of_headers
** buffer is used up.
** ON EXIT:
** returns nothing.
** Subsequent calls to HTAA_getUnfoldedLine()
** will use this buffer first and then
** proceed to read from socket.
*/
PUBLIC void HTAA_setupReader ARGS3(char *, start_of_headers,
int, length,
int, soc)
{
start_pointer = buffer;
if (start_of_headers) {
strncpy(buffer, start_of_headers, length);
buffer[length] = (char)0;
end_pointer = buffer + length;
}
else {
*start_pointer = (char)0;
end_pointer = start_pointer;
}
in_soc = soc;
}
/* PUBLIC HTAA_getUnfoldedLine()
** READ AN UNFOLDED HEADER LINE FROM SOCKET
** ON ENTRY:
** HTAA_setupReader must absolutely be called before
** this function to set up internal buffer.
**
** ON EXIT:
** returns a newly-allocated character string representing
** the read line. The line is unfolded, i.e.
** lines that begin with whitespace are appended
** to current line. E.g.
**
** Field-Name: Blaa-Blaa
** This-Is-A-Continuation-Line
** Here-Is_Another
**
** is seen by the caller as:
**
** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
**
*/
PUBLIC char *HTAA_getUnfoldedLine NOARGS
{
char *line = NULL;
char *cur;
int count;
BOOL peek_for_folding = NO;
if (in_soc < 0) {
fprintf(stderr, "%s %s\n",
"HTAA_getUnfoldedLine: buffer not initialized",
"with function HTAA_setupReader()");
return NULL;
}
for(;;) {
/* Reading from socket */
if (start_pointer >= end_pointer) {/*Read the next block and continue*/
count = NETREAD(in_soc, buffer, BUFFER_SIZE);
if (count <= 0) {
in_soc = -1;
return line;
}
start_pointer = buffer;
end_pointer = buffer + count;
*end_pointer = (char)0;
#ifdef NOT_ASCII
cur = start_pointer;
while (cur < end_pointer) {
*cur = TOASCII(*cur);
cur++;
}
#endif /*NOT_ASCII*/
}
cur = start_pointer;
/* Unfolding */
if (peek_for_folding) {
if (*cur != ' ' && *cur != '\t')
return line; /* Ok, no continuation line */
else /* So this is a continuation line, continue */
peek_for_folding = NO;
}
/* Finding end-of-line */
while (cur < end_pointer && *cur != '\n') /* Find the end-of-line */
cur++; /* (or end-of-buffer). */
/* Terminating line */
if (cur < end_pointer) { /* So *cur==LF, terminate line */
*cur = (char)0; /* Overwrite LF */
if (*(cur-1) == '\r')
*(cur-1) = (char)0; /* Overwrite CR */
peek_for_folding = YES; /* Check for a continuation line */
}
/* Copying the result */
if (line)
StrAllocCat(line, start_pointer); /* Append */
else
StrAllocCopy(line, start_pointer); /* A new line */
start_pointer = cur+1; /* Skip the read line */
} /* forever */
}

342
libwww2/HTAAUtil.h Normal file
View File

@@ -0,0 +1,342 @@
/* Utilities for the Authorization parts of libwww
COMMON PARTS OF AUTHORIZATION MODULE TO BOTH SERVER AND BROWSER
This module is the interface to the common parts of Access Authorization (AA) package
for both server and browser. Important to know about memory allocation:
Routines in this module use dynamic allocation, but free automatically all the memory
reserved by them.
Therefore the caller never has to (and never should) free() any object returned by
these functions.
Therefore also all the strings returned by this package are only valid until the next
call to the same function is made. This approach is selected, because of the nature of
access authorization: no string returned by the package needs to be valid longer than
until the next call.
This also makes it easy to plug the AA package in: you don't have to ponder whether to
free() something here or is it done somewhere else (because it is always done somewhere
else).
The strings that the package needs to store are copied so the original strings given as
parameters to AA functions may be freed or modified with no side effects.
Also note: The AA package does not free() anything else than what it has itself
allocated.
*/
#ifndef HTAAUTIL_H
#define HTAAUTIL_H
#ifndef __SRC__
#include "HTUtils.h" /* BOOL, PARAMS, ARGS */
#include "HTList.h"
#include "tcp.h"
#endif
#ifdef SHORT_NAMES
#define HTAASenu HTAAScheme_enum
#define HTAASnam HTAAScheme_name
#define HTAAMenu HTAAMethod_enum
#define HTAAMnam HTAAMethod_name
#define HTAAMinL HTAAMethod_inList
#define HTAAteMa HTAA_templateMatch
#define HTAAmaPT HTAA_makeProtectionTemplate
#define HTAApALi HTAA_parseArgList
#define HTAAsuRe HTAA_setupReader
#define HTAAgUfL HTAA_getUnfoldedLine
#endif /*SHORT_NAMES*/
/*
Default filenames
*/
#ifndef PASSWD_FILE
#define PASSWD_FILE "/home2/luotonen/passwd"
#endif
#ifndef GROUP_FILE
#define GROUP_FILE "/home2/luotonen/group"
#endif
#define ACL_FILE_NAME ".www_acl"
/*
** Numeric constants
*/
#define MAX_USERNAME_LEN 128 /* @@ Longest allowed username */
#define MAX_PASSWORD_LEN 3*13 /* @@ Longest allowed password */
/* (encrypted, so really only 3*8)*/
#define MAX_METHODNAME_LEN 128 /* @@ Longest allowed method name */
#define MAX_FIELDNAME_LEN 128 /* @@ Longest field name in */
/* protection setup file */
#define MAX_PATHNAME_LEN 128 /* @@ Longest passwd/group file */
/* patname to allow */
/*
** Helpful macros
*/
#define FREE(x) if (x) {free(x); x=NULL;}
/*
Datatype definitions
HTAASCHEME
The enumeration HTAAScheme represents the possible authentication schemes used by the
WWW Access Authorization.
*/
typedef enum {
HTAA_UNKNOWN,
HTAA_NONE,
HTAA_BASIC,
HTAA_PUBKEY,
HTAA_KERBEROS_V4,
HTAA_KERBEROS_V5,
HTAA_MD5,
HTAA_DOMAIN,
HTAA_MAX_SCHEMES, /* THIS MUST ALWAYS BE LAST! Number of schemes */
HTAA_LOGIN /*No...this must always be last because it is a FTP hack*/
} HTAAScheme;
/*
ENUMERATION TO REPRESENT HTTP METHODS
*/
typedef enum {
METHOD_UNKNOWN,
METHOD_GET,
METHOD_PUT,
METHOD_META
} HTAAMethod;
#ifndef __SRC__
/*
Authentication Schemes
*/
/* PUBLIC HTAAScheme_enum()
** TRANSLATE SCHEME NAME TO A SCHEME ENUMERATION
** ON ENTRY:
** name is a string representing the scheme name.
**
** ON EXIT:
** returns the enumerated constant for that scheme.
*/
PUBLIC HTAAScheme HTAAScheme_enum PARAMS((WWW_CONST char* name));
/* PUBLIC HTAAScheme_name()
** GET THE NAME OF A GIVEN SCHEME
** ON ENTRY:
** scheme is one of the scheme enum values:
** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ...
**
** ON EXIT:
** returns the name of the scheme, i.e.
** "none", "basic", "pubkey", ...
*/
PUBLIC char *HTAAScheme_name PARAMS((HTAAScheme scheme));
/*
Methods
*/
/* PUBLIC HTAAMethod_enum()
** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE
** ON ENTRY:
** name is the method name to translate.
**
** ON EXIT:
** returns HTAAMethod enumerated value corresponding
** to the given name.
*/
PUBLIC HTAAMethod HTAAMethod_enum PARAMS((WWW_CONST char * name));
/* PUBLIC HTAAMethod_name()
** GET THE NAME OF A GIVEN METHOD
** ON ENTRY:
** method is one of the method enum values:
** METHOD_GET, METHOD_PUT, ...
**
** ON EXIT:
** returns the name of the scheme, i.e.
** "GET", "PUT", ...
*/
PUBLIC char *HTAAMethod_name PARAMS((HTAAMethod method));
/* PUBLIC HTAAMethod_inList()
** IS A METHOD IN A LIST OF METHOD NAMES
** ON ENTRY:
** method is the method to look for.
** list is a list of method names.
**
** ON EXIT:
** returns YES, if method was found.
** NO, if not found.
*/
PUBLIC BOOL HTAAMethod_inList PARAMS((HTAAMethod method,
HTList * list));
/*
Match Template Against Filename
*/
/* PUBLIC HTAA_templateMatch()
** STRING COMPARISON FUNCTION FOR FILE NAMES
** WITH ONE WILDCARD * IN THE TEMPLATE
** NOTE:
** This is essentially the same code as in HTRules.c, but it
** cannot be used because it is embedded in between other code.
** (In fact, HTRules.c should use this routine, but then this
** routine would have to be more sophisticated... why is life
** sometimes so hard...)
**
** ON ENTRY:
** template is a template string to match the file name
** agaist, may contain a single wildcard
** character * which matches zero or more
** arbitrary characters.
** filename is the filename (or pathname) to be matched
** agaist the template.
**
** ON EXIT:
** returns YES, if filename matches the template.
** NO, otherwise.
*/
PUBLIC BOOL HTAA_templateMatch PARAMS((WWW_CONST char * template,
WWW_CONST char * filename));
/* PUBLIC HTAA_makeProtectionTemplate()
** CREATE A PROTECTION TEMPLATE FOR THE FILES
** IN THE SAME DIRECTORY AS THE GIVEN FILE
** (Used by server if there is no fancier way for
** it to tell the client, and by browser if server
** didn't send WWW-ProtectionTemplate: field)
** ON ENTRY:
** docname is the document pathname (from URL).
**
** ON EXIT:
** returns a template matching docname, and other files
** files in that directory.
**
** E.g. /foo/bar/x.html => /foo/bar/ *
** ^
** Space only to prevent it from
** being a comment marker here,
** there really isn't any space.
*/
PUBLIC char *HTAA_makeProtectionTemplate PARAMS((WWW_CONST char * docname));
/*
MIME Argument List Parser
*/
/* PUBLIC HTAA_parseArgList()
** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD
** ON ENTRY:
** str is a comma-separated list:
**
** item, item, item
** where
** item ::= value
** | name=value
** | name="value"
**
** Leading and trailing whitespace is ignored
** everywhere except inside quotes, so the following
** examples are equal:
**
** name=value,foo=bar
** name="value",foo="bar"
** name = value , foo = bar
** name = "value" , foo = "bar"
**
** ON EXIT:
** returns a list of name-value pairs (actually HTAssocList*).
** For items with no name, just value, the name is
** the number of order number of that item. E.g.
** "1" for the first, etc.
*/
PUBLIC HTList *HTAA_parseArgList PARAMS((char * str));
/*
Header Line Reader
*/
/* PUBLIC HTAA_setupReader()
** SET UP HEADER LINE READER, i.e. give
** the already-read-but-not-yet-processed
** buffer of text to be read before more
** is read from the socket.
** ON ENTRY:
** start_of_headers is a pointer to a buffer containing
** the beginning of the header lines
** (rest will be read from a socket).
** length is the number of valid characters in
** 'start_of_headers' buffer.
** soc is the socket to use when start_of_headers
** buffer is used up.
** ON EXIT:
** returns nothing.
** Subsequent calls to HTAA_getUnfoldedLine()
** will use this buffer first and then
** proceed to read from socket.
*/
PUBLIC void HTAA_setupReader PARAMS((char * start_of_headers,
int length,
int soc));
/* PUBLIC HTAA_getUnfoldedLine()
** READ AN UNFOLDED HEADER LINE FROM SOCKET
** ON ENTRY:
** HTAA_setupReader must absolutely be called before
** this function to set up internal buffer.
**
** ON EXIT:
** returns a newly-allocated character string representing
** the read line. The line is unfolded, i.e.
** lines that begin with whitespace are appended
** to current line. E.g.
**
** Field-Name: Blaa-Blaa
** This-Is-A-Continuation-Line
** Here-Is_Another
**
** is seen by the caller as:
**
** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
**
*/
PUBLIC char *HTAA_getUnfoldedLine NOPARAMS;
#endif /* Not in SRC tree */
#endif /* NOT HTAAUTIL_H */
/*
End of file HTAAUtil.h. */

217
libwww2/HTACL.c Normal file
View File

@@ -0,0 +1,217 @@
/* MODULE HTACL.c
** ACCESS CONTROL LIST ROUTINES
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <stdio.h> /* FILE */
#include <string.h>
#include "HTUtils.h"
#include "HTAAFile.h" /* File routines */
#include "HTGroup.h" /* GroupDef */
#include "HTACL.h" /* Implemented here */
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* PUBLIC HTAA_getAclFilename()
** RESOLVE THE FULL PATHNAME OF ACL FILE FOR A GIVEN FILE
** ON ENTRY:
** path is the pathname of the file for which to
** ACL file should be found.
**
** ACL filename is computed by replacing
** the filename by .www_acl in the pathname
** (this is done to a local copy, of course).
**
** ON EXIT:
** returns the absolute pathname of ACL file
** (which is automatically freed next time
** this fuction is called).
*/
PUBLIC char *HTAA_getAclFilename ARGS1(WWW_CONST char *, pathname)
{
static char * local_copy = NULL;
static char * acl_path = NULL;
char * directory = NULL;
char * filename = NULL;
StrAllocCopy(local_copy, pathname); /* Also frees local_copy */
/* from previous call. */
directory = local_copy;
filename = strrchr(directory, '/');
if (!filename) { /* No path in front of filename */
directory = "."; /* So use current directory */
filename = local_copy; /* and the pathname itself is the filename */
}
else {
*filename = '\0'; /* Truncate filename off from directory path */
filename++; /* and the filename begins from the next character */
}
StrAllocCopy(acl_path, directory); /* Also frees acl_path */
/* from previous call. */
StrAllocCat(acl_path, "/");
StrAllocCat(acl_path, ACL_FILE_NAME);
return acl_path;
}
/* PUBLIC HTAA_openAcl()
** OPEN THE ACL FILE FOR THE GIVEN DOCUMENT
** ON ENTRY:
** pathname is the absolute pathname of
** the file to be accessed.
**
** ON EXIT:
** returns the FILE* to open ACL.
** NULL, if ACL not found.
*/
PUBLIC FILE *HTAA_openAcl ARGS1(WWW_CONST char *, pathname)
{
return fopen(HTAA_getAclFilename(pathname), "r");
}
/* PUBLIC HTAA_closeAcl()
** CLOSE ACL FILE
** ON ENTRY:
** acl_file is Access Control List file to close.
**
** ON EXIT:
** returns nothing.
*/
PUBLIC void HTAA_closeAcl ARGS1(FILE *, acl_file)
{
if (acl_file) fclose(acl_file);
}
/* PUBLIC HTAA_getAclEntry()
** CONSULT THE ACCESS CONTROL LIST AND
** GIVE A LIST OF GROUPS (AND USERS)
** AUTHORIZED TO ACCESS A GIVEN FILE
** ON ENTRY:
** acl_file is an open ACL file.
** pathname is the absolute pathname of
** the file to be accessed.
** method is the method for which access is wanted.
**
** ALC FILE FORMAT:
**
** template : method, method, ... : group@addr, user, group, ...
**
** The last item is in fact in exactly the same format as
** group definition in group file, i.e. everything that
** follows the 'groupname:' part,
** e.g.
** user, group, user@address, group@address,
** (user,group,...)@(address, address, ...)
**
** ON EXIT:
** returns NULL, if there is no entry for the file in the ACL,
** or ACL doesn't exist.
** If there is, a GroupDef object containing the
** group and user names allowed to access the file
** is returned (this is automatically freed
** next time this function is called).
** IMPORTANT:
** Returns the first entry with matching template and
** method. This function should be called multiple times
** to process all the valid entries (until it returns NULL).
** This is because there can be multiple entries like:
**
** *.html : get,put : ari,timbl,robert
** *.html : get : jim,james,jonathan,jojo
**
** NOTE:
** The returned group definition may well contain references
** to groups defined in group file. Therefore these references
** must be resolved according to that rule file by function
** HTAA_resolveGroupReferences() (group file is read in by
** HTAA_readGroupFile()) and after that access authorization
** can be checked with function HTAA_userAndInetGroup().
*/
PUBLIC GroupDef *HTAA_getAclEntry ARGS3(FILE *, acl_file,
WWW_CONST char *, pathname,
HTAAMethod, method)
{
static GroupDef * group_def = NULL;
WWW_CONST char * filename;
int len;
char *buf;
if (!acl_file) return NULL; /* ACL doesn't exist */
if (group_def) {
GroupDef_delete(group_def); /* From previous call */
group_def = NULL;
}
if (!(filename = strrchr(pathname, '/')))
filename = pathname;
else filename++; /* Skip slash */
len = strlen(filename);
if (!(buf = (char*)malloc((strlen(filename)+2)*sizeof(char))))
outofmem(__FILE__, "HTAA_getAuthorizedGroups");
while (EOF != HTAAFile_readField(acl_file, buf, len+1)) {
if (HTAA_templateMatch(buf, filename)) {
HTList *methods = HTList_new();
HTAAFile_readList(acl_file, methods, MAX_METHODNAME_LEN);
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr,
"Filename '%s' matched template '%s', allowed methods:",
filename, buf);
}
#endif
if (HTAAMethod_inList(method, methods)) { /* right method? */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, " METHOD OK\n");
#endif
HTList_delete(methods);
free(buf);
group_def = HTAA_parseGroupDef(acl_file);
return group_def;
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, " METHOD NOT FOUND\n");
#endif
HTList_delete(methods);
} /* if template match */
else {
HTAAFile_nextRec(acl_file);
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr,
"Filename '%s' didn't match template '%s'\n",
filename, buf);
}
#endif
}
HTAAFile_nextRec(acl_file);
} /* while not eof */
free(buf);
return NULL; /* No entry for requested file */
/* (or an empty entry). */
}

108
libwww2/HTACL.h Normal file
View File

@@ -0,0 +1,108 @@
/* ACCESS CONTROL LIST ROUTINES
*/
#ifndef HTACL_H
#define HTACL_H
#include "HTUtils.h"
#include "HTAAUtil.h"
#include "HTGroup.h"
#ifdef SHORT_NAMES
#define HTAAgAFn HTAA_getAclFilename
#define HTAAoACL HTAA_openAcl
#define HTAAcACL HTAA_closeAcl
#define HTAAgAEn HTAA_getAclEntry
#endif /* SHORT_NAMES */
/*
Opening Access Control List File
*/
/* PUBLIC HTAA_openAcl()
** OPEN THE ACL FILE FOR THE GIVEN DOCUMENT
** ON ENTRY:
** pathname is the absolute pathname of
** the file to be accessed.
**
** ON EXIT:
** returns the FILE* to open ACL.
** NULL, if ACL not found.
*/
PUBLIC FILE *HTAA_openAcl PARAMS((WWW_CONST char * pathname));
/* PUBLIC HTAA_closeAcl()
** CLOSE ACL FILE
** ON ENTRY:
** acl_file is Access Control List file to close.
**
** ON EXIT:
** returns nothing.
*/
PUBLIC void HTAA_closeAcl PARAMS((FILE * acl_file));
/*
Getting ACL Entry
*/
/* PUBLIC HTAA_getAclEntry()
** CONSULT THE ACCESS CONTROL LIST AND
** GIVE A LIST OF GROUPS (AND USERS)
** AUTHORIZED TO ACCESS A GIVEN FILE
** ON ENTRY:
** acl_file is an open ACL file.
** pathname is the absolute pathname of
** the file to be accessed.
** method is the method for which access is wanted.
**
** ALC FILE FORMAT:
**
** template : method, method, ... : group@addr, user, group, ...
**
** The last item is in fact in exactly the same format as
** group definition in group file, i.e. everything that
** follows the 'groupname:' part,
** e.g.
** user, group, user@address, group@address,
** (user,group,...)@(address, address, ...)
**
** ON EXIT:
** returns NULL, if there is no entry for the file in the ACL,
** or ACL doesn't exist.
** If there is, a GroupDef object containing the
** group and user names allowed to access the file
** is returned (this is automatically freed
** next time this function is called).
** IMPORTANT:
** Returns the first entry with matching template and
** method. This function should be called multiple times
** to process all the valid entries (until it returns NULL).
** This is because there can be multiple entries like:
**
** *.html : get,put : ari,timbl,robert
** *.html : get : jim,james,jonathan,jojo
**
** NOTE:
** The returned group definition may well contain references
** to groups defined in group file. Therefore these references
** must be resolved according to that rule file by function
** HTAA_resolveGroupReferences() (group file is read in by
** HTAA_readGroupFile()) and after that access authorization
** can be checked with function HTAA_userAndInetGroup().
*/
PUBLIC GroupDef *HTAA_getAclEntry PARAMS((FILE * acl_file,
WWW_CONST char * pathname,
HTAAMethod method));
/*
*/
#endif /* not HTACL_H */
/*
End of file HTACL.h. */

648
libwww2/HTAccess.c Normal file
View File

@@ -0,0 +1,648 @@
/* Access Manager HTAccess.c
** ==============
**
** Authors
** TBL Tim Berners-Lee timbl@info.cern.ch
** JFG Jean-Francois Groff jfg@dxcern.cern.ch
** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
** History
** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
** 6 Oct 92 Moved HTClientHost and logfile into here. TBL
** 17 Dec 92 Tn3270 added, bug fix. DD
** 4 Feb 93 Access registration, Search escapes bad chars TBL
** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
** 28 May 93 WAIS gateway explicit if no WAIS library linked in.
**
** Bugs
** This module assumes that that the graphic object is hypertext, as it
** needs to select it when it has been loaded. A superclass needs to be
** defined which accepts select and select_anchor.
*/
#include "../config.h"
#ifndef DEFAULT_WAIS_GATEWAY
#define DEFAULT_WAIS_GATEWAY "http://www.ncsa.uiuc.edu:8001/"
#endif
/* Implements:
*/
#include "HTAccess.h"
/* Uses:
*/
#include "HTParse.h"
#include "HTUtils.h"
#include "HTML.h" /* SCW */
#include <stdio.h>
#include "HTList.h"
#include "HText.h" /* See bugs above */
#include "HTAlert.h"
#include "../src/proxy.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
extern char *mo_check_for_proxy (char *);
int has_fallbacks(char *protocol);
char *currentURL=NULL;
/* These flags may be set to modify the operation of this module
*/
PUBLIC char * HTClientHost = 0; /* Name of remote login host if any */
/* To generate other things, play with these:
*/
PUBLIC HTFormat HTOutputFormat = NULL;
PUBLIC HTStream* HTOutputStream = NULL; /* For non-interactive, set this */
PUBLIC BOOL using_gateway = NO; /* are we using a gateway? */
PUBLIC BOOL using_proxy = NO; /* are we using a proxy gateway? */
PUBLIC char *proxy_host_fix=NULL; /* Host: header fix */
PRIVATE HTList * protocols = NULL; /* List of registered protocol descriptors */
/* Register a Protocol HTRegisterProtocol
** -------------------
*/
PUBLIC BOOL HTRegisterProtocol(protocol)
HTProtocol * protocol;
{
if (!protocols) protocols = HTList_new();
HTList_addObject(protocols, protocol);
return YES;
}
/* Register all known protocols
** ----------------------------
**
** Add to or subtract from this list if you add or remove protocol modules.
** This routine is called the first time the protocol list is needed,
** unless any protocols are already registered, in which case it is not called.
** Therefore the application can override this list.
*/
PRIVATE void HTAccessInit NOARGS /* Call me once */
{
extern HTProtocol HTTP, HTFile, HTTelnet, HTTn3270, HTRlogin;
extern HTProtocol HTFTP, HTNews, HTGopher, HTMailto, HTNNTP;
#ifdef DIRECT_WAIS
extern HTProtocol HTWAIS;
#endif
HTRegisterProtocol(&HTFTP);
HTRegisterProtocol(&HTNews);
HTRegisterProtocol(&HTGopher);
#ifdef DIRECT_WAIS
HTRegisterProtocol(&HTWAIS);
#endif
HTRegisterProtocol(&HTTP);
HTRegisterProtocol(&HTFile);
HTRegisterProtocol(&HTTelnet);
HTRegisterProtocol(&HTTn3270);
HTRegisterProtocol(&HTRlogin);
HTRegisterProtocol(&HTMailto);
HTRegisterProtocol(&HTNNTP);
}
/* Find physical name and access protocol
** --------------------------------------
**
**
** On entry,
** addr must point to the fully qualified hypertext reference.
** anchor a pareent anchor with whose address is addr
**
** On exit,
** returns HT_NO_ACCESS Error has occured.
** HT_OK Success
**
*/
PRIVATE int get_physical ARGS3(
char *, addr,
HTParentAnchor *, anchor,
int, bong)
{
char * access=NULL; /* Name of access method */
char * physical = NULL;
char * host = NULL;
struct Proxy *GetNoProxy();
extern int useKeepAlive;
HTAnchor_setPhysical(anchor, addr);
access = HTParse(HTAnchor_physical(anchor),
"file:", PARSE_ACCESS);
host = HTParse(HTAnchor_physical(anchor), "", PARSE_HOST);
/*
** set useKeepAlive to the default here because the last pass might
** have turned this off, and the default might have been on.
*/
/*
Init_useKeepAlive();
*/
useKeepAlive=1;
/* Check whether gateway access has been set up for this
*/
#define USE_GATEWAYS
#ifdef USE_GATEWAYS
/* make sure the using_proxy variable is false */
using_proxy = NO;
if (proxy_host_fix) {
free(proxy_host_fix);
proxy_host_fix=NULL;
}
{
char *tmp_access,*tmp_host,*ptr;
for (ptr=tmp_access=strdup(access); ptr && *ptr; ptr++) *ptr=tolower(*ptr);
for (ptr=tmp_host=strdup(host); ptr && *ptr; ptr++) *ptr=tolower(*ptr);
if (!GetNoProxy(tmp_access, tmp_host)) {
char *gateway_parameter, *gateway, *proxy;
struct Proxy *proxent = NULL, *GetProxy();
extern struct Proxy *proxy_list;
char *proxyentry = NULL;
proxy_host_fix=strdup(tmp_host);
/* search for gateways */
gateway_parameter = (char *)malloc(strlen(tmp_access)+20);
if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
strcpy(gateway_parameter, "WWW_");
strcat(gateway_parameter, tmp_access);
strcat(gateway_parameter, "_GATEWAY");
gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
/* search for proxy servers */
strcpy(gateway_parameter, tmp_access);
strcat(gateway_parameter, "_proxy");
proxy = (char *)getenv(gateway_parameter);
free(gateway_parameter);
/*
* Check the proxies list
*/
if ((proxy == NULL)||(proxy[0] == '\0')) {
int fMatchEnd;
char *scheme_info;
scheme_info =HTParse(HTAnchor_physical(anchor), "", PARSE_HOST);
fMatchEnd = 1; /* match hosts from the end */
if ((scheme_info != NULL) && (*scheme_info == '\0')) {
scheme_info = HTParse(HTAnchor_physical(anchor), "", PARSE_PATH);
fMatchEnd = 0; /* match other scheme_info at beginning*/
}
if (bong) { /* this one is bad - disable! */
proxent =
GetProxy(tmp_access, scheme_info, fMatchEnd);
if (proxent != NULL) proxent->alive = bong;
}
proxent = GetProxy(tmp_access, scheme_info, fMatchEnd);
if (proxent != NULL) {
useKeepAlive = 0; /* proxies don't keepalive */
StrAllocCopy(proxyentry, proxent->transport);
StrAllocCat(proxyentry, "://");
StrAllocCat(proxyentry, proxent->address);
StrAllocCat(proxyentry, ":");
StrAllocCat(proxyentry, proxent->port);
StrAllocCat(proxyentry, "/");
proxy = proxyentry;
}
}
#ifndef DIRECT_WAIS
if (!gateway && 0==strcmp(tmp_access, "wais")) {
gateway = DEFAULT_WAIS_GATEWAY;
}
#endif
/* proxy servers have precedence over gateway servers */
if (proxy) {
char * gatewayed;
gatewayed = NULL;
StrAllocCopy(gatewayed,proxy);
StrAllocCat(gatewayed,addr);
using_proxy = YES;
HTAnchor_setPhysical(anchor, gatewayed);
free(gatewayed);
free(access);
if (proxyentry)
free(proxyentry);
access = HTParse(HTAnchor_physical(anchor),
"http:", PARSE_ACCESS);
} else if (gateway) {
char * gatewayed;
gatewayed = NULL;
StrAllocCopy(gatewayed,gateway);
StrAllocCat(gatewayed,addr);
using_gateway = YES;
HTAnchor_setPhysical(anchor, gatewayed);
free(gatewayed);
free(access);
access = HTParse(HTAnchor_physical(anchor),
"http:", PARSE_ACCESS);
} else {
if (proxy_host_fix) {
free(proxy_host_fix);
}
proxy_host_fix=NULL;
using_proxy = NO;
using_gateway = NO;
ClearTempBongedProxies();
}
}
free(tmp_access);
free(tmp_host);
}
#endif
/* Search registered protocols to find suitable one
*/
{
int i, n;
if (!protocols) HTAccessInit();
n = HTList_count(protocols);
for (i=0; i<n; i++) {
HTProtocol *p = HTList_objectAt(protocols, i);
if (strcmp(p->name, access)==0) {
HTAnchor_setProtocol(anchor, p);
free(access);
return (HT_OK);
}
}
}
free(access);
return HT_NO_ACCESS;
}
/* Load a document
** ---------------
**
** This is an internal routine, which has an address AND a matching
** anchor. (The public routines are called with one OR the other.)
**
** On entry,
** addr must point to the fully qualified hypertext reference.
** anchor a pareent anchor with whose address is addr
**
** On exit,
** returns <0 Error has occured.
** HT_LOADED Success
** HT_NO_DATA Success, but no document loaded.
** (telnet sesssion started etc)
**
*/
PRIVATE int HTLoad ARGS4(
WWW_CONST char *, addr,
HTParentAnchor *, anchor,
HTFormat, format_out,
HTStream *, sink)
{
HTProtocol* p;
int ret, status = get_physical(addr, anchor, 0);
int retry=5;
static char *buf1="Do you want to disable the proxy server:\n\n";
static char *buf2="\n\nAlready attempted 5 contacts.";
char *finbuf,*host;
int fallbacks;
/*
* Yes...I know I'm only calling this to get the "name", but it is better
* than looping through all of the proxy list everytime a proxy fails!
* --SWP
*/
p = HTAnchor_protocol(anchor);
if (!p) {
return(HT_NOT_LOADED);
}
fallbacks=has_fallbacks(p->name);
while (1) {
if (status < 0) return status; /* Can't resolve or forbidden */
retry=5;
retry_proxy:
p = HTAnchor_protocol(anchor);
ret = (*(p->load))(HTAnchor_physical(anchor),
anchor, format_out, sink);
if (ret==HT_INTERRUPTED || HTCheckActiveIcon(0)==HT_INTERRUPTED) {
if (using_proxy) {
ClearTempBongedProxies();
}
return(HT_INTERRUPTED);
}
/*
* HT_REDIRECTING supplied by Dan Riley -- dsr@lns598.lns.cornell.edu
*/
if (!using_proxy || !fallbacks
|| ret == HT_LOADED || ret == HT_REDIRECTING
|| (ret == HT_NO_DATA && strncmp((char *)anchor, "telnet", 6) == 0)) {
if (using_proxy) {
ClearTempBongedProxies();
}
return(ret);
}
if (retry>0) {
retry--;
HTProgress("Retrying proxy server...");
goto retry_proxy;
}
/* must be using proxy and have a problem to get here! */
host=HTParse(HTAnchor_physical(anchor), "", PARSE_HOST);
finbuf=(char *)calloc((strlen(host)+
strlen(buf1)+
strlen(buf2)+
5),
sizeof(char));
sprintf(finbuf,"%s%s?%s",buf1,host,buf2);
if (HTConfirm(finbuf)) {
free(finbuf);
finbuf=(char *)calloc((strlen(host)+
strlen("Disabling proxy server ")+
strlen(" and trying again.")+
5),
sizeof(char));
sprintf(finbuf,"Disabling proxy server %s and trying again.",
host);
HTProgress(finbuf);
application_user_feedback(finbuf);
free(finbuf);
finbuf=NULL;
status = get_physical(addr, anchor, 1); /* Perm disable */
}
else if (HTConfirm("Try next fallback proxy server?")) {
status = get_physical(addr, anchor, 2); /* Temp disable */
}
/* else -- Try the same one again */
if (finbuf) {
free(finbuf);
}
}
}
/* Get a save stream for a document
** --------------------------------
*/
PUBLIC HTStream *HTSaveStream ARGS1(HTParentAnchor *, anchor)
{
HTProtocol * p = HTAnchor_protocol(anchor);
if (!p) return NULL;
return (*p->saveStream)(anchor);
}
/* Load a document - with logging etc
** ----------------------------------
**
** - Checks or documents already loaded
** - Logs the access
** - Allows stdin filter option
** - Trace ouput and error messages
**
** On Entry,
** anchor is the node_anchor for the document
** full_address The address of the document to be accessed.
** filter if YES, treat stdin as HTML
**
** On Exit,
** returns 1 Success in opening document
** 0 Failure
** -1 Interrupted
**
*/
/* This is exported all the way to gui-documents.c at the moment,
to tell mo_load_window_text when to use a redirected URL instead. */
char *use_this_url_instead;
PRIVATE int HTLoadDocument ARGS4(
WWW_CONST char *, full_address,
HTParentAnchor *, anchor,
HTFormat, format_out,
HTStream*, sink)
{
int status;
use_this_url_instead = NULL;
/* We LOVE goto's!
*
* Let's rephrase this..._You_ love goto's...we _abhore_ goto's. People who
* LOVE goto's should be shot.
*/
try_again:
#ifndef DISABLE_TRACE
if (www2Trace) fprintf (stderr,
"HTAccess: loading document %s\n", full_address);
#endif
status = HTLoad(full_address, anchor, format_out, sink);
if (status == HT_LOADED) {
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
full_address);
}
#endif
return 1;
}
if (status == HT_REDIRECTING)
{
/* Exported from HTMIME.c, of all places. */
extern char *redirecting_url;
#ifndef DISABLE_TRACE
if (www2Trace)
{
fprintf (stderr, "HTAccess: '%s' is a redirection URL.\n",
full_address);
fprintf (stderr, "HTAccess: Redirecting to '%s'\n",
redirecting_url);
}
#endif
full_address = redirecting_url;
use_this_url_instead = full_address;
goto try_again;
}
if (status == HT_INTERRUPTED)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
"HTAccess: We were interrupted.\n");
#endif
return -1;
}
if (status == HT_NO_DATA) {
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr,
"HTAccess: `%s' has been accessed, No data left.\n",
full_address);
}
#endif
return 0;
}
if (status<0) { /* Failure in accessing a document */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTAccess: Can't access `%s'\n", full_address);
#endif
return 0;
}
/* If you get this, then please find which routine is returning
a positive unrecognised error code! */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"**** HTAccess: socket or file number %d returned by obsolete load routine!\n", status);
#endif
return 0;
} /* HTLoadDocument */
/* Load a document from absolute name
** ---------------
**
** On Entry,
** addr The absolute address of the document to be accessed.
** filter if YES, treat document as HTML
**
** On Exit,
** returns 1 Success in opening document
** 0 Failure
** -1 Interrupted
**
**
*/
PUBLIC int HTLoadAbsolute ARGS1(WWW_CONST char *,addr)
{
if (currentURL) {
free(currentURL);
}
currentURL=strdup(addr);
return HTLoadDocument( addr,
HTAnchor_parent(HTAnchor_findAddress(addr)),
HTOutputFormat ? HTOutputFormat : WWW_PRESENT,
HTOutputStream);
}
/* Load a document from absolute name to stream
** --------------------------------------------
**
** On Entry,
** addr The absolute address of the document to be accessed.
** sink if non-NULL, send data down this stream
**
** On Exit,
** returns YES Success in opening document
** NO Failure
**
**
*/
PUBLIC BOOL HTLoadToStream ARGS3(
WWW_CONST char *, addr,
BOOL, filter,
HTStream *, sink)
{
return HTLoadDocument(addr,
HTAnchor_parent(HTAnchor_findAddress(addr)),
HTOutputFormat ? HTOutputFormat : WWW_PRESENT,
sink);
}
/* Load a document from relative name
** ---------------
**
** On Entry,
** relative_name The relative address of the document
** to be accessed.
**
** On Exit,
** returns YES Success in opening document
** NO Failure
**
**
*/
PUBLIC BOOL HTLoadRelative ARGS2(
WWW_CONST char *, relative_name,
HTParentAnchor *, here)
{
char * full_address = 0;
BOOL result;
char * mycopy = 0;
char * stripped = 0;
char * current_address =
HTAnchor_address((HTAnchor*)here);
StrAllocCopy(mycopy, relative_name);
stripped = HTStrip(mycopy);
full_address = HTParse(stripped,
current_address,
PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
result = HTLoadAbsolute(full_address);
free(full_address);
free(current_address);
free(mycopy);
return result;
}

164
libwww2/HTAccess.h Normal file
View File

@@ -0,0 +1,164 @@
/* HTAccess: Access manager for libwww
ACCESS MANAGER
This module keeps a list of valid protocol (naming scheme)
specifiers with associated access code. It allows documents to be
loaded given various combinations of parameters. New access
protocols may be registered at any time.
Part of the libwww library .
*/
#ifndef HTACCESS_H
#define HTACCESS_H
/* Definition uses:
*/
#include "HTUtils.h"
#include "tcp.h"
#include "HTAnchor.h"
#include "HTFormat.h"
#ifdef SHORT_NAMES
#define HTClientHost HTClHost
#define HTOutputStream HTOuStre
#define HTOutputFormat HTOuForm
#endif
/* Return codes from load routines:
**
** These codes may be returned by the protocol modules,
** and by the HTLoad routines.
** In general, positive codes are OK and negative ones are bad.
*/
#define HT_NO_DATA -9999 /* return code: OK but no data was loaded */
/* Typically, other app started or forked */
/*
Flags which may be set to control this module
*/
extern int HTDiag; /* Flag: load source as plain text */
extern char * HTClientHost; /* Name or number of telnetting host */
extern FILE * logfile; /* File to output one-liners to */
extern HTStream* HTOutputStream; /* For non-interactive, set this */
extern HTFormat HTOutputFormat; /* To convert on load, set this */
/*
Load a document from relative name
ON ENTRY,
relative_name The relative address of the file to be accessed.
here The anchor of the object being searched
ON EXIT,
returns YES Success in opening file
NO Failure
*/
extern BOOL HTLoadRelative PARAMS((
WWW_CONST char * relative_name,
HTParentAnchor * here));
/*
Load a document from absolute name
ON ENTRY,
addr The absolute address of the document to be accessed.
filter if YES, treat document as HTML
*/
/*
ON EXIT,
*/
/*
returns YES Success in opening document
NO Failure
*/
extern int HTLoadAbsolute PARAMS((WWW_CONST char * addr));
/*
Load a document from absolute name to a stream
ON ENTRY,
addr The absolute address of the document to be accessed.
filter if YES, treat document as HTML
ON EXIT,
returns YES Success in opening document
NO Failure
Note: This is equivalent to HTLoadDocument
*/
extern BOOL HTLoadToStream PARAMS((WWW_CONST char * addr, BOOL filter,
HTStream * sink));
/*
Make a stream for Saving object back
ON ENTRY,
anchor is valid anchor which has previously beeing loaded
ON EXIT,
returns 0 if error else a stream to save the object to.
*/
extern HTStream * HTSaveStream PARAMS((HTParentAnchor * anchor));
/*
Register an access method
*/
typedef struct _HTProtocol {
char * name;
int (*load)PARAMS((
WWW_CONST char * full_address,
HTParentAnchor * anchor,
HTFormat format_out,
HTStream* sink));
HTStream* (*saveStream)PARAMS((HTParentAnchor * anchor));
} HTProtocol;
extern BOOL HTRegisterProtocol PARAMS((HTProtocol * protocol));
#endif /* HTACCESS_H */

87
libwww2/HTAlert.c Normal file
View File

@@ -0,0 +1,87 @@
/* Displaying messages and getting input for LineMode Browser
** ==========================================================
**
** REPLACE THIS MODULE with a GUI version in a GUI environment!
**
** History:
** Jun 92 Created May 1992 By C.T. Barker
** Feb 93 Simplified, portablised (ha!) TBL
**
*/
#include "../config.h"
#include "HTAlert.h"
#include "tcp.h" /* for TOUPPER */
#include <ctype.h> /* for toupper - should be in tcp.h */
extern void mo_gui_notify_progress (char *);
extern int mo_gui_check_icon (int);
extern void mo_gui_clear_icon (void);
extern void mo_gui_update_meter(int,char *);
PUBLIC void HTAlert ARGS1(WWW_CONST char *, Msg)
{
mo_gui_notify_progress (Msg);
return;
}
PUBLIC void HTProgress ARGS1(WWW_CONST char *, Msg)
{
mo_gui_notify_progress (Msg);
return;
}
PUBLIC void HTMeter ARGS2(WWW_CONST int, level, WWW_CONST char *, text)
{
mo_gui_update_meter(level,text);
return;
}
PUBLIC int HTCheckActiveIcon ARGS1(int, twirl)
{
int ret;
ret = mo_gui_check_icon (twirl);
return(ret);
}
PUBLIC void HTClearActiveIcon NOARGS
{
mo_gui_clear_icon ();
return;
}
PUBLIC void HTDoneWithIcon NOARGS
{
mo_gui_done_with_icon ();
return;
}
PUBLIC BOOL HTConfirm ARGS1(WWW_CONST char *, Msg)
{
extern int prompt_for_yes_or_no (char *);
if (prompt_for_yes_or_no (Msg))
return(YES);
else
return(NO);
}
PUBLIC char * HTPrompt ARGS2(WWW_CONST char *, Msg, WWW_CONST char *, deflt)
{
extern char *prompt_for_string (char *);
char *Tmp = prompt_for_string (Msg);
char *rep = 0;
StrAllocCopy (rep, (Tmp && *Tmp) ? Tmp : deflt);
return rep;
}
PUBLIC char * HTPromptPassword ARGS1(WWW_CONST char *, Msg)
{
extern char *prompt_for_password (char *);
char *Tmp = prompt_for_password (Msg);
return Tmp;
}

55
libwww2/HTAlert.h Normal file
View File

@@ -0,0 +1,55 @@
/* */
/* Displaying messages and getting input for WWW Library
** =====================================================
**
** May 92 Created By C.T. Barker
** Feb 93 Portablized etc TBL
*/
#include "HTUtils.h"
#include "tcp.h"
/* Display a message and get the input
**
** On entry,
** Msg is the message.
**
** On exit,
** Return value is malloc'd string which must be freed.
*/
extern char * HTPrompt PARAMS((WWW_CONST char * Msg, WWW_CONST char * deflt));
extern char * HTPromptPassword PARAMS((WWW_CONST char * Msg));
/* Display a message, don't wait for input
**
** On entry,
** The input is a list of parameters for printf.
*/
extern void HTAlert PARAMS((WWW_CONST char * Msg));
/* Display a progress message for information (and diagnostics) only
**
** On entry,
** The input is a list of parameters for printf.
*/
extern void HTProgress PARAMS((WWW_CONST char * Msg));
extern int HTCheckActiveIcon PARAMS((int twirl));
extern void HTClearActiveIcon NOPARAMS;
/* Display a message, then wait for 'yes' or 'no'.
**
** On entry,
** Takes a list of parameters for printf.
**
** On exit,
** If the user enters 'YES', returns TRUE, returns FALSE
** otherwise.
*/
extern BOOL HTConfirm PARAMS ((WWW_CONST char * Msg));
/*
*/

547
libwww2/HTAnchor.c Normal file
View File

@@ -0,0 +1,547 @@
/* Hypertext "Anchor" Object HTAnchor.c
** ==========================
**
** An anchor represents a region of a hypertext document which is linked to
** another anchor in the same or a different document.
**
** History
**
** Nov 1990 Written in Objective-C for the NeXT browser (TBL)
** 24-Oct-1991 (JFG), written in C, browser-independant
** 21-Nov-1991 (JFG), first complete version
**
** (c) Copyright CERN 1991 - See Copyright.html
*/
#include "../config.h"
#define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */
#include <ctype.h>
#include "tcp.h"
#include "HTAnchor.h"
#include "HTUtils.h"
#include "HTParse.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
typedef struct _HyperDoc Hyperdoc;
PRIVATE HTList **adult_table=0; /* Point to table of lists of all parents */
/* Creation Methods
** ================
**
** Do not use "new" by itself outside this module. In order to enforce
** consistency, we insist that you furnish more information about the
** anchor you are creating : use newWithParent or newWithAddress.
*/
PRIVATE HTParentAnchor * HTParentAnchor_new
NOARGS
{
HTParentAnchor *newAnchor =
(HTParentAnchor *) calloc (1, sizeof (HTParentAnchor)); /* zero-filled */
newAnchor->parent = newAnchor;
return newAnchor;
}
PRIVATE HTChildAnchor * HTChildAnchor_new
NOARGS
{
return (HTChildAnchor *) calloc (1, sizeof (HTChildAnchor)); /* zero-filled */
}
/* Case insensitive string comparison
** ----------------------------------
** On entry,
** s Points to one string, null terminated
** t points to the other.
** On exit,
** returns YES if the strings are equivalent ignoring case
** NO if they differ in more than their case.
*/
PRIVATE BOOL equivalent
ARGS2 (WWW_CONST char *,s, WWW_CONST char *,t)
{
if (s && t) { /* Make sure they point to something */
for ( ; *s && *t ; s++, t++) {
if (TOUPPER(*s) != TOUPPER(*t))
return NO;
}
return TOUPPER(*s) == TOUPPER(*t);
} else
return s == t; /* Two NULLs are equivalent, aren't they ? */
}
/* Create new or find old sub-anchor
** ---------------------------------
**
** Me one is for a new anchor being edited into an existing
** document. The parent anchor must already exist.
*/
PUBLIC HTChildAnchor * HTAnchor_findChild
ARGS2 (HTParentAnchor *,parent, WWW_CONST char *,tag)
{
HTChildAnchor *child;
HTList *kids;
if (! parent) {
#ifndef DISABLE_TRACE
if (www2Trace) printf ("HTAnchor_findChild called with NULL parent.\n");
#endif
return NULL;
}
if (kids = parent->children) { /* parent has children : search them */
if (tag && *tag) { /* TBL */
while (child = HTList_nextObject (kids)) {
if (equivalent(child->tag, tag)) { /* Case sensitive 920226 */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf (stderr,
"Child anchor %p of parent %p with name `%s' already exists.\n",
(void*)child, (void*)parent, tag);
#endif
return child;
}
}
} /* end if tag is void */
} else /* parent doesn't have any children yet : create family */
parent->children = HTList_new ();
child = HTChildAnchor_new ();
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "new Anchor %p named `%s' is child of %p\n",
(void*)child, (int)tag ? tag : (WWW_CONST char *)"" , (void*)parent); /* int for apollo */
#endif
HTList_addObject (parent->children, child);
child->parent = parent;
StrAllocCopy(child->tag, tag);
return child;
}
/* Create or find a child anchor with a possible link
** --------------------------------------------------
**
** Create new anchor with a given parent and possibly
** a name, and possibly a link to a _relatively_ named anchor.
** (Code originally in ParseHTML.h)
*/
PUBLIC HTChildAnchor * HTAnchor_findChildAndLink
ARGS4(
HTParentAnchor *,parent, /* May not be 0 */
WWW_CONST char *,tag, /* May be "" or 0 */
WWW_CONST char *,href, /* May be "" or 0 */
HTLinkType *,ltype /* May be 0 */
)
{
HTChildAnchor * child = HTAnchor_findChild(parent, tag);
if (href && *href) {
char * relative_to = HTAnchor_address((HTAnchor *) parent);
char * parsed_address = HTParse(href, relative_to, PARSE_ALL);
HTAnchor * dest = HTAnchor_findAddress(parsed_address);
HTAnchor_link((HTAnchor *) child, dest, ltype);
free(parsed_address);
free(relative_to);
}
return child;
}
/* Create new or find old named anchor
** -----------------------------------
**
** Me one is for a reference which is found in a document, and might
** not be already loaded.
** Note: You are not guaranteed a new anchor -- you might get an old one,
** like with fonts.
*/
HTAnchor * HTAnchor_findAddress
ARGS1 (WWW_CONST char *,address)
{
char *tag = HTParse (address, "", PARSE_ANCHOR); /* Anchor tag specified ? */
/* If the address represents a sub-anchor, we recursively load its parent,
then we create a child anchor within that document. */
if (tag && *tag)
{
char *docAddress = HTParse(address, "", PARSE_ACCESS | PARSE_HOST |
PARSE_PATH | PARSE_PUNCTUATION);
HTParentAnchor * foundParent =
(HTParentAnchor *) HTAnchor_findAddress (docAddress);
HTChildAnchor * foundAnchor = HTAnchor_findChild (foundParent, tag);
free (docAddress);
free (tag);
return (HTAnchor *) foundAnchor;
}
else { /* If the address has no anchor tag,
check whether we have this node */
int hash;
WWW_CONST char *p;
HTList * adults;
HTList *grownups;
HTParentAnchor * foundAnchor;
free (tag);
/* Select list from hash table */
for(p=address, hash=0; *p; p++)
hash = (hash * 3 + (*(unsigned char*)p))
% HASH_SIZE;
if (!adult_table)
adult_table = (HTList**) calloc(HASH_SIZE, sizeof(HTList*));
if (!adult_table[hash]) adult_table[hash] = HTList_new();
adults = adult_table[hash];
/* Search list for anchor */
grownups = adults;
while (foundAnchor = HTList_nextObject (grownups)) {
if (equivalent(foundAnchor->address, address)) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "Anchor %p with address `%s' already exists.\n",
(void*) foundAnchor, address);
#endif
return (HTAnchor *) foundAnchor;
}
}
/* Node not found : create new anchor */
foundAnchor = HTParentAnchor_new ();
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "New anchor %p has hash %d and address `%s'\n",
(void*)foundAnchor, hash, address);
#endif
StrAllocCopy(foundAnchor->address, address);
HTList_addObject (adults, foundAnchor);
return (HTAnchor *) foundAnchor;
}
}
/* Delete an anchor and possibly related things (auto garbage collection)
** --------------------------------------------
**
** The anchor is only deleted if the corresponding document is not loaded.
** All outgoing links from parent and children are deleted, and this anchor
** is removed from the sources list of all its targets.
** We also try to delete the targets whose documents are not loaded.
** If this anchor's source list is empty, we delete it and its children.
*/
PRIVATE void deleteLinks
ARGS1 (HTAnchor *,me)
{
if (! me)
return;
/* Recursively try to delete target anchors */
if (me->mainLink.dest) {
HTParentAnchor *parent = me->mainLink.dest->parent;
HTList_removeObject (parent->sources, me);
if (! parent->document) /* Test here to avoid calling overhead */
HTAnchor_delete (parent);
}
if (me->links) { /* Extra destinations */
HTLink *target;
while (target = HTList_removeLastObject (me->links)) {
HTParentAnchor *parent = target->dest->parent;
HTList_removeObject (parent->sources, me);
if (! parent->document) /* Test here to avoid calling overhead */
HTAnchor_delete (parent);
}
}
}
PUBLIC BOOL HTAnchor_delete
ARGS1 (HTParentAnchor *,me)
{
HTChildAnchor *child;
/* Don't delete if document is loaded */
if (me->document)
return NO;
/* Recursively try to delete target anchors */
deleteLinks ((HTAnchor *) me);
if (! HTList_isEmpty (me->sources)) { /* There are still incoming links */
/* Delete all outgoing links from children, if any */
HTList *kids = me->children;
while (child = HTList_nextObject (kids))
deleteLinks ((HTAnchor *) child);
return NO; /* Parent not deleted */
}
/* No more incoming links : kill everything */
/* First, recursively delete children */
while (child = HTList_removeLastObject (me->children)) {
deleteLinks ((HTAnchor *) child);
free (child->tag);
free (child);
}
/* Now kill myself */
HTList_delete (me->children);
HTList_delete (me->sources);
free (me->address);
/* Devise a way to clean out the HTFormat if no longer needed (ref count?) */
free (me);
return YES; /* Parent deleted */
}
/* Move an anchor to the head of the list of its siblings
** ------------------------------------------------------
**
** This is to ensure that an anchor which might have already existed
** is put in the correct order as we load the document.
*/
void HTAnchor_makeLastChild
ARGS1(HTChildAnchor *,me)
{
if (me->parent != (HTParentAnchor *) me) { /* Make sure it's a child */
HTList * siblings = me->parent->children;
HTList_removeObject (siblings, me);
HTList_addObject (siblings, me);
}
}
/* Data access functions
** ---------------------
*/
PUBLIC HTParentAnchor * HTAnchor_parent
ARGS1 (HTAnchor *,me)
{
return me ? me->parent : NULL;
}
void HTAnchor_setDocument
ARGS2 (HTParentAnchor *,me, HyperDoc *,doc)
{
if (me)
me->document = doc;
}
HyperDoc * HTAnchor_document
ARGS1 (HTParentAnchor *,me)
{
return me ? me->document : NULL;
}
/* We don't want code to change an address after anchor creation... yet ?
void HTAnchor_setAddress
ARGS2 (HTAnchor *,me, char *,addr)
{
if (me)
StrAllocCopy (me->parent->address, addr);
}
*/
char * HTAnchor_address
ARGS1 (HTAnchor *,me)
{
char *addr = NULL;
if (me) {
if (((HTParentAnchor *) me == me->parent) ||
!((HTChildAnchor *) me)->tag) { /* it's an adult or no tag */
StrAllocCopy (addr, me->parent->address);
}
else { /* it's a named child */
addr = malloc (2 + strlen (me->parent->address)
+ strlen (((HTChildAnchor *) me)->tag));
if (addr == NULL) outofmem(__FILE__, "HTAnchor_address");
sprintf (addr, "%s#%s", me->parent->address,
((HTChildAnchor *) me)->tag);
}
}
return addr;
}
void HTAnchor_setFormat
ARGS2 (HTParentAnchor *,me, HTFormat ,form)
{
if (me)
me->format = form;
}
HTFormat HTAnchor_format
ARGS1 (HTParentAnchor *,me)
{
return me ? me->format : NULL;
}
void HTAnchor_setIndex
ARGS1 (HTParentAnchor *,me)
{
if (me)
me->isIndex = YES;
}
BOOL HTAnchor_isIndex
ARGS1 (HTParentAnchor *,me)
{
return me ? me->isIndex : NO;
}
BOOL HTAnchor_hasChildren
ARGS1 (HTParentAnchor *,me)
{
return me ? ! HTList_isEmpty(me->children) : NO;
}
/* Title handling
*/
WWW_CONST char * HTAnchor_title
ARGS1 (HTParentAnchor *,me)
{
return me ? me->title : 0;
}
void HTAnchor_setTitle
ARGS2(HTParentAnchor *,me, WWW_CONST char *,title)
{
StrAllocCopy(me->title, title);
}
void HTAnchor_appendTitle
ARGS2(HTParentAnchor *,me, WWW_CONST char *,title)
{
StrAllocCat(me->title, title);
}
/* Link me Anchor to another given one
** -------------------------------------
*/
BOOL HTAnchor_link
ARGS3(HTAnchor *,source, HTAnchor *,destination, HTLinkType *,type)
{
if (! (source && destination))
return NO; /* Can't link to/from non-existing anchor */
#ifndef DISABLE_TRACE
if (www2Trace) printf ("Linking anchor %p to anchor %p\n", source, destination);
#endif
if (! source->mainLink.dest) {
source->mainLink.dest = destination;
source->mainLink.type = type;
} else {
HTLink * newLink = (HTLink *) malloc (sizeof (HTLink));
if (newLink == NULL) outofmem(__FILE__, "HTAnchor_link");
newLink->dest = destination;
newLink->type = type;
if (! source->links)
source->links = HTList_new ();
HTList_addObject (source->links, newLink);
}
if (!destination->parent->sources)
destination->parent->sources = HTList_new ();
HTList_addObject (destination->parent->sources, source);
return YES; /* Success */
}
/* Manipulation of links
** ---------------------
*/
HTAnchor * HTAnchor_followMainLink
ARGS1 (HTAnchor *,me)
{
return me->mainLink.dest;
}
HTAnchor * HTAnchor_followTypedLink
ARGS2 (HTAnchor *,me, HTLinkType *,type)
{
if (me->mainLink.type == type)
return me->mainLink.dest;
if (me->links) {
HTList *links = me->links;
HTLink *link;
while (link = HTList_nextObject (links))
if (link->type == type)
return link->dest;
}
return NULL; /* No link of me type */
}
/* Make main link
*/
BOOL HTAnchor_makeMainLink
ARGS2 (HTAnchor *,me, HTLink *,movingLink)
{
/* Check that everything's OK */
if (! (me && HTList_removeObject (me->links, movingLink)))
return NO; /* link not found or NULL anchor */
else {
/* First push current main link onto top of links list */
HTLink *newLink = (HTLink*) malloc (sizeof (HTLink));
if (newLink == NULL) outofmem(__FILE__, "HTAnchor_makeMainLink");
memcpy (newLink, & me->mainLink, sizeof (HTLink));
HTList_addObject (me->links, newLink);
/* Now make movingLink the new main link, and free it */
memcpy (& me->mainLink, movingLink, sizeof (HTLink));
free (movingLink);
return YES;
}
}
/* Methods List
** ------------
*/
PUBLIC HTList * HTAnchor_methods ARGS1(HTParentAnchor *, me)
{
if (!me->methods) {
me->methods = HTList_new();
}
return me->methods;
}
/* Protocol
** --------
*/
PUBLIC void * HTAnchor_protocol ARGS1(HTParentAnchor *, me)
{
return me->protocol;
}
PUBLIC void HTAnchor_setProtocol ARGS2(HTParentAnchor *, me,
void*, protocol)
{
me->protocol = protocol;
}
/* Physical Address
** ----------------
*/
PUBLIC char * HTAnchor_physical ARGS1(HTParentAnchor *, me)
{
return me->physical;
}
PUBLIC void HTAnchor_setPhysical ARGS2(HTParentAnchor *, me,
char *, physical)
{
StrAllocCopy(me->physical, physical);
}

297
libwww2/HTAnchor.h Normal file
View File

@@ -0,0 +1,297 @@
/* Hypertext "Anchor" Object HTAnchor.h
** ==========================
**
** An anchor represents a region of a hypertext document which is linked
** to another anchor in the same or a different document.
*/
#ifndef HTANCHOR_H
#define HTANCHOR_H
/* Version 0 (TBL) written in Objective-C for the NeXT browser */
/* Version 1 of 24-Oct-1991 (JFG), written in C, browser-independant */
#include "HTList.h"
#include "HTAtom.h"
#ifdef SHORT_NAMES
#define HTAnchor_findChild HTAnFiCh
#define HTAnchor_findChildAndLink HTAnFiLi
#define HTAnchor_findAddress HTAnFiAd
#define HTAnchor_delete HTAnDele
#define HTAnchor_makeLastChild HTAnMaLa
#define HTAnchor_parent HTAnPare
#define HTAnchor_setDocument HTAnSeDo
#define HTAnchor_document HTAnDocu
#define HTAnchor_setFormat HTAnSeFo
#define HTAnchor_format HTAnForm
#define HTAnchor_setIndex HTAnSeIn
#define HTAnchor_isIndex HTAnIsIn
#define HTAnchor_address HTAnAddr
#define HTAnchor_hasChildren HTAnHaCh
#define HTAnchor_title HTAnTitl
#define HTAnchor_setTitle HTAnSeTi
#define HTAnchor_appendTitle HTAnApTi
#define HTAnchor_link HTAnLink
#define HTAnchor_followMainLink HTAnFoMa
#define HTAnchor_followTypedLink HTAnFoTy
#define HTAnchor_makeMainLink HTAnMaMa
#define HTAnchor_setProtocol HTAnSePr
#define HTAnchor_protocol HTAnProt
#define HTAnchor_physical HTAnPhys
#define HTAnchor_setPhysical HTAnSePh
#define HTAnchor_methods HtAnMeth
#endif
/* Main definition of anchor
** =========================
*/
typedef struct _HyperDoc HyperDoc; /* Ready for forward references */
typedef struct _HTAnchor HTAnchor;
typedef struct _HTParentAnchor HTParentAnchor;
/* After definition of HTFormat: */
#include "HTFormat.h"
typedef HTAtom HTLinkType;
typedef struct {
HTAnchor * dest; /* The anchor to which this leads */
HTLinkType * type; /* Semantics of this link */
} HTLink;
struct _HTAnchor { /* Generic anchor : just links */
HTLink mainLink; /* Main (or default) destination of this */
HTList * links; /* List of extra links from this, if any */
/* We separate the first link from the others to avoid too many small mallocs
involved by a list creation. Most anchors only point to one place. */
HTParentAnchor * parent; /* Parent of this anchor (self for adults) */
};
struct _HTParentAnchor {
/* Common part from the generic anchor structure */
HTLink mainLink; /* Main (or default) destination of this */
HTList * links; /* List of extra links from this, if any */
HTParentAnchor * parent; /* Parent of this anchor (self) */
/* ParentAnchor-specific information */
HTList * children; /* Subanchors of this, if any */
HTList * sources; /* List of anchors pointing to this, if any */
HyperDoc * document; /* The document within which this is an anchor */
char * address; /* Absolute address of this node */
HTFormat format; /* Pointer to node format descriptor */
BOOL isIndex; /* Acceptance of a keyword search */
char * title; /* Title of document */
HTList* methods; /* Methods available as HTAtoms */
void * protocol; /* Protocol object */
char * physical; /* Physical address */
};
typedef struct {
/* Common part from the generic anchor structure */
HTLink mainLink; /* Main (or default) destination of this */
HTList * links; /* List of extra links from this, if any */
HTParentAnchor * parent; /* Parent of this anchor */
/* ChildAnchor-specific information */
char * tag; /* Address of this anchor relative to parent */
} HTChildAnchor;
/* Create new or find old sub-anchor
** ---------------------------------
**
** This one is for a new anchor being edited into an existing
** document. The parent anchor must already exist.
*/
extern HTChildAnchor * HTAnchor_findChild
PARAMS(
(HTParentAnchor *parent,
WWW_CONST char *tag)
);
/* Create or find a child anchor with a possible link
** --------------------------------------------------
**
** Create new anchor with a given parent and possibly
** a name, and possibly a link to a _relatively_ named anchor.
** (Code originally in ParseHTML.h)
*/
extern HTChildAnchor * HTAnchor_findChildAndLink
PARAMS((
HTParentAnchor * parent, /* May not be 0 */
WWW_CONST char * tag, /* May be "" or 0 */
WWW_CONST char * href, /* May be "" or 0 */
HTLinkType * ltype /* May be 0 */
));
/* Create new or find old named anchor
** -----------------------------------
**
** This one is for a reference which is found in a document, and might
** not be already loaded.
** Note: You are not guaranteed a new anchor -- you might get an old one,
** like with fonts.
*/
extern HTAnchor * HTAnchor_findAddress
PARAMS(
(WWW_CONST char * address)
);
/* Delete an anchor and possibly related things (auto garbage collection)
** --------------------------------------------
**
** The anchor is only deleted if the corresponding document is not loaded.
** All outgoing links from parent and children are deleted, and this anchor
** is removed from the sources list of all its targets.
** We also try to delete the targets whose documents are not loaded.
** If this anchor's source list is empty, we delete it and its children.
*/
extern BOOL HTAnchor_delete
PARAMS(
(HTParentAnchor *me)
);
/* Move an anchor to the head of the list of its siblings
** ------------------------------------------------------
**
** This is to ensure that an anchor which might have already existed
** is put in the correct order as we load the document.
*/
extern void HTAnchor_makeLastChild
PARAMS(
(HTChildAnchor *me)
);
/* Data access functions
** ---------------------
*/
extern HTParentAnchor * HTAnchor_parent
PARAMS(
(HTAnchor *me)
);
extern void HTAnchor_setDocument
PARAMS(
(HTParentAnchor *me, HyperDoc *doc)
);
extern HyperDoc * HTAnchor_document
PARAMS(
(HTParentAnchor *me)
);
/* We don't want code to change an address after anchor creation... yet ?
extern void HTAnchor_setAddress
PARAMS(
(HTAnchor *me, char *addr)
);
*/
/* Returns the full URI of the anchor, child or parent
** as a malloc'd string to be freed by the caller.
*/
extern char * HTAnchor_address
PARAMS(
(HTAnchor *me)
);
extern void HTAnchor_setFormat
PARAMS(
(HTParentAnchor *me, HTFormat form)
);
extern HTFormat HTAnchor_format
PARAMS(
(HTParentAnchor *me)
);
extern void HTAnchor_setIndex
PARAMS(
(HTParentAnchor *me)
);
extern BOOL HTAnchor_isIndex
PARAMS(
(HTParentAnchor *me)
);
extern BOOL HTAnchor_hasChildren
PARAMS(
(HTParentAnchor *me)
);
/* Title handling
*/
extern WWW_CONST char * HTAnchor_title
PARAMS(
(HTParentAnchor *me)
);
extern void HTAnchor_setTitle
PARAMS(
(HTParentAnchor *me, WWW_CONST char * title)
);
extern void HTAnchor_appendTitle
PARAMS(
(HTParentAnchor *me, WWW_CONST char * title)
);
/* Link this Anchor to another given one
** -------------------------------------
*/
extern BOOL HTAnchor_link
PARAMS(
(HTAnchor *source, HTAnchor *destination, HTLinkType *type)
);
/* Manipulation of links
** ---------------------
*/
extern HTAnchor * HTAnchor_followMainLink
PARAMS(
(HTAnchor *me)
);
extern HTAnchor * HTAnchor_followTypedLink
PARAMS(
(HTAnchor *me, HTLinkType *type)
);
extern BOOL HTAnchor_makeMainLink
PARAMS(
(HTAnchor *me, HTLink *movingLink)
);
/* Read and write methods
** ----------------------
*/
extern HTList * HTAnchor_methods PARAMS((HTParentAnchor *me));
/* Protocol
** --------
*/
extern void * HTAnchor_protocol PARAMS((HTParentAnchor * me));
extern void HTAnchor_setProtocol PARAMS((HTParentAnchor * me,
void* protocol));
/* Physical address
** ----------------
*/
extern char * HTAnchor_physical PARAMS((HTParentAnchor * me));
extern void HTAnchor_setPhysical PARAMS((HTParentAnchor * me,
char * protocol));
#endif /* HTANCHOR_H */

85
libwww2/HTAssoc.c Normal file
View File

@@ -0,0 +1,85 @@
/* MODULE HTAssoc.c
** ASSOCIATION LIST FOR STORING NAME-VALUE PAIRS.
** NAMES NOT CASE SENSITIVE, AND ONLY COMMON LENGTH
** IS CHECKED (allows abbreviations; well, length is
** taken from lookup-up name, so if table contains
** a shorter abbrev it is not found).
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <string.h>
#include "../libnut/str-tools.h"
#include "HTAAUtil.h"
#include "HTAssoc.h"
#include "HTString.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
PUBLIC HTAssocList *HTAssocList_new NOARGS
{
return HTList_new();
}
PUBLIC void HTAssocList_delete ARGS1(HTAssocList *, alist)
{
if (alist) {
HTAssocList *cur = alist;
HTAssoc *assoc;
while (NULL != (assoc = (HTAssoc*)HTList_nextObject(cur))) {
if (assoc->name) free(assoc->name);
if (assoc->value) free(assoc->value);
free(assoc);
}
HTList_delete(alist);
}
}
PUBLIC void HTAssocList_add ARGS3(HTAssocList *, alist,
WWW_CONST char *, name,
WWW_CONST char *, value)
{
HTAssoc *assoc;
if (alist) {
if (!(assoc = (HTAssoc*)malloc(sizeof(HTAssoc))))
outofmem(__FILE__, "HTAssoc_add");
assoc->name = NULL;
assoc->value = NULL;
if (name) StrAllocCopy(assoc->name, name);
if (value) StrAllocCopy(assoc->value, value);
HTList_addObject(alist, (void*)assoc);
}
#ifndef DISABLE_TRACE
else if (www2Trace) fprintf(stderr, "HTAssoc_add: ERROR: assoc list NULL!!\n");
#endif
}
PUBLIC char *HTAssocList_lookup ARGS2(HTAssocList *, alist,
WWW_CONST char *, name)
{
HTAssocList *cur = alist;
HTAssoc *assoc;
while (NULL != (assoc = (HTAssoc*)HTList_nextObject(cur))) {
if (!my_strncasecmp(assoc->name, name, strlen(name)))
return assoc->value;
}
return NULL;
}

42
libwww2/HTAssoc.h Normal file
View File

@@ -0,0 +1,42 @@
/* ASSOCIATION LIST FOR STORING NAME-VALUE PAIRS
Lookups from assosiation list are not case-sensitive.
*/
#ifndef HTASSOC_H
#define HTASSOC_H
#include "HTUtils.h"
#include "HTList.h"
#ifdef SHORT_NAMES
#define HTAL_new HTAssocList_new
#define HTAL_del HTAssocList_delete
#define HTAL_add HTAssocList_add
#define HTAL_lup HTAssocList_lookup
#endif /*SHORT_NAMES*/
typedef HTList HTAssocList;
typedef struct {
char * name;
char * value;
} HTAssoc;
PUBLIC HTAssocList *HTAssocList_new NOPARAMS;
PUBLIC void HTAssocList_delete PARAMS((HTAssocList * alist));
PUBLIC void HTAssocList_add PARAMS((HTAssocList * alist,
WWW_CONST char * name,
WWW_CONST char * value));
PUBLIC char *HTAssocList_lookup PARAMS((HTAssocList * alist,
WWW_CONST char * name));
#endif /* not HTASSOC_H */
/*
End of file HTAssoc.h. */

118
libwww2/HTAtom.c Normal file
View File

@@ -0,0 +1,118 @@
/* Atoms: Names to numbers HTAtom.c
** =======================
**
** Atoms are names which are given representative pointer values
** so that they can be stored more efficiently, and comparisons
** for equality done more efficiently.
**
** Atoms are kept in a hash table consisting of an array of linked lists.
**
** Authors:
** TBL Tim Berners-Lee, WorldWideWeb project, CERN
** (c) Copyright CERN 1991 - See Copyright.html
**
*/
#include "../config.h"
#define HASH_SIZE 101 /* Tunable */
#include "HTAtom.h"
#include <stdio.h> /* joe@athena, TBL 921019 */
#include "HTUtils.h"
#include "tcp.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
PRIVATE HTAtom * hash_table[HASH_SIZE];
PRIVATE BOOL initialised = NO;
#ifdef __STDC__
PUBLIC HTAtom * HTAtom_for(char * string)
#else
PUBLIC HTAtom * HTAtom_for(string)
char * string;
#endif
{
int hash;
WWW_CONST char * p;
HTAtom * a;
/* Bug hack. */
if (!string || !*string)
string = strdup ("blargh");
/* First time around, clear hash table
*/
if (!initialised) {
int i;
for (i=0; i<HASH_SIZE; i++)
hash_table[i] = (HTAtom *) 0;
initialised = YES;
}
/* Generate hash function
*/
for(p=string, hash=0; *p; p++) {
hash = (hash * 3 + *p) % HASH_SIZE;
}
/* Search for the string in the list
*/
for (a=hash_table[hash]; a; a=a->next) {
if (0==strcmp(a->name, string)) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTAtom: Old atom %p for `%s'\n", a, string);
#endif
return a; /* Found: return it */
}
}
/* Generate a new entry
*/
a = (HTAtom *)malloc(sizeof(*a));
if (a == NULL) outofmem(__FILE__, "HTAtom_for");
a->name = (char *)malloc(strlen(string)+1);
if (a->name == NULL) outofmem(__FILE__, "HTAtom_for");
strcpy(a->name, string);
a->next = hash_table[hash]; /* Put onto the head of list */
hash_table[hash] = a;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTAtom: New atom %p for `%s'\n", a, string);
#endif
return a;
}
#ifdef __STDC__
PUBLIC HTAtom * HTAtom_exists(char * string)
#else
PUBLIC HTAtom * HTAtom_exists(string)
char * string;
#endif
{
int hash;
WWW_CONST char * p;
HTAtom * a;
if (!initialised) {
return NULL;
}
/* Generate hash function
*/
for(p=string, hash=0; *p; p++) {
hash = (hash * 3 + *p) % HASH_SIZE;
}
/* Search for the string in the list
*/
for (a=hash_table[hash]; a; a=a->next) {
if (0==strcmp(a->name, string)) {
return a; /* Found: return it */
}
}
return NULL;
}

48
libwww2/HTAtom.h Normal file
View File

@@ -0,0 +1,48 @@
/* */
/* Atoms: Names to numbers HTAtom.h
** =======================
**
** Atoms are names which are given representative pointer values
** so that they can be stored more efficiently, and compaisons
** for equality done more efficiently.
**
** HTAtom_for(string) returns a representative value such that it
** will always (within one run of the program) return the same
** value for the same given string.
**
** Authors:
** TBL Tim Berners-Lee, WorldWideWeb project, CERN
**
** (c) Copyright CERN 1991 - See Copyright.html
**
*/
#ifndef HTATOM_H
#define HTATOM_H
typedef struct _HTAtom HTAtom;
struct _HTAtom {
HTAtom * next;
char * name;
}; /* struct _HTAtom */
#ifdef __STDC__
extern HTAtom * HTAtom_for(char * string);
#else
extern HTAtom * HTAtom_for();
#endif
#ifdef __STDC__
extern HTAtom * HTAtom_exists(char * string);
#else
extern HTAtom * HTAtom_exists();
#endif
#define HTAtom_name(a) ((a)->name)
#endif /* HTATOM_H */
/*
*/

230
libwww2/HTAuth.c Normal file
View File

@@ -0,0 +1,230 @@
/* MODULE HTAuth.c
** USER AUTHENTICATION
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <string.h>
#include "HTUtils.h"
#include "HTPasswd.h" /* Password file routines */
#include "HTAssoc.h"
#include "HTAuth.h" /* Implemented here */
#include "HTUU.h" /* Uuencoding and uudecoding */
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* PRIVATE decompose_auth_string()
** DECOMPOSE AUTHENTICATION STRING
** FOR BASIC OR PUBKEY SCHEME
** ON ENTRY:
** authstring is the authorization string received
** from browser.
**
** ON EXIT:
** returns a node representing the user information
** (as always, this is automatically freed
** by AA package).
*/
PRIVATE HTAAUser *decompose_auth_string ARGS2(char *, authstring,
HTAAScheme, scheme)
{
static HTAAUser *user = NULL;
static char *cleartext = NULL;
char *username = NULL;
char *password = NULL;
char *inet_addr = NULL;
char *timestamp = NULL;
char *browsers_key = NULL;
char *extras = NULL;
if (!user && !(user = (HTAAUser*)malloc(sizeof(HTAAUser)))) /* Allocated */
outofmem(__FILE__, "decompose_auth_string"); /* only once */
user->scheme = scheme;
user->username = NULL; /* Not freed, because freeing */
user->password = NULL; /* cleartext also frees these */
user->inet_addr = NULL; /* See below: || */
user->timestamp = NULL; /* || */
user->secret_key = NULL; /* || */
/* \/ */
FREE(cleartext); /* From previous call. */
/* NOTE: parts of this memory are pointed to by */
/* pointers in HTAAUser structure. Therefore, */
/* this also frees all the strings pointed to */
/* by the static 'user'. */
if (!authstring || !*authstring ||
scheme != HTAA_BASIC || scheme == HTAA_PUBKEY)
return NULL;
if (scheme == HTAA_PUBKEY) { /* Decrypt authentication string */
int bytes_decoded;
char *ciphertext;
int len = strlen(authstring) + 1;
if (!(ciphertext = (char*)malloc(len)) ||
!(cleartext = (char*)malloc(len)))
outofmem(__FILE__, "decompose_auth_string");
bytes_decoded = HTUU_decode(authstring, ciphertext, len);
ciphertext[bytes_decoded] = (char)0;
#ifdef PUBKEY
HTPK_decrypt(ciphertext, cleartext, private_key);
#endif
free(ciphertext);
}
else { /* Just uudecode */
int bytes_decoded;
int len = strlen(authstring) + 1;
if (!(cleartext = (char*)malloc(len)))
outofmem(__FILE__, "decompose_auth_string");
bytes_decoded = HTUU_decode(authstring, cleartext, len);
cleartext[bytes_decoded] = (char)0;
}
/*
** Extract username and password (for both schemes)
*/
username = cleartext;
if (!(password = strchr(cleartext, ':'))) {
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "%s %s\n",
"decompose_auth_string: password field",
"missing in authentication string.\n");
#endif
return NULL;
}
*(password++) = '\0';
/*
** Extract rest of the fields
*/
if (scheme == HTAA_PUBKEY) {
if ( !(inet_addr =strchr(password, ':')) ||
(*(inet_addr++) ='\0'), !(timestamp =strchr(inet_addr,':')) ||
(*(timestamp++) ='\0'), !(browsers_key=strchr(timestamp,':')) ||
(*(browsers_key++)='\0')) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s %s\n",
"decompose_auth_string: Pubkey scheme",
"fields missing in authentication string");
#endif
return NULL;
}
extras = strchr(browsers_key, ':');
}
else extras = strchr(password, ':');
if (extras) {
*(extras++) = '\0';
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s `%s' %s `%s'\n",
"decompose_auth_string: extra field(s) in",
(scheme==HTAA_BASIC ? "Basic" : "Pubkey"),
"authorization string ignored:", extras);
#endif
}
/*
** Set the fields into the result
*/
user->username = username;
user->password = password;
user->inet_addr = inet_addr;
user->timestamp = timestamp;
user->secret_key = browsers_key;
#ifndef DISABLE_TRACE
if (www2Trace) {
if (scheme==HTAA_BASIC)
fprintf(stderr, "decompose_auth_string: %s (%s,%s)\n",
"Basic scheme authentication string:",
username, password);
else
fprintf(stderr, "decompose_auth_string: %s (%s,%s,%s,%s,%s)\n",
"Pubkey scheme authentication string:",
username, password, inet_addr, timestamp, browsers_key);
}
#endif
return user;
}
PRIVATE BOOL HTAA_checkTimeStamp ARGS1(WWW_CONST char *, timestamp)
{
return NO; /* This is just a stub */
}
PRIVATE BOOL HTAA_checkInetAddress ARGS1(WWW_CONST char *, inet_addr)
{
return NO; /* This is just a stub */
}
/* SERVER PUBLIC HTAA_authenticate()
** AUTHENTICATE USER
** ON ENTRY:
** scheme used authentication scheme.
** scheme_specifics the scheme specific parameters
** (authentication string for Basic and
** Pubkey schemes).
** prot is the protection information structure
** for the file.
**
** ON EXIT:
** returns NULL, if authentication failed.
** Otherwise a pointer to a structure
** representing authenticated user,
** which should not be freed.
*/
PUBLIC HTAAUser *HTAA_authenticate ARGS3(HTAAScheme, scheme,
char *, scheme_specifics,
HTAAProt *, prot)
{
if (HTAA_UNKNOWN == scheme || !prot ||
-1 == HTList_indexOf(prot->valid_schemes, (void*)scheme))
return NULL;
switch (scheme) {
case HTAA_BASIC:
case HTAA_PUBKEY:
{
HTAAUser *user = decompose_auth_string(scheme_specifics, scheme);
/* Remember, user is auto-freed */
if (user &&
HTAA_checkPassword(user->username,
user->password,
HTAssocList_lookup(prot->values, "passw")) &&
(HTAA_BASIC == scheme ||
(HTAA_checkTimeStamp(user->timestamp) &&
HTAA_checkInetAddress(user->inet_addr))))
return user;
else
return NULL;
}
break;
default:
/* Other authentication routines go here */
return NULL;
}
}

64
libwww2/HTAuth.h Normal file
View File

@@ -0,0 +1,64 @@
/* AUTHENTICATION MODULE
This is the authentication module. By modifying the function HTAA_authenticate() it can
be made to support external authentication methods.
*/
#ifndef HTAUTH_H
#define HTAUTH_H
#include "HTUtils.h"
#include "HTAAUtil.h"
#include "HTAAProt.h"
#ifdef SHORT_NAMES
#define HTAAauth HTAA_authenticate
#endif /* SHORT_NAMES */
/*
** Server's representation of a user (fields in authentication string)
*/
typedef struct {
HTAAScheme scheme; /* Scheme used to authenticate this user */
char * username;
char * password;
char * inet_addr;
char * timestamp;
char * secret_key;
} HTAAUser;
/*
User Authentication
*/
/* SERVER PUBLIC HTAA_authenticate()
** AUTHENTICATE USER
** ON ENTRY:
** scheme used authentication scheme.
** scheme_specifics the scheme specific parameters
** (authentication string for Basic and
** Pubkey schemes).
** prot is the protection information structure
** for the file.
**
** ON EXIT:
** returns NULL, if authentication failed.
** Otherwise a pointer to a structure
** representing authenticated user,
** which should not be freed.
*/
PUBLIC HTAAUser *HTAA_authenticate PARAMS((HTAAScheme scheme,
char * scheme_specifics,
HTAAProt * prot));
/*
*/
#endif /* not HTAUTH_H */
/*
End of file HTAuth.h. */

96
libwww2/HTChunk.c Normal file
View File

@@ -0,0 +1,96 @@
/* Chunk handling: Flexible arrays
** ===============================
**
*/
#include "../config.h"
#include "HTUtils.h"
#include "HTChunk.h"
#include <stdio.h>
/* Create a chunk with a certain allocation unit
** --------------
*/
PUBLIC HTChunk * HTChunkCreate ARGS1 (int,grow)
{
HTChunk * ch = (HTChunk *) malloc(sizeof(HTChunk));
if (ch == NULL) outofmem(__FILE__, "cretion of chunk");
ch->data = 0;
ch->growby = grow;
ch->size = 0;
ch->allocated = 0;
return ch;
}
/* Clear a chunk of all data
** --------------------------
*/
PUBLIC void HTChunkClear ARGS1 (HTChunk *,ch)
{
if (ch->data) {
free(ch->data);
ch->data = 0;
}
ch->size = 0;
ch->allocated = 0;
}
/* Free a chunk
** ------------
*/
PUBLIC void HTChunkFree ARGS1 (HTChunk *,ch)
{
if (ch->data) free(ch->data);
free(ch);
}
/* Append a character
** ------------------
*/
PUBLIC void HTChunkPutc ARGS2 (HTChunk *,ch, char,c)
{
if (ch->size >= ch->allocated) {
ch->allocated = ch->allocated + ch->growby;
ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated)
: (char *)malloc(ch->allocated);
if (!ch->data) outofmem(__FILE__, "HTChunkPutc");
}
ch->data[ch->size++] = c;
}
/* Ensure a certain size
** ---------------------
*/
PUBLIC void HTChunkEnsure ARGS2 (HTChunk *,ch, int,needed)
{
if (needed <= ch->allocated) return;
ch->allocated = needed-1 - ((needed-1) % ch->growby)
+ ch->growby; /* Round up */
ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated)
: (char *)malloc(ch->allocated);
if (ch->data == NULL) outofmem(__FILE__, "HTChunkEnsure");
}
/* Terminate a chunk
** -----------------
*/
PUBLIC void HTChunkTerminate ARGS1 (HTChunk *,ch)
{
HTChunkPutc(ch, (char)0);
}
/* Append a string
** ---------------
*/
PUBLIC void HTChunkPuts ARGS2 (HTChunk *,ch, WWW_CONST char *,s)
{
WWW_CONST char * p;
for (p=s; *p; p++)
HTChunkPutc(ch, *p);
}

160
libwww2/HTChunk.h Normal file
View File

@@ -0,0 +1,160 @@
/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTChunk.html
CHUNK HANDLING:
FLEXIBLE ARRAYS
This module implements a flexible array. It is a general utility module. A chunk is a
structure which may be extended. These routines create and append data to chunks,
automatically reallocating them as necessary.
*/
typedef struct {
int size; /* In bytes */
int growby; /* Allocation unit in bytes */
int allocated; /* Current size of *data */
char * data; /* Pointer to malloced area or 0 */
} HTChunk;
#ifdef SHORT_NAMES
#define HTChunkClear HTChClea
#define HTChunkPutc HTChPutc
#define HTChunkPuts HTChPuts
#define HTChunkCreate HTChCrea
#define HTChunkTerminate HTChTerm
#define HTChunkEnsure HtChEnsu
#endif
/*
Create new chunk
ON ENTRY,
growby The number of bytes to allocate at a time when the chunk is
later extended. Arbitrary but normally a trade-off time vs.
memory
ON EXIT,
returns A chunk pointer to the new chunk,
*/
extern HTChunk * HTChunkCreate PARAMS((int growby));
/*
Free a chunk
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
ON EXIT,
ch is invalid and may not be used.
*/
extern void HTChunkFree PARAMS((HTChunk * ch));
/*
Clear a chunk
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
ON EXIT,
*ch The size of the chunk is zero.
*/
extern void HTChunkClear PARAMS((HTChunk * ch));
/*
Ensure a chunk has a certain space in
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
s The size required
ON EXIT,
*ch Has size at least s
*/
extern void HTChunkEnsure PARAMS((HTChunk * ch, int s));
/*
Append a character to a chunk
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
c The character to be appended
ON EXIT,
*ch Is one character bigger
*/
extern void HTChunkPutc PARAMS((HTChunk * ch, char c));
/*
Append a string to a chunk
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
str Tpoints to a zero-terminated string to be appended
ON EXIT,
*ch Is bigger by strlen(str)
*/
extern void HTChunkPuts PARAMS((HTChunk * ch, char *str));
/*
Append a zero character to a chunk
*/
/*
ON ENTRY,
ch A valid chunk pointer made by HTChunkCreate()
ON EXIT,
*ch Is one character bigger
*/
extern void HTChunkTerminate PARAMS((HTChunk * ch));
/*
end */

282
libwww2/HTCompressed.c Normal file
View File

@@ -0,0 +1,282 @@
#include "../config.h"
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "HTFormat.h"
#include "HTFile.h"
#include "HTUtils.h"
#include "tcp.h"
#include "HTML.h"
#include "HTMLDTD.h"
#include "HText.h"
#include "HTAlert.h"
#include "HTList.h"
#include "HTInit.h"
#include "HTFWriter.h"
#include "HTPlain.h"
#include "SGML.h"
#include "HTMLGen.h"
#include "../libnut/system.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
struct _HTStream
{
WWW_CONST HTStreamClass* isa;
/* ... */
};
int is_uncompressed=0;
extern char *mo_tmpnam (char *);
extern void application_user_feedback (char *);
extern char *uncompress_program, *gunzip_program;
extern void HTFileCopyToText (FILE *fp, HText *text);
/* Given a filename of a local compressed file, compress it in place.
We assume that the file does not already have a .Z or .z extension
at this point -- this is a little weird but it's convenient. */
void HTCompressedFileToFile (char *fnam, int compressed)
{
char *znam;
char *cmd;
int len;
cmd=NULL;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr, "[HTCompressedFileToFile] Entered; fnam '%s', compressed %d\n",
fnam, compressed);
#endif
/* Punt if we can't handle it. */
if (compressed != COMPRESSED_BIGZ && compressed != COMPRESSED_GNUZIP)
return;
HTProgress ("Preparing to uncompress data.");
znam = (char *)malloc (sizeof (char) * (strlen (fnam) + 8));
/* Either compressed or gzipped. */
if (compressed == COMPRESSED_BIGZ)
sprintf (znam, "%s.Z", fnam);
else
sprintf (znam, "%s.gz", fnam);
/*SWP -- New "mv" fucntion to take care of these /bin/mv things*/
{
char retBuf[BUFSIZ];
int status;
if ((status=my_move(fnam,znam,retBuf,BUFSIZ,1))!=SYS_SUCCESS) {
sprintf(retBuf,"Unable to uncompress compressed data;\nresults may be in error.\n%s",retBuf);
application_user_info_wait(retBuf);
free (znam);
return;
}
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTCompressedFileToFile] Moved '%s' to '%s'\n",
fnam, znam);
#endif
if (compressed == COMPRESSED_BIGZ)
{
cmd = (char *)malloc(strlen(uncompress_program)+strlen(znam)+8);
sprintf (cmd, "%s %s", uncompress_program, znam);
}
else
{
cmd = (char *)malloc (strlen (gunzip_program) + strlen (znam) + 8);
sprintf (cmd, "%s %s", gunzip_program, znam);
}
HTProgress ("Uncompressing data.");
{
int status,skip_output=0;
char retBuf[BUFSIZ];
char final[BUFSIZ];
*retBuf='\0';
*final='\0';
if ((status=my_system(cmd,retBuf,BUFSIZ))!=SYS_SUCCESS) {
switch(status) {
case SYS_NO_COMMAND:
sprintf(final,"%sThere was no command to execute.\n",final);
break;
case SYS_FORK_FAIL:
sprintf(final,"%sThe fork call failed.\n",final);
break;
case SYS_PROGRAM_FAILED:
sprintf(final,"%sThe program specified was not able to exec.\n",final);
break;
case SYS_NO_RETBUF:
sprintf(final,"%sThere was no return buffer.\n",final);
break;
case SYS_FCNTL_FAILED:
sprintf(final,"%sFcntl failed to set non-block on the pipe.\n",final);
break;
}
/*give them the output*/
if (*retBuf) {
sprintf(final,"%s%s",final,retBuf);
}
}
else if (*retBuf) {
/*give them the output*/
sprintf(final,"%s%s",final,retBuf);
}
else {
/*a-okay*/
skip_output=1;
}
if (!skip_output) {
application_user_info_wait(final);
free (cmd);
free (znam);
HTProgress ("Uncompress failed.");
return;
}
}
HTProgress ("Data uncompressed.");
is_uncompressed=1;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr, "[HTCompressedFileToFile] Uncompressed '%s' with command '%s'\n",
znam, cmd);
#endif
free (cmd);
free (znam);
return;
}
void HTCompressedHText (HText *text, int compressed, int plain)
{
char *fnam;
char *znam;
char *cmd;
FILE *fp;
int rv, size_of_data;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr, "[HTCompressedHText] Entered; compressed %d\n",
compressed);
#endif
/* Punt if we can't handle it. */
if (compressed != COMPRESSED_BIGZ && compressed != COMPRESSED_GNUZIP)
return;
/* Hmmmmmmmmm, I'm not sure why we subtract 1 here, but it is
indeed working... */
size_of_data = HText_getTextLength (text) - 1;
if (size_of_data == 0)
{
fprintf (stderr, "[HTCompressedHText] size_of_data 0; punting\n");
return;
}
fnam = mo_tmpnam ((char *) 0);
fp = fopen (fnam, "w");
if (!fp)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "COULD NOT OPEN TMP FILE '%s'\n", fnam);
#endif
application_user_feedback
("Unable to uncompress compressed data;\nresults may be in error.");
free (fnam);
return;
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTCmopressedHText] Going to write %d bytes.\n",
size_of_data);
#endif
rv = fwrite (HText_getText (text), sizeof (char), size_of_data, fp);
if (rv != size_of_data)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "ONLY WROTE %d bytes\n", rv);
#endif
application_user_feedback
("Unable to write compressed data to local disk;\nresults may be in error.");
}
fclose (fp);
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "HTCompressedHText: Calling CompressedFileToFile\n");
#endif
HTCompressedFileToFile (fnam, compressed);
HText_clearOutForNewContents (text);
HText_beginAppend (text);
if (plain)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTCompressedHText] Throwing in PLAINTEXT token...\n");
#endif
HText_appendText(text, "<PLAINTEXT>\n");
}
fp = fopen (fnam, "r");
if (!fp)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "COULD NOT OPEN TMP FILE FOR READING '%s'\n", fnam);
#endif
/* We already get error dialog up above. */
free (fnam);
return;
}
HTFileCopyToText (fp, text);
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTCompressedHText] I think we're done...\n");
#endif
/*SWP*/
/*
cmd = (char *)malloc (sizeof (char) * (strlen (fnam) + 32));
sprintf (cmd, "/bin/rm -f %s", fnam);
system (cmd);
free (cmd);
*/
unlink(fnam);
return;
}

7
libwww2/HTCompressed.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef HTCOMPRESSED_H
#define HTCOMPRESSED_H
extern void HTCompressedFileToFile (char *fnam, int compressed);
extern void HTCompressedHText (HText *text, int compressed, int plain);
#endif /* not HTCOMPRESSED_H */

2843
libwww2/HTFTP.c Normal file

File diff suppressed because it is too large Load Diff

59
libwww2/HTFTP.h Normal file
View File

@@ -0,0 +1,59 @@
/* FTP access module for libwww
FTP ACCESS FUNCTIONS
This isn't really a valid protocol module -- it is lumped together
with HTFile . That could be changed easily.
Author: Tim Berners-Lee. Public Domain. Please mail changes to
timbl@info.cern.ch
*/
#ifndef HTFTP_H
#define HTFTP_H
#include "HTUtils.h"
#include "HTAnchor.h"
#include "HTStream.h"
#include "HTAlert.h"
/*
Retrieve File from Server
ON EXIT,
returns Socket number for file if good.<0 if bad.
*/
extern int HTFTPLoad PARAMS
((
char * name,
HTParentAnchor * anchor,
HTFormat format_out,
HTStream* sink
));
/*
Return Host Name
*/
extern WWW_CONST char * HTHostName NOPARAMS;
/*
* NLST parameters -- SWP
*/
#define NLST_PARAMS "-Lla"
/* Send file to server */
extern int HTFTPSend PARAMS (( char * name ));
#endif
/*
end */

549
libwww2/HTFWriter.c Normal file
View File

@@ -0,0 +1,549 @@
/* FILE WRITER HTFWrite.h
** ===========
**
** This version of the stream object just writes to a C file.
** The file is assumed open and left open.
**
** Bugs:
** strings written must be less than buffer size.
*/
#include "../config.h"
#include <string.h>
#include "HTFWriter.h"
#include "HTFormat.h"
#include "HTAlert.h"
#include "HTFile.h"
#include "HText.h"
#include "tcp.h"
#include "HTCompressed.h"
extern char *currentURL;
int imageViewInternal=0;
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* Stream Object
** ------------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
FILE * fp;
char * fnam;
char * end_command;
int compressed;
int interrupted;
int write_error;
char *mime_type;
};
/* MOSAIC: We now pick up some external variables, handled
in src/mo-www.c: */
extern int force_dump_to_file;
extern char *force_dump_filename;
/* If force_dump_to_file is high, we know we want to dump the
data into a file already named by force_dump_filename and not
do anything else. */
/* If this is high, then we just want to dump the thing to a file;
the file is named by force_dump_filename. */
extern int binary_transfer;
/*_________________________________________________________________________
**
** A C T I O N R O U T I N E S
*/
/* Character handling
** ------------------
*/
PRIVATE void HTFWriter_put_character ARGS2(HTStream *, me, char, c)
{
int rv;
if (me->write_error)
return;
/* Make sure argument to putc is in range 0-255, to avoid weirdness
with rv == -1 == EOF when it's not supposed to. */
rv = putc ((int)(unsigned char)c, me->fp);
if (rv == EOF)
{
HTProgress ("Error writing to temporary file.");
me->write_error = 1;
}
}
/* String handling
** ---------------
**
** Strings must be smaller than this buffer size.
*/
PRIVATE void HTFWriter_put_string ARGS2(HTStream *, me, WWW_CONST char*, s)
{
int rv;
if (me->write_error)
return;
rv = fputs(s, me->fp);
if (rv == EOF)
{
HTProgress ("Error writing to temporary file.");
me->write_error = 1;
}
}
/* Buffer write. Buffers can (and should!) be big.
** ------------
*/
PRIVATE void HTFWriter_write ARGS3(HTStream *, me, WWW_CONST char*, s, int, l)
{
int rv;
if (me->write_error)
return;
rv = fwrite(s, 1, l, me->fp);
if (rv != l)
{
HTProgress ("Error writing to temporary file.");
me->write_error = 1;
}
}
char *supportedTypes[]={
"image/gif",
"image/jpeg",
"image/jpg",
"image/png",
"image/x-png",
"image/x-pcd-jpeg",
"image/x-pcd-jycc",
"image/xpm",
"image/xbm",
"image/xpixmap",
"image/xbitmap",
"image/x-xpixmap",
"image/x-xbitmap",
"\n"
};
int supportedImageType(char *mt) {
int i;
if (!mt || !*mt) {
return(0);
}
for (i=0; supportedTypes[i][0]!='\n'; i++) {
if (!strcmp(supportedTypes[i],mt)) {
return(1);
}
}
return(0);
}
/* Free an HTML object
** -------------------
**
** Note that the SGML parsing context is freed, but the created
** object is not,
** as it takes on an existence of its own unless explicitly freed.
*/
PRIVATE void HTFWriter_free ARGS1(HTStream *, me)
{
HText *text;
static char *envbuf1=NULL;
static char *envbuf2=NULL;
/* I dunno if this is necessary... */
if (me->interrupted)
{
free (me->fnam);
free (me);
return;
}
if (me->write_error)
{
/*
char *cmd = (char *)malloc ((strlen (me->fnam) + 32));
sprintf (cmd, "/bin/rm -f %s &", me->fnam);
system (cmd);
free (cmd);
*/
/*ddt*/unlink(me->fnam);
HTProgress ("Insufficient temporary disk space; could not transfer data.");
free (me->fnam);
free (me);
return;
}
fflush (me->fp);
fclose (me->fp);
/* We do want to be able to handle compressed inlined images,
but we don't want transparent uncompression to take place
in binary transfer mode. */
if (!binary_transfer && me->compressed != COMPRESSED_NOT)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTFWriter] Hi there; compressed is %d, fnam is '%s'\n",
me->compressed, me->fnam);
#endif
HTCompressedFileToFile (me->fnam, me->compressed);
}
if (force_dump_to_file)
{
if (!binary_transfer)
goto done;
}
/* Now, me->end_command can either be something starting with
"<mosaic-internal-reference" or it can be a real command.
Deal with appropriately. */
if (me->end_command)
{
/* Check for forced dump condition. The left paren comes
from the construction of me->end_command as a compound shell
command below. */
if (strstr (me->end_command, "mosaic-internal-dump")) {
rename_binary_file (me->fnam);
}
else if (!strstr (me->end_command, "mosaic-internal-reference")) {
if (imageViewInternal && supportedImageType(me->mime_type)) {
char *newHTML="<html>\n<head>\n<title>Mosaic's Internal Image Display</title>\n</head>\n<body>\n<img align=center src=\"%s\">\n</body>\n</html>\n";
char *buf;
buf=(char *)calloc((strlen(currentURL)+strlen(newHTML)+5),sizeof(char));
sprintf(buf,newHTML,currentURL);
text=HText_new();
HText_beginAppend(text);
HText_appendText(text,buf);
HText_endAppend(text);
free(buf);
buf=(char *)calloc((strlen(currentURL)+strlen(me->fnam)+5),sizeof(char));
sprintf(buf,"%s\n%s",me->fnam,currentURL);
ImageResolve(NULL,buf,0);
free(buf);
goto done;
}
HTProgress("Spawning external viewer.");
/*
* Have to dance around putenv since it makes "envbuf*" part
* of the actual environment string...*sigh* What a mess!
*/
if (envbuf1) {
envbuf2=(char *)calloc((strlen(currentURL)+
strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf2,"MOSAIC_CURRENT_URL=%s",currentURL);
putenv(envbuf2);
free(envbuf1);
envbuf1=NULL;
}
else if (envbuf2) {
envbuf1=(char *)calloc((strlen(currentURL)+
strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf1,"MOSAIC_CURRENT_URL=%s",currentURL);
putenv(envbuf1);
free(envbuf2);
envbuf2=NULL;
}
else { /* Likely it is the first time */
envbuf1=(char *)calloc((strlen(currentURL)+
strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf1,"MOSAIC_CURRENT_URL=%s",currentURL);
putenv(envbuf1);
}
system (me->end_command);
if (envbuf1) {
envbuf2=(char *)calloc((strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf2,"MOSAIC_CURRENT_URL=");
putenv(envbuf2);
free(envbuf1);
envbuf1=NULL;
}
else if (envbuf2) {
envbuf1=(char *)calloc((strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf1,"MOSAIC_CURRENT_URL=");
putenv(envbuf1);
free(envbuf2);
envbuf2=NULL;
}
else { /* Likely it is the first time */
envbuf1=(char *)calloc((strlen("MOSAIC_CURRENT_URL=")+
2),
sizeof(char));
sprintf(envbuf1,"MOSAIC_CURRENT_URL=");
putenv(envbuf1);
}
}
else {
/* Internal reference, aka HDF file. Just close output file. */
}
}
else
{
/* No me->end_command; just close the file. */
}
/* Construct dummy HText thingie so Mosaic knows
not to try to access this "document". */
text = HText_new ();
HText_beginAppend (text);
/* If it's a real internal reference, tell Mosaic. */
if (me->end_command) {
if (strstr (me->end_command, "mosaic-internal-reference")) {
HText_appendText (text, me->end_command);
}
else {
HText_appendText (text, "<mosaic-access-override>\n");
}
free (me->end_command);
}
else {
/* No me->end_command; just override the access. */
HText_appendText (text, "<mosaic-access-override>\n");
}
HText_endAppend (text);
done:
if (binary_transfer)
rename_binary_file (me->fnam);
really_done:
free (me->fnam);
if (me->mime_type) {
free(me->mime_type);
}
free (me);
return;
}
/* End writing
*/
PRIVATE void HTFWriter_end_document ARGS1(HTStream *, me)
{
if (me->interrupted || me->write_error)
return;
fflush(me->fp);
}
PRIVATE void HTFWriter_handle_interrupt ARGS1(HTStream *, me)
{
/* char *cmd;*/
if (me->write_error)
goto outtahere;
/* Close the file, then kill it. */
fclose (me->fp);
/*
cmd = (char *)malloc ((strlen (me->fnam) + 32) * sizeof (char));
sprintf (cmd, "/bin/rm -f %s &", me->fnam);
system (cmd);
free (cmd);
*/
/*ddt*/unlink(me->fnam);
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "*** HTFWriter interrupted; killed '%s'\n", me->fnam);
#endif
outtahere:
me->interrupted = 1;
return;
}
/* Structured Object Class
** -----------------------
*/
PRIVATE WWW_CONST HTStreamClass HTFWriter = /* As opposed to print etc */
{
"FileWriter",
HTFWriter_free,
HTFWriter_end_document,
HTFWriter_put_character, HTFWriter_put_string,
HTFWriter_write,
HTFWriter_handle_interrupt
};
/* Take action using a system command
** ----------------------------------
**
** Creates temporary file, writes to it, executes system command
** on end-document. The suffix of the temp file can be given
** in case the application is fussy, or so that a generic opener can
** be used.
**
** WARNING: If force_dump_to_file is high, pres may be NULL
** (as we may get called directly from HTStreamStack).
*/
PUBLIC HTStream* HTSaveAndExecute ARGS5(
HTPresentation *, pres,
HTParentAnchor *, anchor, /* Not used */
HTStream *, sink,
HTFormat, format_in,
int, compressed) /* Not used */
{
char *command;
WWW_CONST char * suffix;
HTStream* me;
me = (HTStream*)malloc(sizeof(*me));
me->isa = &HTFWriter;
me->interrupted = 0;
me->write_error = 0;
me->fnam = NULL;
me->end_command = NULL;
me->compressed = compressed;
if (!format_in || !format_in->name || !*(format_in->name)) {
me->mime_type=NULL;
}
else {
if (!strncmp(format_in->name,"image",5)) {
me->mime_type=strdup(format_in->name);
}
else {
me->mime_type=NULL;
}
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTSaveAndExecute] me->compressed is '%d'\n",
me->compressed);
#endif
/* Save the file under a suitably suffixed name */
if (!force_dump_to_file)
{
extern char *mo_tmpnam (char *);
suffix = HTFileSuffix(pres->rep);
me->fnam = mo_tmpnam(anchor->address);
if (suffix)
{
char *freeme = me->fnam;
me->fnam = (char *)malloc (strlen (me->fnam) + strlen (suffix) + 8);
strcpy(me->fnam, freeme);
strcat(me->fnam, suffix);
free (freeme);
}
}
else
{
me->fnam = strdup (force_dump_filename);
}
me->fp = fopen (me->fnam, "w");
if (!me->fp)
{
HTProgress("Can't open temporary file -- serious problem.");
me->write_error = 1;
return me;
}
/* If force_dump_to_file is high, we're done here. */
if (!force_dump_to_file)
{
if (!strstr (pres->command, "mosaic-internal-reference"))
{
/* If there's a "%s" in the command, or if the command
is magic... */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "HTFWriter: pres->command is '%s'\n",
pres->command);
#endif
if (strstr (pres->command, "%s") ||
strstr (pres->command, "mosaic-internal"))
{
/* Make command to process file */
command = (char *)malloc
((strlen (pres->command) + 10 + 3*strlen(me->fnam)) *
sizeof (char));
/* Cute. pres->command will be something like "xv %s"; me->fnam
gets filled in as many times as appropriate. */
sprintf (command, pres->command, me->fnam, me->fnam, me->fnam);
me->end_command = (char *)malloc
((strlen (command) + 32 + strlen(me->fnam)) * sizeof (char));
sprintf (me->end_command, "(%s ; /bin/rm -f %s) &",
command, me->fnam);
free (command);
}
else
{
/* Make command to process file -- but we have to cat
to the viewer's stdin. */
me->end_command = (char *)malloc
((strlen (pres->command) + 64 + (2 * strlen(me->fnam))) *
sizeof (char));
sprintf (me->end_command, "((cat %s | %s); /bin/rm -f %s) &",
me->fnam, pres->command, me->fnam);
}
}
else
{
/* Overload me->end_command to be what we should write out as text
to communicate back to client code. */
me->end_command = (char *)malloc
(strlen ("mosaic-internal-reference") + strlen (me->fnam) + 32);
sprintf (me->end_command, "<%s \"%s\">\n", "mosaic-internal-reference", me->fnam);
}
}
return me;
}

22
libwww2/HTFWriter.h Normal file
View File

@@ -0,0 +1,22 @@
/*
C FILE WRITER
It is useful to have both FWriter and Writer for environments in
which fdopen() doesn't exist for example.
*/
#ifndef HTFWRITE_H
#define HTFWRITE_H
#include "HTStream.h"
#include <stdio.h>
#include "HTFormat.h"
extern HTStream * HTSaveAndExecute PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor, /* Not used */
HTStream * sink,
HTFormat format_in,
int compressed));
#endif

1324
libwww2/HTFile.c Normal file

File diff suppressed because it is too large Load Diff

212
libwww2/HTFile.h Normal file
View File

@@ -0,0 +1,212 @@
/* File access in libwww
FILE ACCESS
These are routines for local file access used by WWW browsers and
servers. Implemented by HTFile.c.
If the file is not a local file, then we pass it on to HTFTP in
case it can be reached by FTP.
*/
#ifndef HTFILE_H
#define HTFILE_H
#include "HTFormat.h"
#include "HTAccess.h"
#include "HTML.h" /* SCW */
/*
Controlling globals
These flags control how directories and files are represented as
hypertext, and are typically set by the application from command
line options, etc.
*/
extern int HTDirAccess; /* Directory access level */
#define HT_DIR_FORBID 0 /* Altogether forbidden */
#define HT_DIR_SELECTIVE 1 /* If HT_DIR_ENABLE_FILE exists */
#define HT_DIR_OK 2 /* Any accesible directory */
#define HT_DIR_ENABLE_FILE ".www_browsable" /* If exists, can browse */
extern int HTDirReadme; /* Include readme files in listing? */
/* Values: */
#define HT_DIR_README_NONE 0 /* No */
#define HT_DIR_README_TOP 1 /* Yes, first */
#define HT_DIR_README_BOTTOM 2 /* Yes, at the end */
#define HT_DIR_README_FILE "README"
extern HTList *HTSuffixes;
/*
Convert filenames between local and WWW formats
*/
extern char * HTLocalName PARAMS((WWW_CONST char * name));
/*
Make a WWW name from a full local path name
*/
extern char * WWW_nameOfFile PARAMS((char * name));
/*
Generate the name of a cache file
*/
extern char * HTCacheFileName PARAMS((WWW_CONST char * name));
/*
Output directory titles
This is (like the next one) used by HTFTP. It is common code to
generate the title and heading 1 and the parent directory link for
any anchor.
*/
extern void HTDirTitles PARAMS((
HTStructured * target,
HTAnchor * anchor));
/*
Output a directory entry
This is used by HTFTP.c for example -- it is a common routine for
generating a linked directory entry.
*/
extern void HTDirEntry PARAMS((
HTStructured * target, /* in which to put the linked text */
WWW_CONST char * tail, /* last part of directory name */
WWW_CONST char * entry)); /* name of this entry */
/*
HTSetSuffix: Define the representation for a file suffix
This defines a mapping between local file suffixes and file content
types and encodings.
ON ENTRY,
suffix includes the "." if that is important (normally, yes!)
representation is MIME-style content-type
encoding is MIME-style content-transfer-encoding (8bit, 7bit, etc)
quality an a priori judgement of the quality of such files
(0.0..1.0)
*/
/* Example: HTSetSuffix(".ps", "application/postscript", "8bit", 1.0);
**
*/
extern void HTSetSuffix PARAMS((
WWW_CONST char * suffix,
WWW_CONST char * representation,
WWW_CONST char * encoding,
float quality));
/*
HTFileFormat: Get Representation and Encoding from file name
ON EXIT,
return The represntation it imagines the file is in
*pEncoding The encoding (binary, 7bit, etc). See HTSetSuffix.
*/
#define COMPRESSED_NOT 0
#define COMPRESSED_BIGZ 1
#define COMPRESSED_GNUZIP 2
extern HTFormat HTFileFormat PARAMS((
char * filename,
HTAtom ** pEncoding,
HTAtom *,
int *compressed));
extern char * HTFileMimeType PARAMS((
WWW_CONST char * filename,
WWW_CONST char * default_type));
extern char *HTDescribeURL (char *);
/*
Determine file value from file name
*/
extern float HTFileValue PARAMS((
WWW_CONST char * filename));
/*
Determine write access to a file
ON EXIT,
return value YES if file can be accessed and can be written to.
*/
/*
BUGS
Isn't there a quicker way?
*/
extern BOOL HTEditable PARAMS((WWW_CONST char * filename));
/*
Determine a suitable suffix, given the representation
ON ENTRY,
rep is the atomized MIME style representation
ON EXIT,
returns a pointer to a suitable suffix string if one has been found,
else NULL.
*/
extern WWW_CONST char * HTFileSuffix PARAMS((
HTAtom* rep));
/*
The Protocols
*/
extern HTProtocol HTFTP, HTFile;
#endif /* HTFILE_H */

832
libwww2/HTFormat.c Normal file
View File

@@ -0,0 +1,832 @@
/* Manage different file formats HTFormat.c
** =============================
**
*/
#include "../config.h"
/* Connection: Keep-Alive support -bjs */
#include "HTMIME.h"
#include "HTFormat.h"
PUBLIC float HTMaxSecs = 1e10; /* No effective limit */
PUBLIC float HTMaxLength = 1e10; /* No effective limit */
#include "HTUtils.h"
#include "tcp.h"
#include "HTMLDTD.h"
#include "HText.h"
#include "HTAlert.h"
#include "HTList.h"
#include "HTInit.h"
#include "HTFWriter.h"
#include "HTPlain.h"
#include "SGML.h"
#include "HTML.h"
#include "HTMLGen.h"
/* From gui-documents.c. */
extern int loading_inlined_images;
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
PUBLIC BOOL HTOutputSource = NO; /* Flag: shortcut parser to stdout */
extern BOOL interactive;
struct _HTStream {
WWW_CONST HTStreamClass* isa;
/* ... */
};
/* Whoooooooooooooa ugly!!! */
int loading_length = -1;
int noLength=1;
/*SWP -- Even Uglier*/
extern int ftpKludge;
/* Presentation methods
** --------------------
*/
PUBLIC HTList * HTPresentations = 0;
PUBLIC HTPresentation* default_presentation = 0;
/* Define a presentation system command for a content-type
** -------------------------------------------------------
*/
PUBLIC void HTSetPresentation ARGS5(
WWW_CONST char *, representation,
WWW_CONST char *, command,
float, quality,
float, secs,
float, secs_per_byte
){
HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
pres->rep = HTAtom_for(representation);
pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
pres->converter = HTSaveAndExecute; /* Fixed for now ... */
pres->quality = quality;
pres->secs = secs;
pres->secs_per_byte = secs_per_byte;
pres->rep = HTAtom_for(representation);
pres->command = 0;
StrAllocCopy(pres->command, command);
if (!HTPresentations) HTPresentations = HTList_new();
if (strcmp(representation, "*")==0) {
if (default_presentation) free(default_presentation);
default_presentation = pres;
} else {
HTList_addObjectAtEnd(HTPresentations, pres);
}
}
/* Define a built-in function for a content-type
** ---------------------------------------------
*/
PUBLIC void HTSetConversion ARGS6(
WWW_CONST char *, representation_in,
WWW_CONST char *, representation_out,
HTConverter*, converter,
float, quality,
float, secs,
float, secs_per_byte
){
HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
pres->rep = HTAtom_for(representation_in);
pres->rep_out = HTAtom_for(representation_out);
pres->converter = converter;
pres->command = NULL; /* Fixed */
pres->quality = quality;
pres->secs = secs;
pres->secs_per_byte = secs_per_byte;
pres->command = 0;
if (!HTPresentations) HTPresentations = HTList_new();
if (strcmp(representation_in, "*")==0) {
if (default_presentation) free(default_presentation);
default_presentation = pres;
} else {
HTList_addObject(HTPresentations, pres);
}
}
/********************ddt*/
/*
** Remove a conversion routine from the presentation list.
** The conversion routine must match up with the given args.
*/
PUBLIC void HTRemoveConversion ARGS3(
WWW_CONST char *, representation_in,
WWW_CONST char *, representation_out,
HTConverter*, converter
){
int numberOfPresentations;
HTPresentation * pres;
HTAtom *rep_in, *rep_out;
int x;
numberOfPresentations = HTList_count(HTPresentations);
rep_in = HTAtom_for(representation_in);
rep_out = HTAtom_for(representation_out);
for (x = 0; x < numberOfPresentations; x++) {
pres = HTList_objectAt(HTPresentations, x);
if (pres) {
if ((!strcmp(pres->rep->name,rep_in->name)) &&
(!strcmp(pres->rep_out->name,rep_out->name)) &&
(pres->converter == converter)) {
HTList_removeObject(HTPresentations,pres);
}
}
}
}
/***************** end ddt*/
/* File buffering
** --------------
**
** The input file is read using the macro which can read from
** a socket or a file.
** The input buffer size, if large will give greater efficiency and
** release the server faster, and if small will save space on PCs etc.
*/
#define INPUT_BUFFER_SIZE 65536
PRIVATE char input_buffer[INPUT_BUFFER_SIZE];
PRIVATE char * input_pointer;
PRIVATE char * input_limit;
PRIVATE int input_file_number;
/* Set up the buffering
**
** These routines are public because they are in fact needed by
** many parsers, and on PCs and Macs we should not duplicate
** the static buffer area.
*/
PUBLIC void HTInitInput ARGS1 (int,file_number)
{
input_file_number = file_number;
input_pointer = input_limit = input_buffer;
}
PUBLIC int interrupted_in_htgetcharacter = 0;
PUBLIC char HTGetCharacter NOARGS
{
char ch;
interrupted_in_htgetcharacter = 0;
do
{
if (input_pointer >= input_limit)
{
int status =
NETREAD(input_file_number, input_buffer, INPUT_BUFFER_SIZE);
if (status <= 0)
{
if (status == 0)
return (char)EOF;
if (status == HT_INTERRUPTED)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "HTFormat: Interrupted in HTGetCharacter\n");
#endif
interrupted_in_htgetcharacter = 1;
return (char)EOF;
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"HTFormat: File read error %d\n", status);
#endif
return (char)EOF;
}
input_pointer = input_buffer;
input_limit = input_buffer + status;
}
ch = *input_pointer++;
}
while (ch == (char) 13); /* Ignore ASCII carriage return */
return ch;
}
/* Stream the data to an ouput file as binary
*/
PUBLIC int HTOutputBinary ARGS2( int, input,
FILE *, output)
{
do
{
int status = NETREAD(input, input_buffer, INPUT_BUFFER_SIZE);
if (status <= 0)
{
if (status == 0)
return 0;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTFormat: File read error %d\n", status);
#endif
return 2; /* Error */
}
fwrite(input_buffer, sizeof(char), status, output);
} while (YES);
}
static int partial_wildcard_matches (HTFormat r1, HTFormat r2)
{
/* r1 is the presentation format we're currently looking at out
of the list we understand. r2 is the one we need to get to. */
char *s1, *s2, *subtype1 = NULL, *subtype2 = NULL;
int i;
s1 = HTAtom_name (r1);
s2 = HTAtom_name (r2);
if (!s1 || !s2)
return 0;
s1 = strdup (s1);
s2 = strdup (s2);
for (i = 0; i < strlen (s1); i++)
if (s1[i] == '/')
{
s1[i] = '\0';
subtype1 = &(s1[i+1]);
/* Now s1 contains the main type and subtype1 contains
the subtype. */
goto done1;
}
done1:
if (!subtype1)
goto nope;
/* Bail if we don't have a wildcard possibility. */
if (subtype1[0] != '*')
goto nope;
for (i = 0; i < strlen (s2); i++)
if (s2[i] == '/')
{
s2[i] = '\0';
subtype2 = &(s2[i+1]);
/* Now s2 contains the main type and subtype2 contains
the subtype. */
goto done2;
}
done2:
if (!subtype2)
goto nope;
/* Bail if s1 and s2 aren't the same and s1[0] isn't '*'. */
if (strcmp (s1, s2) && s1[0] != '*')
goto nope;
/* OK, so now either we have the same main types or we have a wildcard
type for s1. We also know that we have a wildcard possibility in
s1. Therefore, at this point, we have a match. */
free (s1);
free (s2);
return 1;
nope:
free (s1);
free (s2);
return 0;
}
/* Create a filter stack
** ---------------------
**
** If a wildcard match is made, a temporary HTPresentation
** structure is made to hold the destination format while the
** new stack is generated. This is just to pass the out format to
** MIME so far. Storing the format of a stream in the stream might
** be a lot neater.
*/
PUBLIC HTStream * HTStreamStack ARGS5(
HTFormat, format_in,
HTFormat, rep_out,
int, compressed,
HTStream*, sink,
HTParentAnchor*, anchor)
{
HTAtom * wildcard = HTAtom_for("*");
HTPresentation temp;
/* Inherit force_dump_to_file from mo-www.c. */
extern int force_dump_to_file;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"[HTStreamStack] Constructing stream stack for %s to %s\n",
HTAtom_name(format_in),
HTAtom_name(rep_out));
#endif
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
" Compressed is %d\n", compressed);
#endif
if (rep_out == WWW_SOURCE ||
rep_out == format_in)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
"[HTStreamStack] rep_out == WWW_SOURCE | rep_out == format_in; returning sink\n");
#endif
return sink;
}
if (!HTPresentations)
HTFormatInit(); /* set up the list */
if (force_dump_to_file && format_in != WWW_MIME)
{
return HTSaveAndExecute (NULL, anchor, sink, format_in, compressed);
}
{
int n = HTList_count(HTPresentations);
int i;
HTPresentation * pres;
for(i=0; i<n; i++)
{
pres = HTList_objectAt(HTPresentations, i);
#ifndef DISABLE_TRACE
if (www2Trace)
{
fprintf (stderr, "HTFormat: looking at pres '%s'\n",
HTAtom_name (pres->rep));
if (pres->command)
fprintf (stderr, "HTFormat: pres->command is '%s'\n",
pres->command);
else
fprintf (stderr, "HTFormat: pres->command doesn't exist\n");
}
#endif
if (pres->rep == format_in ||
partial_wildcard_matches (pres->rep, format_in))
{
if (pres->command && strstr (pres->command, "mosaic-internal-present"))
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTStreamStack] HEY HEY HEY caught internal-present\n");
#endif
return HTPlainPresent (pres, anchor, sink, format_in, compressed);
}
if (pres->rep_out == rep_out)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
"[HTStreamStack] pres->rep_out == rep_out\n");
#endif
return (*pres->converter)(pres, anchor, sink, format_in, compressed);
}
if (pres->rep_out == wildcard)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
"[HTStreamStack] pres->rep_out == wildcard\n");
#endif
temp = *pres;/* make temp conversion to needed fmt */
temp.rep_out = rep_out; /* yuk */
return (*pres->converter)(&temp, anchor, sink, format_in, compressed);
}
}
}
}
#ifndef DISABLE_TRACE
if (www2Trace)
{
fprintf (stderr, "[HTStreamStack] Returning NULL at bottom.\n");
}
#endif
return NULL;
}
/* Find the cost of a filter stack
** -------------------------------
**
** Must return the cost of the same stack which StreamStack would set up.
**
** On entry,
** length The size of the data to be converted
*/
PUBLIC float HTStackValue ARGS4(
HTFormat, format_in,
HTFormat, rep_out,
float, initial_value,
long int, length)
{
HTAtom * wildcard = HTAtom_for("*");
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
HTAtom_name(format_in), initial_value,
HTAtom_name(rep_out));
#endif
if (rep_out == WWW_SOURCE ||
rep_out == format_in) return 0.0;
if (!HTPresentations) HTFormatInit(); /* set up the list */
{
int n = HTList_count(HTPresentations);
int i;
HTPresentation * pres;
for(i=0; i<n; i++) {
pres = HTList_objectAt(HTPresentations, i);
if (pres->rep == format_in && (
pres->rep_out == rep_out ||
pres->rep_out == wildcard)) {
float value = initial_value * pres->quality;
if (HTMaxSecs != 0.0)
value = value - (length*pres->secs_per_byte + pres->secs)
/HTMaxSecs;
return value;
}
}
}
return -1e30; /* Really bad */
}
/* Push data from a socket down a stream
** -------------------------------------
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
#define SWP_HACK
PUBLIC int HTCopy ARGS3(int, file_number,
HTStream*, sink,
int, bytes_already_read)
{
HTStreamClass targetClass;
char line[256];
char *msg;
int bytes = bytes_already_read;
extern int twirl_increment;
int next_twirl = twirl_increment;
int rv = 0;
int left = -1, total_read = bytes_already_read, hdr_len = 0;
/* if(loading_length != -1) left = loading_length;*/
HTClearActiveIcon();
/* Push the data down the stream
**
*/
targetClass = *(sink->isa); /* Copy pointers to procedures */
hdr_len = HTMIME_get_header_length(sink);
/* Push binary from socket down sink */
for(;;)
{
int status, intr;
if (bytes > next_twirl)
{
intr = HTCheckActiveIcon(1);
next_twirl += twirl_increment;
}
else
{
intr = HTCheckActiveIcon(0);
}
if (intr)
{
#ifdef SWP_HACK
loading_length=(-1);
#endif
HTProgress ("Data transfer interrupted.");
noLength=0;
HTMeter(100,NULL);
noLength=1;
(*targetClass.handle_interrupt)(sink);
rv = -1;
goto ready_to_leave;
}
if(loading_length == -1) {
left = -1;
status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
} else {
left = (loading_length+hdr_len)-total_read;
if(left>0) status = NETREAD(file_number, input_buffer,
(left>INPUT_BUFFER_SIZE?
INPUT_BUFFER_SIZE:left));
else status=0;
}
if (status > 0)
total_read += status;
/* fprintf(stderr,"ll = %d status = %d left = %d hdr = %d tr = %d\n",
loading_length,status,left,hdr_len,total_read);
*/
/*
status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
*/
if (status <= 0)
{
if (status == 0)
break;
if (status == HT_INTERRUPTED)
{
#ifdef SWP_HACK
loading_length=(-1);
#endif
HTProgress ("Data transfer interrupted.");
noLength=0;
HTMeter(100,NULL);
noLength=1;
(*targetClass.handle_interrupt)(sink);
rv = -1;
goto ready_to_leave;
}
if (errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE)
{
/* Arrrrgh, HTTP 0/1 compability problem, maybe. */
rv = -2;
goto ready_to_leave;
}
break;
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "HTCopy: put_block on input_buffer '%s'\n", input_buffer);
#endif
(*targetClass.put_block)(sink, input_buffer, status);
if (ftpKludge) {
hdr_len=0;
}
else {
hdr_len = HTMIME_get_header_length(sink);
}
/* left = loading_length - total_read;*/
bytes += status;
/* moved msg stuff here as loading_length may change midstream -bjs*/
if (loading_length == -1){
msg = (loading_inlined_images ?
"Read %d bytes of inlined image data." :
"Read %d bytes of data.");
sprintf (line, msg, bytes);
/* HTMeter(0,NULL);*/
}else{
msg = (loading_inlined_images ?
"Read %d of %d bytes of inlined image data." :
"Read %d of %d bytes of data.");
sprintf (line, msg, bytes, loading_length+hdr_len);
HTMeter((bytes*100)/(loading_length+hdr_len),NULL);
}
HTProgress (line);
if((loading_length != -1) && (total_read>=(loading_length+hdr_len))) {
/* fprintf(stderr,"done\n");*/
break;
}
} /* next bufferload */
/*
HTProgress (loading_inlined_images ?
"Data transfer complete." : "Data transfer complete.");
*/
HTProgress("Data transfer complete.");
noLength=0;
HTMeter(100,NULL);
noLength=1;
/* fprintf(stderr,"HTFormat: KeepAlive Exit\n");*/
/*
NETCLOSE (file_number);
*/
/* Success. */
rv = 0;
ready_to_leave:
/* Reset ourselves so we don't get confused. */
loading_length = -1;
return rv;
}
/* Push data from a file pointer down a stream
** -------------------------------------
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
**
*/
PUBLIC void HTFileCopy ARGS2(
FILE *, fp,
HTStream*, sink)
{
HTStreamClass targetClass;
targetClass = *(sink->isa); /* Copy pointers to procedures */
for(;;) {
int status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, fp);
if (status == 0) { /* EOF or error */
if (ferror(fp) == 0) break;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTFormat: Read error, read returns %d\n", ferror(fp));
#endif
break;
}
(*targetClass.put_block)(sink, input_buffer, status);
} /* next bufferload */
fclose (fp);
return;
}
PUBLIC void HTFileCopyToText ARGS2(
FILE *, fp,
HText *, text)
{
for(;;)
{
int status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, fp);
if (status == 0)
{ /* EOF or error */
if (ferror(fp) == 0) break;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTFormat: Read error, read returns %d\n", ferror(fp));
#endif
break;
}
HText_appendBlock (text, input_buffer, status);
} /* next bufferload */
fclose (fp);
return;
}
/* Parse a socket given format and file number
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
PUBLIC int HTParseSocket ARGS6(
HTFormat, format_in,
HTFormat, format_out,
HTParentAnchor *, anchor,
int, file_number,
HTStream*, sink,
int, compressed)
{
HTStream * stream;
HTStreamClass targetClass;
int rv;
stream = HTStreamStack(format_in,
format_out,
compressed,
sink, anchor);
if (!stream)
{
char buffer[1024]; /* @@@@@@@@ */
sprintf(buffer, "Sorry, can't convert from %s to %s.",
HTAtom_name(format_in), HTAtom_name(format_out));
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTFormat: %s\n", buffer);
#endif
return HTLoadError(sink, 501, buffer);
}
targetClass = *(stream->isa); /* Copy pointers to procedures */
rv = HTCopy(file_number, stream, 0);
if (rv == -1)
{
/* handle_interrupt should have been done in HTCopy */
/* (*targetClass.handle_interrupt)(stream); */
return HT_INTERRUPTED;
}
(*targetClass.end_document)(stream);
/* New thing: we force close the data socket here, so that if
an external viewer gets forked off in the free method below,
the connection doesn't remain upon until the child exits --
which it does if we don't do this. */
NETCLOSE (file_number);
(*targetClass.free)(stream);
return HT_LOADED;
}
/* Parse a file given format and file pointer
**
** This routine is responsible for creating and PRESENTING any
** graphic (or other) objects described by the file.
**
** The file number given is assumed to be a TELNET stream ie containing
** CRLF at the end of lines which need to be stripped to LF for unix
** when the format is textual.
**
*/
PUBLIC int HTParseFile ARGS6(
HTFormat, format_in,
HTFormat, format_out,
HTParentAnchor *, anchor,
FILE *, fp,
HTStream*, sink,
int, compressed)
{
HTStream * stream;
HTStreamClass targetClass;
stream = HTStreamStack(format_in,
format_out,
compressed,
sink , anchor);
if (!stream) {
char buffer[1024]; /* @@@@@@@@ */
sprintf(buffer, "Sorry, can't convert from %s to %s.",
HTAtom_name(format_in), HTAtom_name(format_out));
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
#endif
return HTLoadError(sink, 501, buffer);
}
targetClass = *(stream->isa); /* Copy pointers to procedures */
HTFileCopy(fp, stream);
(*targetClass.end_document)(stream);
(*targetClass.free)(stream);
return HT_LOADED;
}

343
libwww2/HTFormat.h Normal file
View File

@@ -0,0 +1,343 @@
/* HTFormat: The format manager in the WWW Library
MANAGE DIFFERENT DOCUMENT FORMATS
Here we describe the functions of the HTFormat module which handles conversion between
different data representations. (In MIME parlance, a representation is known as a
content-type. In WWW the term "format" is often used as it is shorter).
This module is implemented by HTFormat.c . This hypertext document is used to generate
the HTFormat.h inlude file. Part of the WWW library.
Preamble
*/
#ifndef HTFORMAT_H
#define HTFORMAT_H
#include "HTUtils.h"
#include "HTStream.h"
#include "HTAtom.h"
#include "HTList.h"
#ifdef SHORT_NAMES
#define HTOutputSource HTOuSour
#define HTOutputBinary HTOuBina
#endif
/*
The HTFormat type
We use the HTAtom object for holding representations. This allows faster manipulation
(comparison and copying) that if we stayed with strings.
*/
typedef HTAtom * HTFormat;
/*
These macros (which used to be constants) define some basic internally referenced
representations. The www/xxx ones are of course not MIME standard.
www/source is an output format which leaves the input untouched. It is useful for
diagnostics, and for users who want to see the original, whatever it is.
*/
/* Internal ones */
#define WWW_SOURCE HTAtom_for("www/source") /* Whatever it was originally*/
/*
www/present represents the user's perception of the document. If you convert to
www/present, you present the material to the user.
*/
#define WWW_PRESENT HTAtom_for("www/present") /* The user's perception */
/*
The message/rfc822 format means a MIME message or a plain text message with no MIME
header. This is what is returned by an HTTP server.
*/
#define WWW_MIME HTAtom_for("www/mime") /* A MIME message */
/*
www/print is like www/present except it represents a printed copy.
*/
#define WWW_PRINT HTAtom_for("www/print") /* A printed copy */
#define WWW_PLAINTEXT HTAtom_for("text/plain")
#define WWW_POSTSCRIPT HTAtom_for("application/postscript")
#define WWW_RICHTEXT HTAtom_for("application/x-rtf")
#define WWW_HTML HTAtom_for("text/html")
#define WWW_BINARY HTAtom_for("application/octet-stream")
/*
We must include the following file after defining HTFormat, to which it makes
reference.
The HTEncoding type
typedef HTAtom* HTEncoding;
The following are values for the MIME types:
#define WWW_ENC_7BIT
#define WWW_ENC_8BIT
#define WWW_ENC_BINARY
We also add
*/
#include "HTAnchor.h"
/*
The HTPresentation and HTConverter types
This HTPresentation structure represents a possible conversion
algorithm from one format to annother. It includes a pointer to a
conversion routine. The conversion routine returns a stream to
which data should be fed. See also HTStreamStack which scans the
list of registered converters and calls one. See the initialisation
module for a list of conversion routines.
*/
typedef struct _HTPresentation HTPresentation;
typedef HTStream * HTConverter PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
struct _HTPresentation {
HTAtom* rep; /* representation name atmoized */
HTAtom* rep_out; /* resulting representation */
HTConverter *converter; /* The routine to gen the stream stack */
char * command; /* MIME-format string */
float quality; /* Between 0 (bad) and 1 (good) */
float secs;
float secs_per_byte;
};
/*
The list of presentations is kept by this module. It is also scanned by modules which
want to know the set of formats supported. for example.
*/
extern HTList * HTPresentations;
/*
HTSetPresentation: Register a system command to present a format
ON ENTRY,
rep is the MIME - style format name
command is the MAILCAP - style command template
quality A degradation faction 0..1
maxbytes A limit on the length acceptable as input (0 infinite)
maxsecs A limit on the time user will wait (0 for infinity)
*/
extern void HTSetPresentation PARAMS((
WWW_CONST char * representation,
WWW_CONST char * command,
float quality,
float secs,
float secs_per_byte
));
/*
HTSetConversion: Register a converstion routine
ON ENTRY,
rep_in is the content-type input
rep_out is the resulting content-type
converter is the routine to make the stream to do it
*/
extern void HTSetConversion PARAMS((
WWW_CONST char * rep_in,
WWW_CONST char * rep_out,
HTConverter * converter,
float quality,
float secs,
float secs_per_byte
));
/*
HTStreamStack: Create a stack of streams
This is the routine which actually sets up the conversion. It
currently checks only for direct conversions, but multi-stage
conversions are forseen. It takes a stream into which the output
should be sent in the final format, builds the conversion stack,
and returns a stream into which the data in the input format should
be fed. The anchor is passed because hypertxet objects load
information into the anchor object which represents them.
*/
extern HTStream * HTStreamStack PARAMS((
HTFormat format_in,
HTFormat format_out,
int compressed,
HTStream* stream_out,
HTParentAnchor* anchor));
/*
HTStackValue: Find the cost of a filter stack
Must return the cost of the same stack which HTStreamStack would set up.
ON ENTRY,
format_in The fomat of the data to be converted
format_out The format required
initial_value The intrinsic "value" of the data before conversion on a scale
from 0 to 1
length The number of bytes expected in the input format
*/
extern float HTStackValue PARAMS((
HTFormat format_in,
HTFormat rep_out,
float initial_value,
long int length));
#define NO_VALUE_FOUND -1e20 /* returned if none found */
/*
HTCopy: Copy a socket to a stream
This is used by the protocol engines to send data down a stream,
typically one which has been generated by HTStreamStack.
*/
extern int HTCopy PARAMS((
int file_number,
HTStream* sink,
int bytes_already_read));
/*
HTFileCopy: Copy a file to a stream
This is used by the protocol engines to send data down a stream,
typically one which has been generated by HTStreamStack. It is
currently called by HTParseFile
*/
extern void HTFileCopy PARAMS((
FILE* fp,
HTStream* sink));
#if 0
extern void HTFileCopyToText PARAMS((
FILE* fp,
HText* text));
#endif
/*
Clear input buffer and set file number
This routine and the one below provide simple character input from sockets. (They are
left over from the older architecure and may not be used very much.) The existence of
a common routine and buffer saves memory space in small implementations.
*/
extern void HTInitInput PARAMS((int file_number));
/*
Get next character from buffer
*/
extern char HTGetCharacter NOPARAMS;
/*
HTParseSocket: Parse a socket given its format
This routine is called by protocol modules to load an object. uses
HTStreamStack and the copy routines above. Returns HT_LOADED if
succesful, <0 if not.
*/
extern int HTParseSocket PARAMS((
HTFormat format_in,
HTFormat format_out,
HTParentAnchor *anchor,
int file_number,
HTStream* sink,
int compressed));
/*
HTParseFile: Parse a File through a file pointer
This routine is called by protocols modules to load an object. uses
HTStreamStack and HTFileCopy . Returns HT_LOADED if succesful, <0
if not.
*/
extern int HTParseFile PARAMS((
HTFormat format_in,
HTFormat format_out,
HTParentAnchor *anchor,
FILE *fp,
HTStream* sink,
int compressed));
/*
HTFormatInit: Set up default presentations and conversions
These are defined in HTInit.c or HTSInit.c if these have been
replaced. If you don't call this routine, and you don't define any
presentations, then this routine will automatically be called the
first time a conversion is needed. However, if you explicitly add some
conversions (eg using HTLoadRules) then you may want also to
explicitly call this to get the defaults as well.
*/
extern void HTFormatInit NOPARAMS;
/*
Epilogue
*/
extern BOOL HTOutputSource; /* Flag: shortcut parser */
#endif
/*
end */

823
libwww2/HTGopher.c Normal file
View File

@@ -0,0 +1,823 @@
/* GOPHER ACCESS HTGopher.c
** =============
**
** History:
** 26 Sep 90 Adapted from other accesses (News, HTTP) TBL
** 29 Nov 91 Downgraded to C, for portable implementation.
*/
#include "../config.h"
/* Implements:
*/
#include "HTGopher.h"
#define GOPHER_PORT 70 /* See protocol spec */
#define BIG 1024 /* Bug */
#define LINE_LENGTH 256 /* Bug */
/* Gopher entity types:
*/
#define GOPHER_TEXT '0'
#define GOPHER_MENU '1'
#define GOPHER_CSO '2'
#define GOPHER_ERROR '3'
#define GOPHER_MACBINHEX '4'
#define GOPHER_PCBINHEX '5'
#define GOPHER_UUENCODED '6'
#define GOPHER_INDEX '7'
#define GOPHER_TELNET '8'
#define GOPHER_BINARY '9'
#define GOPHER_DUPLICATE '+'
#define GOPHER_GIF 'g'
#define GOPHER_IMAGE 'I'
#define GOPHER_TN3270 'T'
#define GOPHER_HTML 'h' /* HTML */
#define GOPHER_WWW 'w' /* W3 address */
#define GOPHER_SOUND 's'
#define GOPHER_PLUS_IMAGE ':'
#define GOPHER_PLUS_MOVIE ';'
#define GOPHER_PLUS_SOUND '<'
#define GOPHER_INFO 'i'
#include <ctype.h>
#include "HTUtils.h" /* Coding convention macros */
#include "tcp.h"
#include "HTParse.h"
#include "HTFormat.h"
#include "HTFile.h"
#include "HTTCP.h"
/* Hypertext object building machinery
*/
#include "HTML.h"
#define PUTC(c) (*targetClass.put_character)(target, c)
#define PUTS(s) (*targetClass.put_string)(target, s)
#define START(e) (*targetClass.start_element)(target, e, 0, 0)
#define END(e) (*targetClass.end_element)(target, e)
#define END_TARGET (*targetClass.end_document)(target)
#define FREE_TARGET (*targetClass.free)(target)
struct _HTStructured {
WWW_CONST HTStructuredClass * isa;
/* ... */
};
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
PRIVATE HTStructured *target; /* the new hypertext */
PRIVATE HTStructuredClass targetClass; /* Its action routines */
/* Module-wide variables
*/
PRIVATE int s; /* Socket for GopherHost */
/* Matrix of allowed characters in filenames
** -----------------------------------------
*/
PRIVATE BOOL acceptable[256];
PRIVATE BOOL acceptable_inited = NO;
PRIVATE void init_acceptable NOARGS
{
unsigned int i;
char * good =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
for(i=0; i<256; i++) acceptable[i] = NO;
for(;*good; good++) acceptable[(unsigned int)*good] = YES;
acceptable_inited = YES;
}
PRIVATE WWW_CONST char hex[17] = "0123456789abcdef";
/* Decode one hex character
*/
PRIVATE char from_hex ARGS1(char, c)
{
return (c>='0')&&(c<='9') ? c-'0'
: (c>='A')&&(c<='F') ? c-'A'+10
: (c>='a')&&(c<='f') ? c-'a'+10
: 0;
}
/* Paste in an Anchor
** ------------------
**
** The title of the destination is set, as there is no way
** of knowing what the title is when we arrive.
**
** On entry,
** HT is in append mode.
** text points to the text to be put into the file, 0 terminated.
** addr points to the hypertext refernce address 0 terminated.
*/
PRIVATE void write_anchor ARGS3(WWW_CONST char *,text, WWW_CONST char *,addr,
char *, image_text)
{
PUTS ("<A HREF=\"");
PUTS (addr);
PUTS ("\">");
/* Throw in an inlined image, if one has been requested. */
if (image_text)
{
PUTS ("<IMG SRC=\"");
PUTS (image_text);
PUTS ("\"> ");
}
PUTS(text);
PUTS("</A>");
}
PRIVATE void write_non_anchor ARGS2(WWW_CONST char *,text,
char *, image_text)
{
/* Throw in an inlined image, if one has been requested. */
if (image_text)
{
PUTS ("<IMG SRC=\"");
PUTS (image_text);
PUTS ("\"> ");
}
PUTS(text);
}
/* Parse a Gopher Menu document
** ============================
**
*/
PRIVATE int parse_menu ARGS2 (
WWW_CONST char *, arg,
HTParentAnchor *, anAnchor)
{
char gtype;
char ch;
char line[BIG];
char address[BIG];
char *name, *selector; /* Gopher menu fields */
char *host;
char *port;
char *p = line;
extern int interrupted_in_htgetcharacter;
WWW_CONST char *title;
#define TAB '\t'
#define HEX_ESCAPE '%'
HTProgress ("Retrieving Gopher menu.");
PUTS("<H1>Gopher Menu</H1>\n");
START(HTML_DL);
while ((ch=HTGetCharacter ()) != (char)EOF)
{
if (interrupted_in_htgetcharacter)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "parse_menu: picked up interrupt in htgc\n");
#endif
(*targetClass.handle_interrupt)(target);
return HT_INTERRUPTED;
}
if (ch != LF)
{
*p = ch; /* Put character in line */
if (p< &line[BIG-1]) p++;
}
else
{
*p++ = 0; /* Terminate line */
p = line; /* Scan it to parse it */
port = 0; /* Flag "not parsed" */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "HTGopher: Menu item: %s\n", line);
#endif
gtype = *p++;
/* Break on line with a dot by itself */
if ((gtype=='.') && ((*p=='\r') || (*p==0)))
break;
if (gtype && *p)
{
name = p;
selector = strchr(name, TAB);
START(HTML_DD);
if (selector)
{
*selector++ = 0; /* Terminate name */
host = strchr(selector, TAB);
if (host)
{
*host++ = 0; /* Terminate selector */
port = strchr(host, TAB);
if (port)
{
char *junk;
port[0] = ':'; /* delimit host a la W3 */
junk = strchr(port, TAB);
if (junk)
*junk++ = 0; /* Chop port */
if ((port[1]=='0') && (!port[2]))
port[0] = 0; /* 0 means none */
} /* no port */
} /* host ok */
} /* selector ok */
} /* gtype and name ok */
if (gtype == GOPHER_WWW)
{ /* Gopher pointer to W3 */
write_anchor(name, selector, "internal-gopher-text");
}
else if (port)
{ /* Other types need port */
if (gtype == GOPHER_TELNET)
{
if (*selector)
sprintf(address, "telnet://%s@%s/",
selector, host);
else
sprintf(address, "telnet://%s/", host);
}
else if (gtype == GOPHER_TN3270)
{
if (*selector)
sprintf(address, "tn3270://%s@%s/",
selector, host);
else
sprintf(address, "tn3270://%s/", host);
}
else
{ /* If parsed ok */
char *q;
unsigned char *p;
sprintf(address, "//%s/%c", host, gtype);
q = address+ strlen(address);
for(p=(unsigned char *)selector; *p; p++)
{ /* Encode selector string */
if (acceptable[*p]) *q++ = *p;
else
{
*q++ = HEX_ESCAPE; /* Means hex coming */
*q++ = hex[(*p) >> 4];
*q++ = hex[(*p) & 15];
}
}
*q++ = 0; /* terminate address */
}
/* Error response from Gopher doesn't deserve to
be a hyperlink. */
if (strcmp (address, "//error.host:1/0") != 0 &&
strcmp (address, "//error/0error") != 0 &&
strcmp (address, "//:/0") != 0 &&
gtype != GOPHER_ERROR)
{
switch (gtype)
{
case GOPHER_MENU:
write_anchor(name, address, "internal-gopher-menu");
break;
case GOPHER_TEXT:
write_anchor(name, address, "internal-gopher-text");
break;
case GOPHER_INDEX:
case GOPHER_CSO:
write_anchor(name, address, "internal-gopher-index");
break;
case GOPHER_IMAGE:
case GOPHER_GIF:
case GOPHER_PLUS_IMAGE:
write_anchor(name, address, "internal-gopher-image");
break;
case GOPHER_SOUND:
case GOPHER_PLUS_SOUND:
write_anchor(name, address, "internal-gopher-sound");
break;
case GOPHER_PLUS_MOVIE:
write_anchor(name, address, "internal-gopher-movie");
break;
case GOPHER_TELNET:
case GOPHER_TN3270:
write_anchor(name, address, "internal-gopher-telnet");
break;
case GOPHER_BINARY:
case GOPHER_MACBINHEX:
case GOPHER_PCBINHEX:
case GOPHER_UUENCODED:
write_anchor(name, address, "internal-gopher-binary");
break;
case GOPHER_INFO:
write_non_anchor(name, NULL);
break;
default:
write_anchor(name, address, "internal-gopher-unknown");
break;
}
}
else
{
/* Good error handling??? */
PUTS(line);
}
}
else
{ /* parse error */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTGopher: Bad menu item.\n");
#endif
PUTS(line);
} /* parse error */
p = line; /* Start again at beginning of line */
} /* if end of line */
} /* Loop over characters */
if (interrupted_in_htgetcharacter)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "parse_menu: picked up interrupt in htgc\n");
#endif
(*targetClass.handle_interrupt)(target);
return HT_INTERRUPTED;
}
END(HTML_DL);
END_TARGET;
FREE_TARGET;
HTProgress ("Retrieved Gopher menu.");
return 1;
}
/* Display a Gopher Index document
** -------------------------------
*/
PRIVATE void display_index ARGS2 (
WWW_CONST char *, arg,
HTParentAnchor *,anAnchor)
{
PUTS("<H1>Searchable Gopher Index</H1> <ISINDEX>");
END_TARGET;
FREE_TARGET;
return;
}
/* Display a Gopher CSO document
** -----------------------------
*/
PRIVATE void display_cso ARGS2 (
WWW_CONST char *, arg,
HTParentAnchor *,anAnchor)
{
PUTS("<H1>Searchable CSO Phonebook</H1> <ISINDEX>");
END_TARGET;
FREE_TARGET;
return;
}
/* Parse a Gopher CSO document
** ============================
**
** Accepts an open socket to a CSO server waiting to send us
** data and puts it on the screen in a reasonable manner.
**
** Perhaps this data can be automatically linked to some
** other source as well???
**
** Hacked into place by Lou Montulli@ukanaix.cc.ukans.edu
**
*/
PRIVATE int parse_cso ARGS2 (WWW_CONST char *, arg,
HTParentAnchor *,anAnchor)
{
char ch;
char line[BIG];
char *p = line;
char *second_colon, last_char='\0';
extern int interrupted_in_htgetcharacter;
HTProgress ("Retrieving CSO search results.");
PUTS("<H1>CSO Search Results</H1>\n<PRE>");
/* start grabbing chars from the network */
while ((ch=HTGetCharacter ()) != (char)EOF)
{
if (interrupted_in_htgetcharacter)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "parse_cso: picked up interrupt in htgc\n");
#endif
(*targetClass.handle_interrupt)(target);
return HT_INTERRUPTED;
}
if (ch != '\n')
{
*p = ch; /* Put character in line */
if (p< &line[BIG-1]) p++;
}
else
{
*p++ = 0; /* Terminate line */
p = line; /* Scan it to parse it */
/* OK we now have a line in 'p' lets parse it and print it */
/* Break on line that begins with a 2. It's the end of
* data.
*/
if (*p == '2')
break;
/* lines beginning with 5 are errors,
* print them and quit
*/
if (*p == '5') {
START(HTML_H2);
PUTS(p+4);
END(HTML_H2);
break;
}
if(*p == '-') {
/* data lines look like -200:#:
* where # is the search result number and can be multiple
* digits (infinate?)
* find the second colon and check the digit to the
* left of it to see if they are diferent
* if they are then a different person is starting.
* make this line an <h2>
*/
/* find the second_colon */
second_colon = strchr( strchr(p,':')+1, ':');
if(second_colon != NULL) { /* error check */
if (*(second_colon-1) != last_char) /* print seperator */
{
END(HTML_PRE);
START(HTML_H2);
}
/* right now the record appears with the alias (first line)
* as the header and the rest as <pre> text
* It might look better with the name as the
* header and the rest as a <ul> with <li> tags
* I'm not sure whether the name field comes in any
* special order or if its even required in a record,
* so for now the first line is the header no matter
* what it is (it's almost always the alias)
* A <dl> with the first line as the <DT> and
* the rest as some form of <DD> might good also?
*/
/* print data */
PUTS(second_colon+1);
PUTS("\n");
if (*(second_colon-1) != last_char) /* end seperator */
{
END(HTML_H2);
START(HTML_PRE);
}
/* save the char before the second colon
* for comparison on the next pass
*/
last_char = *(second_colon-1) ;
} /* end if second_colon */
} /* end if *p == '-' */
} /* if end of line */
} /* Loop over characters */
if (interrupted_in_htgetcharacter)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "parse_cso: picked up interrupt in htgc\n");
#endif
(*targetClass.handle_interrupt)(target);
return HT_INTERRUPTED;
}
/* end the text block */
PUTS("\n<PRE>");
END_TARGET;
FREE_TARGET;
HTProgress ("Retrieved CSO search results.");
return 1; /* all done */
} /* end of procedure */
/* De-escape a selector into a command
** -----------------------------------
**
** The % hex escapes are converted. Otheriwse, the string is copied.
*/
PRIVATE void de_escape ARGS2(char *, command, WWW_CONST char *, selector)
{
char *p;
if (!selector)
return;
if (!command)
return;
p = strdup (selector);
HTUnEscape (p);
strcpy (command, p);
free (p);
#if 0
for (p = command; *p; p++)
if (*p == '+')
*p = ' ';
#endif
return;
}
/* Load by name HTLoadGopher
** ============
**
** Bug: No decoding of strange data types as yet.
**
*/
PUBLIC int HTLoadGopher ARGS4(
char *, arg,
HTParentAnchor *, anAnchor,
HTFormat, format_out,
HTStream*, sink)
{
char *command; /* The whole command */
int status; /* tcp return */
char gtype; /* Gopher Node type */
char * selector; /* Selector string */
int rv = 0;
if (!acceptable_inited) init_acceptable();
if (!arg)
return -3; /* Bad if no name sepcified */
if (!*arg)
return -2; /* Bad if name had zero length */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTGopher: Looking for %s\n", arg);
#endif
/* Get entity type, and selector string.
*/
{
char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
gtype = '1'; /* Default = menu */
selector = p1;
if ((*selector++=='/') && (*selector))
{ /* Skip first slash */
gtype = *selector++; /* Pick up gtype */
}
if (gtype == GOPHER_INDEX)
{
char * query;
query = strchr(selector, '?'); /* Look for search string */
if (!query || !query[1])
{ /* No search required */
target = HTML_new(anAnchor, format_out, sink);
targetClass = *target->isa;
display_index(arg, anAnchor); /* Display "cover page" */
return HT_LOADED; /* Local function only */
}
*query++ = 0; /* Skip '?' */
HTUnEscape (query);
command = malloc(strlen(selector)+ 1 + strlen(query)+ 2 + 1);
de_escape(command, selector);
strcat(command, "\t");
strcat(command, query);
}
else if (gtype == GOPHER_CSO)
{
char * query;
query = strchr(selector, '?'); /* Look for search string */
if (!query || !query[1])
{ /* No search required */
target = HTML_new(anAnchor, format_out, sink);
targetClass = *target->isa;
display_cso(arg, anAnchor); /* Display "cover page" */
return HT_LOADED; /* Local function only */
}
*query++ = 0; /* Skip '?' */
HTUnEscape (query);
command = malloc(strlen("query")+ 1 + strlen(query)+ 2 + 1);
de_escape(command, selector);
strcpy(command, "query ");
strcat(command, query);
}
else
{ /* Not index */
command = malloc(strlen(selector)+2+1);
de_escape(command, selector);
}
free(p1);
}
/* Patch security hole. */
{
char *tmp;
for (tmp = command; *tmp; tmp++)
if (*tmp == CR || *tmp == LF)
*tmp = ' ';
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "Fixed security hole: '%s'\n", command);
#endif
*tmp++ = CR;
*tmp++ = LF;
*tmp++ = 0;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "Prepared command: '%s'\n", command);
#endif
}
status = HTDoConnect (arg, "Gopher", 70, &s);
if (status == HT_INTERRUPTED)
{
/* Interrupt cleanly. */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr,
"Gopher: Interrupted on connect; recovering cleanly.\n");
#endif
HTProgress ("Connection interrupted.");
return HT_INTERRUPTED;
}
if (status<0)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"HTTPAccess: Unable to connect to remote host for `%s'.\n",
arg);
#endif
free(command);
return HT_NOT_LOADED;
}
HTInitInput(s); /* Set up input buffering */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"HTGopher: Connected, writing command `%s' to socket %d\n",
command, s);
#endif
status = NETWRITE(s, command, (int)strlen(command));
free(command);
if (status<0)
{
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTGopher: Unable to send command.\n");
#endif
NETCLOSE (s);
return HT_NOT_LOADED;
}
/* Now read the data from the socket: */
switch (gtype)
{
int compressed;
HTAtom *enc;
extern int tweak_gopher_types;
case GOPHER_MENU:
case GOPHER_INDEX:
target = HTML_new(anAnchor, format_out, sink);
targetClass = *target->isa;
rv = parse_menu(arg, anAnchor);
break;
case GOPHER_CSO:
target = HTML_new(anAnchor, format_out, sink);
targetClass = *target->isa;
rv = parse_cso(arg, anAnchor);
break;
case GOPHER_MACBINHEX:
case GOPHER_PCBINHEX:
case GOPHER_UUENCODED:
case GOPHER_BINARY:
if (!tweak_gopher_types)
rv = HTParseSocket(WWW_BINARY, format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket(HTFileFormat (arg, &enc, WWW_BINARY, &compressed),
format_out, anAnchor, s, sink, 0);
break;
case GOPHER_GIF:
case GOPHER_IMAGE:
case GOPHER_PLUS_IMAGE:
if (!tweak_gopher_types)
rv = HTParseSocket(HTAtom_for ("image/gif"),
format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket(HTFileFormat (arg, &enc, HTAtom_for ("image/gif"),
&compressed),
format_out, anAnchor, s, sink, 0);
break;
case GOPHER_SOUND:
case GOPHER_PLUS_SOUND:
if (!tweak_gopher_types)
rv = HTParseSocket(HTAtom_for ("audio/basic"),
format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket(HTFileFormat (arg, &enc,
HTAtom_for ("audio/basic"),
&compressed),
format_out, anAnchor, s, sink, 0);
break;
case GOPHER_PLUS_MOVIE:
/* Sigh..... */
if (!tweak_gopher_types)
rv = HTParseSocket(HTAtom_for ("video/mpeg"),
format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket(HTFileFormat (arg, &enc,
HTAtom_for ("video/mpeg"),
&compressed),
format_out, anAnchor, s, sink, 0);
break;
case GOPHER_HTML:
if (!tweak_gopher_types)
rv = HTParseSocket(WWW_HTML, format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket(HTFileFormat (arg, &enc, WWW_HTML, &compressed),
format_out, anAnchor, s, sink, 0);
break;
case GOPHER_TEXT:
default: /* @@ parse as plain text */
if (!tweak_gopher_types)
rv = HTParseSocket(WWW_PLAINTEXT, format_out, anAnchor, s, sink, 0);
else
rv = HTParseSocket
(HTFileFormat (arg, &enc, WWW_PLAINTEXT, &compressed),
format_out, anAnchor, s, sink, 0);
break;
} /* switch(gtype) */
NETCLOSE(s);
if (rv == HT_INTERRUPTED)
{
HTProgress ("Connection interrupted.");
return HT_INTERRUPTED;
}
else
{
return HT_LOADED;
}
}
PUBLIC HTProtocol HTGopher = { "gopher", HTLoadGopher, NULL };

16
libwww2/HTGopher.h Normal file
View File

@@ -0,0 +1,16 @@
/* GOPHER ACCESS HTGopher.h
** =============
**
** History:
** 8 Jan 92 Adapted from HTTP TBL
*/
#ifndef HTGOPHER_H
#define HTGOPHER_H
#include "HTAccess.h"
#include "HTAnchor.h"
extern HTProtocol HTGopher;
#endif /* HTGOPHER_H */

775
libwww2/HTGroup.c Normal file
View File

@@ -0,0 +1,775 @@
/* MODULE HTGroup.c
** GROUP FILE ROUTINES
**
** Contains group file parser and routines to match IP
** address templates and to find out group membership.
**
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
**
** GROUP DEFINITION GRAMMAR:
**
** string = "sequence of alphanumeric characters"
** user_name ::= string
** group_name ::= string
** group_ref ::= group_name
** user_def ::= user_name | group_ref
** user_def_list ::= user_def { ',' user_def }
** user_part = user_def | '(' user_def_list ')'
**
** templ = "sequence of alphanumeric characters and '*'s"
** ip_number_mask ::= templ '.' templ '.' templ '.' templ
** domain_name_mask ::= templ { '.' templ }
** address ::= ip_number_mask | domain_name_mask
** address_def ::= address
** address_def_list ::= address_def { ',' address_def }
** address_part = address_def | '(' address_def_list ')'
**
** item ::= [user_part] ['@' address_part]
** item_list ::= item { ',' item }
** group_def ::= item_list
** group_decl ::= group_name ':' group_def
**
*/
#include "../config.h"
#include <string.h>
#include "HTUtils.h"
#include "HTAAUtil.h"
#include "HTLex.h" /* Lexical analysor */
#include "HTGroup.h" /* Implemented here */
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/*
** Group file parser
*/
typedef HTList UserDefList;
typedef HTList AddressDefList;
typedef struct {
UserDefList * user_def_list;
AddressDefList * address_def_list;
} Item;
typedef struct {
char * name;
GroupDef * translation;
} Ref;
PRIVATE void syntax_error ARGS3(FILE *, fp,
char *, msg,
LexItem, lex_item)
{
char buffer[41];
int cnt = 0;
char ch;
while ((ch = getc(fp)) != EOF && ch != '\n')
if (cnt < 40) buffer[cnt++] = ch;
buffer[cnt] = (char)0;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "%s %d before: '%s'\nHTGroup.c: %s (got %s)\n",
"HTGroup.c: Syntax error in rule file at line",
lex_line, buffer, msg, lex_verbose(lex_item));
#endif
lex_line++;
}
PRIVATE AddressDefList *parse_address_part ARGS1(FILE *, fp)
{
AddressDefList *address_def_list = NULL;
LexItem lex_item;
BOOL only_one = NO;
lex_item = lex(fp);
if (lex_item == LEX_ALPH_STR || lex_item == LEX_TMPL_STR)
only_one = YES;
else if (lex_item != LEX_OPEN_PAREN ||
((lex_item = lex(fp)) != LEX_ALPH_STR &&
lex_item != LEX_TMPL_STR)) {
syntax_error(fp, "Expecting a single address or '(' beginning list",
lex_item);
return NULL;
}
address_def_list = HTList_new();
for(;;) {
Ref *ref = (Ref*)malloc(sizeof(Ref));
ref->name = NULL;
ref->translation = NULL;
StrAllocCopy(ref->name, lex_buffer);
HTList_addObject(address_def_list, (void*)ref);
if (only_one || (lex_item = lex(fp)) != LEX_ITEM_SEP)
break;
/*
** Here lex_item == LEX_ITEM_SEP; after item separator it
** is ok to have one or more newlines (LEX_REC_SEP) and
** they are ignored (continuation line).
*/
do {
lex_item = lex(fp);
} while (lex_item == LEX_REC_SEP);
if (lex_item != LEX_ALPH_STR && lex_item != LEX_TMPL_STR) {
syntax_error(fp, "Expecting an address template", lex_item);
HTList_delete(address_def_list);
return NULL;
}
}
if (!only_one && lex_item != LEX_CLOSE_PAREN) {
HTList_delete(address_def_list);
syntax_error(fp, "Expecting ')' closing address list", lex_item);
return NULL;
}
return address_def_list;
}
PRIVATE UserDefList *parse_user_part ARGS1(FILE *, fp)
{
UserDefList *user_def_list = NULL;
LexItem lex_item;
BOOL only_one = NO;
lex_item = lex(fp);
if (lex_item == LEX_ALPH_STR)
only_one = YES;
else if (lex_item != LEX_OPEN_PAREN ||
(lex_item = lex(fp)) != LEX_ALPH_STR) {
syntax_error(fp, "Expecting a single name or '(' beginning list",
lex_item);
return NULL;
}
user_def_list = HTList_new();
for (;;) {
Ref *ref = (Ref*)malloc(sizeof(Ref));
ref->name = NULL;
ref->translation = NULL;
StrAllocCopy(ref->name, lex_buffer);
HTList_addObject(user_def_list, (void*)ref);
if (only_one || (lex_item = lex(fp)) != LEX_ITEM_SEP)
break;
/*
** Here lex_item == LEX_ITEM_SEP; after item separator it
** is ok to have one or more newlines (LEX_REC_SEP) and
** they are ignored (continuation line).
*/
do {
lex_item = lex(fp);
} while (lex_item == LEX_REC_SEP);
if (lex_item != LEX_ALPH_STR) {
syntax_error(fp, "Expecting user or group name", lex_item);
HTList_delete(user_def_list);
return NULL;
}
}
if (!only_one && lex_item != LEX_CLOSE_PAREN) {
HTList_delete(user_def_list);
syntax_error(fp, "Expecting ')' closing user/group list", lex_item);
return NULL;
}
return user_def_list;
}
PRIVATE Item *parse_item ARGS1(FILE *, fp)
{
Item *item = NULL;
UserDefList *user_def_list = NULL;
AddressDefList *address_def_list = NULL;
LexItem lex_item;
lex_item = lex(fp);
if (lex_item == LEX_ALPH_STR || lex_item == LEX_OPEN_PAREN) {
unlex(lex_item);
user_def_list = parse_user_part(fp);
lex_item = lex(fp);
}
if (lex_item == LEX_AT_SIGN) {
lex_item = lex(fp);
if (lex_item == LEX_ALPH_STR || lex_item == LEX_TMPL_STR ||
lex_item == LEX_OPEN_PAREN) {
unlex(lex_item);
address_def_list = parse_address_part(fp);
}
else {
if (user_def_list) HTList_delete(user_def_list); /* @@@@ */
syntax_error(fp, "Expected address part (single address or list)",
lex_item);
return NULL;
}
}
else unlex(lex_item);
if (!user_def_list && !address_def_list) {
syntax_error(fp, "Empty item not allowed", lex_item);
return NULL;
}
item = (Item*)malloc(sizeof(Item));
item->user_def_list = user_def_list;
item->address_def_list = address_def_list;
return item;
}
PRIVATE ItemList *parse_item_list ARGS1(FILE *, fp)
{
ItemList *item_list = HTList_new();
Item *item;
LexItem lex_item;
for(;;) {
if (!(item = parse_item(fp))) {
HTList_delete(item_list); /* @@@@ */
return NULL;
}
HTList_addObject(item_list, (void*)item);
lex_item = lex(fp);
if (lex_item != LEX_ITEM_SEP) {
unlex(lex_item);
return item_list;
}
/*
** Here lex_item == LEX_ITEM_SEP; after item separator it
** is ok to have one or more newlines (LEX_REC_SEP) and
** they are ignored (continuation line).
*/
do {
lex_item = lex(fp);
} while (lex_item == LEX_REC_SEP);
unlex(lex_item);
}
}
PUBLIC GroupDef *HTAA_parseGroupDef ARGS1(FILE *, fp)
{
ItemList *item_list = NULL;
GroupDef *group_def = NULL;
LexItem lex_item;
if (!(item_list = parse_item_list(fp))) {
return NULL;
}
group_def = (GroupDef*)malloc(sizeof(GroupDef));
group_def->group_name = NULL;
group_def->item_list = item_list;
if ((lex_item = lex(fp)) != LEX_REC_SEP) {
syntax_error(fp, "Garbage after group definition", lex_item);
}
return group_def;
}
PRIVATE GroupDef *parse_group_decl ARGS1(FILE *, fp)
{
char *group_name = NULL;
GroupDef *group_def = NULL;
LexItem lex_item;
do {
lex_item = lex(fp);
} while (lex_item == LEX_REC_SEP); /* Ignore empty lines */
if (lex_item != LEX_ALPH_STR) {
if (lex_item != LEX_EOF)
syntax_error(fp, "Expecting group name", lex_item);
return NULL;
}
StrAllocCopy(group_name, lex_buffer);
if (LEX_FIELD_SEP != (lex_item = lex(fp))) {
syntax_error(fp, "Expecting field separator", lex_item);
free(group_name);
return NULL;
}
if (!(group_def = HTAA_parseGroupDef(fp))) {
free(group_name);
return NULL;
}
group_def->group_name = group_name;
return group_def;
}
/*
** Group manipulation routines
*/
PRIVATE GroupDef *find_group_def ARGS2(GroupDefList *, group_list,
WWW_CONST char *, group_name)
{
if (group_list && group_name) {
GroupDefList *cur = group_list;
GroupDef *group_def;
while (NULL != (group_def = (GroupDef*)HTList_nextObject(cur))) {
if (!strcmp(group_name, group_def->group_name)) {
return group_def;
}
}
}
return NULL;
}
PUBLIC void HTAA_resolveGroupReferences ARGS2(GroupDef *, group_def,
GroupDefList *, group_def_list)
{
if (group_def && group_def->item_list && group_def_list) {
ItemList *cur1 = group_def->item_list;
Item *item;
while (NULL != (item = (Item*)HTList_nextObject(cur1))) {
UserDefList *cur2 = item->user_def_list;
Ref *ref;
while (NULL != (ref = (Ref*)HTList_nextObject(cur2)))
ref->translation = find_group_def(group_def_list, ref->name);
/* Does NOT translate address_def_list */
}
}
}
PRIVATE void add_group_def ARGS2(GroupDefList *, group_def_list,
GroupDef *, group_def)
{
HTAA_resolveGroupReferences(group_def, group_def_list);
HTList_addObject(group_def_list, (void*)group_def);
}
PRIVATE GroupDefList *parse_group_file ARGS1(FILE *, fp)
{
GroupDefList *group_def_list = HTList_new();
GroupDef *group_def;
while (NULL != (group_def = parse_group_decl(fp)))
add_group_def(group_def_list, group_def);
return group_def_list;
}
/*
** Trace functions
*/
PRIVATE void print_item ARGS1(Item *, item)
{
if (!item)
fprintf(stderr, "\tNULL-ITEM\n");
else {
UserDefList *cur1 = item->user_def_list;
AddressDefList *cur2 = item->address_def_list;
Ref *user_ref = (Ref*)HTList_nextObject(cur1);
Ref *addr_ref = (Ref*)HTList_nextObject(cur2);
if (user_ref) {
fprintf(stderr, "\t[%s%s", user_ref->name,
(user_ref->translation ? "*REF*" : ""));
while (NULL != (user_ref = (Ref*)HTList_nextObject(cur1)))
fprintf(stderr, "; %s%s", user_ref->name,
(user_ref->translation ? "*REF*" : ""));
fprintf(stderr, "] ");
} else fprintf(stderr, "\tANYBODY ");
if (addr_ref) {
fprintf(stderr, "@ [%s", addr_ref->name);
while (NULL != (addr_ref = (Ref*)HTList_nextObject(cur2)))
fprintf(stderr, "; %s", addr_ref->name);
fprintf(stderr, "]\n");
} else fprintf(stderr, "@ ANYADDRESS\n");
}
}
PRIVATE void print_item_list ARGS1(ItemList *, item_list)
{
ItemList *cur = item_list;
Item *item;
if (!item_list)
fprintf(stderr, "EMPTY");
else while (NULL != (item = (Item*)HTList_nextObject(cur)))
print_item(item);
}
PUBLIC void HTAA_printGroupDef ARGS1(GroupDef *, group_def)
{
if (!group_def) {
fprintf(stderr, "\nNULL RECORD\n");
return;
}
fprintf(stderr, "\nGroup %s:\n",
(group_def->group_name ? group_def->group_name : "NULL"));
print_item_list(group_def->item_list);
fprintf(stderr, "\n");
}
PRIVATE void print_group_def_list ARGS1(GroupDefList *, group_list)
{
GroupDefList *cur = group_list;
GroupDef *group_def;
while (NULL != (group_def = (GroupDef*)HTList_nextObject(cur)))
HTAA_printGroupDef(group_def);
}
/*
** IP address template matching
*/
/* PRIVATE part_match()
** MATCH ONE PART OF INET ADDRESS AGAIST
** A PART OF MASK (inet address has 4 parts)
** ON ENTRY:
** tcur pointer to the beginning of template part.
** icur pointer to the beginning of actual inet
** number part.
**
** ON EXIT:
** returns YES, if match.
*/
PRIVATE BOOL part_match ARGS2(WWW_CONST char *, tcur,
WWW_CONST char *, icur)
{
char required[4];
char actual[4];
WWW_CONST char *cur;
int cnt;
if (!tcur || !icur) return NO;
cur=tcur;
cnt=0;
while (cnt < 3 && *cur && *cur != '.')
required[cnt++] = *(cur++);
required[cnt] = (char)0;
cur=icur;
cnt=0;
while (cnt < 3 && *cur && *cur != '.')
actual[cnt++] = *(cur++);
actual[cnt] = (char)0;
#ifndef DISABLE_TRACE
if (www2Trace) {
BOOL status = HTAA_templateMatch(required, actual);
fprintf(stderr, "part_match: req: '%s' act: '%s' match: %s\n",
required, actual, (status ? "yes" : "no"));
return status;
}
#endif
return HTAA_templateMatch(required, actual);
}
/* PRIVATE ip_number_match()
** MATCH INET NUMBER AGAINST AN INET NUMBER MASK
** ON ENTRY:
** template mask to match agaist, e.g. 128.141.*.*
** inet_addr actual inet address, e.g. 128.141.201.74
**
** ON EXIT:
** returns YES, if match; NO, if not.
*/
PRIVATE BOOL ip_number_match ARGS2(WWW_CONST char *, template,
WWW_CONST char *, inet_addr)
{
WWW_CONST char *tcur = template;
WWW_CONST char *icur = inet_addr;
int cnt;
for (cnt=0; cnt<4; cnt++) {
if (!tcur || !icur || !part_match(tcur, icur))
return NO;
if (NULL != (tcur = strchr(tcur, '.'))) tcur++;
if (NULL != (icur = strchr(icur, '.'))) icur++;
}
return YES;
}
/* PRIVATE is_domain_mask()
** DETERMINE IF A GIVEN MASK IS A
** DOMAIN NAME MASK OR AN INET NUMBER MASK
** ON ENTRY:
** mask either a domain name mask,
** e.g.
** *.cern.ch
**
** or an inet number mask,
** e.g.
** 128.141.*.*
**
** ON EXIT:
** returns YES, if mask is a domain name mask.
** NO, if it is an inet number mask.
*/
PRIVATE BOOL is_domain_mask ARGS1(WWW_CONST char *, mask)
{
WWW_CONST char *cur = mask;
if (!mask) return NO;
while (*cur) {
if (*cur != '.' && *cur != '*' && (*cur < '0' || *cur > '9'))
return YES; /* Even one non-digit makes it a domain name mask */
cur++;
}
return NO; /* All digits and dots, so it is an inet number mask */
}
/* PRIVATE ip_mask_match()
** MATCH AN IP NUMBER MASK OR IP NAME MASK
** AGAINST ACTUAL IP NUMBER OR IP NAME
**
** ON ENTRY:
** mask mask. Mask may be either an inet number
** mask or a domain name mask,
** e.g.
** 128.141.*.*
** or
** *.cern.ch
**
** ip_number IP number of connecting host.
** ip_name IP name of the connecting host.
**
** ON EXIT:
** returns YES, if hostname/internet number
** matches the mask.
** NO, if no match (no fire).
*/
PRIVATE BOOL ip_mask_match ARGS3(WWW_CONST char *, mask,
WWW_CONST char *, ip_number,
WWW_CONST char *, ip_name)
{
if (mask && (ip_number || ip_name)) {
if (is_domain_mask(mask)) {
if (HTAA_templateMatch(mask, ip_name))
return YES;
}
else {
if (ip_number_match(mask, ip_number))
return YES;
}
}
return NO;
}
PRIVATE BOOL ip_in_def_list ARGS3(AddressDefList *, address_def_list,
char *, ip_number,
char *, ip_name)
{
if (address_def_list && (ip_number || ip_name)) {
AddressDefList *cur = address_def_list;
Ref *ref;
while (NULL != (ref = (Ref*)HTList_nextObject(cur))) {
/* Value of ref->translation is ignored, i.e. */
/* no recursion for ip address tamplates. */
if (ip_mask_match(ref->name, ip_number, ip_name))
return YES;
}
}
return NO;
}
/*
** Group file cached reading
*/
typedef struct {
char * group_filename;
GroupDefList * group_list;
} GroupCache;
typedef HTList GroupCacheList;
PRIVATE GroupCacheList *group_cache_list = NULL;
PUBLIC GroupDefList *HTAA_readGroupFile ARGS1(WWW_CONST char *, filename)
{
FILE *fp;
GroupCache *group_cache;
if (!group_cache_list)
group_cache_list = HTList_new();
else {
GroupCacheList *cur = group_cache_list;
while (NULL != (group_cache = (GroupCache*)HTList_nextObject(cur))) {
if (!strcmp(filename, group_cache->group_filename)) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s '%s' %s\n",
"HTAA_readGroupFile: group file",
filename, "already found in cache");
#endif
return group_cache->group_list;
} /* if cache match */
} /* while cached files remain */
} /* cache exists */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTAA_readGroupFile: reading group file `%s'\n",
filename);
#endif
if (!(fp = fopen(filename, "r"))) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s '%s'\n",
"HTAA_readGroupFile: unable to open group file",
filename);
#endif
return NULL;
}
if (!(group_cache = (GroupCache*)malloc(sizeof(GroupCache))))
outofmem(__FILE__, "HTAA_readGroupFile");
group_cache->group_filename = NULL;
StrAllocCopy(group_cache->group_filename, filename);
group_cache->group_list = parse_group_file(fp);
HTList_addObject(group_cache_list, (void*)group_cache);
fclose(fp);
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr, "Read group file '%s', results follow:\n", filename);
print_group_def_list(group_cache->group_list);
}
#endif
return group_cache->group_list;
}
/* PUBLIC HTAA_userAndInetInGroup()
** CHECK IF USER BELONGS TO TO A GIVEN GROUP
** AND THAT THE CONNECTION COMES FROM AN
** ADDRESS THAT IS ALLOWED BY THAT GROUP
** ON ENTRY:
** group the group definition structure.
** username connecting user.
** ip_number browser host IP number, optional.
** ip_name browser host IP name, optional.
** However, one of ip_number or ip_name
** must be given.
** ON EXIT:
** returns HTAA_IP_MASK, if IP address mask was
** reason for failing.
** HTAA_NOT_MEMBER, if user does not belong
** to the group.
** HTAA_OK if both IP address and user are ok.
*/
PUBLIC HTAAFailReasonType HTAA_userAndInetInGroup ARGS4(GroupDef *, group,
char *, username,
char *, ip_number,
char *, ip_name)
{
HTAAFailReasonType reason = HTAA_NOT_MEMBER;
if (group && username) {
ItemList *cur1 = group->item_list;
Item *item;
while (NULL != (item = (Item*)HTList_nextObject(cur1))) {
if (!item->address_def_list || /* Any address allowed */
ip_in_def_list(item->address_def_list, ip_number, ip_name)) {
if (!item->user_def_list) /* Any user allowed */
return HTAA_OK;
else {
UserDefList *cur2 = item->user_def_list;
Ref *ref;
while (NULL != (ref = (Ref*)HTList_nextObject(cur2))) {
if (ref->translation) { /* Group, check recursively */
reason = HTAA_userAndInetInGroup(ref->translation,
username,
ip_number,ip_name);
if (reason == HTAA_OK)
return HTAA_OK;
}
else { /* Username, check directly */
if (username && *username &&
0==strcmp(ref->name, username))
return HTAA_OK;
}
} /* Every user/group name in this group */
} /* search for username */
} /* IP address ok */
else {
return HTAA_IP_MASK;
}
} /* while items in group */
} /* valid parameters */
return reason; /* No match, or invalid parameters */
}
PUBLIC void GroupDef_delete ARGS1(GroupDef *, group_def)
{
if (group_def) {
FREE(group_def->group_name);
if (group_def->item_list)
HTList_delete(group_def->item_list); /* @@@@ */
free(group_def);
}
}

184
libwww2/HTGroup.h Normal file
View File

@@ -0,0 +1,184 @@
/* GROUP FILE ROUTINES
*/
#ifndef HTGROUP_H
#define HTGROUP_H
#include "HTUtils.h"
#include "HTList.h"
#ifdef SHORT_NAMES
#define HTAApGrD HTAA_parseGroupDef
#define HTAArGrR HTAA_resolveGroupReferences
#define HTAApGrD HTAA_printGroupDef
#define HTAAGD_d GroupDef_delete
#define HTAAuIIG HTAA_userAndInetInGroup
#endif /* SHORT_NAMES */
typedef HTList GroupDefList;
typedef HTList ItemList;
typedef struct {
char * group_name;
ItemList * item_list;
} GroupDef;
/*
** Access Authorization failure reasons
*/
typedef enum {
HTAA_OK, /* 200 OK */
HTAA_NO_AUTH, /* 401 Unauthorized, not authenticated */
HTAA_NOT_MEMBER, /* 401 Unauthorized, not authorized */
HTAA_IP_MASK, /* 403 Forbidden by IP mask */
HTAA_BY_RULE, /* 403 Forbidden by rule */
HTAA_NO_ACL, /* 403 Forbidden, ACL non-existent */
HTAA_NO_ENTRY, /* 403 Forbidden, no ACL entry */
HTAA_SETUP_ERROR, /* 403 Forbidden, server setup error */
HTAA_NOT_FOUND /* 404 Not found, or read protected */
} HTAAFailReasonType;
/*
Group definition grammar
string
"sequence of alphanumeric characters"
user_name
string
group_name
string
group_ref
group_name
user_def
user_name | group_ref
user_def_list
user_def { ',' user_def }
user_part
user_def | '(' user_def_list ')'
templ
"sequence of alphanumeric characters and '*'s"
ip_number_mask
templ '.' templ '.' templ '.' templ
domain_name_mask
templ { '.' templ }
address
ip_number_mask | domain_name_mask
address_def
address
address_def_list
address_def { ',' address_def }
address_part
address_def | '(' address_def_list ')'
item
[user_part] ['@' address_part]
item_list
item { ',' item }
group_def
item_list
group_decl
group_name ':' group_def
PARSE GROUP DEFINITION
*/
PUBLIC GroupDef *HTAA_parseGroupDef PARAMS((FILE * fp));
/*
Fill in Pointers to referenced Group Definitions in a Group Definition
References to groups (by their name) are resolved from group_def_list and pointers to
those structures are added to group_def.
*/
PUBLIC void HTAA_resolveGroupReferences PARAMS((GroupDef * group_def,
GroupDefList * group_def_list));
/*
Read Group File (and do caching)
If group file is already in cache returns a pointer to previously read group definition
list.
*/
PUBLIC GroupDefList *HTAA_readGroupFile PARAMS((WWW_CONST char * filename));
/*
Delete Group Definition
Groups in cache should never be freed by this function. This should only be used to
free group definitions read by HTAA_parseGroupDef.
*/
PUBLIC void GroupDef_delete PARAMS((GroupDef * group_def));
/*
Print Out Group Definition (for trace purposes)
*/
PUBLIC void HTAA_printGroupDef PARAMS((GroupDef * group_def));
/*
Does a User Belong to a Given Set of Groups
This function checks both the username and the internet address.
*/
/* PUBLIC HTAA_userAndInetInGroup()
** CHECK IF USER BELONGS TO TO A GIVEN GROUP
** AND THAT THE CONNECTION COMES FROM AN
** ADDRESS THAT IS ALLOWED BY THAT GROUP
** ON ENTRY:
** group the group definition structure.
** username connecting user.
** ip_number browser host IP number, optional.
** ip_name browser host IP name, optional.
** However, one of ip_number or ip_name
** must be given.
** ON EXIT:
** returns HTAA_IP_MASK, if IP address mask was
** reason for failing.
** HTAA_NOT_MEMBER, if user does not belong
** to the group.
** HTAA_OK if both IP address and user are ok.
*/
PUBLIC HTAAFailReasonType HTAA_userAndInetInGroup PARAMS((GroupDef * group,
char * username,
char * ip_number,
char * ip_name));
/*
*/
#endif /* not HTGROUP_H */
/*
End of file HTGroup.h. */

70
libwww2/HTIcon.c Normal file
View File

@@ -0,0 +1,70 @@
/*
** Author: Charles Henrich (henrich@crh.cl.msu.edu) October 2, 1993
**
** This routine takes two parameters, Format (as returned by HTFileFormat)
** and a default icon type. The type is the first half of the MIME type field
** (i.e. image from image/jpeg). If the icon type cannot be determined from
** the format or from the default, then the unknown icon is returned.
**
** Note: This routine gurantee's to return something!
**
*/
#include "../config.h"
#include "HTFile.h"
#include "HTAtom.h"
struct typemap
{
char *format;
char *image;
};
struct typemap type_map[] =
{
{"image", "internal-gopher-image"},
{"text", "internal-gopher-text"},
{"audio", "internal-gopher-sound"},
{"application", "internal-gopher-binary"},
{"message", "internal-gopher-text"},
{"video", "internal-gopher-movie"},
{"directory", "internal-gopher-menu"},
{"unknown", "internal-gopher-unknown"},
{"EOFEOF", "EOFEOF"}
};
char *HTgeticonname(HTFormat format, char *defaultformat)
{
int count;
char *ptr;
char subtype[128];
if(format != NULL)
{
strcpy(subtype, format->name);
ptr=strchr(subtype,'/');
if(ptr != NULL)
*ptr = '\0';
}
else
{
subtype[0] = '\0';
}
ptr = NULL;
for(count = 0;strcmp(type_map[count].image,"EOFEOF") != 0; count++)
{
if(strcmp(type_map[count].format, subtype) == 0)
return type_map[count].image;
if(strcmp(type_map[count].format, defaultformat) == 0)
ptr = type_map[count].image;
}
if(ptr != NULL)
return ptr;
return "internal-gopher-unknown";
}

596
libwww2/HTInit.c Normal file
View File

@@ -0,0 +1,596 @@
#include "../config.h"
#include "HTInit.h"
#include "HTML.h"
#include "HTPlain.h"
#include "HTMosaicHTML.h"
#include "HTMLGen.h"
#include "HTFile.h"
#include "HTFormat.h"
#include "HTMIME.h"
#include "HTWSRC.h"
#include "tcp.h"
#include "HTUtils.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* Reread config files. */
PUBLIC void HTReInit NOARGS
{
if (HTPresentations)
{
HTList_delete (HTPresentations);
HTPresentations = 0;
}
HTFormatInit ();
if (HTSuffixes)
{
HTList_delete (HTSuffixes);
HTSuffixes = 0;
}
HTFileInit ();
return;
}
PUBLIC void HTFormatInit NOARGS
{
extern int use_default_type_map;
extern char *global_type_map;
extern char *personal_type_map;
extern int have_hdf;
/* Conversions aren't customizable. */
HTSetConversion("www/mime", "*", HTMIMEConvert, 1.0, 0.0, 0.0);
/* Wonder what HTML will end up as? */
HTSetConversion("text/html", "www/present", HTMosaicHTMLPresent, 1.0, 0.0, 0.0);
HTSetConversion("text/x-html", "www/present", HTMosaicHTMLPresent, 1.0, 0.0, 0.0);
HTSetConversion("application/html", "www/present", HTMosaicHTMLPresent, 1.0, 0.0, 0.0);
HTSetConversion("application/x-html", "www/present", HTMosaicHTMLPresent, 1.0, 0.0, 0.0);
HTSetConversion("text/plain", "www/present", HTPlainPresent, 1.0, 0.0, 0.0);
HTSetConversion("application/x-wais-source", "*", HTWSRCConvert, 1.0, 0.0, 0.0);
/* These should override everything else. */
HTLoadTypesConfigFile (personal_type_map);
/* These should override the default types as necessary. */
HTLoadTypesConfigFile (global_type_map);
/* These should always be installed if we have internal support;
can be overridden by users. */
if (have_hdf)
{
HTSetPresentation("application/x-hdf", "mosaic-internal-reference",
1.0, 3.0, 0.0);
HTSetPresentation("application/x-netcdf", "mosaic-internal-reference",
1.0, 3.0, 0.0);
/* Jumping the gun, but still... */
HTSetPresentation("application/hdf", "mosaic-internal-reference",
1.0, 3.0, 0.0);
HTSetPresentation("application/netcdf", "mosaic-internal-reference",
1.0, 3.0, 0.0);
}
if (use_default_type_map)
{
#if defined(__sgi)
HTSetPresentation("audio/basic", "sfplay %s", 1.0, 3.0, 0.0);
HTSetPresentation("audio/x-aiff", "sfplay %s", 1.0, 3.0, 0.0);
#else /* not __sgi */
#if defined(ultrix) || defined(__alpha)
HTSetPresentation("audio/basic", "aplay %s", 1.0, 3.0, 0.0);
HTSetPresentation("audio/x-aiff", "aplay %s", 1.0, 3.0, 0.0);
#else /* not ultrix or __alpha */
HTSetPresentation("audio/basic", "showaudio %s", 1.0, 3.0, 0.0);
HTSetPresentation("audio/x-aiff", "showaudio %s", 1.0, 3.0, 0.0);
#endif /* not ultrix or __alpha */
#endif /* not __sgi */
HTSetPresentation("image/gif", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/jpeg", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/png", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-png", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/tiff", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-portable-anymap", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-portable-bitmap", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-portable-graymap", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-portable-pixmap", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-rgb", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/rgb", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-xbitmap", "xv %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-xpixmap", "xv %s", 1.0, 3.0, 0.0); /* ?? */
HTSetPresentation("image/xwd", "xwud -in %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-xwd", "xwud -in %s", 1.0, 3.0, 0.0);
HTSetPresentation("image/x-xwindowdump", "xwud -in %s", 1.0, 3.0, 0.0);
HTSetPresentation("video/mpeg", "mpeg_play %s", 1.0, 3.0, 0.0);
#ifdef __sgi
HTSetPresentation("video/quicktime", "movieplayer -f %s", 1.0, 3.0, 0.0); /* sgi */
HTSetPresentation("video/x-sgi-movie", "movieplayer -f %s", 1.0, 3.0, 0.0); /* sgi */
#endif
HTSetPresentation("application/postscript", "ghostview %s", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-dvi", "xdvi %s", 1.0, 3.0, 0.0);
HTSetPresentation("message/rfc822",
"xterm -e metamail %s", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-latex", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-tex", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-texinfo", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-troff", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-troff-man", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-troff-me", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("application/x-troff-ms", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("text/richtext", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("text/tab-separated-values", "mosaic-internal-present", 1.0, 3.0, 0.0);
HTSetPresentation("text/x-setext", "mosaic-internal-present", 1.0, 3.0, 0.0);
}
/* Fallthrough clauses. */
HTSetPresentation ("*/*", "mosaic-internal-dump", 1.0, 3.0, 0.0);
HTSetPresentation ("*", "mosaic-internal-dump", 1.0, 3.0, 0.0);
}
/* Some of the following is taken from: */
/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
Permission to use, copy, modify, and distribute this material
for any purpose and without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies, and that the name of Bellcore not be
used in advertising or publicity pertaining to this
material without the specific, prior written permission
of an authorized representative of Bellcore. BELLCORE
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
*/
/******************************************************
Metamail -- A tool to help diverse mail readers
cope with diverse multimedia mail formats.
Author: Nathaniel S. Borenstein, Bellcore
******************************************************* */
struct MailcapEntry {
char *contenttype;
char *command;
int needsterminal;
};
#define LINE_BUF_SIZE 2000
static char *GetCommand(char *s, char **t)
{
char *s2;
int quoted = 0;
/* marca -- added + 1 for error case -- oct 24, 1993. */
s2 = malloc(strlen(s)*2 + 1); /* absolute max, if all % signs */
*t = s2;
while (s && *s) {
if (quoted) {
if (*s == '%') *s2++ = '%'; /* Quote through next level, ugh! */
*s2++ = *s++;
quoted = 0;
} else {
if (*s == ';') {
*s2 = 0;
return(++s);
}
if (*s == '\\') {
quoted = 1;
++s;
} else {
*s2++ = *s++;
}
}
}
*s2 = 0;
return(NULL);
}
static char *Cleanse(char *s) /* no leading or trailing space, all lower case */
{
char *tmp, *news;
/* strip leading white space */
while (*s && isspace((unsigned char) *s)) ++s;
news = s;
/* put in lower case */
for (tmp=s; *tmp; ++tmp) {
*tmp = TOLOWER ((unsigned char)*tmp);
}
/* strip trailing white space */
while (*--tmp && isspace((unsigned char) *tmp)) *tmp = 0;
return(news);
}
static ProcessMailcapEntry(FILE *fp, struct MailcapEntry *mc)
{
int rawentryalloc = 2000, len;
char *rawentry, *s, *t, *LineBuf;
LineBuf = malloc(LINE_BUF_SIZE);
rawentry = malloc(1 + rawentryalloc);
*rawentry = 0;
while (fgets(LineBuf, LINE_BUF_SIZE, fp)) {
if (LineBuf[0] == '#') continue;
len = strlen(LineBuf);
if (LineBuf[len-1] == '\n') LineBuf[--len] = 0;
if ((len + strlen(rawentry)) > rawentryalloc) {
rawentryalloc += 2000;
rawentry = realloc(rawentry, rawentryalloc+1);
}
if (len > 0 && LineBuf[len-1] == '\\') {
LineBuf[len-1] = 0;
strcat(rawentry, LineBuf);
} else {
strcat(rawentry, LineBuf);
break;
}
}
free(LineBuf);
for (s=rawentry; *s && isspace((unsigned char) *s); ++s) ;
if (!*s) {
/* totally blank entry -- quietly ignore */
free(rawentry);
return(0);
}
s = strchr(rawentry, ';');
if (!s) {
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "Ignoring invalid mailcap entry: %s\n", rawentry);
#endif
free(rawentry);
return(0);
}
*s++ = 0;
mc->needsterminal = 0;
mc->contenttype = malloc(1+strlen(rawentry));
strcpy(mc->contenttype, rawentry);
t = GetCommand(s, &mc->command);
if (!t) {
free(rawentry);
goto do_presentation;
}
while (s && *s && isspace((unsigned char) *s)) ++s;
s = t;
while (s) {
char *arg, *eq;
t = GetCommand(s, &arg);
eq = strchr(arg, '=');
if (eq) *eq++ = 0;
/* Error check added by marca, oct 24 1993. */
if (arg && *arg)
arg = Cleanse(arg);
if (!strcmp(arg, "needsterminal")) {
mc->needsterminal = 1;
}
s = t;
}
free(rawentry);
do_presentation:
HTSetPresentation(mc->contenttype, mc->command, 1.0, 3.0, 0.0);
return(1);
}
static ProcessMailcapFile(char *file)
{
struct MailcapEntry mc;
FILE *fp;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "Loading types config file '%s'\n",
file);
#endif
fp = fopen(file, "r");
while (fp && !feof(fp)) {
ProcessMailcapEntry(fp, &mc);
}
if (fp) fclose(fp);
return(-1);
}
int HTLoadTypesConfigFile (char *fn)
{
return ProcessMailcapFile (fn);
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* Define a basic set of suffixes
** ------------------------------
**
** The LAST suffix for a type is that used for temporary files
** of that type.
** The quality is an apriori bias as to whether the file should be
** used. Not that different suffixes can be used to represent files
** which are of the same format but are originals or regenerated,
** with different values.
*/
PUBLIC void HTFileInit NOARGS
{
extern int use_default_extension_map;
extern char *global_extension_map;
extern char *personal_extension_map;
if (use_default_extension_map)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "@@@ Using default extension map\n");
#endif
HTSetSuffix(".uu", "application/octet-stream", "binary", 1.0); /* xtra */
HTSetSuffix(".saveme", "application/octet-stream", "binary", 1.0); /* xtra */
HTSetSuffix(".dump", "application/octet-stream", "binary", 1.0); /* xtra */
HTSetSuffix(".hqx", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".arc", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".o", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".a", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".bin", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".exe", "application/octet-stream", "binary", 1.0);
/* Temporary only. */
HTSetSuffix(".z", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".gz", "application/octet-stream", "binary", 1.0);
HTSetSuffix(".oda", "application/oda", "binary", 1.0);
HTSetSuffix(".pdf", "application/pdf", "binary", 1.0);
HTSetSuffix(".eps", "application/postscript", "binary", 1.0);
HTSetSuffix(".ai", "application/postscript", "binary", 1.0);
HTSetSuffix(".ps", "application/postscript", "binary", 1.0);
HTSetSuffix(".rtf", "application/rtf", "binary", 1.0);
HTSetSuffix(".dvi","application/x-dvi", "binary", 1.0);
HTSetSuffix(".hdf","application/x-hdf", "binary", 1.0);
HTSetSuffix(".latex", "application/x-latex", "binary", 1.0);
HTSetSuffix(".cdf","application/x-netcdf", "binary", 1.0);
HTSetSuffix(".nc","application/x-netcdf", "binary", 1.0);
HTSetSuffix(".tex", "application/x-tex", "binary", 1.0);
HTSetSuffix(".texinfo", "application/x-texinfo", "binary", 1.0);
HTSetSuffix(".texi", "application/x-texinfo", "binary", 1.0);
HTSetSuffix(".t", "application/x-troff", "binary", 1.0);
HTSetSuffix(".tr", "application/x-troff", "binary", 1.0);
HTSetSuffix(".roff", "application/x-troff", "binary", 1.0);
HTSetSuffix(".man", "application/x-troff-man", "binary", 1.0);
HTSetSuffix(".me", "application/x-troff-me", "binary", 1.0);
HTSetSuffix(".ms", "application/x-troff-ms", "binary", 1.0);
HTSetSuffix(".src", "application/x-wais-source", "binary", 1.0);
HTSetSuffix(".wsrc", "application/x-wais-source", "binary", 1.0); /* xtra */
HTSetSuffix(".zip", "application/zip", "binary", 1.0);
HTSetSuffix(".bcpio", "application/x-bcpio", "binary", 1.0);
HTSetSuffix(".cpio", "application/x-cpio", "binary", 1.0);
HTSetSuffix(".gtar", "application/x-gtar", "binary", 1.0);
HTSetSuffix(".shar", "application/x-shar", "binary", 1.0);
HTSetSuffix(".sh", "application/x-shar", "binary", 1.0); /* xtra */
HTSetSuffix(".sv4cpio", "application/x-sv4cpio", "binary", 1.0);
HTSetSuffix(".sv4crc", "application/x-sv4crc", "binary", 1.0);
HTSetSuffix(".tar", "application/x-tar", "binary", 1.0);
HTSetSuffix(".ustar", "application/x-ustar", "binary", 1.0);
HTSetSuffix(".snd", "audio/basic", "binary", 1.0);
HTSetSuffix(".au", "audio/basic", "binary", 1.0);
HTSetSuffix(".aifc", "audio/x-aiff", "binary", 1.0);
HTSetSuffix(".aif", "audio/x-aiff", "binary", 1.0);
HTSetSuffix(".aiff", "audio/x-aiff", "binary", 1.0);
HTSetSuffix(".wav", "audio/x-wav", "binary", 1.0);
HTSetSuffix(".gif", "image/gif", "binary", 1.0);
HTSetSuffix(".png", "image/png", "binary", 1.0);
HTSetSuffix(".ief", "image/ief", "binary", 1.0);
HTSetSuffix(".jfif","image/jpeg", "binary", 1.0); /* xtra */
HTSetSuffix(".jfif-tbnl","image/jpeg", "binary", 1.0); /* xtra */
HTSetSuffix(".jpe", "image/jpeg", "binary", 1.0);
HTSetSuffix(".jpg", "image/jpeg", "binary", 1.0);
HTSetSuffix(".jpeg","image/jpeg", "binary", 1.0);
HTSetSuffix(".tif", "image/tiff", "binary", 1.0);
HTSetSuffix(".tiff","image/tiff", "binary", 1.0);
HTSetSuffix(".ras", "image/x-cmu-rast", "binary", 1.0);
HTSetSuffix(".pnm", "image/x-portable-anymap", "binary", 1.0);
HTSetSuffix(".pbm", "image/x-portable-bitmap", "binary", 1.0);
HTSetSuffix(".pgm", "image/x-portable-graymap", "binary", 1.0);
HTSetSuffix(".ppm", "image/x-portable-pixmap", "binary", 1.0);
HTSetSuffix(".rgb", "image/x-rgb", "binary", 1.0);
HTSetSuffix(".xbm", "image/x-xbitmap", "binary", 1.0);
HTSetSuffix(".xpm", "image/x-xpixmap", "binary", 1.0);
HTSetSuffix(".xwd", "image/x-xwindowdump", "binary", 1.0);
HTSetSuffix(".htm", "text/html", "binary", 1.0);
HTSetSuffix(".html", "text/html", "binary", 1.0);
HTSetSuffix(".text", "text/plain", "binary", 1.0);
HTSetSuffix(".c", "text/plain", "binary", 1.0);
HTSetSuffix(".cc", "text/plain", "binary", 1.0);
HTSetSuffix(".c++", "text/plain", "binary", 1.0);
HTSetSuffix(".h", "text/plain", "binary", 1.0);
HTSetSuffix(".pl", "text/plain", "binary", 1.0);
HTSetSuffix(".txt", "text/plain", "binary", 1.0);
HTSetSuffix(".rtx", "text/richtext", "binary", 1.0); /* MIME richtext */
HTSetSuffix(".tsv", "text/tab-separated-values", "binary", 1.0);
HTSetSuffix(".etx", "text/x-setext", "binary", 1.0);
HTSetSuffix(".mpg", "video/mpeg", "binary", 1.0);
HTSetSuffix(".mpe", "video/mpeg", "binary", 1.0);
HTSetSuffix(".mpeg", "video/mpeg", "binary", 1.0);
HTSetSuffix(".mov", "video/quicktime", "binary", 1.0);
HTSetSuffix(".qt", "video/quicktime", "binary", 1.0);
HTSetSuffix(".avi", "video/x-msvideo", "binary", 1.0);
HTSetSuffix(".movie", "video/x-sgi-movie", "binary", 1.0);
HTSetSuffix(".mv", "video/x-sgi-movie", "binary", 1.0);
HTSetSuffix(".mime", "message/rfc822", "binary", 1.0);
}
/* These should override the default extensions as necessary. */
HTLoadExtensionsConfigFile (global_extension_map);
/* These should override everything else. */
HTLoadExtensionsConfigFile (personal_extension_map);
}
/* -------------------- Extension config file reading --------------------- */
/* The following is lifted from NCSA httpd 1.0a1, by Rob McCool;
NCSA httpd is in the public domain, as is this code. */
#define MAX_STRING_LEN 256
/*static int getline(char *s, int n, FILE *f) */
/*{*/
/*register int i=0;*/
/*while(1) */
/*{*/
/*s[i] = (char)fgetc(f);*/
/*if(s[i] == CR)*/
/*s[i] = fgetc(f);*/
/*if((s[i] == EOF) || (s[i] == LF) || (i == (n-1)))*/
/*{*/
/*s[i] = '\0';*/
/*return (feof(f) ? 1 : 0);*/
/*}*/
/*++i;*/
/*}*/
/**//* NOTREACHED */
/*}*/
static void getword(char *word, char *line, char stop, char stop2)
{
int x = 0, y;
for (x = 0; line[x] && line[x] != stop && line[x] != stop2; x++)
{
word[x] = line[x];
}
word[x] = '\0';
if (line[x])
++x;
y=0;
while (line[y++] = line[x++])
;
return;
}
int HTLoadExtensionsConfigFile (char *fn)
{
char l[MAX_STRING_LEN],w[MAX_STRING_LEN],*ct,*ptr;
FILE *f;
int x, count = 0;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "Loading extensions config file '%s'\n",
fn);
#endif
if(!(f = fopen(fn,"r")))
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "Could not open extensions config file '%s'\n",fn);
#endif
return -1;
}
while(!(getline(l,MAX_STRING_LEN,f)))
{
/* always get rid of leading white space for "line" -- SWP */
for (ptr=l; *ptr && isspace(*ptr); ptr++);
getword(w,ptr,' ','\t');
if(ptr[0] == '\0' || w[0] == '#')
continue;
ct = (char *)malloc(sizeof(char) * (strlen(w) + 1));
strcpy(ct,w);
while(ptr[0])
{
getword(w,ptr,' ','\t');
if(w[0] && (w[0] != ' '))
{
char *ext = (char *)malloc(sizeof(char) * (strlen(w)+1+1));
for(x=0; w[x]; x++)
ext[x+1] = TOLOWER(w[x]);
ext[0] = '.';
ext[strlen(w)+1] = 0;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "SETTING SUFFIX '%s' to '%s'\n", ext, ct);
#endif
HTSetSuffix (ext, ct, "binary", 1.0);
count++;
free (ext);
}
}
free(ct);
}
fclose(f);
return count;
}

18
libwww2/HTInit.h Normal file
View File

@@ -0,0 +1,18 @@
/* */
/* Initialisation module HTInit.h
**
** This module resisters all the plug&play software modules which
** will be used in the program. This is for a browser.
**
** To override this, just copy it and link in your version
** befoe you link with the library.
*/
#include "HTUtils.h"
extern void HTReInit NOPARAMS;
extern void HTFormatInit NOPARAMS;
extern void HTFileInit NOPARAMS;
extern int HTLoadExtensionsConfigFile (char *fn);

140
libwww2/HTLex.c Normal file
View File

@@ -0,0 +1,140 @@
/* MODULE HTLex.c
** LEXICAL ANALYSOR
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include "HTAAUtil.h"
#include "HTLex.h" /* Implemented here */
/*
** Global variables
*/
PUBLIC char lex_buffer[40]; /* Read lexical string */
PUBLIC int lex_line = 1; /* Line number in source file */
/*
** Module-wide variables
*/
PRIVATE int lex_cnt;
PRIVATE BOOL lex_template;
PRIVATE LexItem lex_pushed_back = LEX_NONE;
PRIVATE FILE *cache = NULL;
PUBLIC void unlex ARGS1(LexItem, lex_item)
{
lex_pushed_back = lex_item;
}
PUBLIC LexItem lex ARGS1(FILE *, fp)
{
int ch;
if (fp != cache) { /* This cache doesn't work ok because the system */
cache = fp; /* often assign same FILE structure the next open */
lex_line = 1; /* file. So, if there are syntax errors in setup */
} /* files it may confuse things later on. */
if (lex_pushed_back != LEX_NONE) {
LexItem ret = lex_pushed_back;
lex_pushed_back = LEX_NONE;
return ret;
}
lex_cnt = 0;
lex_template = NO;
for(;;) {
switch (ch = getc(fp)) {
case EOF:
case ' ':
case '\t':
case '\r':
case '\n':
case ':':
case ',':
case '(':
case ')':
case '@':
if (lex_cnt > 0) {
if (ch != EOF) ungetc(ch,fp);
if (lex_template) return LEX_TMPL_STR;
else return LEX_ALPH_STR;
}
else switch(ch) {
case EOF: return LEX_EOF; break;
case '\n':
lex_line++; return LEX_REC_SEP; break;
case ':': return LEX_FIELD_SEP; break;
case ',': return LEX_ITEM_SEP; break;
case '(': return LEX_OPEN_PAREN; break;
case ')': return LEX_CLOSE_PAREN; break;
case '@': return LEX_AT_SIGN; break;
default: ; /* Leading white space ignored (SP,TAB,CR) */
}
break;
default:
lex_buffer[lex_cnt++] = ch;
lex_buffer[lex_cnt] = (char)0;
if ('*' == ch) lex_template = YES;
} /* switch ch */
} /* forever */
}
PUBLIC char *lex_verbose ARGS1(LexItem, lex_item)
{
static char msg[100];
switch (lex_item) {
case LEX_NONE: /* Internally used */
return "NO-LEX-ITEM";
break;
case LEX_EOF: /* End of file */
return "end-of-file";
break;
case LEX_REC_SEP: /* Record separator */
return "record separator (newline)";
break;
case LEX_FIELD_SEP: /* Field separator */
return "field separator ':'";
break;
case LEX_ITEM_SEP: /* List item separator */
return "item separator ','";
break;
case LEX_OPEN_PAREN: /* Group start tag */
return "'('";
break;
case LEX_CLOSE_PAREN: /* Group end tag */
return "')'";
break;
case LEX_AT_SIGN: /* Address qualifier */
return "address qualifier '@'";
break;
case LEX_ALPH_STR: /* Alphanumeric string */
sprintf(msg, "alphanumeric string '%s'", lex_buffer);
return msg;
break;
case LEX_TMPL_STR: /* Template string */
sprintf(msg, "template string '%s'", lex_buffer);
return msg;
break;
default:
return "UNKNOWN-LEX-ITEM";
break;
}
}

62
libwww2/HTLex.h Normal file
View File

@@ -0,0 +1,62 @@
/* LEXICAL ANALYSOR (MAINLY FOR CONFIG FILES)
*/
#ifndef HTLEX_H
#define HTLEX_H
#include "HTUtils.h"
#ifdef SHORT_NAMES
#define lex_verb lex_verbose
#endif /*SHORT_NAMES*/
typedef enum {
LEX_NONE, /* Internally used */
LEX_EOF, /* End of file */
LEX_REC_SEP, /* Record separator */
LEX_FIELD_SEP, /* Field separator */
LEX_ITEM_SEP, /* List item separator */
LEX_OPEN_PAREN, /* Group start tag */
LEX_CLOSE_PAREN, /* Group end tag */
LEX_AT_SIGN, /* Address qualifier */
LEX_ALPH_STR, /* Alphanumeric string */
LEX_TMPL_STR /* Template string */
} LexItem;
extern char lex_buffer[]; /* Read lexical string */
extern int lex_line; /* Line number in source file */
/*
Get Next Lexical Item
If returns LEX_ALPH_STR or LEX_TMPL_STR the string is in global buffer lex_buffer.
*/
PUBLIC LexItem lex PARAMS((FILE * fp));
/*
Push Back Latest Item
*/
PUBLIC void unlex PARAMS((LexItem lex_item));
/*
Get the Name for Lexical Item
*/
PUBLIC char *lex_verbose PARAMS((LexItem lex_item));
/*
*/
#endif /* not HTLEX_H */
/*
End of file HTLex.h. */

152
libwww2/HTList.c Normal file
View File

@@ -0,0 +1,152 @@
/* A small List class HTList.c
** ==================
**
** A list is represented as a sequence of linked nodes of type HTList.
** The first node is a header which contains no object.
** New nodes are inserted between the header and the rest of the list.
*/
#include "../config.h"
#include "HTList.h"
#include <stdio.h> /* joe@athena, TBL 921019 */
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
HTList * HTList_new NOARGS
{
HTList *newList = (HTList *)malloc (sizeof (HTList));
if (newList == NULL) outofmem(__FILE__, "HTList_new");
newList->object = NULL;
newList->next = NULL;
return newList;
}
void HTList_delete ARGS1(HTList *,me)
{
HTList *current;
while (current = me) {
me = me->next;
free (current);
}
}
void HTList_addObject ARGS2(HTList *,me, void *,newObject)
{
if (me) {
HTList *newNode = (HTList *)malloc (sizeof (HTList));
if (newNode == NULL) outofmem(__FILE__, "HTList_addObject");
newNode->object = newObject;
newNode->next = me->next;
me->next = newNode;
}
#ifndef DISABLE_TRACE
else
if (www2Trace) fprintf(stderr,
"HTList: Trying to add object %p to a nonexisting list\n",
newObject);
#endif
}
void HTList_addObjectAtEnd ARGS2(HTList *,me, void *,newObject)
{
if (me)
{
HTList *newNode = (HTList *)malloc (sizeof (HTList));
if (newNode == NULL) outofmem(__FILE__, "HTList_addObject");
newNode->object = newObject;
newNode->next = NULL;
while (me->next)
me = me->next;
me->next = newNode;
}
#ifndef DISABLE_TRACE
else
if (www2Trace) fprintf(stderr,
"HTList: Trying to add object %p to a nonexisting list\n",
newObject);
#endif
}
BOOL HTList_removeObject ARGS2(HTList *,me, void *,oldObject)
{
if (me) {
HTList *previous;
while (me->next) {
previous = me;
me = me->next;
if (me->object == oldObject) {
previous->next = me->next;
free (me);
return YES; /* Success */
}
}
}
return NO; /* object not found or NULL list */
}
void * HTList_removeLastObject ARGS1 (HTList *,me)
{
if (me && me->next) {
HTList *lastNode = me->next;
void * lastObject = lastNode->object;
me->next = lastNode->next;
free (lastNode);
return lastObject;
} else /* Empty list */
return NULL;
}
void * HTList_removeFirstObject ARGS1 (HTList *,me)
{
if (me && me->next) {
HTList * prevNode;
void *firstObject;
while (me->next) {
prevNode = me;
me = me->next;
}
firstObject = me->object;
prevNode->next = NULL;
free (me);
return firstObject;
} else /* Empty list */
return NULL;
}
int HTList_count ARGS1 (HTList *,me)
{
int count = 0;
if (me)
while (me = me->next)
count++;
return count;
}
int HTList_indexOf ARGS2(HTList *,me, void *,object)
{
if (me) {
int position = 0;
while (me = me->next) {
if (me->object == object)
return position;
position++;
}
}
return -1; /* Object not in the list */
}
void * HTList_objectAt ARGS2 (HTList *,me, int,position)
{
if (position < 0)
return NULL;
if (me) {
while (me = me->next) {
if (position == 0)
return me->object;
position--;
}
}
return NULL; /* Reached the end of the list */
}

61
libwww2/HTList.h Normal file
View File

@@ -0,0 +1,61 @@
/* */
/* List object
**
** The list object is a generic container for storing collections
** of things in order.
*/
#ifndef HTLIST_H
#define HTLIST_H
#include "HTUtils.h" /* for BOOL type and PARAMS and ARGS*/
typedef struct _HTList HTList;
struct _HTList {
void * object;
HTList * next;
HTList * last;
};
#ifdef SHORT_NAMES
#define HTList_new HTLiNew
#define HTList_delete HTLiDele
#define HTList_addObject HTLiAdOb
#define HTList_removeObject HTLiReOb
#define HTList_removeLastObject HTLiReLa
#define HTList_removeFirstObject HTLiReFi
#define HTList_count HTLiCoun
#define HTList_indexOf HTLiInOf
#define HTList_objectAt HTLiObAt
#endif
extern HTList * HTList_new NOPARAMS;
extern void HTList_delete PARAMS((HTList *me));
/* Add object to START of list
*/
extern void HTList_addObject PARAMS((HTList *me, void *newObject));
extern void HTList_addObjectAtEnd PARAMS((HTList *me, void *newObject));
extern BOOL HTList_removeObject PARAMS((HTList *me, void *oldObject));
extern void * HTList_removeLastObject PARAMS((HTList *me));
extern void * HTList_removeFirstObject PARAMS((HTList *me));
#define HTList_isEmpty(me) (me ? me->next == NULL : YES)
extern int HTList_count PARAMS((HTList *me));
extern int HTList_indexOf PARAMS((HTList *me, void *object));
#define HTList_lastObject(me) \
(me && me->next ? me->next->object : NULL)
extern void * HTList_objectAt PARAMS((HTList *me, int position));
/* Fast macro to traverse the list. Call it first with copy of list header :
it returns the first object and increments the passed list pointer.
Call it with the same variable until it returns NULL. */
#define HTList_nextObject(me) \
(me && (me = me->next) ? me->object : NULL)
#endif /* HTLIST_H */
/*
*/

1026
libwww2/HTMIME.c Normal file

File diff suppressed because it is too large Load Diff

25
libwww2/HTMIME.h Normal file
View File

@@ -0,0 +1,25 @@
/* */
/* MIME Parser HTMIME.h
** -----------
**
** The MIME parser stream presents a MIME document.
**
**
*/
#ifndef HTMIME_H
#define HTMIME_H
#include "HTStream.h"
#include "HTAnchor.h"
int HTMIME_get_header_length(HTStream *me);
extern HTStream * HTMIMEConvert PARAMS((HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
#endif

525
libwww2/HTML.c Normal file
View File

@@ -0,0 +1,525 @@
/* Structured stream to Rich hypertext converter
** ============================================
**
** This generates a hypertext object. It converts from the
** structured stream interface from HTML events into the style-
** oriented interface of the HText.h interface. This module is
** only used in clients and should not be linked into servers.
**
** Override this module if you are making a new GUI browser.
**
*/
#include "../config.h"
#include "HTML.h"
#include <ctype.h>
#include <stdio.h>
#include "HTAtom.h"
#include "HTChunk.h"
#include "HText.h"
#include "HTAlert.h"
#include "HTMLGen.h"
#include "HTParse.h"
/* HTML Object
** -----------
*/
#define MAX_NESTING 20 /* Should be checked by parser */
struct _HTStructured {
WWW_CONST HTStructuredClass * isa;
HTParentAnchor * node_anchor;
HText * text;
HTStream* target; /* Output stream */
HTStreamClass targetClass; /* Output routines */
};
struct _HTStream {
WWW_CONST HTStreamClass * isa;
/* .... */
};
/* Entity values -- for ISO Latin 1 local representation
**
** This MUST match exactly the table referred to in the DTD!
*/
static char * ISO_Latin1[] = {
"\306", /* capital AE diphthong (ligature) */
"\301", /* capital A, acute accent */
"\302", /* capital A, circumflex accent */
"\300", /* capital A, grave accent */
"\305", /* capital A, ring */
"\303", /* capital A, tilde */
"\304", /* capital A, dieresis or umlaut mark */
"\307", /* capital C, cedilla */
"\320", /* capital Eth, Icelandic */
"\311", /* capital E, acute accent */
"\312", /* capital E, circumflex accent */
"\310", /* capital E, grave accent */
"\313", /* capital E, dieresis or umlaut mark */
"\315", /* capital I, acute accent */
"\316", /* capital I, circumflex accent */
"\314", /* capital I, grave accent */
"\317", /* capital I, dieresis or umlaut mark */
"\321", /* capital N, tilde */
"\323", /* capital O, acute accent */
"\324", /* capital O, circumflex accent */
"\322", /* capital O, grave accent */
"\330", /* capital O, slash */
"\325", /* capital O, tilde */
"\326", /* capital O, dieresis or umlaut mark */
"\336", /* capital THORN, Icelandic */
"\332", /* capital U, acute accent */
"\333", /* capital U, circumflex accent */
"\331", /* capital U, grave accent */
"\334", /* capital U, dieresis or umlaut mark */
"\335", /* capital Y, acute accent */
"\341", /* small a, acute accent */
"\342", /* small a, circumflex accent */
"\346", /* small ae diphthong (ligature) */
"\340", /* small a, grave accent */
"\046", /* ampersand */
"\345", /* small a, ring */
"\343", /* small a, tilde */
"\344", /* small a, dieresis or umlaut mark */
"\347", /* small c, cedilla */
"\351", /* small e, acute accent */
"\352", /* small e, circumflex accent */
"\350", /* small e, grave accent */
"\360", /* small eth, Icelandic */
"\353", /* small e, dieresis or umlaut mark */
"\076", /* greater than */
"\355", /* small i, acute accent */
"\356", /* small i, circumflex accent */
"\354", /* small i, grave accent */
"\357", /* small i, dieresis or umlaut mark */
"\074", /* less than */
"\361", /* small n, tilde */
"\363", /* small o, acute accent */
"\364", /* small o, circumflex accent */
"\362", /* small o, grave accent */
"\370", /* small o, slash */
"\365", /* small o, tilde */
"\366", /* small o, dieresis or umlaut mark */
"\337", /* small sharp s, German (sz ligature) */
"\376", /* small thorn, Icelandic */
"\372", /* small u, acute accent */
"\373", /* small u, circumflex accent */
"\371", /* small u, grave accent */
"\374", /* small u, dieresis or umlaut mark */
"\375", /* small y, acute accent */
"\377", /* small y, dieresis or umlaut mark */
};
/* Set character set
** ----------------
*/
PRIVATE char** p_entity_values = ISO_Latin1; /* Pointer to translation */
PUBLIC void HTMLUseCharacterSet ARGS1(HTMLCharacterSet, i)
{
p_entity_values = ISO_Latin1;
}
/*_________________________________________________________________________
**
** A C T I O N R O U T I N E S
*/
/* Character handling
** ------------------
*/
PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c)
{
if (!me->text)
{
me->text = HText_new();
HText_beginAppend(me->text);
}
HText_appendCharacter(me->text, c);
}
/* String handling
** ---------------
**
** This is written separately from put_character becuase the loop can
** in some cases be promoted to a higher function call level for speed.
*/
PRIVATE void HTML_put_string ARGS2(HTStructured *, me, WWW_CONST char*, s)
{
if (!me->text)
{
me->text = HText_new();
HText_beginAppend(me->text);
}
HText_appendText(me->text, s);
}
/* Buffer write
** ------------
*/
PRIVATE void HTML_write ARGS3(HTStructured *, me, WWW_CONST char*, s, int, l)
{
WWW_CONST char* p;
WWW_CONST char* e = s+l;
for (p=s; s<e; p++) HTML_put_character(me, *p);
}
/* Start Element
** -------------
*/
PRIVATE void HTML_start_element ARGS4(
HTStructured *, me,
int, element_number,
WWW_CONST BOOL*, present,
WWW_CONST char **, value)
{
if (!me->text)
{
me->text = HText_new();
HText_beginAppend(me->text);
}
switch (element_number)
{
case HTML_A:
{
char *href = NULL;
if (present[HTML_A_HREF])
{
StrAllocCopy(href, value[HTML_A_HREF]);
HTSimplify(href);
}
HText_beginAnchor(me->text, href);
free (href);
}
break;
case HTML_TITLE:
HText_appendText(me->text, "<TITLE>");
break;
case HTML_ISINDEX:
HText_appendText(me->text, "<ISINDEX>\n");
break;
case HTML_P:
HText_appendText(me->text, "<P>\n");
break;
case HTML_DL:
HText_appendText(me->text, "\n<DL>\n");
break;
case HTML_DT:
HText_appendText(me->text, "\n<DT> ");
break;
case HTML_DD:
HText_appendText(me->text, "\n<DD> ");
break;
case HTML_UL:
HText_appendText(me->text, "\n<UL>\n");
break;
case HTML_OL:
HText_appendText(me->text, "\n<OL>\n");
break;
case HTML_MENU:
HText_appendText(me->text, "\n<MENU>\n");
break;
case HTML_DIR:
HText_appendText(me->text, "\n<DIR>\n");
break;
case HTML_LI:
HText_appendText(me->text, "\n<LI> ");
break;
case HTML_LISTING:
HText_appendText(me->text, "<LISTING>");
break;
case HTML_XMP:
HText_appendText(me->text, "<XMP>");
break;
case HTML_PLAINTEXT:
HText_appendText(me->text, "<PLAINTEXT>");
break;
case HTML_PRE:
HText_appendText(me->text, "<PRE>");
break;
case HTML_IMG:
{
char *href = NULL;
if (present[HTML_A_HREF])
{
StrAllocCopy(href, value[HTML_A_HREF]);
HTSimplify(href);
}
if (href)
{
HText_appendText(me->text, "<IMG SRC=\"");
HText_appendText(me->text, href);
HText_appendText(me->text, "\">");
free (href);
}
}
break;
case HTML_H1:
HText_appendText(me->text, "<H1>");
break;
case HTML_H2:
HText_appendText(me->text, "<H2>");
break;
case HTML_H3:
HText_appendText(me->text, "<H3>");
break;
case HTML_H4:
HText_appendText(me->text, "<H4>");
break;
case HTML_H5:
HText_appendText(me->text, "<H5>");
break;
case HTML_H6:
HText_appendText(me->text, "<H6>");
break;
case HTML_ADDRESS:
HText_appendText(me->text, "<ADDRESS>");
break;
case HTML_BLOCKQUOTE:
HText_appendText(me->text, "<BLOCKQUOTE>");
break;
case HTML_TT: /* Physical character highlighting */
case HTML_B: /* Currently ignored */
case HTML_I:
case HTML_U:
case HTML_EM: /* Logical character highlighting */
case HTML_STRONG: /* Currently ignored */
case HTML_CODE:
case HTML_SAMP:
case HTML_KBD:
case HTML_VAR:
case HTML_DFN:
case HTML_CITE:
break;
default:
break;
} /* end switch */
}
/* End Element
** -----------
**
*/
PRIVATE void HTML_end_element ARGS2(HTStructured *, me, int , element_number)
{
switch(element_number)
{
case HTML_A:
HText_endAnchor(me->text);
break;
case HTML_TITLE:
HText_appendText(me->text, "</TITLE>\n");
break;
case HTML_LISTING:
HText_appendText(me->text, "</LISTING>\n");
break;
case HTML_XMP:
HText_appendText(me->text, "</XMP>\n");
break;
case HTML_PRE:
HText_appendText(me->text, "</PRE>\n");
break;
case HTML_DL:
HText_appendText(me->text, "\n</DL>\n");
break;
case HTML_UL:
HText_appendText(me->text, "\n</UL>\n");
break;
case HTML_OL:
HText_appendText(me->text, "\n</OL>\n");
break;
case HTML_MENU:
HText_appendText(me->text, "\n</MENU>\n");
break;
case HTML_DIR:
HText_appendText(me->text, "\n</DIR>\n");
break;
case HTML_H1:
HText_appendText(me->text, "</H1>\n");
break;
case HTML_H2:
HText_appendText(me->text, "</H2>\n");
break;
case HTML_H3:
HText_appendText(me->text, "</H3>\n");
break;
case HTML_H4:
HText_appendText(me->text, "</H4>\n");
break;
case HTML_H5:
HText_appendText(me->text, "</H5>\n");
break;
case HTML_H6:
HText_appendText(me->text, "</H6>\n");
break;
case HTML_ADDRESS:
HText_appendText(me->text, "</ADDRESS>\n");
break;
case HTML_BLOCKQUOTE:
HText_appendText(me->text, "</BLOCKQUOTE>\n");
break;
default:
break;
} /* switch */
}
/* Expanding entities
** ------------------
*/
/* (In fact, they all shrink!)
*/
PRIVATE void HTML_put_entity ARGS2(HTStructured *, me, int, entity_number)
{
HTML_put_string(me, ISO_Latin1[entity_number]); /* @@ Other representations */
}
/* Free an HTML object
** -------------------
**
** If the document is empty, the text object will not yet exist.
So we could in fact abandon creating the document and return
an error code. In fact an empty document is an important type
of document, so we don't.
**
** If non-interactive, everything is freed off. No: crashes -listrefs
** Otherwise, the interactive object is left.
*/
PUBLIC void HTML_free ARGS1(HTStructured *, me)
{
if (me->text)
HText_endAppend(me->text);
if (me->target)
{
(*me->targetClass.end_document)(me->target);
(*me->targetClass.free)(me->target);
}
free(me);
}
PUBLIC void HTML_handle_interrupt ARGS1(HTStructured *, me)
{
if (me->text)
HText_doAbort (me->text);
if (me->target)
{
(*me->targetClass.handle_interrupt)(me->target);
}
/* Not necessarily safe... */
/* free(me); */
}
PRIVATE void HTML_end_document ARGS1(HTStructured *, me)
{ /* Obsolete */
}
/* Structured Object Class
** -----------------------
*/
PUBLIC WWW_CONST HTStructuredClass HTMLPresentation = /* As opposed to print etc */
{
"text/html",
HTML_free,
HTML_end_document, HTML_handle_interrupt,
HTML_put_character, HTML_put_string, HTML_write,
HTML_start_element, HTML_end_element,
HTML_put_entity
};
/* New Structured Text object
** --------------------------
**
** The strutcured stream can generate either presentation,
** or plain text, or HTML.
*/
PUBLIC HTStructured* HTML_new ARGS3(
HTParentAnchor *, anchor,
HTFormat, format_out,
HTStream*, stream)
{
HTStructured * me;
#if 0
if (format_out != WWW_PLAINTEXT && format_out != WWW_PRESENT) {
HTStream * intermediate = HTStreamStack(WWW_HTML, format_out, 0,
stream, anchor);
fprintf (stderr, "+++ YO in HTML_new\n");
if (intermediate) return HTMLGenerator(intermediate);
fprintf(stderr, "** Internal error: can't parse HTML to %s\n",
HTAtom_name(format_out));
exit (-99);
}
#endif
me = (HTStructured*) malloc(sizeof(*me));
if (me == NULL) outofmem(__FILE__, "HTML_new");
me->isa = &HTMLPresentation;
me->node_anchor = anchor;
me->text = 0;
me->target = stream;
if (stream)
me->targetClass = *stream->isa; /* Copy pointers */
return (HTStructured*) me;
}
/* Record error message as a hypertext object
** ------------------------------------------
**
** The error message should be marked as an error so that
** it can be reloaded later.
** This implementation just throws up an error message
** and leaves the document unloaded.
** A smarter implementation would load an error document,
** marking at such so that it is retried on reload.
**
** On entry,
** sink is a stream to the output device if any
** number is the HTTP error number
** message is the human readable message.
**
** On exit,
** returns a negative number to indicate lack of success in the load.
*/
PUBLIC int HTLoadError ARGS3(
HTStream *, sink,
int, number,
WWW_CONST char *, message)
{
HTAlert(message); /* @@@@@@@@@@@@@@@@@@@ */
#if 0
return -number;
#endif
return -1;
}

51
libwww2/HTML.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef HTML_H
#define HTML_H
#include "HTUtils.h"
#include "HTAnchor.h"
#include "HTMLDTD.h"
#ifdef SHORT_NAMES
#define HTMLPresentation HTMLPren
#endif
extern WWW_CONST HTStructuredClass HTMLPresentation;
extern HTStructured* HTML_new PARAMS((
HTParentAnchor * anchor,
HTFormat format_out,
HTStream * target));
/* Names for selected internal representations:
*/
typedef enum _HTMLCharacterSet {
HTML_ISO_LATIN1,
HTML_NEXT_CHARS,
HTML_PC_CP950
} HTMLCharacterSet;
extern void HTMLUseCharacterSet PARAMS((HTMLCharacterSet i));
/*
Record error message as a hypertext object
The error message should be marked as an error so that it can be
reloaded later. This implementation just throws up an error message
and leaves the document unloaded.
*/
/* On entry,
** sink is a stream to the output device if any
** number is the HTTP error number
** message is the human readable message.
** On exit,
** a retrun code like HT_LOADED if object exists else 60; 0
*/
PUBLIC int HTLoadError PARAMS((
HTStream * sink,
int number,
WWW_CONST char * message));
#endif

202
libwww2/HTMLDTD.c Normal file
View File

@@ -0,0 +1,202 @@
/* Our Static DTD for HTML
** -----------------------
*/
/* Implements:
*/
#include "../config.h"
#include "HTMLDTD.h"
/* Entity Names
** ------------
**
** This table must be matched exactly with ALL the translation tables
*/
static WWW_CONST char* entities[] = {
"AElig", /* capital AE diphthong (ligature) */
"Aacute", /* capital A, acute accent */
"Acirc", /* capital A, circumflex accent */
"Agrave", /* capital A, grave accent */
"Aring", /* capital A, ring */
"Atilde", /* capital A, tilde */
"Auml", /* capital A, dieresis or umlaut mark */
"Ccedil", /* capital C, cedilla */
"ETH", /* capital Eth, Icelandic */
"Eacute", /* capital E, acute accent */
"Ecirc", /* capital E, circumflex accent */
"Egrave", /* capital E, grave accent */
"Euml", /* capital E, dieresis or umlaut mark */
"Iacute", /* capital I, acute accent */
"Icirc", /* capital I, circumflex accent */
"Igrave", /* capital I, grave accent */
"Iuml", /* capital I, dieresis or umlaut mark */
"Ntilde", /* capital N, tilde */
"Oacute", /* capital O, acute accent */
"Ocirc", /* capital O, circumflex accent */
"Ograve", /* capital O, grave accent */
"Oslash", /* capital O, slash */
"Otilde", /* capital O, tilde */
"Ouml", /* capital O, dieresis or umlaut mark */
"THORN", /* capital THORN, Icelandic */
"Uacute", /* capital U, acute accent */
"Ucirc", /* capital U, circumflex accent */
"Ugrave", /* capital U, grave accent */
"Uuml", /* capital U, dieresis or umlaut mark */
"Yacute", /* capital Y, acute accent */
"aacute", /* small a, acute accent */
"acirc", /* small a, circumflex accent */
"aelig", /* small ae diphthong (ligature) */
"agrave", /* small a, grave accent */
"amp", /* ampersand */
"aring", /* small a, ring */
"atilde", /* small a, tilde */
"auml", /* small a, dieresis or umlaut mark */
"ccedil", /* small c, cedilla */
"eacute", /* small e, acute accent */
"ecirc", /* small e, circumflex accent */
"egrave", /* small e, grave accent */
"eth", /* small eth, Icelandic */
"euml", /* small e, dieresis or umlaut mark */
"gt", /* greater than */
"iacute", /* small i, acute accent */
"icirc", /* small i, circumflex accent */
"igrave", /* small i, grave accent */
"iuml", /* small i, dieresis or umlaut mark */
"lt", /* less than */
"ntilde", /* small n, tilde */
"oacute", /* small o, acute accent */
"ocirc", /* small o, circumflex accent */
"ograve", /* small o, grave accent */
"oslash", /* small o, slash */
"otilde", /* small o, tilde */
"ouml", /* small o, dieresis or umlaut mark */
"szlig", /* small sharp s, German (sz ligature) */
"thorn", /* small thorn, Icelandic */
"uacute", /* small u, acute accent */
"ucirc", /* small u, circumflex accent */
"ugrave", /* small u, grave accent */
"uuml", /* small u, dieresis or umlaut mark */
"yacute", /* small y, acute accent */
"yuml", /* small y, dieresis or umlaut mark */
};
#define HTML_ENTITIES 65
/* Attribute Lists
** ---------------
**
** Lists must be in alphatbetical order by attribute name
** The tag elements contain the number of attributes
*/
static attr no_attr[] =
{{ 0 }};
static attr a_attr[] = { /* Anchor attributes */
{ "HREF"},
{ "NAME" }, /* Should be ID */
{ "TITLE" },
{ "TYPE" },
{ "URN" },
{ 0 } /* Terminate list */
};
static attr img_attr[] = { /* Anchor attributes */
{ "SRC"},
{ 0 } /* Terminate list */
};
static attr list_attr[] = {
{ "COMPACT"},
{ 0 } /* Terminate list */
};
static attr glossary_attr[] = {
{ "COMPACT" },
{ 0 } /* Terminate list */
};
static attr nextid_attr[] = {
{ "N" }
};
/* Elements
** --------
**
** Must match definitions in HTMLDTD.html!
** Must be in alphabetical order.
**
** Name, Attributes, content
*/
static HTTag tags[HTML_ELEMENTS] = {
{ "A" , a_attr, HTML_A_ATTRIBUTES, SGML_MIXED },
{ "ADDRESS" , no_attr, 0, SGML_MIXED },
{ "B" , no_attr, 0, SGML_MIXED },
{ "BODY" , no_attr, 0, SGML_MIXED },
{ "BLOCKQUOTE", no_attr, 0, SGML_MIXED },
{ "CITE" , no_attr, 0, SGML_MIXED },
{ "CODE" , no_attr, 0, SGML_MIXED },
{ "COMMENT", no_attr, 0, SGML_MIXED },
{ "DD" , no_attr, 0, SGML_EMPTY },
{ "DFN" , no_attr, 0, SGML_MIXED },
{ "DIR" , list_attr, 1, SGML_MIXED },
{ "DL" , glossary_attr,1, SGML_MIXED },
{ "DLC" , glossary_attr,1, SGML_MIXED },
{ "DT" , no_attr, 0, SGML_EMPTY },
{ "EM" , no_attr, 0, SGML_MIXED },
{ "HEAD" , no_attr, 0, SGML_MIXED },
{ "H1" , no_attr, 0, SGML_MIXED },
{ "H2" , no_attr, 0, SGML_MIXED },
{ "H3" , no_attr, 0, SGML_MIXED },
{ "H4" , no_attr, 0, SGML_MIXED },
{ "H5" , no_attr, 0, SGML_MIXED },
{ "H6" , no_attr, 0, SGML_MIXED },
{ "H7" , no_attr, 0, SGML_MIXED },
{ "HTML" , no_attr, 0, SGML_MIXED },
{ "I" , no_attr, 0, SGML_MIXED },
{ "IMG" , img_attr, 0, SGML_EMPTY },
{ "ISINDEX" , no_attr, 0, SGML_EMPTY },
{ "KBD" , no_attr, 0, SGML_MIXED },
{ "LI" , list_attr, 1, SGML_EMPTY },
{ "LINK" , a_attr, HTML_A_ATTRIBUTES, SGML_EMPTY },
{ "LISTING" , no_attr, 0, SGML_LITTERAL },
{ "NEXTID" , nextid_attr, 1, SGML_EMPTY },
{ "MENU" , list_attr, 1, SGML_MIXED },
{ "OL" , list_attr, 1, SGML_MIXED },
{ "P" , no_attr, 0, SGML_EMPTY },
{ "PLAINTEXT", no_attr, 0, SGML_LITTERAL },
{ "PRE" , no_attr, 0, SGML_MIXED },
{ "SAMP" , no_attr, 0, SGML_MIXED },
{ "STRONG" , no_attr, 0, SGML_MIXED },
{ "TITLE", no_attr, 0, SGML_CDATA },
{ "TT" , no_attr, 0, SGML_MIXED },
{ "U" , no_attr, 0, SGML_MIXED },
{ "UL" , list_attr, 1, SGML_MIXED },
{ "VAR" , no_attr, 0, SGML_MIXED },
{ "XMP" , no_attr, 0, SGML_LITTERAL },
};
PUBLIC WWW_CONST SGML_dtd HTML_dtd = {
tags,
HTML_ELEMENTS,
entities,
sizeof(entities)/sizeof(char**)
};
/* Utility Routine: useful for people building HTML objects */
/* Start anchor element
** --------------------
**
** It is kinda convenient to have a particulr routine for
** starting an anchor element, as everything else for HTML is
** simple anyway.
*/
struct _HTStructured {
HTStructuredClass * isa;
/* ... */
};

82
libwww2/HTMLDTD.h Normal file
View File

@@ -0,0 +1,82 @@
/* The HTML DTD -- software interface in libwww
HTML DTD - SOFTWARE INTERFACE
SGML purists should excuse the use of the term "DTD" in this file to represent
DTD-related information which is not exactly a DTD itself.
The C modular structure doesn't work very well here, as the dtd is partly in the .h and
partly in the .c which are not very independent. Tant pis.
*/
#ifndef HTMLDTD_H
#define HTMLDTD_H
#include "HTUtils.h"
#include "SGML.h"
/*
Element Numbers
*/
/*
Must Match all tables by element! These include tables in HTMLDTD.c and code in HTML.c
.
*/
typedef enum _HTMLElement {
HTML_A, HTML_ADDRESS,
HTML_B, HTML_BLOCKQUOTE, HTML_BODY,
HTML_CITE, HTML_CODE, HTML_COMMENT,
HTML_DD, HTML_DFN, HTML_DIR,
HTML_DL, HTML_DLC, HTML_DT,
HTML_EM,
HTML_HEAD,
HTML_H1, HTML_H2, HTML_H3,
HTML_H4, HTML_H5, HTML_H6, HTML_H7,
HTML_HTML,
HTML_I, HTML_IMG, HTML_ISINDEX,
HTML_KBD,
HTML_LI, HTML_LINK, HTML_LISTING,
HTML_NEXTID, HTML_MENU,
HTML_OL, HTML_P, HTML_PLAINTEXT, HTML_PRE,
HTML_SAMP, HTML_STRONG,
HTML_TITLE, HTML_TT,
HTML_U, HTML_UL,
HTML_VAR, HTML_XMP } HTMLElement;
#define HTML_ELEMENTS 45
/*
Attribute numbers
*/
/*
Identifier is HTML_<element>_<attribute>. These must match the tables in HTML.c!
*/
#define HTML_A_HREF 0
#define HTML_A_NAME 1
#define HTML_A_TITLE 2
#define HTML_A_TYPE 3
#define HTML_A_URN 4
#define HTML_A_ATTRIBUTES 5
#define DL_COMPACT 0
#define HTML_IMG_SRC 0
#define NEXTID_N 0
extern WWW_CONST SGML_dtd HTML_dtd;
#endif /* HTMLDTD_H */
/*
End of module definition */

240
libwww2/HTMLGen.c Normal file
View File

@@ -0,0 +1,240 @@
/* HTML Generator
** ==============
**
** This version of the HTML object sends HTML markup to the output stream.
**
** Bugs: Line wrapping is not done at all.
** All data handled as PCDATA.
** Should convert old XMP, LISTING and PLAINTEXT to PRE.
**
** It is not obvious to me right now whether the HEAD should be generated
** from the incomming data or the anchor. Currently it's from the former
** which is cleanest.
*/
#include "../config.h"
/* Implements:
*/
#include "HTMLGen.h"
#include <stdio.h>
#include "HTMLDTD.h"
#include "HTStream.h"
#include "SGML.h"
#include "HTFormat.h"
#define PUTC(c) (*me->targetClass.put_character)(me->target, c)
#define PUTS(s) (*me->targetClass.put_string)(me->target, s)
#define PUTB(s,l) (*me->targetClass.put_block)(me->target, s, l)
/* HTML Object
** -----------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
HTStream * target;
HTStreamClass targetClass; /* COPY for speed */
};
struct _HTStructured {
WWW_CONST HTStructuredClass * isa;
HTStream * target;
HTStreamClass targetClass; /* COPY for speed */
};
/* Character handling
** ------------------
*/
PRIVATE void HTMLGen_put_character ARGS2(HTStructured *, me, char, c)
{
PUTC(c);
}
/* String handling
** ---------------
*/
PRIVATE void HTMLGen_put_string ARGS2(HTStructured *, me, WWW_CONST char*, s)
{
PUTS(s);
}
PRIVATE void HTMLGen_write ARGS3(HTStructured *, me, WWW_CONST char*, s, int, l)
{
PUTB(s,l);
}
/* Start Element
** -------------
*/
PRIVATE void HTMLGen_start_element ARGS4(
HTStructured *, me,
int, element_number,
WWW_CONST BOOL*, present,
WWW_CONST char **, value)
{
int i;
HTTag * tag = &HTML_dtd.tags[element_number];
PUTC('<');
PUTS(tag->name);
if (present) for (i=0; i< tag->number_of_attributes; i++) {
if (present[i]) {
PUTC(' ');
PUTS(tag->attributes[i].name);
if (value[i]) {
PUTS("=\"");
PUTS(value[i]);
PUTC('"');
}
}
}
PUTC('>');
}
/* End Element
** -----------
**
*/
/* When we end an element, the style must be returned to that
** in effect before that element. Note that anchors (etc?)
** don't have an associated style, so that we must scan down the
** stack for an element with a defined style. (In fact, the styles
** should be linked to the whole stack not just the top one.)
** TBL 921119
*/
PRIVATE void HTMLGen_end_element ARGS2(HTStructured *, me,
int , element_number)
{
PUTS("</");
PUTS(HTML_dtd.tags[element_number].name);
PUTC('>');
}
/* Expanding entities
** ------------------
**
*/
PRIVATE void HTMLGen_put_entity ARGS2(HTStructured *, me, int, entity_number)
{
PUTC('&');
PUTS(HTML_dtd.entity_names[entity_number]);
PUTC(';');
}
/* Free an HTML object
** -------------------
**
** Note that the SGML parsing context is freed, but the created object is not,
** as it takes on an existence of its own unless explicitly freed.
*/
PRIVATE void HTMLGen_free ARGS1(HTStructured *, me)
{
(*me->targetClass.free)(me->target); /* ripple through */
free(me);
}
PRIVATE void HTMLGen_end_document ARGS1(HTStructured *, me)
{
PUTC('\n'); /* Make sure ends with newline for sed etc etc */
(*me->targetClass.end_document)(me->target);
}
PRIVATE void HTMLGen_handle_interrupt ARGS1(HTStructured *, me)
{
(*me->targetClass.handle_interrupt)(me->target);
}
PRIVATE void PlainToHTML_end_document ARGS1(HTStructured *, me)
{
PUTS("</PRE></BODY>\n");/* Make sure ends with newline for sed etc etc */
(*me->targetClass.end_document)(me->target);
}
/* Structured Object Class
** -----------------------
*/
PRIVATE WWW_CONST HTStructuredClass HTMLGeneration = /* As opposed to print etc */
{
"text/html",
HTMLGen_free,
HTMLGen_end_document, HTMLGen_handle_interrupt,
HTMLGen_put_character, HTMLGen_put_string, HTMLGen_write,
HTMLGen_start_element, HTMLGen_end_element,
HTMLGen_put_entity
};
/* Subclass-specific Methods
** -------------------------
*/
PUBLIC HTStructured * HTMLGenerator ARGS1(HTStream *, output)
{
HTStructured* me = (HTStructured*)malloc(sizeof(*me));
if (me == NULL) outofmem(__FILE__, "HTMLGenerator");
me->isa = &HTMLGeneration;
me->target = output;
me->targetClass = *me->target->isa; /* Copy pointers to routines for speed*/
return me;
}
/* Stream Object Class
** -------------------
**
** This object just converts a plain text stream into HTML
** It is officially a structured strem but only the stream bits exist.
** This is just the easiest way of typecasting all the routines.
*/
PRIVATE WWW_CONST HTStructuredClass PlainToHTMLConversion =
{
"plaintexttoHTML",
HTMLGen_free,
PlainToHTML_end_document,
HTMLGen_handle_interrupt,
HTMLGen_put_character,
HTMLGen_put_string,
HTMLGen_write,
NULL, /* Structured stuff */
NULL,
NULL
};
/* HTConverter from plain text to HTML Stream
** ------------------------------------------
*/
PUBLIC HTStream* HTPlainToHTML ARGS5(
HTPresentation *, pres,
HTParentAnchor *, anchor,
HTStream *, sink,
HTFormat, format_in,
int, compressed)
{
HTStream* me = (HTStream*)malloc(sizeof(*me));
me->isa = (HTStreamClass*) &PlainToHTMLConversion;
me->target = sink;
me->targetClass = *me->target->isa;
/* Copy pointers to routines for speed*/
PUTS("<BODY>\n<PRE>\n");
return me;
}

28
libwww2/HTMLGen.h Normal file
View File

@@ -0,0 +1,28 @@
/* */
/* HTML generator
*/
#ifndef HTMLGEN_H
#define HTMLGEN_H
#include "HTML.h"
#include "HTStream.h"
/* Subclass:
*/
/* extern WWW_CONST HTStructuredClass HTMLGeneration; */
/* Special Creation:
*/
extern HTStructured * HTMLGenerator PARAMS((HTStream * output));
extern HTStream * HTPlainToHTML PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
#endif

95
libwww2/HTMailto.c Normal file
View File

@@ -0,0 +1,95 @@
/* MAILTO WINDOW HTMailTo.c
** =============
** Authors:
** Mike Peter Bretz (bretz@zdv.uni-tuebingen.de)
** Alan Braverman (alanb@ncsa.uiuc.edu)
**
** History:
** 07 Jul 94 First version (MPB)
** 07 Mar 95 Stuck it in NCSA Mosaic for X 2.6 (AMB)
*/
#include "../config.h"
#include "HTAccess.h"
#include "HTUtils.h"
#include "tcp.h"
#include "HTML.h"
#include "HTParse.h"
#include "HTFormat.h"
#include "../libnut/str-tools.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
struct _HTStructured
{
WWW_CONST HTStructuredClass * isa;
/* ... */
};
/* Module-wide variables
*/
PRIVATE int s; /* Socket for FingerHost */
PRIVATE HTStructured * target; /* The output sink */
PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */
extern int GetMailtoKludgeInfo();
/* Initialisation for this module
** ------------------------------
*/
PRIVATE BOOL initialized = NO;
PRIVATE BOOL initialize NOARGS
{
s = -1; /* Disconnected */
return YES;
}
PUBLIC int HTSendMailTo ARGS4(
WWW_CONST char *, arg,
HTParentAnchor *, anAnchor,
HTFormat, format_out,
HTStream*, stream)
{
char *mailtoURL;
char *mailtoSubject;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "HTMailto: Mailing to %s\n", arg);
#endif
if (!initialized)
initialized = initialize();
if (!initialized)
{
HTProgress ((char *) 0);
return HT_NOT_LOADED;
}
{
WWW_CONST char * p1=arg;
/* We will ask for the document, omitting the host name & anchor.
**
** Syntax of address is
** xxx@yyy User xxx at site yyy (xxx is optional).
*/
if (!my_strncasecmp (arg, "mailto:", 7))
p1 = arg + 7; /* Skip "mailto:" prefix */
if (!*arg)
{
HTProgress ("Could not find email address");
return HT_NOT_LOADED; /* Ignore if no name */
}
GetMailtoKludgeInfo(&mailtoURL,&mailtoSubject);
(void) mo_post_mailto_win(p1,mailtoSubject);
return HT_LOADED;
}
}
PUBLIC HTProtocol HTMailto = { "mailto", HTSendMailTo, NULL };

151
libwww2/HTMosaicHTML.c Normal file
View File

@@ -0,0 +1,151 @@
/* Mosaic HTML text object
** =================
**
** This version of the stream object just writes to a socket.
** The socket is assumed open and left open.
**
** Bugs:
** strings written must be less than buffer size.
*/
#include "../config.h"
#include "HTMosaicHTML.h"
#define BUFFER_SIZE 4096; /* Tradeoff */
#include "HTUtils.h"
#include "HText.h"
#include "HTFile.h"
#include "HTCompressed.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* HTML Object
** -----------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
HText * text;
int interrupted;
int compressed;
};
/* Write the buffer out to the socket
** ----------------------------------
*/
/*_________________________________________________________________________
**
** A C T I O N R O U T I N E S
*/
/* Character handling
** ------------------
*/
PRIVATE void HTMosaicHTML_put_character ARGS2(HTStream *, me, char, c)
{
HText_appendCharacter(me->text, c);
}
/* String handling
** ---------------
**
*/
PRIVATE void HTMosaicHTML_put_string ARGS2(HTStream *, me, WWW_CONST char*, s)
{
HText_appendText(me->text, s);
}
PRIVATE void HTMosaicHTML_write ARGS3(HTStream *, me, WWW_CONST char*, s, int, l)
{
HText_appendBlock (me->text, s, l);
}
/* Free an HTML object
** -------------------
**
** Note that the SGML parsing context is freed, but the created object is not,
** as it takes on an existence of its own unless explicitly freed.
*/
PRIVATE void HTMosaicHTML_free ARGS1(HTStream *, me)
{
if (me->compressed != COMPRESSED_NOT)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr,
"[HTMosaicHTMLFree] OK, we're going to decompress HText\n");
#endif
HTCompressedHText (me->text, me->compressed, 0);
}
free(me);
}
/* End writing
*/
PRIVATE void HTMosaicHTML_end_document ARGS1(HTStream *, me)
{
HText_endAppend(me->text);
}
PRIVATE void HTMosaicHTML_handle_interrupt ARGS1(HTStream *, me)
{
me->interrupted = 1;
HText_doAbort(me->text);
}
/* Structured Object Class
** -----------------------
*/
PUBLIC WWW_CONST HTStreamClass HTMosaicHTML =
{
"SocketWriter",
HTMosaicHTML_free,
HTMosaicHTML_end_document,
HTMosaicHTML_put_character, HTMosaicHTML_put_string,
HTMosaicHTML_write,
HTMosaicHTML_handle_interrupt
};
/* New object
** ----------
*/
PUBLIC HTStream* HTMosaicHTMLPresent ARGS5(
HTPresentation *, pres,
HTParentAnchor *, anchor,
HTStream *, sink,
HTFormat, format_in,
int, compressed)
{
HTStream* me = (HTStream*)malloc(sizeof(*me));
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTMosaicHTMLPresent] Hi there! Compressed is %d\n",
compressed);
#endif
me->isa = &HTMosaicHTML;
me->text = HText_new();
me->interrupted = 0;
me->compressed = compressed;
HText_beginAppend(me->text);
return (HTStream*) me;
}

20
libwww2/HTMosaicHTML.h Normal file
View File

@@ -0,0 +1,20 @@
/* MosaicHTML text object HTMosaicHTML.h
** -----------------
**
**
*/
#ifndef HTMosaicHTML_H
#define HTMosaicHTML_H
#include "HTStream.h"
#include "HTAnchor.h"
extern HTStream* HTMosaicHTMLPresent PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
#endif

2818
libwww2/HTNews.c Normal file

File diff suppressed because it is too large Load Diff

51
libwww2/HTNews.h Normal file
View File

@@ -0,0 +1,51 @@
/* Network News Transfer protocol module for the WWW library
HTNEWS
*/
/* History:
** 26 Sep 90 Written TBL in Objective-C
** 29 Nov 91 Downgraded to C, for portable implementation.
** Mar 96 Moved NewsArt here. Upgraded back to C from Objectionable-C
**
*/
#ifndef HTNEWS_H
#define HTNEWS_H
#include "HTAccess.h"
#include "HTAnchor.h"
#include "../src/newsrc.h"
extern HTProtocol HTNews;
extern void HTSetNewsHost PARAMS((WWW_CONST char *value));
extern WWW_CONST char * HTGetNewsHost NOPARAMS;
extern char * HTNewsHost;
extern int newsShowAllGroups;
extern int newsShowReadGroups;
extern int ConfigView;
extern int newsGotList;
extern char *NewsGroup;
extern newsgroup_t *NewsGroupS;
extern int newsShowAllArticles;
#define NO_CHANGE -1
void HTSetNewsConfig (int, int, int, int, int, int, int, int );
/* Thread Chain Structure */
typedef struct NEWSART {
struct NEWSART *prev, *next, *prevt, *nextt; /* Article List pointers */
char *FirstRef, *LastRef; /* Thread List pointers */
long num; /* Article Header Info */
char *ID;
char *SUBJ;
char *FROM;
} NewsArt;
extern NewsArt *CurrentArt;
#endif /* HTNEWS_H */

526
libwww2/HTParse.c Normal file
View File

@@ -0,0 +1,526 @@
/* Parse HyperText Document Address HTParse.c
** ================================
*/
#include "../config.h"
#include "HTUtils.h"
#include "HTParse.h"
#include "tcp.h"
#define HEX_ESCAPE '%'
struct struct_parts {
char * access;
char * host;
char * absolute;
char * relative;
char * anchor;
};
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* Strip white space off a string
** ------------------------------
**
** On exit,
** Return value points to first non-white character, or to 0 if none.
** All trailing white space is OVERWRITTEN with zero.
*/
#ifdef __STDC__
char * HTStrip(char * s)
#else
char * HTStrip(s)
char *s;
#endif
{
#define SPACE(c) ((c==' ')||(c=='\t')||(c=='\n'))
char * p=s;
for(p=s;*p;p++); /* Find end of string */
for(p--;p>=s;p--) {
if(SPACE(*p)) *p=0; /* Zap trailing blanks */
else break;
}
while(SPACE(*s))s++; /* Strip leading blanks */
return s;
}
/* Scan a filename for its consituents
** -----------------------------------
**
** On entry,
** name points to a document name which may be incomplete.
** On exit,
** absolute or relative may be nonzero (but not both).
** host, anchor and access may be nonzero if they were specified.
** Any which are nonzero point to zero terminated strings.
*/
#ifdef __STDC__
PRIVATE void scan(char * name, struct struct_parts *parts)
#else
PRIVATE void scan(name, parts)
char * name;
struct struct_parts *parts;
#endif
{
char * after_access;
char * p;
int length;
if (name && *name)
length = strlen(name);
else
length = 0;
parts->access = 0;
parts->host = 0;
parts->absolute = 0;
parts->relative = 0;
parts->anchor = 0;
/* Argh. */
if (!length)
return;
after_access = name;
for(p=name; *p; p++) {
if (*p==':') {
*p = 0;
parts->access = name; /* Access name has been specified */
after_access = p+1;
}
if (*p=='/') break;
if (*p=='#') break;
}
for(p=name+length-1; p>=name; p--) {
if (*p =='#') {
parts->anchor=p+1;
*p=0; /* terminate the rest */
}
}
p = after_access;
if (*p=='/'){
if (p[1]=='/') {
parts->host = p+2; /* host has been specified */
*p=0; /* Terminate access */
p=strchr(parts->host,'/'); /* look for end of host name if any */
if(p) {
*p=0; /* Terminate host */
parts->absolute = p+1; /* Root has been found */
}
} else {
parts->absolute = p+1; /* Root found but no host */
}
} else {
parts->relative = (*after_access) ? after_access : 0; /* zero for "" */
}
/* Access specified but no host: the anchor was not really one
e.g. news:j462#36487@foo.bar -- JFG 10/7/92, from bug report */
if (parts->access && ! parts->host && parts->anchor) {
*(parts->anchor - 1) = '#'; /* Restore the '#' in the address */
parts->anchor = 0;
}
} /*scan */
/* Parse a Name relative to another name
** -------------------------------------
**
** This returns those parts of a name which are given (and requested)
** substituting bits from the related name where necessary.
**
** On entry,
** aName A filename given
** relatedName A name relative to which aName is to be parsed
** wanted A mask for the bits which are wanted.
**
** On exit,
** returns A pointer to a malloc'd string which MUST BE FREED
*/
#ifdef __STDC__
char * HTParse(char * aName, char * relatedName, int wanted)
#else
char * HTParse(aName, relatedName, wanted)
char * aName;
char * relatedName;
int wanted;
#endif
{
char * result = 0;
char * return_value = 0;
int len;
char * name = 0;
char * rel = 0;
char * p;
char *access;
struct struct_parts given, related;
if (!aName)
aName = strdup ("\0");
if (!relatedName)
relatedName = strdup ("\0");
/* Make working copies of input strings to cut up:
*/
len = strlen(aName)+strlen(relatedName)+10;
result=(char *)malloc(len); /* Lots of space: more than enough */
StrAllocCopy(name, aName);
StrAllocCopy(rel, relatedName);
scan(name, &given);
scan(rel, &related);
result[0]=0; /* Clear string */
access = given.access ? given.access : related.access;
if (wanted & PARSE_ACCESS)
if (access) {
strcat(result, access);
if(wanted & PARSE_PUNCTUATION) strcat(result, ":");
}
if (given.access && related.access) /* If different, inherit nothing. */
if (strcmp(given.access, related.access)!=0) {
related.host=0;
related.absolute=0;
related.relative=0;
related.anchor=0;
}
if (wanted & PARSE_HOST)
if(given.host || related.host) {
char * tail = result + strlen(result);
if(wanted & PARSE_PUNCTUATION) strcat(result, "//");
strcat(result, given.host ? given.host : related.host);
#define CLEAN_URLS
#ifdef CLEAN_URLS
/* Ignore default port numbers, and trailing dots on FQDNs
which will only cause identical adreesses to look different */
{
char * p;
p = strchr(tail, ':');
if (p && access)
{ /* Port specified */
if ((strcmp(access, "http") == 0 && strcmp(p, ":80") == 0) ||
(strcmp(access, "gopher") == 0 &&
(strcmp(p, ":70") == 0 ||
strcmp(p, ":70+") == 0)))
*p = (char)0; /* It is the default: ignore it */
else if (p && *p && p[strlen(p)-1] == '+')
p[strlen(p)-1] = 0;
}
if (!p)
p = tail + strlen(tail); /* After hostname */
p--; /* End of hostname */
if (strlen (tail) > 3 && (*p == '.'))
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[Parse] tail '%s' p '%s'\n", tail, p);
#endif
*p = (char)0; /* chop final . */
/* OK, at this point we know that *(p+1) exists,
else we would not be here.
If it's 0, then we're done.
If it's not 0, then we move *(p+2) to *(p+1),
etc.
Let's try to use a bcopy... */
if (*(p+1) != '\0')
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[Parse] Copying '%s' to '%s', %d bytes\n",
p+1, p, strlen (p+1));
#endif
/*
bcopy (p+1, p, strlen(p+1));
*/
memcpy (p, p+1, strlen(p+1));
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[Parse] Setting '%c' to 0...\n",
*(p + strlen (p+1)));
#endif
*(p + strlen (p+1)) = '\0';
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[Parse] tail '%s' p '%s'\n", tail, p);
#endif
}
{
char *tmp;
tmp = strchr (tail, '@');
if (!tmp)
tmp = tail;
for (; *tmp; tmp++)
*tmp = TOLOWER (*tmp);
}
}
#endif
}
if (given.host && related.host) /* If different hosts, inherit no path. */
if (strcmp(given.host, related.host)!=0) {
related.absolute=0;
related.relative=0;
related.anchor=0;
}
if (wanted & PARSE_PATH) {
if(given.absolute) { /* All is given */
if(wanted & PARSE_PUNCTUATION) strcat(result, "/");
strcat(result, given.absolute);
} else if(related.absolute) { /* Adopt path not name */
strcat(result, "/");
strcat(result, related.absolute);
if (given.relative) {
p = strchr(result, '?'); /* Search part? */
if (!p) p=result+strlen(result)-1;
for (; *p!='/'; p--); /* last / */
p[1]=0; /* Remove filename */
strcat(result, given.relative); /* Add given one */
HTSimplify (result);
}
} else if(given.relative) {
strcat(result, given.relative); /* what we've got */
} else if(related.relative) {
strcat(result, related.relative);
} else { /* No inheritance */
strcat(result, "/");
}
}
if (wanted & PARSE_ANCHOR)
if(given.anchor || related.anchor) {
if(wanted & PARSE_PUNCTUATION) strcat(result, "#");
strcat(result, given.anchor ? given.anchor : related.anchor);
}
if (rel)
free(rel);
if (name)
free(name);
StrAllocCopy(return_value, result);
free(result);
return return_value; /* exactly the right length */
}
/* Simplify a filename
// -------------------
//
// A unix-style file is allowed to contain the seqeunce xxx/../ which may be
// replaced by "" , and the seqeunce "/./" which may be replaced by "/".
// Simplification helps us recognize duplicate filenames.
//
// Thus, /etc/junk/../fred becomes /etc/fred
// /etc/junk/./fred becomes /etc/junk/fred
//
// but we should NOT change
// http://fred.xxx.edu/../..
//
// or ../../albert.html
*/
#ifdef __STDC__
void HTSimplify(char * filename)
#else
void HTSimplify(filename)
char * filename;
#endif
{
char * p;
char * q;
if (filename[0] && filename[1])
{
for(p=filename+2; *p; p++)
{
if (*p=='/')
{
if ((p[1]=='.') && (p[2]=='.') && (p[3]=='/' || !p[3] ))
{
/* Changed clause below to (q>filename) due to attempted
read to q = filename-1 below. */
for (q = p-1; (q>filename) && (*q!='/'); q--)
; /* prev slash */
if (q[0]=='/' && 0!=strncmp(q, "/../", 4)
&& !(q-1>filename && q[-1]=='/'))
{
strcpy(q, p+3); /* Remove /xxx/.. */
if (!*filename) strcpy(filename, "/");
p = q-1; /* Start again with prev slash */
}
}
else if ((p[1]=='.') && (p[2]=='/' || !p[2]))
{
strcpy(p, p+2); /* Remove a slash and a dot */
}
}
}
}
}
/* Make Relative Name
** ------------------
**
** This function creates and returns a string which gives an expression of
** one address as related to another. Where there is no relation, an absolute
** address is retured.
**
** On entry,
** Both names must be absolute, fully qualified names of nodes
** (no anchor bits)
**
** On exit,
** The return result points to a newly allocated name which, if
** parsed by HTParse relative to relatedName, will yield aName.
** The caller is responsible for freeing the resulting name later.
**
*/
#ifdef __STDC__
char * HTRelative(char * aName, char *relatedName)
#else
char * HTRelative(aName, relatedName)
char * aName;
char * relatedName;
#endif
{
char * result = 0;
WWW_CONST char *p = aName;
WWW_CONST char *q = relatedName;
WWW_CONST char * after_access = 0;
WWW_CONST char * path = 0;
WWW_CONST char * last_slash = 0;
int slashes = 0;
for(;*p; p++, q++) { /* Find extent of match */
if (*p!=*q) break;
if (*p==':') after_access = p+1;
if (*p=='/') {
last_slash = p;
slashes++;
if (slashes==3) path=p;
}
}
/* q, p point to the first non-matching character or zero */
if (!after_access) { /* Different access */
StrAllocCopy(result, aName);
} else if (slashes<3){ /* Different nodes */
StrAllocCopy(result, after_access);
} else if (slashes==3){ /* Same node, different path */
StrAllocCopy(result, path);
} else { /* Some path in common */
int levels= 0;
for(; *q && (*q!='#'); q++) if (*q=='/') levels++;
result = (char *)malloc(3*levels + strlen(last_slash) + 1);
result[0]=0;
for(;levels; levels--)strcat(result, "../");
strcat(result, last_slash+1);
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "HT: `%s' expressed relative to\n `%s' is\n `%s'.",
aName, relatedName, result);
#endif
return result;
}
static unsigned char isAcceptable[96] =
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
{ 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5x PQRSTUVWXYZ[\]^_ */
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7x pqrstuvwxyz{\}~ DEL */
#define HT_HEX(i) (i < 10 ? '0'+i : 'A'+ i - 10)
/* The string returned from here, if any, can be free'd by caller. */
char *HTEscape (char *part)
{
char *q;
char *p; /* Pointers into keywords */
char *escaped;
if (!part)
return NULL;
escaped = (char *)malloc (strlen (part) * 3 + 1);
for (q = escaped, p = part; *p != '\0'; p++)
{
int c = (int)((unsigned char)(*p));
if (c >= 32 && c <= 127 && isAcceptable[c-32])
{
*q++ = *p;
}
else
{
*q++ = '%';
*q++ = HT_HEX(c / 16);
*q++ = HT_HEX(c % 16);
}
}
*q=0;
return escaped;
}
/* Decode %xx escaped characters HTUnEscape()
** -----------------------------
**
** This function takes a pointer to a string in which some
** characters may have been encoded in %xy form, where xy is
** the acsii hex code for character 16x+y.
** The string is converted in place, as it will never grow.
*/
PRIVATE char from_hex ARGS1(char, c)
{
return c >= '0' && c <= '9' ? c - '0'
: c >= 'A' && c <= 'F'? c - 'A' + 10
: c - 'a' + 10; /* accept small letters just in case */
}
PUBLIC char * HTUnEscape ARGS1( char *, str)
{
char * p = str;
char * q = str;
while(*p) {
if (*p == HEX_ESCAPE) {
p++;
if (*p) *q = from_hex(*p++) * 16;
if (*p) *q = (*q + from_hex(*p++));
q++;
} else if (*p == '+')
{
p++;
*q++ = ' ';
} else {
*q++ = *p++;
}
}
*q++ = 0;
return str;
} /* HTUnEscape */

144
libwww2/HTParse.h Normal file
View File

@@ -0,0 +1,144 @@
/* HTParse: URL parsing in the WWW Library
HTPARSE
This module of the WWW library contains code to parse URLs and various related things.
Implemented by HTParse.c .
*/
#ifndef HTPARSE_H
#define HTPARSE_H
#include "HTUtils.h"
/*
The following are flag bits which may be ORed together to form a number to give the
'wanted' argument to HTParse.
*/
#define PARSE_ACCESS 16
#define PARSE_HOST 8
#define PARSE_PATH 4
#define PARSE_ANCHOR 2
#define PARSE_PUNCTUATION 1
#define PARSE_ALL 31
/*
HTParse: Parse a URL relative to another URL
This returns those parts of a name which are given (and requested) substituting bits
from the related name where necessary.
ON ENTRY
aName A filename given
relatedName A name relative to which aName is to be parsed
wanted A mask for the bits which are wanted.
ON EXIT,
returns A pointer to a malloc'd string which MUST BE FREED
*/
extern char * HTParse PARAMS((char * aName, char * relatedName, int wanted));
/*
HTStrip: Strip white space off a string
ON EXIT
Return value points to first non-white character, or to 0 if none.
All trailing white space is OVERWRITTEN with zero.
*/
#ifdef __STDC__
extern char * HTStrip(char * s);
#else
extern char * HTStrip();
#endif
/*
HTSimplify: Simplify a UTL
A URL is allowed to contain the seqeunce xxx/../ which may be replaced by "" , and the
seqeunce "/./" which may be replaced by "/". Simplification helps us recognize
duplicate filenames. It doesn't deal with soft links, though. The new (shorter)
filename overwrites the old.
*/
/*
** Thus, /etc/junk/../fred becomes /etc/fred
** /etc/junk/./fred becomes /etc/junk/fred
*/
#ifdef __STDC__
extern void HTSimplify(char * filename);
#else
extern void HTSimplify();
#endif
/*
HTRelative: Make Relative (Partial) URL
This function creates and returns a string which gives an expression of one address as
related to another. Where there is no relation, an absolute address is retured.
ON ENTRY,
Both names must be absolute, fully qualified names of nodes (no anchor bits)
ON EXIT,
The return result points to a newly allocated name which, if parsed by HTParse relative
to relatedName, will yield aName. The caller is responsible for freeing the resulting
name later.
*/
#ifdef __STDC__
extern char * HTRelative(char * aName, char *relatedName);
#else
extern char * HTRelative();
#endif
/*
HTEscape: Encode unacceptable characters in string
This funtion takes a string containing any sequence of ASCII characters, and returns a
malloced string containing the same infromation but with all "unacceptable" characters
represented in the form %xy where X and Y are two hex digits.
*/
extern char * HTEscape PARAMS((char * str));
/*
HTUnEscape: Decode %xx escaped characters
This function takes a pointer to a string in which character smay have been encoded in
%xy form, where xy is the acsii hex code for character 16x+y. The string is converted
in place, as it will never grow.
*/
extern char * HTUnEscape PARAMS(( char * str));
#endif /* HTPARSE_H */
/*
end of HTParse
*/

275
libwww2/HTPasswd.c Normal file
View File

@@ -0,0 +1,275 @@
/* MODULE HTPasswd.c
** PASSWORD FILE ROUTINES
**
** AUTHORS:
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
**
**
** BUGS:
**
**
*/
#include "../config.h"
#include <string.h>
#include "HTUtils.h"
#include "HTAAUtil.h" /* Common parts of AA */
#include "HTAAFile.h" /* File routines */
#include "HTPasswd.h" /* Implemented here */
#include "tcp.h" /* FROMASCII() */
extern char *crypt();
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
PRIVATE char salt_chars [65] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
/* PUBLIC HTAA_encryptPasswd()
** ENCRYPT PASSWORD TO THE FORM THAT IT IS SAVED
** IN THE PASSWORD FILE.
** ON ENTRY:
** password is a string of arbitrary lenght.
**
** ON EXIT:
** returns password in one-way encrypted form.
**
** NOTE:
** Uses currently the C library function crypt(), which
** only accepts at most 8 characters long strings and produces
** always 13 characters long strings. This function is
** called repeatedly so that longer strings can be encrypted.
** This is of course not as safe as encrypting the entire
** string at once, but then again, we are not that paranoid
** about the security inside the machine.
**
*/
PUBLIC char *HTAA_encryptPasswd ARGS1(WWW_CONST char *, password)
{
char salt[3];
char chunk[9];
char *result;
char *tmp;
WWW_CONST char *cur = password;
int len = strlen(password);
extern time_t theTime;
int random = (int)theTime; /* This is random enough */
if (!(result = (char*)malloc(13*((strlen(password)+7)/8) + 1)))
outofmem(__FILE__, "HTAA_encryptPasswd");
*result = (char)0;
while (len > 0) {
salt[0] = salt_chars[random%64];
salt[1] = salt_chars[(random/64)%64];
salt[2] = (char)0;
strncpy(chunk, cur, 8);
chunk[8] = (char)0;
tmp = crypt((char*)password, salt); /*crypt() doesn't change its args*/
strcat(result, tmp);
free(tmp);
cur += 8;
len -= 8;
} /* while */
return result;
}
/* PUBLIC HTAA_passwdMatch()
** VERIFY THE CORRECTNESS OF A GIVEN PASSWORD
** AGAINST A ONE-WAY ENCRYPTED FORM OF PASSWORD.
** ON ENTRY:
** password is cleartext password.
** encrypted is one-way encrypted password, as returned
** by function HTAA_encryptPasswd().
** This is typically read from the password
** file.
**
** ON EXIT:
** returns YES, if password matches the encrypted one.
** NO, if not, or if either parameter is NULL.
*/
PUBLIC BOOL HTAA_passwdMatch ARGS2(WWW_CONST char *, password,
WWW_CONST char *, encrypted)
{
char *result;
int len;
int status;
if (!password || !encrypted ||
13*((strlen(password)+7)/8) != strlen(encrypted))
return NO;
len = strlen(encrypted);
if (!(result = (char*)malloc(len + 1)))
outofmem(__FILE__, "HTAA_encryptPasswd");
*result = (char)0;
while (len > 0) {
char salt[3];
char chunk[9];
WWW_CONST char *cur1 = password;
WWW_CONST char *cur2 = encrypted;
char *tmp;
salt[0] = *cur2;
salt[1] = *(cur2+1);
salt[2] = (char)0;
strncpy(chunk, cur1, 8);
chunk[8] = (char)0;
tmp = crypt((char*)password, salt);
strcat(result, tmp);
free(tmp);
cur1 += 8;
cur2 += 13;
len -= 13;
} /* while */
status = strcmp(result, encrypted);
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"%s `%s' (encrypted: `%s') with: `%s' => %s\n",
"HTAA_passwdMatch: Matching password:",
password, result, encrypted,
(status==0 ? "OK" : "INCORRECT"));
#endif
free(result);
if (status==0)
return YES;
else
return NO;
}
/* PUBLIC HTAAFile_readPasswdRec()
** READ A RECORD FROM THE PASSWORD FILE
** ON ENTRY:
** fp open password file
** out_username buffer to put the read username, must be at
** least MAX_USERNAME_LEN+1 characters long.
** out_passwd buffer to put the read password, must be at
** least MAX_PASSWORD_LEN+1 characters long.
** ON EXIT:
** returns EOF on end of file,
** otherwise the number of read fields
** (i.e. in a correct case returns 2).
** out_username contains the null-terminated read username.
** out_password contains the null-terminated read password.
**
** FORMAT OF PASSWORD FILE:
** username:password:maybe real name or other stuff
** (may include even colons)
**
** There may be whitespace (blanks or tabs) in the beginning and
** the end of each field. They are ignored.
*/
PUBLIC int HTAAFile_readPasswdRec ARGS3(FILE *, fp,
char *, out_username,
char *, out_password)
{
char terminator;
terminator = HTAAFile_readField(fp, out_username, MAX_USERNAME_LEN);
if (terminator == EOF) { /* End of file */
return EOF;
}
else if (terminator == CR || terminator == LF) { /* End of line */
HTAAFile_nextRec(fp);
return 1;
}
else {
HTAAFile_readField(fp, out_password, MAX_PASSWORD_LEN);
HTAAFile_nextRec(fp);
return 2;
}
}
/* PUBLIC HTAA_checkPassword()
** CHECK A USERNAME-PASSWORD PAIR
** ON ENTRY:
** username is a null-terminated string containing
** the client's username.
** password is a null-terminated string containing
** the client's corresponding password.
** filename is a null-terminated absolute filename
** for password file.
** If NULL or empty, the value of
** PASSWD_FILE is used.
** ON EXIT:
** returns YES, if the username-password pair was correct.
** NO, otherwise; also, if open fails.
*/
PUBLIC BOOL HTAA_checkPassword ARGS3(WWW_CONST char *, username,
WWW_CONST char *, password,
WWW_CONST char *, filename)
{
FILE *fp = NULL;
char user[MAX_USERNAME_LEN+1];
char pw[MAX_PASSWORD_LEN+1];
int status;
if (filename && *filename) fp = fopen(filename,"r");
else fp = fopen(PASSWD_FILE,"r");
if (!fp) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "%s `%s'\n",
"HTAA_checkPassword: Unable to open password file",
(filename && *filename ? filename : PASSWD_FILE));
#endif
return NO;
}
do {
if (2 == (status = HTAAFile_readPasswdRec(fp,user,pw))) {
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"HTAAFile_validateUser: %s \"%s\" %s \"%s:%s\"\n",
"Matching username:", username,
"against passwd record:", user, pw);
#endif
if (username && user && !strcmp(username,user)) {
/* User's record found */
if (pw) { /* So password is required for this user */
if (!password ||
!HTAA_passwdMatch(password,pw)) /* Check the password */
status = EOF; /* If wrong, indicate it with EOF */
}
break; /* exit loop */
} /* if username found */
} /* if record is ok */
} while (status != EOF);
fclose(fp);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTAAFile_checkPassword: (%s,%s) %scorrect\n",
username, password, ((status != EOF) ? "" : "in"));
#endif
if (status == EOF) return NO; /* We traversed to the end without luck */
else return YES; /* The user was found */
}

127
libwww2/HTPasswd.h Normal file
View File

@@ -0,0 +1,127 @@
/* PASSWORD FILE ROUTINES
*/
#ifndef HTPASSWD_H
#define HTPASSWD_H
#include "HTUtils.h"
#include "HTList.h"
#ifdef SHORT_NAMES
#define HTAAenPw HTAA_encryptPasswd
#define HTAApwMa HTAA_passwdMatch
#define HTAAFrPR HTAAFile_readPasswdRec
#define HTAAchPw HTAA_checkPasswd
#endif /* SHORT_NAMES */
/*
User Authentication
HTAA_checkPassword(username,password,passwdfile)opens the password file, and checks if
the username-password pair is correct. Return value is YES, if and only if they are
correct. Otherwise, and also if the open fails, returns NO.
If the given password file name is NULL or an empty string, the default password file
name is used (macro PASSWD_FILE).
*/
/* PUBLIC HTAA_checkPassword()
** VALIDATE A USERNAME-PASSWORD PAIR
** ON ENTRY:
** username is a null-terminated string containing
** the client's username.
** password is a null-terminated string containing
** the client's corresponding password.
** filename is a null-terminated absolute filename
** for password file.
** If NULL or empty, the value of
** PASSWD_FILE is used.
** ON EXIT:
** returns YES, if the username-password pair was correct.
** NO, otherwise; also, if open fails.
*/
PUBLIC BOOL HTAA_checkPassword PARAMS((WWW_CONST char * username,
WWW_CONST char * password,
WWW_CONST char * filename));
/*
Password File Maintenance Routines
*/
/* PUBLIC HTAA_encryptPasswd()
** ENCRYPT PASSWORD TO THE FORM THAT IT IS SAVED
** IN THE PASSWORD FILE.
** ON ENTRY:
** password is a string of arbitrary lenght.
**
** ON EXIT:
** returns password in one-way encrypted form.
**
** NOTE:
** Uses currently the C library function crypt(), which
** only accepts at most 8 characters long strings and produces
** always 13 characters long strings. This function is
** called repeatedly so that longer strings can be encrypted.
** This is of course not as safe as encrypting the entire
** string at once, but then again, we are not that paranoid
** about the security inside the machine.
**
*/
PUBLIC char *HTAA_encryptPasswd PARAMS((WWW_CONST char * password));
/* PUBLIC HTAA_passwdMatch()
** VERIFY THE CORRECTNESS OF A GIVEN PASSWORD
** AGAINST A ONE-WAY ENCRYPTED FORM OF PASSWORD.
** ON ENTRY:
** password is cleartext password.
** encrypted is one-way encrypted password, as returned
** by function HTAA_encryptPasswd().
** This is typically read from the password
** file.
**
** ON EXIT:
** returns YES, if password matches the encrypted one.
** NO, if not, or if either parameter is NULL.
*/
PUBLIC BOOL HTAA_passwdMatch PARAMS((WWW_CONST char * password,
WWW_CONST char * encrypted));
/* PUBLIC HTAAFile_readPasswdRec()
** READ A RECORD FROM THE PASSWORD FILE
** ON ENTRY:
** fp open password file
** out_username buffer to put the read username, must be at
** least MAX_USERNAME_LEN+1 characters long.
** out_passwd buffer to put the read password, must be at
** least MAX_PASSWORD_LEN+1 characters long.
** ON EXIT:
** returns EOF on end of file,
** otherwise the number of read fields
** (i.e. in a correct case returns 2).
** out_username contains the null-terminated read username.
** out_password contains the null-terminated read password.
**
** FORMAT OF PASSWORD FILE:
** username:password:maybe real name or other stuff
** (may include even colons)
**
** There may be whitespace (blanks or tabs) in the beginning and
** the end of each field. They are ignored.
*/
PUBLIC int HTAAFile_readPasswdRec PARAMS((FILE * fp,
char * out_username,
char * out_password));
/*
*/
#endif /* not HTPASSWD_H */
/*
End of file HTPasswd.h. */

140
libwww2/HTPlain.c Normal file
View File

@@ -0,0 +1,140 @@
/* Plain text object HTWrite.c
** =================
**
** This version of the stream object just writes to a socket.
** The socket is assumed open and left open.
**
** Bugs:
** strings written must be less than buffer size.
*/
#include "../config.h"
#include "HTPlain.h"
#include "HTUtils.h"
#include "HText.h"
#include "HTFile.h"
#include "HTCompressed.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* HTML Object
** -----------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
HText * text;
int compressed;
};
/*_________________________________________________________________________
**
** A C T I O N R O U T I N E S
*/
/* Character handling
** ------------------
*/
PRIVATE void HTPlain_put_character ARGS2(HTStream *, me, char, c)
{
HText_appendCharacter(me->text, c);
}
/* String handling
** ---------------
**
*/
PRIVATE void HTPlain_put_string ARGS2(HTStream *, me, WWW_CONST char*, s)
{
HText_appendText(me->text, s);
}
PRIVATE void HTPlain_write ARGS3(HTStream *, me, WWW_CONST char*, s, int, l)
{
HText_appendBlock (me->text, s, l);
}
/* Free an HTML object
** -------------------
**
** Note that the SGML parsing context is freed, but the created object is not,
** as it takes on an existence of its own unless explicitly freed.
*/
PRIVATE void HTPlain_free ARGS1(HTStream *, me)
{
if (me->compressed != COMPRESSED_NOT)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr,
"[HTPlain_free] OK, we're going to decompress HText\n");
#endif
HTCompressedHText (me->text, me->compressed, 1);
}
free(me);
}
/* End writing
*/
PRIVATE void HTPlain_end_document ARGS1(HTStream *, me)
{
HText_endAppend(me->text);
}
PRIVATE void HTPlain_handle_interrupt ARGS1(HTStream *, me)
{
HText_doAbort(me->text);
}
/* Structured Object Class
** -----------------------
*/
PUBLIC WWW_CONST HTStreamClass HTPlain =
{
"SocketWriter",
HTPlain_free,
HTPlain_end_document,
HTPlain_put_character, HTPlain_put_string, HTPlain_write,
HTPlain_handle_interrupt
};
/* New object
** ----------
*/
PUBLIC HTStream* HTPlainPresent ARGS5(
HTPresentation *, pres,
HTParentAnchor *, anchor,
HTStream *, sink,
HTFormat, format_in,
int, compressed)
{
HTStream* me = (HTStream*)malloc(sizeof(*me));
me->isa = &HTPlain;
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "[HTPlainPresent] here we are; format_in is '%s' and compressed is %d\n", HTAtom_name (format_in), compressed);
#endif
me->text = HText_new();
me->compressed = compressed;
HText_beginAppend(me->text);
if (me->compressed == COMPRESSED_NOT)
HText_appendText(me->text, "<PLAINTEXT>\n");
return (HTStream*) me;
}

20
libwww2/HTPlain.h Normal file
View File

@@ -0,0 +1,20 @@
/* Plain text object HTPlain.h
** -----------------
**
**
*/
#ifndef HTPLAIN_H
#define HTPLAIN_H
#include "HTStream.h"
#include "HTAnchor.h"
extern HTStream* HTPlainPresent PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
#endif

71
libwww2/HTSort.c Normal file
View File

@@ -0,0 +1,71 @@
/* Simple string sorting support, thanks to qsort(). */
#include "../config.h"
#include "HTUtils.h"
#include <string.h>
#define SIZE_OF_HUNK 100
static char **hunk = NULL;
static int size_of_hunk;
static int count;
void HTSortInit (void)
{
count = 0;
if (!hunk)
{
size_of_hunk = SIZE_OF_HUNK;
hunk = (char **)malloc (sizeof (char *) * size_of_hunk);
}
return;
}
static void expand_hunk (void)
{
/* Make hunk bigger by SIZE_OF_HUNK elements. */
size_of_hunk += SIZE_OF_HUNK;
hunk = (char **)realloc (hunk, sizeof (char *) * size_of_hunk);
return;
}
void HTSortAdd (char *str)
{
/* If we don't have room, expand. */
if (count == size_of_hunk)
expand_hunk ();
hunk[count++] = str;
return;
}
static int dsortf (char **s1, char **s2)
{
return (strcmp (*(char **)s1, *(char **)s2));
}
void HTSortSort (void)
{
qsort ((void *)hunk,
count,
sizeof (char *),
(void *)dsortf);
return;
}
int HTSortCurrentCount (void)
{
return count;
}
char *HTSortFetch (int i)
{
if (i < count)
return hunk[i];
else
return NULL;
}

5
libwww2/HTSort.h Normal file
View File

@@ -0,0 +1,5 @@
extern void HTSortInit (void);
extern void HTSortAdd (char *str);
extern void HTSortSort (void);
extern int HTSortCurrentCount (void);
extern char *HTSortFetch (int i);

56
libwww2/HTStream.h Normal file
View File

@@ -0,0 +1,56 @@
/* The Stream class definition -- libwww
STREAM OBJECT DEFINITION
A Stream object is something which accepts a stream of text.
The creation methods will vary on the type of Stream Object, but
the methods used to write to it and close it are common.
*/
#ifndef HTSTREAM_H
#define HTSTREAM_H
#include "HTUtils.h"
typedef struct _HTStream HTStream;
/*
These are the common methods of all streams. They should be
self-explanatory, except for end_document which must be called
before free. It should be merged with free in fact: it should be
dummy for new streams.
The put_block method was write, but this upset systems whiuch had
macros for write().
*/
typedef struct _HTStreamClass {
char* name; /* Just for diagnostics */
void (*free) PARAMS((
HTStream* me));
void (*end_document) PARAMS((
HTStream* me));
void (*put_character) PARAMS((
HTStream* me,
char ch));
void (*put_string) PARAMS((
HTStream* me,
char * str));
void (*put_block) PARAMS((
HTStream* me,
char * str,
int len));
void (*handle_interrupt) PARAMS((
HTStream* me));
}HTStreamClass;
#endif /* HTSTREAM_H */

133
libwww2/HTString.c Normal file
View File

@@ -0,0 +1,133 @@
/* Case-independent string comparison HTString.c
**
** Original version came with listserv implementation.
** Version TBL Oct 91 replaces one which modified the strings.
** 02-Dec-91 (JFG) Added stralloccopy and stralloccat
** 23 Jan 92 (TBL) Changed strallocc* to 8 char HTSAC* for VM and suchlike
** 6 Oct 92 (TBL) Moved WWW_TraceFlag in here to be in library
*/
#include "../config.h"
#include <ctype.h>
#include "HTUtils.h"
#include "tcp.h"
PUBLIC int WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */
#ifndef VC
#define VC "unknown"
#endif
PUBLIC WWW_CONST char * HTLibraryVersion = "2.12 modified"; /* String for help screen etc */
/* Strings of any length
** ---------------------
*/
PUBLIC int strcasecomp ARGS2 (WWW_CONST char*,a, WWW_CONST char *,b)
{
WWW_CONST char *p =a;
WWW_CONST char *q =b;
for(p=a, q=b; *p && *q; p++, q++) {
int diff = TOLOWER(*p) - TOLOWER(*q);
if (diff) return diff;
}
if (*p) return 1; /* p was longer than q */
if (*q) return -1; /* p was shorter than q */
return 0; /* Exact match */
}
/* With count limit
** ----------------
*/
PUBLIC int strncasecomp ARGS3(WWW_CONST char*,a, WWW_CONST char *,b, int,n)
{
WWW_CONST char *p =a;
WWW_CONST char *q =b;
for(p=a, q=b;; p++, q++) {
int diff;
if (p == a+n) return 0; /* Match up to n characters */
if (!(*p && *q)) return *p - *q;
diff = TOLOWER(*p) - TOLOWER(*q);
if (diff) return diff;
}
/*NOTREACHED*/
}
/* Allocate a new copy of a string, and returns it
*/
PUBLIC char * HTSACopy
ARGS2 (char **,dest, WWW_CONST char *,src)
{
if (!dest)
return NULL;
if (*dest) free(*dest);
if (!src)
*dest = NULL;
else {
*dest = (char *) malloc (strlen(src) + 1);
if (*dest == NULL) outofmem(__FILE__, "HTSACopy");
strcpy (*dest, src);
}
return *dest;
}
/* String Allocate and Concatenate
*/
PUBLIC char * HTSACat
ARGS2 (char **,dest, WWW_CONST char *,src)
{
if (src && *src) {
if (*dest) {
int length = strlen (*dest);
*dest = (char *) realloc (*dest, length + strlen(src) + 1);
if (*dest == NULL) outofmem(__FILE__, "HTSACat");
strcpy (*dest + length, src);
} else {
*dest = (char *) malloc (strlen(src) + 1);
if (*dest == NULL) outofmem(__FILE__, "HTSACat");
strcpy (*dest, src);
}
}
return *dest;
}
/* Find next Field
** ---------------
**
** On entry,
** *pstr points to a string containig white space separated
** field, optionlly quoted.
**
** On exit,
** *pstr has been moved to the first delimiter past the
** field
** THE STRING HAS BEEN MUTILATED by a 0 terminator
**
** returns a pointer to the first field
*/
PUBLIC char * HTNextField ARGS1(char **, pstr)
{
char * p = *pstr;
char * start; /* start of field */
while(*p && WHITE(*p)) p++; /* Strip white space */
if (!*p) {
*pstr = p;
return NULL; /* No first field */
}
if (*p == '"') { /* quoted field */
p++;
start = p;
for(;*p && *p!='"'; p++) {
if (*p == '\\' && p[1]) p++; /* Skip escaped chars */
}
} else {
start = p;
while(*p && !WHITE(*p)) p++; /* Skip first field */
}
if (*p) *p++ = 0;
*pstr = p;
return start;
}

49
libwww2/HTString.h Normal file
View File

@@ -0,0 +1,49 @@
/* String handling for libwww
STRINGS
Case-independent string comparison and allocations with copies etc
*/
#ifndef HTSTRING_H
#define HTSTRING_H
#include "HTUtils.h"
extern int WWW_TraceFlag; /* Global flag for all W3 trace */
extern WWW_CONST char * HTLibraryVersion; /* String for help screen etc */
/*
Case-insensitive string comparison
The usual routines (comp instead of cmp) had some problem.
*/
extern int strcasecomp PARAMS((WWW_CONST char *a, WWW_CONST char *b));
extern int strncasecomp PARAMS((WWW_CONST char *a, WWW_CONST char *b, int n));
/*
Malloced string manipulation
*/
#define StrAllocCopy(dest, src) HTSACopy (&(dest), src)
#define StrAllocCat(dest, src) HTSACat (&(dest), src)
extern char * HTSACopy PARAMS ((char **dest, WWW_CONST char *src));
extern char * HTSACat PARAMS ((char **dest, WWW_CONST char *src));
/*
Next word or quoted string
*/
extern char * HTNextField PARAMS ((char** pstr));
#endif
/*
end
*/

615
libwww2/HTTCP.c Normal file
View File

@@ -0,0 +1,615 @@
/* Generic Communication Code HTTCP.c
** ==========================
**
** This code is in common between client and server sides.
**
** 16 Jan 92 TBL Fix strtol() undefined on CMU Mach.
** 25 Jun 92 JFG Added DECNET option through TCP socket emulation.
*/
/* SOCKS mods by:
* Ying-Da Lee, <ylee@syl.dl.nec.com>
* NEC Systems Laboratory
* C&C Software Technology Center
*/
#include "../config.h"
#include "HTUtils.h"
#include "HTParse.h"
#include "HTAlert.h"
#include "HTAccess.h"
#include "tcp.h" /* Defines SHORT_NAMES if necessary */
#ifdef SHORT_NAMES
#define HTInetStatus HTInStat
#define HTInetString HTInStri
#define HTParseInet HTPaInet
#endif
#ifdef __STDC__
#include <stdlib.h>
#endif
#if defined(SVR4) && !defined(SCO) && !defined(linux) && !defined(DGUX)
#include <sys/filio.h>
#endif
#if defined(DGUX)
#include <sys/file.h>
#endif
/* Apparently needed for AIX 3.2. */
#ifndef FD_SETSIZE
#define FD_SETSIZE 256
#endif
#ifndef DISABLE_TRACE
extern int httpTrace;
extern int www2Trace;
#endif
/* Module-Wide variables
*/
PRIVATE char *hostname=0; /* The name of this host */
/* PUBLIC VARIABLES
*/
/* PUBLIC SockA HTHostAddress; */ /* The internet address of the host */
/* Valid after call to HTHostName() */
/* Encode INET status (as in sys/errno.h) inet_status()
** ------------------
**
** On entry,
** where gives a description of what caused the error
** global errno gives the error number in the unix way.
**
** On return,
** returns a negative status in the unix way.
*/
#ifndef errno
extern int errno;
#endif /* errno */
/* Report Internet Error
** ---------------------
*/
#ifdef __STDC__
PUBLIC int HTInetStatus(char *where)
#else
PUBLIC int HTInetStatus(where)
char *where;
#endif
{
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr, "TCP: Error %d in `errno' after call to %s() failed.\n\t%s\n",
errno, where, strerror(errno));
}
#endif
return -1;
}
/* Parse a cardinal value parse_cardinal()
** ----------------------
**
** On entry,
** *pp points to first character to be interpreted, terminated by
** non 0:9 character.
** *pstatus points to status already valid
** maxvalue gives the largest allowable value.
**
** On exit,
** *pp points to first unread character
** *pstatus points to status updated iff bad
*/
PUBLIC unsigned int HTCardinal ARGS3
(int *, pstatus,
char **, pp,
unsigned int, max_value)
{
int n;
if ( (**pp<'0') || (**pp>'9')) { /* Null string is error */
*pstatus = -3; /* No number where one expeceted */
return 0;
}
n=0;
while ((**pp>='0') && (**pp<='9')) n = n*10 + *((*pp)++) - '0';
if (n>max_value) {
*pstatus = -4; /* Cardinal outside range */
return 0;
}
return n;
}
/* Produce a string for an Internet address
** ----------------------------------------
**
** On exit,
** returns a pointer to a static string which must be copied if
** it is to be kept.
*/
PUBLIC WWW_CONST char * HTInetString ARGS1(SockA*,sin)
{
static char string[16];
sprintf(string, "%d.%d.%d.%d",
(int)*((unsigned char *)(&sin->sin_addr)+0),
(int)*((unsigned char *)(&sin->sin_addr)+1),
(int)*((unsigned char *)(&sin->sin_addr)+2),
(int)*((unsigned char *)(&sin->sin_addr)+3));
return string;
}
/* Parse a network node address and port
** -------------------------------------
**
** On entry,
** str points to a string with a node name or number,
** with optional trailing colon and port number.
** sin points to the binary internet or decnet address field.
**
** On exit,
** *sin is filled in. If no port is specified in str, that
** field is left unchanged in *sin.
*/
PUBLIC int HTParseInet ARGS2(SockA *,sin, WWW_CONST char *,str)
{
char *port;
char host[256];
struct hostent *phost; /* Pointer to host - See netdb.h */
int numeric_addr;
char *tmp;
static char *cached_host = NULL;
static char *cached_phost_h_addr = NULL;
static int cached_phost_h_length = 0;
strcpy(host, str); /* Take a copy we can mutilate */
/* Parse port number if present */
if (port=strchr(host, ':'))
{
*port++ = 0; /* Chop off port */
if (port[0]>='0' && port[0]<='9')
{
sin->sin_port = htons(atol(port));
}
}
/* Parse host number if present. */
numeric_addr = 1;
for (tmp = host; *tmp; tmp++)
{
/* If there's a non-numeric... */
if ((*tmp < '0' || *tmp > '9') && *tmp != '.')
{
numeric_addr = 0;
goto found_non_numeric_or_done;
}
}
found_non_numeric_or_done:
if (numeric_addr)
{ /* Numeric node address: */
sin->sin_addr.s_addr = inet_addr(host); /* See arpa/inet.h */
}
else
{ /* Alphanumeric node name: */
if (cached_host && (strcmp (cached_host, host) == 0))
{
#if 0
fprintf (stderr, "=-= Matched '%s' and '%s', using cached_phost.\n",
cached_host, host);
#endif
memcpy(&sin->sin_addr, cached_phost_h_addr, cached_phost_h_length);
}
else
{
extern int h_errno;
#if 0
fprintf (stderr, "=+= Fetching on '%s'\n", host);
#endif
phost = gethostbyname (host);
if (!phost)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf
(stderr,
"HTTPAccess: Can't find internet node name `%s'.\n",host);
#endif
return -1; /* Fail? */
}
/* Free previously cached strings. */
if (cached_host) {
free (cached_host);
cached_host=NULL;
}
if (cached_phost_h_addr) {
free (cached_phost_h_addr);
cached_phost_h_addr=NULL;
}
/* Cache new stuff. */
cached_host = strdup (host);
cached_phost_h_addr = calloc (phost->h_length + 1, 1);
memcpy (cached_phost_h_addr, phost->h_addr, phost->h_length);
#if 0
cached_phost_h_addr = strdup (phost->h_addr);
#endif
cached_phost_h_length = phost->h_length;
memcpy(&sin->sin_addr, phost->h_addr, phost->h_length);
}
}
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr,
"TCP: Parsed address as port %d, IP address %d.%d.%d.%d\n",
(int)ntohs(sin->sin_port),
(int)*((unsigned char *)(&sin->sin_addr)+0),
(int)*((unsigned char *)(&sin->sin_addr)+1),
(int)*((unsigned char *)(&sin->sin_addr)+2),
(int)*((unsigned char *)(&sin->sin_addr)+3));
#endif
return 0; /* OK */
}
/* Derive the name of the host on which we are
** -------------------------------------------
**
*/
#ifdef __STDC__
PRIVATE void get_host_details(void)
#else
PRIVATE void get_host_details()
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64 /* Arbitrary limit */
#endif
{
char name[MAXHOSTNAMELEN+1]; /* The name of this host */
#ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
struct hostent * phost; /* Pointer to host -- See netdb.h */
#endif
int namelength = sizeof(name);
if (hostname) return; /* Already done */
gethostname(name, namelength); /* Without domain */
#ifndef DISABLE_TRACE
if (www2Trace) {
fprintf(stderr, "TCP: Local host name is %s\n", name);
}
#endif
StrAllocCopy(hostname, name);
#ifdef NEED_HOST_ADDRESS /* no -- needs name server! */
phost=gethostbyname(name); /* See netdb.h */
if (!phost) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"TCP: Can't find my own internet node address for `%s'!!\n",
name);
#endif
return; /* Fail! */
}
StrAllocCopy(hostname, phost->h_name);
memcpy(&HTHostAddress, &phost->h_addr, phost->h_length);
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, " Name server says that I am `%s' = %s\n",
hostname, HTInetString(&HTHostAddress));
#endif
#endif
}
#ifdef __STDC__
PUBLIC char * HTHostName(void)
#else
PUBLIC char * HTHostName()
#endif
{
get_host_details();
return hostname;
}
#ifdef SOCKS
struct in_addr SOCKS_ftpsrv;
#endif
PUBLIC int HTDoConnect (char *url, char *protocol, int default_port, int *s)
{
struct sockaddr_in soc_address;
struct sockaddr_in *sin = &soc_address;
int status;
/* Set up defaults: */
sin->sin_family = AF_INET;
sin->sin_port = htons(default_port);
/* Get node name and optional port number: */
{
char line[256];
char *p1 = HTParse(url, "", PARSE_HOST);
int status;
sprintf (line, "Looking up %s.", p1);
HTProgress (line);
status = HTParseInet(sin, p1);
if (status)
{
sprintf (line, "Unable to locate remote host %s.", p1);
HTProgress(line);
free (p1);
return HT_NO_DATA;
}
sprintf (line, "Making %s connection to %s.", protocol, p1);
HTProgress (line);
free (p1);
}
/* Now, let's get a socket set up from the server for the data: */
*s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef SOCKS
/* SOCKS can't yet deal with non-blocking connect request */
HTClearActiveIcon();
status = Rconnect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
if ((status == 0) && (strcmp(protocol, "FTP") == 0))
SOCKS_ftpsrv.s_addr = soc_address.sin_addr.s_addr;
{
int intr;
intr = HTCheckActiveIcon(1);
if (intr)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
#endif
status = HT_INTERRUPTED;
errno = EINTR;
}
}
return status;
#else /* SOCKS not defined */
/*
* Make the socket non-blocking, so the connect can be canceled.
* This means that when we issue the connect we should NOT
* have to wait for the accept on the other end.
*/
{
int ret;
int val = 1;
char line[256];
ret = ioctl(*s, FIONBIO, &val);
if (ret == -1)
{
sprintf (line, "Could not make connection non-blocking.");
HTProgress(line);
}
}
HTClearActiveIcon();
/*
* Issue the connect. Since the server can't do an instantaneous accept
* and we are non-blocking, this will almost certainly return a negative
* status.
*/
status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
/*
* According to the Sun man page for connect:
* EINPROGRESS The socket is non-blocking and the con-
* nection cannot be completed immediately.
* It is possible to select(2) for comple-
* tion by selecting the socket for writ-
* ing.
* According to the Motorola SVR4 man page for connect:
* EAGAIN The socket is non-blocking and the con-
* nection cannot be completed immediately.
* It is possible to select for completion
* by selecting the socket for writing.
* However, this is only possible if the
* socket STREAMS module is the topmost
* module on the protocol stack with a
* write service procedure. This will be
* the normal case.
*/
#ifdef SVR4
if ((status < 0) && ((errno == EINPROGRESS)||(errno == EAGAIN)))
#else
if ((status < 0) && (errno == EINPROGRESS))
#endif /* SVR4 */
{
struct timeval timeout;
int ret;
ret = 0;
while (ret <= 0)
{
fd_set writefds;
int intr;
FD_ZERO(&writefds);
FD_SET(*s, &writefds);
/* linux (and some other os's, I think) clear timeout...
let's reset it every time. bjs */
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
#ifdef __hpux
ret = select(FD_SETSIZE, NULL, (int *)&writefds, NULL, &timeout);
#else
ret = select(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
#endif
/*
* Again according to the Sun and Motorola man pagse for connect:
* EALREADY The socket is non-blocking and a previ-
* ous connection attempt has not yet been
* completed.
* Thus if the errno is NOT EALREADY we have a real error, and
* should break out here and return that error.
* Otherwise if it is EALREADY keep on trying to complete the
* connection.
*/
if ((ret < 0)&&(errno != EALREADY))
{
status = ret;
break;
}
else if (ret > 0)
{
/*
* Extra check here for connection success, if we try to connect
* again, and get EISCONN, it means we have a successful
* connection.
*/
status = connect(*s, (struct sockaddr*)&soc_address,
sizeof(soc_address));
if ((status < 0)&&(errno == EISCONN))
{
status = 0;
}
break;
}
/*
* The select says we aren't ready yet.
* Try to connect again to make sure. If we don't get EALREADY
* or EISCONN, something has gone wrong. Break out and report it.
* For some reason SVR4 returns EAGAIN here instead of EALREADY,
* even though the man page says it should be EALREADY.
*/
else
{
status = connect(*s, (struct sockaddr*)&soc_address,
sizeof(soc_address));
#ifdef SVR4
if ((status < 0)&&(errno != EALREADY)&&(errno != EAGAIN)&&
(errno != EISCONN))
#else
if ((status < 0)&&(errno != EALREADY)&&(errno != EISCONN))
#endif /* SVR4 */
{
break;
}
}
intr = HTCheckActiveIcon(1);
if (intr)
{
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
#endif
status = HT_INTERRUPTED;
errno = EINTR;
break;
}
}
}
/*
* Make the socket blocking again on good connect
*/
if (status >= 0)
{
int ret;
int val = 0;
char line[256];
ret = ioctl(*s, FIONBIO, &val);
if (ret == -1)
{
sprintf (line, "Could not restore socket to blocking.");
HTProgress(line);
}
}
/*
* Else the connect attempt failed or was interrupted.
* so close up the socket.
*/
else
{
close(*s);
}
return status;
#endif /* #ifdef SOCKS */
}
/* This is so interruptible reads can be implemented cleanly. */
int HTDoRead (int fildes, void *buf, unsigned nbyte)
{
int ready, ret, intr;
fd_set readfds;
struct timeval timeout;
char *adtestbuf;
ready = 0;
while (!ready)
{
FD_ZERO(&readfds);
FD_SET(fildes, &readfds);
/* linux (and some other os's, I think) clear timeout...
let's reset it every time. bjs */
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
#ifdef __hpux
ret = select(FD_SETSIZE, (int *)&readfds, NULL, NULL, &timeout);
#else
ret = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
#endif
if (ret < 0)
{
return -1;
}
else if (ret > 0)
{
ready = 1;
}
else
{
intr = HTCheckActiveIcon(1);
if (intr)
{
return HT_INTERRUPTED;
}
}
}
ret = read (fildes, buf, nbyte);
#ifndef DISABLE_TRACE
if (httpTrace) {
adtestbuf = buf;
for (intr = 0; intr < ret; fprintf(stderr,"%c",adtestbuf[intr++]) ) ;
}
#endif
return ret;
}

107
libwww2/HTTCP.h Normal file
View File

@@ -0,0 +1,107 @@
/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/src/HTTCP.html
GENERIC TCP/IP COMMUNICATION
This module has the common code for handling TCP/IP connections etc.
*/
#ifndef HTTCP_H
#define HTTCP_H
#include "HTUtils.h"
#include "tcp.h"
#ifdef SHORT_NAMES
#define HTInetStatus HTInStat
#define HTInetString HTInStri
#define HTParseInet HTPaInet
#endif
/* Produce a string for an internet address
** ---------------------------------------
**
** On exit:
** returns a pointer to a static string which must be copied if
** it is to be kept.
*/
#ifdef __STDC__
extern char * HTInetString(struct sockaddr_in* sin);
#else
extern char * HTInetString();
#endif
/* Encode INET status (as in sys/errno.h) inet_status()
** ------------------
**
** On entry:
** where gives a description of what caused the error
** global errno gives the error number in the unix way.
**
** On return:
** returns a negative status in the unix way.
*/
#ifdef __STDC__
extern int HTInetStatus(char *where);
#else
extern int HTInetStatus();
#endif
/* Publicly accessible variables
*/
/* extern struct sockaddr_in HTHostAddress; */
/* The internet address of the host */
/* Valid after call to HTHostName() */
/* Parse a cardinal value parse_cardinal()
** ----------------------
**
** On entry:
** *pp points to first character to be interpreted, terminated by
** non 0..9 character.
** *pstatus points to status already valid,
** maxvalue gives the largest allowable value.
**
** On exit:
** *pp points to first unread character,
** *pstatus points to status updated iff bad
*/
extern unsigned int HTCardinal PARAMS((int *pstatus,
char **pp,
unsigned int max_value));
/* Parse an internet node address and port
** ---------------------------------------
**
** On entry:
** str points to a string with a node name or number,
** with optional trailing colon and port number.
** sin points to the binary internet or decnet address field.
**
** On exit:
** *sin is filled in. If no port is specified in str, that
** field is left unchanged in *sin.
*/
#ifdef __STDC__
extern int HTParseInet(struct sockaddr_in * sin, WWW_CONST char * str);
/*!! had to change this to get it to compile. CTB */
#else
extern int HTParseInet();
#endif
/* Get Name of This Machine
** ------------------------
**
*/
extern WWW_CONST char * HTHostName NOPARAMS;
extern int HTDoConnect (char *, char *, int, int *);
extern int HTDoRead (int, void *, unsigned);
#endif /* HTTCP_H */

1074
libwww2/HTTP.c Normal file

File diff suppressed because it is too large Load Diff

13
libwww2/HTTP.h Normal file
View File

@@ -0,0 +1,13 @@
/* HyperText Tranfer Protocol HTTP.h
** ==========================
*/
#ifndef HTTP_H
#define HTTP_H
#include "HTAccess.h"
extern HTProtocol HTTP;
#endif /* HTTP_H */

313
libwww2/HTTelnet.c Normal file
View File

@@ -0,0 +1,313 @@
/* Telnet Acees, Roligin, etc HTAccess.c
** ==========================
**
** Authors
** TBL Tim Berners-Lee timbl@info.cern.ch
** JFG Jean-Francois Groff jgh@next.com
** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
** History
** 8 Jun 92 Telnet hopping prohibited as telnet is not secure (TBL)
** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. (JFG)
** 6 Oct 92 Moved HTClientHost and logfile into here. (TBL)
** 17 Dec 92 Tn3270 added, bug fix. (DD)
** 2 Feb 93 Split from HTAccess.c. Registration.(TBL)
*/
#include "../config.h"
/* Implements:
*/
#include "HTTelnet.h"
#include "HTParse.h"
#include "HTUtils.h"
#include "HTAnchor.h"
#include "HTTP.h"
#include "HTFile.h"
#include <errno.h>
#include <stdio.h>
#include "tcp.h"
#include "HText.h"
#include "HTAccess.h"
#include "HTAlert.h"
extern void application_user_feedback (char *);
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
/* make a string secure for passage to the
** system() command. Make it contain only alphanumneric
** characters, or the characters '.', '-', '_', '+'.
** Also remove leading '-' or '+'.
** -----------------------------------------------------
*/
PRIVATE void make_system_secure ARGS1(char *, str)
{
char *ptr1, *ptr2;
if ((str == NULL)||(*str == '\0'))
{
return;
}
/*
* remove leading '-' or '+' by making it into whitespace that
* will be stripped later.
*/
if ((*str == '-')||(*str == '+'))
{
*str = ' ';
}
ptr1 = ptr2 = str;
while (*ptr1 != '\0')
{
if ((!isalpha((int)*ptr1))&&(!isdigit((int)*ptr1))&&
(*ptr1 != '.')&&(*ptr1 != '_')&&
(*ptr1 != '+')&&(*ptr1 != '-'))
{
ptr1++;
}
else
{
*ptr2 = *ptr1;
ptr2++;
ptr1++;
}
}
*ptr2 = *ptr1;
}
PRIVATE void run_a_command ARGS1(char *, command)
{
char **argv;
int argc;
char *str;
int alen;
alen = 10;
argv = (char **)malloc(10 * sizeof(char *));
if (argv == NULL)
{
return;
}
argc = 0;
str = strtok(command, " \t\n");
while (str != NULL)
{
argv[argc] = strdup(str);
argc++;
if (argc >= alen)
{
int i;
char **tmp_av;
tmp_av = (char **)malloc((alen + 10) * sizeof(char *));
if (tmp_av == NULL)
{
return;
}
for (i=0; i<alen; i++)
{
tmp_av[i] = argv[i];
}
alen += 10;
free((char *)argv);
argv = tmp_av;
}
str = strtok(NULL, " \t\n");
}
argv[argc] = NULL;
if (fork() == 0)
{
execvp(argv[0], argv);
}
else
{
int i;
/*
* The signal handler in main.c will clean this child
* up when it exits.
*/
for (i=0; i<argc; i++)
{
if (argv[i] != NULL)
{
free(argv[i]);
}
}
free((char *)argv);
}
}
/* Telnet or "rlogin" access
** -------------------------
*/
PRIVATE int remote_session ARGS2(char *, access, char *, host)
{
char *user, *hostname, *port;
int portnum;
char command[256];
char *xterm_str;
enum _login_protocol { telnet, rlogin, tn3270 } login_protocol;
extern char *global_xterm_str;
if (!access || !host)
{
application_user_feedback
("Cannot open remote session, because\nURL is malformed.\0");
return HT_NO_DATA;
}
login_protocol =
strcmp(access, "rlogin") == 0 ? rlogin :
strcmp(access, "tn3270") == 0 ? tn3270 :
telnet;
/* Make sure we won't overrun the size of command with a huge host string */
if (strlen(host) > 200)
{
host[200] = '\0';
}
user = host;
hostname = strchr(host, '@');
port = strchr(host, ':');
if (hostname)
{
*hostname++ = 0; /* Split */
}
else
{
hostname = host;
user = 0; /* No user specified */
}
if (port)
{
*port++ = 0; /* Split */
portnum = atoi(port);
}
/*
* Make user and hostname secure by removing leading '-' or '+'.
* and allowing only alphanumeric, '.', '_', '+', and '-'.
*/
make_system_secure(user);
make_system_secure(hostname);
xterm_str = global_xterm_str;
if (login_protocol == rlogin)
{
/* For rlogin, we should use -l user. */
if ((port)&&(portnum > 0)&&(portnum < 63336))
{
sprintf(command, "%s -e %s %s %d %s %s", xterm_str, access,
hostname,
portnum,
user ? "-l" : "",
user ? user : "");
}
else
{
sprintf(command, "%s -e %s %s %s %s", xterm_str, access,
hostname,
user ? "-l" : "",
user ? user : "");
}
}
else
{
/* For telnet, -l isn't safe to use at all -- most platforms
don't understand it. */
if ((port)&&(portnum > 0)&&(portnum < 63336))
{
sprintf(command, "%s -e %s %s %d", xterm_str, access,
hostname, portnum);
}
else
{
sprintf(command, "%s -e %s %s", xterm_str, access,
hostname);
}
}
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "HTaccess: Command is: %s\n", command);
#endif
run_a_command(command);
/* No need for application feedback if we're rlogging directly
in... */
if (user && login_protocol != rlogin)
{
char str[200];
/* Sleep to let the xterm get up first.
Otherwise, the popup will get buried. */
sleep (2);
sprintf (str, "When you are connected, log in as '%s'.", user);
application_user_feedback (str);
}
return HT_NO_DATA; /* Ok - it was done but no data */
}
/* "Load a document" -- establishes a session
** ------------------------------------------
**
** On entry,
** addr must point to the fully qualified hypertext reference.
**
** On exit,
** returns <0 Error has occured.
** >=0 Value of file descriptor or socket to be used
** to read data.
** *pFormat Set to the format of the file, if known.
** (See WWW.h)
**
*/
PRIVATE int HTLoadTelnet
ARGS4
(
WWW_CONST char *, addr,
HTParentAnchor *, anchor,
HTFormat, format_out,
HTStream *, sink /* Ignored */
)
{
char * access;
char * host;
int status;
if (sink)
{
HTAlert("Can't output a live session -- it has to be interactive");
return HT_NO_ACCESS;
}
access = HTParse(addr, "file:", PARSE_ACCESS);
host = HTParse(addr, "", PARSE_HOST);
status = remote_session(access, host);
free(host);
free(access);
return status;
}
PUBLIC HTProtocol HTTelnet = { "telnet", HTLoadTelnet, NULL };
PUBLIC HTProtocol HTRlogin = { "rlogin", HTLoadTelnet, NULL };
PUBLIC HTProtocol HTTn3270 = { "tn3270", HTLoadTelnet, NULL };

20
libwww2/HTTelnet.h Normal file
View File

@@ -0,0 +1,20 @@
/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/HTTelnet.html
TELNET AND SIMILAR ACCESS METHODS
*/
#ifndef HTTELNET_H
#define HTTELNET_H
#include "HTAccess.h"
extern HTProtocol HTTelnet;
extern HTProtocol HTRlogin;
extern HTProtocol HTTn3270;
#endif
/*
*/

206
libwww2/HTUU.c Normal file
View File

@@ -0,0 +1,206 @@
/* MODULE HTUU.c
** UUENCODE AND UUDECODE
**
** ACKNOWLEDGEMENT:
** This code is taken from rpem distribution, and was originally
** written by Mark Riordan.
**
** AUTHORS:
** MR Mark Riordan riordanmr@clvax1.cl.msu.edu
** AL Ari Luotonen luotonen@dxcern.cern.ch
**
** HISTORY:
** Added as part of the WWW library and edited to conform
** with the WWW project coding standards by: AL 5 Aug 1993
** Originally written by: MR 12 Aug 1990
** Original header text:
** -------------------------------------------------------------
** File containing routines to convert a buffer
** of bytes to/from RFC 1113 printable encoding format.
**
** This technique is similar to the familiar Unix uuencode
** format in that it maps 6 binary bits to one ASCII
** character (or more aptly, 3 binary bytes to 4 ASCII
** characters). However, RFC 1113 does not use the same
** mapping to printable characters as uuencode.
**
** Mark Riordan 12 August 1990 and 17 Feb 1991.
** This code is hereby placed in the public domain.
** -------------------------------------------------------------
**
** BUGS:
**
**
*/
#include "../config.h"
#include "HTUtils.h"
#include "HTUU.h"
PRIVATE char six2pr[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/'
};
PRIVATE unsigned char pr2six[256];
/*--- function HTUU_encode -----------------------------------------------
*
* Encode a single line of binary data to a standard format that
* uses only printing ASCII characters (but takes up 33% more bytes).
*
* Entry bufin points to a buffer of bytes. If nbytes is not
* a multiple of three, then the byte just beyond
* the last byte in the buffer must be 0.
* nbytes is the number of bytes in that buffer.
* This cannot be more than 48.
* bufcoded points to an output buffer. Be sure that this
* can hold at least 1 + (4*nbytes)/3 characters.
*
* Exit bufcoded contains the coded line. The first 4*nbytes/3 bytes
* contain printing ASCII characters representing
* those binary bytes. This may include one or
* two '=' characters used as padding at the end.
* The last byte is a zero byte.
* Returns the number of ASCII characters in "bufcoded".
*/
PUBLIC int HTUU_encode ARGS3(unsigned char *, bufin,
unsigned int, nbytes,
char *, bufcoded)
{
/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) six2pr[c]
register char *outptr = bufcoded;
unsigned int i;
/* This doesn't seem to be needed (AL): register unsigned char *inptr = bufin; */
for (i=0; i<nbytes; i += 3) {
*(outptr++) = ENC(*bufin >> 2); /* c1 */
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
bufin += 3;
}
/* If nbytes was not a multiple of 3, then we have encoded too
* many characters. Adjust appropriately.
*/
if(i == nbytes+1) {
/* There were only 2 bytes in that last group */
outptr[-1] = '=';
} else if(i == nbytes+2) {
/* There was only 1 byte in that last group */
outptr[-1] = '=';
outptr[-2] = '=';
}
*outptr = '\0';
return(outptr - bufcoded);
}
/*--- function HTUU_decode ------------------------------------------------
*
* Decode an ASCII-encoded buffer back to its original binary form.
*
* Entry bufcoded points to a uuencoded string. It is
* terminated by any character not in
* the printable character table six2pr, but
* leading whitespace is stripped.
* bufplain points to the output buffer; must be big
* enough to hold the decoded string (generally
* shorter than the encoded string) plus
* as many as two extra bytes used during
* the decoding process.
* outbufsize is the maximum number of bytes that
* can fit in bufplain.
*
* Exit Returns the number of binary bytes decoded.
* bufplain contains these bytes.
*/
PUBLIC int HTUU_decode ARGS3(char *, bufcoded,
unsigned char *, bufplain,
int, outbufsize)
{
/* single character decode */
#define DEC(c) pr2six[c]
#define MAXVAL 63
static int first = 1;
int nbytesdecoded, j;
register unsigned char *bufin = (unsigned char *) bufcoded;
register unsigned char *bufout = bufplain;
register int nprbytes;
/* If this is the first call, initialize the mapping table.
* This code should work even on non-ASCII machines.
*/
if(first) {
first = 0;
for(j=0; j<256; j++) pr2six[j] = MAXVAL+1;
for(j=0; j<64; j++) pr2six[six2pr[j]] = (unsigned char) j;
#if 0
pr2six['A']= 0; pr2six['B']= 1; pr2six['C']= 2; pr2six['D']= 3;
pr2six['E']= 4; pr2six['F']= 5; pr2six['G']= 6; pr2six['H']= 7;
pr2six['I']= 8; pr2six['J']= 9; pr2six['K']=10; pr2six['L']=11;
pr2six['M']=12; pr2six['N']=13; pr2six['O']=14; pr2six['P']=15;
pr2six['Q']=16; pr2six['R']=17; pr2six['S']=18; pr2six['T']=19;
pr2six['U']=20; pr2six['V']=21; pr2six['W']=22; pr2six['X']=23;
pr2six['Y']=24; pr2six['Z']=25; pr2six['a']=26; pr2six['b']=27;
pr2six['c']=28; pr2six['d']=29; pr2six['e']=30; pr2six['f']=31;
pr2six['g']=32; pr2six['h']=33; pr2six['i']=34; pr2six['j']=35;
pr2six['k']=36; pr2six['l']=37; pr2six['m']=38; pr2six['n']=39;
pr2six['o']=40; pr2six['p']=41; pr2six['q']=42; pr2six['r']=43;
pr2six['s']=44; pr2six['t']=45; pr2six['u']=46; pr2six['v']=47;
pr2six['w']=48; pr2six['x']=49; pr2six['y']=50; pr2six['z']=51;
pr2six['0']=52; pr2six['1']=53; pr2six['2']=54; pr2six['3']=55;
pr2six['4']=56; pr2six['5']=57; pr2six['6']=58; pr2six['7']=59;
pr2six['8']=60; pr2six['9']=61; pr2six['+']=62; pr2six['/']=63;
#endif
}
/* Strip leading whitespace. */
while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
/* Figure out how many characters are in the input buffer.
* If this would decode into more bytes than would fit into
* the output buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded;
while(pr2six[*(bufin++)] <= MAXVAL);
nprbytes = bufin - ((unsigned char *)bufcoded) - 1;
nbytesdecoded = ((nprbytes+3)/4) * 3;
if(nbytesdecoded > outbufsize) {
nprbytes = (outbufsize*4)/3;
}
bufin = bufcoded;
while (nprbytes > 0) {
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
bufin += 4;
nprbytes -= 4;
}
if(nprbytes & 03) {
if(pr2six[bufin[-2]] > MAXVAL) {
nbytesdecoded -= 2;
} else {
nbytesdecoded -= 1;
}
}
return(nbytesdecoded);
}

27
libwww2/HTUU.h Normal file
View File

@@ -0,0 +1,27 @@
/* ENCODING TO PRINTABLE CHARACTERS
File module provides functions HTUU_encode() and HTUU_decode() which convert a buffer
of bytes to/from RFC 1113 printable encoding format. This technique is similar to the
familiar Unix uuencode format in that it maps 6 binary bits to one ASCII character (or
more aptly, 3 binary bytes to 4 ASCII characters). However, RFC 1113 does not use the
same mapping to printable characters as uuencode.
*/
#ifndef HTUU_H
#define HTUU_H
#include "HTUtils.h"
PUBLIC int HTUU_encode PARAMS((unsigned char *bufin,
unsigned int nbytes,
char *bufcoded));
PUBLIC int HTUU_decode PARAMS((char *bufcoded,
unsigned char *bufplain,
int outbufsize));
#endif
/*
End of file. */

268
libwww2/HTUtils.h Normal file
View File

@@ -0,0 +1,268 @@
/* Utitlity macros for the W3 code library
MACROS FOR GENERAL USE
Generates: HTUtils.h
See also: the system dependent file "tcp.h"
*/
#ifndef DEBUG
#define DEBUG /* Noone ever turns this off as trace is too important */
#endif /* Keeep option for really small memory applications tho */
#ifndef HTUTILS_H
#define HTUTILS_H
#ifdef SHORT_NAMES
#define WWW_TraceFlag HTTrFlag
#endif
/*
Debug message control.
*/
#ifndef STDIO_H
#include <stdio.h>
#define STDIO_H
#endif
/*
* Tracing now works as a boolean from a resource. No, there are no
* more if's than before...
*
* SWP -- 02/08/96
*/
/*
#ifdef DEBUG
#define TRACE (WWW_TraceFlag)
#define PROGRESS(str) printf(str)
extern int WWW_TraceFlag;
#else
#define TRACE 0
#define PROGRESS(str)
#endif
#undef TRACE
#define TRACE 1
#ifdef TRACE
#define HTTP_TRACE 1
#endif
#define CTRACE if(TRACE)fprintf
#define tfp stderr
*/
/*
Standard C library for malloc() etc
*/
#ifdef vax
#ifdef unix
#define ultrix /* Assume vax+unix=ultrix */
#endif
#endif
#ifndef VMS
#ifndef ultrix
#ifdef NeXT
#include <libc.h> /* NeXT */
#endif
#ifndef MACH /* Vincent.Cate@furmint.nectar.cs.cmu.edu */
#include <stdlib.h> /* ANSI */
#endif
#else /* ultrix */
#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#endif
#else /* VMS */
#include <stdio.h>
#include <ctype.h>
#endif
#ifdef __sgi
#include <malloc.h>
#endif
/*
Macros for declarations
*/
#define PUBLIC /* Accessible outside this module */
#define PRIVATE static /* Accessible only within this module */
#ifdef __STDC__
#if 0
#define WWW_CONST const /* "const" only exists in STDC */
#endif
#define WWW_CONST
#define NOPARAMS (void)
#define PARAMS(parameter_list) parameter_list
#define NOARGS (void)
#define ARGS1(t,a) \
(t a)
#define ARGS2(t,a,u,b) \
(t a, u b)
#define ARGS3(t,a,u,b,v,c) \
(t a, u b, v c)
#define ARGS4(t,a,u,b,v,c,w,d) \
(t a, u b, v c, w d)
#define ARGS5(t,a,u,b,v,c,w,d,x,e) \
(t a, u b, v c, w d, x e)
#define ARGS6(t,a,u,b,v,c,w,d,x,e,y,f) \
(t a, u b, v c, w d, x e, y f)
#define ARGS7(t,a,u,b,v,c,w,d,x,e,y,f,z,g) \
(t a, u b, v c, w d, x e, y f, z g)
#define ARGS8(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h) \
(t a, u b, v c, w d, x e, y f, z g, s h)
#define ARGS9(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i) \
(t a, u b, v c, w d, x e, y f, z g, s h, r i)
#define ARGS10(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i,q,j) \
(t a, u b, v c, w d, x e, y f, z g, s h, r i, q j)
#else /* not ANSI */
#define WWW_CONST
#define NOPARAMS ()
#define PARAMS(parameter_list) ()
#define NOARGS ()
#define ARGS1(t,a) (a) \
t a;
#define ARGS2(t,a,u,b) (a,b) \
t a; u b;
#define ARGS3(t,a,u,b,v,c) (a,b,c) \
t a; u b; v c;
#define ARGS4(t,a,u,b,v,c,w,d) (a,b,c,d) \
t a; u b; v c; w d;
#define ARGS5(t,a,u,b,v,c,w,d,x,e) (a,b,c,d,e) \
t a; u b; v c; w d; x e;
#define ARGS6(t,a,u,b,v,c,w,d,x,e,y,f) (a,b,c,d,e,f) \
t a; u b; v c; w d; x e; y f;
#define ARGS7(t,a,u,b,v,c,w,d,x,e,y,f,z,g) (a,b,c,d,e,f,g) \
t a; u b; v c; w d; x e; y f; z g;
#define ARGS8(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h) (a,b,c,d,e,f,g,h) \
t a; u b; v c; w d; x e; y f; z g; s h;
#define ARGS9(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i) (a,b,c,d,e,f,g,h,i) \
t a; u b; v c; w d; x e; y f; z g; s h; r i;
#define ARGS10(t,a,u,b,v,c,w,d,x,e,y,f,z,g,s,h,r,i,q,j) (a,b,c,d,e,f,g,h,i,j) \
t a; u b; v c; w d; x e; y f; z g; s h; r i; q j;
#endif /* __STDC__ (ANSI) */
#ifndef NULL
#define NULL ((void *)0)
#endif
/*
Booleans
*/
/* Note: GOOD and BAD are already defined (differently) on RS6000 aix */
/* #define GOOD(status) ((status)38;1) VMS style status: test bit 0 */
/* #define BAD(status) (!GOOD(status)) Bit 0 set if OK, otherwise clear */
#ifndef BOOLEAN_DEFINED
typedef char BOOLEAN; /* Logical value */
#ifndef TRUE
#define TRUE (BOOLEAN)1
#define FALSE (BOOLEAN)0
#endif
#define BOOLEAN_DEFINED
#endif
#ifndef BOOL
#define BOOL BOOLEAN
#endif
#ifndef YES
#define YES (BOOLEAN)1
#define NO (BOOLEAN)0
#endif
#ifndef min
#define min(a,b) ((a) <= (b) ? (a) : (b))
#define max(a,b) ((a) >= (b) ? (a) : (b))
#endif
#define TCP_PORT 80 /* Allocated to http by Jon Postel/ISI 24-Jan-92 */
/* Inline Function WHITE: Is character c white space? */
/* For speed, include all control characters */
#define WHITE(c) (((unsigned char)(c)) <= 32)
/*
Sucess (>=0) and failure (<0) codes
*/
#define HT_REDIRECTING 29998
#define HT_LOADED 29999 /* Instead of a socket */
#define HT_INTERRUPTED -29998
#define HT_NOT_LOADED -29999
#define HT_OK 0 /* Generic success*/
#define HT_NO_ACCESS -10 /* Access not available */
#define HT_FORBIDDEN -11 /* Access forbidden */
#define HT_INTERNAL -12 /* Weird -- should never happen. */
#define HT_BAD_EOF -12 /* Premature EOF */
#include "HTString.h" /* String utilities */
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/*
Out Of Memory checking for malloc() return:
*/
#ifndef __FILE__
#define __FILE__ ""
#define __LINE__ ""
#endif
#define outofmem(file, func) \
{ fprintf(stderr, "%s %s: out of memory.\nProgram aborted.\n", file, func); \
exit(1);}
/*
Upper- and Lowercase macros
The problem here is that toupper(x) is not defined officially unless isupper(x) is.
These macros are CERTAINLY needed on #if defined(pyr) || define(mips) or BDSI
platforms. For safefy, we make them mandatory.
*/
#include <ctype.h>
#ifndef TOLOWER
/* Pyramid and Mips can't uppercase non-alpha */
#define TOLOWER(c) (isupper(c) ? tolower(c) : (c))
#define TOUPPER(c) (islower(c) ? toupper(c) : (c))
#endif /* ndef TOLOWER */
#define CR '\015' /* Must be converted to ^M for transmission */
#define LF '\012' /* Must be converted to ^J for transmission */
#endif /* HTUTILS_H */
/*
end of utilities */

1226
libwww2/HTWAIS.c Normal file

File diff suppressed because it is too large Load Diff

36
libwww2/HTWAIS.h Normal file
View File

@@ -0,0 +1,36 @@
/* WAIS protocol module for the W3 library
WAIS PROTOCOL INTERFACE
This module does not actually perform the WAIS protocol directly, but it does using one
or more library of the freeWAIS distribution. The ui.a library came with the old free
WAIS from TMC, the client.a and wais.a libraries are needed from the freeWAIS from
CNIDR.
If you include this module in the library, you must also
Register the HTWAIS protocol at initialisation (e.g. HTInit or HTSInit) by compiling
it with -DDIRECT_WAIS
Link with the libraries
The wais source files are parsed by a separate and independent module, HTWSRC. You
can include HTWSRC without including direct wais using this module, and your WWW code
will be able to read source files, and access WAIS indexes through a gateway.
A WAIS-WWW gateway is just a normal W3 server with a libwww compiled with this module.
Anyways, this interface won't change much:
*/
#ifndef HTWAIS_H
#define HTWAIS_H
#include "HTUtils.h"
#include "HTAccess.h"
extern HTProtocol HTWAIS;
#endif
/*
Tim BL */

430
libwww2/HTWSRC.c Normal file
View File

@@ -0,0 +1,430 @@
/* Parse WAIS Source file HTWSRC.c
** ======================
**
** This module parses a stream with WAIS source file
** format information on it and creates a structured stream.
** That structured stream is then converted into whatever.
**
** 3 June 93 Bug fix: Won't crash if no description
*/
#include "../config.h"
#include "HTWSRC.h"
#include <stdio.h>
#include "HTML.h"
#include "HTUtils.h"
#include "tcp.h"
#include "HTParse.h"
#define BIG 10000 /* Arbitrary limit to value length */
#define PARAM_MAX BIG
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
struct _HTStructured {
WWW_CONST HTStructuredClass * isa;
/* ... */
};
#define PUTC(c) (*me->target->isa->put_character)(me->target, c)
#define PUTS(s) (*me->target->isa->put_string)(me->target, s)
#define START(e) (*me->target->isa->start_element)(me->target, e, 0, 0)
#define END(e) (*me->target->isa->end_element)(me->target, e)
/* Here are the parameters which can be specified in a source file
*/
PRIVATE WWW_CONST char* par_name[] = {
"version",
"ip-address",
#define PAR_IP_NAME 2
"ip-name",
#define PAR_TCP_PORT 3
"tcp-port",
#define PAR_DATABASE_NAME 4
"database-name",
#define PAR_COST 5
"cost",
#define PAR_COST_UNIT 6
"cost-unit",
#define PAR_FREE 7
"free",
#define PAR_MAINTAINER 8
"maintainer",
#define PAR_DESCRIPTION 9
"description",
"keyword-list",
"source",
#define PAR_UNKNOWN 12
"unknown",
0, /* Terminate list */
#define PAR_COUNT 13
} ;
enum tokenstate { beginning, before_tag, colon, before_value,
value, bracketed_value, quoted_value, escape_in_quoted, done };
/* Stream Object
** ------------
**
** The target is the structured stream down which the
** parsed results will go.
**
** all the static stuff below should go in here to make it reentrant
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
HTStructured * target;
char * par_value[PAR_COUNT];
enum tokenstate state;
char param[BIG+1];
int param_number;
int param_count;
};
PUBLIC WWW_CONST char * hex = "0123456789ABCDEF";
/* Decode one hex character
*/
PUBLIC char from_hex ARGS1(char, c)
{
return (c>='0')&&(c<='9') ? c-'0'
: (c>='A')&&(c<='F') ? c-'A'+10
: (c>='a')&&(c<='f') ? c-'a'+10
: 0;
}
/* State machine
** -------------
**
** On entry,
** me->state is a valid state (see WSRC_init)
** c is the next character
** On exit,
** returns 1 Done with file
** 0 Continue. me->state is updated if necessary.
** -1 Syntax error error
*/
/* Treat One Character
** -------------------
*/
PRIVATE void WSRCParser_put_character ARGS2(HTStream*, me, char, c)
{
switch (me->state) {
case beginning:
if (c=='(') me->state = before_tag;
break;
case before_tag:
if (c==')') {
me->state = done;
return; /* Done with input file */
} else if (c==':') {
me->param_count = 0;
me->state = colon;
} /* Ignore other text */
break;
case colon:
if (WHITE(c)) {
me->param[me->param_count++] = 0; /* Terminate */
for(me->param_number = 0; par_name[me->param_number]; me->param_number++) {
if (0==strcmp(par_name[me->param_number], me->param)) {
break;
}
}
if (!par_name[me->param_number]) { /* Unknown field */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"HTWSRC: Unknown field `%s' in source file\n",
me->param);
#endif
me->param_number = PAR_UNKNOWN;
me->state = before_value; /* Could be better ignore */
return;
}
me->state = before_value;
} else {
if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c;
}
break;
case before_value:
if (c==')') {
me->state = done;
return; /* Done with input file */
}
if (WHITE(c)) return; /* Skip white space */
me->param_count = 0;
if (c=='"') {
me->state = quoted_value;
break;
}
me->state = (c=='"') ? quoted_value :
(c=='(') ? bracketed_value : value;
me->param[me->param_count++] = c; /* Don't miss first character */
break;
case value:
if (WHITE(c)) {
me->param[me->param_count] = 0;
StrAllocCopy(me->par_value[me->param_number], me->param);
me->state = before_tag;
} else {
if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c;
}
break;
case bracketed_value:
if (c==')') {
me->param[me->param_count] = 0;
StrAllocCopy(me->par_value[me->param_number], me->param);
me->state = before_tag;
break;
}
if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c;
break;
case quoted_value:
if (c=='"') {
me->param[me->param_count] = 0;
StrAllocCopy(me->par_value[me->param_number], me->param);
me->state = before_tag;
break;
}
if (c=='\\') { /* Ignore escape but switch state */
me->state = escape_in_quoted;
break;
}
if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c;
break;
case escape_in_quoted:
if (me->param_count < PARAM_MAX) me->param[me->param_count++] = c;
me->state = quoted_value;
break;
case done: /* Ignore anything after EOF */
return;
} /* switch me->state */
}
/* Output equivalent HTML
** ----------------------
**
*/
void give_parameter ARGS2(HTStream *, me, int, p)
{
PUTS(par_name[p]);
if (me->par_value[p]) {
PUTS(": ");
PUTS(me->par_value[p]);
PUTS("; ");
} else {
PUTS(" NOT GIVEN in source file; ");
}
}
/* Generate Outout
** ===============
*/
PRIVATE void WSRC_gen_html ARGS2(HTStream *, me, BOOL, source_file)
{
if (me->par_value[PAR_DATABASE_NAME]) {
char * shortname = 0;
int l;
StrAllocCopy(shortname, me->par_value[PAR_DATABASE_NAME]);
l = strlen(shortname);
if ( l > 4 && !strcasecomp(shortname + l -4, ".src")) {
shortname[l-4] = 0; /* Chop of .src -- boring! */
}
START(HTML_TITLE);
PUTS(shortname);
PUTS(source_file ? " WAIS source file" : " index");
END(HTML_TITLE);
START(HTML_H1);
PUTS(shortname);
PUTS(source_file ? " description" : " index");
END(HTML_H1);
}
START(HTML_DL); /* Definition list of details */
if (source_file) {
START(HTML_DT);
PUTS("Access links");
START(HTML_DD);
if (me->par_value[PAR_IP_NAME] &&
me->par_value[PAR_DATABASE_NAME]) {
char WSRC_address[256];
char * www_database;
www_database = HTEscape(me->par_value[PAR_DATABASE_NAME]);
sprintf(WSRC_address, "wais://%s:%s/%s",
me->par_value[PAR_IP_NAME],
me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT]
: "210",
www_database);
PUTS ("<A HREF=\"");
PUTS (WSRC_address);
PUTS ("\">");
PUTS("Direct access");
PUTS("</A>");
PUTS(" or ");
sprintf(WSRC_address, "http://www.ncsa.uiuc.edu:8001/%s:%s/%s",
me->par_value[PAR_IP_NAME],
me->par_value[PAR_TCP_PORT] ? me->par_value[PAR_TCP_PORT]
: "210",
www_database);
PUTS ("<A HREF=\"");
PUTS (WSRC_address);
PUTS ("\">");
PUTS("through NCSA gateway");
PUTS("</A>");
free(www_database);
} else {
give_parameter(me, PAR_IP_NAME);
give_parameter(me, PAR_IP_NAME);
}
} /* end if source_file */
if (me->par_value[PAR_MAINTAINER]) {
START(HTML_DT);
PUTS("Maintainer");
START(HTML_DD);
PUTS(me->par_value[PAR_MAINTAINER]);
}
START(HTML_DT);
PUTS("Host");
START(HTML_DD);
PUTS(me->par_value[PAR_IP_NAME]);
END(HTML_DL);
if (me->par_value[PAR_DESCRIPTION]) {
START(HTML_PRE); /* Preformatted description */
PUTS(me->par_value[PAR_DESCRIPTION]);
END(HTML_PRE);
}
(*me->target->isa->end_document)(me->target);
(*me->target->isa->free)(me->target);
return;
} /* generate html */
PRIVATE void WSRCParser_put_string ARGS2(HTStream *, context, WWW_CONST char*, str)
{
WWW_CONST char *p;
for(p=str; *p; p++)
WSRCParser_put_character(context, *p);
}
PRIVATE void WSRCParser_write ARGS3(
HTStream *, context,
WWW_CONST char*, str,
int, l)
{
WWW_CONST char *p;
WWW_CONST char *e = str+l;
for(p=str; p<e; p++)
WSRCParser_put_character(context, *p);
}
PRIVATE void WSRCParser_free ARGS1(HTStream *, me)
{
WSRC_gen_html(me, YES);
{
int p;
for(p=0; par_name[p]; p++) { /* Clear out old values */
if (me->par_value[p]) {
free(me->par_value[p]);
}
}
}
free(me);
}
PRIVATE void WSRCParser_end_document ARGS1(HTStream *, me)
{
/* Nothing */
}
PRIVATE void WSRCParser_handle_interrupt ARGS1(HTStream *, me)
{
/* Nothing */
}
/* Stream subclass -- method routines
** ---------------
*/
HTStreamClass WSRCParserClass = {
"WSRCParser",
WSRCParser_free,
WSRCParser_end_document,
WSRCParser_put_character,
WSRCParser_put_string,
WSRCParser_write,
WSRCParser_handle_interrupt
};
/* Converter from WAIS Source to whatever
** --------------------------------------
*/
PUBLIC HTStream* HTWSRCConvert ARGS5(
HTPresentation *, pres,
HTParentAnchor *, anchor,
HTStream *, sink,
HTFormat, format_in,
int, compressed)
{
HTStream * me = (HTStream*) malloc(sizeof(*me));
me->isa = &WSRCParserClass;
me->target = HTML_new(NULL, pres->rep_out, sink);
{
int p;
for(p=0; p < PAR_COUNT; p++) { /* Clear out parameter values */
me->par_value[p] = 0;
}
}
me->state = beginning;
return me;
}

45
libwww2/HTWSRC.h Normal file
View File

@@ -0,0 +1,45 @@
/* A parser for WAIS source files
WAIS SOURCE FILE PARSER
This converter returns a stream object into which a WAIS source file can be written.
The result is put via a structured stream into whatever format was required for the
output stream.
See also: HTWAIS protocol interface module
*/
#ifndef HTWSRC_H
#define HTWSRC_H
#include "HTUtils.h"
#include "HTFormat.h"
extern HTStream* HTWSRCConvert PARAMS((
HTPresentation * pres,
HTParentAnchor * anchor,
HTStream * sink,
HTFormat format_in,
int compressed));
/*
Escaping Strings
HTDeSlash takes out the invlaid characters in a URL path ELEMENT by converting them
into hex-escaped characters. HTEnSlash does the reverse.
Each returns a pointer to a newly allocated string which must eventually be freed by
the caller.
*/
extern char * HTDeSlash PARAMS((WWW_CONST char * str));
extern char * HTEnSlash PARAMS((WWW_CONST char * str));
#endif
/*
Tim BL
*/

207
libwww2/HTWriter.c Normal file
View File

@@ -0,0 +1,207 @@
/* FILE WRITER HTWrite.c
** ===========
**
*/
#include "../config.h"
#include "HTWriter.h"
#define BUFFER_SIZE 4096 /* Tradeoff */
#include "HTUtils.h"
#include "tcp.h"
#include <stdio.h>
char adbuf[1024];
#ifndef DISABLE_TRACE
extern int httpTrace;
extern int www2Trace;
#endif
/* HTML Object
** -----------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa;
int soc;
char *write_pointer;
char buffer[BUFFER_SIZE];
};
/* Write the buffer out to the socket
** ----------------------------------
*/
PRIVATE void flush ARGS1(HTStream *, me)
{
char *read_pointer = me->buffer;
char *write_pointer = me->write_pointer;
while (read_pointer < write_pointer) {
int status;
status = NETWRITE(me->soc, me->buffer,
write_pointer - read_pointer);
#ifndef DISABLE_TRACE
if (httpTrace) {
strncpy(adbuf, me->buffer, write_pointer - read_pointer);
adbuf[write_pointer - read_pointer] = '\0';
fprintf(stderr,"%s",adbuf);
}
#endif
if (status<0) {
#ifndef DISABLE_TRACE
if(www2Trace) fprintf(stderr,
"HTWrite: Error on socket output stream!!!\n");
#endif
return;
}
read_pointer = read_pointer + status;
}
me->write_pointer = me->buffer;
}
/*_________________________________________________________________________
**
** A C T I O N R O U T I N E S
*/
/* Character handling
** ------------------
*/
PRIVATE void HTWriter_put_character ARGS2(HTStream *, me, char, c)
{
if (me->write_pointer == &me->buffer[BUFFER_SIZE]) flush(me);
*me->write_pointer++ = c;
}
/* String handling
** ---------------
**
** Strings must be smaller than this buffer size.
*/
PRIVATE void HTWriter_put_string ARGS2(HTStream *, me, WWW_CONST char*, s)
{
int l = strlen(s);
if (me->write_pointer + l > &me->buffer[BUFFER_SIZE]) flush(me);
strcpy(me->write_pointer, s);
me->write_pointer = me->write_pointer + l;
}
/* Buffer write. Buffers can (and should!) be big.
** ------------
*/
PRIVATE void HTWriter_write ARGS3(HTStream *, me, WWW_CONST char*, s, int, l)
{
WWW_CONST char *read_pointer = s;
WWW_CONST char *write_pointer = s+l;
flush(me); /* First get rid of our buffer */
while (read_pointer < write_pointer) {
int status = NETWRITE(me->soc, read_pointer,
write_pointer - read_pointer);
#ifndef DISABLE_TRACE
if (httpTrace) {
strncpy(adbuf, me->buffer, read_pointer - read_pointer);
adbuf[write_pointer - read_pointer] = '\0';
fprintf(stderr,"%s",adbuf);
}
#endif
if (status<0) {
#ifndef DISABLE_TRACE
if(www2Trace) fprintf(stderr,
"HTWriter_write: Error on socket output stream!!!\n");
#endif
return;
}
read_pointer = read_pointer + status;
}
}
/* Free an HTML object
** -------------------
**
** Note that the SGML parsing context is freed, but the created object is not,
** as it takes on an existence of its own unless explicitly freed.
*/
PRIVATE void HTWriter_free ARGS1(HTStream *, me)
{
NETCLOSE(me->soc);
flush(me);
free(me);
}
/* End writing
*/
PRIVATE void HTWriter_end_document ARGS1(HTStream *, me)
{
flush(me);
}
PRIVATE void HTWriter_handle_interrupt ARGS1(HTStream *, me)
{
}
/* Structured Object Class
** -----------------------
*/
PRIVATE WWW_CONST HTStreamClass HTWriter = /* As opposed to print etc */
{
"SocketWriter",
HTWriter_free,
HTWriter_end_document,
HTWriter_put_character, HTWriter_put_string,
HTWriter_write,
HTWriter_handle_interrupt
};
/* Subclass-specific Methods
** -------------------------
*/
PUBLIC HTStream* HTWriter_new ARGS1(int, soc)
{
HTStream* me = (HTStream*)malloc(sizeof(*me));
if (me == NULL) outofmem(__FILE__, "HTWriter_new");
me->isa = &HTWriter;
me->soc = soc;
me->write_pointer = me->buffer;
return me;
}
/* Subclass-specific Methods
** -------------------------
*/
PUBLIC HTStream* HTASCIIWriter ARGS1(int, soc)
{
HTStream* me = (HTStream*)malloc(sizeof(*me));
if (me == NULL) outofmem(__FILE__, "HTASCIIWriter");
me->isa = &HTWriter;
me->soc = soc;
me->write_pointer = me->buffer;
return me;
}

28
libwww2/HTWriter.h Normal file
View File

@@ -0,0 +1,28 @@
/* */
/* Unix File or Socket Writer HTWriter.c
** --------------------------
**
** This version of the stream object just writes to a socket.
** The socket is assumed open and closed afterward.
**
** There are two versions (identical on ASCII machines)
** one of which converts to ASCII on output.
**
** Bugs:
** strings written must be less than buffer size.
*/
#ifndef HTWRITE_H
#define HTWRITE_H
#include "HTStream.h"
extern HTStream * HTWriter_new PARAMS((int soc));
extern HTStream * HTASCIIWriter PARAMS((int soc));
#endif
/*
*/

121
libwww2/HText.h Normal file
View File

@@ -0,0 +1,121 @@
/* Rich Hypertext object for libWWW
RICH HYPERTEXT OBJECT
*/
/*
This is the C interface to the Objective-C (or whatever) HyperText class.
*/
#ifndef HTEXT_H
#define HTEXT_H
#include "HTAnchor.h"
#include "HTStream.h"
#ifdef SHORT_NAMES
#define HTMainText HTMaText
#define HText_new HTHTNew
#define HText_free HTHTFree
#define HText_beginAppend HTHTBeAp
#define HText_endAppend HTHTEnAp
#define HText_appendCharacter HTHTApCh
#define HText_appendText HTHTApTe
#define HText_appendParagraph HTHTApPa
#define HText_beginAnchor HTHTBeAn
#define HText_endAnchor HTHTEnAn
#define HText_dump HTHTDump
#define HText_nodeAnchor HTHTNoAn
#define HText_select HTHTSele
#define HText_selectAnchor HTHTSeAn
#define HText_replaceSel HTHTRepl
#define HText_applyToSimilar HTHTApTo
#define HText_unlinkSelection HTHTUnSe
#define HText_linkSelTo HTHTLiSe
#define HText_referenceSelected HTHTRefS
#endif
#ifndef THINK_C
#ifndef HyperText /* Objective C version defined HyperText */
typedef struct _HText HText; /* Normal Library */
#endif
#else
class CHyperText; /* Mac Think-C browser hook */
typedef CHyperText HText;
#endif
extern HText * HTMainText; /* Pointer to current main text */
/* Creation and deletion
**
** Create hypertext object HText_new
*/
extern HText * HText_new PARAMS(());
/* Free hypertext object HText_free
*/
extern void HText_free PARAMS((HText * me));
/* Object Building methods
** -----------------------
**
** These are used by a parser to build the text in an object
** HText_beginAppend must be called, then any combination of other
** append calls, then HText_endAppend. This allows optimised
** handling using buffers and caches which are flushed at the end.
*/
extern void HText_beginAppend PARAMS((HText * text));
extern void HText_endAppend PARAMS((HText * text));
extern void HText_doAbort PARAMS((HText * text));
extern void HText_clearOutForNewContents PARAMS((HText * text));
/* Add one character
*/
extern void HText_appendCharacter PARAMS((HText * text, char ch));
/* Add a zero-terminated string
*/
extern void HText_appendText PARAMS((HText * text, WWW_CONST char * str));
/* Add a block.
*/
extern void HText_appendBlock PARAMS((HText * text, WWW_CONST char * str, int len));
/* New Paragraph
*/
extern void HText_appendParagraph PARAMS((HText * text));
/* Start/end sensitive text
**
** The anchor object is created and passed to HText_beginAnchor.
** The senstive text is added to the text object, and then HText_endAnchor
** is called. Anchors may not be nested.
*/
extern void HText_beginAnchor PARAMS((HText * text, char * anc));
extern void HText_endAnchor PARAMS((HText * text));
/* Dump diagnostics to stderr
*/
extern void HText_dump PARAMS((HText * me));
extern char *HText_getText (HText *me);
extern int HText_getTextLength (HText *me);
extern char **HText_getPtrToText (HText *me);
/* Browsing functions
** ------------------
*/
/* Bring to front and highlight it
*/
extern BOOL HText_select PARAMS((HText * text));
#endif /* HTEXT_H */
/*
end */

25
libwww2/Makefile Normal file
View File

@@ -0,0 +1,25 @@
LIBTARGET = libwww.a
all: $(LIBTARGET)
CFILES = CUkerb.c HTAccess.c HTAlert.c HTAnchor.c HTAtom.c HTSort.c HTChunk.c \
HTFTP.c HTFWriter.c HTFile.c HTFormat.c HTGopher.c HTInit.c HTList.c \
HTMIME.c HTML.c HTMLDTD.c HTMLGen.c HTNews.c HTParse.c HTPlain.c \
HTMosaicHTML.c HTString.c HTTCP.c HTTP.c HTTelnet.c HTWSRC.c HTWriter.c \
SGML.c HTWAIS.c HTIcon.c HTCompressed.c HTAAUtil.c HTAssoc.c HTUU.c \
HTAABrow.c HTMailto.c
OBJS = $(CFILES:.c=.o)
$(LIBTARGET): $(OBJS)
-rm -f $(LIBTARGET)
ar rv $(LIBTARGET) $(OBJS)
$(RANLIB) $(LIBTARGET)
$(OBJS): HTUtils.h
HTFTP.o: HTFTP.h
clean:
rm $(LIBTARGET) *.o
tags:
etags -t *.[ch]

78
libwww2/Makefile.in Normal file
View File

@@ -0,0 +1,78 @@
# @configure_output@
# This file is used by Autoconf to make the real Makefile.
# DO NOT EDIT THIS FILE!
# If you want to change something do it to the Makefile autoconf
# creates. You should never have to edit this file.
CC= @CC@
LIBS = @LIBS@
CFLAGS = @CFLAGS@
RANLIB = @RANLIB@
LIBTARGET = libwww.a
all: $(LIBTARGET)
CFILES = \
CUkerb.c \
HTAccess.c \
HTAlert.c \
HTAnchor.c \
HTAtom.c \
HTSort.c \
HTChunk.c \
HTFTP.c \
HTFWriter.c \
HTFile.c \
HTFormat.c \
HTGopher.c \
HTInit.c \
HTList.c \
HTMIME.c \
HTML.c \
HTMLDTD.c \
HTMLGen.c \
HTNews.c \
HTParse.c \
HTPlain.c \
HTMosaicHTML.c \
HTString.c \
HTTCP.c \
HTTP.c \
HTTelnet.c \
HTWSRC.c \
HTWriter.c \
SGML.c \
HTWAIS.c \
HTIcon.c \
HTCompressed.c \
HTAAUtil.c \
HTAssoc.c \
HTUU.c \
HTAABrow.c \
HTMailto.c
# HTPasswd.c \
# HTAuth.c \
# HTLex.c \
# HTGroup.c \
# HTACL.c \
# HTAAProt.c \
# HTAAServ.c \
# HTAAFile.c
OBJS = $(CFILES:.c=.o)
$(LIBTARGET): $(OBJS)
-rm -f $(LIBTARGET)
ar rv $(LIBTARGET) $(OBJS)
$(RANLIB) $(LIBTARGET)
$(OBJS): HTUtils.h
HTFTP.o: HTFTP.h
clean:
-rm $(LIBTARGET) *.o
tags:
etags -t *.[ch]

25
libwww2/Makefile.orig Normal file
View File

@@ -0,0 +1,25 @@
LIBTARGET = libwww.a
all: $(LIBTARGET)
CFILES = CUkerb.c HTAccess.c HTAlert.c HTAnchor.c HTAtom.c HTSort.c HTChunk.c \
HTFTP.c HTFWriter.c HTFile.c HTFormat.c HTGopher.c HTInit.c HTList.c \
HTMIME.c HTML.c HTMLDTD.c HTMLGen.c HTNews.c HTParse.c HTPlain.c \
HTMosaicHTML.c HTString.c HTTCP.c HTTP.c HTTelnet.c HTWSRC.c HTWriter.c \
SGML.c HTWAIS.c HTIcon.c HTCompressed.c HTAAUtil.c HTAssoc.c HTUU.c \
HTAABrow.c HTMailto.c
OBJS = $(CFILES:.c=.o)
$(LIBTARGET): $(OBJS)
-rm -f $(LIBTARGET)
ar rv $(LIBTARGET) $(OBJS)
$(RANLIB) $(LIBTARGET)
$(OBJS): HTUtils.h
HTFTP.o: HTFTP.h
clean:
rm $(LIBTARGET) *.o
tags:
etags -t *.[ch]

698
libwww2/SGML.c Normal file
View File

@@ -0,0 +1,698 @@
/* General SGML Parser code SGML.c
** ========================
**
** This module implements an HTStream object. To parse an
** SGML file, create this object which is a parser. The object
** is (currently) created by being passed a DTD structure,
** and a target HTStructured oject at which to throw the parsed stuff.
**
** 6 Feb 93 Binary seraches used. Intreface modified.
*/
#include "../config.h"
#include "SGML.h"
#include <ctype.h>
#include <stdio.h>
#include "HTUtils.h"
#include "HTChunk.h"
#include "../libnut/str-tools.h"
#ifndef DISABLE_TRACE
extern int www2Trace;
#endif
#define INVALID (-1)
/* The State (context) of the parser
**
** This is passed with each call to make the parser reentrant
**
*/
#define MAX_ATTRIBUTES 20 /* Max number of attributes per element */
/* Element Stack
** -------------
** This allows us to return down the stack reselcting styles.
** As we return, attribute values will be garbage in general.
*/
typedef struct _HTElement HTElement;
struct _HTElement {
HTElement * next; /* Previously nested element or 0 */
HTTag* tag; /* The tag at this level */
};
/* Internal Context Data Structure
** -------------------------------
*/
struct _HTStream {
WWW_CONST HTStreamClass * isa; /* inherited from HTStream */
WWW_CONST SGML_dtd *dtd;
HTStructuredClass *actions; /* target class */
HTStructured *target; /* target object */
HTTag *current_tag;
int current_attribute_number;
HTChunk *string;
HTElement *element_stack;
enum sgml_state { S_text, S_litteral, S_tag, S_tag_gap,
S_attr, S_attr_gap, S_equals, S_value,
S_ero, S_cro,
S_squoted, S_dquoted, S_end, S_entity, S_junk_tag} state;
#ifdef CALLERDATA
void * callerData;
#endif
BOOL present[MAX_ATTRIBUTES]; /* Flags: attribute is present? */
char * value[MAX_ATTRIBUTES]; /* malloc'd strings or NULL if none */
} ;
#define PUTC(ch) ((*context->actions->put_character)(context->target, ch))
/* Handle Attribute
** ----------------
*/
/* PUBLIC WWW_CONST char * SGML_default = ""; ?? */
#ifdef __STDC__
PRIVATE void handle_attribute_name(HTStream * context, char * s)
#else
PRIVATE void handle_attribute_name(context, s)
HTStream * context;
char *s;
#endif
{
HTTag * tag = context->current_tag;
attr* attributes = tag->attributes;
int high, low, i, diff; /* Binary search for attribute name */
for(low=0, high=tag->number_of_attributes;
high > low ;
diff < 0 ? (low = i+1) : (high = i) ) {
i = (low + (high-low)/2);
diff = my_strcasecmp(attributes[i].name, s);
if (diff==0) { /* success: found it */
context->current_attribute_number = i;
context->present[i] = YES;
if (context->value[i]) {
free(context->value[i]);
context->value[i] = NULL;
}
return;
} /* if */
} /* for */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "SGML: Unknown attribute %s for tag %s\n",
s, context->current_tag->name);
#endif
context->current_attribute_number = INVALID; /* Invalid */
}
/* Handle attribute value
** ----------------------
*/
#ifdef __STDC__
PRIVATE void handle_attribute_value(HTStream * context, char * s)
#else
PRIVATE void handle_attribute_value(context, s)
HTStream * context;
char *s;
#endif
{
if (context->current_attribute_number != INVALID) {
StrAllocCopy(context->value[context->current_attribute_number], s);
} else {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "SGML: Attribute value %s ignored\n", s);
#endif
}
context->current_attribute_number = INVALID; /* can't have two assignments! */
}
/* Handle entity
** -------------
**
** On entry,
** s contains the entity name zero terminated
** Bugs:
** If the entity name is unknown, the terminator is treated as
** a printable non-special character in all cases, even if it is '<'
*/
#ifdef __STDC__
PRIVATE void handle_entity(HTStream * context, char term)
#else
PRIVATE void handle_entity(context, term)
HTStream * context;
char term;
#endif
{
WWW_CONST char ** entities = context->dtd->entity_names;
WWW_CONST char *s = context->string->data;
int high, low, i, diff;
for(low=0, high = context->dtd->number_of_entities;
high > low ;
diff < 0 ? (low = i+1) : (high = i)) { /* Binary serach */
i = (low + (high-low)/2);
diff = strcmp(entities[i], s); /* Csse sensitive! */
if (diff==0) { /* success: found it */
(*context->actions->put_entity)(context->target, i);
return;
}
}
/* If entity string not found, display as text */
#ifndef DISABLE_TRACE
if (www2Trace)
fprintf(stderr, "SGML: Unknown entity %s\n", s);
#endif
PUTC('&');
{
WWW_CONST char *p;
for (p=s; *p; p++) {
PUTC(*p);
}
}
PUTC(term);
}
/* End element
** -----------
*/
#ifdef __STDC__
PRIVATE void end_element(HTStream * context, HTTag * old_tag)
#else
PRIVATE void end_element(context, old_tag)
HTTag * old_tag;
HTStream * context;
#endif
{
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "SGML: End </%s>\n", old_tag->name);
#endif
if (old_tag->contents == SGML_EMPTY) {
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,"SGML: Illegal end tag </%s> found.\n",
old_tag->name);
#endif
return;
}
while (context->element_stack) {/* Loop is error path only */
HTElement * N = context->element_stack;
HTTag * t = N->tag;
if (old_tag != t) { /* Mismatch: syntax error */
if (context->element_stack->next) { /* This is not the last level */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"SGML: Found </%s> when expecting </%s>. </%s> assumed.\n",
old_tag->name, t->name, t->name);
#endif
} else { /* last level */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"SGML: Found </%s> when expecting </%s>. </%s> Ignored.\n",
old_tag->name, t->name, old_tag->name);
#endif
return; /* Ignore */
}
}
context->element_stack = N->next; /* Remove from stack */
free(N);
(*context->actions->end_element)(context->target,
t - context->dtd->tags);
if (old_tag == t) return; /* Correct sequence */
/* Syntax error path only */
}
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr,
"SGML: Extra end tag </%s> found and ignored.\n", old_tag->name);
#endif
}
/* Start a element
*/
#ifdef __STDC__
PRIVATE void start_element(HTStream * context)
#else
PRIVATE void start_element(context)
HTStream * context;
#endif
{
HTTag * new_tag = context->current_tag;
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "SGML: Start <%s>\n", new_tag->name);
#endif
(*context->actions->start_element)(
context->target,
new_tag - context->dtd->tags,
context->present,
(WWW_CONST char**) context->value); /* coerce type for think c */
if (new_tag->contents != SGML_EMPTY) { /* i.e. tag not empty */
HTElement * N = (HTElement *)malloc(sizeof(HTElement));
if (N == NULL) outofmem(__FILE__, "start_element");
N->next = context->element_stack;
N->tag = new_tag;
context->element_stack = N;
}
}
/* Find Tag in DTD tag list
** ------------------------
**
** On entry,
** dtd points to dtd structire including valid tag list
** string points to name of tag in question
**
** On exit,
** returns:
** NULL tag not found
** else address of tag structure in dtd
*/
PRIVATE HTTag * find_tag ARGS2(WWW_CONST SGML_dtd*, dtd, char *, string)
{
int high, low, i, diff;
for(low=0, high=dtd->number_of_tags;
high > low ;
diff < 0 ? (low = i+1) : (high = i)) { /* Binary serach */
i = (low + (high-low)/2);
diff = my_strcasecmp(dtd->tags[i].name, string); /* Case insensitive */
if (diff==0) { /* success: found it */
return &dtd->tags[i];
}
}
return NULL;
}
/*________________________________________________________________________
** Public Methods
*/
PUBLIC void SGML_end ARGS1(HTStream *, context)
{
/* Could check that we are back to bottom of stack! @@ */
(*context->actions->end_document)(context->target);
}
PUBLIC void SGML_free ARGS1(HTStream *, context)
{
(*context->actions->free)(context->target);
HTChunkFree(context->string);
free(context);
}
/* Read and write user callback handle
** -----------------------------------
**
** The callbacks from the SGML parser have an SGML context parameter.
** These calls allow the caller to associate his own context with a
** particular SGML context.
*/
#ifdef CALLERDATA
PUBLIC void* SGML_callerData ARGS1(HTStream *, context)
{
return context->callerData;
}
PUBLIC void SGML_setCallerData ARGS2(HTStream *, context, void*, data)
{
context->callerData = data;
}
#endif
PUBLIC void SGML_character ARGS2(HTStream *, context, char,c)
{
WWW_CONST SGML_dtd *dtd = context->dtd;
HTChunk *string = context->string;
switch(context->state) {
case S_text:
if (c=='&' && (!context->element_stack || (
context->element_stack->tag &&
( context->element_stack->tag->contents == SGML_MIXED
|| context->element_stack->tag->contents ==
SGML_RCDATA)
))) {
string->size = 0;
context->state = S_ero;
} else if (c=='<') {
string->size = 0;
context->state = (context->element_stack &&
context->element_stack->tag &&
context->element_stack->tag->contents == SGML_LITTERAL) ?
S_litteral : S_tag;
} else PUTC(c);
break;
/* In litteral mode, waits only for specific end tag!
** Only foir compatibility with old servers.
*/
case S_litteral :
HTChunkPutc(string, c);
if ( TOUPPER(c) != ((string->size ==1) ? '/'
: context->element_stack->tag->name[string->size-2])) {
int i;
/* If complete match, end litteral */
if ((c=='>') && (!context->element_stack->tag->name[string->size-2])) {
end_element(context, context->element_stack->tag);
string->size = 0;
context->current_attribute_number = INVALID;
context->state = S_text;
break;
} /* If Mismatch: recover string. */
PUTC( '<');
for (i=0; i<string->size; i++) /* recover */
PUTC(
string->data[i]);
context->state = S_text;
}
break;
/* Character reference or Entity
*/
case S_ero:
if (c=='#') {
context->state = S_cro; /* &# is Char Ref Open */
break;
}
context->state = S_entity; /* Fall through! */
/* Handle Entities
*/
case S_entity:
if (isalnum(c))
HTChunkPutc(string, c);
else {
HTChunkTerminate(string);
handle_entity(context, c);
context->state = S_text;
}
break;
/* Character reference
*/
case S_cro:
if (isalnum(c))
HTChunkPutc(string, c); /* accumulate a character NUMBER */
else {
int value;
HTChunkTerminate(string);
if (sscanf(string->data, "%d", &value)==1)
PUTC((char)value);
context->state = S_text;
}
break;
/* Tag
*/
case S_tag: /* new tag */
if (isalnum(c))
HTChunkPutc(string, c);
else { /* End of tag name */
HTTag * t;
if (c=='/') {
#ifndef DISABLE_TRACE
if (www2Trace) if (string->size!=0)
fprintf(stderr,"SGML: `<%s/' found!\n", string->data);
#endif
context->state = S_end;
break;
}
HTChunkTerminate(string) ;
t = find_tag(dtd, string->data);
if (!t) {
#ifndef DISABLE_TRACE
if(www2Trace) fprintf(stderr, "SGML: *** Unknown element %s\n",
string->data);
#endif
context->state = (c=='>') ? S_text : S_junk_tag;
break;
}
context->current_tag = t;
/* Clear out attributes
*/
{
int i;
for (i=0; i< context->current_tag->number_of_attributes; i++)
context->present[i] = NO;
}
string->size = 0;
context->current_attribute_number = INVALID;
if (c=='>') {
if (context->current_tag->name) start_element(context);
context->state = S_text;
} else {
context->state = S_tag_gap;
}
}
break;
case S_tag_gap: /* Expecting attribute or > */
if (WHITE(c)) break; /* Gap between attributes */
if (c=='>') { /* End of tag */
if (context->current_tag->name) start_element(context);
context->state = S_text;
break;
}
HTChunkPutc(string, c);
context->state = S_attr; /* Get attribute */
break;
/* accumulating value */
case S_attr:
if (WHITE(c) || (c=='>') || (c=='=')) { /* End of word */
HTChunkTerminate(string) ;
handle_attribute_name(context, string->data);
string->size = 0;
if (c=='>') { /* End of tag */
if (context->current_tag->name) start_element(context);
context->state = S_text;
break;
}
context->state = (c=='=' ? S_equals: S_attr_gap);
} else {
HTChunkPutc(string, c);
}
break;
case S_attr_gap: /* Expecting attribute or = or > */
if (WHITE(c)) break; /* Gap after attribute */
if (c=='>') { /* End of tag */
if (context->current_tag->name) start_element(context);
context->state = S_text;
break;
} else if (c=='=') {
context->state = S_equals;
break;
}
HTChunkPutc(string, c);
context->state = S_attr; /* Get next attribute */
break;
case S_equals: /* After attr = */
if (WHITE(c)) break; /* Before attribute value */
if (c=='>') { /* End of tag */
#ifndef DISABLE_TRACE
if (www2Trace) fprintf(stderr, "SGML: found = but no value\n");
#endif
if (context->current_tag->name) start_element(context);
context->state = S_text;
break;
} else if (c=='\'') {
context->state = S_squoted;
break;
} else if (c=='"') {
context->state = S_dquoted;
break;
}
HTChunkPutc(string, c);
context->state = S_value;
break;
case S_value:
if (WHITE(c) || (c=='>')) { /* End of word */
HTChunkTerminate(string) ;
handle_attribute_value(context, string->data);
string->size = 0;
if (c=='>') { /* End of tag */
if (context->current_tag->name) start_element(context);
context->state = S_text;
break;
}
else context->state = S_tag_gap;
} else {
HTChunkPutc(string, c);
}
break;
case S_squoted: /* Quoted attribute value */
if (c=='\'') { /* End of attribute value */
HTChunkTerminate(string) ;
handle_attribute_value(context, string->data);
string->size = 0;
context->state = S_tag_gap;
} else {
HTChunkPutc(string, c);
}
break;
case S_dquoted: /* Quoted attribute value */
if (c=='"') { /* End of attribute value */
HTChunkTerminate(string) ;
handle_attribute_value(context, string->data);
string->size = 0;
context->state = S_tag_gap;
} else {
HTChunkPutc(string, c);
}
break;
case S_end: /* </ */
if (isalnum(c))
HTChunkPutc(string, c);
else { /* End of end tag name */
HTTag * t;
HTChunkTerminate(string) ;
if (!*string->data) { /* Empty end tag */
t = context->element_stack->tag;
} else {
t = find_tag(dtd, string->data);
}
if (!t) {
#ifndef DISABLE_TRACE
if(www2Trace) fprintf(stderr,
"Unknown end tag </%s>\n", string->data);
#endif
} else {
context->current_tag = t;
end_element( context, context->current_tag);
}
string->size = 0;
context->current_attribute_number = INVALID;
if (c!='>') {
#ifndef DISABLE_TRACE
if (www2Trace && !WHITE(c))
fprintf(stderr,"SGML: `</%s%c' found!\n",
string->data, c);
#endif
context->state = S_junk_tag;
} else {
context->state = S_text;
}
}
break;
case S_junk_tag:
if (c=='>') {
context->state = S_text;
}
} /* switch on context->state */
} /* SGML_character */
PUBLIC void SGML_string ARGS2(HTStream *, context, WWW_CONST char*, str)
{
WWW_CONST char *p;
for(p=str; *p; p++)
SGML_character(context, *p);
}
PUBLIC void SGML_write ARGS3(HTStream *, context, WWW_CONST char*, str, int, l)
{
WWW_CONST char *p;
WWW_CONST char *e = str+l;
for(p=str; p<e; p++)
SGML_character(context, *p);
}
/*_______________________________________________________________________
*/
PRIVATE void SGML_handle_interrupt ARGS1(HTStream *, context)
{
}
/* Structured Object Class
** -----------------------
*/
PUBLIC WWW_CONST HTStreamClass SGMLParser =
{
"SGMLParser",
SGML_free,
SGML_end,
SGML_character, SGML_string, SGML_write,
SGML_handle_interrupt
};
/* Create SGML Engine
** ------------------
**
** On entry,
** dtd represents the DTD, along with
** actions is the sink for the data as a set of routines.
**
*/
PUBLIC HTStream* SGML_new ARGS2(
WWW_CONST SGML_dtd *, dtd,
HTStructured *, target)
{
int i;
HTStream* context = (HTStream *) malloc(sizeof(*context));
if (!context) outofmem(__FILE__, "SGML_begin");
context->isa = &SGMLParser;
context->string = HTChunkCreate(128); /* Grow by this much */
context->dtd = dtd;
context->target = target;
context->actions = (HTStructuredClass*)(((HTStream*)target)->isa);
/* Ugh: no OO */
context->state = S_text;
context->element_stack = 0; /* empty */
#ifdef CALLERDATA
context->callerData = (void*) callerData;
#endif
for(i=0; i<MAX_ATTRIBUTES; i++) context->value[i] = 0;
return context;
}

180
libwww2/SGML.h Normal file
View File

@@ -0,0 +1,180 @@
/* /Net/dxcern/userd/timbl/hypertext/WWW/Library/Implementation/SGML.html
SGML AND STRUCTURED STREAMS
The SGML parser is a state machine. It is called for every
character of the input stream. The DTD data structure contains
pointers to functions which are called to implement the actual
effect of the text read. When these functions are called, the
attribute structures pointed to by the DTD are valid, and the
function is passed a pointer to the curent tag structure, and an
"element stack" which represents the state of nesting within SGML
elements.
The following aspects are from Dan Connolly's suggestions: Binary
search, Strcutured object scheme basically, SGML content enum type.
(c) Copyright CERN 1991 - See Copyright.html
*/
#ifndef SGML_H
#define SGML_H
#include "HTUtils.h"
#include "HTStream.h"
/*
SGML content types
*/
typedef enum _SGMLContent{
SGML_EMPTY, /* no content */
SGML_LITTERAL, /* character data. Recognised excat close tag only. litteral
Old www server compatibility only! Not SGML */
SGML_CDATA, /* character data. recognize </ only */
SGML_RCDATA, /* replaceable character data. recognize </ and &ref; */
SGML_MIXED, /* elements and parsed character data. recognize all markup */
SGML_ELEMENT /* any data found will be returned as an error*/
} SGMLContent;
typedef struct {
char * name; /* The (constant) name of the attribute */
/* Could put type info in here */
} attr;
/* A tag structure describes an SGML element.
** -----------------------------------------
**
**
** name is the string which comes after the tag opener "<".
**
** attributes points to a zero-terminated array
** of attribute names.
**
** litteral determines how the SGML engine parses the charaters
** within the element. If set, tag openers are ignored
** except for that which opens a matching closing tag.
**
*/
typedef struct _tag HTTag;
struct _tag{
char * name; /* The name of the tag */
attr * attributes; /* The list of acceptable attributes */
int number_of_attributes; /* Number of possible attributes */
SGMLContent contents; /* End only on end tag @@ */
};
/* DTD Information
** ---------------
**
** Not the whole DTD, but all this parser usues of it.
*/
typedef struct {
HTTag * tags; /* Must be in strcmp order by name */
int number_of_tags;
WWW_CONST char ** entity_names; /* Must be in strcmp order by name */
int number_of_entities;
} SGML_dtd;
/* SGML context passed to parsers
*/
typedef struct _HTSGMLContext *HTSGMLContext; /* Hidden */
/*__________________________________________________________________________
*/
/* Structured Object definition
**
** A structured object is something which can reasonably be
** represented in SGML. I'll rephrase that. A structured
** object is am ordered tree-structured arrangement of data
** which is representable as text.
**
** The SGML parer outputs to a Structured object.
** A Structured object can output its contents
** to another Structured Object.
** It's a kind of typed stream. The architecure
** is largely Dan Conolly's.
** Elements and entities are passed to the sob by number, implying
** a knowledge of the DTD.
** Knowledge of the SGML syntax is not here, though.
**
** Superclass: HTStream
*/
/* The creation methods will vary on the type of Structured Object.
** Maybe the callerData is enough info to pass along.
*/
typedef struct _HTStructured HTStructured;
typedef struct _HTStructuredClass{
char* name; /* Just for diagnostics */
void (*free) PARAMS((
HTStructured* me));
void (*end_document) PARAMS((
HTStructured* me));
void (*handle_interrupt) PARAMS((
HTStructured* me));
void (*put_character) PARAMS((
HTStructured* me,
char ch));
void (*put_string) PARAMS((
HTStructured* me,
WWW_CONST char * str));
void (*write) PARAMS((
HTStructured* me,
WWW_CONST char * str,
int len));
void (*start_element) PARAMS((
HTStructured* me,
int element_number,
WWW_CONST BOOL* attribute_present,
WWW_CONST char** attribute_value));
void (*end_element) PARAMS((
HTStructured* me,
int element_number));
void (*put_entity) PARAMS((
HTStructured* me,
int entity_number));
}HTStructuredClass;
/* Create an SGML parser
**
** On entry,
** dtd must point to a DTD structure as defined above
** callbacks must point to user routines.
** callData is returned in callbacks transparently.
** On exit,
** The default tag starter has been processed.
*/
extern HTStream* SGML_new PARAMS((
WWW_CONST SGML_dtd * dtd,
HTStructured * target));
extern WWW_CONST HTStreamClass SGMLParser;
#endif /* SGML_H */

287
libwww2/tcp.h Normal file
View File

@@ -0,0 +1,287 @@
/* System dependencies in the W3 library
SYSTEM DEPENDENCIES
System-system differences for TCP include files and macros. This
file includes for each system the files necessary for network and
file I/O.
AUTHORS
TBL Tim Berners-Lee, W3 project, CERN, <timbl@info.cern.ch>
EvA Eelco van Asperen <evas@cs.few.eur.nl>
MA Marc Andreessen NCSA
AT Aleksandar Totic <atotic@ncsa.uiuc.edu>
SCW Susan C. Weber <sweber@kyle.eitech.com>
HISTORY:
22 Feb 91 Written (TBL) as part of the WWW library.
16 Jan 92 PC code from EvA
22 Apr 93 Merged diffs bits from xmosaic release
29 Apr 93 Windows/NT code from SCW
Much of the cross-system portability stuff has been intentionally
REMOVED from this version of the library by Marc A in order to
discourage attempts to make "easy" ports of Mosaic for X to non-Unix
platforms. The library needs to be rewritten from the ground up; in
the meantime, Unix is *all* we support or intend to support with
this set of source code.
*/
#ifndef TCP_H
#define TCP_H
/*
Default values
These values may be reset and altered by system-specific sections
later on. there are also a bunch of defaults at the end .
*/
/* Default values of those: */
#define NETCLOSE close /* Routine to close a TCP-IP socket */
#define NETREAD HTDoRead /* Routine to read from a TCP-IP socket */
#define NETWRITE write /* Routine to write to a TCP-IP socket */
/* Unless stated otherwise, */
#define SELECT /* Can handle >1 channel. */
#define GOT_SYSTEM /* Can call shell with string */
#ifdef unix
#define GOT_PIPE
#endif
typedef struct sockaddr_in SockA; /* See netinet/in.h */
#ifndef STDIO_H
#include <stdio.h>
#define STDIO_H
#endif
#ifdef _AIX
#define AIX
#endif
#ifdef AIX
#define unix
#endif
#ifdef _IBMR2
#define USE_DIRENT /* sys V style directory open */
#endif
/* Solaris. */
#if defined(sun) && defined(__svr4__)
#define USE_DIRENT /* sys V style directory open */
#endif
#if defined(__alpha)
#define USE_DIRENT
#endif
#ifndef USE_DIRENT
#ifdef SVR4
#define USE_DIRENT
#endif
#endif /* not USE_DIRENT */
#include <string.h>
/* Use builtin strdup when appropriate. */
#if defined(ultrix) || defined(VMS) || defined(NeXT)
extern char *strdup ();
#endif
/*
VAX/VMS
Under VMS, there are many versions of TCP-IP. Define one if you do
not use Digital's UCX product:
UCX DEC's "Ultrix connection" (default)
WIN_TCP From Wollongong, now GEC software.
MULTINET From SRI, now from TGV Inv.
DECNET Cern's TCP socket emulation over DECnet
The last three do not interfere with the
unix i/o library, and so they need special calls to read, write and
close sockets. In these cases the socket number is a VMS channel
number, so we make the @@@ HORRIBLE @@@ assumption that a channel
number will be greater than 10 but a unix file descriptor less than
10. It works.
*/
#ifdef vms
#ifdef WIN_TCP
#undef NETREAD
#undef NETWRITE
#undef NETCLOSE
#define NETREAD(s,b,l) ((s)>10 ? netread((s),(b),(l)) : read((s),(b),(l)))
#define NETWRITE(s,b,l) ((s)>10 ? netwrite((s),(b),(l)) : write((s),(b),(l)))
#define NETCLOSE(s) ((s)>10 ? netclose(s) : close(s))
#endif
#ifdef MULTINET
#undef NETCLOSE
#undef NETREAD
#undef NETWRITE
#define NETREAD(s,b,l) ((s)>10 ? socket_read((s),(b),(l)) : read((s),(b),(l)))
#define NETWRITE(s,b,l) ((s)>10 ? socket_write((s),(b),(l)) : \
write((s),(b),(l)))
#define NETCLOSE(s) ((s)>10 ? socket_close(s) : close(s))
#endif
/* Certainly this works for UCX and Multinet; not tried for Wollongong
*/
#ifdef MULTINET
#include "multinet_root:[multinet.include.sys]types.h"
#include "multinet_root:[multinet.include]errno.h"
#include "multinet_root:[multinet.include.sys]time.h"
#else
#include types
#include errno
#include time
#endif /* multinet */
#include string
#ifndef STDIO_H
#include stdio
#define STDIO_H
#endif
#include file
#include unixio
#define INCLUDES_DONE
#ifdef MULTINET /* Include from standard Multinet directories */
#include "multinet_root:[multinet.include.sys]socket.h"
#ifdef __TIME_LOADED /* defined by sys$library:time.h */
#define __TIME /* to avoid double definitions in next file */
#endif
#include "multinet_root:[multinet.include.netinet]in.h"
#include "multinet_root:[multinet.include.arpa]inet.h"
#include "multinet_root:[multinet.include]netdb.h"
#else /* not multinet */
#ifdef DECNET
#include "types.h" /* for socket.h */
#include "socket.h"
#include "dn"
#include "dnetdb"
/* #include "vms.h" */
#else /* UCX or WIN */
#include socket
#include in
#include inet
#include netdb
#endif /* not DECNET */
#endif /* of Multinet or other TCP includes */
#define TCP_INCLUDES_DONE
#endif /* vms */
/*
SCO ODT unix version
*/
#ifdef sco
#include <sys/fcntl.h>
#define USE_DIRENT
#endif
/*
MIPS unix
*/
/* Mips hack (bsd4.3/sysV mixture...) */
#ifdef mips
extern int errno;
#endif
/*
Regular BSD unix versions
These are a default unix where not already defined specifically.
*/
#ifndef INCLUDES_DONE
#include <sys/types.h>
/* #include <streams/streams.h> not ultrix */
#include <string.h>
#include <errno.h> /* independent */
#include <sys/time.h> /* independent */
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/file.h> /* For open() etc */
#define INCLUDES_DONE
#endif /* Normal includes */
/* Directory reading stuff - BSD or SYS V
*/
#ifdef unix /* if this is to compile on a UNIX machine */
#define GOT_READ_DIR 1 /* if directory reading functions are available */
#ifdef USE_DIRENT /* sys v version */
#include <dirent.h>
#define direct dirent
#else
#include <sys/dir.h>
#endif
#if defined(sun) && defined(__svr4__)
#include <sys/fcntl.h>
#include <limits.h>
#endif
#endif
/*
Defaults
INCLUDE FILES FOR TCP
*/
#ifndef TCP_INCLUDES_DONE
#include <sys/ioctl.h> /* EJB */
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __hpux /* this may or may not be good -marc */
#include <arpa/inet.h> /* Must be after netinet/in.h */
#endif
#include <netdb.h>
#endif /* TCP includes */
/*
MACROS FOR MANIPULATING MASKS FOR SELECT()
*/
#ifdef SELECT
#ifndef FD_SET
typedef unsigned int fd_set;
#define FD_SET(fd,pmask) (*(pmask)) |= (1<<(fd))
#define FD_CLR(fd,pmask) (*(pmask)) &= ~(1<<(fd))
#define FD_ZERO(pmask) (*(pmask))=0
#define FD_ISSET(fd,pmask) (*(pmask) & (1<<(fd)))
#endif /* FD_SET */
#endif /* SELECT */
#endif /* TCP_H */