2148 lines
55 KiB
C++
2148 lines
55 KiB
C++
#include <windows.h>
|
|
#include <propbag.h>
|
|
#include <tflist.h>
|
|
#include <stdio.h>
|
|
#include <crchash.h>
|
|
#include <dbgtrace.h>
|
|
#include <nntpdrv.h>
|
|
#include <nntpfs.h>
|
|
#include <nntpfs_i.c>
|
|
#include <nntpex.h>
|
|
#include <nntpex_i.c>
|
|
#include <syncomp.h>
|
|
#include <iadmw.h>
|
|
#include <tigtypes.h>
|
|
#include <nntptype.h>
|
|
#include <nntpvr.h>
|
|
#include <nntperr.h>
|
|
|
|
|
|
|
|
typedef char* LPMULTISZ;
|
|
#include <nwstree.h>
|
|
|
|
#define _ASSERTE( x ) _ASSERT( x )
|
|
#include <atlbase.h>
|
|
|
|
CComModule _Module;
|
|
#include <atlcom.h>
|
|
#include <atlimpl.cpp>
|
|
|
|
typedef char * LPMULTISZ;
|
|
#include <group.h>
|
|
|
|
#define MAX_VROOT_COUNT 128
|
|
#define MAX_TOKEN_BUFFER 512
|
|
#define MAX_ARGS 16
|
|
#define MAX_ARG_LEN 512
|
|
#define MAX_THREAD_POOL 50
|
|
#define MAX_VROOT_TABLE 64
|
|
|
|
enum OP_CODE {
|
|
INVALID, // Invalid instruction
|
|
NOOP, // No operation
|
|
SCRIPTBEGIN,// Beginning of the whole script
|
|
SCRIPTEND, // End of the whole script
|
|
THREADBEGIN,// It's a thread's begin
|
|
THREADEND, // It's a thread's end
|
|
CONNECT, // Connect to a driver
|
|
DISCONNECT, // Disconnect a driver
|
|
MOVE, // Assigment
|
|
SUB, // Subtraction
|
|
JUMP, // Jump to another instruction
|
|
WAIT, // Wait for other thread's instruction to complete
|
|
NEWGROUP, // Allocate a news group object
|
|
SLEEP, // Sleep
|
|
FREEGROUP, // Free group object in variable bag
|
|
RMGROUP, // Remove a group, physically
|
|
XOVER, // Xover
|
|
};
|
|
|
|
enum DRIVER {
|
|
NTFS, // FS Driver
|
|
EXCHANGE // Exchange Driver
|
|
};
|
|
|
|
// Global variable bag ( mainly for NntpPropertyBag )
|
|
CPropBag g_VariableBag;
|
|
CRITICAL_SECTION g_critVarBag; // for synchronizing access to the variable bag
|
|
|
|
void StartHintFunction( void )
|
|
{}
|
|
|
|
DWORD INNHash( PBYTE pb, DWORD )
|
|
{ return 0; }
|
|
|
|
VOID
|
|
InitGlobalVarBag()
|
|
{
|
|
InitializeCriticalSection( &g_critVarBag );
|
|
}
|
|
|
|
VOID
|
|
DeInitGlobalVarBag()
|
|
{
|
|
DeleteCriticalSection( &g_critVarBag );
|
|
}
|
|
|
|
VOID
|
|
LockGlobalVarBag()
|
|
{
|
|
EnterCriticalSection( &g_critVarBag );
|
|
}
|
|
|
|
VOID
|
|
UnlockGlobalVarBag()
|
|
{
|
|
LeaveCriticalSection( &g_critVarBag );
|
|
}
|
|
|
|
VOID
|
|
CopyAsciiStringIntoUnicode(
|
|
IN LPWSTR UnicodeString,
|
|
IN LPCSTR AsciiString
|
|
)
|
|
{
|
|
while ( (*UnicodeString++ = (WCHAR)*AsciiString++) != (WCHAR)'\0');
|
|
|
|
} // CopyAsciiStringIntoUnicode
|
|
|
|
VOID
|
|
CopyUnicodeStringIntoAscii(
|
|
IN LPSTR AsciiString,
|
|
IN LPWSTR UnicodeString
|
|
)
|
|
{
|
|
while ( (*AsciiString++ = (CHAR)*UnicodeString++) != '\0');
|
|
|
|
} // CopyUnicodeStringIntoAscii
|
|
|
|
|
|
GET_DEFAULT_DOMAIN_NAME_FN pfnGetDefaultDomainName = NULL;
|
|
|
|
/*BOOL
|
|
GetDefaultDomainName( PCHAR pch, DWORD dw )
|
|
{
|
|
return TRUE;
|
|
}*/
|
|
|
|
HANDLE g_hProcessImpersonationToken;
|
|
|
|
// Get the process Token
|
|
HANDLE GetProcessToken()
|
|
{
|
|
HANDLE hAccToken;
|
|
HANDLE hImpersonate;
|
|
|
|
if ( !OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|
&hAccToken ) ) {
|
|
return NULL;
|
|
} else {
|
|
// Dup the token to get an impersonation token
|
|
_ASSERT( hAccToken );
|
|
if ( !DuplicateTokenEx( hAccToken,
|
|
0,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenImpersonation,
|
|
&hImpersonate ) ) {
|
|
CloseHandle( hAccToken );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Here we have got the right token
|
|
CloseHandle( hAccToken );
|
|
return hImpersonate;
|
|
}
|
|
|
|
class CNntpServer : public INntpServer {
|
|
public:
|
|
|
|
// Constructor, destructor
|
|
CNntpServer() : m_cRef( 1 ) {}
|
|
~CNntpServer(){}
|
|
|
|
LONG GetRef() { return m_cRef; }
|
|
|
|
VOID STDMETHODCALLTYPE
|
|
FindPrimaryArticle( INNTPPropertyBag *pPropBag,
|
|
DWORD idArtSecond,
|
|
INNTPPropertyBag **ppPropBag,
|
|
DWORD *pidArtPrimary,
|
|
INntpComplete *pICompletion ) {
|
|
HRESULT hr = S_OK;
|
|
|
|
_ASSERT( pPropBag );
|
|
_ASSERT( ppPropBag );
|
|
|
|
hr = pPropBag->QueryInterface( IID_INNTPPropertyBag, (void**)ppPropBag );
|
|
*pidArtPrimary = idArtSecond;
|
|
|
|
pICompletion->SetResult( hr );
|
|
pICompletion->Release();
|
|
}
|
|
|
|
void STDMETHODCALLTYPE
|
|
CreatePostEntries( char *pszMessageId,
|
|
DWORD iHeaderLength,
|
|
STOREID *pStoreId,
|
|
BYTE cGroups,
|
|
INNTPPropertyBag **rgpGroups,
|
|
DWORD *rgArticleIds,
|
|
INntpComplete *pCompletion)
|
|
{}
|
|
|
|
|
|
// IUnknown implementation
|
|
HRESULT __stdcall QueryInterface( const IID& iid, VOID** ppv )
|
|
{
|
|
if ( iid == IID_IUnknown ) {
|
|
*ppv = static_cast<INntpServer*>(this);
|
|
} else if ( iid == IID_INntpServer ) {
|
|
*ppv = static_cast<INntpServer*>(this);
|
|
} else {
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return InterlockedIncrement( &m_cRef );
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
InterlockedDecrement( &m_cRef );
|
|
return m_cRef;
|
|
}
|
|
|
|
private:
|
|
|
|
LONG m_cRef;
|
|
};
|
|
|
|
class CFakeNewsTree : public INewsTree {
|
|
public:
|
|
|
|
// Constructor, destructor
|
|
CFakeNewsTree() : m_cRef( 1 ) {}
|
|
~CFakeNewsTree(){}
|
|
|
|
LONG GetRef() { return m_cRef; }
|
|
|
|
// IUnknown implementation
|
|
HRESULT __stdcall QueryInterface( const IID& iid, VOID** ppv )
|
|
{
|
|
if ( iid == IID_IUnknown ) {
|
|
*ppv = static_cast<INewsTree*>(this);
|
|
} else if ( iid == IID_INewsTree ) {
|
|
*ppv = static_cast<INewsTree*>(this);
|
|
} else {
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG __stdcall AddRef()
|
|
{
|
|
return InterlockedIncrement( &m_cRef );
|
|
}
|
|
|
|
ULONG __stdcall Release()
|
|
{
|
|
InterlockedDecrement( &m_cRef );
|
|
return m_cRef;
|
|
}
|
|
|
|
HRESULT __stdcall FindGroupByID( DWORD dw, INNTPPropertyBag **bag ) {
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall FindOrCreateGroupByName( LPSTR lpstr, int i, INNTPPropertyBag **bag)
|
|
{ return E_NOTIMPL; }
|
|
|
|
HRESULT __stdcall CommitGroup( INNTPPropertyBag *bag ) {
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT __stdcall RemoveGroupByID( DWORD ) { return E_NOTIMPL; }
|
|
|
|
HRESULT __stdcall RemoveGroupByName( const char** ) { return E_NOTIMPL; }
|
|
|
|
HRESULT __stdcall GetIterator( INewsTreeIterator ** piter )
|
|
{ return E_NOTIMPL; }
|
|
|
|
HRESULT __stdcall LookupVRoot( char* ch, INntpDriver ** pDriver )
|
|
{ return E_NOTIMPL; }
|
|
|
|
HRESULT __stdcall GetNntpServer( INntpServer **pserver )
|
|
{ return E_NOTIMPL; }
|
|
|
|
private:
|
|
|
|
LONG m_cRef;
|
|
};
|
|
|
|
CFakeNewsTree *g_pDummyTree = NULL;
|
|
CNNTPVRoot *g_pDummyVroot = NULL;
|
|
|
|
|
|
class CThread;
|
|
class CVroot;
|
|
|
|
CThread *g_rgThreadPool[MAX_THREAD_POOL];
|
|
DWORD g_cThread = 0;
|
|
BOOL g_bVerbal = FALSE;
|
|
|
|
CVroot *g_rgpVrootTable[MAX_VROOT_TABLE];
|
|
|
|
IMSAdminBaseW *g_pMB;
|
|
|
|
CNntpServer *g_pServer = NULL;
|
|
CNewsTreeCore *g_pNewsTree = NULL;
|
|
CNNTPVRootTable *g_pVRTable = NULL;
|
|
|
|
class CInstruction { // in
|
|
|
|
public:
|
|
|
|
// Linked list pointers
|
|
CInstruction *m_pNext;
|
|
CInstruction *m_pPrev;
|
|
|
|
CInstruction( OP_CODE OpCode, DWORD dwIndex ) :
|
|
m_OpCode ( OpCode ),
|
|
m_dwIndex( dwIndex ),
|
|
m_pNext( NULL ),
|
|
m_pPrev( NULL ) {}
|
|
~CInstruction() {}
|
|
OP_CODE GetOpCode() { return m_OpCode; }
|
|
DWORD GetIndex() { return m_dwIndex; }
|
|
|
|
// Interface to pass command parameters out
|
|
virtual BOOL Parse( int argc, char**argv ) = 0;
|
|
virtual BOOL Execute( PVOID pvContext ) = 0;
|
|
|
|
protected:
|
|
|
|
DWORD m_dwVrootId; // which vroot the inst is applied to
|
|
|
|
private:
|
|
|
|
OP_CODE m_OpCode; // operation
|
|
DWORD m_dwIndex; // instruction index
|
|
};
|
|
|
|
class CConnect : public CInstruction { // cn
|
|
|
|
public:
|
|
CConnect( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {
|
|
*m_szPrefix = 0;
|
|
}
|
|
~CConnect() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID );
|
|
|
|
private:
|
|
|
|
DRIVER m_DriverType; // driver type
|
|
DWORD m_idVroot; // vroot id
|
|
CHAR m_szPrefix[MAX_PATH]; // newsgroup prefix
|
|
|
|
CConnect();
|
|
};
|
|
|
|
class CDisconnect : public CInstruction { // ds
|
|
|
|
public:
|
|
CDisconnect( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CDisconnect() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID );
|
|
|
|
private:
|
|
|
|
DWORD m_idVroot; // vroot id
|
|
};
|
|
|
|
class CEnd : public CInstruction { // ed
|
|
|
|
public:
|
|
|
|
CEnd( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CEnd() {}
|
|
|
|
virtual BOOL Parse( int argc, char**argv ) { return TRUE; }
|
|
virtual BOOL Execute( PVOID pvContext ) { return TRUE; }
|
|
};
|
|
|
|
class CMove : public CInstruction { //mv
|
|
|
|
public:
|
|
CMove( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CMove() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_idVar; // variable id
|
|
DWORD m_dwVal; // value
|
|
};
|
|
|
|
class CSubtract : public CInstruction { //sb
|
|
|
|
public:
|
|
CSubtract( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CSubtract() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_idVar; // variable id
|
|
DWORD m_dwOperand; // subtraction operand
|
|
};
|
|
|
|
class CJump : public CInstruction { // jp
|
|
|
|
public:
|
|
CJump( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CJump() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_dwInstruction; // instruction index to jump to
|
|
DWORD m_idVal; // control varaible id
|
|
};
|
|
|
|
class CWait : public CInstruction { //wt
|
|
|
|
public:
|
|
CWait( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction ( opcode, dwIndex ) {}
|
|
~CWait() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_dwThreadId; // which thread shall I wait for
|
|
DWORD m_iInst; // which instruction within that thread shall I wait for
|
|
};
|
|
|
|
class CNewGroup : public CInstruction { //ng
|
|
|
|
public:
|
|
CNewGroup( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CNewGroup() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
BOOL m_bGlobal; // Global or local variable
|
|
BOOL m_bCreatePhysical; // Do you want me to create physical folder ?
|
|
DWORD m_idVar; // Id of variable in variable bag
|
|
CHAR m_szGroupName[MAX_PATH+1];
|
|
};
|
|
|
|
class CSleep : public CInstruction { // sl
|
|
|
|
public:
|
|
CSleep( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CSleep() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_dwMilliSeconds;
|
|
};
|
|
|
|
class CFreeGroup : public CInstruction { //fg
|
|
|
|
public:
|
|
CFreeGroup( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CFreeGroup() {}
|
|
|
|
virtual BOOL Parse( int argc, char**argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_idVar;
|
|
BOOL m_bGlobal;
|
|
};
|
|
|
|
class CRmGroup : public CInstruction { //rg
|
|
|
|
public:
|
|
CRmGroup( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CRmGroup() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_idVar;
|
|
BOOL m_bGlobal;
|
|
};
|
|
|
|
class CXover : public CInstruction { //xv
|
|
|
|
public:
|
|
CXover( OP_CODE opcode, DWORD dwIndex ) :
|
|
CInstruction( opcode, dwIndex ) {}
|
|
~CXover() {}
|
|
|
|
virtual BOOL Parse( int argc, char** argv );
|
|
virtual BOOL Execute( PVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_idVar;
|
|
BOOL m_bGlobal;
|
|
DWORD m_dwLow;
|
|
DWORD m_dwHigh;
|
|
DWORD m_dwBufSize;
|
|
};
|
|
|
|
class CVroot { //vr
|
|
|
|
public:
|
|
|
|
CVroot() {
|
|
InitializeCriticalSection( &m_critLock );
|
|
m_lRef = 0;
|
|
m_pDriver = NULL;
|
|
m_DriverType = NTFS;
|
|
m_pNewsTree = new CFakeNewsTree;
|
|
_ASSERT( m_pNewsTree );
|
|
m_pServer = new CNntpServer;
|
|
_ASSERT( m_pServer );
|
|
}
|
|
~CVroot() {
|
|
DeleteCriticalSection( &m_critLock );
|
|
_ASSERT( NULL == m_pDriver );
|
|
_ASSERT( m_lRef == 0 );
|
|
_VERIFY( m_pNewsTree->Release() == 0 );
|
|
_VERIFY( m_pServer->Release() == 0 );
|
|
delete m_pNewsTree;
|
|
delete m_pServer;
|
|
}
|
|
void Lock() {
|
|
EnterCriticalSection( &m_critLock );
|
|
}
|
|
void Unlock() {
|
|
LeaveCriticalSection( &m_critLock );
|
|
}
|
|
|
|
BOOL Connect( DRIVER DriverType, LPSTR szPrefix, CDriverSyncComplete *pComplete );
|
|
BOOL Disconnect();
|
|
BOOL CreateGroup( INNTPPropertyBag *, LPSTR, CDriverSyncComplete * );
|
|
BOOL RemoveGroup( INNTPPropertyBag *, LPSTR, CDriverSyncComplete * );
|
|
BOOL Xover( INNTPPropertyBag *, LPSTR, DWORD, DWORD, DWORD, CDriverSyncComplete * );
|
|
|
|
LPSTR GetPrefix() { return m_szPrefix; }
|
|
|
|
private:
|
|
|
|
LONG m_lRef; // ref count
|
|
DRIVER m_DriverType; // driver type
|
|
CRITICAL_SECTION m_critLock; // for synchronization
|
|
INntpDriver *m_pDriver; // Driver pointer
|
|
CFakeNewsTree *m_pNewsTree; // dummy newstree pointer
|
|
CNntpServer *m_pServer; // dummy server pointer
|
|
CHAR m_szPrefix[MAX_PATH]; // vroot prefix
|
|
};
|
|
|
|
DWORD
|
|
VrootTableLookup( LPSTR szGroupName )
|
|
{
|
|
for ( int i = 0; i < MAX_VROOT_TABLE; i++ ) {
|
|
if ( strlen( szGroupName ) >= strlen( g_rgpVrootTable[i]->GetPrefix() ) &&
|
|
_strnicmp( szGroupName, g_rgpVrootTable[i]->GetPrefix(), strlen(
|
|
g_rgpVrootTable[i]->GetPrefix() ) ) == 0)
|
|
return i;
|
|
}
|
|
|
|
return 0xffffffff;
|
|
}
|
|
|
|
|
|
class CThread {
|
|
|
|
public:
|
|
|
|
CThread::CThread( DWORD dwThreadId ) :
|
|
m_InstructionList( &CInstruction::m_pPrev, &CInstruction::m_pNext ),
|
|
m_PC( &m_InstructionList ),
|
|
m_dwThreadId( dwThreadId )
|
|
{
|
|
m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
_ASSERT( m_hEvent );
|
|
m_Complete.SetEventHandle( m_hEvent );
|
|
}
|
|
|
|
CThread::~CThread() {
|
|
CInstruction *pInstruction;
|
|
|
|
CloseHandle( m_hThread );
|
|
CloseHandle( m_hEvent );
|
|
while ( pInstruction = m_InstructionList.PopBack() ) {
|
|
delete pInstruction;
|
|
}
|
|
|
|
_ASSERT( m_Complete.GetRef() == 0 );
|
|
}
|
|
|
|
void Advance() { m_PC.Next(); }
|
|
|
|
void Execute();
|
|
void Jump( DWORD idInstruction );
|
|
BOOL SetDWord( DWORD dwId, DWORD dwVal );
|
|
BOOL DecDWord( DWORD dwId, DWORD dwVal );
|
|
BOOL GetDWord( DWORD dwId, PDWORD pdwVal );
|
|
BOOL RemoveDWord( DWORD dwId );
|
|
void PushInstruction( CInstruction *pInstruction );
|
|
BOOL Over( DWORD dwInst );
|
|
VOID KickOff();
|
|
VOID Create();
|
|
VOID BlockForCompletion() { WaitForSingleObject( m_hThread, INFINITE ); }
|
|
DWORD GetThreadId() { return m_dwThreadId; }
|
|
CDriverSyncComplete *GetCompletionObject() { return &m_Complete; }
|
|
|
|
static DWORD WINAPI
|
|
ThreadProc( LPVOID pvContext );
|
|
|
|
private:
|
|
|
|
DWORD m_dwThreadId; // thread id
|
|
|
|
// List of instructions for this thread
|
|
TFList<CInstruction> m_InstructionList;
|
|
|
|
// Program counter
|
|
TFList<CInstruction>::Iterator m_PC;
|
|
|
|
// dword variables that this thread owns
|
|
CPropBag m_VariableBag;
|
|
|
|
// Thread handle
|
|
HANDLE m_hThread;
|
|
|
|
// completion object
|
|
CDriverSyncComplete m_Complete;
|
|
|
|
// Event handle
|
|
HANDLE m_hEvent;
|
|
};
|
|
|
|
class CParser { //ps
|
|
|
|
public:
|
|
|
|
CParser();
|
|
~CParser();
|
|
|
|
BOOL Init( LPSTR szFileName );
|
|
BOOL Parse();
|
|
|
|
private:
|
|
|
|
HANDLE m_hMap;
|
|
HANDLE m_hFile;
|
|
LPSTR m_lpstrContent;
|
|
LPSTR m_lpstrCursor;
|
|
DWORD m_dwLine;
|
|
|
|
OP_CODE GetNextLine( int& argc, char**argv );
|
|
BOOL GetNextToken( char *pchBuffer );
|
|
OP_CODE Interpret( int argc, LPSTR szCmd );
|
|
void AllocBuffer( char **&argv );
|
|
void DeallocBuffer( char **argv );
|
|
CInstruction *CreateInstruction( OP_CODE, DWORD, int, char ** );
|
|
};
|
|
|
|
CParser::CParser()
|
|
{
|
|
m_hMap = INVALID_HANDLE_VALUE;
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
m_lpstrContent = NULL;
|
|
m_dwLine = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Parse arguments for connect instruction
|
|
BOOL
|
|
CConnect::Parse( int argc, char**argv )
|
|
{
|
|
// argument should be in format of "connect [prefix ] [vroot id] [driver name]"
|
|
// where [vroot id] is an integer and [driver name] is "exchange" or "ntfs"
|
|
// and where [prefix] is the newsgroup prefix name
|
|
_ASSERT( argc == 4 );
|
|
_ASSERT( _stricmp( "connect", argv[0] ) == 0 );
|
|
|
|
strcpy( m_szPrefix, argv[1] );
|
|
if ( _stricmp( m_szPrefix, "root" ) == 0 )
|
|
strcpy( m_szPrefix, "" );
|
|
|
|
m_idVroot = atol( argv[2] );
|
|
_ASSERT( m_idVroot < MAX_VROOT_COUNT );
|
|
if ( m_idVroot >= MAX_VROOT_COUNT ) return FALSE;
|
|
|
|
if ( _stricmp( argv[3], "exchange" ) == 0 ) {
|
|
m_DriverType = EXCHANGE;
|
|
} else if ( _stricmp( argv[3], "ntfs" ) == 0 ) {
|
|
m_DriverType = NTFS;
|
|
} else {
|
|
_ASSERT( 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CConnect::Execute( PVOID pvContext )
|
|
{
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]connect %d %d\n",
|
|
pThread->GetThreadId(),
|
|
m_idVroot,
|
|
m_DriverType );
|
|
}
|
|
|
|
_ASSERT( m_idVroot < MAX_VROOT_TABLE );
|
|
if ( g_rgpVrootTable[m_idVroot]->Connect( m_DriverType, m_szPrefix, pThread->GetCompletionObject()) ) {
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
if ( GetLastError() == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ) {
|
|
printf( "[%d]Driver already created\n", pThread->GetThreadId() );
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CDisconnect::Parse( int argc, char**argv )
|
|
{
|
|
// argument should be in format of "disconnect [vroot id]"
|
|
// where [vroot id] is an integer
|
|
_ASSERT( argc == 2 );
|
|
_ASSERT( _stricmp( "disconnect", argv[0] ) == 0 );
|
|
|
|
m_idVroot = atol( argv[1] );
|
|
_ASSERT( m_idVroot < MAX_VROOT_COUNT );
|
|
if ( m_idVroot >= MAX_VROOT_COUNT ) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CDisconnect::Execute( PVOID pvContext )
|
|
{
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]disconnect %d\n",
|
|
pThread->GetThreadId(),
|
|
m_idVroot );
|
|
}
|
|
|
|
_ASSERT( m_idVroot < MAX_VROOT_TABLE );
|
|
if ( g_rgpVrootTable[m_idVroot]->Disconnect() ) {
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
if ( GetLastError() == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ) {
|
|
printf( "[%d]Driver already released\n", pThread->GetThreadId() );
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CMove::Parse( int argc, char**argv )
|
|
{
|
|
// argument should be in format of "move $[n] [m]"
|
|
// where [n] is the variable id and [m] is the value
|
|
_ASSERT( argc == 3 );
|
|
_ASSERT( _stricmp( "move", argv[0] ) == 0 );
|
|
|
|
_ASSERT( *argv[1] == '$' );
|
|
if ( '$' != *argv[1] ) return FALSE;
|
|
|
|
m_idVar = atol( argv[1] + sizeof( CHAR ) );
|
|
m_dwVal = atol( argv[2] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CMove::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
if ( g_bVerbal ) {
|
|
printf ( "[%d] move $%d %d\n",
|
|
pThread->GetThreadId(),
|
|
m_idVar,
|
|
m_dwVal );
|
|
}
|
|
|
|
if ( !pThread->SetDWord( m_idVar, m_dwVal ) )
|
|
return FALSE;
|
|
|
|
pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CSubtract::Parse( int argc, char**argv )
|
|
{
|
|
// should be in format of "sub $[n] [m]"
|
|
// where [n] is variable id and m is the operand
|
|
_ASSERT( argc == 3 );
|
|
_ASSERT( _stricmp( "sub", argv[0] ) == 0 );
|
|
|
|
_ASSERT( *argv[1] == '$' );
|
|
if ( '$' != *argv[1] ) return FALSE;
|
|
|
|
m_idVar = atol( argv[1] + sizeof( CHAR ) );
|
|
m_dwOperand = atol( argv[2] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CSubtract::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
if ( g_bVerbal ) {
|
|
printf ( "[%d] sub $%d %d\n",
|
|
pThread->GetThreadId(),
|
|
m_idVar,
|
|
m_dwOperand );
|
|
}
|
|
|
|
if ( !pThread->DecDWord( m_idVar, m_dwOperand ) )
|
|
return FALSE;
|
|
|
|
pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CJump::Parse( int argc, char**argv )
|
|
{
|
|
// should be in the format of "jump [n] [m]"
|
|
// where [n] is the line ( instruction ) number inside
|
|
// this thread and [m] is the control variable id
|
|
_ASSERT( argc == 3 );
|
|
_ASSERT( _stricmp( argv[0], "jump" ) == 0 );
|
|
|
|
m_dwInstruction = atol( argv[1] );
|
|
|
|
if ( *(argv[2]) != '$' ) {
|
|
printf( "Command \"jump %s %s\" syntax error\n", argv[1], argv[2] );
|
|
return FALSE;
|
|
}
|
|
|
|
m_idVal = atol( argv[2] + 1 );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CJump::Execute( PVOID pvContext )
|
|
{
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
DWORD dwVal;
|
|
|
|
if ( g_bVerbal ) {
|
|
printf ( "[%d]jump %d $%d\n",
|
|
pThread->GetThreadId(),
|
|
m_dwInstruction,
|
|
m_idVal );
|
|
}
|
|
|
|
if ( pThread->GetDWord( m_idVal, &dwVal ) ) {
|
|
if ( dwVal > 0 ) {
|
|
pThread->Jump( m_dwInstruction );
|
|
} else pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
printf( "[%d]Variable %d in thread %d undefined\n", pThread->GetThreadId(), m_idVal, pThread->GetThreadId() );
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CWait::Parse( int argc, char** argv )
|
|
{
|
|
// it should be in the format of "wait [n] [m]"
|
|
// where [n] is the thread id and [m] is the instruction No.
|
|
_ASSERT( argc == 3 );
|
|
_ASSERT( _stricmp( argv[0], "wait" ) == 0 );
|
|
|
|
m_dwThreadId = atol( argv[1] );
|
|
m_iInst = atol( argv[2] ) ;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CWait::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
CThread *pThreadToWait = g_rgThreadPool[m_dwThreadId];
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]wait %d %d\n",
|
|
pThread->GetThreadId(),
|
|
m_dwThreadId,
|
|
m_iInst );
|
|
}
|
|
|
|
_ASSERT( pThreadToWait );
|
|
if ( pThreadToWait->Over( m_iInst ) )
|
|
pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CNewGroup::Parse( int argc, char**argv )
|
|
{
|
|
// it should be in the format of "newgroup [group name] [$/#]id [create/nocreate]"
|
|
// where [group name] is the name of the newsgroup to create
|
|
// $id means creating the group object locally, #id means creating the group
|
|
// object globally. [create/nocreate] tells if we need to create physical folder
|
|
// in the store
|
|
_ASSERT( argc == 4 );
|
|
_ASSERT( _stricmp( argv[0], "newgroup" ) == 0 );
|
|
|
|
strcpy( m_szGroupName, argv[1] );
|
|
_ASSERT( strlen( m_szGroupName ) < MAX_PATH );
|
|
|
|
if ( *(argv[2]) == '$' ) m_bGlobal = FALSE;
|
|
else if ( *(argv[2]) == '#' ) m_bGlobal = TRUE;
|
|
else _ASSERT( 0 );
|
|
|
|
m_idVar = atol( argv[2] + 1 );
|
|
|
|
if ( _stricmp( "create", argv[3] ) == 0 )
|
|
m_bCreatePhysical = TRUE;
|
|
else if ( _stricmp( "nocreate", argv[3] ) == 0 )
|
|
m_bCreatePhysical = FALSE;
|
|
else _ASSERT( 0 );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CNewGroup::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
INNTPPropertyBag *pPropBag = NULL;
|
|
CHAR ch = ( m_bGlobal ? '#' : '$' );
|
|
CHAR szBuffer[MAX_PATH+1];
|
|
if ( m_bCreatePhysical ) strcpy( szBuffer, "create" );
|
|
else strcpy( szBuffer, "nocreate" );
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]newgroup %s %c%d %s\n",
|
|
pThread->GetThreadId(),
|
|
m_szGroupName,
|
|
ch,
|
|
m_idVar,
|
|
szBuffer );
|
|
}
|
|
|
|
// Create the group object
|
|
CNewsGroupCore *pGroup = new CNewsGroupCore( g_pNewsTree );
|
|
_ASSERT( pGroup );
|
|
pGroup->Init( m_szGroupName,
|
|
m_szGroupName,
|
|
1, // fake group id
|
|
NULL );
|
|
|
|
// If asked to create the physical folder, create it
|
|
if ( m_bCreatePhysical ) {
|
|
_ASSERT( pGroup->GetRefCount() == 1 );
|
|
pPropBag = pGroup->GetPropertyBag();
|
|
_ASSERT( pGroup->GetRefCount() == 2 );
|
|
DWORD i = VrootTableLookup( m_szGroupName );
|
|
_ASSERT( i != 0xffffffff );
|
|
|
|
if ( !g_rgpVrootTable[i]->CreateGroup( pPropBag, m_szGroupName, pThread->GetCompletionObject() ) ) {
|
|
delete pGroup;
|
|
if ( GetLastError() == HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) ||
|
|
GetLastError() == HRESULT_FROM_WIN32( NNTP_E_DRIVER_NOT_INITIALIZED )) {
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
else return FALSE;
|
|
}
|
|
|
|
_ASSERT( pGroup->GetRefCount() == 1 );
|
|
|
|
}
|
|
|
|
// Now insert the group object into variable bag
|
|
if ( m_bGlobal ) {
|
|
LockGlobalVarBag();
|
|
g_VariableBag.PutDWord( m_idVar, (DWORD)pGroup );
|
|
UnlockGlobalVarBag();
|
|
} else {
|
|
pThread->SetDWord( m_idVar, (DWORD)pGroup );
|
|
}
|
|
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CSleep::Parse( int argc, char **argv )
|
|
{
|
|
// it should be of foramt "sleep [n]",
|
|
// where [n] is time to sleep in terms of milliseconds
|
|
_ASSERT( argc == 2 );
|
|
_ASSERT( _stricmp( "sleep", argv[0] ) == 0 );
|
|
|
|
m_dwMilliSeconds = atol( argv[1] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CSleep::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
Sleep( m_dwMilliSeconds );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CFreeGroup::Parse( int argc, char** argv )
|
|
{
|
|
// should be in the format of "freegroup $/#[n]"
|
|
// where '$' or '#' tells whether it's global or
|
|
// local variable and [n] is the variable id
|
|
_ASSERT( argc == 2 );
|
|
_ASSERT( _stricmp( "freegroup", argv[0] ) == 0 );
|
|
|
|
if ( *argv[1] == '$' ) m_bGlobal = FALSE;
|
|
else if ( *argv[1] == '#' ) m_bGlobal = TRUE;
|
|
else _ASSERT( 0 );
|
|
|
|
m_idVar = atol( argv[1]+1 );
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CFreeGroup::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
CNewsGroupCore *pGroup;
|
|
HRESULT hr = S_OK;
|
|
CHAR ch = (m_bGlobal? '#' : '$' );
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]freegroup %c%d\n",
|
|
pThread->GetThreadId(),
|
|
ch,
|
|
m_idVar );
|
|
}
|
|
|
|
if ( m_bGlobal ) {
|
|
LockGlobalVarBag();
|
|
hr = g_VariableBag.GetDWord( m_idVar, (PDWORD)&pGroup );
|
|
UnlockGlobalVarBag();
|
|
if ( FAILED( hr ) ) {
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) ) {
|
|
printf( "Group #%d does not exist\n", m_idVar );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
LockGlobalVarBag();
|
|
g_VariableBag.RemoveProperty( m_idVar );
|
|
UnlockGlobalVarBag();
|
|
} else {
|
|
hr = pThread->GetDWord( m_idVar, (PDWORD)&pGroup );
|
|
if ( FAILED( hr ) ) {
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) ) {
|
|
printf( "Group #%d does not exist\n", m_idVar );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
pThread->RemoveDWord( m_idVar );
|
|
}
|
|
|
|
delete pGroup;
|
|
|
|
pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CRmGroup::Parse( int argc, char** argv )
|
|
{
|
|
// should be in the format of "rmgroup $/#[n]"
|
|
// where '$' or '#' tells whether it's global or
|
|
// local variable and [n] is the variable id
|
|
_ASSERT( argc == 2 );
|
|
_ASSERT( _stricmp( "rmgroup", argv[0] ) == 0 );
|
|
|
|
if ( *argv[1] == '$' ) m_bGlobal = FALSE;
|
|
else if ( *argv[1] == '#' ) m_bGlobal = TRUE;
|
|
else _ASSERT( 0 );
|
|
|
|
m_idVar = atol( argv[1]+1 );
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CRmGroup::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread*)pvContext;
|
|
CNewsGroupCore *pGroup = NULL;
|
|
INNTPPropertyBag *pPropBag = NULL;
|
|
CHAR szGroupName[MAX_PATH+1];
|
|
DWORD dwLen = MAX_PATH;
|
|
HRESULT hr = S_OK;
|
|
CHAR ch = m_bGlobal ? '#' : '$';
|
|
|
|
if ( g_bVerbal ) {
|
|
printf( "[%d]rmgroup %c%d\n",
|
|
pThread->GetThreadId(),
|
|
ch,
|
|
m_idVar );
|
|
}
|
|
|
|
|
|
// Get the group object
|
|
if ( m_bGlobal ) {
|
|
LockGlobalVarBag();
|
|
hr = g_VariableBag.GetDWord( m_idVar, PDWORD(&pGroup) );
|
|
UnlockGlobalVarBag();
|
|
}
|
|
else hr = pThread->GetDWord( m_idVar, PDWORD(&pGroup) );
|
|
|
|
if ( FAILED( hr ) ) {
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) ) {
|
|
printf ("Group object %d not defined\n", m_idVar );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
printf( "rm group failed with %x\n", hr );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( pGroup );
|
|
if ( !m_bGlobal ) _ASSERT( pGroup->GetRefCount() == 1 );
|
|
|
|
pPropBag = pGroup->GetPropertyBag();
|
|
|
|
// get group name and do a vroot table lookup
|
|
hr = pPropBag->GetBLOB( NEWSGRP_PROP_NAME, PBYTE(szGroupName), &dwLen );
|
|
if ( FAILED( hr ) ) {
|
|
printf ( "How come group has no name %x\n", hr);
|
|
_ASSERT( 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD i = VrootTableLookup( szGroupName );
|
|
_ASSERT( i != 0xffffffff );
|
|
|
|
if ( !g_rgpVrootTable[i]->RemoveGroup( pPropBag, szGroupName, pThread->GetCompletionObject() ) ) {
|
|
if ( GetLastError() != HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) &&
|
|
GetLastError() != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) &&
|
|
GetLastError() != HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) &&
|
|
GetLastError() != NNTP_E_DRIVER_NOT_INITIALIZED ) {
|
|
printf( "Remove group %s failed %x\n", szGroupName, GetLastError() );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if ( !m_bGlobal ) _ASSERT( pGroup->GetRefCount() == 1 );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CXover::Parse( int argc, char** argv )
|
|
{
|
|
// It should be in the format of "xover $/#[n] [i] [j] [k]"
|
|
// where $ or # specifies a group variable, i is the low range,
|
|
// j is the high range, k is the buffer size
|
|
_ASSERT( argc == 5 );
|
|
_ASSERT( _stricmp( argv[0], "xover" ) == 0 );
|
|
|
|
if ( *argv[1] == '$' ) m_bGlobal = FALSE;
|
|
else if ( *argv[1] == '#' ) m_bGlobal = TRUE;
|
|
else _ASSERT( 0 );
|
|
|
|
m_idVar = atol( argv[1] + 1 );
|
|
m_dwLow = atol( argv[2] );
|
|
m_dwHigh = atol( argv[3] );
|
|
_ASSERT( m_dwHigh >= m_dwLow );
|
|
m_dwBufSize = atol( argv[4] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CXover::Execute( PVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
// Get the group object
|
|
HRESULT hr = S_OK;
|
|
CNewsGroupCore *pGroup = NULL;
|
|
INNTPPropertyBag *pPropBag = NULL;
|
|
DWORD i;
|
|
CHAR szGroupName[MAX_PATH+1];
|
|
DWORD dwLen = MAX_PATH;
|
|
|
|
if ( m_bGlobal ) {
|
|
LockGlobalVarBag();
|
|
hr = g_VariableBag.GetDWord( m_idVar, (PDWORD)&pGroup );
|
|
UnlockGlobalVarBag();
|
|
} else {
|
|
hr = pThread->GetDWord( m_idVar, (PDWORD)&pGroup );
|
|
}
|
|
|
|
if ( FAILED( hr ) ) {
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_NOT_FOUND ) ) {
|
|
printf( "Group object %d not defined\n", m_idVar );
|
|
pThread->Advance();
|
|
return TRUE;
|
|
}
|
|
|
|
printf( "Fatal error when looking for group object %x\n", hr );
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( pGroup );
|
|
if ( !m_bGlobal ) _ASSERT( pGroup->GetRefCount() == 1 );
|
|
pPropBag = pGroup->GetPropertyBag();
|
|
|
|
// Get group name
|
|
hr = pPropBag->GetBLOB( NEWSGRP_PROP_NAME, PBYTE(szGroupName), &dwLen );
|
|
if ( FAILED( hr ) ) {
|
|
printf( "How come a group has no name %x\n", hr );
|
|
pPropBag->Release();
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( strlen( szGroupName ) <= MAX_PATH );
|
|
i = VrootTableLookup( szGroupName );
|
|
_ASSERT( i != 0xffffffff );
|
|
|
|
if ( !g_rgpVrootTable[i]->Xover( pPropBag,
|
|
szGroupName,
|
|
m_dwLow,
|
|
m_dwHigh,
|
|
m_dwBufSize,
|
|
pThread->GetCompletionObject() ) &&
|
|
GetLastError() != HRESULT_FROM_WIN32( NNTP_E_DRIVER_NOT_INITIALIZED )) {
|
|
|
|
printf( "Get Xover failed %x\n", GetLastError() );
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !m_bGlobal ) _ASSERT( pGroup->GetRefCount() == 1 );
|
|
pThread->Advance();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CParser::~CParser()
|
|
{
|
|
if ( m_lpstrContent )
|
|
UnmapViewOfFile( m_lpstrContent );
|
|
|
|
if ( INVALID_HANDLE_VALUE != m_hMap )
|
|
_VERIFY(CloseHandle( m_hMap ));
|
|
|
|
if ( INVALID_HANDLE_VALUE != m_hFile )
|
|
_VERIFY(CloseHandle( m_hFile ) );
|
|
}
|
|
|
|
BOOL
|
|
CParser::Init( LPSTR szFileName )
|
|
{
|
|
m_hFile = CreateFile( szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
if ( INVALID_HANDLE_VALUE != m_hFile ) {
|
|
m_hMap = CreateFileMapping( m_hFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL );
|
|
if ( INVALID_HANDLE_VALUE != m_hMap ) {
|
|
m_lpstrContent = (char*)MapViewOfFile( m_hMap,
|
|
FILE_MAP_READ,
|
|
0,0,0);
|
|
if ( m_lpstrContent == NULL ) {
|
|
printf( "MapViewOfFile failed on script file %d\n", GetLastError() );
|
|
}
|
|
} else printf ( "CreateFileMapping failed on script file %d\n", GetLastError() );
|
|
} else printf ( "Open script file failed %d\n", GetLastError() );
|
|
|
|
m_lpstrCursor = m_lpstrContent;
|
|
return ( NULL != m_lpstrContent );
|
|
}
|
|
|
|
OP_CODE
|
|
CParser::GetNextLine( int& argc, char **argv )
|
|
{
|
|
_ASSERT( argv );
|
|
|
|
char pbBuffer[MAX_TOKEN_BUFFER+1];
|
|
|
|
BOOL bMore = TRUE;
|
|
|
|
argc = 0;
|
|
bMore = GetNextToken( pbBuffer );
|
|
|
|
// skip line number, if it is
|
|
if ( *pbBuffer >= '0' && *pbBuffer <= '9' )
|
|
bMore = GetNextToken( pbBuffer );
|
|
|
|
if ( *pbBuffer != 0 )
|
|
strcpy( argv[argc++], pbBuffer );
|
|
|
|
while ( bMore ) {
|
|
bMore = GetNextToken( pbBuffer );
|
|
if ( *pbBuffer != 0 )
|
|
strcpy( argv[argc++], pbBuffer );
|
|
}
|
|
|
|
m_dwLine++;
|
|
return Interpret( argc, argv[0] );
|
|
}
|
|
|
|
OP_CODE
|
|
CParser::Interpret( int argc, LPSTR szCmd )
|
|
{
|
|
_ASSERT( szCmd );
|
|
|
|
if ( argc == 0 ) return NOOP;
|
|
|
|
if ( _stricmp( szCmd, "scriptbegin" ) == 0 )
|
|
return SCRIPTBEGIN;
|
|
else if ( _stricmp( szCmd, "scriptend" ) == 0 )
|
|
return SCRIPTEND;
|
|
else if ( _stricmp( szCmd, "threadbegin" ) == 0 )
|
|
return THREADBEGIN;
|
|
else if ( _stricmp( szCmd, "threadend" ) == 0 )
|
|
return THREADEND;
|
|
else if ( _stricmp( szCmd, "connect" ) == 0 )
|
|
return CONNECT;
|
|
else if ( _stricmp( szCmd, "disconnect" ) == 0 )
|
|
return DISCONNECT;
|
|
else if ( _stricmp( szCmd, "move" ) == 0 )
|
|
return MOVE;
|
|
else if ( _stricmp( szCmd, "sub" ) == 0 )
|
|
return SUB;
|
|
else if ( _stricmp( szCmd, "jump" ) == 0 )
|
|
return JUMP;
|
|
else if ( _stricmp( szCmd, "wait" ) == 0 )
|
|
return WAIT;
|
|
else if ( _stricmp( szCmd, "sleep" ) == 0 )
|
|
return SLEEP;
|
|
else if ( _stricmp( szCmd, "newgroup" ) == 0 )
|
|
return NEWGROUP;
|
|
else if ( _stricmp( szCmd, "rmgroup" ) == 0 )
|
|
return RMGROUP;
|
|
else if ( _stricmp( szCmd, "freegroup" ) == 0 )
|
|
return FREEGROUP;
|
|
else if ( _stricmp( szCmd, "xover" ) == 0 )
|
|
return XOVER;
|
|
else return INVALID;
|
|
}
|
|
|
|
BOOL
|
|
CParser::GetNextToken( LPSTR pbBuffer )
|
|
{
|
|
_ASSERT( pbBuffer );
|
|
*pbBuffer = 0;
|
|
|
|
while ( *m_lpstrCursor == '\t' ||
|
|
*m_lpstrCursor == ' ' )
|
|
*m_lpstrCursor++;
|
|
|
|
LPSTR lpstrOld = m_lpstrCursor;
|
|
|
|
while ( *m_lpstrCursor != '\t' &&
|
|
*m_lpstrCursor != ' ' &&
|
|
*m_lpstrCursor != '\r' &&
|
|
*m_lpstrCursor != '\n' &&
|
|
*m_lpstrCursor != 0 )
|
|
m_lpstrCursor++;
|
|
|
|
DWORD dwLen = m_lpstrCursor - lpstrOld;
|
|
_ASSERT( dwLen >= 0 );
|
|
|
|
|
|
CopyMemory( pbBuffer, lpstrOld, dwLen );
|
|
*(pbBuffer + dwLen ) = 0;
|
|
|
|
if ( *m_lpstrCursor == '\r' ) {
|
|
m_lpstrCursor++;
|
|
if ( *m_lpstrCursor == '\n' )
|
|
m_lpstrCursor++;
|
|
return FALSE;
|
|
}
|
|
|
|
if ( *m_lpstrCursor == '\n' ) {
|
|
m_lpstrCursor++;
|
|
return FALSE;
|
|
}
|
|
|
|
if ( *m_lpstrCursor == 0 )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
CParser::AllocBuffer( char**& argv )
|
|
{
|
|
argv = (char**)new DWORD[MAX_ARGS];
|
|
_ASSERT( argv );
|
|
|
|
_ASSERT( argv );
|
|
for ( int j = 0; j < MAX_ARGS; j++ ) {
|
|
argv[j] = new char[MAX_ARG_LEN];
|
|
_ASSERT( argv[j] );
|
|
}
|
|
}
|
|
|
|
void
|
|
CParser::DeallocBuffer( char **argv )
|
|
{
|
|
for ( int i = 0; i < MAX_ARGS; i++ )
|
|
delete[] argv[i];
|
|
|
|
delete[] argv;
|
|
}
|
|
|
|
BOOL
|
|
CParser::Parse()
|
|
{
|
|
OP_CODE opcode;
|
|
char **argv;
|
|
int argc;
|
|
CThread *pThread = NULL;
|
|
CInstruction *pInstruction = NULL;
|
|
DWORD iInstruction = 0;
|
|
|
|
AllocBuffer( argv );
|
|
|
|
opcode = GetNextLine( argc, argv );
|
|
while ( opcode != SCRIPTEND ) {
|
|
if ( INVALID == opcode ) {
|
|
printf( "Line %d has invalid command\n", m_dwLine );
|
|
DeallocBuffer( argv );
|
|
return FALSE;
|
|
}
|
|
|
|
// If it's a new thread, I need to create a thread object
|
|
if ( THREADBEGIN == opcode ) {
|
|
_ASSERT( pThread == NULL );
|
|
if ( argc != 2 ) {
|
|
printf( "Line %d thread command needs one argument\n", m_dwLine );
|
|
DeallocBuffer( argv );
|
|
return FALSE;
|
|
}
|
|
|
|
if ( g_cThread == MAX_THREAD_POOL ) {
|
|
printf ("Sorry, you can not have more than %d threads\n", MAX_THREAD_POOL );
|
|
DeallocBuffer( argv );
|
|
return FALSE;
|
|
}
|
|
|
|
pThread = new CThread( atol( argv[1] ) );
|
|
if ( NULL == pThread ) {
|
|
printf( "Create thread object failed on new\n" );
|
|
DeallocBuffer( argv );
|
|
return FALSE;
|
|
}
|
|
|
|
iInstruction = 0;
|
|
goto GetNext;
|
|
}
|
|
|
|
// If it's noop ( mostly blank lines ), continue
|
|
if ( NOOP == opcode || SCRIPTBEGIN == opcode) {
|
|
goto GetNext;
|
|
}
|
|
|
|
|
|
// Now we should create normal instruction objects
|
|
pInstruction = CreateInstruction ( opcode, iInstruction++, argc, argv );
|
|
if ( NULL == pInstruction ) {
|
|
DeallocBuffer( argv );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( pThread );
|
|
pThread->PushInstruction( pInstruction );
|
|
|
|
// If it's end of thread, push it to the global thread list and clean the
|
|
// thread pointer
|
|
if ( THREADEND == opcode ) {
|
|
_ASSERT( pThread );
|
|
g_rgThreadPool[g_cThread++] = pThread;
|
|
pThread = NULL;
|
|
}
|
|
|
|
GetNext:
|
|
opcode = GetNextLine( argc, argv );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CInstruction *
|
|
CParser::CreateInstruction( OP_CODE opcode, DWORD iInstruction, int argc, char **argv )
|
|
{
|
|
_ASSERT( argc > 0 );
|
|
_ASSERT( argv );
|
|
|
|
CInstruction *pInstruction = NULL;
|
|
|
|
switch( opcode ) {
|
|
|
|
case CONNECT:
|
|
pInstruction = new CConnect( opcode, iInstruction );
|
|
break;
|
|
|
|
case DISCONNECT:
|
|
pInstruction = new CDisconnect( opcode, iInstruction );
|
|
break;
|
|
|
|
case SUB:
|
|
pInstruction = new CSubtract( opcode, iInstruction );
|
|
break;
|
|
|
|
case JUMP:
|
|
pInstruction = new CJump( opcode, iInstruction );
|
|
break;
|
|
|
|
case MOVE:
|
|
pInstruction = new CMove( opcode, iInstruction );
|
|
break;
|
|
|
|
case WAIT:
|
|
pInstruction = new CWait( opcode, iInstruction );
|
|
break;
|
|
|
|
case NEWGROUP:
|
|
pInstruction = new CNewGroup( opcode, iInstruction );
|
|
break;
|
|
|
|
case SLEEP:
|
|
pInstruction = new CSleep( opcode, iInstruction );
|
|
break;
|
|
|
|
case RMGROUP:
|
|
pInstruction = new CRmGroup( opcode, iInstruction );
|
|
break;
|
|
|
|
case FREEGROUP:
|
|
pInstruction = new CFreeGroup( opcode, iInstruction );
|
|
break;
|
|
|
|
case XOVER:
|
|
pInstruction = new CXover( opcode, iInstruction );
|
|
break;
|
|
|
|
case THREADEND:
|
|
pInstruction = new CEnd( opcode, iInstruction );
|
|
break;
|
|
}
|
|
|
|
if ( NULL == pInstruction ) {
|
|
return NULL;
|
|
}
|
|
|
|
if ( !pInstruction->Parse( argc, argv ) ) {
|
|
delete pInstruction;
|
|
return NULL;
|
|
}
|
|
|
|
return pInstruction;
|
|
}
|
|
|
|
//
|
|
// Execute instructions that belong to a thread
|
|
//
|
|
void
|
|
CThread::Execute()
|
|
{
|
|
OP_CODE opcode;
|
|
CInstruction *pInstruction;
|
|
|
|
m_PC.Front();
|
|
pInstruction = m_PC.Current();
|
|
opcode = pInstruction->GetOpCode();
|
|
while ( opcode != THREADEND ) {
|
|
pInstruction->Execute( this );
|
|
pInstruction = m_PC.Current();
|
|
opcode = pInstruction->GetOpCode();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Jump to another instruction
|
|
//
|
|
void
|
|
CThread::Jump( DWORD dwInstruction )
|
|
{
|
|
// Set iterator to list head
|
|
m_PC.Front();
|
|
|
|
for ( int i = 0; i < dwInstruction; i++ ) {
|
|
m_PC.Next();
|
|
_ASSERT( !m_PC.AtEnd() );
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CThread::SetDWord( DWORD dwId, DWORD dwVal )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_VariableBag.PutDWord( dwId, dwVal );
|
|
SetLastError( hr );
|
|
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
BOOL
|
|
CThread::DecDWord( DWORD dwId, DWORD dwVal )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwOldVal = 0xffffffff;
|
|
|
|
hr = m_VariableBag.GetDWord( dwId, &dwOldVal );
|
|
if ( FAILED( hr ) ) {
|
|
SetLastError( hr );
|
|
printf( "Variable %d for thread %d undefined\n", dwId, m_dwThreadId );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( dwOldVal != 0xffffffff );
|
|
|
|
dwOldVal -= dwVal;
|
|
|
|
hr = m_VariableBag.PutDWord( dwId, dwOldVal );
|
|
SetLastError( hr );
|
|
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
BOOL
|
|
CThread::GetDWord( DWORD dwId, PDWORD pdwVal )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_VariableBag.GetDWord( dwId, pdwVal );
|
|
SetLastError( hr );
|
|
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
BOOL
|
|
CThread::RemoveDWord( DWORD dwId )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_VariableBag.RemoveProperty( dwId );
|
|
SetLastError( hr );
|
|
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
void
|
|
CThread::PushInstruction( CInstruction *pInstruction )
|
|
{
|
|
_ASSERT( pInstruction );
|
|
m_InstructionList.PushBack( pInstruction );
|
|
}
|
|
|
|
//
|
|
// Test if a thread has done the specified instruction
|
|
//
|
|
BOOL
|
|
CThread::Over( DWORD dwIndex )
|
|
{
|
|
CInstruction *pInstruction;
|
|
|
|
if ( m_PC.AtEnd() ) return TRUE;
|
|
|
|
pInstruction = m_PC.Current();
|
|
|
|
if ( pInstruction == NULL ) return FALSE;
|
|
else return ( dwIndex < pInstruction->GetIndex() );
|
|
}
|
|
|
|
DWORD WINAPI
|
|
CThread::ThreadProc( LPVOID pvContext )
|
|
{
|
|
_ASSERT( pvContext );
|
|
|
|
|
|
// cast context back to thread object
|
|
CThread *pThread = (CThread *)pvContext;
|
|
|
|
printf( "[%d]Begins to execute\n", pThread->GetThreadId() );
|
|
pThread->Execute();
|
|
printf( "[%d]Exists\n", pThread->GetThreadId() );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void
|
|
CThread::Create()
|
|
{
|
|
DWORD dwThreadId;
|
|
|
|
// Create a thread
|
|
m_hThread = CreateThread( NULL,
|
|
0,
|
|
ThreadProc,
|
|
this,
|
|
CREATE_SUSPENDED,
|
|
&dwThreadId );
|
|
if ( NULL == m_hThread ) {
|
|
_ASSERT( 0 );
|
|
}
|
|
}
|
|
|
|
void
|
|
CThread::KickOff()
|
|
{
|
|
ResumeThread( m_hThread );
|
|
}
|
|
|
|
BOOL
|
|
CVroot::Connect( DRIVER DriverType, LPSTR szPrefix, CDriverSyncComplete *pComplete )
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wszMBVroot[MAX_PATH];
|
|
WCHAR wszPrefix[MAX_PATH];
|
|
INntpDriverPrepare *pPrepare;
|
|
|
|
Lock();
|
|
if ( m_pDriver ) {
|
|
Unlock();
|
|
SetLastError( HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) );
|
|
return FALSE;
|
|
}
|
|
|
|
_ASSERT( m_lRef == 0 );
|
|
if ( DriverType == NTFS ) {
|
|
hr = CoCreateInstance( (REFCLSID)CLSID_CNntpFSDriverPrepare,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
(REFIID)IID_INntpDriverPrepare,
|
|
(void**)&pPrepare );
|
|
}
|
|
else if ( DriverType == EXCHANGE ) {
|
|
hr = CoCreateInstance( (REFCLSID)CLSID_CNntpExDriverPrepare,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
(REFIID)IID_INntpDriverPrepare,
|
|
(void**)&pPrepare );
|
|
} else {
|
|
_ASSERT( 0 );
|
|
}
|
|
|
|
if ( FAILED( hr ) ) {
|
|
Unlock();
|
|
printf( "CoCreate Driver failed %x\n", hr );
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
|
|
CopyAsciiStringIntoUnicode( wszPrefix, szPrefix );
|
|
m_pNewsTree->AddRef();
|
|
_ASSERT( m_pNewsTree->GetRef() == 2 );
|
|
m_pServer->AddRef();
|
|
_ASSERT( m_pServer->GetRef() == 2 );
|
|
pComplete->AddRef();
|
|
pComplete->AddRef();
|
|
_ASSERT( pComplete->GetRef() == 2 );
|
|
swprintf( wszMBVroot, L"/LM/nntpsvc/1/root/%s", wszPrefix );
|
|
g_pMB->AddRef();
|
|
pPrepare->Connect( wszMBVroot,
|
|
szPrefix,
|
|
g_pMB,
|
|
m_pServer,
|
|
m_pNewsTree,
|
|
&m_pDriver,
|
|
pComplete,
|
|
g_hProcessImpersonationToken );
|
|
pComplete->WaitForCompletion();
|
|
_ASSERT( pComplete->GetRef() == 0 );
|
|
_ASSERT( m_pNewsTree->GetRef() == 2 );
|
|
_ASSERT( m_pServer->GetRef() == 2 );
|
|
_VERIFY( pPrepare->Release() == 0 );
|
|
|
|
hr = pComplete->GetResult();
|
|
if ( FAILED( hr ) ) {
|
|
SetLastError( hr );
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy( m_szPrefix, szPrefix );
|
|
m_lRef++;
|
|
Unlock();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CVroot::Disconnect()
|
|
{
|
|
Lock();
|
|
if ( NULL == m_pDriver ) {
|
|
_ASSERT( m_lRef == 0 );
|
|
Unlock();
|
|
SetLastError( HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS ) );
|
|
return FALSE;
|
|
}
|
|
|
|
m_lRef--;
|
|
if ( m_lRef == 0 ) {
|
|
_VERIFY( 0 == m_pDriver->Release() );
|
|
_ASSERT( m_pNewsTree->GetRef() == 1 );
|
|
_ASSERT( m_pServer->GetRef() == 1 );
|
|
m_pDriver = NULL;
|
|
}
|
|
|
|
Unlock();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CVroot::CreateGroup( INNTPPropertyBag *pPropBag, LPSTR szGroupName, CDriverSyncComplete *pComplete )
|
|
{
|
|
Lock();
|
|
|
|
if ( NULL == m_pDriver ||
|
|
strlen( szGroupName ) < strlen( m_szPrefix ) ||
|
|
_strnicmp( szGroupName, m_szPrefix, strlen( m_szPrefix ) ) != 0 ) {
|
|
_ASSERT( m_lRef == 0 );
|
|
pPropBag->Release();
|
|
Unlock();
|
|
SetLastError( HRESULT_FROM_WIN32( NNTP_E_DRIVER_NOT_INITIALIZED ) );
|
|
return FALSE;
|
|
}
|
|
m_lRef++;
|
|
Unlock();
|
|
|
|
pComplete->AddRef();
|
|
pComplete->AddRef();
|
|
_ASSERT( pComplete->GetRef() == 2 );
|
|
m_pDriver->CreateGroup( pPropBag, g_hProcessImpersonationToken, pComplete );
|
|
pComplete->WaitForCompletion();
|
|
_ASSERT( pComplete->GetRef() == 0 );
|
|
|
|
HRESULT hr = pComplete->GetResult();
|
|
SetLastError( hr );
|
|
InterlockedDecrement( &m_lRef );
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
BOOL
|
|
CVroot::RemoveGroup( INNTPPropertyBag *pPropBag, LPSTR szGroupName, CDriverSyncComplete *pComplete )
|
|
{
|
|
Lock();
|
|
|
|
if ( NULL == m_pDriver ||
|
|
strlen( szGroupName ) < strlen( m_szPrefix ) ||
|
|
_strnicmp( szGroupName, m_szPrefix, strlen( m_szPrefix ) ) != 0 ) {
|
|
_ASSERT( m_lRef == 0 );
|
|
pPropBag->Release();
|
|
Unlock();
|
|
SetLastError( HRESULT_FROM_WIN32( NNTP_E_DRIVER_NOT_INITIALIZED ) );
|
|
return FALSE;
|
|
}
|
|
m_lRef++;
|
|
Unlock();
|
|
|
|
pComplete->AddRef();
|
|
pComplete->AddRef();
|
|
_ASSERT( pComplete->GetRef() == 2 );
|
|
m_pDriver->RemoveGroup( pPropBag, g_hProcessImpersonationToken, pComplete );
|
|
pComplete->WaitForCompletion();
|
|
_ASSERT( pComplete->GetRef() == 0 );
|
|
|
|
HRESULT hr = pComplete->GetResult();
|
|
SetLastError( hr );
|
|
InterlockedDecrement( &m_lRef );
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
BOOL
|
|
CVroot::Xover( INNTPPropertyBag *pPropBag, LPSTR szGroupName, DWORD dwLow, DWORD dwHigh, DWORD dwBufSize, CDriverSyncComplete *pComplete )
|
|
{
|
|
Lock();
|
|
|
|
if ( NULL == m_pDriver ||
|
|
strlen( szGroupName ) < strlen( m_szPrefix ) ||
|
|
_strnicmp( szGroupName, m_szPrefix, strlen( m_szPrefix ) ) != 0 ) {
|
|
_ASSERT( m_lRef == 0 );
|
|
pPropBag->Release();
|
|
Unlock();
|
|
SetLastError( HRESULT_FROM_WIN32( NNTP_E_DRIVER_NOT_INITIALIZED ) );
|
|
return FALSE;
|
|
}
|
|
m_lRef++;
|
|
Unlock();
|
|
|
|
LPSTR lpstrBuf = new char[dwBufSize+1];
|
|
DWORD dwAct = dwLow;
|
|
DWORD dwMin ;
|
|
DWORD dwSize;
|
|
HRESULT hr = S_OK;
|
|
|
|
while ( dwAct <= dwHigh ) {
|
|
pPropBag->AddRef();
|
|
dwMin = dwAct;
|
|
pComplete->AddRef();
|
|
pComplete->AddRef();
|
|
_ASSERT( pComplete->GetRef() == 2 );
|
|
m_pDriver->GetXover( pPropBag,
|
|
dwMin,
|
|
dwHigh,
|
|
&dwAct,
|
|
lpstrBuf,
|
|
dwBufSize,
|
|
&dwSize,
|
|
g_hProcessImpersonationToken,
|
|
pComplete );
|
|
pComplete->WaitForCompletion();
|
|
_ASSERT( pComplete->GetRef() == 0 );
|
|
hr = pComplete->GetResult();
|
|
if ( hr == S_OK ||
|
|
hr == S_FALSE && dwAct <= dwHigh ) { // need print
|
|
*(lpstrBuf + dwSize) = 0;
|
|
printf( "%s", lpstrBuf );
|
|
}
|
|
|
|
if ( hr == S_OK ) break;
|
|
|
|
if ( hr == S_FALSE && dwAct <= dwHigh ||
|
|
hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER )) { //buffer too small
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) { // need change buf
|
|
delete[] lpstrBuf;
|
|
dwBufSize *= 2;
|
|
lpstrBuf = new char[dwBufSize + 1];
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( hr == S_FALSE && dwAct > dwHigh ) break; // no article in the group
|
|
|
|
// fatal error
|
|
printf( "Fatal error when xover %x\n", hr );
|
|
SetLastError( hr );
|
|
pPropBag->Release();
|
|
delete[] lpstrBuf;
|
|
InterlockedDecrement( &m_lRef );
|
|
return FALSE;
|
|
}
|
|
|
|
pPropBag->Release();
|
|
delete[] lpstrBuf;
|
|
InterlockedDecrement( &m_lRef );
|
|
return TRUE;
|
|
}
|
|
|
|
void InitTreeStuff()
|
|
{
|
|
BOOL fFatal;
|
|
|
|
g_pServer = new CNntpServer();
|
|
_ASSERT( g_pServer );
|
|
|
|
g_pNewsTree = new CNewsTreeCore( g_pServer );
|
|
_ASSERT( g_pNewsTree );
|
|
|
|
g_pVRTable = new CNNTPVRootTable( g_pNewsTree->GetINewsTree(),
|
|
CNewsTreeCore::VRootRescanCallback );
|
|
_ASSERT( g_pVRTable );
|
|
|
|
if ( !g_pNewsTree->Init( g_pVRTable, fFatal, 100, FALSE ) || fFatal ) {
|
|
_ASSERT( 0 );
|
|
}
|
|
}
|
|
|
|
void TermTreeStuff()
|
|
{
|
|
delete g_pNewsTree;
|
|
delete g_pVRTable;
|
|
delete g_pServer;
|
|
}
|
|
|
|
int __cdecl main( int argc, char **argv )
|
|
{
|
|
CParser parser;
|
|
int i;
|
|
HRESULT hr = S_OK;
|
|
|
|
CoInitializeEx ( NULL, COINIT_MULTITHREADED );;
|
|
|
|
if ( argc != 3 && argc != 2) {
|
|
printf ( "Usage: drvstrs [script file name] [-v]\n" );
|
|
exit( 0 );
|
|
}
|
|
|
|
if ( argc == 3 ) g_bVerbal = TRUE;
|
|
else g_bVerbal = FALSE;
|
|
|
|
if ( ! parser.Init( argv[1] ) ) {
|
|
printf ( "Parse init failed somehow %d\n", GetLastError() );
|
|
exit( 0 );
|
|
}
|
|
|
|
if ( ! parser.Parse() ) {
|
|
printf ( "Parse failed somehow %d\n", GetLastError() );
|
|
exit( 0 );
|
|
}
|
|
|
|
for ( i = 0; i < MAX_VROOT_TABLE; i++ ) {
|
|
g_rgpVrootTable[i] = new CVroot;
|
|
_ASSERT( g_rgpVrootTable[i] );
|
|
}
|
|
|
|
// Create the metabase object
|
|
hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL,
|
|
IID_IMSAdminBase, (LPVOID *)&g_pMB );
|
|
if ( FAILED( hr ) ) {
|
|
printf( "Create metabase object failed %x\n", hr );
|
|
goto FreeVroot;
|
|
}
|
|
|
|
// Get process htoken
|
|
g_hProcessImpersonationToken = GetProcessToken();
|
|
if ( NULL == g_hProcessImpersonationToken ) {
|
|
printf( "Get system token failed %d\n", GetLastError() );
|
|
goto FreeVroot;
|
|
}
|
|
|
|
InitGlobalVarBag();
|
|
|
|
InitTreeStuff();
|
|
|
|
// start the threads
|
|
for ( i = 0; i < g_cThread; i++ )
|
|
g_rgThreadPool[i]->Create();
|
|
|
|
for ( i = 0; i < g_cThread; i++ )
|
|
g_rgThreadPool[i]->KickOff();
|
|
|
|
|
|
// wait for them to complete
|
|
for ( i = 0; i < g_cThread; i++ ) {
|
|
g_rgThreadPool[i]->BlockForCompletion();
|
|
delete g_rgThreadPool[i];
|
|
}
|
|
|
|
FreeVroot:
|
|
for ( i = 0; i < MAX_VROOT_TABLE; i++ ) {
|
|
delete g_rgpVrootTable[i];
|
|
}
|
|
|
|
TermTreeStuff();
|
|
|
|
DeInitGlobalVarBag();
|
|
CoUninitialize();
|
|
|
|
// OK, done
|
|
printf( "Goodbye\n" );
|
|
return 0;
|
|
}
|
|
|
|
|