home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / mssrcv.asm < prev    next >
Assembly Source File  |  2020-01-01  |  49KB  |  1,471 lines

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