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

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