[comp.sources.amiga] v89i175: net - network

page%swap@Sun.COM (Bob Page) (09/15/89)

Submitted-by: sas!walker@mcnc.org (Doug Walker)
Posting-number: Volume 89, Issue 175
Archive-name: devices/net.2

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	handler/device.c
#	handler/devio.c
#	handler/dir.c
#	handler/file.c
#	handler/handler.h
#	handler/io.c
#	handler/lock.c
#	handler/main.c
# This is archive 2 of a 4-part kit.
# This archive created: Fri Sep 15 00:24:30 1989
if `test ! -d handler`
then
  mkdir handler
  echo "mkdir handler"
fi
echo "extracting handler/device.c"
sed 's/^X//' << \SHAR_EOF > handler/device.c
X/* Device.c - Device support routines */
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "handler.h"
X
X#define MYNAME "\7NETWORK"
X
Xtypedef struct FileSysStartupMsg *FSSM;
X
Xint GetDevice (global, myfssmsg)
XGLOBAL global;    
XFSSM myfssmsg;
X{
XFSSM  fssmsg;
Xint   devnum;
Xchar  *defaultdev = "serial.device";
X
XBUGP("GetDevice entry")
X
X   BUG(("devname:%s\n",global->n.devname));
X   BUG(("Global->node = %08lx Global->node->dn_Startup = %08lx\n",
X         global->node, BADDR(global->node->dn_Startup)));
X
X   /* Did they give us any information in the device list ? */
X   if( (fssmsg = (FSSM)BADDR(global->node->dn_Startup)) == NULL)
X   {
XBUGP("Null FSSM")
X      /* Initialize the device information */
X      global->unitnum = myfssmsg->fssm_Unit = devnum = 0;
X      myfssmsg->fssm_Device          = (ULONG)defaultdev;
X      myfssmsg->fssm_Flags           = 0;
X      BUG(("GetDevice-fssm_Device:%s\n", myfssmsg->fssm_Device));
X      BUG(("GetDevice-fssm_Unit:%ld\n",   myfssmsg->fssm_Unit)); 
X      BUG(("GetDevice-fssm_Flags:%lx\n", myfssmsg->fssm_Flags));
X   }
X   else
X   {
XBUGP("Good FSSM")
X      /* They gave us all the device information in the mountlist */
X      if(fssmsg->fssm_Device != NULL)
X         myfssmsg->fssm_Device  = (ULONG)BADDR(fssmsg->fssm_Device);
X      else
X         myfssmsg->fssm_Device = (ULONG)defaultdev;
X      global->unitnum        =
X      myfssmsg->fssm_Unit    = fssmsg->fssm_Unit;
X      myfssmsg->fssm_Flags   = (ULONG)BADDR(fssmsg->fssm_Flags);
X  
X      BUG(("fssm:%lx\n", fssmsg));
X      BUG(("fssm_Device:%s\n",    fssmsg->fssm_Device));
X      BUG(("fssm_Unit:%ld\n",      fssmsg->fssm_Unit)); 
X      BUG(("fssm_Flags:%lx\n",    fssmsg->fssm_Flags));
X   }
X
XBUGP("GetDevice exit")
X   return(-1);
X}
X
X
X
Xint InitDevice(global)
XGLOBAL global;
X{
X   struct FileSysStartupMsg myfssmsg;
X   int rc;
X
X   BUGP("InitDevice: Enter")
X   BUG(("InitDevice: Enter\n"));
X
X   if (GetDevice(global,&myfssmsg) == NULL)
X   {
X      BUG(("GetDevice Failed \n"));
X      return(0);
X   }
X
X   if(!(global->n.devport=CreatePort(NULL,0)))
X   {
X      BUG(("ERROR: Can't CreatePort\n"));
X      return(0);
X   }
X
X   BUG(("fssm_Device:%s\n", myfssmsg.fssm_Device));
X   BUG(("fssm_Unit:%ld\n",   myfssmsg.fssm_Unit)); 
X   BUG(("fssm_Flags:%lx\n", myfssmsg.fssm_Flags));
X
X   BUGP("Init NetNode")
X
X   /* Initialize NetNode struct for ourselves - at root of netnodes */
X   global->netchain.next = NULL;
X   global->netchain.status = NODE_UP;
X   MBSTR(MYNAME, global->netchain.name);
X   global->netchain.id = 0;
X   global->netchain.ioptr = NULL;
X   global->netchain.RootLock.NetNode = &global->netchain;
X   /* A NULL RDevice indicates this is a lock on the local root */
X   global->netchain.RootLock.RDevice = NULL;
X   global->netchain.RootLock.RPtr = NULL;
X
X   global->numnodes = global->upnodes = 1;
X#ifndef SMALLPACKET
X   MBSTR(MYNAME, global->RP.handler);
X   global->RP.handlerid = 0;  /* Fix this! */
X#endif
X   rc = InitRDevice(global);
X
X   BUGP("InitDevice: Exit")
X
X   return(rc);
X}
X
Xstruct NetNode *AddNode(global, name, ioptr)
XGLOBAL global;
Xchar *name;
XAPTR ioptr;
X{
X   struct NetNode *node;
X
XBUGBSTR("AddNode: Adding ", name);
XBUG(("ioptr is %lx\n", ioptr));
X
X   /* First see if the node's name is unique */
X   for(node=&global->netchain; node; node=node->next)
X   {
X      if(!stricmp(node->name, name))
X      {
X         if(node->status == NODE_UP) global->upnodes--;
X         break;
X      }
X   }
X   if(!node)
X   {
X      BUG(("AddNode: Node not in chain\n"));
X      /* Node is new, add it */
X      if(!(node=(struct NetNode *)DosAllocMem(global, 
X                                       (long)sizeof(struct NetNode))))
X      {
X         BUG(("AddNode: Out of memory!\n"));
X         return(NULL);
X      }
X      /* Chain the node into the list of network nodes */
X      node->next = global->netchain.next;
X      global->netchain.next = node;
X      strcpy(node->name, name);
X      node->devname[0] = '\0';
X      node->id = 0;
X      global->numnodes++;
X      /* Set up dummy lock for lock templating */
X      node->RootLock.NetNode = node;
X      node->RootLock.RDevice = (RPTR)1L; /* For now - Obtain from remote */
X      node->RootLock.RPtr = NULL; /* For always */
X   }
X
X   node->status = (ioptr ? NODE_UP
X                         : (node->status == NODE_UP ? NODE_CRASHED
X                                                    : NODE_DEAD));
X   node->ioptr = ioptr;
X
X   if(node->status == NODE_UP) global->upnodes++;
X
X   return(node);
X}
X
Xint TermDevice(global)
XGLOBAL global;
X{
X   TermRDevice(global, 0);
X   return(1);
X}
SHAR_EOF
echo "extracting handler/devio.c"
sed 's/^X//' << \SHAR_EOF > handler/devio.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
X* |_o_o|\\ Copyright (c) 1988 The Software Distillery.  All Rights Reserved *
X* |. o.| ||          Written by Doug Walker                                 *
X* | .  | ||          The Software Distillery                                *
X* | o  | ||          235 Trillingham Lane                                   *
X* |  . |//           Cary, NC 27513                                         *
X* ======             BBS:(919)-471-6436                                     *
X\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "handler.h"
X
Xint RemotePacket(global, nptr)
XGLOBAL global;
XNETPTR nptr;
X{
X#if DEBUG
X   if(nptr->RDevice == NULL)
X   {
X      BUGR("Bad NPTR to RPacket")
X      BUG(("************ RemotePacket on root! ************\n"));
X      return(1);
X   }
X   else
X      BUG(("RemotePacket: RDevice %lx\n", nptr->RDevice));
X#endif
X
X#ifndef SMALLPACKET
X   global->RP.serverid = nptr->NetNode->id;
X   MBSTR(nptr->NetNode->name, global->RP.server);
X#endif
X   global->RP.RDevice = nptr->RDevice;
X   
X   if(nptr->NetNode->status == NODE_CRASHED) 
X      ReSync(global, nptr->NetNode->ioptr);
X
X   if(nptr->NetNode->status != NODE_UP ||
X      PutRPacket(global, nptr->NetNode->ioptr) || 
X      GetRPacket(global, nptr->NetNode->ioptr))
X   {
X      BUG(("RemotePacket: No connection\n"));
X      if(nptr->NetNode->status == NODE_UP) global->upnodes--;
X      nptr->NetNode->status = NODE_CRASHED;
X      global->pkt->dp_Res1 = NULL;
X      global->pkt->dp_Res2 = ERROR_NODE_DOWN;
X      return(1);
X   }
X   else
X   {
X      BUG(("RemotePacket: Received codes %lx, %lx\n", 
X         global->RP.Arg1, global->RP.Arg2));
X      global->pkt->dp_Res1 = global->RP.Arg1;
X      global->pkt->dp_Res2 = global->RP.Arg2;
X
X      /* The other side may have decided to change our RDevice */
X      nptr->RDevice = global->RP.RDevice;
X      return(0);
X   }
X}
SHAR_EOF
echo "extracting handler/dir.c"
sed 's/^X//' << \SHAR_EOF > handler/dir.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* Directory Manipulation */
X/*  ActCreateDir ActExamine ActExNext ActParent */
X#include "handler.h"
X
X
Xvoid ActCreateDir(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent      */
X/* Arg1 - Lock */
X/* Arg2 - name */
X/* Arg3 (optional) Attributes */
X{
X   struct FileLock *flock;
X   NETPTR nlock;
X
X   BUG(("ActCreateDir\n"));
X
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      /* The idiot is trying to create a directory in NET: */
X      BUG(("ActCreateDir: Can't create dir in NET:, giving up\n"))
X      pkt->dp_Res1 = NULL;
X      pkt->dp_Res2 = ERROR_WRITE_PROTECTED;
X      return;
X   }
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   MBSTR(pkt->dp_Arg2, global->RP.Data);
X   global->RP.Arg3 = pkt->dp_Arg3;
X   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
X   if(global->RP.DLen == 1) global->RP.DLen = 0;
X
X   if(!RemotePacket(global, nlock) && pkt->dp_Res1)
X   {
X      pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock,
X                               (RPTR)pkt->dp_Res1, ACCESS_READ));
X   }
X}
X
X/*-------------------------------------------------------------------------*/
X/* Structure of the FileInfoBlock                                          */
X/* struct FileInfoBlock {                                                  */
X/*    LONG fib_DiskKey;           Location on disk of entry                */
X/*    LONG fib_DirEntryType;      <0 plain file, >0 a directory            */
X/*    char fib_FileName[108];     Null terminated name of file             */
X/*    LONG fib_Protection;        Protection bits for the file             */
X/*    LONG fib_EntryType;         Internal for Dos use                     */
X/*    LONG fib_Size;              Length of file in bytes                  */
X/*    LONG fib_NumBlocks;         Length of file in blocks                 */
X/*    struct DateStamp fib_Date;  File creation date                       */
X/*    char fib_Comment[116];      Comment associated with file             */
X/*    };                                                                   */
X/*-------------------------------------------------------------------------*/
X
Xstatic void PNum U_ARGS((char *, int));
X
X#define UPSPOT  17
X#define TOTSPOT 24
Xstatic char status[] = "\53Network status: xxx of xxx nodes responding";
X
Xstatic void PNum(string, num)
Xchar *string;
Xint num;
X{
X   static char *digits = " 123456789";
X   /* Format a number into 3 character positions of a string */
X   /* Number must be between 1 and 999 inclusive */
X   num %= 1000;
X   string[0] = digits[num/100]; num %= 100;
X   string[1] = digits[num/10];  num %= 10;
X   string[2] = (num ? digits[num] : '0');
X}
X
Xvoid ExDotInfo U_ARGS((GLOBAL, struct FileInfoBlock *));
X
Xvoid ExDotInfo(global, info)
XGLOBAL global;
Xstruct FileInfoBlock *info;
X{
X   BUGBSTR("ExDotInfo for ", info->fib_FileName);
X   strcpy(info->fib_FileName+(info->fib_FileName[0]+1), ".info");
X   info->fib_FileName[0] += 5;
X   info->fib_EntryType =
X   info->fib_DirEntryType = -3;
X   info->fib_Protection = 0L;
X   info->fib_Size = 974;
X   info->fib_NumBlocks = 2;
X   info->fib_Comment[0] = '\0';
X
X   global->pkt->dp_Res1 = DOS_TRUE;
X}
X
X
Xstatic void ExRoot U_ARGS((GLOBAL, struct FileInfoBlock *));
X
Xstatic void ExRoot(global, info)
XGLOBAL global;
Xstruct FileInfoBlock *info;
X{
X   BUG(("ExRoot\n"))
X   /* Examine on the root of NET: */
X   info->fib_DiskKey = (LONG)&global->netchain;
X   info->fib_DirEntryType = info->fib_EntryType = 2;
X   MBSTR(global->netchain.name, info->fib_FileName);
X   info->fib_Protection = 0;
X   info->fib_NumBlocks = global->numnodes;
X   info->fib_Size = 0;
X   info->fib_Date.ds_Days = 3000;  /* Pick a number */
X   info->fib_Date.ds_Minute =
X   info->fib_Date.ds_Tick = 0L;
X   strcpy(info->fib_Comment, status);
X   PNum(info->fib_Comment+UPSPOT, global->upnodes);
X   PNum(info->fib_Comment+TOTSPOT, global->numnodes);
X
X   global->pkt->dp_Res1 = DOS_TRUE;
X}
X
Xstatic void ExRootNext U_ARGS((GLOBAL, struct FileInfoBlock *));
X
Xstatic void ExRootNext(global, info)
XGLOBAL global;
Xstruct FileInfoBlock *info;
X{
X   struct NetNode *node;
X
X   /* Examine next in the root of NET: */
X   BUG(("ExRootNext\n"))
X
X   node = (struct NetNode *)info->fib_DiskKey;
X
X   /* If the node name is the same length as the filename, we haven't */
X   /* returned the exnext of the .info file yet;  do so               */
X   if(node != &global->netchain && 
X      info->fib_FileName[0] > 0 &&
X      node->name[0] == info->fib_FileName[0])
X   {
X      ExDotInfo(global, info);
X      return;
X   }
X
X#if 0
X   for(node=node->next; 
X       node && node->status != NODE_UP;
X       node=node->next);
X#else
X   node = node->next;
X#endif
X
X   if(!node)
X   {
X      global->pkt->dp_Res1 = DOS_FALSE;
X      global->pkt->dp_Res2 = ERROR_NO_MORE_ENTRIES;
X      BUG(("Returning ERROR_NO_MORE_ENTRIES\n"));
X      return;
X   }
X   
X   info->fib_DiskKey = (LONG)node;
X   info->fib_DirEntryType = info->fib_EntryType = 2;
X   MBSTR(node->name, info->fib_FileName);
X   BUGBSTR("ExNext: Filename is ", info->fib_FileName);
X   info->fib_Protection = 0L;
X   info->fib_NumBlocks = 1;
X   info->fib_Size = 0;
X   info->fib_Date.ds_Days = 3000;
X   info->fib_Date.ds_Minute =
X   info->fib_Date.ds_Tick = 0L;
X   info->fib_Comment[0] = '\0';
X
X   global->pkt->dp_Res1 = DOS_TRUE;
X}
X
Xvoid ActExamine(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X/* Arg1: Lock of object to examine */
X/* Arg2: FileInfoBlock to fill in */
X{
X   NETPTR nlock;
X   struct FileLock *flock;
X   struct FileInfoBlock *info;
X
X   BUG(("ActExamine/ActExNext\n"));
X   
X   info = (struct FileInfoBlock *)pkt->dp_Arg2;
X
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      if(pkt->dp_Type == ACTION_EXAMINE_OBJECT)
X         ExRoot(global, info);
X      else
X         ExRootNext(global, info);
X      return;
X   }
X
X   BUG(("ActEx: Lock %lx on node %s\n",nlock->RPtr,nlock->NetNode->name+1));
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X
X   MQ(info, global->RP.Data, sizeof(struct FileInfoBlock));
X   BUGBSTR("ActEx: filename ", info->fib_FileName);
X
X   global->RP.DLen = sizeof(struct FileInfoBlock);
X
X   if(!RemotePacket(global, nlock))
X   {
X      MQ(global->RP.Data, info, sizeof(struct FileInfoBlock));
X      BUGBSTR("ActEx: Returned filename ", info->fib_FileName);
X   }
X}
X
Xvoid ActParent(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent      */
X/* Arg1 - Lock */
X{
X   struct FileLock *flock;
X   NETPTR nlock;
X
X   BUG(("ActParent\n"));
X
X   /* If this is the root of NET:, return NULL */
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      pkt->dp_Res1 = NULL;
X      return;
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   global->RP.DLen = 0;
X
X   if(RemotePacket(global, nlock)) return;
X      
X   if(pkt->dp_Res1 == NULL)
X   {
X      if(pkt->dp_Res2) return;  /* Error on other side */
X
X      /* Null lock from other side, return a lock on our root */
X      nlock = &global->netchain.RootLock;
X   }
X
X   pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock,
X                          (RPTR)pkt->dp_Res1, ACCESS_READ));
X}
SHAR_EOF
echo "extracting handler/file.c"
sed 's/^X//' << \SHAR_EOF > handler/file.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* File Manipulation  */
X/*  ActDelete ActRename ActSetProtection ActSetComment */
X#include "handler.h"
X
Xvoid ActDelete(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X/* Arg1: Lock	*/
X/* Arg2: Name	*/
X{
X   NETPTR nlock;
X   struct FileLock *flock;
X   BUG(("ActDelete\n"));
X
X   /* Can't delete in the root of NET: */
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      if(ParseName(global, (char *)pkt->dp_Arg2, &nlock, global->RP.Data) || 
X         !nlock)
X      {
X         /* Either he is trying to delete a node or he got the name wrong */
X         pkt->dp_Res1 = DOS_FALSE;
X         pkt->dp_Res2 = (nlock ? ERROR_OBJECT_IN_USE
X                               : ERROR_WRITE_PROTECTED);
X         return;
X      }
X      BUGBSTR("RmtDelete: Sending to node ", nlock->NetNode->name);
X   }
X   else
X      MBSTR(pkt->dp_Arg2, global->RP.Data);
X
X   BUGBSTR("RmtDelete: remote node name =", global->RP.Data);
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
X   if(global->RP.DLen == 1) global->RP.DLen = 0;
X
X   RemotePacket(global, nlock);
X}
X
Xvoid ActRename(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent	*/
X/* Arg1: FromLock	*/
X/* Arg2: FromName	*/
X/* Arg3: ToLock		*/
X/* Arg4: ToName		*/
X{
X   NETPTR nlock, nlock2;
X   struct FileLock *flock;
X   char *tmpchar;
X
X   BUG(("ActRename\n"));
X
X   /* See if it is a local lock */   
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      if(ParseName(global, (char *)pkt->dp_Arg2, &nlock, global->RP.Data) ||
X         !nlock)
X      {
X         /* Trying to rename a node, or something that doesn't exist */
X         pkt->dp_Res1 = DOS_FALSE;
X         pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
X         return;
X      }
X   }
X   else
X      MBSTR(pkt->dp_Arg2, global->RP.Data);
X
X   /* See if the second lock is a local lock */   
X   if((!(flock=(struct FileLock *)pkt->dp_Arg3) || 
X       !(nlock2=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      if(ParseName(global, (char *)pkt->dp_Arg4, &nlock, 
X          global->RP.Data+FILENAMELEN) || !nlock2)
X      {
X         /* See if they are trying to rename a node */
X         if(global->RP.Data[0] == 1 && global->RP.Data[1] == ':')
X         {
X            tmpchar = global->RP.Data+FILENAMELEN;
X            if(tmpchar[0] > RNAMELEN) tmpchar[0] = RNAMELEN;
X            MBSTR(tmpchar, nlock->NetNode->name);
X         }
X         else
X         {
X            pkt->dp_Res1 = DOS_FALSE;
X            pkt->dp_Res2 = (nlock2 ? ERROR_OBJECT_EXISTS
X                                   : ERROR_RENAME_ACROSS_DEVICES);
X         }
X         return;
X      }
X   }
X   else
X      MBSTR(pkt->dp_Arg4, global->RP.Data+FILENAMELEN);
X
X   /* Check for rename across devices */
X   if(nlock->NetNode != nlock2->NetNode)
X   {
X      pkt->dp_Res1 = DOS_FALSE;
X      pkt->dp_Res2 = ERROR_RENAME_ACROSS_DEVICES;
X      return;
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   global->RP.Arg3 = (LONG)nlock2->RPtr;
X   global->RP.DLen = FILENAMELEN + BSTRLEN(global->RP.Data+FILENAMELEN)+1;
X
X   RemotePacket(global, nlock);
X}
X
Xvoid ActSetProtection(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent */
X/* Arg1: Unused */
X/* Arg2: Lock */
X/* Arg3: Name */
X/* Arg4: Mask of protection */
X{
X   struct FileLock *flock;
X   NETPTR nlock;
X
X   BUG(("ActSetProtection\n"));
X
X   BUGBSTR("File to protect: ", pkt->dp_Arg3);
X
X   if((!(flock=(struct FileLock *)pkt->dp_Arg2) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      /* Local lock - protection not implemented yet */
X      pkt->dp_Res1 = DOS_TRUE;
X      return;
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg2 = (LONG)nlock->RPtr;
X   MBSTR(pkt->dp_Arg3, global->RP.Data);
X   global->RP.Arg4 = pkt->dp_Arg4;
X   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
X   if(global->RP.DLen == 1) global->RP.DLen = 0;
X
X   RemotePacket(global, nlock);
X}
X
Xvoid ActSetComment(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent       */
X/* Arg1: Unused */
X/* Arg2: Lock */
X/* Arg3: Name */
X/* Arg4: Comment */
X{
X   struct FileLock *flock;
X   NETPTR nlock;
X
X   BUG(("ActSetComment\n"));
X
X   BUGBSTR("File to Comment: ", pkt->dp_Arg3);
X   BUGBSTR("New Comment Str: ", pkt->dp_Arg4);
X
X   if((!(flock=(struct FileLock *)pkt->dp_Arg2) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      /* Can't SetComment local nodes */
X      pkt->dp_Res1 = DOS_TRUE;
X      return;
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg2 = (LONG)nlock->RPtr;
X   MBSTR(pkt->dp_Arg3, global->RP.Data);
X   MBSTR(pkt->dp_Arg4, global->RP.Data+FILENAMELEN);
X   global->RP.DLen = FILENAMELEN + BSTRLEN(global->RP.Data+FILENAMELEN)+1;
X
X   RemotePacket(global, nlock);
X}
X
Xvoid ActSetFileDate(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   pkt->dp_Res1 = DOS_FALSE;
X   pkt->dp_Res2 = ERROR_NODE_DOWN;
X}
SHAR_EOF
echo "extracting handler/handler.h"
sed 's/^X//' << \SHAR_EOF > handler/handler.h
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the authors:                                          BBS:      */
X/* | o  | ||   John Toebes     Dave Baker     John Mainwaring                */
X/* |  . |//                                                                  */
X/* ======                                                                    */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "netcomm.h"
X
X/* defines for NetNode status field */
X#define NODE_DEAD    0     /* The node has never been heard from       */
X#define NODE_UP      1     /* The node is up and responding normally   */
X#define NODE_CRASHED 2     /* The node was responding, but is now down */
X
X
X/* There is one NetNode structure for each node in the network.  Within*/
X/* the NetNode structure is a definition for the NetPtr structure.  A  */
X/* NetPtr structure completely describes a FileHandle or Lock on a     */
X/* remote system: The NetNode pointer points to the NetNode struct for */
X/* the appropriate node;  the RDevice field gives the address ON THE   */
X/* REMOTE NODE of the AmigaDOS device to communicate with;  the RPtr   */
X/* field gives the address ON THE REMOTE NODE of the FileHandle or Lock*/
X/* we are dealing with.  To handle the NULL lock, we put an instance of*/
X/* the NetPtr struct in the NetNode struct.  The NetNode field points  */
X/* to the top of the struct, the RDevice field is normal and the RPTR  */
X/* field is NULL.                                                      */
X/* The ioptr field of the NetNode contains information specific to the */
X/* communications driver for the node.  I will eventually also put a   */
X/* pointer to the MsgPort for the driver once I support multiple       */
X/* drivers.                                                            */
Xstruct NetNode
X{
X   struct NetNode *next;      /* Next Net Node in chain                */
X   int status;                /* Last known status - see above         */
X   char name[RNAMELEN+2];     /* Name of remote node                   */
X   char devname[RNAMELEN+2];  /* TEMPORARY - name of remote device     */
X   short id;                  /* ID of remote node (timestamp)         */
X   APTR ioptr;                /* Driver-defined pointer                */
X   /* The NetPtr instance here is a special case - its NetNode pointer */
X   /* points to the root of its own struct, its RPtr pointer is NULL.  */
X   /* It is used when a 'template' NETPTR is needed for the net node.  */
X   struct NetPtr
X   {
X      struct NetNode *NetNode;   /* Ptr to network address information     */
X      RPTR RDevice;              /* Address of remote MsgPort              */
X      RPTR RPtr;                 /* Remote file system's lock/filehandle   */
X   } RootLock;
X};
X
X/* The following typedef is used to represent both remote locks and    */
X/* remote filehandles, since the same information is needed for both.  */
X/* Using a single struct allows us to use it as a parm to RemotePacket */
X/* whether we have a filehandle or a lock.                             */
Xtypedef struct NetPtr *NETPTR;
X
Xtypedef struct global
X   {
X   struct NetGlobal      n;          /* Globals in common with server      */
X   struct RPacket       RP;          /* Data area for remote node          */
X   struct DosPacket     *pkt;        /* the packet we are processing       */
X   struct DeviceNode    *node;       /* our device node                    */
X   struct DeviceList    *volume;     /* currently mounted volume           */
X   struct NetNode       netchain;    /* Head of NetNode struct chain       */
X   int    numnodes;                  /* Number of nodes in the chain       */
X   int    upnodes;                   /* Number of up nodes in the chain    */
X   long   unitnum;
X   }* GLOBAL;
X
X/* file.c */
Xvoid ActDelete        U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActRename        U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActSetComment    U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActSetProtection U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActSetFileDate   U_ARGS((GLOBAL, struct DosPacket *));
X
X/* io.c */
Xvoid ActFindwrite U_ARGS((GLOBAL, struct DosPacket *));
X#define ActFindin ActFindWrite
X#define ActFindout ActFindWrite
Xvoid ActEnd       U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActRead      U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActWrite     U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActSeek      U_ARGS((GLOBAL, struct DosPacket *));
X
X/* dir.c */
Xvoid ActCreateDir U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActExamine   U_ARGS((GLOBAL, struct DosPacket *));
X#define ActExNext ActExamine
Xvoid ActParent    U_ARGS((GLOBAL, struct DosPacket *));
X
X/* main.c */
Xvoid ActSetDebug  U_ARGS((GLOBAL, struct DosPacket *));
X
X/* lock.c */
Xstruct FileLock *CreateLock U_ARGS((GLOBAL, NETPTR /* nlock */, 
X                                    RPTR /* RLock */, LONG /* Access */));
Xvoid FreeLock   U_ARGS((GLOBAL, struct FileLock *));
Xvoid ActLock    U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActDupLock U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActUnLock  U_ARGS((GLOBAL, struct DosPacket *));
Xint ParseName   U_ARGS((GLOBAL, char *, NETPTR *, char *));
Xstruct NetNode *FindNode U_ARGS((GLOBAL, char *));
X
X/* Process.c */
Xvoid ActDie     U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActInhibit U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActFlush   U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActTimer   U_ARGS((GLOBAL, struct DosPacket *));
X
X/* volume.c */
Xvoid ActCurentVol  U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActRenameDisk U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActDiskInfo   U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActInfo       U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActNetKludge  U_ARGS((GLOBAL, struct DosPacket *));
Xvoid ActDiskChange U_ARGS((GLOBAL, struct DosPacket *));
X
X/* device.c */
Xint GetDevice  U_ARGS((GLOBAL, struct FileSysStartupMsg *));
Xint InitDevice U_ARGS((GLOBAL));
Xint TermDevice U_ARGS((GLOBAL));
Xstruct NetNode *AddNode U_ARGS((GLOBAL, char *, APTR));
X
X/* Devio.c */
Xint RemotePacket U_ARGS((GLOBAL, NETPTR));
X
X/* inhibit.c */
Xint inhibit  U_ARGS((struct MsgPort *, long));
Xlong sendpkt U_ARGS((struct MsgPort *, long, long*, long));
X
X/* mount.c */
Xvoid Mount         U_ARGS((GLOBAL, char *));
Xvoid DisMount      U_ARGS((GLOBAL));
X
X/* Requester routine */
Xint  request         U_ARGS((GLOBAL, int, char *));
X#define REQ_MUST    0
X#define REQ_ERROR   1
X#define REQ_GENERAL 2
X
X/* Protocol-specific .c file: net#?.c */
XInitRDevice U_ARGS((GLOBAL));
XTermRDevice U_ARGS((GLOBAL, int));
Xvoid ActNetHello   U_ARGS((GLOBAL, struct DosPacket *));
X
X#include "/proto.h"
X
SHAR_EOF
echo "extracting handler/io.c"
sed 's/^X//' << \SHAR_EOF > handler/io.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* File Access:            */
X/* ActRead ActWrite ActSeek ActWaitForChar    */
X/* ActFindwrite ActFindin ActFindout ActEnd   */
X
X#include "handler.h"
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                 ActRead( global, pkt )                                  */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid ActRead(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X/* Arg1: APTR EFileHandle */
X/* Arg2: APTR Buffer      */
X/* Arg3: Length           */
X{
X   NETPTR nfile;
X   long toread, total, amtread;
X   char *data;
X
X   BUG(("ActRead\n"));
X
X   nfile = (NETPTR)pkt->dp_Arg1;
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nfile->RPtr;
X   global->RP.Arg3 = toread = pkt->dp_Arg3;
X
X   for(data=(char *)pkt->dp_Arg2, total=0L; toread>0; toread-=amtread)
X   {
X      global->RP.DLen = 0;
X      if(RemotePacket(global, nfile))
X         return;
X
X      if ((amtread=global->RP.Arg1) == 0)
X         break;
X
X      if(amtread<0)
X      {
X         BUG(("Read error: codes %lx,m, %lx\n",
X            global->RP.Arg1,global->RP.Arg2));
X         total = global->RP.Arg1;
X         goto AFTER;
X      }
X
X      MQ(global->RP.Data, data, amtread);
X      total += amtread;
X      data += amtread;
X   }
XAFTER:
X   pkt->dp_Res1 = total;
X   pkt->dp_Res2 = global->RP.Arg2;
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                      ActWrite( global, pkt )                            */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
X/* This should probably be changed to look for a confirmation after */
X/* each write in order to notice errors faster - djw                */
X
Xvoid ActWrite(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent       */
X/* Arg1: APTR EFileHandle */
X/* Arg2: APTR Buffer */
X/* Arg3: Length */
X{
X   NETPTR nfile;
X   long towrite, total, amtwrite;
X   char *data;
X
X   BUG(("ActWrite\n"));
X
X   nfile = (NETPTR)pkt->dp_Arg1;
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nfile->RPtr;
X   towrite = pkt->dp_Arg3;
X
X   for(data = (char *)pkt->dp_Arg2, total = 0L; 
X       towrite > 0; 
X       towrite -= amtwrite, data += amtwrite)
X   {
X      amtwrite = min(towrite, NETBUFSIZE);
X      MQ(data, global->RP.Data, amtwrite);
X      global->RP.DLen = global->RP.Arg3 = amtwrite;
X      global->RP.Arg4 = (amtwrite == towrite ? 0 : 1);
X
X      if(RemotePacket(global, nfile) || pkt->dp_Res1 == -1) break;
X
X      total += pkt->dp_Res1;
X   }
X
X   if(pkt->dp_Res1 >= 0) pkt->dp_Res1 = total;
X
X   BUG(("ActWrite: Ending, %d bytes written\n", total));
X}
X
X/*---------------------------------------------------------------------------*/
X/*                                                                           */
X/*                       ActSeek( global, pkt )                              */
X/*                                                                           */
X/*---------------------------------------------------------------------------*/
X
Xvoid ActSeek(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent      */
X/* Arg1: APTR EFileHandle */
X/* Arg2: Position */
X/* Arg3: Mode */
X{
X   NETPTR nfile;
X
X   BUG(("ActSeek\n"));
X
X   nfile = (NETPTR)pkt->dp_Arg1;
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nfile->RPtr;
X   global->RP.Arg2 = pkt->dp_Arg2;
X   global->RP.Arg3 = pkt->dp_Arg3;
X   global->RP.DLen = 0;
X
X   RemotePacket(global, nfile);
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                    ActFindwrite( global, pkt )                          */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid ActFindwrite(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X/* ARG1: FileHandle to fill in */
X/* ARG2: Lock for file relative to */
X/* Arg3: Name of file */
X{
X   struct FileHandle *fh;
X   NETPTR nlock, nfile;
X   struct FileLock *flock;
X
X   BUG(("ActFindwrite\n"));
X   /* Code 1004 - 
X      If file does not exist, open should fail.
X      If file does exist, open with an exclusive lock */
X
X   fh = (struct FileHandle *)pkt->dp_Arg1;
X
X   if((!(flock=(struct FileLock *)pkt->dp_Arg2) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      if(ParseName(global, (char *)pkt->dp_Arg3, &nlock, global->RP.Data) ||
X           !nlock)
X      {
X         /* Can't open files in NET: itself */
X         pkt->dp_Res1 = NULL;
X         pkt->dp_Res2 = (nlock ? ERROR_OBJECT_NOT_FOUND 
X                               : ERROR_OBJECT_WRONG_TYPE);
X         return;
X      }
X   }
X   else
X      MBSTR(pkt->dp_Arg3, global->RP.Data);
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg2 = (LONG)nlock->RPtr;
X   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
X   if(global->RP.DLen == 1) global->RP.DLen = 0;
X
X   if(!RemotePacket(global, nlock) && pkt->dp_Res1 != DOS_FALSE)
X   {
X      BUG(("ActFind: Valid local filehandle = %lx\n", fh));
X      if(!(nfile=(NETPTR)DosAllocMem(global, 
X                     (long)sizeof(struct NetPtr))))
X      {
X         BUG(("******NO MEMORY FOR LOCAL LOCK"));
X         pkt->dp_Res1 = DOS_FALSE;
X         pkt->dp_Res2 = ERROR_NO_FREE_STORE;
X         return;
X      }
X
X      nfile->NetNode = nlock->NetNode;
X      nfile->RDevice = nlock->RDevice;
X      /* Remote filehandle passed back in RP.Arg3 */
X      nfile->RPtr    = (RPTR)global->RP.Arg3;
X
X      fh->fh_Arg1 = (LONG)nfile;
X   }
X#if DEBUG
X   else
X      BUG(("ActFind: Remote file open failed, codes %d %d\n",
X         pkt->dp_Res1, pkt->dp_Res2));
X#endif
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                       ActEnd( global, pkt )                             */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid ActEnd( global, pkt )
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X{
X   NETPTR nfile;
X
X   BUG(("ActEnd\n"));
X
X   nfile = (NETPTR)pkt->dp_Arg1;
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nfile->RPtr;
X   global->RP.DLen = 0;
X
X   RemotePacket(global, nfile);
X
X   DosFreeMem((char *)nfile);
X}
SHAR_EOF
echo "extracting handler/lock.c"
sed 's/^X//' << \SHAR_EOF > handler/lock.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X/* Lock.c - lock manipulation */
X/* ActLock, ActDupLock, ActUnLock */
X
X/*-------------------------------------------------------------------------*/
X/* Structure of a Lock:                                                    */
X/*   struct FileLock {                                                     */
X/*      BPTR fl_Link;             Next lock in the chain of device locks   */
X/*      LONG fl_Key;              Block number of directory or file header */
X/*      LONG fl_Access;           Shared Read (-2) or Exclusive Write (-1) */
X/*      struct MsgPort * fl_Task; Handler process for Lock (Us)            */
X/*      BPTR fl_Volume;           Node in DevInfo structure for Lock       */
X/*      };                                                                 */
X/*-------------------------------------------------------------------------*/
X#include "handler.h"
X
X/* create a lock to be returned */
Xstruct FileLock *CreateLock(global, nlock, RLock, Access)
XGLOBAL global;
XNETPTR nlock;
XRPTR RLock;
XLONG Access;
X{
X   struct FileLock *flock;
X   NETPTR newnlock;
X
X   if(!(flock=(struct FileLock *)
X              DosAllocMem(global, sizeof(struct FileLock))) ||
X      !(newnlock=(NETPTR) DosAllocMem(global, sizeof(struct NetPtr)))
X      )
X      return(NULL);
X
X   flock->fl_Key = (LONG)newnlock;
X   flock->fl_Access = Access;
X   flock->fl_Task = global->n.port;
X   flock->fl_Volume = MKBADDR(global->volume);
X   newnlock->NetNode = nlock->NetNode;
X   newnlock->RDevice = nlock->RDevice;
X   newnlock->RPtr    = RLock;
X
X   /* Link the lock into the lock chain */
X   Forbid();
X   flock->fl_Link = global->volume->dl_Lock;
X   global->volume->dl_Lock = MKBADDR(flock);
X   Permit();
X
X   return(flock);
X}
X
Xvoid FreeLock(global, flock)
XGLOBAL global;
Xstruct FileLock *flock;
X{
X   struct FileLock *current, *next;
X
X   if(!flock) return;
X
X   Forbid();
X   if((current=(struct FileLock *)BADDR(global->volume->dl_Lock)) == flock)
X   {
X      global->volume->dl_Lock = flock->fl_Link;
X      Permit();
X      BUG(("FreeLock: Head lock freed, new head = %lx\n", 
X         global->volume->dl_Lock));
X   }
X   else
X   {
X      for(next=NULL; 
X          current && 
X             (next=(struct FileLock *)BADDR(current->fl_Link)) != flock;
X          current = next);
X
X      if(!next)
X      {
X         Permit();
X         BUG(("****************************************\n"));
X         BUG(("******* Lock not found in chain ********\n"));
X         BUG(("****************************************\n"));
X         return;
X      }
X      else
X      {
X         current->fl_Link = next->fl_Link;
X         Permit();
X         BUG(("Lock found and removed from chain\n"));
X      }
X   }
X
X   /* If RDevice == NULL, we have a dummy nlock, so don't free it */
X   /* Otherwise, free it                                          */
X   if(((NETPTR)flock->fl_Key)->RDevice)
X      DosFreeMem((char *)flock->fl_Key);  /* Free the net lock   */
X
X   DosFreeMem((char *)flock);          /* Free the local lock */
X
X}
X
Xvoid ActLock(global, pkt)
XGLOBAL global;
Xstruct DosPacket      *pkt;      /* a pointer to the dos packet sent       */
X/* Arg1: Lock */
X/* Arg2: Name */
X/* Arg3: Mode: ACCESS_READ, ACCESS_WRITE */
X{
X   NETPTR nlock;
X   struct FileLock *flock;
X
X   BUG(("Action Lock\n"));
X   BUGBSTR("File to lock: ", pkt->dp_Arg2);
X
X   /**********************************************************************/
X   /* If the given lock is on the local root, call the ParseName routine */
X   /* to determine if we need to call the remote nodes.  If ParseName    */
X   /* returns 1, we have a name of the form "NET:" and we should return  */
X   /* a lock on the root of NET:.  If it returns 0, we have a name of    */
X   /* the form "NET:FOO" or "NET:FOO/BAR", etc and we need to call the   */
X   /* remote node specified in the pseudo-lock returned.                 */
X   /**********************************************************************/
X   
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      /* ParseName returns 1 if we are locking the root.  It fills in */
X      /* nlock with a pointer to the pseudolock for the node.  The    */
X      /* pseudolock is kept in the NetNode struct.                    */
X      /* Any leftover parts of the name are left in RP.Data as a      */
X      /* BCPL string.                                                 */
X      if(ParseName(global, (char *)pkt->dp_Arg2, &nlock, global->RP.Data))
X      {
X         BUG(("ActLock: Returning lock on root\n"));
X         /* Return lock on root */
X         /* ParseName has put the pseudolock for the root into nlock */
X         pkt->dp_Res1 = 
X               MKBADDR(CreateLock(global, nlock, NULL, pkt->dp_Arg3));
X         return;
X      }
X      else if(!nlock)
X      {
X         BUG(("ActLock: Couldn't find node\n"));
X         pkt->dp_Res1 = NULL;
X         pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
X         return;
X      }
X#if DEBUG
X      else
X         BUG(("ActLock: got nlock, falling through\n"));
X#endif
X   }
X   else
X   {
X      BUGBSTR("ActLock: Relative open, node ", nlock->NetNode->name);
X      /* We are doing a relative open - put filename in Data */
X      MBSTR(pkt->dp_Arg2, global->RP.Data);
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   global->RP.Arg3 = pkt->dp_Arg3;
X   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
X   if(global->RP.DLen == 1) global->RP.DLen = 0;
X
X   if(!RemotePacket(global, nlock) && pkt->dp_Res1)
X   {
X      BUG(("ActLock: Returned RPTR is %lx\n", pkt->dp_Res1));
X      pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock, 
X                                        (RPTR)pkt->dp_Res1, pkt->dp_Arg3));
X   }
X}
X
Xvoid ActDupLock(global,pkt)
XGLOBAL global;
Xstruct DosPacket      *pkt;      /* a pointer to the dos packet sent       */
X{
X   NETPTR nlock;
X   struct FileLock *flock;
X
X   BUG(("Action DupLock\n"));
X
X   /* If this is a lock on the local root, it is a special case */
X   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
X       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
X   {
X      pkt->dp_Res1 = NULL;
X      if(!flock) return;    /* Dup of null lock is null lock            */
X      goto GETLOCK;         /* Dup of real lock on root is real lock (?)*/
X   }
X
X   global->RP.Type = pkt->dp_Type;
X   global->RP.Arg1 = (LONG)nlock->RPtr;
X   global->RP.DLen = 0;
X
X   if(!RemotePacket(global, nlock) && pkt->dp_Res1)
X   {
XGETLOCK:
X      pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock,
X                                 (RPTR)pkt->dp_Res1, flock->fl_Access));
X   }
X}
X
Xvoid ActUnLock(global, pkt)
XGLOBAL global;
Xstruct DosPacket      *pkt;      /* a pointer to the dos packet sent       */
X{
X   NETPTR nlock;
X   struct FileLock *flock;
X
X   BUG(("Action UnLock\n"));
X
X   if(!(flock = (struct FileLock *)pkt->dp_Arg1))
X   {
X      /* No lock - do nothing */
X      pkt->dp_Res1 = DOS_TRUE;
X      return;
X   }
X
X   /* If this lock exists on a remote node, delete it */
X   if((nlock=(NETPTR)flock->fl_Key)->RDevice)
X   {
X      global->RP.Type = pkt->dp_Type;
X      global->RP.Arg1 = (LONG)nlock->RPtr;
X      global->RP.DLen = 0;
X      RemotePacket(global, nlock);
X   }
X   else
X      pkt->dp_Res1 = DOS_TRUE;
X
X   FreeLock(global, flock);
X}
X
Xint ParseName(global, name, nlock, outname)
XGLOBAL global;
Xchar *name;
XNETPTR *nlock;
Xchar *outname;
X{
X   int len, cur;
X   struct NetNode *node;
X
XBUGBSTR("ParseName: Parsing name ", name);
X
X   for(len=*(name++), cur=0; len && *name != '/'; len--, name++)
X   {
X      if(*name==':')
X         cur=0;
X      else
X         outname[cur++] = *name;
X   }
X   outname[cur] = '\0';
X   if(len>0 && *name == '/') name++, len--;
X
X   if(len <= 1 && cur == 0)
X   {
X      /* It is the root of NET: */
X      *nlock = &global->netchain.RootLock;
X      return(1);
X   }
X
X   /* We have a network node name - find it */
X   node = FindNode(global, outname);
X
X   /* OK, check to see if it is a .info file for a node */
X   if(!node && cur >= 6 && !stricmp(outname+cur-5, ".info"))
X   {
X      outname[cur-5] = '\0';
X      if(node = FindNode(global, outname))
X      {
X         BUG(("Got a .info file for node '%s'\n", outname));
X         name = "Node.rinfo";
X         len = 10;
X      }
X   }
X
X   /* No node found - return null nlock */
X   if(!node)
X   {
X      BUG(("ParseName: No node found, nlock is NULL\n"));
X      *nlock = NULL; 
X   }
X   else
X   {
X      /* Node found - return template lock */
X      *nlock = &node->RootLock;
X      BUGBSTR("ParseName: Sending packet to node ", node->name);
X   }
X
X   /* Move the rest of the name into outname as a BSTR */
X   outname[0] = (char)len+1;
X   outname[1] = ':';
X   if(len) MQ(name, outname+2, len);
X   outname[len+2] = '\0';
X   BUG(("Remote filename: len %d text '%s'\n", (int)*outname, outname+1));
X   return(0);
X}
X
Xstruct NetNode *FindNode(global, name)
XGLOBAL global;
Xchar *name;
X{
X   struct NetNode *node;
X
X   for(node=global->netchain.next; node; node=node->next)
X      if(!stricmp(name, node->name+1)) break;
X
X   return(node);
X}
X
SHAR_EOF
echo "extracting handler/main.c"
sed 's/^X//' << \SHAR_EOF > handler/main.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "handler.h"
X
X/******************************************************************************/
X/******************************************************************************/
X/********************* Dispatch table to handle all packets *******************/
X/******************************************************************************/
X/******************************************************************************/
X#define BP1 1
X#define BP2 2
X#define BP3 4
X#define BP4 8
X
Xtypedef void (*ifuncp)(GLOBAL, struct DosPacket *);
Xstruct LookupTable
X   {
X   ifuncp subr;
X   int flags;
X   };
X
X#define LO_FIRST 0
X#define LO_LAST  34
Xstruct LookupTable lowork[LO_LAST+1] = {
X   { NULL,              0  | 0  | 0  | 0   }, /*  0 - ACTION_NIL           */
X   { NULL,              0  | 0  | 0  | 0   }, /*  1 - Unknown              */
X   { NULL,              BP1| BP2| BP3| 0   }, /*  2 - ACTION_GET_BLOCK     */
X   { NULL,              0  | BP2| BP3| 0   }, /*  3 - Unknown              */
X   { NULL,              BP1| BP2| BP3| 0   }, /*  4 - ACTION_SET_MAP       */
X   { ActDie,            0  | 0  | 0  | 0   }, /*  5 - ACTION_DIE           */
X   { NULL,              0  | 0  | 0  | 0   }, /*  6 - ACTION_EVENT         */
X   { ActCurentVol,      BP1| 0  | 0  | 0   }, /*  7 - ACTION_CURRENT_VOLUME*/
X   { ActLock,           BP1| BP2| 0  | 0   }, /*  8 - ACTION_LOCATE_OBJECT */
X   { ActRenameDisk,     BP1| BP2| 0  | 0   }, /*  9 - ACTION_RENAME_DISK   */
X   { NULL,              0  | 0  | 0  | 0   }, /* 10 - Unknown              */
X   { NULL,              0  | 0  | 0  | 0   }, /* 11 - Unknown              */
X   { NULL,              0  | 0  | 0  | 0   }, /* 12 - Unknown              */
X   { NULL,              0  | 0  | 0  | 0   }, /* 13 - Unknown              */
X   { NULL,              0  | 0  | 0  | 0   }, /* 14 - Unknown              */
X   { ActUnLock,         BP1| 0  | 0  | 0   }, /* 15 - ACTION_FREE_LOCK     */
X   { ActDelete,         BP1| BP2| 0  | 0   }, /* 16 - ACTION_DELETE_OBJECT */
X   { ActRename,         BP1| BP2| BP3| BP4 }, /* 17 - ACTION_RENAME_OBJECT */
X   { NULL,              0  | 0  | 0  | 0   }, /* 18 - ACTION_MORE_CACHE    */
X   { ActDupLock,        BP1| 0  | 0  | 0   }, /* 19 - ACTION_COPY_DIR      */
X   { NULL,              0  | 0  | 0  | 0   }, /* 20 - ACTION_WAIT_CHAR     */
X   { ActSetProtection,  0  | BP2| BP3| 0   }, /* 21 - ACTION_SET_PROTECT   */
X   { ActCreateDir,      BP1| BP2| 0  | 0   }, /* 22 - ACTION_CREATE_DIR    */
X   { ActExamine,        BP1| BP2| 0  | 0   }, /* 23 - ACTION_EXAMINE_OBJECT*/
X   { ActExNext,         BP1| BP2| 0  | 0   }, /* 24 - ACTION_EXAMINE_NEXT  */
X   { ActDiskInfo,       BP1| 0  | 0  | 0   }, /* 25 - ACTION_DISK_INFO     */
X   { ActInfo,           BP1| BP2| 0  | 0   }, /* 26 - ACTION_INFO          */
X   { ActFlush,          0  | 0  | 0  | 0   }, /* 27 - ACTION_FLUSH         */
X   { ActSetComment,     0  | BP2| BP3| BP4 }, /* 28 - ACTION_SET_COMMENT   */
X   { ActParent,         BP1| 0  | 0  | 0   }, /* 29 - ACTION_PARENT        */
X   { NULL,              BP1| 0  | 0  | 0   }, /* 30 - ACTION_TIMER         */
X   { ActInhibit,        0  | 0  | 0  | 0   }, /* 31 - ACTION_INHIBIT       */
X   { NULL,              BP1| 0  | 0  | 0   }, /* 32 - ACTION_DISK_TYPE     */
X   { NULL,              0  | 0  | 0  | 0   }, /* 33 - ACTION_DISK_CHANGE   */
X   { ActSetFileDate,    0  | 0  | 0  | 0   }  /* 34 - ACTION_SET_FILE_DATE */
X      };
X
X#define HI_FIRST 1004
X#define HI_LAST  1008
Xstruct LookupTable hiwork[5] = {
X   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_WRITE  - 1004 */
X   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_INPUT  - 1005 */
X   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_OUTPUT - 1006 */
X   { ActEnd,            0  | 0  | 0  | 0   }, /* ACTION_END         - 1007 */
X   { ActSeek,           0  | 0  | 0  | 0   }  /* ACTION_SEEK        - 1008 */
X   };
X
X#define USER_FIRST 2010
X#define USER_LAST  2012
Xstruct LookupTable userwork[3] = {
X   { ActSetDebug,       0  | 0  | 0  | 0   }, /* ACTION_HANDLER_DEBUG 2010 */
X   { NULL,              BP1| 0  | 0  | 0   }, /* ACTION_SET_TRANS_TYPE2011 */
X   { ActNetHello,       BP1| 0  | 0  | 0   }, /* ACTION_NETWORK_HELLO 2012 */
X   };
X
Xstruct DosLibrary *DOSBase;
X
Xvoid _main(x)
Xchar *x;
X{
X   struct DosPacket   *mypkt;      /* a pointer to the dos packet sent       */
X   int                action;
X   ifuncp             subr;
X   int                flags;
X   struct global      global;
X
X   DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME,0);
X
X   /* Initialize our global data structure */
X   memset((char *)&global, 0, sizeof(struct global));
X   global.n.self   = (struct Process *) FindTask(0L);  /* find myself      */
X   global.n.run    = 1;
X   global.n.port   = &(global.n.self->pr_MsgPort);
X                    /* install our taskid ...   */
X
X
X   /* Initialize the intuitext structures for the requesters we might have   */
X   /* to display                                                             */
X   /* Because we have no scruples we can cheat and do this with a couple of  */
X   /* long word assignments.  We leave the acual C code commented out here   */
X   /* so that if this structure ever changed we will still be able to work   */
X#if 0
X   global.n.line1.FrontPen = global.n.line1.BackPen = -1;
X   global.n.line1.DrawMode = JAM1;
X   global.n.line1.LeftEdge = global.n.line1.TopEdge = 4;
X   global.n.line2 = global.n.line1;
X   global.n.line3 = global.n.line1;
X   global.n.retrytxt = global.n.line1;
X   global.n.canceltxt = global.n.line1;
X#else
X   *(long *)&global.n.line1.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line1.LeftEdge     = 0x00040004L;  /* 4,4  */
X   *(long *)&global.n.line2.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line2.LeftEdge     = 0x0004000EL;  /* 4,14 */
X   *(long *)&global.n.line3.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line3.LeftEdge     = 0x00040018L;  /* 4,24 */
X   *(long *)&global.n.retrytxt.FrontPen  = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.retrytxt.LeftEdge  = 0x00040004L;
X   *(long *)&global.n.canceltxt.FrontPen = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.canceltxt.LeftEdge = 0x00040004L;
X#endif
X   global.n.retrytxt.IText = "Retry";
X   global.n.canceltxt.IText = "Cancel";
X
X   /* since we were started as a non-BCPL module we get sent the parameter */
X   /* packet (ie. parameter packet not in D1) */
X
X   mypkt = taskwait(&global);  /* wait for parameter packet */
X
X   global.n.devname  = (((char *)BADDR(mypkt->dp_Arg1))+1);  /* BSTR name */
X
X   /* get pointer to our device node */
X   global.node = (struct DeviceNode *) BADDR(mypkt->dp_Arg3);
X   global.node->dn_Task = global.n.port;
X
X   InitDevice(&global);
X
X   Mount(&global, NULL);
X
X/*   OpenTimer(&global); */
X
X   mypkt->dp_Res1 = DOS_TRUE;
X   retpkt(&global, mypkt);
X
X/*   PostTimerReq(&global); */
X
X   while(global.n.run)   /* start of the real work */
X   {
X      BUG(("Waiting for packet. . ."));
X      mypkt = taskwait(&global);  /* wait for a packet */
X
X      action = mypkt->dp_Type;
X
X      BUG(("action #%ld\n", action));
X
X      switch (action)
X      {
X
X         case ACTION_NETWORK_KLUDGE:
X            subr = ActNetKludge;
X            flags = (BP1 | BP2);
X            break;
X
X         case ACTION_READ:
X            subr = ActRead;
X            flags = 0;
X            break;
X         case ACTION_WRITE:
X            subr = ActWrite;
X            flags = 0;
X            break;
X
X         case ACTION_SET_RAW_MODE:
X            subr = NULL;
X            flags = 0;
X            break;
X
X         case ACTION_FIND_WRITE:  /* 1004 */
X         case ACTION_FIND_INPUT:  /* 1005 */
X         case ACTION_FIND_OUTPUT: /* 1006 */
X         case ACTION_END:         /* 1007 */
X         case ACTION_SEEK:        /* 1008 */
X            subr = hiwork[action-HI_FIRST].subr;
X            flags = hiwork[action-HI_FIRST].flags;
X            break;
X
X         case ACTION_HANDLER_DEBUG:  /* 2010 */
X         case ACTION_SET_TRANS_TYPE: /* 2011 */
X         case ACTION_NETWORK_HELLO:  /* 2012 */
X            subr = userwork[action-USER_FIRST].subr;
X            flags = userwork[action-USER_FIRST].flags;
X            break;
X
X         default:            
X            if ((action >= LO_FIRST) && (action <= LO_LAST))
X            {
X               subr = lowork[action-LO_FIRST].subr;
X               flags = lowork[action-LO_FIRST].flags;
X            }
X            else
X               subr = NULL;
X      }
X 
X      mypkt->dp_Res1 = DOS_FALSE;
X      mypkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
X
X      if (subr != NULL)
X      {
X         global.n.reply = 1;
X         if (flags & BP1)
X            mypkt->dp_Arg1 <<= 2;
X         if (flags & BP2)
X            mypkt->dp_Arg2 <<= 2;
X         if (flags & BP3)
X            mypkt->dp_Arg3 <<= 2;
X         if (flags & BP4)
X            mypkt->dp_Arg4 <<= 2;
X
X         (*subr)(&global, mypkt);
X
X      }
X#if DEBUG
X      else
X      {
X         BUG(("Unknown packet type %ld\n",mypkt->dp_Type));
X      }
X#endif
X
X      /* Now return the packet to them */
X      if (global.n.reply)
X         retpkt(&global, mypkt);
X  
X      BUG(("-----\n"));
X   }
X
X   /* do our final cleanup */
X   global.node->dn_Task = FALSE; /* zero the taskid field of device node */
X   global.node->dn_SegList = 0;  /* make us be gone */
X
X   DisMount(&global);
X   TermDevice(&global);
X
X   BUGTERM()
X}
X
Xvoid ActSetDebug(global, pkt)  /* ACTION_HANDLER_DEBUG */
XGLOBAL global;
Xstruct DosPacket *pkt;
X/* DP_Arg1 - LONG type/flags 0=nodebug                  */
X/* DP_Arg2 - BPTR FileHandle to do debugging to or NULL */
X/* DP_Res1 - BPTR old filehandle                        */
X{
X   /********************************************************************/
X   /*                                                                  */
X   /* Several possibilities:                                           */
X   /* 1. Arg1 is 0:                                                    */
X   /*       All debugging is turned off.  Arg2 is not looked at.       */
X   /*       Res1 is DOS_TRUE, Res2 is a BPTR to the old filehandle.    */
X   /*                                                                  */
X   /* 2. Arg1 is a special handler-defined code:                       */
X   /*       If the second bit from the top is ON, the code is a special*/
X   /*       debugging command to the handler.  If the handler knows the*/
X   /*       command, it returns DOS_TRUE in Res1.  If it doesn't, it   */
X   /*       returns DOS_FALSE in Res1 and Res2.                        */
X   /*                                                                  */
X   /* 3. Neither of the above:                                         */
X   /*       Arg2 contains a BPTR to a FileHandle to send debugging to. */
X   /*       Note that if this is NULL, debugging will be turned off.   */
X   /*       Res1 contains DOS_TRUE, Res2 contains a BPTR to the old    */
X   /*       debugging FileHandle, which may of course be NULL if no    */
X   /*       debugging was on before.                                   */
X   /*                                                                  */
X   /********************************************************************/
X
X#define DEBUG_SPECIAL 0x40000000   /* Mask for handler-defined dbg type*/
X#define DEBUG_SERVER  0x20000000   /* Mask indicating server command   */
X#define DEBUG_WAIT    0x40000001   /* Wait for debugger to catch us    */
X#define DEBUG_INFO    0x40000002   /* Send transmit info to msgport in */
X                                   /* dp_Arg2                          */
X
X   struct NetNode *netnode;
X   extern BPTR debuglog;
X
X   pkt->dp_Res1 = DOS_TRUE;
X   if(pkt->dp_Arg1 & DEBUG_SPECIAL)
X   {
X      BUG(("ActSetDebug: Special debug packet %lx\n", pkt->dp_Arg1))
X      if(pkt->dp_Arg1 == DEBUG_WAIT)
X      {
X         pkt->dp_Res2 = NULL;
X         cprwait(global);
X      }
X      else if(pkt->dp_Arg1 == DEBUG_INFO)
X      {
X         global->n.infoport = (struct MsgPort *)BADDR(pkt->dp_Arg2);
X         global->n.ntirec.m.mn_Node.ln_Type =
X         global->n.ntitrans.m.mn_Node.ln_Type = NT_MESSAGE;
X         if(!global->n.ntirec.m.mn_ReplyPort)
X            global->n.ntirec.m.mn_ReplyPort =
X            global->n.ntitrans.m.mn_ReplyPort = CreatePort(NULL,0);
X         global->n.inf_rec = global->n.inf_trans = 0L;
X      }
X      else if(pkt->dp_Arg1 & DEBUG_SERVER)
X      {
X         global->RP.Type = ACTION_HANDLER_DEBUG;
X         global->RP.Arg1 = pkt->dp_Arg1 & ~(DEBUG_SERVER|DEBUG_SPECIAL);
X         BUG(("Remote debugging code %lx\n", global->RP.Arg1))
X         for(netnode=global->netchain.next;
X             netnode;
X             netnode=netnode->next)
X         {
X            if(netnode->status == NODE_UP &&
X               netnode->RootLock.RDevice)
X            {
X               RemotePacket(global, &netnode->RootLock);
X            }
X         }
X      }
X      else
X      {
X         pkt->dp_Res1 = 
X         pkt->dp_Res2 = DOS_FALSE;
X      }
X   }
X#if DEBUG
X   else if(pkt->dp_Arg1)
X      pkt->dp_Res2 = initdebug((BPTR)pkt->dp_Arg2);
X   else
X   {
X      pkt->dp_Res2 = debuglog;
X      debuglog = NULL;
X   }
X#endif   
X}
X
X
X
X
SHAR_EOF
echo "End of archive 2 (of 4)"
# if you want to concatenate archives, remove anything after this line
exit