/*
 *  MBRESTM - 1/18/88
 *
 *  Copyright (C) 1988, 1989
 *  By the CBBS Group.
 *
 *  This program reads the individual message text files and
 *  produces MAIL.DAT from the information. It is intended to
 *  be used after a mail file crash.
 *
 *  It is expected that this program will be run from the
 *  directory containing the message files. The new MAIL.DAT
 *  file will also be found in this directory. It will have to
 *  copied the the proper bbs directory replacing the corrupted
 *  original mail file.
 *
 */

#include "mb.h"
#ifndef MCH_AMIGA
#include "dos.h"
#else
#include <libraries/dos.h>
#include <exec/memory.h>
#endif
MAIL_HDR *mfhs;
MSG_HDR *tmmhs;
byte flds;
char *fld[maxflds];
char *cmd;
char *line;
char *nullstr = "";

char pp[44], name[500][13], msgfile[10], badfile[10];
int count = 0;
int cmp();

main()
{
  int x, c, y;
  int xx = 1;
  int recno = 1;
  int msgfl, mail;
  char *t;

  mfhs    =  (MAIL_HDR *) malloc(sizeof(MAIL_HDR));
  tmmhs   =  (MSG_HDR *)  malloc(sizeof(MSG_HDR));
  cmd     =  (char *) malloc(linelen);
  line    =  (char *) malloc(linelen);

  if((mail = open("MAIL.DAT", O_CREAT | O_RDWR | O_BINARY, pmode)) < 0)
    { puts("MAIL.DAT cannot be opened - process aborted!\n");
      exit (1);
    }

  dir_list();

  while( xx <= count)
  {
    y = true;
    sprintf (msgfile, "%s",name[xx-1]);
    printf("%s ", msgfile);
    if((msgfl = open( msgfile, O_RDWR | O_BINARY)) < 0)
      {
        printf(" cannot be opened - bypassing this file\n");
        xx++;
        continue;
      }

    read_rec(msgfl, 0, (char *) line);
    if(!((line[253] is '\0') and (line[254] is '\r') and (line[255] is '\n')))
      {
        printf(" seems to be corrupted - bypassing this file\n");
        close(msgfl);
        sprintf(badfile, "%s.BAD", msgfile);
        rename(msgfile, badfile);
        xx++;
        continue;
      }


    fill(tmmhs, '\0', 256);
    tmmhs->rn       = xx;
    tmmhs->read     = atoi( &line[61]);
    tmmhs->number   = atoi( &line[0]);
    tmmhs->size     = atoi( &line[9]);
    tmmhs->type     = line[6];
    switch (line[7])
      {
      case 'O': tmmhs->stat = m_stale; break;
      case 'F': tmmhs->stat = m_fwd; break;
      case 'H': tmmhs->stat = m_hold; break;
      case 'Y': tmmhs->stat = m_read; break;
      case 'K': tmmhs->stat = m_kill; break;
      default:  tmmhs->stat = '\0';
      }

    strncpy(tmmhs->to, &line[15], ln_call);
    strncpy(tmmhs->from, &line[22], ln_call);
    strncpy(tmmhs->bbs, &line[29],ln_call);
    strncpy(tmmhs->date, &line[36], ln_date);
    strncpy(tmmhs->time, &line[43], ln_time);
    fill(tmmhs->bid, ' ', ln_bid);
    if (line[48] isnt ' ') unbl(tmmhs->bid, &line[48], ln_bid);
    tmmhs->ext = line[68] - '0'; 
    if (tmmhs->ext is 1)
    {
      strncpy(tmmhs->flag, &line[70], mmesn);
      for( x=0, c=0; x < mmesn; x++, c++)
        {
        if (tmmhs->flag[x] is ' ') { tmmhs->flag[x] = '0'; c--;}
        tmmhs->flag[x] = (tmmhs->flag[x]-'0');
        }
        tmmhs->count = c;
        y = dodis();
    }
    if (tmmhs->ext is 2)
    {
      strcpy (cmd, &line[70]);
      remnl (cmd);
      strcpy(tmmhs->call[0], cmd);
      t = strchr(&line[68], '\n');
      t++;
      strcpy(cmd, t);
      remnl(cmd);
      strcpy(tmmhs->title, cmd);
    }
    else
    {
      parse();
      strcpy(tmmhs->title, fld[0]);
    }
    write_rec(mail,recno++,(char *)tmmhs);
    close(msgfl);
    if (y) puts("restored");
    xx++;
  }
  mfhs->next    = recno;
  mfhs->first   = 1;
  mfhs->last    = recno-1;
  mfhs->version = mb_version;
  mfhs->free    = 0;
  mfhs->count   = recno-1;
  mfhs->unt_msg = 1;
  fill(mfhs->unu, '\0', mfhsunu);
  fill(mfhs->date, '\0', ln_date);
  fill(mfhs->time, '\0', ln_time);
  x = 1;
  if (count)  x = 1 + atoi(name[count - 1]);
  printf("The next message number will be %u\n", x);
  printf("Enter return if OK or new message number  ");
  gets(cmd);
  if (*cmd)  mfhs->next_msg = atoi(cmd);
  else  mfhs->next_msg = x;
  mfhs->unt_msg = mfhs->next_msg;
  write_rec(mail, 0, (char *)mfhs);

  close(mail);
}

/*
 *  Parse a command line.
 *
 *  Input:   Line of text in line.
 *  Returns: Fields are placed in cmd.
 *           Fields are pointed to by fld[].
 *           flds is set to the number of fields found.
 *           Each field is null-terminated.
 *           Fields beyond maxflds are ignored.
 */

parse()
{
  char skip;
  register short bl;
  register char *in, *out;

  for (flds = 0; flds < maxflds;)
    fld[flds++] = nullstr;

  in  = &line[86];
  out = cmd;
  bl  = false;
  flds = 0;
  skip = true;

  while (*in and (flds < maxflds) and (out < (cmd + linelen - 1)))
  {
    if (*in is '\r') { *in++; continue;}
    if (*in is '\n')  skip = !(skip);
    *out = *in;
    if (bl) {if ((*in <= ' ') and (skip)) { bl = false; *out = '\0'; } out++; }
    else    {if (*in > ' ')  { bl = true; fld[flds++] = out++; }}
    in++;
  }
  *out = '\0';
}


/*
 *  Remove new line  and carriage returns from end of string.
 */

remnl(p)
char *p;
{
  for (; *p; p++)
  {
    if ((*p is '\n') or (*p is '\r')) { *p = '\0'; return; }
  }
}
/*
 *  Read random record.
 */

read_rec(fid, rec, buffer)
int fid;
int rec;
char buffer[];
{
#ifndef MCH_AMIGA
  long lseek();
#endif
  long offs;

  offs = (long)rec * (long)RECSIZE;
  lseek(fid, offs, 0);
  return (read(fid, buffer, RECSIZE) is RECSIZE);
}
/*
 *  Write random record.
 */

write_rec(fid, rec, buffer)
int fid;
int rec;
char buffer[];
{
#ifndef MCH_AMIGA
  long lseek();
#endif
  long offs;

  offs = (long)rec * (long)RECSIZE;
  lseek(fid, offs, 0);
  return (write(fid, buffer, RECSIZE) is RECSIZE);
}
/*
 *  Fill some memory with a character.
 */

fill(adr, ch, len)
char *adr;
char ch;
int len;
{
  while (len--) *adr++ = ch;
}

/*
 *  Create the distribution list, if required.
 */

dodis()
{
  register FILE *dfl;
  char c;
  char tmp[linelen];

  tmmhs->ext = 0;
  if (*tmmhs->bbs is ' ') return;
  unbl(tmp, tmmhs->bbs, ln_call);
  strcat( tmp, ".DIS");

  if ((dfl = fopen( tmp, "r")) is NULL)
     {
     printf("restored without %s (file is not found)\n", tmp);
     return false;
     }
  tmmhs->ext = 0x01;

  for (c = 0; (c <tmmhs->count) and (fgets( tmp, linelen, dfl) isnt NULL);
    c++)
    {
    strupr(tmp);
    pcall(tmmhs->call[c], tmp);
    }
  fclose(dfl);
  return true;
}
/*
 *  Copy LJSF string to C string.
 */

unbl(to, from, size)
char *to, *from;
int size;
{
  while (size--)
  {
    if (*from <= ' ') { *to = '\0'; return; }
    *to++ = *from++;
  }
  *to = '\0';
}
/*
 *  Parse a callsign.
 *  Blank pad the output field, remove trailing ssid from call.
 *  Return the SSID.
*/

pcall(c, p)
char *c;
char *p;
{
  register short i;

/*
 *  Blank fill the target buffer.
 */

  fill (c, ' ', ln_call);

/*
 *  Ignore leading spaces.
 */

  while (*p and (*p is ' ')) p++;

/*
 *  Copy the call from the string into the call buffer.
 */

  for (i = ln_call; i and *p; i--)
  {
    if (*p <= ' ') return 0;
    if (*p is '-') return atoi(++p);
    *c++ = *p++;
  }
  if (*p++ is '-') return atoi(p); else return 0;
}
#ifndef MCH_AMIGA
/*
 *  Read the file names from the current directory and store
 *  the results in an array but exclude any name that is not
 *  made up of all numbers.
 *  Sort the resulting list in ascending order.
 */

dir_list()
{
  int x, y;
  char *file_name = "*.";

  printf("Reading directory - ");
  bdos(0x1a, (unsigned)pp, 0);
  if(18==bdos(0x4e, (unsigned)file_name, 0))
    {
      printf("No message files are found\n");
      return;
    }

  if (num( &pp[30])) strcpy (name[count++], &pp[30]);

  for(;;)
  {
    if(18==bdos(0x4f, 0, 0)) break;
    if (num( &pp[30])) strcpy (name[count++], &pp[30]);
  }
#else
/*
 *  A directory item looks like this:
struct FileInfoBlock {
   LONG fib_DiskKey;
   LONG fib_DirEntryType;
   char fib_FileName[108];
   LONG fib_Protection;
   LONG fib_EntryType;
   LONG fib_Size;
   LONG fib_NumBlocks;
   struct DateStamp fib_Date;
   char fib_Comment[80];
   char padding[36];
};
 */

typedef struct FileInfoBlock FCB;

static FCB *fcb = 0;

/*
 *  Open directory and create list of numeric files.
 */
long lock;
extern long Examine(),Lock(),ExNext();
dir_list()
{
   int x, y;
   long  result,Info();
   extern char *AllocMem();
   fcb = (FCB *)AllocMem((long)sizeof(*fcb),MEMF_PUBLIC|MEMF_CLEAR);
/*
 *  Get a lock on the current directory
 */
   lock = Lock("",ACCESS_READ);
   if(lock == 0L) {
      return;
   }
   /* and examine it to make sure it's OK */
   if((result = Examine(lock,fcb)) == 0L) {
      UnLock(lock);
      return;
   }
   for(;;) {
      /* Get next directory entry */
      if(ExNext(lock,fcb) == 0L) {
         UnLock(lock);
         break;
      }
      /* If the entry is a directory, go back for another */
      if(fcb->fib_DirEntryType > 0)continue;
      /* If the filename is numeric then add it into the list */
      if(num(fcb->fib_FileName))
         strcpy (name[count++], &fcb->fib_FileName[0]);
   }
   FreeMem(fcb,(long)sizeof(*fcb));
#endif
  printf("There are %d message files\n", count);
  if (count)
    {
      printf("***Sorting***\n");
      qsort (name, count, 13, cmp);
      for(x=0, y=1; x< count; x++, y++) 
      {
        printf("%6s", name[x]);
        if(y is 10) { printf("\n"); y=0; }
      }
      printf("\n");
    }
}
/*
 *  Compare two strings converted to integers.
 */

int cmp(n1,n2)
char *n1;
char *n2;
{
   return (atoi(n1) - atoi(n2));

}

/*
 *  Is the string a number?
 */

num(p)
char *p;
{
  for (; *p; p++) if (!isdigit(*p)) return false;
  return true;
}
#ifdef MCH_AMIGA
strupr(s)
unsigned char *s;
{
   register unsigned char *cp;
   for(cp = s;*cp;cp++)if((*cp >= 'a') && (*cp <= 'z'))*cp &= 040;
}
#endif
