home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / mssrcv.asm < prev    next >
Assembly Source File  |  1993-07-12  |  41KB  |  1,255 lines

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