ACLCLSI.CPP

// --aclclsi.cpp------------------------------------------------------------- 
//
// Implementation file for the CIExchangeFolderACLs programmer interface class.
//
// The CFolderACLs class is the controlling class. It controls the
// CIExchangeFolderACLs class (which implements the IExchangeFolderACLs
//programatic interface defined in aclcls.h and which this file implements).
//
// Copyright (C) Microsoft Corp. 1986-1996, All rights reserved.
//
// ---------------------------------------------------------------------------

#include "edk.h"
#include "srowlst.h"
#include "aclclsf.h"
#include "aclclsi.chk"

// IUnknown Methods --
// Let the controlling parent object handle all of these!

// $--CIExchangeFolderACLs::QueryInterface-------------------------------------
//
// DESCRIPTION:Return ptr to object which implements the desired
//interface, if this object supports the interface.
//
//Implemented via the parent object's (CFolderACLs')
//QueryInterface.
// INPUT:
//
// [riid]-- Reference to interface identifier of desired interface.
//
// OUTPUT:
//
// [ppvObj]-- Ptr to object which supports interface. NULL if none.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
//E_NOINTERFACEif interface not supported.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::QueryInterface(// RETURNS: HRESULT
INREFIIDriid, // interface ID reference
OUTLPVOID FAR *ppvObj // interface ptr ptr
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderACLs::QueryInterface().\n");

hr = CHK_CIExchangeFolderACLs_QueryInterface(riid, ppvObj);

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

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA");

// Let parent controlling object handle this. (Let it do all
// parameter checking also!)

hr = m_pFA->QueryInterface(riid, ppvObj);

RETURN(hr);
}


// $--CIExchangeFolderACLs::AddRef---------------------------------------------
//
// DESCRIPTION:Increment this object's reference count.
//
//Implemented via the parent object's (CFolderACLs') AddRef().
//
// INPUT:None.
//
// RETURNS:New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CIExchangeFolderACLs::AddRef()// RETURNS: ULONG
{
ULONGulRefCount =0;

DEBUGPUBLIC("CIExchangeFolderACLs::AddRef().\n");

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA");

// Let parent controlling object handle this.

ulRefCount = m_pFA->AddRef();

return ulRefCount;
}


// $--CIExchangeFolderACLs::Release--------------------------------------------
//
// DESCRIPTION:Decrement this object's reference count.
//
//Implemented via the parent object's (CFolderACLs') Release().
//
// INPUT:None.
//
// RETURNS:New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CIExchangeFolderACLs::Release() // RETURNS: ULONG
{
ULONGulRefCount =0;

DEBUGPUBLIC("CIExchangeFolderACLs::Release().\n");

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA");

// Let parent controlling object handle this.

ulRefCount = m_pFA->Release();

return ulRefCount;
}

//
// Methods unique to the IExchangeFolderACLs interface.
//

// $--CIExchangeFolderACLs::HrDelete-------------------------------------------
//
// DESCRIPTION:Delete the current record.
//
// INPUT:None.
//
// RETURNS:NOERRORif successful;
// E_OUTOFMEMORYif insufficient memory;
// E_FAILif cursor at ACL_PAST_END, or if the
//current record is the default ACL or is
//the ACL for the current user.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrDelete(VOID)// RETURNS: HRESULT
{
HRESULThr =NOERROR;
LONGlPosDeletion =ACL_PAST_END;
LONGlNewRights =0;
LPSRowlpRow =NULL;
CSROWNODE *pDeletedNode =NULL;

DEBUGPUBLIC("CIExchangeFolderACLs::HrDelete().\n");

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

lPosDeletion = m_pFA->m_SRowLst.GetCursor();

hr = m_pFA->m_SRowLst.HrRemoveFromLst(&pDeletedNode);

if (FAILED(hr))
goto cleanup;

lpRow = &pDeletedNode->m_SRow;

if (lpRow->lpProps[I_MEMBER_ENTRYID].Value.bin.cb == 0)
{
hr = HR_LOG(E_FAIL);// Cannot delete default ACL!
}
else
{
hr = m_pFA->m_SRowLst.HrWriteToTable(m_pFA->m_lpExchTbl);
}

if (FAILED(hr))
{
HRESULThrTmp = m_pFA->m_SRowLst.HrInsert(lpRow);

if (FAILED(hrTmp))
hr = HR_LOG(E_UNEXPECTED);
else
lpRow->lpProps = NULL;

goto cleanup;
}

// Check that the deletion actually worked. IExchangeModifyTable will
// actually add back the current user acl if you attempt to delete it,
// albeit with different rights. If we detect that this has happened,
// we modify back to the original rights and fail the call.

hr = m_pFA->HrGetTableEntry(lpRow->lpProps[I_MEMBER_ENTRYID].Value.bin.cb,
(LPENTRYID)
lpRow->lpProps[I_MEMBER_ENTRYID].Value.bin.lpb,
NULL,
&lNewRights);

if (hr == EDK_E_NOT_FOUND)
{
hr = NOERROR;
}
else
{
if (FAILED(hr))
{
// This is not expected to happen. If it does, we need to fix
// the problem so that we can insure that the table and list are
// in sync.

hr = HR_LOG(E_UNEXPECTED);
goto cleanup;
}
else
{
// The entry is still in the table, so reinsert it into the list
// and rewrite the table to insure that the rights are in sync.

hr = HR_LOG(E_FAIL);

HRESULThrTmp = m_pFA->m_SRowLst.HrInsert(lpRow);

if (FAILED(hrTmp))
{
hr = HR_LOG(E_UNEXPECTED);
goto cleanup;
}
else
{
lpRow->lpProps = NULL;
}

hrTmp = m_pFA->m_SRowLst.HrWriteToTable(m_pFA->m_lpExchTbl);

if (FAILED(hrTmp))
hr = HR_LOG(E_UNEXPECTED);

goto cleanup;
}
}

cleanup:

delete pDeletedNode;

RETURN(hr);
}


// $--CIExchangeFolderACLs::HrGet----------------------------------------------
//
// DESCRIPTION:Get the current record and advance the cursor.
//
// OUTPUT:
//
// [lplRights]-- ACL rights bits buffer.
// [lppszDisplayName]-- Member display name buffer.
// [lpcbentryid]-- Count of bytes in member entry ID.
// [lppentryid]-- Member entry ID buffer.
//
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
// E_FAILif cursor at ACL_PAST_END;
// E_OUTOFMEMORYif insufficient memory.
//
// Notes:Space for *lplRights and *lpcbentryid is allocated by the user.
//Space for the other parameters is allocated by this method.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrGet(// RETURNS: HRESULT
OUTLPLONGlplRights,// rights ptr
OUTLPSTR FAR *lppszDisplayName, // display name ptr
OUTULONG FAR *lpcbentryid,// # of bytes in entry ID ptr
OUTLPENTRYID FAR *lppentryid// entry ID ptr ptr
)
{
HRESULThr =NOERROR;
CSROWNODE *pNode =NULL;

DEBUGPUBLIC("CIExchangeFolderACLs::HrGet().\n");

hr = CHK_CIExchangeFolderACLs_HrGet(lplRights,
lppszDisplayName,
lpcbentryid,
lppentryid);
if (FAILED(hr))
RETURN(hr);

// Null the ptrs so we can free them on failure.

*lppszDisplayName =NULL;
*lppentryid =NULL;

*lpcbentryid =0;// Safeguard against misuse.

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

pNode = m_pFA->m_SRowLst.GetCurrentNode();

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

if (pNode->m_SRow.cValues < C_ACLPROPS||
pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].ulPropTag !=
PR_MEMBER_ENTRYID||
pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].ulPropTag !=
PR_MEMBER_RIGHTS||
pNode->m_SRow.lpProps[I_MEMBER_NAME].ulPropTag !=
PR_MEMBER_NAME)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

*lpcbentryid = pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].Value.bin.cb;

if (*lpcbentryid != 0&&
pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].Value.bin.lpb != NULL)
{
hr = MAPIAllocateBuffer(*lpcbentryid, (LPVOID FAR *)lppentryid);

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

memcpy(*lppentryid,
pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].Value.bin.lpb,
*lpcbentryid);
}

*lplRights = pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l;

if (pNode->m_SRow.lpProps[I_MEMBER_NAME].Value.lpszA != NULL)
{
ULONGcb = strlen(pNode->m_SRow.lpProps[I_MEMBER_NAME].Value.lpszA) +
sizeof(char);

hr = MAPIAllocateBuffer(cb, (LPVOID FAR *)lppszDisplayName);

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

strcpy(*lppszDisplayName,
pNode->m_SRow.lpProps[I_MEMBER_NAME].Value.lpszA);
}

// Advance the cursor.

m_pFA->m_SRowLst.SetCursor(m_pFA->m_SRowLst.GetCursor() + 1);

cleanup:

if (FAILED(hr))
{
MAPIFREEBUFFER(*lppszDisplayName);
MAPIFREEBUFFER(*lppentryid);
}

RETURN(hr);
}


// $--CIExchangeFolderACLs::HrInsert-------------------------------------------
//
// DESCRIPTION:Insert record before the current record and advance the cursor.
//
// INPUT:
//
// [lRights]-- Member's ACL Rights bits.
// [lpszDisplayName]-- Member's Display Name.
// [cbentryid]-- Count of bytes in member's entry identifier.
//[lpentryid]-- Ptr to member's entry identifier.
//
// OUTPUT:
//
//[lplRights]-- Ptr to rights bits actually set on completion; if
// this info is not wanted, specify NULL.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
// E_OUTOFMEMORYif memory problems;
// E_FAILotherwise (attempting to insert an acl for
//another existing user, etc.).
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrInsert(// RETURNS: HRESULT
INLONGlRights, // rights bits
INLPSTRlpszDisplayName, // display name
INULONGcbentryid,// # bytes in entry ID
INLPENTRYIDlpentryid,// entry ID ptr
OUTLPLONGlplRights// ptr to output rights bits
)
{
HRESULThr =NOERROR;
LONGlNewRights =0;
LPSTRlpszDisplayNameCopy =NULL;
LPENTRYIDlpentryidCopy =NULL;
LONGlPosInsertion =ACL_PAST_END;
SRowsr = {0, C_ACLPROPS, NULL};

DEBUGPUBLIC("CIExchangeFolderACLs::HrInsert().\n");

hr = CHK_CIExchangeFolderACLs_HrInsert(lRights,
lpszDisplayName,
cbentryid,
lpentryid,
lplRights);
if (FAILED(hr))
RETURN(hr);

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

lPosInsertion = m_pFA->m_SRowLst.GetCursor();

if (lPosInsertion == ACL_PAST_END)
lPosInsertion = m_pFA->m_SRowLst.GetNodeCount();

hr = MAPIAllocateBuffer(sizeof(SPropValue) * C_ACLPROPS,
(LPVOID FAR *)&sr.lpProps);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

memset(sr.lpProps, 0, sizeof(SPropValue) * C_ACLPROPS);

hr = MAPIAllocateMore(cbentryid,
sr.lpProps,
(LPVOID FAR *)&lpentryidCopy);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

memcpy(lpentryidCopy, lpentryid, cbentryid);

hr = MAPIAllocateMore(strlen(lpszDisplayName) + sizeof(char),
sr.lpProps,
(LPVOID FAR *)&lpszDisplayNameCopy);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

strcpy(lpszDisplayNameCopy, lpszDisplayName);

sr.lpProps[I_MEMBER_ENTRYID].ulPropTag =PR_MEMBER_ENTRYID;
sr.lpProps[I_MEMBER_ENTRYID].Value.bin.cb =cbentryid;
sr.lpProps[I_MEMBER_ENTRYID].Value.bin.lpb =(LPBYTE)lpentryidCopy;

sr.lpProps[I_MEMBER_RIGHTS].ulPropTag =PR_MEMBER_RIGHTS;
sr.lpProps[I_MEMBER_RIGHTS].Value.l =lRights;

sr.lpProps[I_MEMBER_NAME].ulPropTag =PR_MEMBER_NAME;
sr.lpProps[I_MEMBER_NAME].Value.lpszA =lpszDisplayNameCopy;

hr = m_pFA->m_SRowLst.HrInsert(&sr);

if (FAILED(hr))
goto cleanup;

hr = m_pFA->m_SRowLst.HrWriteToTable(m_pFA->m_lpExchTbl);

if (FAILED(hr))
{
HRESULThrTmp = NOERROR;

// Delete the node from the list, since the table write failed.

m_pFA->m_SRowLst.SetCursor(lPosInsertion);

hrTmp = m_pFA->m_SRowLst.HrDelete();

if (FAILED(hrTmp))
hr = HR_LOG(E_UNEXPECTED);

// The memory allocated by this method was cleaned up when the
// node was deleted.

sr.lpProps = NULL;
goto cleanup;
}

// Determine what rights bits are actually set.

hr = m_pFA->HrGetTableEntry(cbentryid,
lpentryid,
NULL,
&lNewRights);

if (FAILED(hr))
{
hr = HR_LOG(E_UNEXPECTED);

// The memory allocated by this method is still associated with
// the list.

sr.lpProps = NULL;
goto cleanup;
}

if (lNewRights != lRights)
{
LONGlPos =m_pFA->m_SRowLst.GetCursor();
CSROWNODE *pNode = NULL;

m_pFA->m_SRowLst.SetCursor(lPosInsertion);

pNode = m_pFA->m_SRowLst.GetCurrentNode();

pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l = lNewRights;

m_pFA->m_SRowLst.SetCursor(lPos);
}

if (lplRights != NULL)
*lplRights = lNewRights;

cleanup:

if (FAILED(hr))
MAPIFREEBUFFER(sr.lpProps);

RETURN(hr);
}


// $--CIExchangeFolderACLs::HrModify-------------------------------------------
//
// DESCRIPTION:Modify rights for the current record.
//
// INPUT:
//
//[lRights]-- Rights bits requested to be set.
//
// OUTPUT:
//
//[lplRights]-- Ptr to rights bits actually set on completion; if
// this info is not wanted, specify NULL.
//
// RETURNS:NOERRORif successful;
// E_FAILotherwise.
//
// Notes:We need to return *lplRights because the Exchange MDB may set
//extra bits, depending on the user and other circumstances.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrModify(// RETURNS: HRESULT
INLONGlRights, // input rights bits
OUTLPLONGlplRights// ptr to output rights bits
)
{
HRESULThr =NOERROR;
LONGlNewRights =0;
LONGlPrvRights =0;
CSROWNODE *pNode = NULL;

DEBUGPUBLIC("CIExchangeFolderACLs::HrModify().\n");

hr = CHK_CIExchangeFolderACLs_HrModify(lplRights);

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

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

pNode = m_pFA->m_SRowLst.GetCurrentNode();

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

lPrvRights = pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l;

pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l = lRights;

hr = m_pFA->m_SRowLst.HrWriteToTable(m_pFA->m_lpExchTbl);

if (FAILED(hr))
{
pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l = lPrvRights;
goto cleanup;
}

// Determine what rights bits are actually set.

hr = m_pFA->HrGetTableEntry(
pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].Value.bin.cb,
(LPENTRYID)pNode->m_SRow.lpProps[I_MEMBER_ENTRYID].Value.bin.lpb,
NULL,
&lNewRights);

if (FAILED(hr))
goto cleanup;

pNode->m_SRow.lpProps[I_MEMBER_RIGHTS].Value.l = lNewRights;

if (lplRights != NULL)
*lplRights = lNewRights;

cleanup:

RETURN(hr);
}


// $--CIExchangeFolderACLs::HrSeek---------------------------------------------
//
// DESCRIPTION:Set the current cursor position.
//
// INPUT:
//
// [lPos]-- New cursor position.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrSeek(// RETURNS: HRESULT
INLONGlPos// cursor position
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderACLs::HrSeek().\n");

hr = CHK_CIExchangeFolderACLs_HrSeek(lPos);

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

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

m_pFA->m_SRowLst.SetCursor(lPos);

RETURN(hr);
}


// $--CIExchangeFolderACLs::HrTell---------------------------------------------
//
// DESCRIPTION:Return the current cursor position.
//
// OUTPUT:
//
// [lplPos]-- Ptr for returning current cursor position.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderACLs::HrTell(// RETURNS: HRESULT
OUTLPLONGlplPos// cursor position ptr
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderACLs::HrTell().\n");

hr = CHK_CIExchangeFolderACLs_HrTell(lplPos);

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

ASSERT_READ_PTR_OR_NULL(m_pFA, sizeof(CFolderACLs FAR *), "Bad m_pFA.");

*lplPos = m_pFA->m_SRowLst.GetCursor();

RETURN(hr);
}