home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msk316src.zip / MSSRCV.ASM < prev    next >
Assembly Source File  |  1999-04-24  |  50KB  |  1,492 lines

  1.     NAME    mssrcv
  2. ; File MSSRCV.ASM
  3.     include mssdef.h
  4. ;    Copyright (C) 1982, 1999, Trustees of Columbia University in the 
  5. ;    City of New York.  The MS-DOS Kermit software may not be, in whole 
  6. ;    or in part, licensed or sold for profit as a software product itself,
  7. ;    nor may it be included in or distributed with commercial products
  8. ;    or otherwise distributed by commercial concerns to their clients 
  9. ;    or customers without written permission of the Office of Kermit 
  10. ;    Development and Distribution, Columbia University.  This copyright 
  11. ;    notice must not be removed, altered, or obscured.
  12. ;
  13. ; Edit history
  14. ; 12 Jan 1995 version 3.14
  15. ; Last edit
  16. ; 12 Jan 1995
  17.  
  18.     public    read2, read, rrinit, ackpak, nakpak, rstate, fdate, ftime
  19.  
  20. data     segment
  21.     extrn    encbuf:byte, decbuf:byte, fmtdsp:byte, flags:byte, trans:byte
  22.     extrn    dtrans:byte, sstate:byte, diskio:byte, auxfile:byte
  23.     extrn    maxtry:byte, fsta:word, errlev:byte, kstatus:word
  24.     extrn    rpacket:byte, wrpmsg:byte, numpkt:word, windlow:byte
  25.     extrn    charids:word, windflag:byte, denyflg:word, chkparflg:byte
  26.     extrn    tfilsz:word, filtst:byte, rdbuf:byte
  27.     extrn    ferbyte:byte, ferdate:byte, ferdisp:byte, fertype:byte
  28.     extrn    ferchar:byte, fername:byte, ferunk:byte, termserver:byte
  29.     extrn    k_rto:word, cwindow:byte, vfile:byte, streamok:byte
  30.  
  31. cemsg    db    'User intervention',0
  32. erms11    db    'Not enough disk space for file',0
  33. erms13    db    'Unable to send reply',0
  34. erms14  db    'No response from the host',0
  35. erms15    db    'Error. No buffers in receive routine',0
  36. erms29    db    'Rejecting file: ',0
  37. ifndef    nls_portuguese
  38. infms1  db    cr,'           Receiving: In progress',cr,lf,'$'
  39. else
  40. infms1  db    cr,'               Receiving: In progress',cr,lf,'$'
  41. endif    ; nls_portuguese
  42. infms3  db      'Completed',cr,lf,'$'
  43. infms4  db      'Failed',cr,lf,'$'
  44. infms6  db      'Interrupted',cr,lf,'$'
  45. infms7    db    'Discarding $'
  46. ender    db    bell,bell,'$'
  47. crlf    db    cr,lf,'$'
  48. badrcv    db    0        ; local retry counter
  49. filopn    db    0        ; non-zero if disk file is open
  50. ftime    db    0,0        ; file time (defaults to 00:00:00)
  51. fdate    db    0,0        ; file date (defaults to 1 Jan 1980)
  52. attrib    db    0        ; attribute code causing file rejection
  53. restart_flag db    0        ; non-zero if remote requests file restart
  54. rstate    db    0        ; state of automata
  55. permchrset dw    0        ; permanent file character set holder
  56. permflwflg db    0        ; save file transfer set
  57. dostream db    0        ; non-zero to engage streaming mode
  58. ten    dw    10
  59. temp    dw    0
  60. data    ends
  61.  
  62. data1    segment
  63. filhlp2 db      ' Local path or filename or carriage return$'
  64. data1    ends
  65.  
  66. code1    segment
  67.     extrn bufclr:far, pakptr:far, bufrel:far, makebuf:far, chkwind:far
  68.     extrn firstfree:far, getbuf:far, pakdup:far, rpar:far, winpr:far
  69.     extrn rpack:far, spack:far, fcsrtype:far, prtasz:far, dskspace:far
  70.     extrn logtransact:far, strlen:far, strcpy:far, streampr:far
  71. code1    ends
  72.  
  73. code    segment
  74.     extrn    gofil:near, comnd:near, cntretry:near, perpr:near
  75.     extrn    serini:near, spar:near, lnout:near
  76.     extrn    init:near, cxmsg:near, cxerr:near
  77.     extrn    ptchr:near, ermsg:near
  78.     extrn    stpos:near, rprpos:near, packlen:near, kbpr:near
  79.     extrn    dodec:near, doenc:near, errpack:near, intmsg:near
  80.     extrn    ihostr:near, begtim:near
  81.     extrn    endtim:near, pktsize:near
  82.     extrn    msgmsg:near, clrbuf:near, pcwait:far, goopen:near
  83.     extrn    filekind:near, filecps:near
  84.  
  85.     assume  cs:code, ds:data, es:nothing
  86.  
  87. ; Data structures comments.
  88. ; Received packet material is placed in buffers pointed at by [si].bufadr;
  89. ; SI is typically used as a pointer to a pktinfo packet structure.
  90. ; Sent packet material (typically ACK/NAKs) is placed in a standard packet
  91. ; structure named rpacket.
  92. ; Rpack and Spack expect a pointer in SI to the pktinfo structure for the
  93. ; packet.
  94.  
  95. ; RECEIVE command
  96.  
  97. READ    PROC    NEAR        
  98.     mov    dx,offset filhlp2    ; help message
  99.     mov    bx,offset auxfile    ; local file name string
  100.     mov    ah,cmword        ; local override filename/path
  101.     call    comnd        
  102.     jc    read1a            ; c = failure
  103.     mov    ah,cmeol        ; get a confirm
  104.     call    comnd
  105.     jc    read1a            ; c = failure
  106.     mov    rstate,'R'        ; set state to receive initiate
  107.     mov    flags.xflg,0
  108.     call    serini            ; initialize serial port
  109.     jnc    read1b            ; nc = success
  110.     or    errlev,ksrecv        ; set DOS error level
  111.     or    fsta.xstatus,ksrecv    ; set status, failed
  112.     or    kstatus,ksrecv        ; global status
  113.     test    flags.remflg,dquiet    ; quiet display mode?
  114.     jnz    read1a            ; nz = yes, don't write to screen
  115.     mov    ah,prstr
  116.     mov    dx,offset infms4    ; Failed message
  117.     int    dos
  118.     stc
  119. read1a:    ret                ; return failure
  120.  
  121. read1b:    call    rrinit            ; init variables for read
  122.     call    clrbuf            ; clear serial port buffer
  123.     call    ihostr            ; initialize the host
  124.     cmp    flags.destflg,dest_screen ; destination is screen?
  125.     je    read2            ; e = yes
  126.     mov    flags.xflg,0        ; not writing to screen, yet
  127.     call    init            ; setup display form
  128.     
  129.                     ; Called by GET & SRVSND, display ok
  130. READ2:    mov    kstatus,kssuc        ; global status, success
  131.     mov    windflag,0        ; init windows in use display flag
  132.     mov    numpkt,0        ; set the number of packets to zero
  133.     mov    badrcv,0        ; local retry counter
  134.     mov    fsta.pretry,0        ; clear total retry counter
  135.     mov    flags.cxzflg,0        ; reset ^X/^Z flag
  136.     mov    ax,flags.chrset        ; permanent character set (Code Page)
  137.     mov    permchrset,ax        ; remember here around attributes ptks
  138.     mov    al,flags.flwflg        ; file warning flag
  139.     mov    permflwflg,al        ; save around file transfer set
  140.     mov    si,offset auxfile
  141.     mov    di,offset vfile
  142.     call    strcpy            ; copy name to \v(filename) buffer
  143.     cmp    fmtdsp,0        ; formatted display?
  144.     je    read2a            ; e = no
  145.     call    stpos
  146.     mov    ah,prstr        ; Receiving in progress msg
  147.     mov    dx,offset infms1
  148.     int    dos
  149. read2a:    jmp    dispatch
  150. READ    ENDP
  151.  
  152. ; Call the appropriate action routines for each state of the protocol machine.
  153. ; State is held in byte rstate. Enter at label dispatch.
  154.  
  155. dispatch proc    near            ; dispatch on state variable rstate
  156.     mov    dostream,0        ; assume not doing streaming mode
  157.     mov    ah,rstate        ; get current state
  158.     cmp    ah,'R'            ; Receive initiate state?
  159.     jne    dispat2            ; ne = no
  160.     cmp    termserver,1        ; invoked from terminal emulator?
  161.     jne    dispat1            ; ne = no
  162.     mov    windlow,0        ; lowest acceptable packet number
  163.     mov    trans.chklen,1        ; Use 1 char for NAK packet
  164.     mov    rpacket.seqnum,0
  165.     call    nakpak            ; send an initial NAK
  166.     mov    fsta.nakscnt,0        ; do not count this NAK stimulus
  167.     inc    termserver        ; say have responded to invokation
  168. dispat1:call    rinit
  169.     jmp    short dispatch
  170.  
  171. dispat2:cmp    ah,'F'            ; File header receive state?
  172.     jne    dispat3
  173.     call    rfile            ; receive file header
  174.     jmp    short dispatch
  175.  
  176. dispat3:cmp    ah,'D'            ; Data receive state?
  177.     jne    dispat4
  178.     call    rdata            ; get data packets
  179.     jmp    short dispatch
  180.  
  181. dispat4:cmp    ah,'Z'            ; EOF?
  182.     jne    dispat5
  183.     call    reof            ; do EOF wrapup
  184.     jmp    short dispatch
  185.  
  186. dispat5:cmp    ah,'E'            ; ^C or ^E abort?
  187.     jne    dispat6            ; ne = no
  188.     mov    bx,offset cemsg        ; user intervention message
  189.     call    errpack            ; send error message
  190.     call    intmsg            ; show interrupt msg for Control-C-E
  191.  
  192.                     ; Receive Complete state processor
  193. dispat6:cmp    rstate,'C'        ; completed normally?
  194.     jne    dispat6a        ; ne = no
  195.     cmp    flags.cxzflg,0        ; interrupted?
  196.     je    dispat7            ; e = no, ended normally
  197. dispat6a:or    errlev,ksrecv        ; set DOS error level
  198.     or    fsta.xstatus,ksrecv+ksuser ; set status, failed + intervention
  199.     or    kstatus,ksrecv+ksuser    ; global status
  200. dispat7:xor    ax,ax        ; tell statistics this is a receive operation
  201.     call    endtim            ; stop file statistics accumulator
  202.     call    filecps            ; show file chars/sec
  203.     call    bufclr            ; release all buffers
  204.     mov    windlow,0
  205.     mov    ax,permchrset        ; permanent character set (Code Page)
  206.     mov    flags.chrset,ax        ; restore external version
  207.     mov    al,permflwflg        ; saved around file transfer set
  208.     mov    flags.flwflg,al        ; restore file warning state
  209.     cmp    rstate,'C'        ; receive complete state?
  210.     je    dispat8            ; e = yes
  211.     or    errlev,ksrecv        ; Failed, set DOS error level
  212.     or    fsta.xstatus,ksrecv    ; set status, failed
  213.     or    kstatus,ksrecv        ; global status
  214.     call    fileclose        ; close output file
  215.     call    filedel            ; delete incomplete file
  216.  
  217. dispat8:cmp    flags.destflg,dest_screen ; receiving to screen?
  218.     je    dispa11            ; e = yes, nothing to clean up
  219.     test    flags.remflg,dquiet    ; quiet display mode?
  220.     jnz    dispa11            ; nz = yes, keep going
  221.     test    flags.remflg,dserial    ; serial display mode?
  222.     jnz    dispa10a        ; nz = yes, ring bell
  223.     mov    al,1            ; underline cursor
  224.     call    fcsrtype        ; set IBM-PC cursor to underline
  225.     cmp    flags.xflg,0        ; writing to the screen?
  226.     jne    dispa11            ; ne = yes
  227.     call    stpos            ; position cursor to status line
  228.     mov    dx,offset infms3    ; completed message
  229.     cmp    rstate,'C'        ; receive complete state?
  230.     je    dispa10            ; e = yes
  231.     mov    dx,offset infms4    ; failed message
  232.     cmp    flags.cxzflg,0        ; interrupted?
  233.     je    dispa10            ; e = no, ended normally
  234.     mov    dx,offset infms6    ; interrupted message
  235. dispa10:mov    ah,prstr
  236.     int    dos
  237. dispa10a:cmp    flags.belflg,0        ; bell desired?
  238.     je    dispa11            ; e = no
  239.     mov    ah,prstr
  240.     mov    dx,offset ender        ; ring the bell
  241.     int    dos
  242. dispa11:call    rprpos            ; put cursor at reprompt position
  243.     mov    flags.cxzflg,0        ; clear flag for next command
  244.     mov    auxfile,0        ; clear receive-as filename buffer
  245.     mov    flags.xflg,0        ; clear to-screen flag
  246.     mov    diskio.string,0        ; clear active filename buffer
  247.     mov    fsta.xname,0        ; clear statistics external name
  248.     mov    termserver,0
  249.     ; do not clear decbuf; it is needed to see remote command response.
  250.     mov    encbuf,0
  251.     call    clrbuf            ; drain comms channel of extra junk
  252.     clc                ; return to ultimate caller, success
  253.     ret
  254. dispatch endp
  255.  
  256. ;    Receive routines
  257.  
  258. ; Receive initiate packet (tolerates I E F M S X Y types)
  259. RINIT    PROC    NEAR
  260.     mov    ax,18            ; 18.2 Bios ticks per second
  261.     mul    trans.stime        ; byte, seconds
  262.     mov    k_rto,ax        ; round trip timeout, Bios ticks
  263.     mov    windlow,0        ; lowest acceptable packet number
  264.     mov    trans.chklen,1        ; Use 1 char for init packet
  265.     mov    chkparflg,1        ; check for unexpected parity
  266.     call    rcvpak            ; get a packet
  267.     jnc    rinit2            ; nc = success
  268.     ret
  269.  
  270. rinit2:    mov    ah,[si].pktype        ; examine packet type
  271.     cmp    ah,'S'            ; Send initiate packet?
  272.     je    rinit6            ; e = yes, process 'S' packet
  273.     cmp    ah,'M'            ; Message packet?
  274.     jne    rinit3            ; ne = no
  275.     call    msgmsg            ; display message
  276.     mov    trans.chklen,1        ; send Init checksum is always 1 char
  277.     call    ackpak0            ; ack and release packet
  278.     ret
  279.  
  280. rinit3:    cmp    ah,'I'            ; unexpected 'I' packet?
  281.     jne    rinit4            ; e = yes, respond
  282.     call    spar            ; unexpected I packet, parse info
  283.     call    packlen
  284.     mov    cx,trans.rlong        ; max receiving pkt length to report
  285.     call    makebuf            ; remake buffers for new windowing
  286.     push    si
  287.     mov    si,offset rpacket
  288.     call    rpar            ; setup info about our reception
  289.     pop    si
  290.     mov    al,trans.chklen        ; checksum length negotiated
  291.     push    ax            ; save around reply
  292.     mov    trans.chklen,1        ; reply with 1 char checksum
  293.     call    ackpak            ; send response
  294.     pop    ax            ; restore checksum length
  295.     mov    dtrans.chklen,al    ;  to negotiation value
  296.     cmp    streamok,0        ; doing streaming?
  297.     je    rinit3a            ; e = no
  298.     call    streampr        ; put message on formatted screen
  299. rinit3a:ret                ; stay in this state
  300.  
  301. rinit4:    cmp    ah,'F'            ; File receive?
  302.     je    rinit5            ; e = yes
  303.     cmp    ah,'X'            ; File receive to screen?
  304.     je    rinit5            ; e = yes
  305.     cmp    ah,'Y'            ; ACK to a REMOTE command?
  306.     jne    rinit4a            ; ne = no
  307.     call    msgmsg            ; show any message in the ACK
  308.     mov    rstate,'C'        ; Completed state
  309.     ret
  310.  
  311. rinit4a:call    bufrel            ; release this packet buffer
  312.     ret                ;  and ignore it
  313.  
  314. rinit5:    mov    rstate,'F'        ; File header receive state
  315.     ret
  316.  
  317.                     ; 'S' packet received
  318. rinit6:    call    spar            ; negotiate parameters
  319.     push    si
  320.     mov    si,offset rpacket    ; build response in this packet
  321.     call    rpar            ; report negotiated parameters
  322.     pop    si
  323.     mov    ah,trans.chklen        ; negotiated checksum length
  324.     push    ax            ; save it
  325.     mov    trans.chklen,1        ; use 1 char for init packet reply
  326.     mov    rstate,'F'        ; set state to file header
  327.     call    ackpak            ; ack with negotiated data
  328.     pop    ax            ; recover working checksum
  329.     mov    trans.chklen,ah
  330.     mov    cx,trans.rlong        ; negotiated length of received pkts
  331.     call    makebuf            ; remake buffering for new windowing
  332.     call    packlen            ; compute packet length
  333.     cmp    streamok,0        ; doing streaming?
  334.     je    rinit7            ; e = no
  335.     call    streampr        ; put message on formatted screen
  336. rinit7:    ret                ; stay in this state
  337.     ret
  338. RINIT    ENDP
  339.  
  340.  
  341. ; Receive file header (tolerates E F M X Z types)
  342.  
  343. RFILE    PROC    NEAR
  344.     call    rcvpak            ; receive next packet
  345.     jnc    rfile1            ; nc = success
  346.     ret
  347.  
  348. rfile1: cmp    [si].pktype,'Z'        ; EOF?
  349.     jne    rfile2            ; ne = no, try next type
  350.     mov    rstate,'Z'        ; change to EOF state, SI is valid pkt
  351.     ret
  352.  
  353. rfile2: cmp    [si].pktype,'F'        ; file header (F or X packet)?
  354.     je    rfile3            ; e = yes, 'F' pkt
  355.     cmp    [si].pktype,'X'        ; visual display header?
  356.     jne    rfile5            ; ne = neither one
  357.     mov    flags.xflg,1        ; 'X', say receiving to the screen
  358.  
  359. rfile3:    mov    filopn,0        ; assume not writing to a disk file
  360.     call    dodec            ; decode packet
  361.     call    cxmsg            ; clear Last Message line
  362.     xor    al,al            ; say starting receive operation
  363.     call    begtim            ; start statistics gathering
  364.     mov    al,dtrans.xchset    ; reset Transmission char set
  365.     mov    trans.xchset,al        ;  to the current user default
  366.     mov    ax,permchrset        ; permanent character set (Code Page)
  367.     mov    flags.chrset,ax        ; active character set
  368.     mov    si,offset decbuf
  369.     mov    di,offset rdbuf+cmdblen-65 ; holding spot for original name
  370.     call    strcpy            ; copy to holding spot
  371.     call    gofil            ; open the output file
  372.     jnc    rfile4            ; nc = success
  373.     jmp    giveup            ; failure, dx has message pointer
  374.  
  375. rfile4:    push    si
  376.     push    di
  377.     mov    si,offset decbuf    ; local filename is here
  378.     mov    di,offset encbuf    ; destination is encoding buffer
  379.     mov    byte ptr [di],' '    ; leave space for protocol char
  380.     inc    di            ;  so other Kermits do not react
  381.     call    strcpy            ; copy it, to echo local name to host
  382.     dec    di
  383.     mov    dx,di
  384.     call    strlen            ; get length to cx for doenc
  385.     mov    si,offset rpacket    ; use this packet buffer
  386.     call    doenc            ; encode buffer, cx gets length
  387.     pop    di
  388.     pop    si
  389.     call    ackpak            ; ack the packet, with filename
  390.     call    filekind        ; report Text/Bin, char set
  391.     mov    rstate,'D'        ; set the state to data receive
  392.     ret
  393.  
  394. rfile5:    mov    ah,[si].pktype        ; get reponse packet type
  395.     cmp    ah,'B'            ; 'B' End Of Transmission?
  396.     jne    rfile6            ; ne = no
  397.     mov    rstate,'C'        ; set state to Complete
  398.     jmp    ackpak0            ; ack the packet
  399.  
  400. rfile6:    cmp    ah,'M'            ; Message packet?
  401.     jne    rfile7            ; ne = no
  402.     call    msgmsg            ; display message
  403.     jmp    ackpak0            ; ack packet, stay in this state
  404.  
  405. rfile7:    call    bufrel            ; release buffer
  406.     ret                ;  and ignore unknown packet
  407. RFILE    ENDP
  408.  
  409. ; Get file attributes from packet
  410. ; Recognize file size in bytes and kilobytes (used if bytes missing),
  411. ; file time and date. Reject Mail commands. Return carry clear for success,
  412. ; carry set for failure. If rejecting place reason code in byte attrib.
  413.  
  414. GETATT    PROC    NEAR
  415.     mov    attrib,' '        ; clear failing attribute code
  416.     push    es
  417.     les    bx,[si].datadr        ; pointer to data field
  418. getat0:    push    bx
  419.     sub    bx,word ptr [si].datadr ; bx => length examined
  420.     cmp    bx,[si].datlen        ; more than supplied data?
  421.     pop    bx
  422.     jl    getat1            ; l = not yet
  423.     pop    es
  424.     clc
  425.     ret                ; has carry clear for success
  426.  
  427. getat1:    mov    al,es:[bx]        ; get attribute kind
  428.     mov    attrib,al        ; store for failure report
  429.  
  430.     cmp    al,'1'            ; Byte length field?
  431.     jne    getat2            ; ne = no
  432.     test    flags.attflg,attlen    ; allowed to examine file length?
  433.     jnz    getat1b            ; nz = yes
  434. getat1a:jmp    getatunk        ; z = no, ignore
  435. getat1b:inc    bx            ; step to length of field byte
  436.     call    getas            ; get file size from packet
  437.     jc    getat1a            ; c = failed to decode properly
  438.     call    spchk            ; check available disk space
  439.     jnc    getat0            ; nc = have enough space for file
  440.     pop    es
  441.     ret                ; return failure
  442.  
  443. getat2:    cmp    al,'!'            ; Kilobyte length field?
  444.     jne    getat3            ; ne = no
  445.     test    flags.attflg,attlen    ; allowed to examine file length?
  446.     jnz    getat2b            ; nz = yes
  447. getat2a:jmp    getatunk        ; z = no, ignore
  448. getat2b:inc    bx            ; step to length of field byte
  449.     call    getak            ; get file size from packet
  450.     jc    getat2a            ; carry means decode rejected
  451.     call    spchk            ; check available disk space
  452.     jnc    short getat0        ; nc = have enough space
  453.     pop    es
  454.     ret                ; return failure
  455.  
  456. getat3:    cmp    al,'#'            ; date field?
  457.     jne    getat4            ; ne = no
  458.     mov    word ptr ftime,0    ; clear time and date fields
  459.     mov    word ptr fdate,0
  460.     test    flags.attflg,attdate    ; allowed to update file date/time?
  461.     jnz    getat3a            ; nz = yes
  462.     jmp    getatunk        ; z = no, ignore
  463. getat3a:inc    bx            ; point at length of field
  464.     call    getatd            ; get file date
  465.     jnc    short getat0
  466.     pop    es
  467.     ret                ; return failure
  468.  
  469. getat4:    cmp    al,'+'            ; Disposition?
  470.     jne    getat5            ; ne = no
  471.     mov    ax,es:[bx+1]        ; count byte, disposition byte
  472.     cmp    ah,'M'            ; Mail indicator?
  473.     je    getat4d            ; e = yes, fail
  474.     cmp    ah,'P'            ; REMOTE PRINT?
  475.     jne    getat4b            ; ne = no
  476.     test    flags.remflg,dserver    ; acting as a server now?
  477.     jz    getat4a            ; z = no
  478.     test    denyflg,prtflg        ; is this server command disabled?
  479.     jnz    getat4d            ; nz = yes, disabled
  480. getat4a:mov    word ptr diskio.string,'RP'    ; output to PRN
  481.     mov    word ptr diskio.string+2,'N'     ; ignore options
  482.     inc    bx            ; step to data field
  483.     sub    al,20h            ; count byte bias removal
  484.     xor    ah,ah
  485.     add    bx,ax            ; step to next attribute
  486.     jmp    getat0
  487.  
  488. getat4b:cmp    ah,'R'            ; Restart?
  489.     jne    getat4c            ; ne = no
  490.     or    restart_flag,1        ; say restarting
  491. getat4c:jmp    getatunk        ; ignore field
  492.  
  493. getat4d:stc                ; set carry for failure
  494.     pop    es
  495.     ret
  496.  
  497. getat5:    cmp    al,'"'            ; File Type?
  498.     jne    getat6            ; ne = no
  499.            test    flags.attflg,atttype    ; allowed to examine file type?
  500.     jnz    getat5a            ; nz = yes
  501.     jmp    getatunk        ; z = no, ignore field
  502. getat5a:inc    bx            ; step to length of field byte
  503.     xor    ch,ch
  504.     mov    cl,es:[bx]        ; get length
  505.     inc    bx
  506.     mov    ax,es:[bx]        ; data
  507.     sub    cl,20h            ; remove ascii bias
  508.     jc    getat5d            ; c = error in length, fail
  509.     add    bx,cx            ; step to next field
  510.     cmp    al,'A'            ; Type letter (A, B, I), Ascii?
  511.     jne    getat5b            ; ne = no
  512.     mov    trans.xtype,0        ; say Ascii/Text file type
  513.     jmp    getat0            ; next item please
  514. getat5b:cmp    al,'B'            ; "B" Binary?
  515.     jne    getat5d            ; ne = no, fail
  516.     cmp    cl,2            ; full "B8"?
  517.     jb    getat5c            ; b = no, just "B"
  518.     cmp    ah,'8'            ; proper length?
  519.     jne    getat5d            ; ne = no
  520. getat5c:mov    trans.xtype,1        ; say Binary
  521.     or    restart_flag,2        ; restart, remember binary mode
  522.     jmp    getat0            ; next item please
  523. getat5d:stc                ; set carry for rejection
  524.     pop    es
  525.     ret
  526.  
  527. getat6:    cmp    al,'*'            ; character set usage?
  528.     jne    getat8            ; ne = no
  529.     test    flags.attflg,attchr    ; allowed to examine char-set?
  530.     jnz    getat6a            ; nz = yes
  531. getat6d:jmp    getatunk        ; z = no, ignore
  532.  
  533. getat6a:inc    bx            ; step to length field
  534.     mov    cl,es:[bx]        ; get length
  535.     sub    cl,' '            ; remove ascii bias
  536.     js    getat6c            ; c = length error, fail
  537.     xor    ch,ch
  538.     inc    bx            ; first data byte
  539.     mov    al,es:[bx]
  540.     mov    trans.xchset,0        ; assume Transparent Transfer char-set
  541.     cmp    al,'A'            ; Normal Transparent?
  542.     jne    getat6b            ; be = not Transparent
  543.     add    bx,cx            ; point to next attribute
  544.     jmp    getat0
  545. getat6b:cmp    al,'C'            ; character set?
  546.     je    getat7            ; e = yes
  547. getat6c:stc                ; set carry for rejection
  548.     pop    es
  549.     ret
  550. getat7:    push    di            ; examine transfer character set
  551.     push    si
  552.     mov    di,bx            ; point at first data character
  553.     add    bx,cx            ; point to next attribute
  554.     push    bx            ; save bx
  555.     dec    cx            ; deduct leading 'C' char from count
  556.     inc    di            ; skip the 'C'
  557.     mov    bx,offset charids    ; point to array of char set info
  558.     mov    ax,[bx]            ; number of members
  559.     mov    temp,ax            ; loop counter
  560.     mov    trans.xchset,xfr_xparent ; assume xfer char set Transparent
  561. getat7a:add    bx,2            ; point to a member's address
  562.     mov    si,[bx]            ; point at member [length, string]
  563.     cmp    cl,[si]            ; string lengths the same?
  564.     jne    getat7b            ; ne = no, try the next member
  565.     inc    si            ; point at ident string
  566.     cld
  567.     push    cx            ; save incoming count
  568.     push    di            ; save incoming string pointer
  569.     repe    cmpsb            ; compare cx characters
  570.     pop    di
  571.     pop    cx
  572.     je    getat7d            ; e = idents match
  573. getat7b:inc    trans.xchset        ; try next set
  574.     dec    temp            ; one less member to consider
  575.     jnz    getat7a            ; nz = more members to try
  576.     pop    bx            ; failure to find a match
  577.     pop    si
  578.     pop    di
  579.     mov    trans.xchset,xfr_xparent; use Transparent for unknown char set
  580.     cmp    flags.unkchs,0        ; keep the file?
  581.     je    getat7c            ; e = yes, regardless of unk char set
  582.     pop    es
  583.     stc                ; set carry for rejection
  584.     ret
  585. getat7c:clc
  586.     jmp    getat0            ; report success anyway
  587.  
  588. getat7d:pop    bx            ; a match, use current trans.xchset
  589.     pop    si
  590.     pop    di
  591.     cmp    trans.xchset,xfr_cyrillic ; using Transfer Char Set Cyrillic?
  592.     jne    getat7e            ; ne = no
  593.     mov    flags.chrset,866    ; force CP866 (required by Cyrillic)
  594.     clc
  595.     jmp    getat0
  596. getat7e:cmp    trans.xchset,xfr_japanese ; using Trans Char Set Japanese-EUC?
  597.     jne    getat7f            ; ne = no
  598.     mov    flags.chrset,932    ; force Shift-JIS
  599.     jmp    getat0            ; success
  600. getat7f:cmp    trans.xchset,xfr_latin2    ; using Trans Char Set Latin-2?
  601.     jne    getat7g            ; ne = no
  602.     mov    flags.chrset,852    ; force CP852
  603.     jmp    getat0            ; success
  604. getat7g:cmp    trans.xchset,xfr_hebiso    ; using Hebrew-ISO?
  605.     jne    getat7h            ; ne = no
  606.     mov    flags.chrset,862    ; force CP862
  607. getat7h:jmp    getat0
  608.  
  609. getat8:    cmp    al,'@'            ; attribute count of zero?
  610.     jne    getatunk        ; ne = no
  611.     inc    bx            ; step to length field
  612.     mov    al,es:[bx]        ; length
  613.     inc    bx            ; set to data field
  614.     cmp    al,' '            ; End of Attributes code?
  615.     jne    getatunk        ; ne = no
  616.     test    restart_flag,1        ; has Restart been requested?
  617.     jz    getat8b            ; z = no
  618.     test    restart_flag,2        ; and Binary transfer requested?
  619.     jnz    getat8b            ; nz = yes, that's fine
  620.     mov    attrib,'+'        ; failure reason is disposition
  621. getat8a:pop    es
  622.     stc                ; fail 
  623.     ret
  624. getat8b:clc                ; success, end attributes analysis
  625.     pop    es
  626.     ret
  627.  
  628.  
  629.                     ; workers for above
  630. getatunk:inc    bx            ; Unknown. Look at length field
  631.     mov    al,es:[bx]
  632.     sub    al,' '            ; remove ascii bias
  633.     xor    ah,ah
  634.     inc    ax            ; include length field byte
  635.     add    bx,ax            ; skip to next attribute
  636.     jmp    getat0
  637.  
  638.                     ; Decode File length (Byte) field
  639. getas:    mov    cl,es:[bx]        ; length of file size field
  640.     inc    bx            ; point at file size data
  641.     sub    cl,' '            ; remove ascii bias
  642.     xor    ch,ch
  643.     xor    ax,ax            ; current length, bytes
  644.     xor    dx,dx
  645.     jcxz    getas3            ; z = empty field
  646. getas2:    push    cx
  647.     shl    dx,1            ; high word of size, times two
  648.     mov    di,dx            ; save
  649.     shl    dx,1
  650.     shl    dx,1            ; times 8
  651.     add    dx,di            ; yields dx * 10
  652.     mov    di,dx            ; save dx
  653.     xor    dx,dx
  654.     mov    cx,10            ; also clears ch
  655.     mul    cx            ; scale up previous result in ax
  656.     mov    cl,es:[bx]        ; get a digit
  657.     inc    bx
  658.     sub    cl,'0'            ; remove ascii bias
  659.     add    ax,cx            ; add to current length
  660.     adc    dx,0            ; extend result to dx
  661.     add    dx,di            ; plus old high part
  662.     pop    cx
  663.     loop    getas2
  664.     mov    diskio.sizelo,ax    ; low order word
  665.     mov    diskio.sizehi,dx    ; high order word
  666.     clc
  667.     ret
  668. getas3:    sub    bx,2            ; backup to attribute kind
  669.     stc                ; fail the decode
  670.     ret
  671.                     ; Decode Kilobyte attribute worker
  672. getak:    mov    ax,diskio.sizelo    ; current filesize, low word
  673.     add    ax,diskio.sizehi
  674.     or    ax,ax            ; zero if not used yet
  675.     jz    getak1            ; z = not used before
  676.     dec    bx            ; backup pointer to attribute kind
  677.     stc                ; set carry to ignore this field
  678.     ret
  679.  
  680. getak1:    call    getas            ; parse as if Byte field
  681.     jnc    getak2            ; nc = parsed ok
  682.     ret                ; c = failure
  683. getak2:    mov    ax,diskio.sizelo    ; get low word of size
  684.     mov    dx,diskio.sizehi    ; high word
  685.     mov    dh,dl            ; times 256
  686.     mov    dl,ah
  687.     mov    ah,al
  688.     xor    al,al
  689.     shl    dx,1            ; times four to make times 1024
  690.     shl    dx,1
  691.     rol    ax,1            ; two high bits of ah to al
  692.     rol    ax,1
  693.     and    al,3            ; keep them
  694.     or    dl,al            ; insert into high word
  695.     xor    al,al
  696.     mov    diskio.sizehi,dx    ; store high word
  697.     mov    diskio.sizelo,ax    ; store low word
  698.     clc                ; clear carry
  699.     ret
  700.                     ; File date and time worker
  701. getatd:    mov    word ptr ftime,1    ; two seconds past midnight
  702.     mov    word ptr fdate,0
  703.     mov    dl,es:[bx]        ; field length
  704.     xor    dh,dh
  705.     sub    dl,' '            ; remove ascii bias
  706.     inc    bx            ; next field
  707.     add    dx,bx            ; where next field begins
  708.     mov    temp,dx            ; save in temp
  709.     cmp    byte ptr es:[bx+6],' '    ; short form date (yymmdd)?
  710.     je    getad1            ; e = yes, get current century
  711.     mov    dx,es:[bx]        ; get century digits
  712.     sub    dx,'00'            ; subtract ascii bias
  713.     mov    al,10
  714.     mul    dl
  715.     add    al,dh            ; dh has units
  716.     sub    al,19
  717.     add    bx,2            ; skip to year pair
  718.     jmp    getad2
  719.  
  720. getad1:    mov    ah,getdate        ; DOS date (cx= yyyy, dh= mm, dl= dd)
  721.     int    dos
  722.     mov    ax,cx
  723.     xor    dx,dx
  724.     div    ten
  725.     xor    dx,dx
  726.     div    ten            ; truncate to centuries
  727.     sub    al,19            ; remove 19 bias, current century
  728. getad2:    mul    ten            ; al has centuries - 19
  729.     mul    ten            ; centuries equal 100 years
  730.     mov    cl,al            ; keep results in cl
  731.     mov    dx,es:[bx]        ; get year tens and units digits
  732.     add    bx,2            ; dl has tens, dh has units
  733.     sub    dx,'00'            ; remove ascii bias
  734.     mov    ax,10
  735.     mul    dl            ; ax = high digit times ten
  736.     add    al,dh            ; units digit
  737.     add    al,cl            ; add centuries since 1900
  738.     sub    ax,80            ; remove rest of 1980 bias
  739.     jns    getad2a            ; ns = no sign = non-negative result
  740.     xor    ax,ax            ; don't store less than 1980
  741. getad2a:cmp    ax,128            ; beyond 2108? (1980 + 128)
  742.     jb    getad2c            ; b = no
  743.     stc                ; fail
  744.     ret
  745.  
  746. getad2c:shl    al,1            ; adjust for DOS bit format
  747.     mov    fdate+1,al        ; binary years after 1980
  748.     mov    ax,es:[bx]        ; get month digits
  749.     add    bx,2
  750.     sub    ax,'00'            ; remove ascii bias
  751.     or    al,al            ; tens digit set?
  752.     jz    getad2b            ; z = no
  753.     add    ah,10            ; add to units digit
  754. getad2b:cmp    ah,8            ; high bit of month set?
  755.     jb    getad3            ; b = no
  756.     or    fdate+1,1
  757.     sub    ah,8            ; and deduct it here
  758. getad3:    mov    cl,5
  759.     shl    ah,cl            ; normalize months bits
  760.     mov    fdate,ah
  761.     mov    dx,es:[bx]        ; do day of the month
  762.     add    bx,2            ; dh has units, dl has tens digit
  763.     sub    dx,'00'            ; remove ascii bias
  764.     mov    ax,10
  765.     mul    dl            ; ax = ten times tens digit
  766.     add    al,dh            ; plus units digit
  767.     or    fdate,al
  768.     cmp    bx,temp            ; are we at the end of this field?
  769.     jae    getad5            ; ae = yes, prematurely
  770.     inc    bx            ; skip space separator
  771.     mov    ax,10            ; prepare for hours
  772.     mov    dx,es:[bx]        ; hh digits
  773.     add    bx,2
  774.     sub    dx,'00'            ; remove ascii bias
  775.     mul    dl            ; 10*high digit of hours
  776.     add    al,dh            ; plus low digit of hours
  777.     mov    cl,3            ; normalize bits
  778.     shl    al,cl
  779.     mov    ftime+1,al        ; store hours
  780.     inc    bx            ; skip colon
  781.     mov    ax,10            ; prepare for minutes
  782.     mov    dx,es:[bx]        ; mm digits
  783.     add    bx,2
  784.     sub    dx,'00'            ; remove ascii bias
  785.     mul    dl            ; 10*high digit of minutes
  786.     add    al,dh            ; plus low digit of minutes
  787.     xor    ah,ah
  788.     mov    cl,5            ; normalize bits
  789.     shl    ax,cl
  790.     or    ftime+1,ah        ; high part of minutes
  791.     mov    ftime,al        ; low part of minutes
  792.     cmp    bx,temp            ; are we at the end of this field
  793.     jae    getad5            ; ae = yes, quit here
  794.     inc    bx            ; skip colon
  795.     mov    ax,10            ; prepare for seconds
  796.     mov    dx,es:[bx]        ; ss digits
  797.     add    bx,2
  798.     sub    dx,'00'            ; remove ascii bias
  799.     mul    dl            ; 10*high digit of seconds
  800.     add    al,dh            ; plus low digit of seconds
  801.     shr    al,1            ; store as double-seconds for DOS
  802.     or    ftime,al        ; store seconds
  803. getad5:    cmp    flags.flwflg,filecol_update ; updating?
  804.     jne    getad6            ; ne = no
  805.     cmp    filopn,2        ; file opened yet?
  806.     je    getad6            ; e = yes
  807.     call    goopen            ; open it now
  808.     mov    filopn,2        ; file is open (carry set for fail)
  809.     mov    bx,temp            ; point to next attribute
  810.     ret
  811. getad6:    mov    bx,temp            ; point to next attribute
  812.     clc                ; success
  813.     ret
  814. GETATT    ENDP
  815.  
  816. ; Receive data (tolerates A D E M Z types)
  817.  
  818. RDATA    PROC    NEAR
  819.     call    rcvpak            ; get next packet
  820.     jnc    rdata1            ; nc = success
  821.     ret                ; else return to do new state
  822.  
  823. rdata1:    mov    ah,[si].pktype        ; check packet type
  824.     cmp    ah,'D'            ; Data packet?
  825.     je    rdata3            ; e = yes
  826.     cmp    ah,'A'            ; Attributes packet?
  827.     je    rdata4            ; e = yes
  828.     cmp    ah,'M'            ; Message packet?
  829.     jne    rdat2            ; ne = no
  830.     call    msgmsg            ; display message
  831.     jmp    ackpak0            ; ack the packet, stay in this state
  832.  
  833. rdat2:    cmp    ah,'Z'            ; EOF packet?
  834.     jne    rdat2a            ; ne = no
  835.     mov    rstate,'Z'        ; next state is EOF, do not ack yet
  836.     ret
  837.  
  838. rdat2a:    call    bufrel            ; Unknown packet type, release buffer
  839.     ret                ;  and ignore it
  840.                     ; D data packets
  841. rdata3:    mov    fsta.xstatus,kssuc    ; set status, success
  842.     mov    kstatus,kssuc        ; global status, success
  843.     mov    al,streamok
  844.     mov    dostream,al        ; engage possible streaming mode
  845.     test    restart_flag,1        ; restart negotiations completed?
  846.     jnz    rdat3c            ; nz = no, give up
  847.     cmp    filopn,2        ; file opened yet?
  848.     je    rdata3b            ; e = yes
  849.     call    goopen            ; open it now
  850.     jnc    rdata3a            ; nc = success
  851.     jmp    giveup            ; failure, dx has message pointer
  852. rdata3a:mov    filopn,2        ; say file is open now
  853. rdata3b:call    ptchr            ; decode 'D' packet, output to file
  854.     jc    rdat3c            ; c = failure to write output
  855.     jmp    ackpak0            ; ack the packet, stay in this state
  856.  
  857. rdat3c:    mov    dx,offset erms11    ; cannot store all the data
  858.     jmp    giveup            ; tell the other side
  859.  
  860.                          ; 'A' packet, analyze        
  861. rdata4:    cmp    flags.flwflg,filecol_discard ; no-supersede existing file?
  862.     jne    rdata4e            ; ne = no
  863.     cmp    flags.cxzflg,'X'    ; file being refused from collision?
  864.     jne    rdata4e            ; ne = no
  865.     mov    attrib,'?'        ; say filename collision occured (?)
  866.     mov    flags.cxzflg,0        ; and clear this flag
  867.     jmp    short rdata4c        ; and refuse file via attributes too
  868.     
  869. rdata4e:call    getatt            ; get file attributes from packet
  870.     mov    cx,0            ; reply length, assume 0/nothing
  871.     jnc    rdat4b            ; nc = success, attributes accepted
  872. rdata4c:mov    cx,2            ; 2 bytes, declining the file
  873.     mov    encbuf,'N'        ; decline the transfer
  874.     mov    al,attrib        ; get attribute causing rejection
  875.     mov    encbuf+1,al        ; report rejection reason to sender
  876.     mov    fsta.xstatus2,al    ; remember attributes reason
  877.     cmp    al,'#'            ; date/time?
  878.     jne    rdata4g            ; ne = no
  879.     mov    flags.cxzflg,0        ; don't say failure
  880.     mov    kstatus,kssuc
  881.     mov    fsta.xstatus,kssuc
  882.     jmp    short rdata4f
  883. rdata4g:or    fsta.xstatus,ksrecv+ksattrib ; set status, failed, attributes
  884.     mov    kstatus,ksrecv+ksattrib    ; global status, failed, attributes
  885. rdata4f:test    flags.remflg,dquiet    ; quiet display?
  886.     jnz    rdat4b            ; nz = yes
  887.     push    si
  888.     push    cx
  889.     push    ax
  890.     mov    dx,offset erms29    ; say rejecting the file
  891.     call    ermsg            ; show rejecting file, then reason
  892.     pop    ax
  893.     mov    dx,offset ferbyte
  894.     cmp    al,'1'            ; Byte count?
  895.     je    rdat4a            ; e = yes
  896.     cmp    al,'!'            ; Kilobyte count?
  897.     je    rdat4a            ; e = yes
  898.     mov    dx,offset ferdate
  899.     cmp    al,'#'            ; Date and Time?
  900.     je    rdat4a            ; e = yes
  901.     mov    dx,offset ferdisp
  902.     cmp    al,'+'            ; Disposition?
  903.     je    rdat4a            ; e = yes
  904.     mov    dx,offset fertype
  905.     cmp    al,'"'            ; File Type?
  906.     je    rdat4a
  907.     mov    dx,offset ferchar
  908.     cmp    al,'*'            ; Transfer Char-set?
  909.     je    rdat4a
  910.     mov    dx,offset fername
  911.     cmp    al,'?'            ; filename collision?
  912.     je    rdat4a            ; e = yes
  913.     mov    dx,offset ferunk    ; unknown reason
  914. rdat4a:    call    prtasz            ; display reason
  915.     pop    cx
  916.     pop    si
  917.                     ; Restart check, multiple A pkts ok
  918. rdat4b:    test    restart_flag,2        ; Binary mode requested?
  919.     jz    rdat6            ; z = no
  920.     test    restart_flag,1        ; Restart and Binary requested?
  921.     jz    rdat6            ; z = no
  922.  
  923. rdat4d:    mov    cl,flags.flwflg        ; Restart OK, save warning flag state
  924.     push    cx            ; reg ax is needed for DX:AX in goopen
  925.     mov    flags.flwflg,filecol_append ; append to existing file
  926.     mov    di,offset decbuf
  927.     mov    byte ptr [di+64],0    ; force in null terminator
  928.     mov    si,offset rdbuf+cmdblen-65 ; holding spot for original name
  929.     call    strcpy            ; copy from holding spot
  930.     push    diskio.sizelo
  931.     push    diskio.sizehi
  932.     call    gofil            ; regularize name again
  933.     pop    diskio.sizehi
  934.     pop    diskio.sizelo
  935.     call    goopen            ; open the file, DX:AX gets length
  936.     pop    cx            ; recover file warning flag state
  937.     mov    flags.flwflg,cl        ; restore state
  938.     jnc    rdat5            ; nc = success
  939.     jmp    giveup            ; failure, dx has message pointer
  940. rdat5:    mov    filopn,2        ; say file is open now
  941.     mov    restart_flag,0        ; clear so first D pkt can proceed
  942.     mov    tfilsz,ax        ; count file chars
  943.     mov    tfilsz+2,dx
  944.     push    ax
  945.     push    dx
  946.     call    kbpr            ; show transfer percentages
  947.     call    perpr
  948.     pop    dx
  949.     pop    ax
  950.     push    di
  951.     mov    di,offset encbuf    ; response buffer
  952.     mov    byte ptr [di],'1'    ; file length (Bytes) specifier
  953.     add    di,2            ; skip specifier and count bytes
  954.     call    lnout            ; convert file length, write to [di++]
  955.     mov    cx,di            ; compute field length
  956.     sub    cx,offset encbuf    ; total field for ACK
  957.     mov    al,cl
  958.     add    al,30            ; (32-2) string length to ascii
  959.     mov    encbuf+1,al        ; length of file size string for doenc
  960.     push    si
  961.     push    es
  962.     mov    si,offset encbuf
  963.     mov    rpacket.datlen,cx    ; size of data field
  964.     les    di,rpacket.datadr
  965.     cld
  966.     rep    movsb            ; copy to packet unencoded
  967.     pop    es
  968.     pop    si
  969.     pop    di
  970.     jmp    rcvpat2
  971.  
  972. rdat6:    push    si
  973.     mov    si,offset rpacket    ; encode to this packet
  974.     call    doenc            ; do encoding
  975.     pop    si
  976. rcvpat2:call    filekind        ; report Text/Bin, char set
  977.     jmp    ackpak            ; ACK the attributes packet
  978. rdata endp
  979.  
  980. ; End of File processor (expects Z type to have been received elsewhere)
  981. ; Enter with packet pointer in SI to a 'Z' packet.
  982. reof    proc    near            ; 'Z' End of File packet
  983.     cmp    flags.cxzflg,0        ; interrupted?
  984.     je    reof5            ; e = no
  985.     call    intmsg            ; show interrupt msg on local screen
  986.     or    errlev,ksrecv        ; set DOS error level
  987.     or    fsta.xstatus,ksrecv+ksuser ; set status, failed + intervention
  988.     mov    kstatus,ksrecv+ksuser    ; global status
  989.     cmp    flags.cxzflg,'X'    ; kill one file?
  990.     jne    reof5            ; ne = no
  991.     mov    flags.cxzflg,0        ; clear ^X so next file survives
  992.                     ; common code for file closing
  993. reof5:    call    dodec            ; decode incoming packet to decbuf
  994.     cmp    decbuf,'D'        ; is the data "D" for discard?
  995.     je    reof6            ; e = yes, delete file
  996.     cmp    filopn,2        ; file opened yet?
  997.     je    reof5b            ; e = yes
  998.     call    goopen            ; open it now (zero length file)
  999.     jnc    reof5a            ; nc = success
  1000.     push    dx
  1001.     call    logtransact
  1002.     pop    dx
  1003.     jmp    giveup            ; failure, dx has message pointer
  1004. reof5a:    mov    filopn,2        ; say file is open now
  1005. reof5b:    call    fileclose        ; close the file
  1006.     jmp    short reof7
  1007.  
  1008. reof6:    cmp    filopn,2        ; is the file open?
  1009.     jne    reof7            ; ne = no, declare success anyway
  1010.     call    fileclose        ; close the file
  1011.     call    filedel            ; delete file incomplete file
  1012. reof6a:    or    errlev,ksrecv        ; set DOS error level
  1013.     or    fsta.xstatus,ksrecv+ksuser ; set status, failed + intervention
  1014.     mov    kstatus,ksrecv+ksuser    ; global status
  1015.  
  1016. reof7:    mov    rstate,'F'
  1017.     call    ackpak0            ; acknowledge the packet
  1018.     call    logtransact
  1019.     mov    diskio.string,0        ; clear file name
  1020.     cmp    flags.cxzflg,'Z'    ; stop file group?
  1021.     je    reof8            ; e = yes
  1022.     mov    flags.cxzflg,0        ; else clear it
  1023. reof8:    ret
  1024. reof    endp
  1025.  
  1026. ; init variables for read
  1027. rrinit    proc    near
  1028.     mov    trans.windo,1        ; one window slot before negotiations
  1029.     mov    cx,drpsiz        ; default receive pkt length (94)
  1030.     call    makebuf            ; construct & clear all buffer slots
  1031.     call    packlen            ; compute packet length
  1032.     xor    ax,ax
  1033.     mov    numpkt,ax        ; set the number of packets to zero
  1034.     mov    windlow,al        ; starting sequence number of zero
  1035.     mov    fsta.pretry,ax        ; set the number of retries to zero
  1036.     mov    filopn,al        ; say no file opened yet
  1037.     mov    windflag,al        ; windows in use init flag
  1038.     mov    fmtdsp,al        ; no formatted display yet
  1039.     mov    diskio.string,al    ; clear active filename buffer
  1040.     mov    fsta.xname,al        ; clear statistics external name
  1041.     mov    restart_flag,al        ; restart file xfer to no
  1042.     ret
  1043. rrinit    endp
  1044.  
  1045. ; Deliver packets organized by sequence number.
  1046. ; Delivers a packet pointer in SI whose sequence number matches windlow.
  1047. ; If necessary a new packet is requested from the packet recognizer. Failures
  1048. ; to receive are managed here and may generate NAKs. Updates formatted screen.
  1049. ; Store packets which do not match windlow, process duplicates and strays.
  1050. ; Error packet and ^C/^E interrupts are detected and managed here.
  1051. ; Return success with carry clear and SI holding the packet structure address.
  1052. ; Return failure with carry set, maybe with a new rstate.
  1053.  
  1054. rcvpak    proc    near
  1055.     mov    al,windlow        ; sequence number we want
  1056.     call    pakptr            ; find pkt pointer with this seqnum
  1057.     mov    si,bx            ; the packet pointer
  1058.     jnc    rcvpa1a            ; nc = got one, else read fresh pkt
  1059.     push    ax
  1060.     mov    al,trans.windo        ; number of window slots negotiated
  1061.     mov    cwindow,al        ; assign as receive window 
  1062.     pop    ax
  1063.     call    getbuf            ; get a new buffer address into si
  1064.     jnc    rcvpa1            ; nc = success
  1065.     mov    dx,offset erms15    ; insufficient buffers
  1066.     jmp    giveup
  1067.  
  1068. rcvpa1:    call    winpr            ; show window slots in use
  1069.     call    rpack            ; receive a packet, si has buffer ptr
  1070.     jc    rcvpa2            ; c = failure to receive, analyze
  1071.     inc    numpkt            ; increment the number of packets
  1072.     cmp    flags.xflg,0        ; receiving to screen?
  1073.     jne    rcvpa1a            ; ne = yes, skip displaying
  1074.     cmp    flags.destflg,dest_screen ; destination is screen?
  1075.     je    rcvpa1a            ; e = yes
  1076.     call    pktsize            ; report packet qty and size
  1077. rcvpa1a:jmp    rcvpa6            ; success, validate
  1078. ; ------------------- failure to receive any packet -------------------------
  1079.                     ; Reception failed. What to do?
  1080. rcvpa2:    call    cntretry        ; update retries, detect ^C, ^E
  1081.     jc    rcvpa2a            ; c = exit now from ^C, ^E
  1082.     call    bufrel            ; discard unused buffer
  1083.     inc    badrcv            ; count receive retries
  1084.     cmp    dostream,0        ; streaming mode negotiated?
  1085.     jne    rcvpa2b            ; ne = yes, fail reception now
  1086.     mov    al,badrcv        ; count # bad receptions in a row
  1087.     cmp    al,maxtry        ; too many?
  1088.     jb    rcvpa4            ; b = not yet, NAK intelligently
  1089. rcvpa2b:mov    dx,offset erms14    ; no response from host
  1090.     jmp    giveup            ; tell the other side
  1091.  
  1092. rcvpa2a:call    bufrel            ; discard unwanted buffer
  1093.     stc                ; set carry for failure
  1094.     ret                ; move to Error state
  1095.  
  1096.                     ; do NAKing
  1097. rcvpa4:    mov    al,windlow        ; Timeout or Crunched packet
  1098.     add    al,trans.windo        ; find next slot after last good
  1099.     dec    al
  1100.     and     al,3fh            ; start at window high
  1101.     mov    ah,-1            ; set a not-found marker
  1102.     mov    cl,trans.windo        ; cx = number of slots to examine
  1103.     xor    ch,ch
  1104. rcvpa4a:call    pakptr            ; sequence number (in AL) in use?
  1105.     jnc    rcvpa4b            ; nc = yes, stop here
  1106.     mov    ah,al            ; remember seqnum of highest vacancy
  1107.     dec    al            ; work backward in sequence numbers
  1108.     and    al,3fh
  1109.     loop    rcvpa4a
  1110.  
  1111. rcvpa4b:mov    al,ah            ; last-found empty slot (-1 = none)
  1112.     cmp    ah,-1            ; found a vacant slot?
  1113.     jne    rcvpa4c            ; ne = no, else use first free seqnum
  1114.     call    firstfree        ; set AL to first open slot
  1115.     jc    rcvpa4d            ; c = no free slots, an error
  1116. rcvpa4c:mov    rpacket.seqnum,al    ; NAK this unused sequence number
  1117.     call    nakpak            ; NAK using rpacket
  1118.     jc    rcvpa4d            ; c = failure on sending operation
  1119.     stc                ; rcv failure, stay in current state
  1120.     ret
  1121.  
  1122. rcvpa4d:mov    dx,offset erms13    ; failure, cannot send reply
  1123.     jmp    giveup            ; show msg, change states
  1124. ; ------------------------- received a packet ------------------------------
  1125.             ; remove duplicates, validate sequence number
  1126. rcvpa6:    mov    badrcv,0        ; clear retry counter
  1127.     cmp    [si].pktype,'E'        ; Error packet? Accept w/any seqnum
  1128.     jne    rcvpa6a            ; ne = no
  1129.     call    error            ; display message, change states
  1130.     stc
  1131.     ret
  1132. rcvpa6a:mov    al,[si].seqnum        ; this packet's sequence number
  1133.     mov    rpacket.seqnum,al    ; save here for reply
  1134.     call    pakdup            ; set ah to number of copies
  1135.     cmp    ah,1            ; more than one copy?
  1136.     jbe    rcvpa7            ; be = no, just one
  1137.     call    bufrel            ; discard duplicate
  1138.     mov    al,rpacket.seqnum    ; recover current sequence number
  1139.     call    pakptr            ; get packet pointer for original
  1140.     mov    si,bx            ; should not fail if pakdup works ok
  1141.     jnc    rcvpa7            ; nc = ok, work on the original again
  1142.     ret                ; say failure, stay in current state
  1143.  
  1144. rcvpa7:    call    chkwind            ; validate sequence number (cx=status)
  1145.     jc    rcvpa7b            ; c = outside current window
  1146.     mov    al,[si].seqnum        ; get sequence number again
  1147.     cmp    al,windlow        ; is it the desired sequence number?
  1148.     jne    rcvpa7a            ; ne = no, do not change states yet
  1149.     clc
  1150.     ret                ; return success, SI has packet ptr
  1151.  
  1152. rcvpa7a:stc                ; not desired pkt, stay in this state
  1153.     ret                ; do not increment retry counter here
  1154.  
  1155. rcvpa7b:or    cx,cx            ; inside previous window?
  1156.     jg    rcvpa7c            ; g = outside any window, ignore it
  1157.     mov    al,[si].pktype        ; get packet Type
  1158.     cmp    al,'I'            ; let 'I' and 'S' pkts be reported
  1159.     je    rcvpa7d            ; even if in previous window, to
  1160.     cmp    al,'S'            ; accomodate lost ack w/data
  1161.     je    rcvpa7d
  1162.     cmp    al,'Y'            ; maybe our ACK echoed?
  1163.     je    rcvpa7c            ; e = yes, discard
  1164.     cmp    al,'N'            ; or our NAK echoed?
  1165.     je    rcvpa7c            ; e = yes, discard
  1166.     call    ackpak0            ; previous window, ack and ignore it
  1167.     stc                ; rcv failure, stay in current state
  1168.     ret
  1169.  
  1170. rcvpa7c:call    bufrel            ; ignore packet outside of any window
  1171.     stc                ; rcv failure, stay in current state
  1172.     ret
  1173.  
  1174. rcvpa7d:mov    rstate,'R'        ; redo initialization when 'I'/'S'
  1175.     stc                ;  are observed, keep current pkt
  1176.     ret
  1177. rcvpak    endp
  1178.  
  1179. ; Send ACK packet. Enter with rpacket data field set up.
  1180. ; ACKPAK sends ack with data, ACKPAK0 sends ack without data.
  1181. ackpak    proc    near            ; send an ACK packet
  1182.     cmp    rpacket.datlen,0    ; really just no data?
  1183.     jne    ackpa2            ; ne = no, send prepared ACK packet
  1184.  
  1185. ackpak0:mov    rpacket.datlen,0    ; no data
  1186.     cmp    flags.cxzflg,0        ; user interruption?
  1187.     je    ackpa2            ; e = no
  1188.     push    cx            ; yes, send the interrupt character
  1189.     push    si
  1190.     mov    si,offset rpacket
  1191.     mov    cl,flags.cxzflg        ; send this so host knows about ^X/^Z
  1192.     mov    encbuf,cl        ; put datum into the encode buffer
  1193.     mov    cx,1            ; data size of 1 byte
  1194.     call    doenc            ; encode, char count is in cx
  1195.     pop    si
  1196.     pop    cx
  1197. ackpa2:    mov    rpacket.pktype,'Y'    ; ack packet
  1198.     mov    rpacket.numtry,0
  1199. ackpa3:    cmp    flags.cxzflg,0        ; user interruption?
  1200.     jne    ackpa3b            ; ne = yes
  1201.     cmp    dostream,0        ; streaming mode negotiated?
  1202.     jne    ackpa4            ; ne = yes, simulate succesful send
  1203. ackpa3b:push    si
  1204.     mov    si,offset rpacket
  1205.     call    spack            ; send the packet
  1206.     pop    si
  1207.     jnc    ackpa4            ; nc = success
  1208.     cmp    flags.cxzflg,'C'    ; Control-C abort?
  1209.     je    ackpa3a            ; e = yes, quit now
  1210.     cmp    flags.cxzflg,'E'    ; Control-E abort?
  1211.     je    ackpa3a            ; e = yes, quit now
  1212.     push    ax            ; send failure, retry
  1213.     mov    ax,100            ; 0.1 sec
  1214.     call    pcwait            ; small wait between retries
  1215.     inc    rpacket.numtry
  1216.     mov    al,rpacket.numtry
  1217.     cmp    al,maxtry        ; exceeded retry limit?
  1218.     pop    ax
  1219.     jbe    ackpa3            ; be = ok to try again
  1220.     mov    sstate,'A'        ; set states to abort
  1221.     mov    rstate,'A'
  1222.     mov    rpacket.numtry,0
  1223.     mov    dx,offset erms13    ; unable to send reply
  1224.     jmp    giveup
  1225. ackpa3a:stc                ; set carry for failure
  1226.     ret
  1227.  
  1228. ackpa4:
  1229.     cmp    dostream,0        ; streaming mode negotiated?
  1230.     je    ackpa4a            ; e = no
  1231.     mov    flags.cxzflg,0        ; so we don't repeat CXZ ACK send
  1232. ackpa4a:mov    al,rpacket.seqnum    ; success
  1233.     mov    rpacket.datlen,0    ; clear old contents
  1234.     call    pakptr            ; acking an active buffer?
  1235.     jc    ackpa5            ; c = no such seqnum, stray ack
  1236.     push    si
  1237.     mov    si,bx            ; packet pointer from pakptr
  1238.     call    bufrel            ; release ack'ed packet
  1239.     pop    si
  1240.     mov    rpacket.numtry,0
  1241.     cmp    al,windlow        ; acking window low?
  1242.     jne    ackpa5            ; ne = no
  1243.     mov    al,windlow        ; yes, rotate the window
  1244.     inc    al
  1245.     and    al,3fh
  1246.     mov    windlow,al
  1247. ackpa5:    clc
  1248.     ret
  1249. ackpak    endp
  1250.  
  1251. ; Send a NAK. Uses rpacket structure.
  1252. NAKPAK    proc    near
  1253.     mov    rpacket.numtry,0
  1254. nakpa2:    push    si
  1255.     mov    si,offset rpacket
  1256.     mov    [si].datlen,0        ; no data
  1257.     inc    fsta.nakscnt        ; count NAKs sent
  1258.         mov    [si].pktype,'N'        ; NAK that packet
  1259.     cmp    dostream,0        ; streaming mode negotiated?
  1260.     je    nakpa2a            ; e = no, send the packet
  1261.     clc                ; simulate successful send
  1262.     jmp    short nakpa2b        ;  do not send NAK
  1263. nakpa2a:call    spack
  1264. nakpa2b:pop    si
  1265.     jc    nakpa3            ; c = failure
  1266.     mov    rpacket.numtry,0
  1267.     clc
  1268.     ret                ; return success
  1269.  
  1270. nakpa3:    cmp    flags.cxzflg,'C'    ; Control-C abort?
  1271.     je    nakpa3a            ; e = yes, quit now
  1272.     cmp    flags.cxzflg,'E'    ; Control-E abort?
  1273.     je    nakpa3a            ; e = yes, quit now
  1274.     push    ax            ; send failure, retry
  1275.     mov    ax,100            ; wait 0.1 second
  1276.     call    pcwait
  1277.     inc    rpacket.numtry        ; count attempts to respond
  1278.     mov    al,rpacket.numtry
  1279.     cmp    al,maxtry        ; tried enough times?
  1280.     pop    ax
  1281.     jbe    nakpa2            ; be = ok to try again
  1282.     mov    sstate,'A'        ; set states to abort
  1283.     mov    rstate,'A'
  1284.     mov    rpacket.numtry,0
  1285.     mov    dx,offset erms13    ; unable to send reply
  1286.     jmp    giveup
  1287. nakpa3a:stc
  1288.     ret                ; return failure
  1289. NAKPAK    ENDP
  1290.  
  1291. ; Close, but do not delete, output file. Update file attributes,
  1292. ; add Control-Z or Control-L, if needed.
  1293. fileclose proc    near
  1294.     cmp    filopn,0        ; is a file open?
  1295.     jne    filec0            ; ne = yes
  1296.     ret
  1297. filec0:    cmp    flags.xflg,0        ; receiving to screen?
  1298.     jne    filec2            ; ne = yes
  1299.     cmp    flags.destflg,dest_disk ; destination is disk?
  1300.     jne    filec1            ; ne = no
  1301.     cmp    flags.eofcz,0        ; should we write a ^Z?
  1302.     je    filec1            ; e = no, keep going
  1303.     cmp    trans.xtype,0        ; text mode tranfer?
  1304.     jne    filec2            ; ne = no, binary, no ^Z
  1305.     push    si
  1306.     mov    rpacket.datlen,1    ; one byte to decode and write
  1307.     push    es
  1308.     les    si,rpacket.datadr    ; source buffer address
  1309.     mov    byte ptr es:[si],'Z'-40h ; put Control-Z in buffer
  1310.     pop    es
  1311.     mov    si,offset rpacket    ; address for decoder
  1312.     call    ptchr            ; decode and write to output
  1313.     pop    si
  1314. filec1:    cmp    flags.destflg,dest_printer ; file destination is printer?
  1315.     jne    filec2            ; ne = no, skip next part
  1316.     push    si
  1317.     mov    rpacket.datlen,1    ; one byte to decode and write
  1318.     push    es
  1319.     les    si,rpacket.datadr    ; source buffer address
  1320.     mov    byte ptr es:[si],'L'-40h ; put Control-L (FF) in buffer
  1321.     pop    es
  1322.     mov    si,offset rpacket    ; address for decoder
  1323.     call    ptchr            ; decode and write to output
  1324.     pop    si
  1325. filec2:    mov    ah,write2        ; write to file
  1326.     xor    cx,cx            ; write 0 bytes to truncate length
  1327.     mov    bx,diskio.handle    ; file handle
  1328.     or    bx,bx            ; valid handle?
  1329.     jl    filec5            ; l = no
  1330.     int    dos
  1331.     xor    al,al            ; get device info
  1332.     mov    ah,ioctl
  1333.     int    dos
  1334.     test    dl,80h            ; bit set if handle is for a device
  1335.     jnz    filec4            ; nz = non-disk, no file attributes
  1336.                     ; do file attributes and close
  1337.     mov    cx,word ptr ftime    ; new time
  1338.     mov    dx,word ptr fdate    ; new date
  1339.     mov    word ptr fdate,0
  1340.     mov    word ptr ftime,0    ; clear current time/date attributes
  1341.     or    dx,dx            ; any date?
  1342.     jz    filec4            ; z = no attributes to set
  1343.     or    cx,cx            ; time set as null?
  1344.     jnz    filec3            ; nz = no
  1345.     inc    cl            ; two seconds past midnight
  1346. filec3:    mov    ah,fileattr        ; set file date/time attributes
  1347.     mov    al,1            ; set, not get
  1348.     mov    bx,diskio.handle    ; file handle
  1349.     int    dos            ; end of file attributes
  1350. filec4:    mov    bx,diskio.handle    ; file handle
  1351.     push    dx            ; save dx
  1352.     mov    ah,close2        ; close file
  1353.     int    dos
  1354.     pop    dx
  1355.     mov    diskio.handle,-1
  1356.     mov    filopn,0        ; say file is closed
  1357. filec5:    ret
  1358. fileclose endp
  1359.  
  1360. ; Delete file whose asciiz name is in diskio.string
  1361. filedel    proc    near
  1362.     cmp    flags.flwflg,filecol_update ; update an existing file?
  1363.     je    filede2            ; e = yes
  1364.     mov    dx,offset diskio.string    ; file name, asciiz
  1365.     xor    ax,ax
  1366.     cmp    diskio.string,al    ; filename present?
  1367.     je    filede2            ; e = no
  1368.     cmp    flags.abfflg,al        ; keep incomplete file?
  1369.     je    filede2            ; e = yes
  1370.     test    flags.remflg,dquiet    ; quiet display?
  1371.     jnz    filede1            ; nz = yes
  1372.     cmp    flags.xflg,al        ; receiving to screen?
  1373.     jne    filede1            ; ne = yes, no message
  1374.     push    dx
  1375.     call    cxmsg            ; clear Last message line
  1376.     mov    dx,offset infms7    ; saying Discarding file
  1377.     mov    ah,prstr
  1378.     int    dos
  1379.     pop    dx
  1380.     call    prtasz            ; show filename
  1381. filede1:mov    ah,del2            ; delete the file
  1382.     int    dos
  1383. filede2:ret
  1384. filedel    endp
  1385.  
  1386. ; Error exit. Enter with dx pointing to asciiz error message.
  1387. ; Sends 'E' Error packet and shows message on screen. Changes state to 'A'.
  1388. ; Always returns with carry set.
  1389. giveup    proc    near
  1390.     cmp    flags.destflg,dest_screen ; receiving to the screen?
  1391.     je    giveu1            ; e = yes, no formatted display
  1392.     call    ermsg            ; show msg on error line
  1393. giveu1:    mov    bx,dx            ; set bx to error message
  1394.     call    errpack            ; send error packet just in case
  1395.     mov    rstate,'A'        ; change the state to abort
  1396.     stc                ; set carry
  1397.     ret
  1398. giveup    endp
  1399.  
  1400. ; ERROR sets abort state, positions the cursor and displays the Error message.
  1401.  
  1402. ERROR    PROC    NEAR
  1403.     mov    rstate,'A'        ; set state to abort
  1404.     call    dodec            ; decode to decbuf
  1405.     mov    dx,offset decbuf    ; where msg got decoded, asciiz
  1406.     call    ermsg            ; show string
  1407.     stc                ; set carry for failure state
  1408.     ret
  1409. ERROR    ENDP
  1410.  
  1411. ; Called by GETATT in receiver code to verify sufficient disk space.
  1412. ; Gets file path from diskio.string setup in mssfil, remote size in diskio
  1413. ; from getatt, and whether a disk file or not via ioctl on the file handle.
  1414. ; Returns carry clear if enough space.
  1415. spchk    proc    near            ; check for enough disk space
  1416.     push    ax
  1417.     push    bx
  1418.     push    cx
  1419.     push    dx
  1420.     cmp    filtst.fstat2,0        ; disk file?
  1421.     jne    spchk5b            ; ne = no, always enough space
  1422.     mov    ah,gcurdsk        ; get current disk
  1423.     int    dos
  1424.     add    al,'A'            ; make 0 == A
  1425.     mov    cl,al            ; assume this drive
  1426.     mov    dx,word ptr diskio.string ; filename used in open
  1427.     cmp    dh,':'            ; drive letter given?
  1428.     jne    spchk1            ; ne = no
  1429.     mov    cl,dl            ; get the letter
  1430.     and    cl,not 20h        ; convert to upper case
  1431. spchk1:    call    dskspace        ; calculate space into dx:ax
  1432.     jc    spchk6            ; c = error
  1433.     cmp    restart_flag,0        ; doing a restart?
  1434.     jne    spchk1a            ; ne = yes (pretend file removal)
  1435.     cmp    flags.flwflg,filecol_update ; updating?
  1436.     je    spchk1a            ; e = yes, file will be removed
  1437.     cmp    flags.flwflg,filecol_overwrite    ; overwrite existing file?
  1438.     jne    spchk1b            ; ne = no, file will be kept
  1439. spchk1a:add    ax,diskio.sizelo    ; add size of file to be removed
  1440.     adc    dx,diskio.sizehi    ;  to current disk space
  1441. spchk1b:push    ax            ; save low word of bytes
  1442.     push    dx            ; save high word, dx:ax
  1443.     mov    dx,diskio.sizehi    ; high word of file size dx:ax
  1444.     mov    ax,diskio.sizelo    ; low word
  1445.     cmp    trans.xtype,1        ; binary transfer?
  1446.     je    spchk5a            ; e = yes, do not inflate file size
  1447.     mov    cx,dx            ; copy size long word to cx:bx
  1448.     mov    bx,ax
  1449.     shr    bx,1            ; divide long word by two
  1450.     shr    cx,1
  1451.     jnc    spchk2            ; nc = no carry down
  1452.     or    bx,8000h        ; get carry down
  1453. spchk2:    shr    bx,1            ; divide by two again
  1454.     shr    cx,1
  1455.     jnc    spchk3
  1456.     or    bx,8000h        ; get carry down
  1457. spchk3:    shr    bx,1            ; divide long word by two
  1458.     shr    cx,1
  1459.     jnc    spchk4            ; nc = no carry down
  1460.     or    bx,8000h        ; get carry down
  1461. spchk4:    shr    bx,1            ; divide long word by two
  1462.     shr    cx,1
  1463.     jnc    spchk4a            ; nc = no carry down
  1464.     or    bx,8000h        ; get carry down
  1465. spchk4a:shr    bx,1            ; divide long word by two
  1466.     shr    cx,1
  1467.     jnc    spchk4b            ; nc = no carry down
  1468.     or    bx,8000h        ; get carry down
  1469. spchk4b:shr    bx,1            ; divide long word by two
  1470.     shr    cx,1
  1471.     jnc    spchk5            ; nc = no carry down
  1472.     or    bx,8000h        ; get carry down
  1473. spchk5:    add    ax,bx            ; form dx:ax = (65/64) * dx:ax
  1474.     adc    dx,cx
  1475. spchk5a:pop    cx            ; high word of disk space
  1476.     pop    bx            ; low word
  1477.     sub    bx,ax            ; minus inflated file size, low word
  1478.     sbb    cx,dx            ;  and high word
  1479.     js    spchk6            ; s = not enough space for file
  1480. spchk5b:clc
  1481.     jmp    short spchk7        ; enough space
  1482. spchk6:    stc                ; indicate failure
  1483. spchk7:    pop    dx
  1484.     pop    cx
  1485.     pop    bx
  1486.     pop    ax
  1487.     ret
  1488. spchk    endp
  1489.  
  1490. code    ends
  1491.     end
  1492.