diff options
Diffstat (limited to 'WWW/Library/Implementation/HTFile.c')
-rw-r--r-- | WWW/Library/Implementation/HTFile.c | 3240 |
1 files changed, 0 insertions, 3240 deletions
diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c deleted file mode 100644 index be561e44..00000000 --- a/WWW/Library/Implementation/HTFile.c +++ /dev/null @@ -1,3240 +0,0 @@ -/* - * $LynxId: HTFile.c,v 1.129 2012/02/10 01:10:51 tom Exp $ - * - * File Access HTFile.c - * =========== - * - * This is unix-specific code in general, with some VMS bits. - * These are routines for file access used by browsers. - * Development of this module for Unix DIRED_SUPPORT in Lynx - * regrettably has has been conducted in a manner with now - * creates a major impediment for hopes of adapting Lynx to - * a newer version of the library. - * - * History: - * Feb 91 Written Tim Berners-Lee CERN/CN - * Apr 91 vms-vms access included using DECnet syntax - * 26 Jun 92 (JFG) When running over DECnet, suppressed FTP. - * Fixed access bug for relative names on VMS. - * Sep 93 (MD) Access to VMS files allows sharing. - * 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C - * 27 Dec 93 (FM) FTP now works with VMS hosts. - * FTP path must be Unix-style and cannot include - * the device or top directory. - */ - -#include <HTUtils.h> - -#ifndef VMS -#if defined(DOSPATH) -#undef LONG_LIST -#define LONG_LIST /* Define this for long style unix listings (ls -l), - the actual style is configurable from lynx.cfg */ -#endif -/* #define NO_PARENT_DIR_REFERENCE */ -/* Define this for no parent links */ -#endif /* !VMS */ - -#if defined(DOSPATH) -#define HAVE_READDIR 1 -#define USE_DIRENT -#endif - -#if defined(USE_DOS_DRIVES) -#include <HTDOS.h> -#endif - -#include <HTFile.h> /* Implemented here */ - -#ifdef VMS -#include <stat.h> -#endif /* VMS */ - -#if defined (USE_ZLIB) || defined (USE_BZLIB) -#include <GridText.h> -#endif - -#define MULTI_SUFFIX ".multi" /* Extension for scanning formats */ - -#include <HTParse.h> -#include <HTTCP.h> -#ifndef DECNET -#include <HTFTP.h> -#endif /* !DECNET */ -#include <HTAnchor.h> -#include <HTAtom.h> -#include <HTAAProt.h> -#include <HTFWriter.h> -#include <HTInit.h> -#include <HTBTree.h> -#include <HTAlert.h> -#include <HTCJK.h> -#include <UCDefs.h> -#include <UCMap.h> -#include <UCAux.h> - -#include <LYexit.h> -#include <LYCharSets.h> -#include <LYGlobalDefs.h> -#include <LYStrings.h> -#include <LYUtils.h> - -#ifdef USE_PRETTYSRC -# include <LYPrettySrc.h> -#endif - -#include <LYLeaks.h> - -typedef struct _HTSuffix { - char *suffix; - HTAtom *rep; - HTAtom *encoding; - char *desc; - float quality; -} HTSuffix; - -typedef struct { - struct stat file_info; - char sort_tags; - char file_name[1]; /* on the end of the struct, since its length varies */ -} DIRED; - -#ifndef NGROUPS -#ifdef NGROUPS_MAX -#define NGROUPS NGROUPS_MAX -#else -#define NGROUPS 32 -#endif /* NGROUPS_MAX */ -#endif /* NGROUPS */ - -#ifndef GETGROUPS_T -#define GETGROUPS_T int -#endif - -#include <HTML.h> /* For directory object building */ - -#define PUTC(c) (*target->isa->put_character)(target, c) -#define PUTS(s) (*target->isa->put_string)(target, s) -#define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0) -#define END(e) (*target->isa->end_element)(target, e, 0) -#define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ - (*target->isa->end_element)(target, e, 0) -#define FREE_TARGET (*target->isa->_free)(target) -#define ABORT_TARGET (*targetClass._abort)(target, NULL); - -struct _HTStructured { - const HTStructuredClass *isa; - /* ... */ -}; - -/* - * Controlling globals. - */ -int HTDirAccess = HT_DIR_OK; - -#ifdef DIRED_SUPPORT -int HTDirReadme = HT_DIR_README_NONE; - -#else -int HTDirReadme = HT_DIR_README_TOP; -#endif /* DIRED_SUPPORT */ - -static const char *HTMountRoot = "/Net/"; /* Where to find mounts */ - -#ifdef VMS -static const char *HTCacheRoot = "/WWW$SCRATCH"; /* Where to cache things */ - -#else -static const char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */ -#endif /* VMS */ - -static char s_no_suffix[] = "*"; -static char s_unknown_suffix[] = "*.*"; - -/* - * Suffix registration. - */ -static HTList *HTSuffixes = 0; - -static HTSuffix no_suffix = -{ - s_no_suffix, NULL, NULL, NULL, 1.0 -}; - -static HTSuffix unknown_suffix = -{ - s_unknown_suffix, NULL, NULL, NULL, 1.0 -}; - -/* To free up the suffixes at program exit. - * ---------------------------------------- - */ -#ifdef LY_FIND_LEAKS -static void free_suffixes(void); -#endif - -#ifdef LONG_LIST -static char *FormatStr(char **bufp, - char *start, - const char *entry) -{ - char fmt[512]; - - if (*start) { - sprintf(fmt, "%%%.*ss", (int) sizeof(fmt) - 3, start); - HTSprintf0(bufp, fmt, entry); - } else if (*bufp && !(entry && *entry)) { - **bufp = '\0'; - } else if (entry) { - StrAllocCopy(*bufp, entry); - } - return *bufp; -} - -static char *FormatNum(char **bufp, - char *start, - int entry) -{ - char fmt[512]; - - if (*start) { - sprintf(fmt, "%%%.*sd", (int) sizeof(fmt) - 3, start); - HTSprintf0(bufp, fmt, entry); - } else { - sprintf(fmt, "%d", entry); - StrAllocCopy(*bufp, fmt); - } - return *bufp; -} - -static void LYListFmtParse(const char *fmtstr, - DIRED * data, - char *file, - HTStructured * target, - char *tail) -{ - char c; - char *s; - char *end; - char *start; - char *str = NULL; - char *buf = NULL; - char tmp[LY_MAXPATH]; - char type; - -#ifndef NOUSERS - const char *name; -#endif - time_t now; - char *datestr; - -#ifdef S_IFLNK - int len; -#endif -#define SEC_PER_YEAR (60 * 60 * 24 * 365) - -#ifdef _WINDOWS /* 1998/01/06 (Tue) 21:20:53 */ - static const char *pbits[] = - { - "---", "--x", "-w-", "-wx", - "r--", "r-x", "rw-", "rwx", - 0}; - -#define PBIT(a, n, s) pbits[((a) >> (n)) & 0x7] - -#else - static const char *pbits[] = - {"---", "--x", "-w-", "-wx", - "r--", "r-x", "rw-", "rwx", 0}; - static const char *psbits[] = - {"--S", "--s", "-wS", "-ws", - "r-S", "r-s", "rwS", "rws", 0}; - -#define PBIT(a, n, s) (s) ? psbits[((a) >> (n)) & 0x7] : \ - pbits[((a) >> (n)) & 0x7] -#endif -#if defined(S_ISVTX) && !defined(_WINDOWS) - static const char *ptbits[] = - {"--T", "--t", "-wT", "-wt", - "r-T", "r-t", "rwT", "rwt", 0}; - -#define PTBIT(a, s) (s) ? ptbits[(a) & 0x7] : pbits[(a) & 0x7] -#else -#define PTBIT(a, s) PBIT(a, 0, 0) -#endif - - if (data->file_info.st_mode == 0) - fmtstr = " %a"; /* can't stat so just do anchor */ - - StrAllocCopy(str, fmtstr); - s = str; - end = str + strlen(str); - while (*s) { - start = s; - while (*s) { - if (*s == '%') { - if (*(s + 1) == '%') /* literal % */ - s++; - else - break; - } - s++; - } - /* s is positioned either at a % or at \0 */ - *s = '\0'; - if (s > start) { /* some literal chars. */ - PUTS(start); - } - if (s == end) - break; - start = ++s; - while (isdigit(UCH(*s)) || *s == '.' || *s == '-' || *s == ' ' || - *s == '#' || *s == '+' || *s == '\'') - s++; - c = *s; /* the format char. or \0 */ - *s = '\0'; - - switch (c) { - case '\0': - PUTS(start); - continue; - - case 'A': - case 'a': /* anchor */ - HTDirEntry(target, tail, data->file_name); - FormatStr(&buf, start, data->file_name); - PUTS(buf); - END(HTML_A); - *buf = '\0'; -#ifdef S_IFLNK - if (c != 'A' && S_ISLNK(data->file_info.st_mode) && - (len = (int) readlink(file, tmp, sizeof(tmp) - 1)) >= 0) { - PUTS(" -> "); - tmp[len] = '\0'; - PUTS(tmp); - } -#endif - break; - - case 'T': /* MIME type */ - case 't': /* MIME type description */ - if (S_ISDIR(data->file_info.st_mode)) { - if (c != 'T') { - FormatStr(&buf, start, ENTRY_IS_DIRECTORY); - } else { - FormatStr(&buf, start, ""); - } - } else { - const char *cp2; - HTFormat format; - - format = HTFileFormat(file, NULL, &cp2); - - if (c != 'T') { - if (cp2 == NULL) { - if (!StrNCmp(HTAtom_name(format), - "application", 11)) { - cp2 = HTAtom_name(format) + 12; - if (!StrNCmp(cp2, "x-", 2)) - cp2 += 2; - } else { - cp2 = HTAtom_name(format); - } - } - FormatStr(&buf, start, cp2); - } else { - FormatStr(&buf, start, HTAtom_name(format)); - } - } - break; - - case 'd': /* date */ - now = time(0); - datestr = ctime(&data->file_info.st_mtime); - if ((now - data->file_info.st_mtime) < SEC_PER_YEAR / 2) - /* - * MMM DD HH:MM - */ - sprintf(tmp, "%.12s", datestr + 4); - else - /* - * MMM DD YYYY - */ - sprintf(tmp, "%.7s %.4s ", datestr + 4, - datestr + 20); - FormatStr(&buf, start, tmp); - break; - - case 's': /* size in bytes */ - FormatNum(&buf, start, (int) data->file_info.st_size); - break; - - case 'K': /* size in Kilobytes but not for directories */ - if (S_ISDIR(data->file_info.st_mode)) { - FormatStr(&buf, start, ""); - StrAllocCat(buf, " "); - break; - } - /* FALL THROUGH */ - case 'k': /* size in Kilobytes */ - FormatNum(&buf, start, (int) ((data->file_info.st_size + 1023) / 1024)); - StrAllocCat(buf, "K"); - break; - - case 'p': /* unix-style permission bits */ - switch (data->file_info.st_mode & S_IFMT) { -#if defined(_MSC_VER) && defined(_S_IFIFO) - case _S_IFIFO: - type = 'p'; - break; -#else - case S_IFIFO: - type = 'p'; - break; -#endif - case S_IFCHR: - type = 'c'; - break; - case S_IFDIR: - type = 'd'; - break; - case S_IFREG: - type = '-'; - break; -#ifdef S_IFBLK - case S_IFBLK: - type = 'b'; - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: - type = 'l'; - break; -#endif -#ifdef S_IFSOCK -# ifdef S_IFIFO /* some older machines (e.g., apollo) have a conflict */ -# if S_IFIFO != S_IFSOCK - case S_IFSOCK: - type = 's'; - break; -# endif -# else - case S_IFSOCK: - type = 's'; - break; -# endif -#endif /* S_IFSOCK */ - default: - type = '?'; - break; - } -#ifdef _WINDOWS - sprintf(tmp, "%c%s", type, - PBIT(data->file_info.st_mode, 6, data->file_info.st_mode & S_IRWXU)); -#else - sprintf(tmp, "%c%s%s%s", type, - PBIT(data->file_info.st_mode, 6, data->file_info.st_mode & S_ISUID), - PBIT(data->file_info.st_mode, 3, data->file_info.st_mode & S_ISGID), - PTBIT(data->file_info.st_mode, data->file_info.st_mode & S_ISVTX)); -#endif - FormatStr(&buf, start, tmp); - break; - - case 'o': /* owner */ -#ifndef NOUSERS - name = HTAA_UidToName((int) data->file_info.st_uid); - if (*name) { - FormatStr(&buf, start, name); - } else { - FormatNum(&buf, start, (int) data->file_info.st_uid); - } -#endif - break; - - case 'g': /* group */ -#ifndef NOUSERS - name = HTAA_GidToName((int) data->file_info.st_gid); - if (*name) { - FormatStr(&buf, start, name); - } else { - FormatNum(&buf, start, (int) data->file_info.st_gid); - } -#endif - break; - - case 'l': /* link count */ - FormatNum(&buf, start, (int) data->file_info.st_nlink); - break; - - case '%': /* literal % with flags/width */ - FormatStr(&buf, start, "%"); - break; - - default: - fprintf(stderr, - "Unknown format character `%c' in list format\n", c); - break; - } - if (buf) - PUTS(buf); - - s++; - } - FREE(buf); - PUTC('\n'); - FREE(str); -} -#endif /* LONG_LIST */ - -/* Define the representation associated with a file suffix. - * -------------------------------------------------------- - * - * Calling this with suffix set to "*" will set the default - * representation. - * Calling this with suffix set to "*.*" will set the default - * representation for unknown suffix files which contain a ".". - * - * The encoding parameter can give a trivial (8bit, 7bit, binary) - * or real (gzip, compress) encoding. - * - * If filename suffix is already defined with the same encoding - * its previous definition is overridden. - */ -void HTSetSuffix5(const char *suffix, - const char *representation, - const char *encoding, - const char *desc, - double value) -{ - HTSuffix *suff; - BOOL trivial_enc = (BOOL) IsUnityEncStr(encoding); - - if (strcmp(suffix, s_no_suffix) == 0) - suff = &no_suffix; - else if (strcmp(suffix, s_unknown_suffix) == 0) - suff = &unknown_suffix; - else { - HTList *cur = HTSuffixes; - - while (NULL != (suff = (HTSuffix *) HTList_nextObject(cur))) { - if (suff->suffix && 0 == strcmp(suff->suffix, suffix) && - ((trivial_enc && IsUnityEnc(suff->encoding)) || - (!trivial_enc && !IsUnityEnc(suff->encoding) && - strcmp(encoding, HTAtom_name(suff->encoding)) == 0))) - break; - } - if (!suff) { /* Not found -- create a new node */ - suff = typecalloc(HTSuffix); - if (suff == NULL) - outofmem(__FILE__, "HTSetSuffix"); - - assert(suff != NULL); - - if (!HTSuffixes) { - HTSuffixes = HTList_new(); -#ifdef LY_FIND_LEAKS - atexit(free_suffixes); -#endif - } - - HTList_addObject(HTSuffixes, suff); - - StrAllocCopy(suff->suffix, suffix); - } - } - - if (representation) - suff->rep = HTAtom_for(representation); - - /* - * Memory leak fixed. - * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe - * Invariant code removed. - */ - suff->encoding = HTAtom_for(encoding); - - StrAllocCopy(suff->desc, desc); - - suff->quality = (float) value; -} - -#ifdef LY_FIND_LEAKS -/* - * Purpose: Free all added suffixes. - * Arguments: void - * Return Value: void - * Remarks/Portability/Dependencies/Restrictions: - * To be used at program exit. - * Revision History: - * 05-28-94 created Lynx 2-3-1 Garrett Arch Blythe - */ -static void free_suffixes(void) -{ - HTSuffix *suff = NULL; - - /* - * Loop through all suffixes. - */ - while (!HTList_isEmpty(HTSuffixes)) { - /* - * Free off each item and its members if need be. - */ - suff = (HTSuffix *) HTList_removeLastObject(HTSuffixes); - FREE(suff->suffix); - FREE(suff->desc); - FREE(suff); - } - /* - * Free off the list itself. - */ - HTList_delete(HTSuffixes); - HTSuffixes = NULL; -} -#endif /* LY_FIND_LEAKS */ - -/* Make the cache file name for a W3 document. - * ------------------------------------------- - * Make up a suitable name for saving the node in - * - * E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch - * /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx - * - * On exit: - * Returns a malloc'ed string which must be freed by the caller. - */ -char *HTCacheFileName(const char *name) -{ - char *acc_method = HTParse(name, "", PARSE_ACCESS); - char *host = HTParse(name, "", PARSE_HOST); - char *path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); - char *result = NULL; - - HTSprintf0(&result, "%s/WWW/%s/%s%s", HTCacheRoot, acc_method, host, path); - - FREE(path); - FREE(acc_method); - FREE(host); - return result; -} - -/* Open a file for write, creating the path. - * ----------------------------------------- - */ -#ifdef NOT_IMPLEMENTED -static int HTCreatePath(const char *path) -{ - return -1; -} -#endif /* NOT_IMPLEMENTED */ - -/* Convert filename from URL-path syntax to local path format - * ---------------------------------------------------------- - * Input name is assumed to be the URL-path of a local file - * URL, i.e. what comes after the "file://localhost". - * '#'-fragments to be treated as such must already be stripped. - * If expand_all is FALSE, unescape only escaped '/'. - kw - * - * On exit: - * Returns a malloc'ed string which must be freed by the caller. - */ -char *HTURLPath_toFile(const char *name, - int expand_all, - int is_remote GCC_UNUSED) -{ - char *path = NULL; - char *result = NULL; - - StrAllocCopy(path, name); - if (expand_all) - HTUnEscape(path); /* Interpret all % signs */ - else - HTUnEscapeSome(path, "/"); /* Interpret % signs for path delims */ - - CTRACE((tfp, "URLPath `%s' means path `%s'\n", name, path)); -#if defined(USE_DOS_DRIVES) - StrAllocCopy(result, is_remote ? path : HTDOS_name(path)); -#else - StrAllocCopy(result, path); -#endif - - FREE(path); - - return result; -} -/* Convert filenames between local and WWW formats. - * ------------------------------------------------ - * Make up a suitable name for saving the node in - * - * E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch - * $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx - * - * On exit: - * Returns a malloc'ed string which must be freed by the caller. - */ -/* NOTE: Don't use this function if you know that the input is a URL path - rather than a full URL, use HTURLPath_toFile instead. Otherwise - this function will return the wrong thing for some unusual - paths (like ones containing "//", possibly escaped). - kw -*/ -char *HTnameOfFile_WWW(const char *name, - int WWW_prefix, - int expand_all) -{ - char *acc_method = HTParse(name, "", PARSE_ACCESS); - char *host = HTParse(name, "", PARSE_HOST); - char *path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); - const char *home; - char *result = NULL; - - if (expand_all) { - HTUnEscape(path); /* Interpret all % signs */ - } else - HTUnEscapeSome(path, "/"); /* Interpret % signs for path delims */ - - if (0 == strcmp(acc_method, "file") /* local file */ - ||!*acc_method) { /* implicitly local? */ - if ((0 == strcasecomp(host, HTHostName())) || - (0 == strcasecomp(host, "localhost")) || !*host) { - CTRACE((tfp, "Node `%s' means path `%s'\n", name, path)); - StrAllocCopy(result, HTSYS_name(path)); - } else if (WWW_prefix) { - HTSprintf0(&result, "%s%s%s", "/Net/", host, path); - CTRACE((tfp, "Node `%s' means file `%s'\n", name, result)); - } else { - StrAllocCopy(result, path); - } - } else if (WWW_prefix) { /* other access */ -#ifdef VMS - if ((home = LYGetEnv("HOME")) == NULL) - home = HTCacheRoot; - else - home = HTVMS_wwwName(home); -#else -#if defined(_WINDOWS) /* 1997/10/16 (Thu) 20:42:51 */ - home = Home_Dir(); -#else - home = LYGetEnv("HOME"); -#endif - if (home == NULL) - home = "/tmp"; -#endif /* VMS */ - HTSprintf0(&result, "%s/WWW/%s/%s%s", home, acc_method, host, path); - } else { - StrAllocCopy(result, path); - } - - FREE(host); - FREE(path); - FREE(acc_method); - - CTRACE((tfp, "HTnameOfFile_WWW(%s,%d,%d) = %s\n", - name, WWW_prefix, expand_all, result)); - - return result; -} - -/* Make a WWW name from a full local path name. - * -------------------------------------------- - * - * Bugs: - * At present, only the names of two network root nodes are hand-coded - * in and valid for the NeXT only. This should be configurable in - * the general case. - */ -char *WWW_nameOfFile(const char *name) -{ - char *result = NULL; - -#ifdef NeXT - if (0 == StrNCmp("/private/Net/", name, 13)) { - HTSprintf0(&result, "%s//%s", STR_FILE_URL, name + 13); - } else -#endif /* NeXT */ - if (0 == StrNCmp(HTMountRoot, name, 5)) { - HTSprintf0(&result, "%s//%s", STR_FILE_URL, name + 5); - } else { - HTSprintf0(&result, "%s//%s%s", STR_FILE_URL, HTHostName(), name); - } - CTRACE((tfp, "File `%s'\n\tmeans node `%s'\n", name, result)); - return result; -} - -/* Determine a suitable suffix, given the representation. - * ------------------------------------------------------ - * - * On entry, - * rep is the atomized MIME style representation - * enc is an encoding, trivial (8bit, binary, etc.) or gzip etc. - * - * On exit: - * Returns a pointer to a suitable suffix string if one has been - * found, else "". - */ -const char *HTFileSuffix(HTAtom *rep, - const char *enc) -{ - HTSuffix *suff; - -#ifdef FNAMES_8_3 - HTSuffix *first_found = NULL; -#endif - BOOL trivial_enc; - int n; - int i; - -#define NO_INIT /* don't init anymore since I do it in Lynx at startup */ -#ifndef NO_INIT - if (!HTSuffixes) - HTFileInit(); -#endif /* !NO_INIT */ - - trivial_enc = (BOOL) IsUnityEncStr(enc); - n = HTList_count(HTSuffixes); - for (i = 0; i < n; i++) { - suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i); - if (suff->rep == rep && -#if defined(VMS) || defined(FNAMES_8_3) - /* Don't return a suffix whose first char is a dot, and which - has more dots or asterisks after that, for - these systems - kw */ - (!suff->suffix || !suff->suffix[0] || suff->suffix[0] != '.' || - (strchr(suff->suffix + 1, '.') == NULL && - strchr(suff->suffix + 1, '*') == NULL)) && -#endif - ((trivial_enc && IsUnityEnc(suff->encoding)) || - (!trivial_enc && !IsUnityEnc(suff->encoding) && - strcmp(enc, HTAtom_name(suff->encoding)) == 0))) { -#ifdef FNAMES_8_3 - if (suff->suffix && (strlen(suff->suffix) <= 4)) { - /* - * If length of suffix (including dot) is 4 or smaller, return - * this one even if we found a longer one earlier - kw - */ - return suff->suffix; - } else if (!first_found) { - first_found = suff; /* remember this one */ - } -#else - return suff->suffix; /* OK -- found */ -#endif - } - } -#ifdef FNAMES_8_3 - if (first_found) - return first_found->suffix; -#endif - return ""; /* Dunno */ -} - -/* - * Trim version from VMS filenames to avoid confusing comparisons. - */ -#ifdef VMS -static const char *VMS_trim_version(const char *filename) -{ - const char *result = filename; - const char *version = strchr(filename, ';'); - - if (version != 0) { - static char *stripped; - - StrAllocCopy(stripped, filename); - stripped[version - filename] = '\0'; - result = (const char *) stripped; - } - return result; -} -#define VMS_DEL_VERSION(name) name = VMS_trim_version(name) -#else -#define VMS_DEL_VERSION(name) /* nothing */ -#endif - -/* Determine file format from file name. - * ------------------------------------- - * - * This version will return the representation and also set - * a variable for the encoding. - * - * Encoding may be a unity encoding (binary, 8bit, etc.) or - * a content-coding like gzip, compress. - * - * It will handle for example x.txt, x.txt,Z, x.Z - */ -HTFormat HTFileFormat(const char *filename, - HTAtom **pencoding, - const char **pdesc) -{ - HTSuffix *suff; - int n; - int i; - int lf; - - VMS_DEL_VERSION(filename); - - if (pencoding) - *pencoding = NULL; - if (pdesc) - *pdesc = NULL; - if (LYforce_HTML_mode) { - if (pencoding) - *pencoding = WWW_ENC_8BIT; - return WWW_HTML; - } -#ifndef NO_INIT - if (!HTSuffixes) - HTFileInit(); -#endif /* !NO_INIT */ - lf = (int) strlen(filename); - n = HTList_count(HTSuffixes); - for (i = 0; i < n; i++) { - int ls; - - suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i); - ls = (int) strlen(suff->suffix); - if ((ls <= lf) && 0 == strcasecomp(suff->suffix, filename + lf - ls)) { - int j; - - if (pencoding) - *pencoding = suff->encoding; - if (pdesc) - *pdesc = suff->desc; - if (suff->rep) { - return suff->rep; /* OK -- found */ - } - for (j = 0; j < n; j++) { /* Got encoding, need representation */ - int ls2; - - suff = (HTSuffix *) HTList_objectAt(HTSuffixes, j); - ls2 = (int) strlen(suff->suffix); - if ((ls + ls2 <= lf) && - !strncasecomp(suff->suffix, - filename + lf - ls - ls2, ls2)) { - if (suff->rep) { - if (pdesc && !(*pdesc)) - *pdesc = suff->desc; - if (pencoding && IsUnityEnc(*pencoding) && - *pencoding != WWW_ENC_7BIT && - !IsUnityEnc(suff->encoding)) - *pencoding = suff->encoding; - return suff->rep; - } - } - } - - } - } - - /* defaults tree */ - - suff = (strchr(filename, '.') - ? (unknown_suffix.rep - ? &unknown_suffix - : &no_suffix) - : &no_suffix); - - /* - * Set default encoding unless found with suffix already. - */ - if (pencoding && !*pencoding) { - *pencoding = (suff->encoding - ? suff->encoding - : HTAtom_for("binary")); - } - return suff->rep ? suff->rep : WWW_BINARY; -} - -/* Revise the file format in relation to the Lynx charset. - FM - * ------------------------------------------------------- - * - * This checks the format associated with an anchor for - * an extended MIME Content-Type, and if a charset is - * indicated, sets Lynx up for proper handling in relation - * to the currently selected character set. - FM - */ -HTFormat HTCharsetFormat(HTFormat format, - HTParentAnchor *anchor, - int default_LYhndl) -{ - char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; - BOOL chartrans_ok = FALSE; - int chndl = -1; - - FREE(anchor->charset); - StrAllocCopy(cp, format->name); - LYLowerCase(cp); - if (((cp1 = strchr(cp, ';')) != NULL) && - (cp2 = strstr(cp1, "charset")) != NULL) { - CTRACE((tfp, "HTCharsetFormat: Extended MIME Content-Type is %s\n", - format->name)); - cp2 += 7; - while (*cp2 == ' ' || *cp2 == '=') - cp2++; - StrAllocCopy(cp3, cp2); /* copy to mutilate more */ - for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' && - *cp4 != ';' && *cp4 != ':' && - !WHITE(*cp4)); cp4++) { - ; /* do nothing */ - } - *cp4 = '\0'; - cp4 = cp3; - chndl = UCGetLYhndl_byMIME(cp3); - if (UCCanTranslateFromTo(chndl, current_char_set)) { - chartrans_ok = YES; - *cp1 = '\0'; - format = HTAtom_for(cp); - StrAllocCopy(anchor->charset, cp4); - HTAnchor_setUCInfoStage(anchor, chndl, - UCT_STAGE_MIME, - UCT_SETBY_MIME); - } else if (chndl < 0) { - /* - * Got something but we don't recognize it. - */ - chndl = UCLYhndl_for_unrec; - if (chndl < 0) - /* - * UCLYhndl_for_unrec not defined :-( fallback to - * UCLYhndl_for_unspec which always valid. - */ - chndl = UCLYhndl_for_unspec; /* always >= 0 */ - if (UCCanTranslateFromTo(chndl, current_char_set)) { - chartrans_ok = YES; - HTAnchor_setUCInfoStage(anchor, chndl, - UCT_STAGE_MIME, - UCT_SETBY_DEFAULT); - } - } - if (chartrans_ok) { - LYUCcharset *p_in = HTAnchor_getUCInfoStage(anchor, - UCT_STAGE_MIME); - LYUCcharset *p_out = HTAnchor_setUCInfoStage(anchor, - current_char_set, - UCT_STAGE_HTEXT, - UCT_SETBY_DEFAULT); - - if (!p_out) { - /* - * Try again. - */ - p_out = HTAnchor_getUCInfoStage(anchor, UCT_STAGE_HTEXT); - } - if (!strcmp(p_in->MIMEname, "x-transparent")) { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(anchor, - HTAnchor_getUCLYhndl(anchor, - UCT_STAGE_HTEXT), - UCT_STAGE_MIME, - UCT_SETBY_DEFAULT); - } - if (!strcmp(p_out->MIMEname, "x-transparent")) { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(anchor, - HTAnchor_getUCLYhndl(anchor, - UCT_STAGE_MIME), - UCT_STAGE_HTEXT, - UCT_SETBY_DEFAULT); - } - if (p_in->enc != UCT_ENC_CJK) { - HTCJK = NOCJK; - if (!(p_in->codepoints & - UCT_CP_SUBSETOF_LAT1) && - chndl == current_char_set) { - HTPassEightBitRaw = TRUE; - } - } else if (p_out->enc == UCT_ENC_CJK) { - Set_HTCJK(p_in->MIMEname, p_out->MIMEname); - } - } else { - /* - * Cannot translate. If according to some heuristic the given - * charset and the current display character both are likely to be - * like ISO-8859 in structure, pretend we have some kind of match. - */ - BOOL given_is_8859 = (BOOL) (!StrNCmp(cp4, "iso-8859-", 9) && - isdigit(UCH(cp4[9]))); - BOOL given_is_8859like = (BOOL) (given_is_8859 || - !StrNCmp(cp4, "windows-", 8) || - !StrNCmp(cp4, "cp12", 4) || - !StrNCmp(cp4, "cp-12", 5)); - BOOL given_and_display_8859like = (BOOL) (given_is_8859like && - (strstr(LYchar_set_names[current_char_set], - "ISO-8859") || - strstr(LYchar_set_names[current_char_set], - "windows-"))); - - if (given_and_display_8859like) { - *cp1 = '\0'; - format = HTAtom_for(cp); - } - if (given_is_8859) { - cp1 = &cp4[10]; - while (*cp1 && - isdigit(UCH(*cp1))) - cp1++; - *cp1 = '\0'; - } - if (given_and_display_8859like) { - StrAllocCopy(anchor->charset, cp4); - HTPassEightBitRaw = TRUE; - } - HTAlert(*cp4 ? cp4 : anchor->charset); - } - FREE(cp3); - } else if (cp1 != NULL) { - /* - * No charset parameter is present. Ignore all other parameters, as we - * do when charset is present. - FM - */ - *cp1 = '\0'; - format = HTAtom_for(cp); - } - FREE(cp); - - /* - * Set up defaults, if needed. - FM - */ - if (!chartrans_ok && !anchor->charset && default_LYhndl >= 0) { - HTAnchor_setUCInfoStage(anchor, default_LYhndl, - UCT_STAGE_MIME, - UCT_SETBY_DEFAULT); - } - HTAnchor_copyUCInfoStage(anchor, - UCT_STAGE_PARSER, - UCT_STAGE_MIME, - -1); - - return format; -} - -/* Get various pieces of meta info from file name. - * ----------------------------------------------- - * - * LYGetFileInfo fills in information that can be determined without - * an actual (new) access to the filesystem, based on current suffix - * and character set configuration. If the file has been loaded and - * parsed before (with the same URL generated here!) and the anchor - * is still around, some results may be influenced by that (in - * particular, charset info from a META tag - this is not actually - * tested!). - * The caller should not keep pointers to the returned objects around - * for too long, the valid lifetimes vary. In particular, the returned - * charset string should be copied if necessary. If return of the - * file_anchor is requested, that one can be used to retrieve - * additional bits of info that are stored in the anchor object and - * are not covered here; as usual, don't keep pointers to the - * file_anchor longer than necessary since the object may disappear - * through HTuncache_current_document or at the next document load. - * - kw - */ -void LYGetFileInfo(const char *filename, - HTParentAnchor **pfile_anchor, - HTFormat *pformat, - HTAtom **pencoding, - const char **pdesc, - const char **pcharset, - int *pfile_cs) -{ - char *Afn; - char *Aname = NULL; - HTFormat format; - HTAtom *myEnc = NULL; - HTParentAnchor *file_anchor; - const char *file_csname; - int file_cs; - - /* - * Convert filename to URL. Note that it is always supposed to be a - * filename, not maybe-filename-maybe-URL, so we don't use - * LYFillLocalFileURL and LYEnsureAbsoluteURL. - kw - */ - Afn = HTEscape(filename, URL_PATH); - LYLocalFileToURL(&Aname, Afn); - file_anchor = HTAnchor_findSimpleAddress(Aname); - - file_csname = file_anchor->charset; - format = HTFileFormat(filename, &myEnc, pdesc); - format = HTCharsetFormat(format, file_anchor, UCLYhndl_HTFile_for_unspec); - file_cs = HTAnchor_getUCLYhndl(file_anchor, UCT_STAGE_MIME); - if (!file_csname) { - if (file_cs >= 0) - file_csname = LYCharSet_UC[file_cs].MIMEname; - else - file_csname = "display character set"; - } - CTRACE((tfp, "GetFileInfo: '%s' is a%s %s %s file, charset=%s (%d).\n", - filename, - ((myEnc && *HTAtom_name(myEnc) == '8') ? "n" : myEnc ? "" : - *HTAtom_name(format) == 'a' ? "n" : ""), - myEnc ? HTAtom_name(myEnc) : "", - HTAtom_name(format), - file_csname, - file_cs)); - FREE(Afn); - FREE(Aname); - if (pfile_anchor) - *pfile_anchor = file_anchor; - if (pformat) - *pformat = format; - if (pencoding) - *pencoding = myEnc; - if (pcharset) - *pcharset = file_csname; - if (pfile_cs) - *pfile_cs = file_cs; -} - -/* Determine value from file name. - * ------------------------------- - * - */ -float HTFileValue(const char *filename) -{ - HTSuffix *suff; - int n; - int i; - int lf = (int) strlen(filename); - -#ifndef NO_INIT - if (!HTSuffixes) - HTFileInit(); -#endif /* !NO_INIT */ - n = HTList_count(HTSuffixes); - for (i = 0; i < n; i++) { - int ls; - - suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i); - ls = (int) strlen(suff->suffix); - if ((ls <= lf) && 0 == strcmp(suff->suffix, filename + lf - ls)) { - CTRACE((tfp, "File: Value of %s is %.3f\n", - filename, suff->quality)); - return suff->quality; /* OK -- found */ - } - } - return (float) 0.3; /* Dunno! */ -} - -/* - * Determine compression type from file name, by looking at its suffix. - * Sets as side-effect a pointer to the "dot" that begins the suffix. - */ -CompressFileType HTCompressFileType(const char *filename, - const char *dots, - int *rootlen) -{ - CompressFileType result = cftNone; - size_t len = strlen(filename); - const char *ftype = filename + len; - - VMS_DEL_VERSION(filename); - - if ((len > 4) - && !strcasecomp((ftype - 3), "bz2") - && strchr(dots, ftype[-4]) != 0) { - result = cftBzip2; - ftype -= 4; - } else if ((len > 3) - && !strcasecomp((ftype - 2), "gz") - && strchr(dots, ftype[-3]) != 0) { - result = cftGzip; - ftype -= 3; - } else if ((len > 3) - && !strcasecomp((ftype - 2), "zz") - && strchr(dots, ftype[-3]) != 0) { - result = cftDeflate; - ftype -= 3; - } else if ((len > 2) - && !strcmp((ftype - 1), "Z") - && strchr(dots, ftype[-2]) != 0) { - result = cftCompress; - ftype -= 2; - } - - *rootlen = (int) (ftype - filename); - - CTRACE((tfp, "HTCompressFileType(%s) returns %d:%s\n", - filename, (int) result, filename + *rootlen)); - return result; -} - -/* - * Determine expected file-suffix from the compression method. - */ -const char *HTCompressTypeToSuffix(CompressFileType method) -{ - const char *result = ""; - - switch (method) { - default: - case cftNone: - result = ""; - break; - case cftGzip: - result = ".gz"; - break; - case cftCompress: - result = ".Z"; - break; - case cftBzip2: - result = ".bz2"; - break; - case cftDeflate: - result = ".zz"; - break; - } - return result; -} - -/* - * Determine compression encoding from the compression method. - */ -const char *HTCompressTypeToEncoding(CompressFileType method) -{ - const char *result = NULL; - - switch (method) { - default: - case cftNone: - result = NULL; - break; - case cftGzip: - result = "gzip"; - break; - case cftCompress: - result = "compress"; - break; - case cftBzip2: - result = "bzip2"; - break; - case cftDeflate: - result = "deflate"; - break; - } - return result; -} - -/* - * Check if the token from "Content-Encoding" corresponds to a compression - * type. RFC 2068 (and cut/paste into RFC 2616) lists these: - * gzip - * compress - * deflate - * as well as "identity" (but that does nothing). - */ -CompressFileType HTEncodingToCompressType(const char *coding) -{ - CompressFileType result = cftNone; - - if (coding == NULL) { - result = cftNone; - } else if (!strcasecomp(coding, "gzip") || - !strcasecomp(coding, "x-gzip")) { - result = cftGzip; - } else if (!strcasecomp(coding, "compress") || - !strcasecomp(coding, "x-compress")) { - result = cftCompress; - } else if (!strcasecomp(coding, "bzip2") || - !strcasecomp(coding, "x-bzip2")) { - result = cftBzip2; - } else if (!strcasecomp(coding, "deflate") || - !strcasecomp(coding, "x-deflate")) { - result = cftDeflate; - } - return result; -} - -CompressFileType HTContentTypeToCompressType(const char *ct) -{ - CompressFileType method = cftNone; - - if (ct == NULL) { - method = cftNone; - } else if (!strncasecomp(ct, "application/gzip", 16) || - !strncasecomp(ct, "application/x-gzip", 18)) { - method = cftGzip; - } else if (!strncasecomp(ct, "application/compress", 20) || - !strncasecomp(ct, "application/x-compress", 22)) { - method = cftCompress; - } else if (!strncasecomp(ct, "application/bzip2", 17) || - !strncasecomp(ct, "application/x-bzip2", 19)) { - method = cftBzip2; - } - return method; -} - -/* - * Check the anchor's content_type and content_encoding elements for a gzip or - * Unix compressed file -FM, TD - */ -CompressFileType HTContentToCompressType(HTParentAnchor *anchor) -{ - CompressFileType method = cftNone; - const char *ct = HTAnchor_content_type(anchor); - const char *ce = HTAnchor_content_encoding(anchor); - - if (ce == NULL && ct != 0) { - method = HTContentTypeToCompressType(ct); - } else if (ce != 0) { - method = HTEncodingToCompressType(ce); - } - return method; -} - -/* Determine write access to a file. - * --------------------------------- - * - * On exit: - * Returns YES if file can be accessed and can be written to. - * - * Bugs: - * 1. No code for non-unix systems. - * 2. Isn't there a quicker way? - */ -BOOL HTEditable(const char *filename GCC_UNUSED) -{ -#ifndef NO_GROUPS - GETGROUPS_T groups[NGROUPS]; - uid_t myUid; - int ngroups; /* The number of groups */ - struct stat fileStatus; - int i; - - if (stat(filename, &fileStatus)) /* Get details of filename */ - return NO; /* Can't even access file! */ - - ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */ - myUid = geteuid(); /* Get my user identifier */ - - if (TRACE) { - int i2; - - fprintf(tfp, - "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (", - (unsigned int) fileStatus.st_mode, - (int) fileStatus.st_uid, - (int) fileStatus.st_gid, - (int) myUid, - (int) ngroups); - for (i2 = 0; i2 < ngroups; i2++) - fprintf(tfp, " %d", (int) groups[i2]); - fprintf(tfp, ")\n"); - } - - if (fileStatus.st_mode & 0002) /* I can write anyway? */ - return YES; - - if ((fileStatus.st_mode & 0200) /* I can write my own file? */ - &&(fileStatus.st_uid == myUid)) - return YES; - - if (fileStatus.st_mode & 0020) /* Group I am in can write? */ - { - for (i = 0; i < ngroups; i++) { - if (groups[i] == fileStatus.st_gid) - return YES; - } - } - CTRACE((tfp, "\tFile is not editable.\n")); -#endif /* NO_GROUPS */ - return NO; /* If no excuse, can't do */ -} - -/* Make a save stream. - * ------------------- - * - * The stream must be used for writing back the file. - * @@@ no backup done - */ -HTStream *HTFileSaveStream(HTParentAnchor *anchor) -{ - const char *addr = anchor->address; - char *localname = HTLocalName(addr); - FILE *fp = fopen(localname, BIN_W); - - FREE(localname); - if (!fp) - return NULL; - - return HTFWriter_new(fp); -} - -/* Output one directory entry. - * --------------------------- - */ -void HTDirEntry(HTStructured * target, const char *tail, - const char *entry) -{ - char *relative = NULL; - char *stripped = NULL; - char *escaped = NULL; - int len; - - StrAllocCopy(escaped, entry); - LYTrimPathSep(escaped); - if (strcmp(escaped, "..") != 0) { - stripped = escaped; - escaped = HTEscape(stripped, URL_XPALPHAS); - if (((len = (int) strlen(escaped)) > 2) && - escaped[(len - 3)] == '%' && - escaped[(len - 2)] == '2' && - TOUPPER(escaped[(len - 1)]) == 'F') { - escaped[(len - 3)] = '\0'; - } - } - - if (isEmpty(tail)) { - /* - * Handle extra slash at end of path. - */ - HTStartAnchor(target, NULL, (escaped[0] != '\0' ? escaped : "/")); - } else { - /* - * If empty tail, gives absolute ref below. - */ - relative = 0; - HTSprintf0(&relative, "%s%s%s", - tail, - (*escaped != '\0' ? "/" : ""), - escaped); - HTStartAnchor(target, NULL, relative); - FREE(relative); - } - FREE(stripped); - FREE(escaped); -} - -static BOOL view_structured(HTFormat format_out) -{ - BOOL result = FALSE; - -#ifdef USE_PRETTYSRC - if (psrc_view - || (format_out == HTAtom_for("www/dump"))) - result = TRUE; -#else - if (format_out == WWW_SOURCE) - result = TRUE; -#endif - return result; -} - -/* - * Write a DOCTYPE to the given stream if we happen to want to see the - * source view, or are dumping source. This is not needed when the source - * is not visible, since the document is rendered from a HTStructured object. - */ -void HTStructured_doctype(HTStructured * target, HTFormat format_out) -{ - if (view_structured(format_out)) - PUTS("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"); -} - -void HTStructured_meta(HTStructured * target, HTFormat format_out) -{ - if (view_structured(format_out)) - PUTS("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"); -} -/* Output parent directory entry. - * ------------------------------ - * - * This gives the TITLE and H1 header, and also a link - * to the parent directory if appropriate. - * - * On exit: - * Returns TRUE if an "Up to <parent>" link was not created - * for a readable local directory because LONG_LIST is defined - * and NO_PARENT_DIR_REFERENCE is not defined, so that the - * calling function should use LYListFmtParse() to create a link - * to the parent directory. Otherwise, it returns FALSE. - FM - */ -BOOL HTDirTitles(HTStructured * target, HTParentAnchor *anchor, - HTFormat format_out, - int tildeIsTop) -{ - const char *logical = anchor->address; - char *path = HTParse(logical, "", PARSE_PATH + PARSE_PUNCTUATION); - char *current; - char *cp = NULL; - BOOL need_parent_link = FALSE; - int i; - -#if defined(USE_DOS_DRIVES) - BOOL local_link = (strlen(logical) > 18 - && !strncasecomp(logical, "file://localhost/", 17) - && LYIsDosDrive(logical + 17)); - BOOL is_remote = !local_link; - -#else -#define is_remote TRUE -#endif - - /* - * Check tildeIsTop for treating home directory as Welcome (assume the - * tilde is not followed by a username). - FM - */ - if (tildeIsTop && !StrNCmp(path, "/~", 2)) { - if (path[2] == '\0') { - path[1] = '\0'; - } else { - for (i = 0; path[(i + 2)]; i++) { - path[i] = path[(i + 2)]; - } - path[i] = '\0'; - } - } - - /* - * Trim out the ;type= parameter, if present. - FM - */ - if ((cp = strrchr(path, ';')) != NULL) { - if (!strncasecomp((cp + 1), "type=", 5)) { - if (TOUPPER(*(cp + 6)) == 'D' || - TOUPPER(*(cp + 6)) == 'A' || - TOUPPER(*(cp + 6)) == 'I') - *cp = '\0'; - } - cp = NULL; - } - current = LYPathLeaf(path); /* last part or "" */ - - { - char *printable = NULL; - -#ifdef DIRED_SUPPORT - printable = HTURLPath_toFile(((!strncasecomp(path, "/%2F", 4)) /* "//" ? */ - ? (path + 1) - : path), - TRUE, - is_remote); - if (0 == strncasecomp(printable, "/vmsysu:", 8) || - 0 == strncasecomp(printable, "/anonymou.", 10)) { - StrAllocCopy(cp, (printable + 1)); - StrAllocCopy(printable, cp); - FREE(cp); - } -#else - StrAllocCopy(printable, current); - HTUnEscape(printable); -#endif /* DIRED_SUPPORT */ - - HTStructured_doctype(target, format_out); - - START(HTML_HEAD); - PUTC('\n'); - START(HTML_TITLE); - PUTS(*printable ? printable : WELCOME_MSG); - PUTS(SEGMENT_DIRECTORY); - END(HTML_TITLE); - PUTC('\n'); - HTStructured_meta(target, format_out); - END(HTML_HEAD); - PUTC('\n'); - - START(HTML_BODY); - PUTC('\n'); - -#ifdef DIRED_SUPPORT - START(HTML_H2); - PUTS(*printable ? SEGMENT_CURRENT_DIR : ""); - PUTS(*printable ? printable : WELCOME_MSG); - END(HTML_H2); - PUTC('\n'); -#else - START(HTML_H1); - PUTS(*printable ? printable : WELCOME_MSG); - END(HTML_H1); - PUTC('\n'); -#endif /* DIRED_SUPPORT */ - if (((0 == strncasecomp(printable, "vmsysu:", 7)) && - (cp = strchr(printable, '.')) != NULL && - strchr(cp, '/') == NULL) || - (0 == strncasecomp(printable, "anonymou.", 9) && - strchr(printable, '/') == NULL)) { - FREE(printable); - FREE(path); - return (need_parent_link); - } - FREE(printable); - } - -#ifndef NO_PARENT_DIR_REFERENCE - /* - * Make link back to parent directory. - */ - if (current - path > 0 - && LYIsPathSep(current[-1]) - && current[0] != '\0') { /* was a slash AND something else too */ - char *parent = NULL; - char *relative = NULL; - - current[-1] = '\0'; - parent = strrchr(path, '/'); /* penultimate slash */ - - if ((parent && - (!strcmp(parent, "/..") || - !strncasecomp(parent, "/%2F", 4))) || - !strncasecomp(current, "%2F", 3)) { - FREE(path); - return (need_parent_link); - } - - relative = 0; - HTSprintf0(&relative, "%s/..", current); - -#if defined(DOSPATH) || defined(__EMX__) - if (local_link) { - if (parent != 0 && strlen(parent) == 3) { - StrAllocCat(relative, "/."); - } - } else -#endif - -#if !defined (VMS) - { - /* - * On Unix, if it's not ftp and the directory cannot be read, don't - * put out a link. - * - * On VMS, this problem is dealt with internally by - * HTVMSBrowseDir(). - */ - DIR *dp = NULL; - - if (LYisLocalFile(logical)) { - /* - * We need an absolute file path for the opendir. We also need - * to unescape for this test. Don't worry about %2F now, they - * presumably have been dealt with above, and shouldn't appear - * for local files anyway... Assume OS / filesystem will just - * ignore superfluous slashes. - KW - */ - char *fullparentpath = NULL; - - /* - * Path has been shortened above. - */ - StrAllocCopy(fullparentpath, *path ? path : "/"); - - /* - * Guard against weirdness. - */ - if (0 == strcmp(current, "..")) { - StrAllocCat(fullparentpath, "/../.."); - } else if (0 == strcmp(current, ".")) { - StrAllocCat(fullparentpath, "/.."); - } - - HTUnEscape(fullparentpath); - if ((dp = opendir(fullparentpath)) == NULL) { - FREE(fullparentpath); - FREE(relative); - FREE(path); - return (need_parent_link); - } - closedir(dp); - FREE(fullparentpath); -#ifdef LONG_LIST - need_parent_link = TRUE; - FREE(path); - FREE(relative); - return (need_parent_link); -#endif /* LONG_LIST */ - } - } -#endif /* !VMS */ - HTStartAnchor(target, "", relative); - FREE(relative); - - PUTS(SEGMENT_UP_TO); - if (parent) { - if ((0 == strcmp(current, ".")) || - (0 == strcmp(current, ".."))) { - /* - * Should not happen, but if it does, at least avoid giving - * misleading info. - KW - */ - PUTS(".."); - } else { - char *printable = NULL; - - StrAllocCopy(printable, parent + 1); - HTUnEscape(printable); - PUTS(printable); - FREE(printable); - } - } else { - PUTC('/'); - } - END(HTML_A); - PUTC('\n'); - } -#endif /* !NO_PARENT_DIR_REFERENCE */ - - FREE(path); - return (need_parent_link); -} - -#if defined HAVE_READDIR -/* Send README file. - * ----------------- - * - * If a README file exists, then it is inserted into the document here. - */ -static void do_readme(HTStructured * target, const char *localname) -{ - FILE *fp; - char *readme_file_name = NULL; - int ch; - - HTSprintf0(&readme_file_name, "%s/%s", localname, HT_DIR_README_FILE); - - fp = fopen(readme_file_name, "r"); - - if (fp) { - START(HTML_PRE); - while ((ch = fgetc(fp)) != EOF) { - PUTC((char) ch); - } - END(HTML_PRE); - HTDisplayPartial(); - fclose(fp); - } - FREE(readme_file_name); -} - -#define DIRED_BLOK(obj) (((DIRED *)(obj))->sort_tags) -#define DIRED_NAME(obj) (((DIRED *)(obj))->file_name) - -#define NM_cmp(a,b) ((a) < (b) ? -1 : ((a) > (b) ? 1 : 0)) - -#if defined(LONG_LIST) && defined(DIRED_SUPPORT) -static const char *file_type(const char *path) -{ - const char *type; - - while (*path == '.') - ++path; - type = strchr(path, '.'); - if (type == NULL) - type = ""; - return type; -} -#endif /* LONG_LIST && DIRED_SUPPORT */ - -static int dired_cmp(void *a, void *b) -{ - DIRED *p = (DIRED *) a; - DIRED *q = (DIRED *) b; - int code = p->sort_tags - q->sort_tags; - -#if defined(LONG_LIST) && defined(DIRED_SUPPORT) - if (code == 0) { - switch (dir_list_order) { - case ORDER_BY_SIZE: - code = -NM_cmp(p->file_info.st_size, q->file_info.st_size); - break; - case ORDER_BY_DATE: - code = -NM_cmp(p->file_info.st_mtime, q->file_info.st_mtime); - break; - case ORDER_BY_MODE: - code = NM_cmp(p->file_info.st_mode, q->file_info.st_mode); - break; - case ORDER_BY_USER: - code = NM_cmp(p->file_info.st_uid, q->file_info.st_uid); - break; - case ORDER_BY_GROUP: - code = NM_cmp(p->file_info.st_gid, q->file_info.st_gid); - break; - case ORDER_BY_TYPE: - code = AS_cmp(file_type(p->file_name), file_type(q->file_name)); - break; - default: - code = 0; - break; - } - } -#endif /* LONG_LIST && DIRED_SUPPORT */ - if (code == 0) - code = AS_cmp(p->file_name, q->file_name); -#if 0 - CTRACE((tfp, "dired_cmp(%d) ->%d\n\t%c:%s (%s)\n\t%c:%s (%s)\n", - dir_list_order, - code, - p->sort_tags, p->file_name, file_type(p->file_name), - q->sort_tags, q->file_name, file_type(q->file_name))); -#endif - return code; -} - -static int print_local_dir(DIR *dp, char *localname, - HTParentAnchor *anchor, - HTFormat format_out, - HTStream *sink) -{ - HTStructured *target; /* HTML object */ - HTBTree *bt; - HTStructuredClass targetClass; - STRUCT_DIRENT *dirbuf; - char *pathname = NULL; - char *tail = NULL; - const char *p; - char *tmpfilename = NULL; - BOOL need_parent_link = FALSE; - BOOL preformatted = FALSE; - int status; - struct stat *actual_info; - -#ifdef DISP_PARTIAL - int num_of_entries = 0; /* lines counter */ -#endif - -#ifdef S_IFLNK - struct stat link_info; -#endif - - CTRACE((tfp, "print_local_dir() started\n")); - - pathname = HTParse(anchor->address, "", - PARSE_PATH + PARSE_PUNCTUATION); - - if ((p = strrchr(pathname, '/')) == NULL) - p = "/"; - StrAllocCopy(tail, (p + 1)); - FREE(pathname); - - 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; /* Copy routine entry points */ - - /* - * The need_parent_link flag will be set if an "Up to <parent>" link was - * not created for a readable parent in HTDirTitles() because LONG_LIST is - * defined and NO_PARENT_DIR_REFERENCE is not defined so that need we to - * create the link via an LYListFmtParse() call. - FM - */ - need_parent_link = HTDirTitles(target, anchor, format_out, FALSE); - -#ifdef DIRED_SUPPORT - if (!isLYNXCGI(anchor->address)) { - HTAnchor_setFormat(anchor, WWW_DIRED); - lynx_edit_mode = TRUE; - } -#endif /* DIRED_SUPPORT */ - if (HTDirReadme == HT_DIR_README_TOP) - do_readme(target, localname); - - bt = HTBTree_new(dired_cmp); - - _HTProgress(READING_DIRECTORY); - status = HT_LOADED; /* assume we don't get interrupted */ - while ((dirbuf = readdir(dp)) != NULL) { - /* - * While there are directory entries to be read... - */ - DIRED *data = NULL; - -#ifdef STRUCT_DIRENT__D_INO - if (dirbuf->d_ino == 0) - /* - * If the entry is not being used, skip it. - */ - continue; -#endif - /* - * Skip self, parent if handled in HTDirTitles() or if - * NO_PARENT_DIR_REFERENCE is not defined, and any dot files if - * no_dotfiles is set or show_dotfiles is not set. - FM - */ - if (!strcmp(dirbuf->d_name, ".") /* self */ || - (!strcmp(dirbuf->d_name, "..") /* parent */ && - need_parent_link == FALSE) || - ((strcmp(dirbuf->d_name, "..")) && - (dirbuf->d_name[0] == '.' && - (no_dotfiles || !show_dotfiles)))) - continue; - - StrAllocCopy(tmpfilename, localname); - /* - * If filename is not root directory, add trailing separator. - */ - LYAddPathSep(&tmpfilename); - - StrAllocCat(tmpfilename, dirbuf->d_name); - data = (DIRED *) malloc(sizeof(DIRED) + strlen(dirbuf->d_name) + 4); - if (data == NULL) { - status = HT_PARTIAL_CONTENT; - break; - } - LYTrimPathSep(tmpfilename); - - actual_info = &(data->file_info); -#ifdef S_IFLNK - if (lstat(tmpfilename, actual_info) < 0) { - actual_info->st_mode = 0; - } else { - if (S_ISLNK(actual_info->st_mode)) { - actual_info = &link_info; - if (stat(tmpfilename, actual_info) < 0) - actual_info->st_mode = 0; - } - } -#else - if (stat(tmpfilename, actual_info) < 0) - actual_info->st_mode = 0; -#endif - - strcpy(data->file_name, dirbuf->d_name); -#ifndef DIRED_SUPPORT - if (S_ISDIR(actual_info->st_mode)) { - data->sort_tags = 'D'; - } else { - data->sort_tags = 'F'; - /* D & F to have first directories, then files */ - } -#else - if (S_ISDIR(actual_info->st_mode)) { - if (dir_list_style == MIXED_STYLE) { - data->sort_tags = ' '; - LYAddPathSep0(data->file_name); - } else if (!strcmp(dirbuf->d_name, "..")) { - data->sort_tags = 'A'; - } else { - data->sort_tags = 'D'; - } - } else if (dir_list_style == MIXED_STYLE) { - data->sort_tags = ' '; - } else if (dir_list_style == FILES_FIRST) { - data->sort_tags = 'C'; - /* C & D to have first files, then directories */ - } else { - data->sort_tags = 'F'; - } -#endif /* !DIRED_SUPPORT */ - /* - * Sort dirname in the tree bt. - */ - HTBTree_add(bt, data); - -#ifdef DISP_PARTIAL - /* optimize for expensive operation: */ - if (num_of_entries % (partial_threshold > 0 ? - partial_threshold : display_lines) == 0) { - if (HTCheckForInterrupt()) { - status = HT_PARTIAL_CONTENT; - break; - } - } - num_of_entries++; -#endif /* DISP_PARTIAL */ - - } /* end while directory entries left to read */ - - if (status != HT_PARTIAL_CONTENT) - _HTProgress(OPERATION_OK); - else - CTRACE((tfp, "Reading the directory interrupted by user\n")); - - /* - * Run through tree printing out in order. - */ - { - HTBTElement *next_element = HTBTree_next(bt, NULL); - - /* pick up the first element of the list */ - int num_of_entries_output = 0; /* lines counter */ - - char state; - - /* I for initial (.. file), - D for directory file, - F for file */ - -#ifdef DIRED_SUPPORT - char test; -#endif /* DIRED_SUPPORT */ - state = 'I'; - - while (next_element != NULL) { - DIRED *entry; - -#ifndef DISP_PARTIAL - if (num_of_entries_output % HTMAX(display_lines, 10) == 0) { - if (HTCheckForInterrupt()) { - _HTProgress(TRANSFER_INTERRUPTED); - status = HT_PARTIAL_CONTENT; - break; - } - } -#endif - StrAllocCopy(tmpfilename, localname); - /* - * If filename is not root directory. - */ - LYAddPathSep(&tmpfilename); - - entry = (DIRED *) (HTBTree_object(next_element)); - /* - * Append the current entry's filename to the path. - */ - StrAllocCat(tmpfilename, entry->file_name); - HTSimplify(tmpfilename); - /* - * Output the directory entry. - */ - if (strcmp(DIRED_NAME(HTBTree_object(next_element)), "..")) { -#ifdef DIRED_SUPPORT - test = - (char) (DIRED_BLOK(HTBTree_object(next_element)) - == 'D' ? 'D' : 'F'); - if (state != test) { -#ifndef LONG_LIST - if (dir_list_style == FILES_FIRST) { - if (state == 'F') { - END(HTML_DIR); - PUTC('\n'); - } - } else if (dir_list_style != MIXED_STYLE) - if (state == 'D') { - END(HTML_DIR); - PUTC('\n'); - } -#endif /* !LONG_LIST */ - state = - (char) (DIRED_BLOK(HTBTree_object(next_element)) - == 'D' ? 'D' : 'F'); - if (preformatted) { - END(HTML_PRE); - PUTC('\n'); - preformatted = FALSE; - } - START(HTML_H2); - if (dir_list_style != MIXED_STYLE) { - START(HTML_EM); - PUTS(state == 'D' - ? LABEL_SUBDIRECTORIES - : LABEL_FILES); - END(HTML_EM); - } - END(HTML_H2); - PUTC('\n'); -#ifndef LONG_LIST - START(HTML_DIR); - PUTC('\n'); -#endif /* !LONG_LIST */ - } -#else - if (state != DIRED_BLOK(HTBTree_object(next_element))) { -#ifndef LONG_LIST - if (state == 'D') { - END(HTML_DIR); - PUTC('\n'); - } -#endif /* !LONG_LIST */ - state = - (char) (DIRED_BLOK(HTBTree_object(next_element)) - == 'D' ? 'D' : 'F'); - if (preformatted) { - END(HTML_PRE); - PUTC('\n'); - preformatted = FALSE; - } - START(HTML_H2); - START(HTML_EM); - PUTS(state == 'D' - ? LABEL_SUBDIRECTORIES - : LABEL_FILES); - END(HTML_EM); - END(HTML_H2); - PUTC('\n'); -#ifndef LONG_LIST - START(HTML_DIR); - PUTC('\n'); -#endif /* !LONG_LIST */ - } -#endif /* DIRED_SUPPORT */ -#ifndef LONG_LIST - START(HTML_LI); -#endif /* !LONG_LIST */ - } - if (!preformatted) { - START(HTML_PRE); - PUTC('\n'); - preformatted = TRUE; - } -#ifdef LONG_LIST - LYListFmtParse(list_format, entry, tmpfilename, target, tail); -#else - HTDirEntry(target, tail, entry->file_name); - PUTS(entry->file_name); - END(HTML_A); - MAYBE_END(HTML_LI); - PUTC('\n'); -#endif /* LONG_LIST */ - - next_element = HTBTree_next(bt, next_element); - /* pick up the next element of the list; - if none, return NULL */ - - /* optimize for expensive operation: */ -#ifdef DISP_PARTIAL - if (num_of_entries_output % - ((partial_threshold > 0) - ? partial_threshold - : display_lines) == 0) { - /* num_of_entries, num_of_entries_output... */ - HTDisplayPartial(); - - if (HTCheckForInterrupt()) { - _HTProgress(TRANSFER_INTERRUPTED); - status = HT_PARTIAL_CONTENT; - break; - } - } - num_of_entries_output++; -#endif /* DISP_PARTIAL */ - - } /* end while next_element */ - - if (status == HT_LOADED) { - if (state == 'I') { - START(HTML_P); - PUTS("Empty Directory"); - } -#ifndef LONG_LIST - else - END(HTML_DIR); -#endif /* !LONG_LIST */ - } - } /* end printing out the tree in order */ - if (preformatted) { - END(HTML_PRE); - PUTC('\n'); - } - END(HTML_BODY); - PUTC('\n'); - - FREE(tmpfilename); - FREE(tail); - HTBTreeAndObject_free(bt); - - if (status == HT_LOADED) { - if (HTDirReadme == HT_DIR_README_BOTTOM) - do_readme(target, localname); - FREE_TARGET; - } else { - ABORT_TARGET; - } - HTFinishDisplayPartial(); - return status; /* document loaded, maybe partial */ -} -#endif /* HAVE_READDIR */ - -#ifndef VMS -int HTStat(const char *filename, - struct stat *data) -{ - int result = -1; - size_t len = strlen(filename); - - if (len != 0 && LYIsPathSep(filename[len - 1])) { - char *temp_name = NULL; - - HTSprintf0(&temp_name, "%s.", filename); - result = HTStat(temp_name, data); - FREE(temp_name); - } else { - result = stat(filename, data); -#ifdef _WINDOWS - /* - * Someone claims that stat() doesn't give the proper result for a - * directory on Windows. - */ - if (result == -1 - && access(filename, 0) == 0) { - data->st_mode = S_IFDIR; - result = 0; - } -#endif - } - return result; -} -#endif - -#if defined(USE_ZLIB) || defined(USE_BZLIB) -static BOOL sniffStream(FILE *fp, char *buffer, size_t needed) -{ - long offset = ftell(fp); - BOOL result = FALSE; - - if (fread(buffer, sizeof(char), needed, fp) == needed) { - result = TRUE; - } - if (fseek(fp, offset, SEEK_SET) < 0) { - CTRACE((tfp, "error seeking in stream\n")); - result = FALSE; - } - return result; -} -#endif - -#ifdef USE_ZLIB -static BOOL isGzipStream(FILE *fp) -{ - char buffer[3]; - BOOL result; - - if (sniffStream(fp, buffer, sizeof(buffer)) - && !MemCmp(buffer, "\037\213", sizeof(buffer) - 1)) { - result = TRUE; - } else { - CTRACE((tfp, "not a gzip-stream\n")); - result = FALSE; - } - return result; -} - -static BOOL isDeflateStream(FILE *fp) -{ - char buffer[3]; - BOOL result; - - if (sniffStream(fp, buffer, sizeof(buffer)) - && !MemCmp(buffer, "\170\234", sizeof(buffer) - 1)) { - result = TRUE; - } else { - CTRACE((tfp, "not a deflate-stream\n")); - result = FALSE; - } - return result; -} -#endif - -#ifdef USE_BZLIB -static BOOL isBzip2Stream(FILE *fp) -{ - char buffer[6]; - BOOL result; - - if (sniffStream(fp, buffer, sizeof(buffer)) - && !MemCmp(buffer, "BZh", 3) - && isdigit(UCH(buffer[3])) - && isdigit(UCH(buffer[4]))) { - result = TRUE; - } else { - CTRACE((tfp, "not a bzip2-stream\n")); - result = FALSE; - } - return result; -} -#endif - -#ifdef VMS -#define FOPEN_MODE(bin) "r", "shr=put", "shr=upd" -#define DOT_STRING "._-" /* FIXME: should we check if suffix is after ']' or ':' ? */ -#else -#define FOPEN_MODE(bin) (bin ? BIN_R : "r") -#define DOT_STRING "." -#endif - -static int decompressAndParse(HTParentAnchor *anchor, - HTFormat format_out, - HTStream *sink, - char *nodename GCC_UNUSED, - char *filename, - HTAtom *myEncoding, - HTFormat format, - int *statusp) -{ - HTAtom *encoding = 0; - -#ifdef USE_ZLIB - FILE *zzfp = 0; - gzFile gzfp = 0; -#endif /* USE_ZLIB */ -#ifdef USE_BZLIB - BZFILE *bzfp = 0; -#endif /* USE_ZLIB */ -#if defined(USE_ZLIB) || defined(USE_BZLIB) - CompressFileType internal_decompress = cftNone; - BOOL failed_decompress = NO; -#endif - int rootlen = 0; - char *localname = filename; - int bin; - FILE *fp; - -#ifdef VMS - /* - * Assume that the file is in Unix-style syntax if it contains a '/' after - * the leading one. @@ - */ - localname = (strchr(localname + 1, '/') - ? HTVMS_name(nodename, localname) - : localname + 1); -#endif /* VMS */ - - bin = HTCompressFileType(filename, ".", &rootlen) != cftNone; - fp = fopen(localname, FOPEN_MODE(bin)); - -#ifdef VMS - /* - * If the file wasn't VMS syntax, then perhaps it is Ultrix. - */ - if (!fp) { - char *ultrixname = 0; - - CTRACE((tfp, "HTLoadFile: Can't open as %s\n", localname)); - HTSprintf0(&ultrixname, "%s::\"%s\"", nodename, filename); - fp = fopen(ultrixname, FOPEN_MODE(bin)); - if (!fp) { - CTRACE((tfp, "HTLoadFile: Can't open as %s\n", ultrixname)); - } - FREE(ultrixname); - } -#endif /* VMS */ - CTRACE((tfp, "HTLoadFile: Opening `%s' gives %p\n", localname, (void *) fp)); - if (fp) { /* Good! */ - if (HTEditable(localname)) { - HTAtom *put = HTAtom_for("PUT"); - HTList *methods = HTAnchor_methods(anchor); - - if (HTList_indexOf(methods, put) == (-1)) { - HTList_addObject(methods, put); - } - } - /* - * Fake a Content-Encoding for compressed files. - FM - */ - if (!IsUnityEnc(myEncoding)) { - /* - * We already know from the call to HTFileFormat that - * this is a compressed file, no need to look at the filename - * again. - kw - */ -#if defined(USE_ZLIB) || defined(USE_BZLIB) - CompressFileType method = HTEncodingToCompressType(HTAtom_name(myEncoding)); -#endif - -#define isDOWNLOAD(m) (strcmp(format_out->name, "www/download") && (method == m)) -#ifdef USE_ZLIB - if (isDOWNLOAD(cftGzip)) { - if (isGzipStream(fp)) { - fclose(fp); - gzfp = gzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", - localname, gzfp)); - } - internal_decompress = cftGzip; - } else if (isDOWNLOAD(cftDeflate)) { - if (isDeflateStream(fp)) { - zzfp = fp; - fp = 0; - - CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n", - localname, (void *) zzfp)); - } - internal_decompress = cftDeflate; - } else -#endif /* USE_ZLIB */ -#ifdef USE_BZLIB - if (isDOWNLOAD(cftBzip2)) { - if (isBzip2Stream(fp)) { - fclose(fp); - bzfp = BZ2_bzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", - localname, bzfp)); - } - internal_decompress = cftBzip2; - } else -#endif /* USE_BZLIB */ - { - StrAllocCopy(anchor->content_type, format->name); - StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); - format = HTAtom_for("www/compressed"); - } - } else { - CompressFileType cft = HTCompressFileType(localname, DOT_STRING, &rootlen); - - if (cft != cftNone) { - char *cp = NULL; - - StrAllocCopy(cp, localname); - cp[rootlen] = '\0'; - format = HTFileFormat(cp, &encoding, NULL); - FREE(cp); - format = HTCharsetFormat(format, anchor, - UCLYhndl_HTFile_for_unspec); - StrAllocCopy(anchor->content_type, format->name); - } - - switch (cft) { - case cftCompress: - StrAllocCopy(anchor->content_encoding, "x-compress"); - format = HTAtom_for("www/compressed"); - break; - case cftDeflate: - StrAllocCopy(anchor->content_encoding, "x-deflate"); -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0) { - if (isDeflateStream(fp)) { - zzfp = fp; - fp = 0; - - CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n", - localname, (void *) zzfp)); - } - internal_decompress = cftDeflate; - } -#else /* USE_ZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_ZLIB */ - break; - case cftGzip: - StrAllocCopy(anchor->content_encoding, "x-gzip"); -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0) { - if (isGzipStream(fp)) { - fclose(fp); - gzfp = gzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", - localname, gzfp)); - } - internal_decompress = cftGzip; - } -#else /* USE_ZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_ZLIB */ - break; - case cftBzip2: - StrAllocCopy(anchor->content_encoding, "x-bzip2"); -#ifdef USE_BZLIB - if (strcmp(format_out->name, "www/download") != 0) { - if (isBzip2Stream(fp)) { - fclose(fp); - bzfp = BZ2_bzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", - localname, bzfp)); - } - internal_decompress = cftBzip2; - } -#else /* USE_BZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_BZLIB */ - break; - case cftNone: - break; - } - } -#if defined(USE_ZLIB) || defined(USE_BZLIB) - if (internal_decompress != cftNone) { - switch (internal_decompress) { -#ifdef USE_ZLIB - case cftDeflate: - failed_decompress = (BOOLEAN) (zzfp == NULL); - break; - case cftCompress: - case cftGzip: - failed_decompress = (BOOLEAN) (gzfp == NULL); - break; -#endif -#ifdef USE_BZLIB - case cftBzip2: - failed_decompress = (BOOLEAN) (bzfp == NULL); - break; -#endif - default: - failed_decompress = YES; - break; - } - if (failed_decompress) { - *statusp = HTLoadError(NULL, - -(HT_ERROR), - FAILED_OPEN_COMPRESSED_FILE); - } else { - char *sugfname = NULL; - - if (anchor->SugFname) { - StrAllocCopy(sugfname, anchor->SugFname); - } else { - char *anchor_path = HTParse(anchor->address, "", - PARSE_PATH + PARSE_PUNCTUATION); - char *lastslash; - - HTUnEscape(anchor_path); - lastslash = strrchr(anchor_path, '/'); - if (lastslash) - StrAllocCopy(sugfname, lastslash + 1); - FREE(anchor_path); - } - FREE(anchor->content_encoding); - if (sugfname && *sugfname) - HTCheckFnameForCompression(&sugfname, anchor, - TRUE); - if (sugfname && *sugfname) - StrAllocCopy(anchor->SugFname, sugfname); - FREE(sugfname); -#ifdef USE_BZLIB - if (bzfp) - *statusp = HTParseBzFile(format, format_out, - anchor, - bzfp, sink); -#endif -#ifdef USE_ZLIB - if (gzfp) - *statusp = HTParseGzFile(format, format_out, - anchor, - gzfp, sink); - else if (zzfp) - *statusp = HTParseZzFile(format, format_out, - anchor, - zzfp, sink); -#endif - } - } else -#endif /* USE_ZLIB || USE_BZLIB */ - { - *statusp = HTParseFile(format, format_out, anchor, fp, sink); - fclose(fp); - } - return TRUE; - } /* If successful open */ - return FALSE; -} - -/* Load a document. - * ---------------- - * - * On entry: - * addr must point to the fully qualified hypertext reference. - * This is the physical address of the file - * - * On exit: - * returns <0 Error has occurred. - * HTLOADED OK - * - */ -int HTLoadFile(const char *addr, - HTParentAnchor *anchor, - HTFormat format_out, - HTStream *sink) -{ - char *filename = NULL; - char *acc_method = NULL; - HTFormat format; - char *nodename = NULL; - char *newname = NULL; /* Simplified name of file */ - HTAtom *myEncoding = NULL; /* enc of this file, may be gzip etc. */ - int status = -1; - -#ifndef DISABLE_FTP - char *ftp_newhost; -#endif - -#ifdef VMS - struct stat stat_info; -#endif /* VMS */ - - /* - * Reduce the filename to a basic form (hopefully unique!). - */ - StrAllocCopy(newname, addr); - filename = HTParse(newname, "", PARSE_PATH | PARSE_PUNCTUATION); - nodename = HTParse(newname, "", PARSE_HOST); - - /* - * If access is ftp, or file is on another host, invoke ftp now. - */ - acc_method = HTParse(newname, "", PARSE_ACCESS); - if (strcmp("ftp", acc_method) == 0 || - (!LYSameHostname("localhost", nodename) && - !LYSameHostname(nodename, HTHostName()))) { - status = -1; - FREE(newname); - FREE(filename); - FREE(nodename); - FREE(acc_method); -#ifndef DISABLE_FTP - ftp_newhost = HTParse(addr, "", PARSE_HOST); - if (strcmp(ftp_lasthost, ftp_newhost)) - ftp_local_passive = ftp_passive; - - status = HTFTPLoad(addr, anchor, format_out, sink); - - if (ftp_passive == ftp_local_passive) { - if ((status >= 400) || (status < 0)) { - ftp_local_passive = (BOOLEAN) !ftp_passive; - status = HTFTPLoad(addr, anchor, format_out, sink); - } - } - - free(ftp_lasthost); - ftp_lasthost = ftp_newhost; -#endif /* DISABLE_FTP */ - return status; - } else { - FREE(newname); - FREE(acc_method); - } -#if defined(VMS) || defined(USE_DOS_DRIVES) - HTUnEscape(filename); -#endif /* VMS */ - - /* - * Determine the format and encoding mapped to any suffix. - */ - if (anchor->content_type && anchor->content_encoding) { - /* - * If content_type and content_encoding are BOTH already set in the - * anchor object, we believe it and don't try to derive format and - * encoding from the filename. - kw - */ - format = HTAtom_for(anchor->content_type); - myEncoding = HTAtom_for(anchor->content_encoding); - } else { - int default_UCLYhndl = UCLYhndl_HTFile_for_unspec; - - if (force_old_UCLYhndl_on_reload) { - force_old_UCLYhndl_on_reload = FALSE; - default_UCLYhndl = forced_UCLYhdnl; - } - - format = HTFileFormat(filename, &myEncoding, NULL); - - /* - * Check the format for an extended MIME charset value, and act on it - * if present. Otherwise, assume what is indicated by the last - * parameter (fallback will effectively be UCLYhndl_for_unspec, by - * default ISO-8859-1). - kw - */ - format = HTCharsetFormat(format, anchor, default_UCLYhndl); - } - -#ifdef VMS - /* - * Check to see if the 'filename' is in fact a directory. If it is create - * a new hypertext object containing a list of files and subdirectories - * contained in the directory. All of these are links to the directories - * or files listed. - */ - if (HTStat(filename, &stat_info) == -1) { - CTRACE((tfp, "HTLoadFile: Can't stat %s\n", filename)); - } else { - if (S_ISDIR(stat_info.st_mode)) { - if (HTDirAccess == HT_DIR_FORBID) { - FREE(filename); - FREE(nodename); - return HTLoadError(sink, 403, DISALLOWED_DIR_SCAN); - } - - if (HTDirAccess == HT_DIR_SELECTIVE) { - char *enable_file_name = NULL; - - HTSprintf0(&enable_file_name, "%s/%s", filename, HT_DIR_ENABLE_FILE); - if (HTStat(enable_file_name, &stat_info) == -1) { - FREE(filename); - FREE(nodename); - FREE(enable_file_name); - return HTLoadError(sink, 403, DISALLOWED_SELECTIVE_ACCESS); - } - } - - FREE(filename); - FREE(nodename); - return HTVMSBrowseDir(addr, anchor, format_out, sink); - } - } - - if (decompressAndParse(anchor, - format_out, - sink, - nodename, - filename, - myEncoding, - format, - &status)) { - FREE(nodename); - FREE(filename); - return status; - } - FREE(filename); - -#else /* not VMS: */ - - FREE(filename); - - /* - * For unix, we try to translate the name into the name of a transparently - * mounted file. - * - * Not allowed in secure (HTClientHost) situations. TBL 921019 - */ -#ifndef NO_UNIX_IO - /* Need protection here for telnet server but not httpd server. */ - - if (!HTSecure) { /* try local file system */ - char *localname = HTLocalName(addr); - struct stat dir_info; - -#ifdef HAVE_READDIR - /* - * Multiformat handling. - * - * If needed, scan directory to find a good file. Bug: We don't stat - * the file to find the length. - */ - if ((strlen(localname) > strlen(MULTI_SUFFIX)) && - (0 == strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX), - MULTI_SUFFIX))) { - DIR *dp = 0; - BOOL forget_multi = NO; - - STRUCT_DIRENT *dirbuf; - float best = (float) NO_VALUE_FOUND; /* So far best is bad */ - HTFormat best_rep = NULL; /* Set when rep found */ - HTAtom *best_enc = NULL; - char *best_name = NULL; /* Best dir entry so far */ - - char *base = strrchr(localname, '/'); - size_t baselen = 0; - - if (!base || base == localname) { - forget_multi = YES; - } else { - *base++ = '\0'; /* Just got directory name */ - baselen = strlen(base) - strlen(MULTI_SUFFIX); - base[baselen] = '\0'; /* Chop off suffix */ - - dp = opendir(localname); - } - if (forget_multi || !dp) { - FREE(localname); - FREE(nodename); - return HTLoadError(sink, 500, FAILED_DIR_SCAN); - } - - while ((dirbuf = readdir(dp)) != NULL) { - /* - * While there are directory entries to be read... - */ -#ifdef STRUCT_DIRENT__D_INO - if (dirbuf->d_ino == 0) - continue; /* if the entry is not being used, skip it */ -#endif - if (strlen(dirbuf->d_name) > baselen && /* Match? */ - !StrNCmp(dirbuf->d_name, base, baselen)) { - HTAtom *enc; - HTFormat rep = HTFileFormat(dirbuf->d_name, &enc, NULL); - float filevalue = HTFileValue(dirbuf->d_name); - float value = HTStackValue(rep, format_out, - filevalue, - 0L /* @@@@@@ */ ); - - if (value <= 0.0) { - int rootlen = 0; - const char *atomname = NULL; - CompressFileType cft = - HTCompressFileType(dirbuf->d_name, ".", &rootlen); - char *cp = NULL; - - enc = NULL; - if (cft != cftNone) { - StrAllocCopy(cp, dirbuf->d_name); - cp[rootlen] = '\0'; - format = HTFileFormat(cp, NULL, NULL); - FREE(cp); - value = HTStackValue(format, format_out, - filevalue, 0L); - switch (cft) { - case cftCompress: - atomname = "application/x-compressed"; - break; - case cftGzip: - atomname = "application/x-gzip"; - break; - case cftDeflate: - atomname = "application/x-deflate"; - break; - case cftBzip2: - atomname = "application/x-bzip2"; - break; - case cftNone: - break; - } - } - - if (atomname != NULL) { - value = HTStackValue(format, format_out, - filevalue, 0L); - if (value <= 0.0) { - format = HTAtom_for(atomname); - value = HTStackValue(format, format_out, - filevalue, 0L); - } - if (value <= 0.0) { - format = HTAtom_for("www/compressed"); - value = HTStackValue(format, format_out, - filevalue, 0L); - } - } - } - if (value < NO_VALUE_FOUND) { - CTRACE((tfp, - "HTLoadFile: value of presenting %s is %f\n", - HTAtom_name(rep), value)); - if (value > best) { - best_rep = rep; - best_enc = enc; - best = value; - StrAllocCopy(best_name, dirbuf->d_name); - } - } /* if best so far */ - } - /* if match */ - } /* end while directory entries left to read */ - closedir(dp); - - if (best_rep) { - format = best_rep; - myEncoding = best_enc; - base[-1] = '/'; /* Restore directory name */ - base[0] = '\0'; - StrAllocCat(localname, best_name); - FREE(best_name); - } else { /* If not found suitable file */ - FREE(localname); - FREE(nodename); - return HTLoadError(sink, 403, FAILED_NO_REPRESENTATION); - } - /*NOTREACHED */ - } - /* if multi suffix */ - /* - * Check to see if the 'localname' is in fact a directory. If it is - * create a new hypertext object containing a list of files and - * subdirectories contained in the directory. All of these are links - * to the directories or files listed. NB This assumes the existence - * of a type 'STRUCT_DIRENT', which will hold the directory entry, and - * a type 'DIR' which is used to point to the current directory being - * read. - */ -#if defined(USE_DOS_DRIVES) - if (strlen(localname) == 2 && LYIsDosDrive(localname)) - LYAddPathSep(&localname); -#endif - if (HTStat(localname, &dir_info) == -1) /* get file information */ - { - /* if can't read file information */ - CTRACE((tfp, "HTLoadFile: can't stat %s\n", localname)); - - } else { /* Stat was OK */ - - if (S_ISDIR(dir_info.st_mode)) { - /* - * If localname is a directory. - */ - DIR *dp; - struct stat file_info; - - CTRACE((tfp, "%s is a directory\n", localname)); - - /* - * Check directory access. Selective access means only those - * directories containing a marker file can be browsed. - */ - if (HTDirAccess == HT_DIR_FORBID) { - FREE(localname); - FREE(nodename); - return HTLoadError(sink, 403, DISALLOWED_DIR_SCAN); - } - - if (HTDirAccess == HT_DIR_SELECTIVE) { - char *enable_file_name = NULL; - - HTSprintf0(&enable_file_name, "%s/%s", localname, HT_DIR_ENABLE_FILE); - if (stat(enable_file_name, &file_info) != 0) { - FREE(localname); - FREE(nodename); - FREE(enable_file_name); - return HTLoadError(sink, 403, DISALLOWED_SELECTIVE_ACCESS); - } - } - - CTRACE((tfp, "Opening directory %s\n", localname)); - dp = opendir(localname); - if (!dp) { - FREE(localname); - FREE(nodename); - return HTLoadError(sink, 403, FAILED_DIR_UNREADABLE); - } - - /* - * Directory access is allowed and possible. - */ - - status = print_local_dir(dp, localname, - anchor, format_out, sink); - closedir(dp); - FREE(localname); - FREE(nodename); - return status; /* document loaded, maybe partial */ - - } - /* end if localname is a directory */ - if (S_ISREG(dir_info.st_mode)) { -#ifdef LONG_MAX - if (dir_info.st_size <= LONG_MAX) -#endif - anchor->content_length = (long) dir_info.st_size; - } - - } /* end if file stat worked */ - -/* End of directory reading section -*/ -#endif /* HAVE_READDIR */ - if (decompressAndParse(anchor, - format_out, - sink, - nodename, - localname, - myEncoding, - format, - &status)) { - FREE(nodename); - FREE(localname); - return status; - } - FREE(localname); - } /* local unix file system */ -#endif /* !NO_UNIX_IO */ -#endif /* VMS */ - -#ifndef DECNET - /* - * Now, as transparently mounted access has failed, we try FTP. - */ - { - /* - * Deal with case-sensitivity differences on VMS versus Unix. - */ -#ifdef VMS - if (strcasecomp(nodename, HTHostName()) != 0) -#else - if (strcmp(nodename, HTHostName()) != 0) -#endif /* VMS */ - { - status = -1; - FREE(nodename); - if (StrNCmp(addr, "file://localhost", 16)) { - /* never go to ftp site when URL - * is file://localhost - */ -#ifndef DISABLE_FTP - status = HTFTPLoad(addr, anchor, format_out, sink); -#endif /* DISABLE_FTP */ - } - return status; - } - FREE(nodename); - } -#endif /* !DECNET */ - - /* - * All attempts have failed. - */ - { - CTRACE((tfp, "Can't open `%s', errno=%d\n", addr, SOCKET_ERRNO)); - - return HTLoadError(sink, 403, FAILED_FILE_UNREADABLE); - } -} - -static const char *program_paths[pp_Last]; - -/* - * Given a program number, return its path - */ -const char *HTGetProgramPath(ProgramPaths code) -{ - const char *result = NULL; - - if (code > ppUnknown && code < pp_Last) - result = program_paths[code]; - return result; -} - -/* - * Store a program's path. The caller must allocate the string used for 'path', - * since HTInitProgramPaths() may free it. - */ -void HTSetProgramPath(ProgramPaths code, const char *path) -{ - if (code > ppUnknown && code < pp_Last) { - program_paths[code] = isEmpty(path) ? 0 : path; - } -} - -/* - * Reset the list of known program paths to the ones that are compiled-in - */ -void HTInitProgramPaths(BOOL init) -{ - ProgramPaths code; - int n; - const char *path; - const char *test; - - for (n = (int) ppUnknown + 1; n < (int) pp_Last; ++n) { - switch (code = (ProgramPaths) n) { -#ifdef BZIP2_PATH - case ppBZIP2: - path = BZIP2_PATH; - break; -#endif -#ifdef CHMOD_PATH - case ppCHMOD: - path = CHMOD_PATH; - break; -#endif -#ifdef COMPRESS_PATH - case ppCOMPRESS: - path = COMPRESS_PATH; - break; -#endif -#ifdef COPY_PATH - case ppCOPY: - path = COPY_PATH; - break; -#endif -#ifdef CSWING_PATH - case ppCSWING: - path = CSWING_PATH; - break; -#endif -#ifdef GZIP_PATH - case ppGZIP: - path = GZIP_PATH; - break; -#endif -#ifdef INFLATE_PATH - case ppINFLATE: - path = INFLATE_PATH; - break; -#endif -#ifdef INSTALL_PATH - case ppINSTALL: - path = INSTALL_PATH; - break; -#endif -#ifdef MKDIR_PATH - case ppMKDIR: - path = MKDIR_PATH; - break; -#endif -#ifdef MV_PATH - case ppMV: - path = MV_PATH; - break; -#endif -#ifdef RLOGIN_PATH - case ppRLOGIN: - path = RLOGIN_PATH; - break; -#endif -#ifdef RM_PATH - case ppRM: - path = RM_PATH; - break; -#endif -#ifdef RMDIR_PATH - case ppRMDIR: - path = RMDIR_PATH; - break; -#endif -#ifdef SETFONT_PATH - case ppSETFONT: - path = SETFONT_PATH; - break; -#endif -#ifdef TAR_PATH - case ppTAR: - path = TAR_PATH; - break; -#endif -#ifdef TELNET_PATH - case ppTELNET: - path = TELNET_PATH; - break; -#endif -#ifdef TN3270_PATH - case ppTN3270: - path = TN3270_PATH; - break; -#endif -#ifdef TOUCH_PATH - case ppTOUCH: - path = TOUCH_PATH; - break; -#endif -#ifdef UNCOMPRESS_PATH - case ppUNCOMPRESS: - path = UNCOMPRESS_PATH; - break; -#endif -#ifdef UNZIP_PATH - case ppUNZIP: - path = UNZIP_PATH; - break; -#endif -#ifdef UUDECODE_PATH - case ppUUDECODE: - path = UUDECODE_PATH; - break; -#endif -#ifdef ZCAT_PATH - case ppZCAT: - path = ZCAT_PATH; - break; -#endif -#ifdef ZIP_PATH - case ppZIP: - path = ZIP_PATH; - break; -#endif - default: - path = NULL; - break; - } - test = HTGetProgramPath(code); - if (test != NULL && test != path) { - free((char *) test); - } - if (init) { - HTSetProgramPath(code, path); - } - } -} - -/* - * Protocol descriptors - */ -#ifdef GLOBALDEF_IS_MACRO -#define _HTFILE_C_1_INIT { "ftp", HTLoadFile, 0 } -GLOBALDEF(HTProtocol, HTFTP, _HTFILE_C_1_INIT); -#define _HTFILE_C_2_INIT { "file", HTLoadFile, HTFileSaveStream } -GLOBALDEF(HTProtocol, HTFile, _HTFILE_C_2_INIT); -#else -GLOBALDEF HTProtocol HTFTP = -{"ftp", HTLoadFile, 0}; -GLOBALDEF HTProtocol HTFile = -{"file", HTLoadFile, HTFileSaveStream}; -#endif /* GLOBALDEF_IS_MACRO */ |