/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
/* |. o.| || Reserved.  This program may not be distributed without the    */
/* | .  | || permission of the authors:                            BBS:    */
/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
/* |  . |//                                                                */
/* ======                                                                  */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Directory Manipulation */
/*  ActCreateDir ActExamine ActExNext ActParent */
#include "handler.h"


void ActCreateDir(global,pkt)
GLOBAL global;
struct DosPacket *pkt;              /* a pointer to the dos packet sent      */
/* Arg1 - Lock */
/* Arg2 - name */
/* Arg3 (optional) Attributes */
{
   struct FileLock *flock;
   NETPTR nlock;

   BUG(("ActCreateDir\n"));

   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
   {
      /* The idiot is trying to create a directory in NET: */
      BUG(("ActCreateDir: Can't create dir in NET:, giving up\n"))
      pkt->dp_Res1 = NULL;
      pkt->dp_Res2 = ERROR_WRITE_PROTECTED;
      return;
   }
   global->RP.Type = pkt->dp_Type;
   global->RP.Arg1 = (LONG)nlock->RPtr;
   MBSTR(pkt->dp_Arg2, global->RP.Data);
   global->RP.Arg3 = pkt->dp_Arg3;
   global->RP.DLen = BSTRLEN(global->RP.Data)+1;
   if(global->RP.DLen == 1) global->RP.DLen = 0;

   if(!RemotePacket(global, nlock) && pkt->dp_Res1)
   {
      pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock,
                               (RPTR)pkt->dp_Res1, ACCESS_READ));
   }
}

/*-------------------------------------------------------------------------*/
/* Structure of the FileInfoBlock                                          */
/* struct FileInfoBlock {                                                  */
/*    LONG fib_DiskKey;           Location on disk of entry                */
/*    LONG fib_DirEntryType;      <0 plain file, >0 a directory            */
/*    char fib_FileName[108];     Null terminated name of file             */
/*    LONG fib_Protection;        Protection bits for the file             */
/*    LONG fib_EntryType;         Internal for Dos use                     */
/*    LONG fib_Size;              Length of file in bytes                  */
/*    LONG fib_NumBlocks;         Length of file in blocks                 */
/*    struct DateStamp fib_Date;  File creation date                       */
/*    char fib_Comment[116];      Comment associated with file             */
/*    };                                                                   */
/*-------------------------------------------------------------------------*/

static void PNum U_ARGS((char *, int));

#define UPSPOT  17
#define TOTSPOT 24
static char status[] = "\53Network status: xxx of xxx nodes responding";

static void PNum(string, num)
char *string;
int num;
{
   static char *digits = " 123456789";
   /* Format a number into 3 character positions of a string */
   /* Number must be between 1 and 999 inclusive */
   num %= 1000;
   string[0] = digits[num/100]; num %= 100;
   string[1] = digits[num/10];  num %= 10;
   string[2] = (num ? digits[num] : '0');
}

void ExDotInfo U_ARGS((GLOBAL, struct FileInfoBlock *));

void ExDotInfo(global, info)
GLOBAL global;
struct FileInfoBlock *info;
{
   BUGBSTR("ExDotInfo for ", info->fib_FileName);
   strcpy(info->fib_FileName+(info->fib_FileName[0]+1), ".info");
   info->fib_FileName[0] += 5;
   info->fib_EntryType =
   info->fib_DirEntryType = -3;
   info->fib_Protection = 0L;
   info->fib_Size = 974;
   info->fib_NumBlocks = 2;
   info->fib_Comment[0] = '\0';

   global->pkt->dp_Res1 = DOS_TRUE;
}


static void ExRoot U_ARGS((GLOBAL, struct FileInfoBlock *));

static void ExRoot(global, info)
GLOBAL global;
struct FileInfoBlock *info;
{
   BUG(("ExRoot\n"))
   /* Examine on the root of NET: */
   info->fib_DiskKey = (LONG)&global->netchain;
   info->fib_DirEntryType = info->fib_EntryType = 2;
   MBSTR(global->netchain.name, info->fib_FileName);
   info->fib_Protection = 0;
   info->fib_NumBlocks = global->numnodes;
   info->fib_Size = 0;
   info->fib_Date.ds_Days = 3000;  /* Pick a number */
   info->fib_Date.ds_Minute =
   info->fib_Date.ds_Tick = 0L;
   strcpy(info->fib_Comment, status);
   PNum(info->fib_Comment+UPSPOT, global->upnodes);
   PNum(info->fib_Comment+TOTSPOT, global->numnodes);

   global->pkt->dp_Res1 = DOS_TRUE;
}

static void ExRootNext U_ARGS((GLOBAL, struct FileInfoBlock *));

static void ExRootNext(global, info)
GLOBAL global;
struct FileInfoBlock *info;
{
   struct NetNode *node;

   /* Examine next in the root of NET: */
   BUG(("ExRootNext\n"))

   node = (struct NetNode *)info->fib_DiskKey;

   /* If the node name is the same length as the filename, we haven't */
   /* returned the exnext of the .info file yet;  do so               */
   if(node != &global->netchain && 
      info->fib_FileName[0] > 0 &&
      node->name[0] == info->fib_FileName[0])
   {
      ExDotInfo(global, info);
      return;
   }

#if 0
   for(node=node->next; 
       node && node->status != NODE_UP;
       node=node->next);
#else
   node = node->next;
#endif

   if(!node)
   {
      global->pkt->dp_Res1 = DOS_FALSE;
      global->pkt->dp_Res2 = ERROR_NO_MORE_ENTRIES;
      BUG(("Returning ERROR_NO_MORE_ENTRIES\n"));
      return;
   }
   
   info->fib_DiskKey = (LONG)node;
   info->fib_DirEntryType = info->fib_EntryType = 2;
   MBSTR(node->name, info->fib_FileName);
   BUGBSTR("ExNext: Filename is ", info->fib_FileName);
   info->fib_Protection = 0L;
   info->fib_NumBlocks = 1;
   info->fib_Size = 0;
   info->fib_Date.ds_Days = 3000;
   info->fib_Date.ds_Minute =
   info->fib_Date.ds_Tick = 0L;
   info->fib_Comment[0] = '\0';

   global->pkt->dp_Res1 = DOS_TRUE;
}

void ActExamine(global, pkt)
GLOBAL global;
struct DosPacket *pkt;              /* a pointer to the dos packet sent    */
/* Arg1: Lock of object to examine */
/* Arg2: FileInfoBlock to fill in */
{
   NETPTR nlock;
   struct FileLock *flock;
   struct FileInfoBlock *info;

   BUG(("ActExamine/ActExNext\n"));
   
   info = (struct FileInfoBlock *)pkt->dp_Arg2;

   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
   {
      if(pkt->dp_Type == ACTION_EXAMINE_OBJECT)
         ExRoot(global, info);
      else
         ExRootNext(global, info);
      return;
   }

   BUG(("ActEx: Lock %lx on node %s\n",nlock->RPtr,nlock->NetNode->name+1));
   global->RP.Type = pkt->dp_Type;
   global->RP.Arg1 = (LONG)nlock->RPtr;

   MQ(info, global->RP.Data, sizeof(struct FileInfoBlock));
   BUGBSTR("ActEx: filename ", info->fib_FileName);

   global->RP.DLen = sizeof(struct FileInfoBlock);

   if(!RemotePacket(global, nlock))
   {
      MQ(global->RP.Data, info, sizeof(struct FileInfoBlock));
      BUGBSTR("ActEx: Returned filename ", info->fib_FileName);
   }
}

void ActParent(global,pkt)
GLOBAL global;
struct DosPacket *pkt;              /* a pointer to the dos packet sent      */
/* Arg1 - Lock */
{
   struct FileLock *flock;
   NETPTR nlock;

   BUG(("ActParent\n"));

   /* If this is the root of NET:, return NULL */
   if((!(flock=(struct FileLock *)pkt->dp_Arg1) || 
       !(nlock=(NETPTR)flock->fl_Key)->RDevice))
   {
      pkt->dp_Res1 = NULL;
      return;
   }

   global->RP.Type = pkt->dp_Type;
   global->RP.Arg1 = (LONG)nlock->RPtr;
   global->RP.DLen = 0;

   if(RemotePacket(global, nlock)) return;
      
   if(pkt->dp_Res1 == NULL)
   {
      if(pkt->dp_Res2) return;  /* Error on other side */

      /* Null lock from other side, return a lock on our root */
      nlock = &global->netchain.RootLock;
   }

   pkt->dp_Res1 = MKBADDR(CreateLock(global, nlock,
                          (RPTR)pkt->dp_Res1, ACCESS_READ));
}
