/* 
  WIDE AREA INFORMATION SERVER SOFTWARE:
   No guarantees or restrictions.  See the readme file for the full standard
   disclaimer.

   This is part of the shell user-interface tools for the WAIS software.
   Do with it as you please.

   jonathan@Think.COM
 *
 * $Log:	wais-ui.c,v $
 * Revision 1.2  92/08/05  14:03:50  epeisach
 * Coding errors (caught by c89)
 * 
 * 
 * Revision 1.1  92/08/05  13:53:19  epeisach
 * Initial revision
 * 
 * Revision 1.22  92/05/07  14:52:04  jonathan
 * Changed use of setitimer to alarm.  Thanks to
 * steinkel@carlisle-emh2.army.mil.
 * 
 * Revision 1.21  92/04/30  10:59:05  jonathan
 * Replace strdup with s_strdup.
 * 
 * Revision 1.20  92/04/02  14:21:59  jonathan
 * Copy type in all calls to makeDocObjUsing a generate_retrieval_apdu (which
 * calls makeDocObjUsing...).
 * 
 * Revision 1.19  92/04/01  17:19:35  jonathan
 * Fixed reporting of diagnostics when return text is empty.
 * 
 * Revision 1.18  92/03/17  14:33:17  jonathan
 * Renamed to wais-ui, cleaned up for use by X interface as well as shell
 * interfaces.
 * 
 * Revision 1.17  92/03/08  10:42:28  jonathan
 * Added one last loadSource in ViewWaisDocument.
 * 
 * Revision 1.16  92/03/06  14:50:13  jonathan
 * New and Improved source loading!
 * 
 */

#ifndef lint
static char *RCSid = "$Header: /afs/athena.mit.edu/astaff/project/wais/src/wais-8-b5/ui/RCS/wais-ui.c,v 1.2 92/08/05 14:03:50 epeisach Exp $";
#endif

#define _C_QUESTION

#include "wais.h"
#include "globals.h"

void showDiags(d)
diagnosticRecord **d;
{
  int i;
  char msg[256];

  for (i = 0; d[i] != NULL; i++) {
    if (d[i]->ADDINFO != NULL) {
      sprintf(msg, "\nCode: %s, %s", d[i]->DIAG, d[i] ->ADDINFO);
      PrintStatus(msg);
      sleep(2);
    }
  }
}
	  
void printDiags(d)
diagnosticRecord **d;
{
  int i;

  for (i = 0; d[i] != NULL; i++)
    if (d[i]->ADDINFO != NULL)
      printf("%s\n", d[i] ->ADDINFO);
}
	  
void
write_text_record_completely(fp, record, quote_string_quotes)
FILE *fp;
WAISDocumentText *record;
Boolean quote_string_quotes;
{
  long count;
  /* fprintf(fp," Text\n");
  print_any("     DocumentID:  ", record->DocumentID);
  fprintf(fp,"     VersionNumber:  %d\n", record->VersionNumber);
  */
  for(count = 0; count < record->DocumentText->size; count++){
    int ch = 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 (isprint(ch)){
      if(quote_string_quotes && ch == '"')
	putc('\\', fp);
      putc(ch, fp);
    } 
    else if (ch == '\n' || ch == '\r')
      fprintf(fp, "\n");
  }
}


/* for making searches */

DocList
build_response_list(response, source)
SearchResponseAPDU *response;
SourceID source;
{
  long i, k;
  WAISSearchResponse  *info;
  DocList last = NULL, doc, result = NULL;
  DocumentID docID;

  k = response->NumberOfRecordsReturned;

  if ( response->DatabaseDiagnosticRecords != 0 ) {
    info = (WAISSearchResponse*)response->DatabaseDiagnosticRecords;
    if ( info->DocHeaders != NULL ) {
      for(i = 0; i < k; i++) {
	if(info->DocHeaders[i] != NULL ) {
	  if(result == NULL) {
	    doc = result = makeDocList(NULL, NULL);
	  }
	  else
	    doc = makeDocList(NULL, NULL);

	  docID = fillDocumentID(info->DocHeaders[i], source);
	  doc->thisDoc = docID;

	  if(last != NULL) {
	    last->nextDoc = doc;
	  }
	  last = doc;
	}
      }
    }
  }
  return result;
}

/* right now this hacks out the ^Q/S too.  I'll do better later. */

static void
 replacecontrolM(buffer, length)
char *buffer;
long *length;
{
  char *here, *there, c;
  long i, newlength;

  here = there = buffer;
  for(newlength = 0, i = 0; i < *length; i++) {
    c = *here;
    switch (c) {
    case 0:
      *there = 0;
      *length = newlength;
      return;
    case '\r':
      *there = '\n';
      newlength++;
      here++; there++;
      break;
    case 19:
    case 17:
      here++;
      break;
    default:
      *there = *here;
      newlength++;
      here++; there++;
    }
  }
  *length = newlength;
}

void SearchWais(q)
Question q;
{
  Source source;
  SList asource;
  static long request_buffer_length;
  DocObj **Doc;
  int i;
  char *request_message, *response_message;
  char message[255];
  DocList last;
  diagnosticRecord **diag;
  char *database;
  long numdocs, result;

  request_message = (char*)q->request_message;
  response_message = (char*)q->response_message;

  /* clear the results */

  /*
  freeDocList(q->ResultDocuments);
  */
  q->ResultDocuments = NULL;

  /* build DocObjs */

  Doc = (DocObj**)s_malloc((q->numdocs+1) * sizeof(char*));
  
  q->numsources = listlength((List)q->Sources);

  if (q->numsources != 0)
    numdocs = maxDocs/q->numsources;
  else numdocs = 0;
  {
    DocList dl;
    for(i=0, dl = q->RelevantDocuments;
	dl != NULL;
	dl = dl->nextDoc, i++)
      if(dl->thisDoc->doc != NULL) {
	char* tmptype = s_strdup((dl->thisDoc->doc->type) ?
				 dl->thisDoc->doc->type[0] : "TEXT");
 
	if(dl->thisDoc->doc->id != NULL)
	  if(dl->thisDoc->start >= 0)
	      
	    Doc[i] =
	      makeDocObjUsingLines(anyFromDocID(dl->thisDoc->doc->id),
				   tmptype, dl->thisDoc->start, dl->thisDoc->end);
	  else
	    Doc[i] =
	      makeDocObjUsingWholeDocument(anyFromDocID(dl->thisDoc->doc->id),
					   tmptype);

      }
    Doc[i] = NULL;
  }

  /* check to see if the question has a source */
  source = NULL;

  if(q->Sources != NULL) {
    SourceList slist;

    for(slist = q->Sources;
	slist != NULL;
	slist = slist->nextSource) {
      source = findsource(slist->thisSource->filename);

      if (source == NULL) {
	sprintf(message, "\nCouldn't find source: %s.", slist->thisSource->filename);
	PrintStatus(message);
	sleep(2);
      }
      else {
        if (strstr(source->name,".src")!=NULL) {
	  sprintf(message, "\nSearching: ");
	  strncat(message,source->name,strlen(source->name)-4);
        }
        else
	  sprintf(message, "\nSearching: %s", source->name);
	
	PrintStatus(message);
      
	if(source->initp != TRUE) {
	  PrintStatus("\nInitializing connection...");
	  init_for_source(source, request_message, MAX_MESSAGE_LEN, 
			  response_message);
	  PrintStatus(message);
	}
	if(source->database[0] == 0) database = NULL;
	else database = source->database;

	if(source->initp != FALSE) {
	  result = 0;
	  request_buffer_length = source->buffer_length;
	  if(NULL ==
	     generate_search_apdu(request_message + HEADER_LENGTH, 
				  &request_buffer_length, 
				  q->keywords, database, Doc, numdocs)) {
	    PrintStatus("Buffer overflow: request too large");
	    sleep(2);
	  }
	  else if((result =
		   interpret_message(request_message, 
				     (source->buffer_length - 
				      request_buffer_length), 
				     response_message,
				     source->buffer_length,
				     source->connection,
				     false /* true verbose */
				     )) == 0) {
	    PrintStatus("Warning: no information returned.  Possibly a bad connection");
	    close_source(source);
	  }
	  if (result != 0) { /* use the repsonse */
	    readSearchResponseAPDU(&q->query_response,
				   response_message + HEADER_LENGTH);

      
	    if (q->query_response != NULL)
	      if ((WAISSearchResponse *)q->query_response->DatabaseDiagnosticRecords != NULL) 
		if ((diag =
		     ((WAISSearchResponse *)q->query_response->DatabaseDiagnosticRecords)->Diagnostics) != NULL)
		  showDiags(diag);
      
	    if (q->ResultDocuments != NULL) {
	      last = findLast(q->ResultDocuments);
	      last->nextDoc = build_response_list(q->query_response,
						  slist->thisSource);
	    }
	    else
	      q->ResultDocuments =
		build_response_list(q->query_response,
				    slist->thisSource);
	  }
	}
	else {
	  sprintf(message, "\nError connecting to %s", source->name);
	  PrintStatus(message);
	  sleep(2);
	}
      }
    }
    /* ok, now we've got all the documents, let's sort them */

    sort_document_list(q->ResultDocuments);

    q->numresdocs =  listlength((List)q->ResultDocuments);
    sprintf(message, "\nFound %d items.", q->numresdocs);
    PrintStatus(message);
  }
  else {
    PrintStatus("\nThis Question has no sources to search.  Please add one.");
    q->ResultDocuments = NULL;
    q->numresdocs =  listlength((List)q->ResultDocuments);
  }
  if (Doc != NULL) {
    doList((void**)Doc,freeDocObj);
    s_free(Doc);
  }
}

char* GetWaisDocument(q, doc, type, fp, written)
Question q;
DocumentID doc;
char *type;
FILE *fp;
long* written;
{
  static long request_length, chars_per_page;
  static long lines, size, count, chars, numChars;
  long start_byte, end_byte;
  any* docany;
  WAISDocumentText *text;
  diagnosticRecord **diag;
  char *viewtext, message[255];
  char *viewbuffer;
  char *tmptype;
  Source source;
  SList asource;
  char *database;
  long result;

  sprintf(message, "\nGetting document from server...");
  if(fp != stdout)
    PrintStatus(message);

  source = NULL;

  if(doc == NULL) return NULL;

  if(doc->doc != NULL &&
     doc->doc->sourceID != NULL &&
     doc->doc->sourceID->filename != NULL) {
    source = findsource(doc->doc->sourceID->filename);
  }

  if (source == NULL) {

    PrintStatus("\nCould not find Source for this document!");
    return NULL;
  }

  if(source->database[0] == 0) database = NULL;
  else database = source->database;

  size = 0;

  lines = doc->doc->numLines;
  if(written != NULL && *written != 0)
    chars = *written;
  else
    chars = doc->doc->numChars;

  numChars = chars+1000;	/* for slop? */

  docany = anyFromDocID(doc->doc->id);

  if(source->initp == FALSE)
    init_for_source(source, q->request_message, MAX_MESSAGE_LEN,
		    q->response_message);


  if(source->initp == FALSE) {
    PrintStatus("\nInit Connection Failed.");
    *written = 0;
    return(NULL);
  }

  chars_per_page = source->buffer_length - HEADER_LENGTH - 1000; /* ? */

  if(fp == NULL) {
    viewbuffer = (char*)s_malloc(chars < 0 ? chars_per_page : numChars);

    if(viewbuffer == NULL) {
      PrintStatus("\nUnable to allocate message space.  Something is wrong.");
      return NULL;
    }
    viewtext = viewbuffer;
  }

  tmptype = s_strdup((type ? type : "TEXT"));

  if (chars == 0)
    PrintStatus("\nEmpty document!");
  else if (source->initp != FALSE) {
    for(count = 0; 
	(chars < 0) || (count * chars_per_page < chars);
	count++) {
      /* show as we go... */
      request_length = source->buffer_length;

      if (chars < 0) {
	numChars = (count+1) * chars_per_page;
	if(fp == NULL) {
	  viewbuffer = s_realloc(viewbuffer, numChars);
	}
      }

      start_byte = count * chars_per_page;
      end_byte = (chars < 0 ? 
		  (count + 1) * chars_per_page :
		  MIN((count + 1) * chars_per_page, chars));
      if(NULL ==
	 generate_retrieval_apdu(q->request_message + HEADER_LENGTH,
				 &request_length, docany, CT_byte,
				 start_byte, end_byte,
				 tmptype, database)) {
	PrintStatus("\nWarning: buffer overflow.");
	return NULL;
      }
	     
      if((result =
	  interpret_message(q->request_message, 
			    source->buffer_length - request_length, 
			    q->response_message,
			    source->buffer_length,
			    source->connection,
			    false /* true verbose */	
			    )) == 0) {
	PrintStatus("\nWarning: no information returned.  Possibly a bad connection.");
	close_source(source);
	return NULL;
      }
      if (result != 0) 
	readSearchResponseAPDU(&q->retrieval_response, 
			       q->response_message + HEADER_LENGTH);

      if (q->retrieval_response != NULL)  {
	if ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords != NULL) {
	  diag = ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Diagnostics;
	}
	else diag = NULL;
      
	if(NULL == ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Text) {
	  if (diag != NULL)
	    showDiags(diag);
    
	  PrintStatus("done.");
	  if(written != NULL) *written = size;
	  return(viewbuffer);
	}
	else {
	  text = ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Text[0];
	  if((type == NULL) || (strcmp(type, "TEXT") == 0)) {
	    long length = text->DocumentText->size;;
	    
	    delete_seeker_codes(text->DocumentText->bytes, &length);
	    text->DocumentText->size = length;
	    replacecontrolM(text->DocumentText->bytes, &length);
	    text->DocumentText->size = length;
	  }

	  if(text->DocumentText->size > (end_byte - start_byte))
	    /* something wrong! */
	    text->DocumentText->size = (end_byte - start_byte);

	  viewtext = viewbuffer+size;
	  size+=text->DocumentText->size;
	  if (size <= numChars) {
	    if(fp == NULL) {
	      memcpy(viewtext, text->DocumentText->bytes, text->DocumentText->size);
	    }
	    else {
	      dumptext(fp, text->DocumentText->bytes, text->DocumentText->size);
	    }

	    sprintf(message, "\nReceived %d bytes from %s...",
		    size, source->server);

	    if(fp != stdout)
	      PrintStatus(message);

	    if(diag &&
	       diag[0] &&
	       diag[0]->ADDINFO != NULL &&
	       !strcmp(diag[0]->DIAG, D_PresentRequestOutOfRange))
	      break;
	    if((type != NULL) &&
	       (strcmp(type, "TEXT") != 0) &&
	       (text->DocumentText->size != chars_per_page))
	      break;
	  }
	  else {
	    PrintStatus("\nBuffer overflow!");
	    break;
	  }
	}

	if (diag != NULL)
	  showDiags(diag);
    
      }
    }
  }
  if (written != NULL) *written = size;
  return(viewbuffer);
}

void RetrieveWaisDocument(start_output, end_output, q, doc)
void (*start_output)();
void (*end_output)();
Question q;
DocumentID doc;
{
  static long request_length, chars_per_page;
  static long lines, size, count, chars, numChars;
  any* docany;
  WAISDocumentText *text;
  diagnosticRecord **diag;
  char *viewtext;
  char *viewbuffer;
  Source source;
  SList asource;
  char *database;
  FILE *fp;
  int output_started;

  output_started = FALSE;
  source = NULL;

  if(doc->doc != NULL) {
    if(doc->doc->sourceID != NULL) {
      if(doc->doc->sourceID->filename != NULL) {

	char *sourcename;
	sourcename = doc->doc->sourceID->filename;

	for(asource = Sources;
	    asource != NULL;
	    asource = asource->nextSource) {
	  if (!strcmp(sourcename, asource->thisSource->name)) {
	    source = asource->thisSource;
	    break;
	  }
	}
      }
    }
  }

  if (source == NULL) {
    PrintStatus("Could not find Source for this document!");
    return;
  }

  if(source->database[0] == 0) database = NULL;
  else database = source->database;

  size = 0;

  lines = doc->doc->numLines;
  chars = doc->doc->numChars;
  numChars = chars + 1000; /* for slop? */

  if((viewbuffer = (char*)s_malloc(numChars)) == NULL) {
    PrintStatus("\nUnable to allocate message space.  Something is wrong.");
    return;
  }

  viewtext = viewbuffer;

  docany = anyFromDocID(doc->doc->id);

  if(source->initp == FALSE)
    init_for_source(source, q->request_message,  MAX_MESSAGE_LEN,
		    q->response_message);

  chars_per_page = source->buffer_length - HEADER_LENGTH - 1000; /* ? */

  if (chars <= 0)
      PrintStatus("\nEmpty document.");
  else if (source->initp != FALSE) {
    for(count = 0; 
	count * chars_per_page < chars;
	count++) {
      /* show as we go... */

      request_length = source->buffer_length;

      if(0 ==
	 generate_retrieval_apdu(q->request_message + HEADER_LENGTH,
				 &request_length, 
				 docany,
				 CT_byte,
				 count * chars_per_page,
				 MIN((count + 1) * chars_per_page, chars),
				 (doc->doc->type) ?
				 doc->doc->type[0] : "TEXT",
				 database)) {
	PrintStatus("\nWarning: no information returned.  Possibly a bad connection.");
	break;
      }
	     
      if(0 ==
	 interpret_message(q->request_message, 
			   source->buffer_length - request_length, 
			   q->response_message,
			   source->buffer_length,
			   source->connection,
			   false /* true verbose */	
			   )) {
	PrintStatus("\nWarning: no information returned.  Possibly a bad connection.");
	break;
      }

      readSearchResponseAPDU(&q->retrieval_response, 
			     q->response_message + HEADER_LENGTH);

      if (q->retrieval_response != NULL)
	if ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords != NULL) 
	  if ((diag =
	       ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Diagnostics) != NULL)
	    showDiags(diag);
    
      if(NULL == ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Text) {
	break;
      }

      text = ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Text[0];
      {
	long length;
    
	length = text->DocumentText->size;
	if((doc->doc->type == NULL) || (strcmp(doc->doc->type[0], "TEXT") == 0)) {
	  delete_seeker_codes(text->DocumentText->bytes, &length);
	  text->DocumentText->size = length;
	  replacecontrolM(text->DocumentText->bytes, &length);
	  text->DocumentText->size = length;
	}
      }

      size+=text->DocumentText->size;
      if (size <= numChars) {
	memcpy(viewtext, text->DocumentText->bytes, text->DocumentText->size);
	viewtext+=text->DocumentText->size;
      }
      else {
	PrintStatus("\nBuffer overflow!");
	break;
      }

    }

    /* display_search_response(q->retrieval_response); the general thing */
    if(NULL == ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Text){
      PrintStatus("\nNo text was returned.");
    } else {
      if (output_started==FALSE) {
         start_output(&fp);
         output_started=TRUE;
         if (&fp==NULL) {
           PrintStatus("Unable to open output.");
	   return;
	}
      }
      dumptext(fp, viewbuffer, size);
    }
  }
  if (output_started==TRUE) 
    end_output(&fp);
}

void dumptext(fp, buffer, size)
FILE *fp;
char *buffer;
long size;
{
  long i;

  for (i = 0; i < size; i++)
      fputc(*buffer++,fp);
  fflush(fp);
}
  
#include <signal.h>
#include <setjmp.h>
static jmp_buf jbuf;
static int new, old;

#ifdef _ANSI_C_SOURCE
static void
alarmhandler(sig)
int sig;
#else
static void
alarmhandler(sig, code, scp, addr)
long sig, code;
struct sigcontext *scp;
char *addr;
#endif
{
  longjmp(jbuf, 1);
}

void test_connection(q)
Question q;
{
  Source source;
  SList asource;
  static long request_buffer_length;
  char *request_message, *response_message;
  char message[255];
  diagnosticRecord **diag;
  char *database;

  new = 120; /* 2 minute timeout. */

  request_message = (char*)q->request_message;
  response_message = (char*)q->response_message;

  /* check to see if the question has a source */
  source = NULL;

  if(q->Sources != NULL) {
    SourceList slist;

    for(slist = q->Sources;
	slist != NULL;
	slist = slist->nextSource) {
      for(asource = Sources;
	  asource != NULL;
	  asource = asource->nextSource) {
	if (asource->thisSource != NULL &&
	    asource->thisSource->name != NULL &&
	    !strcmp(slist->thisSource->filename,
		    asource->thisSource->name)) {
	  source = asource->thisSource;
	  break;
	}
      }

      if (source == NULL) {
	sprintf(message, "\nCouldn't find source: %s.", slist->thisSource->filename);
	PrintStatus(message);
      }
      else {
	printf("Source %s ", slist->thisSource->filename);
	if(source->maintainer) 
	  printf("by %s ", source->maintainer);
	if(source->server[0] != 0)
	  printf("at %s ", source->server);

	if(source->initp == FALSE) {
	  freopen("/dev/null", "w", stderr);
	  if (setjmp(jbuf) != 0) {
	    source->initp = FALSE;
	  } 
	  else {
	    signal(SIGALRM, alarmhandler);
	    old = alarm(new);
	    init_for_source(source, q->request_message, MAX_MESSAGE_LEN,
			    q->response_message);
	    alarm(old);
	    signal(SIGALRM, SIG_DFL);
	  }
	  request_buffer_length = source->buffer_length;

	  if(source->initp == FALSE) {
	    printf("not responding.\n");
	  }
	  else {		/* now lets test the database */
	    if(source->database[0] == 0) database = NULL;
	    else database = source->database;

	    if(NULL ==
	       generate_search_apdu(request_message + HEADER_LENGTH, 
				    &request_buffer_length, 
				    "?", database, NULL, 1)) {
	      PrintStatus("Buffer overflow: request too large");
	    }
	    else {
	      long r = 0;
	      if (setjmp(jbuf) != 0) {
		printf("not responding:\n");
		return;
	      } else {
		signal(SIGALRM, alarmhandler);
		old = alarm(new);
		if(0 == 
		   (r = interpret_message(request_message, 
					  (source->buffer_length - 
					   request_buffer_length), 
					  response_message,
					  source->buffer_length,
					  source->connection,
					  false /* true verbose */
					  ))) {
		  PrintStatus("Warning: no information returned.  Possibly a bad connection");
		}
	      }
	      if(r != 0) {
		readSearchResponseAPDU(&q->query_response,
				       response_message + HEADER_LENGTH);

      
		if (q->query_response != NULL)
		  if ((WAISSearchResponse *)q->query_response->DatabaseDiagnosticRecords != NULL) 
		    if ((diag =
			 ((WAISSearchResponse *)q->query_response->DatabaseDiagnosticRecords)->Diagnostics) != NULL) {
		      printf("not responding:\n");
		      printDiags(diag);
		    }
		    else 
		      printf("responding.\n");
	      }
	    }
	  }
	}
      }
    }
  }
  else {
    printf("\nError: No sources to search.  Please add one.\n");
  }
}

void close_source(source)
Source source;
{
  SList t;

  if (source->connection != NULL) {
    fclose(source->connection);
  }
  for(t = Sources; t != NULL; t = t->nextSource) {
    if (strcmp(t->thisSource->server, source->server) == 0 &&
	strcmp(t->thisSource->service, source->service) == 0) {
      t->thisSource->initp = FALSE;
      t->thisSource->connection = NULL;
    }
  }
}

DocumentID
 getNextorPrevDoc(q, source, doc, nextp)
Question q;
Source source;
DocumentID doc;
Boolean nextp;
{
  static long request_length;
  static long lines, size, count, numChars;
  any* docany;
  char message[255];
  int i;
  diagnosticRecord **diag;
  char *database, *type;
  DocumentID result;
  DocID *newdoc;
  DocObj *Doc[2];
  WAISSearchResponse  *info;
  char *text, document_id[MAX_FILE_NAME_LEN];
  char *loc1, *loc2, *loc3, newtype[100], headline[MAX_FILE_NAME_LEN];
  long newsize;

  if(source->database[0] == 0) database = NULL;
  else database = source->database;

  docany = anyFromDocID(doc->doc->id);

  size = 0;

  if(nextp == TRUE)
    type = "WAIS_NEXT";
  else
    type = "WAIS_PREV";

  if(source->initp == FALSE)
    init_for_source(source,q->request_message,MAX_MESSAGE_LEN,
		    q->response_message);

  request_length = source->buffer_length;
  
  Doc[0] = makeDocObjUsingWholeDocument(docany, s_strdup(type));
  Doc[1] = NULL;
  if(0 ==
     generate_search_apdu(q->request_message + HEADER_LENGTH, 
			  &request_length, 
			  "foo", database, Doc, 1)) {
    PrintStatus("\nWarning: Buffer overflow.");
    return NULL;
  }
	     
  if(0 ==
     interpret_message(q->request_message, 
		       (source->buffer_length - request_length), 
		       q->response_message,
		       source->buffer_length,
		       source->connection,
		       false	/* true verbose */	
		       )) {
    PrintStatus("\nWarning: no information returned.  Possibly a bad connection.  Maybe try again.");
    source->initp = FALSE;
    return NULL;
  }

  readSearchResponseAPDU(&q->retrieval_response, 
			 q->response_message + HEADER_LENGTH);

  if (q->retrieval_response != NULL)
    if ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords != NULL) 
      if ((diag =
	   ((WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords)->Diagnostics) != NULL)
	showDiags(diag);

  info = (WAISSearchResponse *)q->retrieval_response->DatabaseDiagnosticRecords;

  if (info != NULL &&
      info->DocHeaders != NULL) {
    return(fillDocumentID(info->DocHeaders[0], doc->doc->sourceID));
  }
  else return NULL;
}
