/*****************************************************************************/ /* Dir.c This module implements a full multi-threaded, AST-driven, asynchronous directory listing. The AST-driven nature makes the code a little more difficult to follow, but creates a powerful, event-driven, multi-threaded server. All of the necessary functions implementing this module are designed to be non-blocking. This module never returns a valid status and ALWAYS calls the supplied next task (AST) function. This should check for a generated error message to determine is there were any problems. This module uses the NetWriteBuffered() function to buffer any output it can into larger chunks before sending it to the client. A directory listing is recognised by the server whenever a wildcard is present in a specification and there is no query string directing another activity (e.g. a query/search). Compliant with other HTTPD implementations, a directory listing is also generated if a URL specifies a directory only and the directory contains no home page. The directory listing is designed to look very much like the default layout of the CERN and NCSA HTTPD implementations, with the exception that all directories are grouped at the top, not dispersed throughout the file names. This looks and functions better than the above (at least in the experience of the author). ACCESS CONTROL -------------- If the server configuration specifies "DirAccessSelective" then the directory must contain the file ".WWW_BROWSABLE" to be listed by this module. If a directory contains the file ".WWW_HIDDEN" it cannot be listed with this module, but individual files are accessable for server access. If a subdirectory contains this file it does not appear in a listing. If a directory contains the file ".WWW_NOWILD" a wildcard directory specification will not work even if allowed by server configuration. If a directory contains the file ".WWW_NOP" it does not show a parent. If a directory contains the file ".WWW_NOS" it does not show subdirectories. If a directory contains the file ".WWW_NOPS" both the above apply. LISTING LAYOUT -------------- The layout of the listing can be controlled from the configuration file or via a server directive. A decimal number may optionally, immediately precede any directive, this becomes the width of that particular field. If a width is not specified an appropriate default is used. Information wider than the field width is truncated, generally without indication. The following layout directives provide: _ (underscore) each underscore provides one space between fields C creation date D content-type description (BEST be the last field specified) D:L content-type description as a link I icon L file anchor (link, including name as link) L:F file anchor, ODS-5 file system name (e.g. spaces, not %20) L:N file anchor, name-only, do not display the file's extension L:U file anchor, force the name to upper-case (these can have multiple specifications, e.g. "__L:U:N__") N file name (without anchor, why I can't imagine :^) O file owner (only when SYSUAF-authenticated and profile accessed) P file protection (only when SYSUAF-authenticated and profile accessed) R revision date S file size S:0 file sizes in 1000 (decimal) not 1024 (binary) kilos S:2 file sizes in 1024 (binary) not 1000 (decimal) kilos S:B file size to be in comma-formatted bytes S:D express file sizes in 1000 (decimal) kilos not 1024 (binary) kilos S:F file size Mb and Kb to be expressed to one significant place S:K file size to be in K-bytes S:M file size to be in M-bytes S:V file size to be in blocks (VMS-ish) (these can have multiple specifications, e.g. "__S:2:F__") U file/directory name in upper case (MUST be the FIRST directive) These may placed in any order ("D" is best last because it does not use a field width) and with any (reasonable) field-width. For example see 'DirDefaultLayout' below. DIRECTORY DIRECTIVES -------------------- These directives may be added to a directory listing URL, or placed into the ".WWW_WASD" file, to modifiy the format and/or behaviour of the resultant listing. Multiple query string directives may be added using the normal query string ampersand syntax. This example forces an ODS-2 volumes file name to upper-case and does not display the file type (extension). ?httpd=index&upper=1¬ype=1 # .WWW_WASD upper=yes notype=yes Precedence is; .WWW_WASD file directives, then if override=yes SSI query string, then if override=yes URI query string; if no .WWW_WASD file then SSI query string and if override=yes URI query string; finally if no SSI query string then URI query string. The following are the directives: autoscript= yes (default), no, true, false, 1, 0 delimit= header, footer, both (default), none expired= yes, no, true, false, 1, 0 (listing pre-expired) font= inherit, or monospace (default) ilink= yes, no, true, false, 1, 0 (icon is a plain-text link) layout= see "listing layout" immediately above local= yes, no (default), true, false, 1, 0 (do not propagate) notype= yes, no (default), true, false, 1, 0 (do not display file type) nop= yes, no (default), true, false, 1, 0 (as if .WWW_NOP found) nops= yes, no (default), true, false, 1, 0 (as if .WWW_NOPS found) nos= yes, no (default), true, false, 1, 0 (as if .WWW_NOS found) override= yes, no (default), true, false, 1, 0 (query string may override) query= set this string as the query string for subsequent requests readme= yes, no (default), true, false, 1, 0 script= script path that will be used when a file link is clicked sort= on column (e.g. 'R','S') then '+' for ascending '-' descending style= any of the mapping SET dir=style= target= open a file in this window (e.g. "_blank") these= one or more comma-separated wildcard file name.type(s) type= force file content-type (e.g. "&type=\"text\"/plain") upper= yes, no (default), true, false, 1, 0 versions= up to many of a file or if '*' then all VMS (ODS-2) FILE NAMES ---------------------- Generally directory listings on ODS-2 volumes (VMS disks prior to VMS V7.2) are displayed lower-case. To force an upper-case listing use any of a directory listing format beginning with "U", or the "httpd=index&upper=1" query string. EXTENDED (ODS-5) FILE NAMES --------------------------- On ODS-5 volumes (available on Alpha VMS V7.2 and following) file names are displayed in mixed, on-disk case. These file names may contain characters that need to be escaped. These are displayed as what the escape sequence represents For example; '^_' as ' ' and '^.' as '.'. PATHWORKS AND SRI ENCODED FILE NAMES ------------------------------------ These will be displayed as what the encoding represents. For example; in Pathworks encoding a '$20' sequence represents a ' ' and in SRI encoding the encoding '$7A' also as ' '. SRI encodings representing mixed-case file names are displayed in mixed case. VERSION HISTORY --------------- 24-JAN-2019 MGD DirFormatAcpInfoAst() double size of AnchorLink 04-JAN-2019 MGD bugfix; AuthCompleted() 25-JAN-2018 MGD SET DIR=TITLE=[default|owner|remote||this=] ?httpd=index&title=[(as above)] 04-MAY-2017 MGD after twenty-plus years do not list "hidden" directories 22-JUN-2016 MGD DirFiles() ignore ambiguous file names containing an escaped ("^.") period but no type 02-MAY-2015 MGD tblst refinement 08-NOV-2014 MGD bugfix; and refine DirFormatSize() 16-SEP-2014 MGD default directory listing style now ed ?httpd=index&font=[inherit|monospace(D)] ?httpd=index&style=table[2] suppress WebDAV metadata subdirectory when path SET ods=name=utf8 then response charset=utf-8 SET dir=font=[inherit|monospace(D)] SET dir=style=TABLE[2] SET ods=name=8bit, ods=name=utf8, ods=name=default SET webdav=meta=dir= SET webdav=[no]hidden *always* conceals hidden file names remove from link (nested s) bugfix; DirAuthorizationAst() tabular with no delimiter bugfix; DirFormatAcpInfoAst() ThisIsADirectory = false; 27-SEP-2013 MGD ?httpd=index&versions=|* SET dir=versions=|* 18-SEP-2013 MGD refine sortable whitespace in older MSIE and font in all MSIE 10-JUL-2013 MGD .WWW_WASD directive file sortable directory listing ?httpd=index&local=[yes|no] ?httpd=index&override=[yes|no] ?httpd=index&query= ?httpd=index&style= ?httpd=index&sort=[+|-] ?httpd=index&target= ?httpd=index&these=[,] SET dir=delimit= SET dir=style= SET dir=sort=[+|-] SET dir=target= SET dir=these=[,] bugfix; DirFormatSize() bytes 01-JUN-2013 MGD bugfix; non-ODS_EXTENDED platforms (e.g. VAX) must OdsParse() NAM$M_NOCONCEAL before OdsSearchNoConceal() 30-JAN-2012 MGD DirFormatSize() now uses quadword DirFormatSize() adjusts units to fit size width 27-SEP-2011 MGD bugfix; OdsSearchNoConceal() to successfully process concealed, multi-value logical device names 28-APR-2010 MGD bugfix; DirAuthorizationAst() only check access on non-empty expanded file names 24-MAR-2010 MGD bugfix; DirBegin() "httpd=index&" detection (since v9.3.0) bugfix; DirEnd() suppress unless RequestEnd() AST 23-AUG-2009 MGD WasdCss[] and some refinements 11-JUN-2009 MGD "*.*__WASDAV;" files ignored 10-DEC-2007 MGD DirBegin() only use query string if it begins "httpd=index&" 09-APR-2007 MGD bugfix; DirFormatAcpInfoAst() 'S' (size) processing for block totals at the end of a listing 24-MAY-2006 MGD DirFormat() and DirFormatSize() allow in-line layouts to specify size with VMS format listings, as well as adding size specification of 'V' (VMS-ish, in blocks) 06-SEP-2004 MGD change from self-relative to absolute links in "Index of" anchor generation (broke usage in some SSI documents) 05-SEP-2003 MGD bugfix; according to the doco "Index of"s from SSI should not be delimited top or bottom (up to SSI to caption it!) 05-JUN-2003 MGD bugfix; DirFormatLayout() static flags (jpp@esme.fr) 11-MAR-2003 MGD set html= directory listing header and footer, there are now three directory listing styles implementing set dir=style[=default|original|anchor|htdir] 15-OCT-2002 MGD demo mode ignores .WWW_HIDDEN, etc. 05-OCT-2002 MGD refine VMS security profile usage 20-SEP-2002 MGD bale-out early if no access 14-SEP-2002 MGD implement SET dir=charset directory listing charset 09-SEP-2002 MGD for consistency return an (if configured) empty listing if protection on the directory doesn't allow wildcards 04-SEP-2002 MGD bugfix; 'Index of..' string encoding 20-AUG-2002 MGD modify formatting for SRI and PWK ODS encodings, remove 'filesys=' listing modifier - it's now all FILESYS! 10-JUL-2002 MGD 'RealPath' for absoluting the likes of SSI 'index of's 31-MAY-2002 MGD path SET directory access control 27-APR-2002 MGD make SYSPRV enabled ASTs asynchronous 07-APR-2002 MGD bugfix; ODS-5 parent directories with multiple periods 02-FEB-2002 MGD for non-textual content types the icon is now an anchor for a "text/plain" content-type access 04-AUG-2001 MGD support module WATCHing 17-JUL-2001 MGD bugfix; 'layout=U' upper-casing 21-FEB-2001 MGD include ODS-5 "hidden" files beginning '^.' 13-FEB-2001 MGD bugfix; directory specfication length (sys$check_access()) 04-DEC-2000 MGD bugfix; DirSearchFiles() call DirFiles() with FAB 04-MAR-2000 MGD use FaolToBuffer(), et.al. 27-DEC-1999 MGD support ODS-2 and ODS-5 using ODS module 18-SEP-1999 MGD bugfix; sys$parse() NAM$M_NOCONCEAL for search lists 23-MAY-1999 MGD make year 4 digits for creation and revision date 19-SEP-1998 MGD improve granularity with use of directory/file/ACP services (not as much as I would have liked, but some things are just not important enough to be worth the trouble using ASTs!) 08-AUG-1998 MGD configurable implied wildcards 19-JUL-1998 MGD bugfix; MapUrl_Map() pass 'rqptr' for conditionals to work 14-MAY-1998 MGD request-specified content-type ("httpd=index&type=") 16-MAR-1998 MGD bugfix; file bytes incorrect when 'FirstFreeByte' zero 28-FEB-1998 MGD improved icon handling efficiency 19-FEB-1998 MGD size layout allows ":B", ":D", ":F", ":K", ":M" modifiers, description layout allows ":L" to make a link out of it, description may now have an associated field width, allow for directory paths like "/dir1/dir2" 02-NOV-1997 MGD "delimit=", "nop=", "nops=", "nos=" and "readme=" directives changed file sizes back from 1000 to 1024 kilos, megas, etc. 17-AUG-1997 MGD message database, internationalized file date/times, file/directory names moved to lower-case (see 'U' above), SYSUAF-authenticated users security-profile 20-APR-1997 MGD changed file sizes from 1024 to 1000 kilos, megas, etc. 01-FEB-1997 MGD HTTPd version 4 24-APR-1996 MGD chagrin ... just realized I don't need full URLs in links 01-DEC-1995 MGD HTTPd version 3 27-SEP-1995 MGD major revision of file and directory anchor generation (far fewer MapUrl()s yielding greater efficiency); added query string capability; added automatic script capability 07-AUG-1995 MGD include VMS-style directory layout and file sizes 16-JUN-1995 MGD file contents description for non-HTML files (see config.c) 25-MAR-1995 MGD bugfix; error handling with DirReadMe() and DirFileExists() 20-DEC-1994 MGD multi-threaded daemon (it suddenly got very complex!) 20-JUN-1994 MGD single-threaded daemon */ /*****************************************************************************/ #ifdef WASD_VMS_V7 #undef _VMS__V6__SOURCE #define _VMS__V6__SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif /* standard C header files */ #include #include #include /* VMS related header files */ #include #include #include #include #include #include #include #include #include #include /* application related header file */ #include "wasd.h" #define WASD_MODULE "DIR" /**********/ /* macros */ /**********/ #define DEFAULT_FIELD_WIDTH_INTERFIELD 1 #define DEFAULT_FIELD_WIDTH_CDT 17 #define DEFAULT_FIELD_WIDTH_NAME 25 #define DEFAULT_FIELD_WIDTH_OWNER 20 #define DEFAULT_FIELD_WIDTH_PROTECTION 19 #define DEFAULT_FIELD_WIDTH_RDT 17 #define DEFAULT_FIELD_WIDTH_SIZE 6 #define DEFAULT_FIELD_WIDTH_DECIMAL 11 #define LAYOUT_PARAMETER ':' /******************/ /* global storage */ /******************/ char DirBrowsableFileName [] = ".WWW_BROWSABLE", DirDefaultLayout [] = DEFAULT_DIR_LAYOUT, DirHiddenFileName [] = ".WWW_HIDDEN", DirNoWildFileName [] = ".WWW_NOWILD", DirNopFileName [] = ".WWW_NOP", DirNosFileName [] = ".WWW_NOS", DirNopsFileName [] = ".WWW_NOPS", DirWasdFileName [] = ".WWW_WASD"; char *DirBlankIconPtr, *DirDirIconPtr, *DirParentIconPtr; static char DirColSpan [96]; static $DESCRIPTOR (DirColSpanDsc, DirColSpan); /********************/ /* external storage */ /********************/ extern BOOL CliDemo, NaturalLanguageEnglish, OdsExtended, WebDavEnabled; extern int SsiSizeMax; extern int ToLowerCase[], ToUpperCase[]; extern unsigned long SysPrvMask[]; extern char *ConfigBlankIconPtr, *ConfigDirIconPtr, *ConfigParentIconPtr; extern char ConfigContentTypeSsi[], ErrorSanityCheck[], SoftwareID[]; extern ACCOUNTING_STRUCT *AccountingPtr; extern CONFIG_STRUCT Config; extern MSG_STRUCT Msgs; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* This function never returns a valid status and ALWAYS calls the supplied next task (AST) function. This should check for a generated error message to determine is there were any problems. */ DirBegin ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction, char *DirSpec, char *DirQueryString, char *RealPath, BOOL AuthorizePath ) { int status; char *cptr, *sptr, *zptr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirBegin() !&A !&Z !&Z !&Z !&B", NextTaskFunction, DirSpec, DirQueryString, RealPath, AuthorizePath); if (ERROR_REPORTED (rqptr)) { /* previous error, cause threaded processing to unravel */ SysDclAst (NextTaskFunction, rqptr); return; } /* network writes are checked for success, fudge the first one! */ rqptr->NetIoPtr->WriteStatus = SS$_NORMAL; if (!rqptr->AccountingDone++) InstanceGblSecIncrLong (&AccountingPtr->DoDirectoryCount); if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "INDEXOF !AZ", DirSpec); if ((!Config.cfDir.Access && !Config.cfDir.AccessSelective && !rqptr->rqPathSet.DirAccess && !rqptr->rqPathSet.DirAccessSelective) || rqptr->rqPathSet.DirNoAccess) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_DISABLED), FI_LI); SysDclAst (NextTaskFunction, rqptr); return; } /* set up the task structure (possibly multiple concurrent) */ rqptr->DirTaskPtr = tkptr = VmGetHeap (rqptr, sizeof(DIR_TASK)); ListAddTail (&rqptr->DirTaskList, tkptr, LIST_ENTRY_TYPE_DIR); tkptr->NextTaskFunction = NextTaskFunction; cptr = MapVmsPath (DirSpec, rqptr); if (!cptr[0]) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, cptr+1, FI_LI); DirEnd (rqptr); return; } zptr = (sptr = tkptr->DirPath) + sizeof(tkptr->DirPath); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); DirEnd (rqptr); return; } *sptr = '\0'; /* when the path may be different from base path (e.g. SSI) */ cptr = RealPath; zptr = (sptr = tkptr->RealPath) + sizeof(tkptr->RealPath); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); DirEnd (rqptr); return; } *sptr = '\0'; while (sptr > tkptr->RealPath && *sptr != '/') sptr--; if (*sptr == '/') sptr++; *sptr = '\0'; cptr = DirSpec; zptr = (sptr = tkptr->DirSpec) + sizeof(tkptr->DirSpec); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); DirEnd (rqptr); return; } *sptr = '\0'; tkptr->DirSpecLength = sptr - tkptr->DirSpec; rqptr->rqResponse.PreExpired = Config.cfDir.PreExpired; tkptr->AsIfNopFound = tkptr->AsIfNosFound = false; tkptr->AutoScriptEnabled = tkptr->IconLinkEnabled = tkptr->IncludeAnyReadme = true; if (tkptr->RealPath[0]) tkptr->DirDelimit = MAPURL_DIR_DELIMIT_NONE; else if (rqptr->rqPathSet.DirDelimit) tkptr->DirDelimit = rqptr->rqPathSet.DirDelimit; else tkptr->DirDelimit = MAPURL_DIR_DELIMIT_BOTH; if (rqptr->rqPathSet.DirSort[0]) { tkptr->DirSort[0] = rqptr->rqPathSet.DirSort[0]; tkptr->DirSort[1] = rqptr->rqPathSet.DirSort[1]; } if (rqptr->rqPathSet.DirFont) tkptr->DirFont = rqptr->rqPathSet.DirFont; else tkptr->DirFont = MAPURL_DIR_FONT_MONOSPACE; if (rqptr->rqPathSet.DirStyle) tkptr->DirStyle = rqptr->rqPathSet.DirStyle; else tkptr->DirStyle = MAPURL_DIR_STYLE_TABLE; if (rqptr->rqPathSet.DirTitle) { tkptr->DirTitle = rqptr->rqPathSet.DirTitle; tkptr->DirTitlePtr = rqptr->rqPathSet.DirTitlePtr; } else tkptr->DirTitle = MAPURL_DIR_TITLE_DEFAULT; if (rqptr->rqPathSet.DirTargetPtr) { zptr = (sptr = tkptr->LinkTarget) + sizeof(tkptr->LinkTarget)-2; for (cptr = " target=\""; *cptr; *sptr++ = *cptr++); for (cptr = rqptr->rqPathSet.DirTargetPtr; *cptr && sptr < zptr; cptr++) if (*cptr != '\"') *sptr++ = *cptr; *sptr++ = '\"'; *sptr = '\0'; } if (rqptr->rqPathSet.DirThesePtr) { for (cptr = sptr = rqptr->rqPathSet.DirThesePtr; *sptr; sptr++); tkptr->ThesePtr = sptr = VmGetHeap (rqptr, sptr-cptr); /* null-separated series of strings terminated by empty string */ while (*cptr) { if (*cptr == ',') *sptr++ = '\0'; else *sptr++ = *cptr; cptr++; } } if (rqptr->rqPathSet.DirVersionsOf) /* negative 1 indicates to revert to zero */ if (rqptr->rqPathSet.DirVersionsOf == -1) tkptr->VersionsOf = 0; else tkptr->VersionsOf = rqptr->rqPathSet.DirVersionsOf; /************************/ /* directory directives */ /************************/ /* .WWW_WASD file */ if (VMSnok (DirWwwWasd (rqptr))) tkptr->QueryOverride = true; /* SSI query string */ if (tkptr->QueryOverride) if (cptr = DirQueryString) if (cptr && TOLO(*cptr) == 'h' && strsame (cptr, "httpd=index&", 12)) DirDirectString (rqptr, cptr+12); /* URI query string */ if (tkptr->QueryOverride) if (cptr = tkptr->QueryStringPtr) if (cptr && TOLO(*cptr) == 'h' && strsame (cptr, "httpd=index&", 12)) DirDirectString (rqptr, cptr+12); /* map any default into the current default */ if (tkptr->DirStyle == MAPURL_DIR_STYLE_DEFAULT) tkptr->DirStyle = MAPURL_DIR_STYLE_TABLE; else if (tkptr->DirStyle == MAPURL_DIR_STYLE_DEFAULT2) tkptr->DirStyle = MAPURL_DIR_STYLE_TABLE2; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) tkptr->DirStyleTabular = true; else tkptr->DirStyleTabular = false; if (AuthorizePath) { /***********************/ /* check authorization */ /***********************/ cptr = MapVmsPath (tkptr->DirSpec, rqptr); Authorize (rqptr, cptr, -1, NULL, 0, &DirAuthorizationAst); if (VMSnok (rqptr->rqAuth.FinalStatus)) { /* if asynchronous authentication is notunderway */ if (rqptr->rqAuth.FinalStatus != AUTH_PENDING) DirEnd (rqptr); return; } } /* not to-be-authorized, or authorized ... just carry on regardless! */ DirAuthorizationAst (rqptr); } /*****************************************************************************/ /* This function provides an AST target is Authorize()ation ended up being done asynchronously, otherwise it is just called directly to continue the modules processing. */ DirAuthorizationAst (REQUEST_STRUCT *rqptr) { static char StyleBasicList [] = "\n"; /* four strings in this array, [0]&[3] fixed, [1]&[2] selected between */ static char *JavaScriptList [] = { "\n\ \n" }; /* four strings in this array, [0]&[3] fixed, [1]&[2] selected between */ static char *StyleTableList [] = { "\n" }; static $DESCRIPTOR (OwnerFaoDsc, "!%I\0"); int status; unsigned short slen; unsigned long FaoVector [32]; unsigned long *vecptr; char Owner [64], Scratch [ODS_MAX_FILE_NAME_LENGTH+1]; char *cptr, *sptr, *IndexOfPtr; $DESCRIPTOR (OwnerDsc, Owner); DIR_TASK *tkptr; REQUEST_AST AstFunction; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirAuthorizationAst() !&F !&S", &DirAuthorizationAst, rqptr->rqAuth.FinalStatus); /* may have been delivered asynchronously */ rqptr->rqAuth.AstFunction = NULL; if (VMSnok (rqptr->rqAuth.FinalStatus)) { DirEnd (rqptr); return; } tkptr = rqptr->DirTaskPtr; /***************************/ /* parse to get components */ /***************************/ OdsStructInit (&tkptr->SearchOds, false); if (tkptr->SearchOds.ExpFileNameLength) AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tkptr->SearchOds, tkptr->DirSpec, tkptr->DirSpecLength, NULL, 0, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->DirSpec; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } memcpy (tkptr->DirectoryPart, tkptr->SearchOds.NamDevicePtr, slen = tkptr->SearchOds.NamNamePtr - tkptr->SearchOds.NamDevicePtr); tkptr->DirectoryPart[slen] = '\0'; Scratch[0] = '\0'; sptr = MapUrl_Map (Scratch, sizeof(Scratch), tkptr->DirectoryPart, 0, NULL, 0, NULL, 0, NULL, 0, NULL, rqptr, NULL); if (!sptr[0] && sptr[1]) { /* mapping report */ rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, sptr+1, FI_LI); DirEnd (rqptr); return; } slen = strlen(Scratch) + 1; tkptr->DirectoryPathPtr = VmGetHeap (rqptr, slen); memcpy (tkptr->DirectoryPathPtr, Scratch, slen); if (tkptr->SearchOds.Nam_fnb & NAM$M_WILD_DIR) { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_NO_WILDCARD), FI_LI); DirEnd (rqptr); return; } /************************/ /* directory access ok? */ /************************/ if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSok (status = OdsFileExists (tkptr->DirectoryPart, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) { status = OdsFileExists (tkptr->DirectoryPart, DirBrowsableFileName); if (status == RMS$_FNF) status = SS$_ABORT; } else if (VMSok (status = OdsFileExists (tkptr->DirectoryPart, DirNoWildFileName))) { if (tkptr->SearchOds.Nam_fnb & NAM$M_WILD_NAME || tkptr->SearchOds.Nam_fnb & NAM$M_WILD_TYPE || tkptr->SearchOds.Nam_fnb & NAM$M_WILD_VER) status = SS$_ABORT; else status = SS$_NORMAL; } else status = SS$_NORMAL; sys$setprv (0, &SysPrvMask, 0, 0); } if (VMSnok (status)) { if (status == SS$_ABORT) { /* abort here means the facility is disabled */ rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_DISABLED), FI_LI); } else { /* give some "disinformation" ;^) */ if (status == RMS$_FNF) status = RMS$_DNF; rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->DirSpec; ErrorVmsStatus (rqptr, status, FI_LI); } DirEnd (rqptr); return; } /*********************************/ /* further process specification */ /*********************************/ tkptr->DirSpecIncludedFilePart = tkptr->SearchOds.NamNameLength > 0 || tkptr->SearchOds.NamTypeLength > 1 || tkptr->SearchOds.NamVersionLength > 1; if (!tkptr->DirSpecIncludedFilePart) { /* no name or type was supplied with the request, wildcard it */ AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tkptr->SearchOds, tkptr->DirSpec, tkptr->DirSpecLength, "*.*", 3, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->DirSpec; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } } if (tkptr->SearchOds.Nam_fnb & NAM$M_WILD_VER || tkptr->SearchOds.Nam_fnb & NAM$M_EXP_VER) { /* wildcard or explicit version number supplied ... VMS format */ memcpy (tkptr->FilePart, tkptr->SearchOds.NamNamePtr, slen = tkptr->SearchOds.NamVersionPtr - tkptr->SearchOds.NamNamePtr + tkptr->SearchOds.NamVersionLength); tkptr->FormatLikeVms = true; } else { /* name and/or type or implied wildcards */ memcpy (tkptr->FilePart, tkptr->SearchOds.NamNamePtr, slen = tkptr->SearchOds.NamVersionPtr - tkptr->SearchOds.NamNamePtr); } if (tkptr->VersionsOf) { /* ?httpd=index&versions= */ if (!(tkptr->SearchOds.Nam_fnb & NAM$M_WILD_VER || tkptr->SearchOds.Nam_fnb & NAM$M_EXP_VER)) tkptr->FilePart[slen++] = ';'; if (!(tkptr->SearchOds.Nam_fnb & NAM$M_WILD_VER)) tkptr->FilePart[slen++] = '*'; } tkptr->FilePart[slen] = '\0'; /********************/ /* begin processing */ /********************/ tkptr->FileCount = tkptr->DirectoryCount = 0; if (VMSnok (DirFormatLayout (rqptr))) { DirEnd (rqptr); return; } if (tkptr->ResponseHeaderSent = !rqptr->rqResponse.HeaderSent) { /* if directory listing charset has been set impose that on any other */ cptr = rqptr->rqPathSet.CharsetPtr; if (rqptr->rqPathSet.DirCharsetPtr) rqptr->rqPathSet.CharsetPtr = rqptr->rqPathSet.DirCharsetPtr; else if (rqptr->rqPathSet.OdsName == MAPURL_ODS_UTF8) rqptr->rqPathSet.CharsetPtr = "utf-8"; /* "index of"s can have pre-expiry controlled from the query string */ ResponseHeader200 (rqptr, "text/html", NULL); /* restore any previous (just to be neat) */ rqptr->rqPathSet.CharsetPtr = cptr; if (rqptr->rqHeader.Method == HTTP_METHOD_HEAD) { DirEnd (rqptr); return; } } if (Config.cfDir.ReadMeTop && tkptr->IncludeAnyReadme) AstFunction = &DirReadMeTop; else AstFunction = &DirHeading; if (tkptr->DirDelimit == MAPURL_DIR_DELIMIT_BOTH || tkptr->DirDelimit == MAPURL_DIR_DELIMIT_HEADER) { /******************/ /* header delimit */ /******************/ vecptr = &FaoVector; *vecptr++ = WASD_DOCTYPE; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2) { *vecptr++ = StyleTableList[0]; if (tkptr->DirFont == MAPURL_DIR_FONT_INHERIT) *vecptr++ = StyleTableList[1]; else *vecptr++ = StyleTableList[2]; *vecptr++ = StyleTableList[3]; } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { *vecptr++ = JavaScriptList[0]; if (tkptr->DirFont == MAPURL_DIR_FONT_INHERIT) *vecptr++ = JavaScriptList[1]; else *vecptr++ = JavaScriptList[2]; *vecptr++ = JavaScriptList[3]; } else { *vecptr++ = StyleBasicList; *vecptr++ = ""; *vecptr++ = ""; } if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; if (Config.cfDir.MetaInfoEnabled) { *vecptr++ = "!AZ\n"; *vecptr++ = HtmlMetaInfo (rqptr, tkptr->DirSpec); *vecptr++ = tkptr->SizeKilo; } else *vecptr++ = ""; IndexOfPtr = MsgFor(rqptr,MSG_DIR_INDEX_OF); /* ... */ if (tkptr->DirTitle && tkptr->DirTitle != MAPURL_DIR_TITLE_DEFAULT) { if (tkptr->DirTitle == MAPURL_DIR_TITLE_NONE) *vecptr++ = " "; else if (tkptr->DirTitle == MAPURL_DIR_TITLE_OWNER) { OdsFileAcpInfo (&tkptr->SearchOds, NULL, 0); sys$fao (&OwnerFaoDsc, &slen, &OwnerDsc, tkptr->SearchOds.FileQio.AtrUic); *vecptr++ = "!&;AZ"; *vecptr++ = Owner; } else if (tkptr->DirTitle == MAPURL_DIR_TITLE_REMOTE) { *vecptr++ = "!&;AZ"; if (rqptr->rqAuth.SourceRealm == AUTH_SOURCE_X509) if (cptr = SesolaClientCertRemoteUser (rqptr)) *vecptr++ = cptr; else *vecptr++ = ""; else *vecptr++ = rqptr->RemoteUser; } else if (tkptr->DirTitle == MAPURL_DIR_TITLE_THIS) { *vecptr++ = "!AZ"; *vecptr++ = tkptr->DirTitlePtr; } else if (tkptr->DirTitle >= 1) { *vecptr++ = "!&;AZ"; *vecptr++ = DirTitleInteger (rqptr); } else *vecptr++ = "SS$_BUGCHECK"; } else if (tkptr->FormatLikeVms) { MapOdsUrlToVms (tkptr->DirPath, Scratch, sizeof(Scratch), 0, rqptr->rqPathSet.MapEllipsis, rqptr->PathOds); *vecptr++ = "!AZ !&;AZ"; *vecptr++ = IndexOfPtr; *vecptr++ = Scratch; } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2) { *vecptr++ = "//!AZ!&;&[AZ"; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->DirPath; } else { *vecptr++ = "!AZ //!AZ!&;&[AZ"; *vecptr++ = IndexOfPtr; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->DirPath; } if (rqptr->rqPathSet.HtmlBodyTagPtr) { /* */ if (rqptr->rqPathSet.HtmlBodyTagPtr[0] == '<') *vecptr++ = "!AZ\n
\n"; else *vecptr++ = "\n
\n"; *vecptr++ = rqptr->rqPathSet.HtmlBodyTagPtr; } else { *vecptr++ = "!AZ\n
\n"; *vecptr++ = Config.cfDir.BodyTag; } if (rqptr->rqPathSet.HtmlHeaderPtr || rqptr->rqPathSet.HtmlHeaderTagPtr) { if (rqptr->rqPathSet.HtmlHeaderTagPtr && rqptr->rqPathSet.HtmlHeaderTagPtr[0] == '<') *vecptr++ = "!AZ\n!&/AZ"; else *vecptr++ = "
\ \n!&/AZ"; *vecptr++ = rqptr->rqPathSet.HtmlHeaderTagPtr; *vecptr++ = rqptr->rqPathSet.HtmlHeaderPtr; } else *vecptr++ = ""; status = FaolToNet (rqptr, "!AZ\ \n\ \n\ !AZ!AZ!AZ\ !&@\ !&@\ !&@\n\ \n\ !&@\ !&@", &FaoVector); if (VMSok (status)) status = DirIndexOf (rqptr, IndexOfPtr, tkptr->FormatLikeVms ? Scratch : NULL); } else { /*********************/ /* no header delimit */ /*********************/ vecptr = &FaoVector; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2) { *vecptr++ = StyleTableList[0]; if (tkptr->DirFont == MAPURL_DIR_FONT_INHERIT) *vecptr++ = StyleTableList[1]; else *vecptr++ = StyleTableList[2]; *vecptr++ = StyleTableList[3]; } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { *vecptr++ = JavaScriptList[0]; if (tkptr->DirFont == MAPURL_DIR_FONT_INHERIT) *vecptr++ = JavaScriptList[1]; else *vecptr++ = JavaScriptList[2]; *vecptr++ = JavaScriptList[3]; } else { *vecptr++ = StyleBasicList; *vecptr++ = ""; *vecptr++ = ""; } if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; status = FaolToNet (rqptr, "!AZ!AZ!AZ!&@", &FaoVector); } if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } if ((tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) && VMSok(status)) { char NoScript [] = "\n"; NetWriteBuffered (rqptr, NULL, NoScript, sizeof(NoScript)-1); } NetWriteFullFlush (rqptr, AstFunction); } /*****************************************************************************/ /* Provide the "Index of" page heading in any of the post-v8.2, traditional WASD, or the "ABI" styles. */ int DirIndexOf ( REQUEST_STRUCT *rqptr, char *IndexOfPtr, char *UrlAsVms ) { int cnt, status, SlashCount; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *FinalSlashPtr, *ThisSlashPtr; char Scratch [ODS_MAX_FILE_NAME_LENGTH+1]; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirIndexOf() !&Z !&Z", IndexOfPtr, UrlAsVms); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; if (tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) { /**************************/ /* traditional WASD style */ /**************************/ vecptr = &FaoVector; *vecptr++ = IndexOfPtr; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->DirPath; status = FaolToNet (rqptr, "

!AZ  !&;&_&[AZ

\n", &FaoVector); return (status); } /****************/ /* other styles */ /****************/ /* convert the path into a displayable path (might be ODS-5, etc.) */ vecptr = &FaoVector; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->DirPath; status = FaolToBuffer (Scratch, sizeof(Scratch), NULL, "!&;&_&[AZ", &FaoVector); if (VMSnok (status)) return (status); /* calculate the number of directory elements */ SlashCount = 0; FinalSlashPtr = ""; for (cptr = Scratch; *cptr; cptr++) { if (*cptr == '/') { SlashCount++; FinalSlashPtr = cptr; } } if (SlashCount > 64) return (SS$_BUGCHECK); if (*FinalSlashPtr) FinalSlashPtr++; vecptr = &FaoVector; if (UrlAsVms) { /* VMS format listing (no ABI rendering) */ *vecptr++ = IndexOfPtr; status = FaolToNet (rqptr, "

!AZ  ", &FaoVector); if (VMSnok (status)) return (status); cptr = UrlAsVms; } else { if (tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2) { /* ABI's style begins with the server name as a 'root' anchor */ *vecptr++ = FinalSlashPtr; if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; status = FaolToNet (rqptr, "

//!AZ/", &FaoVector); } else { /* WASD style provides an "Index of" heading */ *vecptr++ = IndexOfPtr; *vecptr++ = FinalSlashPtr; if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; status = FaolToNet (rqptr, "

!AZ  //!AZ/", &FaoVector); } if (VMSnok (status)) return (status); cptr = Scratch; } /* provide an individual anchor for each directory element */ ThisSlashPtr = tkptr->DirPath; if (*ThisSlashPtr == '/') ThisSlashPtr++; if (SlashCount) SlashCount--; while (SlashCount-- > 0) { while (*ThisSlashPtr && *ThisSlashPtr != '/') ThisSlashPtr++; if (*ThisSlashPtr == '/') ThisSlashPtr++; vecptr = &FaoVector; *vecptr++ = ThisSlashPtr - tkptr->DirPath; *vecptr++ = tkptr->DirPath; *vecptr++ = FinalSlashPtr; if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; if (UrlAsVms) { /* VMS format, parse based on VMS directory delimiting characters */ while (*cptr == '.' || *cptr == ':' || *cptr == '[' || *cptr == ']') cptr++; for (sptr = cptr; *sptr && *sptr != '.' && *sptr != ':' && *sptr != ']'; sptr++) if (*sptr == '^') sptr++; *vecptr++ = sptr - cptr; *vecptr++ = cptr; if (*sptr == ':') *vecptr++ = 2; else *vecptr++ = 1; *vecptr++ = sptr; } else { /* URL format, parse based on delimiting slashes */ if (*cptr == '/') cptr++; for (sptr = cptr; *sptr && *sptr != '/'; sptr++); if (tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2) { /* ABI's style, trailing slashes are part of the link */ if (*sptr) sptr++; *vecptr++ = sptr - cptr; *vecptr++ = cptr; *vecptr++ = 0; *vecptr++ = ""; } else { /* WASD style, trailing slashes are not part of the link */ *vecptr++ = sptr - cptr; *vecptr++ = cptr; *vecptr++ = 1; *vecptr++ = sptr; } } if (VMSnok (status)) return (status); status = FaolToNet (rqptr, "!#AZ!#AZ", &FaoVector); cptr = sptr; } if (!UrlAsVms && (tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2)) { /* ABI's style, 'file' name and type element as an anchor */ if (*cptr == '/') cptr++; vecptr = &FaoVector; *vecptr++ = cptr; if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; *vecptr++ = cptr; status = FaolToNet (rqptr, "!AZ

\n", &FaoVector); } else { /* WASD style, URL or VMS format, 'file' name and type just displayed */ if (UrlAsVms) while (*cptr == ':' || *cptr == '[' || *cptr == '.' || *cptr == ']') cptr++; else if (*cptr == '/') cptr++; vecptr = &FaoVector; *vecptr++ = cptr; status = FaolToNet (rqptr, "!AZ

\n", &FaoVector); } return (status); } /*****************************************************************************/ /* (0 is no title) 1 the top-level directory (device?) 2 the second-level directory ... and so on until the bottom-level directory 99 bottom-level directory. */ char* DirTitleInteger (REQUEST_STRUCT *rqptr) { static char buffer [256]; int number; char *cptr, *sptr, *zptr; char Scratch [ODS_MAX_FILE_NAME_LENGTH+1]; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirTitleInteger()"); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; buffer[0] = '\0'; number = tkptr->DirTitle; if (tkptr->FormatLikeVms) { MapOdsUrlToVms (tkptr->DirPath, Scratch, sizeof(Scratch), 0, rqptr->rqPathSet.MapEllipsis, rqptr->PathOds); if (number == 1) cptr = Scratch; else if (number >= 2) { for (cptr = Scratch; *cptr && *cptr != ':'; cptr++); if (SAME2(cptr,':[')) cptr += 2; else cptr = "?"; for (number -= 2; number > 0; number--) { for (sptr = cptr; *sptr != '.' && *sptr != ']'; sptr++) if (*sptr == '^' && *(sptr+1)) sptr++; if (*sptr == '.') cptr = sptr + 1; else if (*sptr == ']') break; } } zptr = (sptr = buffer) + sizeof(buffer)-1; while (*cptr && *cptr != ':' && *cptr != '.' && *cptr != ']' && sptr < zptr) { if (*cptr == '^') { *sptr++ = *cptr++; if (sptr < zptr) *sptr++ = *cptr++; } else *sptr++ = *cptr++; } *sptr = '\0'; if (sptr >= zptr) { strcpy (buffer, "?"); ErrorNoticed (rqptr, SS$_RESULTOVF, NULL, FI_LI); } } else { cptr = tkptr->DirPath; if (*cptr == '/' && *(cptr+1)) cptr++; while (--number) { for (sptr = cptr; *sptr && *sptr != '/'; sptr++); if (*sptr == '/' && *(sptr+1)) { for (zptr = sptr+1; *zptr && *zptr != '/'; zptr++); if (*zptr == '/') cptr = sptr + 1; } else break; } zptr = (sptr = buffer) + sizeof(buffer)-1; while (*cptr && *cptr != '/' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; if (sptr >= zptr) { strcpy (buffer, "?"); ErrorNoticed (rqptr, SS$_RESULTOVF, NULL, FI_LI); } } return (buffer); } /*****************************************************************************/ /* Release any dynamic memory allocated for parse structures. */ DirEnd (REQUEST_STRUCT *rqptr) { int status; unsigned long FaoVector [16]; unsigned long *vecptr; DIR_TASK *tkptr; REQUEST_AST NextTaskFunction; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirEnd() !&F", &DirEnd); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; NextTaskFunction = tkptr->NextTaskFunction; /* ensure parse internal data structures are released */ OdsParseRelease (&tkptr->SearchOds); if (!ERROR_REPORTED (rqptr)) { vecptr = &FaoVector; if (rqptr->rqPathSet.HtmlFooterPtr || rqptr->rqPathSet.HtmlFooterTagPtr) { if (rqptr->rqPathSet.HtmlFooterTagPtr && rqptr->rqPathSet.HtmlFooterTagPtr[0] == '<') *vecptr++ = "!AZ\n!&@"; else *vecptr++ = "

\ \n!&@"; *vecptr++ = rqptr->rqPathSet.HtmlFooterTagPtr; *vecptr++ = "!&/AZ
\n"; *vecptr++ = rqptr->rqPathSet.HtmlFooterPtr; } else *vecptr++ = ""; if (NextTaskFunction == RequestEnd) { status = FaolToNet (rqptr, "!&@\n\n\n", &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } } } /* restore previous directory task (if any) */ rqptr->DirTaskPtr = LIST_GET_PREV (tkptr); ListRemove (&rqptr->DirTaskList, tkptr); VmFreeFromHeap (rqptr, tkptr, FI_LI); /* explicitly flushed in case it's an SSI activity */ NetWriteFullFlush (rqptr, NextTaskFunction); } /*****************************************************************************/ /* AST-driven output of column headings (these have already generated by DirFormatLayout()). */ DirHeading (REQUEST_STRUCT *rqptr) { int status; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirHeading() !&F", DirHeading); RequestDclAst (rqptr, DirHeading, NULL); /* error in readme file? */ if (ERROR_REPORTED (rqptr)) { DirEnd (rqptr); return; } /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; if (rqptr->rqPathSet.HtmlHeaderPtr || rqptr->rqPathSet.HtmlHeaderTagPtr) { status = FaolToNet (rqptr, "\n", NULL); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->LayoutFaoPtr; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } } if (tkptr->DirDelimit == MAPURL_DIR_DELIMIT_BOTH || tkptr->DirDelimit == MAPURL_DIR_DELIMIT_HEADER || tkptr->DirStyleTabular) { /* header and horizontal line at top of page */ NetWriteBuffered (rqptr, &DirBeginDirectories, tkptr->LayoutHeadingPtr, tkptr->LayoutHeadingLength); return; } else if (!tkptr->DirStyleTabular) { /* just start the preformtted text */ NetWriteBuffered (rqptr, &DirBeginDirectories, "\n", 1); } else SysDclAst (&DirBeginDirectories, rqptr); } /*****************************************************************************/ /* Begin a listing with directories if not expressly forbidden by configuration or local directory-specific configuration files. If required check if there is an accessable parent directory and if so generate a formatted entry for it. */ DirBeginDirectories (REQUEST_STRUCT *rqptr) { int status; char *cptr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirBeginDirectories() !&F", &DirBeginDirectories); tkptr = rqptr->DirTaskPtr; /* Determine if any parent directory or subdirectories will be displayed by checking for the presence of directory listing control files (and a kludge for user directory mapping). */ /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); cptr = tkptr->DirectoryPart; if (tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) tkptr->ListParentDir = true; else tkptr->ListParentDir = false; tkptr->ListSubDir = true; if (tkptr->AsIfNopFound && tkptr->AsIfNosFound) tkptr->ListParentDir = tkptr->ListSubDir = false; else if (OdsFileExists (cptr, DirNopsFileName) != RMS$_FNF) tkptr->ListParentDir = tkptr->ListSubDir = false; else { if (tkptr->AsIfNosFound) tkptr->ListSubDir = false; else if (OdsFileExists (cptr, DirNosFileName) != RMS$_FNF) tkptr->ListSubDir = false; if (tkptr->AsIfNopFound) tkptr->ListParentDir = false; else if (OdsFileExists (cptr, DirNopFileName) != RMS$_FNF) tkptr->ListParentDir = false; else if (SAME2(tkptr->DirPath,'/~')) { /* This is a kludge to better support user directories ("/~username/"). It prevents a "top-level" user directory from displaying a parent directory even if it is not a "top-level" VMS directory. It does this by looking to see if there is any subdirectory to the "top- level" user directory (e.g. "/~username/subdirectory/"). */ for (cptr = tkptr->DirPath; *cptr && *cptr != '/'; cptr++); if (SAME2(cptr,'/\0')) tkptr->ListParentDir = false; } } sys$setprv (0, &SysPrvMask, 0, 0); if (tkptr->ListSubDir) { AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); /* OdsParse() NAM$M_NOCONCEAL before OdsSearchNoConceal() */ OdsParse (&tkptr->SearchOds, tkptr->DirectoryPart, 0, "*.DIR;", 6, NAM$M_NOCONCEAL, &DirBeginDirectoriesParseAst, rqptr); AuthAccessEnable (rqptr, 0, 0); return; } DirBeginDirectoriesParseAst (rqptr); } /*****************************************************************************/ /* AST called from DirDirectoriesBegin() when the asynchronous parse completes, or when called explicitly if not listing subdirectories. */ DirBeginDirectoriesParseAst (REQUEST_STRUCT *rqptr) { int status; char *cptr, *sptr; char ParentDirPath [ODS_MAX_FILE_NAME_LENGTH+1], ParentDirVms [ODS_MAX_FILE_NAME_LENGTH+1]; DIR_TASK *tkptr; REQUEST_AST AstFunction; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirBeginDirectoriesParseAst() !&F sts:!&S stv:!&S", &DirBeginDirectoriesParseAst, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_stv); tkptr = rqptr->DirTaskPtr; if (tkptr->ListSubDir) { /* check the status from the actual sys$parse() */ if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->DirSpec; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } AstFunction = &DirSearchDirectories; } else AstFunction = &DirBeginFiles; if (tkptr->ListParentDir && SAME2(tkptr->DirPath,'/~')) { /* no parent directories for top-level user directories */ for (cptr = tkptr->DirPath + 2; *cptr && *cptr != '/'; cptr++); if (*cptr) cptr++; while (*cptr && *cptr != '/') cptr++; if (!*cptr) tkptr->ListParentDir = false; } if (tkptr->ListParentDir) { cptr = tkptr->DirectoryPart; sptr = ParentDirVms; while (*cptr && *cptr != '[') *sptr++ = *cptr++; if (MATCH8 (cptr, "[000000]")) { /* in Master-File-Directory, therefore no parent */ tkptr->ListParentDir = false; } else { /* Not in a Master-File-Directory, create a parent directory (e.g. "DEVICE:[DIR1.DIR2]" from "DEVICE:[DIR1.DIR2.DIR3]", and "DEVICE:[000000]" from "DEVICE:[DIR1]", etc.) */ if (MATCH8 (cptr, "[000000.")) { /* skip over the Master-File-Directory in the specification */ *sptr++ = *cptr++; cptr += 7; } while (*cptr) *sptr++ = *cptr++; *sptr = '\0'; while (*sptr != ']') sptr--; while (*sptr != '[') { while (*sptr != '.' && *sptr != '[') sptr--; if (*sptr == '[' || *(sptr-1) != '^') break; sptr--; } if (*sptr == '.') { *sptr++ = ']'; *sptr = '\0'; } else memcpy (sptr, "[000000]", 9); /* If access is allowed display the details. Otherwise, its as if the directory just didn't exist! */ /* if the VMS profile allows access, why further prohibit it? */ if (!CliDemo && !rqptr->rqAuth.SkelKeyAuthenticated && !rqptr->rqAuth.VmsUserProfileLength) { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (OdsFileExists (ParentDirVms, DirHiddenFileName) != RMS$_FNF) tkptr->ListParentDir = false; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) { if (VMSnok (OdsFileExists (ParentDirVms, DirBrowsableFileName))) tkptr->ListParentDir = false; } sys$setprv (0, &SysPrvMask, 0, 0); } } if (tkptr->ListParentDir) { ParentDirPath[0] = '\0'; sptr = MapUrl_Map (ParentDirPath, sizeof(ParentDirPath), ParentDirVms, 0, NULL, 0, NULL, 0, NULL, 0, NULL, rqptr, NULL); if (sptr[0]) { DirFormat (rqptr, AstFunction, ParentDirPath, false); return; } /* Mapping error, most probably access forbidden, we'll assume that. This can happen where a subdirectory is mapable but the parent is not (e.g. "pass /parent/subd/* /device/parent/subd/*"), making it forbidden to request "/parent/file" or "/parent/*.*". Hence, for directory listings, it's as if parent does not exist! */ tkptr->ListParentDir = false; } } if (!tkptr->ListParentDir) { /* parent directory was not output, explicitly drive the search */ SysDclAst (AstFunction, rqptr); } } /*****************************************************************************/ /* AST function to invoke another sys$search() call when listing directories. */ DirSearchDirectories (REQUEST_STRUCT *rqptr) { DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirSearchDirectories() !&F !&S", &DirSearchDirectories, rqptr->NetIoPtr->WriteStatus); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DirEnd (rqptr); return; } if (VMSnok (rqptr->NetIoPtr->WriteStatus)) { /* network write has failed (as AST), bail out now */ DirEnd (rqptr); return; } tkptr = rqptr->DirTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsSearchNoConceal (&tkptr->SearchOds, &DirDirectories, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another file name found or have "no more files found" status (or an error!). If a file (directory) has been found check if its a "hidden" directory and if not format its details for the listing. */ DirDirectories (REQUEST_STRUCT *rqptr) { int status; char LocalDirectory [ODS_MAX_FILE_NAME_LENGTH+1]; char *cptr, *sptr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirDirectories() !&F sts:!&S stv:!&S", &DirDirectories, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DirEnd (rqptr); return; } tkptr = rqptr->DirTaskPtr; if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { /* if its a search list treat directory not found as if file not found */ if ((tkptr->SearchOds.Nam_fnb & NAM$M_SEARCH_LIST) && status == RMS$_DNF) status = RMS$_FNF; if (status == RMS$_FNF || status == RMS$_NMF) { /***************************/ /* end of directory search */ /***************************/ tkptr->SearchOds.ParseInUse = false; DirBeginFiles (rqptr); return; } /*************************/ /* protection violation? */ /*************************/ if ((status == SS$_NOPRIV || status == RMS$_PRV) && Config.cfDir.NoPrivIgnore) { tkptr->SearchOds.ParseInUse = false; if (tkptr->FormatLikeVms) { DirFormat (rqptr, &DirEndOutput, "", true); return; } else { DirEndOutput (rqptr); return; } } /**********************/ /* sys$search() error */ /**********************/ rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } /* check if the .DIR is really a directory */ status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSnok (status)) { DirSearchDirectories (rqptr); return; } /* terminate following the last character in the version number */ tkptr->SearchOds.NamVersionPtr[tkptr->SearchOds.NamVersionLength] = '\0'; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "!&Z", tkptr->SearchOds.NamDevicePtr); /***********************************/ /* WebDAV metadata (sub)directory? */ /***********************************/ if (WebDavEnabled) { if (rqptr->rqPathSet.WebDavRead || rqptr->rqPathSet.WebDavWrite || rqptr->rqPathSet.WebDavProfile || rqptr->rqPathSet.WebDavServer) { if (DavMetaDir (rqptr, &tkptr->SearchOds)) { DirSearchDirectories (rqptr); return; } } } /*********************/ /* hidden directory? */ /*********************/ /* Unix-style "hidden" directories do not appear (those beginning ".") */ if (SAME1(tkptr->SearchOds.NamNamePtr,'.') || SAME2(tkptr->SearchOds.NamNamePtr,'^.')) { /* except in demo mode or to VMS authenticated and profiled requests */ if (rqptr->rqPathSet.WebDavNoHidden || !(CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength)) { if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, ".DIRECTORY (hidden)"); DirSearchDirectories (rqptr); return; } } /************************/ /* directory access ok? */ /************************/ /* Create a directory specification from a directory file name. (e.g. "DEVICE:[DIR1.DIR2]" from "DEVICE:[DIR1]DIR2.DIR") */ sptr = LocalDirectory; cptr = tkptr->SearchOds.NamDevicePtr; tkptr->SearchOds.NamTypePtr[0] = '\0'; while (*cptr) *sptr++ = *cptr++; tkptr->SearchOds.NamTypePtr[0] = '.'; *sptr++ = ']'; *sptr = '\0'; sptr -= 2; while (*sptr != ']') sptr--; *sptr = '.'; /* If access is allowed display the details. Otherwise, its as if the directory just didn't exist! Access may also be denied if file protections prevent checking! */ if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else if (VMSok (status = OdsFileExists (LocalDirectory, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) status = OdsFileExists (LocalDirectory, DirBrowsableFileName); else status = SS$_NORMAL; if (VMSnok (status)) { /* directory shouldn't/couldn't be accessed */ DirSearchDirectories (rqptr); return; } tkptr->Description[0] = '\0'; ConfigContentType (&tkptr->ContentInfo, tkptr->SearchOds.NamTypePtr); DirFormat (rqptr, &DirSearchDirectories, "", false); } /*****************************************************************************/ /* Initiate the listing of non-directory files. */ DirBeginFiles (REQUEST_STRUCT *rqptr) { DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirBeginFiles() !&F", &DirBeginFiles); tkptr = rqptr->DirTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); /* OdsParse() NAM$M_NOCONCEAL before OdsSearchNoConceal() */ OdsParse (&tkptr->SearchOds, tkptr->FilePart, 0, tkptr->DirectoryPart, 0, NAM$M_NOCONCEAL, &DirBeginFilesParseAst, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* Asynchronous parse from DirBeginFiles() has completed. */ DirBeginFilesParseAst (REQUEST_STRUCT *rqptr) { int status; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirBeginFilesParseAst() !&F sts:!&S stv:!&S", &DirBeginFilesParseAst, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_stv); tkptr = rqptr->DirTaskPtr; /* check the status from the actual sys$parse() */ if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->DirSpec; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } if (WebDavEnabled) { /* WebDAV metadata (sub)directory? */ if (rqptr->rqPathSet.WebDavRead || rqptr->rqPathSet.WebDavWrite || rqptr->rqPathSet.WebDavProfile || rqptr->rqPathSet.WebDavServer) { if (DavMetaDir (rqptr, &tkptr->SearchOds)) { DirEnd (rqptr); return; } } } /* fudge this status for the first call */ rqptr->NetIoPtr->WriteStatus = SS$_NORMAL; DirSearchFiles (rqptr); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another file found or have "no more files found" status (or an error!). */ DirSearchFiles (REQUEST_STRUCT *rqptr) { int status; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirSearchFiles() !&F !&S", &DirSearchFiles, rqptr->NetIoPtr->WriteStatus); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DirEnd (rqptr); return; } if (VMSnok (rqptr->NetIoPtr->WriteStatus)) { /* network write has failed (as AST), bail out now */ DirEnd (rqptr); return; } tkptr = rqptr->DirTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsSearchNoConceal (&tkptr->SearchOds, &DirFiles, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* This is an AST completion routine called each time sys$search() completes. It will either point to another file name found or have "no more files found" status (or an error!). If a file call a function to determine if the file will contain a "description". When that function returns just return to the AST interrupted routine. */ DirFiles (REQUEST_STRUCT *rqptr) { int status; char *cptr, *sptr; REQUEST_AST AstFunction; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirFiles() !&F sts:!&S stv:!&S", &DirFiles, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->DirTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DirEnd (rqptr); return; } tkptr = rqptr->DirTaskPtr; if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { /* if its a search list treat directory not found as if file not found */ if ((tkptr->SearchOds.Nam_fnb & NAM$M_SEARCH_LIST) && status == RMS$_DNF) status = RMS$_FNF; if (status == RMS$_FNF || status == RMS$_NMF) { /**********************/ /* end of file search */ /**********************/ tkptr->SearchOds.ParseInUse = false; if (tkptr->FormatLikeVms) { DirFormat (rqptr, &DirEndOutput, "", true); return; } else { DirEndOutput (rqptr); return; } } /**********************/ /* sys$search() error */ /**********************/ rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } /* terminate following the last character in the version number */ tkptr->SearchOds.NamVersionPtr[tkptr->SearchOds.NamVersionLength] = '\0'; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "!&Z", tkptr->SearchOds.NamDevicePtr); /* we've already output the directories, ignore them */ if (MATCH5 (tkptr->SearchOds.NamTypePtr, ".DIR;") || MATCH5 (tkptr->SearchOds.NamTypePtr, ".dir;")) { /* check if the .DIR is really a directory */ status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSok (status)) { DirSearchFiles (rqptr); return; } } /* in true Unix-style "hidden" files do not appear (those beginning ".") */ if (SAME1(tkptr->SearchOds.NamNamePtr,'.') || SAME2(tkptr->SearchOds.NamNamePtr,'^.')) { /* except in demo mode or to VMS authenticated and profiled requests */ if (rqptr->rqPathSet.WebDavNoHidden || !(CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength)) { if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, ".FILE (hidden)"); DirSearchFiles (rqptr); return; } } if (DavMetaFile (&tkptr->SearchOds)) { /* found one, next file please */ DirSearchFiles (rqptr); return; } if (tkptr->ThesePtr) { if (!DirTheseFiles (rqptr)) { /* nope, next file please */ DirSearchFiles (rqptr); return; } } if (tkptr->VersionsOf) { if (tkptr->VersionLength) if (tkptr->VersionLength != tkptr->SearchOds.NamNameLength + tkptr->SearchOds.NamTypeLength) tkptr->VersionLength = 0; if (tkptr->VersionLength) if (strncmp (tkptr->VersionName, tkptr->SearchOds.NamNamePtr, tkptr->VersionLength)) tkptr->VersionLength = 0; if (!tkptr->VersionLength) { tkptr->VersionLength = tkptr->SearchOds.NamNameLength + tkptr->SearchOds.NamTypeLength; memcpy (tkptr->VersionName, tkptr->SearchOds.NamNamePtr, tkptr->VersionLength); tkptr->VersionName[tkptr->VersionLength] = '\0'; tkptr->VersionCount = 0; } if (tkptr->VersionCount++ >= tkptr->VersionsOf) { /* enough is enough! */ DirSearchFiles (rqptr); return; } } if (tkptr->SearchOds.NamTypeLength <= 1) { /* no explicit type - look to see if name contains escaped period */ for (cptr = tkptr->SearchOds.NamNamePtr; cptr < tkptr->SearchOds.NamTypePtr; cptr++) if (*(USHORTPTR)cptr == '^.') break; if (cptr < tkptr->SearchOds.NamTypePtr) { /* escaped period - do not list these ambiguous file names */ if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "^.NAME.; !AZ", tkptr->SearchOds.NamNamePtr); DirSearchFiles (rqptr); return; } } if (rqptr->PathOds == MAPURL_PATH_ODS_ADS || rqptr->PathOds == MAPURL_PATH_ODS_SMB) cptr = MapOdsAdsFileType (tkptr->SearchOds.NamTypePtr); else if (rqptr->PathOds == MAPURL_PATH_ODS_SRI) cptr = MapOdsSriFileType (tkptr->SearchOds.NamTypePtr); else cptr = tkptr->SearchOds.NamTypePtr; ConfigContentType (&tkptr->ContentInfo, cptr); if (Config.cfDir.DescriptionLines && ConfigSameContentType (tkptr->ContentInfo.ContentTypePtr, "text/html", -1)) { /* generate an HTML description */ Description (rqptr, &DirEndDescription, tkptr->SearchOds.ResFileName, tkptr->Description, sizeof(tkptr->Description), DESCRIPTION_TEXT_HTML); return; } else { /* description is the content-type */ tkptr->Description[0] = '\0'; DirFormat (rqptr, &DirSearchFiles, "", false); return; } } /*****************************************************************************/ /* */ DirEndDescription (REQUEST_STRUCT *rqptr) { /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirEndDescription() !&F", &DirEndDescription); DirFormat (rqptr, &DirSearchFiles, "", false); } /*****************************************************************************/ /* Directories have been listed, files have been listed. If appropriate provide a readme at the bottom, then conclude the HTML and the directory listing. */ DirEndOutput (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (ColSpanFaoDsc, "!AZ\
\n\ \n\ \n\0"); static $DESCRIPTOR (DirSortFaoDsc, "!AZ\n\0"); static char DirSort [256]; static $DESCRIPTOR (DirSortDsc, DirSort); int cnt, status; unsigned short slen = 0; char *cptr, *sptr; REQUEST_AST AstFunction; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirEndOutput() !&F", &DirEndOutput); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; if (Config.cfDir.ReadMeBottom && tkptr->IncludeAnyReadme) AstFunction = &DirReadMeBottom; else AstFunction = &DirEnd; if (tkptr->DirDelimit == MAPURL_DIR_DELIMIT_BOTH || tkptr->DirDelimit == MAPURL_DIR_DELIMIT_FOOTER) { if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT) { sys$fao (&ColSpanFaoDsc, &slen, &DirColSpanDsc, tkptr->DirFormatBlockTotals ? "" : "\n\n", tkptr->ColSpanCount); cptr = DirColSpan; slen--; if (tkptr->DirSort[0]) { sys$fao (&DirSortFaoDsc, &slen, &DirSortDsc, cptr, tkptr->DirSort); cptr = DirSort; slen--; } } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { if (tkptr->DirFormatBlockTotals) cptr = "\n\n"; else cptr = "\n\n"; slen = 18; if (tkptr->DirSort[0]) { sys$fao (&DirSortFaoDsc, &slen, &DirSortDsc, cptr, tkptr->DirSort); cptr = DirSort; slen--; } } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) { cptr = "\n\n"; slen = 8; } else { cptr = "\n
\n"; slen = 29; } } else if (tkptr->DirStyleTabular) { if (tkptr->DirFormatBlockTotals) cptr = "\n\n"; else cptr = "\n\n"; slen = 16; if (tkptr->DirSort[0]) { sys$fao (&DirSortFaoDsc, &slen, &DirSortDsc, cptr, tkptr->DirSort); cptr = DirSort; slen--; } } else { /* footer not required, just tie-off the preformatted text */ cptr = "\n"; slen = 7; } NetWriteBuffered (rqptr, AstFunction, cptr, slen); } /*****************************************************************************/ /* A series of null-terminated strings (wildcarded file names and/or types) are each matched to the name and type of the currently searched-for file. Return true if the file is matched, false if not. Preceding a string with a '!' negates the match (i.e. not these files). First match is considered a hit. */ BOOL DirTheseFiles (REQUEST_STRUCT *rqptr) { BOOL hit = false, negate = false; char *cptr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirTheseFiles() !AZ", rqptr->DirTaskPtr->ThesePtr); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; *tkptr->SearchOds.NamVersionPtr = '\0'; cptr = tkptr->ThesePtr; while (*cptr) { if (negate = (*cptr == '!')) cptr++; if (hit = StringMatch (NULL, tkptr->SearchOds.NamNamePtr, cptr)) break; while (*cptr) cptr++; if (*(cptr+1)) cptr++; } *tkptr->SearchOds.NamVersionPtr = ';'; if (negate) return (!hit); return (hit); } /*****************************************************************************/ /* Using the directive string pointed to by 'tkptr->LayoutPtr' format the directory listing column headings and sys$fao() directive string used to format the information for each directory/file. Return normal or error status. This function buffers the details of the default generic and VMS directory layout the first time each is required. There-after the buffered layout information is used, reducing overhead. Only if a user-supplied layout is required does any format processing occur again. */ DirFormatLayout (REQUEST_STRUCT *rqptr) { # define LAYOUT_SIZE 512 static BOOL MakeDescriptionLink, ShowNoType, ShowUpperCase; static int FieldWidthCdt, FieldWidthDescription, FieldWidthName, FieldWidthOwner, FieldWidthRdt, FieldWidthSize, HeadingCreatedLength, HeadingDescriptionLength, HeadingNameLength, HeadingOwnerLength, HeadingProtectionLength, HeadingRevisedLength, HeadingSizeLength, LayoutFaoLength, LayoutHeadingLength, LayoutSizeKilo, VmsFieldWidthCdt, VmsFieldWidthDescription, VmsFieldWidthName, VmsFieldWidthOwner, VmsFieldWidthRdt, VmsFieldWidthSize, VmsLayoutFaoLength, VmsLayoutHeadingLength, VmsLayoutSizeKilo; static char LayoutFao [LAYOUT_SIZE/2], LayoutHeading [LAYOUT_SIZE], VmsLayoutFao [LAYOUT_SIZE/2], VmsLayoutHeading [LAYOUT_SIZE]; static char *HeadingCreatedPtr, *HeadingDescriptionPtr, *HeadingNamePtr, *HeadingOwnerPtr, *HeadingProtectionPtr, *HeadingRevisedPtr, *HeadingSizePtr, *ColumnHeadingsPtr; static $DESCRIPTOR (ColSpanFaoDsc, "\n\
\n\ \n\ \n\0"); BOOL ForbiddenLayout, IconInPlace; int cnt, idx, size; char String [LAYOUT_SIZE]; char *aptr, *cptr, *lptr, *sptr, *wptr, *zptr, *LayoutBufferPtr, *LayoutFaoPtr, *LayoutHeadingPtr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirFormatLayout()"); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; IconInPlace = false; tkptr->MakeDescriptionLink = false; if (!ColumnHeadingsPtr) { /******************************/ /* initialize column headings */ /******************************/ sptr = MsgFor(rqptr,MSG_DIR_COLUMN_HEADINGS); cptr = ColumnHeadingsPtr = VmGet (strlen(sptr)); strcpy (cptr, sptr); HeadingCreatedPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingCreatedLength = strlen(HeadingCreatedPtr); HeadingDescriptionPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingDescriptionLength = strlen(HeadingDescriptionPtr); HeadingNamePtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingNameLength = strlen(HeadingNamePtr); HeadingOwnerPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingOwnerLength = strlen(HeadingOwnerPtr); HeadingProtectionPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingProtectionLength = strlen(HeadingProtectionPtr); HeadingRevisedPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingRevisedLength = strlen(HeadingRevisedPtr); HeadingSizePtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; HeadingSizeLength = strlen(HeadingSizePtr); } if (!tkptr->LayoutPtr) { /******************/ /* default layout */ /******************/ if (Config.cfDir.DefaultLayout[0]) tkptr->LayoutPtr = Config.cfDir.DefaultLayout; else tkptr->LayoutPtr = DirDefaultLayout; if (tkptr->DirStyle <= 0) { /* default or no style */ if (!tkptr->FormatLikeVms && LayoutFaoLength) { /* default generic heading and fao have already been generated */ tkptr->LayoutFaoPtr = LayoutFao; tkptr->LayoutFaoLength = LayoutFaoLength; tkptr->LayoutHeadingPtr = LayoutHeading; tkptr->LayoutHeadingLength = LayoutHeadingLength; tkptr->FieldWidthCdt = FieldWidthCdt; tkptr->FieldWidthDescription = FieldWidthDescription; tkptr->FieldWidthName = FieldWidthName; tkptr->FieldWidthOwner = FieldWidthOwner; tkptr->FieldWidthRdt = FieldWidthRdt; tkptr->FieldWidthSize = FieldWidthSize; tkptr->SizeKilo = LayoutSizeKilo; tkptr->MakeDescriptionLink = MakeDescriptionLink; tkptr->ShowNoType = ShowNoType; tkptr->ShowUpperCase = ShowUpperCase; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) { WatchData (LayoutHeading, strlen(LayoutHeading)); WatchData (LayoutFao, strlen(LayoutFao)); } return (SS$_NORMAL); } if (tkptr->FormatLikeVms && VmsLayoutFaoLength) { /* default VMS heading and fao have already been generated */ tkptr->LayoutFaoPtr = VmsLayoutFao; tkptr->LayoutFaoLength = VmsLayoutFaoLength; tkptr->LayoutHeadingPtr = VmsLayoutHeading; tkptr->LayoutHeadingLength = VmsLayoutHeadingLength; tkptr->FieldWidthCdt = VmsFieldWidthCdt; tkptr->FieldWidthDescription = VmsFieldWidthDescription; tkptr->FieldWidthName = VmsFieldWidthName; tkptr->FieldWidthOwner = VmsFieldWidthOwner; tkptr->FieldWidthRdt = VmsFieldWidthRdt; tkptr->FieldWidthSize = VmsFieldWidthSize; tkptr->SizeKilo = VmsLayoutSizeKilo; tkptr->MakeDescriptionLink = MakeDescriptionLink; tkptr->ShowNoType = ShowNoType; tkptr->ShowUpperCase = ShowUpperCase; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) { WatchData (VmsLayoutHeading, strlen(VmsLayoutHeading)); WatchData (VmsLayoutFao, strlen(VmsLayoutFao)); } return (SS$_NORMAL); } /* default headings and layouts have not been generated ... do it! */ if (tkptr->FormatLikeVms) { /* use the function-internal VMS buffers */ LayoutHeadingPtr = VmsLayoutHeading; LayoutFaoPtr = VmsLayoutFao; } else { /* use the function-internal generic buffers */ LayoutHeadingPtr = LayoutHeading; LayoutFaoPtr = LayoutFao; } } else { /* use scratch space to generate the non-default heading and fao */ LayoutHeadingPtr = LayoutFaoPtr = String; tkptr->SizeKilo = 1024; } } else { /**********************/ /* non-default layout */ /**********************/ /* use scratch space to generate the non-default heading and fao */ LayoutHeadingPtr = LayoutFaoPtr = String; tkptr->SizeKilo = 1024; } if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT) for (cptr = tkptr->LayoutPtr; *cptr; cptr++) if (isupper(*cptr)) tkptr->ColSpanCount++; /********************************/ /* assess layout for forbiddens */ /********************************/ if (!Config.cfDir.OwnerEnabled && !rqptr->rqAuth.VmsUserProfileLength) { /* remove OWNER and PROTECTION directives if found */ ForbiddenLayout = false; cptr = tkptr->LayoutPtr; while (*cptr) { if (*cptr == ':') { cptr++; if (*cptr) cptr++; continue; } if (TOUP(*cptr) == 'P' || TOUP(*cptr) == 'O') { ForbiddenLayout = true; cptr++; continue; } cptr++; } if (ForbiddenLayout) { /* remove forbidden directives creating new layout dynamic buffer */ sptr = LayoutBufferPtr = VmGetHeap (rqptr, LAYOUT_SIZE); zptr = sptr + LAYOUT_SIZE; cptr = tkptr->LayoutPtr; while (*cptr) { if (sptr >= zptr) break; if (*cptr == ':') { if (sptr < zptr) *sptr++ = *cptr++; if (*cptr && sptr < zptr) *sptr++ = *cptr++; continue; } if (TOUP(*cptr) == 'P' || TOUP(*cptr) == 'O') { cptr++; while (*cptr == '_') cptr++; continue; } if (sptr < zptr) *sptr++ = *cptr++; } if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); DirEnd (rqptr); return; } *sptr = '\0'; tkptr->LayoutPtr = LayoutBufferPtr; } } /******************************/ /* first, the column headings */ /******************************/ zptr = (sptr = LayoutHeadingPtr) + LAYOUT_SIZE; lptr = tkptr->LayoutPtr; wptr = NULL; switch (tkptr->DirStyle) { case MAPURL_DIR_STYLE_ANCHOR : cptr = "
"; break;
      case MAPURL_DIR_STYLE_ANCHOR2 :
         cptr = "
"; break;
      case MAPURL_DIR_STYLE_HTDIR :
         cptr = "
"; break;
      case MAPURL_DIR_STYLE_HTDIR2 :
         cptr = "
"; break;
      case MAPURL_DIR_STYLE_ORIGINAL :
         cptr = "
"; break;
      case MAPURL_DIR_STYLE_ORIGINAL2 :
         cptr = "
"; break;
      case MAPURL_DIR_STYLE_TABLE :
         cptr = "

\n\n"; break; case MAPURL_DIR_STYLE_TABLE2 : cptr = "

\n\n"; break; case MAPURL_DIR_STYLE_SORT : cptr = "

\n\n"; break; case MAPURL_DIR_STYLE_SORT2 : cptr = "

\n\n"; break; default : cptr = "
";
   }
   while (*cptr && sptr < zptr) *sptr++ = *cptr++;

   while (*lptr && *lptr != '&' && sptr < zptr)
   {
      if (isdigit(*lptr))
      {
         wptr = lptr;
         while (*lptr && isdigit(*lptr)) lptr++;
         continue;
      }
      else
         wptr = NULL;

      if (wptr && wptr[0])
      {
         cnt = atoi(wptr);
         if (cnt < 0) cnt = 0;
      }
      else
         cnt = 0;

      switch (TOUP(*lptr))
      {
         case ' ' :
         case '_' :
            if (!cnt) cnt = DEFAULT_FIELD_WIDTH_INTERFIELD;
            break;

         case 'C' :
            cptr = HeadingCreatedPtr;
            if (!cnt) cnt = DEFAULT_FIELD_WIDTH_CDT;
            if (cnt < (size = HeadingCreatedLength)) cnt = size;
            if (tkptr->FormatLikeVms) cnt += 5;
            tkptr->FieldWidthCdt = cnt;
            break;

         case 'D' :
            /* flush left */
            cptr = HeadingDescriptionPtr;
            if (cnt)
            {
               if (cnt > 255) cnt = 255;
               if (cnt < (size = HeadingDescriptionLength)) cnt = size;
               tkptr->FieldWidthDescription = cnt;
            }
            else
            {
               cnt = size = HeadingDescriptionLength;
               tkptr->FieldWidthDescription = 0;
            }
            if (lptr[1] == LAYOUT_PARAMETER)
            {
               switch (TOUP(lptr[2]))
               {
                  case 'L' :
                     tkptr->MakeDescriptionLink = true;
                     break;
                  default :
                     /* unknown layout directive character */
                     rqptr->rqResponse.HttpStatus = 501;
                     ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI);
                     return (STS$K_ERROR);
               }
            }
            break;

         case 'I' :  /* icon */
            break;

         case 'L' :
         case 'N' :

            cptr = HeadingNamePtr;
            if (tkptr->DirStyleTabular)
            {
               cnt = size = HeadingNameLength;
               tkptr->FieldWidthName = 0;
            }
            else
            {
               if (!cnt) cnt = DEFAULT_FIELD_WIDTH_NAME;
               if (cnt < (size = HeadingNameLength)) cnt = size;
               tkptr->FieldWidthName = cnt;
            }
            /* this layout parameter can be used like "L:F:U" */
            idx = 0;
            while (lptr[idx+1] == LAYOUT_PARAMETER)
            {
               switch (TOUP(lptr[idx+2]))
               {
                  case 'F' :
                     /* for backward compatibility just ignore this */
                     break;
                  case 'N' :
                     tkptr->ShowNoType = true;
                     break;
                  case 'U' :
                     tkptr->ShowUpperCase = true;
                     break;
                  default :
                     /* unknown layout directive character */
                     rqptr->rqResponse.HttpStatus = 501;
                     ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI);
                     return (STS$K_ERROR);
               }
               idx += 2;
            }
            break;

         case 'O' :
            cptr = HeadingOwnerPtr;
            if (!cnt) cnt = DEFAULT_FIELD_WIDTH_OWNER;
            if (cnt < (size = HeadingOwnerLength)) cnt = size;
            tkptr->FieldWidthOwner = cnt;
            break;

         case 'P' :
            cptr = HeadingProtectionPtr;
            if (!cnt) cnt = DEFAULT_FIELD_WIDTH_PROTECTION;
            if (cnt < (size = HeadingProtectionLength)) cnt = size;
            tkptr->FieldWidthProtection = cnt;
            break;

         case 'R' :
            cptr = HeadingRevisedPtr;
            if (!cnt) cnt = DEFAULT_FIELD_WIDTH_RDT;
            if (cnt < (size = HeadingRevisedLength)) cnt = size;
            if (tkptr->FormatLikeVms) cnt += 5;
            tkptr->FieldWidthRdt = cnt;
            break;

         case 'S' :
            /* this layout parameter can be used like "S:2:F" */
            idx = 0;
            while (lptr[idx+1] == LAYOUT_PARAMETER)
            {
               switch (TOUP(lptr[idx+2]))
               {
                  case '0' :
                     tkptr->SizeKilo = 1000;
                     break;
                  case '2' :
                     tkptr->SizeKilo = 1024;
                     break;
                  case 'D' :
                     tkptr->SizeKilo = 1000;
                     /* drop thru into 'f' */
                  case 'F' :
                     if (!cnt) cnt = DEFAULT_FIELD_WIDTH_SIZE;
                     if (cnt < (size = DEFAULT_FIELD_WIDTH_SIZE - 2))
                        cnt = size;
                     break;
                  case 'B' :
                  case 'K' :
                  case 'M' :
                     if (!cnt) cnt = DEFAULT_FIELD_WIDTH_DECIMAL;
                     if (cnt < (size = DEFAULT_FIELD_WIDTH_DECIMAL - 7))
                        cnt = size;
                     break;
                  case 'V' :
                     if (!cnt) cnt = DEFAULT_FIELD_WIDTH_SIZE;
                     if (cnt < (size = DEFAULT_FIELD_WIDTH_SIZE - 2))
                        cnt = size;
                     break;
                  default :
                     /* unknown layout directive character */
                     rqptr->rqResponse.HttpStatus = 501;
                     ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI);
                     return (STS$K_ERROR);
               }
               idx += 2;
            }

            if (tkptr->FormatLikeVms)
            {
               if (!cnt) cnt = DEFAULT_FIELD_WIDTH_SIZE;
               if (cnt < (size = DEFAULT_FIELD_WIDTH_SIZE - 2)) cnt = size;
               /* expand size field width by 7 for blocks allocated/used */
               cnt += 7;
            }
            else
            {
               if (!cnt) cnt = DEFAULT_FIELD_WIDTH_SIZE;
               if (cnt < (size = DEFAULT_FIELD_WIDTH_SIZE - 2)) cnt = size;
               /* expand size field width by 7 for blocks allocated/used */
               if (tkptr->FormatLikeVms) cnt += 7;
            }

            cptr = HeadingSizePtr;
            tkptr->FieldWidthSize = cnt;
            break;

         case 'U' :
            /* force to upper case, just ignore, MUST be first directive */
            tkptr->ShowUpperCase = true;
            break;

         default :
            /* unknown layout directive character */
            rqptr->rqResponse.HttpStatus = 501;
            ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI);
            return (STS$K_ERROR);
      }

      switch (TOUP(*lptr))
      {
         case ' ' :
         case '_' :
            if (tkptr->DirStyleTabular) break;
            while (cnt-- && sptr < zptr) *sptr++ = ' ';
            break;

         case 'C' :
         case 'R' :
         case 'S' :

            if (tkptr->DirStyleTabular)
            {
               if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE ||
                   tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2)
                  aptr = "
"; *aptr && sptr < zptr; *sptr++ = *aptr++); break; case 'D' : case 'L' : case 'N' : case 'O' : case 'P' : if (tkptr->DirStyleTabular) { if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2) aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); else { /* flush the column heading left using spaces */ if (cnt) cnt -= size; while (cnt-- && sptr < zptr) *sptr++ = ' '; } break; case 'I' : if (tkptr->DirStyleTabular) { if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) cptr = ""; else cptr = ""; } else cptr = ConfigBlankIconPtr; while (*cptr && sptr < zptr) *sptr++ = *cptr++; IconInPlace = true; break; } while (lptr[1] == LAYOUT_PARAMETER) lptr += 2; lptr++; } if (tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) cptr = "\n"; else if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT) { sys$fao (&ColSpanFaoDsc, NULL, &DirColSpanDsc, tkptr->ColSpanCount); cptr = DirColSpan; } else if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) cptr = "\n\n\n"; else if (tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR) { if (IconInPlace) cptr = "\n
\n"; else /* when an icon not providing appropriate line spacing to the
*/ cptr = "\n\n
\n"; } else { if (IconInPlace) cptr = "\n
\n"; else /* when an icon not providing appropriate line spacing to the
*/ cptr = "\n\n
\n"; } while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { /* should be enough for all but a deliberate formatting hack! */ rqptr->rqResponse.HttpStatus = 501; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI); return (STS$K_ERROR); } *sptr = '\0'; cnt = sptr - LayoutHeadingPtr; if (LayoutHeadingPtr == LayoutHeading) { /* first time a generic layout has been required, buffer details */ tkptr->LayoutHeadingPtr = LayoutHeading; tkptr->LayoutHeadingLength = LayoutHeadingLength = cnt; FieldWidthCdt = tkptr->FieldWidthCdt; FieldWidthDescription = tkptr->FieldWidthDescription; FieldWidthName = tkptr->FieldWidthName; FieldWidthOwner = tkptr->FieldWidthOwner; FieldWidthRdt = tkptr->FieldWidthRdt; FieldWidthSize = tkptr->FieldWidthSize; MakeDescriptionLink = tkptr->MakeDescriptionLink; ShowNoType = tkptr->ShowNoType; ShowUpperCase = tkptr->ShowUpperCase; } else if (LayoutHeadingPtr == VmsLayoutHeading) { /* first time a VMS layout has been required, buffer details */ tkptr->LayoutHeadingPtr = VmsLayoutHeading; tkptr->LayoutHeadingLength = VmsLayoutHeadingLength = cnt; VmsFieldWidthCdt = tkptr->FieldWidthCdt; VmsFieldWidthDescription = tkptr->FieldWidthDescription; VmsFieldWidthName = tkptr->FieldWidthName; VmsFieldWidthOwner = tkptr->FieldWidthOwner; VmsFieldWidthRdt = tkptr->FieldWidthRdt; VmsFieldWidthSize = tkptr->FieldWidthSize; MakeDescriptionLink = tkptr->MakeDescriptionLink; ShowNoType = tkptr->ShowNoType; ShowUpperCase = tkptr->ShowUpperCase; } else { /* this is a user-supplied layout, place it in the thread's heap */ tkptr->LayoutHeadingPtr = lptr = VmGetHeap (rqptr, cnt+1); memcpy (lptr, LayoutHeadingPtr, cnt+1); tkptr->LayoutHeadingLength = cnt; } /******************************************/ /* second, the sys$fao() directive string */ /******************************************/ zptr = (sptr = LayoutFaoPtr) + LAYOUT_SIZE / 2; lptr = tkptr->LayoutPtr; wptr = NULL; /* accomodate an optional leading new-line (for creating a blank line) */ for (cptr = "!AZ"; *cptr && sptr < zptr; *sptr++ = *cptr++); /* table row for sort */ for (cptr = "!AZ"; *cptr && sptr < zptr; *sptr++ = *cptr++); while (*lptr && *lptr != '&' && sptr < zptr) { if (isdigit(*lptr)) { wptr = lptr; while (*lptr && isdigit(*lptr)) lptr++; continue; } else wptr = NULL; if (wptr && wptr[0]) { cnt = atoi(wptr); if (cnt < 0) cnt = 0; } else cnt = 0; switch (TOUP(*lptr)) { case ' ' : case '_' : if (tkptr->DirStyleTabular) break; if (!cnt) cnt = DEFAULT_FIELD_WIDTH_INTERFIELD; while (cnt-- && sptr < zptr) *sptr++ = ' '; break; case 'C' : case 'R' : case 'S' : /* right justify, then value */ if (tkptr->DirStyleTabular) { if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) cptr = ""; else cptr = ""; } else cptr = "!#"; while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; case 'D' : /* nothing fancy (allow for leading/trailing quotes and link) */ if (tkptr->DirStyleTabular) { if (tkptr->MakeDescriptionLink) if (tkptr->FieldWidthDescription) cptr = ""; else cptr = ""; else if (tkptr->FieldWidthDescription) cptr = ""; else cptr = ""; } else { if (tkptr->MakeDescriptionLink) if (tkptr->FieldWidthDescription) cptr = "!AZ!AZ!AZ!AZ!AZ!AZ!#"; else cptr = "!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ"; else if (tkptr->FieldWidthDescription) cptr = "!AZ!#"; else cptr = "!AZ!AZ!AZ"; } while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; case 'I' : /* nothing fancy */ if (tkptr->DirStyleTabular) { if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) cptr = ""; else cptr = ""; } else cptr = "!AZ!AZ!AZ"; while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; case 'L' : if (tkptr->DirStyleTabular) cptr = ""; else /* left justify, then link, name, and name overflow */ cptr = "!AZ!AZ!AZ!AZ!AZ!#"; while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; case 'N' : /* left justify, string, plus overflow */ if (tkptr->DirStyleTabular) cptr = ""; else cptr = "!#"; while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; case 'O' : case 'P' : if (tkptr->DirStyleTabular) cptr = ""; else /* '!#AZ' will left justify value with spaces */ cptr = "!#AZ"; while (*cptr && sptr < zptr) *sptr++ = *cptr++; break; } if (lptr[1] == LAYOUT_PARAMETER) lptr += 2; lptr++; } /* end table row for sort */ for (cptr = "!AZ"; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr >= zptr) { /* should be enough for all but a deliberate formatting hack! */ rqptr->rqResponse.HttpStatus = 501; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI); return (STS$K_ERROR); } *sptr = '\0'; cnt = sptr - LayoutFaoPtr; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) { WatchData (LayoutHeadingPtr, strlen(LayoutHeadingPtr)); WatchData (LayoutFaoPtr, strlen(LayoutFaoPtr)); } if (LayoutFaoPtr == LayoutFao) { /* first time a generic layout has been required, buffer details */ tkptr->LayoutFaoPtr = LayoutFao; tkptr->LayoutFaoLength = LayoutFaoLength = cnt; LayoutSizeKilo = tkptr->SizeKilo; } else if (LayoutFaoPtr == VmsLayoutFao) { /* first time a VMS layout has been required, buffer details */ tkptr->LayoutFaoPtr = VmsLayoutFao; tkptr->LayoutFaoLength = VmsLayoutFaoLength = cnt; VmsLayoutSizeKilo = 1024; } else { /* this is a user-supplied layout, place it in the thread's heap */ tkptr->LayoutFaoPtr = lptr = VmGetHeap (rqptr, cnt+1); memcpy (lptr, LayoutFaoPtr, cnt+1); tkptr->LayoutFaoLength = cnt; } return (SS$_NORMAL); } /*****************************************************************************/ /* This function uses the ACP-QIO interface detailed in the "OpenVMS I/O User's Reference Manual", and is probably as fast as we can get for this type of file system functionality! */ DirFormat ( REQUEST_STRUCT *rqptr, REQUEST_AST AstFunction, char *ParentDirPath, BOOL BlockTotals ) { int status; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirFormat() !&Z !UL", ParentDirPath, BlockTotals); tkptr = rqptr->DirTaskPtr; tkptr->DirFormatAstFunction = AstFunction; tkptr->DirFormatParentDirPath = ParentDirPath; tkptr->DirFormatBlockTotals = BlockTotals; if (ParentDirPath[0] || BlockTotals) { /***************************/ /* do not queue an ACP I/O */ /***************************/ /* explicitly call the AST format routine */ tkptr->SearchOds.FileQio.IOsb.Status = SS$_NORMAL; DirFormatAcpInfoAst (rqptr); return; } AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsFileAcpInfo (&tkptr->SearchOds, &DirFormatAcpInfoAst, rqptr); AuthAccessEnable (rqptr, 0, 0); } /****************************************************************************/ /* AST called from OdsFileAcpInfo() when ACP QIO completes. This overly-long (sorry) function formats and outputs a line of information for a parent directory, directory file, non-directory file, or for the final line giving used/allocated totals for a VMS format listing. */ DirFormatAcpInfoAst (REQUEST_STRUCT *rqptr) { static unsigned long AddendZero = 0, FiveTwelve = 512, LibDateTimeContext = 0, LibDateTimeSortTableContext = 0, LibDateTimeVmsContext = 0, LibOutputFormat = LIB$K_OUTPUT_FORMAT; static char Cdt [32], CdtSortTable [16], Rdt [32], RdtSortTable [16]; static $DESCRIPTOR (BlocksFaoDsc, "!UL/!UL"); static $DESCRIPTOR (CdtDsc, Cdt); static $DESCRIPTOR (CdtSortTableDsc, CdtSortTable); static $DESCRIPTOR (DeviceDsc, ""); static $DESCRIPTOR (OutputFormatDsc, "|!DB-!MAAC-!Y4|!H04:!M0|"); static $DESCRIPTOR (OutputFormatSortTableDsc, "|!Y4!MN0!D0!H04!M0!S0|"); static $DESCRIPTOR (OutputFormatVmsDsc, "|!DB-!MAAU-!Y4|!H04:!M0:!S0|"); static $DESCRIPTOR (OwnerFaoDsc, "!%I"); static $DESCRIPTOR (OwnerDsc, ""); static $DESCRIPTOR (RdtDsc, Rdt); static $DESCRIPTOR (RdtSortTableDsc, RdtSortTable); static $DESCRIPTOR (SizeDsc, ""); static $DESCRIPTOR (SizeFaoDsc, "!#* !AZ"); static $DESCRIPTOR (TotalFilesDsc, ""); static $DESCRIPTOR (TotalFilesFaoDsc, "!UL files"); BOOL ThisIsADirectory; int idx, status, Count, DateLength, EncodedNameDelta, MaxIdx; unsigned short AcpChannel, Length; unsigned short NumTime [7]; unsigned long AllocatedVbn, EndOfFileVbn; unsigned long QuadBytes [2]; unsigned long FaoVector [64]; char *cptr, *sptr, *zptr, *IconPtr, *AnchorNameOverflowPtr; char AnchorLink [(ODS_MAX_FILE_NAME_LENGTH*2)+1], AnchorName [ODS_MAX_FILE_NAME_LENGTH+1], Description [256], IconAnchor [ODS_MAX_FILE_NAME_LENGTH+1], Owner [64], Protection [64], Size [32], SizeSortTable [32], String [2048], TotalFiles [32]; DIR_TASK *tkptr; unsigned long *ctxptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirFormatAcpInfoAst() !&F !&S", &DirFormatAcpInfoAst, rqptr->DirTaskPtr->SearchOds.FileQio.IOsb.Status); tkptr = rqptr->DirTaskPtr; /* first deassign the channel allocated by OdsFileAcpInfo() */ sys$dassgn (tkptr->SearchOds.FileQio.AcpChannel); if ((status = tkptr->SearchOds.FileQio.IOsb.Status) == SS$_NOSUCHFILE) status = RMS$_FNF; if (VMSnok (status)) { /*************************/ /* protection violation? */ /*************************/ if ((status == SS$_NOPRIV || status == RMS$_PRV) && Config.cfDir.NoPrivIgnore) { /* can't return without queueing the next bit of processing! */ SysDclAst (tkptr->DirFormatAstFunction, rqptr); return; } /*******************/ /* something else! */ /*******************/ rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } if (tkptr->DirFormatBlockTotals) ThisIsADirectory = false; else if (MATCH5 (tkptr->SearchOds.NamTypePtr, ".DIR;") || MATCH5 (tkptr->SearchOds.NamTypePtr, ".dir;")) { /* check if the .DIR is really a directory */ if (VMSok (OdsReallyADir (rqptr, &tkptr->SearchOds))) ThisIsADirectory = true; else ThisIsADirectory = false; } else ThisIsADirectory = false; if (ThisIsADirectory) { /******************************/ /* no need to display the MFD */ /******************************/ if (tkptr->SearchOds.NamNamePtr[0] == '0' && strsame (tkptr->SearchOds.NamNamePtr, "000000.DIR;", 11)) { /* can't return without queueing the next bit of processing! */ SysDclAst (tkptr->DirFormatAstFunction, rqptr); return; } } /****************/ /* begin format */ /****************/ if (!LibDateTimeContext) { /* initialize the date/time formats */ status = lib$init_date_time_context (&LibDateTimeContext, &LibOutputFormat, &OutputFormatDsc); if (VMSok (status)) status = lib$init_date_time_context (&LibDateTimeSortTableContext, &LibOutputFormat, &OutputFormatSortTableDsc); if (VMSok (status)) status = lib$init_date_time_context (&LibDateTimeVmsContext, &LibOutputFormat, &OutputFormatVmsDsc); if (VMSnok (status)) ErrorExitVmsStatus (status, "lib$init_date_time_context()", FI_LI); } /********************************/ /* process file name components */ /********************************/ IconAnchor[0] = '\0'; MaxIdx = sizeof(FaoVector) / sizeof(unsigned long); idx = 0; if (tkptr->DirFormatBlockTotals) { /****************/ /* block totals */ /****************/ /* must be block totals, which requires termination of some sort */ if (idx < MaxIdx) if (tkptr->DirStyleTabular) FaoVector[idx++] = "\n\n"; else FaoVector[idx++] = "\n"; } else if (tkptr->DirFormatParentDirPath[0]) { /********************/ /* parent directory */ /********************/ unsigned long LocalFaoVector [32]; unsigned long *vecptr; /* no leading newline required for the parent directory */ if (idx < MaxIdx) FaoVector[idx++] = ""; tkptr->DirectoryCount = -1; vecptr = &LocalFaoVector; /* when the path may be different from base path (e.g. SSI) */ if (tkptr->RealPath[0]) *vecptr++ = tkptr->DirFormatParentDirPath; else *vecptr++ = "../"; /* any file name/type/version from the original spec */ if (tkptr->DirSpecIncludedFilePart || (!Config.cfDir.NoImpliedWildcard && !rqptr->rqPathSet.DirNoImpliedWildcard)) { *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->FilePart; } else { *vecptr++ = 0; *vecptr++ = ""; } if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; status = FaolToBuffer (AnchorLink, sizeof(AnchorLink), NULL, "!&%AZ!&%&[AZ!&;&@", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); if (tkptr->FormatLikeVms) memcpy (AnchorName, "[-]", 4); else memcpy (AnchorName, "../", 4); } else if (ThisIsADirectory) { /***************/ /* a directory */ /***************/ unsigned long LocalFaoVector [32]; unsigned long *vecptr; /* no leading newline required for directories */ if (idx < MaxIdx) FaoVector[idx++] = ""; if (tkptr->DirectoryCount <= 0) tkptr->DirectoryCount = 1; else tkptr->DirectoryCount++; /* terminate to remove the file type (".DIR") */ tkptr->SearchOds.NamTypePtr[0] = '\0'; vecptr = &LocalFaoVector; /* when the path may be different from base path (e.g. SSI) */ *vecptr++ = tkptr->RealPath; /* the name of this directory */ *vecptr++ = "!&%&[AZ"; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr; /* any file name/type/version from the original spec */ if (tkptr->DirSpecIncludedFilePart || (!Config.cfDir.NoImpliedWildcard && !rqptr->rqPathSet.DirNoImpliedWildcard)) { *vecptr++ = "!&%&[AZ"; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->FilePart; } else *vecptr++ = ""; if (tkptr->QueryStringPtr) { *vecptr++ = "?httpd=index&!AZ"; *vecptr++ = tkptr->QueryStringPtr; } else *vecptr++ = ""; status = FaolToBuffer (AnchorLink, sizeof(AnchorLink), NULL, "!&%AZ!&@/!&@!&;&@", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); vecptr = &LocalFaoVector; if (tkptr->FormatLikeVms) if (!rqptr->PathOds || rqptr->PathOds == MAPURL_PATH_ODS_2) *vecptr++ = "[.!&;&^AZ]"; else *vecptr++ = "[.!&;AZ]"; else { *vecptr++ = "!&;&[AZ/"; *vecptr++ = rqptr->PathOds; } *vecptr++ = tkptr->SearchOds.NamNamePtr; status = FaolToBuffer (AnchorName, sizeof(AnchorName), NULL, "!&@", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); /* restore the type delimitter */ tkptr->SearchOds.NamTypePtr[0] = '.'; if (tkptr->ShowUpperCase) for (cptr = AnchorName; *cptr; cptr++) *cptr = TOUP(*cptr); } else { /**********/ /* a file */ /**********/ unsigned long LocalFaoVector [32]; unsigned long *vecptr; if (tkptr->DirectoryCount && !tkptr->FileCount) { /* leading line-break required for first file after directories */ if (idx < MaxIdx) { if (tkptr->DirStyleTabular) if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) FaoVector[idx++] = "\n"; else FaoVector[idx++] = "\n"; else FaoVector[idx++] = "\n"; } } else if (idx < MaxIdx) FaoVector[idx++] = ""; tkptr->FileCount++; /* if appropriate, terminate to remove the version number */ if (!tkptr->FormatLikeVms && !tkptr->VersionsOf) { if (tkptr->SearchOds.NamTypeLength <= 1) tkptr->SearchOds.NamTypePtr[0] = '\0'; else tkptr->SearchOds.NamVersionPtr[0] = '\0'; } /***************/ /* anchor link */ /***************/ vecptr = &LocalFaoVector; if (tkptr->ScriptName[0]) { /* prepend the (optional) script component of the path */ *vecptr++ = "!&%AZ!&%&[AZ"; *vecptr++ = tkptr->ScriptName; /* need the directory portion of the URL for scripting */ *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->DirectoryPathPtr; } else { *vecptr++ = "!&%&[AZ"; /* when the path may be different from base path (e.g. SSI) */ *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->RealPath; } /* file name and type */ *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr; /* disable auto-scripting by appending a (most-recent) version number */ if (!tkptr->FormatLikeVms && !tkptr->AutoScriptEnabled) *vecptr++ = ";0"; else *vecptr++ = ""; if (tkptr->QueryContentTypePtr && tkptr->QueryContentTypePtr[0]) { /* propagate any request-specified content-type as a query string */ *vecptr++ = "?httpd=content&type=!&%AZ"; *vecptr++ = tkptr->QueryContentTypePtr; } else *vecptr++ = ""; status = FaolToBuffer (AnchorLink, sizeof(AnchorLink), NULL, "!&@!&%&[AZ!AZ!&@", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); /*************/ /* icon link */ /*************/ if (tkptr->IconLinkEnabled && !rqptr->rqPathSet.DirNoIconLink) { vecptr = &LocalFaoVector; *vecptr++ = tkptr->LinkTarget; /* when the path may be different from base path (e.g. SSI) */ *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->RealPath; /* file name and type */ *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr; /* disable auto-scripting by appending (most-recent) version number */ if (!tkptr->FormatLikeVms && !tkptr->AutoScriptEnabled) *vecptr++ = ";0"; else *vecptr++ = ""; *vecptr++ = ConfigContentType (NULL, ".TXT"); status = FaolToBuffer (IconAnchor, sizeof(IconAnchor), NULL, "", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); } else IconAnchor[0] = '\0'; /***************/ /* anchor name */ /***************/ vecptr = &LocalFaoVector; if (tkptr->FormatLikeVms) if (!rqptr->PathOds || rqptr->PathOds == MAPURL_PATH_ODS_2) *vecptr++ = "!&;&^AZ"; else *vecptr++ = "!&;AZ"; else { *vecptr++ = "!&;&[AZ"; *vecptr++ = rqptr->PathOds; } *vecptr++ = tkptr->SearchOds.NamNamePtr; status = FaolToBuffer (AnchorName, sizeof(AnchorName), NULL, "!&@", &LocalFaoVector); if (VMSnok (status) || status == SS$_BUFFEROVF) ErrorNoticed (rqptr, status, NULL, FI_LI); /* if appropriate, restore the version delimitter */ if (!tkptr->FormatLikeVms) if (tkptr->SearchOds.NamTypeLength <= 1) tkptr->SearchOds.NamTypePtr[0] = '.'; else tkptr->SearchOds.NamVersionPtr[0] = ';'; if (tkptr->ShowUpperCase) for (cptr = AnchorName; *cptr; cptr++) *cptr = TOUP(*cptr); } if (!tkptr->DirFormatBlockTotals) { /************************/ /* name post-processing */ /************************/ /* count the extra characters introduced by escaping/encoding */ EncodedNameDelta = 0; AnchorNameOverflowPtr = ""; if (!tkptr->DirStyleTabular) { cptr = AnchorName; while (*cptr && cptr - AnchorName <= tkptr->FieldWidthName + EncodedNameDelta) { if (*cptr != '&') { cptr++; continue; } while (*cptr) { EncodedNameDelta++; cptr++; if (*cptr == ';') break; } } if (cptr - AnchorName > tkptr->FieldWidthName + EncodedNameDelta) { AnchorName[tkptr->FieldWidthName+EncodedNameDelta-1] = '\0'; AnchorNameOverflowPtr = "+"; } } } /***********************************/ /* build the sys$faol() paremeters */ /***********************************/ if (idx < MaxIdx) if (tkptr->DirStyleTabular) FaoVector[idx++] = ""; else FaoVector[idx++] = ""; cptr = tkptr->LayoutPtr; while (*cptr) { if (!isalpha(*cptr)) { cptr++; continue; } if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "!UL \'!1AZ\' !AZ", idx, cptr, cptr); switch (TOUP(*cptr)) { case 'C' : /*****************/ /* creation date */ /*****************/ if (tkptr->DirFormatParentDirPath[0] || tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthCdt; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthCdt; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } /* format the creation date/time */ if (tkptr->FormatLikeVms) ctxptr = &LibDateTimeVmsContext; else ctxptr = &LibDateTimeContext; if (VMSnok (status = lib$format_date_time (&CdtDsc, &tkptr->SearchOds.FileQio.CdtTime64, ctxptr, &DateLength, 0))) { rqptr->rqResponse.ErrorTextPtr = "lib$format_date_time()"; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } Cdt[DateLength] = '\0'; if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { /* custom key as a 64 bit number */ FaoToBuffer (CdtSortTable, sizeof(CdtSortTable), 0, "!@SQ", &tkptr->SearchOds.FileQio.CdtTime64); if (idx < MaxIdx) FaoVector[idx++] = CdtSortTable; } if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthCdt; if (idx < MaxIdx) { /* next parameter right justifies the field */ if (tkptr->FieldWidthCdt - DateLength > 0) FaoVector[idx++] = tkptr->FieldWidthCdt - DateLength; else FaoVector[idx++] = 0; } if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = Cdt; break; case 'D' : /***************/ /* description */ /***************/ if (tkptr->DirFormatParentDirPath[0]) { /********************/ /* parent directory */ /********************/ if (idx < MaxIdx) FaoVector[idx++] = ""; if (tkptr->MakeDescriptionLink) { if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } if (idx < MaxIdx && tkptr->FieldWidthDescription) { FaoVector[idx++] = tkptr->FieldWidthDescription; FaoVector[idx++] = tkptr->FieldWidthDescription; } if (idx < MaxIdx) FaoVector[idx++] = MsgFor(rqptr,MSG_DIR_PARENT); if (idx < MaxIdx && tkptr->MakeDescriptionLink) FaoVector[idx++] = ""; if (idx < MaxIdx && tkptr->FieldWidthDescription) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } else if (tkptr->DirFormatBlockTotals) { /***************************/ /* VMS format block totals */ /***************************/ if (tkptr->DirectoryCount < 0) tkptr->DirectoryCount = 0; TotalFilesDsc.dsc$a_pointer = TotalFiles; TotalFilesDsc.dsc$w_length = sizeof(TotalFiles)-1; sys$fao (&TotalFilesFaoDsc, &Length, &TotalFilesDsc, tkptr->DirectoryCount + tkptr->FileCount); TotalFiles[Length] = '\0'; if (idx < MaxIdx) FaoVector[idx++] = ""; if (tkptr->MakeDescriptionLink) { if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } if (idx < MaxIdx && tkptr->FieldWidthDescription) { FaoVector[idx++] = tkptr->FieldWidthDescription; FaoVector[idx++] = tkptr->FieldWidthDescription; } if (idx < MaxIdx) FaoVector[idx++] = TotalFiles; if (idx < MaxIdx && tkptr->MakeDescriptionLink) FaoVector[idx++] = ""; if (idx < MaxIdx && tkptr->FieldWidthDescription) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } else if (ThisIsADirectory) { /*************/ /* directory */ /*************/ if (idx < MaxIdx) FaoVector[idx++] = ""; if (tkptr->MakeDescriptionLink) { if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } if (idx < MaxIdx && tkptr->FieldWidthDescription) { FaoVector[idx++] = tkptr->FieldWidthDescription; FaoVector[idx++] = tkptr->FieldWidthDescription; } if (idx < MaxIdx) { if (!tkptr->MsgSubDirPtr) FaoVector[idx++] = tkptr->MsgSubDirPtr = MsgFor(rqptr,MSG_DIR_SUB); else FaoVector[idx++] = tkptr->MsgSubDirPtr; } if (idx < MaxIdx && tkptr->MakeDescriptionLink) FaoVector[idx++] = ""; if (idx < MaxIdx && tkptr->FieldWidthDescription) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; } else if (tkptr->Description[0] && tkptr->Description[0] != DESCRIPTION_IMPOSSIBLE) { /******************************/ /* file with HTML description */ /******************************/ if (idx < MaxIdx) FaoVector[idx++] = "\""; if (tkptr->MakeDescriptionLink) { if (idx < MaxIdx) FaoVector[idx++] = "LinkTarget; if (idx < MaxIdx) FaoVector[idx++] = " href=\""; if (idx < MaxIdx) FaoVector[idx++] = AnchorLink; if (idx < MaxIdx) FaoVector[idx++] = "\">"; } if (idx < MaxIdx && tkptr->FieldWidthDescription) { /* the 4 - 1 allows for the leading quote */ if (tkptr->MakeDescriptionLink) FaoVector[idx++] = tkptr->FieldWidthDescription + 3; else FaoVector[idx++] = tkptr->FieldWidthDescription - 1; if ((Count = strlen(tkptr->Description)) > tkptr->FieldWidthDescription - 3) FaoVector[idx++] = tkptr->FieldWidthDescription - 3; else FaoVector[idx++] = Count; } if (idx < MaxIdx) FaoVector[idx++] = tkptr->Description; if (idx < MaxIdx && tkptr->MakeDescriptionLink) FaoVector[idx++] = ""; if (idx < MaxIdx && tkptr->FieldWidthDescription) { if (Count > tkptr->FieldWidthDescription - 3) FaoVector[idx++] = "+"; else FaoVector[idx++] = ""; } if (idx < MaxIdx) FaoVector[idx++] = "\""; } else { /*********************************/ /* file with content description */ /*********************************/ if (idx < MaxIdx) FaoVector[idx++] = ""; if (tkptr->MakeDescriptionLink) { if (idx < MaxIdx) FaoVector[idx++] = "LinkTarget; if (idx < MaxIdx) FaoVector[idx++] = " href=\""; if (idx < MaxIdx) FaoVector[idx++] = AnchorLink; if (idx < MaxIdx) FaoVector[idx++] = "\">"; } if (idx < MaxIdx && tkptr->FieldWidthDescription) { if (tkptr->MakeDescriptionLink) FaoVector[idx++] = tkptr->FieldWidthDescription + 4; else FaoVector[idx++] = tkptr->FieldWidthDescription; if ((Count = strlen(tkptr->ContentInfo.DescriptionPtr)) > tkptr->FieldWidthDescription - 1) FaoVector[idx++] = tkptr->FieldWidthDescription - 1; else FaoVector[idx++] = Count; } if (idx < MaxIdx) FaoVector[idx++] = tkptr->ContentInfo.DescriptionPtr; if (idx < MaxIdx && tkptr->MakeDescriptionLink) FaoVector[idx++] = ""; if (idx < MaxIdx && tkptr->FieldWidthDescription) { if (Count > tkptr->FieldWidthDescription - 3) FaoVector[idx++] = "+"; else FaoVector[idx++] = ""; } if (idx < MaxIdx) FaoVector[idx++] = ""; } break; case 'I' : /********/ /* icon */ /********/ if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) if (idx < MaxIdx) FaoVector[idx++] = tkptr->DirectoryCount + tkptr->FileCount; if (idx < MaxIdx) if (IconAnchor[0]) FaoVector[idx++] = IconAnchor; else FaoVector[idx++] = ""; if (tkptr->DirFormatBlockTotals) IconPtr = ConfigBlankIconPtr; else if (ThisIsADirectory) IconPtr = ConfigDirIconPtr; else if (tkptr->DirFormatParentDirPath[0]) IconPtr = ConfigParentIconPtr; else IconPtr = tkptr->ContentInfo.IconPtr; if (idx < MaxIdx) FaoVector[idx++] = IconPtr; if (idx < MaxIdx) FaoVector[idx++] = ""; break; case 'L' : /***************/ /* link/anchor */ /***************/ if (tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthName; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } if (idx < MaxIdx) FaoVector[idx++] = "LinkTarget; if (idx < MaxIdx) FaoVector[idx++] = " href=\""; if (idx < MaxIdx) FaoVector[idx++] = AnchorLink; if (idx < MaxIdx) FaoVector[idx++] = "\">"; if (idx < MaxIdx) if (tkptr->FieldWidthName) FaoVector[idx++] = tkptr->FieldWidthName + EncodedNameDelta + 4; else FaoVector[idx++] = strlen(AnchorName) + 4; if (idx < MaxIdx) FaoVector[idx++] = AnchorName; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = AnchorNameOverflowPtr; break; case 'N' : /********/ /* name */ /********/ if (tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthName; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } if (idx < MaxIdx) if (tkptr->FieldWidthName) FaoVector[idx++] = tkptr->FieldWidthName + EncodedNameDelta; else FaoVector[idx++] = strlen(AnchorName); if (idx < MaxIdx) FaoVector[idx++] = AnchorName; if (idx < MaxIdx) FaoVector[idx++] = AnchorNameOverflowPtr; break; case 'O' : /*********/ /* owner */ /*********/ if (tkptr->DirFormatParentDirPath[0] || tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (!tkptr->DirStyleTabular) if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthOwner; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } OwnerDsc.dsc$a_pointer = Owner; OwnerDsc.dsc$w_length = sizeof(Owner)-1; sys$fao (&OwnerFaoDsc, &Length, &OwnerDsc, tkptr->SearchOds.FileQio.AtrUic); Owner[Length] = '\0'; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthOwner; if (idx < MaxIdx) FaoVector[idx++] = Owner; break; case 'P' : /**************/ /* protection */ /**************/ if (tkptr->DirFormatParentDirPath[0] || tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (!tkptr->DirStyleTabular) if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthProtection; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } FormatProtection (tkptr->SearchOds.FileQio.AtrFpro, Protection); if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthProtection; if (idx < MaxIdx) FaoVector[idx++] = Protection; break; case 'R' : /*****************/ /* revision date */ /*****************/ if (tkptr->DirFormatParentDirPath[0] || tkptr->DirFormatBlockTotals) { /* make it an empty field */ if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthRdt; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthRdt; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } /* format the revision date/time */ if (tkptr->FormatLikeVms) ctxptr = &LibDateTimeVmsContext; else ctxptr = &LibDateTimeContext; if (VMSnok (status = lib$format_date_time (&RdtDsc, &tkptr->SearchOds.FileQio.RdtTime64, ctxptr, &DateLength, 0))) { rqptr->rqResponse.ErrorTextPtr = "lib$format_date_time()"; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } Rdt[DateLength] = '\0'; if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { /* custom key as a 64 bit number */ FaoToBuffer (RdtSortTable, sizeof(RdtSortTable), 0, "!@SQ", &tkptr->SearchOds.FileQio.RdtTime64); if (idx < MaxIdx) FaoVector[idx++] = RdtSortTable; } if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthRdt; /* next parameter right justifies the field */ if (tkptr->FieldWidthRdt - DateLength > 0) { if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthRdt - DateLength; } else if (idx < MaxIdx) FaoVector[idx++] = 0; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = Rdt; break; case 'S' : /********/ /* size */ /********/ if (tkptr->DirFormatParentDirPath[0]) { /* make it an empty field */ if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthSize; if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthSize; if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = ""; break; } SizeDsc.dsc$a_pointer = Size; SizeDsc.dsc$w_length = sizeof(Size)-1; if (tkptr->FieldWidthSize >= sizeof(Size)-1) SizeDsc.dsc$w_length = sizeof(Size)-1; else SizeDsc.dsc$w_length = tkptr->FieldWidthSize; if (tkptr->DirFormatBlockTotals) { if (tkptr->LayoutPtr == Config.cfDir.DefaultLayout || tkptr->LayoutPtr == DirDefaultLayout) sptr = ""; else for (sptr = tkptr->LayoutPtr; *sptr && TOUP(*sptr) != 'S'; sptr++); if (sptr[0] && sptr[1] == LAYOUT_PARAMETER) { unsigned long BlocksUsed; BlocksUsed = tkptr->TotalUsedBlocks; status = lib$emul (&FiveTwelve, &BlocksUsed, &AddendZero, &QuadBytes); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); Length = DirFormatSize (&QuadBytes, sptr+2, tkptr->SizeKilo, &SizeDsc); } else sys$fao (&BlocksFaoDsc, &Length, &SizeDsc, tkptr->TotalUsedBlocks, tkptr->TotalAllocatedBlocks); } else { AllocatedVbn = ((tkptr->SearchOds.FileQio.RecAttr.fat$l_hiblk & 0xffff) << 16) | ((tkptr->SearchOds.FileQio.RecAttr.fat$l_hiblk & 0xffff0000) >> 16); EndOfFileVbn = ((tkptr->SearchOds.FileQio.RecAttr.fat$l_efblk & 0xffff) << 16) | ((tkptr->SearchOds.FileQio.RecAttr.fat$l_efblk & 0xffff0000) >> 16); if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "AllocatedVbn:!UL EndOfFileVbn:!UL FirstFreeByte:!UL", AllocatedVbn, EndOfFileVbn, tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte); if (EndOfFileVbn <= 1) { QuadBytes[0] = tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte; QuadBytes[1] = 0; } else { unsigned long BlocksUsed, FFbyte; BlocksUsed = EndOfFileVbn - 1; FFbyte = tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte; status = lib$emul (&FiveTwelve, &BlocksUsed, &FFbyte, &QuadBytes); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } if (tkptr->FormatLikeVms && (tkptr->LayoutPtr == Config.cfDir.DefaultLayout || tkptr->LayoutPtr == DirDefaultLayout)) sys$fao (&BlocksFaoDsc, &Length, &SizeDsc, EndOfFileVbn, AllocatedVbn); else if (cptr[1] == LAYOUT_PARAMETER) Length = DirFormatSize (&QuadBytes, cptr+2, tkptr->SizeKilo, &SizeDsc); else if (tkptr->FormatLikeVms) sys$fao (&BlocksFaoDsc, &Length, &SizeDsc, EndOfFileVbn, AllocatedVbn); else Length = DirFormatSize (&QuadBytes, NULL, tkptr->SizeKilo, &SizeDsc); tkptr->TotalAllocatedBlocks += AllocatedVbn; tkptr->TotalUsedBlocks += EndOfFileVbn; } Size[Length] = '\0'; if (tkptr->DirStyle == MAPURL_DIR_STYLE_SORT || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) { /* custom key as 64 bit number */ FaoToBuffer (SizeSortTable, sizeof(SizeSortTable), 0, "!@SQ", &QuadBytes); if (idx < MaxIdx) FaoVector[idx++] = SizeSortTable; } if (tkptr->DirStyleTabular) { if (idx < MaxIdx) FaoVector[idx++] = Length; if (idx < MaxIdx) FaoVector[idx++] = 0; } else { if (idx < MaxIdx) FaoVector[idx++] = tkptr->FieldWidthSize; /* next parameter right justifies the field */ if (idx < MaxIdx) if (tkptr->FieldWidthSize - Length > 0) FaoVector[idx++] = tkptr->FieldWidthSize - Length; else FaoVector[idx++] = 0; } if (idx < MaxIdx) FaoVector[idx++] = ""; if (idx < MaxIdx) FaoVector[idx++] = Size; break; } if (cptr[1] == LAYOUT_PARAMETER) cptr += 2; cptr++; if (idx >= MaxIdx) { /* should be enough for all but a deliberate formatting hack! */ rqptr->rqResponse.HttpStatus = 501; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_DIR_LAYOUT), FI_LI); DirEnd (rqptr); return; } } if (idx < MaxIdx) if (tkptr->DirStyleTabular) FaoVector[idx++] = "\n"; else FaoVector[idx++] = "\n"; if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "!UL !AZ", idx, tkptr->LayoutFaoPtr); /*********************/ /* format and output */ /*********************/ status = FaolToNet (rqptr, tkptr->LayoutFaoPtr, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = tkptr->DirPath; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->LayoutFaoPtr; ErrorVmsStatus (rqptr, status, FI_LI); DirEnd (rqptr); return; } /* empty any file-internal description previously generated */ tkptr->Description[0] = '\0'; NetWritePartFlush (rqptr, tkptr->DirFormatAstFunction); } /*****************************************************************************/ /* Write a string into the supplied descriptor containing the size specified by the 'QuadBytesPtr' parameter and the format string 'FormatCharPtr'. It is recognised the approach truncates rather than rounds the value but in context this is close enough for jazz. 'SizeKilo' will be either 1024 (default) or 1000. Return the number of characters written. This function does not null-terminate the string! */ int DirFormatSize ( unsigned long *QuadBytesPtr, char *FormatPtr, int SizeKilo, struct dsc$descriptor *SizeDscPtr ) { static $DESCRIPTOR (StatusFaoDsc, "%X!8XL"); static $DESCRIPTOR (OverflowFaoDsc, "!256**"); int ccnt, status; unsigned short Length; float fvalue, fgiga, fkilo, fmega; char ch; char *cptr, *sptr, *zptr; char buf [64]; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD_DIR)) WatchThis (WATCHALL, WATCH_MOD_DIR, "DirFormatSize() \"!AZ\" !UL !&,@SQ", FormatPtr, SizeKilo, QuadBytesPtr); Length = 0; status = SS$_NORMAL; fvalue = ((float)QuadBytesPtr[1] * 4294967296.0) + (float)QuadBytesPtr[0]; /* span over any leading kilo specification */ if (!FormatPtr) FormatPtr = ""; if (isdigit(*FormatPtr)) if (*++FormatPtr == LAYOUT_PARAMETER) FormatPtr++; cptr = buf; zptr = (sptr = SizeDscPtr->dsc$a_pointer) + SizeDscPtr->dsc$w_length; switch (TOUP(*FormatPtr)) { case 'B' : status = FaoToBuffer (buf, sizeof(buf), &Length, "!&,@SQ", QuadBytesPtr); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (*cptr) status = SS$_BUFFEROVF; break; case 'K' : fkilo = (float)SizeKilo; sprintf (cptr, "%f", fvalue / fkilo); while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; for (ccnt = 4; ccnt-- && *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr < zptr) *sptr++ = 'K'; else status = SS$_BUFFEROVF; break; case 'M' : fkilo = (float)SizeKilo; fmega = fkilo * fkilo; sprintf (cptr, "%f", fvalue / fmega); while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; for (ccnt = 7; ccnt-- && *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr < zptr) *sptr++ = 'M'; else status = SS$_BUFFEROVF; break; case 'V' : if (fvalue > 0.0) sprintf (cptr, "%f", (fvalue / 512.0) + 1.0); else sprintf (cptr, "%f", fvalue); while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; if (*cptr) status = SS$_BUFFEROVF; break; case 'D' : case 'F' : default : fkilo = (float)SizeKilo; fmega = fkilo * fkilo; fgiga = fmega * fkilo; if (fvalue >= fgiga) { sprintf (cptr, "%f", fvalue / fgiga); ch = 'G'; } else if (fvalue >= fmega) { sprintf (cptr, "%f", fvalue / fmega); ch = 'M'; } else if (fvalue >= fkilo) { sprintf (cptr, "%f", fvalue / fkilo); ch = 'K'; } else { sprintf (cptr, "%f", fvalue); ch = '\0'; } while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; if (fvalue >= fkilo) for (ccnt = 2; ccnt-- && *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr < zptr) { if (ch) *sptr++ = ch; } else status = SS$_BUFFEROVF; } /* fallback, first to Mbytes then to Gbytes */ if (status == SS$_BUFFEROVF) { status = SS$_NORMAL; fkilo = (float)SizeKilo; fmega = fkilo * fkilo; zptr = (sptr = SizeDscPtr->dsc$a_pointer) + SizeDscPtr->dsc$w_length; sprintf (cptr = buf, "%f", fvalue / fmega); while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; while (*cptr && sptr < zptr-1) *sptr++ = *cptr++; if (*(sptr-1) == '.') sptr--; if (sptr < zptr) *sptr++ = 'M'; else { fgiga = fmega * fkilo; zptr = (sptr = SizeDscPtr->dsc$a_pointer) + SizeDscPtr->dsc$w_length; sprintf (cptr = buf, "%f", fvalue / fgiga); while (*cptr && *cptr != '.' && sptr < zptr) *sptr++ = *cptr++; while (*cptr && sptr < zptr-1) *sptr++ = *cptr++; if (*(sptr-1) == '.') sptr--; if (sptr < zptr) *sptr++ = 'G'; else status = SS$_BUFFEROVF; } } /* this function does not null-terminate the string! */ Length = sptr - SizeDscPtr->dsc$a_pointer; if (VMSnok(status) && status != SS$_BUFFEROVF) sys$fao (&StatusFaoDsc, &Length, SizeDscPtr, status); if (status == SS$_BUFFEROVF) sys$fao (&OverflowFaoDsc, &Length, SizeDscPtr); return (Length); } /*****************************************************************************/ /* Process a string of directory directives. The directives can be '&' separated (query string) or '\n' separated (.WWW_WASD) file based. */ DirDirectString ( REQUEST_STRUCT *rqptr, char *DirectString ) { BOOL LocalDirect; int WwwWasd; char *aptr, *cptr, *sptr, *zptr; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHING (rqptr, WATCH_RESPONSE)) WatchData (DirectString, strlen(DirectString)); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; /* override is always false unless the current source allows it */ tkptr->QueryOverride = false; LocalDirect = false; WwwWasd = 0; cptr = DirectString; while (*cptr) { while (*cptr && (*cptr == '&' || *cptr == ' ' || *cptr == '\n')) { if (*cptr == '\n') WwwWasd++; cptr++; } if (!*cptr) break; if (*cptr == '#') { /* .WWW_WASD file can contain comments */ while (*cptr && *cptr != '\n') cptr++; WwwWasd++; continue; } if (TOLO(*cptr) == 'a' && strsame (cptr, "autoscript=", 11)) { cptr += 11; /* if "false", "no" or "0" then turn off auto-scripting */ if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') tkptr->AutoScriptEnabled = false; else tkptr->AutoScriptEnabled = true; } else if (TOLO(*cptr) == 'd' && strsame (cptr, "delimit=", 8)) { cptr += 8; switch (TOLO(*cptr)) { case 'h' : tkptr->DirDelimit = MAPURL_DIR_DELIMIT_HEADER; break; case 'f' : tkptr->DirDelimit = MAPURL_DIR_DELIMIT_FOOTER; break; case 'n' : tkptr->DirDelimit = MAPURL_DIR_DELIMIT_NONE; break; default : tkptr->DirDelimit = MAPURL_DIR_DELIMIT_BOTH; } } else /* experience shows both make it easier! */ if (TOLO(*cptr) == 'e' && (strsame (cptr, "expire=", 7) || strsame (cptr, "expired=", 8))) { if (cptr[7] == '=') cptr += 8; else cptr += 7; /* "true", "yes", "1", "false", "no" or "0" */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') rqptr->rqResponse.PreExpired = true; else if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') rqptr->rqResponse.PreExpired = false; } else if (TOLO(*cptr) == 'f' && strsame (cptr, "font=", 5)) { cptr += 5; if (strsame (cptr, "inherit", 7)) tkptr->DirFont = MAPURL_DIR_FONT_INHERIT; else if (strsame (cptr, "monospace", 8)) tkptr->DirFont = MAPURL_DIR_FONT_MONOSPACE; } else if (TOLO(*cptr) == 'i' && strsame (cptr, "ilink=", 6)) { cptr += 6; /* if "false", "no" or "0" then icon is not a plain-text link */ if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') tkptr->IconLinkEnabled = false; else tkptr->IconLinkEnabled = true; } else if (TOLO(*cptr) == 'l' && strsame (cptr, "layout=", 7)) { cptr += 7; for (sptr = cptr; *sptr && *sptr != '&' && *sptr != '\n'; sptr++); tkptr->LayoutPtr = sptr = VmGetHeap (rqptr, sptr-cptr+1); while (*cptr && *cptr != '&' && *cptr != '\n') *sptr++ = *cptr++; } else if (TOLO(*cptr) == 'l' && strsame (cptr, "local=", 6)) { cptr += 6; /* if "false", "no" or "0" then turn off auto-scripting */ if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') LocalDirect = false; else LocalDirect = true; } else if (TOLO(*cptr) == 'n' && strsame (cptr, "notype=", 7)) { cptr += 7; /* if "true", "yes" or "1" then do not display parent directory */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->ShowNoType = true; else tkptr->ShowNoType = false; } else if (TOLO(*cptr) == 'n' && strsame (cptr, "nop=", 4)) { cptr += 4; /* if "true", "yes" or "1" then do not display parent directory */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->AsIfNopFound = true; else tkptr->AsIfNopFound = false; } else if (TOLO(*cptr) == 'n' && strsame (cptr, "nops=", 5)) { cptr += 5; /* if "true", "yes" or "1" don't display parent or sub directory */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->AsIfNopFound = tkptr->AsIfNosFound = true; else tkptr->AsIfNopFound = tkptr->AsIfNosFound = false; } else if (TOLO(*cptr) == 'n' && strsame (cptr, "nos=", 4)) { cptr += 4; /* if "true", "yes" or "1" then do not display sub directory */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->AsIfNosFound = true; else tkptr->AsIfNosFound = false; } else if (TOLO(*cptr) == 'o' && strsame (cptr, "override=", 9)) { cptr += 9; /* if "true", "yes" or "1" then allow query string to override */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->QueryOverride = true; else tkptr->QueryOverride = false; } else if (TOLO(*cptr) == 'q' && strsame (cptr, "query=", 6)) { cptr += 6; /* this directive is always terminated only by end-of-line */ for (sptr = cptr; *sptr && *sptr != '\n'; sptr++); tkptr->QueryStringPtr = sptr = VmGetHeap (rqptr, sptr-cptr+1); while (*cptr && *cptr != '\n') *sptr++ = *cptr++; } else if (TOLO(*cptr) == 'r' && strsame (cptr, "readme=", 7)) { cptr += 7; /* if "false", "no" or "0" then do not display any readme */ if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') tkptr->IncludeAnyReadme = false; else tkptr->IncludeAnyReadme = true; } else if (TOLO(*cptr) == 's' && strsame (cptr, "script=", 7)) { cptr += 7; zptr = (sptr = tkptr->ScriptName) + sizeof(tkptr->ScriptName)-1; if (*cptr != '/') *sptr++ = '/'; while (*cptr && *cptr != '&' && *cptr != '\n' && sptr < zptr) { if (*cptr != '&' && *cptr != '+') *sptr++ = *cptr; cptr++; } *sptr = '\0'; } else if (TOLO(*cptr) == 's' && strsame (cptr, "sort=", 5)) { cptr += 5; tkptr->DirSort[0] = TOUP(*cptr++); if (*cptr == '+' || *cptr == '-') tkptr->DirSort[1] = *cptr; else tkptr->DirSort[1] = '\0'; /* style is implicit! */ if (tkptr->DirStyle != MAPURL_DIR_STYLE_SORT2) tkptr->DirStyle = MAPURL_DIR_STYLE_SORT; } else if (TOLO(*cptr) == 's' && strsame (cptr, "style=", 6)) { cptr += 6; if (strsame (cptr, "sort2", 5)) tkptr->DirStyle = MAPURL_DIR_STYLE_SORT2; else if (strsame (cptr, "sort", 4)) tkptr->DirStyle = MAPURL_DIR_STYLE_SORT; else if (strsame (cptr, "anchor2", 7)) tkptr->DirStyle = MAPURL_DIR_STYLE_ANCHOR2; else if (strsame (cptr, "anchor", 6)) tkptr->DirStyle = MAPURL_DIR_STYLE_ANCHOR; else if (strsame (cptr, "table2", 6)) tkptr->DirStyle = MAPURL_DIR_STYLE_TABLE2; else if (strsame (cptr, "table", 5)) tkptr->DirStyle = MAPURL_DIR_STYLE_TABLE; else if (strsame (cptr, "htdir2", 6)) tkptr->DirStyle = MAPURL_DIR_STYLE_HTDIR2; else if (strsame (cptr, "htdir", 5)) tkptr->DirStyle = MAPURL_DIR_STYLE_HTDIR; else if (strsame (cptr, "original2", 9)) tkptr->DirStyle = MAPURL_DIR_STYLE_ORIGINAL2; else if (strsame (cptr, "original", 8)) tkptr->DirStyle = MAPURL_DIR_STYLE_ORIGINAL; else if (strsame (cptr, "default2", 8)) tkptr->DirStyle = MAPURL_DIR_STYLE_DEFAULT2; else if (strsame (cptr, "default", 7)) tkptr->DirStyle = MAPURL_DIR_STYLE_DEFAULT; } else if (TOLO(*cptr) == 't' && strsame (cptr, "target=", 7)) { cptr += 7; zptr = (sptr = tkptr->LinkTarget) + sizeof(tkptr->LinkTarget)-2; for (aptr = " target=\""; *aptr; *sptr++ = *aptr++); while (*cptr && *cptr != '&' && *cptr != '\n' && sptr < zptr) { if (*cptr != '\"') *sptr++ = *cptr; cptr++; } *sptr++ = '\"'; *sptr = '\0'; } else if (TOLO(*cptr) == 't' && strsame (cptr, "these=", 6)) { cptr += 6; for (sptr = cptr; *sptr && *sptr != '&' && *sptr != '\n'; sptr++); tkptr->ThesePtr = sptr = VmGetHeap (rqptr, sptr-cptr+2); /* null-separated series of strings terminated by empty string */ while (*cptr && *cptr != '&' && *cptr != '\n') { if (*cptr == ',') *sptr++ = '\0'; else *sptr++ = *cptr; cptr++; } } else if (TOLO(*cptr) == 't' && strsame (cptr, "title=", 6)) { cptr += 6; if (strsame (cptr, "default", 7)) tkptr->DirTitle = MAPURL_DIR_TITLE_DEFAULT; else if (strsame (cptr, "owner", 5)) tkptr->DirTitle = MAPURL_DIR_TITLE_OWNER; else if (strsame (cptr, "remote", 6)) tkptr->DirTitle = MAPURL_DIR_TITLE_REMOTE; else if (*cptr == '0') tkptr->DirTitle = MAPURL_DIR_TITLE_NONE; else if (isdigit(*cptr)) tkptr->DirTitle = atol(cptr); } else if (TOLO(*cptr) == 't' && strsame (cptr, "type=", 5)) { cptr += 5; for (sptr = cptr; *sptr && *sptr != '&' && *sptr != '\n'; sptr++); tkptr->QueryContentTypePtr = sptr = VmGetHeap (rqptr, sptr-cptr+1); while (*cptr && *cptr != '&' && *cptr != '\n') *sptr++ = *cptr++; } else if (TOLO(*cptr) == 'u' && strsame (cptr, "upper=", 6)) { cptr += 6; /* if "true", "yes" or "1" then force to upper case */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') tkptr->ShowUpperCase = true; else tkptr->ShowUpperCase = false; } else if (TOLO(*cptr) == 'v' && strsame (cptr, "versions=", 9)) { cptr += 9; if (*cptr == '*') tkptr->VersionsOf = 65536; else tkptr->VersionsOf = atoi(cptr); } else if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "ERROR:!AZ", cptr); while (*cptr && *cptr != '&' && *cptr != '\n') cptr++; } if (!WwwWasd && !LocalDirect) { /* propagate URI query string directive(s) */ tkptr->QueryStringPtr = sptr = VmGetHeap (rqptr, cptr-DirectString+1); cptr = DirectString; while (*cptr && *cptr != '\n') *sptr++ = *cptr++; } } /*****************************************************************************/ /* Open, read, and process the contents of the .WWW_WASD file. */ int DirWwwWasd (REQUEST_STRUCT *rqptr) { int status, SizeInBytes; char *sptr; char ReadBuffer [2048]; DIR_TASK *tkptr; ODS_STRUCT OdsStruct; ODS_STRUCT *odsptr = &OdsStruct; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirWwwWasd()"); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; for (sptr = tkptr->DirSpec; *sptr; sptr++); while (sptr > tkptr->DirSpec && (*sptr != ']' || *(sptr-1) == '^]')) sptr--; if (*sptr == ']') sptr++; if (sptr - tkptr->DirSpec <= 0) return (SS$_BUGCHECK); OdsStructInit (&OdsStruct, true); odsptr->Fab = cc$rms_fab; odsptr->Fab.fab$b_fac = FAB$M_GET; odsptr->Fab.fab$b_shr = FAB$M_SHRGET; odsptr->Fab.fab$l_fop &= ~FAB$M_ASY; #ifdef ODS_EXTENDED if (OdsExtended) { odsptr->Fab.fab$l_fna = odsptr->Fab.fab$l_dna =-1; odsptr->Fab.fab$b_fns = odsptr->Fab.fab$b_dns = 0; odsptr->Fab.fab$l_nam = &odsptr->Naml; odsptr->NamlInUse = true; ENAMEL_RMS_NAML(odsptr->Naml) odsptr->Naml.naml$l_long_defname = tkptr->DirSpec; odsptr->Naml.naml$l_long_defname_size = sptr - tkptr->DirSpec; odsptr->Naml.naml$l_long_filename = DirWasdFileName; odsptr->Naml.naml$l_long_filename_size = sizeof(DirWasdFileName)-1; odsptr->Naml.naml$l_long_expand = odsptr->ExpFileName; odsptr->Naml.naml$l_long_expand_alloc = sizeof(odsptr->ExpFileName)-1; } else #endif /* ODS_EXTENDED */ { odsptr->Fab.fab$l_dna = tkptr->DirSpec; odsptr->Fab.fab$b_dns = sptr - tkptr->DirSpec; odsptr->Fab.fab$l_fna = DirWasdFileName; odsptr->Fab.fab$b_fns = sizeof(DirWasdFileName)-1; odsptr->NamlInUse = false; odsptr->Nam = cc$rms_nam; odsptr->Nam.nam$l_esa = odsptr->ExpFileName; odsptr->Nam.nam$b_ess = ODS2_MAX_FILE_NAME_LENGTH; } /* ensure we can read this directory listing "control" file */ sys$setprv (1, &SysPrvMask, 0, 0); status = sys$open (&odsptr->Fab, 0, 0); sys$setprv (0, &SysPrvMask, 0, 0); if (VMSnok (status) || VMSnok (status = odsptr->Fab.fab$l_sts)) { if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "!#AZ!AZ !AZ %X!8XL", sptr - tkptr->DirSpec, tkptr->DirSpec, DirWasdFileName, odsptr->ExpFileName, status); return (status); } /* record access block */ odsptr->Rab = cc$rms_rab; odsptr->Rab.rab$l_fab = &odsptr->Fab; /* read ahead performance option, all synchronous */ odsptr->Rab.rab$l_rop = RAB$M_RAH; odsptr->Rab.rab$l_rop &= ~FAB$M_ASY; status = sys$connect (&odsptr->Rab, 0, 0); if (VMSnok (status) || VMSnok (status = odsptr->Rab.rab$l_sts)) { sys$close (&odsptr->Fab, 0, 0); return (status); } sptr = ReadBuffer; SizeInBytes = sizeof(ReadBuffer)-1; for (;;) { odsptr->Rab.rab$l_ubf = sptr; odsptr->Rab.rab$w_usz = SizeInBytes; status = sys$get (&odsptr->Rab, 0, 0); if (VMSnok (status)) break; sptr[odsptr->Rab.rab$w_rsz++] = '\n'; sptr += odsptr->Rab.rab$w_rsz; SizeInBytes -= odsptr->Rab.rab$w_rsz; } *sptr = '\0'; sys$close (&odsptr->Fab, 0, 0); if (status == RMS$_EOF) status = SS$_NORMAL; if (VMSok(status)) DirDirectString (rqptr, ReadBuffer); return (status); } /*****************************************************************************/ /* These comments apply equally to DirReadMeBottom() below. Attempt to send one of possible multiple files ("README.", et. al.) in the specified directory. Then, provided there was not serious error with the send, execute the function specified by the address in 'NextTaskFunction'. The file can be HTML or plain-text. With plain-text the contents will be encapsulated. */ DirReadMeTop (REQUEST_STRUCT *rqptr) { int status; char *cptr, *rptr, *sptr, *TypePtr; char FileName [ODS_MAX_FILE_NAME_LENGTH+1]; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirReadMeTop() !&F", &DirReadMeTop); RequestDclAst (rqptr, DirReadMeTop, NULL); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; while (*(rptr = ConfigReadMeFile(tkptr->ReadMeFileIndex++))) { sptr = FileName; for (cptr = tkptr->DirectoryPart; *cptr; *sptr++ = *cptr++); TypePtr = NULL; for ( /* 'rptr' initialized above! */ ; *rptr; *sptr++ = *rptr++) if (*rptr == '.') TypePtr = rptr; *sptr = '\0'; if (!TypePtr) TypePtr = rptr; cptr = ConfigContentType (&tkptr->ContentInfo, TypePtr); /* ignore any non-text types! */ if (!ConfigSameContentType (cptr, "text/", 5)) continue; if (ConfigSameContentType (cptr, ConfigContentTypeSsi, -1)) { FileSetContentHandler (rqptr, &SsiBegin, SsiSizeMax); FileSetCacheAllowed (rqptr, true); FileBegin (rqptr, &DirHeading, &DirReadMeTop, NULL, FileName, cptr); } else { if (ConfigSameContentType (cptr, "text/plain", -1)) FileSetPreTag (rqptr, true); FileSetCacheAllowed (rqptr, true); FileBegin (rqptr, &DirHeading, &DirReadMeTop, NULL, FileName, cptr); } return; } DirHeading (rqptr); } /*****************************************************************************/ /* See comment in DirReadMeTop() above. */ DirReadMeBottom (REQUEST_STRUCT *rqptr) { int status; char *cptr, *rptr, *sptr, *TypePtr; char FileName [ODS_MAX_FILE_NAME_LENGTH+1]; DIR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_DIR)) WatchThis (WATCHITM(rqptr), WATCH_MOD_DIR, "DirReadMeBottom() !&F", DirReadMeBottom); RequestDclAst (rqptr, DirReadMeBottom, NULL); /* get the pointer to the task structure */ tkptr = rqptr->DirTaskPtr; while (*(rptr = ConfigReadMeFile(tkptr->ReadMeFileIndex++))) { sptr = FileName; for (cptr = tkptr->DirectoryPart; *cptr; *sptr++ = *cptr++); TypePtr = NULL; for ( /* 'rptr' initialized above! */ ; *rptr; *sptr++ = *rptr++) if (*rptr == '.') TypePtr = rptr; *sptr = '\0'; if (!TypePtr) TypePtr = rptr; cptr = ConfigContentType (&tkptr->ContentInfo, TypePtr); /* ignore any non-text types! */ if (!ConfigSameContentType (cptr, "text/", 5)) continue; if (ConfigSameContentType (cptr, ConfigContentTypeSsi, -1)) { FileSetContentHandler (rqptr, &SsiBegin, SsiSizeMax); FileSetCacheAllowed (rqptr, true); FileBegin (rqptr, &DirHeading, &DirReadMeBottom, NULL, FileName, cptr); } else { if (ConfigSameContentType (cptr, "text/plain", -1)) FileSetPreTag (rqptr, true); FileSetCacheAllowed (rqptr, true); FileBegin (rqptr, &DirHeading, &DirReadMeBottom, NULL, FileName, cptr); } return; } DirEnd (rqptr); } /*****************************************************************************/
"; else { if (TOUP(*lptr) == 'C') aptr = ""; else if (TOUP(*lptr) == 'R') aptr = ""; else aptr = ""; } while (*aptr && sptr < zptr) *sptr++ = *aptr++; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); } else { /* flush the column heading right using spaces */ if (cnt) cnt -= size; while (cnt-- && sptr < zptr) *sptr++ = ' '; for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); if (tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); } while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); if (tkptr->DirStyleTabular) for (aptr = ""; else { switch (TOUP(*lptr)) { case 'D' : aptr = ""; break; case 'L' : aptr = ""; break; case 'N' : aptr = ""; break; case 'O' : aptr = ""; break; case 'P' : aptr = ""; } } while (*aptr && sptr < zptr) *sptr++ = *aptr++; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); } else { for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); if (tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); } while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (tkptr->DirStyle == MAPURL_DIR_STYLE_TABLE2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ANCHOR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_SORT2 || tkptr->DirStyle == MAPURL_DIR_STYLE_HTDIR2 || tkptr->DirStyle == MAPURL_DIR_STYLE_ORIGINAL2) for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); for (aptr = ""; *aptr && sptr < zptr; *sptr++ = *aptr++); if (tkptr->DirStyleTabular) for (aptr = "▼▲
!#!#!AZ!AZ!AZ!AZ!AZ!AZ!#!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!#!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!AZ!#!#!AZ