|
|
// File: wabutil.cpp
//
// Generic Windows Address Book utility functions
#include "precomp.h"
#include "wabutil.h"
#include "wabtags.h"
#include "wabiab.h"
#include <confguid.h> // for CLSID_ConferenceManager
static const TCHAR _szCallToWab[] = TEXT("callto://"); // the prefix for NM WAB entries
static const TCHAR g_pcszSMTP[] = TEXT("SMTP"); // value for PR_ADDRTYPE
// see rgData in CreateWabEntry
static const int IENTRYPROP_NM_DEFAULT = 5; static const int IENTRYPROP_NM_ADDRESS = 6;
// REVIEW: There should be an external header file for these.
// They are documented in http://fbi/wabapi.htm
// DEFINE_OLEGUID(PS_Conferencing, 0x00062004, 0, 0);
static const GUID PS_Conferencing = {0x00062004, 0, 0, {0xC0,0,0,0,0,0,0,0x46} };
/////////////////////////////////////////////////////////////////////
static const SizedSPropTagArray(ieidMax, ptaEid)= { ieidMax, { PR_ENTRYID, PR_DISPLAY_NAME, PR_NM_ADDRESS, PR_NM_DEFAULT, PR_NM_CATEGORY } }; static const SizedSPropTagArray(1, ptaEidOnly)= { 1, {PR_ENTRYID} };
enum { icrPR_DEF_CREATE_MAILUSER = 0, icrMax };
static const SizedSPropTagArray(icrMax, ptaCreate) = { icrMax, { PR_DEF_CREATE_MAILUSER, } };
/////////////////////////////////////////////////////////////////////
//
// Dynamic WAB interface
const static TCHAR _szWABRegPathKey[] = TEXT("Software\\Microsoft\\WAB\\DLLPath"); const static TCHAR _szWABDll[] = TEXT("WAB32DLL.dll"); const static char _szWABOpen[] = "WABOpen";
class WABDLL { private: static HINSTANCE m_hInstLib; static LPWABOPEN m_pfnWABOpen;
protected: WABDLL(); ~WABDLL() {}; public: static HRESULT WABOpen(LPADRBOOK FAR *, LPWABOBJECT FAR *, LPWAB_PARAM, DWORD); };
LPWABOPEN WABDLL::m_pfnWABOpen = NULL; HINSTANCE WABDLL::m_hInstLib = NULL;
HRESULT WABDLL::WABOpen(LPADRBOOK FAR * lppAdrBook, LPWABOBJECT FAR * lppWABObject, LPWAB_PARAM lpWP, DWORD dwReserved) { if (NULL == m_pfnWABOpen) { HKEY hKey; TCHAR szPath[MAX_PATH];
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, _szWABRegPathKey, 0, KEY_READ, &hKey)) { // Probably don't have IE4 installed
lstrcpy(szPath, _szWABDll); } else { DWORD dwType = 0; DWORD cbData = sizeof(szPath); // the size in BYTES
RegQueryValueEx(hKey, g_cszEmpty, NULL, &dwType, (LPBYTE) szPath, &cbData); RegCloseKey(hKey); if (FEmptySz(szPath)) return E_NOINTERFACE; }
m_hInstLib = LoadLibrary(szPath); if (NULL == m_hInstLib) return E_NOINTERFACE;
m_pfnWABOpen = (LPWABOPEN) GetProcAddress(m_hInstLib, _szWABOpen); if (NULL == m_pfnWABOpen) { FreeLibrary(m_hInstLib); return E_NOINTERFACE; } }
return m_pfnWABOpen(lppAdrBook, lppWABObject, lpWP, dwReserved); }
///////////////////////////////////////////////////////////////////////////
/* C W A B U T I L */ /*-------------------------------------------------------------------------
%%Function: CWABUTIL -------------------------------------------------------------------------*/ CWABUTIL::CWABUTIL() : m_pAdrBook(NULL), m_pWabObject(NULL), m_pContainer(NULL), m_pPropTags(NULL), m_fTranslatedTags(FALSE) { // Make a copy of the property data
m_pPropTags = (LPSPropTagArray) new BYTE[sizeof(ptaEid)]; if (NULL != m_pPropTags) { CopyMemory(m_pPropTags, &ptaEid, sizeof(ptaEid));
WABDLL::WABOpen(&m_pAdrBook, &m_pWabObject, NULL, 0); } }
CWABUTIL::~CWABUTIL() { delete m_pPropTags;
if (NULL != m_pContainer) { m_pContainer->Release(); } if (NULL != m_pWabObject) { m_pWabObject->Release(); } if (NULL != m_pAdrBook) { m_pAdrBook->Release(); } }
/* P S Z S K I P C A L L T O */ /*-------------------------------------------------------------------------
%%Function: PszSkipCallTo
Return a pointer after the "callto://" string. -------------------------------------------------------------------------*/ LPCTSTR CWABUTIL::PszSkipCallTo(LPCTSTR psz) { ASSERT(!FEmptySz(psz));
TCHAR szTemp[CCHMAX(_szCallToWab)]; lstrcpyn(szTemp, psz, CCHMAX(szTemp)); // FUTURE: Use StrCmpNI
if (0 == lstrcmpi(szTemp, _szCallToWab)) { psz += CCHMAX(_szCallToWab)-1; }
return psz; }
BOOL CWABUTIL::FCreateCallToSz(LPCTSTR pszServer, LPCTSTR pszEmail, LPTSTR pszDest, UINT cchMax) { if ((lstrlen(pszServer) + lstrlen(pszEmail) + CCHMAX(_szCallToWab)) >= cchMax) return FALSE; // it won't fix
// This has the format: "callto://server/[email protected]"
wsprintf(pszDest, TEXT("%s%s/%s"), _szCallToWab, pszServer, pszEmail); ASSERT(lstrlen(pszDest) < (int) cchMax); return TRUE; }
ULONG CWABUTIL::Get_PR_NM_ADDRESS(void) { ASSERT(m_fTranslatedTags); return m_pPropTags->aulPropTag[ieidPR_NM_ADDRESS]; }
ULONG CWABUTIL::Get_PR_NM_DEFAULT(void) { ASSERT(m_fTranslatedTags); return m_pPropTags->aulPropTag[ieidPR_NM_DEFAULT]; }
ULONG CWABUTIL::Get_PR_NM_CATEGORY(void) { ASSERT(m_fTranslatedTags); return m_pPropTags->aulPropTag[ieidPR_NM_CATEGORY]; }
/* F R E E P R O W S */ /*-------------------------------------------------------------------------
%%Function: FreeProws -------------------------------------------------------------------------*/ VOID CWABUTIL::FreeProws(LPSRowSet prows) { if (NULL == prows) return;
for (ULONG irow = 0; irow < prows->cRows; irow++) { m_pWabObject->FreeBuffer(prows->aRow[irow].lpProps); }
m_pWabObject->FreeBuffer(prows); }
/* G E T C O N T A I N E R */ /*-------------------------------------------------------------------------
%%Function: GetContainer -------------------------------------------------------------------------*/ HRESULT CWABUTIL::GetContainer(void) { if (NULL != m_pContainer) return S_OK;
ASSERT(NULL != m_pWabObject); ASSERT(NULL != m_pAdrBook);
// get the entryid for the WAB
ULONG cbEID; LPENTRYID lpEID; HRESULT hr = m_pAdrBook->GetPAB(&cbEID, &lpEID); if (SUCCEEDED(hr)) { // use the entryid to get the container
ULONG ulObjType = 0; hr = m_pAdrBook->OpenEntry(cbEID, lpEID, NULL, 0, &ulObjType, (LPUNKNOWN *)&m_pContainer); m_pWabObject->FreeBuffer(lpEID); }
return hr; }
/* E N S U R E P R O P T A G S */ /*-------------------------------------------------------------------------
%%Function: EnsurePropTags
Ensure the special property tags are available. -------------------------------------------------------------------------*/ HRESULT CWABUTIL::EnsurePropTags(void) { if (m_fTranslatedTags) return S_OK;
ASSERT(NULL != m_pContainer);
LPSRowSet pRowSet = NULL; LPMAPITABLE pAB = NULL; // get the WAB contents
HRESULT hr = m_pContainer->GetContentsTable(0, &pAB); if (FAILED(hr)) { return hr; // probably empty
}
if ((SUCCEEDED(hr = pAB->SetColumns((LPSPropTagArray)&ptaEidOnly, 0))) && (SUCCEEDED(hr = pAB->SeekRow(BOOKMARK_BEGINNING, 0, NULL))) && (SUCCEEDED(hr = pAB->QueryRows(1, 0, &pRowSet))) && (NULL != pRowSet) ) { if (0 != pRowSet->cRows) { LPMAPIPROP pMapiProp = NULL; ULONG ulObjType = 0; hr = m_pContainer->OpenEntry(pRowSet->aRow[0].lpProps[0].Value.bin.cb, (LPENTRYID) pRowSet->aRow[0].lpProps[0].Value.bin.lpb, NULL, // the object's standard i/f
0, // flags
&ulObjType, (LPUNKNOWN *)&pMapiProp); if (SUCCEEDED(hr)) { hr = GetNamedPropsTag(pMapiProp, m_pPropTags); }
if (NULL != pMapiProp) { pMapiProp->Release(); } } FreeProws(pRowSet); }
if (NULL != pAB) { pAB->Release(); }
return hr; }
// Use this version when no m_pContainer is available
HRESULT CWABUTIL::EnsurePropTags(LPMAPIPROP pMapiProp) { if (m_fTranslatedTags) return S_OK;
return GetNamedPropsTag(pMapiProp, m_pPropTags); }
/* G E T N A M E D P R O P S T A G */ /*-------------------------------------------------------------------------
%%Function: GetNamedPropsTag
Translate the named properties into their proper values -------------------------------------------------------------------------*/ HRESULT CWABUTIL::GetNamedPropsTag(LPMAPIPROP pMapiProp, LPSPropTagArray pProps) { ASSERT(!m_fTranslatedTags); ASSERT(NULL != pMapiProp); ASSERT(NULL != pProps);
int iProp; int cProps = pProps->cValues; // total number of property tags
ASSERT(0 != cProps);
int iName; int cNames = 0; // The number of named tags to translate
for (iProp = 0; iProp < cProps; iProp++) { if (0 != (PROP_ID(pProps->aulPropTag[iProp]) & 0x8000)) { cNames++; } } ASSERT(0 != cNames); // allocate memory for the named props pointers array
int cb = sizeof(LPMAPINAMEID) * cNames; LPMAPINAMEID * pNameIds = (LPMAPINAMEID *) new BYTE[cb]; if (NULL == pNameIds) return E_OUTOFMEMORY; ZeroMemory(pNameIds, cb);
// run through the prop tag array and build a MAPINAMEID for each prop tag
HRESULT hr = S_OK; iName = 0; for (iProp = 0; iProp < cProps; iProp++) { ULONG ulTag = pProps->aulPropTag[iProp]; if (0 != (PROP_ID(ulTag) & 0x8000)) { pNameIds[iName] = new MAPINAMEID; if (NULL == pNameIds[iName]) { hr = E_OUTOFMEMORY; break; }
// Either Outlook public or NetMeeting private tag
BOOL fPrivate = 0 != (PROP_ID(ulTag) & NM_TAG_MASK); GUID * pGuid = (GUID *) (fPrivate ? &CLSID_ConferenceManager : &PS_Conferencing); pNameIds[iName]->lpguid = pGuid; pNameIds[iName]->ulKind = MNID_ID; pNameIds[iName]->Kind.lID = PROP_ID(ulTag); iName++; } }
if (SUCCEEDED(hr)) { LPSPropTagArray pta = NULL;
// get the named props "real" tags
hr = pMapiProp->GetIDsFromNames(cNames, pNameIds, MAPI_CREATE, &pta); if (SUCCEEDED(hr)) { if (NULL == pta) { hr = E_FAIL; } else { // replace the named tags with the real tags in the passed in prop tag array,
// maintaining the types.
ULONG * pul = &pta->aulPropTag[0]; for (iProp = 0; iProp < cProps; iProp++) { ULONG ulTag = pProps->aulPropTag[iProp]; if (0 != (PROP_ID(ulTag) & 0x8000)) { // set the property types on the returned props
pProps->aulPropTag[iProp] = CHANGE_PROP_TYPE(*pul++, PROP_TYPE(ulTag)); } }
m_pWabObject->FreeBuffer(pta); } } }
// Cleanup
if (NULL != pNameIds) { for (iName = 0; iName < cNames; iName++) { delete pNameIds[iName]; }
delete [] pNameIds; }
m_fTranslatedTags = SUCCEEDED(hr); return hr; }
/* H R G E T W A B T E M P L A T E I D */ /*-------------------------------------------------------------------------
%%Function: HrGetWABTemplateID
Gets the WABs default Template ID for MailUsers or DistLists. These Template IDs are needed for creating new mailusers and distlists. -------------------------------------------------------------------------*/ HRESULT CWABUTIL::HrGetWABTemplateID(ULONG * lpcbEID, LPENTRYID * lppEID) { *lpcbEID = 0; *lppEID = NULL;
if (NULL == m_pAdrBook) { return E_INVALIDARG; } ASSERT(NULL != m_pWabObject);
ULONG cbWABEID; LPENTRYID lpWABEID; HRESULT hr = m_pAdrBook->GetPAB(&cbWABEID, &lpWABEID); if (FAILED(hr)) return hr;
LPABCONT lpContainer = NULL; ULONG ulObjectType = MAPI_MAILUSER; hr = m_pAdrBook->OpenEntry(cbWABEID, lpWABEID, NULL, 0, &ulObjectType, (LPUNKNOWN *)&lpContainer); if (SUCCEEDED(hr)) { ULONG cNewProps; LPSPropValue lpCreateEIDs = NULL;
// Get the default creation entryids
hr = lpContainer->GetProps((LPSPropTagArray)&ptaCreate, 0, &cNewProps, &lpCreateEIDs); if (S_OK == hr) { // Validate the properites
if (lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag == PR_DEF_CREATE_MAILUSER) { ULONG nIndex = icrPR_DEF_CREATE_MAILUSER; *lpcbEID = lpCreateEIDs[nIndex].Value.bin.cb; if (S_OK == m_pWabObject->AllocateBuffer(*lpcbEID, (LPVOID *) lppEID)) { CopyMemory(*lppEID,lpCreateEIDs[nIndex].Value.bin.lpb,*lpcbEID); } } }
if (NULL != lpCreateEIDs) { m_pWabObject->FreeBuffer(lpCreateEIDs); } }
if (NULL != lpContainer) { lpContainer->Release(); }
if (NULL != lpWABEID) { m_pWabObject->FreeBuffer(lpWABEID); }
return hr; }
/* C R E A T E N E W E N T R Y */ /*-------------------------------------------------------------------------
%%Function: CreateNewEntry -------------------------------------------------------------------------*/ HRESULT CWABUTIL::CreateNewEntry(HWND hwndParent, ULONG cProps, SPropValue * pProps) { ULONG cbEID; LPENTRYID lpEID; ULONG cbTplEID; LPENTRYID lpTplEID;
// Get the template id which is needed to create the new object
HRESULT hr = HrGetWABTemplateID(&cbTplEID, &lpTplEID); if (FAILED(hr)) return hr;
// get the entryid for the WAB
hr = m_pAdrBook->GetPAB(&cbEID, &lpEID); if (FAILED(hr)) return hr;
// use the entryid to get the container
ULONG ulObjType = 0; LPABCONT pContainer = NULL; hr = m_pAdrBook->OpenEntry(cbEID, lpEID, NULL, 0, &ulObjType, (LPUNKNOWN *)&pContainer); m_pWabObject->FreeBuffer(lpEID); if (SUCCEEDED(hr)) { LPMAPIPROP pMapiProp = NULL; hr = pContainer->CreateEntry(cbTplEID, lpTplEID, CREATE_CHECK_DUP_LOOSE, &pMapiProp); if (SUCCEEDED(hr)) { if (PR_NM_ADDRESS == m_pPropTags->aulPropTag[ieidPR_NM_ADDRESS]) { GetNamedPropsTag(pMapiProp, m_pPropTags); } (pProps+IENTRYPROP_NM_DEFAULT)->ulPropTag = m_pPropTags->aulPropTag[ieidPR_NM_DEFAULT]; (pProps+IENTRYPROP_NM_ADDRESS)->ulPropTag = m_pPropTags->aulPropTag[ieidPR_NM_ADDRESS];
LPSPropProblemArray pErr = NULL; hr = pMapiProp->SetProps(cProps, pProps, &pErr); if (SUCCEEDED(hr)) { hr = pMapiProp->SaveChanges(FORCE_SAVE);
// Show the new entry
if (SUCCEEDED(hr)) { ULONG cProp1; LPSPropValue pPropEid; hr = pMapiProp->GetProps((LPSPropTagArray)&ptaEidOnly, 0, &cProp1, &pPropEid); if (S_OK == hr) { hr = m_pAdrBook->Details((LPULONG) &hwndParent, NULL, NULL, pPropEid->Value.bin.cb, (LPENTRYID) pPropEid->Value.bin.lpb, NULL, NULL, NULL, DIALOG_MODAL); }
if (S_OK != hr) { // There was a problem, delete the entry
ENTRYLIST eList; eList.cValues = 1; eList.lpbin = (LPSBinary) &pPropEid->Value.bin;
pContainer->DeleteEntries(&eList, 0); }
m_pWabObject->FreeBuffer(pPropEid); } } else { // How could this ever fail?
m_pWabObject->FreeBuffer(pErr); }
pMapiProp->Release(); } }
if (NULL != pContainer) { pContainer->Release(); }
return hr; }
/* C R E A T E W A B E N T R Y */ /*-------------------------------------------------------------------------
%%Function: CreateWabEntry -------------------------------------------------------------------------*/ HRESULT CWABUTIL::_CreateWabEntry(HWND hwndParent, LPCTSTR pszDisplay, LPCTSTR pszFirst, LPCTSTR pszLast, LPCTSTR pszEmail, LPCTSTR pszLocation, LPCTSTR pszPhoneNum, LPCTSTR pszComments, LPCTSTR pszCallTo) { // These must be non-null
ASSERT(!FEmptySz(pszDisplay)); ASSERT(!FEmptySz(pszEmail));
SPropValue rgData[13]; // maximum number of properties
ZeroMemory(rgData, sizeof(rgData));
rgData[0].ulPropTag = PR_DISPLAY_NAME; rgData[0].Value.lpszA = const_cast<LPTSTR>(pszDisplay); rgData[1].ulPropTag = PR_GIVEN_NAME; rgData[1].Value.lpszA = const_cast<LPTSTR>(pszFirst); rgData[2].ulPropTag = PR_SURNAME; rgData[2].Value.lpszA = const_cast<LPTSTR>(pszLast); rgData[3].ulPropTag = PR_EMAIL_ADDRESS; rgData[3].Value.lpszA = const_cast<LPTSTR>(pszEmail); rgData[4].ulPropTag = PR_ADDRTYPE; rgData[4].Value.lpszA = (LPSTR) g_pcszSMTP;
// There is only one default server
ASSERT(5 == IENTRYPROP_NM_DEFAULT); // LPSPropTagArray pPropTags = pWab->GetTags(); // Translated tags
//rgData[IENTRYPROP_NM_DEFAULT].ulPropTag = pPropTags->aulPropTag[ieidPR_NM_DEFAULT];
rgData[IENTRYPROP_NM_DEFAULT].Value.ul = 0;
ASSERT(6 == IENTRYPROP_NM_ADDRESS); //rgData[IENTRYPROP_NM_ADDRESS].ulPropTag = pPropTags->aulPropTag[ieidPR_NM_ADDRESS];
rgData[IENTRYPROP_NM_ADDRESS].Value.MVszA.cValues = 1; rgData[IENTRYPROP_NM_ADDRESS].Value.MVszA.lppszA = const_cast<LPTSTR*>(&pszCallTo);
// Add any other non-null properties
SPropValue * pProp = &rgData[7];
if (!FEmptySz(pszLocation)) { pProp->ulPropTag = PR_LOCALITY; pProp->Value.lpszA = const_cast<LPTSTR>(pszLocation); pProp++; }
if (!FEmptySz(pszPhoneNum)) { pProp->ulPropTag = PR_BUSINESS_TELEPHONE_NUMBER; pProp->Value.lpszA = const_cast<LPTSTR>(pszPhoneNum); pProp++; }
if (!FEmptySz(pszComments)) { pProp->ulPropTag = PR_COMMENT; pProp->Value.lpszA = const_cast<LPTSTR>(pszComments); pProp++; } ULONG cProp = (ULONG)(pProp - rgData); ASSERT(cProp <= ARRAY_ELEMENTS(rgData));
return CreateNewEntry(hwndParent, cProp, rgData); }
/* C R E A T E W A B E N T R Y */ /*-------------------------------------------------------------------------
%%Function: CreateWabEntry -------------------------------------------------------------------------*/ HRESULT CWABUTIL::CreateWabEntry(HWND hwndParent, LPCTSTR pszDisplay, LPCTSTR pszFirst, LPCTSTR pszLast, LPCTSTR pszEmail, LPCTSTR pszLocation, LPCTSTR pszPhoneNum, LPCTSTR pszComments, LPCTSTR pszServer) { // This has the format: "callto://server/[email protected]"
TCHAR szCallTo[MAX_PATH*2]; LPTSTR pszCallTo = szCallTo; if (!FCreateCallToSz(pszServer, pszEmail, szCallTo, CCHMAX(szCallTo))) return E_OUTOFMEMORY;
return _CreateWabEntry(hwndParent, pszDisplay, pszFirst, pszLast, pszEmail, pszLocation, pszPhoneNum, pszComments, pszCallTo); }
/* C R E A T E W A B E N T R Y */ /*-------------------------------------------------------------------------
%%Function: CreateWabEntry -------------------------------------------------------------------------*/ HRESULT CWABUTIL::CreateWabEntry(HWND hwndParent, LPCTSTR pszDisplay, LPCTSTR pszEmail, LPCTSTR pszLocation, LPCTSTR pszPhoneNum, LPCTSTR pszULSAddress) {
// This has the format: "callto://server/[email protected]"
TCHAR szCallTo[MAX_PATH*2]; LPTSTR pszCallTo = szCallTo; if ((lstrlen(pszULSAddress) + CCHMAX(_szCallToWab)) >= CCHMAX(szCallTo)) return E_FAIL; // it won't fit
wsprintf(szCallTo, TEXT("%s%s"), _szCallToWab, pszULSAddress);
return _CreateWabEntry(hwndParent, pszDisplay, g_szEmpty, g_szEmpty, pszEmail, pszLocation, pszPhoneNum, g_szEmpty, pszCallTo); }
|