NOT HOOKED INTO BUILD. adding FTP directory listing stream converter

This commit is contained in:
valeski%netscape.com 1999-09-09 19:33:16 +00:00
Родитель 92661b962b
Коммит 3db429ff8b
2 изменённых файлов: 1160 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,976 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsFTPDirListingConv.h"
#include "nsIAllocator.h"
#include "plstr.h"
#include "nsIStringStream.h"
#include "nsIHTTPChannel.h"
#include "nsIAtom.h"
#include "nsIServiceManager.h"
#include "nsIGenericFactory.h"
#include "nsCOMPtr.h"
#include "nsIIOService.h"
#include "nsIStringStream.h"
#include "nsILocaleService.h"
#include "nsIComponentManager.h"
#include "nsDateTimeFormatCID.h"
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kLocaleServiceCID, NS_LOCALESERVICE_CID);
static NS_DEFINE_CID(kDateTimeCID, NS_DATETIMEFORMAT_CID);
PRBool is_charAlpha(char chr) {
if ( ( ((chr >= 'a') && (chr <= 'z')) || ((chr >= 'A') && (chr <= 'Z')) ) )
return PR_TRUE;
return PR_FALSE;
}
#define NET_IS_SPACE(x) ((((unsigned int) (x)) > 0x7f) ? 0 : (x == ' ' || x == '\r' || x == '\n' || x == '\t') )
#define IS_DIGITx(x) ( (PRBool) ( x >= '0' && x <= '9' ) ? PR_TRUE : PR_FALSE )
// nsISupports implementation
NS_IMPL_ISUPPORTS2(nsFTPDirListingConv, nsIStreamConverter, nsIStreamListener);
// nsIStreamConverter implementation
// No syncronous conversion at this time.
NS_IMETHODIMP
nsFTPDirListingConv::Convert(nsIInputStream *aFromStream,
const PRUnichar *aFromType,
const PRUnichar *aToType,
nsISupports *aCtxt, nsIInputStream **_retval) {
return NS_ERROR_NOT_IMPLEMENTED;
}
// Stream converter service calls this to initialize the actual stream converter (us).
NS_IMETHODIMP
nsFTPDirListingConv::AsyncConvertData(const PRUnichar *aFromType, const PRUnichar *aToType,
nsIStreamListener *aListener, nsISupports *aCtxt) {
NS_ASSERTION(aListener && aFromType && aToType, "null pointer passed into FTP dir listing converter");
nsresult rv;
// hook up our final listener. this guy gets the various On*() calls we want to throw
// at him.
//
mFinalListener = aListener;
NS_ADDREF(mFinalListener);
// set our internal state to reflect the server type
nsCString fromMIMEString(aFromType);
const char *from = fromMIMEString.GetBuffer();
NS_ASSERTION(from, "nsCString/PRUnichar acceptance failed.");
from = PL_strstr(from, "/ftp-dir-");
if (!from) return NS_ERROR_FAILURE;
from += 9;
fromMIMEString = from;
if (-1 != fromMIMEString.Find("unix")) {
mServerType = UNIX;
} else if (-1 != fromMIMEString.Find("nt")) {
mServerType = NT;
} else if (-1 != fromMIMEString.Find("dcts")) {
mServerType = DCTS;
} else if (-1 != fromMIMEString.Find("ncsa")) {
mServerType = NCSA;
} else if (-1 != fromMIMEString.Find("peter_lewis")) {
mServerType = PETER_LEWIS;
} else if (-1 != fromMIMEString.Find("machten")) {
mServerType = MACHTEN;
} else if (-1 != fromMIMEString.Find("cms")) {
mServerType = CMS;
} else if (-1 != fromMIMEString.Find("tcpc")) {
mServerType = TCPC;
} else if (-1 != fromMIMEString.Find("vms")) {
mServerType = VMS;
} else {
mServerType = GENERIC;
}
// we need our own channel that represents the content-type of the
// converted data.
NS_ASSERTION(aCtxt, "FTP dir listing needs a context (the uri)");
nsIURI *uri;
rv = aCtxt->QueryInterface(NS_GET_IID(nsIURI), (void**)&uri);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = serv->NewInputStreamChannel(uri, "application/http-index-format", nsnull, &mPartChannel);
NS_RELEASE(uri);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
// nsIStreamListener implementation
NS_IMETHODIMP
nsFTPDirListingConv::OnDataAvailable(nsIChannel *channel, nsISupports *ctxt,
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
NS_ASSERTION(channel, "FTP dir listing stream converter needs a channel");
nsresult rv;
PRUint32 read, streamLen;
nsCString indexFormat;
rv = inStr->GetLength(&streamLen);
if (NS_FAILED(rv)) return rv;
char *buffer = (char*)nsAllocator::Alloc(streamLen + 1);
rv = inStr->Read(buffer, streamLen, &read);
if (NS_FAILED(rv)) return rv;
// the dir listings are ascii text, null terminate this sucker.
buffer[streamLen] = '\0';
if (!mBuffer.IsEmpty()) {
// we have data left over from a previous OnDataAvailable() call.
// combine the buffers so we don't lose any data.
mBuffer.Append(buffer);
nsAllocator::Free(buffer);
buffer = mBuffer.ToNewCString();
mBuffer.Truncate();
}
if (!mSentHeading) {
// build up the 300: line
char *spec = nsnull;
nsIURI *uri = nsnull;
rv = channel->GetURI(&uri);
if (NS_FAILED(rv)) return rv;
rv = uri->GetSpec(&spec);
NS_RELEASE(uri);
if (NS_FAILED(rv)) return rv;
indexFormat.Append("300: ");
indexFormat.Append(spec);
indexFormat.Append('\n');
nsAllocator::Free(spec);
// END 300:
// build up the column heading; 200:
indexFormat.Append("200: Filename\tContent-Length\tContent-Type\tFile-type\tLast-Modified\n");
// END 200:
mSentHeading = PR_TRUE;
}
char *line = buffer;
char *eol;
// while we have new lines, parse 'em into application/http-index-format.
while ( line && (eol = PL_strchr(line, '\n')) ) {
*eol = '\0';
indexEntry *thisEntry = nsnull;
NS_NEWXPCOM(thisEntry, indexEntry);
if (!thisEntry) return NS_ERROR_OUT_OF_MEMORY;
// XXX we need to handle comments in the raw stream.
switch (mServerType) {
case UNIX:
case PETER_LEWIS:
case MACHTEN:
{
// don't bother w/ these lines.
if(!PL_strncmp(line, "total ", 6)
|| (PL_strstr(line, "Permission denied") != NULL)
|| (PL_strstr(line, "not available") != NULL)) {
NS_DELETEXPCOM(thisEntry);
line = eol+1;
continue;
}
PRInt32 len = PL_strlen(line);
// check first character of ls -l output
// For example: "dr-x--x--x" is what we're starting with.
if (toupper(line[0]) == 'D') {
/* it's a directory */
thisEntry->mType = Dir;
thisEntry->mSupressSize = PR_TRUE;
} else if (line[0] == 'l') {
thisEntry->mType = Link;
thisEntry->mSupressSize = PR_TRUE;
/* strip off " -> pathname" */
PRInt32 i;
for (i = len - 1; (i > 3) && (!NET_IS_SPACE(line[i])
|| (line[i-1] != '>')
|| (line[i-2] != '-')
|| (line[i-3] != ' ')); i--)
; /* null body */
if (i > 3) {
line[i-3] = '\0';
len = i - 3;
}
}
rv = ParseLSLine(line, thisEntry);
if ( NS_FAILED(rv) || (thisEntry->mName == "..") || (thisEntry->mName == ".") ) {
NS_DELETEXPCOM(thisEntry);
line = eol+1;
continue;
}
/* add a trailing slash to all directories */
if(thisEntry->mType == Dir)
thisEntry->mName.Append('/');
break; // END UNIX, PETER_LEWIS, MACHTEN
}
case NCSA:
case TCPC:
{
thisEntry->mName = line;
if (thisEntry->mName.Last() == '/')
thisEntry->mType = Dir;
break; // END NCSA, TCPC
}
case CMS:
{
thisEntry->mName = line;
break; // END CMS
}
case VMS:
{
/* Interpret and edit LIST output from VMS server */
/* and convert information lines to zero length. */
rv = ParseVMSLine(line, thisEntry);
if (NS_FAILED(rv)) {
NS_DELETEXPCOM(thisEntry);
line = eol+1;
continue;
}
/** Trim off VMS directory extensions **/
//len = thisEntry->mName.Length();
// if ((len > 4) && !PL_strcmp(&entry_info->filename[len-4], ".dir"))
// {
// entry_info->filename[len-4] = '\0';
// entry_info->special_type = NET_DIRECTORY;
// remove_size=TRUE; /* size is not useful */
// /* add trailing slash to directories
// */
// StrAllocCat(entry_info->filename, "/");
// }
break; // END VMS
}
case NT:
{
char *date, *size_s, *name;
if(PL_strlen(line) > 37)
{
date = line;
line[17] = '\0';
size_s = &line[18];
line[38] = '\0';
name = &line[39];
if(PL_strstr(size_s, "<DIR>")) {
thisEntry->mType = Dir;
} else {
nsCAutoString size(size_s);
size.StripWhitespace();
thisEntry->mContentLen = atol(size.GetBuffer());
}
thisEntry->mMDTM = ConvertDOSDate(date);
thisEntry->mName = name;
}
else
{
thisEntry->mName = line;
}
break; // END NT
}
default:
{
thisEntry->mName = line;
break; // END default (catches GENERIC, DCTS)
}
} // end switch (mServerType)
// blast the index entry into the indexFormat buffer as a 201: line.
indexFormat.Append("201: ");
// FILENAME
indexFormat.Append(thisEntry->mName);
indexFormat.Append('\t');
// CONTENT LENGTH
indexFormat.Append(thisEntry->mContentLen);
indexFormat.Append('\t');
// CONTENT TYPE (not very useful for ftp listings)
// XXX this field is currently meaningless for FTP
//indexFormat.Append(thisEntry->mContentType);
indexFormat.Append("n/a");
indexFormat.Append('\t');
// ENTRY TYPE
switch (thisEntry->mType) {
case Dir:
indexFormat.Append("Directory");
break;
case Link:
indexFormat.Append("Sym-Link");
break;
default:
indexFormat.Append("File");
}
indexFormat.Append('\t');
// MODIFIED DATE
nsString lDate;
rv = mDateTimeFormat->FormatPRTime(mLocale, kDateFormatShort, kTimeFormatNoSeconds, thisEntry->mMDTM, lDate);
if (NS_FAILED(rv)) return rv;
indexFormat.Append(lDate);
indexFormat.Append('\n'); // complete this line
// END 201:
NS_DELETEXPCOM(thisEntry);
line = eol+1;
} // end while(eol)
// if there's any data left over, buffer it.
if (line && *line) {
mBuffer.Append(line);
}
nsAllocator::Free(buffer);
// send the converted data out.
nsIInputStream *inputData = nsnull;
nsISupports *inputDataSup = nsnull;
rv = NS_NewStringInputStream(&inputDataSup, indexFormat);
if (NS_FAILED(rv)) return rv;
rv = inputDataSup->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inputData);
NS_RELEASE(inputDataSup);
if (NS_FAILED(rv)) return rv;
rv = mFinalListener->OnDataAvailable(mPartChannel, ctxt, inputData, 0, indexFormat.Length());
NS_RELEASE(inputData);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
// nsIStreamObserver implementation
NS_IMETHODIMP
nsFTPDirListingConv::OnStartRequest(nsIChannel *channel, nsISupports *ctxt) {
// we don't care about start. move along... but start masqeurading
// as the http-index channel now.
return mFinalListener->OnStartRequest(mPartChannel, ctxt);
}
NS_IMETHODIMP
nsFTPDirListingConv::OnStopRequest(nsIChannel *channel, nsISupports *ctxt,
nsresult status, const PRUnichar *errorMsg) {
// we don't care about stop. move along...
return mFinalListener->OnStopRequest(mPartChannel, ctxt, status, errorMsg);
}
// nsFTPDirListingConv methods
nsFTPDirListingConv::nsFTPDirListingConv() {
NS_INIT_ISUPPORTS();
mFinalListener = nsnull;
mServerType = GENERIC;
mPartChannel = nsnull;
mSentHeading = PR_FALSE;
}
nsFTPDirListingConv::~nsFTPDirListingConv() {
NS_IF_RELEASE(mFinalListener);
NS_IF_RELEASE(mPartChannel);
NS_RELEASE(mLocale);
NS_RELEASE(mDateTimeFormat);
}
nsresult
nsFTPDirListingConv::Init() {
// Grab the nsILocale for date parsing.
nsresult rv;
NS_WITH_SERVICE(nsILocaleService, localeSvc, kLocaleServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = localeSvc->GetApplicationLocale(&mLocale);
if (NS_FAILED(rv)) return rv;
// Grab the date/time formatter
nsIComponentManager *comMgr;
rv = NS_GetGlobalComponentManager(&comMgr);
if (NS_FAILED(rv)) return rv;
rv = comMgr->CreateInstance(kDateTimeCID, nsnull, NS_GET_IID(nsIDateTimeFormat), (void**)&mDateTimeFormat);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
PRInt8
nsFTPDirListingConv::MonthNumber(const char *month) {
NS_ASSERTION(month && month[1] && month[2], "bad month");
if (!month || !month[0] || !month[1] || !month[2])
return -1;
char c1 = month[1], c2 = month[2];
switch (*month) {
case 'f': case 'F':
return 1;
case 'm': case 'M':
if (c1 == 'a' || c1 == 'A')
if (c2 == 'r' || c2 == 'R')
return 2;
else if (c2 == 'y' || c2 == 'Y')
return 4;
break;
case 'a': case 'A':
if (c1 == 'p' || c1 == 'P')
return 3;
else if (c1 == 'u' || c1 == 'U')
return 7;
break;
case 'j': case 'J':
if (c1 == 'u' || c1 == 'U')
if (c2 == 'n' || c2 == 'N')
return 5;
else if (c2 == 'l' || c2 == 'L')
return 6;
else if (c1 == 'a' || c1 == 'A')
return 0;
break;
case 's': case 'S':
return 8;
case 'o': case 'O':
return 9;
case 'n': case 'N':
return 10;
case 'd': case 'D':
return 11;
default:
return -1;
}
return -1;
}
// Return true if the string is of the form:
// "Sep 1 1990 " or
// "Sep 11 11:59 " or
// "Dec 12 1989 " or
// "FCv 23 1990 " ...
PRBool
nsFTPDirListingConv::IsLSDate(char *aCStr) {
/* must start with three alpha characters */
if (!is_charAlpha(*aCStr++) || !is_charAlpha(*aCStr++) || !is_charAlpha(*aCStr++))
return PR_FALSE;
/* space */
if (*aCStr != ' ')
return PR_FALSE;
aCStr++;
/* space or digit */
if ((*aCStr != ' ') && !IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* digit */
if (!IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* space */
if (*aCStr != ' ')
return PR_FALSE;
aCStr++;
/* space or digit */
if ((*aCStr != ' ') && !IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* digit */
if (!IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* colon or digit */
if ((*aCStr != ':') && !IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* digit */
if (!IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* space or digit */
if ((*aCStr != ' ') && !IS_DIGITx(*aCStr))
return PR_FALSE;
aCStr++;
/* space */
if (*aCStr != ' ')
return PR_FALSE;
aCStr++;
return PR_TRUE;
}
// Converts a date string from 'ls -l' to a time_t number
// "Sep 1 1990 " or
// "Sep 11 11:59 " or
// "Dec 12 1989 " or
// "FCv 23 1990 " ...
// Returns 0 on error.
PRTime
nsFTPDirListingConv::ConvertUNIXDate(char *aCStr) {
PRExplodedTime curTime;
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &curTime);
char *bcol = aCStr; /* Column begin */
char *ecol; /* Column end */
// MONTH
char tmpChar = bcol[3];
bcol[3] = '\0';
nsCAutoString lMonth(bcol);
bcol[3] = tmpChar;
lMonth.ToUpperCase();
if ((curTime.tm_month = MonthNumber(lMonth.GetBuffer())) < 0)
return (PRTime) 0;
// DAY
ecol = &bcol[3];
while (*ecol++ == ' ') ; /* Spool to other side of day */
while (*ecol++ != ' ') ;
*--ecol = '\0';
PRInt32 error;
nsCAutoString day(bcol);
curTime.tm_mday = day.ToInteger(&error, 10);
//time_info->tm_mday = atoi(bcol);
curTime.tm_wday = 0;
//time_info->tm_wday = 0;
curTime.tm_yday = 0;
//time_info->tm_yday = 0;
// YEAR
bcol = ++ecol;
if ((ecol = PL_strchr(bcol, ':')) == NULL) {
nsCAutoString intStr(bcol);
curTime.tm_year = intStr.ToInteger(&error, 10);
//time_info->tm_year = atoi(bcol)-1900;
curTime.tm_sec = 0;
//time_info->tm_sec = 0;
curTime.tm_min = 0;
//time_info->tm_min = 0;
curTime.tm_hour = 0;
//time_info->tm_hour = 0;
} else {
// TIME
/* If the time is given as hh:mm, then the file is less than 1 year
* old, but we might shift calandar year. This is avoided by checking
* if the date parsed is future or not.
*/
*ecol = '\0';
curTime.tm_sec = 0;
//time_info->tm_sec = 0;
nsCAutoString intStr(++ecol);
curTime.tm_min = intStr.ToInteger(&error, 10);
//time_info->tm_min = atoi(++ecol); /* Right side of ':' */
intStr = bcol;
curTime.tm_hour = intStr.ToInteger(&error, 10);
//time_info->tm_hour = atoi(bcol); /* Left side of ':' */
//if (mktime(time_info) > curtime)
// --time_info->tm_year;
}
return PR_ImplodeTime(&curTime); // compacts the curTime struct into a PRTime (64 bit int)
//return ((tval = mktime(time_info)) == -1 ? (time_t) 0 : tval);
}
PRTime
nsFTPDirListingConv::ConvertVMSDate(char *aCStr) {
PRExplodedTime curTime;
PR_ExplodeTime(PR_Now(), PR_GMTParameters, &curTime);
char *col;
if ((col = strtok(aCStr, "-")) == NULL)
return (PRTime) 0;
// DAY
nsCAutoString intStr(col);
PRInt32 error;
curTime.tm_mday = intStr.ToInteger(&error, 10);
//time_info->tm_mday = atoi(col);
curTime.tm_wday = 0;
//time_info->tm_wday = 0;
curTime.tm_yday = 0;
//time_info->tm_yday = 0;
if ((col = strtok(nsnull, "-")) == nsnull || (curTime.tm_month = MonthNumber(col)) < 0)
//if ((col = strtok(NULL, "-")) == NULL || (time_info->tm_mon = MonthNumber(col)) < 0)
return (PRTime) 0;
// YEAR
if ((col = strtok(NULL, " ")) == NULL)
return (PRTime) 0;
intStr = col;
curTime.tm_year = intStr.ToInteger(&error, 10);
//time_info->tm_year = atoi(col)-1900;
// HOUR
if ((col = strtok(NULL, ":")) == NULL)
return (PRTime) 0;
intStr = col;
curTime.tm_hour = intStr.ToInteger(&error, 10);
//time_info->tm_hour = atoi(col);
// MINS
if ((col = strtok(NULL, " ")) == NULL)
return (PRTime) 0;
intStr = col;
curTime.tm_min = intStr.ToInteger(&error, 10);
//time_info->tm_min = atoi(col);
curTime.tm_sec = 0;
//time_info->tm_sec = 0;
return PR_ImplodeTime(&curTime);
//return ((tval = mktime(time_info)) < 0 ? (time_t) 0 : tval);
}
PRTime
nsFTPDirListingConv::ConvertDOSDate(char *aCStr) {
PRExplodedTime curTime;
PR_ExplodeTime(PR_Now(), PR_GMTParameters, &curTime);
curTime.tm_month = (aCStr[1]-'0')-1;
curTime.tm_mday = (((aCStr[3]-'0')*10) + aCStr[4]-'0');
curTime.tm_year = (((aCStr[6]-'0')*10) + aCStr[7]-'0');
curTime.tm_hour = (((aCStr[10]-'0')*10) + aCStr[11]-'0');
if(aCStr[15] == 'P')
curTime.tm_hour += 12;
curTime.tm_min = (((aCStr[13]-'0')*10) + aCStr[14]-'0');
curTime.tm_wday = 0;
curTime.tm_yday = 0;
curTime.tm_sec = 0;
return PR_ImplodeTime(&curTime);
}
nsresult
nsFTPDirListingConv::ParseLSLine(char *aLine, indexEntry *aEntry) {
PRInt32 base=1;
PRInt32 size_num=0;
char save_char;
char *ptr;
for (ptr = &aLine[PL_strlen(aLine) - 1];
(ptr > aLine+13) && (!NET_IS_SPACE(*ptr) || !IsLSDate(ptr-12)); ptr--)
; /* null body */
save_char = *ptr;
*ptr = '\0';
if (ptr > aLine+13) {
aEntry->mMDTM = ConvertUNIXDate(ptr-12);
} else {
// must be a dl listing
// unterminate the line
*ptr = save_char;
// find the first whitespace and terminate
for(ptr=aLine; *ptr != '\0'; ptr++)
if(NET_IS_SPACE(*ptr)) {
*ptr = '\0';
break;
}
aEntry->mName = aLine;
return NS_OK;
}
// escape and copy
aEntry->mName = ptr+1;
// parse size
if(ptr > aLine+15) {
ptr -= 14;
while (IS_DIGITx(*ptr)) {
size_num += ((PRInt32) (*ptr - '0')) * base;
base *= 10;
ptr--;
}
aEntry->mContentLen = size_num;
}
return NS_OK;
}
nsresult
nsFTPDirListingConv::ParseVMSLine(char *aLine, indexEntry *aEntry) {
int i, j;
int32 ialloc;
char *cp, *cpd, *cps, date[64], *sp = " ";
static char ThisYear[5];
static PRBool HaveYear = PR_FALSE;
/** Get rid of blank lines, and information lines. **/
/** Valid lines have the ';' version number token. **/
if (!PL_strlen(aLine) || (cp=PL_strchr(aLine, ';')) == NULL)
{
// entry_info->display = FALSE;
return NS_ERROR_FAILURE;
}
/** Cut out file or directory name at VMS version number. **/
*cp++ ='\0';
/* escape and copy
*/
aEntry->mName = aLine;
/** Cast VMS file and directory names to lowercase. **/
aEntry->mName.ToLowerCase();
/** Uppercase terminal .z's or _z's. **/
//if ((--i > 2) && entry_info->filename[i] == 'z' &&
// (entry_info->filename[i-1] == '.' || entry_info->filename[i-1] == '_'))
// entry_info->filename[i] = 'Z';
/** Convert any tabs in rest of line to spaces. **/
cps = cp-1;
while ((cps=PL_strchr(cps+1, '\t')) != NULL)
*cps = ' ';
/** Collapse serial spaces. **/
i = 0; j = 1;
cps = cp;
while (cps[j] != '\0')
{
if (cps[i] == ' ' && cps[j] == ' ')
j++;
else
cps[++i] = cps[j++];
}
cps[++i] = '\0';
/* Save the current year.
* It could be wrong on New Year's Eve.
*/
if (!HaveYear)
{
PRExplodedTime curTime;
PR_ExplodeTime(PR_Now(), PR_GMTParameters, &curTime);
nsCAutoString year(curTime.tm_year);
const char *yearCStr = year.GetBuffer();
for (PRInt8 x = 0; x < 4; x++)
ThisYear[x] = yearCStr[x];
HaveYear = PR_TRUE;
}
/* get the date.
*/
if ((cpd=PL_strchr(cp, '-')) != NULL &&
PL_strlen(cpd) > 9 && IS_DIGITx(*(cpd-1)) &&
is_charAlpha(*(cpd+1)) && *(cpd+4) == '-')
{
/* Month
*/
*(cpd+4) = '\0';
*(cpd+2) = tolower(*(cpd+2));
*(cpd+3) = tolower(*(cpd+3));
sprintf(date, "%.32s ", cpd+1);
*(cpd+4) = '-';
/** Day **/
*cpd = '\0';
if (IS_DIGITx(*(cpd-2)))
sprintf(date+4, "%.32s ", cpd-2);
else
sprintf(date+4, " %.32s ", cpd-1);
*cpd = '-';
/** Time or Year **/
if (!PL_strncmp(ThisYear, cpd+5, 4) && PL_strlen(cpd) > 15 && *(cpd+12) == ':')
{
*(cpd+15) = '\0';
sprintf(date+7, "%.32s", cpd+10);
*(cpd+15) = ' ';
}
else
{
*(cpd+9) = '\0';
sprintf(date+7, " %.32s", cpd+5);
*(cpd+9) = ' ';
}
aEntry->mMDTM = ConvertVMSDate(date);
}
/* get the size
*/
if ((cpd=PL_strchr(cp, '/')) != NULL)
{
/* Appears be in used/allocated format */
cps = cpd;
while (IS_DIGITx(*(cps-1)))
cps--;
if (cps < cpd)
*cpd = '\0';
aEntry->mContentLen = atol(cps);
cps = cpd+1;
while (IS_DIGITx(*cps))
cps++;
*cps = '\0';
ialloc = atoi(cpd+1);
/* Check if used is in blocks or bytes */
if (aEntry->mContentLen <= ialloc)
aEntry->mContentLen *= 512;
}
else if ((cps=strtok(cp, sp)) != NULL)
{
/* We just initialized on the version number
* Now let's find a lone, size number
*/
while ((cps=strtok(NULL, sp)) != NULL)
{
cpd = cps;
while (IS_DIGITx(*cpd))
cpd++;
if (*cpd == '\0')
{
/* Assume it's blocks */
aEntry->mContentLen = atol(cps) * 512;
break;
}
}
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// Factory
////////////////////////////////////////////////////////////////////////
FTPDirListingFactory::FTPDirListingFactory(const nsCID &aClass,
const char* className,
const char* progID)
: mClassID(aClass), mClassName(className), mProgID(progID)
{
NS_INIT_ISUPPORTS();
}
FTPDirListingFactory::~FTPDirListingFactory()
{
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction");
}
NS_IMPL_ISUPPORTS(FTPDirListingFactory, NS_GET_IID(nsIFactory));
NS_IMETHODIMP
FTPDirListingFactory::CreateInstance(nsISupports *aOuter,
const nsIID &aIID,
void **aResult)
{
if (! aResult)
return NS_ERROR_NULL_POINTER;
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
*aResult = nsnull;
nsresult rv = NS_OK;
nsISupports *inst = nsnull;
if (mClassID.Equals(kFTPDirListingConverterCID)) {
nsFTPDirListingConv *conv = new nsFTPDirListingConv();
if (!conv) return NS_ERROR_OUT_OF_MEMORY;
rv = conv->Init();
if (NS_FAILED(rv)) return rv;
rv = conv->QueryInterface(NS_GET_IID(nsISupports), (void**)&inst);
if (NS_FAILED(rv)) return rv;
}
else {
return NS_ERROR_NO_INTERFACE;
}
if (!inst)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(inst);
*aResult = inst;
NS_RELEASE(inst);
return rv;
}
nsresult
FTPDirListingFactory::LockFactory(PRBool aLock){
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// Factory END
////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -0,0 +1,184 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef __nsftpdirlistingdconv__h__
#define __nsftpdirlistingdconv__h__
#include "nsIStreamConverter.h"
#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsString2.h"
#include "nsILocale.h"
#include "nsIDateTimeFormat.h"
#include "nsIFactory.h"
#define NS_FTPDIRLISTINGCONVERTER_CID \
{ /* 14C0E880-623E-11d3-A178-0050041CAF44 */ \
0x14c0e880, \
0x623e, \
0x11d3, \
{0xa1, 0x78, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
}
static NS_DEFINE_CID(kFTPDirListingConverterCID, NS_FTPDIRLISTINGCONVERTER_CID);
// The nsFTPDirListingConv stream converter converts a stream of type "text/ftp-dir-SERVER_TYPE"
// (where SERVER_TYPE is one of the following):
//
// SERVER TYPES:
// generic
// unix
// dcts
// ncsa
// peter_lewis
// machten
// cms
// tcpc
// vms
// nt
//
// nsFTPDirListingConv converts the raw ascii text directory generated via a FTP
// LIST or NLST command, to the application/http-index-format MIME-type.
// For more info see: http://www.area.com/~roeber/file_format.html
typedef enum _FTP_Server_Type {
GENERIC,
UNIX,
DCTS,
NCSA,
PETER_LEWIS,
MACHTEN,
CMS,
TCPC,
VMS,
NT
} FTP_Server_Type;
typedef enum _FTPentryType {
Dir,
File,
Link
} FTPentryType;
// indexEntry is the data structure used to maintain directory entry information.
class indexEntry {
public:
indexEntry() { mContentLen = 0; mMDTM = 0; mType = File; mSupressSize = PR_FALSE; };
nsCString mName; // the file or dir name
FTPentryType mType;
PRInt32 mContentLen; // length of the file
nsCString mContentType; // type of the file
PRTime mMDTM; // modified time
PRBool mSupressSize; // supress the size info from display
};
class nsFTPDirListingConv : public nsIStreamConverter {
public:
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIStreamConverter methods
NS_DECL_NSISTREAMCONVERTER
// nsIStreamListener methods
NS_DECL_NSISTREAMLISTENER
// nsIStreamObserver methods
NS_DECL_NSISTREAMOBSERVER
// nsFTPDirListingConv methods
nsFTPDirListingConv();
virtual ~nsFTPDirListingConv();
nsresult Init();
// For factory creation.
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) {
nsresult rv;
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsFTPDirListingConv* _s = new nsFTPDirListingConv();
if (_s == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(_s);
rv = _s->Init();
if (NS_FAILED(rv)) {
delete _s;
return rv;
}
rv = _s->QueryInterface(aIID, aResult);
NS_RELEASE(_s);
return rv;
}
private:
// util parsing methods
PRInt8 MonthNumber(const char *aCStr);
PRBool IsLSDate(char *aCStr);
// date conversion/parsing methods
PRTime ConvertUNIXDate(char *aCStr);
PRTime ConvertVMSDate(char *aCStr);
PRTime ConvertDOSDate(char *aCStr);
// line parsing methods
nsresult ParseLSLine(char *aLine, indexEntry *aEntry);
nsresult ParseVMSLine(char *aLine, indexEntry *aEntry);
// member data
FTP_Server_Type mServerType; // what kind of server is the data coming from?
nsCAutoString mBuffer; // buffered data.
PRBool mSentHeading; // have we sent 100, 101, 200, and 300 lines yet?
nsIStreamListener *mFinalListener; // this guy gets the converted data via his OnDataAvailable()
nsIChannel *mPartChannel; // the channel for the given part we're processing.
// one channel per part.
nsILocale *mLocale; // the application locale for date formating
nsIDateTimeFormat *mDateTimeFormat; // for the actual date time formatting.
};
//////////////////////////////////////////////////
// FACTORY
class FTPDirListingFactory : public nsIFactory
{
public:
FTPDirListingFactory(const nsCID &aClass, const char* className, const char* progID);
// nsISupports methods
NS_DECL_ISUPPORTS
// nsIFactory methods
NS_IMETHOD CreateInstance(nsISupports *aOuter,
const nsIID &aIID,
void **aResult);
NS_IMETHOD LockFactory(PRBool aLock);
protected:
virtual ~FTPDirListingFactory();
protected:
nsCID mClassID;
const char* mClassName;
const char* mProgID;
};
#endif /* __nsftpdirlistingdconv__h__ */