File:  [Public] / libwww / Library / src / HTAccess.c
Revision 1.105: download - view: text, annotated - select for diffs
Fri Dec 1 20:27:11 1995 UTC (28 years, 6 months ago) by frystyk
Branches: MAIN
CVS tags: v4/0, HEAD
version 4.0!

/*								     HTAccess.c
**	ACCESS MANAGER
**
**	(c) COPYRIGHT MIT 1995.
**	Please first read the full copyright statement in the file COPYRIGH.
**
** Authors
**	TBL	Tim Berners-Lee timbl@w3.org
**	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 HTlogfile 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.
**	   Dec 93 Bug change around, more reentrant, etc
**	09 May 94 logfile renamed to HTlogfile to avoid clash with WAIS
**	 8 Jul 94 Insulate free() from _free structure element.
**	   Sep 95 Rewritten, HFN
*/

#if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
#define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
#endif

/* Library include files */
#include "WWWLib.h"
#include "HTReqMan.h"
#include "HTAccess.h"					 /* Implemented here */

#ifndef VC
#define VC "unknown"
#endif

PRIVATE char * HTAppName = NULL;	  /* Application name: please supply */
PRIVATE char * HTAppVersion = NULL;    /* Application version: please supply */

PRIVATE char * HTLibName = "libwww";
PRIVATE char * HTLibVersion = VC;

PRIVATE BOOL   HTSecure = NO;		 /* Can we access local file system? */

/* --------------------------------------------------------------------------*/
/*	           Initialization and Termination of the Library	     */
/* --------------------------------------------------------------------------*/

/*	Information about the Application
**	---------------------------------
*/
PUBLIC CONST char * HTLib_appName (void)
{
    return HTAppName ? HTAppName : "UNKNOWN";
}

PUBLIC CONST char * HTLib_appVersion (void)
{
    return HTAppVersion ? HTAppVersion : "0.0";
}

/*	Information about libwww
**	------------------------
*/
PUBLIC CONST char * HTLib_name (void)
{
    return HTLibName ? HTLibName : "UNKNOWN";
}

PUBLIC CONST char * HTLib_version (void)
{
    return HTLibVersion ? HTLibVersion : "0.0";
}

/*	Access Local File System
**	------------------------
**	In this mode we do not tough the local file system at all
*/
PUBLIC BOOL HTLib_secure (void)
{
    return HTSecure;
}

PUBLIC void HTLib_setSecure (BOOL mode)
{
    HTSecure = mode;
}

/*								     HTLibInit
**
**	This function initiates the Library and it MUST be called when
**	starting up an application. See also HTLibTerminate()
*/
PUBLIC BOOL HTLibInit (CONST char * AppName, CONST char * AppVersion)
{
#ifdef WWW_WIN_ASYNC
    HWND htSocketWin;
    static char className[] = "AsyncWindowClass";
    WNDCLASS wc;
    
    wc.style=0;
    wc.lpfnWndProc=(WNDPROC)AsyncWindowProc;
    wc.cbClsExtra=0;
    wc.cbWndExtra=0;
    wc.hInstance=GetCurrentProcess();
    wc.hIcon=0;
    wc.hCursor=0;
    wc.hbrBackground=0;
    wc.lpszMenuName=(LPSTR)0;
    wc.lpszClassName=className;
#if 0
   {0, /* no style */
	AsyncWindowProc, /* to handle our async messages */
	0, 0, /* allocate no extra bytes */
	GetCurrentProcess(), /* hInstance to be filled in soon */
	0, 0, 0, 0, /* icon, cursor, brush, menu */
	className};
#endif
#endif /* WWW_WIN_ASYNC */

#if WWWTRACE_MODE == WWWTRACE_FILE			  /* Open trace file */
    if ((TDEST = fopen(HT_TRACE_FILE, "a")) != NULL) {
	if (setvbuf(TDEST, NULL, _IOLBF, 0) < 0) {  /* Change to line buffer */
	    TTYPrint(TDEST, "WWWLibInit.. Can't initialize TRACE buffer - no TRACE\n");
	    fclose(TDEST);
	    TDEST = NULL;
	    WWW_TraceFlag = 0;
	}
    } else
	WWW_TraceFlag = 0;
#endif /* WWWTRACE_FILE */

    if (WWWTRACE)
	TTYPrint(TDEST, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE\n");

    /* Set the application name and version */
    if (AppName) {
	char *ptr;
	StrAllocCopy(HTAppName, AppName);
	ptr = HTAppName;
	while (*ptr) {
	    if (WHITE(*ptr)) *ptr = '_';
	    ptr++;
	}
    }
    if (AppVersion) {
	char *ptr;
	StrAllocCopy(HTAppVersion, AppVersion);
	ptr = HTAppVersion;
	while (*ptr) {
	    if (WHITE(*ptr)) *ptr = '_';
	    ptr++;
	}
    }

    HTBind_init();				      /* Initialize bindings */

    /* Register a call back function for the Net Manager */
    HTNetCall_addAfter(HTLoad_terminate, HT_ALL);

#ifdef WWWLIB_SIG
    /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting
    ** to a port where we should get `connection refused'. We ignore this 
    ** using the following function call
    */
    HTSetSignal();				   /* Set signals in library */
#endif

#ifdef WWW_WIN_ASYNC
    if (!RegisterClass(&wc)) {
    	TTYPrint(TDEST, "HTEvent_Loop.. Can't RegisterClass \"%s\"\n", className);
	    return NO;
    }
    if (!(htSocketWin = CreateWindow(className, "", WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 
                                     CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetCurrentProcess(),0))) {
       	TTYPrint(TDEST, "HTEvent_Loop.. Can't CreateWindow \"%s\"\n", "");
    	return NO;
    }
    HTEvent_setWinHandle (htSocketWin, WM_USER);     /* use first available message since app uses none */
#endif /* WWW_WIN_ASYNC */

#ifdef _WINDOWS
    /*
    ** Initialise WinSock DLL. This must also be shut down! PMH
    */
    {
        WSADATA            wsadata;
	if (WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata)) {
	    if (WWWTRACE)
		TTYPrint(TDEST, "WWWLibInit.. Can't initialize WinSoc\n");
            WSACleanup();
            return NO;
        }
        if (wsadata.wVersion < MINIMUM_WINSOCK_VERSION) {
            if (WWWTRACE)
		TTYPrint(TDEST, "WWWLibInit.. Bad version of WinSoc\n");
            WSACleanup();
            return NO;
        }
    }
#endif /* _WINDOWS */

#ifndef NO_TIMEGM
    HTGetTimeZoneOffset();	   /* Find offset from GMT if using mktime() */
#endif
    HTTmp_setRoot(NULL);		     /* Set up default tmp directory */
    return YES;
}


/*	HTLibTerminate
**	--------------
**	This function frees memory kept by the Library and should be called
**	before exit of an application (if you are on a PC platform)
*/
PUBLIC BOOL HTLibTerminate (void)
{
    if (WWWTRACE)
	TTYPrint(TDEST, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE\n");
    HTAtom_deleteAll();					 /* Remove the atoms */
    HTDNS_deleteAll();				/* Remove the DNS host cache */
    HTAnchor_deleteAll(NULL);		/* Delete anchors and drop hyperdocs */

    HTProtocol_deleteAll();  /* Remove bindings between access and protocols */
    HTBind_deleteAll();	    /* Remove bindings between suffixes, media types */

    HTFreeHostName();			    /* Free up some internal strings */
    HTFreeMailAddress();
    HTTmp_freeRoot();

#ifdef _WINDOWS
    WSACleanup();
#endif

#ifdef WWW_WIN_ASYNC
    DestroyWindow(HTEvent_getWinHandle(0));
#endif

#if WWWTRACE_MODE == WWWTRACE_FILE			 /* Close trace file */
    if (TDEST) {
	fclose(TDEST);
	TDEST = NULL;
	WWW_TraceFlag = 0;
    }
#endif /* WWWTRACE_FILE */
    return YES;
}

/* --------------------------------------------------------------------------*/
/*	           		Load Access functions			     */
/* --------------------------------------------------------------------------*/

/*	Request a document
**	-----------------
**	Private version that requests a document from the request manager
**	Returns YES if request accepted, else NO
*/
PRIVATE BOOL HTLoadDocument (HTRequest * request, BOOL recursive)
{
    if (PROT_TRACE) {
	HTParentAnchor *anchor = HTRequest_anchor(request);
	char * full_address = HTAnchor_address((HTAnchor *) anchor);
	TTYPrint(TDEST, "HTAccess.... Accessing document %s\n", full_address);
	free(full_address);
    }
    return HTLoad(request, recursive);
}


/*	Request a document from absolute name
**	-------------------------------------
**	Request a document referencd by an absolute URL.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTLoadAbsolute (CONST char * url, HTRequest* request)
{
    if (url && request) {
	HTAnchor * anchor = HTAnchor_findAddress(url);
	HTRequest_setAnchor(request, anchor);
	return HTLoadDocument(request, NO);
    }
    return NO;
}


/*	Request a document from absolute name to stream
**	-----------------------------------------------
**	Request a document referencd by an absolute URL and sending the data
**	down a stream. This is _excactly_ the same as HTLoadAbsolute as
**	the ourputstream is specified using the function
**	HTRequest_setOutputStream(). 'filter' is ignored!
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTLoadToStream (CONST char * url, BOOL filter, HTRequest *request)
{
    return HTLoadAbsolute(url, request);
}


/*	Request a document from relative name
**	-------------------------------------
**	Request a document referenced by a relative URL. The relative URL is 
**	made absolute by resolving it relative to the address of the 'base' 
**	anchor.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTLoadRelative (CONST char * 	relative,
			    HTParentAnchor *	base,
			    HTRequest *		request)
{
    BOOL status = NO;
    if (relative && base && request) {
	char * rel = NULL;
	char * full_url = NULL;
	char * base_url = HTAnchor_address((HTAnchor *) base);
	StrAllocCopy(rel, relative);
	full_url = HTParse(HTStrip(rel), base_url,
			 PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
	status = HTLoadAbsolute(full_url, request);
	free(rel);
	free(full_url);
	free(base_url);
    }
    return status;
}


/*	Request an anchor
**	-----------------
**	Request the document referenced by the anchor
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTLoadAnchor (HTAnchor * anchor, HTRequest * request)
{
    if (anchor && request) {
	HTRequest_setAnchor(request, anchor);
	return HTLoadDocument(request, NO);
    }
    return NO;
}


/*	Request an anchor
**	-----------------
**	Same as HTLoadAnchor but any information in the Error Stack in the 
**	request object is kept, so that any error messages in one 
**	This function is almost identical to HTLoadAnchor, but it doesn't
**	clear the error stack so that the information in there is kept.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTLoadAnchorRecursive (HTAnchor * anchor, HTRequest * request)
{
    if (anchor && request) {
	HTRequest_setAnchor(request, anchor);
        return HTLoadDocument(request, YES);
    }
    return NO;
}


/*	Search an Anchor
**	----------------
**	Performs a keyword search on word given by the user. Adds the keyword
**	to the end of the current address and attempts to open the new address.
**	The list of keywords must be a space-separated list and spaces will
**	be converted to '+' before the request is issued.
**	Search can also be performed by HTLoadAbsolute() etc.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTSearch (CONST char *	keywords,
		      HTParentAnchor *  base,
		      HTRequest * 	request)
{
    BOOL status = NO;
    if (keywords && base && request) {
	char *base_url = HTAnchor_address((HTAnchor *) base);
	if (*keywords) {
	    char *plus;
	    StrAllocCat(base_url, "?");
	    StrAllocCat(base_url, keywords);
	    plus = strchr(base_url, '?');
	    while (*plus) {
		if (*plus == ' ') *plus = '+';
		plus++;
	    }
	}
	status = HTLoadAbsolute(base_url, request);
	free(base_url);
    }
    return status;
}


/*	Search a document from absolute name
**	------------------------------------
**	Request a document referencd by an absolute URL appended with the
**	keywords given. The URL can NOT contain any fragment identifier!
**	The list of keywords must be a space-separated list and spaces will
**	be converted to '+' before the request is issued.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTSearchAbsolute (CONST char *	keywords,
			      CONST char *	url,
			      HTRequest *	request)
{
    if (url && request) {
	HTAnchor * anchor = HTAnchor_findAddress(url);
	return HTSearch(keywords, HTAnchor_parent(anchor), request);
    }
    return NO;
}

/* --------------------------------------------------------------------------*/
/*				Post Access Functions 			     */
/* --------------------------------------------------------------------------*/

/*	Copy an anchor
**	--------------
**	Fetch the URL (possibly local file URL) and send it using either PUT
**	or POST to the remote destination using HTTP. The caller can decide the
**	exact method used and which HTTP header fields to transmit by setting
**	the user fields in the request structure.
**	If posting to NNTP then we can't dispatch at this level but must pass
**	the source anchor to the news module that then takes all the refs
**	to NNTP and puts into the "newsgroups" header
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTCopyAnchor (HTAnchor * src_anchor, HTRequest * main_req)
{ 
    HTRequest *src_req;
    if (!src_anchor || !main_req)
	return NO;

    /* Build the POST web if not already there */
    if (!main_req->source) {
	src_req = HTRequest_dup(main_req);	  /* First set up the source */
	HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
	src_req->reload = HT_MEM_REFRESH;
	src_req->source = src_req;			  /* Point to myself */
	src_req->output_stream = NULL;
	src_req->output_format = WWW_SOURCE;	 /* We want source (for now) */

	/* Set up the main link in the source anchor */
	{
	    HTLink *main_link = HTAnchor_findMainLink(src_anchor);
	    HTAnchor *main_anchor = HTAnchor_linkDest(main_link);
	    HTMethod method = HTAnchor_linkMethod(main_link);
	    if (!main_link || method==METHOD_INVALID) {
		if (WWWTRACE)
		    TTYPrint(TDEST, "Copy Anchor. No destination found or unspecified method");
		HTRequest_delete(src_req);
		return NO;
	    }
	    if (HTAnchor_linkResult(main_link) == HT_LINK_NONE) {
		main_req->GenMask |= HT_DATE;		 /* Send date header */
		main_req->source = src_req;
		main_req->reload = HT_CACHE_REFRESH;
		main_req->method = method;
		HTRequest_addDestination(src_req, main_req);
		main_req->input_format = WWW_SOURCE;
		if (HTLoadAnchor(main_anchor, main_req) == NO)
		    return NO;
	    }
	}

	/* For all other links in the source anchor */
	if (src_anchor->links) {
	    HTList *cur = src_anchor->links;
	    HTLink *pres;
	    while ((pres = (HTLink *) HTList_nextObject(cur)) &&
		   HTAnchor_linkResult(pres) == HT_LINK_NONE) {
		HTAnchor *dest = HTAnchor_linkDest(pres);
		HTMethod method = HTAnchor_linkMethod(pres);
		HTRequest *dest_req;
		if (!dest || method==METHOD_INVALID) {
		    if (WWWTRACE)
			TTYPrint(TDEST, "Copy Anchor. Bad anchor setup %p\n",
				dest);
		    return NO;
		}
		dest_req = HTRequest_dup(main_req);
		dest_req->GenMask |= HT_DATE;		 /* Send date header */
		dest_req->source = src_req;
		dest_req->reload = HT_CACHE_REFRESH;
		dest_req->method = method;
		HTRequest_addDestination(src_req, dest_req);

		dest_req->output_stream = NULL;
		dest_req->output_format = WWW_SOURCE;

		if (HTLoadAnchor(dest, dest_req) == NO)
		    return NO;
	    }
	}
    } else {			 /* Use the existing Post Web and restart it */
	src_req = main_req->source;
	if (src_req->mainDestination)
	    if (HTLoadDocument(main_req, NO) == NO)
		return NO;
	if (src_req->destinations) {
	    HTList *cur = src_anchor->links;
	    HTRequest *pres;
	    while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
		if (HTLoadDocument(pres, NO) == NO)
		    return NO;
	    }
	}
    }

    /* Now open the source */
    return HTLoadAnchor(src_anchor, src_req);
}


/*	Upload an Anchor
**	----------------
**	Send the contents (in hyperdoc) of the source anchor using either PUT
**	or POST to the remote destination using HTTP. The caller can decide the
**	exact method used and which HTTP header fields to transmit by setting
**	the user fields in the request structure.
**	Returns YES if request accepted, else NO
*/
PUBLIC BOOL HTUploadAnchor (HTAnchor *		src_anchor,
			    HTParentAnchor *	dest_anchor,
			    HTRequest *		dest_req)
{
    if (!src_anchor || !dest_anchor || !dest_req)
	return NO;
    if (!(dest_anchor->methods & dest_req->method)) {
	BOOL confirm = NO;
	HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);
	if (cbf)
	    confirm=(*cbf)(dest_req, HT_A_CONFIRM, HT_MSG_METHOD, NULL,
			   (void *) HTMethod_name(dest_req->method), NULL);
	if (!confirm) return NO;
    }

    /* @@@ NOT FINISHED @@@ */

    return NO;
}

/* --------------------------------------------------------------------------*/
/*	           	      Server Access functions			     */
/* --------------------------------------------------------------------------*/

/*	Serv a Document
**	---------------
**	This function sets up a request to service a document using the
**	specified access scheme.
*/
PUBLIC BOOL HTServDocument (HTRequest * request, CONST char * access)
{
    if (request && access) {
	HTRequest_setAccess(request, (char *) access);
	return HTServ(request, NO);
    }
    return NO;
}

Webmaster