diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 1996-09-02 19:39:24 -0400 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 1996-09-02 19:39:24 -0400 |
commit | e087f6d44e87f489fcb3056e86319ebba4218156 (patch) | |
tree | d045b58011bfbbf5186d34c4fed9e0dedb363275 /WWW/Library/Implementation/HTVMS_WaisProt.c | |
download | lynx-snapshots-e087f6d44e87f489fcb3056e86319ebba4218156.tar.gz |
snapshot of project "lynx", label v2_6
Diffstat (limited to 'WWW/Library/Implementation/HTVMS_WaisProt.c')
-rw-r--r-- | WWW/Library/Implementation/HTVMS_WaisProt.c | 2501 |
1 files changed, 2501 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTVMS_WaisProt.c b/WWW/Library/Implementation/HTVMS_WaisProt.c new file mode 100644 index 00000000..ee3a51c0 --- /dev/null +++ b/WWW/Library/Implementation/HTVMS_WaisProt.c @@ -0,0 +1,2501 @@ +/* HTVMS_WAISProt.c +** +** Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu) +** +** 31-May-1994 FM Initial version. +** +**----------------------------------------------------------------------*/ + +/* +** Routines originally from WProt.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE: + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + + 3.26.90 Harry Morris, morris@think.com + 3.30.90 Harry Morris + - removed chunk code from WAISSearchAPDU, + - added makeWAISQueryType1Query() and readWAISType1Query() which replace + makeWAISQueryTerms() and makeWAISQueryDocs(). + 4.11.90 HWM - generalized conditional includes (see c-dialect.h) + - renamed makeWAISType1Query() to makeWAISTextQuery() + renamed readWAISType1Query() to readWAISTextQuery() + 5.29.90 TS - fixed bug in makeWAISQueryDocs + added CSTFreeWAISFoo functions +*/ + +#define _C_WAIS_protocol_ + +/* This file implements the Z39.50 extensions required for WAIS +*/ + +#include "HTUtils.h" +#include "tcp.h" +#include "HTVMS_WaisUI.h" +#include "HTVMS_WaisProt.h" + +#include "LYLeaks.h" + + +/* very rough estimates of the size of an object */ +#define DefWAISInitResponseSize (size_t)200 +#define DefWAISSearchSize (size_t)3000 +#define DefWAISSearchResponseSize (size_t)6000 +#define DefWAISPresentSize (size_t)1000 +#define DefWAISPresentResponseSize (size_t)6000 +#define DefWAISDocHeaderSize (size_t)500 +#define DefWAISShortHeaderSize (size_t)200 +#define DefWAISLongHeaderSize (size_t)800 +#define DefWAISDocTextSize (size_t)6000 +#define DefWAISDocHeadlineSize (size_t)500 +#define DefWAISDocCodeSize (size_t)500 + +#define RESERVE_SPACE_FOR_WAIS_HEADER(len) \ + if (*len > 0) \ + *len -= header_len; + +/*----------------------------------------------------------------------*/ + +static unsigned long userInfoTagSize _AP((data_tag tag, + unsigned long length)); + +static unsigned long +userInfoTagSize(tag,length) +data_tag tag; +unsigned long length; +/* return the number of bytes required to write the user info tag and + length + */ +{ + unsigned long size; + + /* calculate bytes required to represent tag. max tag is 16K */ + size = writtenCompressedIntSize(tag); + size += writtenCompressedIntSize(length); + + return(size); +} + +/*----------------------------------------------------------------------*/ + +static char* writeUserInfoHeader _AP((data_tag tag,long infoSize, + long estHeaderSize,char* buffer, + long* len)); + +static char* +writeUserInfoHeader(tag,infoSize,estHeaderSize,buffer,len) +data_tag tag; +long infoSize; +long estHeaderSize; +char* buffer; +long* len; +/* write the tag and size, making sure the info fits. return the true end + of the info (after adjustment) note that the argument infoSize includes + estHeaderSize. Note that the argument len is the number of bytes remaining + in the buffer. Since we write the tag and size at the begining of the + buffer (in space that we reserved) we don't want to pass len the calls which + do that writing. + */ +{ + long dummyLen = 100; /* plenty of space for a tag and size */ + char* buf = buffer; + long realSize = infoSize - estHeaderSize; + long realHeaderSize = userInfoTagSize(tag,realSize); + + if (buffer == NULL || *len == 0) + return(NULL); + + /* write the tag */ + buf = writeTag(tag,buf,&dummyLen); + + /* see if the if the header size was correct. if not, + we have to shift the info to fit the real header size */ + if (estHeaderSize != realHeaderSize) + { /* make sure there is enough space */ + CHECK_FOR_SPACE_LEFT(realHeaderSize - estHeaderSize,len); + memmove(buffer + realHeaderSize,buffer + estHeaderSize,(size_t)(realSize)); + } + + /* write the size */ + writeCompressedInteger(realSize,buf,&dummyLen); + + /* return the true end of buffer */ + return(buffer + realHeaderSize + realSize); +} + +/*----------------------------------------------------------------------*/ + +static char* readUserInfoHeader _AP((data_tag* tag,unsigned long* num, + char* buffer)); + +static char* +readUserInfoHeader(tag,num,buffer) +data_tag* tag; +unsigned long* num; +char* buffer; +/* read the tag and size */ +{ + char* buf = buffer; + buf = readTag(tag,buf); + buf = readCompressedInteger(num,buf); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISInitResponse* +makeWAISInitResponse(chunkCode, + chunkIDLen, + chunkMarker, + highlightMarker, + deHighlightMarker, + newLineChars) +long chunkCode; +long chunkIDLen; +char* chunkMarker; +char* highlightMarker; +char* deHighlightMarker; +char* newLineChars; +/* create a WAIS init response object */ +{ + WAISInitResponse* init = (WAISInitResponse*)s_malloc((size_t)sizeof(WAISInitResponse)); + + init->ChunkCode = chunkCode; /* note: none are copied! */ + init->ChunkIDLength = chunkIDLen; + init->ChunkMarker = chunkMarker; + init->HighlightMarker = highlightMarker; + init->DeHighlightMarker = deHighlightMarker; + init->NewlineCharacters = newLineChars; + + return(init); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISInitResponse(init) +WAISInitResponse* init; +/* free an object made with makeWAISInitResponse */ +{ + s_free(init->ChunkMarker); + s_free(init->HighlightMarker); + s_free(init->DeHighlightMarker); + s_free(init->NewlineCharacters); + s_free(init); +} + +/*----------------------------------------------------------------------*/ + +char* +writeInitResponseInfo(init,buffer,len) +InitResponseAPDU* init; +char* buffer; +long* len; +/* write an init response object */ +{ + unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISInitResponseSize); + char* buf = buffer + header_len; + WAISInitResponse* info = (WAISInitResponse*)init->UserInformationField; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeNum(info->ChunkCode,DT_ChunkCode,buf,len); + buf = writeNum(info->ChunkIDLength,DT_ChunkIDLength,buf,len); + buf = writeString(info->ChunkMarker,DT_ChunkMarker,buf,len); + buf = writeString(info->HighlightMarker,DT_HighlightMarker,buf,len); + buf = writeString(info->DeHighlightMarker,DT_DeHighlightMarker,buf,len); + buf = writeString(info->NewlineCharacters,DT_NewlineCharacters,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readInitResponseInfo(info,buffer) +void** info; +char* buffer; +/* read an init response object */ +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + long chunkCode,chunkIDLen; + char* chunkMarker = NULL; + char* highlightMarker = NULL; + char* deHighlightMarker = NULL; + char* newLineChars = NULL; + + chunkCode = chunkIDLen = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_ChunkCode: + buf = readNum(&chunkCode,buf); + break; + case DT_ChunkIDLength: + buf = readNum(&chunkIDLen,buf); + break; + case DT_ChunkMarker: + buf = readString(&chunkMarker,buf); + break; + case DT_HighlightMarker: + buf = readString(&highlightMarker,buf); + break; + case DT_DeHighlightMarker: + buf = readString(&deHighlightMarker,buf); + break; + case DT_NewlineCharacters: + buf = readString(&newLineChars,buf); + break; + default: + s_free(highlightMarker); + s_free(deHighlightMarker); + s_free(newLineChars); + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISInitResponse(chunkCode,chunkIDLen,chunkMarker, + highlightMarker,deHighlightMarker, + newLineChars); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISSearch* +makeWAISSearch(seedWords, + docs, + textList, + dateFactor, + beginDateRange, + endDateRange, + maxDocsRetrieved) +char* seedWords; +DocObj** docs; +char** textList; +long dateFactor; +char* beginDateRange; +char* endDateRange; +long maxDocsRetrieved; + +/* create a type 3 query object */ +{ + WAISSearch* query = (WAISSearch*)s_malloc((size_t)sizeof(WAISSearch)); + + query->SeedWords = seedWords; /* not copied! */ + query->Docs = docs; /* not copied! */ + query->TextList = textList; /* not copied! */ + query->DateFactor = dateFactor; + query->BeginDateRange = beginDateRange; + query->EndDateRange = endDateRange; + query->MaxDocumentsRetrieved = maxDocsRetrieved; + + return(query); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISSearch(query) +WAISSearch* query; + +/* destroy an object made with makeWAISSearch() */ +{ + void* ptr = NULL; + long i; + + s_free(query->SeedWords); + + if (query->Docs != NULL) + for (i = 0,ptr = (void *)query->Docs[i]; ptr != NULL; ptr = (void *)query->Docs[++i]) + freeDocObj((DocObj*)ptr); + s_free(query->Docs); + + if (query->TextList != NULL) /* XXX revisit when textlist is fully defined */ + for (i = 0,ptr = (void *)query->TextList[i]; ptr != NULL; ptr = (void *)query->TextList[++i]) + s_free(ptr); + s_free(query->TextList); + + s_free(query->BeginDateRange); + s_free(query->EndDateRange); + s_free(query); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingWholeDocument(docID,type) +any* docID; +char* type; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->DocumentID = docID; /* not copied! */ + doc->Type = type; /* not copied! */ + doc->ChunkCode = CT_document; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingLines(docID,type,start,end) +any* docID; +char* type; +long start; +long end; + +/* construct a document object using line chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_line; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; /* not copied! */ + doc->ChunkStart.Pos = start; + doc->ChunkEnd.Pos = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingBytes(docID,type,start,end) +any* docID; +char* type; +long start; +long end; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_byte; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; /* not copied! */ + doc->ChunkStart.Pos = start; + doc->ChunkEnd.Pos = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +DocObj* +makeDocObjUsingParagraphs(docID,type,start,end) +any* docID; +char* type; +any* start; +any* end; + +/* construct a document object using byte chunks - only for use by + servers */ +{ + DocObj* doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + doc->ChunkCode = CT_paragraph; + doc->DocumentID = docID; /* not copied */ + doc->Type = type; + doc->ChunkStart.ID = start; + doc->ChunkEnd.ID = end; + return(doc); +} + +/*----------------------------------------------------------------------*/ + +void +freeDocObj(doc) +DocObj* doc; + +/* free a docObj */ +{ + freeAny(doc->DocumentID); + s_free(doc->Type); + if (doc->ChunkCode == CT_paragraph) + { freeAny(doc->ChunkStart.ID); + freeAny(doc->ChunkEnd.ID); + } + s_free(doc); +} + +/*----------------------------------------------------------------------*/ + +static char* writeDocObj _AP((DocObj* doc,char* buffer,long* len)); + +static char* +writeDocObj(doc,buffer,len) +DocObj* doc; +char* buffer; +long* len; + +/* write as little as we can about the doc obj */ +{ + char* buf = buffer; + + /* we alwasy have to write the id, but its tag depends on if its a chunk */ + if (doc->ChunkCode == CT_document) + buf = writeAny(doc->DocumentID,DT_DocumentID,buf,len); + else + buf = writeAny(doc->DocumentID,DT_DocumentIDChunk,buf,len); + + if (doc->Type != NULL) + buf = writeString(doc->Type,DT_TYPE,buf,len); + + switch (doc->ChunkCode) + { case CT_document: + /* do nothing - there is no chunk data */ + break; + case CT_byte: + case CT_line: + buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len); + buf = writeNum(doc->ChunkStart.Pos,DT_ChunkStartID,buf,len); + buf = writeNum(doc->ChunkEnd.Pos,DT_ChunkEndID,buf,len); + break; + case CT_paragraph: + buf = writeNum(doc->ChunkCode,DT_ChunkCode,buf,len); + buf = writeAny(doc->ChunkStart.ID,DT_ChunkStartID,buf,len); + buf = writeAny(doc->ChunkEnd.ID,DT_ChunkEndID,buf,len); + break; + default: + panic("Implementation error: unknown chuck type %ld", + doc->ChunkCode); + break; + } + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +static char* readDocObj _AP((DocObj** doc,char* buffer)); + +static char* +readDocObj(doc,buffer) +DocObj** doc; +char* buffer; + +/* read whatever we have about the new document */ +{ + char* buf = buffer; + data_tag tag; + + *doc = (DocObj*)s_malloc((size_t)sizeof(DocObj)); + + tag = peekTag(buf); + buf = readAny(&((*doc)->DocumentID),buf); + + if (tag == DT_DocumentID) + { (*doc)->ChunkCode = CT_document; + tag = peekTag(buf); + if (tag == DT_TYPE) /* XXX depends on DT_TYPE != what comes next */ + buf = readString(&((*doc)->Type),buf); + /* ChunkStart and ChunkEnd are undefined */ + } + else if (tag == DT_DocumentIDChunk) + { boolean readParagraphs = false; /* for cleanup */ + tag = peekTag(buf); + if (tag == DT_TYPE) /* XXX depends on DT_TYPE != CT_FOO */ + buf = readString(&((*doc)->Type),buf); + buf = readNum(&((*doc)->ChunkCode),buf); + switch ((*doc)->ChunkCode) + { case CT_byte: + case CT_line: + buf = readNum(&((*doc)->ChunkStart.Pos),buf); + buf = readNum(&((*doc)->ChunkEnd.Pos),buf); + break; + case CT_paragraph: + readParagraphs = true; + buf = readAny(&((*doc)->ChunkStart.ID),buf); + buf = readAny(&((*doc)->ChunkEnd.ID),buf); + break; + default: + freeAny((*doc)->DocumentID); + if (readParagraphs) + { freeAny((*doc)->ChunkStart.ID); + freeAny((*doc)->ChunkEnd.ID); + } + s_free(doc); + REPORT_READ_ERROR(buf); + break; + } + } + else + { freeAny((*doc)->DocumentID); + s_free(*doc); + REPORT_READ_ERROR(buf); + } + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +writeSearchInfo(query,buffer,len) +SearchAPDU* query; +char* buffer; +long* len; + +/* write out a WAIS query (type 1 or 3) */ +{ + if (strcmp(query->QueryType,QT_TextRetrievalQuery) == 0) + { return(writeAny((any*)query->Query,DT_Query,buffer,len)); + } + else + { unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISSearchSize); + char* buf = buffer + header_len; + WAISSearch* info = (WAISSearch*)query->Query; + unsigned long size; + long i; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeString(info->SeedWords,DT_SeedWords,buf,len); + + if (info->Docs != NULL) + { for (i = 0; info->Docs[i] != NULL; i++) + { buf = writeDocObj(info->Docs[i],buf,len); + } + } + + /* XXX text list */ + + buf = writeNum(info->DateFactor,DT_DateFactor,buf,len); + buf = writeString(info->BeginDateRange,DT_BeginDateRange,buf,len); + buf = writeString(info->EndDateRange,DT_EndDateRange,buf,len); + buf = writeNum(info->MaxDocumentsRetrieved,DT_MaxDocumentsRetrieved,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); + } +} + +/*----------------------------------------------------------------------*/ + +char* +readSearchInfo(info,buffer) +void** info; +char* buffer; + +/* read a WAIS query (type 1 or 3) */ +{ + data_tag type = peekTag(buffer); + if (type == DT_Query) /* this is a type 1 query */ + { char* buf = buffer; + any* query = NULL; + buf = readAny(&query,buf); + *info = (void *)query; + return(buf); + } + else /* a type 3 query */ + { char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + char* seedWords = NULL; + char* beginDateRange = NULL; + char* endDateRange = NULL; + long dateFactor,maxDocsRetrieved; + char** textList = NULL; + DocObj** docIDs = NULL; + DocObj* doc = NULL; + long docs = 0; + long i; + void* ptr = NULL; + + dateFactor = maxDocsRetrieved = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_SeedWords: + buf = readString(&seedWords,buf); + break; + case DT_DocumentID: + case DT_DocumentIDChunk: + if (docIDs == NULL) /* create a new doc list */ + { docIDs = (DocObj**)s_malloc((size_t)sizeof(DocObj*) * 2); + } + else /* grow the doc list */ + { docIDs = (DocObj**)s_realloc((char*)docIDs,(size_t)(sizeof(DocObj*) * (docs + 2))); + } + buf = readDocObj(&doc,buf); + if (buf == NULL) + { s_free(seedWords); + s_free(beginDateRange); + s_free(endDateRange); + if (docIDs != NULL) + for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i]) + freeDocObj((DocObj*)ptr); + s_free(docIDs); + /* XXX should also free textlist when it is fully defined */ + } + RETURN_ON_NULL(buf); + docIDs[docs++] = doc; /* put it in the list */ + docIDs[docs] = NULL; + break; + case DT_TextList: + /* XXX */ + break; + case DT_DateFactor: + buf = readNum(&dateFactor,buf); + break; + case DT_BeginDateRange: + buf = readString(&beginDateRange,buf); + break; + case DT_EndDateRange: + buf = readString(&endDateRange,buf); + break; + case DT_MaxDocumentsRetrieved: + buf = readNum(&maxDocsRetrieved,buf); + break; + default: + s_free(seedWords); + s_free(beginDateRange); + s_free(endDateRange); + if (docIDs != NULL) + for (i = 0,ptr = (void *)docIDs[i]; ptr != NULL; ptr = (void *)docIDs[++i]) + freeDocObj((DocObj*)ptr); + s_free(docIDs); + /* XXX should also free textlist when it is fully defined */ + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISSearch(seedWords,docIDs,textList, + dateFactor,beginDateRange,endDateRange, + maxDocsRetrieved); + return(buf); + } +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentHeader* +makeWAISDocumentHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines, + types, + source, + date, + headline, + originCity) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +char** types; +char* source; +char* date; +char* headline; +char* originCity; + +/* construct a standard document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentHeader* header = + (WAISDocumentHeader*)s_malloc((size_t)sizeof(WAISDocumentHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + header->Types = types; + header->Source = source; + header->Date = date; + header->Headline = headline; + header->OriginCity = originCity; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentHeader(header) +WAISDocumentHeader* header; + +{ + freeAny(header->DocumentID); + doList((void**)header->Types,fs_free); /* can't use the macro here ! */ + s_free(header->Types); + s_free(header->Source); + s_free(header->Date); + s_free(header->Headline); + s_free(header->OriginCity); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentHeader(header,buffer,len) +WAISDocumentHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentHeaderGroup , + DefWAISDocHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + if (header->Types != NULL) + { long size; + char* ptr = NULL; + long i; + buf = writeTag(DT_TYPE_BLOCK,buf,len); + for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + { long typeSize = strlen(ptr); + size += writtenTagSize(DT_TYPE); + size += writtenCompressedIntSize(typeSize); + size += typeSize; + } + buf = writeCompressedInteger((unsigned long)size,buf,len); + for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + buf = writeString(ptr,DT_TYPE,buf,len); + } + buf = writeString(header->Source,DT_Source,buf,len); + buf = writeString(header->Date,DT_Date,buf,len); + buf = writeString(header->Headline,DT_Headline,buf,len); + buf = writeString(header->OriginCity,DT_OriginCity,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentHeader(header,buffer) +WAISDocumentHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID = NULL; + long versionNumber,score,bestMatch,docLength,lines; + char** types = NULL; + char *source = NULL; + char *date = NULL; + char *headline = NULL; + char *originCity = NULL; + + versionNumber = score = bestMatch = docLength = lines = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + case DT_TYPE_BLOCK: + { unsigned long size = -1; + long numTypes = 0; + buf = readTag(&tag,buf); + buf = readCompressedInteger(&size,buf); + while (size > 0) + { char* type = NULL; + char* originalBuf = buf; + buf = readString(&type,buf); + types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2))); + types[numTypes++] = type; + types[numTypes] = NULL; + size -= (buf - originalBuf); + } + } + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentHeader(docID,versionNumber,score,bestMatch, + docLength,lines,types,source,date,headline, + originCity); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentShortHeader* +makeWAISDocumentShortHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +/* construct a short document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentShortHeader* header = + (WAISDocumentShortHeader*)s_malloc((size_t)sizeof(WAISDocumentShortHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentShortHeader(header) +WAISDocumentShortHeader* header; +{ + freeAny(header->DocumentID); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentShortHeader(header,buffer,len) +WAISDocumentShortHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentShortHeaderGroup , + DefWAISShortHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentShortHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentShortHeader(header,buffer) +WAISDocumentShortHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID = NULL; + long versionNumber,score,bestMatch,docLength,lines; + + versionNumber = score = bestMatch = docLength = lines = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + default: + freeAny(docID); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentShortHeader(docID,versionNumber,score,bestMatch, + docLength,lines); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentLongHeader* +makeWAISDocumentLongHeader(docID, + versionNumber, + score, + bestMatch, + docLen, + lines, + types, + source, + date, + headline, + originCity, + stockCodes, + companyCodes, + industryCodes) +any* docID; +long versionNumber; +long score; +long bestMatch; +long docLen; +long lines; +char** types; +char* source; +char* date; +char* headline; +char* originCity; +char* stockCodes; +char* companyCodes; +char* industryCodes; +/* construct a long document header, note that no fields are copied! + if the application needs to save these fields, it should copy them, + or set the field in this object to NULL before freeing it. + */ +{ + WAISDocumentLongHeader* header = + (WAISDocumentLongHeader*)s_malloc((size_t)sizeof(WAISDocumentLongHeader)); + + header->DocumentID = docID; + header->VersionNumber = versionNumber; + header->Score = score; + header->BestMatch = bestMatch; + header->DocumentLength = docLen; + header->Lines = lines; + header->Types = types; + header->Source = source; + header->Date = date; + header->Headline = headline; + header->OriginCity = originCity; + header->StockCodes = stockCodes; + header->CompanyCodes = companyCodes; + header->IndustryCodes = industryCodes; + + return(header); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentLongHeader(header) +WAISDocumentLongHeader* header; +{ + freeAny(header->DocumentID); + doList((void**)header->Types,fs_free); /* can't use the macro here! */ + s_free(header->Source); + s_free(header->Date); + s_free(header->Headline); + s_free(header->OriginCity); + s_free(header->StockCodes); + s_free(header->CompanyCodes); + s_free(header->IndustryCodes); + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentLongHeader(header,buffer,len) +WAISDocumentLongHeader* header; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentLongHeaderGroup , + DefWAISLongHeaderSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(header->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(header->VersionNumber,DT_VersionNumber,buf,len); + buf = writeNum(header->Score,DT_Score,buf,len); + buf = writeNum(header->BestMatch,DT_BestMatch,buf,len); + buf = writeNum(header->DocumentLength,DT_DocumentLength,buf,len); + buf = writeNum(header->Lines,DT_Lines,buf,len); + if (header->Types != NULL) + { long size; + char* ptr = NULL; + long i; + buf = writeTag(DT_TYPE_BLOCK,buf,len); + for (i = 0,size = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + { long typeSize = strlen(ptr); + size += writtenTagSize(DT_TYPE); + size += writtenCompressedIntSize(typeSize); + size += typeSize; + } + buf = writeCompressedInteger((unsigned long)size,buf,len); + for (i = 0,ptr = header->Types[i]; ptr != NULL; ptr = header->Types[++i]) + buf = writeString(ptr,DT_TYPE,buf,len); + } + buf = writeString(header->Source,DT_Source,buf,len); + buf = writeString(header->Date,DT_Date,buf,len); + buf = writeString(header->Headline,DT_Headline,buf,len); + buf = writeString(header->OriginCity,DT_OriginCity,buf,len); + buf = writeString(header->StockCodes,DT_StockCodes,buf,len); + buf = writeString(header->CompanyCodes,DT_CompanyCodes,buf,len); + buf = writeString(header->IndustryCodes,DT_IndustryCodes,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentLongHeaderGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentLongHeader(header,buffer) +WAISDocumentLongHeader** header; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber,score,bestMatch,docLength,lines; + char **types; + char *source,*date,*headline,*originCity,*stockCodes,*companyCodes,*industryCodes; + + docID = NULL; + versionNumber = score = bestMatch = docLength = lines = UNUSED; + types = NULL; + source = date = headline = originCity = stockCodes = companyCodes = industryCodes = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Score: + buf = readNum(&score,buf); + break; + case DT_BestMatch: + buf = readNum(&bestMatch,buf); + break; + case DT_DocumentLength: + buf = readNum(&docLength,buf); + break; + case DT_Lines: + buf = readNum(&lines,buf); + break; + case DT_TYPE_BLOCK: + { unsigned long size = -1; + long numTypes = 0; + buf = readTag(&tag,buf); + readCompressedInteger(&size,buf); + while (size > 0) + { char* type = NULL; + char* originalBuf = buf; + buf = readString(&type,buf); + types = (char**)s_realloc(types,(size_t)(sizeof(char*) * (numTypes + 2))); + types[numTypes++] = type; + types[numTypes] = NULL; + size -= (buf - originalBuf); + } + } + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + case DT_StockCodes: + buf = readString(&stockCodes,buf); + break; + case DT_CompanyCodes: + buf = readString(&companyCodes,buf); + break; + case DT_IndustryCodes: + buf = readString(&industryCodes,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + s_free(stockCodes); + s_free(companyCodes); + s_free(industryCodes); + REPORT_READ_ERROR(buf); + break; + } + } + + *header = makeWAISDocumentLongHeader(docID,versionNumber,score,bestMatch, + docLength,lines,types,source,date,headline, + originCity,stockCodes,companyCodes, + industryCodes); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISSearchResponse* +makeWAISSearchResponse(seedWordsUsed, + docHeaders, + shortHeaders, + longHeaders, + text, + headlines, + codes, + diagnostics) +char* seedWordsUsed; +WAISDocumentHeader** docHeaders; +WAISDocumentShortHeader** shortHeaders; +WAISDocumentLongHeader** longHeaders; +WAISDocumentText** text; +WAISDocumentHeadlines** headlines; +WAISDocumentCodes** codes; +diagnosticRecord** diagnostics; +{ + WAISSearchResponse* response = (WAISSearchResponse*)s_malloc((size_t)sizeof(WAISSearchResponse)); + + response->SeedWordsUsed = seedWordsUsed; + response->DocHeaders = docHeaders; + response->ShortHeaders = shortHeaders; + response->LongHeaders = longHeaders; + response->Text = text; + response->Headlines = headlines; + response->Codes = codes; + response->Diagnostics = diagnostics; + + return(response); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISSearchResponse(response) +WAISSearchResponse* response; +{ + void* ptr = NULL; + long i; + + s_free(response->SeedWordsUsed); + + if (response->DocHeaders != NULL) + for (i = 0,ptr = (void *)response->DocHeaders[i]; ptr != NULL; ptr = (void *)response->DocHeaders[++i]) + freeWAISDocumentHeader((WAISDocumentHeader*)ptr); + s_free(response->DocHeaders); + + if (response->ShortHeaders != NULL) + for (i = 0,ptr = (void *)response->ShortHeaders[i]; ptr != NULL; ptr = (void *)response->ShortHeaders[++i]) + freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr); + s_free(response->ShortHeaders); + + if (response->LongHeaders != NULL) + for (i = 0,ptr = (void *)response->LongHeaders[i]; ptr != NULL; ptr = (void *)response->LongHeaders[++i]) + freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr); + s_free(response->LongHeaders); + + if (response->Text != NULL) + for (i = 0,ptr = (void *)response->Text[i]; ptr != NULL; ptr = (void *)response->Text[++i]) + freeWAISDocumentText((WAISDocumentText*)ptr); + s_free(response->Text); + + if (response->Headlines != NULL) + for (i = 0,ptr = (void *)response->Headlines[i]; ptr != NULL; ptr = (void *)response->Headlines[++i]) + freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr); + s_free(response->Headlines); + + if (response->Codes != NULL) + for (i = 0,ptr = (void *)response->Codes[i]; ptr != NULL; ptr = (void *)response->Codes[++i]) + freeWAISDocumentCodes((WAISDocumentCodes*)ptr); + s_free(response->Codes); + + if (response->Diagnostics != NULL) + for (i = 0,ptr = (void *)response->Diagnostics[i]; ptr != NULL; ptr = (void *)response->Diagnostics[++i]) + freeDiag((diagnosticRecord*)ptr); + s_free(response->Diagnostics); + + s_free(response); +} + +/*----------------------------------------------------------------------*/ + +char* +writeSearchResponseInfo(query,buffer,len) +SearchResponseAPDU* query; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_UserInformationLength, + DefWAISSearchResponseSize); + char* buf = buffer + header_len; + WAISSearchResponse* info = (WAISSearchResponse*)query->DatabaseDiagnosticRecords; + unsigned long size; + void* header = NULL; + long i; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeString(info->SeedWordsUsed,DT_SeedWordsUsed,buf,len); + + /* write out all the headers */ + if (info->DocHeaders != NULL) + { for (i = 0,header = (void *)info->DocHeaders[i]; header != NULL; header = (void *)info->DocHeaders[++i]) + buf = writeWAISDocumentHeader((WAISDocumentHeader*)header,buf,len); + } + + if (info->ShortHeaders != NULL) + { for (i = 0,header = (void *)info->ShortHeaders[i]; header != NULL; header = (void *)info->ShortHeaders[++i]) + buf = writeWAISDocumentShortHeader((WAISDocumentShortHeader*)header,buf,len); + } + + if (info->LongHeaders != NULL) + { for (i = 0,header = (void *)info->LongHeaders[i]; header != NULL; header = (void *)info->LongHeaders[++i]) + buf = writeWAISDocumentLongHeader((WAISDocumentLongHeader*)header,buf,len); + } + + if (info->Text != NULL) + { for (i = 0,header = (void *)info->Text[i]; header != NULL; header = (void *)info->Text[++i]) + buf = writeWAISDocumentText((WAISDocumentText*)header,buf,len); + } + + if (info->Headlines != NULL) + { for (i = 0,header = (void *)info->Headlines[i]; header != NULL; header = (void *)info->Headlines[++i]) + buf = writeWAISDocumentHeadlines((WAISDocumentHeadlines*)header,buf,len); + } + + if (info->Codes != NULL) + { for (i = 0,header = (void *)info->Codes[i]; header != NULL;header = (void *)info->Codes[++i]) + buf = writeWAISDocumentCodes((WAISDocumentCodes*)header,buf,len); + } + + if (info->Diagnostics != NULL) + { for (i = 0, header = (void *)info->Diagnostics[i]; header != NULL; header = (void *)info->Diagnostics[++i]) + buf = writeDiag((diagnosticRecord*)header,buf,len); + } + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_UserInformationLength,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +static void +cleanUpWaisSearchResponse _AP((char* buf,char* seedWordsUsed, + WAISDocumentHeader** docHeaders, + WAISDocumentShortHeader** shortHeaders, + WAISDocumentLongHeader** longHeaders, + WAISDocumentText** text, + WAISDocumentHeadlines** headlines, + WAISDocumentCodes** codes, + diagnosticRecord**diags)); + +static void +cleanUpWaisSearchResponse (buf,seedWordsUsed,docHeaders,shortHeaders, + longHeaders,text,headlines,codes,diags) +char* buf; +char* seedWordsUsed; +WAISDocumentHeader** docHeaders; +WAISDocumentShortHeader** shortHeaders; +WAISDocumentLongHeader** longHeaders; +WAISDocumentText** text; +WAISDocumentHeadlines** headlines; +WAISDocumentCodes** codes; +diagnosticRecord** diags; +/* if buf is NULL, we have just gotten a read error, and need to clean up + any state we have built. If not, then everything is going fine, and + we should just hang loose + */ +{ + void* ptr = NULL; + long i; + + if (buf == NULL) + { s_free(seedWordsUsed); + if (docHeaders != NULL) + for (i = 0,ptr = (void *)docHeaders[i]; ptr != NULL; + ptr = (void *)docHeaders[++i]) + freeWAISDocumentHeader((WAISDocumentHeader*)ptr); + s_free(docHeaders); + if (shortHeaders != NULL) + for (i = 0,ptr = (void *)shortHeaders[i]; ptr != NULL; + ptr = (void *)shortHeaders[++i]) + freeWAISDocumentShortHeader((WAISDocumentShortHeader*)ptr); + s_free(shortHeaders); + if (longHeaders != NULL) + for (i = 0,ptr = (void *)longHeaders[i]; ptr != NULL; + ptr = (void *)longHeaders[++i]) + freeWAISDocumentLongHeader((WAISDocumentLongHeader*)ptr); + s_free(longHeaders); + if (text != NULL) + for (i = 0,ptr = (void *)text[i]; ptr != NULL; ptr = (void *)text[++i]) + freeWAISDocumentText((WAISDocumentText*)ptr); + s_free(text); + if (headlines != NULL) + for (i = 0,ptr = (void *)headlines[i]; ptr != NULL; + ptr = (void *)headlines[++i]) + freeWAISDocumentHeadlines((WAISDocumentHeadlines*)ptr); + s_free(headlines); + if (codes != NULL) + for (i = 0,ptr = (void *)codes[i]; ptr != NULL; + ptr = (void *)codes[++i]) + freeWAISDocumentCodes((WAISDocumentCodes*)ptr); + s_free(codes); + if (diags != NULL) + for (i = 0,ptr = (void *)diags[i]; ptr != NULL; + ptr = (void *)diags[++i]) + freeDiag((diagnosticRecord*)ptr); + s_free(diags); + } +} + +/*----------------------------------------------------------------------*/ + +char* +readSearchResponseInfo(info,buffer) +void** info; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + void* header = NULL; + WAISDocumentHeader** docHeaders = NULL; + WAISDocumentShortHeader** shortHeaders = NULL; + WAISDocumentLongHeader** longHeaders = NULL; + WAISDocumentText** text = NULL; + WAISDocumentHeadlines** headlines = NULL; + WAISDocumentCodes** codes = NULL; + long numDocHeaders,numLongHeaders,numShortHeaders,numText,numHeadlines; + long numCodes; + char* seedWordsUsed = NULL; + diagnosticRecord** diags = NULL; + diagnosticRecord* diag = NULL; + long numDiags = 0; + + numDocHeaders = numLongHeaders = numShortHeaders = numText = numHeadlines = numCodes = 0; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_SeedWordsUsed: + buf = readString(&seedWordsUsed,buf); + break; + case DT_DatabaseDiagnosticRecords: + if (diags == NULL) /* create a new diag list */ + { diags = (diagnosticRecord**)s_malloc((size_t)sizeof(diagnosticRecord*) * 2); + } + else /* grow the diag list */ + { diags = (diagnosticRecord**)s_realloc((char*)diags,(size_t)(sizeof(diagnosticRecord*) * (numDiags + 2))); + } + buf = readDiag(&diag,buf); + diags[numDiags++] = diag; /* put it in the list */ + diags[numDiags] = NULL; + break; + case DT_DocumentHeaderGroup: + if (docHeaders == NULL) /* create a new header list */ + { docHeaders = (WAISDocumentHeader**)s_malloc((size_t)sizeof(WAISDocumentHeader*) * 2); + } + else /* grow the doc list */ + { docHeaders = (WAISDocumentHeader**)s_realloc((char*)docHeaders,(size_t)(sizeof(WAISDocumentHeader*) * (numDocHeaders + 2))); + } + buf = readWAISDocumentHeader((WAISDocumentHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + docHeaders[numDocHeaders++] = + (WAISDocumentHeader*)header; /* put it in the list */ + docHeaders[numDocHeaders] = NULL; + break; + case DT_DocumentShortHeaderGroup: + if (shortHeaders == NULL) /* create a new header list */ + { shortHeaders = (WAISDocumentShortHeader**)s_malloc((size_t)sizeof(WAISDocumentShortHeader*) * 2); + } + else /* grow the doc list */ + { shortHeaders = (WAISDocumentShortHeader**)s_realloc((char*)shortHeaders,(size_t)(sizeof(WAISDocumentShortHeader*) * (numShortHeaders + 2))); + } + buf = readWAISDocumentShortHeader((WAISDocumentShortHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + shortHeaders[numShortHeaders++] = + (WAISDocumentShortHeader*)header; /* put it in the list */ + shortHeaders[numShortHeaders] = NULL; + break; + case DT_DocumentLongHeaderGroup: + if (longHeaders == NULL) /* create a new header list */ + { longHeaders = (WAISDocumentLongHeader**)s_malloc((size_t)sizeof(WAISDocumentLongHeader*) * 2); + } + else /* grow the doc list */ + { longHeaders = (WAISDocumentLongHeader**)s_realloc((char*)longHeaders,(size_t)(sizeof(WAISDocumentLongHeader*) * (numLongHeaders + 2))); + } + buf = readWAISDocumentLongHeader((WAISDocumentLongHeader**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + longHeaders[numLongHeaders++] = + (WAISDocumentLongHeader*)header; /* put it in the list */ + longHeaders[numLongHeaders] = NULL; + break; + case DT_DocumentTextGroup: + if (text == NULL) /* create a new list */ + { text = (WAISDocumentText**)s_malloc((size_t)sizeof(WAISDocumentText*) * 2); + } + else /* grow the list */ + { text = (WAISDocumentText**)s_realloc((char*)text,(size_t)(sizeof(WAISDocumentText*) * (numText + 2))); + } + buf = readWAISDocumentText((WAISDocumentText**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + text[numText++] = + (WAISDocumentText*)header; /* put it in the list */ + text[numText] = NULL; + break; + case DT_DocumentHeadlineGroup: + if (headlines == NULL) /* create a new list */ + { headlines = (WAISDocumentHeadlines**)s_malloc((size_t)sizeof(WAISDocumentHeadlines*) * 2); + } + else /* grow the list */ + { headlines = (WAISDocumentHeadlines**)s_realloc((char*)headlines,(size_t)(sizeof(WAISDocumentHeadlines*) * (numHeadlines + 2))); + } + buf = readWAISDocumentHeadlines((WAISDocumentHeadlines**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + headlines[numHeadlines++] = + (WAISDocumentHeadlines*)header; /* put it in the list */ + headlines[numHeadlines] = NULL; + break; + case DT_DocumentCodeGroup: + if (codes == NULL) /* create a new list */ + { codes = (WAISDocumentCodes**)s_malloc((size_t)sizeof(WAISDocumentCodes*) * 2); + } + else /* grow the list */ + { codes = (WAISDocumentCodes**)s_realloc((char*)codes,(size_t)(sizeof(WAISDocumentCodes*) * (numCodes + 2))); + } + buf = readWAISDocumentCodes((WAISDocumentCodes**)&header,buf); + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + RETURN_ON_NULL(buf); + codes[numCodes++] = + (WAISDocumentCodes*)header; /* put it in the list */ + codes[numCodes] = NULL; + break; + default: + cleanUpWaisSearchResponse(buf,seedWordsUsed,docHeaders,shortHeaders,longHeaders,text,headlines,codes,diags); + REPORT_READ_ERROR(buf); + break; + } + } + + *info = (void *)makeWAISSearchResponse(seedWordsUsed,docHeaders,shortHeaders, + longHeaders,text,headlines,codes,diags); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentText* +makeWAISDocumentText(docID,versionNumber,documentText) +any* docID; +long versionNumber; +any* documentText; +{ + WAISDocumentText* docText = (WAISDocumentText*)s_malloc((size_t)sizeof(WAISDocumentText)); + + docText->DocumentID = docID; + docText->VersionNumber = versionNumber; + docText->DocumentText = documentText; + + return(docText); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentText(docText) +WAISDocumentText* docText; +{ + freeAny(docText->DocumentID); + freeAny(docText->DocumentText); + s_free(docText); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentText(docText,buffer,len) +WAISDocumentText* docText; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentTextGroup, + DefWAISDocTextSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docText->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docText->VersionNumber,DT_VersionNumber,buf,len); + buf = writeAny(docText->DocumentText,DT_DocumentText,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentTextGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentText(docText,buffer) +WAISDocumentText** docText; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any *docID,*documentText; + long versionNumber; + + docID = documentText = NULL; + versionNumber = UNUSED; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_DocumentText: + buf = readAny(&documentText,buf); + break; + default: + freeAny(docID); + freeAny(documentText); + REPORT_READ_ERROR(buf); + break; + } + } + + *docText = makeWAISDocumentText(docID,versionNumber,documentText); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentHeadlines* +makeWAISDocumentHeadlines(docID, + versionNumber, + source, + date, + headline, + originCity) +any* docID; +long versionNumber; +char* source; +char* date; +char* headline; +char* originCity; +{ + WAISDocumentHeadlines* docHeadline = + (WAISDocumentHeadlines*)s_malloc((size_t)sizeof(WAISDocumentHeadlines)); + + docHeadline->DocumentID = docID; + docHeadline->VersionNumber = versionNumber; + docHeadline->Source = source; + docHeadline->Date = date; + docHeadline->Headline = headline; + docHeadline->OriginCity = originCity; + + return(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentHeadlines(docHeadline) +WAISDocumentHeadlines* docHeadline; +{ + freeAny(docHeadline->DocumentID); + s_free(docHeadline->Source); + s_free(docHeadline->Date); + s_free(docHeadline->Headline); + s_free(docHeadline->OriginCity); + s_free(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentHeadlines(docHeadline,buffer,len) +WAISDocumentHeadlines* docHeadline; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentHeadlineGroup, + DefWAISDocHeadlineSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docHeadline->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docHeadline->VersionNumber,DT_VersionNumber,buf,len); + buf = writeString(docHeadline->Source,DT_Source,buf,len); + buf = writeString(docHeadline->Date,DT_Date,buf,len); + buf = writeString(docHeadline->Headline,DT_Headline,buf,len); + buf = writeString(docHeadline->OriginCity,DT_OriginCity,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentHeadlineGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentHeadlines(docHeadline,buffer) +WAISDocumentHeadlines** docHeadline; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber; + char *source,*date,*headline,*originCity; + + docID = NULL; + versionNumber = UNUSED; + source = date = headline = originCity = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_Source: + buf = readString(&source,buf); + break; + case DT_Date: + buf = readString(&date,buf); + break; + case DT_Headline: + buf = readString(&headline,buf); + break; + case DT_OriginCity: + buf = readString(&originCity,buf); + break; + default: + freeAny(docID); + s_free(source); + s_free(date); + s_free(headline); + s_free(originCity); + REPORT_READ_ERROR(buf); + break; + } + } + + *docHeadline = makeWAISDocumentHeadlines(docID,versionNumber,source,date, + headline,originCity); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +WAISDocumentCodes* +makeWAISDocumentCodes(docID, + versionNumber, + stockCodes, + companyCodes, + industryCodes) +any* docID; +long versionNumber; +char* stockCodes; +char* companyCodes; +char* industryCodes; +{ + WAISDocumentCodes* docCodes = (WAISDocumentCodes*)s_malloc((size_t)sizeof(WAISDocumentCodes)); + + docCodes->DocumentID = docID; + docCodes->VersionNumber = versionNumber; + docCodes->StockCodes = stockCodes; + docCodes->CompanyCodes = companyCodes; + docCodes->IndustryCodes = industryCodes; + + return(docCodes); +} + +/*----------------------------------------------------------------------*/ + +void +freeWAISDocumentCodes(docCodes) +WAISDocumentCodes* docCodes; +{ + freeAny(docCodes->DocumentID); + s_free(docCodes->StockCodes); + s_free(docCodes->CompanyCodes); + s_free(docCodes->IndustryCodes); + s_free(docCodes); +} + +/*----------------------------------------------------------------------*/ + +char* +writeWAISDocumentCodes(docCodes,buffer,len) +WAISDocumentCodes* docCodes; +char* buffer; +long* len; +{ + unsigned long header_len = userInfoTagSize(DT_DocumentCodeGroup , + DefWAISDocCodeSize); + char* buf = buffer + header_len; + unsigned long size; + + RESERVE_SPACE_FOR_WAIS_HEADER(len); + + buf = writeAny(docCodes->DocumentID,DT_DocumentID,buf,len); + buf = writeNum(docCodes->VersionNumber,DT_VersionNumber,buf,len); + buf = writeString(docCodes->StockCodes,DT_StockCodes,buf,len); + buf = writeString(docCodes->CompanyCodes,DT_CompanyCodes,buf,len); + buf = writeString(docCodes->IndustryCodes,DT_IndustryCodes,buf,len); + + /* now write the header and size */ + size = buf - buffer; + buf = writeUserInfoHeader(DT_DocumentCodeGroup,size,header_len,buffer,len); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +readWAISDocumentCodes(docCodes,buffer) +WAISDocumentCodes** docCodes; +char* buffer; +{ + char* buf = buffer; + unsigned long size; + unsigned long headerSize; + data_tag tag; + any* docID; + long versionNumber; + char *stockCodes,*companyCodes,*industryCodes; + + docID = NULL; + versionNumber = UNUSED; + stockCodes = companyCodes = industryCodes = NULL; + + buf = readUserInfoHeader(&tag,&size,buf); + headerSize = buf - buffer; + + while (buf < (buffer + size + headerSize)) + { data_tag tag = peekTag(buf); + switch (tag) + { case DT_DocumentID: + buf = readAny(&docID,buf); + break; + case DT_VersionNumber: + buf = readNum(&versionNumber,buf); + break; + case DT_StockCodes: + buf = readString(&stockCodes,buf); + break; + case DT_CompanyCodes: + buf = readString(&companyCodes,buf); + break; + case DT_IndustryCodes: + buf = readString(&industryCodes,buf); + break; + default: + freeAny(docID); + s_free(stockCodes); + s_free(companyCodes); + s_free(industryCodes); + REPORT_READ_ERROR(buf); + break; + } + } + + *docCodes = makeWAISDocumentCodes(docID,versionNumber,stockCodes, + companyCodes,industryCodes); + return(buf); +} + +/*----------------------------------------------------------------------*/ + +char* +writePresentInfo(present,buffer,len) +PresentAPDU* present; +char* buffer; +long* len; +{ + /* The WAIS protocol doesn't use present info */ + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +readPresentInfo(info,buffer) +void** info; +char* buffer; +{ + /* The WAIS protocol doesn't use present info */ + *info = NULL; + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +writePresentResponseInfo(response,buffer,len) +PresentResponseAPDU* response; +char* buffer; +long* len; +{ + /* The WAIS protocol doesn't use presentResponse info */ + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +char* +readPresentResponseInfo(info,buffer) +void** info; +char* buffer; +{ + /* The WAIS protocol doesn't use presentResponse info */ + *info = NULL; + return(buffer); +} + +/*----------------------------------------------------------------------*/ + +/* support for type 1 queries */ + +/* new use values (for the chunk types) */ +#define BYTE "wb" +#define LINE "wl" +#define PARAGRAPH "wp" +#define DATA_TYPE "wt" + +/* WAIS supports the following semantics for type 1 queries: + + 1. retrieve the header/codes from a document: + + System_Control_Number = docID + Data Type = type (optional) + And + + 2. retrieve a fragment of the text of a document: + + System_Control_Number = docID + Data Type = type (optional) + And + Chunk >= start + And + Chunk < end + And + + Information from multiple documents may be requested by using + groups of the above joined by: + + OR + + ( XXX does an OR come after every group but the first, or do they + all come at the end? ) + + ( XXX return type could be in the element set) +*/ + +static query_term** makeWAISQueryTerms _AP((DocObj** docs)); + +static query_term** +makeWAISQueryTerms(docs) +DocObj** docs; +/* given a null terminated list of docObjs, construct the appropriate + query of the form given above + */ +{ + query_term** terms = NULL; + long numTerms = 0; + DocObj* doc = NULL; + long i; + + if (docs == NULL) + return((query_term**)NULL); + + terms = (query_term**)s_malloc((size_t)(sizeof(query_term*) * 1)); + terms[numTerms] = NULL; + + /* loop through the docs making terms for them all */ + for (i = 0,doc = docs[i]; doc != NULL; doc = docs[++i]) + { any* type = NULL; + + if (doc->Type != NULL) + type = stringToAny(doc->Type); + + if (doc->ChunkCode == CT_document) /* a whole document */ + { terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 3 + 1))); + terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER, + EQUAL,IGNORE,IGNORE, + IGNORE,IGNORE,doc->DocumentID); + if (type != NULL) + { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL, + IGNORE,IGNORE,IGNORE, + IGNORE,type); + terms[numTerms++] = makeOperatorTerm(AND); + } + terms[numTerms] = NULL; + } + else /* a document fragment */ + { char chunk_att[ATTRIBUTE_SIZE]; + any* startChunk = NULL; + any* endChunk = NULL; + + terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 7 + 1))); + + switch (doc->ChunkCode) + { case CT_byte: + case CT_line: + { char start[20],end[20]; + (doc->ChunkCode == CT_byte) ? + strncpy(chunk_att,BYTE,ATTRIBUTE_SIZE) : + strncpy(chunk_att,LINE,ATTRIBUTE_SIZE); + sprintf(start,"%ld",doc->ChunkStart.Pos); + startChunk = stringToAny(start); + sprintf(end,"%ld",doc->ChunkEnd.Pos); + endChunk = stringToAny(end); + } + break; + case CT_paragraph: + strncpy(chunk_att,PARAGRAPH,ATTRIBUTE_SIZE); + startChunk = doc->ChunkStart.ID; + endChunk = doc->ChunkEnd.ID; + break; + default: + /* error */ + break; + } + + terms[numTerms++] = makeAttributeTerm(SYSTEM_CONTROL_NUMBER, + EQUAL,IGNORE,IGNORE, + IGNORE, + IGNORE,doc->DocumentID); + if (type != NULL) + { terms[numTerms++] = makeAttributeTerm(DATA_TYPE,EQUAL,IGNORE, + IGNORE,IGNORE,IGNORE, + type); + terms[numTerms++] = makeOperatorTerm(AND); + } + terms[numTerms++] = makeAttributeTerm(chunk_att, + GREATER_THAN_OR_EQUAL, + IGNORE,IGNORE,IGNORE, + IGNORE, + startChunk); + terms[numTerms++] = makeOperatorTerm(AND); + terms[numTerms++] = makeAttributeTerm(chunk_att,LESS_THAN, + IGNORE,IGNORE,IGNORE, + IGNORE, + endChunk); + terms[numTerms++] = makeOperatorTerm(AND); + terms[numTerms] = NULL; + + if (doc->ChunkCode == CT_byte || doc->ChunkCode == CT_line) + { freeAny(startChunk); + freeAny(endChunk); + } + } + + freeAny(type); + + if (i != 0) /* multiple independent queries, need a disjunction */ + { terms = (query_term**)s_realloc((char*)terms, + (size_t)(sizeof(query_term*) * + (numTerms + 1 + 1))); + terms[numTerms++] = makeOperatorTerm(OR); + terms[numTerms] = NULL; + } + } + + return(terms); +} + +/*----------------------------------------------------------------------*/ + +static DocObj** makeWAISQueryDocs _AP((query_term** terms)); + +static DocObj** +makeWAISQueryDocs(terms) +query_term** terms; +/* given a list of terms in the form given above, convert them to + DocObjs. + */ +{ + query_term* docTerm = NULL; + query_term* fragmentTerm = NULL; + DocObj** docs = NULL; + DocObj* doc = NULL; + long docNum,termNum; + + docNum = termNum = 0; + + docs = (DocObj**)s_malloc((size_t)(sizeof(DocObj*) * 1)); + docs[docNum] = NULL; + + /* translate the terms into DocObjs */ + while (true) + { + query_term* typeTerm = NULL; + char* type = NULL; + long startTermOffset; + + docTerm = terms[termNum]; + + if (docTerm == NULL) + break; /* we're done converting */; + + typeTerm = terms[termNum + 1]; /* get the lead Term if it exists */ + + if (strcmp(typeTerm->Use,DATA_TYPE) == 0) /* we do have a type */ + { startTermOffset = 3; + type = anyToString(typeTerm->Term); + } + else /* no type */ + { startTermOffset = 1; + typeTerm = NULL; + type = NULL; + } + + /* grow the doc list */ + docs = (DocObj**)s_realloc((char*)docs,(size_t)(sizeof(DocObj*) * + (docNum + 1 + 1))); + + /* figure out what kind of docObj to build - and build it */ + fragmentTerm = terms[termNum + startTermOffset]; + if (fragmentTerm != NULL && fragmentTerm->TermType == TT_Attribute) + { /* build a document fragment */ + query_term* startTerm = fragmentTerm; + query_term* endTerm = terms[termNum + startTermOffset + 2]; + + if (strcmp(startTerm->Use,BYTE) == 0){ /* a byte chunk */ + doc = makeDocObjUsingBytes(duplicateAny(docTerm->Term), + type, + anyToLong(startTerm->Term), + anyToLong(endTerm->Term)); + log_write("byte"); + }else if (strcmp(startTerm->Use,LINE) == 0){ /* a line chunk */ + doc = makeDocObjUsingLines(duplicateAny(docTerm->Term), + type, + anyToLong(startTerm->Term), + anyToLong(endTerm->Term)); + log_write("line"); + }else{ + log_write("chunk"); /* a paragraph chunk */ + doc = makeDocObjUsingParagraphs(duplicateAny(docTerm->Term), + type, + duplicateAny(startTerm->Term), + duplicateAny(endTerm->Term)); +} + termNum += (startTermOffset + 4); /* point to next term */ + } + else /* build a full document */ + { + doc = makeDocObjUsingWholeDocument(duplicateAny(docTerm->Term), + type); +log_write("whole doc"); + termNum += startTermOffset; /* point to next term */ + } + + docs[docNum++] = doc; /* insert the new document */ + + docs[docNum] = NULL; /* keep the doc list terminated */ + + + if (terms[termNum] != NULL) + termNum++; /* skip the OR operator it necessary */ + else + break; /* we are done */ + } + + return(docs); +} + +/*----------------------------------------------------------------------*/ + +any* +makeWAISTextQuery(docs) +DocObj** docs; +/* given a list of DocObjs, return an any whose contents is the corresponding + type 1 query + */ +{ + any *buf = NULL; + query_term** terms = NULL; + + terms = makeWAISQueryTerms(docs); + buf = writeQuery(terms); + + doList((void**)terms,freeTerm); + s_free(terms); + + return(buf); +} + +/*----------------------------------------------------------------------*/ + +DocObj** +readWAISTextQuery(buf) +any* buf; +/* given an any whose contents are type 1 queries of the WAIS sort, + construct a list of the corresponding DocObjs + */ +{ + query_term** terms = NULL; + DocObj** docs = NULL; + + terms = readQuery(buf); + docs = makeWAISQueryDocs(terms); + + doList((void**)terms,freeTerm); + s_free(terms); + + return(docs); +} + +/*----------------------------------------------------------------------*/ +/* Customized free WAIS object routines: */ +/* */ +/* This set of procedures is for applications to free a WAIS object */ +/* which was made with makeWAISFOO. */ +/* Each procedure frees only the memory that was allocated in its */ +/* associated makeWAISFOO routine, thus it's not necessary for the */ +/* caller to assign nulls to the pointer fields of the WAIS object. */ +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISInitResponse(init) +WAISInitResponse* init; +/* free an object made with makeWAISInitResponse */ +{ + s_free(init); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISSearch(query) +WAISSearch* query; +/* destroy an object made with makeWAISSearch() */ +{ + s_free(query); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeDocObj(doc) +DocObj* doc; +/* free a docObj */ +{ + s_free(doc); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentHeader(header) +WAISDocumentHeader* header; +{ + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentShortHeader(header) +WAISDocumentShortHeader* header; +{ + s_free(header); +} +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentLongHeader(header) +WAISDocumentLongHeader* header; +{ + s_free(header); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISSearchResponse(response) +WAISSearchResponse* response; +{ + s_free(response); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentText(docText) +WAISDocumentText* docText; +{ + s_free(docText); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocHeadlines(docHeadline) +WAISDocumentHeadlines* docHeadline; +{ + s_free(docHeadline); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISDocumentCodes(docCodes) +WAISDocumentCodes* docCodes; +{ + s_free(docCodes); +} + +/*----------------------------------------------------------------------*/ + +void +CSTFreeWAISTextQuery(query) +any* query; +{ + freeAny(query); +} + +/*----------------------------------------------------------------------*/ + + +/* +** Routines originally from WMessage.c -- FM +** +**----------------------------------------------------------------------*/ +/* WIDE AREA INFORMATION SERVER SOFTWARE + No guarantees or restrictions. See the readme file for the full standard + disclaimer. + 3.26.90 +*/ + +/* This file is for reading and writing the wais packet header. + * Morris@think.com + */ + +/* to do: + * add check sum + * what do you do when checksum is wrong? + */ + +/*---------------------------------------------------------------------*/ + +void +readWAISPacketHeader(msgBuffer,header_struct) +char* msgBuffer; +WAISMessage *header_struct; +{ + /* msgBuffer is a string containing at least HEADER_LENGTH bytes. */ + + memmove(header_struct->msg_len,msgBuffer,(size_t)10); + header_struct->msg_type = char_downcase((unsigned long)msgBuffer[10]); + header_struct->hdr_vers = char_downcase((unsigned long)msgBuffer[11]); + memmove(header_struct->server,(void*)(msgBuffer + 12),(size_t)10); + header_struct->compression = char_downcase((unsigned long)msgBuffer[22]); + header_struct->encoding = char_downcase((unsigned long)msgBuffer[23]); + header_struct->msg_checksum = char_downcase((unsigned long)msgBuffer[24]); +} + +/*---------------------------------------------------------------------*/ + +/* this modifies the header argument. See wais-message.h for the different + * options for the arguments. + */ + +void +writeWAISPacketHeader(header, + dataLen, + type, + server, + compression, + encoding, + version) +char* header; +long dataLen; +long type; +char* server; +long compression; +long encoding; +long version; +/* Puts together the new wais before-the-z39-packet header. */ +{ + char lengthBuf[11]; + char serverBuf[11]; + + long serverLen = strlen(server); + if (serverLen > 10) + serverLen = 10; + + sprintf(lengthBuf, "%010ld", dataLen); + strncpy(header,lengthBuf,10); + + header[10] = type & 0xFF; + header[11] = version & 0xFF; + + strncpy(serverBuf,server,serverLen); + strncpy((char*)(header + 12),serverBuf,serverLen); + + header[22] = compression & 0xFF; + header[23] = encoding & 0xFF; + header[24] = '0'; /* checkSum(header + HEADER_LENGTH,dataLen); XXX the result must be ascii */ +} + +/*---------------------------------------------------------------------*/ + |