home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSSSEN.ASM < prev    next >
Assembly Source File  |  1993-05-14  |  65KB  |  1,961 lines

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