home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / honeywellcp6a / hc6ker.pl6 < prev    next >
Text File  |  2020-01-01  |  173KB  |  5,338 lines

  1. /*
  2.  
  3. Program:  Lee Hallin (Honeywell Bull, Los Angeles Development Center) with
  4.           testing and suggestions from J. T. Anderson (Honeywell Bull, Los
  5.           Angeles Developement Center), and Mike Iglesias and others
  6.           (University California at Irvine).
  7.  
  8.           Many thanks to John Stewart of Carleton University, Tom
  9.           Erskine of CRC, Mike Iglesias of UC Irvine and Mike Schmidt
  10.           of Honeywell Bull, Canada, for their help and supplied code
  11.           for version 1.00.
  12. Language: PL-6
  13. Version:  1.00
  14. Date:     January, 1988
  15.  
  16. Please send any questions, bugs and/or suggestions to any of the following:
  17.  
  18. U.S. Mail:
  19.   Honeywell Bull
  20.   5250 West Century Blvd
  21.   Los Angeles, CA  90045
  22.   Attn: Lee Hallin
  23.  
  24. CP-6 Mail on the LADC support machine (aka L66A):
  25.   Lee Hallin
  26.  
  27. ARPANET Address:
  28.   Lee-Hallin%LADC@BCO-MULTICS.ARPA
  29.  
  30.  
  31. 13.1  Introduction
  32.  
  33. This version of Kermit is written in PL-6; a PL/1-like implementation language
  34. available on the Honeywell CP-6 operating system.  This Kermit contains all of
  35. the "basic" Kermit features and several optional/advanced features.  Some of
  36. the optional features are suggested in the Kermit User's Guide and/or Kermit
  37. Protocol Manual, while others where implemented to provide added flexibility
  38. on CP-6.  The following table briefly summarizes the capabilities of this
  39. version of Kermit.
  40.  
  41. Features this Kermit has or can do:
  42.   Transfers text files
  43.   Transfers binary files
  44.   Sends file groups (wildcarding)
  45.   File overwrite protection
  46.   Timeouts
  47.   8th-bit prefixing
  48.   Repeat count prefixing
  49.   Transaction logging
  50.   Debugging facility
  51.   Acts as a server
  52.   Talks to a server (limited)
  53.   Automatically reads default commands from a file
  54.   Read commands from a file
  55.   Help for each of the commands
  56.   Graceful handling of interrupted group transfers
  57.  
  58. Features not included in this version:
  59.   Advanced server commands
  60.   Extended block checks (2 and 3 byte checks)
  61.   Handling file attributes
  62.  
  63. */
  64. %EJECT;
  65. /*
  66.           The following changes were made to this version of KERMIT
  67.           to support file transfers through a comgroup rather than
  68.           the regular terminal mode.
  69.  
  70.           1. This version is minimum CP-6 C01, so the dcbs used with
  71.              M$EOM (TIMEOUT), M$TRMCTL (ORIG_TRMCTL, STRMCTL) and
  72.              M$TRMATTR (GTRMATTR) were changed from M$UC to F$PACKET_IN.
  73.  
  74.           2. Commands were added to the parse code to add two new options:
  75.              CG= comgroup_name, and STATION= station_name. Both these
  76.              options must be specified for the comgroup stuff to work.
  77.              This implies changes to three files: HC6KERMIT_PAR, the
  78.              partrge source file, HC6KERMIT_C61, the include file for both
  79.              partrge and PL6, and this source file.
  80.  
  81.           3. A bunch of code was added to support comgroup output, and,
  82.              although this required usually minimal changes to the code,
  83.              the way timeouts were handled had to modified slightly, since
  84.              comgroup reads only start to count the timeout after the first
  85.              character has been received. In this case, timeouts had to
  86.              be set both via M$EOM and also by EOFTIME.
  87.  
  88.           4. Code has to be added to give some feedback during comgroup
  89.              based transfers, but this hasn't been done yet.
  90.  
  91.           5. In order to support some communication with other programs,
  92.              some code was added to set the stepcc. This code is really
  93.              only useful if the KERMIT invocation only transfers one file.
  94.              The stepcc only reflects the last 'send' command (and the
  95.              last file sent if there was more than one). It sets the stepcc
  96.              as follows:
  97.  
  98.                   0: The last file sent made it fine (if there was any
  99.                      request).
  100.                   2: The last file started but didn't complete.
  101.                   3: The last file couldn't be found.
  102.  
  103.              The stepcc can't be guaranteed to be accurate if a wild-
  104.              carded send command was used.
  105.  
  106.  
  107.  
  108. Bug fixes:
  109.  
  110.              Fixed bug in Receive_Pack where inter-packet characters
  111.              were being considered as a nak; which caused Kermit to
  112.              go into convulsions, trying to get things straightened
  113.              out.
  114.  
  115.              Fixed bug in server mode: Packet numbers weren't being
  116.              reset after a Break or Abort in Receive mode.
  117.  
  118.              The generic commands Finish and Bye were responding with
  119.              the current seq number, instead of 0.
  120.  
  121.              The Bye command tries to do a bye on the local end, when
  122.              it's specified that it just does that to the remote end.
  123.  
  124.              Neither the Finish nor the Bye command go through the
  125.              parameter exchange, although there is no guarantee that
  126.              they aren't the first command ever issued. Oops, I've taken
  127.              this back out temporarily because it's not working too well.
  128.  
  129.              The Bye command (when received by the server) doesn't close
  130.              the dcbs and exit gracefully, it simply does a !BYE.
  131.              Of course, if you're debugging OVER a debug file, it doesn't
  132.              get closed properly, so no debugging info...
  133.              Fixed by closing F$DEBUG and M$LO before executing !BYE.
  134. */
  135. %EJECT;
  136.  
  137. KERMIT: PROC MAIN;
  138.  
  139. %EQU OS_VERSION = 'D00';                 /* This is B03, C00, C01, D00 or E00 */
  140. %INCLUDE B_ERRORS_C;
  141. %INCLUDE B$JIT;
  142. %INCLUDE CP_6;
  143.   %B$ALT;
  144.   %B$TCB;
  145.   %F$DCB;
  146. %INCLUDE CP_6_SUBS;
  147. /* CLUDE KERMIT_C61; */
  148. %INCLUDE KV_GLBCNS_E;
  149.   %KV_PRTTYP_E;                               /* PARITY values                */
  150. %INCLUDE XS_MACRO_C;
  151.   %XSA_PARAM (FPTN=XSA_PARAM);
  152.   %XSA_ENTRIES;
  153. %INCLUDE XU_FORMAT_C;
  154. %INCLUDE XU_MACRO_C;
  155. %INCLUDE XU_PERR_C;
  156. %IF OS_VERSION~='B03';
  157. %INCLUDE XU_SUBS_C;                           /* For NEVER_ECHO#              */
  158. %ENDIF;
  159. %INCLUDE XUH_MACRO_C;
  160.   %XUH_PARAM;
  161. %IF OS_VERSION='B03';
  162. %INCLUDE XU_WILDCARD_C;                       /* In B03 this is in .X         */
  163. %ELSE;
  164. %INCLUDE XUW_MACRO_C;                         /* In C00 this is in .:LIBRARY  */
  165. %ENDIF;
  166. %EJECT;
  167. %LIST;
  168. %INCLUDE HC6KERMIT_C61;
  169. %PLIST;
  170. %EJECT;
  171. /**/
  172. /* EQUs used to access the PCB */
  173. /**/
  174.  
  175. %EQU BLK1_NSUBLKS = %CHARTEXT('BLK1$->P_OUT.NSUBLKS');
  176. %EQU BLK1_SUBLK$  = %CHARTEXT('BLK1$->P_OUT.SUBLK$');
  177.  
  178. %EQU BLK2_NSUBLKS = %CHARTEXT('BLK2$->P_OUT.NSUBLKS');
  179. %EQU BLK2_SUBLK$  = %CHARTEXT('BLK2$->P_OUT.SUBLK$');
  180. %EQU BLK2_CODE    = %CHARTEXT('BLK2$->P_SYM.CODE');
  181. %EQU BLK2_COUNT   = %CHARTEXT('BLK2$->P_SYM.COUNT');
  182. %EQU BLK2_TEXT    = %CHARTEXT('SUBSTR(BLK2$->P_SYM.TEXT,0,BLK2$->P_SYM.COUNT)');
  183.  
  184. %EQU BLK3_NSUBLKS = %CHARTEXT('BLK3$->P_OUT.NSUBLKS');
  185. %EQU BLK3_SUBLK$  = %CHARTEXT('BLK3$->P_OUT.SUBLK$');
  186. %EQU BLK3_CODE    = %CHARTEXT('BLK3$->P_SYM.CODE');
  187. %EQU BLK3_CPOS    = %CHARTEXT('BLK3$->P_SYM.CPOS');
  188. %EQU BLK3_COUNT   = %CHARTEXT('BLK3$->P_SYM.COUNT');
  189. %EQU BLK3_TEXT    = %CHARTEXT('SUBSTR(BLK3$->P_SYM.TEXT,0,BLK3$->P_SYM.COUNT)');
  190.  
  191. %EQU BLK4_NSUBLKS = %CHARTEXT('BLK4$->P_OUT.NSUBLKS');
  192. %EQU BLK4_SUBLK$  = %CHARTEXT('BLK4$->P_OUT.SUBLK$');
  193. %EQU BLK4_CODE    = %CHARTEXT('BLK4$->P_SYM.CODE');
  194. %EQU BLK4_COUNT   = %CHARTEXT('BLK4$->P_SYM.COUNT');
  195. %EQU BLK4_TEXT    = %CHARTEXT('SUBSTR(BLK4$->P_SYM.TEXT,0,BLK4$->P_SYM.COUNT)');
  196.  
  197. %EQU BLK5_NSUBLKS = %CHARTEXT('BLK5$->P_OUT.NSUBLKS');
  198. %EQU BLK5_SUBLK$  = %CHARTEXT('BLK5$->P_OUT.SUBLK$');
  199. %EQU BLK5_CODE    = %CHARTEXT('BLK5$->P_SYM.CODE');
  200. %EQU BLK5_COUNT   = %CHARTEXT('BLK5$->P_SYM.COUNT');
  201. %EQU BLK5_TEXT    = %CHARTEXT('SUBSTR(BLK5$->P_SYM.TEXT,0,BLK5$->P_SYM.COUNT)');
  202.  
  203. %EQU MONERR       = %CHARTEXT('B$TCB$->B$TCB.ALT$->B$ALT.ERR');
  204. %EQU ERRDCB       = %CHARTEXT('B$TCB$->B$TCB.ALT$->B$ALT.DCB#');
  205. %EJECT;
  206. /**/
  207. /* KERMIT type and state EQUs */
  208. /**/
  209.  
  210. %EQU A_ABORT                 = 'A';
  211. %EQU B_BREAK                 = 'B';
  212. %EQU C_COMPLETE              = 'C';
  213. %EQU D_DATA                  = 'D';
  214. %EQU E_ERROR                 = 'E';
  215. %EQU F_FILE                  = 'F';
  216. %EQU G_GENERIC               = 'G';
  217. %EQU I_INIT                  = 'I';
  218. %EQU K_KERMIT                = 'K';
  219. %EQU N_NAK                   = 'N';
  220. %EQU R_RINIT                 = 'R';
  221. %EQU S_SINIT                 = 'S';
  222. %EQU T_RESERVED              = 'T';
  223. %EQU Y_ACK                   = 'Y';
  224. %EQU Z_EOF                   = 'Z';
  225.  
  226. /**/
  227. /* KERMIT subcommand EQUs */
  228. /**/
  229.  
  230. %EQU C_CWD                   = 'C';
  231. %EQU D_DIRECTORY             = 'D';
  232. %EQU E_ERASE                 = 'E';
  233. %EQU F_FINISH                = 'F';
  234. %EQU H_HELP                  = 'H';
  235. %EQU I_LOGIN                 = 'I';
  236. %EQU J_JOURNAL               = 'J';
  237. %EQU K_COPY                  = 'K';
  238. %EQU L_BYE                   = 'L';
  239. %EQU M_SHORT_MESSAGE         = 'M';
  240. %EQU P_PROG_INVOCATION       = 'P';
  241. %EQU Q_SERVER_STAT_QUERY     = 'Q';
  242. %EQU R_RENAME                = 'R';
  243. %EQU T_TYPE                  = 'T';
  244. %EQU V_VARIABLE_SET_QUERY    = 'V';
  245. %EQU W_WHOS_LOGGED_IN        = 'W';
  246.  
  247. %EQU TAB                     = BINASC(9);
  248. %EQU LF                      = BINASC(10);
  249. %EQU CR                      = BINASC(13);
  250. %EQU SUB                     = BINASC(26);
  251. %EQU DEL                     = BINASC(127);
  252.  
  253. /**/
  254. /* EQUs for LOG file keys (fractional portion of EDIT key) */
  255. /**/
  256.  
  257. %EQU LOG_HEADER#             = 000;
  258. %EQU LOG_STRT_SEND#          = 101;
  259. %EQU LOG_END_SEND#           = 102;
  260. %EQU LOG_STRT_RECEIVE#       = 103;
  261. %EQU LOG_END_RECEIVE#        = 104;
  262. %EQU LOG_MAX_PACKET_SIZES#   = 200;
  263. %EQU LOG_NUM_DATA_PACKETS#   = 300;
  264. %EQU LOG_NUM_BYTES_SENT#     = 400;
  265. %EQU LOG_NUM_BYTES_RCVD#     = 500;
  266. %EQU LOG_ELAPSED_TIME#       = 600;
  267. %EQU LOG_ERRMSG#             = 700;
  268.  
  269. /**/
  270. /* Miscellaneous EQUs */
  271. /**/
  272. %EQU MAX_EXTENSIONS#         = 30;
  273.  
  274. %EQU NOTHING#                = 0;
  275. %EQU BUILD_SEQUENCE#         = 1;
  276. %EQU PUT_CHAR_IN_PACKET#     = 2;
  277. %EQU STUFF_CHAR_IN_PACKET#   = 3;
  278. %EJECT;
  279. /**/
  280. /* Miscellaneous FPTs */
  281. /**/
  282.  
  283. %FPT_INT     (FPTN                     = BREAK_CNTRL,
  284.               UENTRY=KERMIT$BREAK );
  285.  
  286. %FPT_EXIT    (FPTN                     = SET_STEPCC,
  287.               STEPCC=OK );
  288.  
  289. %VLP_ERRCODE (FPTN                     = ERRCODE );
  290.  
  291. %FPT_WRITE   (FPTN                     = FPT_WRITE,
  292.               DCB=M$LO );
  293.  
  294. %IF OS_VERSION='B03';
  295. %FPT_YC      (FPTN                     = FPT_YC,
  296.               CMD=CMD_BUF );
  297. %ELSE;
  298. %FPT_YC      (FPTN                     = FPT_YC,
  299.               CMD=CMD_BUF,
  300.               LINK=YES );
  301. %ENDIF;
  302.  
  303. %FPT_FID     (FPTN                     = FID_IO,
  304.               ACCT=IO_ACCT,
  305.               ASN=MERGE_IN.V.ASN#,
  306.               NAME=TARGET,
  307.               PASS=IO_PASS,
  308.               RES=MERGE_IN.V.RES#,
  309.               SN=IO_SN,
  310.               TEXTFID=SRCE_FID );
  311. %VLP_ACCT    (FPTN                     = IO_ACCT );
  312. %VLP_NAME    (FPTN                     = IO_NAME );
  313. %VLP_PASS    (FPTN                     = IO_PASS );
  314. %VLP_SN      (FPTN                     = IO_SN );
  315.  
  316. %FPT_FID     (FPTN                     = FID_CG,
  317.               ACCT=CG_ACCT,
  318.               ASN=CG_ASN,
  319.               NAME=CG_NAME,
  320.               PASS=CG_PASS,
  321.               TEXTFID=CG_FID);
  322.  
  323. %VLP_ACCT    (FPTN                     = CG_ACCT );
  324. %VLP_NAME    (FPTN                     = CG_NAME );
  325. %VLP_PASS    (FPTN                     = CG_PASS );
  326. %VLP_SN      (FPTN                     = CG_SN );
  327.  
  328. %FPT_OPEN    (FPTN                     = OPEN_CG_OUT,
  329.               DCB=F$PACKET_OUT,
  330.               FUN=UPDATE,
  331.               SHARE=ALL,
  332.               ORG=TERMINAL,
  333.               NAME=CG_NAME,
  334.               ACCT=CG_ACCT,
  335.               PASS=CG_PASS,
  336.               ASN=COMGROUP,
  337.               SETSTA=CG_STATION);
  338.  
  339. %FPT_OPEN    (FPTN                     = OPEN_CG_IN,
  340.               DCB=F$PACKET_IN,
  341.               FUN=UPDATE,
  342.               SHARE=ALL,
  343.               ORG=TERMINAL,
  344.               NAME=CG_NAME,
  345.               ACCT=CG_ACCT,
  346.               PASS=CG_PASS,
  347.               ASN=COMGROUP,
  348.               SETSTA=CG_STATION);
  349.  
  350. %VLP_SETSTA  (FPTN                     = CG_STATION);
  351. /*            ILOCK=YES,   */
  352. /*            OLOCK=YES    */
  353.  
  354. %VLP_STATION (FPTN                     = MY_STATION);
  355.  
  356. %FPT_OPEN    (FPTN                     = MERGE_IN,
  357.               ACCT=IO_ACCT,
  358.               DCB=F$IN,
  359.               FUN=IN,
  360.               NAME=IO_NAME,
  361.               PASS=IO_PASS,
  362.               SETDCB=YES,
  363.               SN=IO_SN );
  364.  
  365. %FPT_OPEN    (FPTN                     = OPEN_IO,
  366.               DCB=F$IN );
  367.  
  368. %FPT_OPEN    (FPTN                     = TEST_OPEN_IO,
  369.               DCB=F$IN );
  370.  
  371. %FPT_CLOSE   (FPTN                     = FPT_CLOSE,
  372.               DISP=SAVE,
  373.               RELG=YES );
  374.  
  375. %FPT_TIME    (FPTN                     = GET_UTS,
  376.               DEST=UTS,
  377.               SOURCE=CLOCK,
  378.               TSTAMP=UTS );
  379.  
  380. %FPT_TIME    (FPTN                     = GET_TIME,
  381.               DEST=LOCAL,
  382.               SOURCE=CLOCK,
  383.               TIME=HHMMSSSS );
  384.  
  385. %FPT_TIME    (FPTN                     = CONVERT_UTS,
  386.               DATE=MMMDDYY,
  387.               DAY=DAY,
  388.               DEST=EXT,
  389.               SOURCE=UTS,
  390.               TIME=HHMMSSSS,
  391.               TSTAMP=UTS );
  392.  
  393. %FPT_WAIT    (FPTN                     = FPT_WAIT );
  394.  
  395. %FPT_READ    (FPTN                     = READ_IN,
  396.            /* BUF=IO_BUF, */
  397.               DCB=F$IN );
  398.  
  399. %FPT_READ    (FPTN                     = READ_PACKET,
  400.            /* BUF=PACKET, */
  401.               DCB=F$PACKET_IN,
  402.               STATION = MY_STATION,
  403.               TRANS=YES );
  404.  
  405. %FPT_WRITE   (FPTN                     = WRITE_PACKET,
  406.            /* BUF=PACKET, */
  407.               DCB=F$PACKET_OUT,
  408.               STATION = MY_STATION,
  409.               TRANS=YES,
  410.               VFC=NO );
  411.  
  412. %FPT_EOM     (FPTN                     = TIMEOUT,
  413.               DCB=F$PACKET_IN,
  414.               STATION = MY_STATION,
  415.               EOMTABLE=VLP_EOMTABLE,
  416.               TIMEOUT=123,
  417.               UTYPE=SEC );
  418. %VLP_EOMTABLE(FPTN                     = VLP_EOMTABLE,
  419.   VALUES="008,044,000,047,000,000,000,000,000,000,000,000,000,000,000,000");
  420.        /*                                                                 */
  421.        /*                                                                 */
  422.        /*      LF     DC2                                                 */
  423.        /*                                                                 */
  424.        /* EOT  FF     DC4                                                 */
  425.        /*      CR     NAK                                                 */
  426.        /*             SYN                                                 */
  427.        /*             ETB                                                 */
  428.  
  429. %FPT_TRMCTL  (FPTN                     = ORIG_TRMCTL,
  430.               DCB=F$PACKET_IN,
  431.               STATION = MY_STATION,
  432.               STCLASS="STATIC SYMDEF",
  433.               TRMCTL=VLP_GTRMCTL );
  434. %VLP_TRMCTL  (FPTN                     = VLP_GTRMCTL );
  435.  
  436. %FPT_TRMCTL  (FPTN                     = STRMCTL,
  437.               DCB=F$PACKET_IN,
  438.               STATION = MY_STATION,
  439.               TRMCTL=VLP_STRMCTL );
  440. %VLP_TRMCTL  (FPTN                     = VLP_STRMCTL,
  441.               ACTONTRN=YES );
  442.  
  443. %FPT_TRMATTR (FPTN                     = FPT_GTRMATTR,
  444.               DCB=F$PACKET_IN,
  445.               STATION = MY_STATION,
  446.               TRMATTR=VLP_GTRMATTR);
  447. %VLP_TRMATTR (FPTN                     = VLP_GTRMATTR );
  448.  
  449. %FPT_WRITE   (FPTN                     = WRITE_DEBUG,
  450.               DCB=F$DEBUG,
  451.               KEY=DEBUG_KEY );
  452.  
  453. %FPT_WRITE   (FPTN                     = WRITE_LOG,
  454.               DCB=F$LOG,
  455.               KEY=LOG_KEY );
  456.  
  457. %FPT_WRITE   (FPTN                     = WRITE_OUT,
  458.            /* BUF=IO_BUF, */
  459.               DCB=F$OUT );
  460.  
  461. %FPT_GDS     (FPTN                     = GDS );
  462. %VLP_VECTOR  (FPTN                     = IO_ );
  463. %VLP_VECTOR  (FPTN                     = PACKET_ );
  464. %VLP_VECTOR  (FPTN                     = DATA_ );
  465.  
  466. %FPT_ERRMSG  (FPTN                     = FPT_ERRMSG,
  467.               BUF=ERR_BUF,
  468.               INCLCODE=NO,
  469.               CODE=ERRCODE,
  470.               RESULTS=VLR_ERRMSG );
  471. %VLR_ERRMSG  (FPTN                     = VLR_ERRMSG );
  472.  
  473. %FPT_UNFID   (FPTN                     = FPT_UNFID );
  474.  
  475. %FPT_OPEN    (FPTN                     = DEFAULT_OPEN );
  476.  
  477. %FPT_OPEN    (FPTN                     = FPT_OPEN,
  478.               ACCT=A_ACCT,
  479.               NAME=A_NAME,
  480.               PASS=A_PASS,
  481.               SN=A_SN,
  482.               WSN=A_WSN );
  483. %VLP_ACCT    (FPTN                     = A_ACCT );
  484. %VLP_NAME    (FPTN                     = A_NAME );
  485. %VLP_PASS    (FPTN                     = A_PASS );
  486. %VLP_SN      (FPTN                     = A_SN );
  487. %VLP_WSN     (FPTN                     = A_WSN );
  488.  
  489. %FPT_FID     (FPTN                     = FPT_FID,
  490.               ACCT=A_ACCT,
  491.               ASN=FPT_OPEN.V.ASN#,
  492.               NAME=A_NAME,
  493.               PASS=A_PASS,
  494.               RES=FPT_OPEN.V.RES#,
  495.               SN=A_SN,
  496.               TEXTFID=FID_STRING,
  497.               RESULTS=VLR_FID,
  498.               WSN=A_WSN );
  499. %VLR_FID     (FPTN                     = VLR_FID );
  500.  
  501. %FPT_READ    (FPTN                     = READ_DEFAULTS,
  502.               BUF=ME_BUF,
  503.               DCB=F$DEFAULTS );
  504.  
  505. %FPT_PFIL    (FPTN                     = PFIL_EOF,
  506.               BOF=NO );
  507.  
  508. %FPT_PRECORD (FPTN                     = BACKUP1,
  509.               KEYR=YES,
  510.               N=-1 );
  511.  
  512. %IF OS_VERSION='B03';
  513. %FPT_TRMATTR (FPTN                     = FPT_TRMATTR,
  514.               DCB=M$UC,
  515.               TRMATTR=VLP_TRMATTR );
  516.  
  517. %VLP_TRMATTR (FPTN                     = VLP_TRMATTR );
  518. %ENDIF;
  519.  
  520. %FPT_TRMPRG  (FPTN                     = PURGE_TYPEAHEAD,
  521.               DCB=F$PACKET_IN,
  522.               STATION = MY_STATION,
  523.               PURGEINPUT=YES );
  524.  
  525. %FPT_GLINEATTR(FPTN                    = FPT_GLINEATTR,
  526.               DCB=F$PACKET_IN,
  527.               STATION = MY_STATION,
  528.               LINEATTR=VLP_LINEATTR );
  529. %VLP_LINEATTR(FPTN                     = VLP_LINEATTR );
  530. %EJECT;
  531. /**/
  532. /* XUR$GETCMD, X$PARSE,XUF$FORMAT & XUW$WLDCMP stuff */
  533. /**/
  534.  
  535. %XUR_INIT    (NAME                     = XUR_INIT,
  536.               PCB=P_PCB,
  537.               STCLASS=STATIC );
  538.  
  539. %F_FDS       (NAME                     = F_FDS,
  540.               BUF=LO_BUF,
  541.               DCB=M$LO,
  542.               STCLASS=STATIC );
  543.  
  544. %P$PCB       (NAME                     = P_PCB,
  545.               STCLASS=STATIC );
  546.  
  547. %PARSE$OUT   (NAME                     = P_OUT,
  548.               STCLASS=BASED );
  549.  
  550. %PARSE$SYM   (NAME                     = P_SYM,
  551.               STCLASS=BASED );
  552.  
  553. %IF OS_VERSION='B03';
  554. %FPT_WILDCARD(FPTN                     = WILD_COMPARE );
  555. %ELSE;
  556. %XUW_WILDCARD(FPTN                     = WILD_COMPARE );
  557. %ENDIF;
  558.  
  559. %IF OS_VERSION='B03';
  560. %FPT_WILDCARD(FPTN                     = COMPARE_EXT );
  561. %ELSE;
  562. %XUW_WILDCARD(FPTN                     = COMPARE_EXT );
  563. %ENDIF;
  564. %EJECT;
  565. /**/
  566. /* BASED items, listed alphabetically */
  567. /**/
  568. DCL IO_BUF                   CHAR(IO_BUF_SIZE)  BASED(IO_.PTR$);
  569. DCL IO_BYTE(0:0)             CHAR(1)            BASED(IO_.PTR$);
  570. DCL STRNG                    CHAR(LEN) BASED(P_PCB.TEXT$);
  571.  
  572. %EJECT;
  573. /**/
  574. /* BIT items, listed alphabetically */
  575. /**/
  576.  
  577. DCL AT_EOF                   BIT(1);
  578. DCL BINARY_QUOTING           BIT(1);
  579. DCL BIN_MASK                 BIT(9);
  580. DCL CCBUF_CMD                BIT(1);
  581. DCL CG_MODE                  BIT(1);
  582. DCL CG_SPECIFIED             BIT(1);
  583. DCL CHARMASK                 BIT(9);
  584. DCL DEBUG_OPTS(0:35)         BIT(1);
  585. DCL DONE                     BIT(1);
  586. DCL DONE_PARSING             BIT(1);
  587. DCL DONE_SENDING             BIT(1);
  588. DCL GOT_TRMCTL               BIT(1) STATIC INIT(%NO#);
  589. DCL GREETING                 BIT(1);
  590. DCL IM_A_SERVER              BIT(1);
  591. DCL NO_DEFAULTS              BIT(1);
  592. DCL OK_TO_SEND               BIT(1);
  593. DCL PROMPTING                BIT(1);
  594. DCL REPEATING                BIT(1);
  595. DCL SILENT_MODE              BIT(1);
  596. DCL STATION_SPECIFIED        BIT(1);
  597. DCL TRANSFER_INTERRUPTED     BIT(1);
  598. DCL WORDMASK                 BIT(36)   ALIGNED;
  599. %EJECT;
  600. /**/
  601. /* CHARacter items, listed alphabetically */
  602. /**/
  603.  
  604. DCL CG_FID                   CHAR(80)  STATIC INIT(' ');
  605. DCL CHR                      CHAR(1)   CALIGNED;
  606. DCL  CHR_BIT REDEF CHR       BIT(9)    CALIGNED;
  607. DCL CHR7                     CHAR(1)   CALIGNED;
  608. DCL  CHR7_BIT REDEF CHR7     BIT(9)    CALIGNED;
  609. DCL CMD_BUF                  CHAR(256) STATIC;
  610. DCL 1 LINK_CMD REDEF CMD_BUF,
  611.       2 LEN                  UBIN(9)   CALIGNED,
  612.       2 BUF                  CHAR(255) CALIGNED;
  613. DCL CP6_FID                  CHAR(80);
  614. DCL CUR_CHR                  CHAR(1);
  615. DCL DAY                      CHAR(3)   STATIC;
  616. DCL  DAYU(0:2) REDEF DAY     UBIN(9)   CALIGNED;
  617. DCL DEBUG_LABEL(0:12)        CHAR(4)   STATIC INIT(
  618.   '    ','All ','Cmnd','Erro','Info','Mcro',
  619.          'Off ','On  ','Read','Rcvd','Sent',
  620.          'Timo','Writ');
  621. DCL EOR_BYTE(0:1)            CHAR(1);
  622. DCL EOR_CHARS                CHAR(10)  STATIC INIT('#M#J');
  623. DCL ERR_BUF                  CHAR(120) STATIC INIT('OOPS');
  624. DCL FID_STRING               CHAR(80)  STATIC INIT(' ');
  625. DCL GREETING_MSG             CHAR(0)   STATIC INIT(
  626.     'CP-6 KERMIT 1.00 Here (01/25/88)\');
  627. DCL HEX(0:15)                CHAR(1)   STATIC INIT(
  628.     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
  629. DCL HHMMSSSS                 CHAR(11)  STATIC;
  630. DCL INT5                     CHAR(5);
  631. DCL LO_BUF                   CHAR(132) STATIC INIT(' ');
  632. DCL LOG_FID                  CHAR(80)  STATIC INIT(
  633.     '*KERMIT_LOG' );
  634. DCL ME_BUF                   CHAR(132) STATIC INIT(' ');
  635. DCL MMMDDYY                  CHAR(10)  STATIC INIT('MMM DD ''YY');
  636. DCL  MMMDDYYU(0:9) REDEF MMMDDYY UBIN(9) CALIGNED;
  637. DCL MODE                     CHAR(7)   STATIC INIT('TEXT');
  638. DCL NO_MEM_FOR_IO_BUF        CHAR(0)   STATIC INIT(
  639.     'CP-6 KERMIT can''t get big enough buffer for READ' );
  640. DCL PACKET_FID               CHAR(80);
  641. DCL PARITY_TBL(0:%KV_PRTTYP_ZERO) CHAR(4) STATIC INIT(
  642.     'NONE','ODD ','EVEN','ONE ','ZERO' );
  643. DCL PREV_CHR                 CHAR(1);
  644. DCL  PREV_CHR_BIT REDEF PREV_CHR BIT(9) CALIGNED;
  645. DCL PREV_CHR7                CHAR(1)   CALIGNED;
  646. DCL  PREV_CHR7_BIT REDEF PREV_CHR7 BIT(9) CALIGNED;
  647. DCL SET_FILE_REPLACEMENT     CHAR(1)   STATIC INIT('_');
  648. DCL SET_FILE_SUBDIRECTORY_CHAR  CHAR(1) STATIC INIT(':');
  649. DCL SPEED(0:15)              CHAR(5)   STATIC INIT(
  650. /*     0       1       2       3       4       5       6       7    */
  651.     '50   ','75   ','110  ','134  ','150  ','200  ','300  ','600  ',
  652. /*     8       9       10      11      12      13      14      15   */
  653.     '1050 ','1200 ','1800 ','2000 ','2400 ','4800 ','9600 ','19200');
  654. DCL SRCE_FID                 CHAR(80)  STATIC INIT(' ');
  655. DCL STATE                    CHAR(1);
  656. DCL STR1                     CHAR(80);
  657. DCL STR2                     CHAR(80);
  658. DCL TYPE                     CHAR(1);
  659. DCL UNIMPLEMENTED_CMD        CHAR(0)   STATIC INIT(
  660.     '.. Unimplemented command.\');
  661. DCL WHAT                     CHAR(80)  STATIC;
  662. %EJECT;
  663. /**/
  664. /* DCBs */
  665. /**/
  666.  
  667. DCL F$DEFAULTS               DCB;
  668. DCL F$IN                     DCB;
  669. DCL M$LO                     DCB;
  670. DCL M$SI                     DCB;
  671. DCL M$SI2                    DCB;
  672.  
  673. %M$DCB       (DCBN                     = F$DEBUG,
  674.               ACS=DIRECT,
  675.               ASN=FILE,
  676.               FUN=CREATE,
  677.               NAME='*DEBUG',
  678.               ORG=KEYED );
  679.  
  680. %M$DCB       (DCBN                     = F$LOG,
  681.               ASN=FILE,
  682.               CTG=YES,
  683.               FUN=CREATE,
  684.               NAME='*KERMIT_LOG',
  685.               ORG=KEYED );
  686.  
  687. %M$DCB       (DCBN                     = F$OUT,
  688.               ASN=FILE,
  689.               CTG=YES,
  690.               FUN=CREATE,
  691.               NAME='*OUT',
  692.               ORG=CONSEC );
  693.  
  694. %M$DCB       (DCBN                     = F$PACKET_IN,
  695.               ASN=DEVICE,
  696.               FUN=IN,
  697.               ORG=TERMINAL,
  698.               RES='UC' );
  699.  
  700. %M$DCB       (DCBN                     = F$PACKET_OUT,
  701.               ASN=DEVICE,
  702.               FUN=CREATE,
  703.               ORG=TERMINAL,
  704.               RES='UC' );
  705. %EJECT;
  706. /**/
  707. /* ENTRYs, listed alphabetically */
  708. /**/
  709.  
  710. DCL KERMIT$BREAK             ENTRY     ASYNC;
  711. DCL XUR$ALLMSG               ENTRY(1)  ALTRET;
  712. %IF OS_VERSION='B03';
  713. DCL XUR$CLOSE_DCBS           ENTRY;
  714. %ELSE;
  715. DCL XUR$CLOSE_DCBS           ENTRY(2);
  716. %ENDIF;
  717. DCL XUR$ECHO                 ENTRY(1)  ALTRET;
  718. DCL XUR$ECHOIF               ENTRY(1)  ALTRET;
  719. DCL XUR$ERRMSG               ENTRY(7)  ALTRET;
  720. DCL XUR$ERRPTR               ENTRY(2)  ALTRET;
  721. DCL XUR$GETCMD               ENTRY(6)  ALTRET;
  722. DCL XUR$HELP                 ENTRY(1)  ALTRET;
  723. DCL XUR$INIT                 ENTRY(3)  ALTRET;
  724. DCL XUR$MOREMSG              ENTRY(1)  ALTRET;
  725. %IF OS_VERSION='B03';
  726. DCL XUR$SETDCBS              ENTRY(2)  ALTRET;
  727. %ELSE;
  728. DCL XUR$SETDCBS              ENTRY(4)  ALTRET;
  729. %ENDIF;
  730. DCL X$WILDCMP                ENTRY(1)  ALTRET;
  731. DCL X$WRITE                  ENTRY(22);
  732. %EJECT;
  733. /**/
  734. /* PTRs, listed alphabetcally */
  735. /**/
  736.  
  737. DCL B$JIT$                   PTR       SYMREF;
  738. DCL B$TCB$                   PTR       SYMREF;
  739. DCL BLK1$                    PTR;
  740. DCL  PERRCODE REDEF BLK1$    BIT(36);
  741. DCL BLK2$                    PTR;
  742. DCL BLK3$                    PTR;
  743. DCL BLK4$                    PTR;
  744. DCL BLK5$                    PTR;
  745. DCL F$DEFAULTS$              PTR;
  746. DCL F$DEBUG$                 PTR;
  747. DCL F$IN$                    PTR;
  748. DCL F$LOG$                   PTR;
  749. DCL F$OUT$                   PTR;
  750. DCL F$PACKET_IN$             PTR;
  751. DCL F$PACKET_OUT$            PTR;
  752. DCL M$LO$                    PTR;
  753. DCL M$SI$                    PTR;
  754. %EJECT;
  755. /**/
  756. /* SBIN/UBIN items, listed alphabetically */
  757. /**/
  758.  
  759. DCL ABORT_REASON             UBIN;
  760. DCL ARS                      SBIN;
  761. DCL BBUF(0:1023)             UBIN;
  762. DCL BINARY_RECL              SBIN      STATIC INIT(128);
  763. DCL BLOCK_CHECK              SBIN      STATIC INIT(%ONE_CHAR_CHECKSUM##);
  764. DCL BRK_CNT                  SBIN      STATIC SYMDEF INIT(0);
  765. DCL CG_ASN                   UBIN(9) STATIC INIT(%FILE#);
  766. DCL CHECKSUM                 UBIN;
  767. DCL CMD#                     SBIN;
  768. DCL CMD_LEN                  SBIN;
  769. DCL CMD_NUM                  SBIN;
  770. DCL CP6_FID_LEN              UBIN      STATIC;
  771. DCL CUR_MODE                 UBIN;
  772. DCL CUR_TAB_EXPANSION        UBIN;
  773. DCL DATA(0:0)                UBIN(9)   CALIGNED BASED(DATA_.PTR$);
  774. DCL DATA_BIT(0:0)            BIT(9)    CALIGNED BASED(DATA_.PTR$);
  775. DCL DATA_BUF                 CHAR(DATA_MAX_SIZE) CALIGNED BASED(DATA_.PTR$);
  776. DCL DATA_MAX_SIZE            UBIN;
  777. DCL DEFAULT_DCB#             SBIN      STATIC INIT(DCBNUM(M$LO));
  778. DCL DELAY                    SBIN      STATIC SYMDEF INIT(10);
  779. DCL END_UTS                  UBIN;
  780. DCL EOR_BYTE_LEN             UBIN;
  781. DCL EOR_CHARS_LEN            UBIN      STATIC INIT(LENGTHC('#M#J'));
  782. DCL ERRDCB#                  SBIN;
  783. DCL F$DEBUG#                 SBIN      STATIC INIT(DCBNUM(F$DEBUG));
  784. DCL F$DEFAULTS#              SBIN      STATIC INIT(DCBNUM(F$DEFAULTS));
  785. DCL F$LOG#                   SBIN      STATIC INIT(DCBNUM(F$LOG));
  786. DCL F$OUT#                   SBIN      STATIC INIT(DCBNUM(F$OUT));
  787. DCL FILE_BYTE_CNT            SBIN      STATIC INIT(0);
  788. DCL FILE_CNT                 SBIN;
  789. DCL HOW_DEBUG                SBIN      STATIC INIT(%OLDFILE#);
  790. DCL HOW_LOG                  SBIN      STATIC INIT(%OLDFILE#);
  791. DCL HOW_RECEIVE              SBIN      STATIC INIT(%ERROR#);
  792. DCL I                        SBIN;
  793. DCL IO_BUF_SIZE              SBIN;
  794. DCL IO_CNT                   SBIN;
  795. DCL IO_INDX                  SBIN;
  796. DCL IO_LEN                   SBIN;
  797. DCL J                        SBIN;
  798. DCL K                        SBIN;
  799. DCL KBUF(0:1023)             UBIN;
  800. DCL L                        SBIN;
  801. DCL LEN                      UBIN;
  802. DCL KERMIT_NODES             SBIN      SYMREF;
  803. DCL M$LO#                    SBIN      STATIC INIT(DCBNUM(M$LO));
  804. DCL NEXT_CALL                SBIN;
  805. DCL NUM_BYTES_RCVD           SBIN      STATIC INIT(0);
  806. DCL NUM_BYTES_SENT           SBIN      STATIC INIT(0);
  807. DCL NUM_CMDS                 SBIN;
  808. DCL NUM_DATA_PACKETS         SBIN      STATIC INIT(0);
  809. DCL NUM_EXTENSIONS           SBIN;
  810. DCL NUM_TABS                 SBIN      STATIC INIT(40);
  811. DCL NUM_TRIES                SBIN;
  812. DCL OFFSET                   SBIN;
  813. DCL OUT_INDX                 SBIN;
  814. DCL PACKET_MAX_SIZE          UBIN;
  815. DCL PACKLEN                  UBIN;
  816. DCL PACKNUM                  UBIN;
  817. DCL RCVD_CHECKSUM            UBIN;
  818. DCL RCVD_PACKNUM             UBIN;
  819. DCL REC_CNT                  UBIN;
  820. DCL REPEAT_CNT               UBIN;
  821. DCL REPEAT_LEN               UBIN;
  822. DCL SEQUENCE_LEN             UBIN;
  823. DCL SET_FILE_CP6_FIDS        UBIN      STATIC INIT(%SET_FILE_CP6_FIDS_NO##);
  824. DCL SET_FILE_EDIT            UBIN      STATIC INIT(%SET_FILE_EDIT_NO##);
  825. DCL SET_FILE_INCOMPLETE      UBIN   STATIC INIT(%SET_FILE_INCOMPLETE_DISCARD##);
  826. DCL SET_FILE_MODE            UBIN      STATIC INIT(%SET_FILE_MODE_AUTO##);
  827. DCL SET_FILE_NAMES           UBIN      STATIC INIT(%SET_FILE_NAMES_ASIS##);
  828. DCL SET_FILE_PC_EXTENSIONS   UBIN    STATIC INIT(%SET_FILE_PC_EXTENSIONS_YES##);
  829. DCL SET_FILE_SUBDIRECTORY    UBIN    STATIC INIT(%SET_FILE_SUBDIRECTORY_OFF##);
  830. DCL SET_FILE_SUBDIRECTORY_INDEX UBIN;
  831. DCL SET_FILE_WARNING         UBIN      STATIC INIT(%SET_FILE_WARNING_ON##);
  832. DCL SET_TAB_EXPANSION        UBIN      STATIC INIT(%SET_TAB_EXPANSION_ON##);
  833. DCL SI_DCB#                  UBIN      STATIC INIT(DCBNUM(M$SI));
  834. DCL SIZE                     UBIN;
  835. DCL SKIP_BLANKS(0:511)       UBIN(9)   CALIGNED CONSTANT SYMDEF INIT
  836.     ( 1 * %ASCBIN(' '), 0, 1 * 0 );
  837. DCL START_UTS                UBIN;
  838. DCL TABS(0:39)               UBIN(9)   STATIC INIT(
  839.     009,017,025,033,041,049,057,065,073,081,
  840.     089,097,105,113,121,129,137,145,153,161,
  841.     169,177,185,193,201,209,217,225,233,241,
  842.     249,257,265,273,281,289,297,305,313,321);
  843. DCL TARGET_WILD_POS          SBIN;
  844. DCL TMP1                     UBIN;
  845. DCL  TMP1_BIT REDEF TMP1     BIT(36);
  846. DCL TX                       UBIN;
  847. DCL UBIN9                    UBIN(9)   CALIGNED;
  848. DCL UTS                      UBIN      STATIC;
  849. DCL X                        UBIN;
  850. %EJECT;
  851. /**/
  852. /* Structures */
  853. /**/
  854.  
  855. DCL 1 TARGET  STATIC,
  856.       2 L#                   UBIN(9)   CALIGNED,
  857.       2 NAME#                CHAR(31)  CALIGNED;
  858.  
  859. DCL 1 CUR_FILE,
  860.       2 L#                   UBIN(9)   CALIGNED,
  861.       2 NAME#                CHAR(31)  CALIGNED;
  862.  
  863. DCL 1 MY_DEFAULT  STATIC  SYMDEF,
  864.       2 PACKET_LENGTH        UBIN(9)   CALIGNED INIT(94),            /* MAXL */
  865.       2 TIMEOUT              UBIN(9)   CALIGNED INIT( 8),            /* TIME */
  866.       2 PADDING              UBIN(9)   CALIGNED INIT( 0),            /* NPAD */
  867.       2 PADCHAR              CHAR(1)   CALIGNED INIT(BINASC(0)),     /* PADC */
  868.       2 END_OF_LINE          CHAR(1)   CALIGNED INIT(BINASC(13)),    /* EOL  */
  869.       2 QUOTE                CHAR(1)   CALIGNED INIT('#'),           /* QCTL */
  870.       2 QBIN                 CHAR(1)   CALIGNED INIT('Y'),           /* QBIN */
  871.       2 BLOCK_CHECK          UBIN(9)   CALIGNED INIT(%ASCBIN('1')),  /* CHKT */
  872.       2 REPT                 CHAR(1)   CALIGNED INIT('~'),           /* REPT */
  873.       2 CAPAS                UBIN(9)   CALIGNED INIT(0),             /* MASK */
  874.  
  875.       2 PAUSE                UBIN(9)   CALIGNED,
  876.       2 START_OF_PACKET      CHAR(1)   CALIGNED INIT(BINASC( 1));
  877.  
  878. DCL 1 MY,
  879.       2 PACKET_LENGTH        UBIN(9)   CALIGNED,                     /* MAXL */
  880.       2 TIMEOUT              UBIN(9)   CALIGNED,                     /* TIME */
  881.       2 PADDING              UBIN(9)   CALIGNED,                     /* NPAD */
  882.       2 PADCHAR              CHAR(1)   CALIGNED,                     /* PADC */
  883.       2 END_OF_LINE          CHAR(1)   CALIGNED,                     /* EOL  */
  884.       2 QUOTE                CHAR(1)   CALIGNED,                     /* QCTL */
  885.       2 QBIN                 CHAR(1)   CALIGNED,                     /* QBIN */
  886.       2 BLOCK_CHECK          UBIN(9)   CALIGNED,                     /* CHKT */
  887.       2 REPT                 CHAR(1)   CALIGNED,                     /* REPT */
  888.       2 CAPAS                UBIN(9)   CALIGNED,                     /* MASK */
  889.  
  890.       2 PAUSE                UBIN(9)   CALIGNED,
  891.       2 START_OF_PACKET      CHAR(1)   CALIGNED;
  892.  
  893. DCL 1 THEIR  STATIC  SYMDEF,
  894.       2 PACKET_LENGTH        UBIN(9)   CALIGNED INIT(94),            /* MAXL */
  895.       2 TIMEOUT              UBIN(9)   CALIGNED INIT( 8),            /* TIME */
  896.       2 PADDING              UBIN(9)   CALIGNED INIT( 0),            /* NPAD */
  897.       2 PADCHAR              CHAR(1)   CALIGNED INIT(BINASC(00)),    /* PADC */
  898.       2 END_OF_LINE          CHAR(1)   CALIGNED INIT(BINASC(13)),    /* EOL  */
  899.       2 QUOTE                CHAR(1)   CALIGNED INIT('#'),           /* QCTL */
  900.       2 QBIN                 CHAR(1)   CALIGNED INIT('N'),           /* QBIN */
  901.       2 BLOCK_CHECK          UBIN(9)   CALIGNED INIT(%ASCBIN('1')),  /* CHKT */
  902.       2 REPT                 CHAR(1)   CALIGNED INIT(' '),           /* REPT */
  903.       2 CAPAS                UBIN(9)   CALIGNED INIT(0),             /* MASK */
  904.  
  905.       2 PAUSE                UBIN(9)   CALIGNED,
  906.       2 START_OF_PACKET      CHAR(1)   CALIGNED INIT(BINASC( 1));
  907.  
  908. DCL 1 PACKET  BASED(PACKET_.PTR$),
  909.       2 MARK                 CHAR(1)   CALIGNED,
  910.       2 LEN                  UBIN(9)   CALIGNED,
  911.       2 SEQ                  UBIN(9)   CALIGNED,
  912.       2 TYPE                 UBIN(9)   CALIGNED,
  913.       2 DATA(0:0)            UBIN(9)   CALIGNED,
  914.       2  DATA_BIT(0:0) REDEF DATA BIT(9),
  915.       2  DATA_BUF REDEF DATA CHAR(1);
  916. DCL PACKET_BUF               CHAR(PACKET_MAX_SIZE) CALIGNED BASED(PACKET_.PTR$);
  917. DCL PACKET_BIT(0:0)          BIT(9)     CALIGNED  BASED(PACKET_.PTR$);
  918. DCL PACKET_WORD(0:0)         BIT(36)              BASED(PACKET_.PTR$);
  919.  
  920. DCL 1 PROTOCOL  STATIC  SYMDEF,
  921.       2 MAX_INITIAL_RETRIES  UBIN             INIT(10),
  922.       2 MAX_PACKET_RETRIES   UBIN             INIT(10),
  923.       2 SYNCHR               CHAR(1)          INIT(%BITASC('001'O));
  924.  
  925. DCL 1 DEFAULT  STATIC SYMDEF,
  926.       2 LEN                  UBIN      CALIGNED INIT(LENGTHC(':KERMIT_INI')),
  927.       2 NAME                 CHAR(76)  CALIGNED INIT(':KERMIT_INI');
  928.  
  929. DCL 1 DEBUG_FILE  STATIC,
  930.       2 LEN                  UBIN               INIT(LENGTHC('*DEBUG')),
  931.       2 NAME#                CHAR(76)           INIT('*DEBUG');
  932.  
  933. DCL 1 LOG_FILE  STATIC,
  934.       2 LEN                  UBIN               INIT(LENGTHC('*KERMIT_LOG')),
  935.       2 NAME#                CHAR(76)           INIT('*KERMIT_LOG');
  936.  
  937. DCL 1 DEST,
  938.       2 L#                   UBIN,
  939.       2 NAME#                CHAR(76);
  940.  
  941. DCL 1 OUT_KEY,
  942.       2 LEN                  UBIN(9)   CALIGNED,
  943.       2 EDIT                 UBIN(27)  CALIGNED;
  944.  
  945. DCL 1 DEBUG_KEY  STATIC,
  946.       2 LEN                  UBIN(9)   CALIGNED,
  947.       2 EDIT                 UBIN(27)  CALIGNED,
  948.       2 *                    CHAR(252) CALIGNED;
  949.  
  950. DCL 1 LOG_KEY  STATIC,
  951.       2 LEN                  UBIN(9)   CALIGNED,
  952.       2 EDIT                 UBIN(27)  CALIGNED,
  953.       2 *                    CHAR(252) CALIGNED;
  954.  
  955. DCL 1 EXTEN(0:%(MAX_EXTENSIONS#-1)),
  956.       2 LEN                  UBIN(9)   CALIGNED,
  957.       2 TEXT                 CHAR(11)  CALIGNED;
  958.  
  959. DCL 1 PROMPT,
  960.     2 VFC#                   BIT(1)    UNAL,
  961.       2 L#                   UBIN(8)   UNAL,
  962.       2 NAME#                CHAR(31)  CALIGNED;
  963. DCL 1 SET_FILE_PREFIX  STATIC,
  964.       2 LEN                  UBIN(9)   CALIGNED INIT(0),
  965.       2 TEXT                 CHAR(19)  CALIGNED;
  966. %EJECT;
  967.  
  968. DCL 1 BAD_FID_CHARS  STATIC,
  969.       2 *(0:127)             UBIN(9)   UNAL   INIT(
  970. /* DECIMAL   OCTAL   */
  971. /*   0-  7 .000-.007 */  001,001,002,003,004,005,006,007,
  972. /*   8- 15 .010-.017 */  008,009,010,011,012,013,014,015,
  973. /*  16- 23 .020-.027 */  016,017,018,019,020,021,022,023,
  974. /*  24- 31 .030-.037 */  024,025,026,027,028,029,030,031,
  975. /*  32- 39 .040-.047 */  032,033,034,035,000,037,038,039,
  976. /*  40- 47 .050-.057 */  040,041,000,043,044,000,046,047,
  977. /*  48- 55 .060-.067 */  000,000,000,000,000,000,000,000,
  978. /*  56- 63 .070-.077 */  000,000,000,059,060,061,062,000,
  979. /*  64- 71 .100-.107 */  064,000,000,000,000,000,000,000,
  980. /*  72- 79 .110-.117 */  000,000,000,000,000,000,000,000,
  981. /*  80- 87 .120-.127 */  000,000,000,000,000,000,000,000,
  982. /*  88- 95 .130-.137 */  000,000,000,091,092,093,094,000,
  983. /*  96-103 .140-.147 */  096,000,000,000,000,000,000,000,
  984. /* 104-111 .150-.157 */  000,000,000,000,000,000,000,000,
  985. /* 112-119 .160-.167 */  000,000,000,000,000,000,000,000,
  986. /* 120-127 .170-.177 */  000,000,000,123,124,125,126,127);
  987. %EJECT;
  988. /**/
  989. /* VECTORs, listed alphabetically */
  990. /**/
  991.  
  992. DCL VEC1_                    BIT(72)          DALIGNED;
  993. DCL VEC2_                    BIT(72)          DALIGNED;
  994. DCL VEC3_                    BIT(72)          DALIGNED;
  995. DCL VEC4_                    BIT(72)          DALIGNED;
  996. DCL VEC5_                    BIT(72)          DALIGNED;
  997. DCL VEC6_                    BIT(72)          DALIGNED;
  998. %EJECT;
  999. /**/
  1000. /* X$WRITE formats */
  1001. /**/
  1002.  
  1003. DCL FMT                      CHAR(0)   STATIC INIT('%>A');
  1004. DCL FMT1                     CHAR(0)   STATIC INIT(
  1005.     'Send cntrl char prefix: %>A%42-Receive cntrl char prefix: %>A');
  1006. DCL FMT2                     CHAR(0)   STATIC INIT(
  1007.     'Receive start-of-packet char: %>A%42-Send start-of-packet char: %>A');
  1008. DCL FMT3                     CHAR(0)   STATIC INIT(
  1009.     'Receive timeout (seconds): %D%42-Send timeout (seconds): %D');
  1010. DCL FMT4                     CHAR(0)   STATIC INIT(
  1011.     'Receive packet size: %D%42-Send packet size: %D');
  1012. DCL FMT5                     CHAR(0)   STATIC INIT(
  1013.     '# of send pad characters: %D%42-# of Receive pad characters: %D');
  1014. DCL FMT6                     CHAR(0)   STATIC INIT(
  1015.     'End-of-line character: %>A%42-Block check used: 1-CHARACTER-CHECKSUM');
  1016. DCL FMT7                     CHAR(0)   STATIC INIT(
  1017.     'Accepting CP-6 fids: %>A%42-%>A');
  1018. DCL FMT8                     CHAR(0)   STATIC INIT(
  1019.     'Illegal fid chars replaced with: %>A%42-%>A');
  1020. DCL FMT9                     CHAR(0)   STATIC INIT(
  1021.     '%>A%42-Delay %D seconds before first packet');
  1022. DCL FMT10                    CHAR(0)   STATIC INIT(
  1023.     'Initial packet retry count: %D%42-Packet retry count: %D');
  1024. DCL FMT11                    CHAR(0)   STATIC INIT(
  1025.     'Tab expansion: %>A%42-Log file:%>A %>A');
  1026. DCL FMT12                    CHAR(0)   STATIC INIT(
  1027.     '.. Key of next record in %>A will be %D.000.');
  1028. DCL FMT13                    CHAR(0)   STATIC INIT(
  1029.     '.. %>A currently has %D records.');
  1030. DCL FMT14                    CHAR(0)   STATIC INIT(
  1031.     '.. Creating %>A');
  1032. DCL FMT15                    CHAR(0)   STATIC INIT(
  1033.     '.. Can''t DEBUG .. %>A is NOT EDIT keyed.');
  1034. DCL FMT16                    CHAR(0)   STATIC INIT(
  1035.     '.. No room to add new integral EDIT key in %>A.');
  1036. DCL FMT17                    CHAR(0)   STATIC INIT(
  1037.     '%A %A, 19%A at %A logged on as %>A,%>A');
  1038. DCL FMT18                    CHAR(0)   STATIC INIT(
  1039.     '   %>A %>A as %>A (%D records) in %>A mode');
  1040. DCL FMT19                    CHAR(0)   STATIC INIT(
  1041.     '   %>A %>A (%D records) in %>A mode');
  1042. DCL FMT20                    CHAR(0)   STATIC INIT(
  1043.     '   %>A %>A%Q (%D records) in %>A mode');
  1044. DCL FMT21                    CHAR(0)   STATIC INIT(
  1045.     '   %>A %>A as %>A%Q (%D records) in %>A mode');
  1046. DCL FMT22                    CHAR(0)   STATIC INIT(
  1047.     '   Maximum packet sizes: Sent: %D  Received: %D');
  1048. DCL FMT23                    CHAR(0)   STATIC INIT(
  1049.     '   %D Data packets used to send the files %D bytes');
  1050. DCL FMT24                    CHAR(0)   STATIC INIT(
  1051.     '   %D Data packets used to receive the files %D bytes');
  1052. DCL FMT25                    CHAR(0)   STATIC INIT(
  1053.     '   %D bytes sent accross the communications line');
  1054. DCL FMT26                    CHAR(0)   STATIC INIT(
  1055.     '   %D bytes received accross the communications line');
  1056. DCL FMT27                    CHAR(0)   STATIC INIT(
  1057.     '   %>A at %>A baud, Parity=%>A');
  1058. DCL FMT28                    CHAR(0)   STATIC INIT(
  1059.     '   Error packet: %>A');
  1060. DCL FMT29                    CHAR(0)   STATIC INIT(
  1061.     '   %>A %>A in %>A mode');
  1062. DCL FMT30                    CHAR(0)   STATIC INIT(
  1063.     '   %>A %>A as %>A in %>A mode');
  1064. DCL FMT31                    CHAR(0)   STATIC INIT(
  1065.   '.. %D is an invalid TAB value; value must be 1-255; default tabs restored.');
  1066. DCL FMT32                    CHAR(0)   STATIC INIT(
  1067.     '.. Tabs must be specified in ascending order; the value %D wasn''t');
  1068. DCL FMT33                    CHAR(0)   STATIC INIT(
  1069.     'Mode determined by file extension: %>A%42-Mode: %>A' );
  1070. DCL FMT34                    CHAR(0)   STATIC INIT(
  1071.     'File warning: %>A%42-Debug file:%>A %>A' );
  1072. DCL FMT35                    CHAR(0)   STATIC INIT(
  1073.     '.. Sorry, too many characters specified; maximum allowed is 2.');
  1074. DCL FMT36                    CHAR(0)   STATIC INIT(
  1075.     '.. %D is an invalid value; value must be 0-255.');
  1076. DCL FMT37                    CHAR(0)   STATIC INIT(
  1077.     'Subdirectories enabled: %>A%42-Subdirectory character: %>A');
  1078. DCL FMT38                    CHAR(0)   STATIC INIT(
  1079.     'CP-6 file prefix is: %>A');
  1080. %EJECT;
  1081. /**/
  1082. /* X$WRITE vectors */
  1083. /**/
  1084.  
  1085. DCL FMT_                     BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT));
  1086. DCL FMT1_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT1));
  1087. DCL FMT2_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT2));
  1088. DCL FMT3_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT3));
  1089. DCL FMT4_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT4));
  1090. DCL FMT5_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT5));
  1091. DCL FMT6_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT6));
  1092. DCL FMT7_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT7));
  1093. DCL FMT8_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT8));
  1094. DCL FMT9_                    BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT9));
  1095. DCL FMT10_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT10));
  1096. DCL FMT11_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT11));
  1097. DCL FMT12_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT12));
  1098. DCL FMT13_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT13));
  1099. DCL FMT14_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT14));
  1100. DCL FMT15_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT15));
  1101. DCL FMT16_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT16));
  1102. DCL FMT17_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT17));
  1103. DCL FMT18_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT18));
  1104. DCL FMT19_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT19));
  1105. DCL FMT20_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT20));
  1106. DCL FMT21_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT21));
  1107. DCL FMT22_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT22));
  1108. DCL FMT23_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT23));
  1109. DCL FMT24_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT24));
  1110. DCL FMT25_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT25));
  1111. DCL FMT26_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT26));
  1112. DCL FMT27_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT27));
  1113. DCL FMT28_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT28));
  1114. DCL FMT29_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT29));
  1115. DCL FMT30_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT30));
  1116. DCL FMT31_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT31));
  1117. DCL FMT32_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT32));
  1118. DCL FMT33_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT33));
  1119. DCL FMT34_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT34));
  1120. DCL FMT35_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT35));
  1121. DCL FMT36_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT36));
  1122. DCL FMT37_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT37));
  1123. DCL FMT38_                   BIT(72)   STATIC DALIGNED INIT(VECTOR(FMT38));
  1124. %EJECT;
  1125. /****
  1126. *
  1127. *   The main program is fairly trivial.  First INITIALIZE gets called to
  1128. *   initialize various items, most of which are in auto.  Next, we call
  1129. *   PARSE_CCBUF.  It kind of does what it says; it parses the options, if any,
  1130. *   specified on the invocation line.  If the NO DEFAULTS option was NOT
  1131. *   specified on the invocation line then any commands in the default file
  1132. *   (:KERMIT_INI) are read and executed.  After the defaults are executed any
  1133. *   options on the invocation line are executed.  If there were any options on
  1134. *   the invocation line besides DONT GREET, DONT PROMPT, NO DEFAULTS and/or
  1135. *   SILENT MODE then KERMIT will exit after the last such command is executed.
  1136. *   Otherwise, KERMIT will prompt the user for additional commands (or read
  1137. *   from the file specified through DCB1 on the invocation line).
  1138. *
  1139. ****/
  1140.  
  1141. START_KERMIT:
  1142.  
  1143.     CALL INITIALIZE          ALTRET( PUT_ERR );
  1144.  
  1145.     CALL PARSE_CCBUF         ALTRET( PUT_ERR );
  1146.  
  1147.     DO WHILE( NOT DONE );
  1148.        CALL DO_1_LINE_OF_OPTIONS              ALTRET( DONE_YET );
  1149. DONE_YET:
  1150.        END;
  1151.  
  1152. EOJ:
  1153.     CALL CLOSE_A_FILE( F$DEBUG# );
  1154.     CALL CLOSE_A_FILE( M$LO#,%SAVE# );
  1155. %IF OS_VERSION='B03';
  1156.     CALL XUR$CLOSE_DCBS;                      /* Close all files              */
  1157. %ELSE;
  1158.     CALL XUR$CLOSE_DCBS( ,ERRCODE);           /* Close all files              */
  1159. %ENDIF;
  1160.     GOTO QUIT;
  1161.  
  1162. PUT_ERR:
  1163.     ERRDCB#= %ERRDCB;
  1164.     IF NOT DONE THEN                          /* If we had unexpected error   */
  1165.        CALL XUR$ERRMSG( %MONERR,ERRDCB# );    /* print an appropriate error.  */
  1166. SET_THE_STEPCC:
  1167.     SET_STEPCC.V.STEPCC#= 4;
  1168. QUIT:
  1169.     IF VLP_GTRMCTL.SINPUTSZ# ~= 255 THEN      /* Did we change anything?      */
  1170.        CALL M$STRMCTL( ORIG_TRMCTL );         /* Yep, change things back      */
  1171.     CALL M$EXIT( SET_STEPCC );                /* Set STEPCC upon exit         */
  1172.  
  1173. %EJECT;
  1174. /****
  1175. *
  1176. *   B L O C K _ M O V E
  1177. *
  1178. *   Move LEN bytes from SOURCE to DESTINATION.  This routine can only be used
  1179. *   in cases where the destination is not a packet buffer that could have
  1180. *   repeating done in it.
  1181. *
  1182. ****/
  1183.  
  1184. BLOCK_MOVE: PROC( DESTINATION,SOURCE,LEN );
  1185. DCL DESTINATION              CHAR(LEN);
  1186. DCL SOURCE                   CHAR(LEN);
  1187. DCL LEN                      UBIN;
  1188.  
  1189.     DESTINATION= SOURCE;
  1190. RE_TURN:
  1191.     RETURN;
  1192.  
  1193. END BLOCK_MOVE;
  1194. %EJECT;
  1195. /****
  1196. *
  1197. *   B U F E M P
  1198. *
  1199. *   This routine basically just repeatedly gets a byte(s) from the incoming
  1200. *   data packet and then deposits it in the CP-6 file being created.  If the
  1201. *   transfer in progress is a TEXT transfer, TABs will be expanded if
  1202. *   SET TAB EXPANSION = ON.
  1203. *
  1204. ****/
  1205.  
  1206. BUFEMP: PROC( DATA_BUF,LEN )  ALTRET;
  1207. DCL DATA_BUF                 CHAR(LEN);
  1208. DCL LEN                      SBIN;
  1209.  
  1210. DCL I                        SBIN;
  1211.  
  1212. DCL TMP_CHR                  CHAR(1);
  1213.  
  1214.     I= 0;
  1215.     DO WHILE( (I < LEN  OR  REPEAT_CNT > 0)  AND  NOT AT_EOF );
  1216.        CALL GET_PACKET_CHAR( DATA_BUF,I );/*Get Ith char; I+1th char if quoted*/
  1217.        IF CUR_MODE = %SET_FILE_MODE_BINARY## THEN DO;
  1218.           CALL STUFF( IO_BUF,IO_LEN )  ALTRET( ALT_RETURN );
  1219.           IF IO_LEN >= BINARY_RECL THEN
  1220.              CALL WRITE_RECORD( IO_BUF,IO_LEN )  ALTRET( ALT_RETURN );
  1221.           END;
  1222.        ELSE
  1223.           IF (CHR = EOR_BYTE(1)  AND  PREV_CHR = EOR_BYTE(0)) OR
  1224.              (CHR = EOR_BYTE(0) AND EOR_BYTE_LEN = 1)  THEN DO;
  1225.              CALL WRITE_RECORD( IO_BUF,IO_LEN )  ALTRET( ALT_RETURN );
  1226.              END;
  1227.           ELSE DO;
  1228.              IF (PREV_CHR = EOR_BYTE(0))  AND  (EOR_BYTE_LEN > 1)  THEN DO;
  1229.                 TMP_CHR= CHR;
  1230.                 CHR= PREV_CHR;
  1231.                 CALL STUFF( IO_BUF,IO_LEN )  ALTRET( ALT_RETURN );
  1232.                 CHR= TMP_CHR;
  1233.                 END;
  1234.              IF CHR ~= EOR_BYTE(0) THEN DO;
  1235.                 IF CHR = %TAB  AND  CUR_MODE=%SET_FILE_MODE_TEXT##  AND
  1236.                    SET_TAB_EXPANSION = %SET_TAB_EXPANSION_ON## THEN DO;
  1237.                       DO X=TX TO NUM_TABS-1;
  1238.                          IF IO_LEN+1 < TABS(X) THEN
  1239.                             GOTO SPACE_INSERT;
  1240.                          END;
  1241.                    IO_LEN= IO_LEN + LENGTHC(' ');
  1242.                    DO WHILE( '0'B );
  1243. SPACE_INSERT:
  1244.                       IO_LEN= TABS(X) - 1;
  1245.                       TX= X + 1;
  1246.                       END;
  1247.                    IF IO_LEN >= IO_BUF_SIZE THEN
  1248.                       CALL EXPAND( IO_,IO_BUF_SIZE,IO_BUF_SIZE )
  1249.                                               ALTRET( ALT_RETURN );
  1250.                    END;
  1251.                 ELSE
  1252.                    IF CHR=%SUB AND CUR_MODE=%SET_FILE_MODE_TEXT## THEN DO;
  1253.                       AT_EOF= %YES#;
  1254.                       GOTO RE_TURN;
  1255.                       END;
  1256.                    ELSE DO;
  1257.                       CALL STUFF( IO_BUF,IO_LEN )  ALTRET( ALT_RETURN );
  1258.                       END;
  1259.                 END;
  1260.              END;
  1261.        PREV_CHR= CHR;
  1262.        END;
  1263.  
  1264. RE_TURN:
  1265.     RETURN;
  1266.  
  1267. ALT_RETURN:
  1268.     ALTRETURN;
  1269.  
  1270. END BUFEMP;
  1271. %EJECT;
  1272. /****
  1273. *
  1274. *   B U F I L L
  1275. *
  1276. *   Get a buffer full of data from the file that's being sent.
  1277. *
  1278. ****/
  1279.  
  1280. BUFILL: PROC  ALTRET;
  1281.  
  1282.     IF AT_EOF THEN DO;                        /* Are we at EOF?               */
  1283.        STATE= %Z_EOF;                         /* Yep, change states           */
  1284.        GOTO ALT_RETURN;
  1285.        END;
  1286.  
  1287.     SIZE= 0;
  1288.  
  1289.     /****
  1290.     *
  1291.     *   Continue where we left off last time we were here.  NEXT_CALL contains
  1292.     *   a code that will take care of this.
  1293.     *
  1294.     ****/
  1295.     DO CASE( NEXT_CALL );
  1296.  
  1297.        CASE( %NOTHING# );
  1298.  
  1299.        CASE( %BUILD_SEQUENCE# );
  1300.           CALL BUILD_REPEAT_SEQUENCE;
  1301.  
  1302.        CASE( %PUT_CHAR_IN_PACKET# );
  1303.           CALL BUILD_REPEAT_SEQUENCE;
  1304.           CALL PUT_CHAR_IN_PACKET( CUR_CHR );
  1305.  
  1306.        CASE( %STUFF_CHAR_IN_PACKET# );
  1307.           CALL STUFF_CHAR_IN_PACKET( CUR_CHR );
  1308.  
  1309.        END;
  1310.  
  1311.     NEXT_CALL= %NOTHING#;
  1312.  
  1313.     CALL GET_CHAR_FROM_FILE  ALTRET( WAS_EOF_HIT );
  1314.     DO WHILE( '1'B );
  1315.  
  1316.        CALL PUT_CHAR_IN_PACKET( IO_BYTE(IO_INDX) )  ALTRET( NO_ROOM );
  1317.        CALL GET_CHAR_FROM_FILE  ALTRET( WAS_EOF_HIT );
  1318.  
  1319.        END;
  1320.  
  1321.     DO WHILE( '0'B );
  1322. WAS_EOF_HIT:
  1323.        IF STATE = %A_ABORT THEN
  1324. ALT_RETURN:
  1325.           ALTRETURN;
  1326.        END;
  1327.  
  1328. NO_ROOM: ;
  1329. RE_TURN:
  1330.     RETURN;
  1331.  
  1332. END BUFILL;
  1333. %EJECT;
  1334. /****
  1335. *
  1336. *   B U I L D _ R E P E A T _ S E Q U E N C E
  1337. *
  1338. *   It is time to put PREV_CHR in the out going packet.  If repeating is
  1339. *   allowed, we may have to build a repeat sequence for that character.
  1340. *
  1341. ****/
  1342.  
  1343. BUILD_REPEAT_SEQUENCE: PROC  ALTRET;
  1344.  
  1345.     CALL CALC_SEQUENCE_LEN( PREV_CHR );
  1346.  
  1347.     IF SIZE+MINIMUM(REPEAT_CNT*SEQUENCE_LEN,REPEAT_LEN+SEQUENCE_LEN) > THEIR.PACKET_LENGTH-3 THEN
  1348.        GOTO ALT_RETURN;                       /* Won't fit in this packet     */
  1349.  
  1350.     IF REPEAT_CNT*SEQUENCE_LEN >= REPEAT_LEN+SEQUENCE_LEN THEN DO;
  1351.        SUBSTR(DATA_BUF,SIZE,1)= THEIR.REPT;/* Stuff their repeat character */
  1352.        DATA(SIZE+1)= REPEAT_CNT;
  1353.        CALL TOCHAR( DATA(SIZE+1),DATA(SIZE+1) );  /* and REPEAT_CNT        */
  1354.        SIZE= SIZE + LENGTHC(THEIR.REPT) + LENGTHC(DATA(SIZE+1));
  1355.        CALL STUFF_CHAR_IN_PACKET( PREV_CHR );
  1356.        END;
  1357.     ELSE DO;
  1358.        DO SEQUENCE_LEN=1 TO REPEAT_CNT;
  1359.           CALL STUFF_CHAR_IN_PACKET( PREV_CHR );
  1360.           END;
  1361.        END;
  1362.  
  1363.     REPEAT_CNT= 0;
  1364.  
  1365. RE_TURN:
  1366.     RETURN;
  1367.  
  1368. ALT_RETURN:
  1369.     ALTRETURN;
  1370.  
  1371. END BUILD_REPEAT_SEQUENCE;
  1372. %EJECT;
  1373. /****
  1374. *
  1375. *   C A L C _ C H E C K S U M
  1376. *
  1377. *   Calculate the checksum for the current packet and return it in CHECKSUM
  1378. *
  1379. ****/
  1380.  
  1381. CALC_CHECKSUM: PROC( CHECKSUM );
  1382. DCL CHECKSUM                 UBIN;
  1383. DCL  CHECKSUM_BITS REDEF CHECKSUM BIT(36);
  1384.  
  1385. DCL TMP                      UBIN;
  1386. DCL  TMP_BITS REDEF TMP      BIT(36);
  1387.  
  1388.     CHECKSUM= PACKET.LEN;                     /* CHECKSUM= PACKET.LEN + 3     */
  1389.     CHECKSUM= CHECKSUM + PACKET.SEQ;          /* CHECKSUM += PACKET.SEQ       */
  1390.     CHECKSUM= CHECKSUM + PACKET.TYPE;         /* CHECKSUM + PACKET.TYPE       */
  1391.  
  1392.     IF CHARMASK = '377'O THEN
  1393.        DO I=0 TO PACKET.LEN-1-3-ASCBIN(' ');  /* CHECKSUM all the data bytes  */
  1394.           CHECKSUM= CHECKSUM + PACKET.DATA(I);
  1395.           END;
  1396.     ELSE
  1397.        DO I=0 TO PACKET.LEN-1-3-ASCBIN(' ');  /* CHECKSUM all the data bytes  */
  1398.           CHECKSUM= CHECKSUM + MOD(PACKET.DATA(I),128);
  1399.           END;
  1400.     CHECKSUM_BITS= CHECKSUM_BITS & '000000000377'O;
  1401.     CHECKSUM= CHECKSUM + (CHECKSUM/64);
  1402.     CHECKSUM_BITS= CHECKSUM_BITS & '000000000077'O;
  1403. RE_TURN:
  1404.     RETURN;
  1405.  
  1406. END CALC_CHECKSUM;
  1407. %EJECT;
  1408. /****
  1409. *
  1410. *   C A L C _ S E Q U E N C E _ L E N
  1411. *
  1412. *   Determine how many bytes CHR will occupy in the out going packet after any
  1413. *   necessary encoding is done.
  1414. *
  1415. ****/
  1416.  
  1417. CALC_SEQUENCE_LEN: PROC( CHR );
  1418. DCL CHR                      CHAR(1);
  1419. DCL  CHR_BIT REDEF CHR       BIT(9);
  1420.  
  1421. DCL CHR7                     CHAR(1);
  1422. DCL  CHR7_BIT REDEF CHR7     BIT(9);
  1423.  
  1424.     SEQUENCE_LEN= LENGTHC(CHR);
  1425.     CHR7_BIT= CHR_BIT & '177'O;
  1426.     IF BINARY_QUOTING  AND  CHR ~= CHR7  THEN
  1427.        SEQUENCE_LEN= SEQUENCE_LEN + LENGTHC(MY.QBIN);
  1428.     IF CHR7 < ' '                           OR
  1429.        CHR7 = MY.QUOTE                      OR
  1430.        CHR7 = %DEL                          OR
  1431.       (REPEATING  AND  CHR7=MY.REPT)        OR
  1432.       (BINARY_QUOTING  AND  CHR7=MY.QBIN)  THEN
  1433.        SEQUENCE_LEN= SEQUENCE_LEN + LENGTHC(MY.QUOTE);
  1434.  
  1435. RE_TURN:
  1436.     RETURN;
  1437.  
  1438. END CALC_SEQUENCE_LEN;
  1439. %EJECT;
  1440. /****
  1441. *
  1442. *   C H A R C T L
  1443. *
  1444. *   Convert VALUE into a printable string.  If VALUE is already printable
  1445. *   (ASCII 32-126) then just move it to STR.  If VALUE < a blank (ASCII 32)
  1446. *   then STR will equal '^x' where x equals VALUE + 64 (eg. if VALUE = 1, then
  1447. *   STR would be '^A').  If VALUE > '~' (ASCII 126) then STR will be set to
  1448. *   the hex representation of VALUE (eg. X'7F').
  1449. *
  1450. ****/
  1451.  
  1452. CHARCTL: PROC( STR,VALUE );
  1453. DCL STR                      CHAR(6);
  1454. DCL VALUE                    UBIN;
  1455.  
  1456.     IF VALUE>0 AND VALUE<%ASCBIN(' ') THEN
  1457.        CALL CONCAT( STR,'^',BINASC(VALUE+%ASCBIN('A')-1) );
  1458.     ELSE
  1459.        IF VALUE>%ASCBIN(' ') AND VALUE<=%ASCBIN('~') THEN
  1460.           STR= BINASC(VALUE);
  1461.        ELSE DO;
  1462.           STR= 'X''000''';
  1463.           SUBSTR(STR,2,1)= HEX(VALUE/256);
  1464.           X= MOD(VALUE,256);
  1465.           SUBSTR(STR,3,1)= HEX(X/16);
  1466.           X= MOD(X,16);
  1467.           SUBSTR(STR,4,1)= HEX(X);
  1468.           END;
  1469. RE_TURN:
  1470.     RETURN;
  1471.  
  1472. END CHARCTL;
  1473. %EJECT;
  1474. /****
  1475. *
  1476. *   C H E C K _ E X T E N S I O N S
  1477. *
  1478. *   Check to see if the file name in SRCE matches any of the extensions in the
  1479. *   EXTEN table.  If it matches at least one in EXTEN then a normal RETURN is
  1480. *   executed else an ALTRETURN.
  1481. *
  1482. ****/
  1483.  
  1484. CHECK_EXTENSIONS: PROC( SRCE )  ALTRET;
  1485. DCL 1 SRCE,
  1486.       2 LEN                  UBIN(9)   CALIGNED,
  1487.       2 TEXT                 CHAR(11)  CALIGNED;
  1488.  
  1489. DCL I                        UBIN;
  1490.  
  1491. %IF OS_VERSION='B03';
  1492.     COMPARE_EXT.INPUT$= ADDR(SRCE);
  1493. %ELSE;
  1494.     COMPARE_EXT.INPUT_= VECTOR(SUBSTR(SRCE.TEXT,0,SRCE.LEN));
  1495. %ENDIF;
  1496.     IF NUM_EXTENSIONS>0 THEN
  1497.        DO I=0 TO NUM_EXTENSIONS-1;
  1498. %IF OS_VERSION='B03';
  1499.           COMPARE_EXT.PATTERN$= ADDR(EXTEN(I));
  1500. %ELSE;
  1501.           COMPARE_EXT.PATTERN_= VECTOR(SUBSTR(EXTEN.TEXT(I),0,EXTEN.LEN(I)));
  1502. %ENDIF;
  1503.           CALL X$WILDCMP( COMPARE_EXT )  ALTRET( TRY_NEXT_EXT );
  1504. RE_TURN:
  1505.           RETURN;
  1506. TRY_NEXT_EXT:
  1507.           END;
  1508.  
  1509. ALT_RETURN:
  1510.     ALTRETURN;
  1511.  
  1512. END CHECK_EXTENSIONS;
  1513. %EJECT;
  1514. /****
  1515. *
  1516. *   C L O S E _ A _ F I L E
  1517. *
  1518. *   CLOSE the DCB number DCB# with a disposition of DISP.  If DISP is not
  1519. *   passed, assume SAVE.
  1520. *
  1521. ****/
  1522.  
  1523. CLOSE_A_FILE: PROC( DCB#,DISP );
  1524. DCL DCB#                     SBIN;
  1525. DCL DISP                     SBIN;
  1526.  
  1527.     FPT_CLOSE.V.DCB#= DCB#;                   /* Use their DCB#               */
  1528.     IF ADDR(DISP) ~= ADDR(NIL)  AND           /* If they specified a DISP     */
  1529.        DISP = %RELEASE#  THEN                 /* and it was RELEASE           */
  1530.        FPT_CLOSE.V.DISP#= %RELEASE#;          /* then RELEASE the file        */
  1531.     ELSE
  1532.        FPT_CLOSE.V.DISP#= %SAVE#;             /* else, SAVE it.               */
  1533.     IF DCB# = DCBNUM(F$IN)  OR  DCB# = DCBNUM(F$OUT) THEN
  1534.        CALL XSA$CLOSE( FPT_CLOSE,XSA_PARAM );
  1535.     ELSE
  1536.        CALL M$CLOSE( FPT_CLOSE );
  1537. RE_TURN:
  1538.     RETURN;
  1539.  
  1540. END CLOSE_A_FILE;
  1541. %EJECT;
  1542. /****
  1543. *
  1544. *   C T L
  1545. *
  1546. *   Make the SRCE byte printable and put the result in DEST.  This basically
  1547. *   means do an exclusive OR on SRCE with 64.
  1548. *
  1549. ****/
  1550.  
  1551. CTL: PROC( DEST,SRCE );
  1552. DCL DEST                     BIT(9)    CALIGNED;
  1553. DCL SRCE                     BIT(9)    CALIGNED;
  1554.  
  1555.     IF SRCE & '100'O THEN
  1556.        DEST= SRCE & '677'O;
  1557.     ELSE
  1558.        DEST= SRCE \ '100'O;
  1559. RE_TURN:
  1560.     RETURN;
  1561.  
  1562. END CTL;
  1563. %EJECT;
  1564. /****
  1565. *
  1566. *   D E T E R M I N E _ R C V D _ M O D E
  1567. *
  1568. *   Attempt to determine the MODE (BINARY or TEXT) of the file being received
  1569. *   by checking the list of BINARY EXTENSIONS (if SET PC EXTENSIONS = ON).  If
  1570. *   the file name has a suffix in the EXTEN table then the transfer will be in
  1571. *   BINARY mode; else it will be in text mode.
  1572. *
  1573. ****/
  1574.  
  1575. DETERMINE_RCVD_MODE: PROC;
  1576.  
  1577.     IF SET_FILE_MODE = %SET_FILE_MODE_AUTO## THEN DO;
  1578.        CUR_MODE= %SET_FILE_MODE_BINARY##;     /* Assume BINARY mode for now   */
  1579.        CALL CHECK_EXTENSIONS( TARGET )  WHENALTRETURN DO;
  1580.           CUR_MODE= %SET_FILE_MODE_TEXT##;
  1581.           END;
  1582.        END;
  1583.     ELSE
  1584.        CUR_MODE= SET_FILE_MODE;
  1585.  
  1586.     IF CUR_MODE = %SET_FILE_MODE_BINARY## THEN DO;
  1587.        MODE= 'BINARY';
  1588.        OPEN_IO.V.TYPE#= 'BI';
  1589.        END;
  1590.     ELSE DO;
  1591.        MODE= 'TEXT';
  1592.        OPEN_IO.V.TYPE#= '  ';
  1593.        END;
  1594.  
  1595. RE_TURN:
  1596.     RETURN;
  1597.  
  1598. END DETERMINE_RCVD_MODE;
  1599. %EJECT;
  1600. /****
  1601. *
  1602. *   D E T E R M I N E _ S E N D _ M O D E
  1603. *
  1604. *   Determine the mode (BINARY or TEXT) of the file being sent.  It will be
  1605. *   BINARY if the TYpe of the CP-6 file is BI or if the suffix of the file
  1606. *   name matches one or more of those suffixes in the EXTEN table and SET PC
  1607. *   EXTENSIONS = ON is true.
  1608. *
  1609. ****/
  1610.  
  1611. DETERMINE_SEND_MODE: PROC;
  1612.  
  1613.     IF SET_FILE_MODE = %SET_FILE_MODE_AUTO## THEN
  1614.        IF F$IN$->F$DCB.TYPE# = 'BI' THEN
  1615.           CUR_MODE= %SET_FILE_MODE_BINARY##;
  1616.        ELSE
  1617.           IF F$IN$->F$DCB.NAME#.L < LENGTHC('-xxx') THEN
  1618.              CUR_MODE= %SET_FILE_MODE_TEXT##;
  1619.           ELSE DO;
  1620.              CUR_MODE= %SET_FILE_MODE_BINARY##;
  1621.              CALL CHECK_EXTENSIONS( F$IN$->F$DCB.NAME# )  WHENALTRETURN DO;
  1622.                 CUR_MODE= %SET_FILE_MODE_TEXT##;
  1623.                 END;
  1624.              END;
  1625.     ELSE
  1626.        CUR_MODE= SET_FILE_MODE;
  1627.     IF CUR_MODE = %SET_FILE_MODE_BINARY## THEN
  1628.        MODE= 'BINARY';
  1629.     ELSE
  1630.        MODE= 'TEXT';
  1631.  
  1632. RE_TURN:
  1633.     RETURN;
  1634.  
  1635. END DETERMINE_SEND_MODE;
  1636. %EJECT;
  1637. /****
  1638. *
  1639. *   D O _ 1 _ L I N E _ O F _ O P T I O N S
  1640. *
  1641. *   The desire is to parse a line of commands and pick off one token at a
  1642. *   time.  This can be done in one of two ways.  1) the line of options is
  1643. *   passed in BUF and is BUF_LEN bytes long or 2) BUF = ADDR(NIL) (ie. no
  1644. *   argument was passed) in which case the first time GET_A_CMD is called, it
  1645. *   will read a record of command(s) from the current command stream, usually
  1646. *   M$SI which is normally set to ME.
  1647. *
  1648. ****/
  1649.  
  1650. DO_1_LINE_OF_OPTIONS: PROC( BUF,BUF_LEN )  ALTRET;
  1651.  
  1652. DCL BUF                      CHAR(BUF_LEN);
  1653. DCL BUF_LEN                  SBIN;
  1654.  
  1655. CONTINUE:
  1656.     DONE_PARSING= %NO#;
  1657.     DO UNTIL( DONE_PARSING );
  1658.        CALL GET_A_CMD( BUF,BUF_LEN )  ALTRET( END_OF_RECORD );  /* Get a cmd  */
  1659.        IF NOT DONE_PARSING THEN               /* If they didn't say to quit,  */
  1660.           CALL DO_A_CMD;                      /* execute their command.       */
  1661.        END;
  1662.  
  1663. END_OF_RECORD:
  1664.     IF NOT DONE_PARSING THEN
  1665.        IF ERRCODE.ERR# = %E$EOF THEN          /* Did we hit EOF?              */
  1666.           IF SI_DCB# = DCBNUM(M$SI) THEN      /* If we're reading from M$SI   */
  1667.              DONE= %YES#;                     /* then we're DONE now          */
  1668.           ELSE                                /* We're READing from M$SI2;    */
  1669.              IF SI_DCB# ~= F$DEFAULTS# THEN DO;
  1670.                 CALL CLOSE_A_FILE( SI_DCB# ); /* CLOSE M$SI2                  */
  1671.                 SI_DCB#= DCBNUM(M$SI);        /* Change DCBs                  */
  1672.                 CALL XUR$SETDCBS( SI_DCB# );  /* Tell XUR we changed DCBs     */
  1673.                 GOTO CONTINUE;                /* Go read another line of cmds */
  1674.                 END;
  1675.              ELSE
  1676.                 ;
  1677.        ELSE DO;
  1678.           CALL PUT_ERROR;                     /* Otherwise, put the finger.   */
  1679.           IF (ERRCODE.ERR# = %E$NOFILE) AND (SI_DCB# = DCBNUM(M$SI)) THEN
  1680.              DONE= %YES#;
  1681.           END;
  1682.     IF (CCBUF_CMD) AND (SI_DCB# ~= F$DEFAULTS#) THEN/*If command was in CCBUF,*/
  1683.        DONE= %YES#;                           /* we're done.                  */
  1684. ALT_RETURN:
  1685.     ALTRETURN;
  1686.  
  1687. END DO_1_LINE_OF_OPTIONS;
  1688. %EJECT;
  1689. /****
  1690. *
  1691. *   D O _ A _ C M D
  1692. *
  1693. *   A command has already been parsed and the code of same is in CMD#.  All we
  1694. *   do here is a large DO CASE on CMD#.
  1695. *
  1696. ****/
  1697.  
  1698. DO_A_CMD: PROC  ALTRET;
  1699.  
  1700.     DO CASE( CMD# );
  1701.        CASE( %ALL_HELP## );
  1702.           CALL XUR$ALLMSG( XUH_PARAM )  ALTRET( HELP_ERR );
  1703.  
  1704.        CASE( %BYE## );
  1705.           PACKNUM= 0;
  1706.           NUM_TRIES = 0;
  1707.           X = MY_DEFAULT.TIMEOUT;
  1708.           CALL SET_TIMEOUT(X);
  1709. /*        CALL SEND_INIT;   */
  1710.           CALL SEND_PACKET('G',0,1,'L');
  1711.           CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  1712.           CALL SET_TIMEOUT(0);
  1713.           IF TYPE = 'Y' THEN GOTO XIT;
  1714.  
  1715.           CASE( %CG## );
  1716.              CG_FID = %BLK3_TEXT;
  1717.              CG_SPECIFIED = %YES#;
  1718.              IF STATION_SPECIFIED THEN CALL OPEN_TO_CG;
  1719.  
  1720.        CASE( %DEBUG## );
  1721.           CALL DO_DEBUG;
  1722.  
  1723.        CASE( %DONT_GREET## );
  1724.  
  1725.        CASE( %DONT_PROMPT## );
  1726.  
  1727.        CASE( %FINISH## );
  1728.           PACKNUM= 0;
  1729.           NUM_TRIES = 0;
  1730.           X = MY_DEFAULT.TIMEOUT;
  1731.           CALL SET_TIMEOUT(X);
  1732. /*        CALL SEND_INIT;   */
  1733.           CALL SEND_PACKET('G',0,1,'F');
  1734.           CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  1735.           CALL SET_TIMEOUT(0);
  1736.           IF TYPE = 'Y' THEN
  1737.              GOTO XIT;
  1738.  
  1739.        CASE( %HELP## );
  1740.           XUH_PARAM.HELP$= BLK3$->P_SYM.TEXTC$;
  1741.           CALL XUR$HELP( XUH_PARAM )   ALTRET( HELP_ERR );
  1742.           DO WHILE('0'B);
  1743. HELP_ERR:
  1744.              IF XUH_PARAM.ERR.ERR# ~= %E$NOHPROC  AND
  1745.                 XUH_PARAM.ERR.ERR# ~= %E$BDTOPIC THEN
  1746.                 CALL XUR$ERRMSG( XUH_PARAM.ERR );
  1747.              END;
  1748.  
  1749.        CASE( %LIST## );
  1750.           IF %BLK2_NSUBLKS = 0 THEN
  1751.              CMD_BUF= 'L';
  1752.           ELSE
  1753.              CALL CONCAT( CMD_BUF,'L ',%BLK3_TEXT );
  1754.           CALL M$YC( FPT_YC )  ALTRET( YC_ERR );
  1755.           DO WHILE('0'B);
  1756. YC_ERR:
  1757.              ERRDCB#= %ERRDCB;
  1758.              CALL XUR$ERRMSG( %MONERR,ERRDCB# );
  1759.              END;
  1760.  
  1761.        CASE( %LOCAL## );
  1762.           CALL DO_LOCAL_COMMAND        ALTRET( RE_TURN );
  1763.  
  1764.        CASE( %LOG## );
  1765.           CALL DO_LOG;
  1766.  
  1767.        CASE( %MORE_HELP## );
  1768. GET_MORE_HELP:
  1769.           CALL XUR$MOREMSG( XUH_PARAM )       ALTRET( HELP_ERR );
  1770.  
  1771.        CASE( %NULL## );
  1772.           IF M$SI$->F$DCB.EOMVAL#.VALUE# = BITBIN('012'O) THEN DO;
  1773.              CMD#= %MORE_HELP##;              /* Pretend they entered '?'     */
  1774.              GOTO GET_MORE_HELP;
  1775.              END;
  1776.  
  1777.        CASE( %NO_DEFAULTS## );
  1778.  
  1779.  
  1780.        CASE( %PROMPT## );
  1781.           IF %BLK3_COUNT > 0 THEN DO;
  1782.              PROMPT.VFC#= %NO#;
  1783.              PROMPT.L#= %BLK3_COUNT;
  1784.              PROMPT.NAME#= %BLK3_TEXT;
  1785.              END;
  1786.           ELSE DO;
  1787.              PROMPT.VFC#= %YES#;
  1788.              PROMPT.L#= LENGTHC('@');
  1789.              PROMPT.NAME#= '@';
  1790.              END;
  1791.           CALL XUR$INIT( XUR_INIT );
  1792.  
  1793.        CASE( %READ## );
  1794.           CALL DO_READ;
  1795.  
  1796.        CASE( %RECEIVE## );
  1797.           FILE_CNT= 0;
  1798.           MY= MY_DEFAULT;
  1799.           PACKNUM= 0;
  1800.           TX= 0;
  1801.           OPEN_IO= DEFAULT_OPEN;
  1802.           OPEN_IO.V_= VECTOR(OPEN_IO.V);
  1803.           HOW_RECEIVE= SET_FILE_WARNING - %SET_FILE_WARNING_ON## + 1;
  1804.           OPEN_IO.V.FUN#= %CREATE#;
  1805.           IF %BLK2_NSUBLKS = 0 THEN
  1806.              SRCE_FID= ' ';                   /* Only 'RECEIVE' was specified */
  1807.           ELSE
  1808.              IF %BLK2_NSUBLKS = 1 THEN        /* Was 'RECEIVE fid" specified? */
  1809.                 SRCE_FID= %BLK3_TEXT;         /* Yep, Remember it.            */
  1810.              ELSE DO;
  1811.                 SRCE_FID= %BLK2_SUBLK$(2)->P_SYM.TEXT;
  1812.                 HOW_RECEIVE= %BLK2_SUBLK$(1)->P_SYM.CODE - %ON## + 1;
  1813.                 END;
  1814.           CALL RECEIVE_A_FILE( %R_RINIT );
  1815.           CALL SNOOZE( DELAY );               /* Wait before we prompt again  */
  1816.  
  1817.        CASE( %SEND## );
  1818.           IF NOT IM_A_SERVER THEN DO;
  1819.              SRCE_FID= %BLK3_TEXT;
  1820.              CALL SEND;
  1821.              END;
  1822.  
  1823.        CASE( %SERVER## );
  1824.           CALL SERVER  ALTRET( XIT );
  1825.  
  1826.        CASE( %SET## );
  1827.           CALL SET;
  1828.  
  1829.        CASE( %SHOW## );
  1830.           CALL SHOW;
  1831.  
  1832.        CASE( %SILENT## );
  1833.           SILENT_MODE= %YES#;                 /* Shut up!                     */
  1834.  
  1835.        CASE( %STATION## );
  1836.           CG_STATION.ISTA.ISTATION# = %BLK3_TEXT;
  1837.           CG_STATION.OSTA.OSTATION# = %BLK3_TEXT;
  1838.           STATION_SPECIFIED = %YES#;
  1839.           IF CG_SPECIFIED THEN CALL OPEN_TO_CG;
  1840.  
  1841.        CASE( %STATISTICS## );
  1842.           CALL PUT( UNIMPLEMENTED_CMD );
  1843.  
  1844.        CASE( %TRANSMIT## );
  1845.           CALL SNOOZE( DELAY );               /* Give them time to go to micro*/
  1846.           CALL CONCAT( CMD_BUF,'C ',%BLK3_TEXT );
  1847.           CALL M$YC( FPT_YC )  ALTRET( YC_ERR );
  1848.  
  1849.        CASE( %XIT## );
  1850. XIT:
  1851.           IF SI_DCB# = DCBNUM(M$SI2) THEN DO; /* Are we READing thru M$SI2?   */
  1852.              CALL CLOSE_A_FILE( SI_DCB# );    /* CLOSE M$SI2                  */
  1853.              SI_DCB#= DCBNUM(M$SI);           /* Revert back to M$SI          */
  1854.              CALL XUR$SETDCBS( SI_DCB# );     /* Tell XUR that we changed DCBs*/
  1855.              END; /* Since we were in M$SI2 ignore the fact we got an END cmd */
  1856.           ELSE DO;                            /* Guess it's time to quit      */
  1857.              DONE= %YES#;
  1858.              DONE_PARSING= %YES#;
  1859.              END;
  1860.  
  1861.        CASE( ELSE );
  1862.           CALL PUT( '.. Oops!  Unknown option encountered by CP-6 Kermit.\' );
  1863.  
  1864.        END;
  1865.  
  1866. RE_TURN:
  1867.     RETURN;
  1868.  
  1869. END DO_A_CMD;
  1870. %EJECT;
  1871. /****
  1872. *
  1873. *   D O _ D E B U G
  1874. *
  1875. *   Do all the various things that need to be done based on what they said on
  1876. *   the DEBUG command.
  1877. *
  1878. ****/
  1879.  
  1880. DO_DEBUG: PROC  ALTRET;
  1881.  
  1882.     FPT_OPEN= DEFAULT_OPEN;
  1883.     FPT_OPEN.V.FUN#= %CREATE#;
  1884.     FPT_OPEN.V.EXIST#= %OLDFILE#;
  1885.     DEBUG_OPTS= '0'B;
  1886.     DO J=0 TO %BLK2_NSUBLKS-1;
  1887.        BLK3$= %BLK2_SUBLK$(J);
  1888.        DEBUG_OPTS(%BLK3_CODE-%DEBUG_FID##)= %YES#;
  1889.        DO CASE( %BLK3_CODE );
  1890.           CASE( %DEBUG_FID## );
  1891.              IF %BLK4_CODE>=%ON## AND %BLK4_CODE<=%OVER## THEN DO;
  1892.                 FPT_OPEN.V.EXIST#= %BLK4_CODE - %ON## + 1;
  1893.                 BLK4$= %BLK3_SUBLK$(1);
  1894.                 END;
  1895.              ELSE
  1896.                 FPT_OPEN.V.EXIST#= %OLDFILE#; /* Extend (or create) the file  */
  1897.              DEBUG_FILE.LEN= %BLK4_COUNT;
  1898.              DEBUG_FILE.NAME#= %BLK4_TEXT;
  1899.  
  1900.           CASE( %DEBUG_ALL## );
  1901.              DO K=1 TO %DEBUG_WRITE##-%DEBUG_FID##;
  1902.                 DEBUG_OPTS(K)= %YES#;
  1903.                 END;
  1904.  
  1905.           CASE( %DEBUG_ERROR## );
  1906.  
  1907.           CASE( %DEBUG_MICRO## );
  1908.  
  1909.           CASE( %DEBUG_OFF## );
  1910.              CALL CLOSE_A_FILE( F$DEBUG# );
  1911.              GOTO RE_TURN;
  1912.  
  1913.           CASE( %DEBUG_ON## );
  1914.  
  1915.           CASE( %DEBUG_READ## );
  1916.  
  1917.           CASE( %DEBUG_RECEIVE## );
  1918.  
  1919.           CASE( %DEBUG_SEND## );
  1920.  
  1921.           CASE( %DEBUG_TIMEOUT## );
  1922.  
  1923.           CASE( %DEBUG_WRITE## );
  1924.  
  1925.           END;
  1926.        END;
  1927.  
  1928.     IF NOT F$DEBUG$->F$DCB.FCD# THEN DO;
  1929.        CALL OPEN_FID( F$DEBUG#,DEBUG_FILE.NAME#,DEBUG_FILE.LEN,FPT_OPEN )
  1930.                                                                WHENALTRETURN DO;
  1931.           DEBUG_FILE.LEN= LENGTHC('*DEBUG');
  1932.           DEBUG_FILE.NAME#= '*DEBUG';
  1933.           VEC1_= VECTOR(SUBSTR(DEBUG_FILE.NAME#,0,DEBUG_FILE.LEN));
  1934.           GOTO OOPS;
  1935.           END;
  1936.        END;
  1937.  
  1938. DO_DEBUG_SET_DEFAULTS: ENTRY;
  1939.  
  1940.     DEBUG_OPTS(0)= %NO#;
  1941.     IF DEBUG_OPTS = '0'B THEN
  1942.        DEBUG_OPTS(%DEBUG_MICRO##-%DEBUG_FID##)= %YES#;
  1943.     IF DEBUG_OPTS(%DEBUG_MICRO##-%DEBUG_FID##) THEN DO;
  1944.        DEBUG_OPTS(%DEBUG_ERROR##-%DEBUG_FID##)= %YES#;
  1945.        DEBUG_OPTS(%DEBUG_RECEIVE##-%DEBUG_FID##)= %YES#;
  1946.        DEBUG_OPTS(%DEBUG_SEND##-%DEBUG_FID##)= %YES#;
  1947.        DEBUG_OPTS(%DEBUG_TIMEOUT##-%DEBUG_FID##)= %YES#;
  1948.        END;
  1949.  
  1950.     VEC1_= VECTOR(SUBSTR(DEBUG_FILE.NAME#,0,DEBUG_FILE.LEN));
  1951.     IF F$DEBUG$->F$DCB.FCD# THEN              /* Is F$DEBUG OPEN?             */
  1952.        CALL POSITION_FILE( F$DEBUG#,DEBUG_KEY,DEBUG_FILE,WRITE_DEBUG )
  1953.                                               ALTRET( OOPS );
  1954.  
  1955.     CALL CONCAT( LO_BUF,'!',B$JIT.CCBUF );
  1956.     LEN= LENGTHC('!') + B$JIT.CCARS;
  1957.     CALL LOG( %DEBUG_INFO##,LO_BUF,LEN );
  1958.  
  1959. RE_TURN:
  1960.     RETURN;
  1961.  
  1962. OOPS:
  1963.     ERRDCB#= %ERRDCB;
  1964.     CALL XUR$ERRMSG( %MONERR,ERRDCB# );
  1965. ALT_RETURN:
  1966.     ALTRETURN;
  1967.  
  1968. END DO_DEBUG;
  1969. %EJECT;
  1970. /****
  1971. *
  1972. *   D O _ L O C A L _ C O M M A N D
  1973. *
  1974. *   Do whatever is needed to execute one of the LOCAL commands.  This usually
  1975. *   just means set up a command buffer to pass to PCL and let him do the work!
  1976. *
  1977. ****/
  1978.  
  1979. DO_LOCAL_COMMAND: PROC  ALTRET;
  1980.  
  1981.     DO CASE( %BLK3_CODE );
  1982.  
  1983.        CASE( %LOCAL_COPY## );
  1984.           CALL CONCAT( CMD_BUF,'COPY ',%BLK4_TEXT );
  1985.  
  1986.        CASE( %LOCAL_CWD## );
  1987.           IF %BLK3_NSUBLKS > 0 THEN
  1988.              CALL CONCAT( CMD_BUF,'DIR .',%BLK4_TEXT );
  1989.           ELSE
  1990.              CALL CONCAT( CMD_BUF,'DIR' );
  1991.  
  1992.        CASE( %LOCAL_DELETE## );
  1993.           CALL CONCAT( CMD_BUF,'DEL ',%BLK4_TEXT );
  1994.  
  1995.        CASE( %LOCAL_DIR## );
  1996.           CALL CONCAT( CMD_BUF,'L ',%BLK4_TEXT );
  1997.  
  1998.        CASE( ELSE );
  1999.           GOTO RE_TURN;
  2000.  
  2001.        END;
  2002.  
  2003.     CALL M$YC( FPT_YC )  ALTRET( ALT_RETURN );
  2004.  
  2005. RE_TURN:
  2006.     RETURN;
  2007.  
  2008. ALT_RETURN:
  2009.     ALTRETURN;
  2010.  
  2011. END DO_LOCAL_COMMAND;
  2012. %EJECT;
  2013. /****
  2014. *
  2015. *   D O _ L O G
  2016. *
  2017. *   Do whatever is needed to take care of the new, possibly first, LOG command
  2018. *   they just issued.  If a previous LOG was in progress, CLOSE and SAVE it
  2019. *   and then process the latest one.
  2020. *
  2021. ****/
  2022.  
  2023. DO_LOG: PROC  ALTRET;
  2024.  
  2025.     CALL CLOSE_A_FILE( F$LOG# );
  2026.     FPT_OPEN= DEFAULT_OPEN;
  2027.     FPT_OPEN.V.ACS#= %DIRECT#;
  2028.     FPT_OPEN.V.FUN#= %CREATE#;
  2029.     FPT_OPEN.V.EXIST#= %OLDFILE#;
  2030.     FPT_OPEN.V.ORG#= %KEYED#;
  2031.     IF %BLK2_NSUBLKS = 2 THEN DO; /* Was {ON|TO|OVER|INTO} specified?         */
  2032.        FPT_OPEN.V.EXIST#= %BLK3_CODE - %ON## + 1; /* Yep, use it!             */
  2033.        BLK3$= %BLK2_SUBLK$(1);
  2034.        END;
  2035.     IF %BLK3_TEXT = 'OFF'  OR  %BLK3_TEXT = 'off'  THEN
  2036.        GOTO RE_TURN;
  2037.  
  2038.     LOG_FILE.LEN= %BLK3_COUNT;
  2039.     LOG_FILE.NAME#= %BLK3_TEXT;
  2040.     VEC1_= VECTOR(SUBSTR(LOG_FILE.NAME#,0,LOG_FILE.LEN));
  2041.     CALL OPEN_FID( F$LOG#,LOG_FILE.NAME#,LOG_FILE.LEN,FPT_OPEN )
  2042.                                               WHENALTRETURN DO;
  2043.        LOG_FILE.LEN= LENGTHC('*KERMIT_LOG');
  2044.        LOG_FILE.NAME#= '*KERMIT_LOG';
  2045.        VEC1_= VECTOR(SUBSTR(LOG_FILE.NAME#,0,LOG_FILE.LEN));
  2046.        GOTO OOPS;
  2047.        END;
  2048.     CALL POSITION_FILE( F$LOG#,LOG_KEY,LOG_FILE,WRITE_LOG )  ALTRET( OOPS );
  2049.     WRITE_LOG.V.ONEWKEY#= %YES#;
  2050.     WRITE_LOG.V.NEWKEY#= %NO#;
  2051.  
  2052. RE_TURN:
  2053.     RETURN;
  2054.  
  2055. OOPS:
  2056.     ERRDCB#= %ERRDCB;
  2057.     CALL XUR$ERRMSG( %MONERR,ERRDCB# );
  2058. ALT_RETURN:
  2059.     ALTRETURN;
  2060.  
  2061. END DO_LOG;
  2062. %EJECT;
  2063. /****
  2064. *
  2065. *   D O _ R E A D
  2066. *
  2067. *   They issued a READ command (READ subsequent KERMIT commands from another
  2068. *   file).  Check to make sure they aren't issuing the READ from within a READ
  2069. *   file.  If so, bitch and ignore it.  Otherwise, OPEN the READ file and then
  2070. *   tell XUR$GETCMD that we switched DCBs.
  2071. *
  2072. ****/
  2073.  
  2074. DO_READ: PROC  ALTRET;
  2075.  
  2076.     IF SI_DCB# = DCBNUM(M$SI2) THEN DO;       /* Are we already READing?      */
  2077.        CALL PUT( '.. Sorry, you can''t nest READ commands; this one ignored.\');
  2078.        END;
  2079.     ELSE DO;
  2080.        X= %BLK3_COUNT;
  2081.        CALL OPEN_FID( DCBNUM(M$SI2),%BLK3_TEXT,X )  ALTRET( OOPS );
  2082.        SI_DCB#= DCBNUM(M$SI2);                /* Remember where we're READing */
  2083.        CALL XUR$SETDCBS( SI_DCB# );           /* Tell XUR too                 */
  2084.        END;
  2085. RE_TURN:
  2086.     RETURN;
  2087.  
  2088. OOPS:
  2089.     ERRDCB#= %ERRDCB;
  2090.     CALL XUR$ERRMSG( %MONERR,ERRDCB# );
  2091. ALT_RETURN:
  2092.     ALTRETURN;
  2093.  
  2094. END DO_READ;
  2095. %EJECT;
  2096. /****
  2097. *
  2098. *   D O _ W E _ W A N T _ T H I S _ F I L E
  2099. *
  2100. *   See if the file name in CUR_FILE matches the one in TARGET.  If it does,
  2101. *   then RETURN else ALTRETURN.
  2102. *
  2103. ****/
  2104.  
  2105. DO_WE_WANT_THIS_FILE: PROC  ALTRET;
  2106.  
  2107.     IF NOT TEST_OPEN_IO.V.OPER.NXTF# THEN
  2108.        OK_TO_SEND= %NO#;
  2109.  
  2110.     IF ERRCODE = '0'B THEN DO;
  2111. %IF OS_VERSION='B03';
  2112.        WILD_COMPARE.INPUT$= ADDR(CUR_FILE);
  2113. %ELSE;
  2114.        WILD_COMPARE.INPUT_= VECTOR(SUBSTR(CUR_FILE.NAME#,0,CUR_FILE.L#));
  2115. %ENDIF;
  2116.        CALL X$WILDCMP( WILD_COMPARE )     ALTRET( TIME_TO_QUIT );
  2117.        DO WHILE('0'B);
  2118. TIME_TO_QUIT:
  2119.           IF TARGET_WILD_POS > 0  AND
  2120.              SUBSTR(TARGET.NAME#,0,TARGET_WILD_POS) ~=
  2121.              SUBSTR(CUR_FILE.NAME#,0,TARGET_WILD_POS)  THEN DO;
  2122.              OK_TO_SEND= %NO#;
  2123.              END;
  2124.           GOTO ALT_RETURN;
  2125.           END;
  2126.        END;
  2127.     ELSE DO;
  2128.        IF NOT IM_A_SERVER THEN
  2129.           CALL XUR$ERRMSG( ERRCODE,ERRDCB# );
  2130.        ELSE DO;
  2131.           CALL WRITE_LOG_REC( %LOG_HEADER# );
  2132.           CALL SEND_ERROR_PACKET;
  2133.           END;
  2134.        OK_TO_SEND= %NO#;
  2135.        GOTO ALT_RETURN;
  2136.        END;
  2137. RE_TURN:
  2138.     RETURN;
  2139.  
  2140. ALT_RETURN:
  2141.     ALTRETURN;
  2142.  
  2143. END DO_WE_WANT_THIS_FILE;
  2144. %EJECT;
  2145. /****
  2146. *
  2147. *   E X P A N D
  2148. *
  2149. *   Expand a data segment.  VEC_ is a vector framing the segment that is to be
  2150. *   expanded by NUM_BYTES bytes.  If VEC_ = VECTOR(NIL) then the next
  2151. *   available data segment will be used.
  2152. *
  2153. ****/
  2154.  
  2155. EXPAND: PROC( VEC_,NUM_BYTES,BUFSIZ )  ALTRET;
  2156. %VLP_VECTOR  (FPTN                     = VEC_,
  2157.               STCLASS=);
  2158. DCL NUM_BYTES                UBIN;
  2159. DCL BUFSIZ                   UBIN;
  2160.  
  2161.     GDS.V.SEGSIZE#= NUM_BYTES/4;
  2162.     GDS.RESULTS_= VECTOR(VEC_);
  2163.     CALL M$GDS( GDS )  ALTRET( ALT_RETURN );
  2164.     SUBSTR(VEC_.PTR$->IO_BUF,VEC_.W1.VSIZE#+1-NUM_BYTES,NUM_BYTES)= ' ';
  2165.     BUFSIZ= VEC_.W1.VSIZE#+1;
  2166. RE_TURN:
  2167.     RETURN;
  2168.  
  2169. ALT_RETURN:
  2170.     ALTRETURN;
  2171.  
  2172. END EXPAND;
  2173. %EJECT;
  2174. /****
  2175. *
  2176. *   F I X _ C P 6 _ F I L E _ N A M E
  2177. *
  2178. *   Fix up any file names based upon the settings of SET FILE NAMES and SET
  2179. *   FILE CP6 FIDS.
  2180. *
  2181. ****/
  2182.  
  2183. FIX_CP6_FILE_NAME: PROC( NAME,LEN,DIRECTION );
  2184. DCL NAME                     CHAR(LEN);
  2185. DCL LEN                      UBIN;
  2186. DCL DIRECTION                UBIN;
  2187.  
  2188.     IF SET_FILE_NAMES = %SET_FILE_NAMES_LC## THEN
  2189.        DO X=0 TO LEN-1;
  2190.           CHR= SUBSTR(NAME,X,1);
  2191.           IF CHR>='A'  AND  CHR<='Z'  THEN
  2192.              SUBSTR(NAME,X,1)= BINASC(ASCBIN(CHR)+32);     /* Make it LC      */
  2193.           END;
  2194.     ELSE
  2195.        IF SET_FILE_NAMES = %SET_FILE_NAMES_UC## THEN
  2196.           DO X=0 TO LEN-1;
  2197.              CHR= SUBSTR(NAME,X,1);
  2198.              IF CHR>='a'  AND  CHR<='z'  THEN
  2199.                 SUBSTR(NAME,X,1)= BINASC(ASCBIN(CHR)-32); /* Make it UC       */
  2200.              END;
  2201.  
  2202.     IF SET_FILE_CP6_FIDS = %SET_FILE_CP6_FIDS_NO## THEN DO;
  2203.        X= 0;
  2204.        IF LEN>1  AND  SUBSTR(NAME,LEN-1,1)='.' THEN
  2205.           LEN= LEN - 1;                       /* Ignore trailing period */
  2206.        DO WHILE( '1'B );
  2207.           CALL SEARCH( X,TMP1,BAD_FID_CHARS,NAME,X )  ALTRET( FID_IS_OK_NOW );
  2208.           SUBSTR(NAME,X,1)= SET_FILE_REPLACEMENT; /* Change character         */
  2209.           X= X + 1;                           /* Skip to next character       */
  2210.           END;
  2211. FID_IS_OK_NOW:
  2212.        END;
  2213.  
  2214.     IF DIRECTION ~= %SEND##  AND
  2215.        SET_FILE_PREFIX.LEN > 0 THEN DO;/* Should we add a prefix?             */
  2216.        STR1= NAME;
  2217.        CALL INDEX( X,'/',NAME );
  2218.        IF X = LENGTHC(NAME) THEN DO;
  2219.           CALL CONCAT( STR1,SUBSTR(SET_FILE_PREFIX.TEXT,0,SET_FILE_PREFIX.LEN),
  2220.                             NAME );
  2221.           LEN= LEN + SET_FILE_PREFIX.LEN;
  2222.           NAME= STR1;
  2223.           END;
  2224.        ELSE DO;
  2225.           CALL CONCAT( STR1,SUBSTR(NAME,0,X+1),
  2226.                             SUBSTR(SET_FILE_PREFIX.TEXT,0,SET_FILE_PREFIX.LEN),
  2227.                             SUBSTR(NAME,X+1) );
  2228.           LEN= LEN + SET_FILE_PREFIX.LEN;
  2229.           NAME= STR1;
  2230.           END;
  2231.        END;
  2232.  
  2233. RE_TURN:
  2234.     RETURN;
  2235.  
  2236. END FIX_CP6_FILE_NAME;
  2237. %EJECT;
  2238. /****
  2239. *
  2240. *   F I X _ P C _ F I L E _ N A M E
  2241. *
  2242. *   Attempt to determine if the file name being passed to the PC has an
  2243. *   extension in it and if so, change the delimiter that separates the file
  2244. *   name from the extension to a period.
  2245. *
  2246. ****/
  2247.  
  2248. FIX_PC_FILE_NAME: PROC( NAME,LEN );
  2249. DCL NAME                     CHAR(LEN);
  2250. DCL LEN                      UBIN;
  2251.  
  2252. DCL I                        SBIN;
  2253.  
  2254.  
  2255.     /*
  2256.        If the SET FILE PREFIX has been specified, look for it on the file name.
  2257.        If found, remove it and continue.
  2258.     */
  2259.     IF SET_FILE_PREFIX.LEN > 0  AND
  2260.        LEN > SET_FILE_PREFIX.LEN  AND
  2261.        SUBSTR(NAME,0,SET_FILE_PREFIX.LEN) =
  2262.                      SUBSTR(SET_FILE_PREFIX.TEXT,0,SET_FILE_PREFIX.LEN) THEN DO;
  2263.        NAME= SUBSTR(NAME,SET_FILE_PREFIX.LEN);
  2264.        LEN= LEN - SET_FILE_PREFIX.LEN;
  2265.        END;
  2266.     ELSE
  2267.        /*
  2268.           Strip off pseudo subdirectory names if they requested it.
  2269.        */
  2270.        IF SET_FILE_SUBDIRECTORY = %SET_FILE_SUBDIRECTORY_ON## THEN DO;
  2271.           CALL INDEX1R(SET_FILE_SUBDIRECTORY_INDEX,SET_FILE_SUBDIRECTORY_CHAR,NAME,1)
  2272.                ALTRET( NO_SUBDIRECTORY_FOUND );
  2273.           NAME= SUBSTR(NAME,SET_FILE_SUBDIRECTORY_INDEX+1);
  2274.           LEN= LEN - SET_FILE_SUBDIRECTORY_INDEX - 1;
  2275. NO_SUBDIRECTORY_FOUND:
  2276.           END; /* Check for subdirectory */
  2277.  
  2278.     IF SET_FILE_PC_EXTENSIONS = %SET_FILE_PC_EXTENSIONS_YES## THEN DO;
  2279.        DO I=LEN-1 DOWNTO MAXIMUM(0,LEN-4) BY -1;
  2280.           IF SUBSTR(NAME,I,1) = SET_FILE_REPLACEMENT   OR
  2281.              SUBSTR(NAME,I,1) = '-'                   THEN DO;
  2282.              SUBSTR(NAME,I,1)= '.';
  2283.              EXIT;
  2284.              END;
  2285.           END;
  2286.        END;
  2287.  
  2288. RE_TURN:
  2289.     RETURN;
  2290.  
  2291. END FIX_PC_FILE_NAME;
  2292. %EJECT;
  2293. /****
  2294. *
  2295. *   F L U S H _ I N P U T ( aka FLUSHINPUT )
  2296. *
  2297. *   Dump all pending input to clear stacked up NACK's.
  2298. *
  2299. ****/
  2300.  
  2301. FLUSH_INPUT: PROC;
  2302.  
  2303.     CALL M$TRMPRG( PURGE_TYPEAHEAD );
  2304. RE_TURN:
  2305.     RETURN;
  2306.  
  2307. END FLUSH_INPUT;
  2308. %EJECT;
  2309. /****
  2310. *
  2311. *   G E T _ A _ C M D
  2312. *
  2313. *   Get a command.  If we have previously parsed a line of them, then just
  2314. *   pick up the next one to be processed.  If none are left to process then
  2315. *   get another line/record of commands.
  2316. *
  2317. ****/
  2318.  
  2319. GET_A_CMD: PROC( CMD,CMD_LEN )  ALTRET;
  2320. DCL CMD                      CHAR(CMD_LEN);
  2321. DCL CMD_LEN                  UBIN;
  2322.  
  2323.     CMD_NUM= CMD_NUM + 1;                     /* Point to next command        */
  2324.     IF CMD_NUM >= NUM_CMDS THEN               /* Anything left?               */
  2325.        IF CMD_NUM >= 9999 OR ADDR(CMD) = ADDR(NIL) THEN DO;/* Nope. Get more. */
  2326.           CMD_NUM= 0;                         /* Set number of commands to 0  */
  2327.           CALL SET_TIMEOUT( 0 );
  2328.           IF ADDR(CMD) = ADDR(NIL) THEN DO;   /* Get commands from user?      */
  2329.              CALL XUR$GETCMD( KERMIT_NODES,BLK1$,PROMPT ) ALTRET( OOPS );
  2330.              END;
  2331.           ELSE                                /* Else: parse what was passed  */
  2332.              CALL XUR$GETCMD( KERMIT_NODES,BLK1$, ,CMD,CMD_LEN ) ALTRET( OOPS );
  2333.           LEN= P_PCB.NCHARS;
  2334.           CALL LOG( %DEBUG_COMMAND##,STRNG,LEN );
  2335.           IF (NOT SILENT_MODE) AND (ADDR(CMD) = ADDR(NIL)) THEN
  2336.              CALL XUR$ECHOIF( M$LO# );
  2337.           IF BLK1$ = ADDR(NIL) THEN        /* Was command done by XUR$GETCMD? */
  2338.              GOTO DONE_FOR_NOW;
  2339.           ELSE
  2340.              NUM_CMDS= %BLK1_NSUBLKS;         /* Remember number of commands  */
  2341.           END;
  2342.        ELSE DO;
  2343. DONE_FOR_NOW:
  2344.           DONE_PARSING= %YES#;                /* Indicate we are done parsing */
  2345.           GOTO RE_TURN;
  2346.           END;
  2347.     BLK2$= %BLK1_SUBLK$(CMD_NUM);             /* Set up some PTRs to the PCB  */
  2348.     IF %BLK2_NSUBLKS > 0 THEN DO;
  2349.        BLK3$= %BLK2_SUBLK$(0);
  2350.        IF %BLK3_NSUBLKS > 0 THEN
  2351.           BLK4$= %BLK3_SUBLK$(0);
  2352.        END;
  2353.     CMD#= %BLK2_CODE;                         /* Remember the command we're on*/
  2354. RE_TURN:
  2355.     RETURN;
  2356.  
  2357. OOPS:                                         /* The label says it all!       */
  2358.     NUM_CMDS= 0;
  2359.     ERRCODE= PERRCODE;                        /* Load the error code returned */
  2360.     ERRDCB#= SI_DCB#;
  2361. ALT_RETURN:
  2362.     ALTRETURN;                                /* by XUR$GETCMD, then ALTRETURN*/
  2363.  
  2364. END GET_A_CMD;
  2365. %EJECT;
  2366. /****
  2367. *
  2368. *   G E T _ C H A R _ F R O M _ F I L E
  2369. *
  2370. *   Get another byte from the file that we are sending to the other computer.
  2371. *   The handling of repeated characters is also taken care of in here (kind
  2372. *   of).
  2373. *
  2374. ****/
  2375.  
  2376. GET_CHAR_FROM_FILE: PROC  ALTRET;
  2377.  
  2378. GET_NEXT_CHAR:
  2379.     IO_INDX= IO_INDX + 1;                     /* Point to next input byte     */
  2380.     IF IO_INDX >= ARS THEN DO;                /* Past end of record?          */
  2381.        IF REC_CNT > 0  AND                    /* Any records already been read*/
  2382.           CUR_MODE = %SET_FILE_MODE_TEXT## THEN DO;
  2383.           IF REPEAT_CNT > 0 THEN DO;    /* Any repeated sequence in progress? */
  2384.              CALL BUILD_REPEAT_SEQUENCE  WHENALTRETURN DO;
  2385.                 NEXT_CALL= %BUILD_SEQUENCE#;
  2386.                 GOTO ALT_RETURN;
  2387.                 END;
  2388.              END;
  2389.           CALL INSERT_EOR_CHARS( DATA_BUF,SIZE )  ALTRET( ALT_RETURN );
  2390.           END;
  2391. READ_AGAIN:
  2392.        CALL XSA$READ( READ_IN,XSA_PARAM )  ALTRET( EOF_HIT );
  2393.        REC_CNT= REC_CNT + 1;
  2394.        ARS= XSA_PARAM.ARS#;
  2395.        FILE_BYTE_CNT= FILE_BYTE_CNT + ARS + 2;
  2396.        CALL LOG( %DEBUG_READ##,IO_BUF,ARS );
  2397.        IO_INDX= 0;
  2398.        IF ARS <= 0 THEN                       /* If null record, go insert    */
  2399.           GOTO GET_NEXT_CHAR;                 /* EOR characters and read agn  */
  2400.        END;
  2401.  
  2402.     DO WHILE('0'B);
  2403. EOF_HIT:
  2404.        ERRCODE= XSA_PARAM.ERR;
  2405.        IF ERRCODE.ERR# = %E$EOF THEN DO;
  2406.           IF REPEAT_CNT > 0 THEN
  2407.              CALL BUILD_REPEAT_SEQUENCE  WHENALTRETURN DO;
  2408.                 NEXT_CALL= %BUILD_SEQUENCE#;
  2409.                 GOTO ALT_RETURN;
  2410.                 END;
  2411.           AT_EOF= %YES#;
  2412.           GOTO ALT_RETURN;
  2413.           END;
  2414.        ELSE
  2415.           IF ERRCODE.ERR# = %E$LD THEN DO;    /* Lost Data?                   */
  2416.              CALL EXPAND( IO_,IO_BUF_SIZE,IO_BUF_SIZE )  ALTRET( NO_MEM );
  2417.              READ_IN.BUF_= IO_;
  2418.              BACKUP1.KEY_= VECTOR(NIL);
  2419.              BACKUP1.V.DCB#= DCBNUM(F$IN);
  2420.              BACKUP1.V.KEYR#= %NO#;
  2421.              CALL XSA$PRECORD( BACKUP1,XSA_PARAM )  WHENALTRETURN DO;
  2422.                 ERRCODE= XSA_PARAM.ERR;
  2423.                 IF ERRCODE.ERR# ~= %E$BOF THEN/*Did we try to BACKUP past BOF?*/
  2424.                    GOTO OH_DEAR;             /* Nope, go report the error.    */
  2425.                 END;
  2426.              GOTO READ_AGAIN;
  2427.              END;
  2428.           ELSE DO;
  2429. OH_DEAR:
  2430.              CALL SEND_ERROR_PACKET;
  2431.              DO WHILE('0'B);
  2432. NO_MEM:
  2433.                 CALL SEND_ERROR_PACKET( NO_MEM_FOR_IO_BUF,LENGTHC(NO_MEM_FOR_IO_BUF) );
  2434.                 END;
  2435.              STATE= %A_ABORT;
  2436. ALT_RETURN:
  2437.              ALTRETURN;
  2438.              END;
  2439.        END;
  2440.  
  2441. RE_TURN:
  2442.     RETURN;
  2443.  
  2444. END GET_CHAR_FROM_FILE;
  2445. %EJECT;
  2446. /****
  2447. *
  2448. *   G E T _ D E F A U L T S
  2449. *
  2450. *   Read any default commands from the default file, :KERMIT_INI.  If no such
  2451. *   file exists, just RETURN.
  2452. *
  2453. ****/
  2454.  
  2455. GET_DEFAULTS: PROC  ALTRET;
  2456.  
  2457.     FILE_CNT= 1;                              /* Start with current FMA       */
  2458.  
  2459.     DO WHILE( '0'B );
  2460. GET_ERR:
  2461.        ERRCODE= %MONERR;
  2462.        ERRDCB#= %ERRDCB;
  2463.        CALL INDEX( L,'.',DEFAULT.NAME );
  2464.        IF (ERRCODE.ERR# = %E$NOFILE)  AND  NOT F$DEFAULTS$->F$DCB.AMR#  THEN DO;
  2465.           FILE_CNT= FILE_CNT + 1;
  2466.           CALL INDEX( L,'.',DEFAULT.NAME );
  2467.           IF L >= LENGTHC(DEFAULT.NAME) THEN
  2468.              CALL INDEX( L,' ',DEFAULT.NAME );
  2469.           DO CASE( FILE_CNT );
  2470.              CASE( 1 );                       /* Current File Management Acct */
  2471.  
  2472.              CASE( 2 );                       /* Try logon account            */
  2473.                 IF B$JIT.FACCN = B$JIT.ACCN THEN
  2474.                    GOTO TRY_LIBRARY_ACCT;
  2475.                 CALL INSERT( DEFAULT.NAME,L,,'.',B$JIT.ACCN );
  2476.              CASE( 3 );                       /* As last resort, try :LIBRARY */
  2477. TRY_LIBRARY_ACCT:
  2478.                 CALL INSERT( DEFAULT.NAME,L,,'.:LIBRARY' );
  2479.              CASE( ELSE );
  2480.                 GOTO CHECK_ERR;
  2481.              END;
  2482.           CALL INDEX( DEFAULT.LEN,'  ',DEFAULT.NAME );
  2483.           END;
  2484.        END;
  2485.  
  2486. OPEN_IT:
  2487.     IF F$DEFAULTS$->F$DCB.AMR# AND F$DEFAULTS$->F$DCB.ASN# ~= %DEVICE# THEN DO;
  2488.        CALL OPEN_FID( F$DEFAULTS#,' ',0 )  ALTRET( GET_ERR );
  2489.        DEFAULT.LEN= LENGTHC(DEFAULT.NAME);
  2490.        CALL UNFID( F$DEFAULTS#,DEFAULT.NAME,DEFAULT.LEN )  ALTRET( GET_ERR );
  2491.        END;
  2492.     ELSE
  2493.        CALL OPEN_FID( F$DEFAULTS#,DEFAULT.NAME,DEFAULT.LEN )  ALTRET( GET_ERR );
  2494.  
  2495.     CALL PUT( ' \' );
  2496.  
  2497.     OFFSET= 0;
  2498.     IF PROMPTING THEN DO;
  2499.        CALL CONCAT( PROMPT.NAME#,SUBSTR(DEFAULT.NAME,0,DEFAULT.LEN),' Cmd> ' );
  2500.        PROMPT.VFC#= %NO#;
  2501.        PROMPT.L#= DEFAULT.LEN + LENGTHC(' Cmd> ');
  2502.        END;
  2503.     CALL XUR$INIT( XUR_INIT )  ALTRET( GET_ERR );
  2504.     SI_DCB#= F$DEFAULTS#;
  2505.     CALL XUR$SETDCBS( SI_DCB# );
  2506.     NUM_CMDS= 0;                            /* Force a READ from default file */
  2507.     DO WHILE( NOT DONE );
  2508.        CALL DO_1_LINE_OF_OPTIONS  ALTRET( RESET_DCBS );
  2509.        END;
  2510.  
  2511. RESET_DCBS:
  2512.     CALL PUT( ' \' );
  2513.     CALL CLOSE_A_FILE( F$DEFAULTS# );
  2514.     IF PROMPTING THEN DO;
  2515.        PROMPT.VFC#= %NO#;
  2516.        PROMPT.L#= LENGTHC('CP-6 Kermit> ');
  2517.        PROMPT.NAME#= 'CP-6 Kermit> ';
  2518.        END;
  2519.     ELSE DO;
  2520.        PROMPT.VFC#= %YES#;
  2521.        PROMPT.L#= LENGTHC('@');
  2522.        PROMPT.NAME#= '@';
  2523.        END;
  2524.     CALL XUR$INIT( XUR_INIT )  ALTRET( GET_ERR );
  2525.     SI_DCB#= DCBNUM(M$SI);
  2526.     CALL XUR$SETDCBS( SI_DCB#,M$LO# );
  2527.  
  2528. CHECK_ERR:
  2529.     IF (ERRCODE.ERR# = %E$NOFILE AND NOT F$DEFAULTS$->F$DCB.AMR#)  OR
  2530.        (ERRCODE.ERR# = %E$EOF)  OR
  2531.        (DONE)  THEN
  2532. RE_TURN:
  2533.        RETURN;
  2534.     ELSE
  2535.        CALL XUR$ERRMSG( ERRCODE,ERRDCB# );
  2536. ALT_RETURN:
  2537.     ALTRETURN;
  2538.  
  2539. END GET_DEFAULTS;
  2540. %EJECT;
  2541. /****
  2542. *
  2543. *   G E T _ F I D _ F R O M _ P A C K E T
  2544. *
  2545. *   Get a fid from the packet.  The main reason this is a separate subroutine
  2546. *   is to handle repeated characters that may be in the fid.  Sigh!
  2547. *
  2548. ****/
  2549.  
  2550. GET_FID_FROM_PACKET: PROC( SRCE_FID,SRCE_LEN,DEST_FID,DEST_LEN );
  2551. DCL SRCE_FID                 CHAR(SRCE_LEN);
  2552. DCL SRCE_LEN                 UBIN;
  2553. DCL DEST_FID                 CHAR(80);
  2554. DCL DEST_LEN                 UBIN;
  2555.  
  2556.     PACKET_FID= ' ';
  2557.     DEST_LEN= 0;
  2558.     I= 0;
  2559.     DO WHILE( I < SRCE_LEN  OR  REPEAT_CNT > 0 );
  2560.        CALL GET_PACKET_CHAR( SRCE_FID,I );
  2561.        CALL STUFF( DEST_FID,DEST_LEN )  ALTRET( RE_TURN );
  2562.        END;
  2563.  
  2564. RE_TURN:
  2565.     RETURN;
  2566.  
  2567. END GET_FID_FROM_PACKET;
  2568. %EJECT;
  2569. /****
  2570. *
  2571. *   G E T _ P A C K E T _ C H A R
  2572. *
  2573. *   Get another character from the packet.  If a repeated sequence is in
  2574. *   progress, simply decrement the repeat count and return the repeated
  2575. *   character.  Otherwise, point to the next byte in the packet and return it.
  2576. *
  2577. ****/
  2578.  
  2579. GET_PACKET_CHAR: PROC( BUF,INDX );
  2580. DCL BUF                      CHAR(INDX);
  2581. DCL INDX                     UBIN;
  2582.  
  2583.     IF REPEAT_CNT > 0 THEN DO;                /* Any repeat in progress?      */
  2584.        REPEAT_CNT= REPEAT_CNT - 1;         /* Just decrement count and return */
  2585.        GOTO RE_TURN;
  2586.        END;
  2587.  
  2588.     CHR= SUBSTR(BUF,INDX,1);                  /* Get next character           */
  2589.     CHR7_BIT= CHR_BIT & '177'O;               /* Leave only low order 7 bits  */
  2590.     INDX= INDX + 1;
  2591.  
  2592.     IF REPEATING  AND  CHR7 = MY.REPT  THEN DO; /* Is it a REPeaT character?  */
  2593.        CHR= SUBSTR(BUF,INDX,1);               /* Yep, get next byte           */
  2594.        CHR7_BIT= CHR_BIT & '177'O;
  2595.        INDX= INDX + 1;                        /* Point to next byte           */
  2596.        CALL UNCHAR( ,CHR7,REPEAT_CNT );       /* Make repeat count useable    */
  2597.        REPEAT_CNT= REPEAT_CNT - 1;            /* Don't count the first time   */
  2598.  
  2599.        CHR= SUBSTR(BUF,INDX,1);               /* Get byte after repeat count  */
  2600.        CHR7_BIT= CHR_BIT & '177'O;
  2601.        INDX= INDX + 1;
  2602.  
  2603.        END;
  2604.  
  2605.     BIN_MASK= '000'O;                         /* Assume binary mask of zero   */
  2606.     IF BINARY_QUOTING  AND  CHR7 = MY.QBIN THEN DO; /* Is IT qbin?            */
  2607.        BIN_MASK= '200'O;                      /* Remember the 8th bit         */
  2608.        CHR= SUBSTR(BUF,INDX,1);               /* Get byte after QBIN          */
  2609.        CHR7_BIT= CHR_BIT & '177'O;
  2610.        INDX= INDX + 1;                        /* Point to next byte           */
  2611.        END;
  2612.  
  2613.     IF CHR7 = MY.QUOTE THEN DO;               /* Is it the QUOTE character?   */
  2614.        CHR= SUBSTR(BUF,INDX,1);               /* get byte after the QUOTE char*/
  2615.        CHR7_BIT= CHR_BIT & '177'O;
  2616.        INDX= INDX + 1;                        /* Point to next byte           */
  2617.        IF (CHR7 = MY.QUOTE)  OR               /* If it's the QUOTE            */
  2618.           (BINARY_QUOTING  AND  CHR7 = MY.QBIN)  OR
  2619.           (REPEATING  AND  CHR7 = MY.REPT)  THEN /* or the .REPT char         */
  2620.           ;                                   /* Don't CTL it                 */
  2621.        ELSE
  2622.           CALL CTL( CHR,CHR );                /* else, CTL it                 */
  2623.        END;
  2624.  
  2625.     CHR_BIT= CHR_BIT | BIN_MASK;              /* OR in the 8th bit            */
  2626. RE_TURN:
  2627.     RETURN;
  2628.  
  2629. END GET_PACKET_CHAR;
  2630. %EJECT;
  2631. /****
  2632. *
  2633. *
  2634. *    Set the activation character set and timeout.
  2635. *
  2636. ****/
  2637.  
  2638. INIT_ACTIVATION: PROC ALTRET;
  2639.  
  2640. IF NOT GOT_TRMCTL THEN DO;
  2641.        CALL M$GTRMCTL( ORIG_TRMCTL )      ALTRET( ALT_RETURN );
  2642.        CALL M$STRMCTL( STRMCTL )          ALTRET( ALT_RETURN );
  2643.        CALL SET_PARITY_MASK('Y');
  2644.        GOT_TRMCTL = %YES#;
  2645.        END;
  2646.     RETURN;
  2647. ALT_RETURN:
  2648.     ALTRETURN;
  2649. END INIT_ACTIVATION;
  2650. %EJECT;
  2651.  
  2652. /****
  2653. *
  2654. *   I N I T I A L I Z E
  2655. *
  2656. *   Initialize various things that can't be at compile time.
  2657. *
  2658. ****/
  2659.  
  2660. INITIALIZE: PROC  ALTRET;
  2661.  
  2662.     F$DEFAULTS$= DCBADDR(DCBNUM(F$DEFAULTS)); /* Set up pointers to some DCBs */
  2663.     F$DEBUG$= DCBADDR(F$DEBUG#);
  2664.     F$LOG$= DCBADDR(DCBNUM(F$LOG));
  2665.     F$IN$= DCBADDR(DCBNUM(F$IN));
  2666.     F$OUT$= DCBADDR(DCBNUM(F$OUT));
  2667.     F$PACKET_IN$= DCBADDR(DCBNUM(F$PACKET_IN));
  2668.     F$PACKET_OUT$= DCBADDR(DCBNUM(F$PACKET_OUT));
  2669.     M$LO$= DCBADDR(DCBNUM(M$LO));
  2670.     M$SI$= DCBADDR(DCBNUM(M$SI));
  2671.  
  2672.     PROMPT.VFC#= %NO#;
  2673.     PROMPT.L#= LENGTHC('CP-6 Kermit> ');
  2674.     PROMPT.NAME#= 'CP-6 Kermit> ';
  2675.  
  2676.     CALL XUR$INIT( XUR_INIT )  ALTRET( ALT_RETURN );
  2677.     CALL XUR$SETDCBS( SI_DCB#,M$LO# );
  2678.  
  2679. /*  CALL M$INT( BREAK_CNTRL )  ALTRET( ALT_RETURN ); */
  2680.  
  2681. /**/
  2682. /* Initialize various limits and constants */
  2683. /**/
  2684.     PROTOCOL.MAX_INITIAL_RETRIES= 10;
  2685.     PROTOCOL.MAX_PACKET_RETRIES=  10;
  2686.     PROTOCOL.SYNCHR= BITASC('001'O);          /* SOH */
  2687.  
  2688.     DONE= %NO#;                               /* Assume we aren't DONE yet!   */
  2689.     GREETING= %YES#;                          /* Assume we will greet them    */
  2690.     NO_DEFAULTS= %NO#;                        /* Assume they want defaults    */
  2691.     PROMPTING= %YES#;                         /* Assume we will prompt also   */
  2692.     SILENT_MODE= %NO#;                        /* Assume we'll "tell all"!     */
  2693.     CG_MODE = %NO#;
  2694.     CG_SPECIFIED = %NO#;
  2695.     STATION_SPECIFIED = %NO#;
  2696.  
  2697.  
  2698. /**/
  2699. /* Initialize various things in auto */
  2700. /**/
  2701.     DEBUG_OPTS= '0'B;
  2702.     IF F$DEBUG$->F$DCB.AMR# THEN DO;          /* Is F$DEBUG SET externally?   */
  2703.        DEBUG_OPTS(%DEBUG_INFO##-%DEBUG_FID##)= %YES#; /* Turn INFO on         */
  2704.        FPT_OPEN= DEFAULT_OPEN;
  2705.        FPT_OPEN.V.ASN#= %FILE#;               /* Assume it's a FILE           */
  2706.        FPT_OPEN.V.FUN#= %CREATE#;             /* FUNction of CREATE           */
  2707.        CALL OPEN_FID( F$DEBUG#,' ',0,FPT_OPEN )  ALTRET( ALT_RETURN );
  2708.        CALL UNFID( F$DEBUG#,DEBUG_FILE.NAME#,DEBUG_FILE.LEN )
  2709.                                                  ALTRET( ALT_RETURN );
  2710.        END;
  2711.  
  2712.     CALL DO_DEBUG_SET_DEFAULTS;
  2713.  
  2714. /**/
  2715. /* Get buffer for reading/writing the transferred file. */
  2716. /**/
  2717.     IO_= VECTOR(NIL);
  2718.     CALL EXPAND( IO_,4096,IO_BUF_SIZE )  ALTRET( ALT_RETURN ); /* 1 K         */
  2719.     WRITE_OUT.BUF_= IO_;
  2720.     READ_IN.BUF_= IO_;
  2721.     XSA_PARAM.BBUF_= VECTOR(BBUF);
  2722.     XSA_PARAM.KBUF_= VECTOR(KBUF);
  2723.  
  2724.     PACKET_= VECTOR(NIL);
  2725.     CALL EXPAND( PACKET_,4096,PACKET_MAX_SIZE )  ALTRET( ALT_RETURN );
  2726.     DATA_= VECTOR(NIL);
  2727.     CALL EXPAND( DATA_,4096,DATA_MAX_SIZE )      ALTRET( ALT_RETURN );
  2728.     READ_PACKET.BUF_= PACKET_;
  2729.     WRITE_PACKET.BUF_= PACKET_;
  2730.     SIZE= 0;
  2731.     EOR_BYTE(0) = %CR;
  2732.     EOR_BYTE(1) = %LF;
  2733.     EOR_BYTE_LEN= LENGTHC(EOR_BYTE(0)) + LENGTHC(EOR_BYTE(1));
  2734.     CALL STUFF_CHAR_IN_PACKET( EOR_BYTE(0) );
  2735.     CALL STUFF_CHAR_IN_PACKET( EOR_BYTE(1) );
  2736.     EOR_CHARS= SUBSTR(DATA_BUF,0,SIZE);
  2737.     EOR_CHARS_LEN= SIZE;
  2738.     REPEAT_CNT= 0;
  2739.  
  2740. /**/
  2741. /* Initialize SET FILE BINARY EXTENSIONS */
  2742. /**/
  2743.     EXTEN.LEN(0) = LENGTHC('?_ARC');
  2744.     EXTEN.TEXT(0)=         '?_ARC';
  2745.     EXTEN.LEN(1) = LENGTHC('?-ARC');
  2746.     EXTEN.TEXT(1)=         '?-ARC';
  2747.     EXTEN.LEN(2) = LENGTHC('?_COM');
  2748.     EXTEN.TEXT(2)=         '?_COM';
  2749.     EXTEN.LEN(3) = LENGTHC('?-COM');
  2750.     EXTEN.TEXT(3)=         '?-COM';
  2751.     EXTEN.LEN(4) = LENGTHC('?_EXE');
  2752.     EXTEN.TEXT(4)=         '?_EXE';
  2753.     EXTEN.LEN(5) = LENGTHC('?-EXE');
  2754.     EXTEN.TEXT(5)=         '?-EXE';
  2755.     EXTEN.LEN(6) = LENGTHC('?_LIB');
  2756.     EXTEN.TEXT(6)=         '?_LIB';
  2757.     EXTEN.LEN(7) = LENGTHC('?-LIB');
  2758.     EXTEN.TEXT(7)=         '?-LIB';
  2759.     NUM_EXTENSIONS= 8;
  2760.  
  2761. RE_TURN:
  2762.     RETURN;
  2763.  
  2764. ALT_RETURN:
  2765.     ALTRETURN;
  2766.  
  2767. END INITIALIZE;
  2768. %EJECT;
  2769. /****
  2770. *
  2771. *   I N S E R T _ E O R _ C H A R S
  2772. *
  2773. *   Insert the End Of Record sequence needed for the packet.  This is
  2774. *   currently always #M#J which is a CR,LF.
  2775. *
  2776. ****/
  2777.  
  2778. INSERT_EOR_CHARS: PROC(BUF,SIZE)  ALTRET;
  2779. DCL BUF                      CHAR(SIZE);
  2780. DCL SIZE                     UBIN;
  2781.  
  2782.     IF SIZE + EOR_CHARS_LEN > THEIR.PACKET_LENGTH-3 THEN/* Is there room?     */
  2783.        GOTO ALT_RETURN;                           /* Nope, don't bother       */
  2784.  
  2785.     IF CUR_MODE = %SET_FILE_MODE_TEXT## THEN      /* Are we in TEXT mode?     */
  2786.        DO X=0 TO EOR_CHARS_LEN-1;       /* Yep, send end of line character(s) */
  2787.           SUBSTR(BUF,SIZE,1)= SUBSTR(EOR_CHARS,X,1);
  2788.           SIZE= SIZE + 1;
  2789.           END;
  2790.  
  2791. RE_TURN:
  2792.     RETURN;
  2793.  
  2794. ALT_RETURN:
  2795.     ALTRETURN;
  2796.  
  2797. END INSERT_EOR_CHARS;
  2798. %EJECT;
  2799. /****
  2800. *
  2801. *   L O G
  2802. *
  2803. *   Write a record to the DEBUG file.  REC_TYPE indicates which type of record
  2804. *   it is.
  2805. *
  2806. ****/
  2807.  
  2808. LOG: PROC( REC_TYPE,BUF,LEN );
  2809. DCL REC_TYPE                 SBIN;
  2810. DCL BUF                      CHAR(LEN);
  2811. DCL LEN                      UBIN;
  2812.  
  2813. DCL 1 REC,
  2814.       2 TYPE                 CHAR(4)   CALIGNED,
  2815.       2 HH_MM_SS_SS          CHAR(11)  CALIGNED,
  2816.       2 DATA                 CHAR(497) CALIGNED;
  2817.  
  2818.     IF DEBUG_OPTS(REC_TYPE-%DEBUG_FID##)  AND  F$DEBUG$->F$DCB.FCD# THEN DO;
  2819.        DEBUG_KEY.EDIT= DEBUG_KEY.EDIT + 1000;
  2820.        REC.TYPE= DEBUG_LABEL(REC_TYPE-%DEBUG_FID##);
  2821.        CALL M$TIME( GET_TIME );
  2822.        REC.HH_MM_SS_SS= HHMMSSSS;
  2823.        REC.DATA= SUBSTR(BUF,0,LEN);
  2824.        WRITE_DEBUG.BUF_= VECTOR(SUBSTR(REC.TYPE,0,LENGTHC(REC.TYPE)+LEN+
  2825.                                                   LENGTHC(REC.HH_MM_SS_SS)) );
  2826.        CALL M$WRITE( WRITE_DEBUG );
  2827.        END;
  2828.  
  2829. RE_TURN:
  2830.     RETURN;
  2831.  
  2832. END LOG;
  2833. %EJECT;
  2834. /****
  2835. *
  2836. *   M E R G E _ F I L E _ N A M E _ I N T O _ D C B
  2837. *
  2838. *   Merge the name in TARGET into the F$IN DCB for use on a subsequent "real"
  2839. *   OPEN (this is just a TEST OPEN).
  2840. *
  2841. ****/
  2842.  
  2843. MERGE_FILE_NAME_INTO_DCB: PROC  ALTRET;
  2844.  
  2845.     TEST_OPEN_IO= DEFAULT_OPEN;
  2846.     TEST_OPEN_IO.V_= VECTOR(TEST_OPEN_IO.V);
  2847.     TEST_OPEN_IO.V.DCB#= DCBNUM(F$IN);
  2848.     TEST_OPEN_IO.V.FUN#= %IN#;                /* Make sure we open it input   */
  2849.     TEST_OPEN_IO.V.OPER.NXTF#= %YES#;         /* Assume more than one file    */
  2850.     TEST_OPEN_IO.V.OPER.TEST#= %YES#;
  2851.     TEST_OPEN_IO.V.ACS# = %SEQUEN#;
  2852.     TEST_OPEN_IO.V.SHARE# = %IN#;
  2853.     TEST_OPEN_IO.V.OPER.THISF#= %YES#;        /* Start with name in DCB       */
  2854.     CALL M$FID( FID_IO )  ALTRET( BAD_FID );  /* SRCE_FID -> TARGET           */
  2855.     IF TARGET.NAME# = ' ' THEN DO;
  2856.        TARGET.L#= LENGTHC('?');
  2857.        TARGET.NAME#= '?';
  2858.        END;
  2859.     CALL INDEX( TARGET_WILD_POS,'?',TARGET.NAME# );
  2860.     IO_NAME= TARGET;
  2861.     IF TARGET_WILD_POS = 0 THEN DO;           /* If leading ? then            */
  2862.        IO_NAME.L#= 0;                        /* we must search entire account */
  2863.        IO_NAME.NAME#= ' ';
  2864.        END;
  2865.     ELSE
  2866.        IF TARGET_WILD_POS < LENGTHC(IO_NAME.NAME#) THEN DO;/* If wildcarded   */
  2867.           IO_NAME.L#= TARGET_WILD_POS;        /* and ? is NOT first character */
  2868.           SUBSTR(IO_NAME.NAME#,TARGET_WILD_POS)= ' ';
  2869.           END;             /* then use characters up to ? as beginning prefix */
  2870.        ELSE
  2871.           TEST_OPEN_IO.V.OPER.NXTF#= %NO#;    /* Just one file                */
  2872.  
  2873.     CALL M$OPEN( MERGE_IN )  ALTRET( MERGE_ERR );/* Merge file name into F$IN */
  2874. RE_TURN:
  2875.     RETURN;
  2876.  
  2877. BAD_FID:
  2878.     CALL SEARCHR( L,X,SKIP_BLANKS,SRCE_FID )  WHENALTRETURN DO;
  2879.        L= LENGTHC(' ');
  2880.        END;
  2881.     CALL CONCAT( ERR_BUF,'File name passed to CP-6 (',
  2882.                          SUBSTR(SRCE_FID,0,L+1),
  2883.                          ') was not a valid CP-6 fid.' );
  2884.     CALL SEARCHR( L,X,SKIP_BLANKS,ERR_BUF );
  2885.     CALL SEND_ERROR_PACKET( ERR_BUF,L+1 );
  2886.     GOTO ALT_RETURN;
  2887.  
  2888. MERGE_ERR:
  2889.     CALL SEND_ERROR_PACKET;
  2890.  
  2891. ALT_RETURN:
  2892.     ALTRETURN;
  2893.  
  2894. END MERGE_FILE_NAME_INTO_DCB;
  2895. %EJECT;
  2896. /****
  2897. *
  2898. *   O P E N _ D E S T _ F I L E
  2899. *
  2900. *   OPEN the destination file; the one being RECEIVED by CP-6.  A record is
  2901. *   written to the LOG file (if one is OPEN) indicating that the transfer has
  2902. *   started.  If an error occurs, that too is recorded in the LOG file.
  2903. *
  2904. ****/
  2905.  
  2906. OPEN_DEST_FILE: PROC  ALTRET;
  2907.  
  2908.     CALL WRITE_LOG_REC( %LOG_HEADER# );
  2909.     CP6_FID= ' ';
  2910.     CALL GET_FID_FROM_PACKET( PACKET.DATA_BUF,LEN,PACKET_FID,J );
  2911.     FILE_CNT= FILE_CNT + 1;
  2912.     IF FILE_CNT > 1  OR  SRCE_FID = ' '  OR  IM_A_SERVER  THEN DO;
  2913.        SRCE_FID= PACKET_FID;
  2914.        CALL FIX_CP6_FILE_NAME( SRCE_FID,J,%RECEIVE## );
  2915.        END;
  2916.  
  2917.     OPEN_IO.V.FUN#= %CREATE#;
  2918.     OPEN_IO.V.EXIST#= HOW_RECEIVE;
  2919.     OPEN_IO.V.DCB#= DCBNUM(F$OUT);
  2920.     CALL M$FID( FID_IO )  ALTRET( OOPS );
  2921.     IF SET_FILE_EDIT = %SET_FILE_EDIT_YES## THEN DO;/* Create EDIT keyed file?*/
  2922.        OPEN_IO.V.ORG#= %KEYED#;               /* yep.                         */
  2923.        WRITE_OUT.KEY_= VECTOR(OUT_KEY);
  2924.        OUT_KEY.LEN= LENGTHC(OUT_KEY.EDIT);
  2925.        OUT_KEY.EDIT= 0;
  2926.        END;
  2927.     ELSE DO;                                  /* Create a CONSEC file         */
  2928.        OPEN_IO.V.ORG#= %CONSEC#;
  2929.        WRITE_OUT.KEY_= VECTOR(NIL);
  2930.        END;
  2931.     CALL DETERMINE_RCVD_MODE;
  2932.     OPEN_IO.V.ACS#= %SEQUEN#;
  2933.     OPEN_IO.V.ASN#= %FILE#;
  2934.     OPEN_IO.V.CTG#= %NO#;
  2935.     OPEN_IO.V.RES#= MERGE_IN.V.RES#;
  2936.     OPEN_IO.V.SHARE#= %NONE#;
  2937.     OPEN_IO.ACCT_= VECTOR(IO_ACCT);
  2938.     OPEN_IO.NAME_= VECTOR(TARGET);
  2939.     OPEN_IO.PASS_= VECTOR(IO_PASS);
  2940.     OPEN_IO.SN_=   VECTOR(IO_SN);
  2941.     CALL XSA$OPEN( OPEN_IO,XSA_PARAM )  ALTRET( OOPS );
  2942.     IF TARGET.NAME# = PACKET_FID THEN  /* Does CP-6 NAME = one in the packet? */
  2943.        PACKET_FID= ' ';                       /* Yep, use CP-6 fid in LOG msgs*/
  2944.     CP6_FID_LEN= LENGTHC(CP6_FID);
  2945.     CALL UNFID( F$OUT#,CP6_FID,CP6_FID_LEN );
  2946.     CALL WRITE_LOG_REC( %LOG_STRT_RECEIVE# );
  2947.     CALL WRITE_LOG_REC( %LOG_MAX_PACKET_SIZES# );
  2948.     IO_CNT= 0;
  2949.     IO_LEN= 0;
  2950.     IO_BUF= ' ';
  2951. RE_TURN:
  2952.     RETURN;
  2953.  
  2954. OOPS:
  2955.     CALL SEND_ERROR_PACKET;
  2956. ALT_RETURN:
  2957.     ALTRETURN;
  2958.  
  2959. END OPEN_DEST_FILE;
  2960. %EJECT;
  2961. /****
  2962. *
  2963. *   O P E N _ F I D
  2964. *
  2965. *   Utility routine to OPEN DCB number DCB# to the file FID whose name is
  2966. *   FID_LEN bytes and the FPT to use on the OPEN is FPT_OPEN.  IF FID was
  2967. *   not passed, use the name currently in the DCB.  If FPT_OPEN was not
  2968. *   passed, use the DEFAULT_OPEN fpt.
  2969. *
  2970. ****/
  2971.  
  2972. OPEN_FID: PROC( DCB#,FID,FID_LEN,OPEN_FPT )  ALTRET;
  2973. DCL DCB#                     UBIN;
  2974. DCL FID                      CHAR(FIDLEN);
  2975. DCL FID_LEN                  SBIN;
  2976. %FPT_OPEN    (FPTN                     = OPEN_FPT,
  2977.               STCLASS=" " );
  2978.  
  2979. DCL FIDLEN                   SBIN;
  2980.  
  2981.     IF ADDR(OPEN_FPT) = ADDR(NIL) THEN        /* Was an FPT passed?           */
  2982.        FPT_OPEN= DEFAULT_OPEN;                /* Nope, use default OPEN       */
  2983.     ELSE
  2984.        FPT_OPEN= OPEN_FPT;                    /* Yep, use it                  */
  2985.     FPT_OPEN.V_= VECTOR(FPT_OPEN.V);          /* Frame the V area in the FPT  */
  2986.     FPT_OPEN.V.DCB#= DCB#;                    /* Use their DCB#               */
  2987.  
  2988.     IF FID_LEN < 0 THEN DO;                   /* Should we find FID length?   */
  2989.        FIDLEN= -FID_LEN;                      /* Yep.                         */
  2990.        CALL SEARCHR( FIDLEN,X,SKIP_BLANKS,FID )  ALTRET( JUST_OPEN_IT );
  2991.        FIDLEN= FIDLEN + 1;
  2992.        END;
  2993.     ELSE
  2994.        FIDLEN= FID_LEN;                      /* Nope. They passed the FID_LEN */
  2995.  
  2996.     IF FID_LEN ~= 0 THEN DO;
  2997.        FPT_FID.V.SCRUB= '111111'B;
  2998.        FPT_FID.TEXTFID_= VECTOR(FID);
  2999.        CALL M$FID( FPT_FID )           ALTRET( ALT_RETURN );
  3000.        IF VLR_FID.NAME THEN                   /* Was NAME in FID?             */
  3001.           FPT_OPEN.NAME_= FPT_FID.NAME_;      /* Yep, use it on OPEN.         */
  3002.        ELSE
  3003.           FPT_OPEN.NAME_= VECTOR(NIL);        /* Nope.                        */
  3004.        IF VLR_FID.ACCT THEN                   /* Was ACCT in FID?             */
  3005.           FPT_OPEN.ACCT_= FPT_FID.ACCT_;      /* Yep, use it on the OPEN.     */
  3006.        ELSE
  3007.           FPT_OPEN.ACCT_= VECTOR(NIL);        /* Nope.                        */
  3008.        IF VLR_FID.PASS THEN                   /* Was PASSword in FID?         */
  3009.           FPT_OPEN.PASS_= FPT_FID.PASS_;      /* Yep, use it on the OPEN.     */
  3010.        ELSE
  3011.           FPT_OPEN.PASS_= VECTOR(NIL);        /* Nope.                        */
  3012.        IF VLR_FID.SN THEN                     /* Was an SN in the FID?        */
  3013.           FPT_OPEN.SN_= FPT_FID.SN_;          /* Yep, use it on the OPEN.     */
  3014.        ELSE
  3015.           FPT_OPEN.SN_= VECTOR(NIL);          /* Nope.                        */
  3016.        END;
  3017. JUST_OPEN_IT:
  3018.     CALL CLOSE_A_FILE( DCB# );                /* CLOSE the DCB, if it's OPEN  */
  3019.     IF DCB# = DCBNUM(F$IN)  OR  DCB# = DCBNUM(F$OUT)  THEN
  3020.        CALL XSA$OPEN( FPT_OPEN,XSA_PARAM )  ALTRET( ALT_RETURN );
  3021.     ELSE
  3022.        CALL M$OPEN( FPT_OPEN )              ALTRET( ALT_RETURN );
  3023. RE_TURN:
  3024.     RETURN;
  3025.  
  3026. ALT_RETURN:
  3027.     ALTRETURN;
  3028.  
  3029. END OPEN_FID;
  3030. %EJECT;
  3031. /****
  3032. *
  3033. *   O P E N _ N E X T _ F I L E
  3034. *
  3035. *   OPEN the next file.  If we can't, so indicate by ALTRETURNing.
  3036. *
  3037. ****/
  3038.  
  3039. OPEN_NEXT_FILE: PROC  ALTRET;
  3040.  
  3041.     CALL M$OPEN( TEST_OPEN_IO )   ALTRET( NOT_OPENED ); /* OPEN [nxtf]        */
  3042.     CUR_FILE= F$IN$->F$DCB.NAME#;             /* Remember filename OPENed     */
  3043.     ERRCODE= '0'B;                            /* No error detected            */
  3044.     GOTO RE_TURN;
  3045.  
  3046. NOT_OPENED:
  3047.     CUR_FILE= F$IN$->F$DCB.NAME#;             /* Remember filename we tried   */
  3048.     ERRCODE= %MONERR;                         /* remember error code          */
  3049.     ERRDCB#= %ERRDCB;                         /* remember what DCB it was on  */
  3050.     IF ERRCODE.ERR# = %E$FDEOF THEN           /* End of File Directory?       */
  3051. ALT_RETURN:
  3052.        ALTRETURN;                             /* Yep!                         */
  3053. RE_TURN:
  3054.     RETURN;
  3055.  
  3056. END OPEN_NEXT_FILE;
  3057. %EJECT;
  3058. /****
  3059. *
  3060. *   OPEN the F$PACKET_IN and F$PACKET_OUT dcbs to the comgroup specified
  3061. *   in CG_FID. If either open fails, we close both dcbs and hope that
  3062. *   everything is still ok.
  3063. *
  3064. ****/
  3065.  
  3066. OPEN_TO_CG: PROC;
  3067.  
  3068.     CALL CLOSE_A_FILE(DCBNUM(F$PACKET_IN));
  3069.     CALL M$FID(FID_CG);
  3070.     IF (CG_ASN=%FILE#) OR (CG_ASN=%COMGROUP#) THEN DO;
  3071.        CALL M$OPEN(OPEN_CG_IN) ALTRET(ALT_RETURN);
  3072.        CALL M$OPEN(OPEN_CG_OUT) ALTRET(ALT_RETURN);
  3073.        IF NOT GOT_TRMCTL THEN CALL INIT_ACTIVATION ALTRET(ALT_RETURN);
  3074.        CG_MODE = %YES#;
  3075.        END;
  3076.      ELSE DO;
  3077. ALT_RETURN:
  3078.        CALL PUT('Sorry, that comgroup is not currently available\');
  3079.        CG_MODE = %NO#;
  3080.        CALL CLOSE_A_FILE(DCBNUM(F$PACKET_IN));
  3081.        CALL CLOSE_A_FILE(DCBNUM(F$PACKET_OUT));
  3082.        END;
  3083. END OPEN_TO_CG;
  3084. %EJECT;
  3085. /****
  3086. *
  3087. *   P A R S E _ C C B U F
  3088. *
  3089. *   See if any commands were passed in CCBUF (ie. on the invocation line).  If
  3090. *   so, parse them.  Then, note any options that are only legal on the
  3091. *   invocation line.  Then, read any commands from the default file
  3092. *   (:KERMIT_INI) unless the specified NO DEFAULTS.  Then perform any left
  3093. *   over options on the invocation line that have not already been taken care
  3094. *   of.
  3095. *
  3096. ****/
  3097.  
  3098. PARSE_CCBUF: PROC  ALTRET;
  3099.  
  3100.     CCBUF_CMD= %NO#;
  3101.     IF B$JIT.CCDISP < B$JIT.CCARS  AND        /* Anything in CCBUF?           */
  3102.        SUBSTR(B$JIT.CCBUF,B$JIT.CCDISP) ~= '('  AND
  3103.        SUBSTR(B$JIT.CCBUF,B$JIT.CCDISP) ~= '()' THEN DO;
  3104.        OFFSET= LENGTHC('!') + B$JIT.CCDISP;
  3105.        CMD_BUF= SUBSTR(B$JIT.CCBUF,B$JIT.CCDISP+1);
  3106.        CMD_LEN= B$JIT.CCARS - B$JIT.CCDISP - 1;
  3107.        CMD_NUM= 9999;                       /* Force GET_A_CMD to look at CMD */
  3108.        NUM_CMDS= -1;
  3109.        CALL GET_A_CMD( CMD_BUF,CMD_LEN ) ALTRET(OOPS);/* Parse CCBUF commands */
  3110.        DO I=0 TO %BLK1_NSUBLKS-1;   /* Did they specify NO DEFAULTS in CCBUF? */
  3111.           IF %BLK1_SUBLK$(I)->P_SYM.CODE = %NO_DEFAULTS## THEN DO;
  3112.              IF %BLK1_NSUBLKS = 1 THEN        /* If ND is only CCBUF option,  */
  3113.                 CCBUF_CMD= %NO#;          /* Get additional options from user */
  3114.              NO_DEFAULTS= %YES#;     /* They did, remember they did.          */
  3115.              END;
  3116.           ELSE
  3117.              IF %BLK1_SUBLK$(I)->P_SYM.CODE = %DONT_GREET## THEN
  3118.                 GREETING= %NO#;               /* Remember not to greet them   */
  3119.              ELSE
  3120.                 IF %BLK1_SUBLK$(I)->P_SYM.CODE = %DONT_PROMPT## THEN DO;
  3121.                    PROMPT.VFC#= %YES#;
  3122.                    PROMPT.L#= LENGTHC('@');
  3123.                    PROMPT.NAME#= '@';
  3124.                    PROMPTING= %NO#;
  3125.                    CALL XUR$INIT( XUR_INIT );
  3126.                    END;
  3127.                 ELSE
  3128.                    IF %BLK1_SUBLK$(I)->P_SYM.CODE = %SILENT## THEN DO;
  3129.                       SILENT_MODE= %YES#;
  3130. %IF OS_VERSION~='B03';
  3131.                       XUR_INIT.ECHO#= %NEVER_ECHO#;
  3132. %ENDIF;
  3133.                       END;
  3134.                    ELSE
  3135.                       CCBUF_CMD= %YES#;
  3136.           END;
  3137.        IF GREETING THEN                       /* Did they want a greeting?    */
  3138.           CALL PUT( GREETING_MSG );           /* Yep, looks that way.         */
  3139.        IF NO_DEFAULTS THEN                    /* Did they say No DEFAULTS?    */
  3140.           GOTO SKIP_DEFAULTS;                 /* Yep, don't read them!        */
  3141.        CALL GET_DEFAULTS;                     /* Go read :KERMIT_INI file     */
  3142.        CMD_NUM= 9999;                       /* Force GET_A_CMD to look at CMD */
  3143.        NUM_CMDS= 0;
  3144.        CALL GET_A_CMD( CMD_BUF,CMD_LEN )  ALTRET( OOPS );
  3145. SKIP_DEFAULTS:
  3146.        CMD_NUM= -1;
  3147.        IF NOT DONE THEN                       /* If they aren't DONE already  */
  3148.           CALL DO_1_LINE_OF_OPTIONS( CMD_BUF,CMD_LEN );
  3149.        END;
  3150.     ELSE DO;
  3151.        CMD_NUM= 0;
  3152.        NUM_CMDS= 0;
  3153.        IF GREETING THEN                       /* Did they want a greeting?    */
  3154.           CALL PUT( GREETING_MSG );           /* Yep, looks that way!         */
  3155.        CALL GET_DEFAULTS;                     /* Go read :KERMIT_INI file     */
  3156.        END;
  3157.     OFFSET= 0;                           /* Set OFFSET for PUT_ERROR's finger */
  3158.     GOTO ARE_WE_DONE;
  3159.  
  3160. OOPS:
  3161.     CALL PUT_ERROR;                           /* Go give user the finger!     */
  3162. ARE_WE_DONE:
  3163.     IF CCBUF_CMD THEN
  3164.        DONE= %YES#;                           /* Quit now if cmd was in CCBUF */
  3165. RE_TURN:
  3166.     RETURN;
  3167.  
  3168. END PARSE_CCBUF;
  3169. %EJECT;
  3170. /****
  3171. *
  3172. *   P O S I T I O N _ F I L E
  3173. *
  3174. *   Position ourselves at the end of the indicated file (via DCB#).  If the
  3175. *   file is KEYED, return the KEY of the next record that will be written.
  3176. *
  3177. ****/
  3178.  
  3179. POSITION_FILE: PROC( DCB#,KEY,NAME,FPT_WRITE )  ALTRET;
  3180. DCL DCB#                     UBIN;
  3181. DCL 1 KEY,
  3182.       2 LEN                  UBIN(9)   CALIGNED,
  3183.       2 EDIT                 UBIN(27)  CALIGNED,
  3184.       2 *                    CHAR(252) CALIGNED;
  3185. DCL 1 NAME,
  3186.       2 LEN                  UBIN,
  3187.       2 NAME#                CHAR(76);
  3188. %FPT_WRITE   (FPTN                     = FPT_WRITE,
  3189.               STCLASS=);
  3190.  
  3191.     F_FDS.DCB#= 0;                            /* Convince X$WRITE NOT to WRITE*/
  3192.     KEY.LEN= LENGTHC(KEY.EDIT);
  3193.     KEY.EDIT= 0;
  3194.     IF DCBADDR(DCB#)->F$DCB.ORG# = %KEYED# THEN DO;
  3195.        FPT_WRITE.KEY_= VECTOR(KEY);
  3196.        IF DCBADDR(DCB#)->F$DCB.FEXT THEN DO;
  3197.           IF DCBADDR(DCB#)->F$DCB.NRECS# > 0 THEN DO;
  3198.              PFIL_EOF.V.DCB#= DCB#;
  3199.              CALL M$PFIL( PFIL_EOF )  ALTRET( ALT_RETURN );
  3200.              BACKUP1.V.DCB#= DCB#;
  3201.              BACKUP1.V.KEYR#= %YES#;
  3202.              BACKUP1.KEY_= VECTOR(KEY);
  3203.              CALL M$PRECORD( BACKUP1 )  ALTRET( ALT_RETURN );
  3204.              IF KEY.LEN ~= LENGTHC(KEY.EDIT) THEN DO;
  3205.                 CALL X$WRITE( F_FDS,FMT15_,VEC1_ );
  3206.                 ME_BUF= LO_BUF;
  3207.                 CALL PUT( SUBSTR(ME_BUF,1,F_FDS.BUFX-1),F_FDS.BUFX-1 );
  3208.                 CALL CLOSE_A_FILE( DCB# );
  3209.                 GOTO RE_TURN;
  3210.                 END;
  3211.              ELSE
  3212.                 IF KEY.EDIT >= 99999000 THEN DO;
  3213.                    CALL X$WRITE( F_FDS,FMT16_,VEC1_ );
  3214.                    ME_BUF= LO_BUF;
  3215.                    CALL PUT( SUBSTR(ME_BUF,1,F_FDS.BUFX-1),F_FDS.BUFX-1 );
  3216.                    CALL CLOSE_A_FILE( DCB# );
  3217.                    GOTO RE_TURN;
  3218.                    END;
  3219.              END;
  3220.           X= (KEY.EDIT/1000) + 1;
  3221.           CALL X$WRITE( F_FDS,FMT12_,VEC1_,VECTOR(X) );
  3222.           ME_BUF= LO_BUF;
  3223.           CALL PUT( SUBSTR(ME_BUF,1,F_FDS.BUFX-1),F_FDS.BUFX-1 );
  3224.           END;
  3225.        ELSE DO;
  3226.           CALL X$WRITE( F_FDS,FMT14_,VEC1_ );
  3227.           ME_BUF= LO_BUF;
  3228.           CALL PUT( SUBSTR(ME_BUF,1,F_FDS.BUFX-1),F_FDS.BUFX-1 );
  3229.           END;
  3230.        END;
  3231.     ELSE DO;
  3232.        FPT_WRITE.KEY_= VECTOR(NIL);
  3233.        CALL X$WRITE( F_FDS,FMT13_,VEC1_,VECTOR(DCBADDR(DCB#)->F$DCB.NRECS#) );
  3234.        ME_BUF= LO_BUF;
  3235.        CALL PUT( SUBSTR(ME_BUF,1,F_FDS.BUFX-1),F_FDS.BUFX-1 );
  3236.        END;
  3237.  
  3238.     F_FDS.DCB#= M$LO#;
  3239.  
  3240. RE_TURN:
  3241.     RETURN;
  3242.  
  3243. ALT_RETURN:
  3244.     ALTRETURN;
  3245.  
  3246. END POSITION_FILE;
  3247. %EJECT;
  3248. /****
  3249. *
  3250. *   P R I N T _ E R R O R _ P A C K E T  ( aka PRERRPKT )
  3251. *
  3252. *   Print contents of error packet received from remote host.
  3253. *
  3254. ****/
  3255.  
  3256. PRINT_ERROR_PACKET: PROC;
  3257.  
  3258.     CALL PUT('CP-6 KERMIT aborting with following error from remote KERMIT:\');
  3259.     CALL PUT( PACKET.DATA,LEN );
  3260.     STATE= %A_ABORT;
  3261. RE_TURN:
  3262.     RETURN;
  3263.  
  3264. END PRINT_ERROR_PACKET;
  3265. %EJECT;
  3266. /****
  3267. *
  3268. *   P U T
  3269. *
  3270. *   Output the passed message (the one in BUF) through DCB number DCB#.  If
  3271. *   LEN was not passed, then everything in BUF up to the first \ will be
  3272. *   printed.  If LEN is positive, it indicates the length of BUF.  If LEN is
  3273. *   negative then it indicates the maximum length of BUF.  In this case, BUF
  3274. *   is scanned from right to left (starting at the -LEN'th byte and working
  3275. *   left until a non blank is hit.  Everything from BUF upto and including the
  3276. *   non blank found will be printed.
  3277. *
  3278. ****/
  3279.  
  3280. PUT: PROC( BUF,LEN,DCB#,WE_SHOULD_ECHO );
  3281. DCL BUF                      CHAR(BUFLEN);
  3282. DCL LEN                      SBIN;
  3283. DCL DCB#                     UBIN;
  3284. DCL WE_SHOULD_ECHO           BIT(1);
  3285.  
  3286. DCL BUFLEN                   SBIN;
  3287.  
  3288.     IF ADDR(LEN) = ADDR(NIL) THEN DO; /* Is BUF message delimited by a '\'? */
  3289.        BUFLEN= 132;
  3290.        CALL INDEX1( BUFLEN,'\',BUF );
  3291.        END;
  3292.     ELSE
  3293.        IF LEN < 0 THEN DO;                    /* Should we find BUF length?   */
  3294.           BUFLEN= -LEN;                       /* Yep.                         */
  3295.           CALL SEARCHR( BUFLEN,X,SKIP_BLANKS,BUF )  ALTRET( BLANK_LINE );
  3296.           BUFLEN= BUFLEN + 1;
  3297.           END;
  3298.        ELSE
  3299.           IF LEN = 0 THEN                     /* Empty buffer (blank line)?   */
  3300. BLANK_LINE:
  3301.              BUFLEN= LENGTHC(' ');            /* Just print a blank           */
  3302.           ELSE
  3303.              BUFLEN= LEN;                     /* Use the length they passed   */
  3304.     IF ADDR(DCB#) = ADDR(NIL) THEN DO;
  3305.        F_FDS.DCB#= DEFAULT_DCB#;
  3306.        END;
  3307.     ELSE DO;
  3308.        F_FDS.DCB#= DCB#;
  3309.        END;
  3310.     IF ADDR(WE_SHOULD_ECHO) ~= ADDR(NIL)  AND  WE_SHOULD_ECHO THEN DO;
  3311.        CALL X$WRITE( F_FDS,FMT_,VECTOR(BUF) );
  3312.        F_FDS.DCB#= DEFAULT_DCB#;              /* ECHO it to M$ME too.         */
  3313.        END;
  3314.     IF (NOT SILENT_MODE) OR (ADDR(DCB#) ~= ADDR(NIL)) THEN
  3315.        CALL X$WRITE( F_FDS,FMT_,VECTOR(BUF) );
  3316. RE_TURN:
  3317.     RETURN;
  3318.  
  3319. END PUT;
  3320. %EJECT;
  3321. /****
  3322. *
  3323. *   P U T _ C H A R _ I N _ P A C K E T
  3324. *
  3325. *   Insert CHR into the packet.  If CHR equals the previous character passed
  3326. *   to this routine then the REPEAT_CNT is just incremented.  Otherwise, the
  3327. *   previous character is put in the packet and CHR is put in PREV_CHR for the
  3328. *   next call.
  3329. *
  3330. ****/
  3331.  
  3332. PUT_CHAR_IN_PACKET: PROC( CHR )  ALTRET;
  3333. DCL CHR                      CHAR(1);
  3334.  
  3335.     IF REPEATING THEN DO;                     /* Is repeating allowed?        */
  3336.        IF REPEAT_CNT > 0 THEN DO;             /* Anything in progress?        */
  3337.           IF CHR = PREV_CHR  AND  REPEAT_CNT < 94 THEN DO;
  3338.              REPEAT_CNT= REPEAT_CNT + 1;
  3339.              GOTO RE_TURN;
  3340.              END;
  3341.           CALL BUILD_REPEAT_SEQUENCE  WHENALTRETURN DO;
  3342.              NEXT_CALL= %PUT_CHAR_IN_PACKET#;
  3343.              CUR_CHR= CHR;
  3344.              GOTO ALT_RETURN;
  3345.              END;
  3346.           END;
  3347.        PREV_CHR= CHR;
  3348.        REPEAT_CNT= 1;
  3349.        END;
  3350.     ELSE DO;
  3351.        CALL CALC_SEQUENCE_LEN( CHR );
  3352.        IF SIZE+SEQUENCE_LEN > THEIR.PACKET_LENGTH-3 THEN DO;
  3353.           NEXT_CALL= %STUFF_CHAR_IN_PACKET#;
  3354.           CUR_CHR= CHR;
  3355.           GOTO ALT_RETURN;
  3356.           END;
  3357.        ELSE
  3358.           CALL STUFF_CHAR_IN_PACKET( CHR );
  3359.        END;
  3360.  
  3361. RE_TURN:
  3362.     RETURN;
  3363.  
  3364. ALT_RETURN:
  3365.        ALTRETURN;
  3366.  
  3367. END PUT_CHAR_IN_PACKET;
  3368. %EJECT;
  3369. /****
  3370. *
  3371. *   P U T _ E R R O R
  3372. *
  3373. *   Print out an error message.
  3374. *
  3375. ****/
  3376.  
  3377. PUT_ERROR: PROC( FINGER_POS );
  3378. DCL FINGER_POS               SBIN;
  3379.  
  3380.     IF ERRCODE.ERR# = %E$SYNERR THEN DO;
  3381.        IF (ADDR(FINGER_POS) = ADDR(NIL))  AND  (NOT SILENT_MODE) THEN
  3382.           CALL XUR$ECHOIF( M$LO# );
  3383.        CALL XUR$ERRPTR( OFFSET+P_PCB.HI_CHAR,M$LO# );
  3384.     /* CALL PUT( '.. Syntax error; parsing stopped where indicated\' ); */
  3385.        END;
  3386.     ELSE
  3387.        CALL XUR$ERRMSG( ERRCODE,ERRDCB# );
  3388. RE_TURN:
  3389.     RETURN;
  3390.  
  3391. END PUT_ERROR;
  3392. %EJECT;
  3393. /****
  3394. *
  3395. *   R E C E I V E _ A _ F I L E  ( aka RECSW )
  3396. *
  3397. *   This is the state table switcher for receiving files.
  3398. *
  3399. ****/
  3400.  
  3401. RECEIVE_A_FILE: PROC( INIT_STATE )  ALTRET;
  3402. DCL INIT_STATE               CHAR(1);
  3403.  
  3404.     NUM_TRIES= 0;
  3405.     STATE= INIT_STATE;
  3406.  
  3407.     DO WHILE( '1'B );
  3408.        DO SELECT( STATE );
  3409.           SELECT( %R_RINIT );
  3410.              CALL RECEIVE_INIT;
  3411.           SELECT( %F_FILE );
  3412.              CALL RECEIVE_FILE  ALTRET( RE_TURN );
  3413.           SELECT( %D_DATA );
  3414.              CALL RECEIVE_DATA;
  3415.           SELECT( %C_COMPLETE );
  3416.              GOTO RE_TURN;
  3417.           SELECT( %S_SINIT );
  3418.              GOTO RE_TURN;
  3419.           SELECT( %A_ABORT );
  3420.              GOTO RE_TURN;
  3421.           SELECT( ELSE );
  3422.  
  3423.           END;
  3424.        END;
  3425.  
  3426. RE_TURN:
  3427.     RETURN;
  3428.  
  3429. END RECEIVE_A_FILE;
  3430. %EJECT;
  3431. /****
  3432. *
  3433. *   R E C E I V E _ D A T A  ( aka RDATA )
  3434. *
  3435. *   Receive data
  3436. *
  3437. ****/
  3438.  
  3439. RECEIVE_DATA: PROC  ALTRET;
  3440.  
  3441.     NUM_TRIES= NUM_TRIES + 1;
  3442.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  3443.        STATE= %A_ABORT;
  3444.        GOTO RE_TURN;
  3445.        END;
  3446.  
  3447.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  3448.  
  3449.     DO SELECT( TYPE );
  3450.  
  3451.        SELECT( %D_DATA );
  3452.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  3453.              CALL BUFEMP( DATA,LEN );
  3454.              NUM_DATA_PACKETS= NUM_DATA_PACKETS + 1;
  3455.              END;
  3456.           ELSE
  3457.              IF RCVD_PACKNUM ~= MOD(PACKNUM+63,64) THEN DO;
  3458.                 GOTO NAK_THIS_PACKET;
  3459.                 END;
  3460.           CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  3461.           NUM_TRIES= 0;
  3462.           PACKNUM= MOD(RCVD_PACKNUM+1,64);
  3463.  
  3464.        SELECT( %F_FILE );
  3465.           IF RCVD_PACKNUM = MOD(PACKNUM+63,64) THEN DO;
  3466.              CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  3467.              NUM_TRIES= 0;
  3468.              END;
  3469.           ELSE
  3470.              STATE= %A_ABORT;
  3471.  
  3472.        SELECT( %Z_EOF );
  3473.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  3474.              CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  3475.              IF IO_LEN > 0 THEN               /* Anything left to write?      */
  3476.                 IF CUR_MODE = %SET_FILE_MODE_TEXT## THEN DO;
  3477.                    DO L=IO_LEN-1 DOWNTO 0 BY -1;
  3478.                       IF SUBSTR(IO_BUF,L,1) ~= %BINASC(0) THEN
  3479.                          GOTO IS_IT_CTL_Z;
  3480.                       END;
  3481.                    L= IO_LEN;
  3482.                    GOTO KEEP_IT;
  3483. IS_IT_CTL_Z:
  3484.                    IF SUBSTR(IO_BUF,L,1) = %SUB THEN
  3485.                       IF L>0 THEN
  3486. KEEP_IT:
  3487.                          CALL WRITE_RECORD( IO_BUF,L );
  3488.                       ELSE;
  3489.                    ELSE
  3490.                       CALL WRITE_RECORD( IO_BUF,L+1 );
  3491.                    END;
  3492.                 ELSE
  3493.                    CALL WRITE_RECORD( IO_BUF,IO_LEN );
  3494.              IF LEN > 0  AND  SUBSTR(DATA_BUF,0,1) = 'D'  THEN
  3495.                 /* Sender requested the transfer to be stopped */
  3496.                 CALL CLOSE_A_FILE( DCBNUM(F$OUT),%RELEASE# );
  3497.              ELSE
  3498.                 CALL CLOSE_A_FILE( DCBNUM(F$OUT) );
  3499.              CALL WRITE_LOG_REC( %LOG_NUM_DATA_PACKETS# );
  3500.              CALL WRITE_LOG_REC( %LOG_END_RECEIVE# );
  3501.              CALL WRITE_LOG_REC( %LOG_ELAPSED_TIME# );
  3502.              PACKNUM= MOD(RCVD_PACKNUM+1,64);
  3503.              STATE= %F_FILE;
  3504.              END;
  3505.           ELSE
  3506.              STATE= %A_ABORT;
  3507.  
  3508.        SELECT( %S_SINIT );
  3509.           STATE= %S_SINIT;
  3510.           CALL CLOSE_A_FILE( F$OUT#,SET_FILE_INCOMPLETE -
  3511.                                    %SET_FILE_INCOMPLETE_DISCARD##+1 );
  3512.  
  3513.        SELECT( %E_ERROR );
  3514.           STATE= %A_ABORT;
  3515.           CALL CLOSE_A_FILE( F$OUT#,SET_FILE_INCOMPLETE -
  3516.                                    %SET_FILE_INCOMPLETE_DISCARD##+1 );
  3517.  
  3518.        SELECT( ELSE );
  3519. NAK_THIS_PACKET:
  3520.           CALL SEND_PACKET( 'N',PACKNUM,0,' ' );
  3521.  
  3522.        END;
  3523.  
  3524. RE_TURN:
  3525.     RETURN;
  3526.  
  3527. END RECEIVE_DATA;
  3528. %EJECT;
  3529. /****
  3530. *
  3531. *   R E C E I V E _ F I L E  ( aka RFILE )
  3532. *
  3533. *   Receive File Header
  3534. *
  3535. ****/
  3536.  
  3537. RECEIVE_FILE: PROC  ALTRET;
  3538.  
  3539.     NUM_TRIES= NUM_TRIES + 1;
  3540.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  3541.        STATE= %A_ABORT;
  3542.        GOTO RE_TURN;
  3543.        END;
  3544.  
  3545.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  3546.  
  3547.     DO SELECT( TYPE );
  3548.  
  3549.        SELECT( %S_SINIT );
  3550.           IF RCVD_PACKNUM = MOD(PACKNUM+63,64) THEN DO;
  3551.              CALL SEND_OUR_PARAMS( %RECEIVE## );
  3552.              CALL SEND_PACKET( 'Y',PACKNUM,PACKLEN,DATA );
  3553.              NUM_TRIES= 0;
  3554.              END;
  3555.           ELSE
  3556.              STATE= %A_ABORT;
  3557.  
  3558.        SELECT( %Z_EOF );
  3559.           IF RCVD_PACKNUM = MOD(PACKNUM+63,64) THEN DO;
  3560.              CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  3561.              NUM_TRIES= 0;
  3562.              END;
  3563.           ELSE
  3564.              STATE= %A_ABORT;
  3565.  
  3566.        SELECT( %F_FILE );
  3567.           IF RCVD_PACKNUM ~= PACKNUM THEN DO;
  3568.              STATE= %A_ABORT;
  3569.              GOTO RE_TURN;
  3570.              END;
  3571.  
  3572.           REPEAT_CNT= 0;
  3573.           CALL OPEN_DEST_FILE  ALTRET( ALT_RETURN );
  3574.  
  3575.           CALL SEND_PACKET( 'Y',PACKNUM,0,' ' );
  3576.  
  3577.           AT_EOF= %NO#;                       /* We haven't seen a SUB yet!   */
  3578.           NUM_TRIES= 0;
  3579.           FILE_BYTE_CNT= 0;
  3580.           NEXT_CALL= %NOTHING#;
  3581.           NUM_DATA_PACKETS= 0;
  3582.           REC_CNT= 0;
  3583.           PACKNUM= MOD(PACKNUM+1,64);
  3584.           STATE= %D_DATA;
  3585.  
  3586.        SELECT( %B_BREAK );
  3587.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  3588.              CALL SEND_PACKET( 'Y',PACKNUM,0,' ' );
  3589.              STATE= %C_COMPLETE;
  3590.              END;
  3591.           ELSE
  3592.              STATE= %A_ABORT;
  3593.  
  3594.        SELECT( ELSE );
  3595.           STATE= %A_ABORT;
  3596.        END;
  3597. RE_TURN:
  3598.     RETURN;
  3599.  
  3600. ALT_RETURN:
  3601.     ALTRETURN;
  3602.  
  3603. END RECEIVE_FILE;
  3604. %EJECT;
  3605. /****
  3606. *
  3607. *   R E C E I V E _ I N I T  ( aka RINIT )
  3608. *
  3609. *   Receive Initialization
  3610. *
  3611. ****/
  3612.  
  3613. RECEIVE_INIT: PROC  ALTRET;
  3614.  
  3615.     NUM_TRIES= NUM_TRIES + 1;
  3616.     IF NUM_TRIES > PROTOCOL.MAX_INITIAL_RETRIES THEN DO;
  3617.        STATE= %A_ABORT;
  3618.        GOTO RE_TURN;
  3619.        END;
  3620.  
  3621.     X= MY.TIMEOUT;
  3622.     CALL SET_TIMEOUT( X );                    /* Set packet read timeout      */
  3623.  
  3624.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  3625.  
  3626.     DO SELECT( TYPE );
  3627.  
  3628.        SELECT( %S_SINIT );
  3629.           CALL RECEIVE_THEIR_PARAMS( LEN,%RECEIVE## );
  3630.           CALL SEND_OUR_PARAMS( %RECEIVE## );
  3631.           CALL SEND_PACKET( 'Y',PACKNUM,PACKLEN,DATA );
  3632.           NUM_TRIES= 0;
  3633.           PACKNUM= MOD(RCVD_PACKNUM+1,64);
  3634.           STATE= %F_FILE;
  3635.  
  3636.        SELECT( %E_ERROR );
  3637.           STATE= %A_ABORT;
  3638.  
  3639.        SELECT( ELSE );
  3640.           CALL SEND_PACKET( 'N',PACKNUM,0,' ' );
  3641.  
  3642.        END;
  3643.  
  3644. RE_TURN:
  3645.     RETURN;
  3646.  
  3647. END RECEIVE_INIT;
  3648. %EJECT;
  3649. /****
  3650. *
  3651. *   R E C E I V E _ P A C K
  3652. *
  3653. *   Read a packet.  Check to see if it is the special case where the user is
  3654. *   trying to exit out of SERVER mode.  If so, remember that and RETURN.
  3655. *   Otherwise, log a record in the DEBUG file (if we're DEBUGging), calculate
  3656. *   the checksum and check it.
  3657. *
  3658. ****/
  3659.  
  3660. RECEIVE_PACK: PROC( TYPE,NUM,LEN,DATA )  ALTRET;
  3661. DCL TYPE                     UBIN(9)   CALIGNED;
  3662. DCL NUM                      UBIN;
  3663. DCL LEN                      UBIN;
  3664. DCL DATA(0:93)               UBIN(9)   CALIGNED;
  3665. DCL DATA_BIT(0:93) REDEF DATA BIT(9);
  3666. DCL IX SBIN;
  3667.  
  3668. DCL PACKET_ARS               UBIN;
  3669.  
  3670.     IF NOT GOT_TRMCTL THEN CALL INIT_ACTIVATION ALTRET(ALT_RETURN);
  3671. READ_AGAIN:
  3672.     PACKET= '0'B;
  3673.     CALL M$READ( READ_PACKET )  ALTRET( TIMED_OUT );
  3674.     PACKET_ARS= F$PACKET_IN$ -> F$DCB.ARS#;
  3675. CONTINUE:
  3676.     SUBSTR(PACKET_BUF,PACKET_ARS,1)= F$PACKET_IN$ -> F$DCB.EOMCHAR#;
  3677.     CALL LOG( %DEBUG_RECEIVE##,PACKET,PACKET_ARS+LENGTHC(F$DCB.EOMCHAR#) );
  3678.  
  3679.     IF CHARMASK ~= '377'O THEN
  3680.        DO J=0 TO (PACKET_ARS+3)/4;
  3681.           PACKET_WORD(J) = PACKET_WORD(J) & WORDMASK;
  3682.           END;
  3683.  
  3684.     /*
  3685.        Do they just want out of SERVER mode?
  3686.     */
  3687.     IF IM_A_SERVER  AND
  3688.       (PACKET_ARS = 0                         OR
  3689.        SUBSTR(PACKET_BUF,0,PACKET_ARS) = ' '  OR
  3690.        SUBSTR(PACKET_BUF,0,PACKET_ARS) = 'END') THEN DO;
  3691.        PACKET_BUF= 'END';
  3692.        TRANSFER_INTERRUPTED= %YES#;
  3693.        GOTO RE_TURN;
  3694.        END;
  3695.  
  3696.     /*
  3697.         We have to flush the characters found between packets, so
  3698.         we look for a 'start_of_packet', and ignore anything that
  3699.         comes before that.
  3700.     */
  3701.  
  3702.     IF PACKET_ARS < 4 THEN GOTO READ_AGAIN;
  3703.     IF PACKET.MARK ~= MY.START_OF_PACKET THEN DO;
  3704.        CALL INDEX(IX,MY.START_OF_PACKET,SUBSTR(PACKET_BUF,0,PACKET_ARS))
  3705.           ALTRET(READ_AGAIN);
  3706.        PACKET_BUF = SUBSTR(PACKET_BUF,IX,PACKET_ARS-IX);
  3707.        PACKET_ARS = PACKET_ARS-IX;
  3708.        IF PACKET_ARS < 4 THEN GOTO READ_AGAIN;
  3709.        END;
  3710.  
  3711.  
  3712.     LEN= PACKET.LEN - 3 - ASCBIN(' ');
  3713.  
  3714.     CALL UNCHAR( ,PACKET.SEQ,NUM );
  3715.  
  3716.     TYPE= PACKET.TYPE;
  3717.  
  3718.     CALL BLOCK_MOVE( DATA,PACKET.DATA,LEN );
  3719.  
  3720.     CALL UNCHAR( ,PACKET.DATA(LEN),RCVD_CHECKSUM );
  3721.  
  3722.     CALL CALC_CHECKSUM( CHECKSUM );
  3723.  
  3724.     IF RCVD_CHECKSUM ~= CHECKSUM THEN         /* Bad checksum?                */
  3725. NAK_THIS_PACKET:
  3726.        TYPE= ASCBIN(%N_NAK);                  /* yep, NAK this packet         */
  3727.  
  3728. RE_TURN:
  3729.     RETURN;
  3730.  
  3731. TIMED_OUT:
  3732.     PACKET_ARS= F$PACKET_IN$ -> F$DCB.ARS#;
  3733.     IF (B$TCB$->B$TCB.ALT$->B$ALT.ERR.CODE = %E$TIMO) OR /* Did READ timeout?*/
  3734.     (B$TCB$->B$TCB.ALT$->B$ALT.ERR.CODE = %E$EOF) THEN
  3735.        IF PACKET_ARS > 0 THEN                          /* Yep, anything read? */
  3736.           GOTO CONTINUE;                               /* Yep, go use it      */
  3737.        ELSE DO;
  3738.           CALL LOG( %DEBUG_TIMEOUT##,' Timeout in RECEIVE_PACK.',25 );
  3739.           TYPE= ASCBIN(%N_NAK);
  3740.           END;
  3741.     ELSE
  3742.        IF B$TCB$->B$TCB.ALT$->B$ALT.ERR.CODE = %E$DI THEN /* Noisy line?      */
  3743.           GOTO READ_AGAIN;                                /* Yep, try again   */
  3744.        ELSE
  3745.           CALL M$MERC;
  3746. ALT_RETURN:
  3747.     ALTRETURN;
  3748.  
  3749. END RECEIVE_PACK;
  3750. %EJECT;
  3751. /****
  3752. *
  3753. *   R E C E I V E _ T H E I R _ P A R A M S  ( aka rpar )
  3754. *
  3755. *   Get the other host's send-init parameters.
  3756. *
  3757. ****/
  3758.  
  3759. RECEIVE_THEIR_PARAMS: PROC( LEN,DIRECTION );
  3760. DCL LEN                      UBIN;
  3761. DCL DIRECTION                UBIN;
  3762.  
  3763.     CALL UNCHAR( THEIR.PACKET_LENGTH,DATA(0) );  /* MAXL */
  3764.     CALL UNCHAR( THEIR.TIMEOUT,      DATA(1) );  /* TIME */
  3765.     CALL UNCHAR( THEIR.PADDING,      DATA(2) );  /* NPAD */
  3766.     CALL    CTL( THEIR.PADCHAR,      DATA(3) );  /* PADC */
  3767.     CALL UNCHAR( THEIR.END_OF_LINE,  DATA(4) );  /* EOL  */
  3768.     THEIR.QUOTE= BINASC(DATA(5));                /* QCTL */
  3769.     IF LEN > 6 THEN
  3770.        THEIR.QBIN= BINASC(DATA(6));              /* QBIN */
  3771.     ELSE
  3772.        THEIR.QBIN= 'N';
  3773.     IF LEN > 7 THEN
  3774.        THEIR.BLOCK_CHECK= %ASCBIN('1');          /* CHKT */
  3775.     ELSE
  3776.        THEIR.BLOCK_CHECK= %ASCBIN('1');          /* CHKT */
  3777.     IF LEN > 8 THEN
  3778.        THEIR.REPT= BINASC(DATA(8));              /* REPT */
  3779.     ELSE
  3780.        THEIR.REPT= ' ';
  3781.     IF LEN > 9 THEN
  3782.        CALL UNCHAR( THEIR.CAPAS,DATA(9) );       /* MASK */
  3783.     ELSE
  3784.        CALL UNCHAR( THEIR.CAPAS,DATA(9) );       /* MASK */
  3785.     CALL SET_PARITY_MASK( THEIR.QBIN );
  3786.     IF DIRECTION = %RECEIVE## THEN DO;
  3787.        IF THEIR.QBIN = 'Y' THEN
  3788.           IF CHARMASK = '177'O THEN DO;    /* Do we need to do 8-bit quoting? */
  3789.              BINARY_QUOTING= %YES#;        /* Yep.                            */
  3790.              IF MY_DEFAULT.QBIN = 'Y' THEN /* If my default is a Y,           */
  3791.                 MY.QBIN= '&';              /* send them an &                  */
  3792.              ELSE
  3793.                 MY.QBIN= MY_DEFAULT.QBIN;  /* Otherwise, use what user said   */
  3794.              THEIR.QBIN= MY.QBIN;          /* Make theirs the same            */
  3795.              END;
  3796.           ELSE DO;
  3797.              BINARY_QUOTING= %NO#;         /* Don't do 8-bit quoting          */
  3798.              MY.QBIN= 'N';
  3799.              THEIR.QBIN= 'N';
  3800.              END;
  3801.        ELSE
  3802.           IF (THEIR.QBIN >= '!'  AND  THEIR.QBIN <= '>')   OR
  3803.              (THEIR.QBIN >= '`'  AND  THEIR.QBIN <= '~')  THEN DO;
  3804.              MY.QBIN= THEIR.QBIN;             /* Use their QBIN               */
  3805.              BINARY_QUOTING= %YES#;
  3806.              END;
  3807.           ELSE DO;                            /* Strange character            */
  3808.              MY.QBIN= 'N';                    /* Don't do 8-bit quoting       */
  3809.              BINARY_QUOTING= %NO#;
  3810.              END;
  3811.        IF (THEIR.REPT >= '!'  AND  THEIR.REPT <= '>')   OR
  3812.           (THEIR.REPT >= '`'  AND  THEIR.REPT <= '~')  THEN DO;
  3813.           MY.REPT= THEIR.REPT;
  3814.           REPEATING= %YES#;
  3815.           REPEAT_LEN= LENGTHC(THEIR.REPT) + 1;
  3816.           END;
  3817.        ELSE DO;
  3818.           REPEATING= %NO#;
  3819.           REPEAT_LEN= 0;
  3820.           MY.REPT= ' ';
  3821.           END;
  3822.        END;
  3823.     ELSE DO; /* DIRECTION = %SEND## */
  3824.        IF (THEIR.QBIN >= '!'  AND  THEIR.QBIN <= '>')   OR
  3825.           (THEIR.QBIN >= '`'  AND  THEIR.QBIN <= '~')  THEN DO;
  3826.           MY.QBIN= THEIR.QBIN;                /* Use their quote character    */
  3827.           BINARY_QUOTING= %YES#;
  3828.           END;
  3829.        ELSE DO;
  3830.           MY.QBIN= 'N';                       /* Don't do 8-bit quoting       */
  3831.           BINARY_QUOTING= %NO#;
  3832.           END;
  3833.        IF ((THEIR.REPT >= '!'  AND  THEIR.REPT <= '>')   OR
  3834.            (THEIR.REPT >= '`'  AND  THEIR.REPT <= '~'))  AND
  3835.           MY.REPT = THEIR.REPT  THEN DO;
  3836.           REPEATING= %YES#;
  3837.           REPEAT_LEN= LENGTHC(THEIR.REPT) + 1;
  3838.           END;
  3839.        ELSE DO;
  3840.           REPEATING= %NO#;
  3841.           REPEAT_LEN= 0;
  3842.           END;
  3843.        END;
  3844.  
  3845. RE_TURN:
  3846.     RETURN;
  3847.  
  3848. END RECEIVE_THEIR_PARAMS;
  3849. %EJECT;
  3850. /****
  3851. *
  3852. *   S E N D
  3853. *
  3854. *   SEND a file(s).
  3855. *
  3856. ****/
  3857.  
  3858. SEND: PROC  ALTRET;
  3859.  
  3860.     SET_STEPCC.V.STEPCC# = 3;     /* default stepcc= can't find file */
  3861.     CALL MERGE_FILE_NAME_INTO_DCB  ALTRET( ALT_RETURN );
  3862. %IF OS_VERSION='B03';
  3863.     WILD_COMPARE.PATTERN$= ADDR(TARGET);
  3864. %ELSE;
  3865.     WILD_COMPARE.PATTERN_= VECTOR(SUBSTR(TARGET.NAME#,0,TARGET.L#));
  3866. %ENDIF;
  3867.  
  3868.     IF DELAY > 0  AND               /* Should we pause before initial packet? */
  3869.        NOT IM_A_SERVER THEN DO;
  3870.        CALL SNOOZE( DELAY );
  3871.        END;
  3872.  
  3873.     FILE_CNT= 0;                              /* No files sent yet...         */
  3874.     OK_TO_SEND= %YES#;
  3875.     PACKNUM= 0;                               /* Zero packet number           */
  3876.     TRANSFER_INTERRUPTED= %NO#;
  3877.  
  3878.     DO WHILE( OK_TO_SEND  AND  (NOT TRANSFER_INTERRUPTED) );
  3879.        CALL OPEN_NEXT_FILE             ALTRET( PUT_SUM );
  3880.        CALL DO_WE_WANT_THIS_FILE       ALTRET( CLOSE_F$IN );
  3881.        CALL SEND_A_FILE                ALTRET( CLOSE_F$IN );
  3882. CLOSE_F$IN:
  3883.        CALL CLOSE_A_FILE( DCBNUM(F$IN) );
  3884.        TEST_OPEN_IO.V.OPER.THISF#= %NO#;
  3885.        END;
  3886.  
  3887. PUT_SUM: ;
  3888.     IF FILE_CNT > 0  AND                      /* Were any file sent?          */
  3889.        (NOT TRANSFER_INTERRUPTED)  THEN DO;
  3890.        STATE= %B_BREAK;                       /* Send BREAK to stop transfer  */
  3891.        DO WHILE( STATE = %B_BREAK );
  3892.           CALL SEND_BREAK;
  3893.           END;
  3894.        END;
  3895.  
  3896. RE_TURN:
  3897.     RETURN;
  3898.  
  3899. ALT_RETURN:
  3900.     ALTRETURN;
  3901.  
  3902. END SEND;
  3903. %EJECT;
  3904. /****
  3905. *
  3906. *   S E N D _ A _ F I L E  ( aka sendsw )
  3907. *
  3908. *   SENDSW is the state table switcher for sending files.  It loops until
  3909. *   either it finishes, or an error is encountered.  The routines called
  3910. *   by SENDSW are responsible for changing the state.
  3911. *
  3912. ****/
  3913.  
  3914. SEND_A_FILE: PROC  ALTRET;
  3915.  
  3916.     CALL OPEN_FID( DCBNUM(F$IN),' ',0 )  ALTRET( OPEN_ERR );
  3917.     CALL DETERMINE_SEND_MODE;                 /* Determine MODE               */
  3918.     CP6_FID= SUBSTR(CUR_FILE.NAME#,0,CUR_FILE.L#);
  3919.     PACKET_FID= CP6_FID;
  3920.     X= CUR_FILE.L#;
  3921.     CALL FIX_PC_FILE_NAME( PACKET_FID,X );
  3922.     IF TARGET_WILD_POS = LENGTHC(TARGET.NAME#) THEN /* Just one file?         */
  3923.        IF NOT IM_A_SERVER THEN
  3924.           IF %BLK2_NSUBLKS > 1 THEN DO;       /* Was "AS" name specified?     */
  3925.              BLK3$= %BLK2_SUBLK$(1);          /* Yep, point to it.            */
  3926.              PACKET_FID= %BLK3_TEXT;
  3927.              END;
  3928.  
  3929.     CALL WRITE_LOG_REC( %LOG_HEADER# );
  3930.     CALL WRITE_LOG_REC( %LOG_STRT_SEND# );
  3931.     CALL WRITE_LOG_REC( %LOG_MAX_PACKET_SIZES# );
  3932.     SET_STEPCC.V.STEPCC# = 2;     /* stepcc= starting to send */
  3933.  
  3934.     X= MY.TIMEOUT;
  3935.     CALL SET_TIMEOUT( X );
  3936.  
  3937.     AT_EOF= %NO#;                             /* Assume we haven't hit EOF yet*/
  3938.     DONE_SENDING= %NO#;                       /* We aren't done yet           */
  3939.     FILE_BYTE_CNT= 0;                         /* Zero # bytes in file count   */
  3940.     NEXT_CALL= %NOTHING#;                     /* Zero this to start with      */
  3941.     NUM_TRIES= 0;                             /* Zero retry count             */
  3942.     NUM_DATA_PACKETS= 0;                      /* Zero count of Data packets   */
  3943.     REPEAT_CNT= 0;                            /* Zero the REPEAT count        */
  3944.     FILE_CNT= FILE_CNT + 1;                   /* Count this file              */
  3945.     IF FILE_CNT < 2 THEN
  3946.        STATE= %S_SINIT;
  3947.     ELSE
  3948.        STATE= %F_FILE;
  3949.     DO UNTIL( DONE_SENDING  OR  TRANSFER_INTERRUPTED );
  3950.        DO SELECT( STATE );
  3951.           SELECT( %D_DATA );
  3952.              CALL SEND_DATA;
  3953.           SELECT( %F_FILE );
  3954.              CALL SEND_FILE;
  3955.           SELECT( %Z_EOF );
  3956.              CALL SEND_EOF;
  3957.           SELECT( %S_SINIT );
  3958.              CALL SEND_INIT;
  3959.           SELECT( %B_BREAK );
  3960.              CALL SEND_BREAK;
  3961.           SELECT( %C_COMPLETE );
  3962.              DONE_SENDING= %YES#;
  3963.           SELECT( %A_ABORT );
  3964.              DONE_SENDING= %YES#;
  3965.           SELECT( ELSE );
  3966.              CALL CONCAT( ERR_BUF,'>> Unexpected SEND state of ''',
  3967.                                   STATE,
  3968.                                   ''' in SEND_A_FILE\' );
  3969.              CALL SEND_ERROR_PACKET( ERR_BUF,46 );
  3970.  
  3971.           END;
  3972.        END;
  3973.  
  3974.  
  3975. RE_TURN:
  3976.     RETURN;
  3977.  
  3978. OPEN_ERR:
  3979.     IF IM_A_SERVER THEN DO;
  3980.        CALL SEND_ERROR_PACKET;
  3981.        END;
  3982.     ELSE DO;
  3983.        ERRCODE= %MONERR;
  3984.        ERRDCB#= %ERRDCB;
  3985.        CALL XUR$ERRMSG( ERRCODE,ERRDCB# );
  3986.        END;
  3987.     OK_TO_SEND= %NO#;
  3988. ALT_RETURN:
  3989.     SET_STEPCC.V.STEPCC# = 3;     /* stepcc= can't find file */
  3990.     ALTRETURN;
  3991.  
  3992. END SEND_A_FILE;
  3993. %EJECT;
  3994. /****
  3995. *
  3996. *   S E N D _ B R E A K  ( aka SBREAK )
  3997. *
  3998. *   Send Break (EOT)
  3999. *
  4000. ****/
  4001.  
  4002. SEND_BREAK: PROC  ALTRET;
  4003.  
  4004.     NUM_TRIES= NUM_TRIES + 1;
  4005.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  4006.        STATE= %A_ABORT;
  4007.        GOTO RE_TURN;
  4008.        END;
  4009.  
  4010.     CALL SEND_PACKET( 'B',PACKNUM,0,DATA );
  4011.  
  4012.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  4013.  
  4014.     DO SELECT( TYPE );
  4015.  
  4016.        SELECT( %N_NAK );
  4017.           IF RCVD_PACKNUM = MOD(PACKNUM+1,64) THEN
  4018.              GOTO ACKUALLY_ITS_OK;
  4019.  
  4020.        SELECT( %Y_ACK );
  4021.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  4022. ACKUALLY_ITS_OK:
  4023.              NUM_TRIES= 0;                    /* Reset number of tries        */
  4024.              PACKNUM= MOD(PACKNUM+1,64);
  4025.              STATE= %C_COMPLETE;
  4026.              CALL SET_TIMEOUT( 0 );
  4027.              END;
  4028.  
  4029.        SELECT( %E_ERROR );
  4030.           CALL PRINT_ERROR_PACKET;
  4031.  
  4032.        SELECT( ELSE );
  4033.           STATE= %A_ABORT;
  4034.  
  4035.        END;
  4036.  
  4037. RE_TURN:
  4038.     RETURN;
  4039.  
  4040. END SEND_BREAK;
  4041. %EJECT;
  4042. /****
  4043. *
  4044. *   S E N D _ D A T A  ( aka SDATA )
  4045. *
  4046. *   Send File Data
  4047. *
  4048. ****/
  4049.  
  4050. SEND_DATA: PROC  ALTRET;
  4051.  
  4052.     NUM_TRIES= NUM_TRIES + 1;
  4053.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  4054.        STATE= %A_ABORT;
  4055.        GOTO RE_TURN;
  4056.        END;
  4057.  
  4058.     CALL SEND_PACKET( 'D',PACKNUM,SIZE,DATA );
  4059.  
  4060.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  4061.  
  4062.     DO SELECT( TYPE );
  4063.  
  4064.        SELECT( %N_NAK );
  4065.           IF RCVD_PACKNUM = MOD(PACKNUM+1,64) THEN
  4066.              GOTO ACKUALLY_ITS_OK;
  4067.  
  4068.        SELECT( %Y_ACK );
  4069.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  4070. ACKUALLY_ITS_OK:
  4071.              NUM_DATA_PACKETS= NUM_DATA_PACKETS + 1;
  4072.              NUM_TRIES= 0;                    /* Reset number of tries        */
  4073.              PACKNUM= MOD(PACKNUM+1,64);
  4074.              IF LEN > 0  AND
  4075.                (SUBSTR(DATA_BUF,0,1) = 'X' OR
  4076.                 SUBSTR(DATA_BUF,0,1) = 'Z')  THEN DO;
  4077.                 STATE= %Z_EOF;
  4078.                 IF SUBSTR(DATA_BUF,0,1) = 'Z' THEN
  4079.                    TRANSFER_INTERRUPTED= %YES#; /* Stop multi file transfer   */
  4080.                 END;
  4081.              ELSE DO;
  4082.                 CALL BUFILL  ALTRET( RE_TURN );
  4083.                 STATE= %D_DATA;
  4084.                 END;
  4085.              END;
  4086.  
  4087.        SELECT( %E_ERROR );
  4088.           CALL PRINT_ERROR_PACKET;
  4089.  
  4090.        SELECT( ELSE );
  4091.           STATE= %A_ABORT;
  4092.  
  4093.        END;
  4094.  
  4095. RE_TURN:
  4096.     RETURN;
  4097.  
  4098. END SEND_DATA;
  4099. %EJECT;
  4100. /****
  4101. *
  4102. *   S E N D _ E O F  ( aka SEOF )
  4103. *
  4104. *   Send End-Of-File.
  4105. *
  4106. ****/
  4107.  
  4108. SEND_EOF: PROC  ALTRET;
  4109.  
  4110.     NUM_TRIES= NUM_TRIES + 1;
  4111.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  4112.        STATE= %A_ABORT;
  4113.        GOTO RE_TURN;
  4114.        END;
  4115.  
  4116.     IF  TRANSFER_INTERRUPTED  THEN DO;
  4117.        LEN= LENGTHC('D');
  4118.        SUBSTR(DATA_BUF,0,1)= 'D';
  4119.        END;
  4120.     ELSE
  4121.        LEN= 0;
  4122.     CALL SEND_PACKET( 'Z',PACKNUM,0,DATA );
  4123.  
  4124.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  4125.  
  4126.     DO SELECT( TYPE );
  4127.  
  4128.        SELECT( %N_NAK );
  4129.           IF RCVD_PACKNUM = MOD(PACKNUM+1,64) THEN
  4130.              GOTO ACKUALLY_ITS_OK;
  4131.  
  4132.        SELECT( %Y_ACK );
  4133.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  4134. ACKUALLY_ITS_OK:
  4135.              CALL WRITE_LOG_REC( %LOG_END_SEND# );
  4136.              CALL WRITE_LOG_REC( %LOG_NUM_DATA_PACKETS# );
  4137.              CALL WRITE_LOG_REC( %LOG_ELAPSED_TIME# );
  4138.              SET_STEPCC.V.STEPCC# = 0;  /* stepcc = successful send */
  4139.              NUM_TRIES= 0;                    /* Reset number of tries        */
  4140.              PACKNUM= MOD(PACKNUM+1,64);
  4141.              STATE= %C_COMPLETE;
  4142.              END;
  4143.  
  4144.        SELECT( %E_ERROR );
  4145.           CALL PRINT_ERROR_PACKET;
  4146.  
  4147.        SELECT( ELSE );
  4148.           STATE= %A_ABORT;
  4149.  
  4150.        END;
  4151.  
  4152. RE_TURN:
  4153.     RETURN;
  4154.  
  4155. END SEND_EOF;
  4156. %EJECT;
  4157. /****
  4158. *
  4159. *   S E N D _ E R R O R _ P A C K E T
  4160. *
  4161. *   Send an error packet to the "other computer".
  4162. *
  4163. ****/
  4164.  
  4165. SEND_ERROR_PACKET: PROC( BUF,LEN );
  4166. DCL BUF                      CHAR(LEN);
  4167. DCL LEN                      UBIN;
  4168.  
  4169.     IF ADDR(BUF)=ADDR(NIL) THEN DO;
  4170.        FPT_ERRMSG.V.DCB#= %ERRDCB;
  4171.        ERRCODE= %MONERR;
  4172.        CALL M$ERRMSG( FPT_ERRMSG );
  4173.        CALL SEARCHR( I,X,SKIP_BLANKS,ERR_BUF )  WHENALTRETURN DO;
  4174.           I= LENGTHC(ERR_BUF) - 1;
  4175.           END;
  4176.        I= I + 1;
  4177.        END;
  4178.     ELSE DO;
  4179.        I= LEN;
  4180.        ERR_BUF= BUF;
  4181.        END;
  4182.  
  4183.     CALL SEND_PACKET( 'E',PACKNUM,I,ERR_BUF );
  4184.     CALL WRITE_LOG_REC( %LOG_ERRMSG#,I );
  4185. RE_TURN:
  4186.     RETURN;
  4187.  
  4188. END SEND_ERROR_PACKET;
  4189. %EJECT;
  4190. /****
  4191. *
  4192. *   S E N D _ F I L E  ( aka SFILE )
  4193. *
  4194. *   Send File Header.
  4195. *
  4196. ****/
  4197.  
  4198. SEND_FILE: PROC  ALTRET;
  4199.  
  4200.     ARS= 0;
  4201.     IO_INDX= 999;
  4202.     REC_CNT= 0;                               /* Zero number record read      */
  4203.     OUT_INDX= 0;
  4204.  
  4205.     NUM_TRIES= NUM_TRIES + 1;
  4206.     IF NUM_TRIES > PROTOCOL.MAX_PACKET_RETRIES THEN DO;
  4207.        STATE= %A_ABORT;
  4208.        GOTO RE_TURN;
  4209.        END;
  4210.  
  4211.     CALL SEARCHR( LEN,X,SKIP_BLANKS,PACKET_FID );
  4212.     CALL SEND_PACKET( 'F',PACKNUM,LEN+1,PACKET_FID );
  4213.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  4214.  
  4215.     DO SELECT( TYPE );
  4216.        SELECT( %N_NAK );
  4217.           IF RCVD_PACKNUM = MOD(PACKNUM+1,64) THEN
  4218.              GOTO ACK_UALLY_ITS_OK;
  4219.        SELECT( %Y_ACK );
  4220.           IF RCVD_PACKNUM = PACKNUM THEN DO;
  4221. ACK_UALLY_ITS_OK:
  4222.              NUM_TRIES= 0;
  4223.              PACKNUM= MOD(PACKNUM+1,64);
  4224.              CALL BUFILL  ALTRET( RE_TURN );
  4225.              STATE= %D_DATA;
  4226.              END;
  4227.        SELECT( %E_ERROR );
  4228.           CALL PRINT_ERROR_PACKET;
  4229.        SELECT( ELSE );
  4230.           STATE= %A_ABORT;
  4231.        END;
  4232.  
  4233. RE_TURN:
  4234.     RETURN;
  4235.  
  4236. END SEND_FILE;
  4237. %EJECT;
  4238. /****
  4239. *
  4240. *   S E N D _ I N I T  ( aka SINIT )
  4241. *
  4242. *   Send Initiate: send this host's parameters and get other sides back.
  4243. *
  4244. ****/
  4245.  
  4246. SEND_INIT: PROC  ALTRET;
  4247.  
  4248.     NUM_TRIES= NUM_TRIES + 1;
  4249.     IF NUM_TRIES > PROTOCOL.MAX_INITIAL_RETRIES THEN DO;
  4250.        STATE= %A_ABORT;
  4251.        GOTO RE_TURN;
  4252.        END;
  4253.  
  4254.     CALL SEND_OUR_PARAMS( %SEND## );          /* Fill in our init info packet */
  4255.     CALL FLUSH_INPUT;                         /* Flush any pending input      */
  4256.     CALL SEND_PACKET( 'S',PACKNUM,PACKLEN,DATA );  /* Send our S packet       */
  4257.     CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );/* Get a reply            */
  4258.  
  4259.     DO SELECT( TYPE );                        /* What did they send?          */
  4260.  
  4261.        SELECT( %N_NAK );
  4262.  
  4263.        SELECT( %Y_ACK );
  4264.           IF RCVD_PACKNUM ~= PACKNUM THEN     /* Wrong packet number?         */
  4265.              EXIT;                            /* Yep, ignore it and try agn   */
  4266.           CALL RECEIVE_THEIR_PARAMS( LEN,%SEND## );
  4267.           NUM_TRIES= 0;
  4268.           PACKNUM= MOD(PACKNUM+1,64);
  4269.           STATE= %F_FILE;
  4270.        SELECT( %E_ERROR );
  4271.           CALL PRINT_ERROR_PACKET;
  4272.        SELECT( ELSE );
  4273.           STATE= %A_ABORT;
  4274.  
  4275.        END;
  4276.  
  4277. RE_TURN:
  4278.     RETURN;
  4279.  
  4280. END SEND_INIT;
  4281. %EJECT;
  4282. /****
  4283. *
  4284. *   S E N D _ O U R _ P A R A M S  ( aka SPAR )
  4285. *
  4286. *   Fill the data array with my send-init parameters
  4287. *
  4288. ****/
  4289.  
  4290. SEND_OUR_PARAMS: PROC( DIRECTION );
  4291. DCL DIRECTION                UBIN;
  4292.  
  4293.     IF DIRECTION = %SEND## THEN               /* If we're SENDing, init MY    */
  4294.        MY= MY_DEFAULT;
  4295.  
  4296.     CALL TOCHAR( DATA(0),MY.PACKET_LENGTH );  /* MAXL */
  4297.     CALL TOCHAR( DATA(1),MY.TIMEOUT );        /* TIME */
  4298.     CALL TOCHAR( DATA(2),MY.PADDING );        /* NPAD */
  4299.     CALL    CTL( DATA(3),MY.PADCHAR );        /* PADC */
  4300.     CALL TOCHAR( DATA(4),MY.END_OF_LINE );    /* EOL  */
  4301.     SUBSTR(DATA_BUF,5,1)= MY.QUOTE;           /* QCTL */
  4302.     SUBSTR(DATA_BUF,6,1)= MY.QBIN;            /* QBIN */
  4303.     SUBSTR(DATA_BUF,7,1)= '1';                /* CHKT */
  4304.     SUBSTR(DATA_BUF,8,1)= MY.REPT;            /* REPT */
  4305.     PACKLEN= 9;
  4306.  
  4307. RE_TURN:
  4308.     RETURN;
  4309.  
  4310. END SEND_OUR_PARAMS;
  4311. %EJECT;
  4312. /****
  4313. *
  4314. *   S E N D _ P A C K E T
  4315. *
  4316. *   Send off the packet in progress.  If a LOG file is OPEN, write the packet
  4317. *   to the LOG file too.
  4318. *
  4319. ****/
  4320.  
  4321. SEND_PACKET: PROC( TYPE,NUM,LEN,DATA )  ALTRET;
  4322. DCL TYPE                     CHAR(1);
  4323. DCL NUM                      UBIN;
  4324. DCL LEN                      UBIN;
  4325. DCL DATA(0:93)               UBIN(9)   CALIGNED;
  4326.  
  4327.     IF NOT GOT_TRMCTL THEN CALL INIT_ACTIVATION ALTRET(ALT_RETURN);
  4328.     IF THEIR.PADDING > 0 THEN                 /* Any padding needed?          */
  4329.        CALL SEND_PADCHARS( THEIR.PADDING );   /* Yep, go do it.               */
  4330.  
  4331.     PACKET.MARK= PROTOCOL.SYNCHR;             /* Usually SOH                  */
  4332.     UBIN9= LEN + 3;
  4333.     CALL TOCHAR( PACKET.LEN,UBIN9 );
  4334.     UBIN9= NUM;
  4335.     CALL TOCHAR( PACKET.SEQ,UBIN9 );
  4336.     PACKET.TYPE= ASCBIN(TYPE);
  4337.     CALL BLOCK_MOVE( PACKET.DATA,DATA,LEN );
  4338.     CALL CALC_CHECKSUM( CHECKSUM );
  4339.     UBIN9= CHECKSUM;
  4340.     CALL TOCHAR( PACKET.DATA(LEN),UBIN9 );
  4341.     PACKET.DATA(LEN+1)= ASCBIN(THEIR.END_OF_LINE);
  4342.     WRITE_PACKET.BUF_.BOUND= LEN + 4 + 1;
  4343.     CALL M$WRITE( WRITE_PACKET )  ALTRET( ALT_RETURN );
  4344.     CALL LOG( %DEBUG_SEND##,PACKET,WRITE_PACKET.BUF_.BOUND+1 );
  4345. RE_TURN:
  4346.     RETURN;
  4347.  
  4348. ALT_RETURN:
  4349.     ALTRETURN;
  4350.  
  4351. END SEND_PACKET;
  4352. %EJECT;
  4353. /****
  4354. *
  4355. *   S E N D _ P A D C H A R S
  4356. *
  4357. *   This currently does nothing!
  4358. *
  4359. ****/
  4360.  
  4361. SEND_PADCHARS: PROC( COUNT );
  4362. DCL COUNT                    UBIN(9)   CALIGNED;
  4363.  
  4364. RE_TURN:
  4365.     RETURN;
  4366.  
  4367. END SEND_PADCHARS;
  4368. %EJECT;
  4369. /****
  4370. *
  4371. *   S E R V E R
  4372. *
  4373. *   This takes care of the SERVER mode.
  4374. *
  4375. ****/
  4376.  
  4377. SERVER: PROC  ALTRET;
  4378.  
  4379.     NEXT_CALL= %NOTHING#;
  4380.     NUM_TRIES= 0;
  4381.     MY= MY_DEFAULT;
  4382.     PACKNUM= 0;
  4383.     REPEAT_CNT= 0;
  4384.  
  4385.     CALL PUT('CP-6 Kermit SERVER at your service\');
  4386.     CALL PUT('To shut me (the SERVER) down, enter BYE or FINISH on your local machine.\');
  4387.  
  4388.     IM_A_SERVER= %YES#;                       /* Remember I'm in SERVER mode  */
  4389.        IF GOT_TRMCTL THEN
  4390.        CALL M$STRMCTL( STRMCTL )  ALTRET( ALT_RETURN ); /* Set ACTONTRN AGAIN */
  4391.     ELSE
  4392.        CALL INIT_ACTIVATION  ALTRET( ALT_RETURN );
  4393.  
  4394.     DO WHILE('1'B);
  4395.  
  4396.        CALL RECEIVE_PACK( TYPE,RCVD_PACKNUM,LEN,DATA );
  4397.  
  4398.        IF PACKET_BUF = 'END' THEN DO;
  4399.           IM_A_SERVER= %NO#;                  /* I won't be a SERVER any more */
  4400.           GOTO RE_TURN;
  4401.           END;
  4402.  
  4403.        DO SELECT( TYPE );
  4404.  
  4405.           SELECT( %N_NAK );
  4406.              CALL SEND_PACKET( 'N',PACKNUM,0,' ' );
  4407.  
  4408.           SELECT( %I_INIT, %S_SINIT );        /* RECEIVE a file(s)            */
  4409.              PACKNUM= RCVD_PACKNUM;
  4410.              CALL RECEIVE_THEIR_PARAMS( LEN,%RECEIVE## );
  4411.              CALL SEND_OUR_PARAMS( %RECEIVE## );
  4412.              CALL SEND_PACKET( 'Y',PACKNUM,PACKLEN,DATA );
  4413.              FILE_CNT= 0;
  4414.              NUM_TRIES= 0;
  4415.              SRCE_FID= ' ';
  4416.              TX= 0;
  4417.              OPEN_IO= DEFAULT_OPEN;
  4418.              OPEN_IO.V_= VECTOR(OPEN_IO.V);
  4419.              HOW_RECEIVE= SET_FILE_WARNING - %SET_FILE_WARNING_ON## + 1;
  4420.              IF TYPE = %S_SINIT THEN DO;
  4421.                 PACKNUM= MOD(PACKNUM+1,64);
  4422.                 CALL RECEIVE_A_FILE( %F_FILE );
  4423.                 PACKNUM = 0;
  4424.                 NUM_TRIES = 0;
  4425.                 END;
  4426.  
  4427.           SELECT( %R_RINIT );                 /* SEND file(s)                 */
  4428.              CALL GET_FID_FROM_PACKET( PACKET.DATA_BUF,LEN,SRCE_FID,K );
  4429.              IF K < LENGTHC(SRCE_FID) THEN
  4430.                 SUBSTR(SRCE_FID,K)= ' ';
  4431.              CALL FIX_CP6_FILE_NAME( SRCE_FID,K,%SEND## );
  4432.              CALL SEND  WHENALTRETURN DO; END;
  4433.              IF FILE_CNT = 0 THEN DO;
  4434.                 CALL CONCAT( LO_BUF,'.. Sorry, no files matching "',
  4435.                                     SUBSTR(TARGET.NAME#,0,TARGET.L#),
  4436.                                     '" were found on CP-6.' );
  4437.                 CALL SEARCHR( L,X,SKIP_BLANKS,LO_BUF );
  4438.                 CALL SEND_ERROR_PACKET( LO_BUF,L+1 );
  4439.                 END;
  4440.              ELSE
  4441.                 PACKNUM= 0;
  4442.  
  4443.           SELECT( %G_GENERIC );
  4444.              DO SELECT( SUBSTR(PACKET.DATA_BUF,0,1) );
  4445.                 SELECT( %F_FINISH );
  4446.                    CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  4447.                    IM_A_SERVER= %NO#;         /* I won't be a SERVER any more */
  4448.                    GOTO ALT_RETURN;
  4449.                 SELECT( %L_BYE );
  4450.                    CALL SEND_PACKET( 'Y',RCVD_PACKNUM,0,' ' );
  4451.                    CALL CLOSE_A_FILE ( F$DEBUG# );
  4452.                    CALL CLOSE_A_FILE ( M$LO#, %SAVE# );
  4453.                    CMD_BUF= 'BYE';
  4454. %IF OS_VERSION~='B03';
  4455.                    FPT_YC.V.LINK#= %NO#;
  4456. %ENDIF;
  4457.                    CALL M$YC( FPT_YC );
  4458.                 SELECT( ELSE );
  4459.                    CALL CONCAT( LO_BUF,'> GENERIC subcommand ',
  4460.                                        SUBSTR(PACKET.DATA_BUF,0,1),
  4461.                                 ' has NOT been implemented by CP-6 KERMIT <\' );
  4462.                    CALL INDEX( K,'\',LO_BUF );
  4463.                    CALL SEND_ERROR_PACKET( LO_BUF,K );
  4464.                    CALL SEND_PACKET( 'Y',PACKNUM,0,' ' );
  4465.                 END;
  4466.  
  4467.        /* SELECT( %K_KERMIT ); */
  4468.  
  4469.           SELECT( ELSE );
  4470.              CALL CONCAT( LO_BUF,'> CP-6 KERMIT SERVER got a type ',
  4471.                                  TYPE,
  4472.                                  ' packet and didn''t know what to do!\' );
  4473.              CALL INDEX( K,'\',LO_BUF );
  4474.              CALL SEND_ERROR_PACKET( LO_BUF,K );
  4475.  
  4476.           END;
  4477.        END;
  4478.  
  4479. RE_TURN:
  4480.     RETURN;
  4481.  
  4482. ALT_RETURN:
  4483.     ALTRETURN;
  4484.  
  4485. END SERVER;
  4486. %EJECT;
  4487. /****
  4488. *
  4489. *   S E T
  4490. *
  4491. *   Do any and all SET commands.
  4492. *
  4493. ****/
  4494.  
  4495. SET: PROC  ALTRET;
  4496.  
  4497.     DO J=0 TO %BLK2_NSUBLKS-1;
  4498.        BLK3$= %BLK2_SUBLK$(J);
  4499.        IF %BLK3_NSUBLKS > 0 THEN DO;
  4500.           BLK4$= %BLK3_SUBLK$(0);
  4501.           IF %BLK4_NSUBLKS > 0 THEN
  4502.              BLK5$= %BLK4_SUBLK$(0);
  4503.           END;
  4504.        DO CASE( %BLK3_CODE );
  4505.           CASE( %SET_BLOCK_CHECK## );
  4506.              DO CASE( %BLK4_CODE );
  4507.                 CASE( %ONE_CHAR_CHECKSUM## );
  4508.                    BLOCK_CHECK= 1;
  4509.                 CASE( %TWO_CHAR_CHECKSUM## );
  4510.                    CALL PUT( '.. Sorry, I only do 1 character checksums\' );
  4511.                 CASE( %THREE_CHAR_CHECKSUM## );
  4512.                    CALL PUT( '.. Sorry, I only do 1 character checksums\' );
  4513.                 END;
  4514.           CASE( %SET_DELAY## );
  4515.              CALL CHARBIN( DELAY,%BLK4_TEXT );
  4516.           CASE( %SET_FILE## );
  4517.              DO CASE( %BLK4_CODE );
  4518.                 CASE( %SET_FILE_BINARY_EXTENSIONS## );
  4519.                    IF %BLK4_NSUBLKS <= %MAX_EXTENSIONS# THEN DO;
  4520.                       DO K=0 TO %BLK4_NSUBLKS-1;
  4521.                          BLK5$= %BLK4_SUBLK$(K);
  4522.                          EXTEN.LEN(K)= LENGTHC('?') + %BLK5_COUNT;
  4523.                          CALL CONCAT( EXTEN.TEXT(K),'?',%BLK5_TEXT );
  4524.                          END;
  4525.                       IF %BLK4_NSUBLKS = 1  AND  EXTEN.TEXT(0)='?NONE' THEN
  4526.                          NUM_EXTENSIONS= 0;
  4527.                       ELSE
  4528.                          NUM_EXTENSIONS= %BLK4_NSUBLKS;
  4529.                       END;
  4530.                    ELSE
  4531.                       CALL PUT('.. Too many extensions specified; max is 30.\');
  4532.                 CASE( %SET_FILE_CP6_FIDS_YES## );
  4533.                    SET_FILE_CP6_FIDS= %SET_FILE_CP6_FIDS_YES##;
  4534.                 CASE( %SET_FILE_CP6_FIDS_NO## );
  4535.                    SET_FILE_CP6_FIDS= %SET_FILE_CP6_FIDS_NO##;
  4536.                 CASE( %SET_FILE_EDIT_YES## );
  4537.                    SET_FILE_EDIT= %SET_FILE_EDIT_YES##;
  4538.                 CASE( %SET_FILE_EDIT_NO## );
  4539.                    SET_FILE_EDIT= %SET_FILE_EDIT_NO##;
  4540.                 CASE( %SET_FILE_END_OF_RECORD## );
  4541.                    IF %BLK4_NSUBLKS > 2 THEN DO;
  4542.                       CALL X$WRITE( F_FDS,FMT35_ );
  4543.                       GOTO NEXT_J;
  4544.                       END;
  4545.                    ELSE DO;
  4546.                       SIZE= 0;
  4547.                       EOR_BYTE_LEN= 0;
  4548.                       DO K = 0 TO %BLK4_NSUBLKS-1;
  4549.                          BLK5$= %BLK4_SUBLK$(K);
  4550.                          CALL CHARBIN( L,%BLK5_TEXT );
  4551.                          IF L > 255 THEN DO;
  4552.                             CALL X$WRITE( F_FDS,FMT36_,VECTOR(L) );
  4553.                             GOTO NEXT_J;
  4554.                             END;
  4555.                          ELSE DO;
  4556.                             CALL STUFF_CHAR_IN_PACKET( BINASC(L) );
  4557.                             EOR_BYTE(K) = BINASC(L);
  4558.                             EOR_BYTE_LEN= EOR_BYTE_LEN + 1;
  4559.                             END;
  4560.                          END;
  4561.                       EOR_CHARS= SUBSTR(DATA_BUF,0,SIZE);
  4562.                       EOR_CHARS_LEN= SIZE;
  4563.                       END;
  4564.                 CASE( %SET_FILE_INCOMPLETE_DISCARD## );
  4565.                    SET_FILE_INCOMPLETE= %SET_FILE_INCOMPLETE_DISCARD##;
  4566.                 CASE( %SET_FILE_INCOMPLETE_KEEP## );
  4567.                    SET_FILE_INCOMPLETE= %SET_FILE_INCOMPLETE_KEEP##;
  4568.                 CASE( %SET_FILE_MODE_AUTO## );
  4569.                    SET_FILE_MODE= %SET_FILE_MODE_AUTO##;
  4570.                 CASE( %SET_FILE_MODE_BINARY## );
  4571.                    SET_FILE_MODE= %SET_FILE_MODE_BINARY##;
  4572.                 CASE( %SET_FILE_MODE_TEXT## );
  4573.                    SET_FILE_MODE= %SET_FILE_MODE_TEXT##;
  4574.                 CASE( %SET_FILE_NAMES_ASIS## );
  4575.                    SET_FILE_NAMES= %SET_FILE_NAMES_ASIS##;
  4576.                 CASE( %SET_FILE_NAMES_LC## );
  4577.                    SET_FILE_NAMES= %SET_FILE_NAMES_LC##;
  4578.                 CASE( %SET_FILE_NAMES_UC## );
  4579.                    SET_FILE_NAMES= %SET_FILE_NAMES_UC##;
  4580.                 CASE( %SET_FILE_PC_EXTENSIONS_YES## );
  4581.                    SET_FILE_PC_EXTENSIONS= %SET_FILE_PC_EXTENSIONS_YES##;
  4582.                 CASE( %SET_FILE_PC_EXTENSIONS_NO## );
  4583.                    SET_FILE_PC_EXTENSIONS= %SET_FILE_PC_EXTENSIONS_NO##;
  4584.                 CASE( %SET_FILE_PREFIX## );
  4585.                    SET_FILE_PREFIX.LEN= %BLK5_COUNT;
  4586.                    SET_FILE_PREFIX.TEXT= %BLK5_TEXT;
  4587.                 CASE( %SET_FILE_REPLACEMENT## );
  4588.                    SET_FILE_REPLACEMENT= %BLK5_TEXT;
  4589.                 CASE( %SET_FILE_SUBDIRECTORY_CHAR## );
  4590.                    SET_FILE_SUBDIRECTORY= %SET_FILE_SUBDIRECTORY_ON##;
  4591.                    SET_FILE_SUBDIRECTORY_CHAR= %BLK5_TEXT;
  4592.                 CASE( %SET_FILE_SUBDIRECTORY_OFF## );
  4593.                    SET_FILE_SUBDIRECTORY= %SET_FILE_SUBDIRECTORY_OFF##;
  4594.                 CASE( %SET_FILE_SUBDIRECTORY_ON## );
  4595.                    SET_FILE_SUBDIRECTORY= %SET_FILE_SUBDIRECTORY_ON##;
  4596.                 CASE( %SET_FILE_WARNING_ON## );
  4597.                    SET_FILE_WARNING= %SET_FILE_WARNING_ON##;
  4598.                 CASE( %SET_FILE_WARNING_INTO## );
  4599.                    SET_FILE_WARNING= %SET_FILE_WARNING_INTO##;
  4600.                 CASE( %SET_FILE_WARNING_OFF## );
  4601.                    SET_FILE_WARNING= %SET_FILE_WARNING_OFF##;
  4602.                 CASE( ELSE );
  4603.                    CALL PUT( '.. Oops, X$PARSE knows of an option I don''t!\' );
  4604.                 END;
  4605.           CASE( %SET_SEND## );
  4606.              DO K=0 TO %BLK3_NSUBLKS-1;
  4607.                 BLK4$= %BLK3_SUBLK$(K);
  4608.                 IF %BLK4_NSUBLKS > 0 THEN
  4609.                    BLK5$= %BLK4_SUBLK$(0);
  4610.                 DO CASE( %BLK4_CODE );
  4611.                    CASE( %SEND_EIGHT_BIT_QUOTE## );
  4612.                       MY_DEFAULT.QBIN= %BLK5_TEXT;
  4613.                    CASE( %SEND_END_OF_LINE## );
  4614.                       CALL CHARBIN( L,%BLK5_TEXT );
  4615.                       MY_DEFAULT.END_OF_LINE= BINASC(L);
  4616.                    CASE( %SEND_PACKET_LENGTH## );
  4617.                       CALL CHARBIN( L,%BLK5_TEXT );
  4618.                       MY_DEFAULT.PACKET_LENGTH= L;
  4619.                    CASE( %SEND_PAUSE## );
  4620.                       CALL CHARBIN( L,%BLK5_TEXT );
  4621.                       MY_DEFAULT.PAUSE= L;
  4622.                    CASE( %SEND_PADDING## );
  4623.                       CALL CHARBIN( L,%BLK5_TEXT );
  4624.                       MY_DEFAULT.PADDING= L;
  4625.                    CASE( %SEND_PADCHAR## );
  4626.                       CALL CHARBIN( L,%BLK5_TEXT );
  4627.                       MY_DEFAULT.PADCHAR= BINASC(L);
  4628.                    CASE( %SEND_QUOTE## );
  4629.                       MY_DEFAULT.QUOTE= %BLK5_TEXT;
  4630.                    CASE( %SEND_REPT## );
  4631.                       MY_DEFAULT.REPT= %BLK5_TEXT;
  4632.                    CASE( %SEND_START_OF_PACKET## );
  4633.                       CALL CHARBIN( L,%BLK5_TEXT );
  4634.                       MY_DEFAULT.START_OF_PACKET= BINASC(L);
  4635.                    CASE( %SEND_TIMEOUT## );
  4636.                       CALL CHARBIN( L,%BLK5_TEXT );
  4637.                       MY_DEFAULT.TIMEOUT= L;
  4638.                    END;
  4639.                 END;
  4640.           CASE( %SET_RETRY## );
  4641.              BLK5$= %BLK4_SUBLK$(0);
  4642.              DO CASE( %BLK4_CODE );
  4643.                 CASE( %RETRY_INITIAL## );
  4644.                    CALL CHARBIN( PROTOCOL.MAX_INITIAL_RETRIES,%BLK5_TEXT );
  4645.                 CASE( %RETRY_PACKETS## );
  4646.                    CALL CHARBIN( PROTOCOL.MAX_PACKET_RETRIES,%BLK5_TEXT );
  4647.                 END;
  4648.           CASE( %SET_TAB_EXPANSION## );
  4649.             SET_TAB_EXPANSION= %BLK4_CODE;
  4650.           CASE( %SET_TABS## );
  4651.              DO K=0 TO %BLK3_NSUBLKS-1;
  4652.                 BLK4$= %BLK3_SUBLK$(K);
  4653.                 CALL CHARBIN( L,%BLK4_TEXT );
  4654.                 TABS(K)= L;
  4655.                 IF K > 0  AND  TABS(K) <= TABS(K-1) THEN DO;
  4656.                    VEC1_= VECTOR(L);
  4657.                    CALL X$WRITE( F_FDS,FMT32_,VEC1_ );
  4658.                    GOTO SET_DEFAULT_TABS;
  4659.                    END;
  4660.                 IF TABS(K) > 255 THEN DO;     /* Tab value to large?          */
  4661.                    VEC1_= VECTOR(L);
  4662.                    CALL X$WRITE( F_FDS,FMT31_,VEC1_ );
  4663.                    GOTO SET_DEFAULT_TABS;
  4664.                    END;
  4665.                 END;
  4666.              NUM_TABS= %BLK3_NSUBLKS;
  4667.              IF NUM_TABS = 1  AND  TABS(0)=0 THEN  /* Reset TABs to defaults? */
  4668.                 GOTO SET_DEFAULT_TABS;
  4669.  
  4670.              IF TABS(0) = 0 THEN              /* No tabs?                     */
  4671.                 NUM_TABS= 0;                  /* Yep.                         */
  4672.  
  4673.              DO WHILE('0'B);
  4674. SET_DEFAULT_TABS:
  4675.                 L= 9;                         /* Start TABs at 9              */
  4676.                 DO K=0 TO 39;
  4677.                    TABS(K)= L;
  4678.                    L= L + 8;                  /* and increment by 8           */
  4679.                    END;
  4680.                 NUM_TABS= 40;
  4681.                 END;
  4682.           CASE( ELSE );
  4683.              CALL PUT( '.. Oops, X$PARSE knows of an option I don''t!\' );
  4684.           END;
  4685. NEXT_J:
  4686.        END;
  4687.  
  4688. RE_TURN:
  4689.     RETURN;
  4690.  
  4691. END SET;
  4692. %EJECT;
  4693. /****
  4694. *
  4695. *   S E T _ P A R I T Y _ M A S K
  4696. *
  4697. *   Based upon the 8-bit quoting character passed (QBIN) and/or the parity
  4698. *   currently in use, setup CHARMASK and WORDMASK for use later to mask off
  4699. *   the parity bit.
  4700. *
  4701. ****/
  4702.  
  4703. SET_PARITY_MASK: PROC( QBIN );
  4704. DCL QBIN                     CHAR(1);
  4705.  
  4706.     IF QBIN = 'Y' THEN DO;
  4707.        CALL M$GTRMATTR(FPT_GTRMATTR);
  4708.        IF (VLP_GTRMATTR.PARITY# = %KV_PRTTYP_NONE)   OR
  4709.           (VLP_GTRMATTR.PARITY# = %KV_PRTTYP_ZERO)  THEN DO;
  4710.           CHARMASK = '377'O;
  4711.           WORDMASK = '377377377377'O;
  4712.           END;
  4713.        ELSE DO;
  4714.           CHARMASK = '177'O;
  4715.           WORDMASK = '177177177177'O;
  4716.           END;
  4717.        END;
  4718.     ELSE
  4719.        IF (QBIN >= '!'  AND  QBIN <= '>')  OR
  4720.           (QBIN >= '^'  AND  QBIN <= '~') THEN DO;
  4721.           CHARMASK = '177'O;
  4722.           WORDMASK = '177177177177'O;
  4723.           END;
  4724.        ELSE DO;
  4725.           CHARMASK = '377'O;
  4726.           WORDMASK = '377377377377'O;
  4727.           END;
  4728.  
  4729. RE_TURN:
  4730.     RETURN;
  4731.  
  4732. END SET_PARITY_MASK;
  4733. %EJECT;
  4734. /****
  4735. *
  4736. *   S E T _ T I M E O U T
  4737. *
  4738. *   Set the timeout for READs.  This is generally done before a transfer
  4739. *   starts and after one is finished.
  4740. *
  4741. ****/
  4742.  
  4743. SET_TIMEOUT: PROC( TIMEOUT_VALUE )  ALTRET;
  4744. DCL TIMEOUT_VALUE            UBIN;
  4745.  
  4746.     IF TIMEOUT.V.TIMEOUT# ~= TIMEOUT_VALUE THEN DO;
  4747.        TIMEOUT.V.TIMEOUT#= TIMEOUT_VALUE;
  4748.        CALL BINCHAR( INT5,TIMEOUT_VALUE );
  4749.        CALL CONCAT( LO_BUF,'Timeout value set to ',INT5 );
  4750.        CALL LOG( %DEBUG_TIMEOUT##,LO_BUF,26 );
  4751.         MY_STATION.EOFTIME# = TIMEOUT_VALUE;
  4752.        CALL M$EOM( TIMEOUT )  ALTRET( ALT_RETURN );
  4753.        END;
  4754.  
  4755.     IF TIMEOUT_VALUE > 0 THEN DO;
  4756.        CALL M$STRMCTL( STRMCTL );
  4757.        END;
  4758.  
  4759. RE_TURN:
  4760.     RETURN;
  4761.  
  4762. ALT_RETURN:
  4763.     ALTRETURN;
  4764.  
  4765. END SET_TIMEOUT;
  4766. %EJECT;
  4767. /****
  4768. *
  4769. *   S H O W
  4770. *
  4771. *   Show the current settings of most SETable values.
  4772. *
  4773. ****/
  4774.  
  4775. SHOW: PROC;
  4776.  
  4777.     MY= MY_DEFAULT;
  4778.     F_FDS.DCB#= DEFAULT_DCB#;
  4779.     CALL X$WRITE( F_FDS,FMT1_,VECTOR(MY.QUOTE),VECTOR(THEIR.QUOTE) );
  4780.  
  4781.     K= ASCBIN(THEIR.START_OF_PACKET);
  4782.     L= ASCBIN(MY.START_OF_PACKET);
  4783.     CALL CHARCTL( STR1,K );
  4784.     CALL CHARCTL( STR2,L );
  4785.     CALL X$WRITE( F_FDS,FMT2_,VECTOR(SUBSTR(STR1,0,6)),
  4786.                               VECTOR(SUBSTR(STR2,0,6)) );
  4787.  
  4788.     CALL X$WRITE( F_FDS,FMT3_,VECTOR(THEIR.TIMEOUT),VECTOR(MY.TIMEOUT) );
  4789.  
  4790.     CALL X$WRITE( F_FDS,FMT4_,VECTOR(THEIR.PACKET_LENGTH),
  4791.                               VECTOR(MY.PACKET_LENGTH) );
  4792.  
  4793.     CALL X$WRITE( F_FDS,FMT5_,VECTOR(THEIR.PADDING),VECTOR(MY.PADDING) );
  4794.  
  4795.     K= ASCBIN(MY.END_OF_LINE);
  4796.     CALL CHARCTL( STR1,K );
  4797.     CALL X$WRITE( F_FDS,FMT6_,VECTOR(SUBSTR(STR1,0,6)) );
  4798.  
  4799.     IF SET_FILE_CP6_FIDS = %SET_FILE_CP6_FIDS_NO## THEN
  4800.        STR1= 'No';
  4801.     ELSE
  4802.        STR1= 'Yes';
  4803.     IF SET_FILE_INCOMPLETE = %SET_FILE_INCOMPLETE_DISCARD## THEN
  4804.        STR2= 'Incomplete files will be discarded';
  4805.     ELSE
  4806.        STR2= 'Incomplete files will be kept';
  4807.     CALL X$WRITE( F_FDS,FMT7_,VECTOR(SUBSTR(STR1,0,3)),VECTOR(STR2) );
  4808.  
  4809.     IF SET_FILE_EDIT = %SET_FILE_EDIT_NO## THEN
  4810.        STR1= 'Received files will not be EDIT keyed';
  4811.     ELSE
  4812.        STR1= 'Received files will be EDIT keyed';
  4813.     CALL X$WRITE( F_FDS,FMT8_,VECTOR(SET_FILE_REPLACEMENT),VECTOR(STR1) );
  4814.  
  4815.     IF SET_FILE_NAMES = %SET_FILE_NAMES_ASIS## THEN
  4816.        STR1= 'Packet file names used ASIS';
  4817.     ELSE
  4818.        IF SET_FILE_NAMES = %SET_FILE_NAMES_LC## THEN
  4819.           STR1= 'Packet file names converted to LowerCase';
  4820.        ELSE
  4821.           STR1= 'Packet file names converted to UpperCase';
  4822.     CALL X$WRITE( F_FDS,FMT9_,VECTOR(STR1),VECTOR(DELAY) );
  4823.  
  4824.     CALL X$WRITE( F_FDS,FMT10_,VECTOR(PROTOCOL.MAX_INITIAL_RETRIES),
  4825.                                VECTOR(PROTOCOL.MAX_PACKET_RETRIES) );
  4826.  
  4827.     IF SET_TAB_EXPANSION = %SET_TAB_EXPANSION_ON## THEN
  4828.        STR1= 'On';
  4829.     ELSE
  4830.        IF SET_TAB_EXPANSION = %SET_TAB_EXPANSION_OFF## THEN
  4831.           STR1= 'Off';
  4832.        ELSE
  4833.           STR1= 'Lee blew it!';
  4834.     IF F$LOG$->F$DCB.FCD# THEN
  4835.        STR2= ' ';
  4836.     ELSE
  4837.        STR2= ' Was ';
  4838.     CALL X$WRITE( F_FDS,FMT11_,VECTOR(STR1),VECTOR(STR2),
  4839.                                VECTOR(LOG_FILE.NAME#) );
  4840.  
  4841.     IF NUM_TABS = 0 THEN
  4842.        STR1= 'Tabs: None';
  4843.     ELSE
  4844.        IF NUM_TABS = 40  AND  TABS(0) = 9  AND  TABS(39) = 321 THEN
  4845.           STR1= 'Tabs: Every 8 columns between 9 and 321';
  4846.        ELSE DO;
  4847.           STR1= 'Tabs: ';
  4848.           OUT_INDX= LENGTHC('Tabs: ');
  4849.           DO K=0 TO NUM_TABS-1;
  4850.              CALL BINCHAR( INT5,TABS(K) );
  4851.              L= 0;
  4852.              DO WHILE( L<4 AND SUBSTR(INT5,L,1)='0' );
  4853.                 L= L + 1;
  4854.                 END;
  4855.              IF OUT_INDX + 5-L + LENGTHC(', ') >= LENGTHC(STR1) THEN DO;
  4856.                 CALL X$WRITE( F_FDS,FMT_,VECTOR(STR1) );
  4857.                 STR1= ' ';
  4858.                 OUT_INDX= LENGTHC('Tabs: ');
  4859.                 END;
  4860.              CALL INSERT( STR1,OUT_INDX,,SUBSTR(INT5,L),', ' );
  4861.              OUT_INDX= OUT_INDX + 5-L + LENGTHC(', ');
  4862.              END;
  4863.           IF OUT_INDX > LENGTHC('Tabs: ') THEN
  4864.              SUBSTR(STR1,OUT_INDX-2,1)= ' ';  /* Blank out the trailing comma */
  4865.           END;
  4866.     CALL X$WRITE( F_FDS,FMT_,VECTOR(STR1) );
  4867.  
  4868.     IF SET_FILE_PC_EXTENSIONS = %SET_FILE_PC_EXTENSIONS_YES## THEN
  4869.        STR1= 'Yes';
  4870.     ELSE
  4871.        STR1= 'No';
  4872.     IF SET_FILE_MODE = %SET_FILE_MODE_AUTO## THEN
  4873.        STR2= 'Automatic';
  4874.     ELSE
  4875.        IF SET_FILE_MODE = %SET_FILE_MODE_BINARY## THEN
  4876.           STR2= 'Binary';
  4877.        ELSE
  4878.           STR2= 'Text';
  4879.     CALL X$WRITE( F_FDS,FMT33_,VECTOR(STR1),VECTOR(STR2) );
  4880.  
  4881.     IF SET_FILE_WARNING = %SET_FILE_WARNING_ON## THEN
  4882.        STR1= 'On (TO)';
  4883.     ELSE
  4884.        IF SET_FILE_WARNING = %SET_FILE_WARNING_INTO## THEN
  4885.           STR1= 'INTO';
  4886.        ELSE
  4887.           STR1= 'Off (OVER)';
  4888.     IF F$DEBUG$->F$DCB.FCD# THEN
  4889.        STR2= ' ';
  4890.     ELSE
  4891.        STR2= ' Was ';
  4892.     CALL X$WRITE( F_FDS,FMT34_,VECTOR(STR1),VECTOR(STR2),
  4893.                                VECTOR(DEBUG_FILE.NAME#) );
  4894.  
  4895.     IF SET_FILE_SUBDIRECTORY = %SET_FILE_SUBDIRECTORY_ON## THEN
  4896.        STR1= 'Yes';
  4897.     ELSE
  4898.        STR1= 'No';
  4899.     CALL X$WRITE( F_FDS,FMT37_,VECTOR(STR1),
  4900.                                VECTOR(SET_FILE_SUBDIRECTORY_CHAR) );
  4901.  
  4902.     IF SET_FILE_PREFIX.LEN = 0 THEN
  4903.        STR1= 'Disabled';
  4904.     ELSE
  4905.        STR1= SET_FILE_PREFIX.TEXT;
  4906.     CALL X$WRITE( F_FDS,FMT38_,VECTOR(STR1) );
  4907.  
  4908.     IF NUM_EXTENSIONS = 0 THEN
  4909.        STR1= 'Binary extensions: None';
  4910.     ELSE DO;
  4911.        STR1= 'Binary extensions: ';
  4912.        OUT_INDX= LENGTHC('Binary extensions: ');
  4913.        DO K = 0 TO NUM_EXTENSIONS-1;
  4914.           L= EXTEN.LEN(K);
  4915.           IF K < NUM_EXTENSIONS-1 THEN /* If not the last extension, put comma*/
  4916.              L= L + LENGTHC(', ');
  4917.           IF OUT_INDX + L >= LENGTHC(STR1) THEN DO;
  4918.              CALL X$WRITE( F_FDS,FMT_,VECTOR(STR1) );
  4919.              STR1= ' ';
  4920.              OUT_INDX= LENGTHC('Binary extensions: ');
  4921.              END;
  4922.           CALL INSERT( STR1,OUT_INDX,L,SUBSTR(EXTEN.TEXT(K),0,EXTEN.LEN(K)),
  4923.                                        ', ' );
  4924.           OUT_INDX= OUT_INDX + L;
  4925.           END;
  4926.        CALL X$WRITE( F_FDS,FMT_,VECTOR(STR1) );
  4927.        END;
  4928.  
  4929. RE_TURN:
  4930.     RETURN;
  4931.  
  4932. END SHOW;
  4933. %EJECT;
  4934. /****
  4935. *
  4936. *   S N O O Z E
  4937. *
  4938. *   Go to sleep for SECONDS seconds.
  4939. *
  4940. ****/
  4941.  
  4942. SNOOZE: PROC( SECONDS );
  4943. DCL SECONDS                  UBIN;
  4944.  
  4945.      IF ~CG_MODE THEN DO;
  4946.         FPT_WAIT.V.UNITS# = SECONDS;
  4947.         CALL M$WAIT( FPT_WAIT )  ALTRET( RE_TURN );
  4948.         END;
  4949. RE_TURN:
  4950.     RETURN;
  4951.  
  4952. END SNOOZE;
  4953. %EJECT;
  4954. /****
  4955. *
  4956. *   S T U F F
  4957. *
  4958. *   Stuff CHR into BUF at byte LEN.  If need be, expand BUF first.
  4959. *
  4960. ****/
  4961.  
  4962. STUFF: PROC( BUF,LEN )  ALTRET;
  4963. DCL BUF                      CHAR(LEN);
  4964. DCL LEN                      UBIN;
  4965.  
  4966.     IF LEN >= IO_BUF_SIZE THEN DO;
  4967.        CALL EXPAND( IO_,4096,IO_BUF_SIZE )  ALTRET( ALT_RETURN );
  4968.        END;
  4969.  
  4970.     SUBSTR(BUF,LEN,LENGTHC(CHR))= CHR;
  4971.     LEN= LEN + LENGTHC(CHR);
  4972. RE_TURN:
  4973.     RETURN;
  4974.  
  4975. ALT_RETURN:
  4976.     ALTRETURN;
  4977.  
  4978. END STUFF;
  4979. %EJECT;
  4980. /****
  4981. *
  4982. *   S T U F F _ C H A R _ I N _ P A C K E T
  4983. *
  4984. *   Stuff CHR into the out going data packet.
  4985. *
  4986. ****/
  4987.  
  4988. STUFF_CHAR_IN_PACKET: PROC( CHR );
  4989. DCL CHR                      CHAR(1);
  4990. DCL CHR_BIT REDEF CHR        BIT(9)    CALIGNED;
  4991.  
  4992. DCL CHR7                     CHAR(1)   CALIGNED;
  4993. DCL CHR7_BIT REDEF CHR7      BIT(9)    CALIGNED;
  4994.  
  4995.     CHR7_BIT= CHR_BIT & '177'O;               /* Mask off parity bit          */
  4996.     IF BINARY_QUOTING AND (CHR ~= CHR7) THEN DO;
  4997.        SUBSTR(DATA_BUF,SIZE,1)= THEIR.QBIN;
  4998.        SIZE= SIZE + LENGTHC(THEIR.QBIN);
  4999.        END;
  5000.     IF CHR7 < ' '  OR
  5001.        CHR7 = MY.QUOTE  OR
  5002.        CHR7 = %DEL      OR
  5003.       (BINARY_QUOTING  AND  CHR7=MY.QBIN)  OR
  5004.       (REPEATING AND CHR7=MY.REPT)  THEN DO;
  5005.        SUBSTR(DATA_BUF,SIZE,1)= THEIR.QUOTE;
  5006.        SIZE= SIZE + LENGTHC(THEIR.QUOTE);
  5007.        IF (CHR7 = MY.QUOTE)  OR
  5008.           (BINARY_QUOTING  AND  CHR7=MY.QBIN)  OR
  5009.           (REPEATING AND CHR7=MY.REPT) THEN
  5010.           CHR7= CHR;
  5011.        ELSE
  5012.           CALL CTL( CHR7,CHR );
  5013.        END;
  5014.     ELSE
  5015.        CHR7= CHR;
  5016.  
  5017.     SUBSTR(DATA_BUF,SIZE,1)= CHR7;
  5018.     SIZE= SIZE + LENGTHC(CHR7);
  5019.  
  5020. RE_TURN:
  5021.     RETURN;
  5022.  
  5023. END STUFF_CHAR_IN_PACKET;
  5024. %EJECT;
  5025. /****
  5026. *
  5027. *   T O C H A R
  5028. *
  5029. *   Make SRCE printable by adding a space (ASCII 32) to it and return the
  5030. *   result in DEST_UBIN if it was passed or DEST if it wasn't.  The UNCHAR
  5031. *   subroutine does the reverse of this.
  5032. *
  5033. ****/
  5034.  
  5035. TOCHAR: PROC( DEST,SRCE,DEST_UBIN );
  5036. DCL DEST                     UBIN(9)   CALIGNED;
  5037. DCL SRCE                     UBIN(9)   CALIGNED;
  5038. DCL DEST_UBIN                UBIN;
  5039.  
  5040.     IF ADDR(DEST_UBIN) = ADDR(NIL) THEN
  5041.        DEST= SRCE + ASCBIN(' ');
  5042.     ELSE
  5043.        DEST_UBIN= SRCE + ASCBIN(' ');
  5044. RE_TURN:
  5045.     RETURN;
  5046.  
  5047. END TOCHAR;
  5048. %EJECT;
  5049. /****
  5050. *
  5051. *   U N C H A R
  5052. *
  5053. *   Restore SRCE back to its original value by subtracting a space (ASCII 32)
  5054. *   from it and return the result in DEST_UBIN if it was passed or DEST if it
  5055. *   wasn't.  The TOCHAR subroutine does the reverse of this one.
  5056. *
  5057. ****/
  5058.  
  5059. UNCHAR: PROC( DEST,SRCE,DEST_UBIN );
  5060. DCL DEST                     UBIN(9)   CALIGNED;
  5061. DCL SRCE                     UBIN(9)   CALIGNED;
  5062. DCL DEST_UBIN                UBIN;
  5063.  
  5064.     IF ADDR(DEST_UBIN) = ADDR(NIL) THEN
  5065.        DEST= SRCE - ASCBIN(' ');
  5066.     ELSE
  5067.        DEST_UBIN= SRCE - ASCBIN(' ');
  5068. RE_TURN:
  5069.     RETURN;
  5070.  
  5071. END UNCHAR;
  5072. %EJECT;
  5073. /****
  5074. *
  5075. *   U N F I D
  5076. *
  5077. *   Get the file name that DCB number DCB# is OPEN to and return the name in
  5078. *   FID and the length of the name in FID_LEN.
  5079. *
  5080. ****/
  5081.  
  5082. UNFID: PROC( DCB#,FID,FID_LEN )  ALTRET;
  5083. DCL DCB#                     UBIN;
  5084. DCL FID                      CHAR(FIDLEN);
  5085. DCL FID_LEN                  SBIN;
  5086.  
  5087. DCL FIDLEN                   SBIN;
  5088.  
  5089.     IF NOT DCBADDR(DCB#)->F$DCB.FCD# THEN     /* If the DCB is not OPEN       */
  5090.        CALL OPEN_FID( DCB#,' ',0 )  ALTRET( PUT_ERR );  /* OPEN it.           */
  5091.     FIDLEN= FID_LEN;
  5092.     FPT_UNFID.V.DCB#= DCB#;
  5093.     FPT_UNFID.LEN_= VECTOR(FID_LEN);
  5094.     FPT_UNFID.TEXTFID_= VECTOR(FID);
  5095.     CALL M$UNFID( FPT_UNFID )  ALTRET( PUT_ERR );
  5096. RE_TURN:
  5097.     RETURN;
  5098.  
  5099. PUT_ERR:
  5100.     ERRDCB#= %ERRDCB;
  5101.     CALL XUR$ERRMSG( %MONERR,ERRDCB# );       /* Output error message         */
  5102. ALT_RETURN:
  5103.     ALTRETURN;
  5104.  
  5105. END UNFID;
  5106. %EJECT;
  5107. /****
  5108. *
  5109. *   W R I T E _ L O G _ R E C
  5110. *
  5111. *   Write a record into the LOG file (if one is OPEN).
  5112. *
  5113. ****/
  5114.  
  5115. WRITE_LOG_REC: PROC( REC_KEY,MSG_LEN );
  5116. DCL REC_KEY                  UBIN;
  5117. DCL MSG_LEN                  UBIN;
  5118.  
  5119.     IF NOT F$LOG$->F$DCB.FCD# THEN            /* Is F$LOG OPEN?               */
  5120.        GOTO RE_TURN;                          /* Nope, Don't bother logging!  */
  5121.  
  5122.     LOG_KEY.EDIT= ((LOG_KEY.EDIT/1000)*1000) + ((REC_KEY/10)*10);
  5123.     F_FDS.DCB#= 0;
  5124.  
  5125.     DO SELECT( REC_KEY );
  5126.  
  5127.        SELECT( %LOG_HEADER# );
  5128.           CALL M$TIME( GET_UTS );
  5129.           CALL M$TIME( CONVERT_UTS );
  5130.           LOG_KEY.EDIT= LOG_KEY.EDIT + 1000;
  5131.           DAYU(1)= DAYU(1) + (ASCBIN('a')-ASCBIN('A'));
  5132.           DAYU(2)= DAYU(2) + (ASCBIN('a')-ASCBIN('A'));
  5133.           MMMDDYYU(1)= MMMDDYYU(1) + (ASCBIN('a')-ASCBIN('A'));
  5134.           MMMDDYYU(2)= MMMDDYYU(2) + (ASCBIN('a')-ASCBIN('A'));
  5135.           CALL X$WRITE( F_FDS,FMT17_,VECTOR(DAY),
  5136.                                      VECTOR(SUBSTR(MMMDDYY,0,6)),
  5137.                                      VECTOR(SUBSTR(MMMDDYY,8,2)),
  5138.                                      VECTOR(SUBSTR(HHMMSSSS,0,8)),
  5139.                                      VECTOR(B$JIT.ACCN),
  5140.                                      VECTOR(B$JIT.UNAME) );
  5141.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5142.           CALL M$WRITE( WRITE_LOG );
  5143.           START_UTS= UTS;
  5144.  
  5145.        SELECT( %LOG_STRT_SEND# );
  5146.           WHAT= 'Started but didn''t finish sending';
  5147.           GOTO TELL_ABOUT_SEND;
  5148.  
  5149.        SELECT( %LOG_END_SEND# );
  5150.           WHAT= 'Sent ';
  5151. TELL_ABOUT_SEND:
  5152.           IF PACKET_FID = CP6_FID THEN
  5153.              CALL X$WRITE( F_FDS,FMT19_,VECTOR(WHAT),
  5154.                                         VECTOR(CP6_FID),
  5155.                                         VECTOR(F$IN$->F$DCB.NRECS#),
  5156.                                         VECTOR(MODE) );
  5157.           ELSE
  5158.              CALL X$WRITE( F_FDS,FMT18_,VECTOR(WHAT),
  5159.                                         VECTOR(CP6_FID),
  5160.                                         VECTOR(PACKET_FID),
  5161.                                         VECTOR(F$IN$->F$DCB.NRECS#),
  5162.                                         VECTOR(MODE) );
  5163.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5164.           CALL M$WRITE( WRITE_LOG );
  5165.  
  5166.        SELECT( %LOG_STRT_RECEIVE# );
  5167.           WHAT= 'Started but DIDN''T finish receiving';
  5168.           IF PACKET_FID = CP6_FID THEN
  5169.              CALL X$WRITE( F_FDS,FMT29_,VECTOR(WHAT),
  5170.                                         VECTOR(CP6_FID),
  5171.                                         VECTOR(MODE) );
  5172.           ELSE
  5173.              CALL X$WRITE( F_FDS,FMT30_,VECTOR(WHAT),
  5174.                                         VECTOR(PACKET_FID),
  5175.                                         VECTOR(CP6_FID),
  5176.                                         VECTOR(MODE) );
  5177.           GOTO TELL_ABOUT_RECEIVE;
  5178.  
  5179.        SELECT( %LOG_END_RECEIVE# );
  5180.           WHAT= 'Received';
  5181.           IF PACKET_FID = ' ' THEN
  5182.              CALL X$WRITE( F_FDS,FMT20_,VECTOR(WHAT),
  5183.                                         VECTOR(CP6_FID),
  5184.                                         VECTOR(IO_CNT),
  5185.                                         VECTOR(MODE) );
  5186.           ELSE
  5187.              CALL X$WRITE( F_FDS,FMT21_,VECTOR(WHAT),
  5188.                                         VECTOR(PACKET_FID),
  5189.                                         VECTOR(CP6_FID),
  5190.                                         VECTOR(IO_CNT),
  5191.                                         VECTOR(MODE) );
  5192. TELL_ABOUT_RECEIVE:
  5193.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5194.           CALL M$WRITE( WRITE_LOG );
  5195.  
  5196.        SELECT( %LOG_MAX_PACKET_SIZES# );
  5197.           CALL X$WRITE( F_FDS,FMT22_,VECTOR(THEIR.PACKET_LENGTH),
  5198.                                      VECTOR(MY.PACKET_LENGTH) );
  5199.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5200.           CALL M$WRITE( WRITE_LOG );
  5201.  
  5202.        SELECT( %LOG_NUM_DATA_PACKETS# );
  5203.           CALL X$WRITE( F_FDS,FMT23_,VECTOR(NUM_DATA_PACKETS),
  5204.                                      VECTOR(FILE_BYTE_CNT) );
  5205.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5206.           CALL M$WRITE( WRITE_LOG );
  5207.  
  5208.        SELECT( %LOG_NUM_BYTES_SENT# );
  5209.  
  5210.        SELECT( %LOG_NUM_BYTES_RCVD# );
  5211.  
  5212.        SELECT( %LOG_ELAPSED_TIME# );
  5213.           CALL M$TIME( GET_UTS );
  5214.           END_UTS= UTS;
  5215.           UTS= END_UTS - START_UTS;
  5216.           CALL M$TIME( CONVERT_UTS );
  5217.           I= 0;
  5218.           DO UNTIL( (I>=LENGTHC(HHMMSSSS)-5)  OR
  5219.                     (SUBSTR(HHMMSSSS,I,1) ~= '0'  AND
  5220.                      SUBSTR(HHMMSSSS,I,1) ~= ':') );
  5221.              I= I + 1;
  5222.              END;
  5223.           ME_BUF= 'Elapsed time: ';
  5224.           L= LENGTHC('Elapsed time: ');
  5225.  
  5226.           IF I < 3 THEN DO;                   /* Did it take hours?           */
  5227.              IF SUBSTR(HHMMSSSS,0,2) = '01' THEN /* Yep, just one?            */
  5228.                 SUBSTR(ME_BUF,L)= 'One';      /* Yep, spell it                */
  5229.              ELSE
  5230.                 IF SUBSTR(HHMMSSSS,0,1) = '0' THEN /* < 10 hours?             */
  5231.                    SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,1,1);  /* Yep, 1 digit   */
  5232.                 ELSE
  5233.                    SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,0,2);   /* Rediculous!   */
  5234.              CALL INDEX( L,'  ',ME_BUF );
  5235.              IF SUBSTR(HHMMSSSS,0,2) = '01' THEN /* Just one hour?            */
  5236.                 SUBSTR(ME_BUF,L)= ' Hour, ';   /* Yep, proper grammar counts! */
  5237.              ELSE
  5238.                 SUBSTR(ME_BUF,L)= ' Hours, ';   /* Plural                     */
  5239.              CALL INDEX( L,', ',ME_BUF );
  5240.              L= L + LENGTHC(', ');
  5241.              END;
  5242.  
  5243.           IF I < 6 THEN DO;                   /* Any minutes?                 */
  5244.              IF SUBSTR(HHMMSSSS,3,2) = '00' THEN /* Zero minutes?             */
  5245.                 SUBSTR(ME_BUF,L)= 'No';       /* Nope, spell it               */
  5246.              ELSE
  5247.                 IF SUBSTR(HHMMSSSS,3,2) = '01' THEN /* Just one minute?       */
  5248.                    SUBSTR(ME_BUF,L)= 'One';   /* Yep, spell it                */
  5249.                 ELSE
  5250.                    IF SUBSTR(HHMMSSSS,3,1) = '0' THEN  /* < 10 minutes?       */
  5251.                       SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,4,1); /* One digit    */
  5252.                    ELSE
  5253.                       SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,3,2);
  5254.              CALL INDEX( L,'  ',ME_BUF );
  5255.              IF SUBSTR(HHMMSSSS,3,2) = '01' THEN  /* Just one minute?         */
  5256.                 SUBSTR(ME_BUF,L)= ' Minute and';    /* Again, grammar counts! */
  5257.              ELSE
  5258.                 SUBSTR(ME_BUF,L)= ' Minutes and';
  5259.              CALL INDEX( L,'  ',ME_BUF );
  5260.              L= L + LENGTHC(' ');
  5261.              END;
  5262.  
  5263.           IF SUBSTR(HHMMSSSS,6,5) = '00.00' THEN    /* Zero seconds?          */
  5264.              SUBSTR(ME_BUF,L)= 'No';          /* Yep, spell it                */
  5265.           ELSE
  5266.              IF SUBSTR(HHMMSSSS,6,1) = '0' THEN  /* less than 10 seconds?     */
  5267.                 SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,7,4); /* Yep                */
  5268.              ELSE
  5269.                 SUBSTR(ME_BUF,L)= SUBSTR(HHMMSSSS,6,5);
  5270.           CALL INDEX( L,'  ',ME_BUF );
  5271.           SUBSTR(ME_BUF,L)= ' Seconds';
  5272.           CALL M$GLINEATTR( FPT_GLINEATTR );
  5273.           CALL X$WRITE( F_FDS,FMT27_,VECTOR(ME_BUF),
  5274.                                      VECTOR(SPEED(VLP_LINEATTR.LINESPEED#)),
  5275.                                      VECTOR(PARITY_TBL(VLP_GTRMATTR.PARITY#)) );
  5276.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5277.           CALL M$WRITE( WRITE_LOG );
  5278.  
  5279.        SELECT( %LOG_ERRMSG# );
  5280.           CALL X$WRITE( F_FDS,FMT28_,VECTOR(SUBSTR(ERR_BUF,0,MSG_LEN)) );
  5281.           WRITE_LOG.BUF_= VECTOR(SUBSTR(LO_BUF,1,F_FDS.BUFX-1));
  5282.           CALL M$WRITE( WRITE_LOG );
  5283.  
  5284.        SELECT( ELSE );
  5285.  
  5286.        END;
  5287.  
  5288. RE_TURN:
  5289.     RETURN;
  5290.  
  5291. END WRITE_LOG_REC;
  5292. %EJECT;
  5293. /****
  5294. *
  5295. *   W R I T E _ R E C O R D
  5296. *
  5297. *   Write a record to the file being RECEIVEd.
  5298. *
  5299. ****/
  5300.  
  5301. WRITE_RECORD: PROC( BUF,LEN )  ALTRET;
  5302. DCL BUF                      CHAR(LEN);
  5303. DCL LEN                      SBIN;
  5304.  
  5305.     OUT_KEY.EDIT= OUT_KEY.EDIT + 1000;
  5306.     IF LEN <= 0 THEN
  5307.        WRITE_OUT.BUF_= VECTOR(NIL);
  5308.     ELSE
  5309.        WRITE_OUT.BUF_= VECTOR(SUBSTR(BUF,0,LEN));
  5310.     CALL XSA$WRITE( WRITE_OUT,XSA_PARAM )  ALTRET( CANT_WRITE );
  5311.     IO_CNT= IO_CNT + 1;
  5312.     FILE_BYTE_CNT= FILE_BYTE_CNT + LEN + EOR_BYTE_LEN;
  5313.     CALL LOG( %DEBUG_WRITE##,BUF,LEN );
  5314.     IO_BUF= ' ';
  5315.     IO_LEN= 0;
  5316.     TX= 0;
  5317. RE_TURN:
  5318.     RETURN;
  5319.  
  5320. CANT_WRITE:
  5321.     CALL SEND_ERROR_PACKET;
  5322. ALT_RETURN:
  5323.     ALTRETURN;
  5324.  
  5325. END WRITE_RECORD;
  5326.  
  5327. END KERMIT;
  5328. %EOD;
  5329. KERMIT$BREAK: PROC  ASYNC;
  5330.  
  5331. DCL BRK_CNT                  SBIN      SYMREF;
  5332.  
  5333.     BRK_CNT= BRK_CNT + 1;
  5334. RE_TURN:
  5335.     RETURN;
  5336.  
  5337. END KERMIT$BREAK;
  5338.