/********************************************************************
* wilkinson
* 3.18VMS
* 1995/09/25 14:40
* gopher_root1:[gopher.g2.vms2_13.gopherd]special.c,v
* Exp
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 1992 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: special.c
* routines to deal with special types of files, compressed, scripts, etc.
*********************************************************************
* Revision History:
* special.c,v
* Revision 3.18VMS 1995/09/25 14:40    wilkinson
* Consolodate VMS/Unix source code for server as well as client
*
* Revision 3.18  1994/07/21  04:08:29  lindner
* Bulletproofing for shell scripts
*
* Revision 3.17  1994/04/25  20:49:11  lindner
* Fix for debug code
*
* Revision 3.16  1994/04/14  15:48:54  lindner
* Fix for files with single quotes
*
* Revision 3.15  1993/11/03  03:32:52  lindner
* Test shell scripts for exec bit
*
* Revision 3.14  1993/08/19  20:52:30  lindner
* Mitra comments
*
* Revision 3.13  1993/08/11  22:47:11  lindner
* Don't let the security stuff trap ask blocks
*
* Revision 3.12  1993/08/06  14:30:49  lindner
* Fixes for better security logging
*
* Revision 3.11  1993/08/04  22:14:54  lindner
* Mods to use Gpopen
*
* Revision 3.10  1993/08/04  22:12:51  lindner
* Mods to use Gpopen
*
* Revision 3.9  1993/07/27  05:27:59  lindner
* Mondo Debug overhaul from Mitra
*
* Revision 3.8  1993/07/25  02:56:51  lindner
* Fixed iscompressed() to return NULL
*
* Revision 3.7  1993/07/23  03:18:13  lindner
* Mods for using decoder:'s
*
* Revision 3.6  1993/07/07  19:35:36  lindner
* removed extra args to popen()
*
* Revision 3.5  1993/06/22  06:58:53  lindner
* Added a little debug code..
*
* Revision 3.4  1993/06/11  16:46:50  lindner
* Support for gzipped files
*
* Revision 3.3  1993/04/09  15:00:19  lindner
* Fixes for ask shell scripts, ensure that they're run in the current
* directory of the script.
*
* Revision 3.2  1993/03/24  20:24:23  lindner
* Addition for compressed file support rfopenz()
*
* Revision 3.1.1.1  1993/02/11  18:02:53  lindner
* Gopher+1.2beta release
*
* Revision 1.3  1993/02/09  22:15:36  lindner
* additions for askfile
*
* Revision 1.2  1993/01/30  23:57:44  lindner
* Additions for ASK block support.
*
* Revision 1.1  1992/12/10  23:13:27  lindner
* gopher 1.1 release
*
*
*********************************************************************/

#ifdef VMS_SERVER
#define GSGOPHEROBJ_C
       /*  Right now, DEC C v5.0 seems to ignore the angle brackets and
               pull in [-.object]string.h instead of the system
                   version of string.h, which we need here.  But all we
                   need it for is a prototype of strchr(), so we'll put
                   that in by hand to get around this for now           */
#include <string.h> /* */
/* char   *strchr       (const char *__s, int __c);  /* */
#endif

#include "gopherd.h"

#ifdef VMS_SERVER
#undef GSGOPHEROBJ_C
#include "serverutil.h"
#endif

#include "ext.h"
#include "Debug.h"

char *iscompressed();

/* Check to see if this file needs special treatment before heading
* back to the client... We will check for:
*      Encoded files           execute decoder...
*      Shellscript             if so, "do it"
*                              (add ask block params if exists..)
* Note: it would be somewhat non-portable to check of a binary
*  (we'd need to check for so many different magic numbers; the
*  shell script designation should be sufficient, since the script
*  can call an executable anyway
* Recognized elsewhere:
*      .snd                    needs special processing on client
*      uuencoded               needs special processing on client
* Other filetypes we could check for:
*      GIF             ->      Bring up GIF previewer
*      Postscript      ->      Bring up Postscript previewer
*/

static int ispipe;
#ifdef VMS_SERVER


/*  Provide a VMS way of doing popen()  */

FILE *
vms_popen(char *cmd, char *mode)
{
   int vms_pipe_status;
   FILE *fopen_VMSopt(char *, char *, char *, char *);

   if (((vms_pipe_status = VMS$system(cmd)) &1)==1)
       return(fopen_VMSopt(vms_pipe_file,mode,"",""));
   if (access(vms_pipe_file, 0) == 0)
       unlink(vms_pipe_file);
   vms_pipe_file[0] = '\0';
   return((FILE *)(0));
}


/*  Provide a VMS way of doing pclose() */
int
vms_pclose(FILE *fp)
{
   int vms_pipe_status;

   vms_pipe_status = fclose(fp);
   if (strlen(vms_pipe_file)!=0)
       unlink(vms_pipe_file);
   vms_pipe_file[0] = '\0';
   return(vms_pipe_status);
}

#endif

FILE *
specialfile(sockfd, fp, pathname)
 int sockfd;
 FILE *fp;
 char *pathname;
{
    FILE *pp;
    static char buf[256];
    char  s[256], *cp;
    long i;
    char *decoder;
#ifdef VMS_SERVER
    char *VMS$Validate_Filespec(char *);
#endif

    ispipe = 0;

    /* Keep track of where we are */
    i = ftell(fp);
    rewind(fp);

    /* Grab the first line or 254 bytes, and rewind */
    if (fgets(s, 255, fp) == NULL)
         return (FILE *)0;

    fseek(fp, i, 0);

    /* Compressed? */
    if ((decoder = iscompressed(pathname)) != NULL) {
#ifndef VMS_SERVER
         dequote1(pathname);
         if (dochroot)
              sprintf(buf, "%s '%s'", decoder, pathname);
         else
              sprintf(buf, "%s '%s/%s'", decoder, Data_Dir, pathname);
#else
           /* Need to set up buf & vms_pipe_file for VMS decoding here */
#endif

         Debug("Executing decoder %s\n",buf);

         pp = popen(buf, "r");

         if (!pp)
              return (FILE *)0;
         ispipe = 1;
         return pp;
    }

    /* Script? */
#ifndef VMS_SERVER
    if (isshellscript(s) && isexec(fileno(fp))) {
         dequote1(pathname);
         s[strlen(s)-1] = '\0';
         if (dochroot)
              sprintf(buf, "\"%s\" %s", pathname, (EXECargs == NULL) ? "" : EXECargs);
         else
              sprintf(buf, "\"%s/%s\" %s", Data_Dir, pathname, (EXECargs == NULL) ? "" : EXECargs);

         if (ASKfile != NULL) {                /* Ick this is a global*/
              strcat(buf, " < ");
              strcat(buf, ASKfile);
         }
       else
              strcat(buf, " < /dev/null ");

         /*
          * Okay, let's change our working directory for the benefit of
          * shell script writers everywhere :-)
          */

         strcpy(s, pathname);
         cp = strrchr(s, '/');
         if (cp != NULL && cp > s) {
              *cp = '\0';
              ;
         } else
              strcpy(s, "/");

         rchdir(s);

#else
    if (isshellscript(s, pathname)) {
       strcpy(vms_pipe_file, pathname);
       if ((cp=strchr(vms_pipe_file,' '))!=NULL)
           *cp = '\0';
       if (VMS$Validate_Filespec(vms_pipe_file)==NULL) {
           vms_pipe_file[0] = '\0';
           return (FILE *)(ispipe=0);
       }
       strcpy(vms_pipe_file, cp=tempnam(GDCgetScratchDir(Config),NULL));
       free(cp);
       sprintf(buf, "$ @%s/output=%s", pathname, vms_pipe_file);
       if (ASKfile != NULL) {
           strcat(buf, "/input=");     /** JLW - I know this won't work */
           strcat(buf, ASKfile);       /** just a placeholder, really **/
       }
       if (EXECargs != NULL) {
           strcat(buf, " \"");
           strcat(buf, EXECargs);
           strcat(buf, "\"");
       }
#endif
         Debug("Executing %s\n", buf);

         if (EXECargs) {
              if (! (pp = Gpopen(sockfd, buf, "r")))
                   return (FILE *)0;
         }
         else {
              if (! (pp = popen(buf, "r")))
                   return (FILE *)0;
         }

         ispipe = 1;

         Debugmsg("Zcat/popen is okay\n");


         return pp;
    }

    return (FILE *)0;
}


char *
iscompressed(pathname)
 char *pathname;
{
    static Extobj *ext = NULL;

    if (pathname == NULL || strlen(pathname)==0)
         return(NULL);

    if (ext == NULL)
         ext = EXnew();

    if (EXAcasedSearch(Config->Extensions, ext, pathname, EXT_DECODER))
         return(EXgetDecoder(ext));

    return(NULL);
}


/*
* Is this a shell script?
*/

#ifndef VMS_SERVER
int
isshellscript(s)
 char *s;
{
    if (! strncmp(s, "#!", 2))
         return 1;
    else
         return 0;
}
#else
int
isshellscript(char *s, char *path)
{
    if (strncasecmp(path+strlen(path)-strlen(".SCRIPT"),".SCRIPT")!=0)
       return 0;
    if (! strncmp(s, "$!", 2))
         return 1;
    else
         return 0;
}
#endif

#ifndef VMS_SERVER
/*
* Are the exec bits set?
*/

int
isexec(fd)
 int fd;
{
    STATSTR sb;

    if (fstat(fd, &sb) == -1)
         return 0;

    if (sb.st_mode & S_IXUSR)
         return 1;
    else
         return 0;
}
#endif

int
Specialclose(fp)
 FILE *fp;
{
    if (ASKfile != NULL)               /* Ick this is a global*/
         unlink(ASKfile);
    if (ispipe)
         return(pclose(fp));
    else
         return(fclose(fp));
}