/*****************************************************************************/
/*
                                FileDot.c

Miscellaneous file processing module.
(We might end up stuffing all sort of miscellaneous file-type functionality
into here!)


FILE.URL
--------
This file type parallels the Microsoft 'file.URL' files that contain Web URLs
as a type of symbolic or soft link into the Internet.  These files are enabled
by creating an HTTPD$CONFIG content-type mapping a file extension (e.g. .URL)
to the content-type "x-internal/url".  This results in FileDotUrlBegin() being
activqted by REQUEST.C module when a file of type .URL is accessed.  Lines
beginning with '#' or '[' are ignored.  Recognised redirections:

   URL=scheme://the.host.name/the/path/
   URL=./relative/path
   URL=../relative/path
   URL=relative/path
   scheme://the.host.name/the/path/
   ./relative/path
   ../relative/path


VERSION HISTORY
---------------
25-FEB-2002  MGD  modifications inline with suggestions (ssh@S-and-B.ru)
01-JAN-2001  MGD  new for HTTPd version 7.2
*/
/*****************************************************************************/

#ifdef WASD_VMS_V6
#undef _VMS_V6_SOURCE
#define _VMS_V6_SOURCE
#undef __VMS_VER
#define __VMS_VER 60000000
#undef __CRTL_VER
#define __CRTL_VER 60000000
#endif

/* standard C header files */
#include <stdio.h>
#include <ctype.h>

/* VMS related header files */
#include <ssdef.h>
#include <stsdef.h>

/* application-related header files */
#include "wasd.h"

#define WASD_MODULE "DOTFILE"

/**********/
/* macros */
/**********/

/* if not in the first 2048 bytes of the file then quit */
#define FILE_DOT_URL_QUIT_AFTER 2048

/********************/
/* external storage */
/********************/

#ifdef DBUG
extern BOOL Debug;
#else
#define Debug 0 
#endif

extern char  SoftwareID[];
extern ACCOUNTING_STRUCT  *AccountingPtr;
extern MSG_STRUCT  Msgs;
extern WATCH_STRUCT  Watch;

/*****************************************************************************/
/*
Using the configuration file (contents supplied by a preceding call to
FileBegin()) interpret the mappings.
*/

FileDotUrlBegin (REQUEST_STRUCT *rqptr)

{
   int  Length;
   char  *cptr, *sptr, *zptr;
   char  FileName [ODS_MAX_FILE_NAME_LENGTH+1];
   FILE_CONTENT  *fcptr;

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "FileDotUrlBegin()\n");

   if (!rqptr->AccountingDone++)
      InstanceGblSecIncrLong (&AccountingPtr->DoDotUrlCount);

   /* take control of the file contents structure */
   fcptr = rqptr->FileContentPtr;
   rqptr->FileContentPtr = NULL;

   if (WATCHING(rqptr) &&
       WATCH_CATEGORY(WATCH_RESPONSE))
      WatchThis (rqptr, FI_LI, WATCH_RESPONSE, "URL !AZ !UL bytes",
                 fcptr->FileName, fcptr->ContentLength);

   /* get the start of the file contents */
   cptr = sptr = fcptr->ContentPtr;
   while (*cptr)
   {
      if (cptr > sptr + FILE_DOT_URL_QUIT_AFTER) break;
      while (*cptr && ISLWS(*cptr)) cptr++;
      if (*cptr == '#' || *cptr == '[' || EOL(*cptr))
      {
         /* ignore comment/directive/empty lines */
         while (*cptr && NOTEOL(*cptr)) cptr++;
         while (*cptr && EOL(*cptr)) cptr++;
         continue;
      }

      if (toupper(cptr[0]) == 'U' &&
          toupper(cptr[1]) == 'R' &&
          toupper(cptr[2]) == 'L' &&
          toupper(cptr[3]) == '=')
      {
         /* no question about this one! */
         cptr += 4;
      }
      else
      if (cptr[0] == '.')
      {
         /* possible relative URL (e.g. "../whatever" or "./whatever") */
         if (!((cptr[1] == '.' && cptr[2] == '/') || cptr[1] != '/'))
         {
            cptr++;
            continue;
         }
      }
      else
      {
         /* possible absolute URL (e.g. "scheme://the.host.name/the/path") */
         if (cptr[0] != ':') { cptr++; continue; };
         if (cptr[1] != '/') { cptr++; continue; };
         if (cptr[2] != '/') { cptr++; continue; };
         /* looks like it, find the start of the scheme, looking backwards */
         if (cptr > fcptr->ContentPtr) cptr--; 
         while (cptr > fcptr->ContentPtr && isalpha(*cptr)) cptr--; 
         if (!isalpha(*cptr)) cptr++;
      }

      /* find the end of the URL, then use it as a redirection location */
      sptr = cptr;
      while (*cptr && !ISLWS(*cptr) && !EOL(*cptr)) cptr++;
      rqptr->rqResponse.LocationPtr = VmGetHeap (rqptr, cptr-sptr+1);
      cptr = rqptr->rqResponse.LocationPtr;
      while (*sptr && !isspace(*sptr)) *cptr++ = *sptr++;
      *cptr = '\0'; 
      break;
   }

   if (rqptr->rqResponse.LocationPtr)
   {
      /************/
      /* redirect */
      /************/

      if (Debug)
         fprintf (stdout, "LocationPtr |%s|\n", rqptr->rqResponse.LocationPtr);

      SysDclAst (fcptr->NextTaskFunction, rqptr);
      return;
   }

   /*****************************/
   /* output file as plain-text */
   /*****************************/

   ResponseHeader (rqptr, 200, "text/plain", -1, NULL, NULL);

   NetWrite (rqptr, fcptr->NextTaskFunction,
             fcptr->ContentPtr, fcptr->ContentLength);
}

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

