/*
  Login.c

    Original sources from Getty which is
         (c)Copyright 1989, Matthew Dillon, All Rights Reserved

$Header: Welmat:src/RCS/login.c,v 1.13 93/01/23 16:08:36 rwm Exp Locker: rwm $
 */

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/devices.h>
#include <devices/timer.h>
#include <devices/serial.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <hardware/cia.h>
#include <stdio.h>
/* #include <stdlib.h> */
#include <proto/all.h>
#include "pwd.h"

extern int     LogToStdout;
extern int     LogLevel;
extern char    *LogProgram;
extern char    *LogHost;
extern char    *LogWho;
extern char    *LogFile;

UBYTE vers[] = "$VER: 0.33 $Id: login.c,v 1.13 93/01/23 16:08:36 rwm Exp Locker: rwm $";

#define arysize(ary)    (sizeof(ary)/sizeof((ary)[0]))

typedef struct IORequest    IOR;
typedef struct timerequest  IOT;
typedef struct IOExtSer     IOSER;
typedef struct MsgPort	    PORT;
typedef struct List	    LIST;
typedef struct Node	    NODE;
typedef struct Message	    MSG;

extern int RunPasswdEntry();

char	*CopyRight = "---\r\n";
char	*ComPortName;

char	*DeviceName = "serial.device";
long	DeviceUnit  = 0;
long	NullFH;

PORT	*ComPort;
PORT	*TimerPort;	/*  Sink for IO reqs.	*/
long	TimerPortMask;
long	ComPortMask;

IOT	Iot;		/*  check-carrier	*/
IOSER	Iosr;		/*  serial read-req	*/
IOSER	Iosw;		/*  serial write-req	*/

char	IotIP;		/*  Iot0 in progress	*/
char	IosrIP;         /* serial read pending */

char	*LoginBuf;
char	PasswdBuf[33];
char	RxBuf[32];
char	HavePasswd;

short	Index;
short	BIndex;

int     ASDG_DSB;
int     INTERNAL;
int     NoCheckBad;
int     UnLockedb;

void	SerPuts();
void	xexit();
void    ClearRecv();

CXBRK()
{
    return(0);
}

void SetUp(av,ac)
char *av[];
int ac;
{
    int uunamel,i,j,k,u;
    char c;

    fflush(stdout);

    if ((LoginBuf=(char *)malloc(33))==NULL) xexit(8);

    LogWho = LoginBuf;
    LogFile = "login.log";
    PasswdFile = "Passwd";
    ASDG_DSB=INTERNAL=FALSE;
    NoCheckBad=FALSE;
    IotIP=FALSE;
    IosrIP=FALSE;
    u=0;
    DeviceName = "serial.device";
    DeviceUnit  = 0;
 
    if((ac<2)) {
     usage:
      printf("Usage: %s [-internal] [-asdg] [-lower] [-nocheckbad] [-p<passwd file>] [-o<logfile>] [-d<device>] [-u<unit>] [-b<modembaud>] person\n",av[0]);
      xexit(2);
    }
   
    i = 1;
    uunamel = FALSE;

    while (ac>1) {      
      if (av[i][0] == '-') {
         switch(av[i][1]) {
           case 'a':
           case 'A':   
               ASDG_DSB=TRUE;
               break;
           case 'i':
           case 'I':   
               INTERNAL=TRUE;
               break;
           case 'n':
           case 'N':   
               NoCheckBad=TRUE;
               break;
           case 'l':
           case 'L':
               uunamel=TRUE;
               break;
           case 'd':
           case 'D':
               DeviceName = &av[i][2];
               break;
           case 'u':
           case 'U':
               DeviceUnit  = atoi(&av[i][2]);
               break;
           case 'b':
           case 'B':
               UnLockedb  = atoi(&av[i][2]);
               break;
           case 'o':
           case 'O':
               LogFile = &av[i][2];
               break;
           case 'p':
           case 'P':
               PasswdFile = &av[i][2];
               break;
           default:
               goto usage;
               break;   

           }
        } else if (u != 0) {
             goto usage;
        } else {
              u=i;
        }
        i++;
        ac--;        
    }  /* End of While */

    /* Do some Sanity Checks on LoginBuf */

    j=k=0;
    while ( (c=(av[u][j])) && (j<32) ) {
      if (!( ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z')) ||

             ((c>=32)&&(c<=64)) )) 
  /*  space ! " # $ % & ' ( ) * + , - . / 0-9 : ; < = > ? @ */

         c=-1;
      if ( uunamel && ((c>='A')&&(c<='Z')) ) c=c-('A'-'a');

      if (c!=-1) LoginBuf[k++]=c;
      j++;
    }
    LoginBuf[k]=0;
    if (k<1) goto usage;

    TimerPort = CreatePort(NULL, 0);
    ComPort = CreatePort(NULL, 0);

    TimerPortMask = 1 << TimerPort->mp_SigBit;

    ComPortMask = 1 << ComPort->mp_SigBit;

    NullFH = Open("NULL:", 1006);
    if (NullFH == NULL) {
	ulog(-1, "LOGIN REQUIRES NULL: HANDLER!");
	puts("Requires NULL: handler!");
	xexit(3);
    }
    freopen("NULL:", "r", stdin);
    freopen("NULL:", "w", stdout);
    freopen("NULL:", "w", stderr);

    /*
     *	Timer Device
     */

    Iot.tr_node.io_Message.mn_ReplyPort = TimerPort;
    if (OpenDevice("timer.device", UNIT_VBLANK, &Iot, 0)) {
	Iot.tr_node.io_Device = NULL;
	xexit(4);
    }
    Iot.tr_node.io_Command = TR_ADDREQUEST;

    /*
     *	SERIAL.DEVICE
     */

    Iosr.IOSer.io_Message.mn_ReplyPort = ComPort;

    Iosr.io_SerFlags = SERF_XDISABLED | SERF_SHARED;
    if (OpenDevice(DeviceName, DeviceUnit, &Iosr, 0)) {
	Iosr.IOSer.io_Device = NULL;
	xexit(5);
    }

    Iosw = Iosr;
}

void SetUpTimeout(secs)
int secs;
{
    Iot.tr_time.tv_secs = secs;
    Iot.tr_time.tv_micro= 0;
    IotIP = 1;
    SendIO(&Iot);
}

int ProcessChar(c) 
char c;
{
  ulog(2, "Rx %02x %c", c, (c < 32) ? ' ' : c);
  c &= 0x7F;

  switch(c) {
    case 0:
      break;
    case 10:
    case 13:
      PasswdBuf[Index] = 0;
      Index = 0;
      SerPuts("\r\n");
      ulog(1, "Password: %s", PasswdBuf);
      return(1);
      break;

    default:
      if (Index == 31)
      break;
      PasswdBuf[Index++] = c;
      break;
    }
  return(0);
}


int GetChar()
{
  long mask;
  IOR  *ior;

  if (!IosrIP) {
    Iosr.IOSer.io_Command = CMD_READ;
    Iosr.IOSer.io_Data = (APTR)RxBuf;
    Iosr.IOSer.io_Length = 1;
    SendIO(&Iosr);
    IosrIP = TRUE;
  }

  mask = Wait(SIGBREAKF_CTRL_C | TimerPortMask | ComPortMask);

  if (mask & SIGBREAKF_CTRL_C) {
    xexit(6);
  }  
  
  if (mask & TimerPortMask) {
    WaitPort(TimerPort);
    IotIP=0;
    xexit(7);
  }

  if(mask & ComPortMask) {
    while((ior=(IOR *)GetMsg(ComPort))!=NULL) {
      if (ior == (IOR *)&Iosr) {
        IosrIP = FALSE;
      }
    }
  }

  if(!IosrIP) {
    return((int)RxBuf[0]);
  }
  else {
    AbortIO(&Iosr);
    WaitIO(&Iosr);
    IosrIP = FALSE;
    return(EOF);
  }
}

void
LoginFailed()
{
  char tempstring[255];

  Delay(100);        
  ulog(-1, "Login Failed user=%s pass=%s", LoginBuf, PasswdBuf);
  sprintf(tempstring,"\r\nLogin Failed:  User=\"%s\"\r\n"
           ,LoginBuf); 
  SerPuts(tempstring);
  xexit(1);
}

void main(ac, av)
char *av[];
int ac;
{
  char c;
  int state;

  SetUp(av,ac);
   
  /*
   *	Run Operation
   */

    
  PasswdBuf[0] = 0;

    /*
     *  If no password required, else request
     *  password.
     */


    if ((state=CheckLoginAndPassword())==1) {
	HavePasswd = 1;
	Index = 0;
        xexit(RunPasswdEntry(Iosr.io_Baud,Iosr.io_SerFlags));
    } else if (state != 3) {
        SerPuts("Password: ");
	ulog(1, "Getty, Passwd");
	HavePasswd = 0;
	Index = 0;
    } else LoginFailed();

  SetUpTimeout(80);


  /* Now get the password */

  while((c=GetChar())!=EOF) {
    HavePasswd=ProcessChar(c);
    
    if (HavePasswd) {
      if ((state=CheckLoginAndPassword())==1) {
        ulog(-1, "login %s", LoginBuf);
        xexit(RunPasswdEntry(Iosr.io_Baud,Iosr.io_SerFlags));
       } else if (state==2) {
        ulog(-1, "loginName:%s Pass:%s", LoginBuf, PasswdBuf);
        xexit(RunPasswdEntry(Iosr.io_Baud,Iosr.io_SerFlags));
       }
       else LoginFailed();
    }
  }
  xexit(9);
}


void
xexit(code)
int code;
{

    if (IotIP) {
	AbortIO(&Iot);
	WaitIO(&Iot);
    }
    if (Iot.tr_node.io_Device) {
	CloseDevice(&Iot);
    }
    if (IosrIP) {
	AbortIO(&Iosr);
	WaitIO(&Iosr);
    }
    if (Iosr.IOSer.io_Device) {
	CloseDevice(&Iosr);
    }
    if (TimerPort) {
	DeletePort(TimerPort);
    }
    if (NullFH) {
	Close(NullFH);
    }
    if (LoginBuf!=NULL) free(LoginBuf);

    exit(code);

  /* 
     0 - Program ran OK, password OK.
     1 - Password In-correct.
     2 - Wrong number of Arguments. (== 3)
     3 - Null Handler not found.
     4 - Could not open timer device.
     5 - Could not open serial device.
     6 - Break Signal Detected.
     7 - Timeout occured
     8 - Couldn't allocate LoginBuf
     9 - Couldn't open redirection files
  */
}

void
SerPuts(str)
char *str;
{
    Iosw.IOSer.io_Command = CMD_WRITE;
    Iosw.IOSer.io_Data = (APTR)str;
    Iosw.IOSer.io_Length = strlen(str);
    DoIO(&Iosw);
}


/* DTR.c -- handle DTR */
/****************************************/
/* Set com DTR line                     */
/* FALSE = DTR off; TRUE = dtr on       */
/****************************************/

void SetInternalDTR(ios,set)
IOSER *ios;
int set;
{
  struct CIA *Ciab;

#ifdef DTR_DEBUG
  printf("DTR is %d\n",set);
#endif

  Ciab=(struct CIA *)0xBFD000;
  Disable();
  Ciab->ciaddra |= CIAF_COMDTR;            /* Set DTR as output */
  if (set) Ciab->ciapra &= ~CIAF_COMDTR;   /* Set DTR low */
  else Ciab->ciapra |=  CIAF_COMDTR;       /* Set DTR high */

  Enable();
}

/****************************************************/
/* ASDG Dual Serial Board (and presumably 4 board)  */
/*  DTR control support.                            */
/****************************************************/
#define SIOCMD_SETCTRLLINES 0x10
#define SIOB_RTSB  0
#define SIOB_DTRB  1
#define SIOB_RTSF  (1<<SIOB_RTSB)
#define SIOB_DTRF  (1<<SIOB_DTRB)

void SetAsdgDTR(ios,set)
IOSER *ios;
int set;
{
  ios->IOSer.io_Command=SIOCMD_SETCTRLLINES;
  ios->IOSer.io_Offset=SIOB_DTRF;
  if(set==TRUE) {
    ios->IOSer.io_Length=SIOB_DTRF;
  }
  else {
    ios->IOSer.io_Length=0;
  }
  DoIO(ios);
}

/*************************************************/


void
SerHangup()
{
  if(!ASDG_DSB && !INTERNAL) return;  /* no DTR support */

  if(ASDG_DSB)
    SetAsdgDTR(&Iosw,FALSE);
  else 
    SetInternalDTR(&Iosw,FALSE);
  
  Delay(30);
  
  if(ASDG_DSB) 
    SetAsdgDTR(&Iosw,TRUE);
  else
    SetInternalDTR(&Iosw,TRUE);
  Delay(60);
}
