



		    bft.c                           04/24/89  1329.7rew 04/24/89  1320.1      182340



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1987                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1985 *
   *                                                         *
   *********************************************************** */


/* HISTORY COMMENTS:
  1) change(86-10-31,Rohs), approve(87-07-13,MCR7580), audit(87-07-13,Leskiw),
     install(87-08-07,MR12.1-1072):
     Created.
  2) change(87-10-31,Flegel), approve(87-10-31,MCR7787),
     audit(88-01-26,DGHowe), install(88-02-24,MR12.2-1028):
     Added support for control_args to accomodate new queueing strategy.
  3) change(87-12-12,Flegel), approve(87-12-12,MCR7819),
     audit(88-01-26,DGHowe), install(88-02-24,MR12.2-1028):
     Added control arguments for a wider scope of request capabilities.
  4) change(89-02-15,Lee), approve(89-02-14,MCR8061), audit(89-02-27,Vu),
     install(89-04-24,MR12.3-1034):
     phx21250 (MOWSE 11) - fixed typo "requesst" in bft_fetch message.
                                                   END HISTORY COMMENTS */

/* COMPILER: Lattice C, V2.15 */

/***************************************************************

     BFT ARGUMENT ANAYLSER

     SYNTAX:     BFT KEY {path1 {path2...path1N path2N}} {/Control_args}

     PARAMETERS: argc - the number of arguments on the command
                        line. (input)
                 argv - a pointer to an array of pointers to
                        strings which contain the arguments
                        that follow the fetch keyword. (input)

     FUNCTION:   Parses the BFT command line for a valid keyword.
                 If one is found then the appropriate routine is
                 called to parse the remainder of the command
                 for filenames. If the command if syntactically
                 correct, then a call to the appropriate BFT
                 minor capability is made.

*****************************************************************/

#include <stdio.h>
#include <mowse.h>
#include <bft.h>

#define CANCEL_SW     0x001
#define DISPLAY_SW    0x002
#define FETCH_SW      0x004
#define LOAD_SW       0x008
#define RECOVER_SW    0x010
#define STORE_SW      0x020
#define UNLOAD_SW     0x040

/* ERROR MESSAGE */

#define NAME          "BFT"
#define USAGE_CANCEL  "\n   Usage: bft cancel request_id {request_id ...}\n"
#define USAGE_UNLOAD  "\n   Usage: bft unload\n"
#define USAGE_RECOVER "\n   Usage: bft unload\n"
#define USAGE_BFT     "\n   Usage: bft KEY {path1 {path2...path1N path2N}} {/Control_args}\n"
#define USAGE_FETCH   "\n   Usage: bft FETCH {path1 {path2...path1N path2N}} {/Control_args}\n"
#define USAGE_STORE   "\n   Usage: bft STORE {path1 {path2...path1N path2N}} {/Control_args}\n"
#define USAGE_KEYS    "\n     (s)tore, (f)etch, (c)ancel, (ls) list, (l)oad, (u)nload, (r)ecover\n"

/* GLOBAL REFERENCE */

int  argp;                            /* Current position in argument list */
int  argcount;                        /* Argument count */
char **argval;                        /* Arguments */
char *arg;                            /* Current argument */
long flags;                           /* Transfer modes */
int  priority;                        /* Transfer priority level */
int  control_sw;                      /* Argument parsing control */

char *find_option ();                 /* Locates a control_arg option */
char *stripquote();                   /* function to remove surrounding quotes */
char *upper();                        /* function to convert string to upper case */
int  bft_cancel ();
int  bft_fetch ();
int  bft_load ();
int  bft_display ();
int  bft_recover ();
int  bft_store ();
int  bft_unload ();

/**/

main (argc, argv)

int  argc;                            /* number of args on the command line */
char **argv;                          /* pointer to the args */
{
int  code;                            /* Error code */
int  (*key_procedure)();              /* Key function handler */
  
/* Initialize */

  code = 0;
  flags = 0;
  priority = 3;
  control_sw = 0;

  argcount = argc;
  argval = argv;
  flags = 0;

/* How many args are there ? */

  if (argcount < 1)
  {
    fprintf (stderr, "%s: Wrong number of arguments.\n%s", NAME, USAGE_BFT);
    return;
  }

/* Extract the keyword */

  argp = 0;
  if ((code = get_arg (0)) != 0)
  {
    bfterror (code, USAGE_BFT, NULL);
    return;
  }

/* This argument MUST be a keywrd, otherwise what are we to do ? */

  if      (!strcmp (argval[argp],"cancel")  || !strcmp (argval[argp],"c"))
  {
    control_sw |= CANCEL_SW;
    key_procedure = bft_cancel;
  }
  else if (!strcmp (argval[argp],"fetch")   || !strcmp (argval[argp],"f"))
  {
    control_sw |= FETCH_SW;
    key_procedure = bft_fetch;
  }
  else if (!strcmp (argval[argp],"load")    || !strcmp (argval[argp],"l") || !strcmp (argval[argp],"ld"))
  {
    control_sw |= LOAD_SW;
    key_procedure = bft_load;
  }
  else if (!strcmp (argval[argp],"list")    || !strcmp (argval[argp],"ls"))
  {
    control_sw |= DISPLAY_SW;
    key_procedure = bft_display;
  }
  else if (!strcmp (argval[argp],"recover") || !strcmp (argval[argp],"r"))
  {
    control_sw |= RECOVER_SW;
    key_procedure = bft_recover;
  }
  else if (!strcmp (argval[argp],"store")   || !strcmp (argval[argp],"s"))
  {
    control_sw |= STORE_SW;
    key_procedure = bft_store;
  }
  else if (!strcmp (argval[argp],"unload")  || !strcmp (argval[argp],"u") || !strcmp (argval[argp],"uld"))
  {
    control_sw |= UNLOAD_SW;
    key_procedure = bft_unload;
  }
  else
  {
    fprintf (stderr, "BFT: Keyword not accepted: %s.%s", arg, USAGE_KEYS);
    return;
  }

/* Parse through control arguments */

  if ((code = parse_args ()) != 0)
  {
    bfterror (code, USAGE_BFT, NULL);
    return;
  }

/* We made it here, so call the handler, skipt the first real argument as it is the keyword */

  argp = 0;
  get_arg (0);
  (*key_procedure) ();
}
/**/
/***************************************************************

     BFT_CANCEL

     SYNTAX:     bft cancel REQUEST_IDENTIFIER {REQUEST_IDENTIFIER ...}
                 bft c      REQUEST_IDENTIFIER {REQUEST_IDENTIFIER ...}

     PARAMETERS: None.

     FUNCTION:   Cancel an element from the request queue.

*****************************************************************/

bft_cancel ()
{
int  code;                             /* Error code */
char id[PATHNAMESIZE];                 /* Request id */
int  passed;                           /* Count of satisfied requests */
char request_type;                     /* Cancellation request type */


  passed = 0;

/* Repeat until all args are exhausted */

  while (argp < argcount - 1)
  {
    if (code = get_arg (1))
    {
      bfterror (code, arg, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for cancellation.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }

/* Verify and cancel the request */

    if (arg[0] != '/')
    {
      strncpy (id, arg, PATHNAMESIZE);
      code = bftcan (BFT_PATH_ID, stripquote (id));
    }
    else
    {
      request_type = arg[1];

      arg = find_option ();
      if (arg == NULL)
        code = BFT_EXPECTING;
      else
      {
        strncpy (id, arg, PATHNAMESIZE);

        if (request_type == 'I')
          code = bftcan (BFT_TIME_ID, stripquote (id));
        else if (request_type == 'E')
          code = bftcan (BFT_ENTRY_ID, stripquote (id));
      }
    }

/* Something went wrong */

    if (code != 0)
    {
      bfterror (code, "Executing bft cancel.", NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for cancellation.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }
    else
      passed += 1;
  }

  if (passed > 0)
    printf ("BFT: %d reques%s submitted for cancellation.\n", passed, ((passed == 1) ? "t" : "ts"));

  return (0);
}
/**/
/***************************************************************

     BFT_DISPLAY

     SYNTAX:     BFT LIST {/Control_args}
                 BFT LS   {/Control_args}

     PARAMETERS: None.

     FUNCTION:   Display the request queues.

*****************************************************************/

bft_display ()
{
  fprintf (stderr, "BFT: PC version of BFT does not implement queue list.  Use Multics list.\n");
}
/**/
/***************************************************************

     BFT_FETCH

     SYNTAX:     bft fetch file1 {file2...file1N file2N} {/Control_args}
                 bft f     file1 {file2...file1N file2N} {/Control_args}

     PARAMETERS: None.

     FUNCTION:   parses the BFT command line after the "fetch"
                 keyword for a source and destination filename.
                 If only one filename is given then it is taken
                 as both the source and destination filename.
                 If the syntax is correct then the bft fetch
                 minor capability is called.

*****************************************************************/

bft_fetch ()
{
char mu_path[MAXARGSTRING];           /* holds arguments to be passed to execap  */
char pc_path[PATHNAMESIZE];           /* source file name */
int  passed;                          /* Number of requests submitted */
int  code;

  passed = 0;

/* Repeat until all args are exhausted */

  while (argp < argcount - 1)
  {

/* Get Multics path */

    if (code = get_arg (0))
    {
      bfterror (code, USAGE_FETCH, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for fetching.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }

    strncpy (mu_path, arg, PATHNAMESIZE);
    strncpy (pc_path, "===", PATHNAMESIZE);

/* Get the Multics path, if it was specified */

    code = get_arg (0);
    if ((code != 0)&&(code != BFT_NOARG))
    {
      bfterror (code, arg, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for fetching.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }
    else if (code == 0)
      strcpy (pc_path, arg);

/* expand the destination filename to a pathname for the fetch */

    getpath (pc_path);

    code = bftfetch (stripquote (mu_path), pc_path, flags, priority);
    if (code != 0)
    {
      bfterror (code, pc_path, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for fetching.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }
    else
      passed += 1;
  }

  /* RL: phx21250 - fixed display message typo "requesst" for singular form */
  if (passed > 0)
    printf ("BFT: %d reques%s submitted for fetching.\n", passed, ((passed == 1) ? "t" : "ts"));

  return (0);
}
/**/
/***************************************************************

     BFT_LOAD

     SYNTAX:     bft load

     PARAMETERS: none

     FUNCTION:   Because of the difference in nature of loading
                 an application between Multics and the PC, this
                 merely tells the user that (s)he must use "bft_load"
                 command.

*****************************************************************/

bft_load ()
{

/* Inform the user of the bft_load command*/

  printf ("BFT: load is not implemented.  Use bft_load.\n");
}
/**/
/**************************************************************
 
     BFT_RECOVER

     SYNTAX:     bft recover
                 bft r

     PARAMETERS: None.

     FUNCTION:   Initiates the appropriate recover procedures
                 by emitting a message to the Multics bft to
                 begin recovery procedures.

*****************************************************************/

bft_recover ()
{
int code;

/* call the recover fetch entry point */

  if ((code = bftrecfe ()) != 0)
    return (bfterror (code, "Recovering fetch requests.", NULL));

/* call the recover store entry point */

  if ((code = bftrecst ()) != 0)
    return (bfterror (code, "Recovering store requests.", NULL));
}
/**/
/***************************************************************

     BFT_STORE

     SYNTAX:     bft store file1 {file2...file1N file2N} {/Control_args}
                 bft s     file1 {file2...file1N file2N} {/Control_args}

     PARAMETERS: None.

     FUNCTION:   Parses the BFT command line after the "store"
                 keyword for a source and destination filename
                 if only one filename is given then it is taken
                 as both the source and destination filename.
                 If the syntax is correct then the bft store
                 minor capability is called with the filenames.

*****************************************************************/

bft_store ()
{
char mu_path[MAXARGSTRING];           /* holds arguments to be passed to execap  */
char pc_path[PATHNAMESIZE];           /* source file name */
int  passed;                          /* Number of requests submitted */
int  code;


  passed = 0;

/* Repeat until there are no argument */

  while (argp < argcount - 1)
  {

/* Get PC path */

    if ((code = get_arg (0)) != 0)
    {
      bfterror (code, USAGE_STORE, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for storing.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }

    strncpy (pc_path, arg, PATHNAMESIZE);
    strncpy (mu_path, "===", PATHNAMESIZE);

/* Get the Multics path, if it was specified */

    code = get_arg (0);
    if ((code != 0)&&(code != BFT_NOARG))
    {
      bfterror (code, arg, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for storing.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }
    else if (code == 0)
      strcpy (mu_path, arg);

/* expand the destination filename to a pathname for the fetch */

    getpath (pc_path);

    code = bftstore (pc_path, stripquote (mu_path), flags, priority);
    if (code != 0)
    {
      bfterror (code, pc_path, NULL);
      if (passed > 0)
        printf ("BFT: %d reques%s submitted for storing.\n", passed, ((passed == 1) ? "t" : "ts"));
      return (code);
    }
    else
      passed += 1;
  }

  if (passed > 0)
    printf ("BFT: %d reques%s submitted for storing.\n", passed, ((passed == 1) ? "t" : "ts"));

  return (0);
}

/**/
/***************************************************************

     BFT_UNLOAD

     SYNTAX:     bft unload
                 bft u

     PARAMETERS: None.

     FUNCTION:   Unloads bft from MOWSE.

*****************************************************************/

bft_unload ()
{
int code;


/* unload the BFT major capability */

  if ((code = bftunld ()) != 0)
    return (bfterror (code, "Unloading.", NULL));
}
/**/
/***************************************************************

     FIND_OPTION

     PARAMETERS: None.

     FUNCTION:   Returns a pointer to the option string to an argument.
                 This is either the [2] character in the current arg,
                 or the next arg.

*****************************************************************/

char *find_option ()
{

  if (arg[2] != 0)
    return (&(arg[2]));

  argp += 1;
  arg = argval[argp];

  if (arg[0] == '/')
    return (NULL);
  else if (argp < argcount)
    return (arg);
  else
    return (NULL);
}
/**/
/***************************************************************

     GET_ARG

     PARAMETERS: SPECIAL - If the special control_args are to be
                           treated as a regular arg.

     FUNCTION:   Sets arg and argp to the next valid non-control
                 argument.  If "special" is set to True, then accept
                 "/C STR" control arguments as a non-control argument.

*****************************************************************/

get_arg (special)

int  special;                         /* Accept "/C STR" */
{
int  queue;                           /* Priority queue */
int  code;


/* Process all control args until a non-control arg is found */

  while (1)
  {
    argp += 1;

    if (argp >= argcount)
      return (BFT_NOARG);

/* Is this an argument, no then return 0 */

    arg = argval[argp];
    if (arg[0] != '/')
      return (0);

/* Else check for special cases */

    switch (toupper (arg[1]))
    {
      case 'E':                       /* These are special */
      case 'I':
        if (special)                  /* Caller wants one of these */
          return (0);
        else                          /* Skip the param */
          find_option ();
        break;

      case 'N':                       /* Skip param */
      case 'F':
      case 'Q':
        find_option ();
        break;

      default:                        /* No param */
        break;
    }
  }
}
/**/
/***************************************************************

     PARSE_ARGS

     PARAMETERS: None.

     FUNCTION:   Processes a control argument.

                 Acceptable control args:

                    /F ascii | binary   - file type {ascii}
                    /N on | off         - notify {off}
                    /Q N                - priority {3}

                 Control arguments skipped (as they are really "single"
                 arguments):

                    /E NAME             - Request entry
                    /I NAME             - Request ID

*****************************************************************/

parse_args ()

{
int  code;
int  queue;                           /* Transfer priority */

  code = 0;

  for (argp = 1; argp < argcount; argp++)
  {
    arg = argval[argp];

    if (arg[0] == '/')
    {
      switch (toupper (arg[1]))
      {
        case 'F':                                         /* File_type */
          if (!(control_sw & STORE_SW || control_sw & FETCH_SW))
            code = BFT_INCOMPATIBLE;
          else if ((arg = find_option ()) == NULL)
            code = BFT_EXPECTING;
          else if (!strcmp (upper (arg), "ASCII"))
            flags &= ~BFT_BINARY;
          else if (!strcmp (upper (arg), "BINARY"))
            flags |= BFT_BINARY;
          else
            code = BFT_BADOPT;
          break;

        case 'N':                                         /* Notify */
          if (!(control_sw & STORE_SW || control_sw & FETCH_SW))
            code = BFT_INCOMPATIBLE;
          else if ((arg = find_option ()) == NULL)
            code = BFT_EXPECTING;
          else if (!strcmp (upper (arg), "OFF"))
            flags &= ~BFT_NOTIFY;
          else if (!strcmp (upper (arg), "ON"))
            flags |= BFT_NOTIFY;
          else
            code = BFT_BADOPT;
          break;

        case 'Q':                                         /* Queue */
          if (!(control_sw & STORE_SW || control_sw & FETCH_SW))
            code = BFT_INCOMPATIBLE;
          else if ((arg = find_option ()) == NULL)
            code = BFT_EXPECTING;
          else if (strlen (arg) != 1)
            code = BFT_BADOPT;
          else if (!isdigit (arg[0]))
            code = BFT_BADOPT;
          else
          {
            queue = (int) (arg[0] - '0');
            if ((queue < BFT_MIN_PRIORITY) || (queue > BFT_MAX_PRIORITY))
              code = BFT_INVALID_PRIORITY;
            else
              priority = queue;
          }
          break;

        case 'I':                                         /* ID */
          if (!(control_sw & CANCEL_SW))
            code = BFT_INCOMPATIBLE;
          break;

        case 'E':                                         /* Entry */
          if (!(control_sw & CANCEL_SW))
            code = BFT_INCOMPATIBLE;
          break;

        default:                                          /* Error */
          code = BFT_BADARG;
          break;
      }

      if (code != 0)
        return (code);
    }
  }

  return (0);
}
/**/
/***************************************************************

     UPPER

     PARAMETERS: STRING - string to convert to upper.

     FUNCTION:   Convert a character string to upper case.

*****************************************************************/

char *upper (str)

char *str;
{
int  i;

  for (i = 0; str[i]; i++)
    str[i] = toupper (str[i]);

  return (str);
}




		    bft.mak                         10/07/88  1553.3rew 10/07/88  1254.4        9153



#  BEGIN MAKEFILE: BFT.MAK
#
#  HISTORY COMMENTS:
# 1) change(88-08-16,Flegel), approve(88-09-07,MCR7978),
#    audit(88-09-14,Lee):
#    Created for clarity and transportability.
#                                                  END HISTORY COMMENTS
#
#  Makefile for compose using MICROSOFT MAKE MACROS
#

#
# DEFINITIONS
#

INCL    = -iC:\lc\ -iC:\include\mowse\ -iC:\include\bft\\

LIBS    = C:\lib\mowse\mowslib+C:\lc\s\lc

HEADER  = C:\lc\c\c

#
# MACROS
#

.c.obj:
     lc1 $*.c  $(INCL) -d -n32
     lc2 $*.q

#
# OBJECT
#

bft.obj:      bft.c bft.h

subrs.obj:    subrs.c bft.h

bft_load.obj: bft_load.c bft.h

bfterror.obj: bfterror.c bft.h

#
# EXECUTABLE
#

bft.com:      bft.obj subrs.obj bfterror.obj
     link $(HEADER) bft subrs bfterror,bft,bft,$(LIBS)
     exe2bin bft bft.com
     del bft.exe

bft_load.com: bft_load.obj subrs.obj bfterror.obj
     link $(HEADER) bft_load subrs bfterror,bft_load,bft_load,$(LIBS)
     exe2bin bft_load bft_load.com
     del bft_load.exe

#  END MAKEFILE: BFT.MAK




		    bft_load.c                      10/07/88  1553.3rew 10/07/88  1254.4      435987



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1987                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1985 *
   *                                                         *
   *********************************************************** */

/* HISTORY COMMENTS:
  1) change(86-10-31,Rohs), approve(87-07-13,MCR7580), audit(87-07-13,Leskiw),
     install(87-08-07,MR12.1-1072):
     Created.
  2) change(87-10-27,Flegel), approve(87-10-29,MCR7787),
     audit(88-01-26,DGHowe), install(88-02-24,MR12.2-1028):
     Re-designed to have Multics BFT maintain ALL queues.
  3) change(88-02-19,Flegel), approve(88-09-07,MCR7978), audit(88-09-14,Lee),
     install(88-10-07,MR12.2-1145):
     Repair expand_path to correctly return the appropriate second component.
  4) change(88-09-28,Flegel), approve(88-09-28,MCR7998), audit(88-09-28,Lee),
     install(88-10-07,MR12.2-1145):
     Repair ascii mode for the transfer of small files (<512 Kbytes) to the PC.
                                                   END HISTORY COMMENTS */

/* COMPILER: Lattice C, V2.15 */

/**************************************************************

     BFT_LOAD.C

     This file contains the minor capabilites for 
     Background File Transfer, and the routines needed to load
     BFT as a major capability on the PC.

***************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <dos.h>
#include <mowse.h>
#include <bft.h>

#define SEEK_START     0      /* Beginning positioning in lseek */
#define SEEK_CURRENT   1      /* Current positioning in lseek */
#define SEEK_EOF       2      /* EOF positioning in lseek */

#define DOS_STAR_FIRST 0x4E   /* DOS Function to locate first starname entry */
#define DOS_STAR_NEXT  0x4F   /* DOS Function to locate next starname entry */
#define DOS_SET_DTA    0x1A   /* DOS Function to set DTA */

#define MAXLONG        0x7FFFFFFF

int _stack = STACKSIZE;     /* Lattice C constant to set stack size of a program */

struct dta_struct           /* DTA structure for starnames */
{
   char filler[30];
   char name[13];
} dta;

long lseek ();              /* File positioning */
char *stptok();             /* C Runtime support */
char *striptok();           /* Extracting tokens from messages */
int  bftmajcap();           /* bft major capability handler */

/*  */
/************************************************************

     BFT_LOAD  (MAIN)

     PARAMETERS: ARGC - number of arguments on the command
                        line. (input)

     FUNCTION:   Loads the BFT major capbility into the CAT.

*************************************************************/

main (argc)

int  argc;                            /* number of args */
{
int majnum;                           /* major capability number of the local system */
int majnumr;                          /* major capability number of the remote system */
int com_id;                           /* command id */
int code;                             /* error code */
mcb *mcb_ptr;                         /* mowse control block pointer */
bft_data_ptr data_ptr;                /* pointer to bft's "static" data */


/* make sure no additional args are given on the command line */

  if (argc > 1)
  {
     printf ("BFT:  Unexpected argument.\n   Usage: bft_load\n");
     return;
  }

/* check to see if BFT is already on the local system */

  majnum = 0;
  if (findnumb ("BFT", WSLOCAL, &majnum) == 0)
  {
    fprintf (stderr, "BFT:  Already loaded.\n");
    return;
  }

/* allocate space for bft's data */

  data_ptr = (bft_data_ptr) malloc (sizeof (bft_data));
  if (data_ptr == NULL)
  {
     fprintf (stderr, "BFT:  Memory allocation error.\n");
     return;
  }

/* initialize variables that need it */

  data_ptr->source_file[0] = 0;
  data_ptr->source_flags = 0L;
  data_ptr->destination_file[0] = 0;
  data_ptr->destination_flags = 0L;
  data_ptr->inbuffpos = 0;
  data_ptr->outbuffpos = 0;
  data_ptr->inpos = 0L;
  data_ptr->outpos = 0L;
  data_ptr->inbufflen = 0;
  data_ptr->inbuffer[0] = '\0';
  data_ptr->outbuffer[0] = '\0';
  data_ptr->expand_dirname[0] = '\0';

/* create the bft instance */

  if ((code = cretinst("BFT", bftmajcap, MAXARGSTRING, MAXARGSTRING, data_ptr, &mcb_ptr)) != 0)
  {
    free (data_ptr);
    return (bfterror (code, "Loading BFT.", NULL));
  }

/* check to see if BFT is on the remote system, if not then load it */

  majnumr = 0;
  if (findnumb ("bft_main_", WSREMOTE, &majnumr) != 0)
  {
    if ((code = execom ("bft_main_", WSREMOTE, &com_id, mcb_ptr)) != 0)
    {
      destinst (&mcb_ptr);
      free (data_ptr);
      bfterror (code, "Loading remote bft_main_.", NULL);
      return;
    }
  }

/* Make BFT resident */

  stayres (mcb_ptr);
}
/*  */
/********************************************************************

     BFTMAJCAP

     PARAMETERS: MINUM      - Minor capability number to execute (input)
                 SENDER     - Major capability number of the sender (input)
                 ARG_STRING - The arguments passed to the minor (input)
                 ARG_LEN    - The length of the argument string (input)
                 DATA_PTR   - Pointer to the BFT data block (input)
                 MCB_PTR    - A pointer to the mowse control block (input)

     FUNCTION:   Executes the specified bft minor capability each of
                 which is described below.

**********************************************************************/

bftmajcap (minum, sender, arg_string, arg_len, data_ptr, mcb_ptr)

int minum;                            /* minor capability number to call */
int sender;                           /* major cap of the caller */
int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
bft_data_ptr *data_ptr;               /* pointer to the BFT data block */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
{
char temp_str[MAXARGSTRING];          /* temporary message */


/* switch on the minor capability */

  switch(minum)
  {
    case(BFT_SHUT_DOWN):
      bft_shut_down(mcb_ptr);
      break;

    case(CHECK_FILE_LENGTH):
      check_length(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

   case(EXPAND_PC_PATH):
      expand_pc_path(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

    case(INITIATE_FETCH):
      init_fetch (arg_string, arg_len, mcb_ptr, data_ptr);
      break;

    case(INITIATE_STORE):
      init_store (arg_string, arg_len, mcb_ptr, data_ptr);
      break;

    case(POSITION_FILE_POINTER):
      position_pointer (arg_string, arg_len, mcb_ptr, data_ptr);
      break;

    case(READ_ERROR):
      read_err (arg_string, arg_len, mcb_ptr, data_ptr);
      break;

    case(REC_DATA):
      rec_data(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

    case(REC_EOF):
      receive_eof(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

    case(SEND_DATA):
      send_data(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

    case(SYSTEM_ERROR):
      system_shutdown();
      break;

    case(WRITE_ERROR):
      write_err (arg_string, arg_len, mcb_ptr, data_ptr);
      break;

    case(MESSAGE_TOO_LONG):
      bfterror (BFT_INVALID_MINOR, "message_too_long", mcb_ptr);
      system_shutdown();
      break;

    case(EXECUTE_COMMAND_REPLY):
      execute_command_reply(arg_string,arg_len,mcb_ptr,data_ptr);
      break;

    case(FAIL_CAPABILITY):
      bfterror (BFT_INVALID_MINOR, "fail_capability", mcb_ptr);
      system_shutdown();
      break;

    case(GET_STATUS):
      bfterror (BFT_INVALID_MINOR, "get_status", mcb_ptr);
      system_shutdown();
      break;

    case(QUERY_REPLY):
      bfterror (BFT_INVALID_MINOR, "query_reply", mcb_ptr);
      system_shutdown();
      break;

    case(RESET_APPLICATION):
      bfterror (BFT_INVALID_MINOR, "reset_application", mcb_ptr);
      system_shutdown();
      break;

    case(RESUME_APPLICATION):
      bfterror (BFT_INVALID_MINOR, "resume_application", mcb_ptr);
      system_shutdown();
      break;

    case(RESPONSE_CONNECT):
      bfterror (BFT_INVALID_MINOR, "response_connect", mcb_ptr);
      system_shutdown();
      break;

    case(RESPONSE_DISCONNECT):
      disconnect_response(mcb_ptr);
      break;

    case(REQUEST_CONNECT):
      bfterror (BFT_INVALID_MINOR, "request_connect", mcb_ptr);
      system_shutdown();
      break;

    case(REQUEST_DISCONNECT):
      disconnect_request(mcb_ptr,sender);
      break;

    case(SUSPEND_APPLICATION):
      bfterror (BFT_INVALID_MINOR, "suspend_application", mcb_ptr);
      system_shutdown();
      break;

    case(TERMINATE_APPLICATION):
      putbgmes(mcb_ptr,0,"BFT","BFT terminating.");
      destinst(&mcb_ptr);
      break;

    case(WAKE_UP):
      bfterror (BFT_INVALID_MINOR, "wake_up", mcb_ptr);
      system_shutdown();
      break;

    default:
      sprintf (temp_str, "%d", minum);
      bfterror (BFT_INVALID_MINOR, temp_str, mcb_ptr);
      system_shutdown();
      break;
  }
}                                       
/*  */
/******************************************************************

BFT MINOR CAPABILITIES

********************************************************************/

/******************************************************************

    BFT_SHUT_DOWN

    PARAMETERS: MCB_PTR    - pointer to the mowse control block (input)

    INFO EXTRACTED FROM ARGLIST:  NONE

    FUNCTION:   Shuts bft down.

********************************************************************/

bft_shut_down(mcb_ptr)

mcb  *mcb_ptr;                      /* pointer to the mowse control block */
{
int   majnum;                       /* major capability number of remote */


/* Display the shutdown message */

  putbgmes (mcb_ptr, 0, "BFT", "BFT is shutting down.");

/* check to see if BFT is on the remote system */

  majnum = 0;
  if (findnumb("bft_main_",WSREMOTE,&majnum) != 0)
  {
    putbgmes (mcb_ptr, 0, "BFT", "BFT major capability not found. BFT aborted.");
    return(0);
  }

  disrqst (majnum, mcb_ptr);
}
/*  */
/******************************************************************

    CHECK_FILE_LENGTH

    PARAMETERS: ARG_STRING - string containing the argument (input)
                ARG_LEN    - length of the arg string (input)
                MCB_PTR    - pointer to the mowse control block (input)
                DATA_PTR   - pointer to BFT data structure (input)

    INFO EXTRACTED FROM ARGLIST:
                DESTINATION FILE NAME - filename on local system
                DESTINATION FLAGS     - transfer flags

    FUNCTION:   Finds out how much is in the destination file
                and calls position file pointer on the remote system.
                This is indicating that a recover store is in progress, so
                remember the stuff that was given to us.

********************************************************************/

check_length (p_arg_string, p_arg_len, p_mcb_ptr, p_data_ptr)

int  p_arg_len;                       /* length of the arg string */
char *p_arg_string;                   /* string containing the argument */
mcb  *p_mcb_ptr;                      /* pointer to the mowse control block */
bft_data_ptr p_data_ptr;              /* pointer to BFT data structure */
{
char  token[MAXARGSTRING];            /* destination file being checked */
char  *arg_pos;                       /* argument position */
int   fp_dest;                        /* incoming file pointer */
char  message[MAXARGSTRING];          /* Output message */
int   message_len;                    /* Length of message */
char  temp_str[MAXARGSTRING];         /* Temporary message holder */
int   buff_pos;                       /* Position in buffer */
int   buff_len;                       /* Length of buffer */
int   line_cnt;                       /* Lines in file */
int   open_mode;                      /* Modes for opening */


/* extract the source and destination file */

  arg_pos = p_arg_string;
  arg_pos = striptok (arg_pos, p_data_ptr->destination_file);
  arg_pos = striptok (arg_pos, token);
  char2long (token, &p_data_ptr->destination_flags);

/* if the destination file is not there return an error */

  open_mode = O_RDONLY;
  if (p_data_ptr->destination_flags & BFT_BINARY)
    open_mode |= O_RAW;

  if ((fp_dest = open (p_data_ptr->destination_file, open_mode)) == -1)
  {
    sprintf (temp_str, "%s opening %s.", getsyserr (errno), p_data_ptr->destination_file);
    message[0] = 0;
    message_len = 0;
    message_len = addtoken (message, message_len, temp_str, 0);
    executeb (WRITE_ERROR, message, message_len, p_mcb_ptr);
    return;
  }

/* Calculate the length of the file:  chars for binary, lines for ascii */

  if (p_data_ptr->destination_flags & BFT_BINARY)
    sprintf (temp_str, "%ld", lseek (fp_dest, 0L, SEEK_EOF));
  else
  {
    p_data_ptr->outpos = 0;
    if ((line_cnt = count_lines (fp_dest, p_data_ptr->outbuffer, &p_data_ptr->outpos, &buff_len, &buff_pos)) == -1)
    {
      sprintf (temp_str, "%s line counting %s.", getsyserr (errno), p_data_ptr->destination_file);
      message[0] = 0;
      message_len = 0;
      message_len = addtoken (message, message_len, temp_str, 0);
      executeb (WRITE_ERROR, message, message_len, p_mcb_ptr);
      close (fp_dest);
      return;
    }
    sprintf (temp_str, "%d", line_cnt);

/* Subtract the half line from the positioning count */

    p_data_ptr->outpos -= (buff_len - buff_pos);
  }
  close(fp_dest);

/* Because we are positioning, we are setting up a new transfer, so store it */

  p_data_ptr->outbuffpos = 0;

/* call position file pointer on the remote system */

  message_len = 0;
  message[0] = 0;
  message_len = addtoken (message, message_len, temp_str, 0);

  executeb (POSITION_FILE_POINTER, message, message_len, p_mcb_ptr);
}
/*  */
/*******************************************************************

     COUNT_LINES

     PARAMETERS: FP       - file to examine                (INPUT)
                 BUFF     - buffer to use                  (INPUT)
                 FILE_POS - file position of last eol+1    (OUTPUT)
                          - maximum eols to pass           (INPUT)
                 BUFF_LEN - length of remaining buffer     (OUTPUT)
                 BUFF_POS - buffer position of last eol+1  (OUTPUT)

     FUNCTION:   Count the number of lines in the file, already opened.
                 If the initial FILE_POS is 0, then count to the last EOL.
                 Ultimately, the actual file_pointer (FP) is set to the next
                 character after the last block read into buff.

********************************************************************/

count_lines (fp, buff, file_pos, buff_len, buff_pos)

int  fp;                     /* File pointer */
char *buff;                  /* Buffer to use fo counting */
long *file_pos;              /* File position */
int  *buff_len;              /* Buffer length */
int  *buff_pos;              /* Position in buffer */
{
long line_cnt;               /* Number of lines */
int  last_eol;               /* Position in buffer of last EOL */
int  status;                 /* Read status */
long max_count;              /* How far to count */
int  i;


/* Read chunks of the file counting LFs until either MAX or EOF */

  max_count = (*file_pos == 0) ? MAXLONG : *file_pos;

  line_cnt = 0;
  while (line_cnt < max_count)
  { 
    if ((status = read (fp, buff, DISKBUFF)) <= 0)
    { 
      if (*file_pos != 0)                             /* Error encountered */
        return (-1);
      else                                            /* Counted all thats there */
      { 
        *file_pos = lseek (fp, 0L, SEEK_CURRENT);
        return ((int)line_cnt);
      }
    }

/* Count of LFs */

    for (i = 0, last_eol = 0; (i < status) && (line_cnt < max_count); i++)
    { 
      if (buff[i] == LF)
      { 
        line_cnt += 1;
        last_eol = i+1;
      }
    }

/* Update the return values */
 
    *buff_len = status;
    *buff_pos = last_eol;
  }

/* Return the line count */

  *file_pos = lseek (fp, 0L, SEEK_CURRENT);
  return ((int)line_cnt);
}
/*  */
/*******************************************************************

     EXPAND_PC_PATH

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 LOCATOR    - position in starname matching (FIRST || NEXT)
                 PATH       - path to be expanded
                 REQUEST_ID - major ID of request
                 DIRECTION  - direction of request

     FUNCTION:   Expand the PC pathname to an absolute pathname and
                 return the results to FULL_PC_PATH on MU:BFT.

********************************************************************/

expand_pc_path (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char path[PATHNAMESIZE];              /* Path to expand */
char *arg_pos;                        /* Argument positioning */
char message[MAXARGSTRING];           /* Return message */
int  message_len;                     /* Return message length */
char request_id[2];                   /* Request ID of expansion */
char entryname[ENTRYNAMESIZE];        /* Entryname porition of request */
char direction[2];                    /* Direction of transfer */
char locator[2];                      /* Starname mathc position */
int  code;


/* Strip the relative path, major, minor IDs from the list */

   arg_pos = arg_string;
   arg_pos = striptok (arg_pos, locator);
   arg_pos = striptok (arg_pos, path);
   arg_pos = striptok (arg_pos, request_id);
   arg_pos = striptok (arg_pos, direction);

/* Expand the path, if one given, otherwise get next match */

   set_dta (&dta);

   if (locator[0] == BFT_FIRST)
   {
      getpath (path);
      expand_path (path, data_ptr->expand_dirname, entryname);
      sprintf (path, "%s\\%s", data_ptr->expand_dirname, entryname);
      code = 1;

      if (stpbrk (path, "*?") != NULL)
      {
         code = findfirst (path);
         sprintf (path, "%s\\%s", data_ptr->expand_dirname, dta.name);
      }
   }
   else
   {
      code = findnext ();
      sprintf (path, "%s\\%s", data_ptr->expand_dirname, dta.name);
   }

   if (code == 0)
      path[0] = '\0';

/* Send the absolute path to MU:FULL_PC_PATH */

   message[0] = 0;
   message_len = 0;
   message_len = addtoken (message, message_len, path, strlen (path));
   message_len = addtoken (message, message_len, request_id, 0);
   message_len = addtoken (message, message_len, direction, 1);
   executeb (FULL_PC_PATH, message, message_len, mcb_ptr);

   return;
}
/*  */
/********************************************************************

     INITIATE_FETCH

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 SOURCE FILE NAME - filename on local system
                 SOURCE FLAGS     - transfer modes

     FUNCTION:   Multics is beginning a PC -> Multics transfer

********************************************************************/

init_fetch (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char  *arg_pos;                       /* argument position */
char  token         [MAXARGSTRING];   /* Argument token */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
char  temp_str      [MAXARGSTRING];   /* arguments to remote routines */
int   temp_len;                       /* length of temp_str */
int   fp_source;                      /* outgoing file pointer */


/* extract the source file */

  arg_pos = arg_string;
  arg_pos = striptok (arg_pos, data_ptr->source_file);
  arg_pos = striptok (arg_pos, token);
  char2long (token, &data_ptr->source_flags);

/* if the file is not there return an error */

  fp_source = open (data_ptr->source_file, O_RDONLY | O_RAW);
  if (fp_source == -1)
  { 
    sprintf (out_str, "%s opening %s.", getsyserr (errno), data_ptr->source_file);
    temp_str[0]=0;
    temp_len = 0;
    temp_len = addtoken (temp_str, temp_len, out_str, 0);
    data_ptr->source_file[0]=0;
    executeb (READ_ERROR, temp_str, temp_len, mcb_ptr);
    return;
  }

/* reset all the input buffers for file input */

  data_ptr->inbuffpos = 0;
  data_ptr->inpos = 0L;
  close(fp_source);

/* Call send data on the local system */

  out_str[0] = 0;
  out_len = 0;
  bftmajcap (SEND_DATA, 0, out_str, out_len, data_ptr, mcb_ptr);
  return;
}
/*  */
/********************************************************************

     INITIATE_STORE

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 DESTINATION FILENAME - the filename that the remote
                                        requests to transfer to.
                 FLAGS                - transfer modes

     FUNCTION:   Multics is beginning a transfer Multics -> PC transfer.

*******************************************************************/

init_store (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char  *arg_pos;                       /* Argumen position */
char  token         [MAXARGSTRING];   /* Stripped token */
char  temp_str      [STRINGSIZE];     /* temp string */
int   temp_len;                       /* length of temp string */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
int   fp_dest;                        /* outgoing file pointer */


/* get the destination filename and transfer flags out of the arglist */

  arg_pos = arg_string;
  arg_pos = striptok (arg_pos, data_ptr->destination_file);
  arg_pos = striptok (arg_pos, token);
  char2long (token, &data_ptr->destination_flags);

/* call remote write error if unable to open the file */

  fp_dest = open (data_ptr->destination_file, O_WRONLY | O_RAW | O_CREAT | O_TRUNC);
  if (fp_dest == -1)
  { 
    sprintf (out_str, "%s opening %s.", getsyserr (errno), data_ptr->destination_file);
    temp_str[0]=0;
    temp_len = 0;
    temp_len = addtoken (temp_str, temp_len, out_str, 0);

    executeb (WRITE_ERROR, temp_str, temp_len, mcb_ptr);
    return;
  }

/* make the file the current destination if all is ok */

  data_ptr->outbuffpos = 0;
  close (fp_dest);

/* call SEND_DATA */

  executeb (SEND_DATA, out_str, 0, mcb_ptr);
}
/*  */
/******************************************************************

     POSITION_FILE_POINTER

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 SOURCE FILE NAME - the source file to open
                 FILE SIZE        - position the pointer this many bytes into the file
                 SOURCE FLAGS     - transfer flags

     FUNCTION:   Opens the source file name to the position passed in
                 the file size and then calls send data locally.

********************************************************************/

position_pointer (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char  token[MAXARGSTRING];            /* Token from message */
char  *arg_pos;                       /* Arg list position */
char  temp_str      [STRINGSIZE];     /* temp string */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
int   fp_source;                      /* outgoing file pointer */
int   line_pos;                       /* Line count positioning */
int   i;
int   open_mode;


/* extract the path and and new position */

  arg_pos = arg_string;
  arg_pos = striptok (arg_pos, data_ptr->source_file);
  arg_pos = striptok (arg_pos, token);
  data_ptr->inpos = (long) atoi (token);
  arg_pos = striptok (arg_pos, token);
  char2long (token, &data_ptr->source_flags);

/* if the file is not there return an error */

  open_mode = O_RDONLY;
  if (data_ptr->source_flags & BFT_BINARY)
    open_mode |= O_RAW;
  fp_source = open (data_ptr->source_file, open_mode);
  if (fp_source == -1)
  {
    sprintf (temp_str, "%s opening %s.", getsyserr (errno), data_ptr->source_file);
    out_str[0]=0;
    out_len = 0;
    out_len = addtoken (out_str, out_len, temp_str, 0);
    executeb (READ_ERROR, out_str, out_len, mcb_ptr);
    data_ptr->source_file[0]=0;
    return;
  }

/* position input buffers to the appropriate position in the file */

  data_ptr->inbufflen = 0;
  data_ptr->inbuffpos = 0;

/* Set the input file pointer position to the appropriate line count for ascii mode */

  if (!(data_ptr->source_flags & BFT_BINARY))
  {
    if (count_lines (fp_source, data_ptr->inbuffer, &data_ptr->inpos, &data_ptr->inbufflen, &data_ptr->inbuffpos) == -1)
    {
      sprintf (temp_str, "%s positioning %s.", getsyserr (errno), data_ptr->source_file);
      out_str[0]=0;
      out_len = 0;
      out_len = addtoken (out_str, out_len, temp_str, 0);
      executeb (READ_ERROR, out_str, out_len, mcb_ptr);
      data_ptr->source_file[0]=0;
      close (fp_source);
      return;
    }
  }
  close(fp_source);

/* call send data on the local system */

  out_str[0] = 0;
  out_len = 0;
  bftmajcap (SEND_DATA, 0, out_str, out_len, data_ptr, mcb_ptr);
}
/*  */
/******************************************************************

     RECEIVE_DATA

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 PART OF FILE - x number of bytes sent from the remote.

     FUNCTION:   Writes out x number of bytes to the destination file.
                 if any error has occured then remote write error is called
                 otherwise send data is called on the remote.

********************************************************************/

rec_data (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
int   i;                              /* temporary vars */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
char  temp_str      [MAXARGSTRING];   /* arguments to remote routines */
int   temp_len;                       /* length of temp_str */


/* write out the info in the arg_string to the file buffer */

  i = put_data (arg_string, arg_len, data_ptr);

/* if there were any problems then call remote write error */

  if (i != arg_len)
  {
    sprintf (out_str, "%s writing %s.", getsyserr (errno), data_ptr->destination_file);
    temp_str[0]=0;
    temp_len = 0;
    temp_len = addtoken (temp_str, temp_len, out_str, 0);
    executeb (WRITE_ERROR, temp_str, temp_len, mcb_ptr);
    data_ptr->destination_file[0]=0;
    return;
  }

/* otherwise call send data on the remote */

  out_str[0]=0;
  out_len = 0;
  executeb (SEND_DATA, out_str, out_len, mcb_ptr);
  return;
}
/*  */
/******************************************************************

     RECEIVE_EOF

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST: - none

     FUNCTION:   Writes out any remaining bytes in the output buffer
                 to the file, the file is closed and and the queue emptied

********************************************************************/

receive_eof (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
int   fp_dest;                        /* incoming file pointer */
int   open_mode;                      /* Opening modes */
int   status;                         /* error codes from reads and writes */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
char  temp_str      [MAXARGSTRING];   /* arguments to remote routines */
int   temp_len;                       /* length of temp_str */


/* open the file for output */

  open_mode = O_RDWR;
  if (data_ptr->destination_flags & BFT_BINARY)
    open_mode |= O_RAW;
  fp_dest = open (data_ptr->destination_file, open_mode);

/* if output file could not be opened call remote write error */

  if (fp_dest == -1)
  {
    sprintf (temp_str, "%s opening %s.", getsyserr (errno), data_ptr->destination_file);
    out_str[0]=0;
    out_len = 0;
    out_len = addtoken (out_str, out_len, temp_str, 0);
    executeb (WRITE_ERROR, out_str, out_len, mcb_ptr);
    return;
  }

/* write out the buffer to the end of the file */

  lseek (fp_dest, 0L, SEEK_EOF);
  status = write (fp_dest, data_ptr->outbuffer, data_ptr->outbuffpos);

/* if any problems writing to the file call remote write error */

  if (status < 0)
  {
    close(fp_dest);
    sprintf (out_str, "%s writing %s", getsyserr (errno), data_ptr->destination_file);
    temp_str[0]=0;
    temp_len = 0;
    temp_len = addtoken (temp_str, temp_len, out_str, 0);
    executeb (WRITE_ERROR, temp_str, temp_len, mcb_ptr);
    return;
  }
  else if (data_ptr->destination_flags & BFT_NOTIFY)
    putbgmes (mcb_ptr, 0, "BFT", "Completed transfer of %s.", data_ptr->destination_file);

/* reset the buffer and close the file */

  data_ptr->outbuffpos = 0;
  close (fp_dest);

/* clean up the destination and check for any remote to local transfers */

  data_ptr->destination_file[0] = 0;

  return;
}
/*  */
/******************************************************************

     READ_ERROR

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 ERROR STRING - an error message describing the problem

     FUNCTION:   A reading error has occurred on Multics.  Remove current
                 store source from the data_block and initiate a store
                 through the remote.

********************************************************************/

read_err (arg_string, arg_len, mcb_ptr, data_ptr)

char *arg_string;                     /* string containing the argument */
int arg_len;                          /* length of the arg string */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char message[MAXARGSTRING];           /* Return message */
int  message_len;                     /* Return message length */


/* Display the error */

  message_len = (arg_len > WSPAKSIZ) ? WSPAKSIZ : arg_len;
  strncpy (message, arg_string, message_len);
  message[message_len] = 0;
  putbgmes (mcb_ptr, 0, "BFT", message);

/* Close the destination file */

  data_ptr->destination_file[0] = 0;

/* Initiate another store */

  message[0] = 0;
  message_len = 0;
  executeb (INITIATE_STORE, message, message_len, mcb_ptr);
}
/*  */
/******************************************************************

     WRITE_ERROR

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST:
                 ERROR STRING -  error message describing the problem

     FUNCTION:   clears flags and queues after error, calls putbgmes
                 with the error message and calls check store flags
                 to see if any other transfers can be initiated.

********************************************************************/

write_err (arg_string, arg_len, mcb_ptr, data_ptr)

char *arg_string;                     /* string containing the argument */
int arg_len;                          /* length of the arg string */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
char  message[MAXARGSTRING];          /* Return message */
int   message_len;                    /* Return message length */


/* Display the error */

  message_len = (arg_len > WSPAKSIZ) ? WSPAKSIZ : arg_len;
  strncpy (message, arg_string, message_len);
  message[message_len] = 0;
  putbgmes(mcb_ptr, 0, "BFT", message);

/* Close the source file */

  data_ptr->source_file[0] = 0;

/* Initiate another fetch */

  message[0] = 0;
  message_len = 0;
  executeb (INITIATE_FETCH, message, message_len, mcb_ptr);
}
/*  */
/*******************************************************************

     SEND_DATA

     PARAMETERS: ARG_STRING - string containing the argument (input)
                 ARG_LEN    - length of the arg string (input)
                 MCB_PTR    - pointer to the mowse control block (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     INFO EXTRACTED FROM ARGLIST: - none.

     FUNCTION:   Read in x number of bytes from the source file.
                 if any error has occured then remote read error is called
                 otherwise receive_data is called on the remote.

********************************************************************/

send_data (arg_string, arg_len, mcb_ptr, data_ptr)

int arg_len;                          /* length of the arg string */
char *arg_string;                     /* string containing the argument */
mcb *mcb_ptr;                         /* pointer to the mowse control block */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
int   i;                              /* temporary vars */
char  out_str       [MAXARGSTRING];   /* arguments to remote routines */
int   out_len;                        /* length of out_str */
char  temp_str      [MAXARGSTRING];   /* temp messages */


/* read in some of the file from the input buffer */

  i = get_data(out_str,BUFFSIZE,data_ptr);
  out_str[i]=0;
  out_len = 0;

/* if there are more characters then call receive data */

  if (i>0)
  {
    out_len = i;
    executeb(REC_DATA,out_str,out_len,mcb_ptr);
    return;
  }

/* if there are no more characters then call receive eof */

  else if (i==0)
    executeb(REC_EOF,out_str,out_len,mcb_ptr);

/* if there was an error reading from the buffer call remote read error */

  else 
  {
    sprintf (temp_str, "%s reading %s.", getsyserr (errno), data_ptr->source_file);
    out_str[0]=0;
    out_len = 0;
    out_len = addtoken (out_str, out_len, temp_str, 0);
    executeb (READ_ERROR, out_str, out_len, mcb_ptr);
  }

  data_ptr->source_file[0]=0;
}
/*  */
/******************************************************************

     REQUEST DISCONNECT

     PARAMETERS: DATA_PTR   - pointer to BFT data structure (input)
                 SENDER     - major capability number of the calling routine (input)

     INFO EXTRACTED FROM ARGLIST: - none.

     FUNCTION:   Shuts BFT down.

********************************************************************/

disconnect_request (mcb_ptr,sender)

mcb  *mcb_ptr;                               /* BFT's MOWSE Control Block */
int  sender;                                 /* Who sent this message */
{
  disresp (WSACCEPT, sender, mcb_ptr);
  destinst (&mcb_ptr);
}
/*  */
/******************************************************************

     RESPONSE DISCONNECT

     PARAMETERS: MCB_PTR    - pointer to the mowse control block (input)

     INFO EXTRACTED FROM ARGLIST: - none.

     FUNCTION:   Shuts BFT down.

********************************************************************/

disconnect_response (mcb_ptr)

mcb  *mcb_ptr;                                /* MOWSE Control block */
{
  destinst(&mcb_ptr);
}
/*  */
/******************************************************************

     EXECUTE COMMAND REPLY

     PARAMETERS: NONE.

     INFO EXTRACTED FROM ARGLIST: NONE

     FUNCTION:   Handler for the execute command reply. Currently
                 ignored.

********************************************************************/

execute_command_reply()
{
  return;
}
/*  */
/*********************************************************************

     INTERNAL FUNCTIONS

**********************************************************************/
/*  */
/*********************************************************************

     GET_DATA

     PARAMETERS: BUFFER     - Pointer to a character string (input)
                 LENGTH     - The number of bytes to try to read in (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     FUNCTION:   Tries to read in "length" bytes from the file into
                 buffer and returns the actual number of bytes read

     WARNINGS:   If a file is opened as ASCII, then the ^Z character
                 indicates to read an EOF.  If there are more characters
                 after the ^Z, then they will NOT be transferred.

**********************************************************************/

int get_data (buffer, length, data_ptr)

int length;                           /* the number of bytes to try to read in */
char *buffer;                         /* pointer to a character string */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
int fp_source;                        /* file descriptor to source file */
int status;                           /* error code returned from reads */
int i;                                /* temporary variable*/
int open_mode;                        /* Opening mode of file */
long file_pos;


/* if the buffer is empty then read a chunk */

   if (data_ptr->inbuffpos == 0)
   {
     open_mode = O_RDONLY;
     if (data_ptr->source_flags & BFT_BINARY)
       open_mode |= O_RAW;
     fp_source = open (data_ptr->source_file, open_mode);

/* if the source file cant be opened return an error */

     if (fp_source == -1)
       return (-1);

/* seek to the correct spot in the file */

    file_pos = lseek (fp_source, data_ptr->inpos, SEEK_START);
    if (file_pos == -1L)
    {
      close (fp_source);
      return (-1);
    }

/* if the read fails give an error message */

    status = read (fp_source, data_ptr->inbuffer, DISKBUFF);
    if (status < 1)
    {
      close (fp_source);
      return (status);
    }

/* set pointers to correct places and close files */

    data_ptr->inpos = lseek (fp_source, 0L, SEEK_CURRENT);
    data_ptr->inbufflen = status;
    close (fp_source);
  }

/* determine actual length of the buffer that will be returned */

  if ((data_ptr->inbuffpos + length) > data_ptr->inbufflen)
    length = data_ptr->inbufflen - data_ptr->inbuffpos;

/* copy portion of the file from the input buffer to the arg */

  for (i=0;i<length;i++)
    buffer[i] = data_ptr->inbuffer[i+data_ptr->inbuffpos];

/* set input buffer pointer to point to next portion of the file */

  if ((data_ptr->inbuffpos + length) == data_ptr->inbufflen)
    data_ptr->inbuffpos = 0;
  else
    data_ptr->inbuffpos = data_ptr->inbuffpos + length;

  return (length);
}
/*  */
/********************************************************************

     PUT_DATA

     PARAMETERS: BUFFER - Pointer to a character string (input)
                 LENGTH - The number of bytes to try to write out (input)
                 DATA_PTR   - pointer to BFT data structure (input)

     FUNCTION:   Tries to write out length bytes from the buffer into
                 the file and returns the actual number of bytes
                 written.

**********************************************************************/

put_data (buffer, length, data_ptr)

int length;                           /* the number of bytes to try to write out */
char *buffer;                         /* pointer to a character string */
bft_data_ptr data_ptr;                /* pointer to BFT data structure */
{
int fp_dest;                          /* file descriptor to source file */
int status;                           /* error code returned from reads */
int i;                                /* temporary variable */
char temp_str[100];
int  open_mode;                       /* Opening modes */
long file_pos;


/* if the incoming data will overflow the buffer then write the buffer out */

  if ((data_ptr->outbuffpos+length ) > DISKBUFF)
  {
    open_mode = O_RDWR;
    if (data_ptr->destination_flags & BFT_BINARY)
      open_mode |= O_RAW;
    fp_dest = open (data_ptr->destination_file, open_mode);
    if (fp_dest == -1)
      return (-1);

/* seek to the write position in the file */

    if (data_ptr->outpos == 0)
      file_pos = lseek (fp_dest, 0L, SEEK_EOF);
    else
    { 
      file_pos = lseek (fp_dest, data_ptr->outpos, SEEK_START);
      data_ptr->outpos = 0;
    }
    if (file_pos == -1L)
    {
      close (fp_dest);
      return (-1);
    }

/* if the write was unsuccessful then return with an error code */

    status = write (fp_dest, data_ptr->outbuffer, data_ptr->outbuffpos);
    if (status < 1)
    {
      close (fp_dest);
      return (status);
    }

    data_ptr->outbuffpos = 0;
    close (fp_dest);
  }


/* copy data passed to put_data into the output buffer */

  for (i=0;i<length;i++)
    data_ptr->outbuffer[i+data_ptr->outbuffpos] = buffer[i];

  data_ptr->outbuffpos += length;

  return (length);
}
/*  */
/********************************************************************

     EXECUTEB

     PARAMETERS: MINUM      - Minor capability number to execute (input)
                 ARG_STRING - The arguments passed to the minor (input)
                 ARG_LEN    - The length of the argument string (input)
                 MCB_PTR    - A pointer to the mowse control block (input)

     FUNCTION:   Executes the specified minor capability on the
                 specified system with the specified arguments.

**********************************************************************/

executeb (minum, arg_string, arg_len, mcb_ptr)

int minum;                   /* minor capability number to call */
int arg_len;                 /* length of the arg string */
mcb *mcb_ptr;                /* pointer to the mowse control block */
char *arg_string;            /* string containing the arguments */
{
int majnum;
int code;


  majnum = 0;
  if ((code = findnumb ("bft_main_", WSREMOTE, &majnum)) != 0)
  {
    putbgmes (mcb_ptr, code, "BFT", "Finding Multics BFT capability.");
    return(0);
  }
  else
     return (execap (majnum, minum, arg_string, arg_len, mcb_ptr));
}
/*  */
/********************************************************************

     EXPAND_PATH

     PARAMETERS:
          PATH      - path to breakdown.   (input)
          DIRNAME   - directory component. (output)
          ENTRYNAME - entry component.     (output)

     FUNCTION:   Initiate a traversal of a directory for pattern matching
                 on filenames.

********************************************************************/

expand_path (path, dirname, entryname)

char *path;                            /* Path to expand */
char *dirname;                         /* Directory component */
char *entryname;                       /* Entryname component */
{
int  i;
int  indx;                             /* Length of directory component */
char token[MU_ENTRYNAME_SIZE];         /* Entryname component component */
char *sp;                              /* String pointer */


   for (i = 0, indx = 0; path[i] != '\0'; i++)
   {  
      if (path[i] == '\\')
         indx = i;
   }

/* Dirname */

   indx = (indx <= PATHNAMESIZE) ? indx : PATHNAMESIZE;
   strncpy (dirname, path, indx);

/* First component of entryname XXX.xxx */

   sp = &(path[indx+1]);
   sp = stptok (sp, token, sizeof (token), ".");
   strncpy (entryname, token, 8);

/* Another component? Then copy in the break, and skip the break char */

   if (*sp == '.')
   {
      sp += 1;
      strcat  (entryname, ".");
   }

/* Second component of entryname xxx.XXX */

   sp = stptok (sp, token, sizeof (token), ".");
   if (strlen (token) > 0)
      strncat (entryname, token, 3);
}
/*  */
/********************************************************************

     FINDFIRST

     PARAMETERS: STR - path spec to initiate traversal

     FUNCTION:   Initiate a traversal of a directory for pattern matching
                 on filenames.

********************************************************************/

findfirst(str)

short str;
{
union REGS sysregs;
int code;

   sysregs.h.ah = DOS_STAR_FIRST;
   sysregs.x.cx = 0;
   sysregs.x.dx = str;
   code = intdos (&sysregs,&sysregs);
   code &= 01;
   return (!code);
}
/*  */
/********************************************************************

     FINDNEXT

     FUNCTION:   Continue on traversal of file matching.

********************************************************************/

findnext()
{
union REGS sysregs;
int code;

    sysregs.h.ah = DOS_STAR_NEXT;
    code = intdos (&sysregs,&sysregs);
    code &= 01;
    return (!code);
}
/*  */
/********************************************************************

     SET_DTA

     ARGUMENTS: OFFSET - Address of dta structure.

     FUNCTION:  Set the DTA address to mine so I can reference it.

********************************************************************/

set_dta (offset)

short offset;                          /* DTA structure */
{
union REGS sysregs;

   sysregs.h.ah = DOS_SET_DTA;
   sysregs.x.dx = offset;
   intdos (&sysregs,&sysregs);
}




		    subrs.c                         02/24/88  0848.7rew 02/24/88  0845.0      162378



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1987 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(86-10-31,Rohs), approve(87-07-13,MCR7580), audit(87-07-13,Leskiw),
     install(87-08-07,MR12.1-1072):
     Created.
  2) change(87-10-04,Flegel), approve(87-10-04,MCR7787),
     audit(88-01-26,DGHowe), install(88-02-24,MR12.2-1028):
     Implemented multiple queue entry strategy with Multics as the controller.
                                                   END HISTORY COMMENTS */

/* COMPILER: Lattice C, V2.15 */

/**************************************************************

     SUBRS.C

     This file contains the various support routines for BFT.

***************************************************************/

#include <stdio.h>
#include <dos.h>
#include <mowse.h>
#include <bft.h>

/* DOS Function calls */

#define DOS_GET_DRIVE     0x1900               /* Get current drive */
#define DEFAULT_DRIVE     0x4700               /* Default drive mask */

/* Masks */

#define CHAR_MASK         0xFF                 /* Zero non-char bits */

/**/
/***************************************************************

     ADDTOKEN

     PARAMETERS: ARGLIST   - a pointer to a string into which the token is 
                             to be placed. (input,output)
                 ARGLEN    - current length of arg string. If 0, then assume 
                             NULL terminated.  (input)
                 TOKEN     - a pointer to a string in which the input token 
                             resides. (input)
                 TOKEN_LEN - length of token.  If 0, then assume NULL 
                             terminated.  (input)

     FUNCTION:   Places a token at the end of the arglist followed by 
                 the DELIMITER character and returns the length of the 
                 arglist.

***************************************************************/

addtoken (p_arglist, p_arg_len, p_token, p_token_len)

char *p_arglist;       /* pointer to string to add the token to */
int  p_arg_len;        /* length of arg_list */
char *p_token;         /* pointer string where token is placed */
int  p_token_len;      /* length of token */
{
int arg_pos;           /* append position in arg_list */
int token_len;         /* actual length of token */
int i;

/* Determine actual lengths */

  arg_pos = (p_arg_len > 0) ? p_arg_len : strlen (p_arglist);
  token_len = (p_token_len > 0) ? p_token_len : strlen (p_token);

/* Append the token to the arg_list */

  for (i = 0; i < token_len; i++, arg_pos++)
    p_arglist[arg_pos] = p_token[i];

/* Append the delimeter */

  for (i = 0; i < strlen (DELIMITER); i++, arg_pos++)
    p_arglist[arg_pos] = DELIMITER[i];
  p_arglist[arg_pos] = 0;

/* Return the next position */

  return (arg_pos);
}
/**/
/***************************************************************

     BFTCAN

     PARAMETERS: ID    - request identifier of cancellation
                       - either PATH or ID
                 ID_SW - PATH_ID || TIME_ID || ENTRY_ID

     FUNCTION:   Performs the call to execute capability for
                 the cancel command.

*****************************************************************/

bftcan (p_id_sw, p_id)

int  p_id_sw;                           /* ID Type */
char *p_id;                             /* ID string */
{
char arg_string[MAXARGSTRING];          /* Message */
int  arg_len;                           /* Message length */
char token[PATHNAMESIZE];               /* Message portion */
char id_sw;                             /* Character version of ID type */

/* Verify the request id type */

  id_sw = (char)p_id_sw;
  if (!((id_sw == BFT_PATH_ID) || (id_sw == BFT_TIME_ID) || (id_sw == BFT_ENTRY_ID)))
    return (BFT_BAD_REQUEST_ID);

/* If the request type is a path, then expand the pathname */

  strncpy (token, p_id, PATHNAMESIZE);
  if (id_sw == BFT_PATH_ID)
    getpath (token);

/* make the arglist for the cancel operation: ID; */

  arg_string[0] = 0;
  arg_len = 0;
  arg_len = addtoken (arg_string, arg_len, &id_sw, 1);
  arg_len = addtoken (arg_string, arg_len, token, 0);

/* execute the CANCEL_REQUEST capability */

  return (execute (CANCEL_REQUEST, WSREMOTE, arg_string, arg_len));
}
/**/
/***************************************************************

     BFTFETCH

     PARAMETERS: MU_PATH  - source file name (input)
                 PC_PATH  - destination file name (input)
                 FLAGS    - transfer modes
                 PRIORITY - transfer priority

     FUNCTION:   Performs the call to execute capability for
                 the fetch command.

*****************************************************************/

bftfetch (p_mu_path, p_pc_path, p_flags, p_priority)

char *p_mu_path;                      /* source file name */
char *p_pc_path;                      /* destination file name */
long p_flags;                         /* Transfer modes */
int  p_priority;                      /* Transfer priority */
{
char arg_string[MAXARGSTRING];        /* holds arguments to be passed to execap  */
int  arg_len;                         /* length of the argument string */
char priority;                        /* Character representation of priority */
char flags[4];                        /* Character representation of flags */
char full_path[PATHNAMESIZE];         /* PC full pathname */
int  i;
int  j;


/* Verify the priority level */

  if ((p_priority < BFT_MIN_PRIORITY) || (p_priority > BFT_MAX_PRIORITY))
     return (BFT_INVALID_PRIORITY);

  priority = (char) p_priority;
  long2char (flags, &p_flags);

/* Expand the PC path to an absolute */

  strncpy (full_path, p_pc_path, PATHNAMESIZE);
  getpath (full_path);

/* make the arglist for the fetch operation: MU_PATH;PC_PATH;FLAGS;PRIORITY */

  arg_string[0] = 0;
  arg_len = 0;
  arg_len = addtoken (arg_string, arg_len, p_mu_path, 0);
  arg_len = addtoken (arg_string, arg_len, full_path, 0);
  arg_len = addtoken (arg_string, arg_len, flags, 4);
  arg_len = addtoken (arg_string, arg_len, &priority, 1);

/* execute the ADD_TO_STORE_QUEUE capability (store is in respect to Multics) */

  return (execute (ADD_TO_STORE_QUEUE, WSREMOTE, arg_string, arg_len));
}
/**/
/***************************************************************

     BFTRECFE

     PARAMETERS: None.

     FUNCTION:   Performs the call to execute capability for
                 the recover fetch command.

*****************************************************************/

bftrecfe ()
{

/* execute the RECOVER_STORE capability to recover PC_to_MULTICS transfers */

  return (execute (REC_STORE, WSREMOTE, NULL, 0));
}
/**/
/***************************************************************

     BFTRECST

     PARAMETERS: none.

     FUNCTION:   Performs the call to execute capability for
                 the recover store command.

*****************************************************************/

bftrecst ()
{

/* execute the RECOVER_FETCH capability to recover MULTICS_to_PC transfers */

  return (execute (REC_FETCH, WSREMOTE, NULL, 0));
}
/**/
/***************************************************************

     BFTSTORE

     PARAMETERS: PC_PATH  - source file name (input)
                 MU_PATH  - destination file name (input)
                 FLAGS    - transfer modes
                 PRIORITY - transfer priority

     FUNCTION:   Performs the call to execute capability for
                 the store command.

*****************************************************************/

bftstore (p_pc_path, p_mu_path, p_flags, p_priority)

char *p_pc_path;                      /* source file name */
char *p_mu_path;                      /* destination file name */
long p_flags;                         /* Transfer modes */
int  p_priority;                      /* Transfer priority */
{
char arg_string[MAXARGSTRING];        /* holds arguments to be passed to execap  */
int  arg_len;                         /* length of the argument string */
char priority;                        /* Character representation of priority */
char flags[4];                        /* Character representation of flags */
char full_path[PATHNAMESIZE];         /* PC full pathname */
int  i;
int  j;


/* Verify the priority level */

  if ((p_priority < BFT_MIN_PRIORITY) || (p_priority > BFT_MAX_PRIORITY))
     return (BFT_INVALID_PRIORITY);

  priority = (char) p_priority;
  long2char (flags, &p_flags);

/* Expand the PC path to an absolute */

  strncpy (full_path, p_pc_path, PATHNAMESIZE);
  getpath (full_path);

/* make the arglist for the fetch operation */

  arg_string[0] = 0;
  arg_len = 0;
  arg_len = addtoken (arg_string, arg_len, p_mu_path, 0);
  arg_len = addtoken (arg_string, arg_len, full_path, 0);
  arg_len = addtoken (arg_string, arg_len, flags, 4);
  arg_len = addtoken (arg_string, arg_len, &priority, 1);

/* execute the ADD_TO_FETCH_QUEUE capability (fetch is in respect to Multics) */

  return (execute (ADD_TO_FETCH_QUEUE, WSREMOTE, arg_string, arg_len));
}
/**/
/***************************************************************

     BFTUNLD

     PARAMETERS: none

     FUNCTION:   Unloads BFT from the PC

*****************************************************************/

bftunld ()
{

/* execute the BFT_SHUT_DOWN capability */

  return (execute (BFT_SHUT_DOWN, WSLOCAL, NULL, 0));
}
/*  */
/*******************************************************************

     EXECUTE

     PARAMETERS: MINOR      - Minor capability number to execute
                 SYSTEM     - the system of the capability
                 ARG_STRING - The arguments passed to the minor
                 ARG_LEN    - The length of the argument string

     FUNCTION:   Executes the specified minor capability on the
                 remote system with the specified arguments.

**********************************************************************/

execute (p_minor,p_system,p_arg_string,p_arg_len)

int  p_minor;                  /* minor capability number to call */
int  p_system;                 /* system to execute on */
char p_arg_string[];           /* string containing the arguments */
int  p_arg_len;                /* length of the arg string */
{
mcb *mcb_ptr;                  /* pointer to the mowse control block */
int bftarghandler();
int majnum;
int bft_major;
int code;

/* Find the appropriate bft capability */

  bft_major = 0;
  if (p_system = WSLOCAL)
  {
    if ((code = findnumb ("BFT", WSLOCAL, &bft_major)) != 0)
      return (code);
  }
  else
  {
    if ((code = findnumb ("bft_main_", WSREMOTE, &bft_major)) != 0)
      return (code);
  }

/* create the bft arg analyser instance */

  if ((code = cretinst ("BFT_ARG", bftarghandler, MAXARGSTRING, MAXARGSTRING, 0, &mcb_ptr)) != 0)
    return (code);

/* check to see if BFT_ARG is on the local system */

  majnum = 0;
  if ((code = findnumb ("BFT_ARG", WSLOCAL, &majnum)) != 0)
  {
    destinst (&mcb_ptr);
    return (code);
  }

/* execute the capability */

  if ((code = execap (bft_major, p_minor, p_arg_string, p_arg_len, mcb_ptr)) != 0)
  {
    destinst (&mcb_ptr);
    return (code);
  }

  destinst (&mcb_ptr);
  return (0);
}
/**/
/************************************************************

     BFTARGHANDLER

     PARAMETERS: none.

     FUNCTION:   This is the internal minor capability handler
                 for the BFT argument capability.  It is a NULL
                 routine as nothing is expected of it.

*************************************************************/

bftarghandler ()
{
}
/*  */
/********************************************************************

     CHAR2LONG

     PARAMETERS: STRING - character string with long in it.
                 FLAGS  - long to be coppied into.

     FUNCTION:   Copy the 4 character string into a long.

**********************************************************************/

char2long (p_string, p_flags)

char *p_string;
long *p_flags;
{
int  i;
int  j;
char *flags_ptr;

/* Copy into flags; NOTE that the characters must be coppied in backwards
   as the HIGH character is the LEAST significant */

  flags_ptr = (char *)(p_flags);
  for (i = 0, j = 3; i < 4; i++, j--)
    flags_ptr[j] = p_string[i];
}
/**/
/***********************************************************

     NAME:       GETPATH

     PARAMETERS: RELPATH- A pointer to a string which
                          contains the relative pathname
                          (input,output)

     FUNCTION:   Expands the relative pathname into an
                 absolute pathname.
*************************************************************/

getpath (relpath)
char *relpath;                            /* relative pathname to be made absolute */
{
union REGS inregs;                        /* input registers for DOS calls  */
union REGS outregs;                       /* output registers for DOS calls */
char abspath[PATHNAMESIZE+ENTRYNAMESIZE]; /* absolute pathname */
char tok[PATHNAMESIZE];                   /* token parsed out of the relative path */
char *parseptr;                           /* pointer to path while parsing */
char *stptok();                           /* token stripping routine */
int  relindex;                            /* pointer to characters in the pathname */


/* Set the drive spec */

  if (relpath[1] != ':')
  {
    relindex = 0;
    inregs.x.dx = 0;
    inregs.x.ax = DOS_GET_DRIVE;
    intdos (&inregs,&outregs);
    abspath[0] = (char) ((outregs.x.ax & CHAR_MASK)+ (int)'A');
    abspath[1] = ':';
  }
  else
  {
    strncpy(abspath,relpath,2);
    outregs.x.ax = toupper(relpath[0]) - (int)'A';
    relindex=2;
  }

/* set the pathname, user may have already given an absolute one */

  if (relpath[relindex]=='\\')
    strcpy (abspath+2,&relpath[relindex]);

  else
  {

/* Set the absolute path to the current working dir */

    abspath[2] = '\\';
    inregs.x.dx = (outregs.x.ax & CHAR_MASK) + 1;
    inregs.x.ax = DEFAULT_DRIVE;
    inregs.x.si = (short) (&abspath[3]);
    intdos (&inregs,&outregs);

/* Traverse each name in the relative path figuring out what to do with the absolute path */

    parseptr = &(relpath[relindex]);
    while ((parseptr < (relpath + strlen (relpath)))&&(strlen (abspath) < PATHNAMESIZE))
    {
      parseptr = stptok (parseptr, tok, PATHNAMESIZE, "\\") + 1;

/* if the token is not ".." then tack the dir to the end of the abspath, else back up */

      if (strcmp (tok, ".."))
      {
        if (abspath[strlen (abspath) - 1] != '\\')
          strcat (abspath, "\\");

        strncat (abspath, tok, strlen(tok));
      }
      else
      {
        relindex = strlen(abspath) - 1;
        while ((abspath[--relindex] != '\\')&&(relindex != 2));
        abspath[relindex]=0;
      }
    }
  }

/* make the pathname uppercase */

  for (relindex = 0; relindex < strlen (abspath); abspath[relindex] = toupper(abspath[relindex++]));

/* copy the absolute path back to the relative path for return */

  strncpy (relpath, abspath, PATHNAMESIZE);
}
/**/
/***********************************************************

     LONG2CHAR

     PARAMETERS: STRING - character string to put into.
                 NUM    - long to copy

     FUNCTION:   Copy into num into string, NOTE that the 
                 characters must be coppied in backwards
                 as the HIGH character is the LEAST significant.

*************************************************************/

long2char (p_string, p_num)

char *p_string;
long *p_num;
{
char *num_ptr;
int  i;
int  j;

  num_ptr = (char *)(p_num);
  for (i = 0, j = 3; i < 4; i++, j--)
    p_string[i] = num_ptr[j];
}
/**/
/***********************************************************
     NAME:       STRIPQUOTE

     PARAMETERS: STRING - a pointer to a string from which
                          the quotes are to be stripped
                          (input)

     FUNCTION:   If there are leading and trailing quotes
                 on a string then they are removed and a pointer to
                 the new string is returned.
*************************************************************/

char *stripquote (string)

char *string;                         /* input string */
{
char tempstr[PATHNAMESIZE];           /* temporary string */

/* if there are leading and trailing quotes then remove them */

  if (string[0]=='"' && string[strlen(string)-1]=='"')
  {
    strcpy (tempstr,string);
    strncpy(string,tempstr+1,strlen(tempstr)-2);
  }

  return(string);
}
/**/
/***********************************************************

     STRIPTOK

     PARAMETERS: STRING - a pointer to a string from which
                          the token is to be parsed from.
                          (input)
                 TOKEN  - a pointer to a string in which the
                          parsed token is placed. (output)

     FUNCTION:   Gets the next token out of a string (which
                 is separated by the DELIMITER character) and 
                 returns a pointer to the character after the 
                 delimiter.

*************************************************************/

char *striptok (string, token)

char *string;                         /* input string */
char *token;                          /* string where token is placed */
{
int i;                                /* counter variable */

/* find position of delimiter in the source string */

  for (i = 0; string[i] != DELIMITER[0]; i++)
    token[i] = string[i];

  token[i] = 0;

/* return the address of the character after the delimiter */

  return (string + i + 1);
}
/**/
/***********************************************************

     SYSTEM SHUTDOWN

     PARAMETERS: None.

     FUNCTION:   Crash the system.

*************************************************************/

system_shutdown()
{
  fprintf (stderr, "\nBFT:  Fatal error encountered.\n");
}




		    bfterror.c                      02/24/88  0855.2rew 02/24/88  0845.9       38952



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1987 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(87-12-18,Flegel), approve(87-10-04,MCR7787),
     audit(88-01-26,DGHowe), install(88-02-24,MR12.2-1028):
     Created for the building of error messages.
                                                   END HISTORY COMMENTS */

/* COMPILER: Lattice C, V2.15 */

#include <stdio.h>
#include <bft.h>
#include <mowse.h>

/* This error table was created from the standard Lattice C "error.h" */

#define D_SYSERR
char *sys_error_table[] =
     {
          "No error",
          "User is not owner",
          "No such file or directory",
          "No such process",
          "Interrupted system call",
          "I/O error",
          "No such device or address",
          "Arg list is too long",
          "Exec format error",
          "Bad file number",
          "No child process",
          "No more processes allowed",
          "No memory available",
          "Access denied",
          "Bad address",
          "Bulk device required",
          "Resource is busy",
          "File already exists",
          "Cross-device link",
          "No such device",
          "Not a directory",
          "Is a directory",
          "Invalid argument",
          "No more files (units) allowed",
          "No more files (units) allowed for this process",
          "Not a terminal",
          "Text file is busy",
          "File is too large",
          "No space left",
          "Seek issued to pipe",
          "Read-only file system",
          "Too many links",
          "Broken pipe",
          "Math function argument error",
          "Math function result is out of range"
     };

int  sys_error_table_size =
     {
          sizeof (sys_error_table) / sizeof (sys_error_table[0])
     };

/* This error table is created from the error codes in "BFT.H" */

#define D_BFTERR
char *bft_error_table[] =
     {
          "No error",
          "Invalid priority",
          "Invalid minor capability",
          "Bad command argument",
          "Bad option to argument",
          "Argument expected",
          "No argument",
          "Invalid request id type",
          "Bad pathname specified",
          "Incomaptible control args"
     };

int  bft_error_table_size =
     {
          sizeof (bft_error_table) / sizeof (bft_error_table[0])
     };
/**/
/***************************************************************

     BFTERROR

     PARAMETERS: CODE      - Error code.
                 MESSAGE   - Error message.
                 MCB_PTR   - NULL if it is a stderr, otherwise a BG message.

     FUNCTION:   Display an error message to the stderr switch.

*****************************************************************/

bfterror (p_code, p_message, p_mcb_ptr)

int  p_code;                           /* Error code */
char p_message[];                      /* Error message */
mcb  *p_mcb_ptr;
{
char error_message[MAXARGSTRING];      /* Message generated */


  if (p_code == 0)
    return (p_code);

  if (issyserr (p_code))
  {
    strcpy (error_message, getsyserr (p_code));
  }
  else if (isbfterr (p_code))
  {
    strcpy (error_message, bft_error_table[p_code-BFT_BASE_ERROR]/*getbfterr (p_code)*/);
  }
  else switch (p_code)
  {
    case (WSINVBUF):
      strcpy (error_message, "Invalid buffer size");
      break;

    case (WSCNTCRE):
      strcpy (error_message, "Can't create instance");
      break;

    case (WSINVNAM):
      strcpy (error_message, "Invalid entry name");
      break;

    case (WSNOTACT):
      strcpy (error_message, "MOWSE not active");
      break;

    case (WSNOTRES):
      strcpy (error_message, "MOWSE is not resident");
      break;

    case (WSINVSYS):
      strcpy (error_message, "Invalid system");
      break;

    case (WSINVMCB):
      strcpy (error_message, "Invalid MCB pointer");
      break;

    default:
      sprintf (error_message, "Error %d", p_code);
      break;
  }

  if (p_mcb_ptr != NULL)
    putbgmes (p_mcb_ptr, 0,"BFT", "%s.  %s", error_message, p_message);
  else
    fprintf (stderr, "BFT: %s.  %s\n", error_message, p_message);

  return (p_code);
}



		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
