home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis3.arc / MSSSEN.ASM < prev    next >
Assembly Source File  |  1990-01-14  |  61KB  |  1,866 lines

  1.     NAME    msssen
  2. ; File MSSSEN.ASM
  3.     include mssdef.h
  4. ; Edit history:
  5. ; Last edit 14 Jan 1990
  6. ; Sliding Windows
  7.  
  8.     public    spar, rpar, nout, send, flags, trans, dtrans, packlen
  9.     public    send10, mail, newfn, errpack, sstate, response, ackmsg
  10.     public    pktnum, numpkt, cntretry, sndpak, sparmax
  11.  
  12. spmin    equ    20        ; Minimum packet size
  13. spmax    equ    94        ; Maximum packet size
  14.  
  15. data     segment    public 'data'
  16.     extrn    fsta:word, auxfile:byte, encbuf:byte, decbuf:byte, maxtry:byte
  17.     extrn    errlev:byte, kstatus:word, diskio:byte, rpacket:byte
  18.     extrn    windflag:byte, rstate:byte, fmtdsp:byte, windlow:byte
  19.     extrn    charids:word
  20.  
  21. flags    flginfo    <>
  22. trans    trinfo    <>        ; negotiated trans information
  23. dtrans    trinfo    <>        ; default trans information
  24. crlf    db    cr,lf,'$'
  25. ender    db    bell,bell,'$'
  26. cemsg    db    'User intervention',0
  27. erms14  db    'No response from the host',0
  28. erms15    db    'File not found',0
  29. erms16    db    'Unknown packet type',0
  30. erms17    db    'Too many retries',0
  31. erms24    db    'Unable to send packet',0
  32. erms25    db    'Host does not support Kermit MAIL command',0
  33. erms26    db    'File rejected by host',0
  34. erms27    db    'Error. No buffers in send routine',0
  35. erms30    db    ': File size',0
  36. erms31    db    ': Date/time',0
  37. erms32    db    ': Mailing refused',0
  38. erms33    db    ': File Type',0
  39. erms34    db    ': Transfer Char-set',0
  40. erms36    db    ': Unknown reason',0
  41. infms1  db    cr,'             Sending: In progress',cr,lf,'$'
  42. infms2  db    cr,'             Mailing: In progress',cr,lf,'$'
  43. infms3  db    'Completed',cr,lf,'$'
  44. infms4  db    'Failed',cr,lf,'$'
  45. infms5    db    'Remote name is ',0
  46. filhlp  db      ' A filename (possibly wild)$'
  47. filmsg    db    ' Local Source File  or press ENTER for prompts$'
  48. remfnm    db    ' Remote Destination File: ',0    ; asciiz
  49. lclfnm    db    ' Local Source File: ',0    ; asciiz
  50. mailhlp    db    ' Filename  mail-address  or press ENTER for prompts$'
  51. mailto    db    ' To: ',0            ; asciiz
  52. mailtohlp db    ' mail address (eg, user@host or host::user)$'
  53. mailflg    db    0        ; 1 if Mail, 0 if Send command
  54. asmsg    db    ' as ',0
  55. sstate    db    0        ; current automata state
  56. pktnum    db    0        ; packet number
  57. sndcnt    db    0        ; retry counter for sndpak, internal
  58. filopn    db    0        ; 1 if disk file is open for reading
  59. tempseq    db    0        ; target sequence number for responses
  60. retry    db    0        ; current retry threshold
  61.     even
  62. attlist    dw    sat1t,sat2t,sat3t,sat4t,sat5t,sat6t,sat7t,0 ;attrib procedures
  63. attptr    dw    0        ; pointer to items in attlist
  64. numpkt    dw    0        ; number of packets for file group
  65. temp    dw    0
  66. temp4    dw    0
  67. ninefive dw    95        ; constant word for long packets
  68. data    ends
  69.  
  70. code    segment    public 'code'
  71.     extrn serini:near, comnd:near, init:near
  72.     extrn spack:near, rpack:near, gtnfil:near, gtchr:near
  73.     extrn getfil:near, rprpos:near, prtasz:near, cxerr:near
  74.     extrn ermsg:near, rtmsg:near, cxmsg:near, stpos:near, decout:near
  75.     extrn doenc:near, dodec:near, lnout:near, getbuf:near, winpr:near
  76.     extrn prompt:near, intmsg:near, chkwind:near, msgmsg:near
  77.     extrn strcpy:near, strlen:near, pktsize:near
  78.     extrn pcwait:near, ihostr:near, begtim:near, endtim:near, makebuf:near
  79.     extrn bufclr:near, pakptr:near, bufrel:near,isfile:near
  80.  
  81.     assume    cs:code, ds:data, es:nothing
  82.  
  83. ; Data structures comments.
  84. ; Sent raw text material (typically rpar and filenames) is placed in encbuf,
  85. ; which may be encoded by doenc. doenc needs an output buffer provided as
  86. ; a pointer generated here via procedure buflist. encbuf is 512 bytes long.
  87. ; Sent packet material is placed in buffers pointed at by buflist. These
  88. ; buffers are subdivisions of one large buffer bufbuf (private to msscom).
  89. ; Proceedure makebuf does the subdivision and initialization of contents.
  90. ; Received material is directed to buffer rbuf which is part of structure
  91. ; rpacket; rbuf is 128 bytes long.
  92. ; Rpack and Spack expect a pointer in SI to the packet data field, done in a
  93. ; pktinfo format.
  94.  
  95. ;    SEND filespec  command
  96. ;    MAIL filspec user@node  command
  97.  
  98. SEND    PROC    NEAR
  99.     mov    mailflg,0        ; Send command, not Mail command
  100.     mov    temp,0
  101.     jmp    short send1        ; join common code
  102.  
  103. MAIL:    mov    mailflg,1        ; set flag for Mail command vs Send
  104.     mov    temp,1            ; temp copy of mailflag
  105.  
  106. send1:    mov    auxfile,0        ; clear send-as name (in case none)
  107.     mov    dx,offset diskio.string ; address of filename string
  108.     mov    bx,offset filmsg    ; help message
  109.     cmp    mailflg,0        ; Mail command?
  110.     je    send2            ; e = no
  111.     mov    mailflg,0        ; clear in case error exit
  112.     mov    bx,offset mailhlp    ; help message
  113. send2:    mov    ah,cmword        ; get input file spec
  114.     call    comnd
  115.     jnc    send2a            ; nc = success
  116.     ret                ; failure
  117. send2a:    cmp    diskio.string,'#'    ; first char a replacement for '?'?
  118.     jne    send2b            ; ne = no
  119.     mov    diskio.string,'?'    ; yes. Change '#' for '?'
  120. send2b:    cmp    ah,0            ; any text given?
  121.     je    send3            ; e = no, prompt
  122.     cmp    temp,0            ; Mail command?
  123.     jne    send5            ; ne = yes, require address
  124.     mov    bx,offset auxfile         ; send file under different name?
  125.     mov    dx,offset filhlp    ; help
  126.     mov    ah,cmline        ; allow embedded white space
  127.     call    comnd
  128.     jnc    send2c            ; nc = success
  129.     ret                ; failure
  130. send2c:    cmp    auxfile,'#'        ; first char a replacement for '?'?
  131.     jne    send2d            ; ne = no
  132.     mov    auxfile,'?'        ; change '#' to '?'
  133. send2d:    jmp    send6            ; join common completion code
  134.  
  135. send3:    mov    dx,offset lclfnm    ; prompt for local filename
  136.     call    prompt
  137.     mov    dx,offset diskio.string ; reload destination of user's text
  138.     mov    bx,offset filhlp    ; help
  139.     mov    ah,cmword        ; get filename
  140.     call    comnd            ; try again for a local filename
  141.     jnc    send3a            ; nc = success
  142.     ret                ; failure
  143. send3a:    cmp    diskio.string,'#'    ; first char a replacement for '?'?
  144.     jne    send3b            ; ne = no
  145.     mov    diskio.string,'?'    ; yes. Change '#' for '?'
  146. send3b:    mov    temp4,ax
  147.     mov    ah,cmeol        ; get the terminating CR
  148.     call    comnd
  149.     jnc    send3c            ; nc = success
  150.     ret                ; failure
  151. send3c:    mov    ax,temp4
  152.     cmp    ah,0            ; user's byte count
  153.     je    send3            ; e = nothing was typed, get some
  154.  
  155. send4:    mov    dx,offset remfnm    ; ask for remote name first
  156.     cmp    temp,0            ; Mail command?
  157.     je    send4a            ; e = no
  158.     mov    dx,offset mailto    ; ask for name@host
  159. send4a:    call    prompt
  160. send5:    mov    bx,offset auxfile         ; send file under different name?
  161.     mov    dx,offset filhlp    ; help
  162.     cmp    temp,0            ; Mail command?
  163.     je    send5a            ; e = no
  164.     mov    dx,offset mailtohlp    ; help
  165. send5a:    mov    ah,cmline        ; allow embedded white space
  166.     call    comnd
  167.     jnc    send5b            ; nc = success
  168.     ret                ; failure
  169. send5b:    cmp    ah,0            ; text entered?
  170.     je    send4            ; e = no, get some
  171.  
  172. send6:    mov    flags.xflg,0        ; reset flag for normal file send[mtd]
  173.     mov    sstate,0        ; dummy state, must be illegal
  174.     mov    ax,temp            ; get temp mailflag
  175.     mov    mailflg,al        ; store in secure area for later
  176.     mov    ah,trans.sdelay        ; seconds to delay before sending
  177.     shl    ah,1            ; times 4*256 to get millisec
  178.     shl    ah,1            ;  for pcwait
  179.     mov    al,1            ; set low byte to 1 for no delay case
  180.     call    pcwait            ; wait number of millisec in ax    
  181. SEND10:                ; SEND10 is an entry point for REMote cmds
  182.     mov    kstatus,0        ; global status, success
  183.     mov    windflag,0        ; init windows in use display flag
  184.     call    makebuf            ; make some packet buffers
  185.     call    packlen            ; compute packet length
  186.     call    cxerr            ; clear Last Error line
  187.     call    cxmsg            ; clear Last Message line
  188.     mov    ax,offset diskio.string    ; filename to send, can be wild
  189.     call    isfile            ; does file exist?
  190.     jnc    send12            ; carry reset = yes, file found
  191.     cmp    sstate,'S'        ; was this from a remote GET?
  192.     jne    send11            ; ne = no, print error and continue
  193.     mov    dx,offset erms15    ; file not found
  194.     mov    trans.chklen,1        ; send init checksum is always 1 char
  195.     call    ermsg
  196.     mov    bx,dx
  197.     call    errpack            ; go complain
  198.     mov    sstate,'A'        ; abort
  199.     ret
  200.  
  201. send11:    mov    ah,prstr
  202.     mov    dx,offset crlf
  203.     int    dos
  204.     mov    dx,offset erms15    ; 'file not found'
  205.     call    prtasz
  206.     or    errlev,1        ; set DOS error level
  207.     or    fsta.xstatus,1        ; set status
  208.     mov    kstatus,1        ; global status
  209.     mov    mailflg,0        ; clear Mail flag
  210.     clc                ; pretend successful completion
  211.     ret
  212.  
  213. send12:    call    serini            ; initialize serial port
  214.     jnc    send13            ; nc = success
  215.     or    errlev,1        ; say send failed
  216.     or    fsta.xstatus,1        ; set status
  217.     mov    kstatus,1        ; global status
  218.     mov    dx,offset erms14    ; no response from host
  219.     call    ermsg            ; show message
  220.     stc                ; return failure
  221.     ret
  222.  
  223. send13:    mov    pktnum,0        ; set the packet number to zero
  224.     mov    fsta.pretry,0         ; set the number of retries to zero
  225.     mov    numpkt,0        ; number pkts send in this file group
  226.     mov    flags.cxzflg,0
  227.     mov    sstate,'S'        ; set the state to send initiate
  228.     call    ihostr            ; initialize the host (clear NAKs)
  229.     call    init            ; clear line and initialize buffers
  230.     test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  231.     jnz    send15            ; nz = yes, surpress msgs
  232.     call    stpos            ; show status of file transfer
  233.     mov    dx,offset infms1    ; Sending in progress message
  234.     cmp    mailflg,0        ; Sending, vs Mailing?
  235.     je    send14            ; e = yes, sending
  236.     mov    dx,offset infms2    ; Mailing in progress message
  237. send14:    mov    ah,prstr
  238.     int    dos
  239. send15:    jmp    dispatch        ; sstate has initial state ('S')
  240. SEND    ENDP
  241.  
  242. dispatch proc    near            ; Dispatch on state variable sstate
  243.     mov    ah,sstate
  244.     cmp    ah,'S'            ; send initiate state?
  245.     jne    dispat2            ; ne = no
  246.     call    sinit            ; negotiate
  247.     jmp    dispatch
  248.  
  249. dispat2:cmp    ah,'F'            ; file header state?
  250.     jne    dispat3            ; ne = no
  251.     call    sfile            ; send file header
  252.     jmp    dispatch
  253.  
  254. dispat3:cmp    ah,'a'            ; send attributes state?
  255.     jne    dispat4            ; ne = no
  256.     call    sattr            ; send attributes
  257.     jmp    dispatch
  258.  
  259. dispat4:cmp    ah,'D'            ; data send state?
  260.     jne    dispat5            ; ne = no
  261.     call    sdata            ; send data
  262.     jmp    dispatch
  263.  
  264. dispat5:cmp    ah,'Z'            ; EOF state?
  265.     jne    dispat6
  266.     call    seof            ; do EOF processing
  267.     jmp    dispatch
  268.  
  269. dispat6:cmp    ah,'B'            ; end of file group state?
  270.     jne    dispat7
  271.     call    seot
  272.     jmp    dispatch
  273.  
  274. dispat7:cmp    ah,'E'            ; user intervention ^C or ^E?
  275.     jne    dispat8            ; ne = no
  276.     call    bufclr
  277.     mov    bx,offset cemsg        ; user intervention message
  278.     call    errpack            ; send error message
  279.     call    intmsg            ; show interrupt msg for Control-C-E
  280.  
  281. dispat8:push    ax                ; 'A' abort or 'C' completion
  282.     pop    ax
  283.     mov    mailflg,0        ; clear Mail flag
  284.     call    bufclr            ; release all buffers
  285.     mov    windlow,0
  286.     mov    pktnum,0
  287.     call    stpos            ; show status of file transfer
  288.     mov    dx,offset infms3    ; Completed message
  289.     cmp    sstate,'C'        ; send complete state?
  290.     je    dispat9            ; e = yes, else failure
  291.     mov    dx,offset infms4    ; Failed message
  292.     or    errlev,1        ; say send failed
  293.     or    fsta.xstatus,1        ; set status
  294.     mov    kstatus,1        ; global status
  295.  
  296. dispat9:test    flags.remflg,dquiet+dserial ; quiet or serial display mode?
  297.     jnz    dispa9a            ; nz = yes, keep going
  298.     mov    ah,prstr        ; show completed/failed message
  299.     int    dos
  300. dispa9a:cmp    flags.cxzflg,0        ; completed normally?
  301.     je    dispa10            ; e = yes
  302.     or    errlev,1        ; say send failed
  303.     or    fsta.xstatus,1+80h    ; set status, failed + intervention
  304.     mov    kstatus,1+80h        ; global status
  305. dispa10:mov    ax,1        ; tell statistics this was a send operation
  306.     call    endtim            ; stop statistics counter
  307.     test    flags.remflg,dquiet    ; quiet display mode?
  308.     jnz    dispa13            ; nz = yes, no talking
  309.     call    intmsg            ; show any interruption
  310.     cmp    flags.belflg,0        ; Bell desired?
  311.     je    dispa13            ; e = no
  312.     mov    ah,prstr
  313.     mov    dx,offset ender        ; ring bells
  314.     int    dos
  315. dispa13:call    rprpos
  316.     mov    flags.cxzflg,0        ; clear flag for next command
  317.     mov    auxfile,0        ; clear send-as filename buffer
  318.     mov    flags.xflg,0        ; clear to-screen flag
  319.     mov    diskio.string,0        ; clear active filename buffer
  320.     mov    fsta.xname,0        ; clear statistics external name
  321.     clc
  322.     ret                ; return to main command parser
  323. dispatch endp
  324.  
  325. ; Enter with filespec in diskio.string, external name/mail address in auxfile
  326.  
  327. ; Send Initiate packet
  328. SINIT    PROC    NEAR
  329.     call    begtim            ; get tod for start of transfer
  330.     mov    trans.windo,1        ; one window slot before negotiations
  331.     call    makebuf            ; remake buffers for new windowing
  332.     call    packlen            ; compute packet length
  333.     mov    windlow,0        ; window lower border
  334.     mov    pktnum,0        ; sequence number to use
  335.     mov    windflag,0        ; windows in use display flag
  336.     mov    al,dtrans.xchset    ; reset Transmission char set
  337.     mov    trans.xchset,al        ;  to the current user default
  338.     mov    al,dtrans.xtype        ; ditto for File Type
  339.     mov    trans.xtype,al
  340.     call    getbuf            ; get a buffer address into si
  341.     call    sparmax            ; set up our maximum capabilities
  342.     call    rpar            ; put them into the packet
  343.     mov    trans.chklen,1        ; Send init checksum is always 1 char
  344.     mov    [si].pktype,'S'        ; send-initiate packet
  345.     call    sndpak            ; send the packet
  346.     jnc    sinit2            ; nc = successful send
  347.     ret                ; failure, change state
  348.  
  349. sinit2:    mov    al,pktnum        ; packet just sent
  350.     mov    ah,maxtry        ; normal retry threshold
  351.     add    ah,ah
  352.     add    ah,maxtry        ; triple the normal threshold
  353.     call    response        ; get response
  354.     jnc    sinit3            ; nc = success
  355.     ret
  356.  
  357. sinit3:    push    si            ; ACK in window
  358.     mov    si,offset rpacket    ; point to packet for spar
  359.     call    spar            ; parse the received data
  360.     pop    si
  361.     call    makebuf            ; remake buffers for new windowing
  362.     call    packlen            ; update max send packet size
  363.     mov    pktnum,1        ; next sequence number after 'S' pkts
  364.     mov    windlow,1        ; lowest acceptable sequence received
  365.     cmp    mailflg,0        ; non-zero to do Mail command
  366.     je    sinit4            ; e = send, not mail command
  367.     cmp    flags.attflg,0        ; file attributes disabled?
  368.     je    sinit5            ; e = yes, so no Mail
  369.     test    trans.capas,8        ; can they do file attributes?
  370.     jz    sinit5            ; z = no, so cannot do Mail
  371. sinit4:    call    getfil            ; open the file
  372.     jc    sinit4a            ; c = error
  373.     mov    filopn,1        ; disk file is open
  374.     mov    sstate,'F'        ; set the state to file send
  375.     ret
  376.  
  377. sinit4a:mov    dx,offset erms15    ; file not found
  378.     jmp    giveup            ;  something is wrong, quit w/msgs
  379.  
  380.                     ; say Mail not supported by host
  381. sinit5:    mov    dx,offset erms25    ; say no mail today
  382.     call    ermsg            ; tell both sides
  383.     mov    sstate,'B'        ; go to EOT state
  384.     ret
  385. SINIT    ENDP
  386.  
  387. ; Send file header
  388. ; Enter with pktnum set for the next transmission, no buffer
  389.  
  390. SFILE    PROC    NEAR
  391.     call    begtim            ; start statistics
  392.     cmp    filopn,1        ; is file open already?
  393.     je    sfile1            ; e = yes
  394.     call    bufrel            ; release buffer for SI
  395.     mov    dx,offset erms24    ; cannot send packet
  396.     jmp    giveup            ; something is wrong, quit
  397.  
  398. sfile1:    mov    flags.cxzflg,0        ; clear ^C, ^E, ^X, ^Z flag 
  399.     call    cxerr            ; clear Last Error line
  400.     call    cxmsg            ; clear Last Message line
  401.     call    getbuf            ; get a packet buffer, address in si
  402.     jnc    sfile2            ; nc = got one
  403.     mov    dx,offset erms27    ; no buffers
  404.     jmp    giveup            ; tell both sides and fail
  405.  
  406. sfile2:    mov    dx,offset encbuf    ; destination = encode source buffer
  407.     call    strlen            ; get length (w/o terminator) into cx
  408.     call    doenc            ; do encoding; length is in cx
  409.     mov    [si].pktype,'F'        ; File header packet
  410.     cmp    flags.xflg,0        ; REMOTE command? (goes to screen)
  411.     je    sfile3            ; e = no
  412.     mov    [si].pktype,'X'        ; use X rather than F for REMOTE cmds
  413. sfile3:    call    sndpak            ; send the packet
  414.     jnc    sfile4            ; nc = success
  415.     ret
  416.  
  417. sfile4:    mov    al,pktnum        ; want response for packet just sent
  418.     mov    ah,maxtry        ; retry threshold
  419.     call    response        ; get response
  420.     jnc    sfile5            ; nc = success (got an ACK)
  421.     ret
  422.  
  423. sfile5:    call    ackmsg            ; show any message in ACK
  424.     inc    pktnum            ; next pkt to send/rcv, from ackpak
  425.     and    pktnum,3fh        ; modulo 64
  426.     mov    sstate,'a'        ; set file attributes as next state
  427.     ret                ; return to do next state
  428. SFILE    ENDP
  429.  
  430. ; Send file attributes. Attributes: file size in bytes and kilobytes,
  431. ; file time and date, machine identification.
  432. ; Writes output to buffer encbuf.
  433. SATTR    PROC    NEAR
  434.     cmp    flags.attflg,0        ; allowed to do file attributes?
  435.     je    satt0            ; e = no
  436.     mov    attptr,offset attlist    ; point at list of attributes procs
  437.     test    trans.capas,8        ; can we do file attributes?
  438.     jnz    satt1            ; nz = yes
  439. satt0:    mov    sstate,'D'        ; set the state to send-data
  440.     ret
  441.  
  442. satt1:    mov    bx,attptr        ; ptr to list of attributes procedures
  443.     cmp    word ptr [bx],0        ; at end of list?
  444.     je    satt0            ; e = yes, do next state
  445.     call    getbuf            ; get buffer for sending
  446.     jnc    satt2            ; nc = got one
  447.     mov    dx,offset erms27    ; no buffers
  448.     call    giveup            ; tell both sides and fail
  449.     stc
  450.     ret
  451. satt2:    mov    di,offset encbuf    ; address of a temp data buffer
  452.     mov    byte ptr [di],0        ; start with null terminator
  453.     push    es            ; save es around this work
  454.     push    ds
  455.     pop    es            ; set es to data segment for es:di
  456.     push    si
  457.     mov    bx,attptr        ; ptr to list of attributes routines
  458.     mov    bx,[bx]            ; de-reference one level
  459.     call    bx            ; do it
  460.     pop    si
  461.     pop    es
  462.     mov    byte ptr [di],0        ; insert null terminator in temp buf
  463.     mov    dx,offset encbuf
  464.     call    strlen            ; get length of this attribute to CX
  465.     cmp    cx,trans.maxdat        ; longer than any packet?
  466.     jbe    satt3            ; be = no, proceed
  467.     call    bufrel            ; release this buffer
  468.     mov    dx,offset erms24    ; "Unable to send packet"
  469.     call    ermsg            ; position cursor, display asciiz msg
  470.     mov    flags.cxzflg,'X'    ; say skip this file
  471.     mov    sstate,'Z'        ; move to EOF state
  472.     ret
  473.  
  474. satt3:    mov    ax,[si].datlen        ; data length for packet, so far
  475.     add    ax,cx            ; plus, maybe, this contribution
  476.     cmp    ax,trans.maxdat        ; new info fits into packet?
  477.     jg    satt4            ; g = no, send what we have
  478.     push    si            ; preserve packet structure pointer
  479.     mov    di,[si].datadr        ; packet buffer beginning
  480.     add    di,[si].datlen        ; plus current contents
  481.     add    [si].datlen,cx        ; say adding this many bytes
  482.     mov    si,offset encbuf    ; temp buffer is source of new info
  483.     cld                ; packet buffer is destination
  484.     rep    movsb            ; copy new material to packet buffer
  485.     pop    si
  486.     add    attptr,2        ; next attributes procedure address
  487.     mov    bx,attptr
  488.     cmp    word ptr [bx],0        ; at end of list?
  489.     jne    satt2            ; ne = no, do next attribute proc
  490.     cmp    [si].datlen,0        ; any data to send?
  491.     jne    satt4            ; ne = yes
  492.     call    bufrel            ; release the unused buffer
  493.     mov    sstate,'D'        ; set the state to send-data
  494.     ret
  495.  
  496. satt4:    call    sndatt            ; send attributes packet, get response
  497.     jc    satt5            ; c = failure
  498.     jmp    satt1            ; get new buffer, do more attributes
  499. satt5:    ret                ; failure, change state
  500.  
  501.                     ; Send Attributes packet, local worker
  502. sndatt:    mov    [si].pktype,'A'        ; Attributes packet
  503.     call    sndpak            ; send the packet
  504.     jnc    sndat1            ; nc = success
  505.     ret
  506. sndat1:    mov    al,pktnum        ; get response for packet just sent
  507.     mov    ah,maxtry        ; retry threshold
  508.     call    response        ; get response
  509.     jnc    sndat2            ; nc = success
  510.     ret
  511.  
  512. sndat2:    inc    pktnum            ; sent and ack'd, next seqnum to use
  513.     and    pktnum,3fh
  514.     cmp    rpacket.datlen,0    ; any data in the ACK?
  515.     je    sndat3            ; e = no
  516.     mov    bx,rpacket.datadr    ; received data field
  517.     cmp    byte ptr[bx],'N'    ; are they refusing this file?
  518.     je    sndat4            ; e = yes, 'N' = refusing the file
  519. sndat3:    clc                ; say success
  520.     ret
  521.                     ; display file refusal reason
  522. sndat4:    test    flags.remflg,dquiet    ; quiet display?
  523.     jnz    sndat7            ; nz = yes
  524.     mov    dx,offset erms26    ; say host rejected the file 
  525.     call    ermsg
  526.     mov    cx,rpacket.datlen    ; display all reasons
  527. sndat5:    dec    cx            ; next byte
  528.     inc    bx            ; point to next data field item
  529.     cmp    cx,0            ; anything there?
  530.     jle    sndat7            ; b = no
  531.     mov    ah,[bx]            ; get reason code
  532.     mov    dx,offset erms30
  533.     cmp    ah,'1'            ; Byte count?
  534.     je    sndat6            ; e = yes
  535.     cmp    ah,'!'            ; Kilobyte count?
  536.     je    sndat6
  537.     mov    dx,offset erms31
  538.     cmp    ah,'#'            ; Date and Time?
  539.     je    sndat6            ; e = yes
  540.     mov    dx,offset erms32
  541.     cmp    ah,'+'            ; Mail?
  542.     je    sndat6            ; e = yes
  543.     mov    dx,offset erms33
  544.     cmp    ah,'"'            ; File Type?
  545.     je    sndat6
  546.     mov    dx,offset erms34
  547.     cmp    ah,'*'            ; Transfer Char-set?
  548.     je    sndat6
  549.     mov    dx,offset erms36    ; unknown reason
  550. sndat6:    call    prtasz            ; display reason
  551.     jmp    short sndat5        ; do any other reasons
  552. sndat7:    mov    flags.cxzflg,'X'    ; simulate Control-X to discard
  553.     mov    sstate,'Z'        ; send EOF with Discard
  554.     stc
  555.     ret
  556.  
  557. ; Individual attribute routines. Each expects DI to point to a free storage
  558. ; byte in an output buffer and it updates DI to the next free byte. Expects
  559. ; ES to be pointing at the data segment. Ok to clobber SI here.
  560.  
  561. sat1t:    test    flags.attflg,attlen    ; can we send length attribute?
  562.     jz    sat1tx            ; z = no
  563.     mov    si,di            ; remember starting location
  564.     mov    byte ptr [di],'1'    ; file length (Bytes) specifier
  565.     mov    dx,diskio.sizehi    ; high word of length
  566.     mov    ax,diskio.sizelo    ; low word of length
  567.     add    di,2
  568.     call    lnout            ; convert file length, write to [di++]
  569.     mov    cx,di            ; compute field length
  570.     sub    cx,si
  571.     sub    cx,2
  572.     add    cl,32            ; field length to ascii
  573.     mov    [si+1],cl        ; length. Done with File Size
  574. sat1tx:    ret
  575.                     ; Kilobyte attribute
  576. sat2t:    test    flags.attflg,attlen    ; can we send length attribute?
  577.     jz    sat2tx            ; z = no
  578.     mov    byte ptr[di],'!'    ; file length (Kilobytes) specifier
  579.     inc    di
  580.     mov    temp4,di        ; remember place for count field
  581.     inc    di            ; data field
  582.     mov    dx,diskio.sizehi    ; high word of length, from file open
  583.     mov    ax,diskio.sizelo    ; low word of length
  584.     add    ax,1023            ; add 1023 to round up
  585.     adc    dx,0
  586.     mov    al,ah            ; do divide by 1024 bytes
  587.     mov    ah,dl
  588.     mov    dl,dh            ; divide by 256 part
  589.     mov    dh,0
  590.     ror    dl,1            ; low bit to carry flag
  591.     rcr    ax,1            ; divide by two, with carry in
  592.     clc
  593.     ror    dl,1            ; low bit to carry flag
  594.     rcr    ax,1            ; divide by two, with carry in
  595.     and     dl,3fh            ; keep low six bits
  596.     call    lnout            ; convert file length
  597.     mov    cx,di            ; compute field length
  598.     sub    cx,temp4        ; count field location
  599.     add    cl,32-1            ; field length to ascii
  600.     push    di
  601.     mov    di,temp4        ; point at count field
  602.     mov    [di],cl            ; store field length
  603.     pop    di            ; Done with Kilobyte attribute
  604. sat2tx:    ret
  605.  
  606. sat3t:    test    flags.attflg,attdate    ; can we send file date and time?
  607.     jnz    sat3t1            ; nz = yes
  608.     ret
  609. sat3t1:    cld                ; file Date and Time
  610.     mov    al,'#'            ; creation date/time specifier
  611.     stosb                ; and point at field length
  612.     mov    al,17+32        ; length of date/time field, to ascii
  613.     stosb
  614.     mov    ah,0
  615.     mov    al,diskio.dta+25    ; yyyyyyym from DOS via file open
  616.     shr    al,1            ; get year
  617.     add    ax,1980            ; add bias
  618.     mov    dx,0
  619.     call    lnout            ; put year (1988) in buffer
  620.     mov    ax,word ptr diskio.dta+24 ; yyyyyyyym mmmddddd  year+month+day
  621.     shr    ax,1            ; month to al
  622.     mov    ah,0
  623.     mov    cl,4
  624.     shr    al,cl            ; month to low nibble
  625.     mov    byte ptr[di],'0'    ; leading digit
  626.     inc    di
  627.     cmp    al,9            ; more than one digit?
  628.     jbe    sat3t2            ; be = no
  629.     mov    byte ptr[di-1],'1'    ; new leading digit
  630.     sub    al,10            ; get remainder
  631. sat3t2:    add    al,'0'            ; to ascii
  632.     stosb                ; end of month
  633.     mov    al,diskio.dta+24    ; get day of month
  634.     and    al,1fh            ; select day bits
  635.     mov    ah,0
  636.     mov    cl,10
  637.     div    cl            ; quot = al, rem = ah
  638.     add    ax,'00'            ; add ascii bias
  639.     stosw                ; leading digit and end of date
  640.     mov    al,' '            ; space separator
  641.     stosb
  642.     mov    al,diskio.dta+23    ; hours  hhhhhmmm
  643.     mov    cl,3
  644.     shr    al,cl            ; move to low nibble
  645.     mov    ah,0
  646.     mov    cl,10
  647.     div    cl            ; quot = al, rem = ah
  648.     add    ax,'00'            ; add ascii bias
  649.     stosw                ; store hours
  650.     mov    al,':'            ; separator
  651.     stosb
  652.     mov    ax,word ptr diskio.dta+22 ; get minutes: hhhhhmmm mmmsssss
  653.     mov    cl,5
  654.     shr    ax,cl            ; minutes to low byte
  655.     and    al,3fh            ; six bits for minutes
  656.     mov    ah,0
  657.     mov    cl,10
  658.     div    cl
  659.     add    ax,'00'            ; add ascii bias
  660.     stosw
  661.     mov    al,':'            ; separator
  662.     stosb
  663.     mov    al,byte ptr diskio.dta+22 ; get seconds (double secs really)
  664.     and    al,1fh
  665.     shl    al,1            ; DOS counts by two sec increments
  666.     mov    ah,0
  667.     mov    cl,10
  668.     div    cl
  669.     add    ax,'00'            ; add ascii bias
  670.     stosw
  671.     ret
  672.  
  673. sat4t:    mov    ax,'".'            ; machine indicator(.), 2 data bytes
  674.     cld
  675.     stosw
  676.     mov    ax,'8U'            ; U8 = Portable O/S, MSDOS
  677.     stosw
  678.     ret
  679.  
  680.  
  681. sat5t:    cmp    mailflg,0        ; Mailing?
  682.     jne    sat5t1            ; ne = yes
  683.     ret
  684. sat5t1:    mov    byte ptr [di],'+'    ; Mail specification
  685.     inc    di
  686.     mov    dx,offset auxfile    ; user@host field
  687.     call    strlen            ; get length into cl
  688.     push    cx            ; save address length
  689.     inc    cl            ; include M for disposition = mail
  690.     add    cl,' '            ; add ascii bias
  691.     mov    [di],cl            ; store in length field
  692.     inc    di
  693.     mov    byte ptr [di],'M'    ; mail the file
  694.     inc    di
  695.     pop    cx            ; recover address length
  696.     jcxz    sat5tx            ; z = empty field
  697.     mov    si,dx            ; user@host field
  698.     cld
  699.     rep    movsb            ; append address text to field
  700. sat5tx:    ret
  701.  
  702. sat6t:    test    flags.attflg,atttype    ; can we send File Type attribute?
  703.     jz    sat6tx            ; z = no
  704.     mov    al,'"'            ; File Type attribute (")
  705.     cld
  706.     stosb
  707.     cmp    dtrans.xtype,0        ; Text?
  708.     jne    sat6t1            ; ne = no, likely Binary
  709.     mov    al,3+20h        ; three bytes follow
  710.     stosb
  711.     mov    al,'A'            ; A for ascii
  712.     stosb
  713.     mov    ax,'JM'            ; using Control-M and Control-J
  714.     stosw                ; as line delimiters
  715.     ret
  716. sat6t1:    mov    al,2+20h        ; two bytes follow
  717.     stosb
  718.     mov    ax,'8B'            ; "B8" = Binary, 8-bit byte literals
  719.     stosw
  720. sat6tx:    ret
  721.  
  722. sat7t:    test    flags.attflg,attchr    ; Character-set allowed?
  723.     jz    sat7tx            ; z = no
  724.     cmp    dtrans.xtype,1        ; Binary?
  725.     je    sat7tx            ; e = yes, no char-set stuff
  726.     mov    al,'*'            ; Encoding strategy
  727.     cld
  728.     stosb
  729.     mov    al,1+20h        ; length following, say one char
  730.     stosb
  731.     mov    al,'A'            ; assume normal Transparent
  732.     stosb
  733.     cmp    dtrans.xchset,0        ; is it transparent?
  734.     je    sat7tx            ; e = yes
  735.     mov    al,'C'            ; say transfer char-set encoding
  736.     dec    di            ; replace 'A' with 'C'
  737.     stosb
  738.     push    bx
  739.     mov    bl,dtrans.xchset    ; get def char set index
  740.     xor    bh,bh
  741.     shl    bx,1            ; count words
  742.     mov    bx,charids[bx+2]    ; bx points at set [length, string]
  743.     mov    al,[bx]            ; get length of ident string
  744.     mov    cl,al            ; copy to loop counter
  745.     xor    ch,ch
  746.     inc    al            ; add 'C' in attribute
  747.     add    al,20h            ; length of string + ascii bias
  748.     mov    byte ptr [di-2],al    ; length of attribute
  749.     push    si
  750.     mov    si,bx            ; ident string length byte
  751.     inc    si            ; text of ident string
  752.     cld
  753.     rep    movsb            ; copy to destination
  754.     pop    si
  755.     pop    bx
  756. sat7tx:    ret
  757.  
  758. SATTR    ENDP
  759.  
  760. ;    Send data
  761. ; Send main body of file, 'D' state
  762.  
  763. SDATA    PROC    NEAR
  764.     cmp    flags.cxzflg,0        ; interrupted?
  765.     je    sdata1            ; e = no
  766.     mov    sstate,'Z'        ; declare EOF, analyze interrupt there
  767.     ret
  768.  
  769. sdata1:    call    getbuf            ; get a buffer for sending
  770.     jnc    sdata2            ; nc = success
  771.     mov    al,windlow        ; earliest sequence number sent
  772.     mov    ah,maxtry        ; retry threshold
  773.     jmp    response        ; can't send, try getting responses
  774.  
  775. sdata2:    mov    [si].pktype,'D'        ; send Data packet
  776.     call    gtchr            ; fill buffer from file and encode
  777.     jc    sdata3            ; c = failure (no data/EOF, other)
  778.     cmp    [si].datlen,0        ; read any data?
  779.     je    sdata3            ; e = end of data, send 'Z' for EOF
  780.     call    sndpak            ; send the packet
  781.     inc    pktnum            ; next sequence number to send
  782.     and    pktnum,3fh        ; modulo 64
  783.     ret
  784.  
  785. sdata3:    call    bufrel            ; release unused buffer
  786.     mov    sstate,'Z'        ; at End of File, change to EOF state
  787.     ret
  788. SDATA    ENDP
  789.  
  790. ; Send EOF, 'Z' state
  791. SEOF    PROC    NEAR
  792.     call    getbuf            ; get a buffer for EOF packet
  793.     jnc    seof1            ; nc = got one, send 'Z' packet
  794.     mov    al,pktnum        ; seqnum of next packet to be used
  795.     dec    al            ; back up to last used
  796.     and    al,3fh            ; sequence number of last sent pkt
  797.     mov    ah,maxtry        ; retry threshold
  798.     jmp    response        ; get responses to earlier packets
  799.  
  800. seof1:    mov    cx,0            ; assume no data
  801.     cmp    flags.cxzflg,0        ; interrupted?
  802.     je    seof3            ; e = no, send normal EOF packet
  803.     call    intmsg            ; say interrupted
  804.     mov    encbuf,'D'        ; Use "D" for discard
  805.     mov    cx,1            ; set data size to 1
  806.     or    errlev,1        ; say send failed
  807.     or    fsta.xstatus,1+80h    ; set status, failed + intervention
  808.     mov    kstatus,1+80h        ; global status
  809. seof3:    call    doenc            ; encode the packet (cx = count)
  810.     mov    [si].pktype,'Z'        ; EOF packet
  811.     call    sndpak            ; send the packet
  812.     jnc    seof6            ; nc = success
  813.     ret
  814.  
  815. seof6:    mov    al,[si].seqnum        ; packet just sent
  816.     mov    ah,maxtry        ; retry threshold
  817.     call    response        ; get reponse
  818.     jnc    seof7            ; nc = success
  819.     ret
  820.  
  821. seof7:    call    ackmsg            ; ACK, get/show any embedded message
  822.     inc    pktnum            ; next sequence number to send
  823.     and    pktnum,3fh        ; modulo 64
  824.                     ; Heuristic: ACK to 'Z' implies
  825.     mov    al,windlow        ;  ACKs to all previous packets
  826.     mov    ah,pktnum        ; loop limit, next packet
  827. seof8:    cmp    al,ah            ; done all "previous" packets?
  828.     je    seof8b            ; e = yes
  829.     call    pakptr            ; access packet for seqnum in AL
  830.     jc    seof8a            ; c = not in use
  831.     mov    si,bx            ; point to it
  832.     call    bufrel            ; release old buffer (synthetic ACK)
  833. seof8a:    inc    al            ; next slot
  834.     and    al,3fh
  835.     jmp    short seof8
  836. seof8b:                    ; end of Heuristic
  837.     mov    al,pktnum
  838.     mov    windlow,al        ; update windlow to next use
  839.     mov    ah,close2        ; close file
  840.     mov    bx,diskio.handle    ; file handle
  841.     int    dos
  842.     mov    filopn,0        ; no files open
  843.     cmp    flags.cxzflg,0        ; interrupted?
  844.     je    seof9            ; e = no
  845.     or    errlev,1        ; say send failed
  846.     or    fsta.xstatus,1+80h    ; set status, failed + intervention
  847.     mov    kstatus,1+80h        ; global status
  848.     mov    ax,1            ; tell statistics this was a send
  849.     call    endtim
  850.     cmp    flags.cxzflg,'Z'    ; Control-Z seen?
  851.     jne    seof9            ; ne = no
  852.     mov    flags.cxzflg,0        ; clear the Control-Z
  853.     mov    auxfile,0        ; clear send-as/mail-address buffer
  854.     mov    sstate,'B'        ; file group complete state
  855.     ret
  856. seof9:    mov    ax,1            ; tell statistics this was a send
  857.     call    endtim
  858.     cmp    flags.cxzflg,0        ; interrupted?
  859.     je    seof10            ; e = no
  860.     cmp    flags.cxzflg,'X'    ; was Control-X signaled?
  861.     je    seof10            ; e = yes
  862.     mov    sstate,'E'         ; not ^X/^Z, must be ^C/^E
  863.     ret
  864. seof10:    mov    flags.cxzflg,0        ; clear the Control-X
  865.     cmp    mailflg,0        ; mail?
  866.     jne    seof11            ; e = yes, retain address in auxfile
  867.     mov    auxfile,0        ; clear send-as name
  868. seof11:    call    GTNFIL            ; get the next file
  869.     jc    seof12            ; c = no more files, do end of group
  870.     mov    filopn,1        ; file opened by gtnfil
  871.     mov    sstate,'F'        ; set state to file header send
  872.     ret
  873. seof12:    mov    sstate,'B'        ; set state to file group completed
  874.     ret
  875. SEOF    ENDP
  876.  
  877.  
  878. ; Send EOT
  879.  
  880. SEOT    PROC    NEAR
  881.     call    getbuf            ; get a buffer for sending
  882.     jnc    seot1            ; nc = got one
  883.     mov    al,pktnum        ; next sequence number to use
  884.     dec    al            ; back up to last used
  885.     and    al,3fh            ; get response to what was just sent
  886.     mov    ah,maxtry        ; retry threshold
  887.     jmp    response        ; get response, stay in this state
  888.  
  889. seot1:    mov    [si].pktype,'B'        ; End of Session packet
  890.     call    sndpak            ; send the packet
  891.     jnc    seot2            ; nc = sucess
  892.     ret
  893. seot2:    mov    al,pktnum        ; sequence number just sent
  894.     mov    ah,maxtry        ; retry threshold
  895.     call    response        ; get a response to it
  896.     jnc    seot3            ; nc = success
  897.     ret
  898. seot3:    call    ackmsg            ; get/show any embedded message
  899.     inc    pktnum            ; next sequence number to use
  900.     and    pktnum,3fh        ; modulo 64
  901.     mov    sstate,'C'        ; set state to file completed
  902.     ret
  903. SEOT    ENDP
  904.  
  905. ; Get response to seqnum in AL, retry AH times if necessary.
  906. ; Success: return carry clear and response data in rpacket
  907. ; Failure: return carry set and new state in sstate, will send Error packet
  908. ; Changes AX, BX, CX
  909. response proc    near
  910.     mov    tempseq,al        ; target sequence number
  911.     mov    retry,ah        ; retry threshold
  912.     mov    rpacket.numtry,0    ; no receive retries yet
  913. resp1:    mov    ah,rpacket.numtry    ; number of attempts in this routine
  914.     cmp    ah,retry        ; done enough?
  915.     ja    resp3            ; yes, feign a timeout
  916.     push    si            ; preserve regular packet pointer
  917.     mov    si,offset rpacket    ; address of receive packet structure
  918.     call    rpack            ; get a packet
  919.     pop    si
  920.     jnc    resp4            ; nc = success
  921.     cmp    flags.cxzflg,'C'    ; Control-C typed?
  922.     je    resp2            ; e = yes, quit
  923.     cmp    flags.cxzflg,'E'    ; Control-E typed?
  924.     jne    resp3            ; ne = no
  925. resp2:    mov    sstate,'E'        ; change to Error state
  926.     stc                ; return failure
  927.     ret
  928.  
  929. resp3:    inc    rpacket.numtry        ; no packet received, resend oldest
  930.     mov    al,windlow        ; get oldest sequence number
  931. resp3a:    call    pakptr            ; get packet pointer to seqnum in AL
  932.     jnc    resp3b            ; nc = ok, sequence number is in use
  933.     clc                ; packet not in use, simulate success
  934.     ret
  935.  
  936. resp3b:    push    si            ; resend oldest packet
  937.     dec    numpkt            ; a retry is not a new packet sent
  938.     mov    si,bx            ; packet pointer, from pakptr
  939.     call    cntretry        ; count retries, sense ^C/^E
  940.     jnc    resp3c            ; nc = ok to continue
  941.     pop    si            ; clean stack
  942.     ret                ; ^C/^E encountered, change states
  943.  
  944. resp3c:    mov    al,[si].numtry        ; times this packet was retried
  945.     cmp    al,retry        ; reached the limit?
  946.     jbe    resp3d            ; be = no, can do more sends
  947.     pop    si            ; clean stack
  948.     mov    dx,offset erms17    ; to many retries
  949.     jmp    giveup            ; abort with msgs to local and remote
  950.  
  951. resp3d:    mov    rpacket.numtry,0
  952.     call    sndpak            ; resend the packet
  953.     pop    si            ; clean stack
  954.     jnc    resp1            ; nc = success, retry getting response
  955.     ret
  956.  
  957. resp4:    call    acknak            ; got packet, get kind of response
  958.     cmp    al,0            ; ACK in window?
  959.     je    resp8            ; e = yes
  960.     cmp    al,1            ; NAK in window?
  961.     je    resp6            ; e = yes, repeat pkt
  962.     cmp    al,3            ; NAK out of window?
  963.     je    resp5            ; e = yes, repeat packet
  964.     cmp    al,4            ; ACK to inactive packet?
  965.     jne    resp4e            ; ne = no
  966.     inc    rpacket.numtry        ; count tries on reception
  967.     jmp    resp1            ; e = yes, retry reception
  968. resp4e:    cmp    al,5            ; NAK to inactive packet?
  969.     jne    resp4a            ; ne = no, leaves "other" types
  970.     jmp    resp1            ; ignore NAK, try again
  971.                     ; other packet types
  972. resp4a:    cmp    rpacket.pktype,'M'    ; Message packet?
  973.     jne    resp4b            ; ne = no
  974.     push    si
  975.     mov    si,offset rpacket
  976.     call    msgmsg            ; display it and discard
  977.     pop    si
  978.     jmp    resp1            ; retry getting an ACK
  979.  
  980. resp4b:    cmp    rpacket.pktype,'E'    ; Error packet?
  981.     jne    resp4c            ; ne = no
  982.     jmp    error
  983.  
  984. resp4c:    mov    dx,offset erms16    ; unknown packet type
  985.     jmp    giveup
  986.  
  987. resp5:    cmp    trans.windo,1        ; is windowing off?
  988.     je    resp5a            ; e = yes, use old heuristic
  989.     call    nakout            ; NAK rcvd outside window, resend all
  990.     inc    rpacket.numtry        ; count this as an internal retry
  991.     jmp    resp1            ; get more responses
  992.     
  993. resp5a:    mov    al,rpacket.seqnum    ; NAK rcvd outside window, say NAK is
  994.     dec    al            ;  ACK for preceeding pkt to satisfy
  995.     and    al,3fh            ;  non-windowing Kermits
  996.     mov    rpacket.seqnum,al    ; force seqnum to preceed this NAK
  997.     mov    rpacket.pktype,'Y'    ; force packet to look like an ACK
  998.     jmp    short resp4        ; reanalyze our status
  999.  
  1000. resp6:    mov    al,rpacket.seqnum    ; single sequence number being NAK'd
  1001.     inc    rpacket.numtry        ; count this as an internal retry
  1002.     jmp    resp3a            ; repeat that packet
  1003.  
  1004.                     ; ACK in window
  1005. resp8:    mov    al,windlow        ; try to purge all ack'd packets
  1006.     call    pakptr            ; get buffer pointer for it into BX
  1007.     jc    resp8a            ; c = buffer not in use
  1008.     cmp    [bx].ackdone,0        ; ack'd yet?
  1009.     je    resp8a            ; e = no, stop here
  1010.     mov    si,bx
  1011.     call    bufrel            ; ack'd active buffer, release si
  1012.     inc    al            ; rotate window
  1013.     and    al,3fh
  1014.     mov    windlow,al
  1015.     jmp    short resp8        ; keep purging
  1016.  
  1017. resp8a:    mov    al,tempseq        ; check for our desired seqnum
  1018.     mov    rpacket.numtry,0
  1019.     cmp    al,rpacket.seqnum    ; is this the desired object?
  1020.     je    resp8b            ; e = yes
  1021.     jmp    resp1            ; no, read another response
  1022. resp8b:    clc                ; return success
  1023.     ret
  1024. response endp
  1025.  
  1026. ; Send packet, with retries
  1027. ; Enter with SI pointing to packet structure. Success returns carry clear.
  1028. ; Failure, after retries, returns carry set and perhaps a new sstate.
  1029. sndpak    proc    near            
  1030.     inc    numpkt            ; number packets sent
  1031.     call    pktsize            ; report packet qty and size
  1032.     mov    sndcnt,0        ; send retry counter, internal
  1033.     cmp    [si].pktype,'I'        ; do not show windows for I/S
  1034.     je    sndpa3
  1035.     cmp    [si].pktype,'S'
  1036.     je    sndpa3
  1037.     call    winpr            ; show windows in use
  1038.  
  1039. sndpa3:    call    spack            ; send the packet
  1040.     jc    sndpa4            ; nc = failure
  1041.     ret                ; return success
  1042.  
  1043. sndpa4:    push    ax            ; failure, do several retries
  1044.     mov    ax,100            ; wait 0.1 seconds
  1045.     call    pcwait
  1046.     call    cntretry        ; show retries on screen
  1047.     inc    sndcnt            ; internal retry counter
  1048.     mov    al,sndcnt
  1049.     cmp    al,maxtry        ; reached retry limit?
  1050.     pop    ax
  1051.     jbe    sndpa3            ; be = no, can do more retries
  1052.     mov    dx,offset erms24    ; cannot send packet
  1053.     jmp    giveup            ; set carry, change state
  1054. sndpak    endp
  1055.  
  1056. ; Check the packet rpacket for an ACK, NAK, or other.
  1057. ; Returns in CX:
  1058. ; 0 for ACK to active packet (marks buffer as ACK'd, may rotate window)
  1059. ; 1 for NAK to active packet
  1060. ; 2 for an unknown packet type
  1061. ; 3 for NAK outside the window
  1062. ; 4 for other ACKs (out of window, to inactive packet)
  1063. ; 5 for NAKs in window to inactive packets.
  1064. ; Timeout packet (type 'T') is regarded as a NAK out of the window.
  1065. ; Marks pkts ACK'd but clears packets only when they rotate below the window.
  1066. ; Uses registers AX ,BX, and CX.
  1067. ACKNAK    PROC    NEAR
  1068.     mov    al,rpacket.seqnum    ; this packet's sequence number
  1069.     mov    ah,rpacket.pktype    ; and packet type
  1070.     cmp    ah,'Y'            ; ack packet?
  1071.     jne    ackna2            ; ne = no
  1072.     call    pakptr            ; is it for an active buffer?
  1073.     jnc    ackna1            ; nc = yes
  1074.     mov    al,4            ; say ACK for inactive pkt
  1075.     clc
  1076.     ret
  1077. ackna1:    mov    [bx].ackdone,1        ; say packet has been acked
  1078.     cmp    al,windlow        ; ok to rotate window?
  1079.     jne    ackna1a            ; ne = no
  1080.     inc    windlow            ; rotate window one slot
  1081.     and    windlow,3fh
  1082.     push    si            ; save pointer
  1083.     mov    si,bx            ; packet pointer from pakptr
  1084.     call    bufrel            ; release buffer for SI
  1085.     pop    si
  1086. ackna1a:cmp    rpacket.datlen,0    ; any data in the ACK?
  1087.     je    ackna1c            ; e = no
  1088.     cmp    sstate,'F'        ; in file header state?
  1089.     je    ackna1c            ; e = yes, no protocol char
  1090.     mov    bx,rpacket.datadr    ; look for data in the ACK
  1091.     mov    ah,[bx]
  1092.     cmp    ah,'C'            ; Control-C message?
  1093.     je    ackna1b            ; e = yes
  1094.     cmp    ah,'X'            ; quit this file?
  1095.     je    ackna1b            ; e = yes
  1096.     cmp    ah,'Z'            ; quit this file group?
  1097.     jne    ackna1c
  1098. ackna1b:mov    flags.cxzflg,ah        ; store here
  1099.     mov    sstate,'Z'        ; move to end of file state
  1100.     mov    rstate,'Z'
  1101. ackna1c:mov    al,0            ; ack'd ok
  1102.     clc
  1103.     ret
  1104.                     ; not an ACK
  1105. ackna2:    cmp    ah,'N'            ; NAK?
  1106.     je    ackna3            ; e = yes
  1107.     cmp    ah,'T'            ; Timeout?
  1108.     je    ackna3a            ; e = yes, same as NAK out of window
  1109.     mov    al,2            ; else say unknown type
  1110.     clc
  1111.     ret
  1112.  
  1113. ackna3:    inc    fsta.nakrcnt        ; count received NAK for statistics
  1114.     push    si
  1115.     mov    si,offset rpacket
  1116.     call    chkwind            ; check if seqnum is in window
  1117.     pop    si
  1118.     cmp    cx,0            ; in window?
  1119.     je    ackna3b            ; e = in window
  1120. ackna3a:mov    al,3            ; say NAK out of window
  1121.     clc
  1122.     ret
  1123.  
  1124. ackna3b:push    bx            ; NAK in window, is pkt still active?
  1125.     call    pakptr            ; seqnum for an active packet?
  1126.     pop    bx
  1127.     jc    ackna4            ; c = no, ignore NAK as "dead NAK" 
  1128.     mov    al,1            ; say NAK for active packet
  1129.     clc
  1130.     ret
  1131.  
  1132. ackna4:    mov    al,5            ; dead NAKs
  1133.     clc
  1134.     ret
  1135. ACKNAK    ENDP
  1136.  
  1137. nakout    proc    near            ; NAK out of window, resend all pkts
  1138.     mov    al,windlow        ; start here
  1139.     mov    ah,al
  1140.     add    ah,trans.windo
  1141.     and    ah,3fh            ; top of window+1
  1142. nakout1:call    pakptr            ; get pkt pointer for seqnum in al
  1143.     jc    nakout4            ; c = slot not in use
  1144.     mov    si,bx            ; bx is packet pointer from pakptr
  1145.     cmp    al,windlow        ; count retries only for windlow
  1146.     jne    nakout2            ; ne = not windlow
  1147.     call    cntretry        ; count retries
  1148.     jc    nakout3            ; c = quit now
  1149.     mov    cl,[si].numtry
  1150.     cmp    cl,retry        ; reached the limit yet?
  1151.     ja    nakout3            ; a = yes, quit
  1152. nakout2:push    ax
  1153.     call    pktsize            ; report packet size
  1154.     call    sndpak            ; resend the packet
  1155.     pop    ax
  1156.     jmp    nakout4            ; do next packet
  1157.  
  1158. nakout3:call    bufclr            ; error exit
  1159.     mov    dx,offset erms17    ; too many retries
  1160.     jmp    giveup            ; too many retries
  1161.  
  1162. nakout4:inc    al            ; next sequence number
  1163.     and    al,3fh
  1164.     cmp    al,ah            ; sent all packets?
  1165.     jne    nakout1            ; ne = no, repeat more packets
  1166.     ret                ; return to do another data send
  1167. nakout    endp
  1168.  
  1169. cntretry proc    near
  1170.     cmp    flags.cxzflg,'C'
  1171.     je    cntre2
  1172.     cmp    flags.cxzflg,'E'
  1173.     je    cntre2
  1174.     inc    fsta.pretry        ; increment the number of retries
  1175.     inc    [si].numtry        ; for this packet too
  1176.     test    flags.remflg,dserver    ; server mode
  1177.     jnz    cntre3            ; nz = yes, writing to their screen
  1178.     cmp    flags.xflg,1        ; writing to screen?
  1179.     je    cntre1            ; e = yes, skip this
  1180. cntre3:    cmp    fmtdsp,0        ; formatted display?
  1181.     je    cntre1            ; e = no
  1182.     call    rtmsg            ; display retries
  1183. cntre1:    clc
  1184.     ret
  1185. cntre2:    mov    sstate,'E'        ; abort, shared by send and receive
  1186.     mov    rstate,'E'        ; abort
  1187.     stc
  1188.     ret
  1189. cntretry endp
  1190.  
  1191. ; Display message in ACK's to F and D packets. Requires a leading protocol
  1192. ; char for D packets and expects message to be encoded.
  1193. ackmsg    proc near
  1194.     test    flags.remflg,dquiet    ; quiet display mode?
  1195.     jnz    ackmsgx            ; nz = yes, don't write to screen
  1196.     cmp    rpacket.datlen,0    ; any embedded message?
  1197.     je    ackmsgx            ; e = no
  1198.     cmp    sstate,'F'        ; file header state?
  1199.     je    ackmsg1            ; e = yes, no leading protocol char
  1200.     cmp    rpacket.datlen,1    ; D packet, skip protocol char
  1201.     je    ackmsgx            ; e = no displayable information
  1202. ackmsg1:push    si
  1203.     push    ax
  1204.     push    dx
  1205.     call    cxmsg            ; clear message space in warning area
  1206.     mov    word ptr decbuf,0    ; clear two bytes
  1207.     mov    si,offset rpacket    ; source address
  1208.     call    dodec            ; decode message, including X/Z/other
  1209.     mov    dx,offset decbuf+1    ; decoded data
  1210.     cmp    sstate,'F'        ; file header state?
  1211.     jne    ackmsg3            ; ne = no
  1212.     push    dx
  1213.     mov    dx,offset infms5    ; give a leader msg
  1214.     call    prtasz
  1215.     pop    dx
  1216.     dec    dx            ; start with first message char
  1217. ackmsg2:mov    bx,dx
  1218.     cmp    byte ptr [bx],' '    ; space?
  1219.     jne    ackmsg3            ; ne = no
  1220.     inc    dx            ; next msg char
  1221.     jmp    short ackmsg2        ; continue stripping off spaces
  1222. ackmsg3:call    prtasz            ; display message
  1223.     mov    ah,prstr
  1224.     mov    dx,offset crlf
  1225.     int    dos
  1226.     pop    dx
  1227.     pop    ax
  1228.     pop    si
  1229. ackmsgx:mov    rpacket.datlen,0
  1230.     ret
  1231. ackmsg    endp
  1232.  
  1233. ; newfn    -- move replacement name from buffer auxfile to buffer encbuf
  1234.  
  1235. newfn    proc    near
  1236.     push    si
  1237.     push    di
  1238.     cmp    auxfile,0        ; sending file under different name?
  1239.     je    newfn4            ; e = no, so don't give new name
  1240.     mov    si,offset auxfile    ; source field
  1241.     mov    di,offset fsta.xname    ; statistics external name area
  1242.     call    strcpy
  1243.     test    flags.remflg,dquiet    ; quiet display mode?
  1244.     jnz    newfn2            ; nz = yes, do not write to screen
  1245.     mov    dx,offset asmsg        ; display ' as '
  1246.     cmp    mailflg,0        ; mail?
  1247.     je    newfn1            ; e = no
  1248.     mov    dx,offset mailto    ; display ' To: '
  1249. newfn1:    call    prtasz            ; display asciiz msg
  1250.     cmp    mailflg,0        ; mail?
  1251.     je    newfn2            ; e = no
  1252.     mov    dx,offset auxfile    ; get name
  1253.     call    prtasz            ; display asciiz string
  1254.     jmp    newfn4            ; don't replace filename
  1255. newfn2:    mov    si,offset auxfile    ; external name
  1256.     mov    di,offset encbuf
  1257.     call    strcpy            ; put into encoder buffer
  1258.     test    flags.remflg,dquiet    ; quiet display mode (should we print)?
  1259.     jnz    newfn5            ; nz = yes
  1260.     mov    dx,si
  1261.     call    prtasz            ; display external name
  1262. newfn4:    test    flags.remflg,dserial    ; serial display mode?
  1263.     jz    newfn5            ; z = no
  1264.     mov    dx,offset crlf        ; start with cr/lf for serial display
  1265.     mov    ah,prstr
  1266.     int    dos
  1267. newfn5:    pop    di
  1268.     pop    si
  1269.     ret
  1270. newfn    endp
  1271.  
  1272. ; This routine sets up the data for the response to an Init packet
  1273. ; trans.rxxx are items which have been negotiated.
  1274. ; Lines marked ;M energize the second CAPAS byte. Leave them as comments
  1275. ; because earlier versions of MS Kermit (and C Kermit) are confused by it
  1276. ; (failed to decode bit saying second CAPAS byte follows and thus lose sync).
  1277. ; Enter with SI = pktinfo pointer
  1278. ; Returns [si].datlen = length of data field, with packet buffer filled in.
  1279. RPAR    PROC    NEAR
  1280.     push    ax
  1281.     push    bx
  1282.     mov    bx,[si].datadr        ; data field address
  1283.     mov    al,trans.rpsiz        ; receive packet size
  1284.     add    al,' '            ; add a space to make it printable
  1285.     mov    [bx],al            ; put it in the packet
  1286.     inc    bx            ; 1
  1287.     mov    al,trans.rtime        ; receive packet time out
  1288.     add    al,' '
  1289.     mov    [bx],al
  1290.     inc    bx            ; 2
  1291.     mov    al,trans.rpad        ; number of padding chars
  1292.     add    al,' '
  1293.     mov    [bx],al
  1294.     inc    bx            ; 3
  1295.     mov    al,trans.rpadch        ; padding char
  1296.     add    al,40h            ; Uncontrol it
  1297.     and    al,7FH
  1298.     mov    [bx],al
  1299.     inc    bx            ; 4
  1300.     mov    al,trans.reol        ; EOL char
  1301.     add    al,' '
  1302.     mov    [bx],al
  1303.     inc    bx            ; 5
  1304.     mov    al,trans.rquote        ; quote char
  1305.     mov    [bx],al
  1306.     inc    bx            ; 6
  1307.     mov    al,trans.ebquot        ; 8-bit quote char
  1308.     mov    [bx],al
  1309.     inc    bx            ; 7
  1310.     mov    al,trans.chklen        ; Length of checksum
  1311.     add    al,'0'            ; make into a real digit
  1312.     mov    [bx],al
  1313.     inc    bx            ; 8
  1314.     mov    al,trans.rptq        ; repeat quote char
  1315.     cmp    al,0            ; null means none
  1316.     jne    rpar0
  1317.     mov    al,' '            ; send a blank instead
  1318. rpar0:    mov    [bx],al
  1319.     inc    bx            ; 9
  1320.     mov    al,2            ; CAPAS, bit1 = can do long packets
  1321.     cmp    flags.attflg,0        ; allowing attributes packets?
  1322.     je    rpar1            ; e = no
  1323.     or    al,8            ; bit #3, can do file attributes
  1324. rpar1:    or    al,4            ; bit #4 can do windows
  1325.     add    al,20h            ; apply tochar() to byte
  1326. ;M    or    al,1            ; say second CAPAS byte follows
  1327.     mov    [bx],al
  1328.     inc    bx            ; 10
  1329.                     ; additional CAPAS go in here
  1330. ;M    mov    byte ptr [bx],20h+20h    ; Allow M (message) pkts, (#6, bit5)
  1331. ;M    inc    bx            ; 11
  1332.     mov    al,trans.windo        ; number of active window slots (1-31)
  1333.     add    al,20h            ; apply tochar()
  1334.     mov    [bx],al
  1335.     inc    bx
  1336.     push    dx            ; save reg
  1337.     mov    ax,trans.rlong        ; longest packet which we can receive
  1338.     xor    dx,dx            ; clear extended part for division
  1339.     div    ninefive        ; divide by 95. quo = ax, rem = dx
  1340.     add    al,20h            ; apply tochar() to quotient
  1341.     mov    [bx],al
  1342.     inc    bx
  1343.     add    dl,20h            ; apply tochar() to remainder
  1344.     mov    [bx],dl
  1345.     pop    dx            ; restore regs
  1346.     inc    bx
  1347.     sub    bx,[si].datadr        ; end minus beginning = length
  1348.     mov    [si].datlen,bx        ; length of rpar data in packet
  1349.     pop    bx
  1350.     pop    ax
  1351.     ret
  1352. RPAR    ENDP
  1353.  
  1354. ; Set maximum capabilities
  1355. ; dtrans are the defaults (which the user can modify), trans are negotiated
  1356. ; and active values.
  1357. SPARMAX    PROC    NEAR
  1358.     push    ax
  1359.     mov    al,dtrans.spsiz        ; [1] regular packet size MAXL
  1360.     mov    trans.spsiz,al
  1361.     mov    al,dtrans.stime        ; [2] send timeout value TIME
  1362.     mov    trans.rtime,al
  1363.     mov    al,dtrans.spad        ; [3] send padding count NPAD
  1364.     mov    trans.spad,al
  1365.     mov    al,dtrans.spadch    ; [4] send padding character PADC
  1366.     mov    trans.spadch,al
  1367.     mov    al,dtrans.seol        ; [5] EOL character EOL
  1368.     mov    trans.seol,al
  1369.     mov    al,dtrans.squote    ; [6] control quote character QCTL
  1370.     mov    trans.squote,al
  1371.     mov    al,dtrans.ebquot    ; [7] 8-bit quote character QBIN
  1372.     mov    trans.ebquot,al
  1373.     mov    al,dtrans.chklen    ; [8] initial checksum type CHKT
  1374.     mov    trans.chklen,al
  1375.     mov    al,dtrans.rptq        ; [9] repeat prefix character REPT
  1376.     mov    trans.rptq,al
  1377.     mov    trans.capas,8+4        ; [10-11] capas bitmap CAPAS
  1378.     mov    trans.capas+1,20h    ;  [11] CAPAS+1, Message pkts
  1379.     mov    al,dtrans.windo        ; [12] window size WINDO
  1380.     mov    trans.windo,al
  1381.     mov    ax,dtrans.slong        ; [13-14] long packet send length,
  1382.     mov    trans.slong,ax        ;  MAXLX1 and MAXLX2
  1383.                     ;
  1384.     mov    al,dtrans.rpsiz        ; max regular packet we can receive
  1385.     mov    trans.rpsiz,al        ;  for window of one slot
  1386.     mov    ax,dtrans.rlong        ; max long packet we can receive
  1387.     mov    trans.rlong,ax        ;  for window of one slot
  1388.     pop    ax
  1389.     ret
  1390. SPARMAX    ENDP
  1391.  
  1392. ; This routine reads in all the send init packet information
  1393. ; Enter with SI = pktinfo address, [si].datlen = packet length
  1394. ; All regs preserved except AX. 
  1395. ; dtrans.xxx are the default parameters if the other side says nothing
  1396. ; trans.sxxx are the active negotiated parameters we will use.
  1397. SPAR    PROC    NEAR
  1398.     push    ax            ; set min defaults for no host data
  1399.     mov    trans.spsiz,80        ; [1] regular packet size MAXL
  1400.     mov    trans.rtime,5        ; [2] send timeout value TIME
  1401.     mov    al,dtrans.stime        ; get user selected stime
  1402.     mov    trans.stime,al
  1403.     mov    trans.spad,0        ; [3] send padding count NPAD
  1404.     mov    al,dtrans.spadch    ; [4] send padding character PADC
  1405.     mov    trans.spadch,al
  1406.     mov    trans.seol,CR        ; [5] EOL character EOL
  1407.  
  1408.     mov    trans.squote,'#'    ; [6] control quote character QCTL
  1409.     mov    trans.ebquot,'Y'    ; [7] 8-bit quote character QBIN
  1410.                     ; end of the basic items
  1411.     mov    al,dtrans.chklen    ; [8] initial checksum type CHKT
  1412.     mov    trans.chklen,al
  1413.     mov    trans.rptq,0        ; [9] repeat prefix character REPT
  1414.     mov    trans.capas,0        ; [10-11] capas bitmap CAPAS
  1415.     mov    trans.capas+1,0
  1416.     mov    trans.windo,1        ; [12] window size WINDO
  1417.     mov    ah,0
  1418.     mov    al,trans.spsiz
  1419.     mov    trans.slong,ax        ; [13-14] long packet send length,
  1420.                     ;  MAXLX1 and MAXLX2
  1421.                     ; start negotiations
  1422.     push    si            ; pktinfo structure pointer
  1423.     mov    ax,[si].datlen        ; length of received data
  1424.     mov    ah,al            ; number of args is now in ah
  1425.     mov    si,[si].datadr        ; pointer to received data
  1426.     cld
  1427.     cmp    ah,0            ; [1] MAXL  any data?
  1428.     jg    spar1a            ; g = yes
  1429.     jmp    sparx1
  1430. spar1a:    lodsb                ; get the max regular packet size
  1431.     dec    ah            ; ah = bytes remaining to be examined
  1432.     sub    al,' '            ; subtract ascii bias
  1433.     jnc    spar1b            ; c = old C Kermit error
  1434.     mov    al,spmax
  1435. spar1b:    cmp    al,dtrans.spsiz        ; user limit is less?
  1436.     jbe    spar1c            ; be = no
  1437.     mov    al,dtrans.spsiz        ; replace with our lower limit
  1438. spar1c:    cmp    al,spmin        ; below the minimum?
  1439.     jge    spar1d            ; ge = no
  1440.     mov    al,spmin
  1441. spar1d:    cmp    al,spmax        ; or above the maximum?
  1442.     jle    spar1e            ; le = no
  1443.     mov    al,spmax
  1444. spar1e:    mov    trans.spsiz,al        ; save it
  1445.     push    ax
  1446.     mov    ah,0            ; set long packet to regular size
  1447.     mov    trans.slong,ax
  1448.     pop    ax
  1449.  
  1450.     cmp    ah,0            ; [2] TIME  more data?
  1451.     jg    spar2a            ; g = yes
  1452.     jmp    sparx1
  1453. spar2a:    lodsb                ; get the timeout value
  1454.     dec    ah
  1455.     sub    al,' '            ; subtract a space
  1456.     cmp    al,0
  1457.     jge    spar2b            ; must be non-negative
  1458.     mov    al,0            ; negative, so use zero
  1459. spar2b:    cmp    al,trans.rtime        ; same as other side's timeout
  1460.     jne    spar2c            ; ne = no
  1461.     add    al,1            ; yes, but make it a little different
  1462. spar2c:    cmp    dtrans.stime,dstime    ; is current value the default?
  1463.     je    spar2d            ; e = yes, else user value overrides
  1464.     mov    al,dtrans.stime        ; get user selected stime
  1465. spar2d:    mov    trans.stime,al        ; save it
  1466.                     ;
  1467.     cmp    ah,0            ; [3] NPAD  more data?
  1468.     jg    spar3a            ; g = yes
  1469.     jmp    sparx1
  1470. spar3a:    lodsb                ; get the number of padding chars
  1471.     dec    ah
  1472.     sub    al,' '
  1473.     cmp    al,0
  1474.     jge    spar3b            ; must be non-negative
  1475.     mov    al,0
  1476. spar3b:    mov    trans.spad,al        ; number of padding chars to send
  1477.                     ;
  1478.     cmp    ah,0            ; [4] PADC  more data?
  1479.     jg    spar4a            ; g = yes
  1480.     jmp    sparx1
  1481. spar4a:    lodsb                ; get the padding char
  1482.     dec    ah
  1483.     add    al,40h            ; remove ascii bias
  1484.     and    al,7FH
  1485.     cmp    al,del            ; Delete?
  1486.     je    spar4b            ; e = yes, then it's OK
  1487.     cmp    al,31            ; control char?
  1488.     jbe    spar4b            ; be = yes, then OK
  1489.     mov    al,0            ; no, use null
  1490. spar4b:    mov    trans.spadch,al
  1491.                     ;
  1492.     cmp    ah,0            ; [5] EOL  more data?
  1493.     jg    spar5a            ; g = yes
  1494.     jmp    sparx1
  1495. spar5a:    lodsb                ; get the EOL char
  1496.     dec    ah
  1497.     sub    al,' '
  1498.     cmp    al,31            ; control char?
  1499.     jbe    spar5b            ; le = yes, then use it
  1500.     mov    al,cr            ; else use the default
  1501. spar5b:    mov    trans.seol,al        ; EOL char to be used
  1502.                     ;
  1503.     cmp    ah,0            ; [6] QCTL  more data?
  1504.     jg    spar6a            ; g = yes
  1505.     jmp    sparx1
  1506. spar6a:    lodsb                ; get the quote char
  1507.     dec    ah
  1508.     cmp    al,' '            ; less than a space?
  1509.     jge    spar6b            ; ge = no
  1510.     mov    al,dsquot        ; yes, use default
  1511. spar6b:    cmp    al,7eh            ; must also be less than a tilde
  1512.     jbe    spar6c            ; be = is ok
  1513.     mov    al,dsquot        ; else use default
  1514. spar6c:    mov    trans.squote,al
  1515.                     ;
  1516.     cmp    ah,0            ; [7] QBIN  more data?
  1517.     jg    spar7a            ; g = yes
  1518.     jmp    sparx1
  1519. spar7a:    lodsb                ; get other side's 8-bit quote request
  1520.     dec    ah
  1521.     call    doquo            ; and set quote char
  1522.                     ;
  1523.     cmp    ah,0            ; [8] CHKT  more data?
  1524.     jg    spar8a            ; a = yes
  1525.     jmp    sparx1
  1526. spar8a:    lodsb                ; get other side's checksum length
  1527.     dec    ah
  1528.     call    dochk            ; determine what size to use
  1529.                     ;
  1530.     cmp    ah,0            ; [9] REPT  more data?
  1531.     jg    spar9a            ; g = yes
  1532.     jmp    sparx1
  1533. spar9a:    lodsb                ; get other side's repeat count prefix
  1534.     dec    ah
  1535.     call    dorpt            ; negotiate prefix into trans.rptq
  1536.                     ;
  1537.     cmp    ah,0            ; [10] CAPAS  more data?
  1538.     ja    spar10a            ; g = yes
  1539.     jmp    sparx1
  1540. spar10a:lodsb                ; get CAPAS bitmap from other side
  1541.     dec    ah
  1542.     and    al,not (1)        ; remove least significant bit
  1543.     sub    al,20h            ; apply unchar()
  1544.     mov    trans.capas,al        ; store result in active byte
  1545.                     ;
  1546. spar11:    cmp    ah,0            ; [11] CAPAS+  more data?
  1547.     ja    spar11a            ; a = yes
  1548.     jmp    sparx1
  1549. spar11a:test    byte ptr [si-1],1    ; is CAPAS byte continued to another?
  1550.     jz    spar12            ; z = no
  1551.     lodsb                ; get 2nd CAPAS bitmap from other side
  1552.     dec    ah
  1553.     and    al,not (1)        ; remove least significant bit
  1554.     sub    al,20h            ; apply unchar(). Store nothing
  1555.     mov    trans.capas+1,al    ; keep second CAPAS byte
  1556.  
  1557. spar11c:cmp    ah,0            ; [11] CAPAS++  more data?
  1558.     ja    spar11d            ; a = yes
  1559.     jmp    sparx1
  1560. spar11d:test    byte ptr [si-1],1    ; is CAPAS byte continued to another?
  1561.     jz    spar12            ; z = no
  1562.     lodsb                ; 3rd et seq CAPAS bitmaps
  1563.     dec    ah
  1564.     and    al,not (1)        ; remove least significant bit
  1565.     sub    al,20h            ; apply unchar(). Store nothing
  1566.     jmp    short spar11c        ; seek more CAPAS bytes
  1567.                     ;
  1568. spar12:    cmp    ah,0            ; [12] WINDO  more data?
  1569.     jg    spar12a            ; g = yes
  1570.     jmp    sparx1            ; exit spar
  1571. spar12a:lodsb                ; get other side's window size
  1572.     dec    ah
  1573.     sub    al,20h            ; apply unchar()
  1574.     call    dewind            ; negotiate window size
  1575.                     ;
  1576.     cmp    ah,2            ; [13-14] MAXL (long packet needs 2)
  1577.     jge    spar13a            ; ge = enough data to look at
  1578.     push    ax            ; make long same size as regular
  1579.     xor    ah,ah
  1580.     mov    al,trans.spsiz        ; normal packet size
  1581.     mov    trans.slong,ax        ; assume not using long packets
  1582.     pop    ax            ; recover ah
  1583.     jmp    sparx1            ; do final checks on packet length
  1584. spar13a:test    trans.capas,2        ; do they have long packet capability?
  1585.     jnz    spar13b            ; nz = yes
  1586.     jmp    sparx1            ; no, skip following l-pkt len fields
  1587. spar13b:lodsb                ; long pkt length, high order byte
  1588.     push    ax            ; save ah
  1589.     sub    al,20h            ; apply unchar()
  1590.     xor    ah,ah
  1591.     mul    ninefive        ; times 95 to dx (high), ax (low)
  1592.     mov    trans.slong,ax        ; store high order part
  1593.     lodsb                ; long pkt length, low order byte
  1594.     sub    al,20h            ; apply unchar()
  1595.     xor    ah,ah
  1596.     add    ax,trans.slong        ; plus high order part
  1597.     mov    trans.slong,ax        ; store it
  1598.     or    ax,ax            ; if result is 0 then use regular pkts
  1599.     jnz    spar13c            ; non-zero, use what they want
  1600.     mov    al,trans.spsiz        ; else default to regular packet size
  1601.     mov    ah,0
  1602.     mov    trans.slong,ax    ;  and ignore the CAPAS bit (no def 500 bytes)
  1603. spar13c:cmp    ax,dtrans.slong        ; longer than we want to do?
  1604.     jbe    spar13d            ; be = no
  1605.     mov    ax,dtrans.slong        ; limit to our longest sending size
  1606.     mov    trans.slong,ax        ; and use it
  1607. spar13d:pop    ax            ; recover ah
  1608.                     ; Windowing can further shrink pkts
  1609. sparx1:    push    cx            ; final packet size negotiations
  1610.     push    dx
  1611.     mov    ax,maxpack        ; our max buffer size
  1612.     mov    cl,trans.windo        ; number of active window slots
  1613.     xor    ch,ch
  1614.     jcxz    sparx2            ; 0 means 1, for safety here
  1615.     xor    dx,dx            ; whole buffer / # window slots
  1616.     div    cx            ; ax = longest windowed pkt possible
  1617.                     ; transmitter packet size
  1618. sparx2:    cmp    ax,trans.slong        ; our slots can be longer than theirs?
  1619.     ja    sparx2a            ; a = yes, use their shorter length
  1620.     mov    trans.slong,ax        ; no, use our shorter length
  1621. sparx2a:mov    cl,trans.spsiz        ; current regular pkt size
  1622.     mov    ch,0
  1623.     cmp    cx,ax            ; is regular longer than window slot?
  1624.     jbe    sparx3            ; be = no
  1625.     mov    trans.spsiz,al        ; shrink regular to windowed size
  1626.                     ; receiver packet size
  1627. sparx3:    cmp    ax,dtrans.rlong        ; slot shorter than longest allowed?
  1628.     jae    sparx5            ; ae = no
  1629.     mov    trans.rlong,ax        ; long size we want to receive
  1630.     mov    cl,dtrans.rpsiz        ; regular packet size user limit
  1631.     mov    ch,0
  1632.     cmp    cx,ax            ; is regular longer than window too?
  1633.     jbe    sparx4            ; be = no
  1634.     mov    cl,al            ; shrink regular to windowed size
  1635. sparx4:    mov    trans.rpsiz,cl        ; regular size we want
  1636. sparx5:    pop    dx
  1637.     pop    cx
  1638.     pop    si            ; saved at start of spar
  1639.     pop    ax
  1640.     ret
  1641. SPAR    ENDP
  1642.  
  1643. ; Set 8-bit quote character based on my capabilities and the other
  1644. ; Kermit's request. Quote if one side says Y and the other a legal char
  1645. ; or if both sides say the same legal char. Enter with AL = their quote char
  1646. DOQUO    PROC    NEAR
  1647.     cmp    dtrans.ebquot,'N'    ; we refuse to do 8-bit quoting?
  1648.     je    dq3            ; e = yes, do not quote
  1649.     cmp    al,'N'            ; 'N' = they refuse quoting?
  1650.     je    dq3            ; e = yes, do not quote
  1651.     cmp    dtrans.ebquot,'Y'    ; can we do it if requested?
  1652.     je    dq2            ; e = yes, use their char in al
  1653.     cmp    al,'Y'            ; 'Y' = they can quote if req'd?
  1654.     jne    dq1            ; ne = no, use their particular char
  1655.     mov    al,dtrans.ebquot    ; we want to use a particular char
  1656.     call    prechk            ;  and they said 'Y', check ours
  1657.     jc    dq3            ; c = ours is out of range, no quoting
  1658. dq1:    cmp    al,dtrans.ebquot    ; active quote vs ours, must match
  1659.     jne    dq3            ; ne = mismatch, no quoting
  1660. dq2:    mov    trans.ebquot,al        ; get active char, ours or theirs
  1661.     call    prechk            ; in range 33-62, 96-126?
  1662.     jc    dq3            ; c = out of range, do not quote
  1663.     cmp    al,trans.rquote        ; same prefix as control-quote?
  1664.     je    dq3            ; e = yes, don't do 8-bit quote
  1665.     cmp    al,trans.squote        ; same prefix control-quote?
  1666.     je    dq3            ; this is illegal too
  1667.     mov    trans.ebquot,al        ; remember what we decided on
  1668.     ret
  1669. dq3:    mov    trans.ebquot,'N'    ; quoting will not be done
  1670.     ret
  1671. DOQUO    ENDP
  1672.  
  1673. ; Check if prefix in AL is in the proper range: 33-62, 96-126. 
  1674. ; Return carry clear if in range, else return carry set.
  1675. prechk:    cmp    al,33
  1676.     jb    prechk2            ; b = out of range
  1677.     cmp    al,62
  1678.     jbe    prechk1            ; be = in range 33-62
  1679.     cmp    al,96
  1680.     jb    prechk2            ; b = out of range
  1681.     cmp    al,126
  1682.     ja    prechk2            ; a = out of range 96-126
  1683. prechk1:clc                ; carry clear for in range
  1684.     ret
  1685. prechk2:stc                ; carry set for out of range
  1686.     ret
  1687.  
  1688. ; Set checksum length. AL holds their checksum request.
  1689. dochk:    cmp    al,'1'            ; Must be '1', '2', or '3'
  1690.     jb    doc1            ; b = not '1' to '3'
  1691.     cmp    al,'3'
  1692.     jbe    doc2            ; be = ok
  1693. doc1:    mov    al,'1'            ; else use default of '1'
  1694. doc2:    sub    al,'0'            ; remove ascii bias
  1695.     mov    trans.chklen,al        ; other side's request is do-able here
  1696.     ret
  1697.  
  1698. ; Set repeat count quote character.  The one used must be different than
  1699. ; the control and eight-bit quote characters.  Also, both sides must 
  1700. ; use the same character
  1701. dorpt:    mov    trans.rptq,0        ; assume will not repeat prefix
  1702.     call    prechk            ; Is it in the valid range?
  1703.     jnc    dorpt1            ; nc = in range
  1704.     mov    al,0            ; don't use their value 
  1705. dorpt1:    cmp    al,trans.squote        ; same as the control quote char?
  1706.     je    dorpt2            ; e = yes, that's illegal, no repeats
  1707.     cmp    al,trans.rquote        ; this too?
  1708.     je    dorpt2            ; e = no good either
  1709.     cmp    al,trans.ebquot        ; same as eight bit quote char?
  1710.     je    dorpt2            ; e = yes, illegal too, no repeats
  1711.     cmp    al,dtrans.rptq        ; both sides using same char?
  1712.     jne    dorpt2            ; ne = no, that's no good either
  1713.     mov    trans.rptq,al        ; use repeat quote char now
  1714. dorpt2:    ret
  1715.  
  1716.                     ; negotiate window size in al
  1717. dewind:    cmp    al,dtrans.windo        ; their (al) vs our max window size
  1718.     jbe    dewind1            ; be = they want less than we can do
  1719.     mov    al,dtrans.windo        ; limit to our max size
  1720. dewind1:cmp    al,0
  1721.     ja    dewind2
  1722.     inc    al            ; use 1 if 0
  1723. dewind2:mov    trans.windo,al        ; store active window size
  1724.     ret
  1725.  
  1726.  
  1727. ; Set the maximum send data packet size; modified for long packets
  1728. PACKLEN    PROC    NEAR
  1729.     push    ax
  1730.     push    cx
  1731.     xor    ah,ah
  1732.     mov    al,trans.spsiz    ; Maximum send packet size for Regular pkts. 
  1733.     cmp    ax,trans.slong        ; negotiated long packet max size
  1734.     jae    packle2            ; ae = use regular packets
  1735.     mov    ax,trans.slong        ; else use long kind
  1736.     sub    ax,3            ; minus extended count & checksum
  1737.     cmp    ax,(95*94-1-2)        ; longer than Long?
  1738.     jle    packle2            ; le = no, Long will do
  1739.     dec    ax            ; minus one more for extra long count
  1740. packle2:sub    ax,2            ; minus Sequence, Type
  1741.     sub    al,trans.chklen        ; And minus Checksum chars
  1742.     sbb    ah,0            ; borrow propagate
  1743.     cmp    trans.ebquot,'N'    ; Doing 8-bit Quoting?
  1744.     je    packle0            ; Nope so we've got our size
  1745.     cmp    trans.ebquot,'Y'
  1746.     je    packle0            ; Not doing it in this case either
  1747.     dec    ax            ; Another 1 for 8th-bit Quoting. 
  1748. packle0:cmp    trans.rptq,0        ; Doing repeat character Quoting?
  1749.     je    packle1            ; Nope, so that's all for now
  1750.     dec    ax            ; minus repeat prefix
  1751.     dec    ax            ;  and repeat count
  1752. packle1:dec    ax            ; for last char might being a control code
  1753.     mov    trans.maxdat,ax        ; Save max length for data field
  1754.     pop    cx
  1755.     pop    ax
  1756.     ret
  1757. PACKLEN    ENDP
  1758.  
  1759.  ; Print the number in AX on the screen in decimal rather that hex
  1760.  
  1761. NOUT     PROC    NEAR
  1762.     test    flags.remflg,dserver    ; server mode?
  1763.     jnz    nout2            ; nz = yes, writing to their screen
  1764.     cmp    flags.xflg,0        ; receiving to screen?
  1765.     jne    nout1            ; ne = yes
  1766. nout2:    test    flags.remflg,dserial     ; serial display mode?
  1767.     jnz    pnout            ; nz = use "dot and plus" for serial mode
  1768.     test    flags.remflg,dquiet    ; quiet display mode?
  1769.     jnz    nout1            ; nz = yes. Don't write to screen
  1770.     call    decout            ; call standard decimal output routine
  1771. nout1:    ret
  1772.  
  1773. pnout:    or    ax,ax            ; display packet in serial display mode
  1774.     jz    pnoutx            ; z = nothing to display
  1775.     push    ax            ; for serial mode display
  1776.     push    cx
  1777.     push    dx            ; output .........+.........+  etc
  1778.     mov    dx,0            ; extended numerator
  1779.     mov    cx,10
  1780.     div    cx            ; number/10. (AX=quo, DX=rem)
  1781.     cmp    dx,0            ; remainder non-zero?
  1782.     jne    pnout1            ; ne = yes
  1783.     mov    dl,'+'            ; symbol plus for tens
  1784.     jmp    pnout2            ; display it
  1785. pnout1:    mov    dl,'.'            ; symbol for between tens
  1786. pnout2:    mov    ah,conout        ; output to console
  1787.     int    dos
  1788.     pop    dx
  1789.     pop    cx
  1790.     pop    ax
  1791. pnoutx:    ret
  1792. NOUT    ENDP
  1793.  
  1794. ; Decode and display Error packet message. 
  1795. ERROR    PROC    NEAR
  1796.     mov    sstate,'A'        ; Set the state to abort
  1797.     push    si
  1798.     mov    si,offset rpacket    ; source address
  1799.     call    dodec            ; decode to decbuf
  1800.     mov    dx,offset decbuf    ; where msg got decoded, asciiz
  1801.     call    ermsg            ; display string
  1802.     pop    si
  1803.     stc                ; set carry for failure state
  1804.     ret
  1805. ERROR    ENDP
  1806.  
  1807. ; General routine for sending an error packet.  Register BX should
  1808. ; point to the text of the message being sent in the packet
  1809.  
  1810. ERRPACK    PROC    NEAR
  1811.     push    cx
  1812.     push    di
  1813.     mov    di,offset encbuf    ; Where to put the message
  1814.     mov    cx,0
  1815. errpa1:    mov    al,[bx]
  1816.     inc    bx
  1817.     cmp    al,'$'            ; At end of message?
  1818.     je    errpa2            ; e = terminator
  1819.     cmp    al,0            ; this kind of terminator too?
  1820.     je    errpa2            ; e = terminator
  1821.     inc    cx            ; count number of chars in msg
  1822.     mov    [di],al            ; copy message
  1823.     inc    di
  1824.     jmp    short errpa1
  1825. errpa2:    push    si
  1826.     mov    si,offset rpacket    ; use response buffer
  1827.     mov    al,pktnum
  1828.     mov    rpacket.seqnum,al
  1829.     call    doenc
  1830.     call    pktsize            ; report packet size
  1831.     mov    rpacket.pktype,'E'    ; send an error packet
  1832.     call    spack
  1833.     mov    rpacket.datlen,0    ; clear response buffer
  1834.     pop    si
  1835.     pop    di
  1836.     pop    cx
  1837.     ret
  1838. ERRPACK    ENDP
  1839.  
  1840. ; Enter with dx pointing to asciiz error message to be sent
  1841. giveup    proc near
  1842.     call    bufclr            ; release all buffers
  1843.     call    ermsg            ; position cursor, display asciiz msg
  1844.     mov    bx,dx
  1845.     call    errpack            ; send error packet
  1846.     mov    auxfile,0        ; clear send-as/mail-to buffer
  1847.     mov    mailflg,0        ; clear Mail flag
  1848.     cmp    filopn,0        ; disk files open?
  1849.     je    giveu2            ; e = no so don't do a close
  1850.     mov    ah,close2        ; close file
  1851.     push    bx
  1852.     mov    bx,diskio.handle    ; file handle
  1853.     int    dos
  1854.     pop    bx
  1855.     mov    filopn,0        ; say file is closed now
  1856. giveu2:    mov    sstate,'A'        ; abort state
  1857.     or    errlev,1        ; set DOS error level
  1858.     or    fsta.xstatus,1        ; set status
  1859.     mov    kstatus,1        ; global status
  1860.     stc                ; set carry for failure status
  1861.     ret
  1862. giveup    endp
  1863.  
  1864. code    ends 
  1865.     end
  1866.