/*
 * COMM1.C
 *
 * Matthew Dillon, August 1986
 *
 * version 2.05M (Manx Version and Additions) by Steve Drew 20-Jan-87
 *
 */

#include "shell.h"
typedef struct FileInfoBlock FIB;
 
#define DIR_SHORT 0x01
#define DIR_FILES 0x02
#define DIR_DIRS  0x04
#define DIR_EXCLUDE 0x08

#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
#define C_TO_BPTR(strtag, var)  ((struct strtag *)(((ULONG)var)>>2))

extern char *btocstr();
extern int has_wild;
char cwd[256];
struct FileLock *Clock;
  
do_sleep()
{
   register int i;
 
   if (ac == 2) {
      i = atoi(av[1]);
      while (i > 0) {
         Delay ((long)50*2);
         i -= 2;
         if (CHECKBREAK())
            break;
      }
   }
   return (0);
}
 
 
do_number()
{
   return (0);
}
 
do_cat()
{
   FILE *fopen(), *fi;
   int i;
   char buf[256];

   if (ac == 1) {
      while (gets(buf)) {
      	 if (CHECKBREAK()) break;
         puts(buf);
         }
      clearerr(stdin);
      return (0);
   }

   for (i = 1; i < ac; ++i) {
      if ((fi = fopen (av[i], "r")) != 0) {
           while (fgets(buf,256,fi)) {
            fputs(buf,stdout);
            fflush(stdout); 
            if (CHECKBREAK()) {
               breakreset();
               break;
            }
         }
         fclose (fi);
      } else {
         fprintf (stderr, "could not open %s\n", av[i]);
      }
   }
   return (0);
}

/* things shared with disp_entry */

int   filecount, col; 
long  bytes, blocks;

do_dir(garbage, com)
char *garbage;
{
   void   		disp_entry();
   struct DPTR          *dp;
   struct InfoData      *info;
   char                 *name;
   int                  i = 0, stat, clen, more;
   char                 options = 0;
   char                 *c;
   char			exclude[40];
   char                 lspec[256];
   char                 volume[40];
   char                 *volname();
   char			*dates();
  
   col = filecount = 0;
   bytes = blocks = 0L;
   
   while((++i < ac) && (av[i][0] == '-')) {
   	for (c = av[i]+1; *c ; c++) {
   		switch(*c) {
   			case 's':
   				options |= DIR_SHORT;
   				break;
   			case 'f':
   				options |= DIR_FILES;
   				break;
   			case 'd':
   				options |= DIR_DIRS;
   				break;
   			case 'e':
   				options |= DIR_EXCLUDE;
   				strcpy(exclude,"*");
   				strcat(exclude,av[++i]);
   				strcat(exclude,"*");
   				break;
   			default:
   				break;
   		}
   	}
   }
   
   if (ac == i) {
      ++ac;
      av[i] = "";
   if (has_wild)
      return(0);
   }
   if (!(options & (DIR_FILES | DIR_DIRS)))  options |= (DIR_FILES | DIR_DIRS);
   
   for (; i < ac; ++i) {
      if (!(dp = dopen (av[i], &stat)))
         continue;
      if (com < 0) {
         info = (struct InfoData *)AllocMem((long)sizeof(struct InfoData), MEMF_PUBLIC);
         if (Info (dp->lock, info)) {
            printf ("Unit:%2ld  Errs:%3ld  Used: %-4ld %3ld%% Free: %-4ld  Volume: %s\n",
                  info->id_UnitNumber,
                  info->id_NumSoftErrors,
                  info->id_NumBlocksUsed,
                  (info->id_NumBlocksUsed * 100)/ info->id_NumBlocks,
                  (info->id_NumBlocks - info->id_NumBlocksUsed),
                  volname(dp->lock,volume));

         } else {
            pError (av[i]);
         }
         FreeMem (info,(long) sizeof(*info));
         dclose(dp);
         continue;
         return(0);
      } 
 
     /* start of directory routine */
      
            c = av[i];
            clen = strlen(c);
            if (!stat || has_wild) {    /* if not wild and is a dir don't */
                                         /* extract dir from file name     */
               while (clen && c[clen] != '/' && c[clen] != ':') clen--;
               if (c[clen] == ':' || c[clen] == '/') clen++;
               c[clen] = '\0';
            }
            if (!clen)  c = cwd;
            if (strcmp (c, &lspec) != 0)  {
               strcpy(lspec, c);
               if (col)    printf("\n");
               printf ("Directory of %s\n", lspec);
               fflush(stdout);
               col = 0;
            } 
            more = stat;
            do {
            	if (more && !has_wild) {
            	    *lspec = '\0';
            	    if (!(more = dnext(dp, &name, &stat)))
            	    break;
            	}
                if (CHECKBREAK()) {
              	   i = ac;
              	   break;
                }
                disp_entry (dp->fib, options,exclude);
      } while(more && !has_wild);     
      dclose(dp); 
    }                /* end for */
   if (col)  printf("\n");    
   if (filecount > 1) {
       blocks += filecount;     /* account for dir blocks */
       printf (" %ld Blocks, %ld Bytes used in %d files\n", blocks, bytes, filecount);
   }
   return (0);
}

char *
volname(lock,buf)
struct FileLock *lock;
char *buf;
{

        struct    DeviceList    *dl;
        char                    *p;

     Forbid();
                /* Only way I know to get Volume label since InfoData  */
                /* seems to always have NULL for this string           */

        lock = BPTR_TO_C(FileLock, lock);
        dl = BPTR_TO_C(DeviceList, lock->fl_Volume);
        p = btocstr(dl->dl_Name,buf);

     Permit();
     return p;
}

void
disp_entry(fib, options, exclude)
char options;
char *exclude;
register struct FileInfoBlock *fib;
{

   char str[5];
   int italics;
   char s;   
   
   if (!(((options & DIR_FILES) && (fib->fib_DirEntryType < 0)) || 
         ((options & DIR_DIRS)  && (fib->fib_DirEntryType > 0))))
                return;

   if ((options & DIR_EXCLUDE) && (compare_ok(exclude,fib->fib_FileName)))
           return;
                
 if (!(options & DIR_SHORT)) { 
   str[4] = '\0';
   str[0] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r';
   str[1] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w';
   str[2] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'e';
   str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';

   printf ("   %-24s  %s  ", fib->fib_FileName, str);
   if (fib->fib_DirEntryType < 0) printf("%6ld %4ld", (long)fib->fib_Size, (long)fib->fib_NumBlocks);
    else printf("   Dir     ");
   printf("  %s", dates(&fib->fib_Date));
   fflush(stdout);
   } 
   else {
   
        if ((col == 3) && strlen(fib->fib_FileName)>18) {
            printf("\n");
            col = 0;
        } 
        if (fib->fib_DirEntryType > 0)  {
            printf ("\033[3m");
            italics = 1;
        }
        if (strlen(fib->fib_FileName)>18) {
            printf(" %-37s",fib->fib_FileName);
            col += 2;
        } 
        else { 
            printf(" %-18s",fib->fib_FileName);
            col++;
        } 
        if (col > 3) {
            printf("\n");
            col = 0;
        }
        if (italics) printf("\033[0m");
   }
   fflush(stdout);
   blocks += fib->fib_NumBlocks;
   bytes  += fib->fib_Size;
   filecount++;
   return;
}

/* converts dos date stamp to a time string of form dd-mmm-yy  */

char *
dates(dss)
struct DateStamp *dss;
{
   register struct tm tm;
   register long time, t;
   register int i;
   static char timestr[20];
   static char months[12][4] = {
   	"Jan","Feb","Mar","Apr","May","Jun",
   	"Jul","Aug","Sep","Oct","Nov","Dec"
   };
   static char days[12] = {
   	31,28,31,30,31,30,31,31,30,31,30,31
   };
   time = dss->ds_Days * 24 * 60 * 60 + dss->ds_Minute * 60 +
   				       dss->ds_Tick/TICKS_PER_SECOND;
   tm.tm_sec = time % 60; time /= 60;
   tm.tm_min = time % 60; time /= 60;
   tm.tm_hour= time % 24; time /= 24;
   tm.tm_wday= time %  7;
   tm.tm_year= 78 + (time/(4*365+1)) * 4; time %= 4 * 365 + 1;
   while (time) {
   	t = 365;
   	if ((tm.tm_year&3) == 0) t++;
   	if (time < t) break;
   	time -= t;
   	tm.tm_year++;
   }
   tm.tm_yday = ++time;
   for (i=0;i<12;i++) {
   	t = days[i];
   	if (i == 1 && (tm.tm_year&3) == 0) t++;
   	if (time <= t) break;
   	time -= t;
   }  
   tm.tm_mon = i;
   tm.tm_mday = time;
   
   sprintf(timestr,"%02d-%s-%2d %02d:%02d:%02d\n",tm.tm_mday,
   		months[tm.tm_mon],tm.tm_year,
   		tm.tm_hour,tm.tm_min,tm.tm_sec);
   return(timestr);
   
}
 
date()
{
   struct   DateStamp   dss;
   char *s, *dates();

   DateStamp(&dss);
   s = dates(&dss);
   printf("%s",s);
   return(0);
}
 
do_quit()
{
   if (Src_stack) {
      Quit = 1;
      return(do_return());
   }
   main_exit (0);
}
 
 
do_echo(str)
char *str;
{
   register char *ptr;
   char nl = 1;
 
   for (ptr = str; *ptr && *ptr != ' '; ++ptr);
   if (*ptr == ' ')
      ++ptr;
   if (av[1] && strcmp (av[1], "-n") == 0) {
      nl = 0;
      ptr += 2;
      if (*ptr == ' ')
         ++ptr;
   }
   printf("%s",ptr);
   fflush(stdout);
   if (nl)
      printf("\n");
   return (0);
}

do_source(str)
char *str;
{
   register FILE *fi;
   char buf[256];

   if (Src_stack == MAXSRC) {
      printf (stderr,"Too many source levels\n");
      return(-1);
   }
   if ((fi = fopen (av[1], "r")) == 0) {
      fprintf (stderr,"Cannot open %s\n", av[1]);
      return(-1);
   }   
   set_var(LEVEL_SET, V_PASSED, next_word(next_word(str)));
   ++H_stack;
   Src_pos[Src_stack] = 0;
   Src_base[Src_stack] = (long)fi;
   ++Src_stack;
   while (fgets (buf, 256, fi)) {
      buf[strlen(buf)-1] = '\0';
      Src_pos[Src_stack - 1] += 1+strlen(buf);
      if (Verbose)
         fprintf(stderr,"%s\n",buf);
      exec_command (buf);
      if (CHECKBREAK())
         break;
   }
   --H_stack;
   --Src_stack;
   unset_level(LEVEL_LABEL + Src_stack);
   unset_var(LEVEL_SET, V_PASSED);
   fclose (fi);
   return (0);
}

/*
 * CD
 *
 * CD(str, -1)      -do pwd and display current cd. if str = NULL don't disp.
 * CD(str, 0)       -do CD operation.
 *
 *    standard operation: breakup path by '/'s and process independantly
 *    x:    -reset cwd base
 *    ..    -remove last cwd element
 *    N     -add N or /N to cwd
 */

do_cd(str, com)
char *str;
{
   char sc, *ptr;
   char *name;

   if (com < 0) {
      struct FileLock *lock, *newlock;
      FIB *fib;
      int i, len;

      fib = (FIB *)AllocMem((long)sizeof(FIB), MEMF_PUBLIC);
      if ((Clock = (struct FileLock *)Myprocess->pr_CurrentDir) == 0) 
          attempt_cd(":"); /* if we just booted 0 = root lock */
      lock = (struct FileLock *)DupLock(Clock);
      cwd[i = 255] = '\0';
      
      while (lock) {
         newlock = (struct FileLock *)ParentDir(lock);
         Examine(lock, fib);
         name = fib->fib_FileName;
         if (*name == '\0')            /* HACK TO FIX RAM: DISK BUG */
            name = "ram";
         len = strlen(name);
         if (newlock) {
            if (i == 255) {
               i -= len;
               bmov(name, cwd + i, len);
            } else {
               i -= len + 1;
               bmov(name, cwd + i, len);
               cwd[i+len] = '/';
            }
         } else {
            i -= len + 1;
            bmov(name, cwd + i, len);
            cwd[i+len] = ':';
         }
         UnLock(lock);
         lock = newlock;
      }
      FreeMem(fib, (long)sizeof(FIB));
      bmov(cwd + i, cwd, 256 - i);
      if (str)
         puts(cwd);
      set_var(LEVEL_SET, V_CWD, cwd);
 
     /* put the current dir name in our CLI task structure */

      ptr = (char *)((ULONG)((struct CommandLineInterface *)
          BADDR(Myprocess->pr_CLI))->cli_SetName << 2);
      ptr[0] = strlen(cwd);
      movmem(cwd,ptr+1,(int)ptr[0]);
      return (0);
   }
   str = next_word(str);
   if (*str == '\0')
      puts(cwd);
   str[strlen(str)+1] = '\0';          /* add second \0 on end */
   while (*str) {
      for (ptr = str; *ptr && *ptr != '/' && *ptr != ':'; ++ptr);
      switch (*ptr) {
      case ':':
         sc = ptr[1];
         ptr[1] = '\0';
         if (attempt_cd(str))
            strcpy(cwd, str);
         ptr[1] = sc;
         break;
      case '\0':
      case '/':
         *ptr = '\0';
         if (strcmp(str, "..") == 0 || str == ptr)
            str = "/";
         if (*str && attempt_cd(str)) {
            if (*str == '/') {
               rmlast(cwd);
            } else {
               if (cwd[0] == 0 || cwd[strlen(cwd)-1] != ':')
                  strcat(cwd, "/");
               strcat(cwd, str);
            }
         }
                            #k                           $g     = wqwp  Áwwp  Uwwp   wwpU   wp4Ipw   pwwp*/wqwp  ÁpsEsp    CHECKIT                           %x                           
X                            i                           T                           **                           **                           *                            )t                                                        4h                                                        **                           **                           )t                           .i                           .t                           ;                            #r                           4I                           %f                           o                           -[                           -[                           -[                           B                           n                           0t                           2i                           e                           %m                           %m                           4I                           #r                           c                           c                                                        +g                           &t                           /p                           e                           n                           0t                            N                            s                           e                           5t                            =                           
}                           **                           **                           /w                            M                           /*                            s                           %                            / < ?>>8<~?8*~?>>8x8*8?>>88x<*?>>8x?[?>>8<~??0?>8<<<?ge = 0;     8                    .H                    E`   f`                   = nfg                    2 `ffc                   imacf`                   * laff`                   4 l`c                   2                          .u                            4henu[1].M                            /                           */                           0                           %m                           5                             =                           %n                           'h                           N                           &er Mode       /* text for menu-bar display */
menu[2].FirstItem = &XFItem[0];    /* pointer to first item in list */

menu[3].NextMenu = NULL;
menu[3].LeftEdge = 255;
menu[3].TopEdge = 0;
menu[3].Width = 85;
menu[3].Height = 10;
menu[3].Flags = MENUENABLED;
menu[3].MenuName = "Script";        /* text for menu-bar display */
menu[3].FirstItem = &ScriptItem[0];    /* pointer to first item in list */
}

     ze = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
   *leftover = '\0';
   rpt = 0;
   eof = 0;
   while (!eof) {
      next = getc(fp);
      if (next == EOF) {
         first = -1;
         eof   =  1;
         }
      else totbytes++;
      osize = size;
      encode(t);
      t = next;
      if (size == spsiz-3) return(size);
      if (size > spsiz-3) {
         for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) ;
         size = osize;
         msgpkt[size] = '\0';
         return(size);
         }
      }
   return(size);
   }

void encode(a)
char a;
   {
   int a7,b8;

   if (p_mode == 1 && a == '\n') {
      rpt = 0;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\r');
      if (size <= spsiz-3) osize = size;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\n');
      msgpkt[size]   = '\0';
      return;
      }
   if (rptflg) {
      if (a == next && (first == 0)) {
         if (++rpt < 94) return;
         else if (rpt == 94) {
            msgpkt[size++] = rptq;
            msgpkt[size++] = tochar(rpt);
            rpt = 0;
            }
         }
      else if (rpt == 1) {
         rpt = 0;
         encode(a);
         if (size <= spsiz-3) osize = size; 
         rpt = 0;
         encode(a);
         return;
         }
      else if (rpt > 1) {
         msgpkt[size++] = rptq;
         msgpkt[size++] = tochar(++rpt);
         rpt = 0;
         }
      }
   a7 = a & 0177;
   b8 = a & 0200;
   if ((a7 < SP) || (a7==DEL)) {
      msgpkt[size++] = quote;
      a = ctl(a);
      }
   if (a7 == quote) msgpkt[size++] = quote;
   if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
   msgpkt[size++] = a;
   msgpkt[size] = '\0';
   }

void decode()
   {
   USHORT  a, a7;
   char *buf;

   buf = msgpkt;
   rpt = 0;
   
   while ((a = *buf++) != '\0') {
      if (rptflg) {
         if (a == rptq) {
            rpt = unchar(*buf++);
            a = *buf++;
            }
         }
      if (a == quote) {
         a  = *buf++;
         a7 = a & 0177;
         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
         }
      if (rpt == 0) rpt = 1;
      if (p_mode == 1 && a == '\r') continue;
      totbytes += rpt;
      for (; rpt > 0; rpt--) putc(a, fp);
      }
   return;
   }

void spar(data)
char data[];
   {
   data[0] = tochar(MAXPACKSIZ);
   data[1] = tochar(TTIME_LONG);
   data[2] = tochar(MYPAD);
   data[3] = ctl(MYPCHAR);
   data[4] = tochar(MYEOL);
   data[5] = MYQUOTE;
   data[6] = 'N';
   data[7] = '1';
   data[8] = MYRPTQ;
   data[9] = '\0';
   }

void rpar(data)
char data[];
   {
   spsiz   = unchar(data[0]);
   timint  = unchar(data[1]);
   pad     = unchar(data[2]);
   padchar = ctl(data[3]);
   eol     = unchar(data[4]);
   quote   = data[5];
   rptflg  = 0;
   if (data[6] == 0) return;
   if (data[7] == 0) return;
   if (data[8] == 0) return;
   rptq    = data[8];
   rptflg  = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177));
   }

saybye()
  {
  int len,num;
  shutdown = 0;
  spack('G',n,1,"F");  /* shut down server no more files */
  rpack(&len,&num,ackpkt);
  }

statusline()
  {
  emits ("\nFile:                 Pckt:   Pckt No:      Retrn:    Bytes:         Stat:      ");
  x = 48;
  curmode = 1;
  emits (filnam);
  return(0);
  }

dostats(type)
char type;
  {
   if (type != 'Y' && type != 'N' && type != 'G') {
      x = 224;
      emit(type);
      x = 312;
      sprintf(snum,"%4d",n+(tp * 64));
      emits(snum);
      if (n==63) tp++;
      x = 408;
      sprintf(snum,"%2d",retry-1);
      emits(snum);
      x = 488;
      sprintf(snum,"%6ld",(long)totbytes);
      emits(snum);
      }
  }

/* allow for multi file xfers separated by commas under kermit and XMODEM */

multi_xfer(name,mode,do_send)
char *name;
int (*mode)();
int do_send;
    {
    int done = 0;
    int status;
    char *p;
    
    p = name;  
    while(*p && *p != ',')   p++;
    if (*p == '\0') { 
         done = TRUE; 
         if (multi == 1) multi++;
         }
     else multi = 1;
    *p = '\0';
    status = ((*mode)(name, multi));
    if (status == TRUE) {
        if (do_send) emits("Sent File: ");
          else emits("Received File: ");
    	emits(name);
    	emits("\n");
    	emit(8);
        }
    else if (status == FALSE)
        {
        close(fd);
        if (do_send) emits("Send Failed: ");
          else emits("Receive Failed: ");
        emits(name);
        emits("\n");	
        emit(8);
        }    
    if (!done) multi_xfer(++p, mode, do_send);
    server = 0;
    multi = 0;
    }

/* gobble up all garb that we received while getting file name strings */

eatup()
   {
  while(CheckIO(Read_Request))  {
     	WaitIO(Read_Request);
     	BeginIO(Read_Request);
        }
   }   

 */
      LL             /* nextselect */
};

struct Menu MyMenu = {
   NULL,          /* pointer to next menu */
   0,0,150,0,     /* left,0,Width,0 */
   MENUENABLED,   /* flags */
   "SpeachToy Menu",   /* menu name */
   &MyMenuItem    /* First Item in list */
};

struct IntuiText ReqText1 = {
   BLUP,         /* Front Pen */
   WHTP,         /* Back pen */
   JAM2,         /* Draw Mode */
   5,            /* Left Edge */
   23,           /* Top */
   &TestFont,    /* pointer to TextFont */
   "Version 1.1  21 Dec, 1985",  /* text */
   NULL          /* next */
};
struct IntuiText ReqText2 = {
   BLUP,         /* Front Pen */
   WHTP,         /* Back pen */
   JAM2,         /* Draw Mode */
   5,            /* Left Edge */
   13,           /* Top */
   &TestFont,    /* pointer to TextFont */
   "Freeware - Public Domain ", /* text */
   &ReqText1     /* next */
};
struct IntuiText ReqText3 = {
   BLUP,         /* Front Pen */
   WHTP,         /* Back pen */
   JAM2,         /* Draw Mode */
   5,            /* Left Edge */
   3,            /* Top */
   &TestFont,    /* pointer to TextFont */
   "Written by David M Lucas ", /* text */
   &ReqText2     /* next */
};

struct IntuiText OKIText = {
   BLUP, WHTP, /* FrontPen, BackPen */
   JAM2,       /* DrawMode *     `          , nf`fn`       `      *o`fogcoam`fff`cf`fo o*laf`l`fgf` c` laf`fl`gcccc`xtlc`c````u                       
s        }        ff ff`     dog	fgf`` fffafc gofinffffc 	f`````mmffp0gc f``llffst falcO                       3t        `        -1a`   `      `        )laacc         |၀fc fffff`         Iafcg`        < aac `f fa        |``fac        F                         /p cc a `  .t afffc`a   ,  agfag	a`t aǇ` aa`ffbS ` `	a`gTi ff`afl  cc灀coi                                               4e `     `                  g              )z fcff c               , fcfc                .t gf``f             H g             2e                          3t        `          =        `   `            gc         %  fff`cff`         H fff`g`         
  fff`cfa         / c`c        I                           ,                           *                            D                           S                           M                           ,                           2                                                          f       wqwp  Áwwp  Lwwp   wwp4e   wp  pw   pwwp4Mwqwp  Áps,sp    640, 20                           %a                                                         a                           ,e                           h                            *                           0                           
                             0                            0                           00                           00                     