!********************************
!*  emas-2900  fep  itp server  *
!*   file: x25_xxx1s/xxx1y         *
!********************************
!! stack size = 500
!*
!*  nsi version - include !n! statements
!*  ring version - !n! -> !n! and !r! -> {r}
!*

#if i
control  x'4001'
include  "b_deimosspecs"
#else
control  1
include  "deimosperm"
#fi

begin 

      conststring  (13)vsn = "xxx...1d "
      #datestring
      recordformat  am1f(integer  rxs, rxd, txs, txd)

      ownrecord  (am1f) name  l == 1;         ! addr passed by eam1

      !!   no of data bytes in a short block  

      constinteger  small block max = 51;          ! 64-4-6-4
       constinteger  big block max = 127;   ! < 256 !

      constintegername  no of big == k'100112'; ! no of free buffs
      constintegername  no of small == k'100114'
      owninteger  critical = 15;        ! switch off o/p level



      recordformat  itpf((byte  res, bytearray  a(1:128) or  string  (128) s))


!n!   %recordformat lev3f(%bytearray reserved(0:5), %c
!n!     %record (itpf) itp)
                                 ! nb: replaces fn,sufl,st,ss,flag,uflag


      recordformat  lev3f(bytearray  reserved(0:6), record  (itpf) itp)

      recordformat  mef(record  (mef) name  link, c 
        byteinteger  len, type, (record  (lev3f)lev3 or  c 
         bytearray  params(0:231)))

      recordformat  m2900f(record  (mef) name  l, byteinteger  len, type, c 
        integer  stream, sub ident, c 
         p2a, p2b, p3a, p3b, p4a, p4b, p5a, p5b, p6a, p6b)

      recordformat  m2900bf(record  (mef) name  l, byteinteger  len, type, c 
        integer  stream, sub ident, c 
         byteintegerarray  b(0:19))

      recordformat  m2900if(record  (mef) name  l, byteinteger  len, type, c 
        integer  stream, sub ident, p2a, p2b, string  (15) int)

      recordformat  m2900cf(record  (mef) name  l, byteinteger  len, type, c 
         integer  stream, sub ident, integerarray  pa(0:9))


      recordformat  maf(record  (mef) name  l, byteinteger  mlen, c 
        mtype, byteintegerarray  a(0:240))


      recordformat  pe(byteinteger  ser, reply, c 
       (integer  a, b, (integer  c or  byte  c1, c2) or  byte  fn, a2, c 
         (record (mef)name  mes, byte  gate port, task port or  c 
         string  (3) facility)))


      recordformat  qf(record  (mef) name  e)

      !********************************************************
      !*  formats of tables, ie stream descriptors, tcps etc  *
      !********************************************************
      recordformat  con desf(record  (mef) name  hold, c 
        integer  state, stream, byteinteger  o state, out go, c 
        in cnt, tcp, cnsl, seq bits, pmt n, mode, hold f, abortf, c 
        integer  trig, i pos, opos, o lim, o trig, p lim, c 
        in lim, out lim, o posx, (record  (mef) name  in mes or  c 
              record  (qf) inp q))

      recordformat  cons statef(record  (con desf) name  con des)

      recordformat  tcpf(integer  state, con state ind, c 
         held, h ind, h no, byteinteger  port, ostate, tcpn, node, term, c 
         size, max,  record  (qf) outq)
      !************************************************************
      !*  upper level (itp&rje) handler messages to gate
      !************************************************************
      include  "b_ygatecalls"

      !**************************************************************
      !*         buffer manager calls   (from and to)               *
      !**************************************************************
!      %constinteger buffer here = 0
      !********** to buffer manager ***********
      constinteger  request buffer = 0
      constinteger  release buffer = 1
      !**************************************************************
      !*             calls to 2900 link handler                     *
      !**************************************************************
      constinteger  send data = 0
      constinteger  low level control = 1
      constinteger  here i am = 2
      constinteger  return control = 3

      !**************************************************************
      !*               replies from 2900 link handler                 *
      !****************************************************************
      constinteger   interf addr = 0
      constinteger  do input = 1
      constinteger  do output = 2
      constinteger  message = 3
      constinteger  mainframe up = 4
      constinteger  mainframe down = 5
      !****************************************************************

      !********** various service numbers *************
      constinteger  gate ser = 24
      constinteger  buffer manager = 17
      constinteger  link handler = 18

      constbyteintegername  change out zero == k'160310'
      constinteger  t3 ser = 21

      constinteger  comm bit = k'1'
      constinteger  accept char = k'002'
      constinteger  acfy = k'010';     ! peter calls it rxfy
      constinteger  xopl = k'020';     ! x operable - latched
!      %constinteger xop  = k'040';     ! x operable
      constinteger  ready = k'200'
      !************************************************************
      !*                   tcp  states                            *
      !************************************************************
!        %constinteger not allocated = 0
      constinteger  connected = 1
      constinteger  disconnecting tcp = 2
      !******  tcp_ostate states  (permission to send)  *****
      constinteger  idle = 0
      constinteger  busy = 1
      !***********************************************************
      !*               2900  states                               *
      !***********************************************************
      own  integer  host state = 0;      ! holds 2900 state
      constinteger  down = 0
      constinteger  up = 1
      !****************** comms control states ********************
!      %constinteger unused = 0
      constinteger  disconnecting = 1
      constinteger  connecting = 2
      constinteger  suspending = 4
      constinteger  aborting = 5
      constinteger  enabling = 7
!      %constinteger enabled = 8

      constinteger  fixed = 10;         ! 1st available stream
      !**************************************************************
      !*            console states                                  *
      !**************************************************************
      constinteger  not allocated = 0
      constinteger  name sent = 1;      ! hello has been received
      constinteger  pass sent = 2;      ! 'name' has been received
      constinteger  logging on = 3
      constinteger  logged on = 4;      ! 2970 has accepted it
      constinteger  input enabled = 5
      constinteger  awaiting int = 6
      constinteger  logging off = 7;    ! 2970 is getting rid of it
      constinteger  logging off 2 = 8;   ! waiting to send it

      !!  ostate  states

      !! %constinteger idle = 0
      constinteger  enabld = 1
      constinteger  out p = 2;          ! output req pending
      constinteger  pmt p = 4;          ! prompt request pending
      !**********************************************************
      !*   itp  header  bytes  definitions                      *
      !**********************************************************
      constinteger  text = 0;           ! in itp_hdb1
      constinteger  bin b = 1
      constinteger  control = 1
      constinteger  go ahead = 2;    ! in itp_hdb1
      constinteger  hello = 8
      constinteger  i disconnect = 4

      constinteger  terminated = 2;  ! in itp_hdb2
      constinteger  prompt = 4
!      %constinteger text marker = 8
      constinteger  seq no valid = 32
!      %constinteger seq no bits = x'c0'
      constinteger  seq inc = x'40'

      constinteger  intm = 1;            ! hdb2 - control message
      constinteger  set mode = 2
!     %constinteger kill transmit = 8
!     %constinteger kill receive = 4
      !******************************************
      !*  reasons for waiting for a buffer      *
      !******************************************
      constinteger  send name prompt = 1
      constinteger  send pass prompt = 2
      constinteger  put echo on =3, put echo off = 4, send nl = 5
      constinteger  store user name = 6
      constinteger  send disconnect = 7
!     %constinteger send login reply = 8;    ! logon successful
!     %constinteger send login fails 1 = 9;   ! 9-17

      constinteger  send emas down = 18
      constinteger  Send int = 19
      constinteger  send kill transmit = 20
      constinteger  send pad params = 21

      constinteger  last itp reason = 21

      constinteger  low level ip transfer = 22
      constinteger  low level op transfer = 23
      constinteger  get op block = 24
      constinteger  send trig reply = 25;     ! must be odd (output trigger)
      constinteger  send the chop = 26;       ! send an "int y" to 2900
      constinteger  get big op block = 27
      constinteger  kick message stream = 28
      !**************************************************************
      routinespec  to gate(integer  fn, record  (mef) name  mes, c 
        integer  flag)
      routinespec  to 2900(integer  fn, record  (m2900f) name  m2900)
      routinespec  get buffer(integer  reason)
      routinespec  free buffer(record  (mef) name  mes)
      routinespec  from gate
      routinespec  from 2900
      routinespec  from buffer manager(record  (pe) name  p)
      integerfnspec  analyse itp message(record  (mef) name  mes)
      routinespec  retrieve(record  (con desf) name  d)
      routinespec  lose consoles(integer  x)
      routinespec  read from am1
      routinespec  write to am1
      routinespec  kick 2900 message(record  (maf) name  log)
      routinespec  tidy message streams
      routinespec  read message from am1
      routinespec  write message to am1
      routinespec  mon mes(record  (mef) name  mes)
      routinespec  mon p(record  (pe) name  p)
      !******************************************************
      record  (pe) p

      ownrecord  (tcpf) name  tcp
      owninteger  tcpn

      ownrecord  (con desf) name  d
      ownrecord  (qf) free des; ! holds free descriptors
      ownrecord  (con desf) name  first d;  ! for dumping only

      ownrecord  (con desf) name  d2, d3
      ownrecord  (qf) name  buffer pool
      owninteger  no of buff = 0

      constinteger  max calls = 50
      constinteger  tcp limit = max calls;  ! increase con statea as well !!!!!!!
      ownrecord  (tcpf) array  tcpa(0:tcp limit)


         constinteger  con lim = max calls;      ! number of active terminals
      ownrecord  (con desf) array  con desa(-2:con lim)

      constinteger  max ports = 50
                                        ! cross index from port to tcp
      constinteger  max tts = 49;      ! ie 0 to 48


      owninteger  mon = 0;              ! monitoring flag
      owninteger  lose op = 0;         ! discard output for erte
      constintegername  users == k'100014'; ! no of users in buffer seg
      owninteger  messflag = 1

      integer  i, n
      ownstring  (63) str

      ownstring  (1) snil = ""

      constinteger  header len = 0
      !**********************************************
      !*      initialisation                        *
      !**********************************************

      change out zero = t3 ser

      first d == con desa(0)
      cycle  i = con lim, -1, 0
         push(free des, con desa(i))
      repeat 

      n = 0
      cycle  i = 1, 1, tcp limit
         tcp == tcpa(i)
         tcp_tcpn = i
      repeat 
      d2 == con desa(-2)
      d2_stream = -2
      d3 == con desa(-1)
      d3_stream = -1


      printstring(vsn)
      #if i
      printstring("new ")
      #fi
      printstring(datestring); newline

      #if i
      map hwr(3);                       ! map am1 to seg 3
      #else
      map hwr(0);                      ! map am1 to segment 0
      #fi
      i = map virt(buffer manager, 5, 4);   ! map buff man stack to seg 4
      i = map virt(buffer manager, 6, 5);   ! and second seg
      users = 0
      con desa(i)_stream = i for  i = 0, 1, con lim

#if ~s
      p_c = 2;                  ! param for 'here i am'
#else
      p_c = 8
#fi
      to 2900(here i am, null)
#if ~s
      p_c = 3;                        ! and claim stream 3
#else
      p_c = 9
#fi
      to 2900(here i am, null)

      tcp == tcpa(0);                 ! dummy for below
      p_ser = gate ser; p_reply = own id
      p_fn = enable facility; p_a2 = 0
      p_facility = "XXX"
      pon(p)
      !**********************************************
      !*           main loop                        *
      !**********************************************
      cycle 
         p_ser = 0;  poff(p)

         if  int # 0 start 
         if  'M' <= int <= 'P' start 
            mon = int-'O'
         finish 
         if  int='A' then  messflag=1;   !turn messages on
         if  int='B' then  messflag=0;   !turn off
         if  int = '?' start ;   ! $$ mon
            write(no of buff, 4); newline
            printstring("term  qu  mq held  no held
")
            cycle  i = 1, 1, tcp limit
               tcp == tcpa(i)
               if  tcp_state = connected start 
                   write(tcp_term, 3)
                  write(tcp_size, 3);  write(tcp_max, 3)
                  write(tcp_held, 3); write(tcp_h no, 5)
                  write(tcp_con state ind, 4)
                   newline
                   tcp_max = 0
               finish 
            repeat 
         finish 
         if  int = 'C' start 
            select output(1)
            close output
            printstring("Done
")
         finish 

         int = 0
         finish 

         if  p_reply = link handler start 
            from 2900
         finish  else  if  p_reply = gate ser start 
            from gate
         finish  else  if  p_reply = buffer manager then  from buffer manager(p)
      repeat 

      !*************************************************
      !*           routines to do the work             *
      !*************************************************

      routine  crunch
         integer  i
         cycle  i = 1, 1, 15
            printstring("xxx: Bad buffer ***** dump fep ********
")
         repeat 
         *=k'104001';                   ! emt wait
      end 

      routine  to gate(integer  fn, record  (mef) name  mes, c 
         integer  flag)
         if  fn = put output or  fn = control data start 
            if  tcp_state # connected start ; ! throw away
                free buffer(mes);  return 
            finish 

            if  addr(mes)&k'140000' = k'140000' then  crunch; ! had it
            tcp_size = tcp_size+1
            tcp_max = tcp_size if  tcp_size>tcp_max
            d_out go = d_out go-1
            if  d_out go = 255 then  d_out go = 0;  ! not negative

            if  mon < 0 start 
               select output(1)
               printstring("To Tcp ");  mon mes(mes)
            finish 
         finish 

         p_ser = gate ser; p_reply = own id
         p_fn = fn; p_gate port = tcp_port; p_mes == mes
         p_a2 = flag
         p_task port = tcp_tcpn
         if  mon # 0 start 
            select output(1);  spaces(5)
            printstring("xxx: to gate:");      mon p(p)
            select output(0)
         finish 
         pon(p)
      end 

      routine  to 2900(integer  fn, record  (m2900f) name  m2900)
         p_ser = link handler; p_reply = own id
         p_fn = fn; p_mes == m2900
         pon(p)
      end 

      routine  get buffer(integer  reason)
         record  (pe) p
         integer  type
      !*******************************************************
      !*    hold a pool, so can call buffer here immedialtely*
      !*         otherwise hold the activity until it arrives*
      !*******************************************************

         if  reason = get big op block then  type=0 else  type=1
         p_c2 = reason
         p_a2 = d_stream
         if  buffer pool == null or  type=0 start ;  ! have to ask for it
            p_ser = buffer manager; p_reply = own id
            p_fn = request buffer
            p_c1 = type;                     ! either size
            pon(p)
         else 
            p_mes == buffer pool;  buffer pool == p_mes_link
            p_mes_link == null
            no of buff = noof buff-1;  from buffer manager(p)
         finish 
      end 

      routine  free buffer(record  (mef) name  mes)
         record  (pe) p

         if  addr(mes)&k'140000' = k'140000' then  crunch

         if  mes_type=0 or  no of buff>10 or  no of small < 15 start 
            p_ser = buffer manager; p_reply = own id
            !! queue it if it is a short buffer
            p_fn = release buffer; p_mes == mes
            pon(p)
         else 
            !! short buffer, so queue it
            mes_link == buffer pool; buffer pool == mes
            no of buff = no of buff+1
         finish 
      end 


      string  (127) fn  unpack(record  (mef) name  mes, integer  no)
         integer  i, l
         unless  mes == null or  mes_len<=0 or  no<=0 start 
            l = 0
            while  no>1 cycle 
               l=l+mes_params(l)+1
               no = no-1
            repeat 
            result  = string(addr(mes_params(l)))
         finish  else  result  = ""
      end 

      routine  pack(record (mef) name  mes, string  (*) name  s)
         string(addr(mes_params(mes_len))) = s
         mes_len = mes_len+length(s)+1
      end 

      routine  get o block

         !! this routine determines whether it is worth asking for
         !! a big buffer to put itp output in, otherwise gets small

         !! nb: 1st transfer is always a small buffer (not done here)

         integer  x
         return  if  d_state = awaiting int
         x = d_o lim-d_o pos
         if  x<0 then  x=x+d_out lim
         if  x>small block max and  no of big>15 then  c 
           get buffer(get big op block) else  c 
           get buffer(get op block)
      end 

      routine  from gate
         record  (mef) name  mes
         record  (tcpf) name  targ
         integer  fn, flag, type, x, q, stream
         switch  fns(connect:Control Data)
         string  (63) calling
         string  (23) qual

         fn = p_fn
         tcpn = p_task port
         tcp == tcpa(tcpn)
         mes == p_mes
         if  mon # 0 start 
            select output(1); spaces(5)
            printstring("xxx: from gate:")
            mon p(p)
            select output(0)
         finish 

         ->fns(fn)

    fns(Connect):
         tcp == null
         cycle  tcpn = tcp limit, -1, 1
            targ == tcpa(tcpn)
               if  targ_state = not allocated then  tcp == targ
         repeat 
         if  tcp == null start 
                                        ! 2900 down or full up
            tcp == tcpa(0)
            tcp_port = p_gate port;          ! for 'to gate' call only
            to gate(Disconnect, null, 17)
            return 
         finish 

        tcp_state = connected;  tcp_ostate = idle
         tcp_port = p_gate port

         tcp_node = 0;       ! ??????
         calling = unpack(mes, 2)
         qual = unpack(mes, 3)

         if  messflag=1 start 
            printstring("       xxx: ")
            printstring(calling)
           printstring(" connected
")
         finish 

         tcp_max = 0; tcp_size = 0; tcp_held = 0;          ! for monitoring

         mes_len = 0
         pack(mes, snil)
         pack(mes, qual)
         pack(mes, snil)
         to gate(accept call, mes, 0)
   !      to gate(enable input, null, 1);  ! out till pre-ack gate ready

            d == pop(free des)
            if  d == null then  return ;       ! reject call later !!!!!!!!!!!!
            stream = d_stream;       ! hold the stream
            d = 0;                   ! zero the record
            d_stream = stream
            d_tcp = tcp_tcpn;  d_cnsl = 0
            tcp_con state ind = stream

            d_state = name sent;        ! if down, goes to logging off whe sent

            if  host state = down start 
               get buffer(send emas down)
               return 

            finish 
            get buffer(send pad params)

            get buffer(send name prompt)
            users = users+1
            d_hold == null
            get buffer(store user name)

         return 

fns(input here):


         if  mes_len <= 0 start 
            free buffer(mes)
            return 
         finish 

         to gate(enable input, null, 1)

         if  mon < 0 start 
            select output(1)
            printstring("From Tcp ");      mon mes(mes)
         finish 

         mes_lev3_reserved(0) = 0;          ! missing gah count
         flag = analyse itp message(mes)
         if  flag < 0 then  free buffer(mes)
                                            ! flag > 0  - going to 2900
                                            ! flag = 0  - used internally
                                            ! flag < 0  - may be freed
         return 

    fns(enable output):
         tcp_ostate = idle
         tcp_size = tcp_size-1 unless  tcp_size = 0
         return  if  tcp_con state ind = 0
         d == con desa(tcp_con state ind)
         d_out go = d_out go+1 unless  d_out go > 2
               if  d_out go = 1 and  d_ostate > enabld start 
                  get o block
               finish 
         return 

      ! ring vsn?
         return ;                          ! handled in 'input recd'

fns(Expedited):                         ! int: etc
      unless  tcp_con state ind = 0 start 
         d == con desa(tcp_con state ind)
         get buffer(Send int)
         d_state = awaiting int
      finish ;       ! buffer involved ??????????????????????????????????
      return 

    fns(Disconnect):                    ! Call has been cleared
         flag = p_a2;                   ! pickup reason for close

         if  messflag=1 start 
            printstring("       t");  write(tcp_term, 1)
            printstring(" connection ")
            if  flag = 0 then  printstring("aborted") else  c 
              printstring("closed")
            write(flag, 1)
            write(tcp_max, 1); newline
         finish 
         lose consoles(-1)
         to gate(disconnect, null, 1)
         tcp_state = not allocated
         free buffer(mes) unless  mes == null
         tcp_max = 0
         return 

    fns(Reset):
      printstring("Reset rec'd
")
      mon mes(mes)
      return 

    fns(Control Data):
            printstring("Control data in:")
            mon mes(mes)

           free buffer(mes)
           to gate(enable input, null, 1)
      end 


      integerfn  analyse itp message(record  (mef) name  mes)

         record  (itpf) name  itp, itp2
         integer  cnsl, index, stream, len, q, x, res
         record  (maf) name  m
         record  (m2900if) name  mi
         string  (15) int mes

         switch  console state(idle:logging off 2)

         itp == mes_lev3_itp

         itp_res = mes_len;             ! nb: overwrites last byte of header


         unless  tcp_con state ind = 0 start 

            d == con desa(tcp_con state ind)

            ->console state(d_state)

         finish 


console state(not allocated):           ! eg no descriptor
           printstring("oops
")
           result  = -1

console state(name sent):               ! user name arrived ?
if  addr(d_hold)&k'140000'=k'140000' then  printstring("name?")and  crunch

            d_state = pass sent
            get buffer(put echo off);   ! switch echo off
            get buffer(send pass prompt);    ! send pass:
            if  length(itp_s) > 2 then  length(itp_s) = length(itp_s)-1
            if  charno(itp_s,length(itp_s))=13 then  length(itp_s) = c 
            length(itp_s)-1
            if  length(itp_s) > 20 then  length(itp_s) = 20
            m == d_hold;                ! pickup buffer with 'address'
            string(addr(m_a(m_mlen))) = itp_s
            m_mlen = m_mlen+length(itp_s)+1
         result  = -1;                  ! de-alloctae block

console state(pass sent):               ! password arrived ??
if  addr(d_hold)&k'140000'=k'140000' then  printstring("pass?")and  crunch

            get buffer(send nl);        ! send out a newline
            get buffer(put echo on);      ! put echo back on
            m == d_hold
            !! check that it has switched buffers??
            if  length(itp_s) > 2 then  length(itp_s) = length(itp_s)-1
            if  charno(itp_s,length(itp_s))=13 then  length(itp_s)= c 
             length(itp_s)-1

            index = d_stream<<1+fixed
            x = m_mlen
            if  x+length(itp_s) > small block max then  c 
              length(itp_s) = small block max-x
            string(addr(m_a(x))) = itp_s; ! put in password
            x = x+length(itp_s)
            m_a(0) = x

            d_state = logging on
            d_hold == null

            kick 2900 message(m);       ! nb: disturbs 'd'
            p_c = index;             ! param for 'here i am'
            to 2900(here i am, null)
            p_c = index+1;           ! param for 'here i am'
            to 2900(here i am, null)

         result  = -1

console state(awaiting int):
            d_state = input enabled
            int mes = itp_s;                 ! copy it out of the way

            len = length(int mes);       ! check for cr, nl  & nl
            len = len-1;                ! delete the cr
            len = 15 if  len > 15
            if  len <= 0 then  res = -1 else  start ;  ! invalid
               length(int mes) = len
   
               mi == mes;                        ! re-use 'mes'
               mi_stream = (d_stream<<1)+fixed;  mi_sub ident = 0
               mi_p2a = -1;  mi_p2b = -1;  ! set up params
               mi_int = int mes;                 ! copy string accross
               to 2900(send data, mi);        ! send to am1h
               res = 2;                     ! don't deallocate buffer
            finish 
if  mon < 0 start 
select output(1)
printstring("On Int:ostate & out go:"); write(d_o state, 1); write(d_out go, 1)
newline
select output(0)
finish 
            if  d_o state > enabld and  d_out go >0 then  get o block
            result  = res

console state(logging on):              ! go ahead only?
console state(logged on):               ! still no input
      result  = -1

console state(input enabled):           ! input messages and ints


            if  not  d_in mes == null start 
               d_seq bits = d_seq bits+seq inc
               itp2 == d_in mes_lev3_itp
               d_in mes_lev3_reserved(0) = d_in mes_lev3_reserved(0)+1; ! missing gah count
               unless  length(itp_s)+length(itp2_s)>240 then  c 
                  itp2_s = itp2_s.itp_s
               result  = -1;           ! chuck the buffer
            finish 
            get buffer(low level ip transfer);                         ! signal to 2900 input here
            d_in mes == mes
            mes_lev3_reserved(1) = 0;          ! pos in block flag = 0
            result  = 2



console state(logging off):             ! message is out, just disconnect
         d_state = logging off 2
         get buffer(send disconnect)
         result  = -1


get rid of it:
console state(logging off 2):            ! ignore
         result  = -1
      end 



      routine  free transient
         if  not  d_in mes == null then  free buffer(d_in mes) and  c 
           d_in mes == null
         if  not  d_hold == null start 
            free buffer(d_hold); d_hold == null
        finish 
      end 

      !! r o u t i n e    from 2900 

      !!  all messages from the 2900 come to this routine

      routine  from 2900
         record  (m2900f) name  m2900
         record  (m2900bf) name  m2900b
         record  (m2900cf) name  m2900c
         record  (mef) name  mes

         integer  stream, sub ident, state, trig, l reply, mode, i
         integer  type, p2b, pf
         switch  link fns(interf addr:mainframe down)

         m2900 == p_mes;  m2900b == m2900
         if  p_fn = message  start 
            stream = m2900_stream;               ! get first stream no
         else 
            if  p_fn > message then  ->link fns(p_fn)
            stream = p_c
         finish 
         d == con desa((stream-fixed)>>1)
          tcp == tcpa(d_tcp)
         -> link fns(p_fn)


link fns(interf addr):               ! interface addr from eam5
         #if i
         l == record(addr(p_mes)&k'17777'!k'060000'); ! put in seg 3
         #else
         l == record(addr(p_mes)&k'17777');  ! force to seg 0
         #fi
         return 


link fns(do output):         ! -> 11/34
#if ~s
         if  stream = 3 then  read message from am1 else  c 
#else
         if  stream = 9 then  read message from am1 else  c 
#fi
           read from am1
!         ->d mon
         return 

link fns(do input):      ! -> 2900
#if ~s
         if  stream = 2 then  write message to am1 else  c 
#else
         if  stream = 8 then  write message to am1 else  c 
#fi
           write to am1
!d mon:   %if mon #0 %start
!            select output(1);!  printsymbol('t')
!            write(p_fn, 1);!  write(stream, 1);! newline;!  select output(0)
!         %finish
         return 

link fns(mainframe up):
         printstring("emas-2900 up
")
         -> tidy

link fns(mainframe down):
         printstring("Emas Down
")
tidy:    tidy message streams
         cycle  i = 0, 1, con lim
            d == con desa(i)
            if  d_state # not allocated and  d_cnsl=255 then  c 
              retrieve(d) else  start 
               if  not allocated < d_state < logging off start 
                  free transient
                  get buffer(send emas down)
                  d_state = logging off
               finish 
            finish 
            if  i&3 = 3 then  set prio(1);  ! force re-schedule
         repeat 
         host state = down
         users = -1
         return 


link fns(message):
#if ~s
         if  stream = 2 then  d == d2
         if  stream = 3 then  d == d3
#else
         if  stream = 8 then  d == d2
         if  stream = 9 then  d == d3
#fi
         type = 0
         sub ident = m2900_sub ident
         state = m2900b_b(1);  mode = m2900b_b(0)
            if  mon < 0 start 
               select output(1)
               printstring("mess:")
               write(stream, 1); write(sub ident, 1); write(state, 1)
               write(m2900_p2b, 1); write(m2900_p3b, 1)
               newline
               select output(0)
            finish 


         if  sub ident # 0 start ;      ! low level
            if  stream < 10 start 
               if  state = connecting start 
                  !! initial logon stream connected
                  host state = up
                  printstring("logon stream connected
")
                  users = 0
               else 
                  if  state = enabling start 
                     d_o state = enabld
                     d_state = logged on;     ! not quite right, but?
                     d_out lim = m2900_p2b; d_o pos = 0; d_o lim = 0; d_o posx=0
                     printstring("logon stream enabled
")
                  finish 

                  if  state = disconnecting start 
                     host state = down
                     printstring("logon stream disconnected
")
                  tidy message streams
                  finish 
               finish 
            else 

               if  d_state = not allocated start 
                  if  stream&1=0 start ; ! monitor input str only
                     printstring("xxx: not allocated problem")
                     write(state, 1); newline
                  finish 
                  -> send reply
               finish 

               if  state = enabling start ;   ! 1st intersting condition
                  if  stream&1 = 0 start 
                     d_state = input enabled
                     if  d_cnsl = 255 start ;   ! gone away
                         type = 1
                     else 
                        d_in lim = m2900_p2b
                        d_i pos = m2900_p3b
                     finish 
                  else 

                     d_out lim = m2900_p2b;  d_o state = enabld
                     d_o pos = m2900_p3b;  d_o lim = 0;  d_p lim = 0
                     d_mode = mode>>4; ! 0-iso,x'20'-bin,x'30'-cont
                  finish 
               finish  else  if  state = disconnecting start 
                  if  stream&1 = 0 then  d_in lim = 0 else  start 
                     d_out lim = 0
                     d_o state = idle
                  finish 
                  if  d_in lim = 0 and  d_out lim = 0 start 
                                        ! both disconnected
                     d_state = logging off
                     get buffer(send disconnect)
                  finish 

               finish  else  if  state = aborting or  state = suspending start 
                  if  stream&1 # 0 start ;     ! output side
                      d_o state = idle;       ! stop transfers
                     d_abortf = state;                 ! remember type
                     if  not  d_hold == null then  c 
                       free buffer(d_hold) and  d_hold == null
                  finish 
               finish 
            finish 
            m2900_p2a = 0;  m2900_p2b = 0
send reply:
            to 2900(low level control, m2900)
            if  type # 0 then  get buffer(send the chop)
            return 
         finish 

         !*********************************
         !* high level message
         !********************************
         if  stream&1 = 0 and  stream > 2 start ;        ! input high level
            trig = m2900_p3b
            if  d_i pos = trig start 
               d_p lim = m2900_p2b
               i = d_o state
               d_o state = i!pmt p
                                         ! hold for use later
               if  i = enabld start 
                  d_hold == m2900;          ! retain buffer
                  get buffer(low level op transfer)
                  return 
               finish 
            finish 
            free buffer(m2900);      ! past that position already
         else 
            !************************
            !*  output  stream      *
            !************************
#if ~s
            if  stream = 3 start 
#else
            if  stream = 9 start 
#fi


               !! update of pointer on message stream
               p2b = m2900_p2b
               free buffer(m2900)
               get buffer(get op block) if  d_o lim = d_o pos
               d_o lim = p2b
            else 

               !! request output message
               ! %integer output pos, trig pos

               d_o lim = m2900_p2b
               d_o trig = m2900_p3b
               m2900_p3a = k'050505';    ! diagnostic purposes

               !! check whether immediate trig reply is needed

               if  d_o trig >= 0 start ;    ! maybe
                  get buffer(send trig reply) if  d_opos = d_olim or  c 
                    (d_opos<d_olim and  not  d_opos<d_otrig<=d_olim) c 
                     or  c 
                    (d_opos>d_olim and  d_olim<=d_otrig<=d_opos)
                  finish 

                d_o state = d_o state&(¬pmt p);    ! discard prompt
                if  d_o state&out p = 0 and  d_opos # d_olim start 
                   d_ostate = d_ostate!outp
                   if  mon < 0 start 
                      select output(1)
                      printstring("o/p: go, size:")
                      write(d_out go, 1); write(tcp_size, 1); newline
                      select output(0)
                   finish 
                  if  d_out go > 0 start ;  ! allowed to send
                     if  not  d_hold == null start 
                        free buffer(m2900)
                     else 
                        d_hold == m2900
                     finish 

                     if  tcp_size>=4 or  no of small < critical start 
                        d_hold f = 1; tcp_held = tcp_held+1
                        free buffer(d_hold); d_hold == null
                     else 
                        get buffer(low level op transfer)
                     finish 
                     return 
                  finish 
               finish 
               free buffer(m2900)
            finish 
         finish 
      end 

      routine  fill(record  (mef) name  mes, integer  no)
         integer  n, pt, max

         constbyteintegerarray  pts(1:last itp reason) =
           1, 10, 19, 26, 33, 39, 40, 45, 45, 45(8),
         45, 64, 74, 80
           !! pt to itp mess

         ownbyteintegerarray  itp message(1:98) =
         8, 2, k'146', 5, 'U', 's', 'e', 'r', ':',;  ! name prompt
         8, 0, k'246', 5, 'P', 'a', 's', 's', ':',;  ! pass prompt
         5, 1, 2, 3, 2, 2, 1,;                           ! echo on
         5, 3, 2, 3, 2, 2, 0,;                           ! echo off
         5, 0, 2, 2, 13, nl,;                        ! nl
         0,;                                         ! not used
         3, 5, 0, 1, 1,;                                ! i disconnect
         18, 0, 2, 15, 13, nl, '*', '*', '2', '9', '0', '0', ' ',
            'D', 'o', 'w', 'n', 13, nl,;             ! emas down
          0, 0, 0, 6, 13, nl, 'I', 'n', 't', ':',;      ! send Int:
          0, 0, 0, 2, 13, nl,;                       ! nl

          0(3), 15, 2, 2, 1, 3,2, 7, 1, 9, 0, 10, 80,

                       12, 0, 13, 4;                  ! sensible pad parameters


         pt = pts(no)

         mes_lev3_itp_s = string(addr(itp message(pt+3)))
         mes_len = length(mes_lev3_itp_s)
      end 


      !! r o u t i n e  move user name  (from big to small buffer)

      routine  move user name(record  (maf) name  logr)
         record  (mef) name  mes
         string  (3) add

         !  N B
         !      Total length of addr, name and password must not exceed
         !      small block max
         !      Password is truncated if this is so

         if  d_state # name sent start 
           printstring("xxx:mun fails")
           write(d_state, 1); newline
           free buffer(logr);  return 
        finish 
!         mes == d_hold
         logr_a(1) = 1
         logr_a(2) = 0
         logr_a(3) = d_stream<<1+fixed
!         string(addr(logr_a(4))) = mes_bsp_itp_s
!         logr_mlen = length(mes_bsp_itp_s)+5+1

         ! until tcp passes address
         length(add) = 3
         charno(add, 1) = tcpa(d_tcp)_node
         charno(add, 2) = tcpa(d_tcp)_term
         string(addr(logr_a(4))) = add
         logr_mlen = logr_a(4) +4+1
!         free buffer(mes)
         d_hold == logr
      end 


      !! r o u t i n e   from buffer manager

      !! all requests for buffers come back through here

      routine  from buffer manager(record  (pe) name  p)
         integer  reason, type, call ty
         record  (m2900f) name  m2900
          record  (mef) name  mes
         record  (m2900if) name  mi
         conststring  (1) the chop = "Y"

         reason = p_c2;                 ! get reason for calling
!n!      n = p_gate port;                    ! byte quantity !
         n = p_a2
         if  n >= 254 then  n = n-256
         d == con desa(n);  ! get console desxcriptor
         if  mon < 0 start 
            select output(1); printstring("from buff:")
            write(p_gate port, 1); write(n, 1); write(reason, 1)
            write(d_stream, 1); write(d_state, 1)
            newline; select output(0)
         finish 
         if  d_state = not allocated then  -> free
         if  reason = store user name then  move user name(p_mes) andc 
           return 
         if  reason <= last itp reason start 
            if  d_cnsl # 255 start ;   ! cnsl = 255 - disconnected
               fill(p_mes, reason);    ! insert the message

               call ty = put output
               if  3<=reason<=4 or  reason = 7 or  c 
                 reason = send pad params then  call ty = Control data

               tcp == tcpa(d_tcp)
               to gate(call ty, p_mes, 0)
               if  reason = send emas down then  d_state = logging off 2 and  c 
                 get buffer(send disconnect)
            else 
free:          free buffer(p_mes)
            finish 

            if  reason = send disconnect start 
               retrieve(d)
           finish 
         else 

            if  reason=get op block or  reason=get big op block start 
               if  d_o state = idle then  -> free; ! kill o/p done
               unless  d_hold==null then  free buffer(d_hold)
               d_hold == p_mes
               get buffer(low level op transfer)
               return 
            finish 

            !! message to 2900 reason
            m2900 == p_mes
            m2900_stream = d_stream<<1+fixed+reason&1
            m2900_sub ident = 10

#if ~s
            if  d_stream < 0 then  m2900_stream = 4+d_stream
#else
            if  d_stream < 0 then  m2900_stream = 10+d_stream
                   ! streams 8 & 9 are internally -2 & -1
#fi

            if  reason = low level op transfer start 
               mes == d_hold
               if  mes == null or  d_state = awaiting int then  -> free
                             ! kill op done, so ignore tran request
               length(mes_lev3_itp_s) = 1
               m2900_p2a = k'400';        ! = swab(1)
               m2900_p2b = swab(d_o pos)
            else 
               m2900_p2b = 0;  m2900_p2a = 0
            finish 

            type = low level control

            if  reason = send trig reply start 
               m2900_sub ident = 0
               m2900_p5a = 0;  m2900_p5b = swab(d_opos)
               type = send data
               d_o trig = -1
            finish 
            if  reason = send the chop start 
               mi == m2900;  mi_sub ident = 0;  type = send data
               mi_p2a = -1;  mi_p2b = -1
               mi_int = the chop
            finish 

            if  mon < 0 start 
               select output(1)
               printstring("trf:")
               write(m2900_stream, 1);  write(m2900_sub ident, 1)
               write(swab(m2900_p2a), 1); write(swab(m2900_p2b), 1)
               write(d_o lim, 4);  write(d_p lim, 1)
               newline;  select output(0)
            finish 

            to 2900(type, m2900)
         finish 
      end 


      routine  retrieve(record  (con desf) name  d)
         record  (tcpf) name  tcp

         return  if  d_state = not allocated
         if  d_cnsl # 255 start ;   ! cnsl = 255 - disconnected
            tcp == tcpa(d_tcp)
            tcp_con state ind = 0;      ! only one user in XXX
         finish 

        free transient

        d_state = not allocated
        users = users-1 unless  users<0

         push(free des, d)
      end 


      !! r o u t i n e   lose consoles(all or a specific one)

      routine  lose consoles(integer  x)
         !! throw away connected consoles
         integer  index, i, t, q

            q = tcp_con state ind

            unless  q = 0 start 
               d == con desa(q)
               d_cnsl = 255;             ! no messages to the tcp now
               free transient
               unless  d_state >= logging off start 
                  if  input enabled <= d_state <= awaiting int start 
                     !! log off 2900
                     !! nb: **** the case of "logged on" is not catered for
                     get buffer(send the chop)
                  else 
                     unless  d_state >= logging on then  c 
                       retrieve(d);           ! may re-claim immediately
                  finish 
               finishelseif  d_state=logging off then  retrieve(d)
            finish 
      end 


      routine  read from am1
         !! itp server has control of the link
         record  (mef) name  mes
         record  (itpf) name  it
         integer  n, flag, sym, lim, type, t, stat, len

         mes == d_hold

         if  mes == null or  d_state = not allocated start 
            printstring("xxx:sequence?
")
            p_c1 = 0!128;  to 2900(return control, null)
            return 
         finish 

         d_hold == null

         if  mes_type=0 then  len=bigblockmax-2 else  c 
            len = small block max-2
         it == mes_lev3_itp
         n = it_a(0)
         flag = 0

         if  d_ostate&out p # 0 start 
            lim = d_o lim;  type = out p
         else 
            lim = d_p lim;  type = pmt p
            d_o posx = d_o pos if  n = 1
            !! hold beginning of prompt (temporarily) in oposx
            !!       in case it spans the end of buffer
         finish 

         cycle 
            cycle 
               stat = l_rxs
               exit  if  stat&(ready!xopl) # 0
            repeat 

            if  stat&xopl # 0 start ;       ! xop gone down
               t = 64;  -> skip;        ! send unsuccessfull
            finish 

            sym = l_rxd;                ! read the char
            if  l_rxs&acfy # 0 start ;  ! failed to read
               sym = l_rxd;             ! read it again
               if  l_rxs&acfy # 0 start ; ! hard failure - parity
                  t = 3;  -> skip
               finish 
            finish 

            if  stat&comm bit # 0 start 
               t = 2!128

skip:
               p_c1 = t;                ! long block+accept last
               to 2900(return control, null)
               d_hold == mes;  it_a(0) = n
               return 
            finish 

             if  sym = nl and  d_mode = 0 start 
                 it_a(n) = 13; n = n+1;   ! plant cr
             finish 

            if  d_o pos = d_out lim then  d_opos = -1
            d_o pos = d_o pos+1
            it_a(n) = sym

            if  d_o pos = d_o trig start ;     ! send trigger message
               get buffer(send trig reply)
            finish 

            if  d_o pos = lim start 
               d_ostate = d_ostate&(¬out p)

reply:
               p_c1 = 0!128;             ! eam1 to reject last char
               if  type = pmt p start 

                  !!      this is actually a prompt  - not output

                  d_o pos = d_o posx;   ! see comment above at type = pmt p
                  d_ostate = enabld
               else 
               finish 

               to 2900(return control, null)
               mes_len = n+header len;     ! no of chars

               if  d_cnsl = 255 start ;      ! gone away
                  free buffer(mes)
               else 
                   if  type # out p or  lose op = 0 then  c 
                    to gate(put output, mes, 0) else  c 
                    free buffer(mes)
               finish 

               if  d_out go > 0 and  d_ostate > enabld then  c 
                   get o block
               return 
            finish 

            if  n >= len start 
                !! leave room for a cr/lf sequence
               -> reply
            finish 
            n = n+1


            l_rxs = l_rxs!accept char;    ! accept the last char

         repeat 
      end 

      routine  write to am1

         record  (mef) name  mes
         record  (itpf) name  it
         integer  n, max, char, stat, gah
         constinteger  cr = 13

         mes == d_in mes
         if  d_state # input enabled or  mes == null start 
            p_c1 = 0;              ! terminate
            ->am1 rep;              ! reply to am1 hanmdler
         finish 

         it == mes_lev3_itp
         n = mes_lev3_reserved(1)+1;   ! pos in buffer, when buffer split
         max = it_a(0)
         if  mon < 0 start 
            select output(1); printstring("inp:")
            printstring(string(addr(it_a(0)))); newline; select output(0)
         finish 


         cycle 
            cycle 
               stat = l_rxs
               if  stat&xopl # 0 then  p_c1 = 64 and  ->am1 rep

               if  stat&ready # 0 start 

                 !! l i m i t sent
                 p_c1 = 2;              ! long block
                 mes_lev3_reserved(1) = n-1
am1 rep:         to 2900(return control, null)
                 return 
               finish 

               if  l_txs&ready # 0 then  exit 
            repeat 

            if  n > max start 
               p_c1 = 4;                 ! condition y
               to 2900(return control, null)
               free buffer(d_in mes);  d_in mes == null
               return 
            finish 


            char = it_a(n)
            char = nl if  char = cr;    ! forwarding on cr, with no lf
            n = n+1

            l_txd = char
            if  d_i pos = d_in lim then  d_i pos = -1
            d_i pos = d_i pos+1
         repeat 
      end 



      routine  kick 2900 message(record  (maf) name  log)

         !! this routine sends 'log' to the 2900 by inserting
         !! it in the input q for stream 4, and kicking it if
         !! necessary

         d == d2
         if  (d_hold == null and  d_inp q_e == null) or  d_incnt>5 then  c 
           get buffer(kick message stream)
         push(d_inp q, log)
         d_in cnt = d_in cnt+1
      end 

      routine  tidy message streams
         d2_o state = idle; d3_o state = idle
         while  not  d2_inp q_e == null cycle 
            free buffer(pop(d2_inp q))
         repeat 
      end 



      !!         r e a d   m e s s a g e   f r o m   a m 1


      routine  read message from am1


         record  (maf) name  m
         integer  n, sym, t, stat, lreply, stream
         record  (mef) name  mes
         integer  type
         record  (itpf) name  itp

         switch  hlm(1:2)

         ! d3 is allways used
         m == d3_hold; d3_hold == null
         if  m == null or  d3_opos = d3_o lim start 
              printstring("xxx: seq2!
")
              t = 0!128; -> reply
         finish 

         !!  (cater for partial block rec'd)
         n = d3_o posx
         if  n = 0 then  d3_in cnt = 0

         cycle 
            cycle 
               stat = l_rxs
               exit  if  stat&(ready!xopl) # 0
            repeat 

            if  stat&xopl # 0 start ;       ! xop gone down
               t = 64;                ! send unsuccessfull
               printstring("xxx: xop d
")
               -> skip
            finish 

            sym = l_rxd;                ! read the char
            if  l_rxs&acfy # 0 start ;  ! failed to read
               sym = l_rxd;             ! read it again
               if  l_rxs&acfy # 0 start ; ! hard failure - parity
                  t = 3
                  printstring("xxx: parity
")
                  -> skip
               finish 
            finish 

            if  stat&comm bit # 0 start 
              t = 2!128
skip:
               d3_o posx = n; d3_hold == m
reply:
               p_c1 = t;                ! long block+accept last
               to 2900(return control, null)
               return 
            finish 

            if  d3_o pos = d3_out lim then  d3_o pos = -1
            if  d3_o pos = d3_o lim then  -> badm

            d3_o pos = d3_o pos+1

            if  mon < 0 start 
            select output(1)
               printsymbol('i'); write(n, 2); write(sym, 2); space
               printsymbol(sym) if  sym > 32; newline
            select output(0)
            finish 

            m_a(n) = sym;   n = n+1

            if  n = 1 start ;           ! Got the total length
               d3_in cnt = m_a(0);         ! max = 256
               unless  5 <  d3_in cnt <= 64-18 start 
                                        ! nb: SMALL buffer is used
badm:             printstring("***xxx: message fails -")
                  write(d3_in cnt, 1); write(d3_o pos, 1); write(d3_out lim, 1)
                  write(d3_o lim, 1); write(type, 1); write(n, 1)
                  printstring(" xxx messages lost
")
                  if  n > 0 start 
                     cycle  sym = 0, 1, n
                         write(m_a(sym), 2); newline if  n&15=15
                     repeat 
                     newline
                  finish 
                  d3_o pos = d3_o lim
                  -> reply
               finish 

            else 
               if  n = d3_in cnt then  -> exit3; ! Got the whole message
            finish 

            l_rxs = l_rxs!accept char;    ! accept the last char

         repeat 

exit3:
         d3_o posx = 0;                 ! full message taken
         t = 0!128;                     ! normal+accept last

         if  d3_o pos # d3_o lim start ;     ! Another message waiting
            d == d3
            get buffer(get op block)
         finish 

         type = m_a(1);                 ! max = 256

! ?         x = (8+m_a(4))&x'fffe'
            stream = m_a(2)<<8!m_a(3)
         m_m len = n
         unless  1 <= type <= 2 then  ->badm
         d == con desa((stream-fixed)>>1)
         if  d_state = not allocated start ;  ! user has disconnected etc
            printstring("xxx: Invalid logon reply
")
            free buffer(m)
            -> reply
         finish 

         -> hlm(type)

hlm(1):                                 ! Logon Reply

                  lreply = m_a(5)
                  str = string(addr(m_a(6)));   ! copy text out of way
                  mes == m;            ! make it a network buffer
                  mes_len = length(str)
                  mes_lev3_itp_s = str;    ! copy text back in
                  tcp == tcpa(d_tcp)
                  to gate(put output, mes, 0)
               d_out go = d_out go-1
               if  l reply = 0 start 
                  d_state = logged on
               else 
                  d_state = logging off
                  retrieve(d) if  d_cnsl = 255
                  get buffer(send disconnect);  ! immediate request to go
               finish 
         -> reply

hlm(2):                                 ! setmode out, string at m_a(5)
         if  d_cnsl = 255 start 
            free buffer(m); -> reply
         finish 

         str = string(addr(m_a(5)));      ! copy setmode out of the way
         mes == m;                      ! change the buffer to an itp one
         itp == mes_lev3_itp
         itp_s = str;                     ! put the setmode back in
         mes_len = length(str)+4+header len;       ! hdr+string+string length
         tcp == tcpa(d_tcp);            ! map to tcp description
!?!         to gate(put output, mes, 0);   ! send the buffer
            FREE BUFFER(MES);            ! CANT HANDLE SETMODE
         ->reply;                       ! give control back to am1h

     end 



      !!     w r i t e   m e s s a g e   t o    a m 1

      routine  write message to am1

         record  (maf) name  m
         integer  n, max, am1 reply, stat

         ! allways use d2
         am1 reply = 4;          ! "condition y"

         cycle 

         m == d2_hold
         if  m == null then  m == pop(d2_inp q) and  d2_in cnt = d2_in cnt-1

         if  m == null then  exit 
                          !! terminate with "normal" (shouldnt happen)

         n = d2_o posx;       ! start of block - d2_o posx = 0

         cycle 
            cycle 
               stat = l_rxs

               if  stat&xopl#0 start 
                  d2_hold == m;           ! retain buffer for retry
                  am1 reply = 64;  d2_hold f = n; ->am1 rep
               finish 

               if  stat&ready # 0 start 
                  !! l i m i t sent
                  am1 reply = 2;              ! long block
                  d2_o posx = n;  d2_o pos = max
                  d2_hold == m;         ! retain for later
                 -> am1 rep
               finish 

               if  l_txs&ready # 0 then  exit 
            repeat 


            if  n > m_a(0) start 
               free buffer(m)
               d2_hold == null;  d2_o posx = 0; d2_hold f = 0

               if  d2_inp q_e == null then  ->am1 rep
              exit 
            finish 

            if  mon < 0 start 
            select output(1)
               printsymbol('o'); write(n, 2); write(m_a(n), 2); space
               printsymbol(m_a(n)) if  m_a(n) > 32; newline
               select output(0)
            finish 

            l_txd = m_a(n); n=n+1
         repeat 
         repeat 

am1 rep:
         p_c1 = am1 reply
         to 2900(return control, null)
      end 


      routine  mon mes(record  (mef) name  mes)
         integer  i, j, k, n
         record  (itpf) name  itp

         k = mes_len;  itp == mes_lev3_itp
         write(k, 1); space; space
         j = 0
         cycle  i = 1, 1, k
            if  mon > 0 and  i > 3 start ;        ! 'p' and not header
               n = itp_a(i)
               printsymbol(n) unless  n = 0 or  n = 4
            else 
                  write(itp_a(i), 1)
               j = j+1;  if  j = 25 then  j = 0 and  newline
            finish 
         repeat 
         newline;  select output(0)
      end 
   
   
      routine  mon p(record  (pe)name  p)
         integer  i
         printstring(" fn ="); write(p_fn, 1)
         printstring(" gate port"); write(p_gate port, 1)
         printstring(" task port"); write(p_task port, 1)
         printstring(" a2"); write(p_a2, 1)
         if  not  p_mes == null start 
            newline; spaces(5)
            write(p_mes_len, 3)
            cycle  i = 1, 1, 25
               write(p_mes_params(i), 2)
            repeat 
         finish 
         newline
      end 
   
   
endofprogram