init
This commit is contained in:
683
libwww2/CUkerb.c
Normal file
683
libwww2/CUkerb.c
Normal 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
1132
libwww2/HTAABrow.c
Normal file
File diff suppressed because it is too large
Load Diff
182
libwww2/HTAABrow.h
Normal file
182
libwww2/HTAABrow.h
Normal 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
199
libwww2/HTAAFile.c
Normal 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
124
libwww2/HTAAFile.h
Normal 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
562
libwww2/HTAAProt.c
Normal 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
199
libwww2/HTAAProt.h
Normal 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
640
libwww2/HTAAServ.c
Normal 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
144
libwww2/HTAAServ.h
Normal 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
538
libwww2/HTAAUtil.c
Normal 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
342
libwww2/HTAAUtil.h
Normal 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
217
libwww2/HTACL.c
Normal 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
108
libwww2/HTACL.h
Normal 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
648
libwww2/HTAccess.c
Normal 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
164
libwww2/HTAccess.h
Normal 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
87
libwww2/HTAlert.c
Normal 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
55
libwww2/HTAlert.h
Normal 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
547
libwww2/HTAnchor.c
Normal 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
297
libwww2/HTAnchor.h
Normal 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
85
libwww2/HTAssoc.c
Normal 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
42
libwww2/HTAssoc.h
Normal 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
118
libwww2/HTAtom.c
Normal 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
48
libwww2/HTAtom.h
Normal 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
230
libwww2/HTAuth.c
Normal 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
64
libwww2/HTAuth.h
Normal 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
96
libwww2/HTChunk.c
Normal 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
160
libwww2/HTChunk.h
Normal 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
282
libwww2/HTCompressed.c
Normal 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
7
libwww2/HTCompressed.h
Normal 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
2843
libwww2/HTFTP.c
Normal file
File diff suppressed because it is too large
Load Diff
59
libwww2/HTFTP.h
Normal file
59
libwww2/HTFTP.h
Normal 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
549
libwww2/HTFWriter.c
Normal 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
22
libwww2/HTFWriter.h
Normal 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
1324
libwww2/HTFile.c
Normal file
File diff suppressed because it is too large
Load Diff
212
libwww2/HTFile.h
Normal file
212
libwww2/HTFile.h
Normal 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
832
libwww2/HTFormat.c
Normal 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
343
libwww2/HTFormat.h
Normal 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
823
libwww2/HTGopher.c
Normal 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
16
libwww2/HTGopher.h
Normal 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
775
libwww2/HTGroup.c
Normal 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
184
libwww2/HTGroup.h
Normal 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
70
libwww2/HTIcon.c
Normal 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
596
libwww2/HTInit.c
Normal 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
18
libwww2/HTInit.h
Normal 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
140
libwww2/HTLex.c
Normal 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
62
libwww2/HTLex.h
Normal 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
152
libwww2/HTList.c
Normal 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
61
libwww2/HTList.h
Normal 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
1026
libwww2/HTMIME.c
Normal file
File diff suppressed because it is too large
Load Diff
25
libwww2/HTMIME.h
Normal file
25
libwww2/HTMIME.h
Normal 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
525
libwww2/HTML.c
Normal 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
51
libwww2/HTML.h
Normal 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
202
libwww2/HTMLDTD.c
Normal 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
82
libwww2/HTMLDTD.h
Normal 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
240
libwww2/HTMLGen.c
Normal 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
28
libwww2/HTMLGen.h
Normal 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
95
libwww2/HTMailto.c
Normal 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
151
libwww2/HTMosaicHTML.c
Normal 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
20
libwww2/HTMosaicHTML.h
Normal 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
2818
libwww2/HTNews.c
Normal file
File diff suppressed because it is too large
Load Diff
51
libwww2/HTNews.h
Normal file
51
libwww2/HTNews.h
Normal 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
526
libwww2/HTParse.c
Normal 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
144
libwww2/HTParse.h
Normal 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
275
libwww2/HTPasswd.c
Normal 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
127
libwww2/HTPasswd.h
Normal 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
140
libwww2/HTPlain.c
Normal 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
20
libwww2/HTPlain.h
Normal 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
71
libwww2/HTSort.c
Normal 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
5
libwww2/HTSort.h
Normal 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
56
libwww2/HTStream.h
Normal 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
133
libwww2/HTString.c
Normal 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
49
libwww2/HTString.h
Normal 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
615
libwww2/HTTCP.c
Normal 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
107
libwww2/HTTCP.h
Normal 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
1074
libwww2/HTTP.c
Normal file
File diff suppressed because it is too large
Load Diff
13
libwww2/HTTP.h
Normal file
13
libwww2/HTTP.h
Normal 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
313
libwww2/HTTelnet.c
Normal 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
20
libwww2/HTTelnet.h
Normal 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
206
libwww2/HTUU.c
Normal 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
27
libwww2/HTUU.h
Normal 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
268
libwww2/HTUtils.h
Normal 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
1226
libwww2/HTWAIS.c
Normal file
File diff suppressed because it is too large
Load Diff
36
libwww2/HTWAIS.h
Normal file
36
libwww2/HTWAIS.h
Normal 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
430
libwww2/HTWSRC.c
Normal 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
45
libwww2/HTWSRC.h
Normal 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
207
libwww2/HTWriter.c
Normal 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
28
libwww2/HTWriter.h
Normal 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
121
libwww2/HText.h
Normal 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
25
libwww2/Makefile
Normal 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
78
libwww2/Makefile.in
Normal 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
25
libwww2/Makefile.orig
Normal 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
698
libwww2/SGML.c
Normal 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
180
libwww2/SGML.h
Normal 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
287
libwww2/tcp.h
Normal 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 */
|
||||
Reference in New Issue
Block a user