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

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

   Version 0.82
   Wed Apr 24 1991

   jonathan@Think.COM

*/

#define _C_SOURCE

#include "xwais.h"

#define DESC_SIZE 65535

char desc_string[DESC_SIZE];

char **
buildSourceItemList(sourcelist)
SourceList sourcelist;
{
  char **result;
  int num, i;
  SourceList source;

  /* find the length of the sidlist in the question */

  for(num = 0, source = sourcelist; 
      source != NULL && source->thisSource != NULL;
      num++, source = source->nextSource);

  result = (char**) s_malloc(1+num*sizeof(char*));
  if(num > 0)
    for(i =0, source = sourcelist; i<num; i++, source = source->nextSource)
      result[i] = source->thisSource->filename;
  result[num] = NULL;
  return(result);
}

char **
buildSItemList(sourcelist)
SList sourcelist;
{
  char **result;
  int num, i;
  SList source;

  /* find the length of the sidlist in the question */

  for(num = 0, source = sourcelist; 
      source != NULL;
      num++, source = source->nextSource);

  result = (char**) s_malloc(1+num*sizeof(char*));
  if(num > 0)
    for(i =0, source = sourcelist; i<num; i++, source = source->nextSource)
      if(source->thisSource != NULL)
	result[i] = source->thisSource->name;
  result[num] = NULL;
  return(result);
}

short
ReadSourceID(file, sid)
FILE *file;
SourceID sid;
{
  char temp_string[MAX_SYMBOL_SIZE];
  char filename[MAX_SYMBOL_SIZE];
  short check_result;
  long lines, chars, best;

  check_result = CheckStartOfStruct("source-id", file);
  filename[0] = '\0';
  if(FALSE == check_result){ 
    return(false);
  }
  if(END_OF_STRUCT_OR_LIST == check_result)
    {
      return(FALSE);
    }
    
  /* read the slots: */
  while(TRUE){
    long val;
    short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
    if(END_OF_STRUCT_OR_LIST == check_result) break;
    if(FALSE == check_result){
      return(false);
    } 
    if(0 == strcmp(temp_string, ":filename")) {
      if (FALSE == ReadString(filename, file, MAX_SYMBOL_SIZE))
	return(false);
      if(sid->filename != NULL) s_free(sid->filename);
      sid->filename = s_strdup(filename);
    }
  }
  return(TRUE);
}

SourceList ReadListOfSources(file)
FILE *file;
{
  char temp_string[MAX_SYMBOL_SIZE];
  short check_result;
  SourceID sid = NULL;
  SourceList result, this, last;
          
  /* initialize */
  this = last = result = NULL;

  if(ReadStartOfList(file) == FALSE)
    return(NULL);

  while(TRUE) {
    sid = (SourceID)s_malloc(sizeof(_SourceID));
    check_result = ReadSourceID(file, sid);
    if(check_result == END_OF_STRUCT_OR_LIST) {
      s_free(sid);
      return(result);
    }
    else if(check_result == FALSE)
      return(result);

    else if(check_result == TRUE) {
      if(result == NULL)
	result = this = (SourceList) s_malloc(sizeof(_SourceList));
      else
	this = (SourceList) s_malloc(sizeof(_SourceList));
      this->thisSource = sid;
      if(last != NULL)
	last->nextSource = this;
      last = this;
    }
  }
}

short ReadSource(source, file)
Source source;
FILE *file;
{
  char temp_string[MAX_SYMBOL_SIZE];
  char filename[MAX_SYMBOL_SIZE];
  short check_result;
  long port;

  long version, view;

  /* make sure it's a Source */
  
  check_result = CheckStartOfStruct("source", file);
  if(FALSE == check_result){ 
    return(false);
  }
  if(END_OF_STRUCT_OR_LIST == check_result)
    {
      return(FALSE);
    }
    
  /* read the slots: */
  while(TRUE){
    long val;
    short check_result = ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE);
    if(END_OF_STRUCT_OR_LIST == check_result) break;
    if(FALSE == check_result){
      return(false);
    } 
    if(0 == strcmp(temp_string, ":version")) {
      if(FALSE == ReadLong(file, &version))
	return(false);
    }
    else if(0 == strcmp(temp_string, ":ip-name")) {
      if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      strcpy(source->server, temp_string);
    }
    else if(0 == strcmp(temp_string, ":ip-address")) {
      if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      strcpy(source->server, temp_string);
    }
    else if(0 == strcmp(temp_string, ":configuration")) {
      if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      find_value(temp_string, "IPAddress", source->server, STRINGSIZE);
      find_value(temp_string, "RemotePort", source->service, STRINGSIZE);
    }
    else if(0 == strcmp(temp_string, ":tcp-port")) {
      if(FALSE == ReadLong(file, &port))
	return(false);
      sprintf(source->service,"%d", port);
    }
    else if(0 == strcmp(temp_string, ":maintainer")) {
      if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      if(source->maintainer != NULL) s_free(source->maintainer);
      source->maintainer = s_strdup(temp_string);
    }
    else if(0 == strcmp(temp_string, ":database-name")) {
      if(FALSE == ReadString(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      strcpy(source->database, temp_string);
    }
    else if(0 == strcmp(temp_string, ":cost")) {
      double cost;
      if(FALSE == ReadDouble(file, &cost))
	return(false);
      sprintf(source->cost, "%d", cost);
    }
    else if(0 == strcmp(temp_string, ":cost-unit")) {
      if(FALSE == ReadSymbol(temp_string, file, MAX_SYMBOL_SIZE))
	return(false);
      strcpy(source->units, temp_string);
    }
    else if(0 == strcmp(temp_string, ":description")) {
      if(FALSE == ReadString(desc_string, file, DESC_SIZE))
	return(false);
      if(source->description != NULL) s_free(source->description);
      source->description = s_strdup(desc_string);
    }
    else if(0 == strcmp(temp_string, ":update-time")) {
      if(FALSE == ReadStartOfList(file))
	return(false);
      while(getc(file) != ')')
	;
    }
    else
      return(false);
  }

  return(TRUE);
}

boolean newSourcep(name, num)
char *name;
int num;
{
  SList s;

  for (s = Sources; s != NULL; s = s->nextSource)
    if(!strcmp(name, s->thisSource->name))
      return FALSE;

  return TRUE;
}

boolean is_source(name, test)
char *name;
boolean test;
{
  char lastchar;

  lastchar = name[strlen(name)-1];
  if(test) 
    return ((strlen(name) > 4) &&
	  strstr(name, ".src") &&
	  (!strcmp(".src", strstr(name, ".src"))));
  else 
    return (lastchar != '~' &&
	    lastchar != '#' &&
	    strcmp(name, ".") &&
	    strcmp(name, ".."));
}

/* read all the sources from a directory.  If test is true, only files ending
   in .src are valid
*/

void ReadSourceDirectory(directory, test)
char *directory;
Boolean test;
{
#ifdef SYSV
  FILE *dirp;
#else
  DIR *dirp;
#endif
  struct dirent *dp;
  char filename[MAX_FILENAME_LEN], lastchar;
  FILE *fp;
  int i, newNumSources;
  SList Last;
  Source source;

#ifdef SYSV
  if((dirp = fopen(directory, "r")) == NULL)
#else
  if((dirp = opendir(directory)) == NULL)
#endif
    {
      char booboo[STRINGSIZE];
      sprintf(booboo, "Error on open of source directory: %s.\n", directory);
      XwaisPrintf(booboo);
      return;
    }

  /* find the end of the sourcelist */
  if(Sources == NULL)
    Sources = makeSList(NULL, NULL);

  for(Last = Sources; Last->nextSource != NULL; Last = Last->nextSource);

  for (i = NumSources;
#ifdef SYSV
       (fread((char *)dp,  sizeof( *dp), 1, dirp) == 1);
#else
       ((dp = readdir(dirp))!= NULL);
#endif
       ) {

    if (is_source(dp->d_name, test)) {
      strcpy(filename, directory);
      strcat(filename, dp->d_name);
      if ((fp = fopen(filename, "r")) != NULL) {
	source = (Source) s_malloc(sizeof(_Source));
	source->initp = FALSE;
	source->name = s_strdup(dp->d_name);
	source->directory = s_strdup(directory);
	ReadSource(source, fp);
	fclose(fp);
	if(Last->thisSource == NULL)
	  Last->thisSource = source;
	else {
	  Last->nextSource = makeSList(source, NULL);
	  Last = Last->nextSource;
	}
	i++;
      }
    }
  }
  newNumSources = i;

#ifdef SYSV
    fclose(dirp);
#else /* ndef SYSV */
    closedir(dirp);
#endif
  NumSources = newNumSources;
}

void WriteSource(directory, source, overwrite)
char *directory;
Source source;
Boolean overwrite;
{
  char filename[MAX_FILENAME_LEN];
  FILE *fp;

  /* build filename */

  strcpy(filename, directory);
  strcat(filename, source->name);

  /* test to see if it exists */

  if (overwrite == FALSE) 
    if ((fp = fopen(filename, "r")) != NULL) {
      char outstring[STRINGSIZE];
      sprintf(outstring, "File %s exists, click again to overwrite.\n", filename);
      XwaisPrintf(outstring);
      fclose(fp);
      return;
    }
  
  if ((fp = fopen(filename, "w")) == NULL) {
    char outstring[STRINGSIZE];
    sprintf(outstring, "Error openning %s.\n", filename);
    XwaisPrintf(outstring);
    return;
  }
  
  fprintf(fp, "(:source\n:version  3\n");

  if(source->server != NULL) 
    if(source->server[0] != 0)
      if(isdigit(source->server[0])) /* then it's an ip-address */
	fprintf(fp, ":ip-address \"%s\"\n", source->server);
      else
	fprintf(fp, ":ip-name \"%s\"\n", source->server);

  if(source->service != NULL) 
    if(source->service[0] != 0)
      fprintf(fp, ":tcp-port %s\n", source->service);

  fprintf(fp, ":database-name \"%s\"\n", source->database);
  if(source->cost != NULL) 
    if(source->cost[0] != 0)
      fprintf(fp, "   :cost %s \n", source->cost);
  else
      fprintf(fp, "   :cost 0.00 \n");

  if(source->units != NULL) 
    if(source->units[0] != 0)
      fprintf(fp, "   :cost-unit %s \n", source->units);
  else
    fprintf(fp, "   :cost-unit :free \n");
  
  if(source->maintainer != NULL) 
    if(source->maintainer[0] != 0)
      fprintf(fp, "   :maintainer \"%s\"\n", 
	      source->maintainer);
  else
      fprintf(fp, "   :maintainer \"%s\"\n", 
	      current_user_name());

  if(source->maintainer != NULL) 
    if(source->maintainer[0] != 0)
      fprintf(fp, ":description \"%s\")\n", source->description);
  else
    fprintf(fp, ":description \"Created with XWAIS by %s on %s.\")\n",
	    printable_time(), current_user_name());

  fclose(fp);
}

SourceList
makeSourceList(source, rest)
SourceID source;
SourceList rest;
{
  SourceList result;
  if((result = (SourceList)s_malloc(sizeof(_SourceList))) != NULL) {
    result->thisSource = source;
    result->nextSource = rest;
  }
  return(result);
}


SList
  makeSList(source, rest)
Source source;
SList rest;
{
  SList result;
  if((result = (SList)s_malloc(sizeof(_SList))) != NULL) {
    result->thisSource = source;
    result->nextSource = rest;
  }
  return(result);
}

FreeSource(source)
Source source;
{
  if (source != NULL) {
    if(source->name != NULL)
      s_free (source->name);
    if(source->directory != NULL)
      s_free (source->directory);
    if(source->description != NULL)
      s_free (source->description);
    if(source->maintainer != NULL)
      s_free (source->maintainer);
    s_free(source);
  }
}

FreeSources(sources)
SList sources;
{
 SList s, n;

 for (s = sources; s != NULL; s = n) {
   n = s->nextSource;
   FreeSource(s->thisSource);
   s_free(s);
 }

 NumSources = 0;
 sources = NULL;
}

Source
  findsource(name)
char *name;
{
  SList asource;

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

Source
  findSource(n)
int n;
{
  SList asource;

  for(asource = Sources; 
      (n > 0) && (asource != NULL);
      asource = asource->nextSource, n--);

  if (asource != NULL) return asource->thisSource;
  else return NULL;
}
