home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msssen.asm < prev    next >
Assembly Source File  |  2020-01-01  |  82KB  |  2,465 lines

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