home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / b / vmsmsg.bli < prev    next >
Text File  |  2020-01-01  |  153KB  |  6,714 lines

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