320 lines
8.4 KiB
C++
320 lines
8.4 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
||
|
//
|
||
|
// File: queue.hxx
|
||
|
//
|
||
|
// Contents:
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History: 01-05-96 Rohanp Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#ifndef __QUEUE_H__
|
||
|
#define __QUEUE_H__
|
||
|
|
||
|
const DWORD SMTP_QUEUE_TYPE = 0;
|
||
|
enum QUEUE_TYPE {LOCALQ, REMOTEQ, RETRYQ};
|
||
|
enum QUEUE_OPCODE {PROCESS_QUEUE, TERMINATE_QUEUE};
|
||
|
enum QUEUE_POSITION {QUEUE_TAIL, QUEUE_HEAD};
|
||
|
enum QUEUE_SIG {SIGNAL, NONSIGNAL};
|
||
|
|
||
|
|
||
|
// The PERSIST_QUEUE_ENTRY is the wrapper for the message in the queue,
|
||
|
// containing creation and last access time for messages, as well as
|
||
|
// Identifiers, flags, and retrys. Actual queue elements will be derived
|
||
|
// from PERSIST_QUEUE_ENTRY
|
||
|
|
||
|
//forward declaration
|
||
|
class PERSIST_QUEUE;
|
||
|
class SMTP_SERVER_INSTANCE;
|
||
|
|
||
|
class PERSIST_QUEUE_ENTRY
|
||
|
{
|
||
|
private:
|
||
|
|
||
|
QUEUE_OPCODE m_OpCode;
|
||
|
PERSIST_QUEUE * m_ParentQ;
|
||
|
SMTP_SERVER_INSTANCE * m_pInstance;
|
||
|
|
||
|
protected:
|
||
|
|
||
|
LONGLONG m_ExpireTime; // Time to delete object
|
||
|
LONGLONG m_LastAccess; // Time of last access
|
||
|
DWORD m_QueueId; // Unique ID
|
||
|
DWORD m_RefId; // Sub-ref ID for duplicates
|
||
|
DWORD m_Flags; // Flags
|
||
|
DWORD m_Retries; // Number of retries
|
||
|
|
||
|
public:
|
||
|
|
||
|
LIST_ENTRY m_QEntry; // List pointers
|
||
|
|
||
|
PERSIST_QUEUE_ENTRY(SMTP_SERVER_INSTANCE * pInstance)
|
||
|
{
|
||
|
m_OpCode = PROCESS_QUEUE;
|
||
|
m_ParentQ = NULL;
|
||
|
m_ExpireTime = (LONGLONG) 0;
|
||
|
m_LastAccess = (LONGLONG) 0;
|
||
|
m_QueueId = 0;
|
||
|
m_RefId = 0;
|
||
|
m_Flags = 0;
|
||
|
m_Retries = 0;
|
||
|
m_pInstance = pInstance;
|
||
|
}
|
||
|
|
||
|
SMTP_SERVER_INSTANCE * QuerySmtpInstance( VOID ) const
|
||
|
{ _ASSERT(m_pInstance != NULL); return m_pInstance; }
|
||
|
|
||
|
BOOL IsSmtpInstance( VOID ) const
|
||
|
{ return m_pInstance != NULL; }
|
||
|
|
||
|
VOID SetSmtpInstance( IN SMTP_SERVER_INSTANCE * pInstance )
|
||
|
{ _ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }
|
||
|
|
||
|
void SetExpireTime(LONGLONG ExpireTime) {m_ExpireTime = ExpireTime;}
|
||
|
LONGLONG GetExpireTime (void) const{return m_ExpireTime;}
|
||
|
void SetLastAccessTime(LONGLONG LastTime) {m_LastAccess = LastTime;}
|
||
|
LONGLONG GetLastAccessTime(void) const {return m_LastAccess;}
|
||
|
void SetOpCode (QUEUE_OPCODE OpCode){m_OpCode = OpCode;}
|
||
|
void SetParentQ (PERSIST_QUEUE *ParentQ){m_ParentQ = ParentQ;}
|
||
|
PERSIST_QUEUE * GetParentQ (void)const {return m_ParentQ;}
|
||
|
QUEUE_OPCODE GetOpCode (void) const {return m_OpCode;}
|
||
|
LIST_ENTRY & QueryListEntry(void) {return ( m_QEntry);}
|
||
|
virtual void BeforeDelete(void){}
|
||
|
virtual ~PERSIST_QUEUE_ENTRY(){}
|
||
|
|
||
|
};
|
||
|
|
||
|
typedef PERSIST_QUEUE_ENTRY * PQUEUE_ENTRY;
|
||
|
|
||
|
//
|
||
|
// A PERSIST_QUEUE is the convenient abstraction to hold all of the messages that
|
||
|
// we're trying to deliver. Threads wait on the queue throught the m_QEvent handle.
|
||
|
// This thread is used to dispatch various entries as they become available
|
||
|
// either through magically appearing in the queue from somewhere else, or
|
||
|
// through the timeout (RetryInterval).
|
||
|
// All times in the queue are FILETIMES
|
||
|
|
||
|
//QHEADER is the part of the queue that will be written to disk.
|
||
|
//it is the header.
|
||
|
|
||
|
struct QHEADER
|
||
|
{
|
||
|
DWORD TypeOfEntry;
|
||
|
DWORD Entries; // Number of entries
|
||
|
DWORD Flags; // Flags
|
||
|
DWORD RetryInterval; // Retry interval for messages
|
||
|
DWORD StoreInterval; // Flush to store interval
|
||
|
LONGLONG LastStore; // Time of last store
|
||
|
};
|
||
|
|
||
|
class PERSIST_QUEUE
|
||
|
{
|
||
|
|
||
|
private :
|
||
|
|
||
|
QHEADER m_QData;
|
||
|
HANDLE m_QEvent; // Queue event
|
||
|
DWORD m_NumThreads;
|
||
|
HANDLE m_ThreadHandle[64]; // Thread handle
|
||
|
CRITICAL_SECTION m_CritSec; // Guard
|
||
|
LIST_ENTRY m_QHead; // List pointers
|
||
|
SMTP_SERVER_INSTANCE * m_ParentInst;
|
||
|
|
||
|
BOOL InitializeQueue(void);
|
||
|
|
||
|
public:
|
||
|
|
||
|
PERSIST_QUEUE (SMTP_SERVER_INSTANCE * pSmtpInst) //initialize stuff that can't fail
|
||
|
{
|
||
|
TraceFunctEnterEx((LPARAM)this, "PERSIST_QUEUE::PERSIST_QUEUE");
|
||
|
|
||
|
_ASSERT(pSmtpInst != NULL);
|
||
|
|
||
|
m_QEvent = NULL;
|
||
|
m_ParentInst = pSmtpInst;
|
||
|
|
||
|
m_NumThreads = 1;
|
||
|
|
||
|
//Init or critical section. This protects the queue
|
||
|
InitializeCriticalSection(&m_CritSec);
|
||
|
|
||
|
//Init the heaad of the queue
|
||
|
InitializeListHead(&m_QHead);
|
||
|
|
||
|
TraceFunctLeaveEx((LPARAM)this);
|
||
|
}
|
||
|
|
||
|
void SetNumThreads (DWORD NumThreads)
|
||
|
{
|
||
|
m_NumThreads = min(NumThreads, sizeof(m_ThreadHandle)/sizeof(m_ThreadHandle[0]));
|
||
|
}
|
||
|
|
||
|
virtual ~PERSIST_QUEUE ()
|
||
|
{
|
||
|
TraceFunctEnterEx((LPARAM)this, "~PERSIST_QUEUE");
|
||
|
|
||
|
//FlushQueueEvents();
|
||
|
|
||
|
if(m_QEvent != NULL)
|
||
|
CloseHandle(m_QEvent);
|
||
|
|
||
|
WaitForQThread();
|
||
|
|
||
|
DWORD Loop = 0;
|
||
|
|
||
|
for (Loop = 0; Loop < m_NumThreads; Loop++)
|
||
|
{
|
||
|
if(m_ThreadHandle[Loop] != NULL)
|
||
|
CloseHandle(m_ThreadHandle[Loop]);
|
||
|
}
|
||
|
|
||
|
DeleteCriticalSection (&m_CritSec);
|
||
|
|
||
|
TraceFunctLeaveEx((LPARAM)this);
|
||
|
}
|
||
|
|
||
|
void WaitForQThread(void)
|
||
|
{
|
||
|
|
||
|
DWORD WhichEvent;
|
||
|
|
||
|
WhichEvent = WaitForMultipleObjects(m_NumThreads, m_ThreadHandle, TRUE, INFINITE);
|
||
|
|
||
|
}
|
||
|
|
||
|
void SetQueueEvent(void)
|
||
|
{
|
||
|
_ASSERT(m_QEvent != NULL);
|
||
|
_ASSERT(m_ParentInst != NULL);
|
||
|
|
||
|
SetEvent(m_QEvent);
|
||
|
}
|
||
|
|
||
|
virtual PQUEUE_ENTRY PopQEntry(void)
|
||
|
{
|
||
|
PLIST_ENTRY plEntry = NULL;
|
||
|
PQUEUE_ENTRY pqEntry = NULL;
|
||
|
|
||
|
_ASSERT(m_ParentInst != NULL);
|
||
|
|
||
|
//get the first item off the queue
|
||
|
plEntry = RemoveHeadList (&m_QHead);
|
||
|
pqEntry = CONTAINING_RECORD(plEntry, PERSIST_QUEUE_ENTRY, m_QEntry);
|
||
|
|
||
|
//decrement the number of entries in the queue
|
||
|
--m_QData.Entries;
|
||
|
|
||
|
return pqEntry;
|
||
|
}
|
||
|
|
||
|
SMTP_SERVER_INSTANCE * GetParentInst(void)const {return m_ParentInst;}
|
||
|
void LockQ () {EnterCriticalSection (&m_CritSec);}
|
||
|
void UnLockQ() {LeaveCriticalSection (&m_CritSec);}
|
||
|
virtual void DropRetryCounter(void) {}
|
||
|
virtual void BumpRetryCounter(void) {}
|
||
|
virtual DWORD GetRetryMinutes(void) {return INFINITE;}
|
||
|
HANDLE GetQueueThreadHandle(void) const {return NULL;}
|
||
|
HANDLE GetQueueEventHandle(void) const {return m_QEvent;}
|
||
|
static PERSIST_QUEUE * CreateQueue(QUEUE_TYPE Qtype, SMTP_SERVER_INSTANCE * pSmtpInst);
|
||
|
LIST_ENTRY & QueryListHead(void) {return ( m_QHead);}
|
||
|
DWORD GetNumEntries(void) const {return m_QData.Entries;}
|
||
|
BOOL IsQueueEmpty(void) const {return IsListEmpty(&m_QHead);}
|
||
|
virtual BOOL ProcessQueueEvents(ISMTPConnection *pISMTPConnection);
|
||
|
virtual BOOL IsAtLeastOneValidUser (void){return TRUE;}
|
||
|
static DWORD WINAPI QueueThreadRoutine(void * ThisPtr);
|
||
|
void FlushQueueEvents(void);
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Name :
|
||
|
PERSIST_QUEUE::InsertEntry
|
||
|
|
||
|
Description:
|
||
|
This function inserts an element into the queue.
|
||
|
It always inserts aat the tail
|
||
|
|
||
|
Arguments:
|
||
|
pEntry - Element to insert into the queue
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
always TRUE
|
||
|
--*/
|
||
|
virtual BOOL InsertEntry(IN OUT PERSIST_QUEUE_ENTRY * pEntry, QUEUE_SIG Qsig = SIGNAL, QUEUE_POSITION Qpos = QUEUE_TAIL)
|
||
|
{
|
||
|
_ASSERT( pEntry != NULL);
|
||
|
_ASSERT(m_ParentInst != NULL);
|
||
|
|
||
|
|
||
|
//get the lock the protects the queue
|
||
|
LockQ();
|
||
|
|
||
|
//increment number of entries in the queue
|
||
|
++m_QData.Entries;
|
||
|
|
||
|
//Insert into the list of mail contexts.
|
||
|
if(Qpos == QUEUE_TAIL)
|
||
|
{
|
||
|
InsertTailList( &m_QHead, &pEntry->QueryListEntry());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InsertHeadList( &m_QHead, &pEntry->QueryListEntry());
|
||
|
}
|
||
|
|
||
|
if(Qsig == SIGNAL)
|
||
|
SetEvent (m_QEvent);
|
||
|
|
||
|
//release the lock and return
|
||
|
UnLockQ();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Name :
|
||
|
PERSIST_QUEUE::RemoveEntry
|
||
|
|
||
|
Description:
|
||
|
This function deletes an entry from the queue
|
||
|
|
||
|
Arguments:
|
||
|
pEntry - Element to insert into the queue
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
--*/
|
||
|
void RemoveEntry(IN OUT PERSIST_QUEUE_ENTRY * pEntry)
|
||
|
{
|
||
|
_ASSERT( pEntry != NULL);
|
||
|
_ASSERT(m_ParentInst != NULL);
|
||
|
|
||
|
LockQ();
|
||
|
|
||
|
//decrement number of entries in the queue
|
||
|
--m_QData.Entries;
|
||
|
|
||
|
// Remove from list of connections
|
||
|
RemoveEntryList( &pEntry->QueryListEntry());
|
||
|
|
||
|
UnLockQ();
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
typedef PERSIST_QUEUE * PQUEUE;
|
||
|
|
||
|
BOOL OpenQueueFile (char * FileName, char * InputBuffer, HANDLE* QFHandle, char * Sender);
|
||
|
HANDLE GetDuplicateMailQHandle (HANDLE QFileHandle);
|
||
|
|
||
|
#endif
|