/* This file was derived from the libwww code, version 2.15, from CERN. A number of modifications have been made by Spyglass. Copyright 1995 Spyglass, Inc. All Rights Reserved eric@spyglass.com */ /***************************************************************************** Included Files *****************************************************************************/ #include "all.h" /***************************************************************************** Constants and Structures *****************************************************************************/ #define PUTS(s) (*target->isa->put_string)(target, s) #define START(e) (*target->isa->start_element)(target, e, 0, 0) #define END(e) (*target->isa->end_element)(target, e) struct _HTStructured { CONST HTStructuredClass *isa; /* ... */ }; struct _HTStream { CONST HTStreamClass *isa; /* ... */ }; /***************************************************************************** More Constants *****************************************************************************/ #define STATE_FILE_STREAMINIT (STATE_OTHER + 1) #define STATE_FILE_COPYING (STATE_OTHER + 2) #ifdef FEATURE_LOCAL_DIRECTORY int HTLoadDir (struct Mwin *tw, HTRequest *request, char *pszLocalname); #endif /***************************************************************************** Private prototypes *****************************************************************************/ #ifdef MAC extern struct Viewer_Info * PREF_GetViewerInfoBy_FileType (OSType reqType); #endif static int HTLoadFile_TryFTP (struct Mwin *tw, struct Data_LoadFile* pData, char *addr); int HTLoadFile_Async_SetFileInfo (struct Mwin* tw, struct Data_LoadFile* pData, char* pszURL, char** pszLocalname); int HTLoadFile_Async_Init (struct Mwin *tw, void **ppInfo, int openType); int HTLoadFile_Async_File_Copy (struct Mwin *tw, struct Data_LoadFile *pData); int HTLoadFile_Async_File_StreamInit (struct Mwin *tw, struct Data_LoadFile *pData); int HTLoadFile_Async_Abort (struct Mwin *tw, struct Data_LoadFile *pData); /***************************************************************************** Code *****************************************************************************/ /***************************************************************************** HTFileFormat *****************************************************************************/ PUBLIC HTFormat HTFileFormat(CONST char *filename, HTAtom *pencoding, HTAtom *planguage) { char *p; CONST char *pslash; if (planguage) { *planguage = 0; /* note that this isn't supported at all yet */ } pslash = strrchr(filename, '/'); if (pslash) { pslash++; /* the filename passed in was a URL. pslash now points to the basename */ } else { pslash = filename; } p = strrchr(pslash, '.'); /* In the case of an HTTP/0.9 server, we have to assume that the root page (e.g. "http://www.foo.com/") is HTML even though it doesn't have a filename, let alone an extension. */ #ifndef _GIBRALTAR // // Without any extention at all, we assume html // if (p || *pslash == '\0') #endif // _GIBRALTAR { ////////////////////////////////////////////////////////////////////// // // ((q - szSuff) < 32) below causes the NULL char // to be written one past the boundary!!!! // //char szSuff[32]; char szSuff[SUFF_BUF_LEN + 1]; char *q; struct Viewer_Info *pvi = NULL; if (p) { szSuff[0] = 0; p++; /* skip the dot */ q = szSuff; while (*p && (*p != '/') && ((q - szSuff) < SUFF_BUF_LEN)) { *q++ = *p++; } *q = 0; XX_DMsg(DBG_WWW, ("HTFileFormat: Looking for extension %s... ", szSuff)); pvi = PREF_GetViewerInfoBy_Suffix(szSuff); } else { pvi = PREF_GetViewerInfoBy_Suffix("html"); } if (pvi) { XX_DMsg(DBG_WWW, ("found! MIME=%s\n", HTAtom_name(pvi->atomMIMEType))); if (pencoding) *pencoding = pvi->atomEncoding; return pvi->atomMIMEType; } XX_DMsg(DBG_WWW, ("Suffix not found.\n")); if (pencoding) *pencoding = 0; return WWW_BINARY; } #ifndef _GIBRALTAR else { if (pencoding) *pencoding = HTAtom_for("8bit"); return WWW_PLAINTEXT; } #endif // _GIBRALTAR } /***************************************************************************** HTContentToEncoding *****************************************************************************/ PUBLIC HTAtom HTContentToEncoding(HTAtom content_type) { struct Viewer_Info *pvi; pvi = PREF_GetViewerInfoBy_MIMEAtom(content_type); if (pvi) { return pvi->atomEncoding; } else { return HTAtom_for("binary"); } } /***************************************************************************** HTFileSuffix *****************************************************************************/ PUBLIC CONST char *HTFileSuffix(HTAtom rep) { struct Viewer_Info *pvi; static char szSuff[SUFF_BUF_LEN + 1]; int i; char *p; pvi = PREF_GetViewerInfoBy_MIMEAtom(rep); if (pvi && pvi->nSuffixes) { for (i=0; inSuffixes; i++) { PREF_GetSuffix(szSuff, pvi, i); p = szSuff; if (*p == '.') { p++; } #ifdef UNIX if (strlen(p) >= 4) /* we prefer our suffixes long */ #else if (strlen(p) <= 3) #endif { return szSuff; } } /* A suffix could not be found. Just return the first one */ if (0 > PREF_GetSuffix(szSuff, pvi, 0)) return NULL; return szSuff; } else { return NULL; } } /***************************************************************************** HTLocalName *****************************************************************************/ /* Convert filenames between local and WWW formats ** ----------------------------------------------- ** Make up a suitable name for saving the node in ** ** E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch ** $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx ** ** On exit, ** returns a GTR_MALLOC'ed string which must be freed by the caller. */ PUBLIC char *HTLocalName(CONST char *name) { char *host = HTParse(name, "", PARSE_HOST); int iLoc; #ifdef WIN32 int iSlash; #endif if (!host || !*host || (0 == strcasecomp(host, HTHostName())) || (0 == strcasecomp(host, "localhost"))) { char *path; if (host) { GTR_FREE(host); } path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); #ifdef MAC #define SLASH ':' /* Convert slashes to colons before we unescape */ for (iLoc = 0; path[iLoc]; iLoc++) { if (path[iLoc] == '/') path[iLoc] = SLASH; } #endif HTUnEscape (path); /* Interpret % signs */ /* BEGIN NCSA Copy-Paste */ #ifdef WIN32 #define SLASH '\\' if ( (path[0] == '/') && (strchr(path, ':') || strchr(path, '|')) ) { char *shuffle = path; // We have drive spec - strip leading slash while (*shuffle && (*(shuffle + 1))) { *shuffle = *(shuffle + 1); shuffle++; } *shuffle = 0; } iSlash = 0; for (iLoc = 0; iLoc < strlen(path); iLoc++) { if (path[iLoc] == '|') path[iLoc] = ':'; else if (path[iLoc] == '/') { path[iLoc] = SLASH; iSlash++; } else if (path[iLoc] == SLASH) iSlash++; } if ((path[strlen(path) - 1] == SLASH) && (iSlash > 1)) path[strlen(path) - 1] = 0; #endif #ifdef MAC /* Remove initial colon. Note that this could cause a problem with a relative path name, if a person were so foolish as to enter one. */ if (path[0] == ':') memmove(path, path + 1, strlen(path)); #endif /* END NCSA Copy-Paste */ XX_DMsg(DBG_WWW, ("Node `%s' means path `%s'\n", name, path)); return (path); } else { GTR_FREE(host); return NULL; } } // // Adjust local file name -- if it's relative to the document // it's embedded in (and that doc is a 'file:' itself), // adjust it to be an absolute reference // // Note: this may return a newly allocate a new string and free the old one // so the input string must have been malloc'ed // static char *AdjustLocalNameIfRelative( struct Mwin *tw, char *localname ) { char *retval = localname; if ( tw && tw->w3doc && tw->w3doc->szActualURL ) { char *p = tw->w3doc->szActualURL; if ( _strnicmp( p, "file:", 5 ) == 0 ) { char *s; p += 5; // move past 'file:' if ( s = strrchr( p, '\\' ) ) { s++; // move past the last slash if ( localname[0] && localname[0] != '\\' && localname[1] != ':' ) // is it relative? { char *newlocalname = (char *) GTR_MALLOC( (s-p) + strlen(localname) + 1); if ( newlocalname ) { // // Build absolute local name // strncpy( newlocalname, p, (s-p) ); strcpy( newlocalname + (s-p), localname ); GTR_FREE( localname ); retval = newlocalname; } } } } } return retval; } /***************************************************************************** HTDirEntry Output one directory entry *****************************************************************************/ PUBLIC void HTDirEntry(HTStructured * target, CONST char *tail, CONST char *entry, BOOL isdir) { char *relative; char *escaped = HTEscape(entry, URL_XPALPHAS, '\0'); char buf[_MAX_PATH+5]; /* If empty tail, gives absolute ref below */ relative = (char *) GTR_MALLOC(strlen(tail) + strlen(escaped) + 2); if (relative) { sprintf(relative, "%s/%s", tail, escaped); HTStartAnchor(target, NULL, relative); GTR_FREE(relative); } else { ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL); } GTR_FREE(escaped); if (isdir) { sprintf (buf, "< %s > ", entry); PUTS(buf); } else PUTS(entry); END(HTML_A); } /***************************************************************************** HTDirTitles Output parent directory entry This gives the TITLE and H1 header, and also a link to the parent directory if appropriate. *****************************************************************************/ PUBLIC void HTDirTitles(HTStructured * target, CONST char *szURL, BOOL bLocal) { char *path; char *current; if (bLocal) path = GTR_strdup (szURL); else path = HTParse(szURL, "", PARSE_PATH + PARSE_PUNCTUATION); current = strrchr(path, '/'); /* last part or "" */ if (current) { char *printable = NULL; printable = GTR_strdup((current+1)); if (!bLocal) HTUnEscape(printable); START(HTML_TITLE); if (*printable) { PUTS(printable); //PUTS(" directory"); PUTS(GTR_GetString(SID_INF_DIRECTORY)); } else { /* PUTS("Welcome"); */ //PUTS("Top Level Directory"); PUTS(GTR_GetString(SID_INF_TOP_LEVEL_DIRECTORY)); } END(HTML_TITLE); START(HTML_H1); //PUTS(*printable ? printable : "Top Level"); PUTS(*printable ? printable : GTR_GetString(SID_INF_TOP_LEVEL)); END(HTML_H1); GTR_FREE(printable); } /* Make link back to parent directory */ if (current && current[1]) { /* was a slash AND something else too */ char *parent; char *relative; *current++ = 0; parent = strrchr(path, '/'); /* penultimate slash */ relative = (char *) GTR_MALLOC(strlen(current) + 4); if (relative) { sprintf(relative, "%s/..", current); HTStartAnchor(target, "", relative); GTR_FREE(relative); } else { ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL); } //PUTS("Up to "); PUTS(GTR_GetString(SID_INF_UP_TO)); if (parent) { char *printable = NULL; printable = GTR_strdup((parent+1)); if (!bLocal) HTUnEscape(printable); PUTS(printable); GTR_FREE(printable); } else { PUTS("/"); } END(HTML_A); } if (path) GTR_FREE(path); } /***************************************************************************** HTLoadFile_Async_SetFileInfo *****************************************************************************/ int HTLoadFile_Async_SetFileInfo (struct Mwin* tw, struct Data_LoadFile* pData, char* pszURL, char** pszLocalname) { char *pszFilename; HTFormat format; HTAtom encoding; HTAtom language; char *myhost = HTParse (pszURL, "", PARSE_HOST); if (myhost) { if (*myhost) { GTR_FREE (myhost); /* be a good boy and clean up memory before we leave */ return HTLoadFile_TryFTP (tw, pData, pszURL); } GTR_FREE (myhost); /* memory cleanup */ } /* Reduce the filename to a basic form (hopefully unique!) */ pszFilename = HTParse (pszURL, "", PARSE_PATH | PARSE_PUNCTUATION); *pszLocalname = HTLocalName (pszURL); if (!*pszLocalname) { /* No localname */ *pData->pStatus = -403; ERR_ReportError (tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL); return STATE_DONE; } /* take care of the case where we have been given (via ShowFile event) the MIMEtype */ if (tw && tw->SDI_MimeType != 0) { struct Viewer_Info* pvi = NULL; pvi = PREF_GetViewerInfoBy_MIMEAtom (tw->SDI_MimeType); if (pvi) { format = pvi->atomMIMEType; encoding = pvi->atomEncoding; language = 0; goto GotIt; } } #ifdef MAC { /* see if we can figure out the type ourselves from the fileTYPE */ struct Viewer_Info* pvi = NULL; Str255 spMacFilename; FInfo fndrInfo; strncpy (spMacFilename, *pszLocalname, sizeof (Str255)); c2pstr (spMacFilename); if (GetFInfo (spMacFilename, 0, &fndrInfo) == noErr) { if (fndrInfo.fdType == 'TEXT') { /* TEXT is inconclusive, check based on extension */ format = HTFileFormat (pszFilename, &encoding, &language); if (format == WWW_BINARY) { pvi = PREF_GetViewerInfoBy_MIMEAtom (WWW_PLAINTEXT); } } else { pvi = PREF_GetViewerInfoBy_FileType (fndrInfo.fdType); } if (pvi) { format = pvi->atomMIMEType; encoding = pvi->atomEncoding; language = 0; } } if (!pvi) format = HTFileFormat (pszFilename, &encoding, &language); } #else format = HTFileFormat (pszFilename, &encoding, &language); #endif GotIt: /* memory cleanup */ if (pszFilename) { GTR_FREE (pszFilename); pszFilename = NULL; } pData->request->content_type = format; pData->request->content_encoding = encoding; pData->request->content_language = language; return STATE_INIT; } /* HTLoadFile_Async_SetFileInfo */ /***************************************************************************** HTLoadFile_Async_Init NOTES: Since we are reading a local file, we record that fact in the request structure. If this request happens to end up in the FileWriter class, that class can avoid writing a temp file and simply read this file directly. It is the responsibility of FileWriter to make sure that this filename is not marked for deletion as a temporary file. It is the responsibility of the caller (loaddoc.c) to make sure that this string gets freed. The "openType" parameter is used to determine if we are opening a local file, or handling a "cache" file. This was done to condense the dcache code with this code, since there was considerable overlap in functionality. 0 = open local 1 = dcache other = undefined [der: 5/24/95] *****************************************************************************/ int HTLoadFile_Async_Init (struct Mwin *tw, void **ppInfo, int openType) { struct Params_InitStream* pis; struct Params_LoadAsync* pParams; struct Data_LoadFile* pData; char *pszURL; char *pszLocalname; pParams = *ppInfo; /****************************************/ /* this code copied from FTP_DoInit() to remove trailing slash */ /* this line fixed the infinite looping bug */ if (openType == 0) /* local file rather than dcache */ { char *name; name = pParams->request->destination->szActualURL; if (!name || !*name) { *pParams->pStatus = HT_INTERNAL; return STATE_DONE; } /* It's common for someone to enter an invalid directory URL which ends in a slash ("ftp://foo.com/pub/mac/"), so make sure this isn't malformed like that. */ { char *filename; char *p = NULL; char buf[MAX_URL_STRING]; filename = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION); if (filename) p = strrchr(filename, '/'); if (p && !*(p+1) && p != filename) { /* The URL was, in fact, malformed. I told you it was common. */ /* Fix up the URL and try again. */ p = strrchr(name, '/'); strncpy(buf, name, p - name); buf[p - name] = '\0'; Dest_UpdateActual(pParams->request->destination, buf); *pParams->pStatus = HT_REDIRECTION_ON_FLY; GTR_FREE(filename); return STATE_DONE; } GTR_FREE(filename); } } /****************************************/ pData = GTR_CALLOC(sizeof(*pData), 1); if (!pData) { /* out of memory error! */ ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL); return STATE_ABORT; } pData->request = pParams->request; pData->pStatus = pParams->pStatus; *ppInfo = pData; GTR_FREE(pParams); if (!pData->request) { *pData->pStatus = HT_INTERNAL; return STATE_DONE; } pData->request->content_length = 0; pData->iTotalBytes = 0; pszURL = pData->request->destination->szActualURL; /* get the local name, MIMEtype, encoding, etc... info for this URL */ switch (openType) { case 0: /* open local */ if (HTLoadFile_Async_SetFileInfo (tw, pData, pszURL, &pszLocalname) == STATE_DONE) return STATE_DONE; break; case 1: if (HTLoadDCache_Async_SetFileInfo (tw, pData, pszURL, &pszLocalname) == STATE_DONE) return STATE_DONE; break; default: /* guano case here -- we should never get here */ *pData->pStatus = -403; ERR_ReportError(tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL); return STATE_DONE; break; } if (tw) tw->SDI_MimeType = 0; /* clear this now */ /****************************************/ #ifdef FEATURE_LOCAL_DIRECTORY if (Dir_IsDirectory (pszLocalname)) { *pData->pStatus = HTLoadDir (tw, pData->request, pszLocalname); return STATE_DONE; } #endif /* open the file */ pData->fp = fopen (pszLocalname, "rb"); if (!pData->fp) { /* unable to open the file */ GTR_FREE (pszLocalname); pszLocalname = NULL; pData->request->szLocalFileName = NULL; *pData->pStatus = -403; ERR_ReportError(tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL); return STATE_DONE; } pData->request->szLocalFileName = GTR_strdup (pszLocalname); GTR_FREE (pszLocalname); pszLocalname = NULL; /* get the length of the data */ if (0 == fseek(pData->fp, 0, SEEK_END)) { pData->request->content_length = ftell(pData->fp); if (pData->request->content_length < 0) { pData->request->content_length = 0; } fseek(pData->fp, 0, SEEK_SET); } /* set the stream */ pData->stream = HTStreamStack(tw, pData->request->content_type, pData->request); if (!pData->stream) { *pData->pStatus = -501; return STATE_DONE; } /* Ignore CRLF if necessary */ if (!(pData->request->iFlags & HTREQ_BINARY) && ((pData->request->content_encoding == HTAtom_for("7bit") || pData->request->content_encoding == HTAtom_for("8bit")))) { pData->stream = HTNetToText(pData->stream); } HTSetStreamStatus (tw, pData->stream, pData->request); if (!pData->stream->isa->init_Async) { return STATE_FILE_COPYING; } else { /* the stream has an async initialization function */ pis = GTR_CALLOC (sizeof (*pis), 1); if (!pis) { /* HEY - THE FILE SEEMS TO BE LEFT OPEN HERE!!! [der: 4/25/95] */ ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL); return STATE_ABORT; } pis->me = pData->stream; pis->request = pData->request; pis->pResult = pData->pStatus; Async_DoCall (pData->stream->isa->init_Async, pis); return STATE_FILE_STREAMINIT; } } /* HTLoadFile_Async_Init */ /***************************************************************************** HTLoadFile_Async_File_Copy NOTE: This function also used by dcache functions *****************************************************************************/ int HTLoadFile_Async_File_Copy (struct Mwin *tw, struct Data_LoadFile *pData) { char input_buffer[INPUT_BUFFER_SIZE]; BOOL bError = FALSE; BOOL bDone = FALSE; int iNumBytesRead; iNumBytesRead = fread(input_buffer, 1, INPUT_BUFFER_SIZE, pData->fp); if (iNumBytesRead == 0) { /* EOF or error */ bDone = TRUE; if (ferror(pData->fp) != 0) { bError = TRUE; } } else { pData->iTotalBytes += iNumBytesRead; if (pData->request->content_length) { WAIT_SetTherm (tw, pData->iTotalBytes); } if (!(*pData->stream->isa->put_block)(pData->stream, input_buffer, iNumBytesRead)) { bError = TRUE; bDone = TRUE; } } if (!bDone && !bError) { return STATE_FILE_COPYING; } /* close the file */ fclose(pData->fp); pData->fp = NULL; /* cleanup -- abort (error) or free (success) */ if (bError) { (*pData->stream->isa->abort)(pData->stream, 0); pData->stream = NULL; *pData->pStatus = -1; } else { (*pData->stream->isa->free)(pData->stream); pData->stream = NULL; *pData->pStatus = HT_LOADED; } return STATE_DONE; } /***************************************************************************** HTLoadFile_Async_File_StreamInit NOTE: This function also used by dcache functions *****************************************************************************/ int HTLoadFile_Async_File_StreamInit (struct Mwin *tw, struct Data_LoadFile *pData) { if (*pData->pStatus < 0) { (*pData->stream->isa->abort)(pData->stream, 0); return STATE_DONE; } if (*pData->pStatus == 0) { /* This only happens if the async init function told us we were already done. In other words, only FileWriter should do this, and only when request->szLocalFileName is true. */ fclose(pData->fp); pData->fp = NULL; (*pData->stream->isa->free)(pData->stream); pData->stream = NULL; *pData->pStatus = HT_LOADED; return STATE_DONE; } return HTLoadFile_Async_File_Copy (tw, pData); } /***************************************************************************** HTLoadFile_Async_Abort NOTE: This function also used by dcache functions *****************************************************************************/ int HTLoadFile_Async_Abort (struct Mwin *tw, struct Data_LoadFile *pData) { /* allow the stream to abort */ if (pData->stream) { (*pData->stream->isa->abort)(pData->stream, HTERROR_CANCELLED); } /* close the file if we opened it */ if (pData->fp) { fclose(pData->fp); } *pData->pStatus = -1; return STATE_DONE; } /***************************************************************************** HTLoadFile_Async This is a pretty pathetic async version - once it starts copying it just keeps going. *****************************************************************************/ PRIVATE int HTLoadFile_Async(struct Mwin *tw, int nState, void **ppInfo) { int result; struct Data_LoadFile *pData; pData = *ppInfo; switch (nState) { case STATE_INIT: result = HTLoadFile_Async_Init (tw, ppInfo, 0); break; case STATE_FILE_STREAMINIT: result = HTLoadFile_Async_File_StreamInit (tw, pData); break; case STATE_FILE_COPYING: result = HTLoadFile_Async_File_Copy (tw, pData); break; case STATE_ABORT: result = HTLoadFile_Async_Abort (tw, pData); break; default: XX_Assert((0), ("Function called with illegal state: %d", nState)); result = STATE_DONE; break; } return result; } /***************************************************************************** HTLoadFile_TryFTP *****************************************************************************/ static int HTLoadFile_TryFTP (struct Mwin *tw, struct Data_LoadFile* pData, char *addr) { char* newname = GTR_MALLOC(strlen(addr)); if (!newname) { ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL); return STATE_ABORT; } strcpy(newname, "ftp:"); strcat(newname, addr + 5); Dest_UpdateActual(pData->request->destination, newname); GTR_FREE(newname); *pData->pStatus = HT_REDIRECTION_ON_FLY; return STATE_DONE; } static void file_MakeSizeString1 (char *buf, int nSize) { if (nSize >= 0) { if (nSize < 999) { sprintf(buf, "%ld", (long) nSize); } else if (nSize < 9999) { sprintf(buf, "%ld,%03ld", (long) nSize / 1000, (long) nSize % 1000); } else if (nSize < (999 * 1024)) { sprintf(buf, "%ld", (long) nSize / 1024); } else { sprintf (buf, "%ld.%ld", (long) nSize / (1024 * 1024), (long) (nSize / (1024 * 1024 / 10)) % 10); } } else { strcpy(buf, "(unknown size?)"); } } static void file_MakeSizeString2(char *buf, int nSize) { if (nSize >= 0) { if (nSize < 999) { strcpy(buf, "bytes"); } else if (nSize < 9999) { strcpy(buf, "bytes"); } else if (nSize < (999 * 1024)) { strcpy(buf, "KB"); } else { strcpy (buf, "MB"); } } else { strcpy (buf, "unknown size"); } } #ifdef FEATURE_LOCAL_DIRECTORY /* ** This function will read a directory and display ** the sorted entries in a ** ** Calls Dir_OpenDirectory() reading functions ** Calls HTML_new() to create the output */ int HTLoadDir (struct Mwin *tw, HTRequest *request, char *pszLocalname) { HTStructured *target; int i; #ifdef HTLOADDIR_USE_TABLE char size_buf1[100]; char size_buf2[100]; #endif char buf[_MAX_PATH+100]; HTBTree *bt; /* btree for sorting elements */ HTBTElement *ele; CONST char *hrvalues[HTML_HR_ATTRIBUTES]; BOOL hrpresent[HTML_HR_ATTRIBUTES]; #ifdef HTLOADDIR_USE_TABLE CONST char *tvalues[HTML_TABLE_ATTRIBUTES]; BOOL tpresent[HTML_TABLE_ATTRIBUTES]; CONST char *tdvalues[HTML_TD_ATTRIBUTES]; BOOL tdpresent[HTML_TD_ATTRIBUTES]; CONST char *trvalues[HTML_TR_ATTRIBUTES]; BOOL trpresent[HTML_TR_ATTRIBUTES]; #endif void *dp; /* opendirectory private data */ HT_DirEntry *dir_ent; char *p; /****************************************/ /****************************************/ target = HTML_new (tw, request, NULL, WWW_HTML, request->output_format, request->output_stream); GTR_strncpy (buf, pszLocalname, _MAX_PATH); p = buf + strlen(buf) - 1; if (*p == '/') *p = '\0'; HTDirTitles (target, buf, 1); if (!(dp = Dir_OpenDirectory (buf))) return HT_ERROR; if (NULL == (bt = HTBTree_new ((HTComparer) strcasecomp))) { Dir_CloseDirectory (dp); return HT_ERROR; } for (i = 0 ; i < HTML_HR_ATTRIBUTES ; i++) hrpresent[i] = 0; #ifdef HTLOADDIR_USE_TABLE for (i = 0 ; i < HTML_TABLE_ATTRIBUTES ; i++) tpresent[i] = 0; for (i = 0 ; i < HTML_TD_ATTRIBUTES ; i++) tdpresent[i] = 0; for (i = 0 ; i < HTML_TR_ATTRIBUTES ; i++) trpresent[i] = 0; #endif while ( Dir_NextEntry (dp, dir_ent = (HT_DirEntry *)GTR_CALLOC (1, sizeof (*dir_ent)))) { if ( dir_ent && dir_ent->name[0] && (strcmp (dir_ent->name, ".") && strcmp (dir_ent->name, "..")) ) HTBTree_add (bt, dir_ent); } (*target->isa->start_element) (target, HTML_HR, hrpresent, hrvalues); #ifdef HTLOADDIR_USE_TABLE tvalues[HTML_TABLE_CELLSPACING] = "50"; tpresent[HTML_TABLE_CELLSPACING] = 1; /* start table */ (*target->isa->start_element) (target, HTML_TABLE, tpresent, tvalues); #else START (HTML_DIR); #endif for (ele = HTBTree_next(bt, NULL); ele != NULL; ele = HTBTree_next(bt, ele)) { dir_ent = (HT_DirEntry *) HTBTree_object (ele); #ifdef HTLOADDIR_USE_TABLE /* Row */ (*target->isa->start_element) (target, HTML_TR, trpresent, trvalues); /* Data Cell for directory info */ (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); if (dir_ent->type & HTDIR_DIR) //PUTS (" "); PUTS(GTR_GetString(SID_INF_DIR)); /* Column 2: file name */ (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); HTDirEntry (target, request->destination->szActualURL, (CONST char *) dir_ent->name, 0); /* toss in a couple colums for space */ (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); /* size number */ tdvalues[HTML_TD_ALIGN] = "right"; tdpresent[HTML_TD_ALIGN] = 1; (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); file_MakeSizeString1 (size_buf1, dir_ent->size); PUTS (size_buf1); /* size units */ tdvalues[HTML_TD_ALIGN] = "left"; tdpresent[HTML_TD_ALIGN] = 1; (*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues); file_MakeSizeString2 (size_buf2, dir_ent->size); PUTS (size_buf2); tdpresent[HTML_TD_ALIGN] = 0; /* reset just in case */ END (HTML_TD); END (HTML_TR); #else START (HTML_LI); HTDirEntry (target, request->destination->szActualURL, (CONST char *) dir_ent->name, 0); #endif /* HTLOADDIR_USE_TABLE */ } #ifdef HTLOADDIR_USE_TABLE END (HTML_TABLE); #else END (HTML_DIR); #endif (*target->isa->free) (target); /* clean up stream */ HTBTreeAndObject_free (bt); /* free btree AND dir_ent's */ Dir_CloseDirectory (dp); /* close directory */ return HT_LOADED; } #endif /* FEATURE_LOCAL_DIRECTORY */ /***************************************************************************** Protocol descriptors *****************************************************************************/ GLOBALDEF PUBLIC HTProtocol HTFile ={"file", NULL, HTLoadFile_Async};