#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef char* LPMULTISZ; #include #define _ASSERTE( x ) _ASSERT( x ) #include CComModule _Module; #include #include typedef char * LPMULTISZ; #include #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(this); } else if ( iid == IID_INntpServer ) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(*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(this); } else if ( iid == IID_INewsTree ) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(*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 m_InstructionList; // Program counter TFList::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; }