home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.muug.mb.ca
/
2014.06.ftp.muug.mb.ca.tar
/
ftp.muug.mb.ca
/
pub
/
src
/
gopher
/
gopher1.01
/
misc
/
waisgopher
/
waisgopher.c
< prev
Wrap
C/C++ Source or Header
|
1992-05-14
|
17KB
|
686 lines
/* WAISgopher daemon...
Paul Lindner, March 1992
<lindner@boombox.micro.umn.edu>
*/
/* WIDE AREA INFORMATION SERVER SOFTWARE:
No guarantees or restrictions. See the readme file for the full standard
disclaimer.
Brewster@think.com
*/
#include <ctype.h>
#include <string.h>
#include <ui.h>
#include <sockets.h>
#include <docid.h>
/*#include <netinet/in.h>
#include <netdb.h>
*/
#define MAIN
#include "wais.h"
#define MAX_MESSAGE_LEN 100000
#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
#define MAX_FILE_NAME_LEN 1000
#define WAISSEARCH_DATE "Fri Sep 13 1991"
char* log_file_name = NULL;
FILE* logfile = NULL;
void
PrintStatus(str)
char * str;
{
fprintf(stderr, "%s", str);
}
void ZapTabs(in)
char *in;
{
/** replace tabs with a space... **/
while (*in != '\0') {
if (*in == '\t')
*in = ' ';
in ++;
}
}
/*** Modified from ../ir/ui.c to add \r\n at the ends of the line... ***/
void
Mydisplay_text_record_completely(record,quote_string_quotes)
WAISDocumentText *record;
boolean quote_string_quotes;
{
long count;
/* printf(" Text\n");
print_any(" DocumentID: ", record->DocumentID);
printf(" VersionNumber: %d\n", record->VersionNumber);
*/
for(count = 0; count < record->DocumentText->size; count++){
long ch = (unsigned char)record->DocumentText->bytes[count];
if(27 == ch){
/* then we have an escape code */
/* if the next letter is '(' or ')', then ignore two letters */
if('(' == record->DocumentText->bytes[count + 1] ||
')' == record->DocumentText->bytes[count + 1])
count += 1; /* it is a term marker */
else count += 4; /* it is a paragraph marker */
}
else if (ch == '\t') /* a TAB! */
putc(ch, stdout);
else if (isprint(ch)){
if(quote_string_quotes && ch == '"')
putc('\\', stdout);
putc(ch, stdout);
}
else if (ch == '\n' || ch == '\r')
printf ("\r\n");
}
}
/* modified from Jonny G's version in ui/question.c */
void showDiags(d)
diagnosticRecord **d;
{
long i;
for (i = 0; d[i] != NULL; i++) {
if (d[i]->ADDINFO != NULL) {
printf("Code: %s, %s\n", d[i]->DIAG, d[i] ->ADDINFO);
}
}
}
void
ZapCRLF(inputline)
char *inputline;
{
char *cp;
cp = strchr(inputline, '\r'); /* Zap CR-LF */
if (cp != NULL)
*cp = '\0';
else {
cp = strchr(inputline, '\n');
if (cp != NULL)
*cp = '\0';
}
}
int
acceptable(foo)
char foo;
{
if (foo == '\t' || foo == '\r' || foo == '\n' || foo == '\0')
return(0);
else if (!isprint(foo))
return(0);
else
return(1);
}
static char * hex = "0123456789ABCDEF";
/* Decode one hex character
*/
char
from_hex(c)
char c;
{
return (c>='0')&&(c<='9') ? c-'0'
: (c>='A')&&(c<='F') ? c-'A'+10
: (c>='a')&&(c<='f') ? c-'a'+10
: 0;
}
/*
* DocId_to_Gopher transforms a docid into a character string suitable for
* transmission
*/
char *DocId_to_Gopher(docid, docsize)
any *docid;
{
static char GopherString[512];
char *q = GopherString;
char *p;
int l, i;
/** First lets stick on the size of the document first **/
sprintf(GopherString, "%d", docsize);
q += strlen(GopherString);
*q++ = ':';
for (p=docid->bytes; (p < docid->bytes + docid->size) && q<&GopherString[512];) {
if (*p >= 10) {
; /* Bad thing happened, can't understand docid, punt */
return(NULL);
}
*q++ = (*p++) + '0'; /* Record Type */
*q++ = '='; /* Seperate */
l = *p++; /* Length */
for (i=0; i<l; i++, p++) {
if (acceptable(*p)==0) {
*q++ = '%';
*q++ = hex[(*p) >> 4];
*q++ = hex[(*p) & 15];
}
else *q++ = *p;
}
*q++ = ';';
}
*q++ = 0;
return(GopherString);
}
/*
* Gstring is a name produced by DocID_to_Gopher
*/
any *Gopher_to_DocId(Gstring, DocSize)
char *Gstring;
int *DocSize;
{
static any docid;
char *outptr;
char *inptr;
char *sor;
char *eqptr;
char *semiptr;
int size;
/* Strip off the Document size first.... */
inptr = strchr(Gstring, ':');
if (inptr == NULL)
return;
*DocSize = atoi(Gstring);
Gstring = inptr +1;
for (size=0, inptr=Gstring; *inptr; inptr++) {
size ++;
if (*inptr == ';')
size--;
else if (*inptr == '%')
size -=2;
}
docid.size = size;
docid.bytes = (char *) malloc(docid.size);
outptr = docid.bytes;
for (inptr = Gstring; *inptr;) {
*outptr++ = *inptr++ - '0'; /* Record Type */
eqptr = strchr(inptr, '=');
if (!eqptr)
return(0);
semiptr = strchr(inptr, ';');
if (!semiptr)
return(0);
sor = outptr;
outptr++;
for (inptr = eqptr+1; *inptr!=';' ; ) {
if (*inptr == '%') {
char c;
unsigned int b;
inptr++;
c = *inptr++;
b = from_hex(c);
c = *inptr++;
if (!c) break;
*outptr++ = (b<<4) + from_hex(c);
} else {
*outptr++ = *inptr++;
}
}
*sor = (outptr-sor-1);
inptr++;
}
return(&docid);
}
/*-----------------------------------------------------------------*/
/* modified from tracy shen's version in wutil.c
* displays either a text record of a set of headlines.
*/
void
display_search_response(response, hostname, port, dbname, GateHost, GatePort, SourceName)
SearchResponseAPDU *response;
char *hostname, *port, *dbname, *GateHost, *GatePort, *SourceName;
{
WAISSearchResponse *info;
long continue_viewing;
long i, k;
struct sockaddr_in serv_addr;
int length = sizeof(serv_addr);
int GopherPort;
/** Try to figure out the port we're running on. **/
if (getsockname(0, &serv_addr,&length) == 0)
GopherPort = ntohs(serv_addr.sin_port);
if ( response->DatabaseDiagnosticRecords != 0 ) {
info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
i =0;
if (info->Diagnostics != NULL)
showDiags(info->Diagnostics);
if ( info->DocHeaders != 0 ) {
k =0;
while (info->DocHeaders[k] != 0 ) {
i++;
ZapCRLF(info->DocHeaders[k]->Headline);
ZapTabs(info->DocHeaders[k]->Headline);
printf("0%s\t-%s:%s\t%s\t%d\r\n",
info->DocHeaders[k]->Headline,
SourceName,
DocId_to_Gopher(info->DocHeaders[k]->DocumentID, info->DocHeaders[k]->DocumentLength),
GateHost,
GopherPort
);
k++;
}
printf(".\r\n");
}
if ( info->Text != 0 ) {
k =0;
while ( (continue_viewing == 1) && (info->Text[k] != 0) ) {
i++;
printf("\n Text record %2d, ", i);
Mydisplay_text_record_completely( info->Text[k++], false);
}
}
} /* display user info */
}
#define MAX_KEYWORDS_LENGTH 1000
#define MAX_SERVER_LENGTH 1000
#define MAX_DATABASE_LENGTH 1000
#define MAX_SERVICE_LENGTH 1000
#define MAXDOCS 40
/* any*
copy_any(thing)
any *thing;
{
int i;
any* result;
result = NULL;
if(thing != NULL) {
if((result = (any*)s_malloc(sizeof(any))) != NULL) {
result->bytes = NULL;
result->size = thing->size;
if((result->bytes = s_malloc(thing->size)) != NULL) {
for(i = 0; i < thing->size; i++)
result->bytes[i] = thing->bytes[i];
}
}
}
return result;
}
*/
/******************************************************************/
void main(argc, argv)
int argc;
char *argv[];
{
char* request_message = NULL; /* arbitrary message limit */
char* response_message = NULL; /* arbitrary message limit */
long request_buffer_length; /* how of the request is left */
SearchResponseAPDU *query_response;
SearchResponseAPDU *retrieval_response;
WAISSearchResponse *query_info, *retrieval_info;
char server_name[MAX_SERVER_LENGTH + 1];
char service[MAX_SERVICE_LENGTH + 1];
char database[MAX_DATABASE_LENGTH + 1];
char *next_argument, *command_name;
long count;
FILE *connection;
int Searching = 1; /** Default is to search **/
char *keywords;
char *DocIdString;
char *Inputline;
char *Dotsrcfile;
char *SourceName;
char *WaisGateHost=NULL, *WaisGatePort=NULL;
next_argument = next_arg(&argc, &argv);
command_name = next_argument;
server_name[0] = '\0'; /* null it out */
database[0] = '\0'; /* null it out */
service[0] = '\0'; /* null it out */
while(NULL != (next_argument = next_arg(&argc, &argv))) {
/* then we have an argument to process */
if(0 == strcmp("-debug", next_argument)){
logfile = stderr;
}
else if(0 == strcmp("-v", next_argument)){
printf("%s version: %s, %s\n",
command_name, VERSION, WAISSEARCH_DATE);
}
else if(0 == strcmp("-h", next_argument)) {
if (NULL == (next_argument = next_arg(&argc, &argv)))
printf("Syntax error, need a host!!\n"), exit(-1);
else
WaisGateHost = next_argument;
}
else if(0== strcmp("-s", next_argument)) {
if (NULL == (next_argument = next_arg(&argc, &argv)))
printf("Syntax error, need a sourcefile!!\n"), exit(-1);
else {
FILE *Srcfile;
Source Moo;
Moo = (Source)malloc(sizeof(_Source));
Srcfile = fopen(next_argument, "r");
if (Srcfile == NULL) {
printf("File \"%s\" does not exist\r\n", next_argument), exit(-1);
}
ReadSource(Moo, Srcfile);
/* printf("server: %s, database: %s, service: %s\n", Moo->server, Moo->database, Moo->service);*/
strcpy(server_name, Moo->server);
strcpy(database, Moo->database);
strcpy(service, Moo->service);
}
}
else if(0 == strcmp("-p", next_argument)) {
if (NULL == (next_argument = next_arg(&argc, &argv)))
printf("Syntax error, need a port number!!\n"), exit(-1);
else
WaisGatePort = next_argument;
}
else if (0== strcmp("-i", next_argument)) {
Searching = 0; /** Not searching, we're fetching by docid **/
}
else{
panic("Don't recognize the %s option", next_argument);
}
}
if (Searching == 1 && (WaisGateHost == NULL)) {
printf("4Must specify a gateway host and port!\r\n.\r\n"), exit(-1);
}
Inputline = (char *) malloc(1024);
gets(Inputline);
ZapCRLF(Inputline);
if (Inputline[0] == '-') {
Searching = 0; /** We got ourselves a docid... **/
Inputline++;
}
/**
** Next load up the name of the source...
*/
{
FILE *Srcfile;
Source Moo;
char *cp;
/*
* A search request will have a tab separator. A document
* request will have a : separator.
*/
if (Searching) {
cp = strchr(Inputline, '\t');
keywords = cp + 1;
}
else {
cp =strchr(Inputline, ':');
DocIdString = cp +1;
}
if (cp == NULL) {
/** An error occured, probably old client software... **/
printf(".\r\n");
} else
*cp = '\0';
SourceName= Inputline;
Moo = (Source)malloc(sizeof(_Source));
Srcfile = fopen(SourceName, "r");
if (Srcfile == NULL) {
printf("File \"%s\" does not exist\r\n.\r\n", SourceName), exit(-1);
}
ReadSource(Moo, Srcfile);
strcpy(server_name, Moo->server);
strcpy(database, Moo->database);
strcpy(service, Moo->service);
}
if (server_name[0] == 0)
connection = NULL;
else if ((connection=connect_to_server(server_name,atoi(service))) == NULL)
{
fprintf (stderr, "Error openning connection to %s via service %s.\r\n.\r\n",
server_name, service);
exit(-1);
}
request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
{
char userInfo[500];
char hostname[80];
gethostname(hostname, 80);
sprintf(userInfo, "waisgopher %s, gateway: %s, user: gopher@boombox.micro.umn.edu",
VERSION, hostname );
init_connection(request_message, response_message,
MAX_MESSAGE_LEN,
connection,
userInfo);
}
request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
/***********************************************************************
**** Branch off here, if we have a search request do it.
otherwise if we have a docid, fetch it.
****/
if (Searching) {
if(NULL ==
generate_search_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
keywords, database, NULL, MAXDOCS))
panic("request too large");
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
connection,
false /* true verbose */
)) { /* perhaps the server shut down on us, let's see: */
if ( connection != NULL) {
fclose(connection);
if ((connection=connect_to_server(server_name,atoi(service))) == NULL)
{
printf("Error openning connection to %s via service %s.\n",
server_name, service);
exit(-1);
}
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
connection,
false /* true verbose */
))
panic("really couldn't deliver message");
}
else
panic("returned message too large");
}
readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH);
display_search_response(query_response, server_name, service, database, WaisGateHost, WaisGatePort, SourceName);
freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( query_response);
} /*** Searching? ***/
else { /*** Retrieve by docid ***/
any *docid;
int DocLen;
docid = Gopher_to_DocId(DocIdString, &DocLen);
/*** First let's transform the first word into a docid ***/
/*** What we need from net: DocumentLength, Types: (TEXT!), docid, **/
/* printf("Headline: %s\n",
query_info->DocHeaders[document_number - 1]->Headline);
/* we must retrieve the document in parts since it might be very long*/
for(count = 0;
count * CHARS_PER_PAGE <
DocLen;
count++){
char *type;
/* if(query_info->DocHeaders[1]->Types == NULL)*/
type = s_strdup("TEXT");
/* else
type = s_strdup(query_info->DocHeaders[1]->Types[0]);*/
request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
if(0 ==
generate_retrieval_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
docid,
CT_byte,
count * CHARS_PER_PAGE,
MIN((count + 1) * CHARS_PER_PAGE,
DocLen),
type,
database
))
panic("request too long");
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
connection,
false /* true verbose */
)) { /* perhaps the server shut down on us, let's see: */
if ( connection != NULL) {
fclose(connection);
if ((connection=connect_to_server(server_name,atoi(service))) == NULL)
{
fprintf (stderr, "Error openning connection to %s via service %s.\n",
server_name, service);
exit(-1);
}
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
connection,
false /* true verbose */
))
panic("really couldn't deliver message");
}
else
panic("returned message too large");
}
readSearchResponseAPDU(&retrieval_response,
response_message + HEADER_LENGTH);
/* display_search_response(retrieval_response); the general thing */
if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text){
display_search_response(retrieval_response);
panic("No text was returned");
}
Mydisplay_text_record_completely
(((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], false);
}
freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords);
freeSearchResponseAPDU( retrieval_response);
}
close_connection(connection);
s_free(request_message);
s_free(response_message);
exit(0);
}