home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / gendoc / machmach.dqc / MACHMACH.DOC
Encoding:
Internet Message Format  |  1985-02-10  |  66.0 KB

  1. From unc!duke!decvax!watmath!rhbartels Fri Jun 4 16:25:48 1982
  2. Subject: General Machine-Machine Transfer
  3. Newsgroups: net.sources
  4.  
  5.  
  6.  
  7.                                  SYSTEM OUTLINE
  8.                                        by
  9.                                 J. C. Winterton
  10.  
  11.                     Machine to Machine Transmission Package
  12.                                        at
  13.                      Mathematics Faculty Computing Facility
  14.                 Copyright (c) 1982 by the University of Waterloo
  15.  
  16.  
  17.      Outline            Machine to Machine Transmission      March 15, 1982
  18.  
  19.  
  20.                                TABLE OF CONTENTS
  21.  
  22.               1. General.............................................     1
  23.               2. Requirements........................................     1
  24.                    2.1 Program address space.........................     1
  25.                    2.2 Simplicity....................................     1
  26.                    2.3 Specification.................................     2
  27.               3. Capabilities........................................     2
  28.                    3.1 Shell.........................................     2
  29.                    3.2 Multiple Protocols............................     2
  30.                    3.3 Unattended Operation..........................     2
  31.  
  32.  
  33.      Draft - Subject to Change       - ii -          University of Waterloo
  34.  
  35.      Outline            Machine to Machine Transmission      March 15, 1982
  36.  
  37.           Current  and  projected numbers of computers and work stations in
  38.      the University  and  the  existence  of  local  area  network  systems
  39.      accessible  to  them  raises  the  need  for a straightforward program
  40.      designed to allow the various machines on campus to  communicate  with
  41.      each other.  Communication over the local networks can be either under
  42.      control of a terminal attached to one of the machines in  a  conversa-
  43.      tion  or  of  a system daemon running on at least one of the machines.
  44.      This document  presents  the  specification  for  such  a  program  in
  45.      outline.
  46.  
  47.           This section discusses the requirements of the  program  as  they
  48.      are known and understood at this date.
  49.  
  50.           Since  it  is  expected  that  the program will usually be run in
  51.      restricted address space in a work station or personal  micro-computer
  52.      running  something  like  CP/M,  the  program  address  space is quite
  53.      limited.  It is doubtful that most machines actually running CP/M will
  54.      have  more  than, say, 64K bytes.  Since 8K is taken up by the monitor
  55.      and I/O system, there is an upper limit of 56K Bytes on  the  program.
  56.      The  program  size  target should be considerably smaller than this to
  57.      allow for imponderables.  At this time, the target is 32K Bytes.
  58.  
  59.           It is felt that this will also be a benefit it larger  multi-user
  60.      machines,  but  considering the size of some libraries (e.g. TSS Blib)
  61.      it may not be possible to meet this target in these cases.
  62.  
  63.           It is not expected that a  program  will  be  supplied  for  each
  64.      machine  in  existence.   An  implementation will be done for UNIX[1],
  65.      TSS, GCOS6 and, perhaps, THOTH.  The  source  code  and  specification
  66.      will  be  supplied  to  anyone else wanting to implement this program.
  67.      Because of this stand, it is necessary that simplicity  of  algorithms
  68.      be   of   higher   priority   than   efficiency   so  that  relatively
  69.      unsophisticated users may successfully implement the  program.   Hope-
  70.      fully,  like  music  by  J.S.Bach,  this program will be writeable and
  71.      compilable in whatever reasonable language is available on the  target
  72.      machine. [2]
  73.  
  74.      __________________
  75.      [1] UNIX is a Trademark of Bell Laboratories.
  76.      [2] Bach wrote non-specifically and most of his works can be
  77.      played on whatever instruments are available.
  78.  
  79.      Draft - Subject to Change       - 1 -           University of Waterloo
  80.  
  81.      Outline            Machine to Machine Transmission      March 15, 1982
  82.  
  83.           Where  data  are to be encoded, they will be converted from 8 bit
  84.      representation to hexadecimal.  Data compression is provided  whenever
  85.      two implimentations of this program are in communication.
  86.  
  87.           The  specification  of  this  program  must  be  as  complete  as
  88.      possible.  Pseudo code or some similar representation  shall  be  used
  89.      where  logic is complex.  At least one of the implementations prepared
  90.      by us shall be wholly from this specification.
  91.  
  92.           The following are the capabilities that are foreseen an necessary
  93.      in the program.
  94.  
  95.           The term shell is used in the UNIX sense.  The program acts as  a
  96.      link  between  the user and the network session.  It is able to accept
  97.      commands to be executed:
  98.  
  99.           (a)  By the host machine;
  100.  
  101.           (b)  By the network (if possible); and
  102.  
  103.           (c)  By the remote host machine.
  104.  
  105.           The host/remote host commands in the repertoire  of  the  program
  106.      include redirection commands to facilitate file transfers.
  107.  
  108.           Multiple  protocols  in the style of the UNIX uucp system are not
  109.      envisaged.  Where two copies of the program are  able  to  co-operate,
  110.      8-bit  data  may  be encoded and sent.  The program should be built to
  111.      handle only a seven bit data path.  Where only one copy of the program
  112.      is  active  in  the circuit, data may very well be restricted to ascii
  113.      graphics.
  114.  
  115.           Unattended operation of the program  is  desirable  where  it  is
  116.      under  the  control  of  a daemon such as the UNIX cron.  It should be
  117.      possible to set up a list of machines to  be  polled  for  work  on  a
  118.      "spooled"  basis  so  that  lengthy  transmissions may be accomplished
  119.      without the need for an  "operator"  at  a  terminal  controlling  the
  120.      program.   This  is on all fours with the present UNIX uucp capability
  121.      which has served as a model for much of this design.
  122.  
  123.      Draft - Subject to Change       - 2 -           University of Waterloo
  124.  
  125. ---------------------------------------------------------------------------
  126.                Brief On-Line Documentation
  127. ---------------------------------------------------------------------------
  128. MMX - machine to machine transfer program.
  129.  
  130. Syntax:
  131.      MMX [SLave] [l=linename] [s=baudrate]
  132.  
  133. Description:
  134.      This C program transfers  files  over  a  communication
  135. line  in  a  secure manner.  Checksumming and other controls
  136. are present as well as data compression.  A 7-bit data  path
  137. is  assumed, so that the use of "transparent" or "raw" modes
  138. on communication lines is avoided.
  139.      The  program  operates  in two modes: MASTER and SLAVE.
  140. Operation in the MASTER mode implies that commands  will  be
  141. given  from the standard input device and that communication
  142. with the network will be over a separate device.  SLAVE mode
  143. implies  that  the  communications network is identical with
  144. the standard input/output device.  Unless and until the host
  145. system  has  the  ability  to attach separate communications
  146. lines to programs, the program must  be  operated  in  SLAVE
  147. mode.
  148.      Currently,  Honeywell  TSS   cannot   attach   separate
  149. communication  lines,  and therefore, it is necessary to use
  150. SLAVE mode on that machine.  The Math UNIX machine,  on  the
  151. other  hand,  is  perfectly  capable  of operating in either
  152. mode.
  153.  
  154. Options:
  155.    SLave
  156.        Causes the program to issue internal !SLave and !Open
  157.        command on start up.
  158.    l=linename
  159.        In   machines   that  possess  the  capability,  this
  160.        parameter sets a  string  to  be  used  by  the  open
  161.        command for the separate communication line.
  162.    s=baudrate
  163.        In   machines   that  possess  the  capability,  this
  164.        parameter allows the program to set the baud rate  of
  165.        the line.
  166.  
  167. Defaults:
  168.      Defaults are set in each machine for the  options.   In
  169. the  current  version  for  Honeywell  TSS,  SLave is forced
  170. during startup.  In the math UNIX machine the defaults  are:
  171. MAster, l=/dev/sytek, s=2400.
  172.  
  173. Program Operation:
  174.      When called, the program operates as a  minor  "shell".
  175. The  initiating  end  of  the  conversation  operates as the
  176. master (in MASTER mode) and the responding end as SLAVE.  It
  177. accepts  commands  and  acts  upon  them as described below.
  178. Commands  are  prefixed  by  the  command  escape  character
  179. exclamation-point   (!).    When   an  exclamation-point  is
  180. recognized at the beginning of a line, the  line  is  parsed
  181. and  validated  commands  obeyed.   When  an error occurs, a
  182. descriptive  error  message  appears.    When   the   second
  183. character  of  a command line is also a command escape, then
  184. the line is sent to the other program stripped of the  first
  185. escape  (!).   There  is  no escape sequence to issue system
  186. commands from within this program.
  187.  
  188.  
  189. Commands:
  190.  
  191.    Open
  192.        Condition the communication line as necessary.   This
  193.        command  must be issued to both copies of the program
  194.        before  any  transfer  can  take  place.   Note  that
  195.        calling  the  program  with the SLave option performs
  196.        this  function   automatically   for   the   standard
  197.        input/output device.
  198.  
  199.    Send localfile remotefile
  200.        Transmit file localfile from the master to remotefile
  201.        at  the  slave.   Correct  pathnames  and formats for
  202.        pathnames are the responsibility of the user.
  203.  
  204.    Get remotefile localfile
  205.        Transmit  the  file  remotefile  from  the  slave  to
  206.        localfile at the  master.   Pathnames  are  the  full
  207.        responsibility of the user.
  208.  
  209.    MaxData
  210.        Sets the  maximum  number  of  data  bytes  from  the
  211.        sending  file  that  will be passed in any one packet
  212.        during file transmission.
  213.  
  214.        It is necessary to limit this artificially due to the
  215.        fact  that  some  systems  are line oriented and have
  216.        limited  line   sizes   (Honeywell   TSS).    MaxData
  217.        represents  a  count of bytes that will be taken from
  218.        the file being  sent.   Since  a  four  bit  encoding
  219.        techinique   is   used,   each   eight  bit  byte  is
  220.        transmitted as two graphic characters.   This  expan-
  221.        sion  is  alleviated  somewhat by also employing data
  222.        compression techinques where the number of  identical
  223.        characters  exceeds two.  There are ten (10) overhead
  224.        characters on  a  data  packet  in  addition  to  the
  225.        encoded bytes.  Default is 60 bytes.
  226.  
  227.    Quit
  228.        Stops  the  program.   In  the  UNIX  environment,  a
  229.        control-D (EOT, D) may be sent as a command to effect
  230.        a  wrapup  of  the  program,  but  the   command   is
  231.        available.
  232.  
  233.    MAster
  234.        If the program is in slave state,  switch  to  master
  235.        state.
  236.  
  237.    SLave
  238.        If the program is in master state,  switch  to  slave
  239.        state.
  240.  
  241.    Remote
  242.        Inform the program of the type of system that  is  at
  243.        the  other end of the conversation.  This feature has
  244.        not been useful to date, and may be removed.
  245.  
  246.    Viewsetup
  247.        Display the controlling parameters of the program.
  248.  
  249.    Continue
  250.        Because many systems do not prompt, end of  transmis-
  251.        sion  over  the  communication  line is detected by a
  252.        time out heuristic.  The command is provided to cause
  253.        the  program  to  re-examine  the  communication line
  254.        buffers where it is believed that more  data  may  be
  255.        present.   This  is  useful  when  system are heavily
  256.        loaded and multiple line output may be sent with more
  257.        than four seconds between data bursts.
  258.  
  259.    Zdebug
  260.        Some versions of this program (notably the UNIX  ver-
  261.        sion) contain debugging code activated by the command
  262.        "!Zdebug on" and deactivated by "!Zdebug off".   This
  263.        code may be removed when not required or impractical.
  264.  
  265.  
  266. (Copyright (c) 1982, University of Waterloo)
  267. ------------------------------------------------------------
  268.  
  269.                      DATA STRUCTURES FOR FILE TRANSMISSION
  270.                                        by
  271.                                 J. C. Winterton
  272.  
  273.                     Machine to Machine Transmission Package
  274.                                        at
  275.                      Mathematics Faculty Computing Facility
  276.  
  277.                 Copyright (c) 1982 by the University of Waterloo
  278.  
  279.      Formats            Machine to Machine Transmission      April 29, 1982
  280.  
  281.                                TABLE OF CONTENTS
  282.  
  283.               1. General..................................................1
  284.               2. Data Packet..............................................1
  285.                    2.1 Data Compression Scheme............................1
  286.                    2.2 Processing the Data packet.........................2
  287.               3. Beginning of File Packet.................................2
  288.                    3.1 Beginning of File Packet Processing................2
  289.               4. End of File Packet.......................................3
  290.                    4.1 End of File Packet Processing......................3
  291.               5. Hand Shake Packet........................................3
  292.               6. Warm Feelings............................................4
  293.  
  294.      Draft - Subject to Change       - ii -          University of Waterloo
  295.  
  296.      Formats            Machine to Machine Transmission      April 29, 1982
  297.  
  298.      1. General.
  299.  
  300.           This document contains the data structures necessary  to  operate
  301.      the  Machine to Machine Transmission program.  All of these structures
  302.      are effectively character arrays (strings).   In  this  design  it  is
  303.      considered that only a 7-bit data path is available.
  304.  
  305.           When  files  are being transmitted, all data is packetized in the
  306.      format shown below.  Two other packet structures are necessary, namely
  307.      a  beginning  of file packet and an end of file packet.  An additional
  308.      packet is defined for the activation/deactivation of data compression.
  309.      For  convenience  of  description,  PL/I  is  used  as the description
  310.      language.  Because it is believed that many of the  operating  systems
  311.      involved  consider  the  ASCII  control  characters  as proprietary to
  312.      themselves, use of these characters has been avoided.
  313.  
  314.      2. Data Packet.
  315.  
  316.           The data packet shown below is used to transfer
  317.  
  318.            dcl 1 data_packet unaligned,
  319.                 2 d_soh char init ('|'),
  320.                 2 check_sum char(4),                     /* modulo 10000 */
  321.                 2 data_length char(3),                          /* <=250 */
  322.                 2 d_stx char init ('{'),
  323.                 2 data_bytes(data_length) char,       /* data characters */
  324.                 2 data_terminator char;
  325.                                            /* '~' if incomplete "record" */
  326.                                                /* '}' if end of "record" */
  327.      2.1 Data Compression Scheme.
  328.  
  329.           Data  compression  is  a feature of this protocol.  The technique
  330.      employed is:
  331.  
  332.           Scan the uncompressed  data  for  occurances  of  three  or  more
  333.           occurances  of  the  same  character.   When  such are found, the
  334.           packet encoding routine translates them into GS-count-hh (4 ASCII
  335.           characters).[1]
  336.           Count is  the  binary  number  of  characters  to  be  propagated
  337.           expressed  as  an  ASCII  graphic  character  by  adding  a space
  338.           ('0100000'b).  This technique limits  the  compression  range  to
  339.           '0000011'b  through  '0011010'b  (3 through 26) in order to avoid
  340.           entering control characters and key signal characters  improperly
  341.           in the text.
  342.           hh is the  hexadecimal  representation  of  the  character  being
  343.           compressed.
  344.  
  345.      ___________________________
  346.      [1] GS is the ASCII character '!'.
  347.  
  348.  
  349.      Draft - Subject to Change       - 1 -           University of Waterloo
  350.  
  351.      Formats            Machine to Machine Transmission      April 29, 1982
  352.  
  353.           This  scheme  will  only be invoked when co-operating versions of
  354.      the program are in contact.  If  the  identity  handshake  fails  when
  355.      transmission begins, the data are transmitted uncompressed.
  356.  
  357.      2.2 Processing the Data packet.
  358.  
  359.           The  data  of Figure 1 are encoded in ASCII hexadecimal notation,
  360.      two characters per byte for transmission.  On transmission, the  final
  361.      byte pair is followed by either an ASCII '}' or '~' character [2] and,
  362.      if necessary, a new-line character (\n) as  appropriate  to  the  host
  363.      system.   In  most cases, the '}' will be used as a packet terminator.
  364.      However, when it is considered important to pass data in  "blocks"  or
  365.      "records",  '~' is used at the end of each packet of a block until the
  366.      last, when '}' is used to indicate to the receiving  program  that  an
  367.      output write may now  be  accomplished.   [3]  The  receiving  program
  368.      decodes  the packet, and if found correct an ASCII 'y' character and a
  369.      newline are returned.  On receipt of  the  'y',  the  sending  program
  370.      sends the next packet.  If an error is detected, the receiving program
  371.      returns a sequence consisting of an ASCII 'n' followed  by  a  newline
  372.      character.  On receipt of the 'n', the sending program will retransmit
  373.      the packet.  The sending program shall attempt to send each  packet  a
  374.      minimum  of  five (5) times.  If receipt of the packet is not possible
  375.      after the retry limit, the programs should wrap up gracefully.
  376.  
  377.      3. Beginning of File Packet.
  378.  
  379.           When it is desired  to  transmit  a  file  between  two  machines
  380.      running  this  program,  the  fact is announced by the sending machine
  381.      with the transmission of a Beginning of File Packet Figure 2.
  382.  
  383.      3.1 Beginning of File Packet Processing.
  384.  
  385.           This packet is not encoded, but sent as plain ASCII text followed
  386.      by  a  newline  character.   Pathnames  are  the  resonsibility of the
  387.      sending program.  Retry processing is the same for this packet as  for
  388.      a data packet with the following exceptions:
  389.  
  390.           (a) The   sending   program   will  open  the  file  to  be  sent
  391.           (send_pathname) before sending this packet.  If the  file  cannot
  392.           be opened, appropriate error action shall be taken.
  393.  
  394.           (b) On  receipt  of this packet, in addition to checksumming, the
  395.           receiving program will attempt to open/create the receiving file.
  396.           An 'n' shall be sent if this fails.
  397.  
  398.      ___________________________
  399.      [2] This restricts the operation of  Hazeltine  2000  series
  400.      equipment  to  having  the escape character set to the ASCII
  401.      ESC ('0011011'b).
  402.      [3]  A  record is an arbitrary division of text which may be
  403.      considered to be sent as a unit.  In some computer  systems,
  404.      it may be a logical record.
  405.  
  406.      Draft - Subject to Change       - 2 -           University of Waterloo
  407.  
  408.      Formats            Machine to Machine Transmission      April 29, 1982
  409.  
  410.        dcl 1 beginning_of_file_packet unaligned,
  411.                 2 bof_indicator char(5) init ('|FILE'),
  412.                 2 bof_direction char(1),
  413.                                                   /* 1 = slave_to_master */
  414.                                                   /* 2 = master_to_slave */
  415.                 2 bof_checksum char(4),                  /* modulo 10000 */
  416.                 2 bof_stx char init ('{'),
  417.                 2 send_pathname_size char(3), /* length of send-pathname */
  418.                 2 receive_pathname_size char(3),
  419.                                            /* length of receive_pathname */
  420.                 2 send_pathname(send_pathname_size) char,
  421.                                                         /* send_pathname */
  422.                 2 receive_pathname(receive_pathname_size) char,
  423.                                                      /* receive_pathname */
  424.                 2 bof_terminator char init ('}');
  425.  
  426.                        Figure 2. Beginning of File Packet
  427.  
  428.  
  429.      4. End of File Packet.
  430.  
  431.           When  all  the  data  of a file has been transferred, the sending
  432.      program sends an End of File Packet Figure 3.
  433.  
  434.            dcl 1 end_of_file_packet unaligned,
  435.                 2 eof_heading char(4) ('|EOF'),
  436.                 2 eof_stx char init ('{'),
  437.                 2 eof_length char (3),           /* length of next field */
  438.                 2 eof_sending_name(eof_length) char,
  439.                                         /* send_pathname from bof packet */
  440.                 2 eof_terminator char init ('}');
  441.  
  442.  
  443.                           Figure 3. End of File Packet
  444.  
  445.      4.1 End of File Packet Processing.
  446.  
  447.           This  packet  is  sent  in plain ASCII text followed by a newline
  448.      with the retry protocol of the data packet.  Once  the  processing  of
  449.      this  packet  is  completed, the files are closed at both ends and the
  450.      program returns to manual or shell mode to accept new commands.
  451.  
  452.      5. Hand Shake Packet.
  453.  
  454.           This packet is sent by the sending program before the start of  a
  455.      file  transfer.   If it is returned by the receiving program, the data
  456.      compression algorithm is activated.  If  the  packet  is  acknowledged
  457.      improperly, data compression is disengaged for the transfer.
  458.  
  459.      Draft - Subject to Change       - 3 -           University of Waterloo
  460.  
  461.      Formats            Machine to Machine Transmission      April 29, 1982
  462.  
  463.            dcl 1 hand_shake_packet unaligned,
  464.                 2 hs_soh char init ('|'),
  465.                 2 hs_dum char(12) init ('!$Compress$!'),
  466.                 2 hs_stx char init ('{'),
  467.                 2 hs_etx char init ('}');
  468.  
  469.                           Figure 4. Hand Shake Packet
  470.  
  471.      6. Warm Feelings.
  472.  
  473.           Since  this  program  is  probably  operated  under  control of a
  474.      terminal attached to an operator, it is sensible to send out some kind
  475.      of reassuring message every five or six seconds.  It is suggested that
  476.      this "warm feelings" message should be brief.  It has  been  suggested
  477.      that the output could be the number of characters or packets sent.  If
  478.      it is known that the operator  terminal  is  a  CRT  with  addressable
  479.      cursor, an update in place would be desireable.
  480.  
  481.      Draft - Subject to Change       - 4 -           University of Waterloo
  482. ---------------------------------------------------------------------------
  483.          HERE      COME     DE     CODE
  484. ---------------------------------------------------------------------------
  485. /* This program was developed by John C. Winterton at the University of
  486.    Waterloo using UNIX 4.1BSD under an educational licence.  The program
  487.    is made available without support or warranty of any kind implicit
  488.    or explicit.
  489.  
  490.    The purpose of the program is to communicate over a seven bit data
  491.    path with a similarly working copy of itself for the purpose of securely
  492.    transfering files from machine to machine.  This version contains specific
  493.    code for the version of the UNIX operating system on which it was
  494.    developed.  It further contains some code aimed at communicating with
  495.    a Honeywell TSS machine.
  496.  
  497.    The subroutine _abbrv is the work of Kevin P. Martin, and works well
  498.    indeed.  The other stuff is the author's, who takes the blame but
  499.    but no responsibility.                        */
  500.  
  501. /*    manifests for the mmx package                    */
  502.  
  503. #ifdef unix
  504. #include <stdio.h>
  505. #include <sgtty.h>
  506. #include <ascii.h>
  507. #define SPEEDEFAULT B2400        /* default baud rate        */
  508. #define LINEDEFAULT "/dev/sytek"    /* default comm line file    */
  509. #define LINETTY     "/dev/tty"        /* name of login tty        */
  510. #endif
  511.  
  512. #define BUFFSIZE 1024            /* length of keyboard buffers    */
  513. #define MAXSTRING 1024            /* length of general strings    */
  514. #define PACKSIZE 1024            /* length of packet buffers    */
  515. #define DEF_LENGTH 60            /* default data length in pkts    */
  516.  
  517. #define CL 017                /* four bit mask for lower char    */
  518. #define CU 0360                /* four bit mask for upper char    */
  519. #define CM 0177                /* 7    bit mask for input char    */
  520.  
  521. #define HEXUPPER 0x30            /* hex encodeing upper bits    */
  522. #define HEXFIRST HEXUPPER         /* '0'                */
  523. #define HEXLAST  0x3f            /* '?'                */
  524. #define HEXERROR -2            /* error signal for conversion    */
  525.  
  526. #define PROGESC '!'            /* escape character for commands*/
  527.  
  528. #define DISCONNECTED 0            /* state of communication line    */
  529. #define CONNECTED    1
  530.  
  531. #define MASTERPROMPT "\n>"        /* prompt for master state    */
  532. #define SLAVEPROMPT  "?"        /* prompt for slave state    */
  533.  
  534.  
  535.     /* manifests for ourcmd's line parsing */
  536.  
  537. #define STRING        0
  538. #define OPENLINE    1
  539. #define SENDFILE    2
  540. #define    GETFILE        3
  541. #define MAXLINE        4
  542. #define FINISHED    5
  543. #define MASTER        6
  544. #define SLAVE        7
  545. #define REMOTE        8
  546. #define VIEWSETUP    9
  547. #define CONTINUE    10
  548. #define ZDEBUG        11
  549.  
  550.     /* manifests for the promptable (system names) */
  551.  
  552. #define SYTEK        1
  553. #define LOCALNET    2
  554. #define    UNIX        3
  555. #define    GCOS        4
  556. #define MOD400        5
  557. #define THOTH        6
  558.  
  559.     /* manifests for packet transmission (special chars) */
  560.  
  561. #define X_SOH        '|'    /* pseudo start of header        */
  562. #define X_STX        '{'    /* pseudo start of text            */
  563. #define X_ETX        '}'    /* pseudo end of text            */
  564. #define X_ETB        '~'    /* pseudo end of text block        */
  565. #define X_GS        '!'    /* pseudo group separator (comprssion    */
  566.  
  567.     /* manifests for character offsets into decoded packet blocks    */
  568.  
  569. /* data packet */
  570.  
  571. #define D_SOH        0
  572. #define D_CKSUM        1
  573. #define D_DLENGTH    5
  574. #define D_STX        8
  575. #define D_BYTES        9
  576.  
  577. /* begin file packet */
  578.  
  579. #define F_SOH        0
  580. #define F_FILE        1
  581. #define F_DIRECTION    5
  582. #define F_CKSUM        6
  583. #define F_STX        10
  584. #define F_SENDLENGTH    11
  585. #define F_RECVLENGTH    14
  586. #define F_SENDPATH    17
  587.  
  588. /* end file packet */
  589.  
  590. #define E_SOH        0
  591. #define E_EOF        1
  592. #define E_STX        4
  593. #define E_EOFLENGTH    5
  594. #define E_SENDPATH    8
  595.  
  596. /* values for F_DIRECTION */
  597. #define TO_MASTER    '1'
  598. #define TO_SLAVE    '2'
  599.  
  600. /* for direction of motion in the data packet processor */
  601. #define NONE        0
  602. #define IN        1
  603. #define OUT        2
  604.  
  605. #define ERR_LIMIT    5    /* transmission error limit */
  606. #define COM_LIMIT    26    /* maximum number of chars for compression */
  607. #define WARM_FEEL    10    /* number of packets to pass before output
  608.                    of warm feelings indicator to MASTER    */
  609. /*
  610.  * _abbrv( pat, str )
  611.  *
  612.  * Perform match against string pattern.
  613.  * The pattern characters which are lowercase are optional.
  614.  * This routine recurs to a depth of n, where n is the number of optional
  615.  * characters provided in the match string.
  616.  *
  617.  */
  618.  
  619. int _abbrv( pat, str )
  620. char *str, *pat;
  621. {
  622.     char c;
  623.     /*
  624.      * Neither reqd nor patc is used without setting after the recursion,
  625.      * so they can be static to save stack space.
  626.      */
  627.     static int reqd;
  628.     static char patc;
  629.  
  630.     for(;;) {    /* each target character */
  631.         /*
  632.          * Pick up the next character to be matched.
  633.          * and uppercase it.
  634.          */
  635.         c = *(str++);
  636.         if( c >= 'a' && c <= 'z' )
  637.             c &= ~040;
  638.  
  639.         for(;;) {    /* each pattern character */
  640.             patc = *(pat++);
  641.  
  642.             /*
  643.              * Is it required (non-lowercase, including null) ?
  644.              */
  645.             reqd = patc < 'a' || patc > 'z';
  646.  
  647.             /*
  648.              * Compare uppercased pattern char with uppercased
  649.              * target char.
  650.              */
  651.             if( (reqd ? patc : patc & ~040) == c ) {
  652.                 /*
  653.                  * We have a hit. If the character was required,
  654.                  * continue along the target string.
  655.                  */
  656.                 if( reqd )
  657.                     break;
  658.  
  659.                 /*
  660.                  * Otherwise, recursively look down the string.
  661.                  * If the remainder of the string matches the
  662.                  * remainder of the pattern, all is matched.
  663.                  */
  664.                 if( _abbrv( pat, str ) )
  665.                     return( 1 );
  666.  
  667.                 /*
  668.                  * If the remainder of the string and the rest
  669.                  * of the pattern did not match, try skipping
  670.                  * this (optional) pattern character,
  671.                  * and find the next.
  672.                  */
  673.             }
  674.             else {
  675.                 /*
  676.                  * Didn't match. If it was required, fail.
  677.                  * else try next pattern character.
  678.                  */
  679.                 if( reqd )
  680.                     return( 0 );
  681.             }
  682.             /*
  683.              * Loop back to next pattern character (on same
  684.              * target character).
  685.              */
  686.         }
  687.  
  688.         /*
  689.          * We matched a required character... Was it a null?
  690.          * (end of pattern)
  691.          */
  692.         if( c == '\0' )
  693.             return( 1 );
  694.         /*
  695.          * Loop back to next target string character and next pattern
  696.          * character.
  697.          */
  698.     }
  699. }
  700. /*        convert input 8-bit  character to hexadecimal    */
  701.  
  702. #include "manifs.h"
  703.  
  704. char *a_to_hex(cin, cout)
  705. char cin, *cout;
  706. {
  707.     cout[0] = ((cin >> 4) & CL) | HEXUPPER;
  708.     cout[1] = (cin & CL) | HEXUPPER;
  709.     return (cout);
  710. }
  711. /*    output the appropriate ack    */
  712.  
  713. #include "manifs.h"
  714.  
  715. int ack()
  716.  
  717. {
  718.     sendline("y\n",2);
  719.     return(1);
  720. }
  721.         /* NON-PORTABLE    - UCB UNIX 4.X */
  722.  
  723. /* this routine uses an ioctl to see if there are any characters in the
  724.     input stream.
  725.     It returns the number of chars if there are any.        */
  726.  
  727. #include "manifs.h"
  728.  
  729. long ccount(stream)
  730. FILE *stream;
  731. {
  732.  
  733.     extern char prtab[];
  734.     extern int prompt, data_present;
  735.  
  736.     long nchars;
  737.     unsigned sleeptime;
  738.  
  739.     ioctl(fileno(stream), FIONREAD, &nchars);
  740.     nchars += (long) stream->_cnt;
  741.  
  742.     while (nchars == 0)
  743.     {
  744.         if (prtab[prompt] != DEL)
  745.             return(nchars);
  746.         for (sleeptime = 1; sleeptime <= 16; sleeptime *= 2)
  747.         {
  748.             ioctl(fileno(stream), FIONREAD, &nchars);
  749.             nchars += (long) stream->_cnt;
  750.             if (nchars != 0)
  751.                 return(nchars);
  752.             if (sleeptime > 2 && data_present)
  753.                 return(nchars);
  754.             if (sleeptime == 8)
  755.                 message ("Wait");
  756.             if (sleeptime > 8)
  757.                 message (".");
  758.             sleep(sleeptime);
  759.         }
  760.         break;
  761.     }
  762.  
  763.     return(nchars);
  764. }
  765. /*    checksum from a given X_STX to either a X_ETX or X_ETB exclusive */
  766.  
  767. #include "manifs.h"
  768.  
  769. unsigned checksum(p)
  770. char *p;
  771.  
  772. {        /* p->X_STX */
  773.  
  774.     int c, i;
  775.     unsigned sum;
  776.  
  777.  
  778.     if (p[0] != X_STX)
  779.         return (0);    /* error */
  780.     sum = 0;
  781.     for (i = 1; ; ++i)
  782.     {
  783.         c = (p[i]) & CM;
  784.         switch(c)
  785.         {
  786.         default:
  787.             if (c < ' ' || c > '~')
  788.                 return(0);    /* non-packet char */
  789.             sum += c;
  790.             continue;
  791.         case X_ETX:
  792.         case X_ETB:
  793.             return(sum);
  794.         }
  795.     }
  796. }
  797. /*    process incoming packet in indicated buffer    */
  798.  
  799. #include "manifs.h"
  800.  
  801. int dopacket(ptr, len)
  802. char ptr[];
  803. int len;
  804. {
  805.     extern char handshake[];
  806.     extern int errcount, compress;
  807.  
  808.     char c;
  809.     int i;
  810.  
  811.     c = ptr[1];    /*    get first char of header    */
  812.     switch(c)    /*    and identify packet        */
  813.     {
  814.     case '!':
  815.         i = strncmp(ptr, handshake, strlen(handshake) - 1);
  816.         if (i == 0)
  817.         {
  818.             compress = 1;
  819.             return(ack());
  820.         }
  821.         message("Compression request garbled - quitting.\n");
  822.         nack();
  823.         return(2);    /* transfer request fails */
  824.     case 'F':
  825.         if (filepacket(ptr, len))
  826.             return(ack());
  827.         return(nack());
  828.     case 'E':
  829.         if(eofpacket(ptr, len))
  830.         {
  831.             ack();
  832.             return(2);
  833.         }
  834.         return(nack());
  835.     default:
  836.         if (c >= '0' && c <= '9')
  837.             if(xferpacket( ptr, len))
  838.             {
  839.                 errcount = 0;
  840.                 return(ack());
  841.             }
  842.         if ( (++errcount) > ERR_LIMIT )
  843.         {
  844.             message ("Too many errors - quitting.\n");
  845.             nack();
  846.             return(2);
  847.         }
  848.         return(nack());
  849.     }
  850. }
  851. /*    process incoming eof packet    */
  852.  
  853. #include "manifs.h"
  854.  
  855. int eofpacket(ptr, len)
  856. char ptr[];
  857. int len;
  858. {
  859.     extern FILE *xfer_file;
  860.     extern int filecmd;
  861.  
  862.     filecmd = NONE;
  863.     fclose(xfer_file);
  864.     return(1);
  865. }
  866.     /* NON PORTABLE - UCB UNIX 4.X */
  867.  
  868. /*    externals for mmx program                    */
  869.  
  870. #include "manifs.h"
  871.  
  872. FILE *in_line = 0;        /*    comm line input unit        */
  873. FILE *out_line = 0;        /*    comm line output unit        */
  874. FILE *xfer_file;        /*    for current file transfer    */
  875. int filecmd = NONE;        /*    direction indicator for xfer    */
  876. struct sgttyb com_line;        /*    comm line parameters from gtty    */
  877. struct sgttyb com_save;        /*    copy of com_line for wrapup    */
  878. struct tchars com_1;        /*    from ioctl for signals        */
  879. struct tchars com_1s;        /*    copy of com_1 for wrapup    */
  880. struct ltchars com_2;        /*    from ioctl for other signals    */
  881. struct ltchars com_2s;        /*    copy of com_2 for wrapup    */
  882.  
  883. unsigned zdebug = 0;        /*    debug control            */
  884. int on_line = 0;        /*    flag set by setup if /dev/tty    */
  885.                 /*    really is a terminal        */
  886.  
  887. char syntax[] = {
  888.     "Use:mmx [slave] [l=linename] [s=baudrate]\n"
  889. };
  890. char fileformat[] =         /*    constant used in inwards    */
  891.     {"%03d%03d%s%s%c"};
  892.  
  893. char callname[20];        /*    name for the message routine    */
  894.  
  895. char handshake[] = {
  896.     "|!$Compress$!{}\n"    /*    data compression handshake    */
  897. };
  898.  
  899. char linebuf[BUFFSIZE];        /*    keyboard input buffer        */
  900.  
  901. char packet[PACKSIZE];        /*    data packet            */
  902.  
  903. int eofsw = 0;            /*    additional control for loadline    */
  904.  
  905. char file_local[MAXSTRING];    /*    name of local transfer file    */
  906. char file_remote[MAXSTRING];    /*    name of remote tranfer file    */
  907.  
  908.     /*    Table of _abbrv patterns for the main ourcmd processor    */
  909.  
  910.     /* note: The zeroth and last entry of all tables of this type
  911.          are set to null strings for the benefit of the identify()
  912.          routine                        */
  913.  
  914. char *optab[] = {
  915.     "",            /*    zero'th one is always null    */
  916.     "Open",            /*    open the line            */
  917.     "Send",            /*    send infile outfile        */
  918.     "Get",            /*    get infile outfile        */
  919.     "MaxData",        /*    maxdata nnn            */
  920.     "Quit",            /*    quit                */
  921.     "MAster",        /*    enter master state (default)    */
  922.     "SLave",        /*    enter slave state        */
  923.     "Remote",        /*    request new remote set up    */
  924.     "Viewsetup",        /*    display remote set up        */
  925.     "Continue",        /*    read the comm_line send nothing    */
  926.     "Zdebug",        /*    zdebug on|off            */
  927.     ""            /*    last one is always null        */
  928. };
  929.  
  930.     /*    This collection of variables contains the program state    */
  931.  
  932. int progstate = MASTER;        /*    current state of things        */
  933. int linestate = DISCONNECTED;    /*    current state of comm line    */
  934. int speed;            /*    line speed             */
  935. int errcount = 0;        /*    error count for packet xmit    */
  936. int compress = 0;        /*    data compression enable switch    */
  937. int maxline = DEF_LENGTH;    /*    default maximum transmission    */
  938. int newline = SYTEK;        /*    settable newline for outgoing    */
  939. int prompt  = SYTEK;        /*    termination style of input    */
  940. int remote = SYTEK;        /*    comm line device type        */
  941. int data_present = 0;        /*    for readline routine        */
  942. char line_name[MAXSTRING];    /*    comm line name string        */
  943. char line_save[MAXSTRING];    /*    copy of line_name (MASTER)    */
  944. char in_prompt[5]        /*    prompt string at terminal    */
  945.     = {MASTERPROMPT};    /*    default for starting up        */
  946.  
  947.     /*    The entries in the following three tables bear a one-to-one
  948.         relation to each other as follows:
  949.  
  950.         prtable is the table of known system names for _abbrv
  951.             processing by the !remote request;
  952.         prtab entries indicate the prompt character for the
  953.             corresponding system;
  954.         nltab entries contain the chracter that the relevant system
  955.             accepts as a <newline> or <end transmission>    */
  956.  
  957. char *prtable[] = {
  958.  
  959.     "",
  960.     "Sytek",
  961.     "Localnet",
  962.     "Unix",
  963.     "Gcos8",
  964.     "Mod400",
  965.     "Thoth",
  966.     ""
  967. };
  968.  
  969.     /* note: in prtab an entry of DEL (\0177) indicates a system with
  970.         no particular known prompt. Serviced by timeout        */
  971.  
  972. char prtab[] = {
  973.     NUL,
  974.     DEL,        /*    sytek                */
  975.     DEL,        /*    localnet            */
  976.     DEL,        /*    unix                */
  977.     DEL,        /*    control-q for the bun        */
  978.     DEL,        /*    Mod400 (GCOS6)            */
  979.     DEL,        /*    thoth(?)            */
  980.     NUL
  981. };
  982. char nltab[] = {
  983.     NUL,
  984.     CR,            /*    sytek                */
  985.     CR,            /*    localnet            */
  986.     CR,            /*    unix                */
  987.     CR,            /*    gcos8                */
  988.     CR,            /*    Mod400                */
  989.     CR,            /*    thoth(?)            */
  990.     NUL
  991. };
  992. /*    routine to packetize and send an input file    */
  993.  
  994. #include "manifs.h"
  995.  
  996. int fileout()
  997.  
  998. {
  999.     extern FILE *xfer_file;
  1000.     extern char packet[], linebuf[], file_local[];
  1001.     extern int compress, maxline, errcount, progstate;
  1002.  
  1003.     int lx, c, pkt_cnt;
  1004.  
  1005.     c = lx = pkt_cnt = 0;
  1006.     while ( (c = getc(xfer_file)) != EOF)
  1007.     {
  1008.         linebuf[lx++] = c;
  1009.         if (lx < maxline)
  1010.             continue;
  1011.         outdata(linebuf, lx);
  1012.         if (errcount >= ERR_LIMIT)
  1013.             return(0);
  1014.         if ( (progstate == MASTER) &&
  1015.             ( (++pkt_cnt % WARM_FEEL) == 0) )
  1016.                 message(".");
  1017.         lx = 0;
  1018.     }
  1019.     if (lx)
  1020.     {
  1021.         outdata(linebuf, lx);
  1022.         if (errcount >= ERR_LIMIT)
  1023.             return(0);
  1024.     }
  1025.     sprintf(packet, "|EOF{%03d%s}", strlen(file_local), file_local);
  1026.     for (errcount = 0; errcount < ERR_LIMIT; errcount++)
  1027.         if (sendpacket(packet))
  1028.             break;
  1029.  
  1030.     return(errcount < ERR_LIMIT);
  1031. }
  1032. /*    process an incoming file header packet        */
  1033.  
  1034. #include "manifs.h"
  1035.  
  1036. int filepacket(ptr, len)
  1037. char ptr[];
  1038. int len;
  1039. {
  1040.     extern FILE *xfer_file;
  1041.     extern char file_local[];
  1042.     extern int progstate, filecmd;
  1043.     extern unsigned checksum();
  1044.  
  1045.     char filename[160];
  1046.     int i, s_length, r_length, limit;
  1047.     unsigned cksum, value;
  1048.     char *pick;
  1049.  
  1050.     value = checksum(&(ptr[F_STX]));
  1051.     i = sscanf(ptr, "|FILE%*c%4d{%3d%3d", &cksum, &s_length, &r_length);
  1052.     if (i < 3)
  1053.         return(0);        /* error on packet */
  1054.     if (value != cksum)
  1055.         return(0);
  1056.  
  1057.     switch(progstate)
  1058.     {
  1059.     case MASTER:
  1060.         switch (ptr[F_DIRECTION])
  1061.         {
  1062.         case TO_MASTER:
  1063.             pick = &(ptr[F_SENDPATH + s_length]);
  1064.             limit = r_length;
  1065.             break;
  1066.         case TO_SLAVE:
  1067.             pick = &(ptr[F_SENDPATH]);
  1068.             limit = s_length;
  1069.             break;
  1070.         default:
  1071.             return(0);
  1072.         }
  1073.         break;
  1074.     case SLAVE:
  1075.         switch (ptr[F_DIRECTION])
  1076.         {
  1077.         case TO_SLAVE:
  1078.             pick = &(ptr[F_SENDPATH + s_length]);
  1079.             limit = r_length;
  1080.             break;
  1081.         case TO_MASTER:
  1082.             pick = &(ptr[F_SENDPATH]);
  1083.             limit = s_length;
  1084.             break;
  1085.         default:
  1086.             return(0);
  1087.         }
  1088.         break;
  1089.     default:
  1090.         message("Program in an impossible state in filepacket\n");
  1091.         message("Dumping");
  1092.         kill(getpid(), 9);
  1093.     }
  1094.  
  1095.     for (i = 0; i < limit; ++i)
  1096.         filename[i] = pick[i];
  1097.     filename[i] = NUL;
  1098.  
  1099.     filecmd = IN;
  1100.     if (progstate == MASTER)
  1101.         if (ptr[F_DIRECTION] == TO_MASTER)
  1102.         {
  1103.             filecmd   = OUT;
  1104.             xfer_file = fopen(filename, "w");
  1105.         }
  1106.         else
  1107.             xfer_file = fopen(filename, "r");
  1108.     else    /* state is SLAVE */
  1109.         if (ptr[F_DIRECTION] == TO_SLAVE)
  1110.         {
  1111.             filecmd = OUT;
  1112.             xfer_file = fopen(filename, "w");
  1113.         }
  1114.         else
  1115.             xfer_file = fopen(filename, "r");
  1116.  
  1117.     if (xfer_file == NULL)
  1118.     {
  1119.         filecmd = NONE;
  1120.         return(0);
  1121.     }
  1122.  
  1123.     strcpy (file_local, filename);
  1124.     return(1);
  1125. }
  1126. /* convert a pair of hexadecimal coded input chars to an 8 bit char    */
  1127.  
  1128. #include "manifs.h"
  1129.  
  1130. int hex_to_a(cin)
  1131. char *cin;
  1132. {
  1133.  
  1134.     register int i, cout;
  1135.     register char c;
  1136.  
  1137.     cout = 0;        /* insurance */
  1138.     for (i = 0; i < 2; ++i)
  1139.     {
  1140.         c = cin[i];
  1141.         if (HEXFIRST <= c && c <= HEXLAST)
  1142.             cout = ( ( cout << 4 ) & CU ) | (c & CL);
  1143.         else
  1144.             return(HEXERROR);
  1145.     }
  1146.     return (cout);
  1147. }
  1148. /*        This routine identifies the presented argument
  1149.         againts the table of acceptable commands        */
  1150.  
  1151. #include "manifs.h"
  1152.  
  1153. int identify(table,string)
  1154. char *table[];
  1155. char string[];
  1156.  
  1157. {
  1158.  
  1159.     int i;
  1160.  
  1161.     for (i = 1; table[i][0] != NUL; ++i)
  1162.         if ((_abbrv(table[i], string) == 1))
  1163.             return (i);
  1164.     return (0);
  1165. }
  1166. /*        This routine tests stdin and returns 1 if it is a tty
  1167.         otherwise it returns 0                    */
  1168.  
  1169. int ifonline ()
  1170. {
  1171.     extern int on_line;
  1172.  
  1173.     return (on_line);
  1174. }
  1175. /*    manage an inbound file transfer                    /*
  1176.  
  1177. /*    when called, localname has been opened on xfer_file and
  1178.     compression handshaking is complete.  This routine formats and
  1179.     sends out the file header packet with verification then turns
  1180.     control over to the inbound packet processor            */
  1181.  
  1182. #include "manifs.h"
  1183.  
  1184. int inwards(remotename, localname)
  1185. char remotename[], localname[];
  1186. {
  1187.     extern char packet[], *rawfgets(), fileformat[];
  1188.     extern int progstate;
  1189.     extern unsigned checksum();
  1190.  
  1191.     int err_cnt, l_length, r_length, i, q;
  1192.     unsigned cksum;
  1193.     char work[BUFFSIZE], *p;
  1194.  
  1195.     strcpy (packet, "|FILE");
  1196.     packet[F_DIRECTION] = (progstate == MASTER ? TO_MASTER : TO_SLAVE);
  1197.     packet[F_STX] = X_STX;
  1198.     l_length = strlen(localname);
  1199.     r_length = strlen(remotename);
  1200.     if (progstate == MASTER)
  1201.         sprintf(work, fileformat,
  1202.             r_length, l_length, remotename, localname, X_ETX);
  1203.     else
  1204.         sprintf(work, fileformat,
  1205.             l_length, r_length, localname, remotename, X_ETX);
  1206.     p = &(packet[F_SENDLENGTH]);
  1207.     q = strlen(work);
  1208.     for (i = 0; i < q; ++i)
  1209.         p[i] = work[i];
  1210.     cksum = checksum(&(packet[F_STX]));
  1211.     if (cksum == 0)
  1212.     {
  1213.         message ("Error calculating checksum in inwards routine\n");
  1214.         kill (getpid(), 9);    /* program bug if happens */
  1215.     }
  1216.     sprintf(work, "%04d", cksum % 10000);
  1217.     p = &(packet[F_CKSUM]);
  1218.     for (i = 0; i < 4; ++i)
  1219.         p[i] = work[i];
  1220.     for (err_cnt = 0; err_cnt < ERR_LIMIT; ++err_cnt)
  1221.         if (sendpacket(packet))
  1222.             break;
  1223.     if (err_cnt >= ERR_LIMIT)
  1224.     {
  1225.         message ("Error limit reached on file packet\n");
  1226.         return(0);
  1227.     }
  1228.     if (!procpack())
  1229.         message("Get: File transfer failed\n");
  1230.     else
  1231.         message("Get: Completed\n");
  1232.     return(1);
  1233. }
  1234. /*    parse the command option l=string for the comm line    */
  1235.  
  1236. int linearg(string)
  1237. char *string;
  1238. {
  1239.     extern char line_name[], line_save[];
  1240.  
  1241.     if (string[1] != '=')
  1242.     {
  1243.         message ("%s not understood\n", string);
  1244.         return (1);
  1245.     }
  1246.     strcpy(line_name, &string[2]);    /*    used here    */
  1247.     strcpy(line_save, line_name);    /*    remember here    */
  1248.     return(0);
  1249. }
  1250. /*    list options for a verb when they consist of another table    */
  1251.  
  1252. #include "manifs.h"
  1253.  
  1254. int listopt(string, table)
  1255. char string[], *table[];
  1256. {
  1257.  
  1258.     int i;
  1259.  
  1260.     message ("Options for the %s command are:\n", string);
  1261.     for (i = 1; table[i][0] != NUL; ++i)
  1262.         message ("%s ", table[i]);
  1263.     message ("\n");
  1264.     return(1);
  1265. }
  1266. /*    load a line into a string from the stdin file        */
  1267.  
  1268. #include "manifs.h"
  1269.  
  1270. int loadline(string, limit)
  1271. char string[];
  1272. int limit;
  1273. {
  1274.     extern int progstate, eofsw, progstate, linestate;
  1275.     extern char in_prompt[];
  1276.     extern char *rawfgets();
  1277.  
  1278.     char *ret;
  1279.  
  1280.     if (eofsw > 0)
  1281.         return (EOF);
  1282.  
  1283.     message ("%s", in_prompt);    /* prompt */
  1284.  
  1285.     if (progstate == SLAVE && linestate == CONNECTED)
  1286.         ret = rawfgets(string, limit, stdin);
  1287.     else
  1288.         ret = fgets(string, limit, stdin);
  1289.     if (ret == NULL)
  1290.     {
  1291.         eofsw = 1;
  1292.         return (EOF);
  1293.     }
  1294.     return ( strlen(string) );
  1295. }
  1296.     /* NON PORTABLE     UCB UNIX 4.X */
  1297.  
  1298. /*    Set up input and output units for the comm line        */
  1299.  
  1300. #include "manifs.h"
  1301.  
  1302. int lopen()
  1303. {
  1304.  
  1305.     extern int linestate;
  1306.     extern int speed;
  1307.     extern char line_name[];
  1308.     extern FILE *in_line, *out_line;
  1309.     extern struct sgttyb com_line;
  1310.     extern struct sgttyb com_save;
  1311.     extern struct tchars com_1;
  1312.     extern struct tchars com_1s;
  1313.     extern struct ltchars com_2;
  1314.     extern struct ltchars com_2s;
  1315.  
  1316.     int stat, stat_too;
  1317.     int ldiscipline = NTTYDISC;
  1318.     int not_the_tty;
  1319.  
  1320.     not_the_tty = ( strcmp (line_name, LINETTY) );    /* zero if terminal */
  1321.  
  1322.     if (linestate == CONNECTED)
  1323.     {
  1324.         message ("Line is already open\n");
  1325.         return(1);
  1326.     }
  1327.  
  1328.     if (not_the_tty)
  1329.     {
  1330.         in_line = fopen (line_name, "r");    /* open for read */
  1331.         out_line = fopen (line_name, "w");    /* open for write */
  1332.         if (in_line == NULL || out_line == NULL    )
  1333.         {
  1334.             message ("Could not open line %s\n", line_name);
  1335.             return(0);
  1336.         }
  1337.     }
  1338.     else
  1339.     {
  1340.         in_line = stdin;
  1341.         out_line = stdout;
  1342.     }
  1343.  
  1344.     /* set new tty    */
  1345.     stat = ioctl(fileno(in_line), TIOCSETD, &ldiscipline);
  1346.     if (stat < 0)
  1347.     {
  1348.         message ("Couldn't set new tty discipline on line %s\n",
  1349.             line_name);
  1350.         return(0);
  1351.     }
  1352.  
  1353.         /* read line parameters */
  1354.     stat = ioctl(fileno(in_line), TIOCGETP, &com_line);
  1355.     stat_too = ioctl(fileno(in_line), TIOCGETP, &com_save);
  1356.     if (stat < 0 || stat_too < 0)
  1357.     {
  1358.         message ("Open routine failed reading line parameters\n");
  1359.         return(0);
  1360.     }
  1361.     ioctl (fileno(in_line), TIOCGETC, &com_1);
  1362.     ioctl (fileno(in_line), TIOCGETC, &com_1s);
  1363.     ioctl (fileno(in_line), TIOCGLTC, &com_2);
  1364.     ioctl (fileno(in_line), TIOCGLTC, &com_2s);
  1365.     com_1.t_intrc = com_1.t_quitc = com_1.t_eofc = -1;
  1366.     ioctl(fileno(in_line), TIOCSETC, &com_1);
  1367.     com_2.t_suspc = com_2.t_dsuspc = com_2.t_rprntc =
  1368.         com_2.t_flushc = com_2.t_werasc = com_2.t_lnextc = -1;
  1369.     ioctl(fileno(in_line), TIOCSLTC, &com_2);
  1370.  
  1371.     if (not_the_tty)
  1372.         com_line.sg_ispeed = com_line.sg_ospeed = speed;
  1373.  
  1374.     com_line.sg_erase = '\010';    /* erase char is backspace */
  1375.     com_line.sg_kill  = '\030';    /* kill char is ctrl-x       */
  1376.         /* set line controls for char by char */
  1377.     com_line.sg_flags = CBREAK | TANDEM;
  1378.  
  1379.     stat = ioctl(fileno(in_line), TIOCSETP, &com_line); /* set it up */
  1380.     if (stat < 0)
  1381.     {
  1382.         message ("Failed to set up line properly\n");
  1383.         return(0);
  1384.     }
  1385.  
  1386.     /* set exclusive use */
  1387.     stat = ioctl(fileno(in_line), TIOCEXCL, NULL);
  1388.     if (stat < 0)
  1389.     {
  1390.         message ("Failed to set exclusive use on line\n");
  1391.         return(0);
  1392.     }
  1393.  
  1394.     /* set hangup on close */
  1395.     stat = ioctl(fileno(in_line), TIOCHPCL, NULL);
  1396.     if (stat < 0)
  1397.     {
  1398.         message("Failed to set hang up on close on line\n");
  1399.         return(0);
  1400.     }
  1401.  
  1402.     linestate = CONNECTED;
  1403.     message("Line connected\n");
  1404.     return(1);
  1405. }
  1406.     /* general machine to machine file transfer shell program */
  1407.  
  1408. #include "manifs.h"
  1409.  
  1410. int main (argc, argv)
  1411. int argc;
  1412. char *argv[];
  1413. {
  1414.     extern char linebuf[], callname[];
  1415.     extern int progstate;
  1416.  
  1417.     int status, i;
  1418.     char c;
  1419.  
  1420.     status = setup (argc, argv);
  1421.     if (status == 0)
  1422.     {
  1423.         message ("%s: Setup fails\n", callname);
  1424.         exit(-1);
  1425.     }
  1426.     message ("%s: Setup complete\nType !v for program status\n",
  1427.         callname);
  1428.     for (status = 1; status != 0; )
  1429.         switch (status) {
  1430.             case 1:
  1431.                 status = process(loadline(linebuf, BUFFSIZE));
  1432.                 continue;
  1433.             case 2:
  1434.                     /* note - anti-reflection code */
  1435.  
  1436.                 i = readline(linebuf, BUFFSIZE);
  1437.                 c = linebuf[0];
  1438.                 if ( ( (progstate == SLAVE) && (c == X_SOH) )
  1439.                     || (c == PROGESC) )
  1440.                     status = process(i);
  1441.                 else
  1442.                     status = 1;
  1443.                 continue;
  1444.             default:
  1445.                 message ("Illegal status in main %d\n",
  1446.                     status);
  1447.                 wrapup();
  1448.                 exit(-1);
  1449.         }
  1450.     exit(0);
  1451.  
  1452.     /* note on anti-reflection:
  1453.         The case 2 above must be left this way.  If process is
  1454.         called directly (e.g. status = process(readline ...))
  1455.         then the last line input will be sent to the other device
  1456.         ad nauseam.  This code checks for things that CAN be
  1457.         handled by process().  It is left to the maintainer to
  1458.         fathom why it was done this way.
  1459.     */
  1460. }
  1461. /*    This routine is not portable, and is used to hide printf    */
  1462. /*    do a printf and return the value 1                */
  1463.  
  1464. #include "manifs.h"
  1465.  
  1466. int message(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
  1467. char *format;
  1468. int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  1469. {
  1470.     fprintf (stdout, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
  1471.     fflush(stdout);
  1472.     return (1);
  1473. }
  1474. /*    make a data packet obeying compression rules
  1475.     input is in in_char for length in_len chars
  1476.     output is ready to send packet in out_pack    */
  1477.  
  1478. #include "manifs.h"
  1479.  
  1480. mkdatapacket(in_char, out_pack, in_len)
  1481. char in_char[], out_pack[];
  1482. int in_len;
  1483. {
  1484.     extern int compress;
  1485.  
  1486.     char *cp, pair[2], *a_to_hex();
  1487.     int wx, px, ix, count;
  1488.     unsigned cksum;
  1489.  
  1490.     cksum = 0;
  1491.     for (ix = 0; ix < in_len; ++ix)
  1492.         cksum += in_char[ix];
  1493.     cksum %= 10000;
  1494.     sprintf(out_pack, "|%04d%03d{", cksum, in_len);
  1495.     cp = &(out_pack[D_BYTES]);
  1496.     px = ix = 0;
  1497.     while (ix < in_len)
  1498.     {
  1499.         if (compress && ((in_len - ix) > 2))
  1500.         {
  1501.             wx = ix;        /* in case of backout */
  1502.  
  1503.             while ((in_char[wx] == in_char[++ix]) && ix < in_len)
  1504.                 ;
  1505.             count = ix - wx;
  1506.             if (count > COM_LIMIT)
  1507.             {
  1508.                 ix -= (count - COM_LIMIT);
  1509.                 count = COM_LIMIT;
  1510.             }
  1511.             if (count > 2)
  1512.             {
  1513.                 cp[px++] = X_GS;
  1514.                 cp[px++] = (count | 0x40) & CM;
  1515.                 a_to_hex(in_char[wx], pair);
  1516.                 cp[px++] = pair[0];
  1517.                 cp[px++] = pair[1];
  1518.                 continue;
  1519.             }
  1520.             else
  1521.                 ix = wx;    /* back off */
  1522.         }
  1523.  
  1524.         a_to_hex(in_char[ix++], pair);
  1525.         cp[px++] = pair[0];
  1526.         cp[px++] = pair[1];
  1527.     }
  1528.     cp[px] = X_ETX;
  1529. }
  1530. /*    output the appropriate nack    */
  1531.  
  1532. #include "manifs.h"
  1533.  
  1534. int nack()
  1535.  
  1536. {
  1537.     sendline("n\n",2);
  1538.     return(0);
  1539. }
  1540. /*        process a command line from the stdin device        */
  1541.  
  1542. #include "manifs.h"
  1543.  
  1544. int ourcmd(linebuf, inlength)
  1545. char linebuf[];
  1546. int inlength;
  1547. {
  1548.     extern char *optab[], *prtable[];
  1549.     extern int  linestate, progstate;
  1550.     extern char line_name[], line_save[], in_prompt[];
  1551.     extern char file_local[], file_remote[];
  1552.     extern unsigned zdebug;
  1553.  
  1554.     int cmd, argcount;
  1555.     char arglist[20][MAXSTRING];
  1556.  
  1557.     if (linebuf[1] == PROGESC)    /* two escapes - send it */
  1558.     {
  1559.         sendline (&linebuf[1], inlength - 1);
  1560.         return(2);        /* main will read line   */
  1561.     }
  1562.  
  1563.     argcount = tokenize(&linebuf[1], inlength-1, arglist);
  1564.     if (!argcount)
  1565.     {
  1566.         message ("%s - no valid arguments found", linebuf);
  1567.         return(1);
  1568.     }
  1569.  
  1570.     cmd = identify(optab, arglist[0]);
  1571.  
  1572.     switch (cmd)
  1573.     {
  1574.  
  1575.         case OPENLINE:        /* open the communications line   */
  1576.             if (lopen() == 0) {
  1577.                 wrapup();    /* fatal error          */
  1578.                 return(0);
  1579.             }
  1580.             return(1);
  1581.  
  1582.         case SENDFILE:        /* send a file from here to there */
  1583.             if (progstate == SLAVE)
  1584.             {
  1585.                 message("Send: MASTER state command ");
  1586.                 message("but program is in SLAVE\n");
  1587.             }
  1588.             if (argcount != 3)
  1589.             {
  1590.                 message ("Usage: Send localfile remotefile\n");
  1591.                 return (1);
  1592.             }
  1593.             strcpy(file_local, arglist[1]);
  1594.             strcpy(file_remote, arglist[2]);
  1595.             return(send(file_local, file_remote));
  1596.  
  1597.         case GETFILE:        /* get a file from there to here  */
  1598.             if (progstate == SLAVE)
  1599.             {
  1600.                 message ("Get: MASTER state command ");
  1601.                 message ("but program is in SLAVE\n");
  1602.                 return(1);
  1603.             }
  1604.             if (argcount != 3)
  1605.             {
  1606.                 message ("Usage: Get remotefile localfile\n");
  1607.                 return(1);
  1608.             }
  1609.             strcpy(file_remote, arglist[1]);
  1610.             strcpy(file_local, arglist[2]);
  1611.             return(receive(file_remote, file_local));
  1612.  
  1613.         case MAXLINE:        /* set the maximum number of bytes
  1614.                        that can be sent at one time   */
  1615.             if (argcount != 2)
  1616.             {
  1617.                 message ("Usage: %s nn\n", optab[cmd]);
  1618.                 return(1);
  1619.             }
  1620.             return(setmaxl(arglist[1]));
  1621.  
  1622.         case FINISHED:        /* close out program          */
  1623.             wrapup();
  1624.             return(0);
  1625.  
  1626.         case MASTER:
  1627.         case SLAVE:
  1628.             if (progstate == cmd)
  1629.                 message ("Already in %s state\n",
  1630.                     optab[cmd]);
  1631.             else {
  1632.                 progstate = cmd;
  1633.                 if (cmd == MASTER)
  1634.                 {
  1635.                     strcpy (in_prompt, MASTERPROMPT);
  1636.                     strcpy (line_name, line_save);
  1637.                 }
  1638.                 else
  1639.                 {
  1640.                     strcpy (in_prompt, SLAVEPROMPT);
  1641.                     strcpy (line_name, LINETTY);
  1642.                 }
  1643.                 message ("%s state set\n", optab[cmd]);
  1644.             }
  1645.             return (1);
  1646.  
  1647.         case REMOTE:
  1648.             if (argcount != 2)
  1649.             {
  1650.                 listopt (optab[cmd], prtable);
  1651.                 return (1);
  1652.             }
  1653.             setremote(arglist[1]);
  1654.             return(1);
  1655.  
  1656.         case VIEWSETUP:
  1657.             showsetup();
  1658.             return(1);
  1659.  
  1660.         case CONTINUE:
  1661.             return(2);
  1662.  
  1663.         case ZDEBUG:
  1664.             zdebug = ((arglist[1][1] | ' ') == 'n');
  1665.             return(1);
  1666.  
  1667.         default:
  1668.             message ("%s not recognized as a command\n",
  1669.                 arglist[0]);
  1670.             listopt("on-line", optab);
  1671.             return  (ifonline());
  1672.     }
  1673. }
  1674. /* make and output a data packet    */
  1675.  
  1676. #include "manifs.h"
  1677.  
  1678. outdata(p, l)
  1679. char p[];
  1680. int l;
  1681. {
  1682.     extern char packet[];
  1683.     extern int errcount;
  1684.  
  1685.     mkdatapacket(p, packet, l);
  1686.     for (errcount = 0; errcount < ERR_LIMIT; ++errcount)
  1687.         if (sendpacket(packet))
  1688.             break;
  1689. }
  1690. /* manage an outbound file transfer                    */
  1691.  
  1692. /* this routine is the converse of inwards and is called with similar
  1693.    conditions (xfer_file is open, etc.).  After formatting the file
  1694.    header and having it accepted by the other program, fileout is
  1695.    called to transfer the data.                        */
  1696.  
  1697. #include "manifs.h"
  1698.  
  1699. int outwards (file_local, file_remote)
  1700. char file_local[], file_remote[];
  1701. {
  1702.     extern char packet[], *rawfgets(), fileformat[];
  1703.     extern int progstate;
  1704.     extern unsigned checksum();
  1705.  
  1706.     int err_cnt, l_length, r_length, i, q;
  1707.     unsigned cksum;
  1708.     char work[BUFFSIZE], *p;
  1709.  
  1710.     strcpy (packet, "|FILE");
  1711.     packet[F_DIRECTION] = (progstate == MASTER ? TO_SLAVE : TO_MASTER);
  1712.     packet[F_STX] = X_STX;
  1713.     l_length = strlen(file_local);
  1714.     r_length = strlen(file_remote);
  1715.     if (progstate == MASTER)
  1716.         sprintf( work, fileformat,
  1717.             l_length, r_length, file_local, file_remote, X_ETX);
  1718.     else
  1719.         sprintf( work, fileformat,
  1720.             r_length, l_length, file_remote, file_local, X_ETX);
  1721.     p = &(packet[F_SENDLENGTH]);
  1722.     q = strlen(work);
  1723.     for (i = 0; i < q; ++i)
  1724.         p[i] = work[i];
  1725.     cksum = checksum(&(packet[F_STX]));
  1726.     if (cksum == 0)
  1727.     {
  1728.         message("Error calculating checksum in outwards routine\n");
  1729.         kill (getpid(), 9);    /* program bug if happens */
  1730.     }
  1731.     sprintf(work, "%04d", cksum % 10000);
  1732.     p = &(packet[F_CKSUM]);
  1733.     for (i = 0; i < 4; ++i)
  1734.         p[i] = work[i];
  1735.     for (err_cnt = 0; err_cnt < ERR_LIMIT; ++err_cnt)
  1736.         if (sendpacket(packet))
  1737.             break;
  1738.     if (err_cnt >= ERR_LIMIT)
  1739.     {
  1740.         message("Error limit reached on file packet\n");
  1741.         return(0);
  1742.     }
  1743.     if (!fileout())
  1744.         message("Send: File transfer failed\n");
  1745.     else
  1746.         message("Send: Completed\n");
  1747.     return(1);
  1748. }
  1749. /* process the contents of linebuf and decide where to get the next line */
  1750.  
  1751. #include "manifs.h"
  1752.  
  1753. int process(i)
  1754. int i;
  1755. {
  1756.     extern char *rawfgets(), linebuf[];
  1757.     extern int progstate, linestate, filecmd;
  1758.     extern FILE *in_line;
  1759.  
  1760.     char c;
  1761.  
  1762.     if (i == EOF) {                /* wrap up, friends    */
  1763.         wrapup();
  1764.         return (0);
  1765.     }
  1766.     if (i == 0)
  1767.         return(1);
  1768.     c = linebuf[0];
  1769.     if (progstate == SLAVE && c == X_SOH)
  1770.         if (linestate == DISCONNECTED)
  1771.         {
  1772.             message("Packet input, but line is not open\n");
  1773.             return(1);
  1774.         }
  1775.         else
  1776.         {
  1777.             while ((dopacket(linebuf, i) < 2)
  1778.                 && (filecmd != IN))
  1779.                 i = strlen(rawfgets (linebuf, BUFFSIZE, in_line));
  1780.             if (filecmd == IN)
  1781.                 if (!fileout())
  1782.                 {
  1783.                     message ("Too many errors - fileout\n");
  1784.                     return(0);
  1785.                 }
  1786.             return(2);
  1787.         }
  1788.     if (c == PROGESC)            /* something for us    */
  1789.         return(ourcmd(linebuf,i));    /* returns 0, 1, 2    */
  1790.     sendline(linebuf, i);            /* something for remote    */
  1791.     return (2);                /* main should read line*/
  1792. }
  1793. /*    loop doing rawfgets and processing packets until an end of file
  1794.     packet is found.  This is the main inwards file transfer routine */
  1795.  
  1796. #include "manifs.h"
  1797.  
  1798. int procpack()
  1799. {
  1800.     extern char linebuff[], *rawfgets(), packet[];
  1801.     extern int progstate;
  1802.     extern FILE *in_line;
  1803.  
  1804.     int pkt_cnt = 0;
  1805.     int err_cnt = 0;
  1806.     char c;
  1807.  
  1808.     while (err_cnt < ERR_LIMIT)
  1809.     {
  1810.         rawfgets(packet, PACKSIZE, in_line);
  1811.         if (packet[0] != X_SOH)
  1812.         {
  1813.             nack();
  1814.             ++err_cnt;
  1815.             continue;
  1816.         }
  1817.         switch ((c = packet[1] & CM))
  1818.         {
  1819.         case 'E':
  1820.             eofpacket(packet, strlen(packet));
  1821.             return(ack());
  1822.         default:
  1823.             if ( c >= '0' && c <= '9')
  1824.                 if (xferpacket (packet, strlen(packet)))
  1825.                 {
  1826.                     err_cnt = 0;
  1827.                     ack();
  1828.                     if ( (progstate == MASTER) &&
  1829.                         ( (++pkt_cnt % WARM_FEEL) == 0) )
  1830.                             message(".");
  1831.                     continue;
  1832.                 }
  1833.                 else
  1834.                 {
  1835.                     ++err_cnt;
  1836.                     nack();        /* bad packet */
  1837.                     continue;
  1838.                 }
  1839.             else
  1840.             {
  1841.                 ++err_cnt;
  1842.                 nack();            /* data packet expected */
  1843.                 continue;
  1844.             }
  1845.  
  1846.         }
  1847.     }
  1848.     return(err_cnt < ERR_LIMIT);
  1849. }
  1850.     /* NON PORTABLE - UCB UNIX 4.x    */
  1851.  
  1852. /* do an fgets on a line that is set to raw or cbreak mode using the newline
  1853.    table entry nltab[newline] as the end of input line character    */
  1854.  
  1855. #include "manifs.h"
  1856.  
  1857. char *rawfgets(string, limit, unit)
  1858. char string[];
  1859. int  limit;
  1860. FILE *unit;
  1861. {
  1862.     extern char nltab[];
  1863.     extern int newline, progstate;
  1864.     extern unsigned zdebug;
  1865.  
  1866.     int i = 0;
  1867.     char c = NUL;
  1868.  
  1869.     while (c != nltab[newline] && i < limit)
  1870.     {
  1871.         c = (fgetc(unit)) & CM;    /* hangs on the read */
  1872.  
  1873.         if (zdebug && (progstate == MASTER))
  1874.         {
  1875.             char dc[3];
  1876.  
  1877.             dc[0] = ' ';
  1878.             dc[1] = c;
  1879.             dc[2] = NUL;
  1880.             if (c <= US || c == DEL)
  1881.             {
  1882.                 dc[0] = '^';
  1883.                 dc[1] = (c == DEL ? '?' : (c | '@'));
  1884.             }
  1885.             message ("Rawfgets: Debug: input char = %s\n", dc);
  1886.         }
  1887.             /* control character filter */
  1888.  
  1889.         if (NUL <= c && c <= US)
  1890.             if ((c = nltab[newline]) || (c = '\n'))
  1891.                 ;        /* do nothing */
  1892.             else
  1893.                 continue;    /* scrag all except newline */
  1894.         if (c == DEL)
  1895.             continue;
  1896.         string[i++] = c;
  1897.     }
  1898.     string[i] = NUL;
  1899.     if (zdebug && progstate == MASTER)
  1900.         message ("Rawfgets: Debug: return string -->%s<--\n", string);
  1901.     return(string);
  1902. }
  1903. /* read characters from the comm_line and put them on stdout
  1904.    also accumulating each "line" in the string buffer until a
  1905.    prompt sequence is seen.  In cases where the entry in prtab[prompt]
  1906.    is a del, the end of the input is determined by absence of further input
  1907.    and is controlled by a non-portable routine (ccount)            */
  1908.  
  1909. #include "manifs.h"
  1910.  
  1911. int readline(string, limit)
  1912. char string[];
  1913. int limit;
  1914. {
  1915.     extern int data_present, linestate, prompt, newline;
  1916.     extern FILE *in_line;
  1917.     extern char prtab[], nltab[];
  1918.     extern long ccount();
  1919.  
  1920.     register int i, j;
  1921.     int reset_line;
  1922.     register char c;
  1923.     long nchars;
  1924.  
  1925.  
  1926.     if (linestate == CONNECTED)
  1927.     {
  1928.         data_present = i = reset_line = 0;
  1929.         for (;;)
  1930.         {
  1931.             nchars = ccount(in_line);
  1932.             if (!nchars)
  1933.                 break;
  1934.             data_present = 1;
  1935.             for (j = 0; j < nchars; ++j)
  1936.             {
  1937.                 if (reset_line)
  1938.                 {
  1939.                     reset_line = 0;
  1940.                     i = 0;
  1941.                 }
  1942.                 c = (fgetc(in_line)) & CM;
  1943.  
  1944.                     /* control character filter */
  1945.  
  1946.                 if ((c == DEL) || (NUL <= c && c <= US))
  1947.                 {
  1948.                     if ( c == nltab[newline] || c == '\n')
  1949.                         reset_line = 1;
  1950.                     else if (prtab[prompt] != DEL)
  1951.                     {
  1952.                         if (c == prtab[prompt])
  1953.                             reset_line = 1;
  1954.                     }
  1955.                     else
  1956.                         continue;
  1957.                 }
  1958.  
  1959.                 if (c == nltab[newline])
  1960.                     c = NL;
  1961.                 string[i++] = c;
  1962.                 putchar(c);
  1963.                 if (i >= limit)
  1964.                     break;
  1965.             }
  1966.             fflush(stdout);
  1967.             if (i >= limit)
  1968.                 break;
  1969.         }
  1970.         fflush(stdout);
  1971.     }
  1972.     else
  1973.     {
  1974.         message("Readline - line not connected\n");
  1975.         return(0);
  1976.     }
  1977.     string[i] = NUL;
  1978.     return(i);
  1979. }
  1980. /*    routine controls file transfers inwards        */
  1981.  
  1982. #include "manifs.h"
  1983.  
  1984. int receive(remotename, localname)
  1985. char remotename[], localname[];
  1986. {
  1987.     extern int linestate, compress, filecmd;
  1988.     extern FILE *xfer_file;
  1989.  
  1990.     if (linestate == DISCONNECTED)
  1991.     {
  1992.         message ("Get: Can't run. Line disconnected\n");
  1993.         return(1);
  1994.     }
  1995.  
  1996.     xfer_file = fopen(localname, "w");
  1997.     if (xfer_file == NULL)
  1998.     {
  1999.         message ("Get: Can't open %s for write\n", localname);
  2000.         return(1);
  2001.     }
  2002.     filecmd = OUT;
  2003.  
  2004.     compress = setcomp();
  2005.  
  2006.     return(inwards(remotename, localname));
  2007. }
  2008. /*    routine controls outward file transfers    */
  2009.  
  2010. #include "manifs.h"
  2011.  
  2012. int send (file_local, file_remote)
  2013. char file_local[],  file_remote[];
  2014. {
  2015.     extern int linestate, compress, filecmd;
  2016.     extern FILE *xfer_file;
  2017.  
  2018.     if (linestate == DISCONNECTED)
  2019.     {
  2020.         message("Send: Can't run.  Line disconnected`n");
  2021.         return(1);
  2022.     }
  2023.  
  2024.     xfer_file = fopen(file_local, "r");
  2025.     if (xfer_file == NULL)
  2026.     {
  2027.         message ("Send: Can't open %s for read\n", file_local);
  2028.         return(1);
  2029.     }
  2030.  
  2031.     filecmd = IN;
  2032.  
  2033.     compress = setcomp();
  2034.  
  2035.     return(outwards(file_local, file_remote));
  2036. }
  2037. /*    send a line out on the comm line        */
  2038.  
  2039. #include "manifs.h"
  2040.  
  2041. int sendline(buffer, nchars)
  2042. char buffer[];
  2043. int  nchars;
  2044. {
  2045.     extern int linestate, newline;
  2046.     extern FILE *out_line;
  2047.     extern char nltab[];
  2048.     char c;
  2049.     register int i;
  2050.  
  2051.     if (linestate == CONNECTED)
  2052.     {
  2053.         for ( i = 0; i < nchars; ++i )
  2054.         {
  2055.             if (buffer[i] == NL)
  2056.                 c = nltab[newline];
  2057.             else
  2058.                 c = buffer[i];
  2059.             fputc(c, out_line);
  2060.         }
  2061.         fflush(out_line);
  2062.     }
  2063.     else
  2064.         message ("Communications line not opened\n");
  2065.     return(1);
  2066. }
  2067. /*    send the packet found in the incoming buffer    */
  2068.  
  2069. #include "manifs.h"
  2070.  
  2071. int sendpacket(p)
  2072. char p[];
  2073.  
  2074. {
  2075.  
  2076.     extern FILE *in_line, *out_line;
  2077.     extern int newline, progstate;
  2078.     extern char nltab[], linebuf[], *rawfgets();
  2079.     extern unsigned zdebug;
  2080.  
  2081.     int i;
  2082.     char c;
  2083.  
  2084.     if (zdebug && (progstate == MASTER))
  2085.         showpacket("sendpacket", p);
  2086.     i = 0;
  2087.     do
  2088.     {
  2089.         c = p[i++];
  2090.         fputc(c, out_line);
  2091.     }
  2092.     while (c != X_ETB && c != X_ETX);
  2093.     fputc(nltab[newline], out_line);
  2094.     fflush(out_line);
  2095.     rawfgets(linebuf, BUFFSIZE, in_line);
  2096.     return (linebuf[0] == 'y' ? 1 : 0);
  2097. }
  2098. /*    offer to enable compression if other program is willing        */
  2099.  
  2100. #include "manifs.h"
  2101.  
  2102. int setcomp()
  2103. {
  2104.     extern char handshake[], linebuf[];
  2105.     extern FILE *in_line;
  2106.     extern char *rawfgets();
  2107.  
  2108.     sendline(handshake, strlen(handshake));
  2109.     rawfgets(linebuf, BUFFSIZE, in_line);
  2110.     return (linebuf[0] == 'y' ? 1 : 0);
  2111.  
  2112. }
  2113. /*    set maximum transmission line length            */
  2114.  
  2115. #include "manifs.h"
  2116.  
  2117. int setmaxl(string)
  2118. char *string;
  2119. {
  2120.     extern maxline;
  2121.  
  2122.     int state;
  2123.  
  2124.     state = sscanf(string, "%d", &maxline);
  2125.     if (state != 1)
  2126.         message ("Unable to set maxline. Current value = %d\n",
  2127.             maxline);
  2128.     else
  2129.         message ("Maximum line length set to %d\n", maxline);
  2130.     return(1);
  2131. }
  2132. /*        set remote system paramters                */
  2133.  
  2134. #include "manifs.h"
  2135.  
  2136. int setremote(string)
  2137. char string[];
  2138. {
  2139.  
  2140.     extern char *prtable[];
  2141.     extern int newline, prompt, remote;
  2142.  
  2143.     int i;
  2144.  
  2145.     i = identify(prtable, string);
  2146.     if (prtable[i][0] == NUL) {
  2147.         message("Cannot set remote state to %s - not supported\n",
  2148.             string);
  2149.         return(1);
  2150.     }
  2151.  
  2152.     newline = prompt = remote = i;
  2153.     return(1);
  2154. }
  2155.     /* NON PORTABLE - UCB UNIX 4.X    */
  2156.  
  2157. /*    setup - This routine performs whatever setup is necessary    */
  2158.  
  2159. #include "manifs.h"
  2160.  
  2161. int setup (argc, argv)
  2162. int argc;
  2163. char *argv[];
  2164. {
  2165.  
  2166.     extern int  on_line, speed;
  2167.     extern char line_name[], line_save[];
  2168.     extern char syntax[], *upperc(), callname[];
  2169.  
  2170.     int i, p;
  2171.  
  2172.     p = 0;
  2173.  
  2174.     if (strlen(argv[0]) < 19)
  2175.         strcpy (callname, argv[0]);    /* copy call name for msgs */
  2176.     else
  2177.         strncpy (callname, argv[0], 19);
  2178.     upperc(callname);
  2179.  
  2180.     on_line = isatty(fileno(stdin));    /* control errors    */
  2181.  
  2182.     speed = SPEEDEFAULT;            /* set defaults        */
  2183.     strcat(line_name, LINEDEFAULT);
  2184.     for (i = 1; i < argc; ++i)
  2185.         switch (argv[i][0]) {
  2186.             case 'l':
  2187.             case 'L':
  2188.                 p += linearg(argv[i]);
  2189.                 continue;
  2190.             case 's':
  2191.             case 'S':
  2192.                 if (argv[i][1] == 'l' || argv[i][1] == 'L')
  2193.                 {
  2194.                     ourcmd ("!slave", 6);
  2195.                     ourcmd ("!open", 5);
  2196.                     continue;
  2197.                 }
  2198.                 p += speedarg(argv[i]);
  2199.                 continue;
  2200.             default:
  2201.                 fprintf(stderr, "%s not understood\n%s",
  2202.                     argv[i], syntax);
  2203.                 return(0);
  2204.         }
  2205.     if (p != 0)
  2206.         return(0);
  2207.  
  2208.     return (1);
  2209. }
  2210. /*    debugging tool - can be dropped later        */
  2211.  
  2212. #include "manifs.h"
  2213.  
  2214. void showpacket(who, packet)
  2215. char *who, packet[];
  2216. {
  2217.     char work[MAXSTRING], c;
  2218.     unsigned i;
  2219.  
  2220.     i = 0;
  2221.     do
  2222.     {
  2223.         c = work[i] = packet[i];
  2224.         ++i;
  2225.     } while (( c != X_ETX) && (c != X_ETB));
  2226.     work[i] = NUL;
  2227.     message ("Debug: from %s: packet contents\n%s\n", who, work);
  2228. }
  2229. /*    routine to display the current state of the world        */
  2230.  
  2231. #include "manifs.h"
  2232.  
  2233. int showsetup()
  2234. {
  2235.  
  2236.     extern int progstate, linestate, speed, compress, maxline;
  2237.     extern char line_name[];
  2238.     extern char *optab[], *prtable[];
  2239.     extern char nltab[], prtab[], callname[], line_name[];
  2240.     extern int remote, newline, prompt;
  2241.  
  2242.     message ("%s: Program Status\n", callname);
  2243.     message ("State is %s\n", optab[progstate]);
  2244.     message ("Communications line %s is %s\n", line_name,
  2245.         (linestate == CONNECTED ? "open" : "closed"));
  2246.     message ("Remote device is %s\n", prtable[remote]);
  2247.     showspeed(speed);
  2248.     message ("Remote newline is 0%o\n", nltab[newline]);
  2249.     message ("Remote prompt is 0%o\n", prtab[prompt]);
  2250.     message ("Maximum characters to transmit per packet is %d\n", maxline);
  2251.     message ("Compression is %s\n", compress ? "ON" : "OFF");
  2252.     return(1);
  2253. }
  2254.     /*    NON PORTABLE - UCB UNIX 4.X */
  2255.  
  2256. /*        print the interpreted value in speed        */
  2257.  
  2258. #include "manifs.h"
  2259.  
  2260. int showspeed(speed)
  2261. {
  2262.  
  2263.  
  2264.     message("External line speed is ");
  2265.  
  2266.     switch(speed) {
  2267.  
  2268.         case B0:
  2269.             message("Null\n");
  2270.             return;
  2271.         case B50:
  2272.             message("50");
  2273.             break;
  2274.         case B75:
  2275.             message ("75");
  2276.             break;
  2277.         case B110:
  2278.             message ("110");
  2279.             break;
  2280.         case B134:
  2281.             message("134.5");
  2282.             break;
  2283.         case B150:
  2284.             message ("150");
  2285.             break;
  2286.         case B200:
  2287.             message("200");
  2288.             break;
  2289.         case B300:
  2290.             message ("300");
  2291.             break;
  2292.         case B600:
  2293.             message ("600");
  2294.             break;
  2295.         case B1200:
  2296.             message ("1200");
  2297.             break;
  2298.         case B1800:
  2299.             message ("1800");
  2300.             break;
  2301.         case B2400:
  2302.             message("2400");
  2303.             break;
  2304.         case B4800:
  2305.             message("4800");
  2306.             break;
  2307.         case B9600:
  2308.             message("9600");
  2309.             break;
  2310.         case EXTA:
  2311.         case EXTB:
  2312.             message("External\n");
  2313.             return;
  2314.         default:
  2315.             message("Erroneous\n");
  2316.             return;
  2317.     }
  2318.     message (" bits per second\n");
  2319.     return;
  2320. }
  2321.     /*    NON PORTABLE - UCB UNIX 4.X    */
  2322.  
  2323. /*            Parse s=value                    */
  2324.  
  2325. #include "manifs.h"
  2326.  
  2327. int speedarg(string)
  2328. char *string;
  2329. {
  2330.     extern int speed;
  2331.  
  2332.     int i;
  2333.  
  2334.     int val;
  2335.  
  2336.     i = sscanf (string, "s=%4d", &val);
  2337.     if (i != 1) {
  2338.         message ("%s not understood\n", string);
  2339.         return(1);
  2340.     }
  2341.  
  2342.     switch (val) {
  2343.         case 110:
  2344.             speed = B110;
  2345.             return(0);
  2346.         case 300:
  2347.             speed = B300;
  2348.             return(0);
  2349.         case 1200:
  2350.             speed = B1200;
  2351.             return(0);
  2352.         case 1800:
  2353.             speed = B1800;
  2354.             return(0);
  2355.         case 2400:
  2356.             speed = B2400;
  2357.             return(0);
  2358.         case 4800:
  2359.             speed = B4800;
  2360.             return(0);
  2361.         case 9600:
  2362.             speed = B9600;
  2363.             return(0);
  2364.         default:
  2365.             message ("Speed %d is not supported\n", val);
  2366.             return(1);
  2367.     }
  2368. }
  2369. /*    this routine breaks the input string up into tokens in the
  2370.     list of strings given.                        */
  2371.  
  2372. #include "manifs.h"
  2373.  
  2374. int tokenize(string, limit, list)
  2375. char string[];
  2376. int limit;
  2377. char list[][MAXSTRING];
  2378. {
  2379.     int i, j, k;
  2380.     char c;
  2381.  
  2382.     j = k = 0;
  2383.     for (i = 0; i < limit; ++i) {
  2384.         c = string[i];
  2385.         switch(c) {
  2386.             case ' ':
  2387.             case '\t':
  2388.                 if (k > 0) {
  2389.                     list[j][k++] = NUL;
  2390.                     ++j;
  2391.                     k = 0;
  2392.                 }
  2393.                 continue;
  2394.             case NUL:
  2395.             case '\r':
  2396.             case '\n':
  2397.                 if ( k > 0)
  2398.                     list[j][k++] = NUL;
  2399.                 return (++j);
  2400.             default:
  2401.                 list[j][k++] = c;
  2402.         }
  2403.     }
  2404.     list[j][k] = NUL;
  2405.     return(++j);
  2406. }
  2407. /*    uppercase an input string's alphabetic characters    */
  2408. char *upperc(string)
  2409. char string[];
  2410. {
  2411.     int i, j;
  2412.     char c;
  2413.  
  2414.     j = strlen(string);
  2415.     for (i = 0; i <= j; ++i) {
  2416.         c = string[i];
  2417.         if ( c >= 'a' && c <= 'z')
  2418.             string[i] ^= 040;
  2419.     }
  2420.     return(string);
  2421. }
  2422. /*    routine to perform wrapup functions at end of run        */
  2423.  
  2424. #include "manifs.h"
  2425.  
  2426. int wrapup()
  2427. {
  2428.     extern char callname[];
  2429.     extern int linestate;
  2430.     extern FILE *in_line, *out_line;
  2431.     extern struct sgttyb com_save;
  2432.     extern struct tchars com_1s;
  2433.     extern struct ltchars com_2s;
  2434.     extern char line_name[];
  2435.  
  2436.     if (linestate == CONNECTED)
  2437.     {
  2438.         ioctl(fileno(in_line), TIOCSETC, &com_1s);
  2439.         ioctl(fileno(in_line), TIOCSLTC, &com_2s);
  2440.         ioctl(fileno(in_line), TIOCSETP, &com_save);    /* restore */
  2441.         if (strcmp (line_name, LINETTY))    /* not the tty */
  2442.         {
  2443.             fclose(in_line);
  2444.             fclose(out_line);
  2445.         }
  2446.         else
  2447.             in_line = out_line = NULL;
  2448.         linestate = DISCONNECTED;
  2449.         message("%s: Communication line closed\n", callname);
  2450.     }
  2451.     return(1);
  2452. }
  2453. /*    process incoming data packet    */
  2454.  
  2455. #include "manifs.h"
  2456.  
  2457. int xferpacket(ptr, len)
  2458. char ptr[];
  2459. int len;
  2460. {
  2461.     extern FILE *xfer_file;
  2462.     extern int compress;
  2463.  
  2464.     int ret_char, dx, px;
  2465.     unsigned value, nchars, cksum, count;
  2466.     char data[MAXSTRING], *p;
  2467.  
  2468.     sscanf(ptr, "|%4d%3d{", &value, &count);
  2469.     dx = px = 0;
  2470.     p = &(ptr[D_BYTES]);
  2471.  
  2472.     while ((p[px] != X_ETX) && (p[px] != X_ETB))
  2473.     {
  2474.         if (compress && p[px] == X_GS)
  2475.         {                /* de-compression */
  2476.             nchars = p[px + 1] ^ 0x40;
  2477.             px += 2;
  2478.             ret_char = hex_to_a(&(p[px]));
  2479.             if (ret_char == HEXERROR)
  2480.                 return(0);
  2481.             while (nchars--)
  2482.                 data[dx++] = ret_char;
  2483.             px += 2;
  2484.         }
  2485.         else
  2486.         {
  2487.             ret_char = hex_to_a(&(p[px]));
  2488.             if (ret_char == HEXERROR)
  2489.                 return(0);
  2490.             data[dx++] = ret_char;
  2491.             px += 2;
  2492.         }
  2493.         if (dx >= count)
  2494.             break;
  2495.     }
  2496.  
  2497.     for (cksum = px = 0; px < dx; px++)
  2498.         cksum += data[px];
  2499.     cksum %= 10000;
  2500.     if (cksum != value)
  2501.         return(0);
  2502.  
  2503.     for (px = 0; px < dx; px++)
  2504.         putc(data[px], xfer_file);
  2505.  
  2506.     fflush(xfer_file);
  2507.     return(1);
  2508. }
  2509.  
  2510.