diff options
Diffstat (limited to 'WWW/Library/Implementation/HTVMSUtils.c')
-rw-r--r-- | WWW/Library/Implementation/HTVMSUtils.c | 1131 |
1 files changed, 1131 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTVMSUtils.c b/WWW/Library/Implementation/HTVMSUtils.c new file mode 100644 index 0000000..38e583a --- /dev/null +++ b/WWW/Library/Implementation/HTVMSUtils.c @@ -0,0 +1,1131 @@ +/* + * $LynxId: HTVMSUtils.c,v 1.40 2020/01/21 21:58:29 tom Exp $ + * + * MODULE HTVMSUtil.c + * VMS Utility Routines + * + * AUTHORS: + * MD Mark Donszelmann duns@vxdeop.cern.ch + * + * HISTORY: + * 14 Nov 93 MD Written + * + * BUGS: + * + * + */ + +#include <HTUtils.h> +#ifdef VMS +#include <HTFormat.h> +#include <HTStream.h> +#include <UCDefs.h> +#include <UCMap.h> +#include <UCAux.h> +#include <HTFTP.h> +#include <HTTCP.h> +#include <HTVMSUtils.h> +#include <ssdef.h> +#include <jpidef.h> +#include <prvdef.h> +#include <acldef.h> +#include <chpdef.h> +#include <descrip.h> +#include <lib$routines.h> +#include <starlet.h> +#include <rmsdef.h> + +#include <LYGlobalDefs.h> +#include <LYUtils.h> +#include <LYLeaks.h> +#include <LYStrings.h> + +BOOL HTVMSFileVersions = FALSE; /* Include version numbers in listing? */ + +typedef struct { + unsigned long BufferLength:16; + unsigned long ItemCode:16; + unsigned long BufferAddress:32; + unsigned long ReturnLengthAddress:32; +} ItemStruct; + +/* PUBLIC HTVMS_authSysPrv() + * CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV + * ON ENTRY: + * No arguments. + * + * ON EXIT: + * returns YES if SYSPRV is authorized + */ +BOOL HTVMS_authSysPrv(void) +{ + unsigned long Result; + ItemStruct ItemList[2]; + unsigned long Length; + unsigned long Buffer[2]; + + /* fill Item */ + ItemList[0].BufferLength = sizeof(Buffer); + ItemList[0].BufferAddress = (unsigned long) Buffer; + ItemList[0].ReturnLengthAddress = (unsigned long) &Length; + ItemList[0].ItemCode = JPI$_AUTHPRIV; + + /* terminate list */ + ItemList[1].ItemCode = 0; + ItemList[1].BufferLength = 0; + + /* call system */ + Result = sys$getjpiw(0, 0, 0, ItemList, 0, 0, 0); + + if (Result != SS$_NORMAL) + return (NO); + + if (Buffer[0] & PRV$M_SYSPRV) + return (YES); + + return (NO); +} + +/* PUBLIC HTVMS_enableSysPrv() + * ENABLES SYSPRV + * ON ENTRY: + * No arguments. + * + * ON EXIT: + * + */ +void HTVMS_enableSysPrv(void) +{ + unsigned long Result; + unsigned long Prv[2], PreviousPrv[2]; + + Prv[0] = PRV$M_SYSPRV; + Prv[1] = 0; + Result = sys$setprv(1, &Prv, 0, &PreviousPrv); + + if (Result == SS$_NORMAL) { + if (!(PreviousPrv[0] & PRV$M_SYSPRV)) { + CTRACE((tfp, "HTVMS_enableSysPrv: Enabled SYSPRV\n")); + } + } +} + +/* PUBLIC HTVMS_disableSysPrv() + * DISABLES SYSPRV + * ON ENTRY: + * No arguments. + * + * ON EXIT: + * + */ +void HTVMS_disableSysPrv(void) +{ + unsigned long Result; + unsigned long Prv[2], PreviousPrv[2]; + + Prv[0] = PRV$M_SYSPRV; + Prv[1] = 0; + Result = sys$setprv(0, &Prv, 0, &PreviousPrv); + + if (Result == SS$_NORMAL) { + if (PreviousPrv[0] & PRV$M_SYSPRV) { + CTRACE((tfp, "HTVMS_disableSysPrv: Disabled SYSPRV\n")); + } + } +} + +/* PUBLIC HTVMS_checkAccess() + * CHECKS ACCESS TO FILE FOR CERTAIN USER + * ON ENTRY: + * FileName The file to be accessed + * UserName Name of the user to check access for. + * User nobody, represented by "" is given NO for an answer + * Method Name of the method to be checked + * + * ON EXIT: + * returns YES if access is allowed + * + */ +BOOL HTVMS_checkAccess(const char *FileName, + const char *UserName, + const char *Method) +{ + unsigned long Result; + ItemStruct ItemList[2]; + unsigned long Length; + unsigned long Buffer; + unsigned long ObjType; + + char *VmsName; + + struct dsc$descriptor_s FileNameDesc; + struct dsc$descriptor_s UserNameDesc; + + char *colon; + + /* user nobody should access as from account under which server is running */ + if (0 == strcmp(UserName, "")) + return (NO); + + /* check Filename and convert */ + colon = StrChr(FileName, ':'); + if (colon) + VmsName = HTVMS_name("", colon + 1); + else + VmsName = HTVMS_name("", FileName); + + /* check for GET */ + if (0 == strcmp(Method, "GET")) { + /* fill Item */ + ItemList[0].BufferLength = sizeof(Buffer); + ItemList[0].BufferAddress = (unsigned long) &Buffer; + ItemList[0].ReturnLengthAddress = (unsigned long) &Length; + ItemList[0].ItemCode = CHP$_FLAGS; + + /* terminate list */ + ItemList[1].ItemCode = 0; + ItemList[1].BufferLength = 0; + + /* fill input */ + ObjType = ACL$C_FILE; + Buffer = CHP$M_READ; + UserNameDesc.dsc$w_length = strlen(UserName); + UserNameDesc.dsc$b_dtype = DSC$K_DTYPE_T; + UserNameDesc.dsc$b_class = DSC$K_CLASS_S; + UserNameDesc.dsc$a_pointer = (char *) UserName; + FileNameDesc.dsc$w_length = strlen(VmsName); + FileNameDesc.dsc$b_dtype = DSC$K_DTYPE_T; + FileNameDesc.dsc$b_class = DSC$K_CLASS_S; + FileNameDesc.dsc$a_pointer = VmsName; + + /* call system */ + Result = sys$check_access(&ObjType, &FileNameDesc, &UserNameDesc, ItemList); + + if (Result == SS$_NORMAL) + return (YES); + else + return (NO); + } + + return (NO); +} + +/* PUBLIC HTVMS_wwwName() + * CONVERTS VMS Name into WWW Name + * ON ENTRY: + * vmsname VMS file specification (NO NODE) + * + * ON EXIT: + * returns www file specification + * + * EXAMPLES: + * vmsname wwwname + * DISK$USER disk$user + * DISK$USER: /disk$user/ + * DISK$USER:[DUNS] /disk$user/duns + * DISK$USER:[DUNS.ECHO] /disk$user/duns/echo + * [DUNS] duns + * [DUNS.ECHO] duns/echo + * [DUNS.ECHO.-.TRANS] duns/echo/../trans + * [DUNS.ECHO.--.TRANS] duns/echo/../../trans + * [.DUNS] duns + * [.DUNS.ECHO] duns/echo + * [.DUNS.ECHO]TEST.COM duns/echo/test.com + * TEST.COM test.com + * + * + */ +const char *HTVMS_wwwName(const char *vmsname) +{ + static char wwwname[LY_MAXPATH]; + const char *src; + char *dst; + int dir; + + dst = wwwname; + src = vmsname; + dir = 0; + if (StrChr(src, ':')) + *(dst++) = '/'; + for (; *src != '\0'; src++) { + switch (*src) { + case ':': + *(dst++) = '/'; + break; + case '-': + if (dir) { + if ((*(src - 1) == '[' || + *(src - 1) == '.' || + *(src - 1) == '-') && + (*(src + 1) == '.' || + *(src + 1) == '-')) { + *(dst++) = '/'; + *(dst++) = '.'; + *(dst++) = '.'; + } else + *(dst++) = '-'; + } else { + if (*(src - 1) == ']') + *(dst++) = '/'; + *(dst++) = '-'; + } + break; + case '.': + if (dir) { + if (*(src - 1) != '[') + *(dst++) = '/'; + } else { + if (*(src - 1) == ']') + *(dst++) = '/'; + *(dst++) = '.'; + } + break; + case '[': + dir = 1; + break; + case ']': + dir = 0; + break; + default: + if (*(src - 1) == ']') + *(dst++) = '/'; + *(dst++) = *src; + break; + } + } + *(dst++) = '\0'; + return (wwwname); +} + +/* + * The code below is for directory browsing by VMS Curses clients. + * It is based on the newer WWWLib's HTDirBrw.c. - Foteos Macrides + */ +int HTStat(const char *filename, + struct stat *info) +{ + /* + the following stuff does not work in VMS with a normal stat... + --> /disk$user/duns/www if www is a directory + is statted like: /disk$user/duns/www.dir + after a normal stat has failed + --> /disk$user/duns if duns is a toplevel directory + is statted like: /disk$user/000000/duns.dir + --> /disk$user since disk$user is a device + is statted like: /disk$user/000000/000000.dir + --> / + searches all devices, no solution yet... + --> /vxcern!/disk$cr/wwwteam/login.com + is not statted but granted with fake information... + */ + int Result; + int Len; + char *Ptr, *Ptr2; + static char *Name; + + /* try normal stat... */ + Result = stat((char *) filename, info); + if (Result == 0) + return (Result); + + /* make local copy */ + StrAllocCopy(Name, filename); + + /* failed,so do device search in case root is requested */ + if (!strcmp(Name, "/")) { /* root requested */ + return (-1); + } + + /* failed so this might be a directory, add '.dir' */ + Len = strlen(Name); + if (Name[Len - 1] == '/') + Name[Len - 1] = '\0'; + + /* fail in case of device */ + Ptr = StrChr(Name + 1, '/'); + if ((Ptr == NULL) && (Name[0] == '/')) { /* device only... */ + StrAllocCat(Name, "/000000/000000"); + } + + if (Ptr != NULL) { /* correct filename in case of toplevel dir */ + Ptr2 = StrChr(Ptr + 1, '/'); + if ((Ptr2 == NULL) && (Name[0] == '/')) { + char End[256]; + + LYStrNCpy(End, Ptr, sizeof(End) - 1); + *(Ptr + 1) = '\0'; + StrAllocCat(Name, "000000"); + StrAllocCat(Name, End); + } + } + + /* try in case a file on toplevel directory or .DIR was already specified */ + Result = stat(Name, info); + if (Result == 0) + return (Result); + + /* add .DIR and try again */ + StrAllocCat(Name, ".dir"); + Result = stat(Name, info); + return (Result); +} + +#ifndef _POSIX_SOURCE +#define d_ino d_fileno /* compatibility */ +#ifndef NULL +#define NULL 0 +#endif +#endif /* !_POSIX_SOURCE */ + +typedef struct __dirdesc { + long context; /* context descriptor for LIB$FIND_FILE calls */ + char dirname[255 + 1]; /* keeps the directory name, including *.* */ + struct dsc$descriptor_s dirname_desc; /* descriptor of dirname */ +} DIR; + +static DIR *HTVMSopendir(char *dirname); +static struct dirent *HTVMSreaddir(DIR *dirp); +static int HTVMSclosedir(DIR *dirp); + +/*** #include <sys_dirent.h> ***/ +/*** "sys_dirent.h" ***/ +struct dirent { + unsigned long d_fileno; /* file number of entry */ + unsigned short d_namlen; /* length of string in d_name */ + char d_name[255 + 1]; /* name (up to MAXNAMLEN + 1) */ +}; + +#ifndef _POSIX_SOURCE +/* + * It's unlikely to change, but make sure that sizeof d_name above is + * at least MAXNAMLEN + 1 (more may be added for padding). + */ +#define MAXNAMLEN 255 +/* + * The macro DIRSIZ(dp) gives the minimum amount of space required to represent + * a directory entry. For any directory entry dp->d_reclen >= DIRSIZ(dp). + * Specific filesystem types may use this macro to construct the value + * for d_reclen. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ + (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3) + +#endif /* !_POSIX_SOURCE */ + +static DIR *HTVMSopendir(char *dirname) +{ + static DIR dir; + char *closebracket; + long status; + struct dsc$descriptor_s entryname_desc; + struct dsc$descriptor_s dirname_desc; + static char *DirEntry; + char Actual[256]; + char VMSentry[256]; + char UnixEntry[256]; + int index; + char *dot; + + /* check if directory exists */ + /* dirname can look like /disk$user/duns/www/test/multi */ + /* or like /disk$user/duns/www/test/multi/ */ + /* DirEntry should look like disk$user:[duns.www.test]multi in both cases */ + /* dir.dirname should look like disk$user:[duns.www.test.multi] */ + sprintf(UnixEntry, "%.*s", sizeof(UnixEntry) - 2, dirname); + if (UnixEntry[strlen(UnixEntry) - 1] != '/') + strcat(UnixEntry, "/"); + + StrAllocCopy(DirEntry, HTVMS_name("", UnixEntry)); + if (strlen(DirEntry) > sizeof(dir.dirname) - 1) + return (NULL); + strcpy(dir.dirname, DirEntry); + index = strlen(DirEntry) - 1; + + if (DirEntry[index] == ']') + DirEntry[index] = '\0'; + + if ((dot = strrchr(DirEntry, '.')) == NULL) { /* convert disk$user:[duns] into disk$user:[000000]duns.dir */ + char *openbr = strrchr(DirEntry, '['); + + if (!openbr) { /* convert disk$user: into disk$user:[000000]000000.dir */ + if (strlen(dir.dirname) > sizeof(dir.dirname) - 10) + return (NULL); + sprintf(dir.dirname, "%.*s[000000]", sizeof(dir.dirname) - 9, DirEntry); + StrAllocCat(DirEntry, "[000000]000000.dir"); + } else { + char End[256]; + + strcpy(End, openbr + 1); + *(openbr + 1) = '\0'; + StrAllocCat(DirEntry, "000000]"); + StrAllocCat(DirEntry, End); + StrAllocCat(DirEntry, ".dir"); + } + } else { + *dot = ']'; + StrAllocCat(DirEntry, ".dir"); + } + /* lib$find_file needs a fixed-size buffer */ + LYStrNCpy(Actual, DirEntry, sizeof(Actual) - 1); + + dir.context = 0; + dirname_desc.dsc$w_length = strlen(Actual); + dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + dirname_desc.dsc$b_class = DSC$K_CLASS_S; + dirname_desc.dsc$a_pointer = (char *) &(Actual); + + /* look for the directory */ + entryname_desc.dsc$w_length = 255; + entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + entryname_desc.dsc$b_class = DSC$K_CLASS_S; + entryname_desc.dsc$a_pointer = VMSentry; + + status = lib$find_file(&(dirname_desc), + &entryname_desc, + &(dir.context), + 0, 0, 0, 0); + if (!(status & 0x01)) { /* directory not found */ + return (NULL); + } + + if (strlen(dir.dirname) > sizeof(dir.dirname) - 10) + return (NULL); + if (HTVMSFileVersions) + strcat(dir.dirname, "*.*;*"); + else + strcat(dir.dirname, "*.*"); + dir.context = 0; + dir.dirname_desc.dsc$w_length = strlen(dir.dirname); + dir.dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + dir.dirname_desc.dsc$b_class = DSC$K_CLASS_S; + dir.dirname_desc.dsc$a_pointer = (char *) &(dir.dirname); + return (&dir); +} + +static struct dirent *HTVMSreaddir(DIR *dirp) +{ + static struct dirent entry; + long status; + struct dsc$descriptor_s entryname_desc; + char *space, *slash; + char VMSentry[256]; + const char *UnixEntry; + + entryname_desc.dsc$w_length = 255; + entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T; + entryname_desc.dsc$b_class = DSC$K_CLASS_S; + entryname_desc.dsc$a_pointer = VMSentry; + + status = lib$find_file(&(dirp->dirname_desc), + &entryname_desc, + &(dirp->context), + 0, 0, 0, 0); + if (status == RMS$_NMF) { /* no more files */ + return (NULL); + } else { /* ok */ + if (!(status & 0x01)) + return (0); + if (HTVMSFileVersions) + space = StrChr(VMSentry, ' '); + else + space = StrChr(VMSentry, ';'); + if (space) + *space = '\0'; + + /* convert to unix style... */ + UnixEntry = HTVMS_wwwName(VMSentry); + slash = strrchr(UnixEntry, '/') + 1; + strcpy(entry.d_name, slash); + entry.d_namlen = strlen(entry.d_name); + entry.d_fileno = 1; + return (&entry); + } +} + +static int HTVMSclosedir(DIR *dirp) +{ + long status; + + status = lib$find_file_end(&(dirp->context)); + if (!(status & 0x01)) + exit_immediately(status); + dirp->context = 0; + return (0); +} + +#include <HTAnchor.h> +#include <HTParse.h> +#include <HTBTree.h> +#include <HTFile.h> /* For HTFileFormat() */ +#include <HTAlert.h> +/* + * Hypertext object building machinery. + */ +#include <HTML.h> +#define PUTC(c) (*targetClass.put_character)(target, c) +#define PUTS(s) (*targetClass.put_string)(target, s) +#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0) +#define END(e) (*targetClass.end_element)(target, e, 0) +#define FREE_TARGET (*targetClass._free)(target) +#define ABORT_TARGET (*targetClass._free)(target) +struct _HTStructured { + const HTStructuredClass *isa; + /* ... */ +}; + +#define STRUCT_DIRENT struct dirent + +static char *months[12] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +typedef struct _VMSEntryInfo { + char *filename; + char *type; + char *date; + unsigned int size; + BOOLEAN display; /* show this entry? */ +} VMSEntryInfo; + +static void free_VMSEntryInfo_contents(VMSEntryInfo * entry_info) +{ + if (entry_info) { + FREE(entry_info->filename); + FREE(entry_info->type); + FREE(entry_info->date); + } + /* don't free the struct */ +} + +int compare_VMSEntryInfo_structs(VMSEntryInfo * entry1, VMSEntryInfo * entry2) +{ + int i, status; + char date1[16], date2[16], time1[8], time2[8], month[4]; + + switch (HTfileSortMethod) { + case FILE_BY_SIZE: + /* both equal or both 0 */ + if (entry1->size == entry2->size) + return (strcasecomp(entry1->filename, + entry2->filename)); + else if (entry1->size > entry2->size) + return (1); + else + return (-1); + case FILE_BY_TYPE: + if (entry1->type && entry2->type) { + status = strcasecomp(entry1->type, entry2->type); + if (status) + return (status); + /* else fall to filename comparison */ + } + return (strcasecomp(entry1->filename, + entry2->filename)); + case FILE_BY_DATE: + if (entry1->date && entry2->date) { + /* + * Make sure we have the correct length. - FM + */ + if (strlen(entry1->date) != 12 || + strlen(entry2->date) != 12) { + return (strcasecomp(entry1->filename, + entry2->filename)); + } + /* + * Set up for sorting in reverse + * chronological order. - FM + */ + if (entry1->date[7] != ' ') { + strcpy(date1, "9999"); + strcpy(time1, (char *) &entry1->date[7]); + } else { + strcpy(date1, (char *) &entry1->date[8]); + strcpy(time1, "00:00"); + } + LYStrNCpy(month, entry1->date, 3); + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%02d", i); + strcat(date1, month); + StrNCat(date1, (char *) &entry1->date[4], 2); + date1[8] = '\0'; + if (date1[6] == ' ') { + date1[6] = '0'; + } + strcat(date1, time1); + if (entry2->date[7] != ' ') { + strcpy(date2, "9999"); + strcpy(time2, (char *) &entry2->date[7]); + } else { + strcpy(date2, (char *) &entry2->date[8]); + strcpy(time2, "00:00"); + } + LYStrNCpy(month, entry2->date, 3); + for (i = 0; i < 12; i++) { + if (!strcasecomp(month, months[i])) { + break; + } + } + i++; + sprintf(month, "%02d", i); + strcat(date2, month); + StrNCat(date2, (char *) &entry2->date[4], 2); + date2[8] = '\0'; + if (date2[6] == ' ') { + date2[6] = '0'; + } + strcat(date2, time2); + /* + * Do the comparison. - FM + */ + status = strcasecomp(date2, date1); + if (status) + return (status); + /* else fall to filename comparison */ + } + return (strcasecomp(entry1->filename, + entry2->filename)); + case FILE_BY_NAME: + default: + return (strcmp(entry1->filename, + entry2->filename)); + } +} + +/* HTVMSBrowseDir() + * + * This function generates a directory listing as an HTML-object + * for local file URL's. It assumes the first two elements of + * of the path are a device followed by a directory: + * + * file://localhost/device/directory[/[foo]] + * + * Will not accept 000000 as a directory name. + * Will offer links to parent through the top directory, unless + * a terminal slash was included in the calling URL. + * + * Returns HT_LOADED on success, HTLoadError() messages on error. + * + * Developed for Lynx by Foteos Macrides (macrides@sci.wfeb.edu). + */ +int HTVMSBrowseDir(const char *address, + HTParentAnchor *anchor, + HTFormat format_out, + HTStream *sink) +{ + HTStructured *target; + HTStructuredClass targetClass; + char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION); + char *tail = NULL; + char *title = NULL; + char *header = NULL; + char *parent = NULL; + char *relative = NULL; + char *cp, *cp1; + int pathend, len; + DIR *dp; + struct stat file_info; + time_t NowTime; + static char ThisYear[8]; + VMSEntryInfo *entry_info = 0; + char string_buffer[64]; + + HTUnEscape(pathname); + CTRACE((tfp, "HTVMSBrowseDir: Browsing `%s\'\n", pathname)); + + /* + * Require at least two elements (presumably a device and directory) and + * disallow the device root (000000 directory). Symbolic paths (e.g., + * sys$help) should have been translated and expanded (e.g., to + * /sys$sysroot/syshlp) before calling this routine. + */ + if (((*pathname != '/') || + (cp = StrChr(pathname + 1, '/')) == NULL || + *(cp + 1) == '\0' || + 0 == StrNCmp((cp + 1), "000000", 6)) || + (dp = HTVMSopendir(pathname)) == NULL) { + FREE(pathname); + return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR); + } + + /* + * Set up the output stream. + */ + _HTProgress(BUILDING_DIR_LIST); + if (UCLYhndl_HTFile_for_unspec >= 0) { + HTAnchor_setUCInfoStage(anchor, + UCLYhndl_HTFile_for_unspec, + UCT_STAGE_PARSER, + UCT_SETBY_DEFAULT); + } + target = HTML_new(anchor, format_out, sink); + targetClass = *(target->isa); + + /* + * Set up the offset string of the anchor reference, and strings for the + * title and header. + */ + cp = strrchr(pathname, '/'); /* find lastslash */ + StrAllocCopy(tail, (cp + 1)); /* take slash off the beginning */ + if (*tail != '\0') { + StrAllocCopy(title, tail); + *cp = '\0'; + if ((cp1 = strrchr(pathname, '/')) != NULL && + cp1 != pathname && + StrNCmp((cp1 + 1), "000000", 6)) + StrAllocCopy(parent, (cp1 + 1)); + *cp = '/'; + } else { + pathname[strlen(pathname) - 1] = '\0'; + cp = strrchr(pathname, '/'); + StrAllocCopy(title, (cp + 1)); + pathname[strlen(pathname)] = '/'; + } + StrAllocCopy(header, pathname); + + /* + * Initialize path name for HTStat(). + */ + pathend = strlen(pathname); + if (*(pathname + pathend - 1) != '/') { + StrAllocCat(pathname, "/"); + pathend++; + } + + /* + * Output the title and header. + */ + START(HTML_HTML); + PUTC('\n'); + START(HTML_HEAD); + PUTC('\n'); + HTUnEscape(title); + START(HTML_TITLE); + PUTS(title); + PUTS(" directory"); + END(HTML_TITLE); + PUTC('\n'); + FREE(title); + END(HTML_HEAD); + PUTC('\n'); + START(HTML_BODY); + PUTC('\n'); + HTUnEscape(header); + START(HTML_H1); + PUTS(header); + END(HTML_H1); + PUTC('\n'); + if (HTDirReadme == HT_DIR_README_TOP) { + FILE *fp; + + if (header[strlen(header) - 1] != '/') + StrAllocCat(header, "/"); + StrAllocCat(header, HT_DIR_README_FILE); + if ((fp = fopen(header, "r")) != NULL) { + START(HTML_PRE); + for (;;) { + char c = fgetc(fp); + + if (c == (char) EOF) + break; +#ifdef NOTDEFINED + switch (c) { + case '&': + case '<': + case '>': + PUTC('&'); + PUTC('#'); + PUTC((char) (c / 10)); + PUTC((char) (c % 10)); + PUTC(';'); + break; + default: + PUTC(c); + } +#else + PUTC(c); +#endif /* NOTDEFINED */ + } + END(HTML_PRE); + fclose(fp); + } + } + FREE(header); + if (parent) { + HTSprintf0(&relative, "%s/..", tail); + HTStartAnchor(target, "", relative); + PUTS("Up to "); + HTUnEscape(parent); + PUTS(parent); + END(HTML_A); + START(HTML_P); + PUTC('\n'); + FREE(relative); + FREE(parent); + } + + /* + * Set up the date comparison. + */ + NowTime = time(NULL); + strcpy(ThisYear, (char *) ctime(&NowTime) + 20); + ThisYear[4] = '\0'; + + /* + * Now, generate the Btree and put it out to the output stream. + */ + { + char dottest = 2; /* To avoid two strcmp() each time */ + STRUCT_DIRENT *dirbuf; + HTBTree *bt; + + /* Set up sort key and initialize BTree */ + bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs); + + /* Build tree */ + while ((dirbuf = HTVMSreaddir(dp))) { + HTAtom *encoding = NULL; + HTFormat format; + + /* Skip if not used */ + if (!dirbuf->d_ino) { + continue; + } + + /* Current and parent directories are never shown in list */ + if (dottest && (!strcmp(dirbuf->d_name, ".") || + !strcmp(dirbuf->d_name, ".."))) { + dottest--; + continue; + } + + /* Don't show the selective enabling file + * unless version numbers are included */ + if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) { + continue; + } + + /* Skip files beginning with a dot? */ + if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') { + continue; + } + + /* OK, make an lstat() and get a key ready. */ + *(pathname + pathend) = '\0'; + StrAllocCat(pathname, dirbuf->d_name); + if (HTStat(pathname, &file_info)) { + /* for VMS the failure here means the file is not readable... + we however continue to browse through the directory... */ + continue; + } + entry_info = (VMSEntryInfo *) malloc(sizeof(VMSEntryInfo)); + if (entry_info == NULL) + outofmem(__FILE__, "HTVMSBrowseDir"); + entry_info->type = 0; + entry_info->size = 0; + entry_info->date = 0; + entry_info->filename = 0; + entry_info->display = TRUE; + + /* Get the type */ + format = HTFileFormat(dirbuf->d_name, &encoding, + (const char **) &cp); + if (!cp) { + if (!StrNCmp(HTAtom_name(format), "application", 11)) { + cp = HTAtom_name(format) + 12; + if (!StrNCmp(cp, "x-", 2)) + cp += 2; + } else + cp = HTAtom_name(format); + } + StrAllocCopy(entry_info->type, cp); + + StrAllocCopy(entry_info->filename, dirbuf->d_name); + if (S_ISDIR(file_info.st_mode)) { + /* strip .DIR part... */ + char *dot; + + dot = strstr(entry_info->filename, ".DIR"); + if (dot) + *dot = '\0'; + LYLowerCase(entry_info->filename); + StrAllocCopy(entry_info->type, "Directory"); + } else { + if ((cp = strstr(entry_info->filename, "READ")) == NULL) { + cp = entry_info->filename; + } else { + cp += 4; + if (!StrNCmp(cp, "ME", 2)) { + cp += 2; + while (cp && *cp && *cp != '.') { + cp++; + } + } else if (!StrNCmp(cp, ".ME", 3)) { + cp = (entry_info->filename + + strlen(entry_info->filename)); + } else { + cp = entry_info->filename; + } + } + LYLowerCase(cp); + if (((len = strlen(entry_info->filename)) > 2) && + entry_info->filename[len - 1] == 'z') { + if (entry_info->filename[len - 2] == '.' || + entry_info->filename[len - 2] == '_') + entry_info->filename[len - 1] = 'Z'; + } + } + + /* Get the date */ + { + char *t = (char *) ctime((const time_t *) &file_info.st_ctime); + + *(t + 24) = '\0'; + + StrAllocCopy(entry_info->date, (t + 4)); + *((entry_info->date) + 7) = '\0'; + if ((atoi((t + 19))) < atoi(ThisYear)) + StrAllocCat(entry_info->date, (t + 19)); + else { + StrAllocCat(entry_info->date, (t + 11)); + *((entry_info->date) + 12) = '\0'; + } + } + + /* Get the size */ + if (!S_ISDIR(file_info.st_mode)) + entry_info->size = (unsigned int) file_info.st_size; + else + entry_info->size = 0; + + /* Now, update the BTree etc. */ + if (entry_info->display) { + CTRACE((tfp, "Adding file to BTree: %s\n", + entry_info->filename)); + HTBTree_add(bt, entry_info); + } + + } /* End while HTVMSreaddir() */ + + FREE(pathname); + HTVMSclosedir(dp); + + START(HTML_PRE); + /* + * Run through the BTree printing out in order + */ + { + HTBTElement *ele; + int i; + + for (ele = HTBTree_next(bt, NULL); + ele != NULL; + ele = HTBTree_next(bt, ele)) { + entry_info = (VMSEntryInfo *) HTBTree_object(ele); + + /* Output the date */ + if (entry_info->date) { + PUTS(entry_info->date); + PUTS(" "); + } else + PUTS(" * "); + + /* Output the type */ + if (entry_info->type) { + for (i = 0; entry_info->type[i] != '\0' && i < 15; i++) + PUTC(entry_info->type[i]); + for (; i < 17; i++) + PUTC(' '); + + } + + /* Output the link for the name */ + HTDirEntry(target, tail, entry_info->filename); + PUTS(entry_info->filename); + END(HTML_A); + + /* Output the size */ + if (entry_info->size) { + if (entry_info->size < 1024) + sprintf(string_buffer, " %d bytes", + entry_info->size); + else + sprintf(string_buffer, " %dKb", + entry_info->size / 1024); + PUTS(string_buffer); + } + + PUTC('\n'); /* end of this entry */ + + free_VMSEntryInfo_contents(entry_info); + } + } + + HTBTreeAndObject_free(bt); + + } /* End of both BTree loops */ + + /* + * Complete the output stream. + */ + END(HTML_PRE); + PUTC('\n'); + END(HTML_BODY); + PUTC('\n'); + END(HTML_HTML); + PUTC('\n'); + FREE(tail); + FREE_TARGET; + + return HT_LOADED; + +} /* End of directory reading section */ + +/* + * Remove all versions of the given file. We assume there are no permissions + * problems, since we do this mainly for removing temporary files. + */ +int HTVMS_remove(char *filename) +{ + int code = remove(filename); /* return the first status code */ + + while (remove(filename) == 0) ; + return code; +} + +/* + * Remove all older versions of the given file. We may fail to remove some + * version due to permissions -- the loop stops either at that point, or when + * we run out of older versions to remove. + */ +void HTVMS_purge(char *filename) +{ + char *older_file = 0; + char *oldest_file = 0; + struct stat sb; + + StrAllocCopy(older_file, filename); + StrAllocCat(older_file, ";-1"); + + while (remove(older_file) == 0) ; + /* + * If we do not have any more older versions, it is safe to rename the + * current file to version #1. + */ + if (stat(older_file, &sb) != 0) { + StrAllocCopy(oldest_file, filename); + StrAllocCat(oldest_file, ";1"); + rename(older_file, oldest_file); + FREE(oldest_file); + } + + FREE(older_file); +} +#endif /* VMS */ |