"Fossies" - the Fresh Open Source Software Archive

Member "lynx2.9.0dev.1/WWW/Library/Implementation/HTVMSUtils.c" (28 Nov 2013, 28097 Bytes) of package /linux/www/lynx2.9.0dev.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "HTVMSUtils.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * $LynxId: HTVMSUtils.c,v 1.39 2013/11/28 11:15:31 tom Exp $
    3  *
    4  * MODULE                           HTVMSUtil.c
    5  *      VMS Utility Routines
    6  *
    7  * AUTHORS:
    8  *  MD  Mark Donszelmann    duns@vxdeop.cern.ch
    9  *
   10  * HISTORY:
   11  *  14 Nov 93  MD   Written
   12  *
   13  * BUGS:
   14  *
   15  *
   16  */
   17 
   18 #include <HTUtils.h>
   19 #ifdef VMS
   20 #include <HTFormat.h>
   21 #include <HTStream.h>
   22 #include <UCDefs.h>
   23 #include <UCMap.h>
   24 #include <UCAux.h>
   25 #include <HTFTP.h>
   26 #include <HTTCP.h>
   27 #include <HTVMSUtils.h>
   28 #include <ssdef.h>
   29 #include <jpidef.h>
   30 #include <prvdef.h>
   31 #include <acldef.h>
   32 #include <chpdef.h>
   33 #include <descrip.h>
   34 #include <lib$routines.h>
   35 #include <starlet.h>
   36 #include <rmsdef.h>
   37 
   38 #include <LYGlobalDefs.h>
   39 #include <LYUtils.h>
   40 #include <LYLeaks.h>
   41 #include <LYStrings.h>
   42 
   43 BOOL HTVMSFileVersions = FALSE; /* Include version numbers in listing? */
   44 
   45 typedef struct {
   46     unsigned long BufferLength:16;
   47     unsigned long ItemCode:16;
   48     unsigned long BufferAddress:32;
   49     unsigned long ReturnLengthAddress:32;
   50 } ItemStruct;
   51 
   52 /* PUBLIC                           HTVMS_authSysPrv()
   53  *      CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV
   54  * ON ENTRY:
   55  *  No arguments.
   56  *
   57  * ON EXIT:
   58  *  returns YES if SYSPRV is authorized
   59  */
   60 BOOL HTVMS_authSysPrv(void)
   61 {
   62     unsigned long Result;
   63     ItemStruct ItemList[2];
   64     unsigned long Length;
   65     unsigned long Buffer[2];
   66 
   67     /* fill Item */
   68     ItemList[0].BufferLength = sizeof(Buffer);
   69     ItemList[0].BufferAddress = (unsigned long) Buffer;
   70     ItemList[0].ReturnLengthAddress = (unsigned long) &Length;
   71     ItemList[0].ItemCode = JPI$_AUTHPRIV;
   72 
   73     /* terminate list */
   74     ItemList[1].ItemCode = 0;
   75     ItemList[1].BufferLength = 0;
   76 
   77     /* call system */
   78     Result = sys$getjpiw(0, 0, 0, ItemList, 0, 0, 0);
   79 
   80     if (Result != SS$_NORMAL)
   81     return (NO);
   82 
   83     if (Buffer[0] & PRV$M_SYSPRV)
   84     return (YES);
   85 
   86     return (NO);
   87 }
   88 
   89 /* PUBLIC                           HTVMS_enableSysPrv()
   90  *      ENABLES SYSPRV
   91  * ON ENTRY:
   92  *  No arguments.
   93  *
   94  * ON EXIT:
   95  *
   96  */
   97 void HTVMS_enableSysPrv(void)
   98 {
   99     unsigned long Result;
  100     unsigned long Prv[2], PreviousPrv[2];
  101 
  102     Prv[0] = PRV$M_SYSPRV;
  103     Prv[1] = 0;
  104     Result = sys$setprv(1, &Prv, 0, &PreviousPrv);
  105 
  106     if (Result == SS$_NORMAL) {
  107     if (!(PreviousPrv[0] & PRV$M_SYSPRV)) {
  108         CTRACE((tfp, "HTVMS_enableSysPrv: Enabled SYSPRV\n"));
  109     }
  110     }
  111 }
  112 
  113 /* PUBLIC                           HTVMS_disableSysPrv()
  114  *      DISABLES SYSPRV
  115  * ON ENTRY:
  116  *  No arguments.
  117  *
  118  * ON EXIT:
  119  *
  120  */
  121 void HTVMS_disableSysPrv(void)
  122 {
  123     unsigned long Result;
  124     unsigned long Prv[2], PreviousPrv[2];
  125 
  126     Prv[0] = PRV$M_SYSPRV;
  127     Prv[1] = 0;
  128     Result = sys$setprv(0, &Prv, 0, &PreviousPrv);
  129 
  130     if (Result == SS$_NORMAL) {
  131     if (PreviousPrv[0] & PRV$M_SYSPRV) {
  132         CTRACE((tfp, "HTVMS_disableSysPrv: Disabled SYSPRV\n"));
  133     }
  134     }
  135 }
  136 
  137 /* PUBLIC                           HTVMS_checkAccess()
  138  *      CHECKS ACCESS TO FILE FOR CERTAIN USER
  139  * ON ENTRY:
  140  *  FileName    The file to be accessed
  141  *  UserName    Name of the user to check access for.
  142  *          User nobody, represented by "" is given NO for an answer
  143  *  Method      Name of the method to be chceked
  144  *
  145  * ON EXIT:
  146  *  returns YES if access is allowed
  147  *
  148  */
  149 BOOL HTVMS_checkAccess(const char *FileName,
  150                const char *UserName,
  151                const char *Method)
  152 {
  153     unsigned long Result;
  154     ItemStruct ItemList[2];
  155     unsigned long Length;
  156     unsigned long Buffer;
  157     unsigned long ObjType;
  158 
  159     char *VmsName;
  160 
  161     struct dsc$descriptor_s FileNameDesc;
  162     struct dsc$descriptor_s UserNameDesc;
  163 
  164     char *colon;
  165 
  166     /* user nobody should access as from account under which server is running */
  167     if (0 == strcmp(UserName, ""))
  168     return (NO);
  169 
  170     /* check Filename and convert */
  171     colon = StrChr(FileName, ':');
  172     if (colon)
  173     VmsName = HTVMS_name("", colon + 1);
  174     else
  175     VmsName = HTVMS_name("", FileName);
  176 
  177     /* check for GET */
  178     if (0 == strcmp(Method, "GET")) {
  179     /* fill Item */
  180     ItemList[0].BufferLength = sizeof(Buffer);
  181     ItemList[0].BufferAddress = (unsigned long) &Buffer;
  182     ItemList[0].ReturnLengthAddress = (unsigned long) &Length;
  183     ItemList[0].ItemCode = CHP$_FLAGS;
  184 
  185     /* terminate list */
  186     ItemList[1].ItemCode = 0;
  187     ItemList[1].BufferLength = 0;
  188 
  189     /* fill input */
  190     ObjType = ACL$C_FILE;
  191     Buffer = CHP$M_READ;
  192     UserNameDesc.dsc$w_length = strlen(UserName);
  193     UserNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
  194     UserNameDesc.dsc$b_class = DSC$K_CLASS_S;
  195     UserNameDesc.dsc$a_pointer = (char *) UserName;
  196     FileNameDesc.dsc$w_length = strlen(VmsName);
  197     FileNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
  198     FileNameDesc.dsc$b_class = DSC$K_CLASS_S;
  199     FileNameDesc.dsc$a_pointer = VmsName;
  200 
  201     /* call system */
  202     Result = sys$check_access(&ObjType, &FileNameDesc, &UserNameDesc, ItemList);
  203 
  204     if (Result == SS$_NORMAL)
  205         return (YES);
  206     else
  207         return (NO);
  208     }
  209 
  210     return (NO);
  211 }
  212 
  213 /* PUBLIC                           HTVMS_wwwName()
  214  *      CONVERTS VMS Name into WWW Name
  215  * ON ENTRY:
  216  *  vmsname     VMS file specification (NO NODE)
  217  *
  218  * ON EXIT:
  219  *  returns     www file specification
  220  *
  221  * EXAMPLES:
  222  *  vmsname             wwwname
  223  *  DISK$USER           disk$user
  224  *  DISK$USER:          /disk$user/
  225  *  DISK$USER:[DUNS]        /disk$user/duns
  226  *  DISK$USER:[DUNS.ECHO]       /disk$user/duns/echo
  227  *  [DUNS]              duns
  228  *  [DUNS.ECHO]         duns/echo
  229  *  [DUNS.ECHO.-.TRANS]     duns/echo/../trans
  230  *  [DUNS.ECHO.--.TRANS]        duns/echo/../../trans
  231  *  [.DUNS]             duns
  232  *  [.DUNS.ECHO]            duns/echo
  233  *  [.DUNS.ECHO]TEST.COM        duns/echo/test.com
  234  *  TEST.COM            test.com
  235  *
  236  *
  237  */
  238 const char *HTVMS_wwwName(const char *vmsname)
  239 {
  240     static char wwwname[LY_MAXPATH];
  241     const char *src;
  242     char *dst;
  243     int dir;
  244 
  245     dst = wwwname;
  246     src = vmsname;
  247     dir = 0;
  248     if (StrChr(src, ':'))
  249     *(dst++) = '/';
  250     for (; *src != '\0'; src++) {
  251     switch (*src) {
  252     case ':':
  253         *(dst++) = '/';
  254         break;
  255     case '-':
  256         if (dir) {
  257         if ((*(src - 1) == '[' ||
  258              *(src - 1) == '.' ||
  259              *(src - 1) == '-') &&
  260             (*(src + 1) == '.' ||
  261              *(src + 1) == '-')) {
  262             *(dst++) = '/';
  263             *(dst++) = '.';
  264             *(dst++) = '.';
  265         } else
  266             *(dst++) = '-';
  267         } else {
  268         if (*(src - 1) == ']')
  269             *(dst++) = '/';
  270         *(dst++) = '-';
  271         }
  272         break;
  273     case '.':
  274         if (dir) {
  275         if (*(src - 1) != '[')
  276             *(dst++) = '/';
  277         } else {
  278         if (*(src - 1) == ']')
  279             *(dst++) = '/';
  280         *(dst++) = '.';
  281         }
  282         break;
  283     case '[':
  284         dir = 1;
  285         break;
  286     case ']':
  287         dir = 0;
  288         break;
  289     default:
  290         if (*(src - 1) == ']')
  291         *(dst++) = '/';
  292         *(dst++) = *src;
  293         break;
  294     }
  295     }
  296     *(dst++) = '\0';
  297     return (wwwname);
  298 }
  299 
  300 /*
  301  *  The code below is for directory browsing by VMS Curses clients.
  302  *  It is based on the newer WWWLib's HTDirBrw.c. - Foteos Macrides
  303  */
  304 int HTStat(const char *filename,
  305        struct stat *info)
  306 {
  307     /*
  308        the following stuff does not work in VMS with a normal stat...
  309        -->   /disk$user/duns/www if www is a directory
  310        is statted like:  /disk$user/duns/www.dir
  311        after a normal stat has failed
  312        -->   /disk$user/duns     if duns is a toplevel directory
  313        is statted like:  /disk$user/000000/duns.dir
  314        -->   /disk$user since disk$user is a device
  315        is statted like:  /disk$user/000000/000000.dir
  316        -->   /
  317        searches all devices, no solution yet...
  318        -->   /vxcern!/disk$cr/wwwteam/login.com
  319        is not statted but granted with fake information...
  320      */
  321     int Result;
  322     int Len;
  323     char *Ptr, *Ptr2;
  324     static char *Name;
  325 
  326     /* try normal stat... */
  327     Result = stat((char *) filename, info);
  328     if (Result == 0)
  329     return (Result);
  330 
  331     /* make local copy */
  332     StrAllocCopy(Name, filename);
  333 
  334     /* failed,so do device search in case root is requested */
  335     if (!strcmp(Name, "/")) {   /* root requested */
  336     return (-1);
  337     }
  338 
  339     /* failed so this might be a directory, add '.dir' */
  340     Len = strlen(Name);
  341     if (Name[Len - 1] == '/')
  342     Name[Len - 1] = '\0';
  343 
  344     /* fail in case of device */
  345     Ptr = StrChr(Name + 1, '/');
  346     if ((Ptr == NULL) && (Name[0] == '/')) {    /* device only... */
  347     StrAllocCat(Name, "/000000/000000");
  348     }
  349 
  350     if (Ptr != NULL) {      /* correct filename in case of toplevel dir */
  351     Ptr2 = StrChr(Ptr + 1, '/');
  352     if ((Ptr2 == NULL) && (Name[0] == '/')) {
  353         char End[256];
  354 
  355         LYStrNCpy(End, Ptr, sizeof(End) - 1);
  356         *(Ptr + 1) = '\0';
  357         StrAllocCat(Name, "000000");
  358         StrAllocCat(Name, End);
  359     }
  360     }
  361 
  362     /* try in case a file on toplevel directory or .DIR was already specified */
  363     Result = stat(Name, info);
  364     if (Result == 0)
  365     return (Result);
  366 
  367     /* add .DIR and try again */
  368     StrAllocCat(Name, ".dir");
  369     Result = stat(Name, info);
  370     return (Result);
  371 }
  372 
  373 #ifndef _POSIX_SOURCE
  374 #define d_ino   d_fileno    /* compatability */
  375 #ifndef NULL
  376 #define NULL    0
  377 #endif
  378 #endif /* !_POSIX_SOURCE */
  379 
  380 typedef struct __dirdesc {
  381     long context;       /* context descriptor for LIB$FIND_FILE calls */
  382     char dirname[255 + 1];  /* keeps the directory name, including *.* */
  383     struct dsc$descriptor_s dirname_desc;   /* descriptor of dirname */
  384 } DIR;
  385 
  386 static DIR *HTVMSopendir(char *dirname);
  387 static struct dirent *HTVMSreaddir(DIR *dirp);
  388 static int HTVMSclosedir(DIR *dirp);
  389 
  390 /*** #include <sys_dirent.h> ***/
  391 /*** "sys_dirent.h" ***/
  392 struct dirent {
  393     unsigned long d_fileno; /* file number of entry */
  394     unsigned short d_namlen;    /* length of string in d_name */
  395     char d_name[255 + 1];   /* name (up to MAXNAMLEN + 1) */
  396 };
  397 
  398 #ifndef _POSIX_SOURCE
  399 /*
  400  * It's unlikely to change, but make sure that sizeof d_name above is
  401  * at least MAXNAMLEN + 1 (more may be added for padding).
  402  */
  403 #define MAXNAMLEN   255
  404 /*
  405  * The macro DIRSIZ(dp) gives the minimum amount of space required to represent
  406  * a directory entry.  For any directory entry dp->d_reclen >= DIRSIZ(dp).
  407  * Specific filesystem types may use this macro to construct the value
  408  * for d_reclen.
  409  */
  410 #undef  DIRSIZ
  411 #define DIRSIZ(dp) \
  412     (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3)
  413 
  414 #endif /* !_POSIX_SOURCE */
  415 
  416 static DIR *HTVMSopendir(char *dirname)
  417 {
  418     static DIR dir;
  419     char *closebracket;
  420     long status;
  421     struct dsc$descriptor_s entryname_desc;
  422     struct dsc$descriptor_s dirname_desc;
  423     static char *DirEntry;
  424     char Actual[256];
  425     char VMSentry[256];
  426     char UnixEntry[256];
  427     int index;
  428     char *dot;
  429 
  430     /* check if directory exists */
  431     /* dirname can look like /disk$user/duns/www/test/multi    */
  432     /* or like               /disk$user/duns/www/test/multi/   */
  433     /* DirEntry should look like     disk$user:[duns.www.test]multi in both cases */
  434     /* dir.dirname should look like  disk$user:[duns.www.test.multi] */
  435     sprintf(UnixEntry, "%.*s", sizeof(UnixEntry) - 2, dirname);
  436     if (UnixEntry[strlen(UnixEntry) - 1] != '/')
  437     strcat(UnixEntry, "/");
  438 
  439     StrAllocCopy(DirEntry, HTVMS_name("", UnixEntry));
  440     if (strlen(DirEntry) > sizeof(dir.dirname) - 1)
  441     return (NULL);
  442     strcpy(dir.dirname, DirEntry);
  443     index = strlen(DirEntry) - 1;
  444 
  445     if (DirEntry[index] == ']')
  446     DirEntry[index] = '\0';
  447 
  448     if ((dot = strrchr(DirEntry, '.')) == NULL) {   /* convert disk$user:[duns] into disk$user:[000000]duns.dir */
  449     char *openbr = strrchr(DirEntry, '[');
  450 
  451     if (!openbr) {      /* convert disk$user: into disk$user:[000000]000000.dir */
  452         if (strlen(dir.dirname) > sizeof(dir.dirname) - 10)
  453         return (NULL);
  454         sprintf(dir.dirname, "%.*s[000000]", sizeof(dir.dirname) - 9, DirEntry);
  455         StrAllocCat(DirEntry, "[000000]000000.dir");
  456     } else {
  457         char End[256];
  458 
  459         strcpy(End, openbr + 1);
  460         *(openbr + 1) = '\0';
  461         StrAllocCat(DirEntry, "000000]");
  462         StrAllocCat(DirEntry, End);
  463         StrAllocCat(DirEntry, ".dir");
  464     }
  465     } else {
  466     *dot = ']';
  467     StrAllocCat(DirEntry, ".dir");
  468     }
  469     /* lib$find_file needs a fixed-size buffer */
  470     LYStrNCpy(Actual, DirEntry, sizeof(Actual) - 1);
  471 
  472     dir.context = 0;
  473     dirname_desc.dsc$w_length = strlen(Actual);
  474     dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  475     dirname_desc.dsc$b_class = DSC$K_CLASS_S;
  476     dirname_desc.dsc$a_pointer = (char *) &(Actual);
  477 
  478     /* look for the directory */
  479     entryname_desc.dsc$w_length = 255;
  480     entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  481     entryname_desc.dsc$b_class = DSC$K_CLASS_S;
  482     entryname_desc.dsc$a_pointer = VMSentry;
  483 
  484     status = lib$find_file(&(dirname_desc),
  485                &entryname_desc,
  486                &(dir.context),
  487                0, 0, 0, 0);
  488     if (!(status & 0x01)) { /* directory not found */
  489     return (NULL);
  490     }
  491 
  492     if (strlen(dir.dirname) > sizeof(dir.dirname) - 10)
  493     return (NULL);
  494     if (HTVMSFileVersions)
  495     strcat(dir.dirname, "*.*;*");
  496     else
  497     strcat(dir.dirname, "*.*");
  498     dir.context = 0;
  499     dir.dirname_desc.dsc$w_length = strlen(dir.dirname);
  500     dir.dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  501     dir.dirname_desc.dsc$b_class = DSC$K_CLASS_S;
  502     dir.dirname_desc.dsc$a_pointer = (char *) &(dir.dirname);
  503     return (&dir);
  504 }
  505 
  506 static struct dirent *HTVMSreaddir(DIR *dirp)
  507 {
  508     static struct dirent entry;
  509     long status;
  510     struct dsc$descriptor_s entryname_desc;
  511     char *space, *slash;
  512     char VMSentry[256];
  513     const char *UnixEntry;
  514 
  515     entryname_desc.dsc$w_length = 255;
  516     entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  517     entryname_desc.dsc$b_class = DSC$K_CLASS_S;
  518     entryname_desc.dsc$a_pointer = VMSentry;
  519 
  520     status = lib$find_file(&(dirp->dirname_desc),
  521                &entryname_desc,
  522                &(dirp->context),
  523                0, 0, 0, 0);
  524     if (status == RMS$_NMF) {   /* no more files */
  525     return (NULL);
  526     } else {            /* ok */
  527     if (!(status & 0x01))
  528         return (0);
  529     if (HTVMSFileVersions)
  530         space = StrChr(VMSentry, ' ');
  531     else
  532         space = StrChr(VMSentry, ';');
  533     if (space)
  534         *space = '\0';
  535 
  536     /* convert to unix style... */
  537     UnixEntry = HTVMS_wwwName(VMSentry);
  538     slash = strrchr(UnixEntry, '/') + 1;
  539     strcpy(entry.d_name, slash);
  540     entry.d_namlen = strlen(entry.d_name);
  541     entry.d_fileno = 1;
  542     return (&entry);
  543     }
  544 }
  545 
  546 static int HTVMSclosedir(DIR *dirp)
  547 {
  548     long status;
  549 
  550     status = lib$find_file_end(&(dirp->context));
  551     if (!(status & 0x01))
  552     exit_immediately(status);
  553     dirp->context = 0;
  554     return (0);
  555 }
  556 
  557 #include <HTAnchor.h>
  558 #include <HTParse.h>
  559 #include <HTBTree.h>
  560 #include <HTFile.h>     /* For HTFileFormat() */
  561 #include <HTAlert.h>
  562 /*
  563  *  Hypertext object building machinery.
  564  */
  565 #include <HTML.h>
  566 #define PUTC(c) (*targetClass.put_character)(target, c)
  567 #define PUTS(s) (*targetClass.put_string)(target, s)
  568 #define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0)
  569 #define END(e) (*targetClass.end_element)(target, e, 0)
  570 #define FREE_TARGET (*targetClass._free)(target)
  571 #define ABORT_TARGET (*targetClass._free)(target)
  572 struct _HTStructured {
  573     const HTStructuredClass *isa;
  574     /* ... */
  575 };
  576 
  577 #define STRUCT_DIRENT struct dirent
  578 
  579 static char *months[12] =
  580 {
  581     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  582     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  583 };
  584 
  585 typedef struct _VMSEntryInfo {
  586     char *filename;
  587     char *type;
  588     char *date;
  589     unsigned int size;
  590     BOOLEAN display;        /* show this entry? */
  591 } VMSEntryInfo;
  592 
  593 static void free_VMSEntryInfo_contents(VMSEntryInfo * entry_info)
  594 {
  595     if (entry_info) {
  596     FREE(entry_info->filename);
  597     FREE(entry_info->type);
  598     FREE(entry_info->date);
  599     }
  600     /* dont free the struct */
  601 }
  602 
  603 int compare_VMSEntryInfo_structs(VMSEntryInfo * entry1, VMSEntryInfo * entry2)
  604 {
  605     int i, status;
  606     char date1[16], date2[16], time1[8], time2[8], month[4];
  607 
  608     switch (HTfileSortMethod) {
  609     case FILE_BY_SIZE:
  610     /* both equal or both 0 */
  611     if (entry1->size == entry2->size)
  612         return (strcasecomp(entry1->filename,
  613                 entry2->filename));
  614     else if (entry1->size > entry2->size)
  615         return (1);
  616     else
  617         return (-1);
  618     case FILE_BY_TYPE:
  619     if (entry1->type && entry2->type) {
  620         status = strcasecomp(entry1->type, entry2->type);
  621         if (status)
  622         return (status);
  623         /* else fall to filename comparison */
  624     }
  625     return (strcasecomp(entry1->filename,
  626                 entry2->filename));
  627     case FILE_BY_DATE:
  628     if (entry1->date && entry2->date) {
  629         /*
  630          * Make sure we have the correct length. - FM
  631          */
  632         if (strlen(entry1->date) != 12 ||
  633         strlen(entry2->date) != 12) {
  634         return (strcasecomp(entry1->filename,
  635                     entry2->filename));
  636         }
  637         /*
  638          * Set up for sorting in reverse
  639          * chronological order. - FM
  640          */
  641         if (entry1->date[7] != ' ') {
  642         strcpy(date1, "9999");
  643         strcpy(time1, (char *) &entry1->date[7]);
  644         } else {
  645         strcpy(date1, (char *) &entry1->date[8]);
  646         strcpy(time1, "00:00");
  647         }
  648         LYStrNCpy(month, entry1->date, 3);
  649         for (i = 0; i < 12; i++) {
  650         if (!strcasecomp(month, months[i])) {
  651             break;
  652         }
  653         }
  654         i++;
  655         sprintf(month, "%02d", i);
  656         strcat(date1, month);
  657         StrNCat(date1, (char *) &entry1->date[4], 2);
  658         date1[8] = '\0';
  659         if (date1[6] == ' ') {
  660         date1[6] = '0';
  661         }
  662         strcat(date1, time1);
  663         if (entry2->date[7] != ' ') {
  664         strcpy(date2, "9999");
  665         strcpy(time2, (char *) &entry2->date[7]);
  666         } else {
  667         strcpy(date2, (char *) &entry2->date[8]);
  668         strcpy(time2, "00:00");
  669         }
  670         LYStrNCpy(month, entry2->date, 3);
  671         for (i = 0; i < 12; i++) {
  672         if (!strcasecomp(month, months[i])) {
  673             break;
  674         }
  675         }
  676         i++;
  677         sprintf(month, "%02d", i);
  678         strcat(date2, month);
  679         StrNCat(date2, (char *) &entry2->date[4], 2);
  680         date2[8] = '\0';
  681         if (date2[6] == ' ') {
  682         date2[6] = '0';
  683         }
  684         strcat(date2, time2);
  685         /*
  686          * Do the comparison. - FM
  687          */
  688         status = strcasecomp(date2, date1);
  689         if (status)
  690         return (status);
  691         /* else fall to filename comparison */
  692     }
  693     return (strcasecomp(entry1->filename,
  694                 entry2->filename));
  695     case FILE_BY_NAME:
  696     default:
  697     return (strcmp(entry1->filename,
  698                entry2->filename));
  699     }
  700 }
  701 
  702 /*                          HTVMSBrowseDir()
  703  *
  704  *  This function generates a directory listing as an HTML-object
  705  *  for local file URL's.  It assumes the first two elements of
  706  *  of the path are a device followed by a directory:
  707  *
  708  *      file://localhost/device/directory[/[foo]]
  709  *
  710  *  Will not accept 000000 as a directory name.
  711  *  Will offer links to parent through the top directory, unless
  712  *  a terminal slash was included in the calling URL.
  713  *
  714  *  Returns HT_LOADED on success, HTLoadError() messages on error.
  715  *
  716  *  Developed for Lynx by Foteos Macrides (macrides@sci.wfeb.edu).
  717  */
  718 int HTVMSBrowseDir(const char *address,
  719            HTParentAnchor *anchor,
  720            HTFormat format_out,
  721            HTStream *sink)
  722 {
  723     HTStructured *target;
  724     HTStructuredClass targetClass;
  725     char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION);
  726     char *tail = NULL;
  727     char *title = NULL;
  728     char *header = NULL;
  729     char *parent = NULL;
  730     char *relative = NULL;
  731     char *cp, *cp1;
  732     int pathend, len;
  733     DIR *dp;
  734     struct stat file_info;
  735     time_t NowTime;
  736     static char ThisYear[8];
  737     VMSEntryInfo *entry_info = 0;
  738     char string_buffer[64];
  739 
  740     HTUnEscape(pathname);
  741     CTRACE((tfp, "HTVMSBrowseDir: Browsing `%s\'\n", pathname));
  742 
  743     /*
  744      * Require at least two elements (presumably a device and directory) and
  745      * disallow the device root (000000 directory).  Symbolic paths (e.g.,
  746      * sys$help) should have been translated and expanded (e.g., to
  747      * /sys$sysroot/syshlp) before calling this routine.
  748      */
  749     if (((*pathname != '/') ||
  750      (cp = StrChr(pathname + 1, '/')) == NULL ||
  751      *(cp + 1) == '\0' ||
  752      0 == StrNCmp((cp + 1), "000000", 6)) ||
  753     (dp = HTVMSopendir(pathname)) == NULL) {
  754     FREE(pathname);
  755     return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR);
  756     }
  757 
  758     /*
  759      * Set up the output stream.
  760      */
  761     _HTProgress(BUILDING_DIR_LIST);
  762     if (UCLYhndl_HTFile_for_unspec >= 0) {
  763     HTAnchor_setUCInfoStage(anchor,
  764                 UCLYhndl_HTFile_for_unspec,
  765                 UCT_STAGE_PARSER,
  766                 UCT_SETBY_DEFAULT);
  767     }
  768     target = HTML_new(anchor, format_out, sink);
  769     targetClass = *(target->isa);
  770 
  771     /*
  772      * Set up the offset string of the anchor reference, and strings for the
  773      * title and header.
  774      */
  775     cp = strrchr(pathname, '/');    /* find lastslash */
  776     StrAllocCopy(tail, (cp + 1));   /* take slash off the beginning */
  777     if (*tail != '\0') {
  778     StrAllocCopy(title, tail);
  779     *cp = '\0';
  780     if ((cp1 = strrchr(pathname, '/')) != NULL &&
  781         cp1 != pathname &&
  782         StrNCmp((cp1 + 1), "000000", 6))
  783         StrAllocCopy(parent, (cp1 + 1));
  784     *cp = '/';
  785     } else {
  786     pathname[strlen(pathname) - 1] = '\0';
  787     cp = strrchr(pathname, '/');
  788     StrAllocCopy(title, (cp + 1));
  789     pathname[strlen(pathname)] = '/';
  790     }
  791     StrAllocCopy(header, pathname);
  792 
  793     /*
  794      * Initialize path name for HTStat().
  795      */
  796     pathend = strlen(pathname);
  797     if (*(pathname + pathend - 1) != '/') {
  798     StrAllocCat(pathname, "/");
  799     pathend++;
  800     }
  801 
  802     /*
  803      * Output the title and header.
  804      */
  805     START(HTML_HTML);
  806     PUTC('\n');
  807     START(HTML_HEAD);
  808     PUTC('\n');
  809     HTUnEscape(title);
  810     START(HTML_TITLE);
  811     PUTS(title);
  812     PUTS(" directory");
  813     END(HTML_TITLE);
  814     PUTC('\n');
  815     FREE(title);
  816     END(HTML_HEAD);
  817     PUTC('\n');
  818     START(HTML_BODY);
  819     PUTC('\n');
  820     HTUnEscape(header);
  821     START(HTML_H1);
  822     PUTS(header);
  823     END(HTML_H1);
  824     PUTC('\n');
  825     if (HTDirReadme == HT_DIR_README_TOP) {
  826     FILE *fp;
  827 
  828     if (header[strlen(header) - 1] != '/')
  829         StrAllocCat(header, "/");
  830     StrAllocCat(header, HT_DIR_README_FILE);
  831     if ((fp = fopen(header, "r")) != NULL) {
  832         START(HTML_PRE);
  833         for (;;) {
  834         char c = fgetc(fp);
  835 
  836         if (c == (char) EOF)
  837             break;
  838 #ifdef NOTDEFINED
  839         switch (c) {
  840         case '&':
  841         case '<':
  842         case '>':
  843             PUTC('&');
  844             PUTC('#');
  845             PUTC((char) (c / 10));
  846             PUTC((char) (c % 10));
  847             PUTC(';');
  848             break;
  849         default:
  850             PUTC(c);
  851         }
  852 #else
  853         PUTC(c);
  854 #endif /* NOTDEFINED */
  855         }
  856         END(HTML_PRE);
  857         fclose(fp);
  858     }
  859     }
  860     FREE(header);
  861     if (parent) {
  862     HTSprintf0(&relative, "%s/..", tail);
  863     HTStartAnchor(target, "", relative);
  864     PUTS("Up to ");
  865     HTUnEscape(parent);
  866     PUTS(parent);
  867     END(HTML_A);
  868     START(HTML_P);
  869     PUTC('\n');
  870     FREE(relative);
  871     FREE(parent);
  872     }
  873 
  874     /*
  875      * Set up the date comparison.
  876      */
  877     NowTime = time(NULL);
  878     strcpy(ThisYear, (char *) ctime(&NowTime) + 20);
  879     ThisYear[4] = '\0';
  880 
  881     /*
  882      * Now, generate the Btree and put it out to the output stream.
  883      */
  884     {
  885     char dottest = 2;   /* To avoid two strcmp() each time */
  886     STRUCT_DIRENT *dirbuf;
  887     HTBTree *bt;
  888 
  889     /* Set up sort key and initialize BTree */
  890     bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs);
  891 
  892     /* Build tree */
  893     while ((dirbuf = HTVMSreaddir(dp))) {
  894         HTAtom *encoding = NULL;
  895         HTFormat format;
  896 
  897         /* Skip if not used */
  898         if (!dirbuf->d_ino) {
  899         continue;
  900         }
  901 
  902         /* Current and parent directories are never shown in list */
  903         if (dottest && (!strcmp(dirbuf->d_name, ".") ||
  904                 !strcmp(dirbuf->d_name, ".."))) {
  905         dottest--;
  906         continue;
  907         }
  908 
  909         /* Don't show the selective enabling file
  910          * unless version numbers are included */
  911         if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) {
  912         continue;
  913         }
  914 
  915         /* Skip files beginning with a dot? */
  916         if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') {
  917         continue;
  918         }
  919 
  920         /* OK, make an lstat() and get a key ready. */
  921         *(pathname + pathend) = '\0';
  922         StrAllocCat(pathname, dirbuf->d_name);
  923         if (HTStat(pathname, &file_info)) {
  924         /* for VMS the failure here means the file is not readable...
  925            we however continue to browse through the directory... */
  926         continue;
  927         }
  928         entry_info = (VMSEntryInfo *) malloc(sizeof(VMSEntryInfo));
  929         if (entry_info == NULL)
  930         outofmem(__FILE__, "HTVMSBrowseDir");
  931         entry_info->type = 0;
  932         entry_info->size = 0;
  933         entry_info->date = 0;
  934         entry_info->filename = 0;
  935         entry_info->display = TRUE;
  936 
  937         /* Get the type */
  938         format = HTFileFormat(dirbuf->d_name, &encoding,
  939                   (const char **) &cp);
  940         if (!cp) {
  941         if (!StrNCmp(HTAtom_name(format), "application", 11)) {
  942             cp = HTAtom_name(format) + 12;
  943             if (!StrNCmp(cp, "x-", 2))
  944             cp += 2;
  945         } else
  946             cp = HTAtom_name(format);
  947         }
  948         StrAllocCopy(entry_info->type, cp);
  949 
  950         StrAllocCopy(entry_info->filename, dirbuf->d_name);
  951         if (S_ISDIR(file_info.st_mode)) {
  952         /* strip .DIR part... */
  953         char *dot;
  954 
  955         dot = strstr(entry_info->filename, ".DIR");
  956         if (dot)
  957             *dot = '\0';
  958         LYLowerCase(entry_info->filename);
  959         StrAllocCopy(entry_info->type, "Directory");
  960         } else {
  961         if ((cp = strstr(entry_info->filename, "READ")) == NULL) {
  962             cp = entry_info->filename;
  963         } else {
  964             cp += 4;
  965             if (!StrNCmp(cp, "ME", 2)) {
  966             cp += 2;
  967             while (cp && *cp && *cp != '.') {
  968                 cp++;
  969             }
  970             } else if (!StrNCmp(cp, ".ME", 3)) {
  971             cp = (entry_info->filename +
  972                   strlen(entry_info->filename));
  973             } else {
  974             cp = entry_info->filename;
  975             }
  976         }
  977         LYLowerCase(cp);
  978         if (((len = strlen(entry_info->filename)) > 2) &&
  979             entry_info->filename[len - 1] == 'z') {
  980             if (entry_info->filename[len - 2] == '.' ||
  981             entry_info->filename[len - 2] == '_')
  982             entry_info->filename[len - 1] = 'Z';
  983         }
  984         }
  985 
  986         /* Get the date */
  987         {
  988         char *t = (char *) ctime((const time_t *) &file_info.st_ctime);
  989 
  990         *(t + 24) = '\0';
  991 
  992         StrAllocCopy(entry_info->date, (t + 4));
  993         *((entry_info->date) + 7) = '\0';
  994         if ((atoi((t + 19))) < atoi(ThisYear))
  995             StrAllocCat(entry_info->date, (t + 19));
  996         else {
  997             StrAllocCat(entry_info->date, (t + 11));
  998             *((entry_info->date) + 12) = '\0';
  999         }
 1000         }
 1001 
 1002         /* Get the size */
 1003         if (!S_ISDIR(file_info.st_mode))
 1004         entry_info->size = (unsigned int) file_info.st_size;
 1005         else
 1006         entry_info->size = 0;
 1007 
 1008         /* Now, update the BTree etc. */
 1009         if (entry_info->display) {
 1010         CTRACE((tfp, "Adding file to BTree: %s\n",
 1011             entry_info->filename));
 1012         HTBTree_add(bt, entry_info);
 1013         }
 1014 
 1015     }           /* End while HTVMSreaddir() */
 1016 
 1017     FREE(pathname);
 1018     HTVMSclosedir(dp);
 1019 
 1020     START(HTML_PRE);
 1021     /*
 1022      * Run through the BTree printing out in order
 1023      */
 1024     {
 1025         HTBTElement *ele;
 1026         int i;
 1027 
 1028         for (ele = HTBTree_next(bt, NULL);
 1029          ele != NULL;
 1030          ele = HTBTree_next(bt, ele)) {
 1031         entry_info = (VMSEntryInfo *) HTBTree_object(ele);
 1032 
 1033         /* Output the date */
 1034         if (entry_info->date) {
 1035             PUTS(entry_info->date);
 1036             PUTS("  ");
 1037         } else
 1038             PUTS("     * ");
 1039 
 1040         /* Output the type */
 1041         if (entry_info->type) {
 1042             for (i = 0; entry_info->type[i] != '\0' && i < 15; i++)
 1043             PUTC(entry_info->type[i]);
 1044             for (; i < 17; i++)
 1045             PUTC(' ');
 1046 
 1047         }
 1048 
 1049         /* Output the link for the name */
 1050         HTDirEntry(target, tail, entry_info->filename);
 1051         PUTS(entry_info->filename);
 1052         END(HTML_A);
 1053 
 1054         /* Output the size */
 1055         if (entry_info->size) {
 1056             if (entry_info->size < 1024)
 1057             sprintf(string_buffer, "  %d bytes",
 1058                 entry_info->size);
 1059             else
 1060             sprintf(string_buffer, "  %dKb",
 1061                 entry_info->size / 1024);
 1062             PUTS(string_buffer);
 1063         }
 1064 
 1065         PUTC('\n'); /* end of this entry */
 1066 
 1067         free_VMSEntryInfo_contents(entry_info);
 1068         }
 1069     }
 1070 
 1071     HTBTreeAndObject_free(bt);
 1072 
 1073     }               /* End of both BTree loops */
 1074 
 1075     /*
 1076      * Complete the output stream.
 1077      */
 1078     END(HTML_PRE);
 1079     PUTC('\n');
 1080     END(HTML_BODY);
 1081     PUTC('\n');
 1082     END(HTML_HTML);
 1083     PUTC('\n');
 1084     FREE(tail);
 1085     FREE_TARGET;
 1086 
 1087     return HT_LOADED;
 1088 
 1089 }               /* End of directory reading section */
 1090 
 1091 /*
 1092  * Remove all versions of the given file.  We assume there are no permissions
 1093  * problems, since we do this mainly for removing temporary files.
 1094  */
 1095 int HTVMS_remove(char *filename)
 1096 {
 1097     int code = remove(filename);    /* return the first status code */
 1098 
 1099     while (remove(filename) == 0) ;
 1100     return code;
 1101 }
 1102 
 1103 /*
 1104  * Remove all older versions of the given file.  We may fail to remove some
 1105  * version due to permissions -- the loop stops either at that point, or when
 1106  * we run out of older versions to remove.
 1107  */
 1108 void HTVMS_purge(char *filename)
 1109 {
 1110     char *older_file = 0;
 1111     char *oldest_file = 0;
 1112     struct stat sb;
 1113 
 1114     StrAllocCopy(older_file, filename);
 1115     StrAllocCat(older_file, ";-1");
 1116 
 1117     while (remove(older_file) == 0) ;
 1118     /*
 1119      * If we do not have any more older versions, it is safe to rename the
 1120      * current file to version #1.
 1121      */
 1122     if (stat(older_file, &sb) != 0) {
 1123     StrAllocCopy(oldest_file, filename);
 1124     StrAllocCat(oldest_file, ";1");
 1125     rename(older_file, oldest_file);
 1126     FREE(oldest_file);
 1127     }
 1128 
 1129     FREE(older_file);
 1130 }
 1131 #endif /* VMS */