RULECLSF.CPP

// --ruleclsf.cpp------------------------------------------------------------- 
//
// Implementation file for the CFolderRules control class and its
//class factory.
//
// The CFolderRules class is a controlling class. It controls the
// CIExchangeFolderRules class (which implements the IExchangeFolderRules
// programatic interface defined in rulecls.h). When we add automation
// capabilities, it will also control the standard OLE dispatch interface
// for this class.
//
// Copyright (C) Microsoft Corp. 1986-1996. All rights reserved.
//
// ---------------------------------------------------------------------------

#include "edk.h"
#include "srowlst.h"
#include "ruleclsf.h"
#include "ruleclsf.chk"


// $--CFolderRules::CFolderRules-----------------------------------------------
//
// DESCRIPTION:CFolderRules controlling class class constructor.
//
// INPUT:None.
//
// RETURNS: Ptr to new CFolderRules instance.
//
//-----------------------------------------------------------------------------

CFolderRules::CFolderRules()
{
DEBUGPRIVATE("CFolderRules::CFolderRules().\n");

m_hr =NOERROR; // no error so far
m_refs =1;
m_lpMapiTbl =NULL;
m_lpExchTbl =NULL;
m_lpFolder =NULL;

m_prog_interface = new CIExchangeFolderRules;

if ( m_prog_interface == NULL )
{
m_hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Set programming interface ptr to this object.

m_prog_interface->m_pFR = this;

cleanup:

; // no operation
}


// $--CFolderRules::~CFolderRules----------------------------------------------
//
// DESCRIPTION:CFolderRules controlling class class destructor.
//
// INPUT:None.
//
// RETURNS: Nothing.
//
//-----------------------------------------------------------------------------

CFolderRules::~CFolderRules()
{
DEBUGPRIVATE("CFolderRules::~CFolderRules().\n");

delete m_prog_interface;

ULRELEASE(m_lpMapiTbl);
ULRELEASE(m_lpExchTbl);
ULRELEASE(m_lpFolder);
}

// $--CFolderRules::Create-----------------------------------------------------
//
// DESCRIPTION:Create a new instance of the CFolderRules object.
//Also take care of setting up the standard OLE dispatch
//object pointer for the new instance.
//
// INPUT:None.
//
// RETURNS: Ptr to new CFolderRules object on success; NULL otherwise.
//
//-----------------------------------------------------------------------------

CFolderRules FAR *
CFolderRules::Create()// RETURNS CFolderRules pointer
{
CFolderRules FAR *pFolderRules =NULL;

DEBUGPRIVATE("CFolderRules::Create().\n");

// Create an instance of CFolderRules.

pFolderRules = new FAR CFolderRules();

if (pFolderRules == NULL)
{
HR_LOG(E_FAIL);
pFolderRules = NULL;
goto cleanup;
}

if (FAILED(pFolderRules->m_hr))
{
HR_LOG(pFolderRules->m_hr);
ULRELEASE(pFolderRules);
goto cleanup;
}

cleanup:

return pFolderRules;
}


// $--CFolderRules::HrGetProviders---------------------------------------------
//
// DESCRIPTION:Get an array of rules provider names.
//
// OUTPUT:
//
// [lpcProviders]-- Pointer to ulong that will be set to count of
// providers on successful return.
//[lpppszProviders]-- Pointer to array of string pointers that will be set
// to point at an array of provider name string pointers
// on successful return.
//
// RETURNS: NOERRORif successful;
//E_OUTOFMEMORYif not enough memory;
// E_FAIL otherwise.
//
//-----------------------------------------------------------------------------

HRESULT
CFolderRules::HrGetProviders(// RETURNS: HRESULT
OUTLPULONGlpcProviders,// count of providers
OUTLPSTR FAR * FAR *lpppszProviders// ptr to array of providers
)
{
HRESULThr =NOERROR;

DEBUGPRIVATE("CFolderRules::HrGetProviders()\n");

if (m_lpFolder == NULL)
hr = E_FAIL;
else
hr = m_SRowLst.HrGetProviders(lpcProviders, lpppszProviders);

RETURN(hr);
}


// $--CFolderRules::HrOpen-----------------------------------------------------
//
// DESCRIPTION:Open the object on a rules folder.
//
// INPUT:
//
// [lpMDB]-- Ptr to MDB object containing the rules folder.
// [cbentryid]-- Number of bytes in folder's entry identifier.
// [lpentryid]-- Folder's entry identifier.
// [lpszProvider]-- Provider for rules. Multiple providers may have
// rules on a folder. The IExchangeFolderRules interface
// provides access to the rules associated with a
// single specified provider. May be NULL, in which case
// a provider list can be obtained, but no other operations
// are possible.
//
// RETURNS: NOERROR on success;
// E_INVALIDARG if bad input;
//E_NOINTERFACE if the rules table does not exist on the folder;
// E_FAIL otherwise.
//
//-----------------------------------------------------------------------------

HRESULT
CFolderRules::HrOpen(// RETURNS: HRESULT
INLPMDBlpMDB,// MDB store pointer
INULONGcbentryid, // # bytes in entry ID
INLPENTRYIDlpentryid,// entry ID pointer
INLPSTRlpszProvider// provider name
)
{
HRESULThr =NOERROR;
LPSRowSetlpRows =NULL;
ULONGulObjType =0;

// NOTE: The following order of properties is assumed by lots
// of other code (CFolderRules, CIExchangeFolderRules).

SizedSPropTagArray(C_RULEPROPS, rgPropTag) =
{
C_RULEPROPS,
{
PR_RULE_SEQUENCE,
PR_RULE_STATE,
PR_RULE_CONDITION,
PR_RULE_ACTIONS,
PR_RULE_PROVIDER,
PR_RULE_LEVEL,
PR_RULE_NAME
}
};

DEBUGPRIVATE("CFolderRules::HrOpen()\n");

hr = CHK_CFolderRules_HrOpen(lpMDB, cbentryid, lpentryid, lpszProvider);

if (FAILED(hr))
RETURN(hr);

// Don't allow multiple opens on one object.

if (m_lpFolder != NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Open the folder.

hr = lpMDB->OpenEntry(cbentryid,
lpentryid,
NULL,
MAPI_BEST_ACCESS|
MAPI_DEFERRED_ERRORS,
&ulObjType,
(LPUNKNOWN FAR *)&m_lpFolder);
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if (ulObjType != MAPI_FOLDER)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Open the RULE table property on the folder. The returned table
// pointer may be used to get a MAPI table for reading and it can
// also be used to modify the rules table. If there is no rules table,
// this call will fail with E_NOINTERFACE.

hr = m_lpFolder->OpenProperty(PR_RULES_TABLE,
(LPGUID)&IID_IExchangeModifyTable,
0,
MAPI_DEFERRED_ERRORS,
(LPUNKNOWN FAR *)&m_lpExchTbl);
if (FAILED(hr))
goto cleanup;

// Open a MAPI table on the RULE table property. This table can be
// read to determine what the rules table looks like.

hr = m_lpExchTbl->GetTable(0, &m_lpMapiTbl);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Select columns needed.

hr = m_lpMapiTbl->SetColumns((LPSPropTagArray)&rgPropTag, 0);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Get all the rows in the table up to EDK_MAX_QUERY_ROWS. If there
// are more rows than this, fail with MAPI_E_TABLE_TOO_BIG.

hr = m_lpMapiTbl->QueryRows(EDK_MAX_QUERY_ROWS, 0, &lpRows);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Check to be sure that table is not bigger than EDK_MAX_QUERY_ROWS.
// We do this by checking whether or not the cursor is positioned at
// the end of the table.

if (lpRows->cRows == EDK_MAX_QUERY_ROWS)
{
ULONGulRow =0;
ULONGulNumerator =0;
ULONGulDenominator =0;

hr = m_lpMapiTbl->QueryPosition(&ulRow, &ulNumerator, &ulDenominator);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// SeekRowApprox() doc states that if ulNumerator == ulDenominator, you
// are at the end of the table.

if (ulNumerator != ulDenominator)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

// Store the table in a sorted and more manageable format.

hr = m_SRowLst.HrInitialize(lpszProvider, lpRows);

if (FAILED(hr))
goto cleanup;

// NOTE - lpRows gets deallocated in SROWLST::Initialize(). We NULL it
// out here as a safeguard against future use.

lpRows = NULL;

cleanup:

if (FAILED(hr))
{
ULRELEASE(m_lpMapiTbl);
ULRELEASE(m_lpExchTbl);
ULRELEASE(m_lpFolder);
}

RETURN(hr);
}

//---------------------------------------------------------------------
// IUnknown methods
//---------------------------------------------------------------------

// $--CFolderRules::QueryInterface---------------------------------------------
//
// DESCRIPTION:Return pointer to object which implements the desired
//interface, if this object supports the interface.
//
// INPUT:
//
// [riid]-- Reference to interface identifier of desired interface.
//
// [ppv]-- Ptr to object which supports interface. NULL if none.
//
// RETURNS: NOERROR if successful;
//E_INVALIDARG if bad input.
//E_NOINTERFACE if interface isn't supported.
//
// Interfaces supported:
//
// IUnknown
// IDispatch (eventually)
// IExchangeFolderRules
// DFolderRules (eventually)
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CFolderRules::QueryInterface(// RETURNS: HRESULT
INREFIIDriid, // interface ID reference
OUTLPVOID FAR *ppv // pointer to interface pointer
)
{
HRESULT hr =NOERROR;

DEBUGPRIVATE("CFolderRules::QueryInterface().\n");

hr = CHK_CFolderRules_QueryInterface(riid, ppv);

if (FAILED(hr))
RETURN(hr);

*ppv = NULL;

// See if we support the requested interface.

if (IsEqualIID(riid, IID_IUnknown)) // IUnknown interface is ourself
{
*ppv = this; // Return ourself
}
else if (IsEqualIID(riid, IID_IExchangeFolderRules))
{
// User wants our programatic interface.

*ppv = m_prog_interface;
}
else
{
// We don't support the requested interface.

*ppv = NULL;
hr = HR_LOG(E_NOINTERFACE);
goto cleanup;
}

// If we reach this point, no error occurred. Increment reference count.

AddRef();

cleanup:

RETURN(hr);
}


// $--CFolderRules::AddRef-----------------------------------------------------
//
// DESCRIPTION:Increment the reference count on this object.
//
// INPUT:None.
//
// RETURNS: New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CFolderRules::AddRef()// RETURNS: ULONG
{
DEBUGPRIVATE("CFolderRules::AddRef().\n");

ASSERTERROR(m_refs, "Bad m_refs.");

m_refs++;

return m_refs;
}


// $--CFolderRules::Release----------------------------------------------------
//
// DESCRIPTION:Decrement the reference count on this object. If the
//reference count reaches 0, destroy this object.
//
// INPUT:None.
//
// RETURNS: New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CFolderRules::Release()// RETURNS: ULONG
{
ULONG ulRefCount =0;

DEBUGPRIVATE("CFolderRules::Release().\n");

ASSERTERROR(m_refs, "Bad m_refs.");

m_refs--;

if (!m_refs)
{
delete this;
ulRefCount = 0;
}
else
{
ulRefCount = m_refs;
}

return ulRefCount;
}