ftp.nice.ch/pub/next/connectivity/infosystems/WAIStation.1.9.6.N.b.tar.gz#/WAIS/doc/waisprot.txt

This is waisprot.txt in view mode; [Download] [Up]

-----------------------------------------------------------------------------

				     
			WAIS Protocol Users Manual

				     
			       Release 1.0.1
				     

Harry Morris 
(morris@think.com)
Thinking Machines Corporation
3.30.90



	 1.0	INTRODUCTION:
	 2.0	THE PROTOCOL ARCHITECTURE:
	 3.0	THE Z39.50 APDU LIBRARY:
	 4.0	THE Z39.50 UTILITY FUNCTIONS:
	 5.0 	Z39.50 TYPE 1 QUERY
	 6.0	INTEGRATION OF WAIS AND Z39.50 LIBRARIES:
	 7.0	THE WAIS LIBRARY:
	 8.0	WAIS TYPE 1 QUERY:
	 9.0	IMPLEMENTATION NOTES:
	10.0	WALK THROUGH OF INIT APDU:
	11.0	WALK THROUGH OF WAIS INIT RESPONSE PROTOCOL EXTENSION:
	12.0	WALK THROUGH OF SAMPLE APPLICATION:
	13.0	ISSUES:
	14.0	SPEC NOTES:
	15.0	DISCLAIMER:
 
 
 
1.0		INTRODUCTION:

The WAIS protocol is an extension to ANSI's Z39.50 protocol.  The
extensions are documented in "WAIS Intgerface Protocol Prototype
Functional Specification Version 1.5" by Franklin Davis. 

This document describes an initial implementation of the protocol.
The implementation is in ANSI C.  It is provided in two libraries - 
the base Z39.50 library and the WAIS protocol libarary.  The libraries
define structures for each APDU and element set.  Functions are
provided to build, and destroy the structures.  Each structure can
also be written into a buffer and read from a buffer.  The structure's
representation in the buffer is defined in the specifications.


2.0		THE PROTOCOL ARCHITECTURE:

The Z39.50 layer provides support for the basic APDU's, utility functions 
for  manipulating tagged data, and hooks for use by the application layer.  

The WAIS protocol defines several structures which may be associated with 
APDU's.  It also provides definitions of the Z39.50 hook functions, which 
allow the structures to be read and written.

These layers specify the translation of an object (a C struct) to and from
a memory buffer.  The representation within the buffer is that defined in
the Z.39.50 spec.  

It is the responsibility of application to construct, send, recieve, and
destroy the Z39.50 and WAIS objects.  


3.0		THE Z39.50 APDU LIBRARY:

Six APDU's are currently defined: Init,InitResponse,Search,SearchResponse,
Present,PresentResponse.  Other APDU's will be added as time premits.
The C definitions are direct translations of the structures outlined in
appendix A of the Z39.50 spec.  The following functions are provided to
create, destroy, read, and write the respective APDU's.


	typedef struct InitAPDU {
		pdu_type		PDUType;
		boolean			willSearch,willPresent,willDelete;
		boolean			supportAccessControl,supportResourceControl;
		long			PreferredMessageSize;
		long			MaximumRecordSize;
		char*			IDAuthentication;
		char*			ImplementationID;
		char* 			ImplementationName;
		char*			ImplementationVersion;
		any*			ReferenceID;
		void*			UserInformationField;
		} InitAPDU;
	
	InitAPDU* makeInitAPDU(
		boolean search,boolean present,boolean delete,
		boolean accessControl,boolean resourceControl,
		long prefMsgSize,long maxMsgSize,
		char* auth,char* id,char* name, char* version,
		any* refID,any* userInfo);

	void freeInitAPDU(InitAPDU* init);

	void writeInitAPDU(InitAPDU* init,char* buffer);

	InitAPDU* readInitAPDU(char* buffer);


	typedef struct InitResponseAPDU {
		pdu_type		PDUType;
		boolean			Result;
		boolean			willSearch,willPresent,willDelete;
		boolean			supportAccessControl,supportResourceControl;
		long			PreferredMessageSize;
		long 			MaximumRecordSize;
		char*			IDAuthentication;
		char*			ImplementationID;
		char* 			ImplementationName;
		char*			ImplementationVersion;
		any*			ReferenceID;
		void*			UserInformationField;
		} InitResponseAPDU;

	InitResponseAPDU* makeInitResponseAPDU(
		boolean result,
		boolean search,boolean present,boolean delete,
		boolean accessControl,boolean resourceControl,
		long prefMsgSize,long maxMsgSize,
		char* auth,char* id,char* name, char* version,
		any* refID,any* userInfo);
		
	void freeInitResponseAPDU(InitResponseAPDU* init);

	void writeInitResponseAPDU(InitResponseAPDU* init,char* buffer);

	InitResponseAPDU* readInitResponseAPDU(char* buffer);

	InitResponseAPDU* replyToInitAPDU(InitAPDU* init,boolean result,
		any* userInfo);
		This is a convienience function to create a default InitResponse
		given a response.


	typedef struct SearchAPDU {
		pdu_type		PDUType;
		long	 		SmallSetUpperBound;
		long			LargeSetLowerBound;
		long	 		MediumSetPresentNumber;
		boolean 		ReplaceIndicator;
		char*			ResultSetName;
		char**			DatabaseNames;   
		char*			QueryType;
		char**			ElementSetNames;  
		any*			ReferenceID;
		void*			Query;
		} SearchAPDU;

	SearchAPDU* makeSearchAPDU(
		long small,long large, long medium,
		boolean replace,char* name,char** databases,char* type,
		char** elements,any* refID,any* queryInfo);

	void freeSearchAPDU(SearchAPDU* query);

	void writeSearchAPDU(SearchAPDU* query,char* buffer);
	
	SearchAPDU* readSearchAPDU(char* buffer);


	typedef struct SearchResponseAPDU {
		pdu_type		PDUType;
		long			SearchStatus;
		long			ResultCount;
		long			NumberOfRecordsReturned;
		long		 	NextResultSetPosition;
		long			ResultSetStatus;
		long 			PresentStatus;
		any*			ReferenceID;
		void*			DatabaseDiagnosticRecords;
		} SearchResponseAPDU;

	SearchResponseAPDU* makeSearchResponseAPDU(
		boolean result,long count,
		long recordsReturned,long nextPos,
		long resultStatus,long presentStatus,
		any* refID,any* records);

	void freeSearchResponseAPDU(SearchResponseAPDU* queryResponse);

	void writeSearchResponseAPDU(SearchResponseAPDU* queryResponse,
	                             char* buffer);

	SearchResponseAPDU* readSearchResponseAPDU(char* buffer);


	typedef struct PresentAPDU {
		pdu_type		PDUType;
		long			NumberOfRecordsRequested;
		long			ResultSetStartPosition;
		char*		 	ResultSetID;
		char*			ElementSetNames; 
		any*			ReferenceID;
		void*			PresentInfo; /* XXX not in Z39.50 spec !!! */
		} PresentAPDU;

	PresentAPDU* makePresentAPDU(long recsReq, long startPos,
		char* resultID,any* refID,void* info);

	void freePresentAPDU(PresentAPDU* present);

	void writePresentAPDU(PresentAPDU* present,char* buffer);

	PresentAPDU* readPresentAPDU(char* buffer);


	typedef struct PresentResponseAPDU {
		pdu_type		PDUType;
		boolean			PresentStatus;
		long			NumberOfRecordsReturned;
		long			NextResultSetPosition;
		any*			ReferenceID;
		void*			DatabaseDiagnosticRecords;
		} PresentResponseAPDU;

	PresentResponseAPDU* makePresentResponseAPDU(boolean status, 
		long recsRet,long nextPos,any* refID,any* records);

	void freePresentResponseAPDU(PresentResponseAPDU* present);

	void writePresentResponseAPDU(PresentResponseAPDU* present,char* buffer);

	PresentResponseAPDU* readPresentResponseAPDU(char* buffer);



4.0		THE Z39.50 UTILITY FUNCTIONS:

	The utility functions implement the core Z39.50 datatypes.  They are 
	used internaly by the Z39.50 APDU library functions, and can be used 
	to implement "user information" fields.  They are divided into four 
	categories:
	
		1. Tagged Data Functions - these functions operate on tagged data.
		   They are available for use in "user information" fields.
		   
		2. Raw Data Functions - these functions are used to implement the
		   tagged data functions, and the fixed area of each APDU.  They
		   are should not be used for "user information".
		
		3. Version Functions - these functions provide default definitions 
		   for the optional version fields.
		   
		4. Utility Functions.

	Tagged Data Functions:
	
	typedef struct any {	/* an any is a non-ascii string of characters */
		unsigned long	size; 
		char*			bytes;
		} any;

	any* makeAny(unsigned int size,char* data);
	void freeAny(any* a);
	any* duplicateAny(any* a);
	char* writeAny(any* a,data_tag tag,char* buffer);
	char* readAny(any** anAny,char* buffer);
	unsigned long writtenAnySize(any* a);

	typedef any	bit_map; 	/* a bit_map is a group of packed bits */

	bit_map* makeBitMap(int numBits,...);
		The variable arguments are boolean "bits".
	void freeBitMap(bit_map* bm);
	boolean bitAtPos(int pos,bit_map* bm);
	char* writeBitMap(bit_map* bm,data_tag tag,char* buffer);
	char* readBitMap(bit_map** bm,char* buffer);

	char* writeNum(long num,data_tag tag,char* buffer);
	char* readNum(long* num,char* buffer);

	char* writeString(char* s,data_tag tag,char* buffer);
	char* readString(char** s,char* buffer);
		These are convienience functions that can be used anywhere an
		Any is called for.


	Raw Data Functions:
	
	char* writeCompressedInteger(unsigned int num,char* buf);
	char* readCompressedInteger(unsigned int *num,char* buf);
	char* writeCompressedIntegerWithPadding(unsigned long num,
											unsigned int size,char* buffer);
	unsigned long writtenCompressedIntSize(unsigned long num);
		Compressed Integers are described on p. XXX of the Z39.50 document.
	

	typedef unsigned long data_tag;

	char* writeTag(data_tag tag,char* buf);
	char* readTag(data_tag* tag,char* buf);
	data_tag peekTag(char* buf);
	unsigned long writtenTagSize(data_tag tag);
		
	char* writeByte(unsigned char byte,char* buf);
	char* readByte(unsigned char* byte,char* buf);

	char* writeBoolean(boolean flag,char* buf);
	char* readBoolean(boolean* flag,char* buf);

	typedef unsigned long pdu_type;

	char* writePDUType(pdu_type pduType,char* buf);
	char* readPDUType(pdu_type* pduType,char* buf);
	pdu_type peekPDUType(char* buf);

	char* writeBinaryInteger(long num,unsigned int size,char* buf);
	char* readBinaryInteger(long* num,unsigned int size,char* buf);
	unsigned long writtenCompressedBinIntSize(long num);


	Version Functions:
	
	char* writeProtocolVersion(char* buf);
		Writes the version of the Z39.50 spec that is implemented.
		This implementation is version 1.
		
	char* defaultImplementationID(void);
	char* defaultImplementationName(void);
	char* defaultImplementationVersion(void);
		These functions write default information as suggested by the
		implementers of the protocol.  The application may override
		these fields.


	Utility Functions:
	
	doList(void** list,void (*func)());
	

5.0 	Z39.50 TYPE 1 QUERY

The Z39.50 specification defines a type one query as a series of terms, each
of which is of type Attribute, ResultsSet, or Operator.  The the Attribute
terms bind a variable in the current data base (eg. Author = E.A.Poe).  The
ResultSet terms specify a subset of the database.  They are used to store 
intermediate results.  The Operator terms specify an operation relating
Attribute and ResultSet terms (eg. Author = E.A.Poe AND Publisher =
McGraw-Hill).  The terms are gathered on a stack, and evaluated in RPN 
order.  Results are left on the stack for return to the calling program.
The following code defines a query term and provides functions for writing
and reading terms and lists of terms.

	typedef struct query_term {
	  /* type */
	  int	TermType;
	  /* for term */
	  char	Use[ATTRIBUTE_SIZE];
	  char	Relation[ATTRIBUTE_SIZE];
	  char	Position[ATTRIBUTE_SIZE];
	  char	Structure[ATTRIBUTE_SIZE];
	  char	Truncation[ATTRIBUTE_SIZE];
	  char	Completeness[ATTRIBUTE_SIZE];
	  any*	Term;
	  /* for result set */
	  any*	ResultSetID;
	  /* for operator */
	  char	Operator[OPERATOR_SIZE];
	} query_term;
		
	query_term* makeAttributeTerm(
	        char* use,char* relation,char* position,char* structure,
			char* truncation,char* completeness,any* term);
	query_term* makeResultSetTerm(any* resultSet);
	query_term* makeOperatorTerm(char* operator);
	void freeTerm(query_term* qt);
	char* writeQueryTerm(query_term* qt,char* buffer);
	char* readQueryTerm(query_term** qt,char* buffer);
	any* writeQuery(query_term** terms);
	query_term** readQuery(any* info);
	


6.0		INTEGRATION OF WAIS AND Z39.50 LIBRARIES:

The WAIS protocol is implemented through the "user information" field of 
Z39.50's APDU's.  Each Z39.50 APDU has a pointer to user information, and
a hook function to read and write the information.  

The functions are:

	extern char* writeInitInfo(InitAPDU* init,char* buffer);
	extern char* readInitInfo(void** info,char* buffer);
	
	extern char* writeInitResponseInfo(InitResponseAPDU* init,char* buffer);
	extern char* readInitResponseInfo(void** info,char* buffer);
	
	extern char* writeSearchInfo(SearchAPDU* query,char* buffer);
	extern char* readSearchInfo(void** info,char* buffer);
	
	extern char* writeSearchResponseInfo(SearchResponseAPDU* query,
	          							 char* buffer);
	extern char* readSearchResponseInfo(void** info,char* buffer);
	
	extern char* writePresentInfo(PresentAPDU* present,char* buffer);
	extern char* readPresentInfo(void** info,char* buffer);
	
	extern char* writePresentResponseInfo(PresentResponseAPDU* present,
									      char* buffer);
	extern char* readPresentResponseInfo(void** info,char* buffer);

The write functions are called after writing the standard APDU, and only if
the user information field is not NULL.  The read functions are called 
after reading the standard APDU.  They should return NULL if there is no
user information, otherwise they should use the Z39.50 utility functions
to reconstruct the user information as it was written.  


7.0		THE WAIS LIBRARY:
	
The WAIS library is devided into two parts.  The first part defines 
structures and code to manipulate the WAIS components which are directly
mapped to Z39.50 APDUs.  The second part defines component structures 
which are used by the WAIS protocol to pass specific elements between the
origin and target.  Note that all objects of the first type also provide 
implementations of the read and write functions described in section 6.0.


	Basic WAIS Components:

	
	typedef struct WAISInitResponse {
		long				ChunkCode;
		long				ChunkIDLength;
		char*				ChunkMarker;
		char*				HighlightMarker;
		char* 				DeHighlightMarker;
		char*				NewlineCharacters;
		/* XXX  need to add UpdateFrequency and Update Time */
		} WAISInitResponse;
	
	WAISInitResponse* makeWAISInitResponse(
		long chunkCode,long chunkIDLen,char* chunkMarker,
		char* highlightMarker,
		char* deHighlightMarker,char* newLineChars);
	void freeWAISInitResponse(WAISInitResponse* init);


	typedef struct WAISSearch {
		char*				SeedWords;
		DocObj**			Docs;
		char**				TextList;
		long				DateFactor;
		char*				BeginDateRange;
		char*				EndDateRange;
		long				MaxDocumentsRetrieved;
		} WAISSearch;
	
	WAISSearch* makeWAISSearch(
		char* seedWords,DocObj** docs,char** textList,
		long dateFactor,char* beginDateRange,char* endDateRange,
		long maxDocsRetrieved);
	void freeWAISSearch(WAISSearch* query);

		
	typedef struct WAISSearchResponse {
		char*			       		SeedWordsUsed;
		WAISDocumentHeader** 		DocHeaders;
		WAISDocumentShortHeader** 	ShortHeaders;
		WAISDocumentLongHeader** 	LongHeaders;
		WAISDocumentText**			Text;
		WAISDocumentHeadlines**		Headlines;
		WAISDocumentCodes**			Codes;
		} WAISSearchResponse;
	
	WAISSearchResponse* makeWAISSearchResponse(
		char* seedWordsUsed,WAISDocumentHeader** docHeaders,
		WAISDocumentShortHeader** shortHeaders,
		WAISDocumentLongHeader** longHeaders,
		WAISDocumentText** text,WAISDocumentHeadlines** headlines,
		WAISDocumentCodes** codes);
	void freeWAISSearchResponse(WAISSearchResponse* response);


	typedef struct WAISPresent {
		DocObj**	Documents; /* type of request is in element set */
		} WAISPresent;
	
	WAISPresent* makeWAISPresent(DocObj** docs);
	void freeWAISPresent(WAISPresent* present);


	typedef struct WAISPresentResponse {
		WAISDocumentText**		Text;
		WAISDocumentHeadlines**	Headlines;
		WAISDocumentCodes**		Codes;
		} WAISPresentResponse;

	WAISPresentResponse* makeWAISPresentResponse(WAISDocumentText** text,
						     WAISDocumentHeadlines** headlines,
						     WAISDocumentCodes** codes);
	void freeWAISPresentResponse(WAISPresentResponse* response);


	WAIS Elements:
	
		
	typedef struct DocObj { /* specifies a section of a document */
		any*	DocID;
		long	ChunkCode;
		union {
			long	Pos;
			any*	ID;
		} ChunkStart;
		union {
			long	Pos;
			any*	ID;
		} ChunkEnd;
		} DocObj;

	DocObj* makeDocObjUsingWholeDocument(any* docID);
	DocObj* makeDocObjUsingBytes(any* docID,long start,long end);
	DocObj* makeDocObjUsingLines(any* docID,long start,long end);
	DocObj* makeDocObjUsingParagraphs(any* docID,any* start,any* end);
	void freeDocObj(DocObj* doc);
		Note that DocObjs are used read and written internally.


	typedef struct WAISDocumentHeader {
		any*				DocumentID;
		long				VersionNumber;
		long				Score;     
		long				BestMatch; 
		long				DocumentLength;
		long 				Lines;
		char*				Source;
		char*				Date;
		char*				Headline;
		char*				OriginCity;
		} WAISDocumentHeader;
	
	WAISDocumentHeader* makeWAISDocumentHeader(
		any* docID,long versionNumber,long score,long bestMatch,long docLen,
		long lines,char* source,char* date,char* headline,char* originCity);
	void freeWAISDocumentHeader(WAISDocumentHeader* header);
	char* writeWAISDocumentHeader(WAISDocumentHeader* header,char* buffer);
	char* readWAISDocumentHeader(WAISDocumentHeader** header,char* buffer);
	
	
	typedef struct WAISDocumentShortHeader {
		any*				DocumentID;
		long				VersionNumber;
		long				Score;     
		long				BestMatch; 
		long				DocumentLength;
		long 				Lines;
	 	} WAISDocumentShortHeader;
	 
	WAISDocumentShortHeader* makeWAISDocumentShortHeader(
		any* docID,long versionNumber,long score,long bestMatch,
		long docLen,long lines);
	void freeWAISDocumentShortHeader(WAISDocumentShortHeader* header);
	char* writeWAISDocumentShortHeader(WAISDocumentShortHeader* header,
	                                   char* buffer);
	char* readWAISDocumentShortHeader(WAISDocumentShortHeader** header,
	                                  char* buffer);


	typedef struct WAISDocumentLongHeader {
		any*				DocumentID;
		long				VersionNumber;
		long				Score;     
		long				BestMatch; 
		long				DocumentLength;
		long 				Lines;
		char*				Source;
		char*				Date;
		char*				Headline;
		char*				OriginCity;
		char*				StockCodes;
		char* 				CompanyCodes;
		char*				IndustryCodes;
	 	} WAISDocumentLongHeader;
	WAISDocumentLongHeader* makeWAISDocumentLongHeader(
		any* docID,long versionNumber,long score,long bestMatch,long docLen,
		long lines,char* source,char* date, char* headline,char* originCity,
		char* stockCodes,char* companyCodes,char* industryCodes);
	void freeWAISDocumentLongHeader(WAISDocumentLongHeader* header);
	char* writeWAISDocumentLongHeader(WAISDocumentLongHeader* header,
									  char* buffer);
	char* readWAISDocumentLongHeader(WAISDocumentLongHeader** header,
									 char* buffer);

	
	typedef struct WAISDocumentText {
		any*				DocumentID;
		long				VersionNumber;
		any*				DocumentText;
		} WAISDocumentText;
		
	WAISDocumentText* makeWAISDocumentText(any* docID,long versionNumber,
					       any* documentText);
	void freeWAISDocumentText(WAISDocumentText* docText);
	char* writeWAISDocumentText(WAISDocumentText* docText,char* buffer);
	char* readWAISDocumentText(WAISDocumentText** docText,char* buffer);
	
	
	typedef struct WAISDocumentHeadlines {
		any*				DocumentID;
		long				VersionNumber;
		char*				Source;
		char*				Date;
		char*				Headline;
		char*				OriginCity;
		} WAISDocumentHeadlines;
		
	WAISDocumentHeadlines* makeWAISDocumentHeadlines(
		any* docID,long versionNumber,char* source,char* date,
		char* headline,char* originCity);
	void freeWAISDocumentHeadlines(WAISDocumentHeadlines* docHeadline);
	char* writeWAISDocumentHeadlines(WAISDocumentHeadlines* docHeadline,
									 char* buffer);
	char* readWAISDocumentHeadlines(WAISDocumentHeadlines** docHeadline,
									char* buffer);
	
	
	typedef struct WAISDocumentCodes {
		any*				DocumentID;
		long				VersionNumber;
		char*				StockCodes;
		char*				CompanyCodes;
		char*				IndustryCodes;
		} WAISDocumentCodes;
	
	WAISDocumentCodes* makeWAISDocumentCodes(
		any* docID,long versionNumber,char* stockCodes,char* companyCodes,
		char* industryCodes);
	void freeWAISDocumentCodes(WAISDocumentCodes* docCodes);
	char* writeWAISDocumentCodes(WAISDocumentCodes* docCodes,char* buffer);
	char* readWAISDocumentCodes(WAISDocumentCodes** docCodes,char* buffer);
	

8.0		WAIS TYPE 1 QUERY

The WAIS Protocol used type one queries to retrieve fragments of text from
the target.  The syntax is:
       
     1.  retrieve the header/codes from a document:

            System_Control_Number = docID	(attribute)

	     return type is dependent on element set requested

     2.  retrieve a fragment of the text of a document:

            System_Control_Number = docID	(attribute)
	 		Chunk >= start					(attribute)
	    	And								(operator)
	    	Chunk < end						(attribute)
	    	And								(operator)

	     return type is always WAISDocumentText

   Information from multiple documents may be requested by using 
   groups of the above joined by:

            OR								(operator)

The following functions translate between list of DocObjs and an any
containing the DocObjs written in the form given above.

	any* makeWAISType1Query(DocObj** docs);	
	DocObj** readWAISType1Query(any* terms);


9.0		IMPLEMENTATION NOTES:

	Z39.50 Types:
	
		ANY	- 	Implemented as a structure containing a size field and
				an arbitrary length block of bytes.  Value is NULL if
				the element is not present.
				
		ASCII - Implemented as a C string (null terminated).  
		        Value is NULL if the element is not present.
		
		BitMap -	Implemented as an any, with packed bits.  Value is NULL 
		            if the element is not present.
		
		Data Tag -	Implemented as an unsigned int. 
		
		PduType -	Implemented as an enum.
		
		Binary Integer - 	implemented as a long.  Value is UNUSED if the
							element is not present.
		

	Memory Mangement:
	
  		Memory management is fairly simple.  The idea is to minimize the 
  		copying of large (application specific) data (eg. text buffers),
  		while minimizing the amount of explicit freeing that must be
  		done by the user of the protocol.
  		
  		Calls to makeFoo() always copy small arguments and simply reference 
  		large arguments.  All Z39.50 APDU's are small, so they always copy.
  		All WAIS objects are large, so they always reference.
  		
  		Calls to freeFoo() always free all elements of foo.
  		
  		What this means to you:   
  		
  		1. When making and APDU, be sure to free the arguments (an easy way
  		   to do this is to use automatic arguments).
  		
  		2. When making a WAIS object, don't free the arguments (don't use
  		   automatic arguments).
  		
  		3. If you want to hold onto part of an object that is about to be
  		   freed, make a pointer to the part, and NULL out the pointer
  		   in the object.
  		   
  		This is much harder to explain than to do.  Study the example code
  		and/or call the author if you have questions.
  		
  		
10.0		WALK THROUGH OF INIT APDU:

The Init APDU is a typical of the Z39.50 APDU's.  The pseudo code for its
functions is presented here.


	makeInitAPDU(boolean willSearch,boolean willPresent,boolean willDelete,
			     boolean supportAccessControl,
			     boolean supportResourceControl,
			     int preferredMessageSize,int maxMessageSize,
			     string authorization,string identification,
			     string implementationName,string implementationVersion,
			     any referenceID,pointer userInformation)
	 
	{	Allocate space for an init APDU.
	
		Assign it values based on the arguments.  This may involve checking
		that all required arguments are there, and making copies of some 
		arguments.
		
	 	Return the new APDU.
	}
  
	
	freeInitAPDU(InitAPDU init)
	
	{ 	Deallocate any arguments that were copied in makeInitAPDU().
	
		Deallocate the APDU itself.
	}
	
	
	writeInitAPDU(InitAPDU init,memoryBuffer buffer)
	
	{	Declare a pointer buf pointing into buffer, starting HEADER_LEN
		bytes in.
		
		Write init's PDUType at buf, and set buf to the end of the write.
		
		Write the rest of init's data, doing any conversions necessary.
		
		Record the size of APDU (buf - buffer) in the first HEADER_LEN 
		bytes of buffer.
		
		Call writeInitInfo() to write user information into the buffer.		
	}
	
	
	readInitAPDU(memoryBuffer buffer)
	
	{	Declare a pointer buf pointing into the begining of buffer.
	
		Declare local variables for the elements of the APDU.
		
		Read the APDU's size (stored in the first HEADER_LEN bytes).
		
		Read the APDU elements that are reqired to be there.
		
		Decode the ones which are packed (bitmaps)
		
		While buf is less that (buffer + size + HEADER_LEN)
	    { 	Read the next tag.
	    	
	    	Based on the value of the tag, read in an optional element.
	    	
	    	Increment buf by the size of the element.
	    }
	    
	    Call readInitInfo() to read user information from the buffer.
	    
	    Call makeInitAPDU() to create an init APDU.
	    
	    Deallocate any local variables.
	    
	    Return the new init APDU.
	}
	

11.0		WALK THROUGH OF WAIS INIT RESPONSE PROTOCOL EXTENSION:

The WAIS Init Response is a typical of the Z39.50 protocol extension.  
The pseudo code for its functions is presented here.  It is essentially
identical to that of any of the Z39.50 APDU's.  Note that the reading and
writing routines are Z39.50 hooks.


	makeWAISInitResponse(int chunkCode,int chunkIDLen,string chunkMarker,
						 string highlightMarker,string deHighlightMarker,
						 string newLineChars)
			
	{	Allocate space for an init response.
	
		Assign it values based on the arguments.  This may involve checking
		that all required arguments are there, and making copies of some 
		arguments.
		
	 	Return the new response object.
	}
	
	
	freeWAISInitResponse(WAISInitResponse response)
	
	{	Deallocate any arguments that were copied in makeWAISInitResponse().
	
		Deallocate the response itself.
	}
	
	
	writeInitResponseInfo(InitResponseAPDU responseAPDU,memoryBuffer buffer)

	{	Declare a pointer response pointing at the user information field
		of responseAPDU.
		
		Estimate the size of the written representation in bytes.  Determine
		how many bytes are needed to represent that size (round up).  Add 
		the size of a tag field, and the size of the size field (always 1). 
	    This is the WAIS_HEADER_LEN.
	
	   	Declare a pointer buf pointing into buffer, starting WAIS_HEADER_LEN
		bytes in.
		
		Write the response's data at buf, doing any conversions necessary.
		
		Record the size of response's size (buf - buffer) in the first 
		WAIS_HEADER_LEN bytes of buffer.
	}
	
	
	readInitResponseInfo(memoryBuffer buffer)

	{	Declare a pointer buf pointing into the begining of buffer.
	
		Declare local variables for the elements of the response.
		
		Read the response's size (the first element).
		
		While buf is less that (buffer + size)
	    { 	Read the next tag.
	    	
	    	Based on the value of the tag, read in an element.
	    	
	    	Increment buf by the size of the element.
	    }
	    
	    Call makeWAISInitResponse() to create an response object.
	    
	    Deallocate any local variables.
	    
	    Return the new response object.
	}
	

12.0	WALK THROUGH OF SAMPLE APPLICATION:

This section outlines how an application may play the role of origin or 
target.  The pseudo code will be the same for every APDU. 


	requestText(document,startLine,endLine)     (for example)
	
	{ 	Call makeWAISPresent(document,startLine,endLine) to construct a 
		WAIS present object.
	
		Call makePresentAPDU(<z39.50 args>,WAISpresent) to construct a 
		z39.50 present APDU with WAIS present object as its user 
		information.
		
		Call writePresentAPDU(presentAPDU,buffer) to write the APDU and the
		user information to the buffer.
		
		Send the buffer to the target over whatever transport mechanism is
		available.
		
		Free the objects, or store them for future use.
	}

	
	recieveAPDU(buffer)
	
	{	Call peekPDUType(buffer) to determine which APDU is in the buffer.
	
		Switch on the result to the appropriate reading routines:
		
			if pdu = initResponseAPDU
				apdu := readInitAPDU(buffer)
				
			else if pdu = searchResponseAPDU
				apdu := readSearchResponseAPDU(buffer)
				
			else if pdu = presentResponseAPDU
				apdu := readPresentResponseAPDU(buffer)
				
		 Process the response.
		 
		 Free the apdu.
	}


13.0	ISSUES:

The following are some of the open issues which we are still working on
This is not necessarily a complete set.  If you think of more, or
have suggestions on how to approach these, please don't hesitate to contact
the author.

- The following parts are defined in the WAIS Protocol Spec 1.5, but are 
  not yet supported in the libraries: Chunk negotiation
  
  
- Although the Present and PresentResponse APDUs (and their matching WAIS
  elements) are defined, they are not officially part of the WAIS protocol
  library, and as such they have not been fully implemented/tested.
  
- The Z39.50 spec does not define the concrete representation of the Present 
  Response APDU.  The structure defined here is a straigtforward translation
  of the abstract representation.

- The spec does not provide for a user information field in the Present 
  APDU.  We have added one, and believe it should be made a standard part of the
  spec.

- We do not check to ensure that the refID fields are limited to 64 
  characters as outlined in the spec.

- We do nothing to respect MaximumRecordSize

- Fix up naming conventions - should all these functions be prefixed with
  "Z3950_" to prevent name collisions?

- Add support for other apdu's.

- Check consistency with spec.

- Test portability to other platforms - Partial port to Saber-C on Sun
  platforms is successful.

- We need a way for servers to indicate what chunk sizes they will support.
  This could be done in the init/initResponse APDUs by passing a bitmap
  with the bit at possition N specifying the availablity of chunk size N.
  There are other difficulties with Chunks that the are under consideration
  at Thinking Machines.
  
- The use of malloc will contribute to fragmentation of the heap which
  may be unacceptable on machines w/o virtual memory (macs).  We may
  need a more abstract memory model.
  

14.0	SPEC NOTES:

There are several issues alluded to in the spec that are not directly 
addressed.  They are discussed here.

- The size of a Binary integer is unspecified.  We have chosen to use C long
  ints (4 bytes).  When writing them in a variable section, we use only as
  many bytes as are required to represent their data.


14.0	DISCLAIMER:

The libraries described here are initial implementations and are 
subject to change.  We will make every effort to stabilize the
libraries as soon as possible, and to inform all users of changes.

One of our first goals will be to confirm that the implementation
actually conforms to the Z39.50 specification.  The WAIS protocol
will undoubtably evolve over time as we gain experience with developing
information servers and clients.

These libraries will be placed in the public domain as soon as they
are suitably stable.  Until Thinking Machines releases the libraries,
please do not distribute the libraries without first contacting the
author.

As always, if there is a discrepancy between the documentation and the
code - believe the code.




01234567890123456789012345678901234567890123456789012345678901234567890123456789




These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.