// --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);
}