home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / decpro300 / promsg.bli < prev    next >
Text File  |  2020-01-01  |  142KB  |  6,525 lines

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