/************************************************************************
*          dbmake - WHOIS database support program.
*                   Translates an ascii file containing WHOIS entries
*                   into a binary file for use by whoisd.
*************************************************************************
* Author : Eric Smith
* Date   : 12/20/91
* Usage  : dbmake input_file
*          Output file is called whois.data.
*          For instructions on creating the whois database and reconfiguring
*          the fields in the database, read the file whoisadmin.help.
************************************************************************/
#include <stdio.h>
#include "whoisd.h"

main(argc, argv)
  int argc;
  char *argv[];
{
  FILE *fpin, *fpout;
  char *cc;
  int i;
  int filepos;
  int startpos;
  char *tempptr;
  char tempbuff[100];
  static int user_field_size[USER_FIELDS+1] = USER_FIELD_SIZES;
  int *last_filepos[26];
  int *first_filepos[26];
  int *handle_filepos[26];
  int *mbox_name_filepos[26];
  int *mbox_host_filepos[26];
  int last_index[26];
  int first_index[26];
  int handle_index[26];
  int mbox_name_index[26];
  int mbox_host_index[26];
  int last_size[26];
  int first_size[26];
  int handle_size[26];
  int mbox_name_size[26];
  int mbox_host_size[26];
/*
 * Initially there is no space for index entries.  They will be allocated as
 * needed.
 */
  for (i=0; i<26; i++) {
    last_filepos[i] = first_filepos[i] = handle_filepos[i] = 0;
    mbox_name_filepos[i] = mbox_host_filepos[i] = 0;
    last_index[i] = first_index[i] = handle_index[i] = 0;
    mbox_name_index[i] = mbox_host_index[i] = 0;
    last_size[i] = first_size[i] = handle_size[i] = 0;
    mbox_name_size[i] = mbox_host_size[i] = 0;
  }
/*
 * Open input file.
 */
  if ((fpin = fopen(argv[1], "r")) == NULL) {
    printf("Unable to open input file %s\n", argv[1]);
    exit();
  }
/*
 * Open output file.
 */
  if ((fpout = fopen(WHOIS_DATA, "w")) == NULL) {
    printf("Unable to open output file whois.data\n");
    exit();
  }
/*
 * Set output file position pointer to beginning of file.
 */
  filepos = 0;
  do {
    startpos = filepos;
/*
 * Get last name field from input file and process if not end of file.
 */
    if ((cc = fgets(tempbuff, sizeof(tempbuff), fpin)) != NULL) {
      tempptr = tempbuff;
/*
 * Remove leading white space.
 */
      while (is_space(*tempptr)) tempptr++;
/*
 * Remove trailing white space.
 */
      strip_space(tempptr);
/*
 * Seek to new writing position.
 */
      fseek(fpout, filepos, 0);
/*
 * Notify user if error in field size.
 */
      if (strlen(tempptr) > LAST_NAME_SIZE)
        input_error("last name", LAST_NAME_SIZE, tempptr);
/*
 * Write field to output file.
 */
      fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
/*
 * Update index entries.
 */
      if ((tempptr[0]>='a') && (tempptr[0]<='z'))
        tempptr[0] -= 32;
      if ((tempptr[0]<'A') || (tempptr[0]>'Z'))
        input_error("last name", LAST_NAME_SIZE, tempptr);
      else
        add_index_entry(last_filepos, last_index, last_size,
                        startpos, tempptr[0]-65);
/*
 * Adjust file position pointer to start of next field.
 */
      filepos += LAST_NAME_SIZE+1;
/*
 * Process first name field.
 */
      fseek(fpout, filepos, 0);
      fgets(tempbuff, sizeof(tempbuff), fpin);
      tempptr = tempbuff;
      while (is_space(*tempptr)) tempptr++;
      strip_space(tempptr);
      if (strlen(tempptr) > FIRST_NAME_SIZE)
        input_error("first name", FIRST_NAME_SIZE, tempptr);
      fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
      if ((tempptr[0]>='a') && (tempptr[0]<='z'))
        tempptr[0] -= 32;
      if ((tempptr[0]<'A') || (tempptr[0]>'Z'))
        input_error("first name", FIRST_NAME_SIZE, tempptr);
      else
        add_index_entry(first_filepos, first_index, first_size,
                        startpos, tempptr[0]-65);
      filepos += FIRST_NAME_SIZE+1;
/*
 * Process middle initial field.
 */
      fseek(fpout, filepos, 0);
      fgets(tempbuff, sizeof(tempbuff), fpin);
      tempptr = tempbuff;
      while (is_space(*tempptr)) tempptr++;
      strip_space(tempptr);
      if (strlen(tempptr) > MIDDLE_INITIAL_SIZE)
        input_error("middle initial", MIDDLE_INITIAL_SIZE, tempptr);
      fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
      filepos += MIDDLE_INITIAL_SIZE+1;
/*
 * Process handle field.
 */
      fseek(fpout, filepos, 0);
      fgets(tempbuff, sizeof(tempbuff), fpin);
      tempptr = tempbuff;
      while (is_space(*tempptr)) tempptr++;
      strip_space(tempptr);
      if (strlen(tempptr) > HANDLE_SIZE)
        input_error("handle", HANDLE_SIZE, tempptr);
      fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
      if ((tempptr[0]>='a') && (tempptr[0]<='z'))
        tempptr[0] -= 32;
      if ((tempptr[0]<'A') || (tempptr[0]>'Z'))
        input_error("handle", HANDLE_SIZE, tempptr);
      else
        add_index_entry(handle_filepos, handle_index, handle_size,
                        startpos, tempptr[0]-65);
      filepos += HANDLE_SIZE+1;
/*
 * Process net address field.
 */
      fseek(fpout, filepos, 0);
      fgets(tempbuff, sizeof(tempbuff), fpin);
      tempptr = tempbuff;
      while (is_space(*tempptr)) tempptr++;
      strip_space(tempptr);
      if (strlen(tempptr) > NET_ADDRESS_SIZE)
        input_error("net address", NET_ADDRESS_SIZE, tempptr);
      fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
      if ((tempptr[0]>='a') && (tempptr[0]<='z'))
        tempptr[0] -= 32;
      if ((tempptr[0]<'A') || (tempptr[0]>'Z'))
        input_error("mailbox name", NET_ADDRESS_SIZE, tempptr);
      else
        add_index_entry(mbox_name_filepos, mbox_name_index, mbox_name_size,
                        startpos, tempptr[0]-65);
      i = search_string(tempptr, '@');
      if (i != -1) {
        i++;
        while (is_space(tempptr[i])) i++;
        if ((tempptr[i]>='a') && (tempptr[i]<='z'))
          tempptr[i] -= 32;
        if ((tempptr[i]<'A') || (tempptr[i]>'Z'))
          input_error("mailbox name", NET_ADDRESS_SIZE, tempptr);
        else
          add_index_entry(mbox_host_filepos, mbox_host_index, mbox_host_size,
                          startpos, tempptr[i]-65);
      }

      filepos += NET_ADDRESS_SIZE+1;
/*
 * Process each user field.
 */
      for (i=0; i<USER_FIELDS; i++) {
        fseek(fpout, filepos, 0);
        fgets(tempbuff, sizeof(tempbuff), fpin);
        tempptr = tempbuff;
        while (is_space(*tempptr)) tempptr++;
        strip_space(tempptr);
        if (strlen(tempptr) > user_field_size[i])
          input_error(user_field_name[i], user_field_size[i], tempptr);
        fwrite(tempptr, strlen(tempptr)+1, 1, fpout);
        filepos += user_field_size[i]+1;
      }
    }
  } while (cc != NULL);
/*
 * Seek to end of last field and write a zero to make sure the file gets
 * written to end of final field.
 */
  fseek(fpout, filepos-1, 0);
  tempbuff[0] = 0;
  fwrite(tempbuff, 1, 1, fpout);
  fclose(fpin);
  fclose(fpout);
/*
 * Open index file and write index information.
 */
  if ((fpout = fopen(WHOIS_INDEX, "w")) == NULL)
    printf("Unable to open index file, %s\n", WHOIS_INDEX);
  else {
    for (i=0; i<26; i++)
      fwrite(&(last_index[i]), sizeof(int), 1, fpout);
    for (i=0; i<26; i++)
      fwrite(&(first_index[i]), sizeof(int), 1, fpout);
    for (i=0; i<26; i++)
      fwrite(&(handle_index[i]), sizeof(int), 1, fpout);
    for (i=0; i<26; i++)
      fwrite(&(mbox_name_index[i]), sizeof(int), 1, fpout);
    for (i=0; i<26; i++)
      fwrite(&(mbox_host_index[i]), sizeof(int), 1, fpout);

    for (i=0; i<26; i++)
      fwrite(last_filepos[i], sizeof(int)*last_index[i], 1, fpout);
    for (i=0; i<26; i++)
      fwrite(first_filepos[i], sizeof(int)*first_index[i], 1, fpout);
    for (i=0; i<26; i++)
      fwrite(handle_filepos[i], sizeof(int)*handle_index[i], 1, fpout);
    for (i=0; i<26; i++)
      fwrite(mbox_name_filepos[i], sizeof(int)*mbox_name_index[i], 1, fpout);
    for (i=0; i<26; i++)
      fwrite(mbox_host_filepos[i], sizeof(int)*mbox_host_index[i], 1, fpout);

    fclose(fpout);
  }
}



/*
 * This routine is called when an illegal field size is found in the input
 * file.  Enough debug information is output to enable the user to fix the
 * problem in the input file.
 */
input_error(field_name, field_size, input_field)
  char *field_name;
  int field_size;
  char *input_field;
{
  printf("Illegal field in input file.\n");
  printf("field name = %s\n", field_name);
  printf("field size = %d\n", field_size);
  printf("Input field = \042%s\042\n", input_field);
  printf("Input field size = %d\n", strlen(input_field));
/*
  exit();
*/
}


/*
 * This routine strips off all trailing white_space from a string.
 */
strip_space(string)
  char *string;
{
  static int index;

  index = strlen(string)-1;
  while (is_space(string[index])) index--;
  string[index+1] = 0;
}



/*
 * This routine returns a 1 if the character is white_space and 0 if not.
 * White space is considered to be one of the following:  space, line feed,
 * carriage return, tab or form feed.
 */
is_space(value)
  char value;
{
  static int i;
  static space_chars[5] = {' ', '\n', '\r', '\011', '\014'};

  for (i=0; i<5; i++)
    if (space_chars[i] == value)
      return(1);
  return(0);
}




/*
 * This routine returnes the position of a character within a string.  -1 is
 * returned if character not found.
 */
search_string(string, search_char)
  char *string;
  char search_char;
{
  static int i;
  static int char_pos;

  char_pos = -1;
  for (i=0; i<strlen(string); i++) {
    if (string[i] == search_char) {
      char_pos = i;
      break;
    }
  }

  return(char_pos);
}



add_index_entry(filepos, index, size, startpos, key)
  int *filepos[26];
  int index[26];
  int size[26];
  int startpos;
  char key;
{
/*
 * Check for sufficient space.
 */
  if (index[key] == size[key]) {
    if (!filepos[key]) {
      size[key] = 100;
      filepos[key] = (int *)malloc(100*sizeof(int));
      if (filepos[key] == 0) {
        printf("Error in allocating index space.\n");
        printf("Try increasing the memory available for process.\n");
        exit();
      }
    }
    else {
      size[key] += 100;
      filepos[key] = (int *)realloc(filepos[key], size[key]*sizeof(int));
      if (filepos[key] == 0) {
        printf("Error in re-allocating index space.\n");
        printf("Try increasing the memory available for process.\n");
        exit();
      }
    }
  }
/*
 * Update index entry.
 */
  filepos[key][index[key]] = startpos;
  index[key] += 1;
}
