Nntp test harness and associated stub files....

This commit is contained in:
mscott%netscape.com 1999-01-31 07:02:24 +00:00
Родитель 846bb23626
Коммит c7cc85cb3d
5 изменённых файлов: 2148 добавлений и 0 удалений

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

@ -0,0 +1,648 @@
/* -*- Mode: C++; tab-width: 4; 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.
*/
/*=============================================================================
* This test program is designed to test netlib's implementation of nsITransport.
* In particular, it is currently geared towards testing their socket implemnation.
* When the test program starts up, you are prompted for a port and domain
* (I may have these hard coded right now to be nsmail-2 and port 143).
* After entering this information, we'll build a connection to the host name.
* You can then enter raw protocol text (i.e. "1 capability") and watch the data
* that comes back from the socket. After data is returned, you can enter another
* line of protocol.
*===============================================================================*/
#include <stdio.h>
#include <assert.h>
#ifdef XP_PC
#include <windows.h>
#endif
#include "plstr.h"
#include "plevent.h"
#include "nsIStreamListener.h"
#include "nsIInputStream.h"
#include "nsITransport.h"
#include "nsIURL.h"
#include "nsINetService.h"
#include "nsRepository.h"
#include "nsString.h"
#include "nntpCore.h"
#include "nsNNTPProtocol.h"
#include "nsNntpUrl.h"
// include the event sinks for the protocol you are testing
#include "nsINNTPHost.h"
#include "nsINetService.h"
#include "nsIServiceManager.h"
#include "nsIEventQueueService.h"
#include "nsXPComCIID.h"
#ifdef XP_PC
#define NETLIB_DLL "netlib.dll"
#define XPCOM_DLL "xpcom32.dll"
#else
#ifdef XP_MAC
#include "nsMacRepository.h"
#else
#define NETLIB_DLL "libnetlib.so"
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////
// Define keys for all of the interfaces we are going to require for this test
/////////////////////////////////////////////////////////////////////////////////
static NS_DEFINE_IID(kNetServiceCID, NS_NETSERVICE_CID);
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID);
static NS_DEFINE_IID(kIURLIID, NS_IURL_IID);
static NS_DEFINE_IID(kINntpUrlIID, NS_INNTPURL_IID);
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
/////////////////////////////////////////////////////////////////////////////////
// Define default values to be used to drive the test
/////////////////////////////////////////////////////////////////////////////////
#define DEFAULT_HOST "zia.mcom.com"
#define DEFAULT_PORT NEWS_PORT /* we get this value from nntpCore.h */
#define DEFAULT_URL_TYPE "sockstub://" /* do NOT change this value until netlib re-write is done...*/
extern NET_StreamClass *MIME_MessageConverter(int format_out, void *closure,
URL_Struct *url, MWContext *context);
/////////////////////////////////////////////////////////////////////////////////
// This function is used to load and prepare an nntp url which can be run by
// a transport instance. For different protocols, you'll have different url
// functions like this one in the test harness...
/////////////////////////////////////////////////////////////////////////////////
nsresult NS_NewNntpUrl(nsINntpUrl ** aResult, const nsString urlSpec)
{
nsIURL * pUrl = NULL;
nsresult rv = NS_OK;
nsNntpUrl * nntpUrl = new nsNntpUrl(nsnull, nsnull);
if (nntpUrl)
{
nntpUrl->ParseURL(urlSpec); // load the spec we were given...
rv = nntpUrl->QueryInterface(kINntpUrlIID, (void **) aResult);
}
return rv;
}
// temporary hack...we don't have escape search url in the new world yet....
char *MSG_EscapeSearchUrl (const char *nntpCommand)
{
char *result = NULL;
// max escaped length is two extra characters for every character in the cmd.
char *scratchBuf = (char*) PR_Malloc (3*PL_strlen(nntpCommand) + 1);
if (scratchBuf)
{
char *scratchPtr = scratchBuf;
while (1)
{
char ch = *nntpCommand++;
if (!ch)
break;
if (ch == '#' || ch == '?' || ch == '@' || ch == '\\')
{
*scratchPtr++ = '\\';
sprintf (scratchPtr, "%X", ch);
scratchPtr += 2;
}
else
*scratchPtr++ = ch;
}
*scratchPtr = '\0';
result = PL_strdup (scratchBuf); // realloc down to smaller size
PR_Free(scratchBuf);
}
return result;
}
//////////////////////////////////////////////////////////////////////////////////
// The nsNntpTestDriver is a class that I envision could be generalized to form the
// building block of a protocol test harness. To configure it, you would list all of
// the events you know how to handle and when one of those events is triggered, you
// would be asked to process it....right now it is just NNTP specific....
///////////////////////////////////////////////////////////////////////////////////
class nsNntpTestDriver
{
public:
nsNntpTestDriver(nsINetService * pService);
virtual ~nsNntpTestDriver();
// run driver initializes the instance, lists the commands, runs the command and when
// the command is finished, it reads in the next command and continues...theoretically,
// the client should only ever have to call RunDriver(). It should do the rest of the
// work....
nsresult RunDriver();
// User drive commands
void InitializeTestDriver(); // will end up prompting the user for things like host, port, etc.
nsresult ListCommands(); // will list all available commands to the user...i.e. "get groups, get article, etc."
nsresult ReadAndDispatchCommand(); // reads a command number in from the user and calls the appropriate command generator
nsresult PromptForUserDataAndBuildUrl(const char * userPrompt);
// The following are event generators. They convert all of the available user commands into
// URLs and then run the urls.
nsresult OnListAllGroups(); // lists all the groups on the host
nsresult OnListIDs();
nsresult OnGetGroup(); // lists the status of the user specified group...
nsresult OnListArticle();
nsresult OnSearch();
nsresult OnExit();
protected:
char m_urlSpec[200]; // "sockstub://hostname:port" it does not include the command specific data...
char m_urlString[500]; // string representing the current url being run. Includes host AND command specific data.
char m_userData[250]; // generic string buffer for storing the current user entered data...
// host and port info...
PRUint32 m_port;
char m_host[200];
nsINntpUrl * m_url;
nsNNTPProtocol * m_nntpProtocol; // running protocol instance
nsITransport * m_transport; // a handle on the current transport object being used with the protocol binding...
PRBool m_runningURL; // are we currently running a url? this flag is set to false on exit...
void InitializeProtocol(const char * urlSpec);
PRBool m_protocolInitialized;
};
nsNntpTestDriver::nsNntpTestDriver(nsINetService * pNetService)
{
m_urlSpec[0] = '\0';
m_urlString[0] = '\0';
m_url = nsnull;
m_protocolInitialized = PR_FALSE;
m_runningURL = PR_TRUE;
InitializeTestDriver(); // prompts user for initialization information...
// create a transport socket...
pNetService->CreateSocketTransport(&m_transport, m_port, m_host);
m_nntpProtocol = nsnull; // we can't create it until we have a url...
}
void nsNntpTestDriver::InitializeProtocol(const char * urlString)
{
// this is called when we don't have a url nor a protocol instance yet...
NS_NewNntpUrl(&m_url, urlString);
// now create a protocl instance...
m_nntpProtocol = new nsNNTPProtocol(m_url, m_transport);
m_protocolInitialized = PR_TRUE;
}
nsNntpTestDriver::~nsNntpTestDriver()
{
NS_IF_RELEASE(m_url);
NS_IF_RELEASE(m_transport);
delete m_nntpProtocol;
}
nsresult nsNntpTestDriver::RunDriver()
{
nsresult status = NS_OK;
while (m_runningURL)
{
// if we haven't gotten started (and created a protocol) or
// if the protocol instance is currently not busy, then read in a new command
// and process it...
if ((!m_nntpProtocol) || m_nntpProtocol->IsRunningUrl() == PR_FALSE) // if we aren't running the url anymore, ask ueser for another command....
{
status = ReadAndDispatchCommand();
} // if running url
#ifdef XP_PC
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#endif
} // until the user has stopped running the url (which is really the test session.....
return status;
}
void nsNntpTestDriver::InitializeTestDriver()
{
// prompt the user for port and host name
char portString[20]; // used to read in the port string
char hostString[200];
portString[0] = '\0';
hostString[0] = '\0';
m_host[0] = '\0';
m_port = DEFAULT_PORT;
// load default host name and set the start of the url
PL_strcpy(m_host, DEFAULT_HOST);
PL_strcpy(m_urlSpec, DEFAULT_URL_TYPE); // copy "sockstub://" part into url spec...
// prompt user for port...
printf("Enter port to use [%d]: ", m_port);
scanf("%[^\n]", portString);
if (portString && *portString)
{
m_port = atoi(portString);
}
scanf("%c", portString); // eat the extra CR
// now prompt for the host name....
printf("Enter host name to use [%s]: ", m_host);
scanf("%[^\n]", hostString);
scanf("%c", portString); // eat the extra CR
if(hostString && *hostString)
{
PL_strcpy(m_host, hostString);
}
PL_strcat(m_urlSpec, m_host);
// we'll actually build the url (spec + user data) once the user has specified a command they want to try...
}
// prints the userPrompt and then reads in the user data. Assumes urlData has already been allocated.
// it also reconstructs the url string in m_urlString but does NOT reload it....
nsresult nsNntpTestDriver::PromptForUserDataAndBuildUrl(const char * userPrompt)
{
char tempBuffer[500];
tempBuffer[0] = '\0';
if (userPrompt && *userPrompt)
printf(userPrompt);
else
printf("Enter data for command: ");
scanf("%[^\n]", tempBuffer);
if (*tempBuffer)
{
if (tempBuffer[0]) // kill off any CR or LFs...
{
PRUint32 length = PL_strlen(tempBuffer);
if (length > 0 && tempBuffer[length-1] == '\r')
tempBuffer[length-1] = '\0';
// okay, user gave us a valid line so copy it into the user data field..o.t. leave user
// data field untouched. This allows us to use default values for things...
m_userData[0] = '\0';
PL_strcpy(m_userData, tempBuffer);
}
}
char buffer[2];
scanf("%c", buffer); // eat up the CR that is still in the input stream...
return NS_OK;
}
nsresult nsNntpTestDriver::ReadAndDispatchCommand()
{
nsresult status = NS_OK;
PRInt32 command = 0;
char commandString[5];
commandString[0] = '\0';
printf("Enter command number: ");
scanf("%[^\n]", commandString);
if (commandString && *commandString)
{
command = atoi(commandString);
}
scanf("%c", commandString); // eat the extra CR
// now switch on command to the appropriate
switch (command)
{
case 0:
status = ListCommands();
break;
case 1:
status = OnListAllGroups();
break;
case 2:
status = OnGetGroup();
break;
case 3:
status = OnListIDs();
break;
case 4:
status = OnListArticle();
break;
case 5:
status = OnSearch();
break;
default:
status = OnExit();
break;
}
return status;
}
nsresult nsNntpTestDriver::ListCommands()
{
printf("Commands currently available: \n");
printf("0) List available commands. \n");
printf("1) List all news groups. \n");
printf("2) Get (and subscribe) to a group. \n");
printf("3) List ids. \n");
printf("4) Get an article. \n");
printf("5) Perform Search. \n");
printf("9) Exit the test application. \n");
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////
// Begin protocol specific command url generation code...gee that's a mouthful....
///////////////////////////////////////////////////////////////////////////////////
nsresult nsNntpTestDriver::OnExit()
{
printf("Terminating NNTP test harness....\n");
m_runningURL = PR_FALSE; // next time through the test driver loop, we'll kick out....
return NS_OK;
}
nsresult nsNntpTestDriver::OnListAllGroups()
{
nsresult rv = NS_OK;
// no prompt for url data....just append a '*' to the url data and run it...
m_urlString[0] = '\0';
PL_strcpy(m_urlString, m_urlSpec);
PL_strcat(m_urlString, "/");
PL_strcat(m_urlString, "*");
if (m_protocolInitialized == PR_FALSE)
InitializeProtocol(m_urlString);
m_url->SetSpec(m_urlString); // reset spec
rv = m_nntpProtocol->LoadURL(m_url);
return rv;
}
nsresult nsNntpTestDriver::OnListIDs()
{
nsresult rv = NS_OK;
// no prompt for url data....just append a '*' to the url data and run it...
m_urlString[0] = '\0';
PL_strcpy(m_urlString, m_urlSpec);
PL_strcat(m_urlString, "/");
rv = PromptForUserDataAndBuildUrl("Group to fetch IDs for: ");
PL_strcat(m_urlString, m_userData);
PL_strcat(m_urlString, "?list-ids");
if (m_protocolInitialized == PR_FALSE)
InitializeProtocol(m_urlString);
else
rv = m_url->SetSpec(m_urlString); // reset spec
// load the correct newsgroup interface as an event sink...
if (NS_SUCCEEDED(rv))
{
// before we re-load, assume it is a group command and configure our nntpurl correctly...
nsINNTPHost * host = nsnull;
nsINNTPNewsgroup * group = nsnull;
nsINNTPNewsgroupList * list = nsnull;
rv = m_url->GetNntpHost(&host);
if (host)
{
rv = host->FindGroup(m_userData, &group);
if (group)
group->GetNewsgroupList(&list);
rv = m_url->SetNewsgroup(group);
rv = m_url->SetNewsgroupList(list);
NS_IF_RELEASE(group);
NS_IF_RELEASE(list);
NS_IF_RELEASE(host);
}
rv = m_nntpProtocol->LoadURL(m_url);
} // if user provided the data...
return rv;
}
nsresult nsNntpTestDriver::OnListArticle()
{
nsresult rv = NS_OK;
// first, prompt the user for the name of the group to fetch
// prime article number with a default value...
m_userData[0] = '\0';
PL_strcpy(m_userData, "35D8A048.3C0F0C7A@zia.mcom.com");
rv = PromptForUserDataAndBuildUrl("Article Number to Fetch: ");
// no prompt for url data....just append a '*' to the url data and run it...
m_urlString[0] = '\0';
PL_strcpy(m_urlString, m_urlSpec);
PL_strcat(m_urlString, "/");
PL_strcat(m_urlString, m_userData);
if (m_protocolInitialized == PR_FALSE)
InitializeProtocol(m_urlString);
else
m_url->SetSpec(m_urlString); // reset spec
if (NS_SUCCEEDED(rv))
{
// before we re-load, assume it is a group command and configure our nntpurl correctly...
nsINNTPHost * host = nsnull;
nsINNTPNewsgroup * group = nsnull;
nsINNTPNewsgroupList * list = nsnull;
rv = PromptForUserDataAndBuildUrl("Group article is in: ");
rv = m_url->GetNntpHost(&host);
if (host)
{
rv = host->FindGroup(m_userData, &group);
if (group)
group->GetNewsgroupList(&list);
rv = m_url->SetNewsgroup(group);
rv = m_url->SetNewsgroupList(list);
NS_IF_RELEASE(group);
NS_IF_RELEASE(list);
NS_IF_RELEASE(host);
}
rv = m_nntpProtocol->LoadURL(m_url);
} // if user provided the data...
return rv;
}
nsresult nsNntpTestDriver::OnSearch()
{
nsresult rv = NS_OK;
// first, prompt the user for the name of the group to fetch
rv = PromptForUserDataAndBuildUrl("Group to search: ");
m_urlString[0] = '\0';
PL_strcpy(m_urlString, m_urlSpec);
PL_strcat(m_urlString, "/");
PL_strcat(m_urlString, m_userData);
// now append "?search" to the end...
PL_strcat(m_urlString, "?search/");
rv = PromptForUserDataAndBuildUrl("Search criteria: ");
if (m_userData[0]) // did the user enter in something???
{
char * escapedBuffer = MSG_EscapeSearchUrl(m_userData);
PL_strcat(m_urlString, escapedBuffer);
}
if (m_protocolInitialized == PR_FALSE)
InitializeProtocol(m_urlString);
else
m_url->SetSpec(m_urlString); // reset spec
if (NS_SUCCEEDED(rv))
{
// before we re-load, assume it is a group command and configure our nntpurl correctly...
nsINNTPHost * host = nsnull;
nsINNTPNewsgroup * group = nsnull;
nsINNTPNewsgroupList * list = nsnull;
rv = m_url->GetNntpHost(&host);
if (host)
{
rv = host->FindGroup(m_userData, &group);
if (group)
group->GetNewsgroupList(&list);
rv = m_url->SetNewsgroup(group);
rv = m_url->SetNewsgroupList(list);
NS_IF_RELEASE(group);
NS_IF_RELEASE(list);
NS_IF_RELEASE(host);
}
rv = m_nntpProtocol->LoadURL(m_url);
} // if user provided the data...
return rv;
}
nsresult nsNntpTestDriver::OnGetGroup()
{
nsresult rv = NS_OK;
// first, prompt the user for the name of the group to fetch
rv = PromptForUserDataAndBuildUrl("Group to fetch: ");
// no prompt for url data....just append a '*' to the url data and run it...
m_urlString[0] = '\0';
PL_strcpy(m_urlString, m_urlSpec);
PL_strcat(m_urlString, "/");
PL_strcat(m_urlString, m_userData);
if (m_protocolInitialized == PR_FALSE)
InitializeProtocol(m_urlString);
else
m_url->SetSpec(m_urlString); // reset spec
if (NS_SUCCEEDED(rv))
{
// before we re-load, assume it is a group command and configure our nntpurl correctly...
nsINNTPHost * host = nsnull;
nsINNTPNewsgroup * group = nsnull;
nsINNTPNewsgroupList * list = nsnull;
rv = m_url->GetNntpHost(&host);
if (host)
{
rv = host->FindGroup(m_userData, &group);
if (group)
group->GetNewsgroupList(&list);
rv = m_url->SetNewsgroup(group);
rv = m_url->SetNewsgroupList(list);
NS_IF_RELEASE(group);
NS_IF_RELEASE(list);
NS_IF_RELEASE(host);
}
rv = m_nntpProtocol->LoadURL(m_url);
} // if user provided the data...
return rv;
}
int main()
{
nsINetService * pNetService;
nsresult result;
nsIURL * pURL = NULL;
PL_InitializeEventsLib("");
nsRepository::RegisterFactory(kNetServiceCID, NETLIB_DLL, PR_FALSE, PR_FALSE);
nsRepository::RegisterFactory(kEventQueueServiceCID, XPCOM_DLL, PR_FALSE, PR_FALSE);
// Create the Event Queue for this thread...
nsIEventQueueService *pEventQService = nsnull;
result = nsServiceManager::GetService(kEventQueueServiceCID,
kIEventQueueServiceIID,
(nsISupports **)&pEventQService);
if (NS_SUCCEEDED(result)) {
// XXX: What if this fails?
result = pEventQService->CreateThreadEventQueue();
}
// ask the net lib service for a nsINetStream:
result = NS_NewINetService(&pNetService, NULL);
if (NS_FAILED(result) || !pNetService)
{
printf("unable to initialize net serivce. \n");
return 1;
}
// now register a mime converter....
NET_RegisterContentTypeConverter (MESSAGE_RFC822, FO_NGLAYOUT, NULL, MIME_MessageConverter);
NET_RegisterContentTypeConverter (MESSAGE_RFC822, FO_CACHE_AND_NGLAYOUT, NULL, MIME_MessageConverter);
// okay, everything is set up, now we just need to create a test driver and run it...
nsNntpTestDriver * driver = new nsNntpTestDriver(pNetService);
if (driver)
{
driver->RunDriver();
// when it kicks out...it is done....so delete it...
delete driver;
}
// shut down:
NS_RELEASE(pNetService);
return 0;
}

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

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; 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.
*/
/* This is a stub event sink for a NNTP Newsgroup introduced by mscott to test
the NNTP protocol */
#include "nsISupports.h" /* interface nsISupports */
#include "nsINNTPCategoryContainer.h"
#include "nsINNTPNewsgroup.h" /* interface nsINNTPNewsgroup */
#include "nscore.h"
#include "plstr.h"
#include "prmem.h"
#include <stdio.h>
static NS_DEFINE_IID(kINNTPCategoryContainerIID, NS_INNTPCATEGORYCONTAINER_IID);
class nsNNTPCategoryContainerStub : public nsISupports {
public:
nsNNTPCategoryContainerStub();
virtual ~nsNNTPCategoryContainerStub();
NS_DECL_ISUPPORTS
NS_IMETHOD GetRootCategory(nsINNTPNewsgroup * *aRootCategory);
NS_IMETHOD SetRootCategory(nsINNTPNewsgroup * aRootCategory);
protected:
nsINNTPNewsgroup * m_newsgroup;
};
NS_IMPL_ISUPPORTS(nsNNTPCategoryContainerStub, kINNTPCategoryContainerIID);
nsNNTPCategoryContainerStub::nsNNTPCategoryContainerStub()
{
NS_INIT_REFCNT();
m_newsgroup = nsnull;
}
nsNNTPCategoryContainerStub::~nsNNTPCategoryContainerStub()
{
printf("Destroying category container. \n");
NS_IF_RELEASE(m_newsgroup);
}
nsresult nsNNTPCategoryContainerStub::GetRootCategory(nsINNTPNewsgroup * *aRootCategory)
{
if (aRootCategory)
{
*aRootCategory = m_newsgroup;
NS_IF_ADDREF(m_newsgroup);
}
return NS_OK;
}
nsresult nsNNTPCategoryContainerStub::SetRootCategory(nsINNTPNewsgroup * aRootCategory)
{
if (aRootCategory)
{
char * name = nsnull;
aRootCategory->GetName(&name);
printf("Setting root category for container to %s", name ? name : "unspecified");
m_newsgroup = aRootCategory;
NS_IF_ADDREF(m_newsgroup);
}
return NS_OK;
}
extern "C" {
nsresult NS_NewCategoryContainerFromNewsgroup(nsINNTPCategoryContainer ** aInstancePtr, nsINNTPNewsgroup* group)
{
nsresult rv = NS_OK;
nsNNTPCategoryContainerStub * stub = nsnull;
if (aInstancePtr)
{
stub = new nsNNTPCategoryContainerStub();
stub->SetRootCategory(group);
rv = stub->QueryInterface(kINNTPCategoryContainerIID, (void **) aInstancePtr);
}
return rv;
}
}

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

@ -0,0 +1,693 @@
/* -*- Mode: C++; tab-width: 4; 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.
*/
/* This is a stub event sink for a NNTP Host introduced by mscott to test
the NNTP protocol */
#include "nsINNTPHost.h"
#include "nscore.h"
#include "plstr.h"
#include "prmem.h"
#include <stdio.h>
#include "nsINNTPNewsgroup.h"
#include "nsMsgGroupRecord.h"
#include "nsMsgPtrArray.h"
#include "nsNNTPNewsgroupList.h"
#include "nsNNTPNewsgroup.h"
static NS_DEFINE_IID(kINNTPHostIID, NS_INNTPHOST_IID);
static NS_DEFINE_IID(kINNTPNewsgroupIID, NS_INNTPNEWSGROUP_IID);
class nsNNTPHostStub : public nsINNTPHost
{
public:
nsNNTPHostStub(const char *name, PRInt32 port);
virtual ~nsNNTPHostStub();
// nsISupports
NS_DECL_ISUPPORTS
// nsINNTPHost
NS_IMETHOD GetSupportsExtensions(PRBool *aSupportsExtensions);
NS_IMETHOD SetSupportsExtensions(PRBool aSupportsExtensions);
NS_IMETHOD AddExtension (const char *ext);
NS_IMETHOD QueryExtension (const char *ext, PRBool *_retval);
NS_IMETHOD GetPostingAllowed(PRBool * aPostingAllowed);
NS_IMETHOD SetPostingAllowed(PRBool aPostingAllowed);
NS_IMETHOD GetPushAuth(PRBool *aPushAuth);
NS_IMETHOD SetPushAuth(PRBool aPushAuth);
NS_IMPL_CLASS_GETSET(LastUpdatedTime, PRInt64, m_lastGroupUpdate);
NS_IMETHOD GetNewsgroupList(const char *groupname, nsINNTPNewsgroupList **_retval);
NS_IMETHOD GetNewsgroupAndNumberOfID(const char *message_id,
nsINNTPNewsgroup **group,
PRUint32 *messageNumber);
/* get this from MSG_Master::FindNewsFolder */
NS_IMETHOD FindNewsgroup(const char *groupname, PRBool create,
nsINNTPNewsgroup **_retval) { return FindGroup(groupname, _retval);}
NS_IMETHOD AddPropertyForGet (const char *property, const char *value);
NS_IMETHOD QueryPropertyForGet (const char *property, char **_retval);
NS_IMETHOD AddSearchableGroup(const char *groupname);
// should these go into interfaces?
NS_IMETHOD QuerySearchableGroup (const char *group, PRBool *);
//NS_IMETHOD QuerySearchableGroupCharsets(const char *group, char **);
// Virtual groups
NS_IMETHOD AddVirtualGroup(const char *responseText) { return NS_OK;}
NS_IMETHOD SetIsVirtualGroup(const char *groupname, PRBool isVirtual);
NS_IMETHOD GetIsVirtualGroup(const char *groupname, PRBool *_retval);
// custom/searchable headers
NS_IMETHOD AddSearchableHeader(const char *headerName);
NS_IMETHOD QuerySearchableHeader(const char *headerName, PRBool *_retval);
// Go load the newsrc for this host. Creates the subscribed hosts as
// children of the given nsIMsgFolder.
NS_IMETHOD LoadNewsrc();
// Write out the newsrc for this host right now. In general, either
// MarkDirty() or WriteIfDirty() should be called instead.
NS_IMETHOD WriteNewsrc();
// Write out the newsrc for this host right now, if anything has changed
// in it.
NS_IMETHOD WriteIfDirty();
// Note that something has changed, and we need to rewrite the newsrc file
// for this host at some point.
NS_IMETHOD MarkDirty();
/* the Setter implementation is a little more complex */
NS_IMPL_CLASS_GETTER(GetNewsRCFilename, char *, m_filename);
NS_IMETHOD SetNewsRCFilename(char *);
NS_IMETHOD FindGroup(const char* name, nsINNTPNewsgroup* *_retval);
NS_IMETHOD AddGroup(const char *groupname,
nsINNTPNewsgroup **retval);
//NS_IMETHOD AddGroup(const char *groupname,
// nsMsgGroupRecord *groupRecord,
// nsINNTPNewsgroup **retval);
NS_IMETHOD RemoveGroupByName(const char *groupName);
NS_IMETHOD RemoveGroup(const nsINNTPNewsgroup*);
NS_IMETHOD AddNewNewsgroup(const char *groupName,
PRInt32 first,
PRInt32 last,
const char *flags,
PRBool xactiveFlags);
/* Name of directory to store newsgroup
databases in. This needs to have
"/groupname" appended to it, and the
whole thing can be passed to the XP_File
stuff with a type of xpXoverCache. */
NS_IMETHOD GetDbDirName(char * *aDbDirName);
/* Returns a list of newsgroups. The result
must be free'd using PR_Free(); the
individual strings must not be free'd. */
NS_IMETHOD GetGroupList(char **_retval);
NS_IMETHOD DisplaySubscribedGroup(const char *groupname,
PRInt32 first_message,
PRInt32 last_message,
PRInt32 total_messages,
PRBool visit_now);
// end of nsINNTPHost
private:
virtual PRBool IsNews () { return PR_TRUE; }
virtual nsINNTPHost *GetNewsHost() { return this; }
// Get the nsIMsgFolder which represents this host; the children
// of this nsIMsgFolder are the groups in this host.
nsIMsgFolder* GetHostInfo() {return m_hostinfo;}
// GetNumGroupsNeedingCounts() returns how many newsgroups we have
// that we don't have an accurate count of unread/total articles.
NS_IMETHOD GetNumGroupsNeedingCounts(PRInt32 *);
// GetFirstGroupNeedingCounts() returns the name of the first newsgroup
// that does not have an accurate count of unread/total articles. The
// string must be free'd by the caller using PR_Free().
NS_IMETHOD GetFirstGroupNeedingCounts(char **);
// GetFirstGroupNeedingExtraInfo() returns the name of the first newsgroup
// that does not have extra info (xactive flags and prettyname). The
// string must be free'd by the caller using PR_Free().
NS_IMETHOD GetFirstGroupNeedingExtraInfo(char **);
// Returns the pretty name for the given group. The resulting string
// must be free'd using delete[].
char* GetPrettyName(const char* groupname) { return m_prettyName;}
NS_IMETHOD SetPrettyName(const char* groupname, const char* prettyname);
NS_IMETHOD SetGroupNeedsExtraInfo(const char *groupname, PRBool value);
// Finds the container newsgroup for this category (or NULL if this isn't
// a category). The resulting string must be free'd using delete[].
char* GetCategoryContainer(const char* groupname, nsMsgGroupRecord *inGroupRecord = NULL);
nsINNTPNewsgroup *GetCategoryContainerFolderInfo(const char *groupname);
nsMsgGroupRecord* GetGroupTree() {return m_groupTree;}
NS_IMETHOD GroupNotFound(const char *groupName, PRBool opening);
protected:
char* m_hostname;
char * m_prettyName;
PRInt32 m_port;
nsISupportsArray *m_groups; // List of nsINNTPNewsgroup* objects.
nsIMsgFolder* m_hostinfo; // Object representing entire newshost in
// tree.
char* m_optionLines;
char* m_filename; /* The name of the newsrc file associated with
this host. This will be of the form:
"" meaning .newsrc or .snewsrc
HOST meaning .newsrc-HOST
HOST:PORT meaning .newsrc-HOST:PORT
Whether it begins with .newsrc or .snewsrc
depends on a special property slot
(we pass one of
the types xpNewsRC or xpSNewsRC to xp_file.)
The reason this is not simply derived from
the host_name and port slots is that it's
not a 1:1 mapping; if the user has a file
called "newsrc", we will use that for the
default host (the "" name.) Likewise,
".newsrc-H" and ".newsrc-H:119" are
ambiguous.
*/
char* m_dbfilename;
PRBool m_dirty;
PRBool m_supportsExtensions;
PRBool m_everexpanded; // Whether the user ever opened up this
// newshost this session.
PRBool m_checkedForNew; // Whether we've checked for new newgroups
// in this newshost this session.
PRBool m_groupSucceeded; // Whether a group command has succeeded this
// session, protect against server bustage
// where it says no group exists.
XPPtrArray m_supportedExtensions;
XPPtrArray m_searchableGroups;
XPPtrArray m_searchableHeaders;
XPPtrArray m_propertiesForGet;
XPPtrArray m_valuesForGet;
PRBool m_postingAllowed;
PRBool m_pushAuth; // PR_TRUE if we should volunteer authentication without a
// challenge
nsMsgGroupRecord* m_groupTree; // Tree of groups we're remembering.
PRInt64 m_lastGroupUpdate;
};
NS_IMPL_ISUPPORTS(nsNNTPHostStub, kINNTPHostIID);
nsNNTPHostStub::nsNNTPHostStub(const char * name, PRInt32 port)
{
NS_INIT_REFCNT();
m_supportsExtensions = PR_FALSE;
m_postingAllowed = PR_FALSE;
m_lastGroupUpdate = 0;
NS_NewISupportsArray(&m_groups);
}
nsNNTPHostStub::~nsNNTPHostStub()
{
}
nsresult nsNNTPHostStub::GetSupportsExtensions(PRBool *aSupportsExtensions)
{
printf("Supports Extensions: %s. \n", m_supportsExtensions ? "TRUE" : "FALSE");
if (aSupportsExtensions)
*aSupportsExtensions = m_supportsExtensions;
return NS_OK;
}
nsresult nsNNTPHostStub::SetSupportsExtensions(PRBool aSupportsExtensions)
{
m_supportsExtensions = aSupportsExtensions;
printf("Setting supports extensions to: %s. \n", m_supportsExtensions ? "TRUE" : "FALSE");
return NS_OK;
}
nsresult nsNNTPHostStub::AddExtension(const char * extension)
{
printf("Adding extension: %s. \n", extension ? extension : "invalid extension");
return NS_OK;
}
nsresult nsNNTPHostStub::QueryExtension(const char * extension, PRBool * aRetValue)
{
printf("Querying extension %s. \n", extension ? extension : "invalid extension");
if (PL_strstr(extension, "SEARCH"))
*aRetValue = PR_TRUE;
else
*aRetValue = PR_FALSE;
return NS_OK;
}
nsresult nsNNTPHostStub::GetPostingAllowed(PRBool * aPostingAllowed)
{
printf("Posting Allowed: %s. \n", m_postingAllowed ? "TRUE" : "FALSE");
if (aPostingAllowed)
*aPostingAllowed = m_postingAllowed;
return NS_OK;
}
nsresult nsNNTPHostStub::SetPostingAllowed(PRBool aPostingAllowed)
{
m_postingAllowed = aPostingAllowed;
printf("Setting posting allowed to: %s. \n", m_postingAllowed ? "TRUE" : "FALSE");
return NS_OK;
}
nsresult nsNNTPHostStub::GetPushAuth(PRBool * aPushAuth)
{
printf("Push Authentication: %s. \n", m_pushAuth ? "TRUE" : "FALSE");
if (aPushAuth)
*aPushAuth = m_pushAuth;
return NS_OK;
}
nsresult nsNNTPHostStub::SetPushAuth(PRBool aPushAuth)
{
m_pushAuth = aPushAuth;
printf("Setting push auth to: %s. \n", m_pushAuth ? "TRUE" : "FALSE");
return NS_OK;
}
nsresult nsNNTPHostStub::AddPropertyForGet (const char *property, const char *value)
{
char *tmp = NULL;
tmp = PL_strdup(property);
if (tmp)
m_propertiesForGet.Add (tmp);
tmp = PL_strdup(value);
if (tmp)
m_valuesForGet.Add (tmp);
printf("Adding property %s for value %s. \n", property, value);
// this is odd. do we need this return value?
return NS_OK;
}
nsresult nsNNTPHostStub::QueryPropertyForGet (const char *property, char **retval)
{
*retval=NULL;
for (int i = 0; i < m_propertiesForGet.GetSize(); i++)
if (!PL_strcasecmp(property, (const char *) m_propertiesForGet.GetAt(i))) {
*retval = (char *)m_valuesForGet.GetAt(i);
printf("Retrieving property %s for get. \n", *retval);
return NS_OK;
}
return NS_OK;
}
nsresult nsNNTPHostStub::AddSearchableGroup (const char *group)
{
PRBool searchableGroup;
nsresult rv = QuerySearchableGroup(group, &searchableGroup);
if (NS_SUCCEEDED(rv) && !searchableGroup)
{
char *ourGroup = PL_strdup (group);
if (ourGroup)
{
// strip off character set spec
char *space = PL_strchr(ourGroup, ' ');
if (space)
*space = '\0';
m_searchableGroups.Add(ourGroup);
printf("Adding %s to list of searchable groups. \n", ourGroup);
space++; // walk over to the start of the charsets
// Add the group -> charset association.
// XP_Puthash(m_searchableGroupCharsets, ourGroup, space);
}
}
return NS_OK;
}
nsresult nsNNTPHostStub::QuerySearchableGroup (const char *group, PRBool *_retval)
{
*_retval = PR_FALSE;
for (int i = 0; i < m_searchableGroups.GetSize(); i++)
{
const char *searchableGroup = (const char*) m_searchableGroups.GetAt(i);
char *starInSearchableGroup = NULL;
if (!PL_strcmp(searchableGroup, "*")) {
*_retval = PR_TRUE; // everything is searchable
return NS_OK;
}
else if (NULL != (starInSearchableGroup = PL_strchr(searchableGroup, '*')))
{
if (!PL_strncasecmp(group, searchableGroup, PL_strlen(searchableGroup)-2)) {
*_retval = PR_TRUE; // this group is in a searchable hierarchy
return NS_OK;
}
}
else if (!PL_strcasecmp(group, searchableGroup)) {
*_retval = PR_TRUE; // this group is individually searchable
return NS_OK;
}
}
return NS_OK;
}
nsresult nsNNTPHostStub::SetIsVirtualGroup(const char * groupname, PRBool isVirtual)
{
return NS_OK;
}
nsresult nsNNTPHostStub::GetIsVirtualGroup(const char * groupname, PRBool * isVirtual)
{
*isVirtual = PR_FALSE;
return NS_OK;
}
nsresult nsNNTPHostStub::AddSearchableHeader (const char *header)
{
PRBool searchable;
nsresult rv = QuerySearchableHeader(header, &searchable);
if (NS_SUCCEEDED(rv) && searchable)
{
char *ourHeader = PL_strdup(header);
if (ourHeader)
m_searchableHeaders.Add(ourHeader);
printf("Added %s as a searchable header. \n", ourHeader);
}
return NS_OK;
}
nsresult nsNNTPHostStub::QuerySearchableHeader(const char *header, PRBool *retval)
{
*retval=PR_FALSE;
for (int i = 0; i < m_searchableHeaders.GetSize(); i++)
if (!PL_strncasecmp(header, (char*) m_searchableHeaders.GetAt(i), PL_strlen(header))) {
*retval = PR_TRUE;
return NS_OK;
}
return NS_OK;
}
nsresult nsNNTPHostStub::GroupNotFound(const char *groupName, PRBool opening)
{
printf("Group %s not found. \n", groupName);
return NS_OK;
}
nsresult nsNNTPHostStub::AddNewNewsgroup(const char *groupName,
PRInt32 first,
PRInt32 last,
const char *flags,
PRBool xactiveFlags)
{
printf ("Adding new newsgroup: %s. \n", groupName);
nsINNTPNewsgroup * group = nsnull;
AddGroup(groupName, &group);
NS_IF_RELEASE(group); // we don't care about it...
return NS_OK;
}
nsresult nsNNTPHostStub::GetNumGroupsNeedingCounts(PRInt32 * aNumGroups)
{
printf("Getting number of groups needing counts. \n");
*aNumGroups = 0;
return NS_OK;
}
nsresult nsNNTPHostStub::GetFirstGroupNeedingCounts(char ** aFirstGroup)
{
*aFirstGroup = nsnull;
return NS_OK;
}
nsresult nsNNTPHostStub::DisplaySubscribedGroup(const char * groupname, PRInt32 first_message, PRInt32 last_message, PRInt32 total_messages,
PRBool visit_now)
{
printf("Displaying subscribed group %s which has %d total messages. \n", groupname, total_messages);
nsresult rv;
nsINNTPNewsgroup *newsgroup=NULL;
rv = FindGroup(groupname, &newsgroup);
// SetGroupSucceeded(TRUE);
if (!newsgroup && visit_now) // let's try autosubscribe...
{
rv = AddGroup(groupname, &newsgroup);
}
if (!newsgroup)
return NS_OK;
else
{
PRBool subscribed;
newsgroup->GetSubscribed(&subscribed);
if (!subscribed)
newsgroup->SetSubscribed(PR_TRUE);
}
if (!newsgroup) return NS_OK;
newsgroup->UpdateSummaryFromNNTPInfo(first_message, last_message,
total_messages);
return NS_OK;
}
nsresult nsNNTPHostStub::GetFirstGroupNeedingExtraInfo(char ** retval)
{
if (retval)
*retval = nsnull;
return NS_OK;
}
nsresult nsNNTPHostStub::SetGroupNeedsExtraInfo(const char * groupName, PRBool needsExtraInfo)
{
printf("Setting group %s to need extra info.\n", groupName);
return NS_OK;
}
nsresult nsNNTPHostStub::GetNewsgroupAndNumberOfID(const char *messageID, nsINNTPNewsgroup ** group, PRUint32 * messageNumber)
{
return NS_OK;
}
nsresult nsNNTPHostStub::SetPrettyName(const char * groupname, const char * prettyname)
{
printf("Setting group %s to have pretty name %s. \n", groupname, prettyname);
return NS_OK;
}
nsresult nsNNTPHostStub::LoadNewsrc()
{
printf("Loading newsrc....\n");
return NS_OK;
}
nsresult nsNNTPHostStub::WriteNewsrc()
{
printf("Writing out newsrc ...\n");
return NS_OK;
}
nsresult nsNNTPHostStub::WriteIfDirty()
{
return NS_OK;
}
nsresult nsNNTPHostStub::MarkDirty()
{
return NS_OK;
}
#if 0
nsresult nsNNTPHostStub::GetNewsRCFilename(char ** aNewsRCFileName)
{
if (aNewsRCFileName)
*aNewsRCFileName = "temp.rc";
return NS_OK;
}
#endif
nsresult nsNNTPHostStub::SetNewsRCFilename(char * fileName)
{
printf ("Setting newsrc file name to %s\n.", fileName);
return NS_OK;
}
nsresult nsNNTPHostStub::GetNewsgroupList(const char *groupname, nsINNTPNewsgroupList **_retval)
{
nsresult rv = NS_OK;
// find group with the group name...
nsINNTPNewsgroup * group = nsnull;
rv = FindGroup(groupname, &group);
if (group)
{
rv = group->GetNewsgroupList(_retval);
NS_RELEASE(group);
}
return rv;
}
nsresult nsNNTPHostStub::FindGroup(const char * name, nsINNTPNewsgroup ** retVal)
{
PRBool found = PR_FALSE;
*retVal = nsnull;
printf ("Looking up group %s.\n", name);
for (PRInt32 count = 0; count < m_groups->Count() && !found; count++)
{
nsISupports * elem = m_groups->ElementAt(count);
if (elem)
{
nsINNTPNewsgroup * group = nsnull;
elem->QueryInterface(kINNTPNewsgroupIID, (void **) &group);
if (group)
{
char * groupName = nsnull;
group->GetName(&groupName);
if (groupName && PL_strcmp(name, groupName) == 0)
{
found = PR_TRUE;
*retVal = group;
NS_ADDREF(group);
}
PR_FREEIF(groupName);
NS_RELEASE(group);
} // if group
NS_RELEASE(elem);
} // if elem
}
return NS_OK;
}
nsresult nsNNTPHostStub::AddGroup(const char *groupname, nsINNTPNewsgroup **retval)
{
nsresult rv = NS_OK;
printf ("Adding group %s to host.\n", groupname);
// turn the group name into a new news group and create a newsgroup list for it as well...
nsINNTPNewsgroup * group = nsnull;
rv = NS_NewNewsgroup(&group, nsnull, /* nsNNTPArticleSet * */ nsnull, PR_TRUE, this, 0);
if (group) // set the name for our group..
group->SetName((char *) groupname);
// generate a news group list for the new group...
nsINNTPNewsgroupList * list = nsnull;
rv = NS_NewNewsgroupList(&list,this, group);
// now bind the group list to the group....
if (list)
{
group->SetNewsgroupList(list);
NS_RELEASE(list);
}
// now add this group to our global list...
m_groups->AppendElement(group);
if (retval)
{
*retval = group;
NS_IF_ADDREF(group);
}
return NS_OK;
}
nsresult nsNNTPHostStub::RemoveGroup(const nsINNTPNewsgroup * group)
{
char * name = nsnull;
group->GetName(&name);
printf ("Removing group %s.\n", name ? name : "unspecified");
PR_FREEIF(name);
return NS_OK;
}
nsresult nsNNTPHostStub::RemoveGroupByName(const char *groupName)
{
printf ("Removing group %s. \n", groupName);
return NS_OK;
}
nsresult nsNNTPHostStub::GetDbDirName(char ** aDirName)
{
if (aDirName)
*aDirName = "temp.db";
return NS_OK;
}
nsresult nsNNTPHostStub::GetGroupList(char ** retVal)
{
if (retVal)
*retVal = nsnull;
return NS_OK;
}
extern "C"{
nsresult NS_NewNNTPHost(nsINNTPHost ** aInstancePtr, const char * name, PRUint32 port)
{
nsresult rv = NS_OK;
if (aInstancePtr)
{
nsNNTPHostStub * host = new nsNNTPHostStub(name, port);
if (host)
rv =host->QueryInterface(kINNTPHostIID, (void **) aInstancePtr);
}
return rv;
}
}

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

@ -0,0 +1,366 @@
/* -*- Mode: C++; tab-width: 4; 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.
*/
/* This is a stub event sink for a NNTP Newsgroup introduced by mscott to test
the NNTP protocol */
#include "nscore.h"
#include "plstr.h"
#include "prmem.h"
#include "nsCRT.h"
#include "prmem.h"
#include <stdio.h>
#include "nsISupports.h" /* interface nsISupports */
#include "nsINNTPNewsgroup.h"
#include "nsINNTPNewsgroupList.h"
#include "nsNNTPArticleSet.h"
#include "nsNNTPNewsgroupList.h"
/* temporary hack until MessageKey is defined */
typedef PRUint32 MessageKey;
static NS_DEFINE_IID(kINNTPNewsgroupListIID, NS_INNTPNEWSGROUPLIST_IID);
class nsNNTPNewsgroupListStub : public nsINNTPNewsgroupList {
public:
nsNNTPNewsgroupListStub(nsINNTPHost * host, nsINNTPNewsgroup * newsgroup);
virtual ~nsNNTPNewsgroupListStub();
NS_DECL_ISUPPORTS;
NS_IMETHOD GetRangeOfArtsToDownload(PRInt32 first_message, PRInt32 last_message, PRInt32 maxextra, PRInt32 *real_first_message,
PRInt32 *real_last_message, PRInt32 *_retval);
NS_IMETHOD AddToKnownArticles(PRInt32 first_message, PRInt32 last_message);
NS_IMETHOD InitXOVER(PRInt32 first_message, PRInt32 last_message);
NS_IMETHOD ProcessXOVER(const char *line, PRInt32 *status);
NS_IMETHOD ProcessNonXOVER(const char *line);
NS_IMETHOD ResetXOVER();
NS_IMETHOD FinishXOVER(PRInt32 status, PRInt32 *newstatus);
NS_IMETHOD ClearXOVERState();
protected:
NS_METHOD Init(nsINNTPHost *, nsINNTPNewsgroup*);
PRBool m_finishingXover;
nsINNTPHost* GetHost() {return m_host;}
const char * GetGroupName() {return m_groupName;}
PRBool m_startedUpdate;
PRBool m_getOldMessages;
PRBool m_promptedAlready;
PRBool m_downloadAll;
PRInt32 m_maxArticles;
char *m_groupName;
nsINNTPHost *m_host;
nsINNTPNewsgroup * m_group;
MessageKey m_lastProcessedNumber;
MessageKey m_firstMsgNumber;
MessageKey m_lastMsgNumber;
PRInt32 m_firstMsgToDownload;
PRInt32 m_lastMsgToDownload;
struct MSG_NewsKnown m_knownArts;
nsNNTPArticleSet *m_set;
};
NS_IMPL_ISUPPORTS(nsNNTPNewsgroupListStub, kINNTPNewsgroupListIID);
nsNNTPNewsgroupListStub::nsNNTPNewsgroupListStub(nsINNTPHost* host,
nsINNTPNewsgroup *newsgroup)
{
NS_INIT_REFCNT();
Init(host, newsgroup);
}
nsNNTPNewsgroupListStub::~nsNNTPNewsgroupListStub()
{
}
nsresult nsNNTPNewsgroupListStub::Init(nsINNTPHost * host, nsINNTPNewsgroup * newsgroup)
{
m_group = newsgroup;
NS_IF_ADDREF(newsgroup);
if (m_group)
m_group->GetName(&m_groupName);
m_host = host;
NS_IF_ADDREF(host);
m_lastProcessedNumber = 0;
m_lastMsgNumber = 0;
m_set = nsNNTPArticleSet::Create(host);
m_finishingXover = PR_FALSE;
m_startedUpdate = PR_FALSE;
m_knownArts.host = nsnull;
m_knownArts.set = m_set;
m_knownArts.first_possible = 0;
m_knownArts.last_possible = 0;
m_knownArts.shouldGetOldest = PR_FALSE;
m_knownArts.group_name = m_groupName;
m_knownArts.host = m_host;
NS_IF_ADDREF(m_host);
m_getOldMessages = PR_FALSE;
m_promptedAlready = PR_FALSE;
m_downloadAll = PR_FALSE;
m_maxArticles = 0;
m_firstMsgToDownload = 0;
m_lastMsgToDownload = 0;
return NS_OK;
}
nsresult nsNNTPNewsgroupListStub::GetRangeOfArtsToDownload(
PRInt32 first_possible,
PRInt32 last_possible,
PRInt32 maxextra,
PRInt32* first,
PRInt32* last,
PRInt32 *status)
{
PRBool emptyGroup_p = PR_FALSE;
if (!first || !last) return NS_ERROR_FAILURE;
*first = 0;
*last = 0;
m_set->SetLastMember(last_possible); // make sure highwater mark is valid.
m_knownArts.first_possible = first_possible;
m_knownArts.last_possible = last_possible;
/* Determine if we only want to get just new articles or more messages.
If there are new articles at the end we haven't seen, we always want to get those first.
Otherwise, we get the newest articles we haven't gotten, if we're getting more.
My thought for now is that opening a newsgroup should only try to get new articles.
Selecting "More Messages" will first try to get unseen messages, then old messages. */
if (m_getOldMessages || !m_knownArts.set->IsMember(last_possible))
{
}
m_firstMsgToDownload = *first;
m_lastMsgToDownload = *last;
if (status) *status=0;
return NS_OK;
}
nsresult nsNNTPNewsgroupListStub::AddToKnownArticles(PRInt32 first, PRInt32 last)
{
printf ("Adding articles %d to %d to known article set. \n", first, last);
int status;
// another temporary hack
nsINNTPHost *host = m_knownArts.host;
const char* group_name = m_knownArts.group_name;
if (m_knownArts.host != host ||
m_knownArts.group_name == NULL ||
PL_strcmp(m_knownArts.group_name, group_name) != 0 ||
!m_knownArts.set)
{
m_knownArts.host = host;
PR_FREEIF(m_knownArts.group_name);
m_knownArts.group_name = PL_strdup(group_name);
delete m_knownArts.set;
m_knownArts.set = nsNNTPArticleSet::Create();
if (!m_knownArts.group_name || !m_knownArts.set) {
return NS_ERROR_FAILURE;
}
}
status = m_knownArts.set->AddRange(first, last);
return status;
}
nsresult nsNNTPNewsgroupListStub::InitXOVER(PRInt32 first_msg, PRInt32 last_msg)
{
int status = 0;
/* Consistency checks, not that I know what to do if it fails (it will
probably handle it OK...) */
/* If any XOVER lines from the last time failed to come in, mark those
messages as read. */
if (m_lastProcessedNumber < m_lastMsgNumber)
{
m_set->AddRange(m_lastProcessedNumber + 1, m_lastMsgNumber);
}
m_firstMsgNumber = first_msg;
m_lastMsgNumber = last_msg;
m_lastProcessedNumber = first_msg > 1 ? first_msg - 1 : 1;
return status;
}
#define NEWS_ART_DISPLAY_FREQ 10
nsresult nsNNTPNewsgroupListStub::ProcessXOVER(const char *line, int *status)
{
const char *next;
PRUint32 message_number=0;
// PRInt32 lines;
PRBool read_p = PR_FALSE;
if (!line)
return NS_ERROR_FAILURE;
next = line;
if (m_set && message_number > m_lastProcessedNumber + 1)
{
/* There are some articles that XOVER skipped; they must no longer
exist. Mark them as read in the newsrc, so we don't include them
next time in our estimated number of unread messages. */
if (m_set->AddRange(m_lastProcessedNumber + 1, message_number - 1))
{
/* This isn't really an important enough change to warrant causing
the newsrc file to be saved; we haven't gathered any information
that won't also be gathered for free next time.
*/
}
}
m_lastProcessedNumber = message_number;
if (m_knownArts.set)
{
int result = m_knownArts.set->Add(message_number);
if (result < 0) {
if (status) *status = result;
return NS_ERROR_NOT_INITIALIZED;
}
}
if (message_number > m_lastMsgNumber)
m_lastMsgNumber = message_number;
else if (message_number < m_firstMsgNumber)
m_firstMsgNumber = message_number;
if (m_set) {
read_p = m_set->IsMember(message_number);
}
return NS_OK;
}
nsresult
nsNNTPNewsgroupListStub::ResetXOVER()
{
printf("Resetting XOVER for newsgroup list. \n");
m_lastMsgNumber = m_firstMsgNumber;
m_lastProcessedNumber = m_lastMsgNumber;
return 0;
}
/* When we don't have XOVER, but use HEAD, this is called instead.
It reads lines until it has a whole header block, then parses the
headers; then takes selected headers and creates an XOVER line
from them. This is more for simplicity and code sharing than
anything else; it means we end up parsing some things twice.
But if we don't have XOVER, things are going to be so horribly
slow anyway that this just doesn't matter.
*/
nsresult nsNNTPNewsgroupListStub::ProcessNonXOVER (const char * /*line*/)
{
// ### dmb write me
return NS_OK;
}
nsresult nsNNTPNewsgroupListStub::FinishXOVER (int status, int *newstatus)
{
struct MSG_NewsKnown* k;
/* If any XOVER lines from the last time failed to come in, mark those
messages as read. */
if (status >= 0 && m_lastProcessedNumber < m_lastMsgNumber)
{
m_set->AddRange(m_lastProcessedNumber + 1, m_lastMsgNumber);
}
k = &m_knownArts;
if (k->set)
{
PRInt32 n = k->set->FirstNonMember();
if (n < k->first_possible || n > k->last_possible)
{
/* We know we've gotten all there is to know. Take advantage of that to
update our counts... */
// ### dmb
}
}
if (m_finishingXover)
{
// turn on m_finishingXover - this is a horrible hack to avoid recursive
// calls which happen when the fe selects a message as a result of getting EndingUpdate,
// which interrupts this url right before it was going to finish and causes FinishXOver
// to get called again.
m_finishingXover = PR_TRUE;
// if we haven't started an update, start one so the fe
// will know to update the size of the view.
if (!m_startedUpdate)
{
m_startedUpdate = PR_TRUE;
}
m_startedUpdate = PR_FALSE;
if (m_lastMsgNumber > 0)
{
}
}
if (newstatus) *newstatus=0;
return NS_OK;
// nsNNTPNewsgroupList object gets deleted by the master when a new one is created.
}
nsresult nsNNTPNewsgroupListStub::ClearXOVERState()
{
return NS_OK;
}
extern "C" nsresult NS_NewNewsgroupList(nsINNTPNewsgroupList **aInstancePtrResult,
nsINNTPHost *newsHost,
nsINNTPNewsgroup *newsgroup)
{
nsNNTPNewsgroupListStub * stub = nsnull;
stub = new nsNNTPNewsgroupListStub(newsHost, newsgroup);
nsresult rv = stub->QueryInterface(kINNTPNewsgroupListIID, (void **) aInstancePtrResult);
return rv;
}

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

@ -0,0 +1,337 @@
/* -*- Mode: C++; tab-width: 4; 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.
*/
/* This is a stub event sink for a NNTP Newsgroup introduced by mscott to test
the NNTP protocol */
#include "nscore.h"
#include "plstr.h"
#include "prmem.h"
#include <stdio.h>
#include "nsISupports.h" /* interface nsISupports */
#include "nsINNTPNewsgroup.h"
#include "nsNNTPArticleSet.h"
static NS_DEFINE_IID(kINNTPNewsgroupIID, NS_INNTPNEWSGROUP_IID);
class nsNNTPNewsgroupStub : public nsINNTPNewsgroup
{
public:
nsNNTPNewsgroupStub();
virtual ~nsNNTPNewsgroupStub();
NS_DECL_ISUPPORTS
NS_IMETHOD GetName(char * *aName) const;
NS_IMETHOD SetName(char * aName);
NS_IMETHOD GetPrettyName(char * *aPrettyName) const;
NS_IMETHOD SetPrettyName(char * aPrettyName);
NS_IMETHOD GetPassword(char * *aPassword) const;
NS_IMETHOD SetPassword(char * aPassword);
NS_IMETHOD GetUsername(char * *aUsername) const;
NS_IMETHOD SetUsername(char * aUsername);
NS_IMETHOD GetNeedsExtraInfo(PRBool *aNeedsExtraInfo) const;
NS_IMETHOD SetNeedsExtraInfo(PRBool aNeedsExtraInfo);
NS_IMETHOD IsOfflineArticle(PRInt32 num, PRBool *_retval);
NS_IMETHOD GetCategory(PRBool *aCategory) const;
NS_IMETHOD SetCategory(PRBool aCategory);
NS_IMETHOD GetSubscribed(PRBool *aSubscribed) const;
NS_IMETHOD SetSubscribed(PRBool aSubscribed);
NS_IMETHOD GetWantNewTotals(PRBool *aWantNewTotals) const;
NS_IMETHOD SetWantNewTotals(PRBool aWantNewTotals);
NS_IMETHOD GetNewsgroupList(nsINNTPNewsgroupList * *aNewsgroupList) const;
NS_IMETHOD SetNewsgroupList(nsINNTPNewsgroupList * aNewsgroupList);
NS_IMETHOD UpdateSummaryFromNNTPInfo(PRInt32 oldest, PRInt32 youngest, PRInt32 total_messages);
protected:
char * m_groupName;
char * m_prettyName;
char * m_password;
char * m_userName;
PRBool m_isSubscribed;
PRBool m_wantsNewTotals;
PRBool m_needsExtraInfo;
PRBool m_category;
nsINNTPNewsgroupList * m_newsgroupList;
};
nsNNTPNewsgroupStub::nsNNTPNewsgroupStub()
{
NS_INIT_REFCNT();
m_groupName = nsnull;
m_prettyName = nsnull;
m_password = nsnull;
m_userName = nsnull;
m_newsgroupList = nsnull;
m_needsExtraInfo = PR_FALSE;
m_category = PR_FALSE;
}
nsNNTPNewsgroupStub::~nsNNTPNewsgroupStub()
{
printf("destroying newsgroup: %s", m_groupName ? m_groupName : "");
NS_IF_RELEASE(m_newsgroupList);
PR_FREEIF(m_groupName);
PR_FREEIF(m_password);
PR_FREEIF(m_userName);
PR_FREEIF(m_prettyName);
}
NS_IMPL_ISUPPORTS(nsNNTPNewsgroupStub, kINNTPNewsgroupIID);
nsresult nsNNTPNewsgroupStub::GetName(char ** aName) const
{
if (aName)
{
*aName = PL_strdup(m_groupName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetName(char *aName)
{
if (aName)
{
printf("Setting newsgroup name to %s. \n", aName);
m_groupName = PL_strdup(aName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetPrettyName(char ** aName) const
{
if (aName)
{
*aName = PL_strdup(m_prettyName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetPrettyName(char *aName)
{
if (aName)
{
printf("Setting pretty newsgroup name to %s. \n", aName);
m_prettyName = PL_strdup(aName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetPassword(char ** aName) const
{
if (aName)
{
*aName = PL_strdup(m_password);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetPassword(char *aName)
{
if (aName)
{
printf("Setting password for newsgroup %s to %s. \n", m_groupName, aName);
m_password = PL_strdup(aName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetUsername(char ** aUsername) const
{
if (aUsername)
{
*aUsername = PL_strdup(m_userName);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetUsername(char *aUsername)
{
if (aUsername)
{
printf("Setting username for newsgroup %s to %s. \n", m_groupName, aUsername);
m_userName = PL_strdup(aUsername);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetNeedsExtraInfo(PRBool *aNeedsExtraInfo) const
{
if (aNeedsExtraInfo)
{
*aNeedsExtraInfo = m_needsExtraInfo;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetNeedsExtraInfo(PRBool aNeedsExtraInfo)
{
if (aNeedsExtraInfo)
{
printf("Setting needs extra info for newsgroup %s to %s. \n", m_groupName, aNeedsExtraInfo ? "TRUE" : "FALSE" );
m_needsExtraInfo = aNeedsExtraInfo;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::IsOfflineArticle(PRInt32 num, PRBool *_retval)
{
printf("Testing for offline article %d in %s. \n", num, m_groupName);
if (_retval)
*_retval = PR_FALSE;
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetCategory(PRBool *aCategory) const
{
if (aCategory)
{
*aCategory = m_category;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetCategory(PRBool aCategory)
{
if (aCategory)
{
printf("Setting is category for newsgroup %s to %s. \n", m_groupName, aCategory ? "TRUE" : "FALSE" );
m_category = aCategory;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetSubscribed(PRBool *aSubscribed) const
{
if (aSubscribed)
{
*aSubscribed = m_isSubscribed;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetSubscribed(PRBool aSubscribed)
{
if (aSubscribed)
{
printf("Setting is subscribed for newsgroup %s to %s. \n", m_groupName, aSubscribed ? "TRUE" : "FALSE" );
m_isSubscribed = aSubscribed;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetWantNewTotals(PRBool *aWantNewTotals) const
{
if (aWantNewTotals)
{
*aWantNewTotals = m_wantsNewTotals;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetWantNewTotals(PRBool aWantNewTotals)
{
if (aWantNewTotals)
{
printf("Setting wants new totals for newsgroup %s to %s. \n", m_groupName, aWantNewTotals ? "TRUE" : "FALSE" );
m_wantsNewTotals = aWantNewTotals;
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::GetNewsgroupList(nsINNTPNewsgroupList * *aNewsgroupList) const
{
if (aNewsgroupList)
{
*aNewsgroupList = m_newsgroupList;
NS_IF_ADDREF(m_newsgroupList);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::SetNewsgroupList(nsINNTPNewsgroupList * aNewsgroupList)
{
if (aNewsgroupList)
{
printf("Setting newsgroup list for newsgroup %s. \n", m_groupName);
m_newsgroupList = aNewsgroupList;
NS_IF_ADDREF(m_newsgroupList);
}
return NS_OK;
}
nsresult nsNNTPNewsgroupStub::UpdateSummaryFromNNTPInfo(PRInt32 oldest, PRInt32 youngest, PRInt32 total_messages)
{
printf("Updating summary with oldest= %d, youngest= %d, and total messages = %d. \n", oldest, youngest, total_messages);
return NS_OK;
}
extern "C" {
nsresult NS_NewNewsgroup(nsINNTPNewsgroup **info,
char *line,
nsNNTPArticleSet *set,
PRBool subscribed,
nsINNTPHost *host,
int depth)
{
nsresult rv = NS_OK;
nsNNTPNewsgroupStub * group = new nsNNTPNewsgroupStub();
if (group)
{
group->SetSubscribed(subscribed);
rv = group->QueryInterface(kINNTPNewsgroupIID, (void **) info);
}
return rv;
}
}