home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / misc / pdp10 / k10msg.bli < prev    next >
Text File  |  2020-01-01  |  151KB  |  6,739 lines

  1. %TITLE 'KERMSG - Kermit message processing'
  2. MODULE KERMSG (IDENT = '3.3.108'
  3.         ) =
  4. BEGIN
  5.  
  6. SWITCHES LANGUAGE (COMMON);
  7.  
  8. !<BLF/WIDTH:100>
  9.  
  10. !++
  11. ! FACILITY:
  12. !   Kermit-10, VMS Kermit, Pro/Kermit
  13. !
  14. ! ABSTRACT:
  15. !    KERMSG is the message processing routines for Kermit-10, VMS Kermit,
  16. !    and PRO/Kermit.
  17. !    This module is written in common BLISS, so that it can be
  18. !    transported for the DECsystem-10 and VAX/VMS systems.
  19. !
  20. ! ENVIRONMENT:
  21. !   User mode
  22. !
  23. ! AUTHOR: Robert C. McQueen, CREATION DATE: 24-January-1983
  24. !
  25. ! MODIFIED BY:
  26. !
  27. !--
  28.  
  29. %SBTTL 'Table of Contents'
  30. !+
  31. !.pag.lit
  32. !        Table of Contents for KERMSG
  33. !
  34. !
  35. !               Section                  Page
  36. !   1. Revision History . . . . . . . . . . . . . . . . . . .    3
  37. !   2. Interface requirements . . . . . . . . . . . . . . . .    4
  38. !   3. Declarations
  39. !        3.1.   Forward definitions . . . . . . . . . . . . .    5
  40. !   4. Require files. . . . . . . . . . . . . . . . . . . . .   28
  41. !   5. Macro definitions. . . . . . . . . . . . . . . . . . .   29
  42. !   6. KERMIT Protocol Definitions. . . . . . . . . . . . . .   30
  43. !        6.1.   Packet offsets. . . . . . . . . . . . . . . .   31
  44. !        6.2.   Message dependent field . . . . . . . . . . .   32
  45. !        6.3.   SEND initiate packet. . . . . . . . . . . . .   33
  46. !   7. KERMIT Protocol States . . . . . . . . . . . . . . . .   34
  47. !   8. Internal constants . . . . . . . . . . . . . . . . . .   35
  48. !   9. Storage - External . . . . . . . . . . . . . . . . . .   36
  49. !  10. Storage - Local. . . . . . . . . . . . . . . . . . . .   37
  50. !  11. External references. . . . . . . . . . . . . . . . . .   38
  51. !  12. MSG_INIT . . . . . . . . . . . . . . . . . . . . . . .   39
  52. !  13. SND_ERROR. . . . . . . . . . . . . . . . . . . . . . .   40
  53. !  14. SERVER - Server mode . . . . . . . . . . . . . . . . .   41
  54. !  15. SEND_SWITCH. . . . . . . . . . . . . . . . . . . . . .   42
  55. !  16. REC_SWITCH . . . . . . . . . . . . . . . . . . . . . .   43
  56. !  17. Server
  57. !       17.1.   DO_GENERIC - Execute a generic command. . . .   44
  58. !  18. DO_TRANSACTION - Main loop for FSM . . . . . . . . . .   45
  59. !  19. REC_SERVER_IDLE - Idle server state. . . . . . . . . .   46
  60. !  20. SEND_SERVER_INIT . . . . . . . . . . . . . . . . . . .   47
  61. !  21. SEND_DATA. . . . . . . . . . . . . . . . . . . . . . .   48
  62. !  22. SEND_FILE. . . . . . . . . . . . . . . . . . . . . . .   49
  63. !  23. SEND_EOF . . . . . . . . . . . . . . . . . . . . . . .   50
  64. !  24. SEND_INIT. . . . . . . . . . . . . . . . . . . . . . .   51
  65. !  25. SEND_OPEN_FILE - Open file for sending . . . . . . . .   52
  66. !  26. SEND_GENCMD. . . . . . . . . . . . . . . . . . . . . .   53
  67. !  27. SEND_BREAK . . . . . . . . . . . . . . . . . . . . . .   54
  68. !  28. REC_INIT . . . . . . . . . . . . . . . . . . . . . . .   55
  69. !  29. REC_FILE . . . . . . . . . . . . . . . . . . . . . . .   56
  70. !  30. REC_DATA . . . . . . . . . . . . . . . . . . . . . . .   57
  71. !  31. SERVER - Generic commands. . . . . . . . . . . . . . .   58
  72. !  32. HOST_COMMAND - perform a host command. . . . . . . . .   59
  73. !  33. CALL_SY_RTN - handle operating system dependent functions  60
  74. !  34. Message processing
  75. !       34.1.   PRS_SEND_INIT - Parse send init params. . . .   61
  76. !  35. SET_SEND_INIT. . . . . . . . . . . . . . . . . . . . .   62
  77. !  36. SEND_PACKET. . . . . . . . . . . . . . . . . . . . . .   63
  78. !  37. REC_MESSAGE - Receive a message. . . . . . . . . . . .   64
  79. !  38. REC_PACKET . . . . . . . . . . . . . . . . . . . . . .   65
  80. !  39. CALC_BLOCK_CHECK . . . . . . . . . . . . . . . . . . .   66
  81. !  40. NORMALIZE_FILE - Put file name into normal form. . . .   67
  82. !  41. Buffer filling
  83. !       41.1.   Main routine. . . . . . . . . . . . . . . . .   68
  84. !  42. BFR_EMPTY. . . . . . . . . . . . . . . . . . . . . . .   69
  85. !  43. Buffer filling and emptying subroutines. . . . . . . .   70
  86. !  44. Add parity routine . . . . . . . . . . . . . . . . . .   71
  87. !  45. Parity routine . . . . . . . . . . . . . . . . . . . .   72
  88. !  46. Per transfer
  89. !       46.1.   Initialization. . . . . . . . . . . . . . . .   73
  90. !  47. Statistics
  91. !       47.1.   Finish message transfer . . . . . . . . . . .   74
  92. !  48. Status type out
  93. !       48.1.   STS_OUTPUT. . . . . . . . . . . . . . . . . .   75
  94. !  49. TYPE_CHAR - Type out a character . . . . . . . . . . .   76
  95. !  50. Debugging
  96. !       50.1.   DBG_SEND. . . . . . . . . . . . . . . . . . .   77
  97. !       50.2.   DBG_RECEIVE . . . . . . . . . . . . . . . . .   78
  98. !       50.3.   DBG_MESSAGE . . . . . . . . . . . . . . . . .   79
  99. !  51. End of KERMSG. . . . . . . . . . . . . . . . . . . . .   80
  100. !.end lit.pag
  101. !-
  102. %SBTTL 'Revision History'
  103.  
  104. !++
  105. ! Start of version 1.
  106. !
  107. ! 1.0.000    By: Robert C. McQueen        On: 4-Jan-1983
  108. !        Create this program.
  109. !
  110. ! 1.0.001    By: Robert C. McQueen        On: 30-Apr-1983
  111. !        Change PAR_xxx to be PR_xxx, so that they can be used for
  112. !        KERMIT-10.
  113. !
  114. ! 1.0.002    By: Robert C. McQueen        On: 1-May-1983
  115. !        Add DO_GENERIC routine to cause a generic Kermit command to
  116. !        be executed on the remote Kermit.
  117. !
  118. ! 1.0.003    By: Robert C. McQueen        On: 3-May-1983
  119. !        Fix message number incrementing.
  120. !
  121. ! 1.0.004    By: Robert C. McQueen        On: 4-May-1983
  122. !        Allow RECEIVE file-specification to work correctly.
  123. !
  124. ! 1.0.005    By: Robert C. McQueen        On: 6-May-1983
  125. !        Add more stats support.
  126. !
  127. ! 1.0.006    By: Nick Bush            On: 13-June-1983
  128. !        Fix SEND_PACKET to copy correct characters when fixing
  129. !        parity bits.
  130. !
  131. ! 1.1.007    By: Nick Bush            On: 15-July-1983
  132. !        Correct SEND-INIT message handling to do the right things
  133. !        with the protocol version 3 items.
  134. !
  135. ! 1.1.010    By: Robert C. McQueen        On: 20-July-1983
  136. !        Make PARITY a global routine, so that it can be called by
  137. !        CONNECT processing.  Change the name from PARITY to GEN_PARITY
  138. !        add a new routine to generate the parity, since it is not
  139. !        part of the checksum.
  140. !
  141. ! 1.1.011    By: Robert C. McQueen        On: 28-July-1983
  142. !        KER_TIMEOUT errors in the SERVER loop would cause
  143. !        KER_UNISRV error messages to be returned to the remote.
  144. !        Check for receive failures and send NAKs instead.
  145. !
  146. ! 1.2.012    By: Robert C. McQueen        On: 23-August-1983
  147. !        Don't abort if we get a message that is just an end of line
  148. !        character.  It could be noise on the line.
  149. !
  150. ! 1.2.013    By: Nick Bush            On: 7-September-1983
  151. !        Fix several problems with the SEND_xxx parameters
  152. !
  153. ! 1.2.014    By: Robert C. McQueen        On: 15-September-1983
  154. !        Add routine calls to XFR_STATUS to tell the user on the
  155. !        number of packets have changed.
  156. !
  157. ! 1.2.015    By: Nick Bush            On: 5-October-1983
  158. !        Add 2 and 3 character checksum (block check) support.
  159. !        Add support for data within acknowledgement packets
  160. !        and withing end-of-file packets to allow for file
  161. !        transmission to be aborted.  Also add support for
  162. !        "I" packet to allow server parameters to be initialized.
  163. !
  164. ! 1.2.016    By: Nick Bush            On: 19-October-1983
  165. !        Add repeat character support.
  166. !
  167. ! 2.0.017    Release TOPS-10 Kermit-10 version 2.0
  168. !        Release VAX/VMS Kermit-32 version 2.0
  169. !
  170. ! 2.0.018    By: Robert C. McQueen        On: 16-November-1983
  171. !        Fix four checks on the message number that were not
  172. !        mod 64.
  173. !
  174. ! 2.0.019    By: Robert C. McQueen        On: 16-November-1983
  175. !        Remove the CLEAR routine.  It is not really needed.
  176. !
  177. ! 2.0.020    By: Nick Bush            On: 12-Dec-1983
  178. !        Fix SEND_DATA and BFR_FILL to handle empty files and
  179. !        files which happen to end just on a message boundary.
  180. !        This would sometimes produce extra nulls.
  181. !
  182. ! 2.0.021    By: Nick Bush            On: 15-Dec-1983
  183. !        Fix some problems with REC_MESSAGE which would cause
  184. !        aborts when a message timed out.
  185. !
  186. ! 2.0.022    By: Robert C. McQueen        19-Dec-1983
  187. !        Make STATUS a local for most routines and remove FILE_DUMP
  188. !        as it is nolonger needed.
  189. !
  190. ! 2.0.023    By: Nick Bush            On: 3-Jan-1984
  191. !        Change FIL_NORMAL_FORM to contain not just a flag, but
  192. !        a file name type instead.
  193. !
  194. ! 2.0.024    By: Nick Bush            On: 11-Jan-1984
  195. !        Fix REC_MESSAGE to send NAK for packet we expect, not
  196. !        previous packet.
  197. !
  198. ! 2.0.025    By: Nick Bush            On: 23-Jan-1984
  199. !        Re-enable server-init packet and complete code so that
  200. !        parameters set by it will remain set.
  201. !        Fix file name copying to use BFR_FILL or BFR_EMPTY
  202. !        so that all quoting/compression is done properly.
  203. !
  204. ! 2.0.026    By: Nick Bush            On: 15-Feb-1984
  205. !        Add code for generic command support (both directions).
  206. !        There is now only one state dispatch loop, entered
  207. !        in various states for different functions.
  208. !
  209. ! 2.0.027    By: Robert C. McQueen        On: 16-Feb-1984
  210. !        At some point SEND_TIMEOUT became global, but it was not moved
  211. !        to KERGLB.  This edit moves it to KERGLB.BLI.
  212. !
  213. ! 2.0.030    By: Nick Bush            On: 2-March-1984
  214. !        Fix BFR_FILL to handle case of last repeated character
  215. !        not fitting within a packet.  It was forgetting to
  216. !        send the characters at all.
  217. !
  218. ! 2.0.031    By: Nick Bush            On: 6-March-1984
  219. !        Make sure FILE_OPEN_FLAG is set properly when advancing
  220. !        to next file of a wild-card send.  The file was not
  221. !        being set true, leading to problems after a couple files.
  222. !
  223. ! 2.0.032    By: Nick Bush            On: 9-March-1984
  224. !        Fix UNPACK_DATA in SERVER_GENERIC to properly store
  225. !        new string pointer.
  226. !
  227. ! 2.0.033    By: Robert C. McQueen        On: 12-March-1984
  228. !        If NEXT_FILE fails with anything other than a NOMORFILES
  229. !        it should change state to STATE_A not STATE_SB.  This
  230. !        fixes a problem caused by Pro/Kermit and KERFIL (VMS).
  231. !
  232. ! 2.0.034    By: Nick Bush            On: 15-March-1984
  233. !        Put file spec into X packet as well as F packet. This
  234. !        makes wild card TYPE's work nicer.
  235. !
  236. ! 2.0.035    By: Nick Bush            On: 20-March-1984
  237. !        Fix send/receive quoting to conform to the way the
  238. !        protocol manual says it should be done, rather
  239. !        than the way we (and Kermit-20) have always done it.
  240. !
  241. ! 2.0.036    By: Nick Bush            On: 28-March-1984
  242. !        Make SERVER_GENERIC more defensive against badly
  243. !        constructed packets.  If an argument has negative
  244. !        length, punt the request.  Also put angle brackets
  245. !        around data from "X" packet header, so file names will
  246. !        stick out.
  247. !
  248. ! 3.0.037    Start of version 3.
  249. !
  250. ! 3.0.040    By: Nick Bush            On: 2-April-1984
  251. !        Add separate server timeout.  This allows stopping the
  252. !        server NAK's without affecting the normal packet timeout.
  253. !
  254. ! 3.0.041    By: Nick Bush            On: 12-April-1984
  255. !        Fix block check calculation to account for the fact
  256. !        that the parity bits are put onto the message when
  257. !        it is sent (in place), so that if a retransmission is
  258. !        done without refilling the buffer (as is normal with
  259. !        data messages), the parity bits will be there.  Make
  260. !        sure we strip them out for block check calculation.
  261. !
  262. ! 3.1.042    By: Nick Bush            On: 27-August-1984
  263. !        If we get too many retries when sending a server init (I)
  264. !        packet, don't abort.  Instead, just try sending the server
  265. !        command, since the Kermit on the other end might be coded
  266. !        wrong and is responding to packets it doesn't understand
  267. !        with a NAK.
  268. !
  269. ! 3.1.043    By: Nick Bush            On: 27-August-1984
  270. !        Don't abort receives on zero length messages.  Just treat
  271. !        it like a timeout.
  272. !
  273. ! 3.1.044    By: Nick Bush            On: 10-April-1985
  274. !        Remove IBM mode.  It will be instituted by IBM_CHAR being
  275. !        set >= 0 if handshaking is needed.
  276. !
  277. ! 3.1.045    BY: David Stevens        On: 15-July-1985
  278. !        Fix terminal message for multiple file sendings. Type out
  279. !        "Sending: " in the system dependent NEXT_FILE routine.
  280. !
  281. ! Start of version 3.2
  282. !
  283. ! 3.2.070    By: Robert McQueen        On: 17-Dec-1985
  284. !        Fix CRC calculations when sending 8 bit data and not
  285. !        using 8 bit quoting.
  286. !
  287. ! 3.2.071    By: Robert McQueen        On: 11-March-186
  288. !        Include space in the message buffer for the line termination
  289. !        character.
  290. !
  291. ! 3.3.100    By: Gregory P. Welsh        On: 1-June-1986
  292. !        Made FILE_OPEN_FLAG GLOBAL so it could be updated properly for
  293. !        Transmit function from module KERTRM. Also renamed it to
  294. !        FFILE_OPEN_FLAG so it could be distinguished externally from
  295. !        routine FILE_OPEN.
  296. !
  297. ! 3.3.104    By: Robert McQueen            On: 5-July-1986
  298. !        Add changes/fixes suggested by Art Guion and David Deley for
  299. !        KERMSG.BLI.
  300. !        - Always attempt a handshake in IBM mode.  Failing to handshake
  301. !          may cause 3704/5 style controller to hang a VM system.
  302. !        - Don't lose the last character in a buffer.   BFR_FILL logic
  303. !          forgets to send the last cahracters of a file when it doesn't
  304. !          fit into the current packet.
  305. !
  306. ! 3.3.107    By: Antonino N. Mione            On: 8-Sep-1986
  307. !        Do not abort on ERROR packet while in SERVER mode. Instead,
  308. !        return to SERVER IDLE mode.
  309. !
  310. ! 3.3.108    By: Dan Norstedt        On: 17-June-1989
  311. !        Added sketchy support for Extended Length packets;
  312. !        Header parity is computed, but not used.
  313. !        Undone 3.3.107, to allow for Ctrl-Cs to work properly
  314. !--
  315.  
  316. %SBTTL 'Interface requirements'
  317.  
  318. !++
  319. !        Interface requirements
  320. !
  321. ! The following routines and data locations are rquired for a correct
  322. ! implementation of KERMIT.
  323. !
  324. ! File routines:
  325. !
  326. !    FILE_OPEN (Function)
  327. !        This routine will open a file for reading or writting.  It
  328. !        will assume that FILE_SIZE contains the number of bytes
  329. !        and FILE_NAME contains the file name of length FILE_SIZE.
  330. !        The function that is passed is either FNC_READ or FNC_WRITE.
  331. !
  332. !    FILE_CLOSE ()
  333. !        This routine will close the currently open file.  This
  334. !        routine will return the status of the operation.
  335. !
  336. !    GET_FILE (Character)
  337. !        This routine will get a character from the currently open file
  338. !        and store it in the location specified by "Character".  There
  339. !        will be a true/false value returned by the routine to determine
  340. !        if there was an error.
  341. !
  342. !    PUT_FILE (Character)
  343. !        This routine will output a character to the currently open
  344. !        file.  It will return a true/false value to determine if the
  345. !        routine was successful.
  346. !
  347. !    NEXT_FILE ()
  348. !        This routine will advance to the next file.  This routine
  349. !        will return false if there are no more files to process.
  350. !
  351. ! Communications line routines:
  352. !
  353. !    RECEIVE (Buffer address, Address of var to store length into)
  354. !        This routine will receive a message from the remote Kermit.
  355. !
  356. !    SEND (Buffer address, Length in characters)
  357. !        This routine will send a message to the remote Kermit.
  358. !
  359. !    GEN_CRC (Buffer address, length in characters)
  360. !        This routine will calculate the CRC-CCITT for the characters
  361. !        in the buffer.
  362. !
  363. ! Operating system routines:
  364. !
  365. !    SY_DISMISS (Seconds)
  366. !        This routine will cause Kermit to sleep for the specified
  367. !        number of seconds.  It is used to handle the DELAY parameter.
  368. !
  369. !    SY_LOGOUT ()
  370. !        Log the job off of the system. (Kill the process).
  371. !
  372. !    SY_TIME ()
  373. !        This routine will return the starting time milliseconds.
  374. !        It can be the start of Kermit, the system, etc, so long
  375. !        as it always is incrementing.
  376. !
  377. ! Status routines:
  378. !
  379. !    XFR_STATUS (Type, Subtype);
  380. !        This routine is called to indicate the occurance of
  381. !        a significant event that the user interface may wish
  382. !        to inform the user about.  The arguments indicate the
  383. !        type of event.
  384. !        Type: "S" - Send, "R" - Receive
  385. !            Subtype: "P" - Packet
  386. !                 "N" - NAK
  387. !                 "T" - timeout
  388. !        For type = "I" (initiate), "T" (terminate):
  389. !            Subtype: "S" - a file send
  390. !                 "R" - a file receive
  391. !                 "G" - a generic command
  392. !                 "I" - for "T" only, returning to server idle
  393. !        For type = "F" (file operation):
  394. !            Subtype: "S" - open for sending
  395. !                 "R" - open for receiving
  396. !                 "C" - closing file OK
  397. !                 "X" - aborting file by user request
  398. !                 "Z" - aborting group by user request
  399. !                 "D" - aborting file, but saving due to disposition
  400. !                 "A" - aborting file due to protocol error
  401. !
  402. ! Error processing:
  403. !
  404. !    KRM_ERROR (Error parameter)
  405. !        This routine will cause an error message to be issued.
  406. !        The error parameter is defined by KERERR.  This may cause
  407. !        SND_ERROR to be called to send an "E" message to the remote.
  408. !
  409. ! Terminal I/O routines:
  410. !
  411. !    TERM_DUMP (Buffer, Count)
  412. !    DBG_DUMP (Buffer, Count)
  413. !        This routine will dump the buffer onto the user's terminal.
  414. !        The routine is supplied with the count of the characters
  415. !        and the address of the buffer.
  416. !        These may be the same routine or different.  DBG_DUMP
  417. !        is only called for debugging output.
  418. !
  419. !
  420. !            ENTRY POINTS
  421. !
  422. ! KERMSG contains the following entry points for the KERMIT.
  423. !
  424. !    SERVER ()
  425. !        This routine will cause KERMIT go enter server mode.
  426. !
  427. !    SEND_SWITCH ()
  428. !        This routine will send a file.  It expects that the user
  429. !        has stored the text of the file name into FILE_NAME and
  430. !        the length of the text into FILE_SIZE.
  431. !
  432. !    REC_SWITCH ()
  433. !        This routine will receive a file.  It expects that the default
  434. !        file name is set up in FILE_NAME and the length is in
  435. !        FILE_SIZE.
  436. !
  437. !    GEN_PARITY (Character)
  438. !        This routine will return the character with the proper parity
  439. !        on the character.
  440. !
  441. !    SND_ERROR (COUNT, ADDRESS)
  442. !        This routine will send the text of an error to the remote
  443. !        Kermit.
  444. !
  445. !    DO_GENERIC (TYPE)
  446. !        This routine will cause a generic function to be sent to
  447. !        the remote Kermit.  This routine will then do all of the
  448. !        necessary hand shaking to handle the local end of the generic
  449. !        Kermit command.
  450. !
  451. !
  452. !        GLOBAL Storage
  453. !
  454. ! The following are the global storage locations that are used to interface
  455. ! to KERMSG.  These locations contains the various send and receive parameters.
  456. !
  457. ! Receive parameters:
  458. !
  459. !    RCV_PKT_SIZE
  460. !        Receive packet size.
  461. !    RCV_NPAD
  462. !        Padding length
  463. !    RCV_PADCHAR
  464. !        Padding character
  465. !    RCV_TIMEOUT
  466. !        Time out
  467. !    RCV_EOL
  468. !        End of line character
  469. !    RCV_QUOTE_CHR
  470. !        Quote character
  471. !    RCV_8QUOTE_CHR
  472. !        8-bit quoting character
  473. !    RCV_SOH
  474. !        Start of header character
  475. !
  476. ! Send parameters (Negative values denote the default, positive user supplied):
  477. !
  478. !    SND_PKT_SIZE
  479. !        Send packet size
  480. !    SND_NPAD
  481. !        Padding length
  482. !    SND_PADCHAR
  483. !        Padding character
  484. !    SND_TIMEOUT
  485. !        Time out
  486. !    SND_EOL
  487. !        End of line character
  488. !    SND_QUOTE_CHR
  489. !        Quote character
  490. !    SND_SOH
  491. !        Start of header character (normally 001)
  492. !
  493. ! Statistics:
  494. !
  495. !    SND_TOTAL_CHARS
  496. !        Total characters sent for this Kermit session
  497. !    RCV_TOTAL_CHARS
  498. !        Total characters received for this Kermit session
  499. !    SND_DATA_CHARS
  500. !        Total number of data characters sent for this Kermit session
  501. !    RCV_DATA_CHARS
  502. !        Total number of data characters received for this Kermit session
  503. !    SND_COUNT
  504. !        Total number of packets that have been sent
  505. !    RCV_COUNT
  506. !        Total number of packets that have been received.
  507. !    SMSG_TOTAL_CHARS
  508. !        Total characters sent for this file transfer
  509. !    RMSG_TOTAL_CHARS
  510. !        Total characters received for this file transfer
  511. !    SMSG_DATA_CHARS
  512. !        Total data characters sent for this file transfer
  513. !    RMSG_DATA_CHARS
  514. !        Total data characters received for this file transfer
  515. !    SMSG_NAKS
  516. !        Total number of NAKs sent for this file transfer
  517. !    RMSG_NAKS
  518. !        Total number of NAKs received for this file transfer
  519. !    XFR_TIME
  520. !        Amount of time the last transfer took in milliseconds.
  521. !    TOTAL_TIME
  522. !        Total amount of time spend transfering data.
  523. !
  524. ! Misc constants:
  525. !
  526. !    LAST_ERROR
  527. !        ASCIZ of the last error message issued.
  528. !    FILE_NAME
  529. !        Vector containing the ASCII characters of the file name.
  530. !    FILE_SIZE
  531. !        Number of characters in the FILE_NAME vector.
  532. !    DELAY
  533. !        Amount of time to delay
  534. !    DUPLEX
  535. !        DP_HALF or DP_FULL to denote either half duplex or full duplex.
  536. !        [Currently only DP_FULL is supported]
  537. !    PKT_RETRIES
  538. !        Number of retries to attempt to read a message.
  539. !    SI_RETRIES
  540. !        Number of retries to attempt on send inits
  541. !    DEBUG_FLAG
  542. !        Debugging mode on/off
  543. !    WARN_FLAG
  544. !        File warning flag
  545. !    IBM_FLAG
  546. !        True if talking to an IBM system, else false.
  547. !    ECHO_FLAG
  548. !        Local echo flag
  549. !    CONNECT_FLAG
  550. !        Connected flag; True if terminal and SET LINE are the same
  551. !    PARITY_TYPE
  552. !        Type of parity to use on sends.
  553. !    DEV_PARITY_FLAG
  554. !        Device will add parity to message.  True if device adds
  555. !        parity and false if we must do it.
  556. !    FLAG_FILE_OPEN
  557. !        File is opened.
  558. !
  559. !--
  560.  
  561. %SBTTL 'Declarations -- Forward definitions'
  562. !<BLF/NOFORMAT>
  563. !
  564. ! Forward definitions
  565. !
  566.  
  567. FORWARD ROUTINE
  568.  
  569. ! Main loop for a complete transaction
  570.     DO_TRANSACTION,        ! Perform a complete transaction
  571.  
  572. ! Send processing routines
  573.  
  574.     SEND_SERVER_INIT,        ![026] Send a server init packet
  575.     SEND_DATA,            ! Send data to the micro
  576.     SEND_FILE,            ! Send file name
  577.     SEND_OPEN_FILE,            ! Open file for sending
  578.     SEND_GENCMD,        ! Send generic command
  579.     SEND_EOF,            ! Send EOF
  580.     SEND_INIT,            ! Send initialization msg
  581.     SEND_BREAK,            ! Send break end of transmission
  582.  
  583. ! Receive processing routines
  584.  
  585.     REC_SERVER_IDLE,        ! Wait for message while server is idle
  586.     REC_INIT,            ! Receive initialization
  587.     REC_FILE,            ! Receive file information
  588.     REC_DATA,            ! Receive data
  589. !
  590. ! Server processing routines
  591. !
  592.     SERVER_GENERIC,        ! Process generic KERMIT commands
  593.     HOST_COMMAND,        ! Process host command
  594.     KERMIT_COMMAND,        ! Process Kermit command
  595.     CALL_SY_RTN,        ! Handle calling system routine and returning result
  596. !
  597. ! Statistic gathering routines
  598. !
  599.     END_STATS    : NOVALUE,    ! End of a message processing stats routine
  600.  
  601. ! Low level send/receive routines
  602.  
  603.     CALC_BLOCK_CHECK,        ! Routine to calculate the block check value
  604.     SET_SEND_INIT : NOVALUE,    ! Set up the MSG_SND_INIT parameters.
  605.     PRS_SEND_INIT,        ! Parse MSG_SND_INIT parameters.
  606.     DO_PARITY : NOVALUE,    ! Routine to generate parity for a message
  607.     GEN_PARITY,            ! Routine to add parity to a character
  608.     SEND_PACKET,        ! Send a packet to the remote
  609.     REC_MESSAGE,        ! Receive a message with retry processing
  610.     REC_PACKET,            ! Receive a packet from the remote
  611.  
  612. ! Utility routines
  613.  
  614.     NORMALIZE_FILE : NOVALUE,    ! Force file name into normal form
  615.     BFR_EMPTY,            ! Empty the data buffer
  616.     BFR_FILL,            ! Fill the data buffer from a file
  617.     SET_STRING,            ![025] Routine to set alternate get/put routines
  618.                     ! for use with in memory strings
  619.     TYPE_CHAR,            ! Type a character from a packet
  620.     INIT_XFR    : NOVALUE,    ! Initialize the per transfer processing
  621.     STS_OUTPUT    : NOVALUE,    ! Output current transfer status
  622. !
  623. ! Debugging routines
  624. !
  625.     DBG_MESSAGE    : NOVALUE,    ! Type out a formatted message
  626.     DBG_SEND    : NOVALUE,    ! Send message debugging routine
  627.     DBG_RECEIVE    : NOVALUE;    ! Receive message debugging routine
  628.     %SBTTL    'Require files'
  629.  
  630. !
  631. !<BLF/FORMAT>
  632. !
  633. ! REQUIRE FILES:
  634. !
  635.  
  636. %IF %BLISS (BLISS32)
  637. %THEN
  638.  
  639. LIBRARY 'SYS$LIBRARY:STARLET';
  640.  
  641. %FI
  642.  
  643. REQUIRE 'KERCOM';
  644.  
  645. REQUIRE 'KERERR';
  646.  
  647. %SBTTL 'Macro definitions'
  648. !
  649. ! MACROS:
  650. !
  651.  
  652. MACRO
  653.     CTL (C) =
  654.  ((C) XOR %O'100')%,
  655.     CHAR (C) =
  656.  ((C) + %O'40')%,
  657.     UNCHAR (C) =
  658.  ((C) - %O'40')%;
  659.  
  660. %SBTTL 'KERMIT Protocol Definitions'
  661.  
  662. !++
  663. ! The following describes the various items that are found in the
  664. ! KERMIT messages.  A complete and through desription of the protocol can be
  665. ! found in the KERMIT PROTOCOL MANUAL.
  666. !
  667. !
  668. ! All KERMIT messages have the following format:
  669. !
  670. ! <Mark><CHAR(Count)><CHAR(Seq)><Message-dependent information><Check><EOL>
  671. !
  672. ! <MARK>
  673. !    Normally SOH (Control-A, octal 001).
  674. !
  675. ! <CHAR(Count)>
  676. !    Count of the number of characters following this position.
  677. !    Character counts of ONLY 0 to 94 are valid.
  678. ! [108] Charavcter count = 0 means extended length type packet.
  679. !
  680. ! <CHAR(Seq)>
  681. !    Packet sequence number, modulo 100 (octal).
  682. !
  683. ! [108]    <CHAR(Type)>
  684. ! [108]        Packet type, usually a mnemonic ASCII character.
  685. ! [108]
  686. ! [108]    For Extended Length packets only:
  687. ! [108]   <CHAR(Count/95)>
  688. ! [108]        Count of the number of characters / 95, from (HeaderCheck)
  689. ! [108]
  690. ! [108]   <CHAR(Count MOD 95)>
  691. ! [108]        Count of the number of characters MOD 95, from (HeaderCheck)
  692. ! [108]
  693. ! [108]   <CHAR(HeaderCheck)>
  694. ! [108]        Kermit type-1 checksum of the 5 preceding ASCII characters.
  695. !
  696. ! <MESSAGE-DEPENDENT INFORMATION>
  697. !    This field contains the message dependent information.  There can
  698. !    be multiple fields in this section.  See the KERMIT Protocol document
  699. !    for a complete description of this.
  700. !
  701. ! <Check>
  702. !    A block check on the characters in the packet between, but not
  703. !    including, the mark and the checksum itself.  It may be one to three
  704. !    characters, depending upon the type agreed upon.
  705. !
  706. !    1. Single character arithmetic sum equal to:
  707. !        chksum = (s + ((s AND 300)/100)) AND 77
  708. !        Character sent is CHAR(chksum).
  709. !
  710. !    2. Two character arithmetic sum.  CHAR of bits 6-11 are the first
  711. !       character, CHAR of bits 0-5 are the second character.
  712. !
  713. !    3. Three character CRC-CCITT.  First character is CHAR of bits 12-15,
  714. !       second is CHAR of bits 6-11, third is CHAR of bits 0-5.
  715. !
  716. !
  717. ! <EOL>
  718. !    End of line.  Any line terminator that may be required by the host.
  719. !--
  720.  
  721. %SBTTL 'KERMIT Protocol Definitions -- Packet offsets'
  722.  
  723. !++
  724. ! The following define the various offsets of the standard KERMIT
  725. ! packets.
  726. !--
  727.  
  728. LITERAL
  729.     PKT_MARK = 0,                ! <MARK>
  730.     PKT_COUNT = 1,                ! <CHAR(Count)>
  731.     PKT_SEQ = 2,                ! <CHAR(Seq)>
  732.     PKT_TYPE = 3,                ! <Message type>
  733.     PKT_MSG = 4,                ! <MESSAGE-DEPENDENT INFORMATION>
  734.     PKT_COUNTX1 = 4,            ! [108]    ! Ext. pkt: <CHAR(MSB(Count))>
  735.     PKT_COUNTX2 = 5,            ! [108]    ! Ext. pkt: <CHAR(LSB(Count))>
  736.     PKT_HCHECK = 6,            ! [108]    ! Ext. pkt: Header parity
  737.     PKT_MSGX = 7,            ! [108]    ! <MESSAGE-DEPENDENT INFORMATION>
  738.     PKT_MAX_MSG = 94 - 5,            ! Maximum size of the message dependent
  739.                             !  information
  740.     PKT_CHKSUM = 0,                ! <CHAR(Chksum)> offset from end of
  741.                             !    Message dependent information
  742.     PKT_EOL = 1,                ! <Eol> offset from end of data
  743. ! [108]   PKT_OVR_HEAD_B = 2,            ! Header overhead
  744. ! [108]   PKT_OVR_HEAD_E = 1,            ! Overhead at the end
  745.     PKT_OVR_HEAD = 3,                ! Overhead added to data length
  746.     PKT_TOT_OVR_HEAD = 6;            ! Total overhead of the message
  747.  
  748. %SBTTL 'KERMIT Protocol Definitions -- Message dependent field'
  749.  
  750. !++
  751. ! The MESSAGE-DEPENDENT information field of the message contains at
  752. ! least one part.  That is the type of message.  The remainder of the message
  753. ! MESSAGE-DEPENDENT field is different depending on the message.
  754. !
  755. ! <TYPE><TYPE-DEPENDENT-INFORMATION>
  756. !
  757. ! <TYPE>
  758. !    The type defines the type of message that is being processed.
  759. !
  760. !--
  761.  
  762. ! Protocol version 1.0 message types
  763.  
  764. LITERAL
  765.     MSG_DATA = %C'D',                ! Data packet
  766.     MSG_ACK = %C'Y',                ! Acknowledgement
  767.     MSG_NAK = %C'N',                ! Negative acknowledgement
  768.     MSG_SND_INIT = %C'S',            ! Send initiate
  769.     MSG_BREAK = %C'B',                ! Break transmission
  770.     MSG_FILE = %C'F',                ! File header
  771.     MSG_EOF = %C'Z',                ! End of file (EOF)
  772.     MSG_ERROR = %C'E';                ! Error
  773.  
  774. ! Protocol version 2.0 message types
  775.  
  776. LITERAL
  777.     MSG_RCV_INIT = %C'R',            ! Receive initiate
  778.     MSG_COMMAND = %C'C',            ! Host command
  779.     MSG_GENERIC = %C'G',            ! Generic KERMIT command.
  780.     MSG_KERMIT = %C'K';                ! Perform KERMIT command (text)
  781.  
  782. ! Protocol version 4.0 message types
  783.  
  784. LITERAL
  785.     MSG_SER_INIT = %C'I',            ! Server initialization
  786.     MSG_TEXT = %C'X';                ! Text header message
  787.  
  788. !++
  789. ! Generic KERMIT commands
  790. !--
  791.  
  792. LITERAL
  793.     MSG_GEN_LOGIN = %C'I',            ! Login
  794.     MSG_GEN_EXIT = %C'F',            ! Finish (exit to OS)
  795.     MSG_GEN_CONNECT = %C'C',            ! Connect to a directory
  796.     MSG_GEN_LOGOUT = %C'L',            ! Logout
  797.     MSG_GEN_DIRECTORY = %C'D',            ! Directory
  798.     MSG_GEN_DISK_USAGE = %C'U',            ! Disk usage
  799.     MSG_GEN_DELETE = %C'E',            ! Delete a file
  800.     MSG_GEN_TYPE = %C'T',            ! Type a file specification
  801. !    MSG_GEN_SUBMIT = %C'S',            ! Submit
  802. !    MSG_GEN_PRINT = %C'P',            ! Print
  803.     MSG_GEN_WHO = %C'W',            ! Who's logged in
  804.     MSG_GEN_SEND = %C'M',            ! Send a message to a user
  805.     MSG_GEN_HELP = %C'H',            ! Help
  806.     MSG_GEN_QUERY = %C'Q',            ! Query status
  807.     MSG_GEN_RENAME = %C'R',            ! Rename file
  808.     MSG_GEN_COPY = %C'K',            ! Copy file
  809.     MSG_GEN_PROGRAM = %C'P',            ! Run program and pass data
  810.     MSG_GEN_JOURNAL = %C'J',            ! Perform journal functions
  811.     MSG_GEN_VARIABLE = %C'V';            ! Return/set variable state
  812.  
  813. !
  814. ! Acknowledgement modifiers (protocol 4.0)
  815. !
  816.  
  817. LITERAL
  818.     MSG_ACK_ABT_CUR = %C'X',            ! Abort current file
  819.     MSG_ACK_ABT_ALL = %C'Z';            ! Abort entire stream of files
  820.  
  821. !
  822. ! End of file packet modifier
  823. !
  824.  
  825. LITERAL
  826.     MSG_EOF_DISCARD = %C'D';            ! Discard data from previous file
  827.  
  828. %SBTTL 'KERMIT Protocol Definitions -- SEND initiate packet'
  829.  
  830. !++
  831. !
  832. ! The following describes the send initiate packet.  All fields in the message
  833. ! data area are optional.
  834. !
  835. ! <"S"><CHAR(Bufsiz)><CHAR(Timeout)><CHAR(npad)><CTL(pad)><CHAR(Eol)><Quote>
  836. !    <8-bit-quote><Check-type><Repeat-count-processing><Reserved><Reserved>
  837. !
  838. ! BUFSIZ
  839. !    Sending Kermit's maximum buffer size.
  840. !
  841. ! Timeout
  842. !    Number of seconds after which the sending Kermit wishes to be timed out
  843. !
  844. ! Npad
  845. !    Number of padding caracters the sending Kermit needs preceding each
  846. !    packet.
  847. !
  848. ! PAD
  849. !    Padding character.
  850. !
  851. ! EOL
  852. !    A line terminator required on all packets set by the receiving
  853. !    Kermit.
  854. !
  855. ! Quote
  856. !    The printable ASCII characer the sending Kermit will use when quoting
  857. !    the control cahracters.  Default is "#".
  858. !
  859. ! 8-bit-quote
  860. !    Specify quoting mecanism for 8-bit quantities.  A quoting mecanism is
  861. !    mecessary when sending to hosts which prevent the use of the 8th bit
  862. !    for data.  When elected, the quoting mechanism will be used by both
  863. !    hosts, and the quote character must be in the range of 41-76 or 140-176
  864. !    octal, but different from the control-quoting character.  This field is
  865. !    interpreted as follows:
  866. !
  867. !    "Y" - I agree to 8-bit quoting if you request it.
  868. !    "N" - I will not do 8-bit quoting.
  869. !    "&" - (or any other character in the range of 41-76 or 140-176) I want
  870. !          to do 8-bit quoting using this character (it will be done if the
  871. !          other Kermit puts a "Y" in this field.
  872. !    Anything else: Quoting will not be done.
  873. !
  874. ! Check-type
  875. !    Type of block check.  The only values presently allowed in this
  876. !    field are "1", "2" or "3".  Future implementations may allow other
  877. !    values.  Interpretation of the values is:
  878. !
  879. !    "1" - Single character checksum.  Default value if none specified.
  880. !    "2" - Double character checksum.
  881. !    "3" - Three character CRC.
  882. !
  883. ! Repeat-count-processing
  884. !    The prefix character to be used to indicate a repeated character.
  885. !    This can be any printable cahracter other than blank (which denotes
  886. !    no repeat count).
  887. !
  888. ! [108]    Capability byte(s)
  889. ! [108]        Bit mask containing extra capabilities, currently we only use
  890. ! [108]        bit 1 (extended-length packets) and bit 0 (more capability
  891. ! [108]        bytes follows).
  892. ! [108]
  893. ! [108]    Window length (not used)
  894. ! [108]
  895. ! [108]    Extended packet length
  896. ! [108]        Maximum length for extended-length packets
  897. !
  898. !--
  899.  
  900. LITERAL
  901.     P_SI_BUFSIZ = 0,                ! Buffersize
  902.     MY_PKT_SIZE = 80,                ! My packet size
  903.     P_SI_TIMOUT = 1,                ! Time out
  904.     MY_TIME_OUT = 60,            ! [046] Increased ! My time out
  905.     P_SI_NPAD = 2,                ! Number of padding characters
  906.     MY_NPAD = 0,                ! Amount of padding I require
  907.     P_SI_PAD = 3,                ! Padding character
  908.     MY_PAD_CHAR = 0,                ! My pad character
  909.     P_SI_EOL = 4,                ! End of line character
  910.     MY_EOL_CHAR = %O'015',            ! My EOL cahracter
  911.     P_SI_QUOTE = 5,                ! Quote character
  912.     MY_QUOTE_CHAR = %C'#',            ! My quoting character
  913.     P_SI_8QUOTE = 6,                ! 8-bit quote
  914.     MY_8BIT_QUOTE = %C'&',            ! Don't do it
  915.     P_SI_CHKTYPE = 7,                ! Checktype used
  916.     MY_CHKTYPE = CHK_1CHAR,            ! Use single character checksum
  917.     P_SI_REPEAT = 8,                ! Repeat character
  918.     MY_REPEAT = %C'~',                ! My repeat character
  919.     P_SI_LENGTH = 9,                ! Length of the std message
  920.                     ! [108]
  921.     P_SI_CAPAS = 9,            ! [108]    ! Capability field (if used)
  922.     EXTLEN_CAPAS = 2,            ! [108]    ! Extended length packets
  923.     P_SI_WINDO = 10,            ! [108]    ! (Send only) Not used, filler
  924.     P_SI_MAXLX1 = 11,            ! [108]    ! (Send only) Ext. len / 95
  925.     MY_MAXLX1 = 0,            ! [108]
  926.     P_SI_MAXLX2 = 12,            ! [108]    ! (Send only) Ext. len MOD 95
  927.     MY_MAXLX2 = 80,            ! [108]
  928.                     ! [108]
  929.     P_SI_XLENGTH = 13;            ! [108]    ! (Send only) Len of ext. msg
  930.  
  931. %SBTTL 'KERMIT Protocol States'
  932.  
  933. !++
  934. ! The following are the various states that KERMIT can be in.
  935. ! The state transitions are defined in the KERMIT Protocol manual.
  936. !--
  937.  
  938. LITERAL
  939.     STATE_MIN = 1,                ! Min state number
  940.     STATE_S = 1,                ! Send init state
  941.     STATE_SF = 2,                ! Send file header
  942.     STATE_SD = 3,                ! Send file data packet
  943.     STATE_SZ = 4,                ! Send EOF packet
  944.     STATE_SB = 5,                ! Send break
  945.     STATE_R = 6,                ! Receive state (wait for send-init)
  946.     STATE_RF = 7,                ! Receive file header packet
  947.     STATE_RD = 8,                ! Receive file data packet
  948.     STATE_C = 9,                ! Send complete
  949.     STATE_A = 10,                ! Abort
  950.     STATE_SX = 11,                ! Send text header
  951.     STATE_SG = 12,                ! Send generic command
  952.     STATE_SI = 13,                ! Send server init
  953.     STATE_ID = 14,                ! Server idle loop
  954.     STATE_II = 15,                ! Server idle after server init
  955.     STATE_FI = 16,                ! Server should exit
  956.     STATE_LG = 17,                ! Server should logout
  957.     STATE_OF = 18,                ! Send - open first input file
  958.     STATE_EX = 19,                ! Exit back to command parser
  959.     STATE_ER = 20,                ! Retries exceeded error
  960.     STATE_MAX = 20;                ! Max state number
  961.  
  962. %SBTTL 'Internal constants'
  963.  
  964. !++
  965. ! The following represent various internal KERMSG constants.
  966. !--
  967.  
  968. LITERAL
  969.     MAX_PKT_RETRIES = 16,            ! Maximum packet retries
  970.     MAX_SI_RETRIES = 5;                ! Maximum send init retries
  971.  
  972. %SBTTL 'Storage - External'
  973. !
  974. ! OWN STORAGE:
  975. !
  976.  
  977. EXTERNAL
  978. !
  979. ! Receive parameters
  980. !
  981.     RCV_PKT_SIZE,                ! Receive packet size
  982.     RCV_NPAD,                    ! Padding length
  983.     RCV_PADCHAR,                ! Padding character
  984.     RCV_TIMEOUT,                ! Time out
  985.     RCV_EOL,                    ! EOL character
  986.     RCV_QUOTE_CHR,                ! Quote character
  987.     RCV_SOH,                    ! Start of header character
  988.     RCV_8QUOTE_CHR,                ! 8-bit quoting character
  989. !
  990. ! Miscellaneous parameters
  991. !
  992.     SET_REPT_CHR,                ! Repeat character
  993. !
  994. ! Send parameters
  995. !
  996.     SND_PKT_SIZE,                ! Send packet size
  997.     SND_NPAD,                    ! Padding length
  998.     SND_PADCHAR,                ! Padding character
  999.     SND_TIMEOUT,                ! Time out
  1000.     SND_EOL,                    ! EOL character
  1001.     SND_QUOTE_CHR,                ! Quote character
  1002.     SND_SOH,                    ! Start of header character
  1003.     SEND_TIMEOUT,                ! Time to wait for receiving message
  1004. !
  1005. ! Server parameters
  1006. !
  1007.     SRV_TIMEOUT,                ! Time between NAK's when server is idle
  1008. !
  1009. ! Statistics
  1010. !
  1011.     SND_TOTAL_CHARS,                ! Total characters sent
  1012.     RCV_TOTAL_CHARS,                ! Total characters received
  1013.     SND_DATA_CHARS,                ! Total number of data characters sent
  1014.     RCV_DATA_CHARS,                ! Total number of data characters received
  1015.     SND_NAKS,                    ! Total NAKs sent
  1016.     RCV_NAKS,                    ! Total NAKs received
  1017.     SND_COUNT,                    ! Count of total number of packets
  1018.     RCV_COUNT,                    ! Count of total number packets received
  1019.     SMSG_COUNT,                    ! Total number of packets sent
  1020.     RMSG_COUNT,                    ! Total number of packets received
  1021.     SMSG_TOTAL_CHARS,                ! Total chars sent this file xfer
  1022.     RMSG_TOTAL_CHARS,                ! Total chars rcvd this file xfer
  1023.     SMSG_DATA_CHARS,                ! Total data chars this file xfer
  1024.     RMSG_DATA_CHARS,                ! Total data chars this file xfer
  1025.     SMSG_NAKS,                    ! Total number of NAKs this file xfer
  1026.     RMSG_NAKS,                    ! Total number of NAKs received
  1027.     XFR_TIME,                    ! Amount of time last xfr took
  1028.     TOTAL_TIME,                    ! Total time of all xfrs
  1029.                             !  this file xfer
  1030.     LAST_ERROR : VECTOR [CH$ALLOCATION (MAX_MSG + 1)],    ! Last error message
  1031. !
  1032. ! Misc constants.
  1033. !
  1034.     FILE_NAME : VECTOR [CH$ALLOCATION (MAX_FILE_NAME)],
  1035.     FILE_SIZE,
  1036.     SI_RETRIES,                    ! Send init retries to attempt
  1037.     PKT_RETRIES,                ! Number of retries to try for a message
  1038.     DELAY,                    ! Amount of time to delay
  1039.     DUPLEX,                    ! Type of connection (half or full)
  1040.     PARITY_TYPE,                ! Type of parity to use
  1041.     DEV_PARITY_FLAG,                ! True if output device does
  1042.                             !  parity, false if we do it
  1043.     CHKTYPE,                    ! Type of block check desired
  1044.     ABT_FLAG,                    ! True if aborted file should be discarded
  1045.     DEBUG_FLAG,                    ! Debugging mode on/off
  1046.     WARN_FLAG,                    ! File warning flag
  1047.     IBM_CHAR,                    ! Turnaround character for IBM mode
  1048.     ECHO_FLAG,                    ! Local echo flag
  1049.     CONNECT_FLAG,                ! Connected flag; True if
  1050.                             !  terminal and SET LINE are
  1051.                             !  the same
  1052.     ABT_CUR_FILE,                ! Abort current file
  1053.     ABT_ALL_FILE,                ! Abort all files in stream
  1054.     TYP_STS_FLAG,                ! Type status next message
  1055.     TY_FIL,                    ! Type file specs
  1056.     TY_PKT,                    ! Type packet info
  1057.     FIL_NORMAL_FORM,                ! If true, file names should be normalized
  1058.     GEN_1DATA : VECTOR [CH$ALLOCATION (MAX_MSG)],    ! Data for generic command
  1059.     GEN_1SIZE,                    ! Size of data in GEN_1DATA
  1060.     GEN_2DATA : VECTOR [CH$ALLOCATION (MAX_MSG)],    ! Second argument for generic
  1061.  command
  1062.     GEN_2SIZE,                    ! Size of data in GEN_2DATA
  1063.     GEN_3DATA : VECTOR [CH$ALLOCATION (MAX_MSG)],    ! Third arg for generic
  1064.  command
  1065.     GEN_3SIZE;                    ! Size of data in GEN_3DATA
  1066.  
  1067. %SBTTL 'Storage - Local'
  1068. !
  1069. ! LOCAL OWN STORAGE:
  1070. !
  1071.  
  1072. OWN
  1073. !
  1074. ! Receive parameters
  1075. !
  1076.     RECV_8QUOTE_CHR,                ! 8th-bit quoting character
  1077.     REPT_CHR,                    ! Repeat prefix character
  1078.     RECV_PKT_MSG,            ! [108]    ! Msg offset (4 std, 7 ext.)
  1079. !
  1080. ! Send parameters
  1081. !
  1082.     SEND_PKT_SIZE,                ! Send packet size
  1083.     SEND_NPAD,                    ! Padding length
  1084.     SEND_PADCHAR,                ! Padding character
  1085.     SEND_EOL,                    ! EOL character
  1086.     SEND_QUOTE_CHR,                ! Quote character
  1087.     SEND_8QUOTE_CHR,                ! 8-bit quoting character
  1088.     SEND_INIT_SIZE,                ! Size of INIT message
  1089. !
  1090. ! Misc parameters
  1091. !
  1092.     INI_CHK_TYPE,                ! Type of block checking from init message
  1093.     BLK_CHK_TYPE,                ! Type of block check to use
  1094.     FLAG_8QUOTE,                ! Flag to determine if doing 8bit quoting
  1095.     FLAG_REPEAT,                ! True if doing repeated character compression
  1096.     STATE,                    ! Current state
  1097.     SIZE,                    ! Size of the current message
  1098. ! [108]                          Negative len for ext msgs
  1099.     OLD_RETRIES,                ! Saved number of retries done.
  1100.     NUM_RETRIES,                ! Number of retries
  1101.     MSG_NUMBER,                    ! Current message number
  1102.     REC_SEQ,                    ! Sequence number of msg in REC_MSG
  1103.     REC_LENGTH,                    ! Length of the message recv'd
  1104.     REC_TYPE,                    ! Type of the message received.
  1105.     REC_MSG : VECTOR [CH$ALLOCATION (MAX_MSG + 1, CHR_SIZE)],    ! Message received
  1106.     SND_MSG : VECTOR [CH$ALLOCATION (MAX_MSG + 1, CHR_SIZE)],    ! Message sent
  1107.     FILE_CHARS,                    ! Number of characters sent or received
  1108.     TEXT_HEAD_FLAG,                ! Text header received, not file header
  1109.     NO_FILE_NEEDED,                ! Don't open a file
  1110.     INIT_PKT_SENT,                ! Server-init sent and ACKed
  1111.     GEN_TYPE,                    ! Command message type
  1112.     GEN_SUBTYPE,                ! Generic command subtype
  1113.     GET_CHR_ROUTINE,            ! Address of routine to get a character for BFR_FILL
  1114.     PUT_CHR_ROUTINE;            ! Address of routine to put a character for BFR_EMPTY
  1115. !
  1116. ! KERMSG Global storage
  1117. !
  1118. GLOBAL
  1119.     FLAG_FILE_OPEN;            ! File is opened.
  1120.  
  1121. %SBTTL 'External references'
  1122. !
  1123. ! EXTERNAL REFERENCES:
  1124. !
  1125. ! Packet I/O routines
  1126.  
  1127. EXTERNAL ROUTINE
  1128.     SEND,                    ! Send a packet to the remote
  1129.     IBM_WAIT,                    ! Wait for IBM turnaround
  1130.     RECEIVE;                    ! Receive a packet from the remote
  1131.  
  1132. !
  1133. ! Terminal I/O routines
  1134. !
  1135.  
  1136. EXTERNAL ROUTINE
  1137.     TERM_DUMP : NOVALUE,            ! Normal terminal output
  1138.     DBG_DUMP : NOVALUE,                ! Debugging output
  1139.     TT_SET_OUTPUT,                ! Set output routine
  1140.     TT_CHAR : NOVALUE,                ! Output a single character
  1141.     TT_CRLF : NOVALUE,                ! Output a CRLF
  1142.     TT_NUMBER : NOVALUE,            ! Output a three digit number to the
  1143.                             !  terminal
  1144.     TT_TEXT : NOVALUE,                ! Output a string to the user's
  1145.     TT_OUTPUT : NOVALUE;            ! Force buffered output to terminal
  1146.  
  1147. ! Operating system routines and misc routines
  1148.  
  1149. EXTERNAL ROUTINE
  1150.     CRCCLC,                    ! Calculate a CRC-CCITT
  1151.     XFR_STATUS : NOVALUE,            ! Routine to tell the user the
  1152.                             !  status of a transfer
  1153.     KRM_ERROR : NOVALUE,            ! Issue an error message
  1154.     SY_LOGOUT : NOVALUE,            ! Log the job off
  1155.     SY_GENERIC,                    ! Perform a generic command
  1156.     SY_TIME,                    ! Return elapsed time in milliseconds
  1157.     SY_DISMISS : NOVALUE;            ! Routine to dismiss for n seconds.
  1158.  
  1159. !
  1160. ! External file processing routines
  1161. !
  1162.  
  1163. EXTERNAL ROUTINE
  1164.     FILE_OPEN,                    ! Open a file for reading/writing
  1165.     FILE_CLOSE,                    ! Close an open file
  1166.     NEXT_FILE,                    ! Determine if there is a next file
  1167.                             !  and open it for reading.
  1168.     GET_FILE,                    ! Get a byte from the file
  1169.     PUT_FILE;                    ! Put a byte in the file.
  1170.  
  1171. %SBTTL 'MSG_INIT'
  1172.  
  1173. GLOBAL ROUTINE MSG_INIT : NOVALUE =
  1174.  
  1175. !++
  1176. ! FUNCTIONAL DESCRIPTION:
  1177. !
  1178. !    This routine will initialize the message processing for
  1179. !    KERMIT-32/36.
  1180. !
  1181. ! CALLING SEQUENCE:
  1182. !
  1183. !    MSG_INIT();
  1184. !
  1185. ! INPUT PARAMETERS:
  1186. !
  1187. !    None.
  1188. !
  1189. ! IMPLICIT INPUTS:
  1190. !
  1191. !    None.
  1192. !
  1193. ! OUTPUT PARAMETERS:
  1194. !
  1195. !    None.
  1196. !
  1197. ! IMPLICIT OUTPUTS:
  1198. !
  1199. !    None.
  1200. !
  1201. ! COMPLETION CODES:
  1202. !
  1203. !    None.
  1204. !
  1205. ! SIDE EFFECTS:
  1206. !
  1207. !    None.
  1208. !
  1209. !--
  1210.  
  1211.     BEGIN
  1212. !
  1213. ! Initialize some variables
  1214. !
  1215. ! Receive parameters first
  1216. !
  1217.     RCV_PKT_SIZE = MY_PKT_SIZE;
  1218.     RCV_NPAD = MY_NPAD;
  1219.     RCV_PADCHAR = MY_PAD_CHAR;
  1220.     RCV_TIMEOUT = MY_TIME_OUT;
  1221.     RCV_EOL = MY_EOL_CHAR;
  1222.     RCV_QUOTE_CHR = MY_QUOTE_CHAR;
  1223.     RCV_SOH = CHR_SOH;
  1224.     RCV_8QUOTE_CHR = MY_8BIT_QUOTE;
  1225.     SET_REPT_CHR = MY_REPEAT;
  1226. !
  1227. ! Send parameters.
  1228. !
  1229.     SND_PKT_SIZE = -MY_PKT_SIZE;
  1230.     SND_NPAD = -MY_NPAD;
  1231.     SND_PADCHAR = -MY_PAD_CHAR;
  1232.     SND_TIMEOUT = -MY_TIME_OUT;
  1233.     SND_EOL = -MY_EOL_CHAR;
  1234.     SND_QUOTE_CHR = -MY_QUOTE_CHAR;
  1235.     SND_SOH = CHR_SOH;
  1236. !
  1237. ! Server parameters
  1238. !
  1239.     SRV_TIMEOUT = 5*MY_TIME_OUT;
  1240. !
  1241. ! Other random parameters
  1242. !
  1243.     PKT_RETRIES = MAX_PKT_RETRIES;        ! Number of retries per message
  1244.     SI_RETRIES = MAX_SI_RETRIES;        ! Number of retries on send inits
  1245.     DELAY = INIT_DELAY;
  1246.     DUPLEX = DP_FULL;                ! Use full duplex
  1247.     DEBUG_FLAG = FALSE;
  1248.     WARN_FLAG = FALSE;
  1249.     ECHO_FLAG = FALSE;
  1250.     BLK_CHK_TYPE = CHK_1CHAR;            ! Start using single char checksum
  1251.     CHKTYPE = MY_CHKTYPE;            ! Desired block check type
  1252.     INI_CHK_TYPE = .CHKTYPE;            ! Same as default for now
  1253.     DEV_PARITY_FLAG = FALSE;            ! We generate parity
  1254.     PARITY_TYPE = PR_NONE;            ! No parity
  1255.     ABT_FLAG = TRUE;                ! Discard incomplete files
  1256.     FLAG_FILE_OPEN = FALSE;
  1257.     IBM_CHAR = -1;                ![044] No handsake by default
  1258.     TY_FIL = TRUE;                ! Default to typing files
  1259.     TY_PKT = FALSE;                ! But not packet numbers
  1260.     FIL_NORMAL_FORM = FNM_NORMAL;        ! Default to normal form names
  1261.     GET_CHR_ROUTINE = GET_FILE;            ![025] Initialize the get-a-char routine
  1262.     PUT_CHR_ROUTINE = PUT_FILE;            ![025] And the put-a-char
  1263.     END;                    ! End of MSG_INIT
  1264.  
  1265. %SBTTL 'SND_ERROR'
  1266.  
  1267. GLOBAL ROUTINE SND_ERROR (COUNT, ADDRESS) : NOVALUE =
  1268.  
  1269. !++
  1270. ! FUNCTIONAL DESCRIPTION:
  1271. !
  1272. !    This routine will send an error packet to the remote KERMIT.  It
  1273. !    is called with the count of characters and the address of the text.
  1274. !
  1275. ! CALLING SEQUENCE:
  1276. !
  1277. !    SND_ERROR(COUNT, %ASCII 'Error text');
  1278. !
  1279. ! INPUT PARAMETERS:
  1280. !
  1281. !    None.
  1282. !
  1283. ! IMPLICIT INPUTS:
  1284. !
  1285. !    None.
  1286. !
  1287. ! OUTPUT PARAMETERS:
  1288. !
  1289. !    None.
  1290. !
  1291. ! IMPLICIT OUTPUTS:
  1292. !
  1293. !    None.
  1294. !
  1295. ! COMPLETION CODES:
  1296. !
  1297. !    None.
  1298. !
  1299. ! SIDE EFFECTS:
  1300. !
  1301. !
  1302. !--
  1303.  
  1304.     BEGIN
  1305. !
  1306. ! Pack the message into the buffer
  1307. !
  1308.     SET_STRING (CH$PTR (.ADDRESS), .COUNT, TRUE);
  1309.     BFR_FILL (TRUE);
  1310.     SET_STRING (0, 0, FALSE);
  1311. !
  1312. ! Save the last error message also
  1313. !
  1314.  
  1315.     IF .COUNT GTR MAX_MSG THEN COUNT = MAX_MSG;
  1316.  
  1317.     CH$COPY (.COUNT, CH$PTR (.ADDRESS), 0, MAX_MSG + 1, CH$PTR (LAST_ERROR));
  1318.  
  1319.     IF NOT SEND_PACKET (MSG_ERROR, .SIZE, .MSG_NUMBER) THEN RETURN KER_ABORTED;
  1320.  
  1321.     END;                    ! End of SND_ERROR
  1322.  
  1323. %SBTTL 'SERVER - Server mode'
  1324.  
  1325. GLOBAL ROUTINE SERVER =
  1326.  
  1327. !++
  1328. ! FUNCTIONAL DESCRIPTION:
  1329. !
  1330. !    This routine will handle the server function in the v2.0 protocol
  1331. !    for KERMIT.  This routine by it's nature will call various operating
  1332. !    system routines to do things like logging off the system.
  1333. !
  1334. ! CALLING SEQUENCE:
  1335. !
  1336. !    EXIT_FLAG = SERVER();
  1337. !
  1338. ! INPUT PARAMETERS:
  1339. !
  1340. !    None.
  1341. !
  1342. ! IMPLICIT INPUTS:
  1343. !
  1344. !    None.
  1345. !
  1346. ! OUTPUT PARAMETERS:
  1347. !
  1348. !    None.
  1349. !
  1350. ! IMPLICIT OUTPUTS:
  1351. !
  1352. !    None.
  1353. !
  1354. ! COMPLETION CODES:
  1355. !
  1356. !    None.
  1357. !
  1358. ! SIDE EFFECTS:
  1359. !
  1360. !    None.
  1361. !
  1362. !--
  1363.  
  1364.     BEGIN
  1365.  
  1366.     LOCAL
  1367.     STATUS;                    ! Status returned by various routines
  1368.  
  1369.     DO
  1370.     BEGIN
  1371.     INIT_XFR ();
  1372.     XFR_STATUS (%C'T', %C'I');        ! Now idle
  1373.     STATUS = DO_TRANSACTION (STATE_ID);
  1374.     END
  1375.     UNTIL .STATUS EQL KER_EXIT OR .STATUS EQL KER_ABORTED;
  1376.  
  1377.     RETURN .STATUS;
  1378.     END;                    ! End of GLOBAL ROUTINE SERVER
  1379.  
  1380. %SBTTL 'SEND_SWITCH'
  1381.  
  1382. GLOBAL ROUTINE SEND_SWITCH =
  1383.  
  1384. !++
  1385. ! FUNCTIONAL DESCRIPTION:
  1386. !
  1387. !    This routine is the state table switcher for sending files.  It
  1388. !    loops until either it is finished or an error is encountered.  The
  1389. !    routines called by SEND_SWITCH are responsible for changing the state.
  1390. !
  1391. ! CALLING SEQUENCE:
  1392. !
  1393. !    SEND_SWITCH();
  1394. !
  1395. ! INPUT PARAMETERS:
  1396. !
  1397. !    None.
  1398. !
  1399. ! IMPLICIT INPUTS:
  1400. !
  1401. !    None.
  1402. !
  1403. ! OUTPUT PARAMETERS:
  1404. !
  1405. !    Returns:
  1406. !        TRUE - File sent correctly.
  1407. !        FALSE - Aborted sending the file.
  1408. !
  1409. ! IMPLICIT OUTPUTS:
  1410. !
  1411. !    None.
  1412. !
  1413. ! COMPLETION CODES:
  1414. !
  1415. !    None.
  1416. !
  1417. ! SIDE EFFECTS:
  1418. !
  1419. !    None.
  1420. !
  1421. !--
  1422.  
  1423.     BEGIN
  1424.  
  1425.     LOCAL
  1426.     STATUS;                    ! Status result
  1427.  
  1428.     IF .CONNECT_FLAG THEN SY_DISMISS (.DELAY);    ! Sleep if the user wanted us to
  1429.  
  1430.     INIT_XFR ();                ! Initialize for this transfer
  1431.     TEXT_HEAD_FLAG = FALSE;            ! Set text flag correctly
  1432.     XFR_STATUS (%C'I', %C'S');            ! Start of file send
  1433.     STATUS = DO_TRANSACTION (STATE_S);        ! Call routine to do real work
  1434.     XFR_STATUS (%C'T', %C'S');            ! Done with send
  1435.     RETURN .STATUS;                ! Return the result
  1436.     END;
  1437.  
  1438. %SBTTL 'REC_SWITCH'
  1439.  
  1440. GLOBAL ROUTINE REC_SWITCH =
  1441.  
  1442. !++
  1443. ! FUNCTIONAL DESCRIPTION:
  1444. !
  1445. !    This routine will cause file(s) to be received by the remote
  1446. !    KERMIT.  This routine contains the main loop for the sending of the
  1447. !    data.
  1448. !
  1449. ! CALLING SEQUENCE:
  1450. !
  1451. !    REC_SWITCH();
  1452. !
  1453. ! INPUT PARAMETERS:
  1454. !
  1455. !    None.
  1456. !
  1457. ! IMPLICIT INPUTS:
  1458. !
  1459. !    FILE_DESC - Descriptor describing the file to be received by
  1460. !        the remote KERMIT.
  1461. !
  1462. ! OUTPUT PARAMETERS:
  1463. !
  1464. !    None.
  1465. !
  1466. ! IMPLICIT OUTPUTS:
  1467. !
  1468. !    None.
  1469. !
  1470. ! COMPLETION CODES:
  1471. !
  1472. !    True - File received correctly.
  1473. !    FALSE - File transfer aborted.
  1474. !
  1475. ! SIDE EFFECTS:
  1476. !
  1477. !    None.
  1478. !
  1479. !--
  1480.  
  1481.     BEGIN
  1482.  
  1483.     LOCAL
  1484.     INIT_STATE,                ! State to start up DO_TRANSACTION in
  1485.     STATUS;                    ! Status returned by various routines
  1486.  
  1487.     INIT_STATE = STATE_R;            ! Initialize the state
  1488.     MSG_NUMBER = 0;
  1489.     INIT_XFR ();                ! Initialize the per transfer info
  1490. !
  1491. ! Determine if they said REC <file-spec>
  1492. !    Send MSG_RCV_INIT and then receive the file
  1493. !
  1494.  
  1495.     IF .FILE_SIZE GTR 0
  1496.     THEN
  1497.     BEGIN
  1498.     GEN_TYPE = MSG_RCV_INIT;        ! Use receive-init message
  1499.     CH$MOVE (.FILE_SIZE, CH$PTR (FILE_NAME), CH$PTR (GEN_1DATA));
  1500.     GEN_1SIZE = .FILE_SIZE;            ! Save the length
  1501.     INIT_STATE = STATE_SI;            ! Start out with server init
  1502.     END;
  1503.  
  1504. !
  1505. ! Now receive the file normally
  1506. !
  1507.     XFR_STATUS (%C'I', %C'R');            ! Start of a file receive
  1508.     STATUS = DO_TRANSACTION (.INIT_STATE);
  1509.     XFR_STATUS (%C'T', %C'R');            ! End of file receive
  1510.     RETURN .STATUS;                ! Return the result
  1511.     END;                    ! End of REC_SWITCH
  1512.  
  1513. %SBTTL 'Server -- DO_GENERIC - Execute a generic command'
  1514.  
  1515. GLOBAL ROUTINE DO_GENERIC (TYPE) =
  1516.  
  1517. !++
  1518. ! FUNCTIONAL DESCRIPTION:
  1519. !
  1520. !    This routine will send a generic command to the remote Kermit.
  1521. !    it will do all the processing required for the generic command
  1522. !    that was executed.  It will return to the caller after the
  1523. !    command has be executed.
  1524. !
  1525. ! CALLING SEQUENCE:
  1526. !
  1527. !    STATUS = DO_GENERIC (Command-type);
  1528. !
  1529. ! INPUT PARAMETERS:
  1530. !
  1531. !    Command-type -- Command type to be executed.
  1532. !
  1533. ! IMPLICIT INPUTS:
  1534. !
  1535. !    None.
  1536. !
  1537. ! OUTPUT PARAMETERS:
  1538. !
  1539. !    None.
  1540. !
  1541. ! IMPLICIT OUTPUTS:
  1542. !
  1543. !    None.
  1544. !
  1545. ! COMPLETION CODES:
  1546. !
  1547. !    None.
  1548. !
  1549. ! SIDE EFFECTS:
  1550. !
  1551. !    None.
  1552. !
  1553. !--
  1554.  
  1555.     BEGIN
  1556.  
  1557.     LOCAL
  1558.     INIT_STATE;                ! Initial state for FSM
  1559.  
  1560. !
  1561. ! Set up the per transfer items
  1562. !
  1563.     INIT_XFR ();
  1564.     NUM_RETRIES = 0;
  1565.     MSG_NUMBER = 0;
  1566. !
  1567. ! These are all generic commands
  1568. !
  1569.     GEN_TYPE = MSG_GENERIC;
  1570. !
  1571. ! Assume we will not need server init
  1572. !
  1573.     INIT_STATE = STATE_SG;
  1574.  
  1575.     CASE .TYPE FROM GC_MIN TO GC_MAX OF
  1576.     SET
  1577.  
  1578.     [GC_EXIT] :
  1579.         GEN_SUBTYPE = MSG_GEN_EXIT;
  1580.  
  1581.     [GC_LOGOUT] :
  1582.         GEN_SUBTYPE = MSG_GEN_LOGOUT;
  1583.  
  1584.     [GC_DIRECTORY] :
  1585.         BEGIN
  1586.         INIT_STATE = STATE_SI;        ! We will need server-init
  1587.         GEN_SUBTYPE = MSG_GEN_DIRECTORY;
  1588.         END;
  1589.  
  1590.     [GC_DISK_USAGE] :
  1591.         BEGIN
  1592.         INIT_STATE = STATE_SI;        ! We will need server-init
  1593.         GEN_SUBTYPE = MSG_GEN_DISK_USAGE;
  1594.         END;
  1595.  
  1596.     [GC_DELETE] :
  1597.         GEN_SUBTYPE = MSG_GEN_DELETE;
  1598.  
  1599.     [GC_TYPE] :
  1600.         BEGIN
  1601.         INIT_STATE = STATE_SI;        ! We will need server-init
  1602.         GEN_SUBTYPE = MSG_GEN_TYPE;
  1603.         END;
  1604.  
  1605.     [GC_HELP] :
  1606.         BEGIN
  1607.         INIT_STATE = STATE_SI;        ! We will need server-init
  1608.         GEN_SUBTYPE = MSG_GEN_HELP;
  1609.         END;
  1610.  
  1611.     [GC_LGN] :
  1612.         GEN_SUBTYPE = MSG_GEN_LOGIN;    ! Login just gets ACK
  1613.  
  1614.     [GC_CONNECT] :
  1615.         GEN_SUBTYPE = MSG_GEN_CONNECT;    ! CWD just gets ACK
  1616.  
  1617.     [GC_RENAME] :
  1618.         GEN_SUBTYPE = MSG_GEN_RENAME;    ! Rename file just needs ACK
  1619.  
  1620.     [GC_COPY] :
  1621.         GEN_SUBTYPE = MSG_GEN_COPY;        ! Copy file just needs ACK
  1622.  
  1623.     [GC_WHO] :
  1624.         BEGIN
  1625.         INIT_STATE = STATE_SI;        ! May get large response
  1626.         GEN_SUBTYPE = MSG_GEN_WHO;
  1627.         END;
  1628.  
  1629.     [GC_SEND_MSG] :
  1630.         GEN_SUBTYPE = MSG_GEN_SEND;        ! Just need an ACK
  1631.  
  1632.     [GC_STATUS] :
  1633.         BEGIN
  1634.         INIT_STATE = STATE_SI;        ! May get large response
  1635.         GEN_SUBTYPE = MSG_GEN_QUERY;
  1636.         END;
  1637.  
  1638.     [GC_COMMAND] :
  1639.         BEGIN
  1640.         INIT_STATE = STATE_SI;        ! Large response likely
  1641.         GEN_TYPE = MSG_COMMAND;        ! This is host command
  1642.         END;
  1643.  
  1644.     [GC_KERMIT] :
  1645.         GEN_TYPE = MSG_KERMIT;        ! Perform Kermit command (short response)
  1646.  
  1647.     [GC_PROGRAM] :
  1648.         BEGIN
  1649.         INIT_STATE = STATE_SI;        ! Assume large response
  1650.         GEN_SUBTYPE = MSG_GEN_PROGRAM;    ! Generic program command
  1651.         END;
  1652.  
  1653.     [GC_JOURNAL] :
  1654.         GEN_SUBTYPE = MSG_GEN_JOURNAL;    ! Do journal function (short reply)
  1655.  
  1656.     [GC_VARIABLE] :
  1657.         GEN_SUBTYPE = MSG_GEN_VARIABLE;    ! Set or get a variable value
  1658.  
  1659.     [INRANGE, OUTRANGE] :
  1660.         BEGIN
  1661.         KRM_ERROR (KER_UNIMPLGEN);
  1662.         RETURN STATE_A;
  1663.         END;
  1664.     TES;
  1665.  
  1666.     RETURN DO_TRANSACTION (.INIT_STATE);    ! Go do the command
  1667.     END;                    ! End of DO_GENERIC
  1668.  
  1669. %SBTTL 'DO_TRANSACTION - Main loop for FSM'
  1670. ROUTINE DO_TRANSACTION (INIT_STATE) =
  1671.  
  1672. !++
  1673. ! FUNCTIONAL DESCRIPTION:
  1674. !
  1675. !    This is the main routine for performing a Kermit transaction.
  1676. !    It is structured as a finite state machine with each state
  1677. !    determining the next based upon the packet which is received.
  1678. !    It is supplied with the initial state by the caller.
  1679. !
  1680. ! CALLING SEQUENCE:
  1681. !
  1682. !    Status = DO_TRANSACTION(.INIT_STATE);
  1683. !
  1684. ! INPUT PARAMETERS:
  1685. !
  1686. !    INIT_STATE - Initial state.
  1687. !
  1688. ! IMPLICIT INPUTS:
  1689. !
  1690. !    None.
  1691. !
  1692. ! OUTPUT PARAMETERS:
  1693. !
  1694. !    None.
  1695. !
  1696. ! IMPLICIT OUTPUTS:
  1697. !
  1698. !    None.
  1699. !
  1700. ! COMPLETION CODES:
  1701. !
  1702. !    None.
  1703. !
  1704. ! SIDE EFFECTS:
  1705. !
  1706. !    None.
  1707. !
  1708. !--
  1709.  
  1710.     BEGIN
  1711.  
  1712.     LOCAL
  1713.     RETURN_VALUE;
  1714.  
  1715.     NUM_RETRIES = 0;                ! Initialize the number of retries
  1716.     STATE = .INIT_STATE;            ! Initialize the state
  1717.  
  1718.     WHILE TRUE DO
  1719.  
  1720.     CASE .STATE FROM STATE_MIN TO STATE_MAX OF
  1721.         SET
  1722. !
  1723. ! Send states
  1724. !
  1725.  
  1726.         [STATE_ID] :
  1727. !
  1728. ! Server while idle.  Set the timeout to twice the normal wait
  1729. ! and wait for something to show up
  1730. !
  1731.         BEGIN
  1732.  
  1733.         LOCAL
  1734.             SAVED_TIMEOUT;
  1735.  
  1736.         SAVED_TIMEOUT = .SEND_TIMEOUT;
  1737.  
  1738.         IF .SEND_TIMEOUT NEQ 0 THEN SEND_TIMEOUT = .SRV_TIMEOUT;
  1739.  
  1740.         STATE = REC_SERVER_IDLE ();
  1741.         SEND_TIMEOUT = .SAVED_TIMEOUT;
  1742.         END;
  1743.  
  1744.         [STATE_II] :
  1745. !
  1746. ! Here while server idle after having received a server-init packet
  1747. !
  1748.         STATE = REC_SERVER_IDLE ();
  1749.  
  1750.         [STATE_FI, STATE_LG] :
  1751. !
  1752. ! Here when we are supposed to exit
  1753. !
  1754.         RETURN KER_EXIT;
  1755.  
  1756.         [STATE_SD] :
  1757.         STATE = SEND_DATA ();
  1758.  
  1759.         [STATE_SF] :
  1760.         STATE = SEND_FILE ();
  1761.  
  1762.         [STATE_SZ] :
  1763.         STATE = SEND_EOF ();
  1764.  
  1765.         [STATE_S] :
  1766.         STATE = SEND_INIT ();
  1767.  
  1768.         [STATE_OF] :
  1769.         STATE = SEND_OPEN_FILE ();
  1770.  
  1771.         [STATE_SI] :
  1772.         STATE = SEND_SERVER_INIT ();
  1773.  
  1774.         [STATE_SG] :
  1775.         STATE = SEND_GENCMD ();
  1776.  
  1777.         [STATE_SB] :
  1778.         STATE = SEND_BREAK ();
  1779. !
  1780. ! Receiving of the data and the end of file message.
  1781. !
  1782.  
  1783.         [STATE_RD] :
  1784.         STATE = REC_DATA ();
  1785. !
  1786. ! Receiving the FILE information of the break to end the transfer of
  1787. ! one or more files
  1788. !
  1789.  
  1790.         [STATE_RF] :
  1791.         STATE = REC_FILE ();
  1792. !
  1793. ! Initialization for the receiving of a file
  1794. !
  1795.  
  1796.         [STATE_R] :
  1797.         STATE = REC_INIT ();
  1798. !
  1799. ! Here if we have completed the receiving of the file
  1800. !
  1801.  
  1802.         [STATE_C] :
  1803.         BEGIN
  1804.         RETURN_VALUE = TRUE;
  1805.         EXITLOOP;
  1806.         END;
  1807. !
  1808. ! Here if we aborted the transfer or we have gotten into some random
  1809. ! state (internal KERMSG problem).
  1810. !
  1811.  
  1812.         [STATE_A, STATE_EX, STATE_ER, INRANGE, OUTRANGE] :
  1813.         BEGIN
  1814.         RETURN_VALUE = FALSE;
  1815.  
  1816.         IF .STATE EQL STATE_EX THEN RETURN_VALUE = KER_ABORTED;
  1817.  
  1818.         !
  1819.         ! Determine if the file is still open and if so close it
  1820.         !
  1821.  
  1822.         IF .FLAG_FILE_OPEN
  1823.         THEN
  1824.             BEGIN
  1825.             FLAG_FILE_OPEN = FALSE;
  1826.  
  1827.             IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  1828.             THEN
  1829.             BEGIN
  1830.             TT_TEXT (UPLIT (%ASCIZ' [Aborted]'));
  1831.             TT_CRLF ();
  1832.             END;
  1833.  
  1834.             FILE_CLOSE (.ABT_FLAG AND (.STATE EQL STATE_A OR .STATE EQL STATE_EX OR
  1835.  .STATE
  1836.             EQL STATE_ER));
  1837.             XFR_STATUS (%C'F', %C'A');
  1838.             END;
  1839.  
  1840. !
  1841. ! Give error if aborted due to too many retries
  1842. !
  1843.  
  1844.         IF .STATE EQL STATE_ER THEN KRM_ERROR (KER_RETRIES);
  1845.  
  1846.         EXITLOOP;
  1847.         END;
  1848.         TES;
  1849.  
  1850. !
  1851. ! End the stats and return to the caller
  1852. !
  1853.     END_STATS ();
  1854. !
  1855.     RETURN .RETURN_VALUE;
  1856.     END;                    ! End of DO_TRANSACTION
  1857. %SBTTL 'REC_SERVER_IDLE - Idle server state'
  1858. ROUTINE REC_SERVER_IDLE =
  1859.  
  1860. !++
  1861. ! FUNCTIONAL DESCRIPTION:
  1862. !
  1863. ! This routine is called from DO_TRANSACTION when is the server idle
  1864. ! state.  It will receive a message and properly dispatch to the new
  1865. ! state.
  1866. !
  1867. ! CALLING SEQUENCE:
  1868. !
  1869. !    STATE = REC_SERVER_IDLE ();
  1870. !
  1871. ! INPUT PARAMETERS:
  1872. !
  1873. !    None.
  1874. !
  1875. ! IMPLICIT INPUTS:
  1876. !
  1877. !    Almost everything.
  1878. !
  1879. ! OUPTUT PARAMETERS:
  1880. !
  1881. !    Routine value is new state for FSM
  1882. !
  1883. ! IMPLICIT OUTPUTS:
  1884. !
  1885. !    None.
  1886. !
  1887. ! COMPLETION CODES:
  1888. !
  1889. !    None.
  1890. !
  1891. ! SIDE EFFECTS:
  1892. !
  1893. !    None.
  1894. !
  1895. !--
  1896.  
  1897.     BEGIN
  1898.  
  1899.     LOCAL
  1900.     STATUS;
  1901.  
  1902.     STATUS = REC_PACKET ();
  1903. !
  1904. ! Now determine what to do by the type of message we have receive.
  1905. !
  1906.  
  1907.     IF .STATUS EQL KER_ABORTED THEN RETURN STATE_EX;
  1908.  
  1909.     IF .STATUS
  1910.     THEN
  1911.     BEGIN
  1912.  
  1913.     SELECTONE .REC_TYPE OF
  1914.         SET
  1915.         !
  1916.         ! Server initialization message received. ACK the
  1917.         ! message and continue.
  1918.         !
  1919.  
  1920.         [MSG_SER_INIT] :
  1921.         BEGIN
  1922.  
  1923.         IF (STATUS = PRS_SEND_INIT ())
  1924.         THEN
  1925.             BEGIN
  1926.             SET_SEND_INIT ();
  1927.  
  1928.             IF (STATUS = SEND_PACKET (MSG_ACK, .SEND_INIT_SIZE, .REC_SEQ)) ! [108]
  1929.             THEN
  1930.             BEGIN
  1931.             SND_PKT_SIZE = -.SEND_PKT_SIZE;
  1932.             SND_TIMEOUT = -.SEND_TIMEOUT;
  1933.             SND_NPAD = -.SEND_NPAD;
  1934.             SND_PADCHAR = -.SEND_PADCHAR;
  1935.             SND_EOL = -.SEND_EOL;
  1936.             SND_QUOTE_CHR = -.SEND_QUOTE_CHR;
  1937.             RCV_8QUOTE_CHR = .SEND_8QUOTE_CHR;
  1938.             CHKTYPE = .INI_CHK_TYPE;
  1939.             SET_REPT_CHR = .REPT_CHR;
  1940.             RETURN STATE_II;    ! Now idle after INIT
  1941.             END;
  1942.  
  1943.             END;
  1944.  
  1945.         KRM_ERROR (KER_PROTOERR);
  1946.         RETURN STATE_A;
  1947.         END;
  1948.         !
  1949.         ! Send init message received.  We must ACK the message and
  1950.         ! then attempt to receive a file from the remote.
  1951.         !
  1952.  
  1953.         [MSG_SND_INIT] :
  1954.         BEGIN
  1955.         MSG_NUMBER = (.REC_SEQ + 1) AND %O'77';
  1956.  
  1957.         IF (STATUS = PRS_SEND_INIT ())
  1958.         THEN
  1959.             BEGIN
  1960.             SET_SEND_INIT ();
  1961.             !
  1962.             ! ACK the message then receive everything.
  1963.             !
  1964.  
  1965.             IF SEND_PACKET (MSG_ACK, .SEND_INIT_SIZE, .REC_SEQ) ! [108]
  1966.             THEN
  1967.             BEGIN
  1968.             BLK_CHK_TYPE = .INI_CHK_TYPE;    ! Switch to desired form of block check
  1969.             XFR_STATUS (%C'I', %C'R');    ! Start of file receive
  1970.             RETURN STATE_RF;
  1971.             END;
  1972.  
  1973.             END;
  1974.  
  1975.         KRM_ERROR (KER_PROTOERR);
  1976.         RETURN STATE_A;
  1977.         END;
  1978.         !
  1979.         ! Here if we receive a receive init message.
  1980.         ! We will be sending a file to the other end.
  1981.         !
  1982.  
  1983.         [MSG_RCV_INIT] :
  1984.         BEGIN
  1985.         !
  1986.         ! Move the file specification if we received one
  1987.         !
  1988.         SET_STRING (CH$PTR (FILE_NAME), MAX_FILE_NAME, TRUE);
  1989.         BFR_EMPTY ();
  1990.         FILE_SIZE = SET_STRING (0, 0, FALSE);
  1991.         CH$WCHAR (CHR_NUL, CH$PTR (FILE_NAME, .FILE_SIZE));
  1992.  
  1993.         IF .FILE_SIZE GTR 0
  1994.         THEN
  1995.             BEGIN
  1996.             XFR_STATUS (%C'I', %C'S');    ! Start of a file send
  1997.             RETURN STATE_S;
  1998.             END;
  1999.  
  2000.         KRM_ERROR (KER_PROTOERR);
  2001.         RETURN STATE_A;
  2002.         END;
  2003. !
  2004. ! Generic KERMIT commands
  2005. !
  2006.  
  2007.         [MSG_GENERIC] :
  2008.         RETURN SERVER_GENERIC ();
  2009. !
  2010. ! Host command
  2011. !
  2012.  
  2013.         [MSG_COMMAND] :
  2014.         RETURN HOST_COMMAND ();
  2015. !
  2016. ! Kermit command
  2017. !
  2018.  
  2019.         [MSG_KERMIT] :
  2020.         RETURN KERMIT_COMMAND ();
  2021. !
  2022. ! Unimplimented server routines
  2023. !
  2024.  
  2025.         [OTHERWISE] :
  2026.         BEGIN
  2027.         KRM_ERROR (KER_UNISRV);
  2028.         RETURN STATE_A;
  2029.         END;
  2030.         TES;
  2031.  
  2032.     END;
  2033.  
  2034. !
  2035. ! If we get here, we must have gotten something random.  Therefore,
  2036. ! just send a NAK and remain in the current state (unless we have done this
  2037. ! too many times).
  2038. !
  2039.     NUM_RETRIES = .NUM_RETRIES + 1;
  2040.  
  2041.     IF .NUM_RETRIES GTR .SI_RETRIES THEN RETURN STATE_A;
  2042.  
  2043.     IF SEND_PACKET (MSG_NAK, 0, 0) THEN RETURN .STATE ELSE RETURN STATE_EX;
  2044.  
  2045.     END;                    ! End of REC_SERVER_IDLE
  2046. %SBTTL 'SEND_SERVER_INIT'
  2047. ROUTINE SEND_SERVER_INIT =
  2048.  
  2049. !++
  2050. ! FUNCTIONAL DESCRIPTION:
  2051. !
  2052. !    This routine will send a server initialization message to the
  2053. !    remote KERMIT.
  2054. !
  2055. ! CALLING SEQUENCE:
  2056. !
  2057. !    STATE = SEND_SERVER_INIT();
  2058. !
  2059. ! INPUT PARAMETERS:
  2060. !
  2061. !    None.
  2062. !
  2063. ! IMPLICIT INPUTS:
  2064. !
  2065. !    RECV_xxx - desired receive parameters
  2066. !
  2067. ! OUTPUT PARAMETERS:
  2068. !
  2069. !    New state to change the finite state machine to.
  2070. !
  2071. ! IMPLICIT OUTPUTS:
  2072. !
  2073. !    SEND_xxx - Other Kermit's desired parameters
  2074. !
  2075. ! COMPLETION CODES:
  2076. !
  2077. !    None.
  2078. !
  2079. ! SIDE EFFECTS:
  2080. !
  2081. !    None.
  2082. !
  2083. !--
  2084.  
  2085.     BEGIN
  2086.  
  2087.     LOCAL
  2088.     OLD_OUTPUT,                ! Saved terminal output routine
  2089.     STATUS;                    ! Status returned by various routines
  2090.  
  2091. ![026] Local routine to ignore error message output
  2092.     ROUTINE IGNORE_ERROR (ADDRESS, LENGTH) =
  2093.     BEGIN
  2094.     RETURN TRUE;
  2095.     END;
  2096.     SET_SEND_INIT ();
  2097. ![026] If too many tries, just give up.  Maybe the other Kermit doesn't
  2098. ![026] know what to do with this packet.
  2099.  
  2100.     IF .NUM_RETRIES GTR .SI_RETRIES THEN RETURN STATE_SG;
  2101.  
  2102. ![026]
  2103. ![026] Count the number of times we try this
  2104. ![026]
  2105.     NUM_RETRIES = .NUM_RETRIES + 1;
  2106.  
  2107.     IF NOT SEND_PACKET (MSG_SER_INIT, .SEND_INIT_SIZE, .MSG_NUMBER) THEN RETURN
  2108.  STATE_A; ! [108]
  2109.  
  2110. ![026]
  2111. ![026] Determine if we received a packet it good condition.  If we timed out
  2112. ![026] just try again.  If we get an error packet back, ignore it and
  2113. ![026] just continue.  The other Kermit must not support this packet.
  2114. ![026]
  2115.     OLD_OUTPUT = TT_SET_OUTPUT (IGNORE_ERROR);
  2116.     STATUS = REC_PACKET ();
  2117.     TT_OUTPUT ();
  2118.     TT_SET_OUTPUT (.OLD_OUTPUT);
  2119.  
  2120.     IF .STATUS EQL KER_ERRMSG THEN RETURN STATE_SG;
  2121.  
  2122.     IF NOT .STATUS
  2123.     THEN
  2124.  
  2125.     IF NOT ((.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS
  2126.  EQL
  2127.         KER_CHKSUMERR))
  2128.     THEN
  2129.         RETURN STATE_EX
  2130.     ELSE
  2131.         RETURN .STATE;
  2132.  
  2133. !
  2134. ! Determine if the packet is good.
  2135. !
  2136.  
  2137.     IF .REC_TYPE EQL MSG_ACK AND .REC_SEQ EQL .MSG_NUMBER
  2138.     THEN
  2139.     BEGIN
  2140. !
  2141. ! Here if we have an ACK for the initialization message that was just sent
  2142. ! to the remote KERMIT.
  2143. !
  2144.  
  2145.     IF NOT (STATUS = PRS_SEND_INIT ()) THEN RETURN STATE_A;
  2146.  
  2147.     NUM_RETRIES = 0;
  2148.     INIT_PKT_SENT = TRUE;            ! We have exchanged init's
  2149.     RETURN STATE_SG;
  2150.     END;
  2151.  
  2152. !
  2153. ! If we haven't returned yet, we must have gotten an invalid response.
  2154. ! Just stay in the same state so we try again
  2155. !
  2156.     RETURN .STATE;
  2157.     END;
  2158. %SBTTL 'SEND_DATA'
  2159. ROUTINE SEND_DATA =
  2160.  
  2161. !++
  2162. ! FUNCTIONAL DESCRIPTION:
  2163. !
  2164. !    This routine will send a data message to the remote KERMIT.
  2165. !
  2166. ! CALLING SEQUENCE:
  2167. !
  2168. !    STATE = SEND_DATA();
  2169. !
  2170. ! INPUT PARAMETERS:
  2171. !
  2172. !    None.
  2173. !
  2174. ! IMPLICIT INPUTS:
  2175. !
  2176. !    None.
  2177. !
  2178. ! OUTPUT PARAMETERS:
  2179. !
  2180. !    New state to change the finite state machine to.
  2181. !
  2182. ! IMPLICIT OUTPUTS:
  2183. !
  2184. !    None.
  2185. !
  2186. ! COMPLETION CODES:
  2187. !
  2188. !    None.
  2189. !
  2190. ! SIDE EFFECTS:
  2191. !
  2192. !    None.
  2193. !
  2194. !--
  2195.  
  2196.     BEGIN
  2197.  
  2198.     LOCAL
  2199.     SUB_TYPE,                ! Subtype for XFR_STATUS call
  2200.     STATUS;                    ! Status returned by various routines
  2201.  
  2202. !
  2203. ! If there is nothing in the data packet, we should not bother to send it.
  2204. ! Instead, we will just call BFR_FILL again to get some more data
  2205. !
  2206.  
  2207.     IF .SIZE NEQ 0            ! [108]
  2208.     THEN
  2209.     BEGIN
  2210. !
  2211. ! Check to see if the number of retries have been exceeded.
  2212. !
  2213.  
  2214.     IF .NUM_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  2215.  
  2216. !
  2217. ! Not exceeded yet.  Increment the number of retries we have attempted
  2218. ! on this message.
  2219. !
  2220.     NUM_RETRIES = .NUM_RETRIES + 1;
  2221. !
  2222. ! Attempt to send the packet and abort if the send fails.
  2223. !
  2224.  
  2225.     IF NOT SEND_PACKET (MSG_DATA, .SIZE, .MSG_NUMBER) THEN RETURN STATE_EX;
  2226.  
  2227. !
  2228. ! Attempt to receive a message from the remote KERMIT.
  2229. !
  2230.     STATUS = REC_PACKET ();
  2231.  
  2232.     IF NOT .STATUS
  2233.     THEN
  2234.         BEGIN
  2235.  
  2236.         IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS
  2237.  EQL
  2238.         KER_CHKSUMERR)
  2239.         THEN
  2240.         RETURN .STATE
  2241.         ELSE
  2242.         RETURN STATE_EX;
  2243.  
  2244.         END;
  2245.  
  2246. !
  2247. ! Determine if the message is a NAK and the NAK is for the message number
  2248. ! that we are current working on.  If the NAK is for the next packet then
  2249. ! treat it like an ACK for this packet
  2250. !
  2251.  
  2252.     IF .REC_TYPE EQL MSG_NAK AND (.REC_SEQ NEQ ((.MSG_NUMBER + 1) AND %O'77'))
  2253.     THEN
  2254.         RETURN .STATE;
  2255.  
  2256. !
  2257. ! Make sure we have a NAK or ACK
  2258. !
  2259.  
  2260.     IF NOT (.REC_TYPE EQL MSG_ACK OR .REC_TYPE EQL MSG_NAK)
  2261.     THEN
  2262. !
  2263. ! Not an ACK or NAK, abort.
  2264. !
  2265.         BEGIN
  2266.         KRM_ERROR (KER_PROTOERR);
  2267.         RETURN STATE_A;
  2268.         END;
  2269.  
  2270. !
  2271. ! Is this for this message?
  2272. !
  2273.  
  2274.     IF .REC_TYPE EQL MSG_ACK AND .REC_SEQ NEQ .MSG_NUMBER THEN RETURN .STATE;
  2275.  
  2276. !
  2277. ! It was.  Set up for sending the next data message to the remote KERMIT
  2278. ! and return.
  2279. !
  2280. !
  2281. ! Check for data field in ACK indicating abort file or stream
  2282. !
  2283. !
  2284.  
  2285.     IF .REC_TYPE EQL MSG_ACK AND .REC_LENGTH EQL 1
  2286.     THEN
  2287.  
  2288.         SELECTONE CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG, CHR_SIZE)) OF ! [108]
  2289.         SET
  2290.  
  2291.         [MSG_ACK_ABT_CUR] :
  2292.             ABT_CUR_FILE = TRUE;
  2293.  
  2294.         [MSG_ACK_ABT_ALL] :
  2295.             ABT_ALL_FILE = TRUE;
  2296.         TES;
  2297.  
  2298.     NUM_RETRIES = 0;
  2299.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2300.     END;                    ! End of IF .SIZE NEQ 0
  2301.  
  2302.     IF (BFR_FILL (FALSE) EQL KER_NORMAL) AND NOT (.ABT_CUR_FILE OR
  2303.  .ABT_ALL_FILE)
  2304.     THEN
  2305.     RETURN STATE_SD
  2306.     ELSE
  2307.     BEGIN
  2308.  
  2309.     IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  2310.     THEN
  2311.         BEGIN
  2312.  
  2313.         IF .ABT_ALL_FILE
  2314.         THEN
  2315.         TT_TEXT (UPLIT (%ASCIZ' [Group interrupted]'))
  2316.         ELSE
  2317.  
  2318.         IF .ABT_CUR_FILE
  2319.         THEN
  2320.             TT_TEXT (UPLIT (%ASCIZ' [Interrupted]'))
  2321.         ELSE
  2322.             TT_TEXT (UPLIT (%ASCIZ' [OK]'));
  2323.  
  2324.         TT_CRLF ();
  2325.         END;
  2326.  
  2327.     IF .FLAG_FILE_OPEN THEN FILE_CLOSE (FALSE);
  2328.  
  2329.     SUB_TYPE = %C'C';            ! Assume ok
  2330.  
  2331.     IF .ABT_ALL_FILE
  2332.     THEN
  2333.         SUB_TYPE = %C'Z'
  2334.     ELSE
  2335.  
  2336.         IF .ABT_CUR_FILE THEN SUB_TYPE = %C'X';
  2337.  
  2338.     XFR_STATUS (%C'F', .SUB_TYPE);
  2339.     FLAG_FILE_OPEN = FALSE;
  2340.     RETURN STATE_SZ;
  2341.     END;
  2342.  
  2343.     END;
  2344. %SBTTL 'SEND_FILE'
  2345. ROUTINE SEND_FILE =
  2346.  
  2347. !++
  2348. ! FUNCTIONAL DESCRIPTION:
  2349. !
  2350. !    This routine will send the file specification that is being
  2351. !    transfered, or it will send a text header message.
  2352. !
  2353. ! CALLING SEQUENCE:
  2354. !
  2355. !    STATE = SEND_FILE();
  2356. !
  2357. ! INPUT PARAMETERS:
  2358. !
  2359. !    None.
  2360. !
  2361. ! IMPLICIT INPUTS:
  2362. !
  2363. !    TEXT_HEAD_FLAG - If true, send text header instead of file header
  2364. !
  2365. ! OUTPUT PARAMETERS:
  2366. !
  2367. !    New state to change the finite state machine to.
  2368. !
  2369. ! IMPLICIT OUTPUTS:
  2370. !
  2371. !    None.
  2372. !
  2373. ! COMPLETION CODES:
  2374. !
  2375. !    None.
  2376. !
  2377. ! SIDE EFFECTS:
  2378. !
  2379. !    None.
  2380. !
  2381. !--
  2382.  
  2383.     BEGIN
  2384.  
  2385.     LOCAL
  2386.     M_TYPE,                    ! Message type to send
  2387.     STATUS;                    ! Status returned by various routines
  2388.  
  2389. !
  2390. ! Flag we don't want to abort yet
  2391. !
  2392.     ABT_CUR_FILE = FALSE;
  2393.     ABT_ALL_FILE = FALSE;
  2394. !
  2395. ! First determine if we have exceed the number of retries that are
  2396. ! allowed to attempt to send this message.
  2397. !
  2398.  
  2399.     IF .NUM_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  2400.  
  2401. !
  2402. ! The number of retries are not exceeded.  Increment the number and then
  2403. ! attempt to send the packet again.
  2404. !
  2405.     NUM_RETRIES = .NUM_RETRIES + 1;
  2406.     SIZE = 0;                    ! Assume no name
  2407.  
  2408.     IF .TEXT_HEAD_FLAG THEN M_TYPE = MSG_TEXT ELSE M_TYPE = MSG_FILE;
  2409.  
  2410.     IF .FILE_SIZE NEQ 0 AND NOT .NO_FILE_NEEDED
  2411.     THEN
  2412.     BEGIN
  2413. ![025]    CH$MOVE (.FILE_SIZE, CH$PTR (FILE_NAME),
  2414. ![025]        CH$PTR (SND_MSG, PKT_MSG,
  2415. ![025]        CHR_SIZE));
  2416. ![025]
  2417. ![025] Fill packet with file name
  2418. ![025]
  2419.     SET_STRING (CH$PTR (FILE_NAME), .FILE_SIZE, TRUE);
  2420.     BFR_FILL (TRUE);
  2421.     SET_STRING (0, 0, FALSE);
  2422.     END;
  2423.  
  2424.     IF NOT SEND_PACKET (.M_TYPE, .SIZE, .MSG_NUMBER) THEN RETURN STATE_EX;
  2425.  
  2426. !
  2427. ! Now get the responce from the remote KERMIT.
  2428. !
  2429.     STATUS = REC_PACKET ();
  2430.  
  2431.     IF NOT .STATUS
  2432.     THEN
  2433.     BEGIN
  2434.  
  2435.     IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS EQL
  2436.  KER_CHKSUMERR)
  2437.     THEN
  2438.         RETURN .STATE
  2439.     ELSE
  2440.         RETURN STATE_EX;
  2441.  
  2442.     END;
  2443.  
  2444. !
  2445. ! Determine if the packet is good.
  2446. !
  2447.  
  2448.     IF NOT (.REC_TYPE EQL MSG_ACK OR .REC_TYPE EQL MSG_NAK)
  2449.     THEN
  2450.     BEGIN
  2451.     KRM_ERROR (KER_PROTOERR);
  2452.     RETURN STATE_A;
  2453.     END;
  2454.  
  2455. !
  2456. ! If this is a NAK and the message number is not the one we just send
  2457. ! treat this like an ACK, otherwise resend the last packet.
  2458. !
  2459.  
  2460.     IF .REC_TYPE EQL MSG_NAK AND (.REC_SEQ NEQ ((.MSG_NUMBER + 1) AND %O'77'))
  2461.  THEN RETURN .STATE;
  2462.  
  2463.     IF .REC_TYPE EQL MSG_ACK AND .REC_SEQ NEQ .MSG_NUMBER THEN RETURN .STATE;
  2464.  
  2465. !
  2466. ! If all is ok, bump the message number and fill first buffer
  2467. !
  2468.     NUM_RETRIES = 0;
  2469.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2470.  
  2471.     IF BFR_FILL (TRUE) THEN RETURN STATE_SD ELSE RETURN STATE_A;
  2472.  
  2473.     END;                    ! End of SEND_FILE
  2474. %SBTTL 'SEND_EOF'
  2475. ROUTINE SEND_EOF =
  2476.  
  2477. !++
  2478. ! FUNCTIONAL DESCRIPTION:
  2479. !
  2480. !    This routine will send the end of file message to the remote
  2481. !    KERMIT.  It will then determine if there are more files to
  2482. !    send to the remote.
  2483. !
  2484. ! CALLING SEQUENCE:
  2485. !
  2486. !    STATE = SEND_EOF();
  2487. !
  2488. ! INPUT PARAMETERS:
  2489. !
  2490. !    None.
  2491. !
  2492. ! IMPLICIT INPUTS:
  2493. !
  2494. !    None.
  2495. !
  2496. ! OUTPUT PARAMETERS:
  2497. !
  2498. !    New state to change the finite state machine to.
  2499. !
  2500. ! IMPLICIT OUTPUTS:
  2501. !
  2502. !    None.
  2503. !
  2504. ! COMPLETION CODES:
  2505. !
  2506. !    None.
  2507. !
  2508. ! SIDE EFFECTS:
  2509. !
  2510. !    Sets up for the next file to be processed if there is one.
  2511. !
  2512. !--
  2513.  
  2514.     BEGIN
  2515.  
  2516.     LOCAL
  2517.     STATUS,                    ! Status returned by various routines
  2518.     EOF_MSG_LEN;                ! Length of EOF message to send
  2519.  
  2520. !
  2521. ! First determine if we have exceed the number of retries that are
  2522. ! allowed to attempt to send this message.
  2523. !
  2524.  
  2525.     IF .NUM_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  2526.  
  2527. !
  2528. ! The number of retries are not exceeded.  Increment the number and then
  2529. ! attempt to send the packet again.
  2530. !
  2531.     NUM_RETRIES = .NUM_RETRIES + 1;
  2532. !
  2533. ! Store character in packet to indicate discard of file
  2534. ! Character will only be sent if file should be discarded
  2535. !
  2536.     CH$WCHAR (MSG_EOF_DISCARD, CH$PTR (SND_MSG, PKT_MSG, CHR_SIZE));
  2537.  
  2538.     IF .ABT_CUR_FILE OR .ABT_ALL_FILE THEN EOF_MSG_LEN = 1 ELSE EOF_MSG_LEN = 0;
  2539.  
  2540.     IF NOT SEND_PACKET (MSG_EOF, .EOF_MSG_LEN, .MSG_NUMBER) THEN RETURN
  2541.  STATE_EX;
  2542.  
  2543. !
  2544. ! Now get the responce from the remote KERMIT.
  2545. !
  2546.     STATUS = REC_PACKET ();
  2547.  
  2548.     IF NOT .STATUS
  2549.     THEN
  2550.     BEGIN
  2551.  
  2552.     IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS EQL
  2553.  KER_CHKSUMERR)
  2554.     THEN
  2555.         RETURN .STATE
  2556.     ELSE
  2557.         RETURN STATE_EX;
  2558.  
  2559.     END;
  2560.  
  2561. !
  2562. ! Determine if the packet is good.
  2563. !
  2564.  
  2565.     IF NOT (.REC_TYPE EQL MSG_ACK OR .REC_TYPE EQL MSG_NAK)
  2566.     THEN
  2567.     BEGIN
  2568.     KRM_ERROR (KER_PROTOERR);
  2569.     RETURN STATE_A;
  2570.     END;
  2571.  
  2572. !
  2573. ! If this is a NAK and the message number is not the one we just send
  2574. ! treat this like an ACK, otherwise resend the last packet.
  2575. !
  2576.  
  2577.     IF .REC_TYPE EQL MSG_NAK AND (.REC_SEQ NEQ ((.MSG_NUMBER + 1) AND %O'77'))
  2578.  THEN RETURN .STATE;
  2579.  
  2580.     IF .REC_TYPE EQL MSG_ACK AND .REC_SEQ NEQ .MSG_NUMBER THEN RETURN .STATE;
  2581.  
  2582. !
  2583. ! Here to determine if there is another file to send.
  2584. !
  2585.     NUM_RETRIES = 0;
  2586.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2587.  
  2588.     IF NOT .ABT_ALL_FILE THEN STATUS = NEXT_FILE () ELSE STATUS =
  2589.  KER_NOMORFILES;
  2590.  
  2591.     IF ( NOT .STATUS) OR (.STATUS EQL KER_NOMORFILES)
  2592.     THEN
  2593.     BEGIN
  2594.  
  2595.     IF (.STATUS NEQ KER_NOMORFILES) THEN RETURN STATE_A ELSE RETURN STATE_SB;
  2596.  
  2597.     END
  2598.     ELSE
  2599.     BEGIN
  2600.     FLAG_FILE_OPEN = TRUE;            ! Have a file open again
  2601.  
  2602.     IF .FIL_NORMAL_FORM THEN NORMALIZE_FILE (FILE_NAME, FILE_SIZE, -1, -1);
  2603.  
  2604.     XFR_STATUS (%C'F', %C'S');        ! Inform display routine
  2605.  
  2606.     IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  2607.     THEN
  2608.         BEGIN
  2609. !![045]        TT_TEXT (UPLIT (%ASCIZ'Sending: '));
  2610.         TT_TEXT (FILE_NAME);
  2611.         TT_OUTPUT ();
  2612.         END;
  2613.  
  2614.     FILE_CHARS = 0;                ! No characters sent yet
  2615.     RETURN STATE_SF;
  2616.     END;
  2617.  
  2618.     END;                    ! End of SEND_EOF
  2619. %SBTTL 'SEND_INIT'
  2620. ROUTINE SEND_INIT =
  2621.  
  2622. !++
  2623. ! FUNCTIONAL DESCRIPTION:
  2624. !
  2625. !    This routine will send the initialization packet to the remote
  2626. !    KERMIT.  The message type sent is S.
  2627. !
  2628. ! CALLING SEQUENCE:
  2629. !
  2630. !    STATE = SEND_INIT();
  2631. !
  2632. ! INPUT PARAMETERS:
  2633. !
  2634. !    None.
  2635. !
  2636. ! IMPLICIT INPUTS:
  2637. !
  2638. !    None.
  2639. !
  2640. ! OUTPUT PARAMETERS:
  2641. !
  2642. !    New state to change the finite state machine to.
  2643. !
  2644. ! IMPLICIT OUTPUTS:
  2645. !
  2646. !    None.
  2647. !
  2648. ! COMPLETION CODES:
  2649. !
  2650. !    None.
  2651. !
  2652. ! SIDE EFFECTS:
  2653. !
  2654. !    None.
  2655. !
  2656. !--
  2657.  
  2658.     BEGIN
  2659.  
  2660.     LOCAL
  2661.     STATUS;                    ! Status returned by various routines
  2662.  
  2663.     SET_SEND_INIT ();
  2664.  
  2665.     IF .NUM_RETRIES GTR .SI_RETRIES THEN RETURN STATE_ER;
  2666.  
  2667. !
  2668. ! Count the number of times we try this
  2669. !
  2670.     NUM_RETRIES = .NUM_RETRIES + 1;
  2671.  
  2672.     IF NOT SEND_PACKET (MSG_SND_INIT, .SEND_INIT_SIZE, .MSG_NUMBER) THEN RETURN
  2673.  STATE_EX; ! [108]
  2674.  
  2675. !
  2676. ! Determine if we received a packet it good condition.  If we timed out or
  2677. ! got an illegal message, just try again.
  2678. !
  2679.     STATUS = REC_PACKET ();
  2680.  
  2681.     IF NOT .STATUS
  2682.     THEN
  2683.     BEGIN
  2684.  
  2685.     IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS EQL
  2686.  KER_CHKSUMERR)
  2687.     THEN
  2688.         RETURN .STATE
  2689.     ELSE
  2690.         RETURN STATE_EX;
  2691.  
  2692.     END;
  2693.  
  2694. !
  2695. ! Determine if the packet is good.
  2696. !
  2697.  
  2698.     IF .REC_TYPE NEQ MSG_ACK THEN RETURN .STATE;
  2699.  
  2700.     IF .REC_SEQ NEQ .MSG_NUMBER THEN RETURN .STATE;
  2701.  
  2702. !
  2703. ! Here if we have an ACK for the initialization message that was just sent
  2704. ! to the remote KERMIT.
  2705. !
  2706.  
  2707.     IF NOT (STATUS = PRS_SEND_INIT ()) THEN RETURN STATE_A;
  2708.  
  2709.     BLK_CHK_TYPE = .INI_CHK_TYPE;        ! We now use agreed upon block check type
  2710.     NUM_RETRIES = 0;
  2711.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2712.     RETURN STATE_OF;                ! Now need to open the file
  2713.     END;
  2714. %SBTTL 'SEND_OPEN_FILE - Open file for sending'
  2715. ROUTINE SEND_OPEN_FILE =
  2716.  
  2717. !++
  2718. ! FUNCTIONAL DESCRIPTION:
  2719. !
  2720. ! This routine is called from DO_TRANSACTION when the first input file
  2721. ! needs to be opened.
  2722. !
  2723. ! CALLING SEQUENCE:
  2724. !
  2725. !    STATE = SEND_OPEN_FILE ();
  2726. !
  2727. ! INPUT PARAMETERS:
  2728. !
  2729. !    None.
  2730. !
  2731. ! IMPLICIT INPUTS:
  2732. !
  2733. !    FILE_NAME, FILE_SIZE, etc.
  2734. !
  2735. ! OUPTUT PARAMETERS:
  2736. !
  2737. !    New state for FSM.
  2738. !
  2739. ! IMPLICIT OUTPUTS:
  2740. !
  2741. !    None.
  2742. !
  2743. ! COMPLETION CODES:
  2744. !
  2745. !    None.
  2746. !
  2747. ! SIDE EFFECTS:
  2748. !
  2749. !    None.
  2750. !
  2751. !--
  2752.  
  2753.     BEGIN
  2754.  
  2755.     IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  2756.     THEN
  2757.     BEGIN
  2758.     TT_TEXT (UPLIT (%ASCIZ'Sending: '));
  2759.     TT_OUTPUT ();
  2760.     END;
  2761.  
  2762.     FILE_CHARS = 0;                ! No characters sent yet
  2763.  
  2764.     IF NOT .NO_FILE_NEEDED
  2765.     THEN
  2766.  
  2767.     IF NOT FILE_OPEN (FNC_READ) THEN RETURN STATE_A ELSE FLAG_FILE_OPEN = TRUE;
  2768.  
  2769. ![023]
  2770. ![023] If we want normalized file names, beat up the name now
  2771. ![023]
  2772.  
  2773.     IF .FIL_NORMAL_FORM THEN NORMALIZE_FILE (FILE_NAME, FILE_SIZE, -1, -1);
  2774.  
  2775.     XFR_STATUS (%C'F', %C'S');            ! Inform display routine
  2776.  
  2777.     IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  2778.     THEN
  2779.     BEGIN
  2780.     TT_TEXT (FILE_NAME);
  2781.     TT_OUTPUT ();
  2782.     END;
  2783.  
  2784.     RETURN STATE_SF;
  2785.     END;                    ! End of FSM_OPEN_FILE
  2786. %SBTTL 'SEND_GENCMD'
  2787. ROUTINE SEND_GENCMD =
  2788.  
  2789. !++
  2790. ! FUNCTIONAL DESCRIPTION:
  2791. !
  2792. !    This routine will send a command packet to the server Kermit.
  2793. !    The new state will depend upon the response.  If a send-init
  2794. !    is received, it will process it and switch to STATE_RF.
  2795. !    If a text-header is received it will switch to STATE_RD.
  2796. !    If an ACK is received, it will type the data portion and
  2797. !    switch to STATE_C.
  2798. !
  2799. ! CALLING SEQUENCE:
  2800. !
  2801. !    STATE = SEND_GENCMD();
  2802. !
  2803. ! INPUT PARAMETERS:
  2804. !
  2805. !    None.
  2806. !
  2807. ! IMPLICIT INPUTS:
  2808. !
  2809. !    GEN_TYPE - Message type to send (normally MSG_GENERIC)
  2810. !    GEN_SUBTYPE - Message subtype (only if MSG_GENERIC)
  2811. !    GEN_1DATA - First argument string
  2812. !    GEN_1SIZE - Size of first argument
  2813. !    GEN_2DATA - Second argument string
  2814. !    GEN_2SIZE - Size of second argument
  2815. !    GEN_3DATA - Third argument string
  2816. !    GEN_3SIZE - Size of third argument
  2817. !
  2818. ! OUTPUT PARAMETERS:
  2819. !
  2820. !    New state for the finite state machine.
  2821. !
  2822. ! IMPLICIT OUTPUTS:
  2823. !
  2824. !    None.
  2825. !
  2826. ! COMPLETION CODES:
  2827. !
  2828. !    None.
  2829. !
  2830. ! SIDE EFFECTS:
  2831. !
  2832. !    None.
  2833. !
  2834. !--
  2835.  
  2836.     BEGIN
  2837.  
  2838.     LOCAL
  2839.     POINTER,                ! Pointer at DATA_TEXT
  2840.     DATA_TEXT : VECTOR [CH$ALLOCATION (MAX_MSG)],    ! Data buffer
  2841.     DATA_SIZE,                ! Length of data buffer used
  2842.     STATUS;                    ! Status returned by various routines
  2843.  
  2844.     ROUTINE PACK_DATA (POINTER, LENGTH, SRC_ADDR, SRC_LEN) =
  2845. !
  2846. ! Routine to pack an argument into the buffer.
  2847. !
  2848.     BEGIN
  2849.  
  2850.     IF .SRC_LEN GTR MAX_MSG - .LENGTH - 1 THEN SRC_LEN = MAX_MSG - .LENGTH - 1;
  2851.  
  2852.     LENGTH = .LENGTH + .SRC_LEN + 1;
  2853.     CH$WCHAR_A (CHAR (.SRC_LEN), .POINTER);
  2854.     .POINTER = CH$MOVE (.SRC_LEN, CH$PTR (.SRC_ADDR), ..POINTER);
  2855.     RETURN .LENGTH;
  2856.     END;
  2857. !
  2858. ! First determine if we have exceed the number of retries that are
  2859. ! allowed to attempt to send this message.
  2860. !
  2861.  
  2862.     IF .NUM_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  2863.  
  2864. !
  2865. ! The number of retries are not exceeded.  Increment the number and then
  2866. ! attempt to send the packet again.
  2867. !
  2868.     NUM_RETRIES = .NUM_RETRIES + 1;
  2869. !
  2870. ! Build the packet data field
  2871. !
  2872.     POINTER = CH$PTR (DATA_TEXT);
  2873.     DATA_SIZE = 0;
  2874.  
  2875.     IF .GEN_TYPE EQL MSG_GENERIC
  2876.     THEN
  2877.     BEGIN
  2878.     CH$WCHAR_A (.GEN_SUBTYPE, POINTER);
  2879.     DATA_SIZE = 1;
  2880.  
  2881.     IF .GEN_1SIZE GTR 0 OR .GEN_2SIZE GTR 0 OR .GEN_3SIZE GTR 0
  2882.     THEN
  2883.         BEGIN
  2884.         DATA_SIZE = PACK_DATA (POINTER, .DATA_SIZE, GEN_1DATA, .GEN_1SIZE);
  2885.  
  2886.         IF .GEN_2SIZE GTR 0 OR .GEN_3SIZE GTR 0
  2887.         THEN
  2888.         BEGIN
  2889.         DATA_SIZE = PACK_DATA (POINTER, .DATA_SIZE, GEN_2DATA, .GEN_2SIZE);
  2890.  
  2891.         IF .GEN_3SIZE GTR 0
  2892.         THEN
  2893.             BEGIN
  2894.             DATA_SIZE = PACK_DATA (POINTER, .DATA_SIZE, GEN_3DATA, .GEN_3SIZE);
  2895.             END;
  2896.  
  2897.         END;
  2898.  
  2899.         END;
  2900.  
  2901.     END
  2902.     ELSE
  2903.     BEGIN
  2904.  
  2905.     IF .GEN_1SIZE GTR MAX_MSG THEN GEN_1SIZE = MAX_MSG;
  2906.  
  2907.     DATA_SIZE = .GEN_1SIZE;
  2908.     CH$MOVE (.GEN_1SIZE, CH$PTR (GEN_1DATA), .POINTER);
  2909.     END;
  2910.  
  2911.     SET_STRING (CH$PTR (DATA_TEXT), .DATA_SIZE, TRUE);
  2912.     BFR_FILL (TRUE);
  2913.     SET_STRING (0, 0, FALSE);
  2914. !
  2915. ! Send the packet
  2916. !
  2917.  
  2918.     IF NOT SEND_PACKET (.GEN_TYPE, .SIZE, .MSG_NUMBER) THEN RETURN STATE_EX;
  2919.  
  2920. !
  2921. ! Now get the responce from the remote KERMIT.
  2922. !
  2923.     STATUS = REC_PACKET ();
  2924.  
  2925.     IF NOT .STATUS
  2926.     THEN
  2927.     BEGIN
  2928.  
  2929.     IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS EQL
  2930.  KER_CHKSUMERR)
  2931.     THEN
  2932.         RETURN .STATE
  2933.     ELSE
  2934.         RETURN STATE_EX;
  2935.  
  2936.     END;
  2937.  
  2938. ! Did we get a send-init?
  2939.  
  2940.     SELECTONE .REC_TYPE OF
  2941.     SET
  2942.  
  2943.     [MSG_SND_INIT] :
  2944.         BEGIN
  2945.         MSG_NUMBER = .REC_SEQ;        ! Initialize sequence numbers
  2946. ! Determine if the parameters are ok.  If not, give up
  2947.  
  2948.         IF NOT (STATUS = PRS_SEND_INIT ()) THEN RETURN .STATUS;
  2949.  
  2950.         SET_SEND_INIT ();            ! Set up our acknowledgement to the send-init
  2951.         SEND_PACKET (MSG_ACK, .SEND_INIT_SIZE, .MSG_NUMBER);    ! [108] ! Send it
  2952.         BLK_CHK_TYPE = .INI_CHK_TYPE;    ! Can now use agreed upon type
  2953.         OLD_RETRIES = .NUM_RETRIES;
  2954.         NUM_RETRIES = 0;
  2955.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2956.         RETURN STATE_RF;            ! Now expect file header
  2957.         END;
  2958.  
  2959.     [MSG_TEXT] :
  2960. !
  2961. ! If we just got a text header, set up for typing on the terminal and
  2962. ! shift to receiving data
  2963. !
  2964.         BEGIN
  2965.         TEXT_HEAD_FLAG = TRUE;        ! We want terminal output
  2966.         PUT_CHR_ROUTINE = TYPE_CHAR;    ! Set up the put a character routine
  2967.  
  2968.         IF .REC_LENGTH GTR 0
  2969.         THEN
  2970.         BEGIN
  2971.         TT_TEXT (UPLIT (%ASCIZ'<<'));    ! Make sure file name sticks out
  2972.         BFR_EMPTY ();            ! Dump the packet data to the terminal
  2973.         TT_TEXT (UPLIT (%ASCIZ'>>'));    ! So user can tell where name ends
  2974.         TT_CRLF ();            ! And a CRLF
  2975.         END;
  2976.  
  2977.         SEND_PACKET (MSG_ACK, 0, .MSG_NUMBER);    ! Send an ACK
  2978.         OLD_RETRIES = .NUM_RETRIES;
  2979.         NUM_RETRIES = 0;
  2980.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  2981.         RETURN STATE_RD;            ! We now want data
  2982.         END;
  2983.  
  2984.     [MSG_ACK] :
  2985. !
  2986. ! If we get an ACK, just type the data on the terminal and complete the
  2987. ! transaction.
  2988. !
  2989.         BEGIN
  2990.         PUT_CHR_ROUTINE = TYPE_CHAR;    ! Dump to terminal
  2991.         BFR_EMPTY ();            ! Do it
  2992.  
  2993.         IF .REC_LENGTH GTR 0 THEN TT_CRLF ();
  2994.  
  2995.         RETURN STATE_C;            ! And go idle
  2996.         END;
  2997.  
  2998.     [MSG_NAK] :
  2999. !
  3000. ! If we get a NAK, stay in the same state.  We will re-transmit the
  3001. ! packet again.
  3002. !
  3003.         RETURN .STATE;
  3004.     TES;
  3005.  
  3006. !
  3007. ! If we get here, we didn't get anything resembling an acceptable
  3008. ! packet, so we will abort.
  3009. !
  3010.     KRM_ERROR (KER_PROTOERR);
  3011.     RETURN STATE_A;
  3012.     END;
  3013. %SBTTL 'SEND_BREAK'
  3014. ROUTINE SEND_BREAK =
  3015.  
  3016. !++
  3017. ! FUNCTIONAL DESCRIPTION:
  3018. !
  3019. !    This routine will send the break (end of transmission) message
  3020. !    to the remote KERMIT.  On an ACK the state becomes STATE_C.
  3021. !
  3022. ! CALLING SEQUENCE:
  3023. !
  3024. !    STATE = SEND_BREAK();
  3025. !
  3026. ! INPUT PARAMETERS:
  3027. !
  3028. !    None.
  3029. !
  3030. ! IMPLICIT INPUTS:
  3031. !
  3032. !    None.
  3033. !
  3034. ! OUTPUT PARAMETERS:
  3035. !
  3036. !    New state for the finite state machine.
  3037. !
  3038. ! IMPLICIT OUTPUTS:
  3039. !
  3040. !    None.
  3041. !
  3042. ! COMPLETION CODES:
  3043. !
  3044. !    None.
  3045. !
  3046. ! SIDE EFFECTS:
  3047. !
  3048. !    None.
  3049. !
  3050. !--
  3051.  
  3052.     BEGIN
  3053.  
  3054.     LOCAL
  3055.     STATUS;                    ! Status returned by various routines
  3056.  
  3057. !
  3058. ! First determine if we have exceed the number of retries that are
  3059. ! allowed to attempt to send this message.
  3060. !
  3061.  
  3062.     IF .NUM_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  3063.  
  3064. !
  3065. ! The number of retries are not exceeded.  Increment the number and then
  3066. ! attempt to send the packet again.
  3067. !
  3068.     NUM_RETRIES = .NUM_RETRIES + 1;
  3069.  
  3070.     IF NOT SEND_PACKET (MSG_BREAK, 0, .MSG_NUMBER) THEN RETURN STATE_EX;
  3071.  
  3072. !
  3073. ! Now get the responce from the remote KERMIT.
  3074. !
  3075.     STATUS = REC_PACKET ();
  3076.  
  3077.     IF NOT .STATUS
  3078.     THEN
  3079.     BEGIN
  3080.  
  3081.     IF (.STATUS EQL KER_ZEROLENMSG) OR (.STATUS EQL KER_TIMEOUT) OR (.STATUS EQL
  3082.  KER_CHKSUMERR)
  3083.     THEN
  3084.         RETURN .STATE
  3085.     ELSE
  3086.         RETURN STATE_EX;
  3087.  
  3088.     END;
  3089.  
  3090. !
  3091. ! Determine if the packet is good.
  3092. !
  3093.  
  3094.     IF NOT (.REC_TYPE EQL MSG_ACK OR .REC_TYPE EQL MSG_NAK)
  3095.     THEN
  3096.     BEGIN
  3097.     KRM_ERROR (KER_PROTOERR);
  3098.     RETURN STATE_A;
  3099.     END;
  3100.  
  3101. !
  3102. ! If this is a NAK and the message number is not the one we just send
  3103. ! treat this like an ACK, otherwise resend the last packet.
  3104. !
  3105.  
  3106.     IF .REC_TYPE EQL MSG_NAK AND .REC_SEQ NEQ 0 THEN RETURN .STATE;
  3107.  
  3108.     IF .REC_TYPE EQL MSG_ACK AND .REC_SEQ NEQ .MSG_NUMBER THEN RETURN .STATE;
  3109.  
  3110. !
  3111. ! Here to determine if there is another file to send.
  3112. !
  3113.     NUM_RETRIES = 0;
  3114.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3115.     RETURN STATE_C;
  3116.     END;
  3117. %SBTTL 'REC_INIT'
  3118. ROUTINE REC_INIT =
  3119.  
  3120. !++
  3121. ! FUNCTIONAL DESCRIPTION:
  3122. !
  3123. !    This routine will process an initialization message received from
  3124. !    the remote KERMIT.
  3125. !
  3126. ! CALLING SEQUENCE:
  3127. !
  3128. !    STATE = REC_INIT();
  3129. !
  3130. ! INPUT PARAMETERS:
  3131. !
  3132. !    None.
  3133. !
  3134. ! IMPLICIT INPUTS:
  3135. !
  3136. !    None.
  3137. !
  3138. ! OUTPUT PARAMETERS:
  3139. !
  3140. !    New machine state.
  3141. !
  3142. ! IMPLICIT OUTPUTS:
  3143. !
  3144. !    None.
  3145. !
  3146. ! COMPLETION CODES:
  3147. !
  3148. !    None.
  3149. !
  3150. ! SIDE EFFECTS:
  3151. !
  3152. !    None.
  3153. !
  3154. !--
  3155.  
  3156.     BEGIN
  3157.  
  3158.     LOCAL
  3159.     STATUS;                    ! Status returned by various routines
  3160.  
  3161.     ROUTINE CHECK_INIT =
  3162.     BEGIN
  3163.  
  3164.     IF .REC_TYPE EQL MSG_SND_INIT THEN RETURN TRUE ELSE RETURN FALSE;
  3165.  
  3166.     END;
  3167.  
  3168.     IF NOT (STATUS = REC_MESSAGE (CHECK_INIT))
  3169.     THEN
  3170.  
  3171.     IF .STATUS NEQ KER_ABORTED THEN RETURN STATE_A ELSE RETURN STATE_EX;
  3172.  
  3173.     MSG_NUMBER = .REC_SEQ;
  3174.  
  3175.     IF NOT (STATUS = PRS_SEND_INIT ()) THEN RETURN STATE_A;
  3176.  
  3177.     SET_SEND_INIT ();
  3178.     SEND_PACKET (MSG_ACK, .SEND_INIT_SIZE, .MSG_NUMBER);    ! [108]
  3179.     BLK_CHK_TYPE = .INI_CHK_TYPE;        ! Can now use agreed upon type
  3180.     OLD_RETRIES = .NUM_RETRIES;
  3181.     NUM_RETRIES = 0;
  3182.     MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3183.     RETURN STATE_RF;
  3184.     END;                    ! End of REC_INIT
  3185. %SBTTL 'REC_FILE'
  3186. ROUTINE REC_FILE =
  3187.  
  3188. !++
  3189. ! FUNCTIONAL DESCRIPTION:
  3190. !
  3191. !    This routine expects to receive an MSG_FILE packet from the remote
  3192. !    KERMIT.  If the message is correct this routine will change the state
  3193. !    to STATE_RD.
  3194. !
  3195. !    This routine also expects MSG_SND_INIT, MSG_EOF, or MSG_BREAK.
  3196. !
  3197. ! CALLING SEQUENCE:
  3198. !
  3199. !    STATE = REC_FILE();
  3200. !
  3201. ! INPUT PARAMETERS:
  3202. !
  3203. !    None.
  3204. !
  3205. ! IMPLICIT INPUTS:
  3206. !
  3207. !    None.
  3208. !
  3209. ! OUTPUT PARAMETERS:
  3210. !
  3211. !    New state.
  3212. !
  3213. ! IMPLICIT OUTPUTS:
  3214. !
  3215. !    None.
  3216. !
  3217. ! COMPLETION CODES:
  3218. !
  3219. !    None.
  3220. !
  3221. ! SIDE EFFECTS:
  3222. !
  3223. !    None.
  3224. !
  3225. !--
  3226.  
  3227.     BEGIN
  3228.  
  3229.     LOCAL
  3230.     STATUS;
  3231.  
  3232.     ROUTINE CHECK_FILE =
  3233.     BEGIN
  3234.  
  3235.     IF (.REC_TYPE EQL MSG_SND_INIT) OR (.REC_TYPE EQL MSG_EOF) OR (.REC_TYPE EQL
  3236.  MSG_FILE) OR (
  3237.         .REC_TYPE EQL MSG_BREAK) OR (.REC_TYPE EQL MSG_TEXT)
  3238.     THEN
  3239.         RETURN TRUE
  3240.     ELSE
  3241.         RETURN FALSE;
  3242.  
  3243.     END;
  3244. !
  3245. ! Initialize the abort flags
  3246. !
  3247.     ABT_CUR_FILE = FALSE;
  3248.     ABT_ALL_FILE = FALSE;
  3249. !
  3250. ! Get a message
  3251. !
  3252.  
  3253.     IF NOT (STATUS = REC_MESSAGE (CHECK_FILE))
  3254.     THEN
  3255.  
  3256.     IF .STATUS NEQ KER_ABORTED THEN RETURN STATE_A ELSE RETURN STATE_EX;
  3257.  
  3258.     SELECTONE .REC_TYPE OF
  3259.     SET
  3260.  
  3261.     [MSG_SND_INIT] :
  3262.         BEGIN
  3263.  
  3264.         IF .OLD_RETRIES GTR .SI_RETRIES THEN RETURN STATE_ER;
  3265.  
  3266.         OLD_RETRIES = .OLD_RETRIES + 1;
  3267.  
  3268.         IF ((.MSG_NUMBER - 1) AND %O'77') EQL .REC_SEQ
  3269.         THEN
  3270.         BEGIN
  3271.         SET_SEND_INIT ();
  3272.         BLK_CHK_TYPE = CHK_1CHAR;    ! Must use 1 character CHKSUM
  3273.         SEND_PACKET (MSG_ACK, .SEND_INIT_SIZE, .REC_SEQ); ! [108]
  3274.         BLK_CHK_TYPE = .INI_CHK_TYPE;    ! Back to agreed upon type
  3275.         NUM_RETRIES = 0;
  3276.         RETURN .STATE;
  3277.         END
  3278.         ELSE
  3279.         BEGIN
  3280.         KRM_ERROR (KER_PROTOERR);
  3281.         RETURN STATE_A;
  3282.         END;
  3283.  
  3284.         END;
  3285.  
  3286.     [MSG_EOF] :
  3287.         BEGIN
  3288.  
  3289.         IF .OLD_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  3290.  
  3291.         OLD_RETRIES = .OLD_RETRIES + 1;
  3292.  
  3293.         IF ((.MSG_NUMBER - 1) AND %O'77') EQL .REC_SEQ
  3294.         THEN
  3295.         BEGIN
  3296.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3297.         NUM_RETRIES = 0;
  3298.         RETURN .STATE;
  3299.         END
  3300.         ELSE
  3301.         BEGIN
  3302.         KRM_ERROR (KER_PROTOERR);
  3303.         RETURN STATE_A;
  3304.         END;
  3305.  
  3306.         END;
  3307.  
  3308.     [MSG_FILE] :
  3309.         BEGIN
  3310.  
  3311.         IF .MSG_NUMBER NEQ .REC_SEQ THEN RETURN STATE_ER;
  3312.  
  3313.         IF .REC_LENGTH EQL 0
  3314.         THEN
  3315.         BEGIN
  3316.         KRM_ERROR (KER_PROTOERR);
  3317.         RETURN STATE_A;
  3318.         END;
  3319.  
  3320. ![025]
  3321. ![025] Get file name from packet with all quoting undone
  3322. ![025]
  3323.         SET_STRING (CH$PTR (FILE_NAME), MAX_FILE_NAME, TRUE);
  3324.         BFR_EMPTY ();
  3325.         FILE_SIZE = SET_STRING (0, 0, FALSE);
  3326.         CH$WCHAR (CHR_NUL, CH$PTR (FILE_NAME, .FILE_SIZE));
  3327. ![025]        FILE_SIZE = .REC_LENGTH;
  3328. ![025]        CH$COPY (.REC_LENGTH, CH$PTR (REC_MSG, PKT_MSG, CHR_SIZE), CHR_NUL,
  3329.  MAX_FILE_NAME,
  3330. ![025]        CH$PTR (FILE_NAME));
  3331.  
  3332.         IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  3333.         THEN
  3334.         BEGIN
  3335.         TT_TEXT (UPLIT (%ASCIZ'Receiving: '));
  3336.         TT_TEXT (FILE_NAME);
  3337.         TT_OUTPUT ();
  3338.         END;
  3339.  
  3340. ![023]
  3341. ![023] Force file name into normal form if desired
  3342. ![023]
  3343.  
  3344.         IF .FIL_NORMAL_FORM THEN NORMALIZE_FILE (FILE_NAME, FILE_SIZE, 9, 3);
  3345.  
  3346.         FILE_CHARS = 0;            ! No characters received yet
  3347.  
  3348.         IF NOT FILE_OPEN (FNC_WRITE) THEN RETURN STATE_A;
  3349.  
  3350.         XFR_STATUS (%C'F', %C'R');        ! Tell display routine
  3351.         TEXT_HEAD_FLAG = FALSE;        ! Got an F, not an X
  3352.         FLAG_FILE_OPEN = TRUE;
  3353.         SEND_PACKET (MSG_ACK, 0, .MSG_NUMBER);
  3354.         OLD_RETRIES = .NUM_RETRIES;
  3355.         NUM_RETRIES = 0;
  3356.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3357.         RETURN STATE_RD;
  3358.         END;
  3359.  
  3360.     [MSG_TEXT] :
  3361. !
  3362. ! If we get a text header, we will want to type the data on
  3363. ! the terminal.  Set up the put a character routine correctly.
  3364. !
  3365.         BEGIN
  3366.  
  3367.         IF .MSG_NUMBER NEQ .REC_SEQ
  3368.         THEN
  3369.         BEGIN
  3370.         KRM_ERROR (KER_PROTOERR);
  3371.         RETURN STATE_A;
  3372.         END;
  3373.  
  3374.         TEXT_HEAD_FLAG = TRUE;        ! Got an X, not an F
  3375.         PUT_CHR_ROUTINE = TYPE_CHAR;    ! Empty buffer on terminal
  3376.  
  3377.         IF .REC_LENGTH GTR 0
  3378.         THEN
  3379.         BEGIN
  3380.         TT_TEXT (UPLIT (%ASCIZ'<<'));    ! Make file name stick out
  3381.         BFR_EMPTY ();            ! Do the header data
  3382.         TT_TEXT (UPLIT (%ASCIZ'>>'));
  3383.         TT_CRLF ();            ! And a crlf
  3384.         END;
  3385.  
  3386.         SEND_PACKET (MSG_ACK, 0, .MSG_NUMBER);
  3387.         OLD_RETRIES = .NUM_RETRIES;
  3388.         NUM_RETRIES = 0;
  3389.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3390.         RETURN STATE_RD;
  3391.         END;
  3392.  
  3393.     [MSG_BREAK] :
  3394.         BEGIN
  3395.  
  3396.         IF .MSG_NUMBER NEQ .REC_SEQ
  3397.         THEN
  3398.         BEGIN
  3399.         KRM_ERROR (KER_PROTOERR);
  3400.         RETURN STATE_A;
  3401.         END;
  3402.  
  3403.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3404.         RETURN STATE_C;
  3405.         END;
  3406.  
  3407.     [OTHERWISE] :
  3408.         BEGIN
  3409.         KRM_ERROR (KER_PROTOERR);
  3410.         RETURN STATE_A;
  3411.         END;
  3412.     TES;
  3413.  
  3414.     END;                    ! End of REC_FILE
  3415. %SBTTL 'REC_DATA'
  3416. ROUTINE REC_DATA =
  3417.  
  3418. !++
  3419. ! FUNCTIONAL DESCRIPTION:
  3420. !
  3421. ! This routine will accept data messages and write them to disk.
  3422. ! It will also accept MSG_FILE, MSG_TEXT and MSG_EOF messages.
  3423. !
  3424. ! CALLING SEQUENCE:
  3425. !
  3426. !    STATE = REC_DATA();
  3427. !
  3428. ! INPUT PARAMETERS:
  3429. !
  3430. !    None.
  3431. !
  3432. ! IMPLICIT INPUTS:
  3433. !
  3434. !    None.
  3435. !
  3436. ! OUTPUT PARAMETERS:
  3437. !
  3438. !    New state for the finite state machine.
  3439. !
  3440. ! IMPLICIT OUTPUTS:
  3441. !
  3442. !    None.
  3443. !
  3444. ! COMPLETION CODES:
  3445. !
  3446. !    None.
  3447. !
  3448. ! SIDE EFFECTS:
  3449. !
  3450. !    None.
  3451. !
  3452. !--
  3453.  
  3454.     BEGIN
  3455.  
  3456.     LOCAL
  3457.     STATUS;
  3458.  
  3459.     ROUTINE CHECK_DATA =
  3460.     BEGIN
  3461.  
  3462.     IF .REC_TYPE EQL MSG_DATA OR (.REC_TYPE EQL MSG_FILE AND NOT .TEXT_HEAD_FLAG)
  3463.  OR .REC_TYPE
  3464.         EQL MSG_EOF OR (.REC_TYPE EQL MSG_TEXT AND .TEXT_HEAD_FLAG)
  3465.     THEN
  3466.         RETURN TRUE
  3467.     ELSE
  3468.         RETURN FALSE;
  3469.  
  3470.     END;
  3471.  
  3472.     LOCAL
  3473.     SUB_TYPE,                ! Subtype for XFR_STATUS
  3474.     DISCARD_FILE_FLAG,            ! Sender requested discard
  3475.     ACK_MSG_LEN;                ! Length of ACK to send
  3476.  
  3477. !
  3478. ! First get a message
  3479. !
  3480.  
  3481.     IF NOT (STATUS = REC_MESSAGE (CHECK_DATA))
  3482.     THEN
  3483.  
  3484.     IF .STATUS NEQ KER_ABORTED THEN RETURN STATE_A ELSE RETURN STATE_EX;
  3485.  
  3486.     SELECTONE .REC_TYPE OF
  3487.     SET
  3488.  
  3489.     [MSG_DATA] :
  3490.         BEGIN
  3491.  
  3492.         IF .MSG_NUMBER NEQ .REC_SEQ
  3493.         THEN
  3494.         BEGIN
  3495.  
  3496.         IF .OLD_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  3497.  
  3498.         OLD_RETRIES = .OLD_RETRIES + 1;
  3499.  
  3500.         IF ((.MSG_NUMBER - 1) AND %O'77') EQL .REC_SEQ
  3501.         THEN
  3502.             BEGIN
  3503.             SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3504.             NUM_RETRIES = 0;
  3505.             RETURN .STATE;
  3506.             END
  3507.         ELSE
  3508.             BEGIN
  3509.             KRM_ERROR (KER_PROTOERR);
  3510.             RETURN STATE_A;
  3511.             END;
  3512.  
  3513.         END;
  3514.  
  3515. !
  3516. ! Here if we have a message with a valid message number
  3517. !
  3518.  
  3519.         IF NOT BFR_EMPTY () THEN RETURN STATE_A;
  3520.  
  3521. !
  3522. ! Check if we wish to abort for some reason
  3523. !
  3524.  
  3525.         IF .ABT_CUR_FILE
  3526.         THEN
  3527.         BEGIN
  3528.         CH$WCHAR (MSG_ACK_ABT_CUR, CH$PTR (SND_MSG, PKT_MSG, CHR_SIZE));
  3529.         ACK_MSG_LEN = 1;
  3530.         END
  3531.         ELSE
  3532.  
  3533.         IF .ABT_ALL_FILE
  3534.         THEN
  3535.             BEGIN
  3536.             CH$WCHAR (MSG_ACK_ABT_ALL, CH$PTR (SND_MSG, PKT_MSG, CHR_SIZE));
  3537.             ACK_MSG_LEN = 1;
  3538.             END
  3539.         ELSE
  3540.             ACK_MSG_LEN = 0;
  3541.  
  3542. !
  3543. ! Now send the ACK
  3544. !
  3545.         SEND_PACKET (MSG_ACK, .ACK_MSG_LEN, .REC_SEQ);
  3546.         OLD_RETRIES = .NUM_RETRIES;
  3547.         NUM_RETRIES = 0;
  3548.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3549.         RETURN STATE_RD;
  3550.         END;
  3551.  
  3552.     [MSG_FILE, MSG_TEXT] :
  3553.         BEGIN
  3554.  
  3555.         IF .OLD_RETRIES GTR .PKT_RETRIES THEN RETURN STATE_ER;
  3556.  
  3557.         OLD_RETRIES = .OLD_RETRIES + 1;
  3558.  
  3559.         IF ((.MSG_NUMBER - 1) AND %O'77') EQL .REC_SEQ
  3560.         THEN
  3561.         BEGIN
  3562.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3563.         NUM_RETRIES = 0;
  3564.         RETURN .STATE;
  3565.         END
  3566.         ELSE
  3567.         BEGIN
  3568.         KRM_ERROR (KER_PROTOERR);
  3569.         RETURN STATE_A;
  3570.         END;
  3571.  
  3572.         END;
  3573.  
  3574.     [MSG_EOF] :
  3575.         BEGIN
  3576.  
  3577.         IF .MSG_NUMBER NEQ .REC_SEQ
  3578.         THEN
  3579.         BEGIN
  3580.         KRM_ERROR (KER_PROTOERR);
  3581.         RETURN STATE_A;
  3582.         END;
  3583.  
  3584.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3585.  
  3586.         IF NOT .TEXT_HEAD_FLAG
  3587.         THEN
  3588.         BEGIN
  3589.         FLAG_FILE_OPEN = FALSE;
  3590.         DISCARD_FILE_FLAG = FALSE;    ! Assume we want file
  3591.  
  3592.         IF .REC_LENGTH EQL 1
  3593.         THEN
  3594.  
  3595.             IF CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG, CHR_SIZE)) EQL
  3596.  MSG_EOF_DISCARD ! [108]
  3597.             THEN
  3598.             DISCARD_FILE_FLAG = TRUE;
  3599.  
  3600.         IF ( NOT .CONNECT_FLAG) AND .TY_FIL
  3601.         THEN
  3602.             BEGIN
  3603.  
  3604.             IF .DISCARD_FILE_FLAG
  3605.             THEN
  3606.  
  3607.             IF .ABT_FLAG
  3608.             THEN
  3609.                 TT_TEXT (UPLIT (%ASCIZ' [Interrupted]'))
  3610.             ELSE
  3611.                 TT_TEXT (UPLIT (%ASCIZ' [Interrupted, partial file saved]'))
  3612.  
  3613.             ELSE
  3614.             TT_TEXT (UPLIT (%ASCIZ' [OK]'));
  3615.  
  3616.             TT_CRLF ();
  3617.             END;
  3618.  
  3619.         IF NOT FILE_CLOSE (.DISCARD_FILE_FLAG AND .ABT_FLAG) THEN RETURN STATE_A;
  3620.  
  3621.         IF .DISCARD_FILE_FLAG
  3622.         THEN
  3623.  
  3624.             IF .ABT_FLAG THEN SUB_TYPE = %C'X' ELSE SUB_TYPE = %C'D'
  3625.  
  3626.         ELSE
  3627.             SUB_TYPE = %C'C';
  3628.  
  3629.         END
  3630.         ELSE
  3631.         BEGIN
  3632.         TT_CRLF ();            ! Make sure we have a CRLF
  3633.         TT_OUTPUT ();            ! And make sure all output is sent
  3634.         END;
  3635.  
  3636.         XFR_STATUS (%C'F', .SUB_TYPE);
  3637.         MSG_NUMBER = (.MSG_NUMBER + 1) AND %O'77';
  3638.         RETURN STATE_RF;
  3639.         END;
  3640.  
  3641.     [OTHERWISE] :
  3642.         BEGIN
  3643.         KRM_ERROR (KER_PROTOERR);
  3644.         RETURN STATE_A;
  3645.         END;
  3646.     TES;
  3647.  
  3648.     END;                    ! End of REC_DATA
  3649. %SBTTL 'SERVER - Generic commands'
  3650. ROUTINE SERVER_GENERIC =
  3651.  
  3652. !++
  3653. ! FUNCTIONAL DESCRIPTION:
  3654. !
  3655. !    This routine will handle the generic server messages.
  3656. !    The generic server messages include FINISH, LOGOUT.
  3657. !
  3658. ! CALLING SEQUENCE:
  3659. !
  3660. !    STATE = SERVER_GENERIC();
  3661. !
  3662. ! INPUT PARAMETERS:
  3663. !
  3664. !    None.
  3665. !
  3666. ! IMPLICIT INPUTS:
  3667. !
  3668. !    Generic message receive in REC_MSG.
  3669. !
  3670. ! OUTPUT PARAMETERS:
  3671. !
  3672. !    Returns new state for FSM
  3673. !
  3674. ! IMPLICIT OUTPUTS:
  3675. !
  3676. !    None.
  3677. !
  3678. ! COMPLETION CODES:
  3679. !
  3680. !    None.
  3681. !
  3682. ! SIDE EFFECTS:
  3683. !
  3684. !    None.
  3685. !
  3686. !--
  3687.  
  3688.     BEGIN
  3689.  
  3690.     LOCAL
  3691.     STATUS,                    ! Returned status
  3692.     G_FUNC,                    ! Generic command function
  3693.     POINTER,                ! Character pointer
  3694.     DATA_TEXT : VECTOR [CH$ALLOCATION (MAX_MSG)],    ! Unpacked message
  3695.     DATA_SIZE;                ! Actual size of data
  3696.  
  3697.     ROUTINE UNPACK_DATA (POINTER, SIZE, DST_ADDR, DST_LEN) =
  3698. !
  3699. ! Routine to unpack an argument.
  3700. ! This will copy the argument data to the desired buffer.
  3701. !
  3702.     BEGIN
  3703.  
  3704.     IF .SIZE GTR 0                ! If we have something to unpack
  3705.     THEN
  3706.         BEGIN
  3707.         .DST_LEN = UNCHAR (CH$RCHAR_A (.POINTER));
  3708.  
  3709.         IF ..DST_LEN LSS 0
  3710.         THEN
  3711.         BEGIN
  3712.         KRM_ERROR (KER_PROTOERR);    ! Someone screwed up
  3713.         ..DST_LEN = 0;
  3714.         RETURN -1;
  3715.         END;
  3716.  
  3717.         IF ..DST_LEN GTR .SIZE - 1 THEN .DST_LEN = .SIZE - 1;
  3718.  
  3719.         CH$COPY (..DST_LEN, ..POINTER, CHR_NUL, MAX_MSG, CH$PTR (.DST_ADDR));
  3720.         .POINTER = CH$PLUS (..POINTER, ..DST_LEN);
  3721.         RETURN .SIZE - ..DST_LEN - 1;
  3722.         END
  3723.     ELSE
  3724. !
  3725. ! If nothing left in buffer, return the current size (0)
  3726. !
  3727.         RETURN .SIZE;
  3728.  
  3729.     END;
  3730. !
  3731. ! First unpack the message data into its various pieces
  3732. !
  3733.     SET_STRING (CH$PTR (DATA_TEXT), MAX_MSG, TRUE);    ! Initialize for unpacking
  3734.     BFR_EMPTY ();                ! Unpack the data
  3735.     DATA_SIZE = SET_STRING (0, 0, FALSE);    ! All done, get size
  3736.  
  3737.     IF .DATA_SIZE LEQ 0
  3738.     THEN
  3739.     BEGIN
  3740.     KRM_ERROR (KER_PROTOERR);        ! Someone screwed up
  3741.     RETURN STATE_A;                ! Since no subtype
  3742.     END;
  3743.  
  3744. !
  3745. ! Get the arguments from the unpacked data (if any)
  3746. !
  3747.     GEN_1SIZE = 0;                ! Assume no args
  3748.     GEN_2SIZE = 0;                ! none at all
  3749.     GEN_3SIZE = 0;
  3750.     CH$WCHAR (CHR_NUL, CH$PTR (GEN_1DATA));    ! Ensure all are null terminated
  3751.     CH$WCHAR (CHR_NUL, CH$PTR (GEN_2DATA));
  3752.     CH$WCHAR (CHR_NUL, CH$PTR (GEN_3DATA));
  3753.     POINTER = CH$PTR (DATA_TEXT, 1);        ! Point at second character
  3754.     DATA_SIZE = .DATA_SIZE - 1;            ! Account for subtype
  3755.  
  3756.     IF .DATA_SIZE GTR 0                ! Room for first arg?
  3757.     THEN
  3758.     BEGIN
  3759.     DATA_SIZE = UNPACK_DATA (POINTER, .DATA_SIZE, GEN_1DATA, GEN_1SIZE);
  3760.  
  3761.     IF .DATA_SIZE LSS 0 THEN RETURN STATE_A;    ! Punt if bad arguments
  3762.  
  3763.     IF .DATA_SIZE GTR 0            ! Second argument present?
  3764.     THEN
  3765.         BEGIN
  3766.         DATA_SIZE = UNPACK_DATA (POINTER, .DATA_SIZE, GEN_2DATA, GEN_2SIZE);
  3767.  
  3768.         IF .DATA_SIZE LSS 0 THEN RETURN STATE_A;    ! Punt if bad arguments
  3769.  
  3770.         IF .DATA_SIZE GTR 0            ! Third argument here?
  3771.         THEN
  3772.         BEGIN
  3773.         DATA_SIZE = UNPACK_DATA (POINTER, .DATA_SIZE, GEN_3DATA, GEN_3SIZE);
  3774.  
  3775.         IF .DATA_SIZE LSS 0 THEN RETURN STATE_A;    ! Punt if bad arguments
  3776.  
  3777.         END;
  3778.  
  3779.         END;
  3780.  
  3781.     END;
  3782.  
  3783.     SELECTONE CH$RCHAR (CH$PTR (DATA_TEXT)) OF
  3784.     SET
  3785.     !
  3786.     ! EXIT command, just return the status to the upper level
  3787.     !
  3788.  
  3789.     [MSG_GEN_EXIT] :
  3790.         BEGIN
  3791.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3792.         RETURN STATE_FI;
  3793.         END;
  3794.     !
  3795.     ! LOGOUT command, ACK the message then call the system routine to
  3796.     ! kill the process (log the job out, etc.)
  3797.     !
  3798.  
  3799.     [MSG_GEN_LOGOUT] :
  3800.         BEGIN
  3801.         SEND_PACKET (MSG_ACK, 0, .REC_SEQ);
  3802.         SY_LOGOUT ();
  3803.         RETURN STATE_LG;
  3804.         END;
  3805. !
  3806. ! For a type command, just set up a transfer flagging we want a text header
  3807. ! instead of a file header.
  3808. !
  3809.  
  3810.     [MSG_GEN_TYPE] :
  3811.         BEGIN
  3812.         CH$COPY (.GEN_1SIZE, CH$PTR (GEN_1DATA), CHR_NUL, MAX_FILE_NAME, CH$PTR
  3813. (FILE_NAME));
  3814.         FILE_SIZE = .GEN_1SIZE;
  3815.         TEXT_HEAD_FLAG = TRUE;        ! Now want text header
  3816.         XFR_STATUS (%C'I', %C'G');        ! Tell display routine we are doing a command
  3817.  
  3818.         IF .STATE EQL STATE_II AND .BLK_CHK_TYPE EQL .INI_CHK_TYPE
  3819.         THEN
  3820.         RETURN STATE_OF            ! Must open the file
  3821.         ELSE
  3822.         RETURN STATE_S;            ! Start the transaction with a send
  3823.  
  3824.         END;
  3825.  
  3826.     [MSG_GEN_DIRECTORY] :
  3827.         G_FUNC = GC_DIRECTORY;
  3828.  
  3829.     [MSG_GEN_DISK_USAGE] :
  3830.         G_FUNC = GC_DISK_USAGE;
  3831.  
  3832.     [MSG_GEN_DELETE] :
  3833.         G_FUNC = GC_DELETE;
  3834.  
  3835.     [MSG_GEN_HELP] :
  3836.         G_FUNC = GC_HELP;
  3837.  
  3838.     [MSG_GEN_LOGIN] :
  3839.         G_FUNC = GC_LGN;
  3840.  
  3841.     [MSG_GEN_CONNECT] :
  3842.         G_FUNC = GC_CONNECT;
  3843.  
  3844.     [MSG_GEN_RENAME] :
  3845.         G_FUNC = GC_RENAME;
  3846.  
  3847.     [MSG_GEN_COPY] :
  3848.         G_FUNC = GC_COPY;
  3849.  
  3850.     [MSG_GEN_WHO] :
  3851.         G_FUNC = GC_WHO;
  3852.  
  3853.     [MSG_GEN_SEND] :
  3854.         G_FUNC = GC_SEND_MSG;
  3855.  
  3856.     [MSG_GEN_QUERY] :
  3857.         G_FUNC = GC_STATUS;
  3858.  
  3859.     [MSG_GEN_PROGRAM] :
  3860.         G_FUNC = GC_PROGRAM;
  3861.  
  3862.     [MSG_GEN_JOURNAL] :
  3863.         G_FUNC = GC_JOURNAL;
  3864.  
  3865.     [MSG_GEN_VARIABLE] :
  3866.         G_FUNC = GC_VARIABLE;
  3867. !
  3868. ! Here if we have a function that is not implemented in KERMSG.
  3869. !
  3870.  
  3871.     [OTHERWISE] :
  3872.         BEGIN
  3873.         KRM_ERROR (KER_UNIMPLGEN);
  3874.         RETURN STATE_A;
  3875.         END;
  3876.     TES;
  3877.  
  3878. !
  3879. ! If we get here, we have gotten a known type of generic message that
  3880. ! we need to have our operating system dependent routine handle.
  3881. !
  3882.     RETURN CALL_SY_RTN (.G_FUNC);
  3883.     END;                    ! End of SERVER_GENERIC
  3884. %SBTTL 'HOST_COMMAND - perform a host command'
  3885. ROUTINE HOST_COMMAND =
  3886.  
  3887. !++
  3888. ! FUNCTIONAL DESCRIPTION:
  3889. !
  3890. ! This routine will handle the host command packet.
  3891. ! It will set up the data for the call to the system routine.
  3892. !
  3893. ! CALLING SEQUENCE:
  3894. !
  3895. !    STATE = HOST_COMMAND();
  3896. !
  3897. ! INPUT PARAMETERS:
  3898. !
  3899. !    None.
  3900. !
  3901. ! IMPLICIT INPUTS:
  3902. !
  3903. !    Generic message receive in REC_MSG.
  3904. !
  3905. ! OUTPUT PARAMETERS:
  3906. !
  3907. !    Returns new state for FSM
  3908. !
  3909. ! IMPLICIT OUTPUTS:
  3910. !
  3911. !    None.
  3912. !
  3913. ! COMPLETION CODES:
  3914. !
  3915. !    None.
  3916. !
  3917. ! SIDE EFFECTS:
  3918. !
  3919. !    None.
  3920. !
  3921. !--
  3922.  
  3923.     BEGIN
  3924.     GEN_1SIZE = 0;
  3925.     GEN_2SIZE = 0;
  3926.     GEN_3SIZE = 0;
  3927.  
  3928.     IF .REC_LENGTH LEQ 0
  3929.     THEN
  3930.     BEGIN
  3931.     KRM_ERROR (KER_PROTOERR);        ! Return an error
  3932.     RETURN STATE_A;                ! Just abort
  3933.     END;
  3934.  
  3935.     SET_STRING (CH$PTR (GEN_1DATA), MAX_MSG, TRUE);    ! Start writing to buffer
  3936.     BFR_EMPTY ();                ! Dump the text
  3937.     GEN_1SIZE = SET_STRING (0, 0, FALSE);    ! Get the result
  3938.     RETURN CALL_SY_RTN (GC_COMMAND);
  3939.     END;                    ! End of HOST_COMMAND
  3940. %SBTTL 'KERMIT_COMMAND - perform a KERMIT command'
  3941. ROUTINE KERMIT_COMMAND =
  3942.  
  3943. !++
  3944. ! FUNCTIONAL DESCRIPTION:
  3945. !
  3946. ! This routine will handle the KERMIT command packet.
  3947. ! It will set up the data for the call to the system routine.
  3948. !
  3949. ! CALLING SEQUENCE:
  3950. !
  3951. !    STATE = KERMIT_COMMAND();
  3952. !
  3953. ! INPUT PARAMETERS:
  3954. !
  3955. !    None.
  3956. !
  3957. ! IMPLICIT INPUTS:
  3958. !
  3959. !    Generic message receive in REC_MSG.
  3960. !
  3961. ! OUTPUT PARAMETERS:
  3962. !
  3963. !    Returns new state for FSM
  3964. !
  3965. ! IMPLICIT OUTPUTS:
  3966. !
  3967. !    None.
  3968. !
  3969. ! COMPLETION CODES:
  3970. !
  3971. !    None.
  3972. !
  3973. ! SIDE EFFECTS:
  3974. !
  3975. !    None.
  3976. !
  3977. !--
  3978.  
  3979.     BEGIN
  3980.     GEN_1SIZE = 0;
  3981.     GEN_2SIZE = 0;
  3982.     GEN_3SIZE = 0;
  3983.  
  3984.     IF .REC_LENGTH LEQ 0
  3985.     THEN
  3986.     BEGIN
  3987.     KRM_ERROR (KER_PROTOERR);        ! Return an error
  3988.     RETURN STATE_A;                ! Just abort
  3989.     END;
  3990.  
  3991.     SET_STRING (CH$PTR (GEN_1DATA), MAX_MSG, TRUE);    ! Start writing to buffer
  3992.     BFR_EMPTY ();                ! Dump the text
  3993.     GEN_1SIZE = SET_STRING (0, 0, FALSE);    ! Get the result
  3994.     RETURN CALL_SY_RTN (GC_KERMIT);
  3995.     END;                    ! End of KERMIT_COMMAND
  3996. %SBTTL 'CALL_SY_RTN - handle operating system dependent functions'
  3997. ROUTINE CALL_SY_RTN (G_FUNC) =
  3998.  
  3999. !++
  4000. ! FUNCTIONAL DESCRIPTION:
  4001. !
  4002. ! This routine will handle calling the operating system dependent routine
  4003. ! for a server function and returning the response.
  4004. !
  4005. ! CALLING SEQUENCE:
  4006. !
  4007. !    STATE = CALL_SY_RTN(.G_FUNC);
  4008. !
  4009. ! INPUT PARAMETERS:
  4010. !
  4011. !    G_FUNC - Generic function code
  4012. !
  4013. ! IMPLICIT INPUTS:
  4014. !
  4015. !    Generic message data in GEN_1DATA
  4016. !
  4017. ! OUTPUT PARAMETERS:
  4018. !
  4019. !    Returns new state for FSM
  4020. !
  4021. ! IMPLICIT OUTPUTS:
  4022. !
  4023. !    None.
  4024. !
  4025. ! COMPLETION CODES:
  4026. !
  4027. !    None.
  4028. !
  4029. ! SIDE EFFECTS:
  4030. !
  4031. !    None.
  4032. !
  4033. !--
  4034.  
  4035.     BEGIN
  4036.  
  4037.     LOCAL
  4038.     STRING_ADDRESS,                ! Address of string result
  4039.     STRING_LENGTH,                ! Length of string result
  4040.     GET_CHR_SUBROUTINE,            ! Routine to get a response character
  4041.     STATUS;                    ! Status value
  4042.  
  4043. !
  4044. ! Call the routine with the desired type of command.
  4045. !
  4046.     STRING_LENGTH = 0;                ! Initialize for no string
  4047.     GET_CHR_SUBROUTINE = 0;            ! And no subroutine
  4048.  
  4049.     IF NOT SY_GENERIC (.G_FUNC, STRING_ADDRESS, STRING_LENGTH,
  4050.  GET_CHR_SUBROUTINE)
  4051.     THEN
  4052.     RETURN STATE_A;                ! And abort
  4053.  
  4054.     IF .STRING_LENGTH GTR 0
  4055.     THEN
  4056.     BEGIN
  4057.     SET_STRING (CH$PTR (.STRING_ADDRESS), .STRING_LENGTH, TRUE);
  4058.  
  4059.     IF .STRING_LENGTH LSS .SEND_PKT_SIZE - PKT_OVR_HEAD
  4060.     THEN
  4061.         BEGIN
  4062.         BFR_FILL (TRUE);            ! If it should fit, pack it in
  4063.  
  4064.         IF SET_STRING (0, 0, FALSE) GEQ .STRING_LENGTH
  4065.         THEN                 ! It fit, so just send the ACK
  4066.  
  4067.         IF SEND_PACKET (MSG_ACK, .SIZE, .REC_SEQ) THEN RETURN STATE_C ELSE RETURN
  4068.  STATE_EX;
  4069.  
  4070. !
  4071. ! It didn't fit, reset the pointers to the beginning
  4072. !
  4073.         SET_STRING (CH$PTR (.STRING_ADDRESS), .STRING_LENGTH, TRUE);
  4074.         END;
  4075.  
  4076.     NO_FILE_NEEDED = TRUE;            ! Don't need a file
  4077.     END
  4078.     ELSE
  4079.  
  4080.     IF .GET_CHR_SUBROUTINE NEQ 0        ! If we got a subroutine back
  4081.     THEN
  4082.         BEGIN
  4083.         GET_CHR_ROUTINE = .GET_CHR_SUBROUTINE;
  4084.         NO_FILE_NEEDED = TRUE;
  4085.         END;
  4086.  
  4087.     TEXT_HEAD_FLAG = TRUE;            ! Send to be typed
  4088.     XFR_STATUS (%C'I', %C'G');            ! Doing a generic command
  4089.  
  4090.     IF .STATE EQL STATE_II AND .BLK_CHK_TYPE EQL .INI_CHK_TYPE
  4091.     THEN
  4092.     RETURN STATE_OF
  4093.     ELSE
  4094.     RETURN STATE_S;                ! Send the response
  4095.  
  4096.     END;                    ! End of CALL_SY_RTN
  4097. %SBTTL 'Message processing -- PRS_SEND_INIT - Parse send init params'
  4098. ROUTINE PRS_SEND_INIT =
  4099.  
  4100. !++
  4101. ! FUNCTIONAL DESCRIPTION:
  4102. !
  4103. !    This routine will parse the SEND_INIT parameters that were sent by
  4104. !    the remote Kermit.  The items will be stored into the low segment.
  4105. !
  4106. ! CALLING SEQUENCE:
  4107. !
  4108. !    PRS_SEND_INIT ();
  4109. !
  4110. ! INPUT PARAMETERS:
  4111. !
  4112. !    None.
  4113. !
  4114. ! IMPLICIT INPUTS:
  4115. !
  4116. !    Message stored in REC_MSG.
  4117. !
  4118. ! OUTPUT PARAMETERS:
  4119. !
  4120. !    None.
  4121. !
  4122. ! IMPLICIT OUTPUTS:
  4123. !
  4124. !    None.
  4125. !
  4126. ! COMPLETION CODES:
  4127. !
  4128. !    None.
  4129. !
  4130. ! SIDE EFFECTS:
  4131. !
  4132. !    None.
  4133. !
  4134. !--
  4135.  
  4136.     BEGIN
  4137. ! The following section of code will parse the various send parameters
  4138. ! that are found in the send-init message.  The following code will store
  4139. ! the following as the value.
  4140. !
  4141. ! If the user specified a value then the user supplied value will be used else
  4142. ! the value in the message and if none in the message then the default value.
  4143. !
  4144. ! User supplied values are denoted as positive values in SND_xxxxxxx.
  4145. !
  4146. ! Parse the packet size
  4147. !
  4148.     SEND_PKT_SIZE = (IF .SND_PKT_SIZE GEQ 0 THEN        ! [108]
  4149.       (IF .SND_PKT_SIZE GTR 94 THEN 94 ELSE .SND_PKT_SIZE) ELSE    ! [108]
  4150.     BEGIN
  4151.  
  4152.     IF .REC_LENGTH GTR P_SI_BUFSIZ
  4153.     THEN
  4154.         UNCHAR (CH$RCHAR (CH$PTR (REC_MSG,
  4155.             .RECV_PKT_MSG + P_SI_BUFSIZ, CHR_SIZE))) ! [108]
  4156.     ELSE
  4157.         ABS (.SND_PKT_SIZE)
  4158.  
  4159.     END
  4160.     );
  4161. !
  4162. ! Parse the time out value
  4163. !
  4164.     SEND_TIMEOUT = (IF .SND_TIMEOUT GEQ 0 THEN .SND_TIMEOUT ELSE
  4165.     BEGIN
  4166.  
  4167.     IF .REC_LENGTH GTR P_SI_TIMOUT
  4168.     THEN
  4169.         UNCHAR (CH$RCHAR (CH$PTR (REC_MSG,
  4170.             .RECV_PKT_MSG + P_SI_TIMOUT, CHR_SIZE))) ! [108]
  4171.     ELSE
  4172.         ABS (.SND_TIMEOUT)
  4173.  
  4174.     END
  4175.     );
  4176. !
  4177. ! Parse the number of padding characters supplied
  4178. !
  4179.     SEND_NPAD = (IF .SND_NPAD GEQ 0 THEN .SND_NPAD ELSE
  4180.     BEGIN
  4181.  
  4182.     IF .REC_LENGTH GTR P_SI_NPAD
  4183.     THEN
  4184.         UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG + P_SI_NPAD,
  4185.             CHR_SIZE)))                       ! [108]
  4186.     ELSE
  4187.         ABS (.SND_NPAD)
  4188.  
  4189.     END
  4190.     );
  4191. !
  4192. ! Parse the padding character
  4193. !
  4194.     SEND_PADCHAR = (IF .SND_PADCHAR GEQ 0 THEN .SND_PADCHAR ELSE
  4195.     BEGIN
  4196.  
  4197.     IF .REC_LENGTH GTR P_SI_PAD
  4198.     THEN
  4199.         CTL (CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG + P_SI_PAD,
  4200.             CHR_SIZE)))                       ! [108]
  4201.     ELSE
  4202.         ABS (.SND_PADCHAR)
  4203.  
  4204.     END
  4205.     );
  4206. !
  4207. ! Parse the end of line character
  4208. !
  4209.     SEND_EOL = (IF .SND_EOL GEQ 0 THEN .SND_EOL ELSE
  4210.     BEGIN
  4211.  
  4212.     IF .REC_LENGTH GTR P_SI_EOL
  4213.     THEN
  4214.         UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG + P_SI_EOL,
  4215.             CHR_SIZE)))                       ! [108]
  4216.     ELSE
  4217.         ABS (.SND_EOL)
  4218.  
  4219.     END
  4220.     );
  4221. !
  4222. ! Parse the quoting character
  4223. !
  4224.     SEND_QUOTE_CHR = (IF .SND_QUOTE_CHR GEQ 0 THEN .SND_QUOTE_CHR ELSE
  4225.     BEGIN
  4226.  
  4227.     IF .REC_LENGTH GTR P_SI_QUOTE
  4228.     THEN
  4229.         CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG + P_SI_QUOTE,     ! [108]
  4230.             CHR_SIZE))
  4231.     ELSE
  4232.         ABS (.SND_QUOTE_CHR)
  4233.  
  4234.     END
  4235.     );
  4236. !
  4237. ! Parse the 8-bit quoting character
  4238. !
  4239. ! If the character was not included in the packet, assume no eight-bit
  4240. ! quoting allowed (we are probably talking to an old version of Kermit).
  4241. !
  4242.     SEND_8QUOTE_CHR = (IF .REC_LENGTH GTR P_SI_8QUOTE THEN CH$RCHAR (CH$PTR
  4243. (REC_MSG,
  4244.         .RECV_PKT_MSG + P_SI_8QUOTE, CHR_SIZE)) ELSE %C'N' ! [108] ! Assume no 8-bit
  4245.  quoting allowed
  4246.     );
  4247. !
  4248. ! Parse the checksum type
  4249. !
  4250.  
  4251.     IF .REC_LENGTH GTR P_SI_CHKTYPE
  4252.     THEN
  4253.     BEGIN
  4254.  
  4255.     LOCAL
  4256.         REQ_CHK_TYPE;
  4257.  
  4258.     REQ_CHK_TYPE = CH$RCHAR (CH$PTR (REC_MSG, .RECV_PKT_MSG +      ! [108]
  4259.                     P_SI_CHKTYPE, CHR_SIZE));
  4260.  
  4261.     IF .REC_TYPE NEQ MSG_ACK
  4262.     THEN
  4263.  
  4264.         IF .REQ_CHK_TYPE GEQ CHK_1CHAR AND .REQ_CHK_TYPE LEQ CHK_CRC
  4265.         THEN
  4266.         INI_CHK_TYPE = .REQ_CHK_TYPE
  4267.         ELSE
  4268.         INI_CHK_TYPE = CHK_1CHAR
  4269.  
  4270.     ELSE
  4271.  
  4272.         IF .REQ_CHK_TYPE NEQ .CHKTYPE
  4273.         THEN
  4274.         INI_CHK_TYPE = CHK_1CHAR
  4275.         ELSE
  4276.         INI_CHK_TYPE = .REQ_CHK_TYPE
  4277.  
  4278.     END
  4279.     ELSE
  4280.     INI_CHK_TYPE = CHK_1CHAR;        ! Only single character checksum if not specified
  4281.  
  4282. !
  4283. ! Parse the repeat character
  4284. !
  4285.     REPT_CHR = (IF .REC_LENGTH GTR P_SI_REPEAT THEN CH$RCHAR (CH$PTR (REC_MSG,
  4286.         .RECV_PKT_MSG + P_SI_REPEAT, CHR_SIZE)) ELSE %C' ');   ! [108]
  4287. !                                       ! [108]
  4288. ! Parse the capas field, if present and if we enabled extended length  ! [108]
  4289. !                                       ! [108]
  4290.                                        ! [108]
  4291.     IF (.REC_LENGTH GTR P_SI_CAPAS) AND (ABS(.SND_PKT_SIZE) GTR 94)    ! [108]
  4292.     THEN                                   ! [108]
  4293.     BEGIN                                   ! [108]
  4294.                                        ! [108]
  4295.     LOCAL                                   ! [108]
  4296.         CAPAS_OFFSET;                           ! [108]
  4297.                                        ! [108]
  4298.     CAPAS_OFFSET = .RECV_PKT_MSG + P_SI_CAPAS;               ! [108]
  4299.  
  4300.     IF (UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, .CAPAS_OFFSET, CHR_SIZE))) AND 2) NEQ 0
  4301.     THEN                                   ! [108]
  4302.         BEGIN                               ! [108]
  4303.                                        ! [108]
  4304.         SEND_PKT_SIZE = 500;                       ! [108]
  4305.                                        ! [108]
  4306.         WHILE (.REC_LENGTH GTR .CAPAS_OFFSET-.RECV_PKT_MSG) AND    ! [108]
  4307.           ((UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, .CAPAS_OFFSET,  ! [108]
  4308.                         CHR_SIZE))) AND 1) EQL 1) DO   ! [108]
  4309.         BEGIN                               ! [108]
  4310.         CAPAS_OFFSET = .CAPAS_OFFSET + 1;               ! [108]
  4311.         END;                               ! [108]
  4312.         IF .REC_LENGTH GTR .CAPAS_OFFSET-.RECV_PKT_MSG+3           ! [108]
  4313.         THEN                               ! [108]
  4314.         SEND_PKT_SIZE = UNCHAR (CH$RCHAR (CH$PTR (REC_MSG,     ! [108]
  4315.                     .CAPAS_OFFSET+2, CHR_SIZE))) * 95 +
  4316.                 UNCHAR (CH$RCHAR (CH$PTR (REC_MSG,     ! [108]
  4317.                     .CAPAS_OFFSET+3, CHR_SIZE)));  ! [108]
  4318.         IF .SEND_PKT_SIZE GTR MAX_MSG - 2                   ! [108]
  4319.         THEN                               ! [108]
  4320.         SEND_PKT_SIZE = MAX_MSG - 2;                   ! [108]
  4321.         IF .SEND_PKT_SIZE GTR ABS(.SND_PKT_SIZE)               ! [108]
  4322.         THEN                               ! [108]
  4323.         SEND_PKT_SIZE = ABS(.SND_PKT_SIZE);               ! [108]
  4324.         END;                               ! [108]
  4325.     END;                                   ! [108]
  4326. !
  4327. ! Check for a valid quoting character.  If it is not valid, then we have
  4328. ! a protocol error
  4329. !
  4330.  
  4331.     IF NOT ((.SEND_QUOTE_CHR GEQ %O'41' AND .SEND_QUOTE_CHR LEQ %O'76') OR
  4332. (.SEND_QUOTE_CHR GEQ %O
  4333.     '140' AND .SEND_QUOTE_CHR LEQ %O'176'))
  4334.     THEN
  4335.     BEGIN
  4336.     KRM_ERROR (KER_PROTOERR);
  4337.     RETURN KER_PROTOERR;
  4338.     END;
  4339.  
  4340. !
  4341. ! Check for a valid 8 bit quoting and set the 8 bit quoting flag as needed
  4342. !
  4343.  
  4344.     IF ( NOT ((.SEND_8QUOTE_CHR GEQ %O'041' AND .SEND_8QUOTE_CHR LEQ %O'076') OR
  4345.  (.SEND_8QUOTE_CHR
  4346.     GEQ %O'140' AND .SEND_8QUOTE_CHR LEQ %O'176') OR (.SEND_8QUOTE_CHR EQL %C'N')
  4347.  OR (
  4348.     .SEND_8QUOTE_CHR EQL %C'Y'))) OR .SEND_8QUOTE_CHR EQL .SEND_QUOTE_CHR OR
  4349.  .SEND_8QUOTE_CHR
  4350.     EQL .RCV_QUOTE_CHR
  4351.     THEN
  4352.     BEGIN
  4353.     KRM_ERROR (KER_PROTOERR);
  4354.     RETURN KER_PROTOERR;
  4355.     END;
  4356.  
  4357.     IF .SEND_8QUOTE_CHR EQL %C'Y' THEN SEND_8QUOTE_CHR = .RECV_8QUOTE_CHR;
  4358.  
  4359.     IF .SEND_8QUOTE_CHR NEQ %C'N' AND .SEND_8QUOTE_CHR NEQ %C'Y'
  4360.     THEN
  4361.     FLAG_8QUOTE = TRUE
  4362.     ELSE
  4363.     FLAG_8QUOTE = FALSE;
  4364.  
  4365. !
  4366. ! Check the repeat character and set flags
  4367. !
  4368.  
  4369.     IF ( NOT ((.REPT_CHR GEQ %O'41' AND .REPT_CHR LEQ %O'76') OR (.REPT_CHR GEQ
  4370.  %O'140' AND
  4371.     .REPT_CHR LEQ %O'176')) OR .REPT_CHR EQL .SEND_QUOTE_CHR OR .REPT_CHR EQL
  4372.  .SEND_8QUOTE_CHR
  4373.     OR .REPT_CHR EQL .RCV_QUOTE_CHR) AND .REPT_CHR NEQ %C' '
  4374.     THEN
  4375.     BEGIN
  4376.     KRM_ERROR (KER_PROTOERR);
  4377.     RETURN KER_PROTOERR;
  4378.     END;
  4379.  
  4380.     IF .REPT_CHR NEQ %C' ' THEN FLAG_REPEAT = TRUE ELSE FLAG_REPEAT = FALSE;
  4381.  
  4382.     RETURN KER_NORMAL;
  4383.     END;                    ! End of PRS_SEND_INIT
  4384. %SBTTL 'SET_SEND_INIT'
  4385. ROUTINE SET_SEND_INIT : NOVALUE =
  4386.  
  4387. !++
  4388. ! FUNCTIONAL DESCRIPTION:
  4389. !
  4390. !    This routine will initialize the various parameters for the
  4391. !    MSG_SND_INIT message.
  4392. !
  4393. ! CALLING SEQUENCE:
  4394. !
  4395. !    SET_SEND_INIT();
  4396. !
  4397. ! INPUT PARAMETERS:
  4398. !
  4399. !    None.
  4400. !
  4401. ! IMPLICIT INPUTS:
  4402. !
  4403. !    None.
  4404. !
  4405. ! OUTPUT PARAMETERS:
  4406. !
  4407. !    None.
  4408. !
  4409. ! IMPLICIT OUTPUTS:
  4410. !
  4411. !    SND_MSG parameters set up.
  4412. !
  4413. ! COMPLETION CODES:
  4414. !
  4415. !    None.
  4416. !
  4417. ! SIDE EFFECTS:
  4418. !
  4419. !    None.
  4420. !
  4421. !--
  4422.  
  4423.     BEGIN
  4424.     CH$WCHAR (CHAR ((IF .RCV_PKT_SIZE LSS 94 THEN .RCV_PKT_SIZE ELSE 94)),
  4425.         CH$PTR (SND_MSG, PKT_MSG + P_SI_BUFSIZ, CHR_SIZE)); ! [108]
  4426.     CH$WCHAR (CHAR (.RCV_TIMEOUT), CH$PTR (SND_MSG, PKT_MSG + P_SI_TIMOUT,
  4427.  CHR_SIZE));
  4428.     CH$WCHAR (CHAR (.RCV_NPAD), CH$PTR (SND_MSG, PKT_MSG + P_SI_NPAD,
  4429.  CHR_SIZE));
  4430.     CH$WCHAR (CTL (.RCV_PADCHAR), CH$PTR (SND_MSG, PKT_MSG + P_SI_PAD,
  4431.  CHR_SIZE));
  4432.     CH$WCHAR (CHAR (.RCV_EOL), CH$PTR (SND_MSG, PKT_MSG + P_SI_EOL, CHR_SIZE));
  4433.     CH$WCHAR (.RCV_QUOTE_CHR, CH$PTR (SND_MSG, PKT_MSG + P_SI_QUOTE, CHR_SIZE));
  4434.     CH$WCHAR (.SEND_8QUOTE_CHR, CH$PTR (SND_MSG, PKT_MSG + P_SI_8QUOTE,
  4435.  CHR_SIZE));
  4436.     CH$WCHAR (.INI_CHK_TYPE, CH$PTR (SND_MSG, PKT_MSG + P_SI_CHKTYPE,
  4437.  CHR_SIZE));
  4438.     CH$WCHAR (.REPT_CHR, CH$PTR (SND_MSG, PKT_MSG + P_SI_REPEAT, CHR_SIZE));
  4439.     SEND_INIT_SIZE = P_SI_LENGTH;                       ! [108]
  4440.     IF .RCV_PKT_SIZE GTR 94                           ! [108]
  4441.     THEN                                   ! [108]
  4442.     BEGIN                                   ! [108]
  4443.     CH$WCHAR (CHAR (EXTLEN_CAPAS), CH$PTR (SND_MSG, PKT_MSG + P_SI_CAPAS,
  4444.  CHR_SIZE));
  4445.     CH$WCHAR (CHAR (0), CH$PTR (SND_MSG, PKT_MSG + P_SI_WINDO, CHR_SIZE));
  4446.     CH$WCHAR (CHAR (.RCV_PKT_SIZE/95), CH$PTR (SND_MSG, PKT_MSG + P_SI_MAXLX1,
  4447.  CHR_SIZE));
  4448.     CH$WCHAR (CHAR (.RCV_PKT_SIZE MOD 95), CH$PTR (SND_MSG, PKT_MSG + P_SI_MAXLX2,
  4449.  CHR_SIZE));
  4450.                                        ! [108]
  4451.     SEND_INIT_SIZE = P_SI_XLENGTH;                       ! [108]
  4452.     END;                                   ! [108]
  4453.  
  4454.     END;                    ! End of SET_SEND_INIT
  4455. %SBTTL 'SEND_PACKET'
  4456. ROUTINE SEND_PACKET (TYPE, LENGTH, MN) =
  4457.  
  4458. !++
  4459. ! FUNCTIONAL DESCRIPTION:
  4460. !
  4461. !    This routine will cause a packet to be sent over the line
  4462. !    that has been opened by OPEN_TERMINAL.
  4463. !
  4464. ! CALLING SEQUENCE:
  4465. !
  4466. !    SEND_PACKET(Type, Length);
  4467. !
  4468. ! INPUT PARAMETERS:
  4469. !
  4470. !    TYPE - Type of packet to send.
  4471. !
  4472. !    LENGTH - Length of the packet being sent.
  4473. ! [108]         Negative length means it's an extended length packet
  4474. !
  4475. ! IMPLICIT INPUTS:
  4476. !
  4477. !    None.
  4478. !
  4479. ! OUTPUT PARAMETERS:
  4480. !
  4481. !    None.
  4482. !
  4483. ! IMPLICIT OUTPUTS:
  4484. !
  4485. !    None.
  4486. !
  4487. ! COMPLETION CODES:
  4488. !
  4489. !    None.
  4490. !
  4491. ! SIDE EFFECTS:
  4492. !
  4493. !    None.
  4494. !
  4495. !--
  4496.  
  4497.     BEGIN
  4498.  
  4499.     LOCAL
  4500.     FILLER : VECTOR [CH$ALLOCATION (MAX_MSG, CHR_SIZE)],
  4501.     TOT_MSG_LEN,                ! Length of message including all characters
  4502.     CHKSUM,                    ! Checksum for the message we calculate
  4503.     POINTER;                ! Pointer to the information in the message
  4504.  
  4505. !
  4506. ! Do any filler processing that the remote KERMIT requires.
  4507. !
  4508.  
  4509.     IF .SEND_NPAD NEQ 0
  4510.     THEN
  4511.     BEGIN
  4512.     CH$FILL (.SEND_PADCHAR, MAX_MSG, CH$PTR (FILLER, 0, CHR_SIZE));
  4513. !
  4514. ! Update the send stats
  4515. !
  4516.     SMSG_TOTAL_CHARS = .SMSG_TOTAL_CHARS + .SEND_NPAD;
  4517. !
  4518. ! Send the fill
  4519. !
  4520.     DO_PARITY (FILLER, .SEND_NPAD + PKT_TOT_OVR_HEAD);
  4521.     SEND (FILLER, .SEND_NPAD + PKT_TOT_OVR_HEAD);
  4522.     END;
  4523.  
  4524. !
  4525. ! Store the header information into the message.
  4526. !
  4527.     CH$WCHAR (.TYPE, CH$PTR (SND_MSG, PKT_TYPE, CHR_SIZE));
  4528.     CH$WCHAR (.SND_SOH, CH$PTR (SND_MSG, PKT_MARK, CHR_SIZE));
  4529.     CH$WCHAR (CHAR (IF .MN LSS 0 THEN 0 ELSE .MN), CH$PTR (SND_MSG, PKT_SEQ,
  4530.  CHR_SIZE));
  4531.  
  4532.     IF .LENGTH LSS 0                               ! [108]
  4533.     THEN                                   ! [108]
  4534.     BEGIN                                   ! [108]
  4535.     TOT_MSG_LEN = PKT_OVR_HEAD + 3 - .LENGTH;               ! [108]
  4536.     CH$WCHAR (CHAR (0), CH$PTR (SND_MSG, PKT_COUNT, CHR_SIZE));    ! [108]
  4537.     CH$WCHAR (CHAR ((.TOT_MSG_LEN - PKT_HCHECK + 1 +           ! [108]
  4538.              (.BLK_CHK_TYPE - CHK_1CHAR)) / 95),           ! [108]
  4539.             CH$PTR (SND_MSG, PKT_COUNTX1, CHR_SIZE));      ! [108]
  4540.     CH$WCHAR (CHAR ((.TOT_MSG_LEN - PKT_HCHECK + 1 +           ! [108]
  4541.              (.BLK_CHK_TYPE - CHK_1CHAR)) MOD 95),           ! [108]
  4542.             CH$PTR (SND_MSG, PKT_COUNTX2, CHR_SIZE));      ! [108]
  4543.  
  4544.     POINTER = CH$PTR(SND_MSG, PKT_SEQ, CHR_SIZE);               ! [108]
  4545.     CHKSUM = CHAR (0) + CH$RCHAR_A (POINTER);               ! [108]
  4546.     CHKSUM = .CHKSUM + CH$RCHAR_A (POINTER);               ! [108]
  4547.     CHKSUM = .CHKSUM + CH$RCHAR_A (POINTER);               ! [108]
  4548.     CHKSUM = .CHKSUM + CH$RCHAR_A (POINTER);               ! [108]
  4549.  
  4550.     CH$WCHAR (CHAR ((.CHKSUM + ((.CHKSUM AND %O'300')/%O'100')) AND %O'77'),
  4551.             CH$PTR (SND_MSG, PKT_HCHECK, CHR_SIZE));       ! [108]
  4552.     END                                   ! [108]
  4553.     ELSE                                   ! [108]
  4554.     BEGIN                                   ! [108]
  4555.     TOT_MSG_LEN = PKT_OVR_HEAD + .LENGTH;                   ! [108]
  4556.     CH$WCHAR (CHAR (.TOT_MSG_LEN + (.BLK_CHK_TYPE - CHK_1CHAR)),   ! [108]
  4557.                 CH$PTR (SND_MSG, PKT_COUNT, CHR_SIZE));
  4558.     END;                                   ! [108]
  4559.  
  4560. !
  4561. ! Calculate the block check value
  4562. !
  4563.     POINTER = CH$PTR (SND_MSG, PKT_MARK + 1, CHR_SIZE);
  4564.     CHKSUM = CALC_BLOCK_CHECK (.POINTER, .TOT_MSG_LEN);               ! [108]
  4565. !
  4566. ! Store the checksum into the message
  4567. !
  4568.     POINTER = CH$PTR (SND_MSG, .TOT_MSG_LEN + 1, CHR_SIZE);           ! [108]
  4569.  
  4570.     CASE .BLK_CHK_TYPE FROM CHK_1CHAR TO CHK_CRC OF
  4571.     SET
  4572.  
  4573.     [CHK_1CHAR] :
  4574.         CH$WCHAR_A (CHAR (.CHKSUM), POINTER);
  4575.  
  4576.     [CHK_2CHAR] :
  4577.         BEGIN
  4578.         CH$WCHAR_A (CHAR (.CHKSUM<6, 6>), POINTER);
  4579.         CH$WCHAR_A (CHAR (.CHKSUM<0, 6>), POINTER);
  4580.         TOT_MSG_LEN = .TOT_MSG_LEN + 1;
  4581.         END;
  4582.  
  4583.     [CHK_CRC] :
  4584.         BEGIN
  4585.         CH$WCHAR_A (CHAR (.CHKSUM<12, 4>), POINTER);
  4586.         CH$WCHAR_A (CHAR (.CHKSUM<6, 6>), POINTER);
  4587.         CH$WCHAR_A (CHAR (.CHKSUM<0, 6>), POINTER);
  4588.         TOT_MSG_LEN = .TOT_MSG_LEN + 2;
  4589.         END;
  4590.     TES;
  4591.  
  4592. !
  4593. ! Store in the end of line character
  4594. !
  4595.     CH$WCHAR_A (.SEND_EOL, POINTER);
  4596. !
  4597. ! If we are debugging then type out the message we are sending.
  4598. !
  4599.     DBG_SEND (SND_MSG, (.TOT_MSG_LEN + PKT_TOT_OVR_HEAD - PKT_OVR_HEAD));
  4600. !
  4601. ! Update the stats for total characters and the data characters
  4602. !
  4603.     SMSG_TOTAL_CHARS = .SMSG_TOTAL_CHARS + .TOT_MSG_LEN + PKT_TOT_OVR_HEAD -
  4604.  PKT_OVR_HEAD;
  4605. ! Make data characters really be that, not just characters in data field
  4606. !    SMSG_DATA_CHARS = .SMSG_DATA_CHARS + .LENGTH;
  4607.  
  4608.     IF .TYPE EQL MSG_NAK
  4609.     THEN
  4610.     BEGIN
  4611.     SMSG_NAKS = .SMSG_NAKS + 1;
  4612.     XFR_STATUS (%C'S', %C'N');
  4613.     END
  4614.     ELSE
  4615.     BEGIN
  4616.     SMSG_COUNT = .SMSG_COUNT + 1;
  4617.     XFR_STATUS (%C'S', %C'P');
  4618.     END;
  4619.  
  4620. !
  4621. ! Check if we are in IBM mode and need to wait for an XON first
  4622. ! We will not wait if this is a packet which might be going out
  4623. ! without previous traffic (generic commands, init packets).
  4624.  
  4625.     IF (.IBM_CHAR GEQ 0)             ! If handshaking on
  4626.     THEN
  4627.     IF NOT IBM_WAIT () THEN RETURN KER_ABORTED;
  4628.  
  4629. !
  4630. ! Now call the O/S routine to send the message out to the remote KERMIT
  4631. !
  4632.     DO_PARITY (SND_MSG, .TOT_MSG_LEN + PKT_TOT_OVR_HEAD - PKT_OVR_HEAD);
  4633.     RETURN SEND (SND_MSG, .TOT_MSG_LEN + PKT_TOT_OVR_HEAD - PKT_OVR_HEAD);
  4634.     END;                    ! End of SEND_PACKET
  4635. %SBTTL 'REC_MESSAGE - Receive a message'
  4636. ROUTINE REC_MESSAGE (CHK_ROUTINE) =
  4637.  
  4638. !++
  4639. ! FUNCTIONAL DESCRIPTION:
  4640. !
  4641. !    This routine will handle the retry processing for the various
  4642. !    messages that can be received.
  4643. !
  4644. ! CALLING SEQUENCE:
  4645. !
  4646. ! INPUT PARAMETERS:
  4647. !
  4648. !    None.
  4649. !
  4650. ! IMPLICIT INPUTS:
  4651. !
  4652. !    None.
  4653. !
  4654. ! OUTPUT PARAMETERS:
  4655. !
  4656. !    None.
  4657. !
  4658. ! IMPLICIT OUTPUTS:
  4659. !
  4660. !    None.
  4661. !
  4662. ! COMPLETION CODES:
  4663. !
  4664. !    KER_NORMAL - Normal return
  4665. !    KER_RETRIES - Too many retries
  4666. !    (What ever REC_PACKET returns).
  4667. !
  4668. ! SIDE EFFECTS:
  4669. !
  4670. !    None.
  4671. !
  4672. !--
  4673.  
  4674.     BEGIN
  4675.  
  4676.     LOCAL
  4677.     STATUS;                    ! Status returned by various routines
  4678.  
  4679.     RETURN
  4680.  
  4681.     WHILE TRUE DO
  4682.         BEGIN
  4683.  
  4684.         IF .NUM_RETRIES GTR .PKT_RETRIES
  4685.         THEN
  4686.         BEGIN
  4687.         KRM_ERROR (KER_RETRIES);    ! Report the error
  4688.         RETURN KER_RETRIES;
  4689.         END;
  4690.  
  4691.         NUM_RETRIES = .NUM_RETRIES + 1;
  4692.         STATUS = REC_PACKET ();
  4693. ![043] Don't abort on errors which might just be due to noise.
  4694.  
  4695.         IF NOT .STATUS AND .STATUS NEQ KER_CHKSUMERR AND .STATUS NEQ KER_TIMEOUT
  4696.  AND .STATUS NEQ
  4697.         KER_ZEROLENMSG
  4698.         THEN
  4699.         RETURN .STATUS;
  4700.  
  4701.         IF NOT .STATUS
  4702.         THEN
  4703.         SEND_PACKET (MSG_NAK, 0, .MSG_NUMBER)    ![024]
  4704.         ELSE
  4705.         BEGIN
  4706. ![021]
  4707. ![021] If the packet type is not acceptable by our caller, nak it so the
  4708. ![021] other end tries again, and abort the current operation.  This is so
  4709. ![021] we will return to server mode (if we are running that way) quickly
  4710. ![021] when the other Kermit has been aborted and then restarted, and should
  4711. ![021] also make restarting quick, since we will not need to wait for the
  4712. ![021] other Kermit to time this message out before retransmitting.
  4713. ![021]
  4714.  
  4715.         IF NOT (.CHK_ROUTINE) ()
  4716.         THEN
  4717.             BEGIN
  4718.             SEND_PACKET (MSG_NAK, 0, .REC_SEQ);
  4719.             RETURN FALSE;        ! Just indicate an error
  4720.             END
  4721.         ELSE
  4722.             EXITLOOP KER_NORMAL;
  4723.  
  4724.         END;
  4725.  
  4726.         END;
  4727.  
  4728.     END;                    ! End of REC_PARSE
  4729. %SBTTL 'REC_PACKET'
  4730. ROUTINE REC_PACKET =
  4731.  
  4732. !++
  4733. ! FUNCTIONAL DESCRIPTION:
  4734. !
  4735. !    This routine will do the oppoiste of SEND_PACKET.  It will wait
  4736. !    for the message to be read from the remote and then it will
  4737. !    check the message for validity.
  4738. !
  4739. ! CALLING SEQUENCE:
  4740. !
  4741. !    Flag = REC_PACKET();
  4742. !
  4743. ! INPUT PARAMETERS:
  4744. !
  4745. !    None.
  4746. !
  4747. ! IMPLICIT INPUTS:
  4748. !
  4749. !    None.
  4750. !
  4751. ! OUTPUT PARAMETERS:
  4752. !
  4753. !    None.
  4754. !
  4755. ! IMPLICIT OUTPUTS:
  4756. !
  4757. !    REC_MSG - Contains the message received.
  4758. !
  4759. ! COMPLETION CODES:
  4760. !
  4761. !    True - Packet receive ok.
  4762. !    False - Problem occured during the receiving of the packet.
  4763. !
  4764. ! SIDE EFFECTS:
  4765. !
  4766. !    None.
  4767. !
  4768. !--
  4769.  
  4770.     BEGIN
  4771.  
  4772.     BIND
  4773.     ATTEMPT_TEXT = UPLIT (%ASCIZ'Attempting to receive');
  4774.  
  4775.     LOCAL
  4776.     STATUS,                    ! Status returned by various routines
  4777.     MSG_LENGTH,
  4778.     ERR_POINTER,                ! Pointer to the error buffer
  4779.     POINTER,
  4780.     CHKSUM;                    ! Checksum of the message
  4781.  
  4782. !
  4783. ! Attempt to read the message from the remote.
  4784. !
  4785. !    DO
  4786. !    BEGIN
  4787.  
  4788.     IF .DEBUG_FLAG
  4789.     THEN
  4790.     BEGIN
  4791.  
  4792.     LOCAL
  4793.         OLD_RTN;
  4794.  
  4795.     OLD_RTN = TT_SET_OUTPUT (DBG_DUMP);
  4796.     TT_TEXT (ATTEMPT_TEXT);
  4797.     TT_CRLF ();
  4798.     TT_SET_OUTPUT (.OLD_RTN);
  4799.     END;
  4800.  
  4801. !
  4802. ! If status type out requested, do it once
  4803. !
  4804.  
  4805.     IF .TYP_STS_FLAG
  4806.     THEN
  4807.     BEGIN
  4808.     STS_OUTPUT ();
  4809.     TYP_STS_FLAG = FALSE;
  4810.     END;
  4811.  
  4812. !
  4813. ! Receive the message from the remote Kermit
  4814. !
  4815.     STATUS = RECEIVE (REC_MSG, MSG_LENGTH);
  4816. !
  4817. ! Check for timeouts
  4818. !
  4819.  
  4820.     IF .STATUS EQL KER_TIMEOUT THEN XFR_STATUS (%C'R', %C'T');
  4821.  
  4822. !
  4823. ! If it failed return the status to the upper level
  4824. !
  4825.  
  4826.     IF NOT .STATUS
  4827.     THEN
  4828.     BEGIN
  4829.  
  4830.     IF .STATUS NEQ KER_ABORTED AND .STATUS NEQ KER_TIMEOUT THEN KRM_ERROR
  4831. (.STATUS);
  4832.  
  4833.                         ! Report error
  4834.     RETURN .STATUS;
  4835.     END;
  4836.  
  4837. !
  4838. ! Determine if we got a good message
  4839. !
  4840.  
  4841.     IF .MSG_LENGTH LSS PKT_TOT_OVR_HEAD - 1
  4842.     THEN
  4843.     BEGIN
  4844.     RETURN KER_ZEROLENMSG;
  4845.     END;
  4846.  
  4847.     IF UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, PKT_COUNT, CHR_SIZE))) EQL 0 ! [108]
  4848.     THEN                                   ! [108]
  4849.     BEGIN                                   ! [108]
  4850.     IF .MSG_LENGTH LSS PKT_TOT_OVR_HEAD - 1 + 3               ! [108]
  4851.     THEN                                   ! [108]
  4852.         BEGIN                               ! [108]
  4853.         RETURN KER_ZEROLENMSG;                       ! [108]
  4854.         END;                               ! [108]
  4855.     END;                                   ! [108]
  4856. !
  4857. ! Update the stats on the total number of characters received.
  4858. !
  4859.     RMSG_TOTAL_CHARS = .RMSG_TOTAL_CHARS + .MSG_LENGTH;
  4860. !
  4861. ! Initialize the checksum and others
  4862. !
  4863.     REC_TYPE = CH$RCHAR (CH$PTR (REC_MSG, PKT_TYPE, CHR_SIZE));
  4864. !
  4865. ! Now break the message apart byte by byte.
  4866. !
  4867.     RECV_PKT_MSG = PKT_MSG;                           ! [108]
  4868.     REC_LENGTH = UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, PKT_COUNT, CHR_SIZE)));
  4869.     IF .REC_LENGTH EQL 0                           ! [108]
  4870.     THEN                                   ! [108]
  4871.     BEGIN                                   ! [108]
  4872.     REC_LENGTH = UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, PKT_COUNTX1, CHR_SIZE))) * 95 +
  4873.         UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, PKT_COUNTX2, CHR_SIZE))) +
  4874.                         PKT_HCHECK - 1;           ! [108]
  4875.     RECV_PKT_MSG = PKT_MSGX;                       ! [108]
  4876.     END;                                   ! [108]
  4877.  
  4878.     REC_SEQ = UNCHAR (CH$RCHAR (CH$PTR (REC_MSG, PKT_SEQ, CHR_SIZE)));
  4879. !
  4880. ! Typed the packet if we are debugging
  4881. !
  4882.     DBG_RECEIVE (REC_MSG);
  4883. !
  4884. ! Now compute the final checksum and make sure that it is identical
  4885. ! to what we received from the remote KERMIT
  4886. !
  4887.     POINTER = CH$PTR (REC_MSG, PKT_MARK + 1, CHR_SIZE);
  4888.     REC_LENGTH = .REC_LENGTH - (.BLK_CHK_TYPE - CHK_1CHAR);           ! [108]
  4889.     CHKSUM = CALC_BLOCK_CHECK (.POINTER, .REC_LENGTH);               ! [108]
  4890.     POINTER = CH$PTR (REC_MSG, .REC_LENGTH + 1, CHR_SIZE);           ! [108]
  4891.     REC_LENGTH = .REC_LENGTH - .RECV_PKT_MSG + 1;               ! [108]
  4892.     STATUS = KER_NORMAL;            ! Assume good checksum
  4893.  
  4894.     CASE .BLK_CHK_TYPE FROM CHK_1CHAR TO CHK_CRC OF
  4895.     SET
  4896.  
  4897.     [CHK_1CHAR] :
  4898.  
  4899.         IF .CHKSUM NEQ UNCHAR (CH$RCHAR_A (POINTER)) THEN STATUS = KER_CHKSUMERR;
  4900.  
  4901.     [CHK_2CHAR] :
  4902.  
  4903.         IF (.CHKSUM<6, 6> NEQ UNCHAR (CH$RCHAR_A (POINTER))) OR (.CHKSUM<0, 6> NEQ
  4904.  UNCHAR (
  4905.             CH$RCHAR_A (POINTER)))
  4906.         THEN
  4907.         STATUS = KER_CHKSUMERR;
  4908.  
  4909.     [CHK_CRC] :
  4910.  
  4911.         IF (.CHKSUM<12, 4> NEQ UNCHAR (CH$RCHAR_A (POINTER))) OR (.CHKSUM<6, 6> NEQ
  4912.  UNCHAR (
  4913.             CH$RCHAR_A (POINTER))) OR (.CHKSUM<0, 6> NEQ UNCHAR (CH$RCHAR_A
  4914. (POINTER)))
  4915.         THEN
  4916.         STATUS = KER_CHKSUMERR;
  4917.  
  4918.     TES;
  4919.  
  4920. !
  4921. ! If we have a bad checksum, check for the special cases when we might be out
  4922. ! of sync with the sender.  This can occur if the sender is retransmitting
  4923. ! a send-init (because our ACK got lost), and we have agreed on multi-char
  4924. ! checksums, or because the sender is a server who has aborted back to being
  4925. ! idle without telling us.
  4926. ! Note that in either case, we return back to using single character checksums
  4927. !
  4928.  
  4929.     IF .STATUS EQL KER_CHKSUMERR
  4930.     THEN
  4931.     BEGIN
  4932.  
  4933.     IF (.BLK_CHK_TYPE NEQ CHK_1CHAR AND .REC_SEQ EQL 0) AND (.REC_LENGTH LSS 1 -
  4934. (.BLK_CHK_TYPE
  4935.         - CHK_1CHAR) AND .REC_TYPE EQL MSG_NAK) OR (.REC_TYPE EQL MSG_SND_INIT)
  4936.     THEN
  4937.         BEGIN
  4938.  
  4939.         LOCAL
  4940.         SAVE_BLK_CHK_TYPE;
  4941.  
  4942.         SAVE_BLK_CHK_TYPE = .BLK_CHK_TYPE;    ! Remember what we are using
  4943.         BLK_CHK_TYPE = CHK_1CHAR;
  4944.         POINTER = CH$PTR (REC_MSG, PKT_MARK + 1, CHR_SIZE);
  4945.         CHKSUM = CALC_BLOCK_CHECK (.POINTER, .REC_LENGTH + .RECV_PKT_MSG - 1); !
  4946.  [108]
  4947.         POINTER = CH$PTR (REC_MSG, .REC_LENGTH + .RECV_PKT_MSG, CHR_SIZE); ! [108]
  4948.  
  4949.         IF .CHKSUM NEQ UNCHAR (CH$RCHAR_A (POINTER))
  4950.         THEN
  4951.         BEGIN
  4952.         BLK_CHK_TYPE = .SAVE_BLK_CHK_TYPE;
  4953.         RETURN KER_CHKSUMERR;
  4954.         END;
  4955.  
  4956.         END
  4957.     ELSE
  4958.         RETURN KER_CHKSUMERR;
  4959.  
  4960.     END;
  4961.  
  4962. !
  4963. ! Update the stats
  4964. !
  4965. !    RMSG_DATA_CHARS = .RMSG_DATA_CHARS + .REC_LENGTH;
  4966.  
  4967.     IF .REC_TYPE EQL MSG_NAK
  4968.     THEN
  4969.     BEGIN
  4970.     RMSG_NAKS = .RMSG_NAKS + 1;
  4971.     XFR_STATUS (%C'R', %C'N');
  4972.     END
  4973.     ELSE
  4974.     BEGIN
  4975.     RMSG_COUNT = .RMSG_COUNT + 1;
  4976.     XFR_STATUS (%C'R', %C'P');
  4977.     END;
  4978.  
  4979. !
  4980. ! Now check to see if we have an E type (Error) packet.
  4981. !
  4982.  
  4983.     IF .REC_TYPE NEQ MSG_ERROR THEN RETURN KER_NORMAL;
  4984.  
  4985. !
  4986. ! Here to process an error packet.  Call the user routine to output the
  4987. ! error message to the terminal.
  4988. !
  4989. !
  4990. ![026] Use decoding routine to fetch the error text
  4991. !
  4992.     CH$FILL (CHR_NUL, MAX_MSG + 1, CH$PTR (LAST_ERROR));
  4993.     SET_STRING (CH$PTR (LAST_ERROR), MAX_MSG, TRUE);
  4994.     BFR_EMPTY ();
  4995.     SET_STRING (0, 0, FALSE);
  4996. ![026]    ERR_POINTER = CH$PTR (LAST_ERROR);
  4997. ![026]    POINTER = CH$PTR (REC_MSG, PKT_MSG, CHR_SIZE);
  4998. ![026]
  4999. ![026]    INCR I FROM 1 TO .REC_LENGTH DO
  5000. ![026]    CH$WCHAR_A (CH$RCHAR_A (POINTER), ERR_POINTER);
  5001. ![026]
  5002. ![026]    CH$WCHAR (CHR_NUL, ERR_POINTER);
  5003.     TT_TEXT (LAST_ERROR);
  5004.     TT_CRLF ();
  5005.     RETURN KER_ERRMSG;
  5006.     END;                    ! End of REC_PACKET
  5007. %SBTTL 'CALC_BLOCK_CHECK'
  5008. ROUTINE CALC_BLOCK_CHECK (POINTER, LENGTH) =
  5009.  
  5010. !++
  5011. ! FUNCTIONAL DESCRIPTION:
  5012. !
  5013. !    This routine will calculate the proper value for the block check
  5014. !    for a given message.  The value it returns is dependant upon the
  5015. !    type of block check requested in BLK_CHK_TYPE.
  5016. !
  5017. ! CALLING SEQUENCE:
  5018. !
  5019. !    CHKSUM = CALC_BLOCK_CHECK (.POINTER, .LENGTH);
  5020. !
  5021. ! INPUT PARAMETERS:
  5022. !
  5023. !    POINTER - A character pointer to the first character to be
  5024. !        included in the block check.
  5025. !
  5026. !    LENGTH - The number of characters to be included.
  5027. !
  5028. ! IMPLICIT INPUTS:
  5029. !
  5030. !    BLK_CHK_TYPE - The type of block check to generate.
  5031. !
  5032. ! OUPTUT PARAMETERS:
  5033. !
  5034. !    The value is the block check.
  5035. !
  5036. ! IMPLICIT OUTPUTS:
  5037. !
  5038. !    None.
  5039. !
  5040. ! COMPLETION CODES:
  5041. !
  5042. !    None.
  5043. !
  5044. ! SIDE EFFECTS:
  5045. !
  5046. !    None.
  5047. !
  5048. !--
  5049.  
  5050.     BEGIN
  5051.  
  5052.     LOCAL
  5053.     CHAR_MASK,                ! Mask for stripping bits
  5054.     BLOCK_CHECK;                ! To build initial block check value
  5055.  
  5056.     BLOCK_CHECK = 0;                ! Start out at 0
  5057. !
  5058. ! Set mask for characters so that we calculate the block check correctly
  5059. !
  5060.     CHAR_MASK = (IF .PARITY_TYPE EQL PR_NONE THEN %O'377' ELSE %O'177');
  5061.  
  5062.     CASE .BLK_CHK_TYPE FROM CHK_1CHAR TO CHK_CRC OF
  5063.     SET
  5064.  
  5065.     [CHK_1CHAR, CHK_2CHAR] :
  5066.  
  5067.         INCR I FROM 1 TO .LENGTH DO
  5068.         BLOCK_CHECK = .BLOCK_CHECK + (CH$RCHAR_A (POINTER) AND .CHAR_MASK);
  5069.  
  5070.     [CHK_CRC] :
  5071.         BEGIN
  5072. !
  5073. ! Ensure that the calculation is done with correct type of characters
  5074. !
  5075.  
  5076.         LOCAL
  5077.         TMP_PTR;            ! Temp pointer for copying chars
  5078.  
  5079.         TMP_PTR = .POINTER;
  5080.  
  5081.         IF .PARITY_TYPE NEQ PR_NONE
  5082.         THEN
  5083.  
  5084.         INCR I FROM 1 TO .LENGTH DO
  5085.             CH$WCHAR_A ((CH$RCHAR (.TMP_PTR) AND %O'177'), TMP_PTR);
  5086.  
  5087.         BLOCK_CHECK = CRCCLC (.POINTER, .LENGTH);
  5088.         END;
  5089.     TES;
  5090.  
  5091.     IF .BLK_CHK_TYPE EQL CHK_1CHAR
  5092.     THEN
  5093.     BLOCK_CHECK = (.BLOCK_CHECK + ((.BLOCK_CHECK AND %O'300')/%O'100')) AND %O'77';
  5094.  
  5095.     RETURN .BLOCK_CHECK;            ! Return the correct value
  5096.     END;                    ! End of CALC_BLOCK_CHK
  5097. %SBTTL 'NORMALIZE_FILE - Put file name into normal form'
  5098. ROUTINE NORMALIZE_FILE (FILE_ADDRESS, FILE_LENGTH, NAME_LENGTH, TYPE_LENGTH) :
  5099.  NOVALUE =
  5100.  
  5101. !++
  5102. ! FUNCTIONAL DESCRIPTION:
  5103. !
  5104. !    This routine will ensure that a file specification is in normal
  5105. !    form.  It does this by replacing all non-alphanumeric characters
  5106. !    (except the first period) with "X".  It will also ensure that
  5107. !    the resulting specification (of form name.type) has only
  5108. !    a specified number of characters in the name portion and type portion.
  5109. !
  5110. ! CALLING SEQUENCE:
  5111. !
  5112. !    NORMALIZE_FILE (FILE_ADDRESS, FILE_LENGTH, NAME_LENGTH, TYPE_LENGTH);
  5113. !
  5114. ! INPUT PARAMETERS:
  5115. !
  5116. !    FILE_ADDRESS - Address of file specification string to be normalized
  5117. !
  5118. !    FILE_LENGTH - Length of file specification
  5119. !
  5120. !    NAME_LENGTH - Maximum length desired for "name" portion.
  5121. !
  5122. !    TYPE_LENGTH - Maximum length desired for "type" portion.
  5123. !
  5124. !    With both NAME_LENGTH and TYPE_LENGTH, a negative value indicates
  5125. !    unlimited lenght.
  5126. !
  5127. ! IMPLICIT INPUTS:
  5128. !
  5129. !    None.
  5130. !
  5131. ! OUPTUT PARAMETERS:
  5132. !
  5133. !    FILE_LENGTH - The length of the resulting file spec
  5134. !
  5135. !    NAME_LENGTH - The actual length of the resulting file name
  5136. !
  5137. !    TYPE_LENGTH - The actual length of the resulting file type
  5138. !
  5139. ! IMPLICIT OUTPUTS:
  5140. !
  5141. !    None.
  5142. !
  5143. ! COMPLETION CODES:
  5144. !
  5145. !    None.
  5146. !
  5147. ! SIDE EFFECTS:
  5148. !
  5149. !    None.
  5150. !
  5151. !--
  5152.  
  5153.     BEGIN
  5154.  
  5155.     LOCAL
  5156.     CH,                    ! Character being processed
  5157.     POINTER,                ! Pointer to file spec
  5158.     WRT_POINTER,                ! Pointer to write file spec
  5159.     WRT_SIZE,
  5160.     FIRST_PERIOD,                ! Flag we have seen a period
  5161.     IGNORE_BAD,                ! Flag we should ignore bad characters
  5162.     BAD_CHAR,                ! Flag this character was bad
  5163.     FILE_CTR,                ! Counter for overall length
  5164.     NAME_CTR,                ! Counter for name characters
  5165.     TYPE_CTR;                ! Counter for type characters
  5166.  
  5167.     FILE_CTR = 0;
  5168.     NAME_CTR = 0;
  5169.     TYPE_CTR = 0;
  5170.     WRT_SIZE = 0;
  5171.     FIRST_PERIOD = FALSE;            ! No periods yet
  5172.     POINTER = CH$PTR (.FILE_ADDRESS);        ! Set up pointer to file name
  5173.     WRT_POINTER = .POINTER;
  5174.  
  5175.     IF .NAME_LENGTH EQL 0 THEN FIRST_PERIOD = TRUE;    ! Pretend we did name
  5176.  already
  5177.  
  5178.     IGNORE_BAD = FALSE;
  5179.  
  5180.     IF .NAME_LENGTH GTR 0
  5181.     THEN
  5182.     BEGIN
  5183.  
  5184.     DECR I FROM ..FILE_LENGTH TO 0 DO
  5185.  
  5186.         IF CH$RCHAR_A (POINTER) EQL %C'.'
  5187.         THEN
  5188.         BEGIN
  5189.         IGNORE_BAD = TRUE;
  5190.         EXITLOOP;
  5191.         END;
  5192.  
  5193.     END;
  5194.  
  5195.     POINTER = .WRT_POINTER;
  5196.  
  5197.     WHILE .FILE_CTR LSS ..FILE_LENGTH DO
  5198.     BEGIN
  5199.     CH = CH$RCHAR_A (POINTER);        ! Get a character
  5200.     FILE_CTR = .FILE_CTR + 1;
  5201.  
  5202.     IF (.CH LSS %C'0' AND (.CH NEQ %C'.' OR .FIRST_PERIOD)) OR .CH GTR %C'z' OR
  5203. (.CH GTR %C'9'
  5204.         AND .CH LSS %C'A') OR (.CH GTR %C'Z' AND .CH LSS %C'a')
  5205.     THEN
  5206.         BEGIN
  5207.         BAD_CHAR = TRUE;
  5208.         CH = %C'X';
  5209.         END
  5210.     ELSE
  5211.         BEGIN
  5212.         BAD_CHAR = FALSE;
  5213.  
  5214.         IF .CH GEQ %C'a' THEN CH = .CH - (%C'a' - %C'A');
  5215.  
  5216.         END;
  5217.  
  5218.     IF .CH EQL %C'.'
  5219.     THEN
  5220.         BEGIN
  5221.         FIRST_PERIOD = TRUE;
  5222.         CH$WCHAR_A (.CH, WRT_POINTER);
  5223.         WRT_SIZE = .WRT_SIZE + 1;
  5224.         END
  5225.     ELSE
  5226.  
  5227.         IF NOT .BAD_CHAR OR NOT .IGNORE_BAD
  5228.         THEN
  5229.  
  5230.         IF NOT .FIRST_PERIOD
  5231.         THEN
  5232.             BEGIN
  5233.  
  5234.             IF .NAME_LENGTH LSS 0 OR .NAME_CTR LSS .NAME_LENGTH
  5235.             THEN
  5236.             BEGIN
  5237.             NAME_CTR = .NAME_CTR + 1;
  5238.             WRT_SIZE = .WRT_SIZE + 1;
  5239.             CH$WCHAR_A (.CH, WRT_POINTER);
  5240.             END;
  5241.  
  5242.             END
  5243.         ELSE
  5244.  
  5245.             IF .TYPE_LENGTH LSS 0 OR .TYPE_CTR LSS .TYPE_LENGTH
  5246.             THEN
  5247.             BEGIN
  5248.             TYPE_CTR = .TYPE_CTR + 1;
  5249.             WRT_SIZE = .WRT_SIZE + 1;
  5250.             CH$WCHAR_A (.CH, WRT_POINTER);
  5251.             END;
  5252.  
  5253.     END;
  5254.  
  5255.     .FILE_LENGTH = .WRT_SIZE;
  5256.     CH$WCHAR_A (CHR_NUL, WRT_POINTER);
  5257.     END;                    ! End of NORMALIZE_FILE
  5258. %SBTTL 'Buffer filling -- Main routine'
  5259. ROUTINE BFR_FILL (FIRST_FLAG) =
  5260.  
  5261. !++
  5262. ! FUNCTIONAL DESCRIPTION:
  5263. !
  5264. !    This routine will fill the buffer with data from the file.  It
  5265. !    will do all the quoting that is required.
  5266. !
  5267. ! CALLING SEQUENCE:
  5268. !
  5269. !    EOF_FLAG = BFR_FILL(.FIRST_FLAG);
  5270. !
  5271. ! INPUT PARAMETERS:
  5272. !
  5273. !    FIRST_FLAG - Flag whether first call for this file
  5274. !
  5275. ! IMPLICIT INPUTS:
  5276. !
  5277. !    None.
  5278. !
  5279. ! OUTPUT PARAMETERS:
  5280. !
  5281. !    True - Buffer filled may be at end of file.
  5282. !    False - At end of file.
  5283. !
  5284. ! IMPLICIT OUTPUTS:
  5285. !
  5286. !    Number of characters stored in the buffer.
  5287. !
  5288. ! COMPLETION CODES:
  5289. !
  5290. !    None.
  5291. !
  5292. ! SIDE EFFECTS:
  5293. !
  5294. !    None.
  5295. !
  5296. !--
  5297.  
  5298.     BEGIN
  5299.  
  5300.     LITERAL
  5301.     NO_CHAR = -1,                ! No character next
  5302.     EOF_CHAR = -2;                ! EOF seen
  5303.  
  5304.     LOCAL
  5305.     I,                    ! Temp loop index
  5306.     MAX_SIZE,                ! Maximum size of data
  5307.     POINTER;                ! Pointer into the message buffer
  5308.  
  5309.     OWN
  5310.     NEXT_CHR,                ! Saved character
  5311.     STATUS,                    ! Status value
  5312.     REPEAT_COUNT,                ! Number of times character repeated
  5313.     CHAR_8_BIT,                ! 8 bit character from file
  5314.     CHRS : VECTOR [5],            ! String needed to represent character
  5315.     CHR_IDX,                ! Index into CHRS
  5316.     OLD_CHAR_8_BIT,                ! Previous 8-bit character
  5317.     OLD_CHRS : VECTOR [5],            ! String for previous character
  5318.     OLD_CHR_IDX;                ! Index for previous character
  5319.  
  5320.     ROUTINE GET_QUOTED_CHAR =
  5321. !
  5322. ! This routine gets a character from the file and returns both
  5323. ! the character and the string needed to represent the character
  5324. ! if it needs quoting.
  5325. !
  5326.     BEGIN
  5327.  
  5328.     IF .NEXT_CHR GEQ 0
  5329.     THEN
  5330.         BEGIN
  5331.         CHAR_8_BIT = .NEXT_CHR;
  5332.         NEXT_CHR = NO_CHAR;
  5333.         STATUS = KER_NORMAL;
  5334.         END
  5335.     ELSE
  5336.  
  5337.         IF .NEXT_CHR EQL NO_CHAR
  5338.         THEN
  5339.         STATUS = (.GET_CHR_ROUTINE) (CHAR_8_BIT)
  5340.         ELSE
  5341.         STATUS = KER_EOF;
  5342.  
  5343.     IF .STATUS EQL KER_NORMAL
  5344.     THEN
  5345.         BEGIN
  5346. !
  5347. ! Determine if we should just quote the character
  5348. !    Either:
  5349. !        Character is a delete (177 octal)
  5350. !    or    Character is a control character (less than 40 octal)
  5351. !    or    Character is a quote character
  5352. !    or    Character is the repeat character and doing repeat compression
  5353. !    or    Character is an eight bit quote character and doing eight bit
  5354. !          quoting.
  5355. !
  5356.  
  5357.         IF ((.CHAR_8_BIT AND %O'177') LSS %C' ') OR ((.CHAR_8_BIT AND %O'177') EQL
  5358.  CHR_DEL) OR (
  5359.         (.CHAR_8_BIT AND %O'177') EQL .RCV_QUOTE_CHR) OR (.FLAG_REPEAT AND (
  5360. (.CHAR_8_BIT AND
  5361.         %O'177') EQL .REPT_CHR)) OR (.FLAG_8QUOTE AND ((.CHAR_8_BIT AND %O'177') EQL
  5362.         .SEND_8QUOTE_CHR))
  5363.         THEN
  5364.         BEGIN
  5365. !
  5366. ! If the character is a control character or delete we must do a CTL(Character)
  5367. ! so it is something that we can be sure we can send.
  5368. !
  5369.  
  5370.         IF ((.CHAR_8_BIT AND %O'177') LSS %C' ') OR ((.CHAR_8_BIT AND %O'177') EQL
  5371.  CHR_DEL)
  5372.         THEN
  5373.             CHRS [0] = CTL (.CHAR_8_BIT)
  5374.         ELSE
  5375.             CHRS [0] = .CHAR_8_BIT;
  5376.  
  5377.         CHR_IDX = 1;
  5378.         CHRS [1] = .RCV_QUOTE_CHR;    ![035] Use character we said we would send
  5379.         END
  5380.         ELSE
  5381.         BEGIN
  5382.         CHR_IDX = 0;
  5383.         CHRS [0] = .CHAR_8_BIT;
  5384.         END;
  5385.  
  5386.         END
  5387.     ELSE
  5388.  
  5389.         IF .STATUS NEQ KER_EOF THEN KRM_ERROR (.STATUS);    ! Report error
  5390.  
  5391.     RETURN .STATUS;
  5392.     END;
  5393.     ROUTINE GET_8_QUOTED_CHAR =
  5394. !
  5395. ! This routine will get the quoted representation of a character
  5396. ! (by calling GET_QUOTED_CHAR), and return the 8th-bit quoted
  5397. ! representation.
  5398. !
  5399.     BEGIN
  5400.  
  5401.     IF (STATUS = GET_QUOTED_CHAR ()) EQL KER_NORMAL
  5402.     THEN
  5403.         BEGIN
  5404. !
  5405. ! Determine if we must quote the eighth bit (parity bit on)
  5406. !
  5407.  
  5408.         IF (((.CHRS [0] AND %O'177') NEQ .CHRS [0]) AND .FLAG_8QUOTE)
  5409.         THEN
  5410.         BEGIN
  5411.         CHRS [0] = .CHRS [0] AND %O'177';
  5412.         CHR_IDX = .CHR_IDX + 1;
  5413.         CHRS [.CHR_IDX] = .SEND_8QUOTE_CHR;
  5414.         END;
  5415.  
  5416.         END;
  5417.  
  5418.     RETURN .STATUS;
  5419.     END;
  5420. !
  5421. ! Start of code for BFR_FILL
  5422. !
  5423. ! Initialize pointer and count
  5424. !
  5425.     SIZE = 0;
  5426.     IF .SEND_PKT_SIZE GTR 94                           ! [108]
  5427.     THEN                                   ! [108]
  5428.     BEGIN                                   ! [108]
  5429.     POINTER = CH$PTR (SND_MSG, PKT_MSGX, CHR_SIZE);               ! [108]
  5430.     MAX_SIZE = .SEND_PKT_SIZE - PKT_MSGX + 1 - (.BLK_CHK_TYPE - CHK_1CHAR);
  5431.     END                                   ! [108]
  5432.     ELSE                                   ! [108]
  5433.     BEGIN                                   ! [108]
  5434.     POINTER = CH$PTR (SND_MSG, PKT_MSG, CHR_SIZE);               ! [108]
  5435.     MAX_SIZE = .SEND_PKT_SIZE - PKT_MSG + 1 - (.BLK_CHK_TYPE - CHK_1CHAR);
  5436.         END;                                   ! [108]
  5437. !
  5438. ! If last call got an error or eof, return it now
  5439. !
  5440.  
  5441.     IF NOT .FIRST_FLAG AND (.STATUS NEQ KER_NORMAL) THEN RETURN .STATUS;
  5442.  
  5443. !
  5444. ! If first time for a file prime the pump with the first character.
  5445. !
  5446.  
  5447.     IF .FIRST_FLAG
  5448.     THEN
  5449.     BEGIN
  5450.     FIRST_FLAG = FALSE;
  5451.     NEXT_CHR = -1;                ! No backed up character
  5452.  
  5453.     IF .FLAG_8QUOTE THEN STATUS = GET_8_QUOTED_CHAR () ELSE STATUS =
  5454.  GET_QUOTED_CHAR ();
  5455.  
  5456.     IF .STATUS NEQ KER_NORMAL THEN RETURN .STATUS;
  5457.  
  5458.     OLD_CHAR_8_BIT = .CHAR_8_BIT;
  5459.  
  5460.     INCR OLD_CHR_IDX FROM 0 TO .CHR_IDX DO
  5461.         OLD_CHRS [.OLD_CHR_IDX] = .CHRS [.OLD_CHR_IDX];
  5462.  
  5463.     OLD_CHR_IDX = .CHR_IDX;
  5464.     REPEAT_COUNT = 0;            ! Character was not repeated yet
  5465.                         ! Will always be incremented
  5466.     END;
  5467.  
  5468. !
  5469. ! Otherwise, loop until we fill buffer
  5470. !
  5471.  
  5472.     WHILE .SIZE LSS .MAX_SIZE DO         ! Normal exit is via an EXITLOOP
  5473.     BEGIN
  5474. !
  5475. ! Check if we are doing run compression
  5476. !
  5477.  
  5478.     IF .FLAG_REPEAT
  5479.     THEN
  5480.         BEGIN
  5481. !
  5482. ! Here with previous character in OLD_xxx.  As long as we
  5483. ! are getting the same character, just count the run.
  5484. !
  5485.  
  5486.         WHILE (.CHAR_8_BIT EQL .OLD_CHAR_8_BIT) AND (.REPEAT_COUNT LSS 94) DO
  5487.         BEGIN
  5488.         REPEAT_COUNT = .REPEAT_COUNT + 1;
  5489.  
  5490.         IF .FLAG_8QUOTE THEN STATUS = GET_8_QUOTED_CHAR () ELSE STATUS =
  5491.  GET_QUOTED_CHAR ();
  5492.  
  5493.         IF .STATUS NEQ KER_NORMAL
  5494.         THEN
  5495.  
  5496.             IF .STATUS NEQ KER_EOF
  5497.             THEN
  5498.             CHAR_8_BIT = NO_CHAR
  5499.             ELSE
  5500.             BEGIN
  5501.             CHAR_8_BIT = EOF_CHAR;
  5502.             CHR_IDX = -1;
  5503.             END;
  5504.  
  5505.         END;
  5506.  
  5507.         IF .OLD_CHR_IDX + 1 + 2 LSS ((.OLD_CHR_IDX + 1)*.REPEAT_COUNT)
  5508.         THEN
  5509.         BEGIN
  5510.  
  5511.         IF .SIZE + .OLD_CHR_IDX + 1 + 2 GTR .MAX_SIZE
  5512.         THEN
  5513.             BEGIN
  5514.  
  5515.             IF .CHAR_8_BIT EQL .OLD_CHAR_8_BIT
  5516.             THEN
  5517.             BEGIN
  5518.             NEXT_CHR = .CHAR_8_BIT;
  5519.             REPEAT_COUNT = .REPEAT_COUNT - 1;
  5520.             END;
  5521.  
  5522.             IF .CHAR_8_BIT EQL EOF_CHAR
  5523.             THEN
  5524.             BEGIN
  5525.             NEXT_CHR = EOF_CHAR;    ! Remember EOF for next time
  5526.             STATUS = KER_NORMAL;    ! And give good return now
  5527.             END;
  5528.  
  5529.             EXITLOOP;
  5530.             END;
  5531.  
  5532.         OLD_CHRS [.OLD_CHR_IDX + 1] = CHAR (.REPEAT_COUNT);
  5533.         OLD_CHRS [.OLD_CHR_IDX + 2] = .REPT_CHR;
  5534.         OLD_CHR_IDX = .OLD_CHR_IDX + 2;
  5535. !
  5536. ! Count the number of file characters this represents
  5537. !
  5538.         SMSG_DATA_CHARS = .SMSG_DATA_CHARS + .REPEAT_COUNT - 1;
  5539.         FILE_CHARS = .FILE_CHARS + .REPEAT_COUNT - 1;
  5540.         REPEAT_COUNT = 1;        ! Only one time for this string
  5541.         END;
  5542.  
  5543. !
  5544. ! If we don't have enough room for this character, wait till next
  5545. ! time.
  5546. !
  5547.  
  5548.         IF .SIZE + (.OLD_CHR_IDX + 1)*.REPEAT_COUNT GTR .MAX_SIZE
  5549.         THEN
  5550.         BEGIN
  5551. ! If the next character is the same, the count will get incremented
  5552. ! next time we enter, so back it off now.
  5553.  
  5554.         IF .CHAR_8_BIT EQL .OLD_CHAR_8_BIT
  5555.         THEN
  5556.             BEGIN
  5557.             NEXT_CHR = .CHAR_8_BIT;
  5558.             REPEAT_COUNT = .REPEAT_COUNT - 1;
  5559.             END;
  5560. !
  5561. ! If this is the last character of the file,
  5562. ! remember that for next time, but give good return now.
  5563. !
  5564.         IF .CHAR_8_BIT EQL EOF_CHAR
  5565.         THEN
  5566.             BEGIN
  5567.             NEXT_CHR = EOF_CHAR;
  5568.             STATUS = KER_NORMAL
  5569.             END;
  5570.  
  5571.         EXITLOOP;
  5572.         END;
  5573.  
  5574.         SMSG_DATA_CHARS = .SMSG_DATA_CHARS + .REPEAT_COUNT;
  5575.         FILE_CHARS = .FILE_CHARS + .REPEAT_COUNT;
  5576.  
  5577.         DECR REPEAT_COUNT FROM .REPEAT_COUNT TO 1 DO
  5578.  
  5579.         DECR I FROM .OLD_CHR_IDX TO 0 DO
  5580.             BEGIN
  5581.             CH$WCHAR_A (.OLD_CHRS [.I], POINTER);
  5582.             SIZE = .SIZE + 1;
  5583.             END;
  5584.  
  5585. !
  5586. ! If we had to defer EOF condition, reactivate it now.
  5587. !
  5588.         IF (.CHAR_8_BIT EQL EOF_CHAR) THEN STATUS = KER_EOF;
  5589. !
  5590. ! If we got an error (or EOF) then exit
  5591. !
  5592.  
  5593.         IF (.STATUS NEQ KER_NORMAL) THEN EXITLOOP;
  5594.  
  5595. !
  5596. ! Otherwise, copy the character which broke the run
  5597. !
  5598.         OLD_CHAR_8_BIT = .CHAR_8_BIT;
  5599.  
  5600.         INCR OLD_CHR_IDX FROM 0 TO .CHR_IDX DO
  5601.         OLD_CHRS [.OLD_CHR_IDX] = .CHRS [.OLD_CHR_IDX];
  5602.  
  5603.         OLD_CHR_IDX = .CHR_IDX;
  5604.         REPEAT_COUNT = 0;
  5605.         END
  5606.     ELSE
  5607. !
  5608. ! Here if we are not doing run compression.  We can do things much
  5609. ! easier.
  5610. !
  5611.         BEGIN
  5612.  
  5613.         IF (.SIZE + .CHR_IDX + 1) GTR .MAX_SIZE THEN EXITLOOP;
  5614.  
  5615.         SMSG_DATA_CHARS = .SMSG_DATA_CHARS + 1;
  5616.         FILE_CHARS = .FILE_CHARS + 1;
  5617.  
  5618.         DECR CHR_IDX FROM .CHR_IDX TO 0 DO
  5619.         BEGIN
  5620.         CH$WCHAR_A (.CHRS [.CHR_IDX], POINTER);
  5621.         SIZE = .SIZE + 1;
  5622.         END;
  5623.  
  5624.         IF .FLAG_8QUOTE THEN STATUS = GET_8_QUOTED_CHAR () ELSE STATUS =
  5625.  GET_QUOTED_CHAR ();
  5626.  
  5627.         IF (.STATUS NEQ KER_NORMAL) THEN EXITLOOP;
  5628.  
  5629.         END;
  5630.  
  5631.     END;
  5632.  
  5633. ! [108] Return negative size if we use extend packet format
  5634.  
  5635.     IF .SEND_PKT_SIZE GTR 94                           ! [108]
  5636.     THEN                                   ! [108]
  5637.     SIZE = -.SIZE;                               ! [108]
  5638.  
  5639. !
  5640. ! Determine if we really stored anything into the buffer.
  5641. !
  5642.  
  5643.     IF .SIZE NEQ 0 THEN RETURN KER_NORMAL ELSE RETURN .STATUS;
  5644.  
  5645.     END;                    ! End of BFR_FILL
  5646. %SBTTL 'BFR_EMPTY'
  5647. ROUTINE BFR_EMPTY =
  5648.  
  5649. !++
  5650. ! FUNCTIONAL DESCRIPTION:
  5651. !
  5652. !    This routine will empty the data from the REC_MSG message buffer
  5653. !    to the file.  It will process quoting characters.
  5654. !
  5655. ! CALLING SEQUENCE:
  5656. !
  5657. !    Flag = BFR_EMPTY();
  5658. !
  5659. ! INPUT PARAMETERS:
  5660. !
  5661. !    None.
  5662. !
  5663. ! IMPLICIT INPUTS:
  5664. !
  5665. !    None.
  5666. !
  5667. ! OUTPUT PARAMETERS:
  5668. !
  5669. !    True - No problems writing the file.
  5670. !    False - I/O error writing the file.
  5671. !
  5672. ! IMPLICIT OUTPUTS:
  5673. !
  5674. !    None.
  5675. !
  5676. ! COMPLETION CODES:
  5677. !
  5678. !    None.
  5679. !
  5680. ! SIDE EFFECTS:
  5681. !
  5682. !    None.
  5683. !
  5684. !--
  5685.  
  5686.     BEGIN
  5687.  
  5688.     LOCAL
  5689.     STATUS,                    ! Status returned by various routines
  5690.     REPEAT_COUNT,                ! Count of times to repeat character
  5691.     TURN_BIT_8_ON,                ! If eight bit quoting
  5692.     COUNTER,                ! Count of the characters left
  5693.     CHARACTER,                ! Character we are processing
  5694.     POINTER;                ! Pointer to the data
  5695.  
  5696.     POINTER = CH$PTR (REC_MSG, .RECV_PKT_MSG, CHR_SIZE);           ! [108]
  5697.     COUNTER = 0;
  5698.  
  5699.     WHILE (.COUNTER LSS .REC_LENGTH) DO
  5700.     BEGIN
  5701.     CHARACTER = CH$RCHAR_A (POINTER);
  5702.     COUNTER = .COUNTER + 1;
  5703. !
  5704. ! If the character is the repeat character (and we are doing repeat
  5705. ! compression), then get the count.
  5706. !
  5707.  
  5708.     IF ((.CHARACTER EQL .REPT_CHR) AND .FLAG_REPEAT)
  5709.     THEN
  5710.         BEGIN
  5711.         REPEAT_COUNT = UNCHAR (CH$RCHAR_A (POINTER) AND %O'177');
  5712.         CHARACTER = CH$RCHAR_A (POINTER);
  5713.         COUNTER = .COUNTER + 2;
  5714.         END
  5715.     ELSE
  5716.         REPEAT_COUNT = 1;
  5717.  
  5718. !
  5719. ! If the character is an eight bit quoting character and we are doing eight
  5720. ! bit quoting then turn on the flag so we turn the eighth bit on when we
  5721. ! get the real character.
  5722. !
  5723.  
  5724.     IF ((.CHARACTER EQL .SEND_8QUOTE_CHR) AND .FLAG_8QUOTE)
  5725.     THEN
  5726.         BEGIN
  5727.         TURN_BIT_8_ON = TRUE;
  5728.         COUNTER = .COUNTER + 1;
  5729.         CHARACTER = CH$RCHAR_A (POINTER);
  5730.         END
  5731.     ELSE
  5732.         TURN_BIT_8_ON = FALSE;
  5733.  
  5734. !
  5735. ! Now determine if we are quoting the character.  If so then we must eat
  5736. ! the quoting character and get the real character.
  5737. !
  5738.  
  5739.     IF .CHARACTER EQL .SEND_QUOTE_CHR
  5740.                     ![035] Is this character other Kermit sends as quote?
  5741.     THEN
  5742.         BEGIN
  5743.         CHARACTER = CH$RCHAR_A (POINTER);
  5744.         COUNTER = .COUNTER + 1;
  5745. !
  5746. ! Determine if we must undo what someone else has done to the character
  5747. !
  5748.  
  5749.         IF ((.CHARACTER AND %O'177') GEQ CTL (CHR_DEL)) AND ((.CHARACTER AND
  5750.  %O'177') LEQ CTL (
  5751.             CHR_DEL) + %O'40')
  5752.         THEN
  5753.         CHARACTER = CTL (.CHARACTER);
  5754.  
  5755.         END;
  5756.  
  5757. !
  5758. ! Turn on the eight bit if needed and then write the character out
  5759. !
  5760.  
  5761.     IF .TURN_BIT_8_ON THEN CHARACTER = .CHARACTER OR %O'200';
  5762.  
  5763.     RMSG_DATA_CHARS = .RMSG_DATA_CHARS + .REPEAT_COUNT;
  5764.     FILE_CHARS = .FILE_CHARS + .REPEAT_COUNT;
  5765.  
  5766.     DECR REPEAT_COUNT FROM .REPEAT_COUNT TO 1 DO
  5767.         BEGIN
  5768.         STATUS = (.PUT_CHR_ROUTINE) (.CHARACTER);
  5769.  
  5770.         IF NOT .STATUS THEN RETURN .STATUS;
  5771.  
  5772.         END;
  5773.  
  5774.     END;
  5775.  
  5776.     RETURN KER_NORMAL;
  5777.     END;                    ! End of BFR_EMPTY
  5778. %SBTTL 'Buffer filling and emptying subroutines'
  5779. ROUTINE SET_STRING (POINTER, LENGTH, START) =
  5780.  
  5781. !++
  5782. ! FUNCTIONAL DESCRIPTION:
  5783. !
  5784. !    This routine is used to set up the buffer filling and emptying
  5785. !    routines to use a string for input (or output) rather than
  5786. !    the file I/O routines.
  5787. !
  5788. ! CALLING SEQUENCE:
  5789. !
  5790. !    SET_STRING (.POINTER, .LENGTH, .START)
  5791. !
  5792. ! INPUT PARAMETERS:
  5793. !
  5794. !    POINTER - Character pointer to string
  5795. !
  5796. !    LENGTH - Number of characters in string
  5797. !
  5798. !    START - True to start string, false to end it
  5799. !
  5800. ! IMPLICIT INPUTS:
  5801. !
  5802. !    None.
  5803. !
  5804. ! OUPTUT PARAMETERS:
  5805. !
  5806. !    Returns 0 if START = TRUE, actual number of characters used
  5807. !    by last string if START = FALSE.
  5808. !
  5809. ! IMPLICIT OUTPUTS:
  5810. !
  5811. !    GET_CHR_ROUTINE and PUT_CHR_ROUTINE modifed so that string
  5812. !    routines are called instead of file I/O.
  5813. !
  5814. ! COMPLETION CODES:
  5815. !
  5816. !    None.
  5817. !
  5818. ! SIDE EFFECTS:
  5819. !
  5820. !    None.
  5821. !
  5822. !--
  5823.  
  5824.     BEGIN
  5825.  
  5826.     OWN
  5827.     STR_POINTER,                ! Pointer to string
  5828.     STR_LENGTH,                ! Length of string
  5829.     STR_ORG_LENGTH,                ! Original length of string
  5830.     OLD_GET_CHR,                ! Old get-char routine
  5831.     OLD_PUT_CHR;                ! Old put-char routine
  5832.  
  5833. !
  5834. ! Routine to get a character from the string
  5835. !
  5836.     ROUTINE GET_STRING (CHAR_ADDRESS) =
  5837.     BEGIN
  5838. !
  5839. ! If some characters are left, count down the length and get next character
  5840. ! Otherwise return and end of file indication.
  5841. !
  5842.  
  5843.     IF .STR_LENGTH GTR 0
  5844.     THEN
  5845.         BEGIN
  5846.         STR_LENGTH = .STR_LENGTH - 1;
  5847.         .CHAR_ADDRESS = CH$RCHAR_A (STR_POINTER);
  5848.         RETURN KER_NORMAL;
  5849.         END
  5850.     ELSE
  5851.         RETURN KER_EOF;
  5852.  
  5853.     END;                    ! End of GET_STRING
  5854.     ROUTINE PUT_STRING (CHAR_VALUE) =
  5855.     BEGIN
  5856. !
  5857. ! If there is enough room to store another character, store the character
  5858. ! and count it.  Otherwise return a line too long indication.
  5859. !
  5860.  
  5861.     IF .STR_LENGTH GTR 0
  5862.     THEN
  5863.         BEGIN
  5864.         STR_LENGTH = .STR_LENGTH - 1;
  5865.         CH$WCHAR_A (.CHAR_VALUE, STR_POINTER);
  5866.         RETURN KER_NORMAL;
  5867.         END
  5868.     ELSE
  5869.         RETURN KER_LINTOOLNG;
  5870.  
  5871.     END;                    ! End of PUT_STRING
  5872. !
  5873. ! If we have a request to start a string (input or output), save the old
  5874. ! routines and set up ours.  Also save the string pointer and length for
  5875. ! use by our get/put routines.
  5876. ! Otherwise this is a request to stop using the string routines, so reset
  5877. ! the old routines and return the actual number of characters read or
  5878. ! written
  5879. !
  5880.  
  5881.     IF .START
  5882.     THEN
  5883.     BEGIN
  5884.     STR_POINTER = .POINTER;
  5885.     STR_ORG_LENGTH = .LENGTH;
  5886.     STR_LENGTH = .LENGTH;
  5887.     OLD_GET_CHR = .GET_CHR_ROUTINE;
  5888.     OLD_PUT_CHR = .PUT_CHR_ROUTINE;
  5889.     GET_CHR_ROUTINE = GET_STRING;
  5890.     PUT_CHR_ROUTINE = PUT_STRING;
  5891.     RETURN 0;
  5892.     END
  5893.     ELSE
  5894.     BEGIN
  5895.     GET_CHR_ROUTINE = .OLD_GET_CHR;
  5896.     PUT_CHR_ROUTINE = .OLD_PUT_CHR;
  5897.     RETURN .STR_ORG_LENGTH - .STR_LENGTH;
  5898.     END;
  5899.  
  5900.     END;                    ! End of SET_STRING
  5901. %SBTTL 'Add parity routine'
  5902. ROUTINE DO_PARITY (MESSAGE, LENGTH) : NOVALUE =
  5903.  
  5904. !++
  5905. ! FUNCTIONAL DESCRIPTION:
  5906. !
  5907. !    This routine will add parity for a complete message that is to be
  5908. !    sent to the remote Kermit.
  5909. !
  5910. ! CALLING SEQUENCE:
  5911. !
  5912. !    DO_PARITY (Message_address, Message_length);
  5913. !
  5914. ! INPUT PARAMETERS:
  5915. !
  5916. !    Message_address - Address of the message to put parity on.
  5917. !    Message_length  - Lengtho of the message.
  5918. !
  5919. ! IMPLICIT INPUTS:
  5920. !
  5921. !    None.
  5922. !
  5923. ! OUTPUT PARAMETERS:
  5924. !
  5925. !    None.
  5926. !
  5927. ! IMPLICIT OUTPUTS:
  5928. !
  5929. !    None.
  5930. !
  5931. ! COMPLETION CODES:
  5932. !
  5933. !    None.
  5934. !
  5935. ! SIDE EFFECTS:
  5936. !
  5937. !    None.
  5938. !
  5939. !--
  5940.  
  5941.     BEGIN
  5942.  
  5943.     MAP
  5944.     MESSAGE : REF VECTOR [CH$ALLOCATION (MAX_MSG, CHR_SIZE)];
  5945.  
  5946.     LOCAL
  5947.     POINTER;                ! Point into the message
  5948.  
  5949.     IF NOT .DEV_PARITY_FLAG
  5950.     THEN
  5951.     BEGIN
  5952.     POINTER = CH$PTR (.MESSAGE,, CHR_SIZE);
  5953.  
  5954.     INCR I FROM 1 TO .LENGTH DO
  5955.         CH$WCHAR_A (GEN_PARITY (CH$RCHAR (.POINTER)), POINTER);
  5956.  
  5957.     END;
  5958.  
  5959.     END;                    ! End of DO_PARITY
  5960. %SBTTL 'Parity routine'
  5961.  
  5962. GLOBAL ROUTINE GEN_PARITY (CHARACTER) =
  5963.  
  5964. !++
  5965. ! FUNCTIONAL DESCRIPTION:
  5966. !
  5967. !    This routine will add parity to the character that is supplied.
  5968. !
  5969. ! CALLING SEQUENCE:
  5970. !
  5971. !    CHARACTER = GEN_PARITY(CHARACTER)
  5972. !
  5973. ! INPUT PARAMETERS:
  5974. !
  5975. !    CHARACTER - Produce the parity for this character depending on the
  5976. !        setting of the SET PARITY switch.
  5977. !
  5978. ! IMPLICIT INPUTS:
  5979. !
  5980. !    None.
  5981. !
  5982. ! OUTPUT PARAMETERS:
  5983. !
  5984. !    None.
  5985. !
  5986. ! IMPLICIT OUTPUTS:
  5987. !
  5988. !    None.
  5989. !
  5990. ! COMPLETION CODES:
  5991. !
  5992. !    None.
  5993. !
  5994. ! SIDE EFFECTS:
  5995. !
  5996. !    None.
  5997. !
  5998. !--
  5999.  
  6000.     BEGIN
  6001.  
  6002.     LOCAL
  6003.     TEMP_CHAR;
  6004.  
  6005.  
  6006.     CASE .PARITY_TYPE FROM PR_MIN TO PR_MAX OF
  6007.     SET
  6008.  
  6009.     [PR_NONE] :
  6010.         RETURN .CHARACTER;
  6011.  
  6012.     [PR_SPACE] :
  6013.         RETURN .CHARACTER AND %O'177';
  6014.  
  6015.     [PR_MARK] :
  6016.         RETURN .CHARACTER OR %O'200';
  6017.  
  6018.     [PR_ODD] :
  6019.         TEMP_CHAR = .CHARACTER AND %O'177' OR %O'200';
  6020.  
  6021.     [PR_EVEN] :
  6022.         TEMP_CHAR = .CHARACTER AND %O'177';
  6023.     TES;
  6024.  
  6025.     TEMP_CHAR = .TEMP_CHAR XOR (.TEMP_CHAR^-4);
  6026.     TEMP_CHAR = .TEMP_CHAR XOR (.TEMP_CHAR^-2);
  6027.  
  6028.     IF .TEMP_CHAR<0, 2> EQL %B'01' OR .TEMP_CHAR<0, 2> EQL %B'10'
  6029.     THEN
  6030.     RETURN .CHARACTER AND %O'177' OR %O'200'
  6031.     ELSE
  6032.     RETURN .CHARACTER AND %O'177';
  6033.  
  6034.     END;                    ! End of GEN_PARITY
  6035.  
  6036. %SBTTL 'Per transfer -- Initialization'
  6037. ROUTINE INIT_XFR : NOVALUE =
  6038.  
  6039. !++
  6040. ! FUNCTIONAL DESCRIPTION:
  6041. !
  6042. !    This routine will initialize the various locations that the
  6043. !    send and receive statistics are kept.
  6044. !
  6045. ! CALLING SEQUENCE:
  6046. !
  6047. !    INIT_XFR();
  6048. !
  6049. ! INPUT PARAMETERS:
  6050. !
  6051. !    None.
  6052. !
  6053. ! IMPLICIT INPUTS:
  6054. !
  6055. !    None.
  6056. !
  6057. ! OUTPUT PARAMETERS:
  6058. !
  6059. !    None.
  6060. !
  6061. ! IMPLICIT OUTPUTS:
  6062. !
  6063. !    None.
  6064. !
  6065. ! COMPLETION CODES:
  6066. !
  6067. !    None.
  6068. !
  6069. ! SIDE EFFECTS:
  6070. !
  6071. !    None.
  6072. !
  6073. !--
  6074.  
  6075.     BEGIN
  6076. !
  6077. ! Determine if we should do 8 bit quoting
  6078. !
  6079.  
  6080.     IF .PARITY_TYPE NEQ PR_NONE
  6081.     THEN
  6082.     BEGIN
  6083.     RECV_8QUOTE_CHR = .RCV_8QUOTE_CHR;
  6084.     END
  6085.     ELSE
  6086.     BEGIN
  6087.     RECV_8QUOTE_CHR = %C'Y';
  6088.     END;
  6089.  
  6090.     NUM_RETRIES = 0;
  6091.     SEND_8QUOTE_CHR = .RECV_8QUOTE_CHR;
  6092. !
  6093. ! Send parameters that may not get set before we need them for the first
  6094. ! time.
  6095. !
  6096.     SEND_PKT_SIZE = ABS (.SND_PKT_SIZE);
  6097.     SEND_NPAD = ABS (.SND_NPAD);
  6098.     SEND_PADCHAR = ABS (.SND_PADCHAR);
  6099.     SEND_TIMEOUT = ABS (.SND_TIMEOUT);
  6100.     SEND_EOL = ABS (.SND_EOL);
  6101.     SEND_QUOTE_CHR = ABS (.SND_QUOTE_CHR);
  6102. !
  6103. ! For initialization messages, we must use single character checksum
  6104. ! When the send-init/ack sequence has been done, we will switch to the
  6105. ! desired form
  6106. !
  6107.     BLK_CHK_TYPE = CHK_1CHAR;
  6108.     INI_CHK_TYPE = .CHKTYPE;            ! Send desired type
  6109. !
  6110. ! Set desired repeat character for use in we are doing send-init
  6111. ! Will be overwritten by other ends desired character if it sends
  6112. ! the send-init.
  6113. !
  6114.     REPT_CHR = .SET_REPT_CHR;
  6115. !
  6116. ! Assume packet assembly/disassembly uses characters from a file
  6117. !
  6118.     GET_CHR_ROUTINE = GET_FILE;            ! Initialize the get-a-char routine
  6119.     PUT_CHR_ROUTINE = PUT_FILE;            ! And the put-a-char
  6120.     TEXT_HEAD_FLAG = FALSE;            ! And assume we will get an File header
  6121.     NO_FILE_NEEDED = FALSE;            ! Assume will do file ops
  6122.     INIT_PKT_SENT = FALSE;            ! And no server-init sent
  6123. !
  6124. ! Always start with packet number 0
  6125. !
  6126.     MSG_NUMBER = 0;                ! Initial message number
  6127. !
  6128. ! Stats information
  6129. !
  6130.     SMSG_TOTAL_CHARS = 0;
  6131.     RMSG_TOTAL_CHARS = 0;
  6132.     SMSG_DATA_CHARS = 0;
  6133.     RMSG_DATA_CHARS = 0;
  6134.     SMSG_COUNT = 0;
  6135.     RMSG_COUNT = 0;
  6136.     RMSG_NAKS = 0;
  6137.     SMSG_NAKS = 0;
  6138.     XFR_TIME = SY_TIME ();
  6139.     END;                    ! End of INIT_XFR
  6140. %SBTTL 'Statistics -- Finish message transfer'
  6141. ROUTINE END_STATS : NOVALUE =
  6142.  
  6143. !++
  6144. ! FUNCTIONAL DESCRIPTION:
  6145. !
  6146. !    This routine will end the collection of the statistices.  It will
  6147. !    update the various overall statistic parameters.
  6148. !
  6149. ! CALLING SEQUENCE:
  6150. !
  6151. !    END_STATS ();
  6152. !
  6153. ! INPUT PARAMETERS:
  6154. !
  6155. !    None.
  6156. !
  6157. ! IMPLICIT INPUTS:
  6158. !
  6159. !    None.
  6160. !
  6161. ! OUTPUT PARAMETERS:
  6162. !
  6163. !    None.
  6164. !
  6165. ! IMPLICIT OUTPUTS:
  6166. !
  6167. !    None.
  6168. !
  6169. ! COMPLETION CODES:
  6170. !
  6171. !    None.
  6172. !
  6173. ! SIDE EFFECTS:
  6174. !
  6175. !    None.
  6176. !
  6177. !--
  6178.  
  6179.     BEGIN
  6180.     SND_COUNT = .SND_COUNT + .SMSG_COUNT;
  6181.     RCV_COUNT = .RCV_COUNT + .RMSG_COUNT;
  6182.     SND_TOTAL_CHARS = .SND_TOTAL_CHARS + .SMSG_TOTAL_CHARS;
  6183.     SND_DATA_CHARS = .SND_DATA_CHARS + .SMSG_DATA_CHARS;
  6184.     RCV_TOTAL_CHARS = .RCV_TOTAL_CHARS + .RMSG_TOTAL_CHARS;
  6185.     RCV_DATA_CHARS = .RCV_DATA_CHARS + .RMSG_DATA_CHARS;
  6186.     SND_NAKS = .SND_NAKS + .SMSG_NAKS;
  6187.     RCV_NAKS = .RCV_NAKS + .RMSG_NAKS;
  6188.     XFR_TIME = SY_TIME () - .XFR_TIME;
  6189.     TOTAL_TIME = .TOTAL_TIME + .XFR_TIME;
  6190.     END;                    ! End of END_STATS
  6191. %SBTTL 'Status type out -- STS_OUTPUT'
  6192. ROUTINE STS_OUTPUT : NOVALUE =
  6193.  
  6194. !++
  6195. ! FUNCTIONAL DESCRIPTION:
  6196. !
  6197. !    This routine will output the current status of a transfer.
  6198. !    This is used when the user types a ^A during a transfer.
  6199. !
  6200. ! CALLING SEQUENCE:
  6201. !
  6202. !    STS_OUTPUT ()
  6203. !
  6204. ! INPUT PARAMETERS:
  6205. !
  6206. !    None.
  6207. !
  6208. ! IMPLICIT INPUTS:
  6209. !
  6210. !    Statistics blocks, file names, etc.
  6211. !
  6212. ! OUPTUT PARAMETERS:
  6213. !
  6214. !    None.
  6215. !
  6216. ! IMPLICIT OUTPUTS:
  6217. !
  6218. !    None.
  6219. !
  6220. ! COMPLETION CODES:
  6221. !
  6222. !    None.
  6223. !
  6224. ! SIDE EFFECTS:
  6225. !
  6226. !    None.
  6227. !
  6228. !--
  6229.  
  6230.     BEGIN
  6231.     TT_CHAR (%C'[');                ! Start the message
  6232.  
  6233.     CASE .STATE FROM STATE_MIN TO STATE_MAX OF
  6234.     SET
  6235.  
  6236.     [STATE_ID, STATE_II] :
  6237.         TT_TEXT (UPLIT (%ASCIZ'Idle in server mode'));
  6238.  
  6239.     [STATE_S, STATE_SF] :
  6240.         BEGIN
  6241.         TT_TEXT (UPLIT (%ASCIZ'Initializing for sending file '));
  6242.         TT_TEXT (FILE_NAME);
  6243.         END;
  6244.  
  6245.     [STATE_SI] :
  6246.         TT_TEXT (UPLIT (%ASCIZ'Initializing for remote command'));
  6247.  
  6248.     [STATE_SG] :
  6249.         TT_TEXT (UPLIT (%ASCIZ'Waiting for response to remote command'));
  6250.  
  6251.     [STATE_SD] :
  6252.         BEGIN
  6253.         TT_NUMBER (.FILE_CHARS);
  6254.         TT_TEXT (UPLIT (%ASCIZ' characters sent for file '));
  6255.         TT_TEXT (FILE_NAME);
  6256.         END;
  6257.  
  6258.     [STATE_SZ] :
  6259.         BEGIN
  6260.         TT_TEXT (UPLIT (%ASCIZ'At end of file '));
  6261.         TT_TEXT (FILE_NAME);
  6262.         END;
  6263.  
  6264.     [STATE_SB] :
  6265.         TT_TEXT (UPLIT (%ASCIZ'Finishing transfer session'));
  6266.  
  6267.     [STATE_R] :
  6268.         TT_TEXT (UPLIT (%ASCIZ'Waiting for initialization'));
  6269.  
  6270.     [STATE_RF] :
  6271.         TT_TEXT (UPLIT (%ASCIZ'Waiting for next file or end of session'));
  6272.  
  6273.     [STATE_RD] :
  6274.         BEGIN
  6275.         TT_NUMBER (.FILE_CHARS);
  6276.         TT_TEXT (UPLIT (%ASCIZ' characters received for file '));
  6277.         TT_TEXT (FILE_NAME);
  6278.         END;
  6279.  
  6280.     [STATE_C] :
  6281.         TT_TEXT (UPLIT (%ASCIZ' Session complete'));
  6282.  
  6283.     [STATE_A] :
  6284.         TT_TEXT (UPLIT (%ASCIZ' Session aborted'));
  6285.  
  6286.     [INRANGE, OUTRANGE] :
  6287.         TT_TEXT (UPLIT (%ASCIZ' Unknown state'));
  6288.     TES;
  6289.  
  6290.     SELECTONE .STATE OF
  6291.     SET
  6292.  
  6293.     [STATE_S, STATE_SF, STATE_SD, STATE_SZ, STATE_SB] :
  6294.         BEGIN
  6295.  
  6296.         IF .RMSG_NAKS GTR 0
  6297.         THEN
  6298.         BEGIN
  6299.         TT_TEXT (UPLIT (%ASCIZ', '));
  6300.         TT_NUMBER (.RMSG_NAKS);
  6301.         TT_TEXT (UPLIT (%ASCIZ' NAKs received'));
  6302.         END;
  6303.  
  6304.         END;
  6305.  
  6306.     [STATE_R, STATE_RF, STATE_RD] :
  6307.         BEGIN
  6308.  
  6309.         IF .SMSG_NAKS GTR 0
  6310.         THEN
  6311.         BEGIN
  6312.         TT_TEXT (UPLIT (%ASCIZ', '));
  6313.         TT_NUMBER (.SMSG_NAKS);
  6314.         TT_TEXT (UPLIT (%ASCIZ' NAKs sent'));
  6315.         END;
  6316.  
  6317.         END;
  6318.     TES;
  6319.  
  6320.     TT_CHAR (%C']');                ! End the line
  6321.     TT_CRLF ();                    ! with a CRLF
  6322.     END;                    ! End of STS_OUTPUT
  6323. %SBTTL 'TYPE_CHAR - Type out a character'
  6324. ROUTINE TYPE_CHAR (CHARACTER) =
  6325.  
  6326. !++
  6327. ! FUNCTIONAL DESCRIPTION:
  6328. !
  6329. ! This routine is used as an alternate output routine for BFR_EMPTY.
  6330. ! It will type the character on the terminal, and always return a
  6331. ! true status.
  6332. !
  6333. ! CALLING SEQUENCE:
  6334. !
  6335. !    STATUS = TYPE_CHAR (.CHARACTER);
  6336. !
  6337. ! INPUT PARAMETERS:
  6338. !
  6339. !    CHARACTER - The character to type
  6340. !
  6341. ! IMPLICIT INPUTS:
  6342. !
  6343. !    None.
  6344. !
  6345. ! OUPTUT PARAMETERS:
  6346. !
  6347. !    None.
  6348. !
  6349. ! IMPLICIT OUTPUTS:
  6350. !
  6351. !    None.
  6352. !
  6353. ! COMPLETION CODES:
  6354. !
  6355. !    None.
  6356. !
  6357. ! SIDE EFFECTS:
  6358. !
  6359. !    None.
  6360. !
  6361. !--
  6362.  
  6363.     BEGIN
  6364.     TT_CHAR (.CHARACTER);            ! Type the character
  6365.     RETURN KER_NORMAL;                ! And return OK
  6366.     END;                    ! End of TYPE_CHAR
  6367. %SBTTL 'Debugging -- DBG_SEND'
  6368. ROUTINE DBG_SEND (ADDRESS, LENGTH) : NOVALUE =
  6369.  
  6370. !++
  6371. ! FUNCTIONAL DESCRIPTION:
  6372. !
  6373. !    This routine will output the message that is going to be sent
  6374. !    as part of the debugging information that is turned on in the
  6375. !    SET DEBUG command.
  6376. !
  6377. ! CALLING SEQUENCE:
  6378. !
  6379. !    DBG_SEND(MSG_ADDRESS, MSG_LENGTH);
  6380. !
  6381. ! INPUT PARAMETERS:
  6382. !
  6383. !    MSG_ADDRESS - Address of the message that is going to be sent
  6384. !        to the remote KERMIT.  The bytes are CHR_SIZE.
  6385. !    MSG_LENGTH - Length of the message.
  6386. !
  6387. ! IMPLICIT INPUTS:
  6388. !
  6389. !    None.
  6390. !
  6391. ! OUTPUT PARAMETERS:
  6392. !
  6393. !    None.
  6394. !
  6395. ! IMPLICIT OUTPUTS:
  6396. !
  6397. !    None.
  6398. !
  6399. ! COMPLETION CODES:
  6400. !
  6401. !    None.
  6402. !
  6403. ! SIDE EFFECTS:
  6404. !
  6405. !    None.
  6406. !
  6407. !--
  6408.  
  6409.     BEGIN
  6410.  
  6411.     BIND
  6412.     SEND_TEXT = UPLIT (%ASCIZ'Sending...');
  6413.  
  6414.     IF .DEBUG_FLAG
  6415.     THEN
  6416.     BEGIN
  6417.  
  6418.     LOCAL
  6419.         OLD_RTN;
  6420.  
  6421.     OLD_RTN = TT_SET_OUTPUT (DBG_DUMP);
  6422.     TT_TEXT (SEND_TEXT);
  6423.     DBG_MESSAGE (.ADDRESS, .LENGTH);
  6424.     TT_SET_OUTPUT (.OLD_RTN);
  6425.     END;
  6426.  
  6427.     END;                    ! End of DBG_SEND
  6428. %SBTTL 'Debugging -- DBG_RECEIVE'
  6429. ROUTINE DBG_RECEIVE (ADDRESS) : NOVALUE =
  6430.  
  6431. !++
  6432. ! FUNCTIONAL DESCRIPTION:
  6433. !
  6434. !    This routine will output the message that was received from
  6435. !    the remote KERMIT.  This routine is called only if the DEBUG_FLAG
  6436. !    is true.
  6437. !
  6438. ! CALLING SEQUENCE:
  6439. !
  6440. !    DBG_RECEIVE(MSG_ADDRESS);
  6441. !
  6442. ! INPUT PARAMETERS:
  6443. !
  6444. !    MSG_ADDRESS - Address of the message received by the remote KERMIT.
  6445. !
  6446. ! IMPLICIT INPUTS:
  6447. !
  6448. !    None.
  6449. !
  6450. ! OUTPUT PARAMETERS:
  6451. !
  6452. !    None.
  6453. !
  6454. ! IMPLICIT OUTPUTS:
  6455. !
  6456. !    None.
  6457. !
  6458. ! COMPLETION CODES:
  6459. !
  6460. !    None.
  6461. !
  6462. ! SIDE EFFECTS:
  6463. !
  6464. !    None.
  6465. !
  6466. !--
  6467.  
  6468.     BEGIN
  6469.  
  6470.     BIND
  6471.     RECEIVE_TEXT = UPLIT (%ASCIZ'Received...');
  6472.  
  6473.     IF .DEBUG_FLAG
  6474.     THEN
  6475.     BEGIN
  6476.  
  6477.     LOCAL
  6478.         OLD_RTN;
  6479.  
  6480.     OLD_RTN = TT_SET_OUTPUT (DBG_DUMP);
  6481.     TT_TEXT (RECEIVE_TEXT);
  6482.     DBG_MESSAGE (.ADDRESS, .REC_LENGTH);
  6483.     TT_SET_OUTPUT (.OLD_RTN);
  6484.     END;
  6485.  
  6486.     END;                    ! End of DBG_RECEIVE
  6487. %SBTTL 'Debugging -- DBG_MESSAGE'
  6488. ROUTINE DBG_MESSAGE (MSG_ADDRESS, MSG_LENGTH) : NOVALUE =
  6489.  
  6490. !++
  6491. ! FUNCTIONAL DESCRIPTION:
  6492. !
  6493. !    This routine will display a message that is either being sent
  6494. !    or received on the user's terminal.
  6495. !
  6496. ! CALLING SEQUENCE:
  6497. !
  6498. !    DBG_MESSAGE(MSG_ADDRESS, MSG_LENGTH);
  6499. !
  6500. ! INPUT PARAMETERS:
  6501. !
  6502. !    MSG_ADDRESS - Address of the message to be output
  6503. !    MSG_LENGTH - Length of the message to be output.
  6504. !
  6505. ! IMPLICIT INPUTS:
  6506. !
  6507. !    None.
  6508. !
  6509. ! OUTPUT PARAMETERS:
  6510. !
  6511. !    None.
  6512. !
  6513. ! IMPLICIT OUTPUTS:
  6514. !
  6515. !    None.
  6516. !
  6517. ! COMPLETION CODES:
  6518. !
  6519. !    None.
  6520. !
  6521. ! SIDE EFFECTS:
  6522. !
  6523. !    None.
  6524. !
  6525. !--
  6526.  
  6527.     BEGIN
  6528.  
  6529.     MAP
  6530.     MSG_ADDRESS : REF VECTOR [CH$ALLOCATION (MAX_MSG, CHR_SIZE)];    ! Point to the
  6531.  vector
  6532.  
  6533.     LOCAL
  6534.     OLD_RTN,                ! Old type out routine
  6535.     CHKSUM,                    ! Numeric value of block check
  6536.     TEMP_POINTER,                ! Temporary character pointer
  6537.     MSG_MSG,            ! [108]    ! Starting point for data
  6538.     MSG_LEN;
  6539.  
  6540. !
  6541. ! Message type text
  6542. !
  6543.  
  6544.     BIND
  6545.     DATA_TEXT = UPLIT (%ASCIZ' (Data)'),
  6546.     ACK_TEXT = UPLIT (%ASCIZ' (ACK)'),
  6547.     NAK_TEXT = UPLIT (%ASCIZ' (NAK)'),
  6548.     SND_INIT_TEXT = UPLIT (%ASCIZ' (Send init)'),
  6549.     BREAK_TEXT = UPLIT (%ASCIZ' (Break)'),
  6550.     TEXT_TEXT = UPLIT (%ASCIZ' (Text header)'),
  6551.     FILE_TEXT = UPLIT (%ASCIZ' (File header)'),
  6552.     EOF_TEXT = UPLIT (%ASCIZ' (EOF)'),
  6553.     ERROR_TEXT = UPLIT (%ASCIZ' (Error)'),
  6554.     RCV_INIT_TEXT = UPLIT (%ASCIZ' (Receive initiate)'),
  6555.     COMMAND_TEXT = UPLIT (%ASCIZ' (Command)'),
  6556.     KERMIT_TEXT = UPLIT (%ASCIZ' (Generic KERMIT command)');
  6557.  
  6558. !
  6559. ! Header information
  6560. !
  6561.  
  6562.     BIND
  6563.     MN_TEXT = UPLIT (%ASCIZ'Message number: '),
  6564.     LENGTH_TEXT = UPLIT (%ASCIZ'    Length: '),
  6565.     DEC_TEXT = UPLIT (%ASCIZ' (dec)'),
  6566.     MSG_TYP_TEXT = UPLIT (%ASCIZ'Message type: '),
  6567.     CHKSUM_TEXT = UPLIT (%ASCIZ'Checksum: '),
  6568.     CHKSUM_NUM_TEXT = UPLIT (%ASCIZ' = '),
  6569.     OPT_DATA_TEXT = UPLIT (%ASCIZ'Optional data: '),
  6570.     PRE_CHAR_TEXT = UPLIT (%ASCIZ' "');
  6571.  
  6572. !
  6573. ! Ensure that the type out will go to the debugging location
  6574. !
  6575.     OLD_RTN = TT_SET_OUTPUT (DBG_DUMP);
  6576. !
  6577. ! Preliminary calculations
  6578. !
  6579.     MSG_LEN = UNCHAR (CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_COUNT, CHR_SIZE)));
  6580.     MSG_MSG = PKT_MSG;                               ! [108]
  6581.     IF .MSG_LEN EQL 0                               ! [108]
  6582.     THEN                                   ! [108]
  6583.     BEGIN                                   ! [108]
  6584.     MSG_LEN = UNCHAR (CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_COUNTX1, CHR_SIZE))) * 95
  6585.  +
  6586.         UNCHAR (CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_COUNTX2, CHR_SIZE))) +
  6587.                         PKT_HCHECK - 1;           ! [108]
  6588.     MSG_MSG = PKT_MSGX;                           ! [108]
  6589.     END;                                   ! [108]
  6590.  
  6591. !
  6592. ! First output some header information for the packet.
  6593. !
  6594.     TT_CRLF ();
  6595.     TT_TEXT (MN_TEXT);
  6596.     TT_NUMBER (UNCHAR (CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_SEQ, CHR_SIZE))));
  6597.     TT_TEXT (DEC_TEXT);
  6598.     TT_TEXT (LENGTH_TEXT);
  6599.     TT_NUMBER (.MSG_LEN);
  6600.     TT_TEXT (DEC_TEXT);
  6601.     TT_CRLF ();
  6602. !
  6603. ! Now output the message type and dependent information
  6604. !
  6605.     TT_TEXT (MSG_TYP_TEXT);
  6606.     TT_CHAR (CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_TYPE, CHR_SIZE)));
  6607.  
  6608.     SELECTONE CH$RCHAR (CH$PTR (.MSG_ADDRESS, PKT_TYPE, CHR_SIZE)) OF
  6609.     SET
  6610.  
  6611.     [MSG_DATA] :
  6612.         TT_TEXT (DATA_TEXT);
  6613.  
  6614.     [MSG_ACK] :
  6615.         TT_TEXT (ACK_TEXT);
  6616.  
  6617.     [MSG_NAK] :
  6618.         TT_TEXT (NAK_TEXT);
  6619.  
  6620.     [MSG_SND_INIT] :
  6621.         TT_TEXT (SND_INIT_TEXT);
  6622.  
  6623.     [MSG_BREAK] :
  6624.         TT_TEXT (BREAK_TEXT);
  6625.  
  6626.     [MSG_FILE] :
  6627.         TT_TEXT (FILE_TEXT);
  6628.  
  6629.     [MSG_TEXT] :
  6630.         TT_TEXT (TEXT_TEXT);
  6631.  
  6632.     [MSG_EOF] :
  6633.         TT_TEXT (EOF_TEXT);
  6634.  
  6635.     [MSG_ERROR] :
  6636.         TT_TEXT (ERROR_TEXT);
  6637.  
  6638.     [MSG_GENERIC] :
  6639.         TT_TEXT (KERMIT_TEXT);
  6640.  
  6641.     [MSG_COMMAND] :
  6642.         TT_TEXT (COMMAND_TEXT);
  6643.     TES;
  6644.  
  6645.     TT_CRLF ();
  6646. !
  6647. ! Now output any of the optional data.
  6648. !
  6649.  
  6650.     IF .MSG_LEN - .MSG_MSG + 1 - (.BLK_CHK_TYPE - CHK_1CHAR) NEQ 0     ! [108]
  6651.     THEN
  6652.     BEGIN
  6653.     TT_TEXT (OPT_DATA_TEXT);
  6654.     TT_CRLF ();
  6655.     TEMP_POINTER = CH$PTR (.MSG_ADDRESS, .MSG_MSG, CHR_SIZE);      ! [108]
  6656.  
  6657.     INCR I FROM 1 TO .MSG_LEN - .MSG_MSG + 1 - (.BLK_CHK_TYPE - CHK_1CHAR) DO !
  6658.  [108]
  6659.         BEGIN
  6660.  
  6661.         IF (.I MOD 10) EQL 1
  6662.         THEN
  6663.         BEGIN
  6664.         TT_CRLF ();
  6665.         TT_CHAR (CHR_TAB);
  6666.         END;
  6667.  
  6668.         TT_TEXT (PRE_CHAR_TEXT);
  6669.         TT_CHAR (CH$RCHAR_A (TEMP_POINTER));
  6670.         TT_CHAR (%C'"');
  6671.         END;
  6672.  
  6673.     IF ((.MSG_LEN - .MSG_MSG + 1 - (.BLK_CHK_TYPE - CHK_1CHAR)) MOD 10) EQL 1 THEN
  6674.  TT_CRLF (); ! [108]
  6675.  
  6676.     TT_CRLF ();
  6677.     END;
  6678.  
  6679. !
  6680. ! Now output the checksum for the message that we received
  6681. !
  6682. ! This could be either 1 two or three characters.
  6683.     TT_TEXT (CHKSUM_TEXT);
  6684.     TEMP_POINTER = CH$PTR (.MSG_ADDRESS,
  6685.     .MSG_LEN + PKT_CHKSUM + 1 - (.BLK_CHK_TYPE - CHK_1CHAR), CHR_SIZE); ! [108]
  6686.  
  6687.     CASE .BLK_CHK_TYPE FROM CHK_1CHAR TO CHK_CRC OF
  6688.     SET
  6689.  
  6690.     [CHK_1CHAR] :
  6691.         BEGIN
  6692.         TT_TEXT (PRE_CHAR_TEXT);
  6693.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6694.         TT_CHAR (%C'"');
  6695.         CHKSUM = UNCHAR (CH$RCHAR (.TEMP_POINTER));
  6696.         END;
  6697.  
  6698.     [CHK_2CHAR] :
  6699.         BEGIN
  6700.         CHKSUM = 0;
  6701.         TT_TEXT (PRE_CHAR_TEXT);
  6702.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6703.         TT_CHAR (%C'"');
  6704.         CHKSUM<6, 6> = UNCHAR (CH$RCHAR_A (TEMP_POINTER));
  6705.         TT_TEXT (PRE_CHAR_TEXT);
  6706.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6707.         TT_CHAR (%C'"');
  6708.         CHKSUM<0, 6> = UNCHAR (CH$RCHAR (.TEMP_POINTER));
  6709.         END;
  6710.  
  6711.     [CHK_CRC] :
  6712.         BEGIN
  6713.         CHKSUM = 0;
  6714.         TT_TEXT (PRE_CHAR_TEXT);
  6715.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6716.         TT_CHAR (%C'"');
  6717.         CHKSUM<12, 4> = UNCHAR (CH$RCHAR_A (TEMP_POINTER));
  6718.         TT_TEXT (PRE_CHAR_TEXT);
  6719.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6720.         TT_CHAR (%C'"');
  6721.         CHKSUM<6, 6> = UNCHAR (CH$RCHAR_A (TEMP_POINTER));
  6722.         TT_TEXT (PRE_CHAR_TEXT);
  6723.         TT_CHAR (CH$RCHAR (.TEMP_POINTER));
  6724.         TT_CHAR (%C'"');
  6725.         CHKSUM<0, 6> = UNCHAR (CH$RCHAR (.TEMP_POINTER));
  6726.         END;
  6727.     TES;
  6728.  
  6729.     TT_TEXT (CHKSUM_NUM_TEXT);
  6730.     TT_NUMBER (.CHKSUM);
  6731.     TT_TEXT (DEC_TEXT);
  6732.     TT_CRLF ();
  6733.     TT_SET_OUTPUT (.OLD_RTN);            ! Reset output destination
  6734.     END;                    ! End of DBG_MESSAGE
  6735. %SBTTL 'End of KERMSG'
  6736. END
  6737.  
  6738. ELUDOM
  6739.