/***************************************************************************
 *                                                                         *
 *   VDIROS.C                                                              *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Virtual Directory API Server for selected OS drives                   *
 *                                                                         *
 *                                        - RNStein  7/11/94               *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "vdir.h"
#include "vdiros.h"

#define FILREV "$Revision: 4 $"

static INT dosdir(VOID);
static INT dos1st(CHAR *fspec);
static INT dosnxt(VOID);
static INT dpwrap(INT rc);
static VOID rwflags(VOID);
static CHAR *dosinf(INT type);
static CHAR *dospth(VOID);
static CHAR *pthutl(CHAR *fspec);
static INT doslog(CHAR *desc);
static INT dosdel(VOID);
static INT dosrnm(CHAR *newnam);
static INT dosmkd(VOID);
static INT dosrmd(VOID);

#define DOSROOT 0                  /* trgnum: parent dir of all drives     */
#define DOSDRIV 1                  /* trgnum: root or subdir of some drive */

CHAR *ospath="C";                  /* Allowed drives (must be upper case)  */
GBOOL osdots=FALSE;                /* show "." and ".." in file listing    */

struct vdirsvc vdiros={            /* VDIRserver for OS subtree            */
     NULL,                         /* next link in list of VDIRservers     */
     SLS"DOS",                     /* directory prefix                     */
     dosdir,                       /* select new subdir (vdirscb->trgdir)  */
     dos1st,                       /* find one, or first of a set, of files*/
     dosnxt,                       /* find next files in a set             */
     dosinf,                       /* information (VDFXXX/VDDXXX in VDIR.H)*/
     dospth,                       /* OS path for file from vds1st/nxt=1   */
     NULL,                         /* record reading a file fm vds1st/nxt=1*/
     doslog,                       /* log in new file after vds1st=0/1     */
     dosdel,                       /* delete file from vds1st/nxt=1        */
     dosrnm,                       /* rename file from vds1st/nxt=1        */
     dosmkd,                       /* make dir from recent vds1st=0        */
     dosrmd,                       /* remove dir from recent vdsdir=1      */
     0,                            /* creation date                        */
     0                             /* creation time                        */
};

static INT
dosdir(VOID)                       /* Change current directory (to trgdir) */
{                                  /* returns 1=mine & valid, 0=otherwise  */
     CHAR *ptr;
     struct ffblk fb;

     if (!canosvis()) {
          return(0);
     }
     ptr=vdirscb->trgdir;
     if (ptr[0] == '\0') {
          vdirscb->trgnum=(LONG)DOSROOT;
          return(1);
     }
     if (strchr(ospath,toupper(ptr[0])) == NULL) {
          return(0);
     }
     vdirscb->trgnum=(LONG)DOSDRIV;
     if (ptr[1] == '\0') {
          return(1);
     }
     if (ptr[1] != SL || strchr(ptr,'*') != NULL
                         || strchr(ptr,'?') != NULL) {
          return(0);
     }
     return(fnd1st(&fb,pthutl(""),FAMDIR) && fb.ff_attrib&FAMDIR);
}

static INT
dos1st(                            /* find a file relative to current dir  */
CHAR *fspec)                       /* may contain wildcards (if VDSWLD)    */
                                   /* vdflags implicit input               */
                                   /* note - no vdirroom size restrictions */
{                                  /* returns 1=got, 0=none, 2=call again  */
     if ((INT)vdirscb->trgnum == DOSROOT) {
          if (fspec[0] == '\0' || fspec[0] == '*' && vdflags&VDSWLD) {
               vdirscb->j.misc=0;
               return(2);
          }
          return(0);
     }
     return(dpwrap(fnd1st(&vdirscb->fb,pthutl(autwex(fspec)),FAMDIR)));
}

static INT
dosnxt(VOID)                       /* find next file of a multi-file spec  */
{                                  /* ret: 1=next, 0=no more, 2=call again */

     INT i;
     struct ffblk fb;

     if ((INT)vdirscb->trgnum == DOSROOT) {
          if ((i=vdirscb->j.misc) >= strlen(ospath)) {
               return(0);
          }
          if (fnd1st(&fb,spr("%c:\\.",ospath[i]),FAMDIR)) {
               vdirscb->fb.ff_fdate=fb.ff_fdate;
               vdirscb->fb.ff_ftime=fb.ff_ftime;
          }
          vdirscb->fb.ff_attrib=FAMDIR;
          vdirscb->flags|=VDPVSBL+VDPEXIS;
          rwflags();
          sprintf(vdirscb->fb.ff_name,"%c",ospath[i]);
          vdirscb->j.misc++;
          return(1);
     }
     return(dpwrap(fndnxt(&vdirscb->fb)));
}

static INT
dpwrap(                            /* wrap up fb and flags fields for VDIR */
INT rc)                            /* return code from fnd1st() or fndnxt()*/
{                                  /* returns 1=got, 2=not yet, 0=no more  */
     if (rc
      && !osdots
      && vdirscb->fb.ff_attrib&FAMDIR
      && (sameas(vdirscb->fb.ff_name,".")
       || sameas(vdirscb->fb.ff_name,".."))) {
          return(2);
     }
     if (rc) {
          vdirscb->flags|=VDPEXIS+VDPVSBL;
     }
     rwflags();
     return(rc);
}

static VOID
rwflags(VOID)                      /* set read & write flags as appropriate*/
{
     if (canosget()) {
          vdirscb->flags|=VDPREAD;
     }
     if (canosput()) {
          vdirscb->flags|=VDPWRIT;
     }
}

static CHAR *
dosinf(                            /* get info on DOS file                 */
INT type)                          /* see VDFXXX and VDDXXX in VDIR.H      */
{
     CHAR *cp;

     if ((INT)vdirscb->trgnum == DOSROOT) {
          switch (type) {
          case VDDNAM:
               return("DOS \"master\" directory.");
          case VDDDSC:
               return("Type \"DIR\" for a list of drives.");
          default:
               return("");
          }
     }
     switch (type) {
     case VDDNAM:
          cp=spr("DOS directory %c:%s",vdirscb->trgdir[0],vdirscb->trgdir+1);
          if (vdirscb->trgdir[1] == '\0') {
               strcat(cp,SLS);
          }
          return(cp);
     default:
          return("");
     }
}

static CHAR *
dospth(VOID)                       /* construct DOS path of a DOS file     */
{
     return((INT)vdirscb->trgnum == DOSROOT ? "" : pthutl(vdirscb->fb.ff_name));
}

static CHAR *
pthutl(                            /* get full DOS path for DOS file       */
CHAR *fspec)                       /* file spec, no directory prefix       */
{                                  /* return alternates between 2 buffers  */
     static CHAR buffer[2][VDRFSPEC+1];
     static INT cycle=0;

     cycle++;
     cycle&=1;
     if ((INT)vdirscb->trgnum == DOSROOT) {
          return("");
     }
     if ((buffer[cycle][0]=vdirscb->trgdir[0]) != '\0') {
          buffer[cycle][1]=':';
          strcpy(&buffer[cycle][2],vdirscb->trgdir+1);
          if (fspec[0] != '\0') {
               strcat(buffer[cycle],SLS);
               stzcat(buffer[cycle],fspec,VDRFSPEC+1);
          }
     }
     return(buffer[cycle]);
}

static INT
doslog(                            /* log in new file after vds1st=0       */
CHAR *desc)                        /* description or ""                    */
{                                  /* returns 1=could, 0=couldn't          */
     (VOID)desc;
     return((INT)vdirscb->trgnum != DOSROOT);
}

static INT
dosdel(VOID)                       /* delete file from recent vds1st/nxt=1 */
{                                  /* returns 1=could, 0=couldn't, 2=trying*/
     return((INT)vdirscb->trgnum != DOSROOT
         && unlink(dospth()) == 0);
}

static INT
dosrnm(                            /* rename file from recent vds1st/nxt=1 */
CHAR *newnam)                      /* new name (no path prefix)            */
{
     return((INT)vdirscb->trgnum != DOSROOT
         && rename(dospth(),pthutl(newnam)) == 0);
}

static INT
dosmkd(VOID)                       /* make dir from recent vds1st=0        */
{                                  /* returns 1=could, 0=couldn't          */
     return((INT)vdirscb->trgnum != DOSROOT
         && canosput()
         && mkdir(dospth()) == 0);
}

static INT
dosrmd(VOID)                       /* remove dir from recent vdsdir=1      */
{                                  /* returns 1=could, 0=couldn't          */
     return((INT)vdirscb->trgnum != DOSROOT
         && canosput()
         && rmdir(pthutl("")) == 0);
}

