/* hatch - a tool for hatching files into Fidonet file areas
 *
 * This program does two things. First, it stores stdin into
 * a file in the fidonet outbound directory and it creates a tic file.
 *
 * look into the readme for former information
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "config.h"

#define PROGRAM "hatch"
#define VERSION "0.5"
#define AUTHOR "Martin Schulze"
#define COPYRIGHT "Copyright (c) 1994 by Joey Software"
#define HELP "\
hatch [-d description] -a area -f file

hatches a given file into a fidonet file area.
-d description	the description that ist shown
-a area		the area the file is hatched into
-f file		the filename

This program searches for the bossnode.
"

struct fido_address {      /* for z:n/f.p addresses */
  unsigned int zone;       /* fido zone */
  unsigned int region;     /* fido region */
  unsigned int node;       /* fido node */
  unsigned int point;      /* fido point */
};

/*
 * consults the file FILEAREA_FILE and reads the bossnode of the filearea 
 * and the name of the bossnode.
 */
int consult_filearea_file(const char *ca_area, struct fido_address *address, char *bossname)
{
  int i_found = 0;
  FILE *fp_filearea;
  char ca_line[256];
  char *cp_line;

  char ca__area[41] = "";
  char ca__boss[15] = "";
  char ca__name[51] = "";

  int i,k,l;

  if ((fp_filearea = fopen(FILEAREA_FILE, "r")) == NULL) {
    return -1;
  }
  while ((!i_found) && fgets(ca_line, 255, fp_filearea)) {
    cp_line = ca_line;

    /* split line into several entries */
    i = strchr(ca_line, ' ');
    k = strchr(ca_line, '\t');
    if ((i==0) && (k==0)) continue;
    l = (i=0?k:i<k?i:k);                /* find the least occurrence */
    strncpy(ca__area, ca_line, l-(int)cp_line);
    if (!strcmp(ca_area, ca__area)) {
      i_found = 1;

      /* get the fido address */
      (int)cp_line = l;
      while ((*cp_line == ' ')||(*cp_line == '\t')) cp_line++;
      i = strchr(cp_line, ' ');
      k = strchr(cp_line, '\t');
      if ((i==0) && (k==0)) continue;
      l = (i=0?k:i<k?i:k);                /* find the least occurrence */
      strncpy(ca__boss, cp_line, l-(int)cp_line);
      sscanf(ca__boss, "%d:%d/%d", &address->zone, &address->region, &address->node); 

      /* get the bossnode's name */
      (int)cp_line = l;
      while ((*cp_line == ' ')||(*cp_line == '\t')) cp_line++;
      strcpy(bossname, cp_line);
      if ((i = strlen(bossname)) > 0) bossname[i-1] = '\0';
    }
  }
  if (!i_found) return -2;
  fclose(fp_filearea);
  return 1;
}

/*
 * consults the file ALIASES_FILE to get the point number
 */
int consult_aliases_file(struct fido_address *address)
{
  FILE *fp_aliases;
  int i_found = 0;
  char ca_line[256];
  char *cp_line;
  struct fido_address s_sfido;

  int i,k,l;
  char ca_s[20];

  if ((fp_aliases = fopen(ALIASES_FILE, "r")) == NULL) {
    return -1;
  }
  while ((!i_found) && fgets(ca_line, 255, fp_aliases)) {
    cp_line = ca_line;
    
    /* split line into several entries */
    i = strchr(ca_line, ' ');
    k = strchr(ca_line, '\t');
    if ((i==0) && (k==0)) continue;
    l = (i=0?k:i<k?i:k);                /* find the least occurrence */
    (int)cp_line = l;
    while ((*cp_line == ' ')||(*cp_line == '\t')) cp_line++;
    i = strchr(cp_line, ' ');
    k = strchr(cp_line, '\t');
    if ((i==0) && (k==0)) continue;
    l = (i=0?k:i<k?i:k);                /* find the least occurrence */
    strncpy(ca_s, cp_line, l-(int)cp_line);
    for (i=0;(ca_s[i] != ' ')&&(ca_s[i] != '\t')&& i < 20; i++);
    cp_line[i] = '\0';
    sscanf(ca_s, "%d:%d/%d.%d", &s_sfido.zone, &s_sfido.region, &s_sfido.node, &s_sfido.point); 
    if ((s_sfido.zone == address->zone)
	&& (s_sfido.region == address->region)
	&& (s_sfido.node == address->node)) {
      i_found = 1;
      address->point = s_sfido.point;
    }
  }
  if (!i_found) return -2;
  fclose(fp_aliases);
  return 1;
}

/*
 * consults the file PASSWDS_FILE to get the point number
 */
int consult_passwds_file(const struct fido_address address, char *passwd)
{
  FILE *fp_passwds;
  int i_found = 0;
  char ca_line[256];
  char *cp_line;
  struct fido_address s_sfido;
  char ca_boss[20];

  int i,k,l;
  char ca_s[20];

  if ((fp_passwds = fopen(PASSWDS_FILE, "r")) == NULL) {
    return -1;
  }
  while ((!i_found) && fgets(ca_line, 255, fp_passwds)) {
    cp_line = ca_line;
    
    /* split line into several entries
     */
    i = strchr(ca_line, ' ');
    k = strchr(ca_line, '\t');
    if ((i==0) && (k==0)) continue;
    l = (i=0?k:i<k?i:k);                /* find the least occurrence */
    strncpy(ca_s, ca_line, l-(int)cp_line);
    ca_s[l-(int)cp_line] = '\0';
    if (!strcmp(ca_s, "password")) {
      
      /* get the fido address
       */
      (int)cp_line = l;
      while ((*cp_line == ' ')||(*cp_line == '\t')) cp_line++;
      i = strchr(cp_line, ' ');
      k = strchr(cp_line, '\t');
      if ((i==0) && (k==0)) continue;
      l = (i=0?k:i<k?i:k);                /* find the least occurrence */
      strncpy(ca_boss, cp_line, l-(int)cp_line);
      sscanf(ca_boss, "%d:%d/%d", &s_sfido.zone, &s_sfido.region, &s_sfido.node); 
      if ((s_sfido.zone == address.zone)
	  && (s_sfido.region == address.region)
	  && (s_sfido.node == address.node)) {
	i_found = 1;

      /* get the password
       */
      (int)cp_line = l;
      while ((*cp_line == ' ')||(*cp_line == '\t')) cp_line++;
      strcpy(passwd, cp_line);
      if ((i = strlen(passwd)) > 0) passwd[i-1] = '\0';
      }
    }
  }
  if (!i_found) return -3;
  fclose(fp_passwds);
  return 1;
}

/* print_tick creates the tick file and fills it with the correct
 * entries.
 */
int print_tick(const char *area, const struct fido_address address, const char *bossname, const char *file, const char *description, const char *password, const ulong crcval)
{
  FILE *fp_tick;
  char ca_s[256], ca_x[256];
  char ca_buffer[4096];
  char *cp_basename;
  int fd_in, fd_out;

  int i;

  /* strip all '/' */
  cp_basename = strrchr(file,'/');
  if (!cp_basename)
    cp_basename = file;
  else
    ++cp_basename;

  /* This copy part comes from Juergen Fischer - thanks
   */
  if ((fd_in=open(file,O_RDONLY)) == -1) return -2;

  sprintf(ca_x, "%s/%s", OUTBOUND, cp_basename);
  if ((fd_out=open(ca_x,O_WRONLY|O_CREAT,0666)) == -1) return -3;
  while (write(fd_out,ca_buffer,read(fd_in,ca_buffer,4096))) ;
  close(fd_out);
  close(fd_in);

  i = strchr(cp_basename, '.');
  if (i == (int)NULL) sprintf (ca_s, "%s/%s.tic", OUTBOUND, cp_basename);
  else {
    strncpy(ca_x, cp_basename, i-(int)cp_basename);
    ca_x[i-(int)cp_basename] = '\0';
    sprintf (ca_s, "%s/%s.tic", OUTBOUND, ca_x);
  }

  if ((fp_tick = fopen(ca_s, "w")) == NULL) {
    return -1;
  }
  fprintf(fp_tick, "Area %s\n", area);
  fprintf(fp_tick, "Origin %d:%d/%d.%d\n", address.zone, address.region, address.node, address.point);
  fprintf(fp_tick, "From %d:%d/%d.%d\n", address.zone, address.region, address.node, address.point);
  fprintf(fp_tick, "To %s, %d:%d/%d\n", bossname, address.zone, address.region, address.node);
  fprintf(fp_tick, "File %s\n", cp_basename);
  if (strlen(description) == 0)
    fprintf(fp_tick, "Desc (no description given)\n");
  else
    fprintf(fp_tick, "Desc %s\n", description);
  fprintf(fp_tick, "Created by %s %s, %s\n", PROGRAM, VERSION, COPYRIGHT);
  fprintf(fp_tick, "Path %d:%d/%d.%d\n", address.zone, address.region, address.node, address.point);
  fprintf(fp_tick, "Seenby %d:%d/%d.%d\n", address.zone, address.region, address.node, address.point);
  fprintf(fp_tick, "Crc %08lX\n", crcval);
  fprintf(fp_tick, "Pw %s\n", password);
  fclose (fp_tick);

  /* now comes the flo file
   */
  sprintf(ca_x, "%s/%04x%04x.%s", OUTBOUND, address.region, address.node, FLO);
  if ((fp_tick = fopen(ca_x, "a")) == NULL) {
    return -4;
  }
  fprintf(fp_tick, "^%s\n", ca_s);
  fprintf(fp_tick, "^%s/%s\n", OUTBOUND, cp_basename);
  fclose (fp_tick);
  return 1;
}

int main(int argc, char **argv)
{
  char ca_description[41] = "";      /* description of the hatched file */
  char ca_area[41] = "";             /* area the file is hatched into */
  char ca_file[41] = "";             /* filename */
  struct fido_address s_address = {0,0,0,0};     /* my address */
  char ca_bossname[51] = "";         /* aka of the bossnode */
  char ca_password[20] = "";         /* fido password at bossnode */
  ulong ul_crc;                      /* calculated crc over whole file */

  char c;

  if (argc == 1) {
    fprintf(stderr,"%s: no arguments specified\n\t-h gives help.\n",argv[0]);
    return 1;
  }
  while ((c = getopt(argc, argv, "hd:a:f:")) != EOF) {
    switch (c) {
    case 'h': /* display help */
      printf("%s %s %s\n\n",PROGRAM, VERSION, COPYRIGHT);
      printf(HELP);
      return 0;
    case 'd': /* file description */
      strncpy(ca_description, optarg, 40);
      break;
    case 'a': /* file area */
      strncpy(ca_area, optarg, 40);
      break;
    case 'f': /* file name */
      strncpy(ca_file, optarg, 40);
      break;
    }
  }

  if ((strlen(ca_area) == 0)||(strlen(ca_file) == 0)) {
    fprintf(stderr,"%s: no area or filename specified\n\t-h gives help.\n",argv[0]);
    return 1;
  }

  /* Try to get some information out of the filearea file
   */
  switch (consult_filearea_file(ca_area, &s_address, &ca_bossname)) {
  case -1: /* file not found */
    fprintf(stderr,"%s: error occurred while opening filearea file.\n",argv[0]);
    return 1;
  case -2: /* entry not found */
    fprintf(stderr,"%s: no information for %s found in filearea file.\n", argv[0], ca_area);
    return 1;
  }

  /* Try to get the point number out of the aliases file
   */
  switch (consult_aliases_file(&s_address)) {
  case -1: /* file not found */
    fprintf(stderr,"%s: error occurred while opening aliases file.\n",argv[0]);
    return 1;
  case -2: /* entry not found */
    fprintf(stderr,"%s: no information for %d:%d/%d found in aliases file.\n", 
	    argv[0], s_address.zone, s_address.region, s_address.node);
    return 1;
  }

  /* Try to fetch the password
   */
  switch (consult_passwds_file(s_address, &ca_password)) {
  case -1:
    fprintf(stderr,"%s: error occurred while opening passwords file.\n",argv[0]);
    return 1;
  case -2:
    fprintf(stderr, "%s: suid failed.\n", argv[0]);
    return 1;
  case -3:
    fprintf(stderr, "%s: no password entry for %d:%d/%d found in passwords file.\n", 
	    argv[0], s_address.zone, s_address.region, s_address.node);
    return 1;
  }

  /* get the CRC information
   */
  switch (crc_file(ca_file, &ul_crc)) {
  case -1:
    fprintf(stderr,"%s: error occurred while opening file \"%s\".\n",argv[0], ca_file);
    return 1;
  case -2:
    fprintf(stderr, "%s: can't calculate crc, sorry.\n", argv[0]);
    return 1;
  }

  /* Now print the information into a tick file
   */
  switch (print_tick(ca_area, s_address, ca_bossname, ca_file, ca_description, ca_password, ul_crc)) {
  case -1:
    fprintf(stderr,"%s: error occurred while opening tick file.\n",argv[0]);
    return 1;
  case -2:
    fprintf(stderr, "%s: can't open file \"%s\".\n", argv[0], ca_file);
    return 1;
  case -3:
    fprintf(stderr, "%s: can't open file \"%s/%s\".\n", argv[0], OUTBOUND, ca_file);
    return 1;
  case -4:
    fprintf(stderr,"%s: error occurred while opening flo file.\n",argv[0]);
    return 1;
  }
}
