******************************************************************
*                                                                *
         nam   Login
         ttl   Program Module       
*                                                                *
* This is a Y2K-compliant revision of the 'login' module         *
* supplied with the OS9 Level 2 Development Pack.  The welcome   *
* screen displays the current date with a 4-digit year in the    *
* range 1900-2155.  Revision by Richard S. Bair, April 15, 1999. *
*                                                                *
******************************************************************
*
         ifp1
         use   /dd/defs/os9defs
         endc
*
         mod  CSIZE,NAME,TYPE,ATRV,START,DSIZE
NAME     fcs  /Login/
EDITION  fcb  $10
TYPE     set  Prgrm+Objct
REVS     set  $02
ATRV     set  ReEnt+REVS
*
* variable storage area
*
NARWFLAG rmb  1 default = 0 (wide display)
PSWDPATH rmb  1 path # of password file
MOTDPTHN rmb  1 path # of MOTD file
ATTEMPTS rmb  1 tally of password attempts
PROCSNUM rmb  1 process # assigned by OS9
PRIORITY rmb  1 priority (from password file)
PWFLNPTR rmb  2 points to line from pw file
INSTRPTR rmb  2 points to input string area
OTSTRPTR rmb  2 points to output string area
LDNG0FLG rmb  1 leading zero flag when clear
DATEPCKT rmb  6 date/time data packet area
         rmb  $FA stack space
STACK    equ  .
PSWDFLIN rmb  $80 password file entry
INSTRING rmb  $50 input string space
OUTSTRNG rmb  $50 output string space
PD.OPTSP rmb  $20 space for SS.OPT data
PD.EKO   equ  $04
DSIZE    equ  .
*
* storage space for constants
*
PASSWPTH fcc  "SYS/PASSWORD"
         fcb  $0D
WIDEHEDR fcb  $0A
         fcb  $0A
         fcc  /OS-9 Timesharing system/
         fcb  $0A
         fcc  /Level II  RS VR. 02.00.01/
         fcb  $0A
WDHDRLEN equ  *-WIDEHEDR
NARWHEDR fcb  $0A
         fcb  $0A
         fcc  /OS-9 Level II  RS Vr02.00.01/
         fcb  $0A
NRHDRLEN equ  *-NARWHEDR
NAMEQ    fcb  $0A
         fcc  /User name?: /
NAMEQLEN equ  *-NAMEQ
WHO      fcc  /Who?/
         fcb  $0D
PASSWRDQ fcc  /Password: /
PSWDQLEN equ  *-PASSWRDQ
INVALID  fcc  /Invalid password./
         fcb  $0D
PROCESS  fcb  $0A
         fcc  /Process #/
PROCSLEN equ  *-PROCESS
LOGGED1  equ  *
LOGGED2  fcc  / logged on /
LOGD1LEN equ  *-LOGGED1
         fcb  $0A
LOGD2LEN equ  *-LOGGED2
WELCOME  fcc  /Welcome!/
         fcb  $0D
NOTFOUND fcc  /Directory not found./
         fcb  $0D
SYNTXERR fcb  $0A
         fcc  /Syntax Error in password file/
KISSOFF  fcb  $0A
         fcc  /It's been nice communicating /
         fcc  /with you./
         fcb  $0A
         fcc  /Better luck next time./
         fcb  $0D
MOTDPATH fcc  "SYS/MOTD"
         fcb  $0D
ROOTPATH fcc  "/dd"
*
* code area
*
SGNLRUTN rti Bare minimum signal handler.
START    equ   *
         leas STACK,u Relocate the stack.
         pshs y,x Save these registers.
         leax <SGNLRUTN,pcr Point to signal handler.
         OS9  F$Icpt Have OS9 set it up.
         bcs  SKIP1 If error, skip to exit.
         ldy  #$0000 Set user i.d. to 0
         OS9  F$SUser through OS9.
SKIP1    puls y,x Restore these registers.
         lbcs EXIT Quit on error.
         clr  NARWFLAG Default = wide display.
         leay OUTSTRNG,u Point to outstring space,
         sty  OTSTRPTR record the pointer.
         leay INSTRING,u Point to instring space,
         sty  INSTRPTR record that pointer.
         std  ,--s Save params size on stack.
         beq  SKIP2 If no params, skip next part.
LOOP1    lda  ,x+ Get a byte from param string,
         sta  ,y+ transfer it to input string.
         cmpa #$0D Was it a carriage return?
         bne  LOOP1 If not, loop for another.
SKIP2    lda  #$01 For output,
         ldb  #SS.ScSiz find out the
         OS9  I$GetStt size of the display.
         bcc  SKIP3 Successful? Interpret result.
         cmpb #$D0 'Illegal request' error?
         beq  SKIP4 If so, go with default width.
         lbra ABORT Else abort.
SKIP3    cmpx #$0046 Display 70 columns or more?
         bcc  SKIP4 If so, leave flag at default.
         inc  NARWFLAG Else set it to 'narrow'.
SKIP4    lda  #$01 Access mode = 'read'
         leax ROOTPATH,pcr Point to '...... ',
         OS9  I$ChgDir get to root dir of disk.
         lda  #$01 Access mode still = 'read',
         leax PASSWPTH,pcr pathname is 'SYS/PASSWORD',
         OS9  I$Open now open that file.
         lbcs EXIT Exit on error.
         sta  PSWDPATH Record path number from OS9.
         lda  #$03 Three tries is the limit
         sta  ATTEMPTS for logging in.
         ldd  ,s++ Retrieve size of parm string.
         beq  DOTITLE If none then skip next steps.
         ldx  INSTRPTR Point to copy of parm string,
         lda  ,x get one byte.
         cmpa #$0D Is it a C.R.?
         bne  SKIP5 No? Skip title and prompt.
DOTITLE  tst  NARWFLAG What width display?
         beq  SKIP6 If wide, skip ahead.
         leax NARWHEDR,pcr Point to narrow title,
         ldy  #NRHDRLEN note its length,
         bra  SKIP7 skip wide setup steps.
SKIP6    leax WIDEHEDR,pcr Point to wide title,
         ldy  #WDHDRLEN note its length,
SKIP7    lbsr WRITHEDR write it and date out.
LOOP2    dec  ATTEMPTS Tally this login attempt,
         leax KISSOFF,pcr point to errmssge (in case),
         lbmi ERREXIT exit if too many attempts.
         leax INSTRING,u Else point to start of input
         stx  INSTRPTR string, record pointer.
         leax NAMEQ,pcr Point to username prompt,
         ldy  #NAMEQLEN note its length,
         lbsr PRMTNRED print it and get response.
         bcs  SAYWHO Input problem? Try 'Who?'.
SKIP5    lbsr VALIDATE Check for valid username.
         bcc  PSWDCHK If O.K., check password.
SAYWHO    leax WHO,pcr Else use second prompt,
LOOP3    lbsr WRITEWCR write it out,
         bra  LOOP2 loop back to retry input.
PSWDCHK  lbsr COMPARE Was password in usrname line?
         bcc  SETUSER If it's right, skip ahead.
         ldx  INSTRPTR Else look at next byte
         lda  ,x of input string.
         cmpa #$0D Is it a C.R.?
         bne  SAMENAME Check for duplicate username.
         lda  #$2C Otherwise replace it with
         sta  ,x+ a comma, advance the pointer
         stx  INSTRPTR and record its new value.
         lbsr ECHOOFF No echo for password entry.
         leax PASSWRDQ,pcr Point to 'Password: ',
         ldy  #PSWDQLEN note its length,
         lbsr PRMTNRED prompt and get user response.
         lbsr ECHOSET Turn echo back on.
         bcs  SAYWHO Retry if error.
         lbsr COMPARE Else examine response.
         bcc  SETUSER If a match, skip ahead.
SAMENAME leax INSTRING,u Else check remaining lines of
         stx  INSTRPTR password file for another
         lbsr LOOP4 entry w. same username.
         bcc  PSWDCHK If found, check passwd again.
         leax INVALID,pcr Else point to 'Invalid...',
         bra  LOOP3 write it and retry.
SETUSER  lda  PSWDPATH User identified;  close
         OS9  I$Close password file.
         lbsr DECTOBIN Evaluate user number,
         tfr  d,y have OS9
         OS9  F$SUser set it.
         lbsr DECTOBIN Get priority setting;
         tsta must be <256 --
         lbne SNTXEXIT abort if it's not.
         tstb Also must be >0;
         lbeq SNTXEXIT abort if it's not.
         stb  PRIORITY It's O.K.;  save it.
         OS9  F$ID Get process # from OS9,
         sta  PROCSNUM record it.
         lda  #$01 Access mode = 'read',
         leax MOTDPATH,pcr point to 'SYS/MOTD,
         OS9  I$Open open that file.
         bcc  SKIP8 If error, just
         clra set path number = 0.
SKIP8    sta  MOTDPTHN Else record actual one.
         lda  #$04 Access mode = 'execute'.
         bsr  SETDIR Set execution directory.
         lda  #$03 Access mode = 'write, read';
         bsr  SETDIR set data directory.
         leax PROCESS,pcr Point to 'Process # ',
         ldy  #PROCSLEN note its length,
         lbsr XFRSTRNG put it in the outstring.
         leax PROCSNUM,u Point to process # (binary),
         lbsr BINTODEC add to outstring (in dec).
         tst  NARWFLAG Narrow display?
         beq  SKIP9 If not, skip.
         leax LOGGED2,pcr Yes, so use extra linefeed.
         ldy  #LOGD2LEN Note length of string.
         bra  SKIP10 Skip over wide-display steps.
SKIP9    leax LOGGED1,pcr Wide-display statement --
         ldy  #LOGD1LEN note the length,
SKIP10   bsr  WRITHEDR add it + date/time to outstr.
         leax WELCOME,pcr Point to 'Welcome!',
         bsr  WRITEWCR write it to stdout.
         lbsr WRITMOTD Write Message of the Day.
         clrb ?
         ldx  PWFLNPTR Look at last field of pass-
         leau ,x word file line.
* x will point to the module name, u to possible parameter string.
LOOP5    lda  ,u+ Look at next byte.
         cmpa #$30 Part of module name?
         bcc  LOOP5 If so, loop for next byte.
         cmpa #$2C A comma?
         beq  LOOP6 If so, leave pointer past it.
         leau -$01,u Else back it up one byte.
LOOP6    lda  ,u+ Get a byte;
         cmpa #$20 is it a space?
         beq  LOOP6 Then skip past it.
         leau -$01,u Else back pointer up,
         pshs u save it momentarily,
         ldy  #$0000 and count the
LOOP7    lda  ,u+ remaining parameter
         leay $01,y bytes up to
         cmpa #$0D the carriage-return.
         bne  LOOP7 Loop 'til done.
         puls u Retrieve the start pointer,
         lda  PROCSNUM get the process #
         ldb  PRIORITY and the desired priority.
         OS9  F$SPrior Set the priority.
         ldd  #$0100
         OS9  F$Chain Transfer to shell or ??.
ABORT    OS9  F$PErr If chain fails, print error
EXIT     OS9  F$Exit and abort.
*
SETDIR   ldx  PWFLNPTR Point to directry pathstring,
         OS9  I$ChgDir  change to it.
         bcs  MSINGDIR Exit on error.
         ldx  PWFLNPTR Look at pwfile line again.
LOOP8    lda  ,x+ Get a byte.
         cmpa #$0D A carriage return?
         beq  SNTXEXIT Not good!  Error exit.
         cmpa #$2C A comma?
         bne  LOOP8 No? Loop 'til we find one.
         lda  #$20 Is next byte 
LOOP9    cmpa ,x+ a space?
         beq  LOOP9 Skip over it if so.
         leax ,-x Else back pointer up,
         stx  PWFLNPTR record it,
         rts and return.
MSINGDIR leax NOTFOUND,pcr Point to 'Dir. not found',
         bra  ERREXIT write message and return.
SNTXEXIT leax SYNTXERR,pcr Point to 'Syntax error..',
ERREXIT  bsr  WRITEWCR write it out,
         clrb carry out no error,
         OS9  F$Exit but exit.
*
WRITEWCR ldy  #$0100 Max. 256 bytes --
         lda  #$01 to stdout;
         OS9  I$WritLn write to first C.R.
         rts and return.
*
WRITHEDR bsr  XFRSTRNG Add this string to outstr.,
         lbsr ADDSPACE Add
         lbsr ADDSPACE three
         lbsr ADDSPACE spaces,
         lbra DATETIME append date/time and return.
*
XFRSTRNG lda  ,x+ Get a byte,
         lbsr ADDBYTE add it to outstring,
         leay -$01,y count down # of bytes,
         bne  XFRSTRNG loop until finished.
         rts Then return.
*
PRMTNRED bsr  XFRSTRNG Transfer prompt to outstring,
         lbsr WRITEOUT write it out.
         ldx  INSTRPTR Point to instring area,
         ldy  #$0050 read max 80 bytes
         clra from stdin
         OS9  I$ReadLn via OS9,
         rts and return.
ECHOOFF  pshs x,b,a Save registers,
         leax PD.OPTSP,u point to data storage area.
         ldb  #$00 Code for SS.OPT.
         clra Path is stdin;
         OS9  I$GetStt Get option data pack.
         bcs  SKIP11 If error, take error exit.
         lda  ,x Get PD.DTP (device class).
         cmpa #$00 Is is a SCF-type device?
         bne  SKIP11 If not, abort.
         lda  PD.EKO,x Else get PD.EKO byte,
         pshs a save it temporarily,
         clr  PD.EKO,x set image to 'no echo',
         bsr  ECHOSET write that image to OS9.
         puls a Get the original value back
         sta  PD.EKO,x and restore image for later.
         puls a,b,x,pc Restore registers, return.
SKIP11   lda  #$FF Set flag: echo not changed;
         sta  ,x no need to restore it.
         puls a,b,x,pc Restore and return.
*
ECHOSET  pshs x,b,a,cc Save registers,
         leax PD.OPTSP,u point to data image.
         lda  ,x Check flag:
         cmpa #$00 If not zero, no need
         bne  SKIP12 to restore data;  exit.
         ldb  #$00 Else send the original
         clra data packet back
         OS9  I$SetStt through OS9.
SKIP12   puls cc,a,b,x,pc Restore and return.
*
VALIDATE pshs u Save register, get
         lda  PSWDPATH path # of password file.
         ldx  #$0000 Rewind to beginning
         leau ,x (if necessary),
         OS9  I$Seek have OS9 reset pointer.
         puls u Restore register.
LOOP4    lda  PSWDPATH Get password file path #,
         leax PSWDFLIN,u point to string space for it.
         ldy  #$0080 Max. 128 bytes:
         OS9  I$ReadLn get a line.
         bcs  SKIP13 Return on error.
         stx  PWFLNPTR Save location pointer.
         bsr  COMPARE Compare to user response.
         bcs  LOOP4 If no match, try next line.
         stx  PWFLNPTR Else save current pointer
SKIP13   rts location and return.
*
COMPARE  ldx  PWFLNPTR Point to passwordfile line,
         ldy  INSTRPTR point to user response.
LOOP10   lda  ,x+ Get a byte from file line;
         cmpa #$2C a comma?
         beq  SKIP14 See if user did too.
         cmpa #$0D End of this line?
         lbeq SNTXEXIT No good!  Abort.
         eora ,y+ Compare with user byte.
         anda #$DF Uppercase = lowercase.
         beq  LOOP10 If same, then try another.
NOMATCH  comb Set flag: no match this line.
         rts Return.
SKIP15   leax -$01,x Back up pointer,
SKIP14   lda  ,y+ get user byte again.
         cmpa #$2C A comma?
         beq  XTRLSPCS That's O.K.
         cmpa #$30 Another alphanumeric?
         bcc  NOMATCH Then no match.
         leay -$01,y Else back up again.
XTRLSPCS lda  ,y+ Look at this byte;
         cmpa #$20 a space?
         beq  XTRLSPCS Then pass over it, loop.
         leay -$01,y Else back up again,
         sty  INSTRPTR save
         stx  PWFLNPTR pointers,
         clrb set flag:  a match,
         rts and return.
*
LOOP11   lbsr WRITEWCR Write line out.
WRITMOTD lda  MOTDPTHN Get MOTD path number,
         beq  SKIP16 (if = 0, abort)
         leax INSTRING,u point to input string space,
         ldy  #$0050 (max. 80 bytes)
         OS9  I$ReadLn read a line in.
         bcc  LOOP11 If no error, write & repeat.
         lda  MOTDPTHN Else get pathnumber to
         OS9  I$Close close the file,
SKIP16   clrb erase the error code
         rts and return.
*
DECTOBIN ldx  PWFLNPTR Get pointer to digits.
         clra Clear two bytes of space
         clrb on the stack (and
         pshs y,x,b,a save registers).
LOOP12    ldb  ,x+ Get a digit.
         subb #$30 Change digit to binary.
         cmpb #$09 Within digit range?
         bhi  SKIP17 If not, exit this loop.
         clra Else make it a 2-byte integr,
         ldy  #$000A add to it
LOOP13   addd ,s ten times
         lbcs SNTXEXIT (abort on overflow)
         leay -$01,y the previous
         bne  LOOP13 total.
         std  ,s Save the result on the stack,
         bra  LOOP12 loop for another digit.
SKIP17   lda  -$01,x Look at last character again.
         cmpa #$2C A comma?
         lbne SNTXEXIT If not, take error exit.
         stx  PWFLNPTR Else record current pointer,
L0452    puls a,b,x,y,pc Restore and return.
*
DATETIME leax DATEPCKT,u Point to space for data.
         OS9  F$Time Get data packet from OS9.
         bsr  DATE Do year, month, and day.
         bsr  ADDSPACE Insert a space.
         bsr  TIME Do hours, minutes, seconds.
         bra  WRITLINE Write line out and return.
TIME     bsr  BINTODEC Do hour;
         bsr  COLONPLS add ':', do minutes.
COLONPLS lda  #$3A Get ':',
         bra  DELINPLS append it and digits.
DATE     bsr  YEAR Do year;
         bsr  SLASHPLS add '/', do minutes.
SLASHPLS lda  #$2F Get '/',
DELINPLS bsr  ADDBYTE add it to outstring.
BINTODEC ldb  ,x+ Get binary amount,
         lda  #$2F start at '0' - 1,
         clr  LDNG0FLG set flag:  no nonzero yet.
LOOP14   inca Increase 100's digit,
         subb #$64 reduce binary by 100,
         bcc  LOOP14 loop 'til we pass 0.
         bsr  LDNG0CHK Adjust flag if necessary.
TWODIGTS lda  #$3A Now start with '9' + 1,
LOOP15   deca  reduce 10's digit,
         addb #$0A increase binary by 10,
         bcc  LOOP15 until we pass 0 again.
         bsr  ADDBYTE Write this one regardless.
         tfr  b,a Put binary remainder into a,
         adda #$30 convert to ASCII,
         bra  ADDBYTE add to string and return.
LDNG0CHK inc  LDNG0FLG Tentatively non-zero.
         cmpa #$30 If that's right,
         bne  ADDBYTE proceed.
         dec  LDNG0FLG Else restore flag to prior
         bne  ADDBYTE setting;  if >0, write digit.
         rts Else just return.
*
ADDSPACE lda  #$20 Get a space.
ADDBYTE  pshs x Save register,
         ldx  OTSTRPTR get pointer to outstring.
         sta  ,x+ Put byte there,
         stx  OTSTRPTR save advanced pointer.
         puls x,pc Restore register and return.
*
WRITLINE    pshs a Save register,
         lda  #$0D get a carriage return,
         bsr  ADDBYTE add it to outstring.
         puls a Restore register.
WRITEOUT pshs y,x,b,a Save registers,
         leax OUTSTRNG,u point to outstring.
         ldd  OTSTRPTR Calculate its length
         stx  OTSTRPTR (in case there's no C.R.
         subd  OTSTRPTR at the end of it),
         tfr  d,y put the result in y.
         lda  #$01 = stdout
         OS9  I$WritLn Write it out via OS9.
         puls a,b,x,y,pc Restore and return.
YEAR     ldb  ,x Get year byte,
         lda  #18-100 start at 1800.
LOOP16   inca Increase century count,
         subb #$64 reduce binary by 100,
         bcc  LOOP16 until we pass 0.
         stb  ,x Save remainder a moment,
         tfr  a,b put century count into b,
         bsr  TWODIGTS write those 2 digits.
         ldb  ,x+ Retrieve the remainder,
         bra  TWODIGTS write 2 digits and return.
         emod
CSIZE    equ  *
