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

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