/* dir.c */
#include <libraries/dos.h>
#include <exec/memory.h>
#include "mb.h"
/*
 *  Directory access routines.
 */


/*
 *  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;
extern char tmpstr[];
extern short debug;
static int olddta;
static FCB *fcb = 0;
static  struct InfoData *ID = 0L;
char wcstring[100];

/*
 *  Open directory, return first item.
 */
diropen(cp, p, dirdef)
UBYTE  *cp;
DIRDEF *dirdef;
DIRENT *p;
{
   long  result;
   if(fcb == 0) {
      fcb = (FCB *)AllocMem((long)sizeof(*fcb),
                                   (long)MEMF_PUBLIC|MEMF_CLEAR);
   }
   if(ID == 0) {
      ID = (struct InfoData *)AllocMem((long)sizeof(*ID),
                                   (long)MEMF_PUBLIC|MEMF_CLEAR);
   }

/*
 *  Get the first directory entry.
 */
   dirdef->lock = Lock(cp,ACCESS_READ);
   if(dirdef->lock == 0L) {
      p->size = -1;
      return (false);
   }
   if(Info(dirdef->lock,ID) == 0L) {
      /* If Info fails then the named file/device is NOT a disk */
      dirdef->size = 0L;
      dirdef->free = 0L;
      return(false);
   }
   else {
      dirdef->size =
              ((ID->id_BytesPerBlock*ID->id_NumBlocksUsed + 1023L) / 1024L);
      dirdef->free =
              ((ID->id_BytesPerBlock * ID->id_NumBlocks + 1023L) / 1024L)
                  - dirdef->size;
   }
   /* Examine this name to find out what it is - it MUST be a directory */
   if((result = Examine(dirdef->lock,fcb)) == 0L) {
      UnLock(dirdef->lock);
      p->size = -1;
      return (false);
   }
   if(fcb->fib_DirEntryType < 0) {  /* It's a file! That's WRONG! */
      UnLock(dirdef->lock);
      p->size = -1;
      return (false);
   }
   if(dirnext(p,dirdef))return(false);
   if(dodir(p)) return (true);
   return (false);
}
freefcb()
{
   if(fcb)FreeMem(fcb,(long)sizeof(*fcb));
   if(ID)FreeMem(ID,(long)sizeof(*ID));
}
/*
 *  Return first and succeeding filenames in the directory.
 *  And if a wildcard is specified only return the matching
 *  names.
 */

dirnext(p, dirdef)
DIRENT *p;
DIRDEF *dirdef;
{
   /* search for next filename in the directory */
   while(true) {
      if(ExNext(dirdef->lock,fcb) == 0L) {
         p->size    = -1;
         UnLock(dirdef->lock);
         return(1);
      }
      if (dodir(p)) {
         return(0);
      }
   }
}

dodir(p)
DIRENT *p;
{
   /* wcmatch checks wcstring against fcb->fib_FileName
      If the wildcard is null then everything matches it and
      wcmatch returns a true, otherwise it returns true only
      if the wcstring and filename match
   */
   if(wcmatch(&fcb->fib_FileName[0],&wcstring[0]) == 0)return(false);
   strcpy(p->name,&fcb->fib_FileName[0]);
   if(fcb->fib_DirEntryType >= 0) {  /*It's a directory */
      if(!match(p->name, "/")) {
         return (false);
      }
      if(port->mode & (local | sysop)) {
         strcat(p->name, "/");
      }
      else {
         return (false);
      }
   }
   /* return the size in Kb rounded up */
   p->size = (fcb->fib_Size+01777)>>10;
   return (true);
}

/*
 *  Modified form of getdir from original mbfile.c
 *  The amiga searches directories for wildcards in
 *  a different way than does the IBM. SO set it up
 *  for a wildcard match for the amiga.
 *
 */
extern DIRPATH *dphd;
DIRPATH *setdir(p)
char *p;
{
   register DIRPATH *dp;
   register char *cp,*pp;
   cp = p;
   pp = &wcstring[0];
   *pp = 0;
   for(dp = dphd; dp isnt NULL; dp = dp->next)
      if (dp->id is port->opt2)  {
         strcpy(port->line, dp->path);
         while(*cp)*pp++ = *cp++;
         *pp = 0;
         return dp;
      }
   port->msg = mndir;
   return NULL;
}
/* Check filename in *a against a possibly null wildcard string in *b */
wcmatch(a,b)
char *a,*b;
{
   register char *p,*q;
   p = a;
   q = b;
   /* If the wildcard is null then everything matches */
   if(*q == 0)return(1);
   if(*q == '*') {
      /* Leading wildcard * in the pattern */
      while(*p)p++;
      while(*q)q++;
      p--;
      q--;
      while(*q != '*') {
         if(toupper(*p) == toupper(*q)) {
            p--;
            q--;
            continue;
         }
         break;
      }
      if(*q == '*')return(1);
      return(0);
   }
   while(*p && *q && (*q != '*')) {
      if(toupper(*p) == toupper(*q)) {
         p++;
         q++;
         continue;
      }
      break;
   }
   if((*p == 0) && (*q == 0))return(1);
   if(*q == '*')return(1);
   return(0);
}
/* Check call or @bbs in *a against a wildcard string in *b
   Both are ln_call characters long and have trailing spaces added
*/

wmatch(a,b)
char *a,*b;
{
   register char *p,*q;
   register short i;
   char inname[ln_call+1],wildc[ln_call+1];

   /* copy the two input strings into temporary storage, removing the
      trailing blanks. This routine is obviously a slightly modified
      form of the directory wcmatch routine.
      The copy also forces both strings to upper case to save having
      to do it later.
   */
   p = a;
   q = inname;
   for(i = 0;i<ln_call;i++) {
      if(*p == ' ')break;
      *q++ = toupper(*p++);
   }
   *q++ = 0;
   p = b;
   q = wildc;
   for(i = 0;i<ln_call;i++) {
      if(*p == ' ')break;
      *q++ = toupper(*p++);
   }
   *q++ = 0;
   p = inname;
   q = wildc;
   /* If the wildcard is null then everything matches */
   if(*q == 0)return(1);
   if(*q == '*') {
      /* Leading wildcard * in the pattern */
      while(*p)p++;
      while(*q)q++;
      p--;
      q--;
      while(*q != '*') {
         if(*p == *q) {
            p--;
            q--;
            continue;
         }
         break;
      }
      if(*q == '*')return(1);
      return(0);
   }
   while(*p && *q && (*q != '*')) {
      if(*p == *q) {
         p++;
         q++;
         continue;
      }
      break;
   }
   if((*p == 0) && (*q == 0))return(1);
   if(*q == '*')return(1);
   return(0);
}
/* Check title in *a against a quoted string in *b */
/* If the string occurs anywhere in the title then
   return non-null.
*/
umatch(a,b)
char *a,*b;
{
   register char *p,*q,*r,*s;
   short i,j;
   if((i = strlen(a)) > 79) {
      i = 79;
      *(a+79) = 0;
   }
   if((j = strlen(b)) > 79) {
      j = 79;
      *(b+79) = 0;
   }
   j -= 2;                 /* Don't count the quotes */
   if(j > i)return(0);     /* Quoted string is longer than title */
   r = a + i - j;
   for(p = a;p <= r;p++) {
      q = p;
      s = b+1;             /* Skip the quote */
      while(*s && (*s != '"')) {
         if(toupper(*q) != *s)break;      /* The string is already upper */
         q++;
         s++;
      }
      if((*s == '"') || (*s == 0))return(1);
   }
   return(0);
}
kill_list()
{
   register int from,to,i;
   register PORTS *p;
   p = port;
   ioport(cport);
   if(!num(port->fld[1]) || !num(port->fld[2])) {
      port->msg = mwhat;
      ioport(p);
      return;
   }
   from = atoi(port->fld[1]);
   to = atoi(port->fld[2]);
   if((from < 1) || (to < 1) || (from >= to)) {
      port->msg = mwhat;
      ioport(p);
      return;
   }
   sprintf(tmpstr,"Delete messages from #%d to #%d\n",from,to);
   outstr(tmpstr);
   if(sure())return;
/* Search forwards through the file to find the first message number
   The messages are more likely to be near the front of the file than
   the end. The end of the file has more recent messages.
   However, a binary search would be the best strategy and I'll put it in
   here when I have time.
*/
   check_mail();
   unlock_mail();
   for(i = 1; i <= mfhs->last ; i++)  {
      read_rec(mfl, i, (char *)port->mmhs);
/*
sprintf(tmpstr,"rec#%d = msg#%d\n",i,port->mmhs->number);
ttputs(tmpstr);
*/
      if (port->mmhs->number >= from) break;
   }
   if((port->mmhs->number < from) || (port->mmhs->number > to)) {
      outstr("No messages in the specified range\n");
      return;
   }
/* This re-reads the very first record but the loop is easier to
   write this way.
   Delete messages within the specified range.
*/
   for( ; i <= mfhs->last ; i++) {
      read_rec(mfl, i, (char *)port->mmhs);
      if (port->mmhs->number > to) break;

      /* Is it already dead? */
      if(port->mmhs->stat & m_kill) continue;

      /* Don't kill traffic this way. They must be done individually */
      if(port->mmhs->type is 'T')continue;

      sprintf(tmpstr,"%d",port->mmhs->number);
      outstr(tmpstr);
      outstr(" - Killed\n");

      port->mmhs->stat setbit m_kill;
      write_rec(mfl, i, (char *)port->mmhs);
      makehdr2();

   }
   sprintf(tmpstr,"from %d to %d",from,to);
   log('M', 'K', 'L', tmpstr);
   ioport(p);
   port->msg = mdone;
   titles();
}


char reject[TOT_REJECT][3][ln_call];
short num_reject = 0;

get_reject()
{
   /* This routine MUST be called before the window is opened */
   FILE *fp;
   register char *p,*q;
   register int fc,i;
   if((fp = fopen("reject.btn","r")) == NULL)return;
   while(fgets(&tmpstr[0],80,fp) != NULL) {
      p = tmpstr;
      if(*p == '\n')continue;
      fc = 0;
      while(1) {
         switch(*p) {
         case '<':         /* FROM field */
            p++;
            fc++;
            q = &reject[num_reject][2][0];
            pcall(q,p);
            break;
         case '@':         /* AT (BBS) field */
            p++;
            fc++;
            q = &reject[num_reject][1][0];
            pcall(q,p);
            break;
         case '>':         /* TO field */
            p++;
            fc++;
            q = &reject[num_reject][0][0];
            pcall(q,p);
            break;
         }
         while((*p != ' ') && (*p != '\n')  && *p)p++;
         if((*p == '\n') || (*p == 0))break;
         while(*p == ' ')p++;
      }
      if(fc == 0) {    /* No fields found .. don't use it */
         reject[num_reject][0][0] = 0;
         reject[num_reject][1][0] = 0;
         reject[num_reject][2][0] = 0;
         continue;
      }
      if(++num_reject > TOT_REJECT-1)break;
   }
   fclose(fp);
   if(num_reject > TOT_REJECT-1)num_reject = TOT_REJECT-1;
   printf("\nReject.btn list\n");
   /* This loop does not only prepare the reject list for printing.
      It also converts the fields to upper case. So do not delete
      the entire loop
   */

   for(fc = 0;fc < num_reject;fc++) {
      for(i=0;i<3;i++) {
         p = tmpstr;
         *p = 0;
         q = &reject[fc][i][0];
         while(*q && (*q != ' ') && (q < &reject[fc][i][ln_call])) {
            *q = toupper(*q);
            *p++ = *q++;
            *p = 0;
         }
         printf("%c%s ",">@<"[i],&tmpstr[0]);
      }
      printf("\n");
   }
   printf("\n");
}

test_reject()
{
   register short i;
   /* Allow sysop to send them out, but reject them from anyone else? */
   /* How about rejecting only when forwarding? */
   if(port->mode == local)return(0);
   for(i=0;i<num_reject;i++) {
      if(reject[i][0][0]) {
         if(!matchn(&reject[i][0][0],port->mmhs->to,ln_call))continue;
      }
      if(reject[i][1][0]) {
         if(!matchn(&reject[i][1][0],port->mmhs->bbs,ln_call))continue;
      }
      if(reject[i][2][0]) {
         if(!matchn(&reject[i][2][0],port->mmhs->from,ln_call))continue;
      }
      return(1);
   }
   return(0);
}
