You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1955 lines
60 KiB
1955 lines
60 KiB
/*
|
|
* Profiles.C - Stuff dealing with WAB Profile Handling
|
|
*
|
|
*/
|
|
|
|
|
|
#include <_apipch.h>
|
|
|
|
enum {
|
|
proDisplayName=0,
|
|
proObjectType,
|
|
proFolderEntries,
|
|
proFolderShared,
|
|
proFolderOwner, // upto this many props are common to all folders
|
|
proUserSubFolders,
|
|
proUserProfileID, // these are used by User Folders only
|
|
proUserFolderMax,
|
|
};
|
|
|
|
#define proFolderMax proUserSubFolders
|
|
|
|
|
|
/*
|
|
- helper function for quick saving of folder props
|
|
-
|
|
*/
|
|
HRESULT HrSaveFolderProps(LPADRBOOK lpAdrBook, BOOL bCreateUserFolder, ULONG ulcProps, LPSPropValue lpProps, LPMAPIPROP * lppObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPMAPIPROP lpObject = NULL;
|
|
ULONG ulFlags = CREATE_CHECK_DUP_STRICT;
|
|
BOOL bTryAgain = FALSE;
|
|
|
|
TryAgain:
|
|
|
|
// Create a new mailuser for this entry
|
|
if(HR_FAILED(hr = HrCreateNewObject(lpAdrBook, NULL, MAPI_MAILUSER, ulFlags, &lpObject)))
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = lpObject->lpVtbl->SetProps( lpObject, ulcProps, lpProps,NULL)))
|
|
goto out;
|
|
|
|
if(bCreateUserFolder)
|
|
{
|
|
// if we are creating a user folder, we can't rely on the currently loaded folder-
|
|
// container info so we will forcibly reset the parent folder item on the MailUser/Folder
|
|
// object we are savign
|
|
((LPMailUser)lpObject)->pmbinOlk = NULL;
|
|
}
|
|
|
|
// SaveChanges
|
|
if(HR_FAILED(hr = lpObject->lpVtbl->SaveChanges(lpObject, KEEP_OPEN_READWRITE)))
|
|
{
|
|
if(!bCreateUserFolder || hr != MAPI_E_COLLISION)
|
|
goto out;
|
|
|
|
// If something already exists with this same exact name, we want to merge with it
|
|
// without losing any info on it, since most likely, the original dupe is also a contact
|
|
if(!bTryAgain)
|
|
{
|
|
bTryAgain = TRUE;
|
|
ulFlags |= CREATE_REPLACE | CREATE_MERGE;
|
|
lpObject->lpVtbl->Release(lpObject);
|
|
lpObject = NULL;
|
|
lpProps[proFolderEntries].ulPropTag = PR_NULL; // don't overwrite the folder's contents
|
|
goto TryAgain;
|
|
}
|
|
}
|
|
|
|
if(lppObject)
|
|
{
|
|
*lppObject = lpObject;
|
|
lpObject = NULL;
|
|
}
|
|
out:
|
|
if(lpObject)
|
|
lpObject->lpVtbl->Release(lpObject);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
-
|
|
- FreeProfileContainerInfo(lpIAB)
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
void FreeProfileContainerInfo(LPIAB lpIAB)
|
|
{
|
|
if( lpIAB &&
|
|
lpIAB->cwabci &&
|
|
lpIAB->rgwabci)
|
|
{
|
|
//ULONG i = 0;
|
|
//for(i=0;i<lpIAB->cwabci;i++)
|
|
// LocalFreeAndNull(&(lpIAB->rgwabci[i].lpszName));
|
|
if( lpIAB->rgwabci[0].lpEntryID &&
|
|
!lpIAB->rgwabci[0].lpEntryID->cb &&
|
|
!lpIAB->rgwabci[0].lpEntryID->lpb &&
|
|
lpIAB->rgwabci[0].lpszName &&
|
|
lstrlen(lpIAB->rgwabci[0].lpszName))
|
|
{
|
|
LocalFree(lpIAB->rgwabci[0].lpEntryID);
|
|
LocalFree(lpIAB->rgwabci[0].lpszName);
|
|
}
|
|
|
|
LocalFreeAndNull(&(lpIAB->rgwabci));
|
|
lpIAB->cwabci = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-
|
|
- FindWABFolder - Searches the list of cached folders for a specific WAB folder
|
|
-
|
|
* The search is based on either the EID or the Name or the ProfileID
|
|
* If ProfileID is specified, we only search for user folders
|
|
*
|
|
*/
|
|
LPWABFOLDER FindWABFolder(LPIAB lpIAB, LPSBinary lpsb, LPTSTR lpName, LPTSTR lpProfileID)
|
|
{
|
|
LPWABFOLDER lpFolder = lpIAB->lpWABFolders;
|
|
BOOL bUserFolders = FALSE;
|
|
|
|
if(!lpFolder || lpProfileID)
|
|
{
|
|
lpFolder = lpIAB->lpWABUserFolders;
|
|
bUserFolders = TRUE;
|
|
}
|
|
while(lpFolder)
|
|
{
|
|
if(lpsb)
|
|
{
|
|
if( lpsb->cb == lpFolder->sbEID.cb &&
|
|
!memcmp(lpsb->lpb, lpFolder->sbEID.lpb, lpsb->cb) )
|
|
return lpFolder;
|
|
}
|
|
else
|
|
if(lpName)
|
|
{
|
|
if(!lstrcmpi(lpFolder->lpFolderName, lpName))
|
|
return lpFolder;
|
|
}
|
|
else
|
|
if(lpProfileID)
|
|
{
|
|
if( lpFolder->lpProfileID &&
|
|
!lstrcmpi(lpFolder->lpProfileID, lpProfileID))
|
|
return lpFolder;
|
|
}
|
|
lpFolder = lpFolder->lpNext;
|
|
if(!lpFolder && !bUserFolders)
|
|
{
|
|
lpFolder = lpIAB->lpWABUserFolders;
|
|
bUserFolders = TRUE;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
-
|
|
- HrGetWABProfileContainerInfo
|
|
*
|
|
* Looks up all the folders for the current user and tabulates
|
|
* them into a list of container names and entry ids for easy access
|
|
* similar to Outlook ...
|
|
* If there is no current user, we'll include all the folders for now
|
|
*
|
|
*/
|
|
HRESULT HrGetWABProfileContainerInfo(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ULONG j = 0, i = 0, cVal = 0, cUserFolders = 0, cOtherFolders = 0;
|
|
LPWABFOLDER lpFolder = NULL;
|
|
LPWABFOLDERLIST lpFolderItem = NULL;
|
|
|
|
if(lpIAB->cwabci)
|
|
FreeProfileContainerInfo(lpIAB);
|
|
|
|
if(!bIsThereACurrentUser(lpIAB))
|
|
{
|
|
// No specific user specified .. need to add ALL folders
|
|
|
|
// Count all the folders
|
|
lpFolder = lpIAB->lpWABUserFolders;
|
|
while(lpFolder)
|
|
{
|
|
cUserFolders++;
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
cOtherFolders++;
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
|
|
cVal = cUserFolders + cOtherFolders + 1; // +1 for Virtual PAB
|
|
}
|
|
else
|
|
{
|
|
// For a user, we add all the user's folders except shared ones followed by
|
|
// all the shared folders...
|
|
lpFolderItem = lpIAB->lpWABCurrentUserFolder->lpFolderList;
|
|
while(lpFolderItem)
|
|
{
|
|
if(!lpFolderItem->lpFolder->bShared)
|
|
cVal++;
|
|
lpFolderItem = lpFolderItem->lpNext;
|
|
}
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
if(lpFolder->bShared)
|
|
cVal++;
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
cVal++; // add 1 for the user folder itself
|
|
cVal++; // add 1 for a virtual root item for this user TEXT("All Contacts")
|
|
}
|
|
|
|
if(cVal)
|
|
{
|
|
if(!(lpIAB->rgwabci = LocalAlloc(LMEM_ZEROINIT, sizeof(struct _OlkContInfo)*cVal)))
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
cUserFolders = 0;
|
|
// Add the TEXT("All Contacts") item to the root - entryid is 0, NULL
|
|
{
|
|
TCHAR sz[MAX_PATH];
|
|
ULONG cchSize;
|
|
int nID = (bDoesThisWABHaveAnyUsers(lpIAB)) ? idsSharedContacts : idsContacts;
|
|
LoadString(hinstMapiX, nID, sz, CharSizeOf(sz));
|
|
cchSize = lstrlen(sz)+1;
|
|
if(!(lpIAB->rgwabci[cUserFolders].lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize)))
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
StrCpyN(lpIAB->rgwabci[cUserFolders].lpszName, sz, cchSize);
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary));
|
|
cUserFolders++;
|
|
}
|
|
if(!lpIAB->lpWABCurrentUserFolder)
|
|
{
|
|
lpFolder = lpIAB->lpWABUserFolders;
|
|
while(lpFolder)
|
|
{
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = &(lpFolder->sbEID);
|
|
lpIAB->rgwabci[cUserFolders].lpszName = lpFolder->lpFolderName;
|
|
cUserFolders++;
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = &(lpFolder->sbEID);
|
|
lpIAB->rgwabci[cUserFolders].lpszName = lpFolder->lpFolderName;
|
|
cUserFolders++;
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add the first folder and then find the other folders one by one
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = &(lpIAB->lpWABCurrentUserFolder->sbEID);
|
|
lpIAB->rgwabci[cUserFolders].lpszName = lpIAB->lpWABCurrentUserFolder->lpFolderName;
|
|
cUserFolders++;
|
|
lpFolderItem = lpIAB->lpWABCurrentUserFolder->lpFolderList;
|
|
while(lpFolderItem)
|
|
{
|
|
if(!lpFolderItem->lpFolder->bShared)
|
|
{
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = &(lpFolderItem->lpFolder->sbEID);
|
|
lpIAB->rgwabci[cUserFolders].lpszName = lpFolderItem->lpFolder->lpFolderName;
|
|
cUserFolders++;
|
|
}
|
|
lpFolderItem = lpFolderItem->lpNext;
|
|
}
|
|
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
if(lpFolder->bShared)
|
|
{
|
|
lpIAB->rgwabci[cUserFolders].lpEntryID = &(lpFolder->sbEID);
|
|
lpIAB->rgwabci[cUserFolders].lpszName = lpFolder->lpFolderName;
|
|
cUserFolders++;
|
|
}
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
}
|
|
|
|
lpIAB->cwabci = cUserFolders;
|
|
}
|
|
hr = S_OK;
|
|
|
|
out:
|
|
if(HR_FAILED(hr) && lpIAB->rgwabci)
|
|
FreeProfileContainerInfo(lpIAB);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- FreeWABFoldersList
|
|
-
|
|
-
|
|
* Clears up existing Profile Folders info from the IAB object
|
|
*/
|
|
void FreeFolderItem(LPWABFOLDER lpFolder)
|
|
{
|
|
LPWABFOLDERLIST lpFolderItem = NULL;
|
|
if(!lpFolder)
|
|
return;
|
|
LocalFreeAndNull(&lpFolder->lpFolderName);
|
|
LocalFreeAndNull(&lpFolder->lpProfileID);
|
|
LocalFreeAndNull((LPVOID *) (&lpFolder->sbEID.lpb));
|
|
LocalFreeAndNull(&lpFolder->lpFolderOwner);
|
|
lpFolderItem = lpFolder->lpFolderList;
|
|
while(lpFolderItem)
|
|
{
|
|
lpFolder->lpFolderList = lpFolderItem->lpNext;
|
|
LocalFree(lpFolderItem);
|
|
lpFolderItem = lpFolder->lpFolderList;
|
|
}
|
|
LocalFree(lpFolder);
|
|
}
|
|
void FreeWABFoldersList(LPIAB lpIAB)
|
|
{
|
|
LPWABFOLDER lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
lpIAB->lpWABFolders = lpFolder->lpNext;
|
|
FreeFolderItem(lpFolder);
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
}
|
|
lpFolder = lpIAB->lpWABUserFolders;
|
|
while(lpFolder)
|
|
{
|
|
lpIAB->lpWABFolders = lpFolder->lpNext;
|
|
FreeFolderItem(lpFolder);
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
}
|
|
lpIAB->lpWABUserFolders = NULL;
|
|
lpIAB->lpWABCurrentUserFolder = NULL;
|
|
lpIAB->lpWABFolders = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
- SetCurrentUserFolder - scans list and updates pointer
|
|
-
|
|
*
|
|
*/
|
|
void SetCurrentUserFolder(LPIAB lpIAB, LPTSTR lpszProfileID)
|
|
{
|
|
LPWABUSERFOLDER lpFolder = lpIAB->lpWABUserFolders;
|
|
|
|
while(lpFolder && lpszProfileID && lstrlen(lpszProfileID))
|
|
{
|
|
if(!lstrcmpi(lpFolder->lpProfileID, lpszProfileID))
|
|
{
|
|
lpIAB->lpWABCurrentUserFolder = lpFolder;
|
|
break;
|
|
}
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-
|
|
- CreateUserFolderName
|
|
*
|
|
*/
|
|
void CreateUserFolderName(LPTSTR lpProfile, LPTSTR * lppszName)
|
|
{
|
|
LPTSTR lpName = NULL;
|
|
TCHAR sz[MAX_PATH];
|
|
LoadString(hinstMapiX, idsUsersContacts, sz, CharSizeOf(sz));
|
|
FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
sz, 0, 0, (LPTSTR)&lpName, 0, (va_list *)&lpProfile);
|
|
*lppszName = lpName;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrLinkOrphanFoldersToDefaultUser(lpIAB)
|
|
-
|
|
* If there are any folders that are associated with deleted users or that have
|
|
* no parent and are orphaned, we want to associate them with the default user
|
|
*
|
|
* This function is dependent on lpFolder->bOwned being correctly set in the
|
|
* HrLinkUserFoldersToWABFolders
|
|
*
|
|
*/
|
|
HRESULT HrLinkOrphanFoldersToDefaultUser(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABUSERFOLDER lpDefUser = NULL;
|
|
LPWABFOLDER lpFolder = NULL;
|
|
TCHAR szDefProfile[MAX_PATH + 1];
|
|
|
|
// First detect the user folder corresponding to the Default User
|
|
*szDefProfile = '\0';
|
|
if( HR_FAILED(hr = HrGetDefaultIdentityInfo(lpIAB, DEFAULT_ID_PROFILEID, NULL, szDefProfile, ARRAYSIZE(szDefProfile), NULL, 0)))
|
|
{
|
|
if(hr == 0x80040154) // E_CLASS_NOT_REGISTERD means no IDentity Manager
|
|
hr = S_OK;
|
|
else
|
|
goto out;
|
|
}
|
|
|
|
if(lstrlen(szDefProfile))
|
|
{
|
|
lpDefUser = FindWABFolder(lpIAB, NULL, NULL, szDefProfile);
|
|
}
|
|
else
|
|
{
|
|
// can't find the default user so just fall back to picking someone at random
|
|
lpDefUser = lpIAB->lpWABUserFolders;
|
|
}
|
|
|
|
// see if there are any orphan folders
|
|
// To qualify as an orphan, the lpFolder->bOwned should be FALSE and the folder must
|
|
// also not be shared because if it's shared it will show up as part of Shared Contacts
|
|
lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
if(!lpFolder->bOwned && !lpFolder->bShared)
|
|
{
|
|
LPWABUSERFOLDER lpOwnerFolder = lpDefUser;
|
|
if(lpFolder->lpFolderOwner)
|
|
{
|
|
// Someone created this folder .. we need to make sure this is associated back to that original
|
|
// creator and only if that doesn't work should we append it to the default user
|
|
if(!(lpOwnerFolder = FindWABFolder(lpIAB, NULL, NULL, lpFolder->lpFolderOwner)))
|
|
lpOwnerFolder = lpDefUser;
|
|
}
|
|
|
|
if(lpOwnerFolder)
|
|
{
|
|
if(HR_FAILED(hr = HrAddRemoveFolderFromUserFolder( lpIAB, lpDefUser,
|
|
&lpFolder->sbEID, NULL, FALSE ) ))
|
|
goto out;
|
|
}
|
|
}
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
|
|
out:
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
- HrLinkUserFoldersToWABFolders
|
|
-
|
|
*
|
|
* Cross-links the user folder contents with the regular folders
|
|
* This makes accessing folder info much easier ..
|
|
*/
|
|
HRESULT HrLinkUserFoldersToWABFolders(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWABUSERFOLDER lpUserFolder = NULL;
|
|
LPWABFOLDER lpFolder = NULL;
|
|
ULONG ulcPropCount = 0, i = 0, j = 0;
|
|
LPSPropValue lpProp = NULL;
|
|
|
|
if(!lpIAB->lpWABUserFolders || !lpIAB->lpWABFolders)
|
|
goto out;
|
|
|
|
lpUserFolder = lpIAB->lpWABUserFolders;
|
|
while(lpUserFolder)
|
|
{
|
|
if(HR_FAILED(hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore, &lpUserFolder->sbEID,
|
|
0, &ulcPropCount, &lpProp)))
|
|
goto out;
|
|
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if(lpProp[i].ulPropTag == PR_WAB_USER_SUBFOLDERS)
|
|
{
|
|
for(j=0;j<lpProp[i].Value.MVbin.cValues;j++)
|
|
{
|
|
lpFolder = FindWABFolder(lpIAB, &(lpProp[i].Value.MVbin.lpbin[j]), NULL, NULL);
|
|
if(lpFolder)
|
|
{
|
|
LPWABFOLDERLIST lpFolderItem = LocalAlloc(LMEM_ZEROINIT, sizeof(WABFOLDERLIST));
|
|
if(lpFolderItem)
|
|
{
|
|
lpFolderItem->lpFolder = lpFolder;
|
|
lpFolder->bOwned = TRUE;
|
|
lpFolderItem->lpNext = lpUserFolder->lpFolderList;
|
|
lpUserFolder->lpFolderList = lpFolderItem;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
ReadRecordFreePropArray(NULL, ulcPropCount, &lpProp);
|
|
ulcPropCount = 0;
|
|
lpProp = NULL;
|
|
lpUserFolder = lpUserFolder->lpNext;
|
|
}
|
|
|
|
out:
|
|
ReadRecordFreePropArray(NULL, ulcPropCount, &lpProp);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrGetFolderInfo()
|
|
-
|
|
* Reads a folder name directly from the prop store
|
|
* Also checks if this is a user folder and what the profile is
|
|
* Returns LocalAlloced LPTSTRs which caller needs to free
|
|
*/
|
|
HRESULT HrGetFolderInfo(LPIAB lpIAB, LPSBinary lpsbEID, LPWABFOLDER lpFolder)
|
|
{
|
|
LPTSTR lpName = NULL, lpProfileID = NULL, lpOwner = NULL;
|
|
HRESULT hr = S_OK;
|
|
ULONG ulcPropCount = 0, j=0;
|
|
LPSPropValue lpProp = NULL;
|
|
BOOL bShared = FALSE;
|
|
|
|
if(!bIsWABSessionProfileAware(lpIAB) || !lpsbEID)
|
|
goto out;
|
|
|
|
if(!lpsbEID->cb && !lpsbEID->lpb)
|
|
{
|
|
// special case - read the address book item
|
|
lpName = LocalAlloc(LMEM_ZEROINIT, MAX_PATH);
|
|
if(lpName)
|
|
LoadString(hinstMapiX, idsContacts/*IDS_ADDRBK_CAPTION*/, lpName, MAX_PATH-1);
|
|
}
|
|
else
|
|
{
|
|
hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore, lpsbEID,
|
|
0, &ulcPropCount, &lpProp);
|
|
if(HR_FAILED(hr))
|
|
goto out;
|
|
|
|
for(j=0;j<ulcPropCount;j++)
|
|
{
|
|
ULONG cchSize;
|
|
if(lpProp[j].ulPropTag == PR_DISPLAY_NAME)
|
|
{
|
|
cchSize = lstrlen(lpProp[j].Value.LPSZ)+1;
|
|
if(lpName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize))
|
|
StrCpyN(lpName, lpProp[j].Value.LPSZ, cchSize);
|
|
else
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
}
|
|
if(lpProp[j].ulPropTag == PR_WAB_USER_PROFILEID)
|
|
{
|
|
cchSize = lstrlen(lpProp[j].Value.LPSZ)+1;
|
|
if(lpProfileID = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize))
|
|
StrCpyN(lpProfileID, lpProp[j].Value.LPSZ, cchSize);
|
|
else
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
}
|
|
if(lpProp[j].ulPropTag == PR_WAB_FOLDEROWNER)
|
|
{
|
|
TCHAR szName[CCH_IDENTITY_NAME_MAX_LENGTH];
|
|
*szName = '\0';
|
|
if( !HR_FAILED(HrGetIdentityName(lpIAB, lpProp[j].Value.LPSZ, szName, ARRAYSIZE(szName))) &&
|
|
lstrlen(szName))
|
|
{
|
|
cchSize = lstrlen(szName)+1;
|
|
if(lpOwner = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize))
|
|
StrCpyN(lpOwner, szName, cchSize);
|
|
else
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
if(lpProp[j].ulPropTag == PR_WAB_SHAREDFOLDER)
|
|
{
|
|
bShared = (lpProp[j].Value.l==FOLDER_SHARED?TRUE:FALSE);
|
|
}
|
|
}
|
|
|
|
// ideally, we should be reading in a new name for all user folders at this point
|
|
//if(lpProfileID && lstrlen(lpProfileID))
|
|
//{
|
|
// if(lpName)
|
|
// LocalFree(lpName);
|
|
// CreateUserFolderName(lpProfileID, &lpName);
|
|
//}
|
|
}
|
|
lpFolder->lpFolderName = lpName;
|
|
lpFolder->lpProfileID = lpProfileID;
|
|
lpFolder->bShared = bShared;
|
|
lpFolder->lpFolderOwner = lpOwner;
|
|
|
|
out:
|
|
|
|
ReadRecordFreePropArray(NULL, ulcPropCount, &lpProp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrLoadWABFolders
|
|
-
|
|
* Gets a list of all the folders from the WAB and sorts them out based on
|
|
* whether they are user folders or ordinary folders
|
|
*
|
|
*/
|
|
HRESULT HrLoadWABFolders(LPIAB lpIAB)
|
|
{
|
|
SCODE sc;
|
|
HRESULT hr = E_FAIL;
|
|
SPropertyRestriction PropRes = {0};
|
|
SPropValue sp = {0};
|
|
ULONG ulCount = 0;
|
|
LPSBinary rgsbEntryIDs = NULL;
|
|
ULONG i = 0;
|
|
int nID = IDM_VIEW_FOLDERS1;
|
|
|
|
// Now we will search the WAB for all objects of PR_OBJECT_TYPE = MAPI_ABCONT
|
|
//
|
|
sp.ulPropTag = PR_OBJECT_TYPE;
|
|
sp.Value.l = MAPI_ABCONT;
|
|
|
|
PropRes.ulPropTag = PR_OBJECT_TYPE;
|
|
PropRes.relop = RELOP_EQ;
|
|
PropRes.lpProp = &sp;
|
|
|
|
hr = FindRecords( lpIAB->lpPropertyStore->hPropertyStore,
|
|
NULL, 0, TRUE,
|
|
&PropRes, &ulCount, &rgsbEntryIDs);
|
|
|
|
if (HR_FAILED(hr))
|
|
goto out;
|
|
|
|
if(ulCount && rgsbEntryIDs)
|
|
{
|
|
for(i=0;i<ulCount;i++)
|
|
{
|
|
ULONG cb = 0;
|
|
LPENTRYID lpb = NULL;
|
|
LPWABFOLDER lpFolder = NULL;
|
|
|
|
lpFolder = LocalAlloc(LMEM_ZEROINIT, sizeof(WABFOLDER));
|
|
if(!lpFolder)
|
|
goto out;
|
|
|
|
if(HR_FAILED(HrGetFolderInfo(lpIAB, &rgsbEntryIDs[i], lpFolder)))
|
|
goto out;
|
|
|
|
if(!HR_FAILED(CreateWABEntryID( WAB_CONTAINER,
|
|
rgsbEntryIDs[i].lpb, NULL, NULL,
|
|
rgsbEntryIDs[i].cb, 0,
|
|
NULL, &cb, &lpb)))
|
|
{
|
|
// Add the entryids to this prop - ignore errors
|
|
SetSBinary(&(lpFolder->sbEID), cb, (LPBYTE)lpb);
|
|
MAPIFreeBuffer(lpb);
|
|
}
|
|
|
|
if(lpFolder->lpProfileID)
|
|
{
|
|
// this is a user folder
|
|
lpFolder->lpNext = lpIAB->lpWABUserFolders;
|
|
lpIAB->lpWABUserFolders = lpFolder;
|
|
}
|
|
else
|
|
{
|
|
lpFolder->lpNext = lpIAB->lpWABFolders;
|
|
lpFolder->nMenuCmdID = nID++;
|
|
lpIAB->lpWABFolders = lpFolder;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(HR_FAILED(hr = HrLinkUserFoldersToWABFolders(lpIAB)))
|
|
goto out;
|
|
|
|
HrLinkOrphanFoldersToDefaultUser(lpIAB); // we can ignore errors in this call since it's not life-and-death
|
|
|
|
out:
|
|
if(ulCount && rgsbEntryIDs)
|
|
{
|
|
FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore,
|
|
ulCount,
|
|
rgsbEntryIDs);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
-
|
|
- HrCreateNewFolder
|
|
*
|
|
* Takes a profile ID, uses it to create a folder in the WAB
|
|
* and sticks the new user folder onto the IAB
|
|
* Can create a user folder or an ordinary folder
|
|
* For ordinary folders, we can also specify a parent folder to which the item can be added
|
|
*
|
|
*/
|
|
HRESULT HrCreateNewFolder(LPIAB lpIAB, LPTSTR lpName, LPTSTR lpProfileID, BOOL bUserFolder,
|
|
LPWABFOLDER lpParentFolder, BOOL bShared, LPSBinary lpsbNew)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SPropValue spv[proUserFolderMax];
|
|
LPSBinary lpsb = NULL;
|
|
SBinary sb = {0};
|
|
LPMAPIPROP lpObject = NULL;
|
|
ULONG ulcProps = 0, j = 0;
|
|
LPSPropValue lpProps = NULL;
|
|
LPWABFOLDER lpFolder = NULL;
|
|
ULONG ulPropCount = 0;
|
|
ULONG cchSize;
|
|
|
|
if(!(lpFolder = LocalAlloc(LMEM_ZEROINIT, sizeof(WABFOLDER))))
|
|
return MAPI_E_NOT_ENOUGH_MEMORY;
|
|
|
|
if(bUserFolder)
|
|
{
|
|
CreateUserFolderName(lpName ? lpName : lpProfileID, &lpFolder->lpFolderName);
|
|
cchSize = lstrlen(lpProfileID)+1;
|
|
if(!(lpFolder->lpProfileID = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize)))
|
|
return MAPI_E_NOT_ENOUGH_MEMORY;
|
|
StrCpyN(lpFolder->lpProfileID, lpProfileID, cchSize);
|
|
}
|
|
else
|
|
{
|
|
cchSize = lstrlen(lpName)+1;
|
|
if(!(lpFolder->lpFolderName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize)))
|
|
return MAPI_E_NOT_ENOUGH_MEMORY;
|
|
StrCpyN(lpFolder->lpFolderName, lpName, cchSize);
|
|
}
|
|
|
|
// if there isn't a current user, all new folders should go into the shared contacts folder
|
|
if(!bIsThereACurrentUser(lpIAB) && !lpProfileID && !lpParentFolder)
|
|
bShared = TRUE;
|
|
|
|
spv[ulPropCount].ulPropTag = PR_DISPLAY_NAME;
|
|
spv[ulPropCount++].Value.LPSZ = lpFolder->lpFolderName;
|
|
|
|
spv[ulPropCount].ulPropTag = PR_OBJECT_TYPE;
|
|
spv[ulPropCount++].Value.l = MAPI_ABCONT;
|
|
|
|
spv[ulPropCount].ulPropTag = PR_WAB_FOLDER_ENTRIES;
|
|
spv[ulPropCount].Value.MVbin.cValues = 1;
|
|
spv[ulPropCount++].Value.MVbin.lpbin = &sb;
|
|
|
|
spv[ulPropCount].ulPropTag = PR_WAB_SHAREDFOLDER;
|
|
spv[ulPropCount++].Value.l = (bUserFolder ? FOLDER_PRIVATE : (bShared ? FOLDER_SHARED : FOLDER_PRIVATE));
|
|
|
|
if(lpProfileID)
|
|
{
|
|
spv[ulPropCount].ulPropTag = PR_WAB_FOLDEROWNER;
|
|
spv[ulPropCount++].Value.LPSZ = lpProfileID;
|
|
}
|
|
|
|
if(bUserFolder)
|
|
{
|
|
spv[ulPropCount].ulPropTag = PR_WAB_USER_SUBFOLDERS;
|
|
spv[ulPropCount].Value.MVbin.cValues = 1;
|
|
spv[ulPropCount++].Value.MVbin.lpbin = &sb;
|
|
|
|
spv[ulPropCount].ulPropTag = PR_WAB_USER_PROFILEID;
|
|
spv[ulPropCount++].Value.LPSZ = lpFolder->lpProfileID;
|
|
}
|
|
|
|
if(HR_FAILED(hr = HrSaveFolderProps((LPADRBOOK)lpIAB, bUserFolder,
|
|
ulPropCount,
|
|
spv, &lpObject)))
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = lpObject->lpVtbl->GetProps(lpObject, NULL, MAPI_UNICODE, &ulcProps, &lpProps)))
|
|
goto out;
|
|
|
|
for(j=0;j<ulcProps;j++)
|
|
{
|
|
if(lpProps[j].ulPropTag == PR_ENTRYID)
|
|
{
|
|
lpsb = &(lpProps[j].Value.bin);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(lpsb)
|
|
{
|
|
ULONG cb = 0;
|
|
LPENTRYID lpb = NULL;
|
|
if(!HR_FAILED(CreateWABEntryID( WAB_CONTAINER,
|
|
lpsb->lpb, NULL, NULL,
|
|
lpsb->cb, 0,
|
|
NULL, &cb, &lpb)))
|
|
{
|
|
// Add the entryids to this prop - ignore errors
|
|
SetSBinary(&(lpFolder->sbEID), cb, (LPBYTE) lpb);
|
|
MAPIFreeBuffer(lpb);
|
|
}
|
|
}
|
|
|
|
if(bUserFolder)
|
|
{
|
|
lpFolder->lpNext = lpIAB->lpWABUserFolders;
|
|
lpIAB->lpWABUserFolders = lpFolder;
|
|
}
|
|
else
|
|
{
|
|
lpFolder->lpNext = lpIAB->lpWABFolders;
|
|
lpIAB->lpWABFolders = lpFolder;
|
|
// Add this folder to the current user's profile
|
|
HrAddRemoveFolderFromUserFolder(lpIAB, lpParentFolder, &(lpFolder->sbEID), NULL, FALSE);
|
|
}
|
|
|
|
if(lpsbNew)
|
|
SetSBinary(lpsbNew, lpFolder->sbEID.cb, lpFolder->sbEID.lpb);
|
|
|
|
hr = HrGetWABProfiles(lpIAB);
|
|
|
|
out:
|
|
if(lpObject)
|
|
lpObject->lpVtbl->Release(lpObject);
|
|
|
|
FreeBufferAndNull(&lpProps);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- HrAddAllContactsToFolder
|
|
-
|
|
* Adds all existing contacts and groups to the current user folder
|
|
*
|
|
*/
|
|
HRESULT HrAddAllContactsToFolder(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = 0;
|
|
SPropertyRestriction PropRes;
|
|
LPSBinary rgsbEntryIDs = NULL;
|
|
ULONG ulCount = 0, i,j;
|
|
ULONG rgObj[] = {MAPI_MAILUSER, MAPI_DISTLIST};
|
|
// This can be a labor intesive process
|
|
HCURSOR hOldC = NULL;
|
|
|
|
if(!bIsThereACurrentUser(lpIAB))
|
|
return hr;
|
|
|
|
hOldC = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
//for(j=0;j<2;j++)
|
|
{
|
|
SPropValue sp = {0};
|
|
sp.ulPropTag = PR_WAB_FOLDER_PARENT;
|
|
//sp.Value.l = rgObj[j];
|
|
|
|
PropRes.ulPropTag = PR_WAB_FOLDER_PARENT;
|
|
PropRes.relop = RELOP_NE;
|
|
PropRes.lpProp = &sp;
|
|
|
|
// Find stuff that isn't in any folder
|
|
if(!HR_FAILED(hr = FindRecords( lpIAB->lpPropertyStore->hPropertyStore,
|
|
NULL, AB_MATCH_PROP_ONLY, TRUE, &PropRes, &ulCount, &rgsbEntryIDs)))
|
|
{
|
|
for(i=0;i<ulCount;i++)
|
|
{
|
|
AddEntryToFolder((LPADRBOOK)lpIAB,NULL,
|
|
lpIAB->lpWABCurrentUserFolder->sbEID.cb,
|
|
(LPENTRYID) lpIAB->lpWABCurrentUserFolder->sbEID.lpb,
|
|
rgsbEntryIDs[i].cb,
|
|
(LPENTRYID) rgsbEntryIDs[i].lpb);
|
|
}
|
|
|
|
FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
|
|
}
|
|
}
|
|
|
|
if(hOldC)
|
|
SetCursor(hOldC);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/*
|
|
- UpdateCurrentUserFolderName
|
|
-
|
|
*
|
|
*/
|
|
void UpdateCurrentUserFolderName(LPIAB lpIAB)
|
|
{
|
|
LPTSTR lpsz = NULL;
|
|
CreateUserFolderName(lpIAB->szProfileName, &lpsz);
|
|
if(lstrcmpi(lpsz, lpIAB->lpWABCurrentUserFolder->lpFolderName))
|
|
{
|
|
LocalFree(lpIAB->lpWABCurrentUserFolder->lpFolderName);
|
|
lpIAB->lpWABCurrentUserFolder->lpFolderName = lpsz;
|
|
HrUpdateFolderInfo(lpIAB, &lpIAB->lpWABCurrentUserFolder->sbEID, FOLDER_UPDATE_NAME, FALSE, lpIAB->lpWABCurrentUserFolder->lpFolderName);
|
|
}
|
|
else
|
|
LocalFree(lpsz);
|
|
}
|
|
|
|
|
|
/*
|
|
- HrGetWABProfiles
|
|
-
|
|
* Collates information about the WAB User Folders etc from the WAB
|
|
* Creates a list of User Folders and generic Folders and caches these on the Address Book
|
|
* Matches the provided profile to the user folders .. if it matches, points to the
|
|
* corresponding folder .. if it doesn't match, creates a new User Folder for the
|
|
* Profile ID.
|
|
*
|
|
* <TBD> when the account manager is profile ready, use the profile ID to pull in the
|
|
* users name from the account manager and then use that to call it TEXT("UserName's Contacts")
|
|
* For now, we'll just use the profile id to do that
|
|
*/
|
|
HRESULT HrGetWABProfiles(LPIAB lpIAB)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
EnterCriticalSection(&lpIAB->cs);
|
|
|
|
if(!bIsWABSessionProfileAware(lpIAB))
|
|
goto out;
|
|
|
|
if(!lstrlen(lpIAB->szProfileID))
|
|
HrGetUserProfileID(&lpIAB->guidCurrentUser, lpIAB->szProfileID, CharSizeOf(lpIAB->szProfileID));
|
|
|
|
if(!lstrlen(lpIAB->szProfileName))
|
|
HrGetIdentityName(lpIAB, NULL, lpIAB->szProfileName, ARRAYSIZE(lpIAB->szProfileName));
|
|
|
|
// Clear out old data
|
|
if(lpIAB->lpWABUserFolders || lpIAB->lpWABFolders)
|
|
FreeWABFoldersList(lpIAB);
|
|
|
|
// Get a list of all the folders in the WAB
|
|
if(HR_FAILED(hr = HrLoadWABFolders(lpIAB)))
|
|
goto out;
|
|
|
|
SetCurrentUserFolder(lpIAB, lpIAB->szProfileID);
|
|
|
|
if(!bIsThereACurrentUser(lpIAB) && lstrlen(lpIAB->szProfileID) && lstrlen(lpIAB->szProfileName))
|
|
{
|
|
// Not Found!!!
|
|
// Create a new user folder ..
|
|
BOOL bFirstUser = bDoesThisWABHaveAnyUsers(lpIAB) ? FALSE : TRUE;
|
|
|
|
if(HR_FAILED(hr = HrCreateNewFolder(lpIAB, lpIAB->szProfileName, lpIAB->szProfileID, TRUE, NULL, FALSE, NULL)))
|
|
goto out;
|
|
|
|
SetCurrentUserFolder(lpIAB, lpIAB->szProfileID);
|
|
|
|
if(bFirstUser)
|
|
{
|
|
if(lpIAB->lpWABFolders)
|
|
{
|
|
// we want to put all existing folders under this user
|
|
LPWABFOLDER lpFolder = lpIAB->lpWABFolders;
|
|
while(lpFolder)
|
|
{
|
|
// There is a weird case where a preexisting folder with the same name as
|
|
// a user's folder becomes nested under itself .. so don't add this folder to the
|
|
// User Folder
|
|
if(lstrcmpi(lpIAB->lpWABCurrentUserFolder->lpFolderName, lpFolder->lpFolderName))
|
|
HrAddRemoveFolderFromUserFolder(lpIAB, NULL, &lpFolder->sbEID, NULL, FALSE);
|
|
lpFolder = lpFolder->lpNext;
|
|
}
|
|
hr = HrLinkUserFoldersToWABFolders(lpIAB);
|
|
}
|
|
//We also want to put all existing contacts into this user folder
|
|
hr = HrAddAllContactsToFolder(lpIAB);
|
|
}
|
|
}
|
|
|
|
if( lpIAB->szProfileID && lstrlen(lpIAB->szProfileID) && lpIAB->szProfileName && lstrlen(lpIAB->szProfileName) && bIsThereACurrentUser(lpIAB))
|
|
{
|
|
// Use the latest name for this entry
|
|
UpdateCurrentUserFolderName(lpIAB);
|
|
}
|
|
|
|
if(HR_FAILED(hr = HrGetWABProfileContainerInfo(lpIAB)))
|
|
goto out;
|
|
|
|
hr = S_OK;
|
|
out:
|
|
LeaveCriticalSection(&lpIAB->cs);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- bIsProfileMember
|
|
-
|
|
*
|
|
*/
|
|
BOOL bIsProfileMember(LPIAB lpIAB, LPSBinary lpsb, LPWABFOLDER lpWABFolder, LPWABUSERFOLDER lpUserFolder)
|
|
{
|
|
LPWABFOLDERLIST lpFolderItem = NULL;
|
|
LPWABFOLDER lpFolder = lpWABFolder;
|
|
|
|
if(!lpUserFolder && !lpIAB->lpWABCurrentUserFolder)
|
|
return FALSE;
|
|
|
|
lpFolderItem = lpUserFolder ? lpUserFolder->lpFolderList : lpIAB->lpWABCurrentUserFolder->lpFolderList;
|
|
|
|
if(!lpFolder && lpsb)
|
|
lpFolder = FindWABFolder(lpIAB, lpsb, NULL, NULL);
|
|
|
|
while(lpFolderItem && lpFolder)
|
|
{
|
|
if(lpFolderItem->lpFolder == lpFolder)
|
|
return TRUE;
|
|
lpFolderItem = lpFolderItem->lpNext;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
- bDoesEntryNameAlreadyExist
|
|
-
|
|
* Checks if a given name already exists in the WAB
|
|
* Used for preventing duplicate folder and group names
|
|
*/
|
|
BOOL bDoesEntryNameAlreadyExist(LPIAB lpIAB, LPTSTR lpsz)
|
|
{
|
|
SPropertyRestriction PropRes;
|
|
SPropValue Prop = {0};
|
|
LPSBinary rgsbEntryIDs = NULL;
|
|
ULONG ulCount = 0;
|
|
BOOL bRet = FALSE;
|
|
|
|
// Verify that the new name doesn't actually exist
|
|
Prop.ulPropTag = PR_DISPLAY_NAME;
|
|
Prop.Value.LPSZ = lpsz;
|
|
PropRes.lpProp = &Prop;
|
|
PropRes.relop = RELOP_EQ;
|
|
PropRes.ulPropTag = PR_DISPLAY_NAME;
|
|
|
|
if (HR_FAILED(FindRecords(lpIAB->lpPropertyStore->hPropertyStore,
|
|
NULL, // pmbinFolder
|
|
0, // ulFlags
|
|
TRUE, // Always TRUE
|
|
&PropRes, // Propertyrestriction
|
|
&ulCount, // IN: number of matches to find, OUT: number found
|
|
&rgsbEntryIDs)))
|
|
goto out;
|
|
|
|
FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
|
|
|
|
if(ulCount >=1)
|
|
bRet = TRUE;
|
|
out:
|
|
return bRet;
|
|
}
|
|
|
|
/*
|
|
- UpdateFolderName
|
|
-
|
|
*
|
|
*/
|
|
HRESULT HrUpdateFolderInfo(LPIAB lpIAB, LPSBinary lpsbEID, ULONG ulFlags, BOOL bShared, LPTSTR lpsz)
|
|
{
|
|
LPSPropValue lpProp = NULL, lpPropNew = NULL;
|
|
ULONG ulcPropCount = 0, i =0, ulcPropNew = 0;
|
|
HRESULT hr = S_OK;
|
|
BOOL bUpdate = FALSE, bFoundShare = FALSE;//, bOldShareState = FALSE;
|
|
ULONG cchSize;
|
|
|
|
if(!lpsbEID || !lpsbEID->cb || !lpsbEID->lpb)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
if(!HR_FAILED(hr = ReadRecord( lpIAB->lpPropertyStore->hPropertyStore,
|
|
lpsbEID, 0, &ulcPropCount, &lpProp)))
|
|
{
|
|
for(i=0;i<ulcPropCount;i++)
|
|
{
|
|
if( (ulFlags & FOLDER_UPDATE_NAME) &&
|
|
lpProp[i].ulPropTag == PR_DISPLAY_NAME)
|
|
{
|
|
BOOL bCaseChangeOnly = (!lstrcmpi(lpsz, lpProp[i].Value.LPSZ) &&
|
|
lstrcmp(lpsz, lpProp[i].Value.LPSZ) );
|
|
LocalFree(lpProp[i].Value.LPSZ);
|
|
cchSize = lstrlen(lpsz)+1;
|
|
lpProp[i].Value.LPSZ = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
|
|
if(lpProp[i].Value.LPSZ)
|
|
{
|
|
StrCpyN(lpProp[i].Value.LPSZ, lpsz, cchSize);
|
|
if(!bCaseChangeOnly) // if this isn't just a case change, look for the name (if it's a case change, there will be a spurious error) //bug 33067
|
|
{
|
|
if(bDoesEntryNameAlreadyExist(lpIAB, lpProp[i].Value.LPSZ))
|
|
{
|
|
hr = MAPI_E_COLLISION;
|
|
goto out;
|
|
}
|
|
}
|
|
bUpdate = TRUE;
|
|
}
|
|
}
|
|
if( (ulFlags & FOLDER_UPDATE_SHARE) &&
|
|
lpProp[i].ulPropTag == PR_WAB_SHAREDFOLDER)
|
|
{
|
|
bFoundShare = TRUE;
|
|
//bOldShareState = (lpProp[i].Value.l == FOLDER_SHARED) ? TRUE : FALSE;
|
|
lpProp[i].Value.l = bShared ? FOLDER_SHARED : FOLDER_PRIVATE;
|
|
bUpdate = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!bFoundShare && (ulFlags & FOLDER_UPDATE_SHARE)) // this value doesnt already exist on the contact so update it
|
|
{
|
|
SPropValue Prop = {0};
|
|
Prop.ulPropTag = PR_WAB_SHAREDFOLDER;
|
|
Prop.Value.l = bShared ? FOLDER_SHARED : FOLDER_PRIVATE;
|
|
|
|
// Create a new prop array with this additional property
|
|
if(!(ScMergePropValues( 1, &Prop, ulcPropCount, lpProp,
|
|
&ulcPropNew, &lpPropNew)))
|
|
{
|
|
ReadRecordFreePropArray(NULL, ulcPropCount, &lpProp);
|
|
ulcPropCount = ulcPropNew;
|
|
lpProp = lpPropNew;
|
|
bUpdate = TRUE;
|
|
}
|
|
}
|
|
|
|
if(bUpdate)
|
|
{
|
|
if(HR_FAILED(hr = HrSaveFolderProps((LPADRBOOK)lpIAB, FALSE, ulcPropCount, lpProp, NULL)))
|
|
goto out;
|
|
}
|
|
|
|
|
|
out:
|
|
if(lpProp)
|
|
{
|
|
if(lpProp == lpPropNew)
|
|
FreeBufferAndNull(&lpProp);
|
|
else
|
|
ReadRecordFreePropArray(NULL, ulcPropCount, &lpProp);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- HrAddRemoveFolderFromCurrentUserFolder
|
|
-
|
|
* Given a folder EID, adds or removes the folder EID from the current users
|
|
* user folder
|
|
* If there is no current user folder then use the lpUserFolder provided
|
|
* else return
|
|
*
|
|
* lpUFolder - parent folder to / from which to add / remove
|
|
* lpsbEID - EID of folder we want to add / remove
|
|
* lpName - Name to look for if we don't have an EID
|
|
*/
|
|
HRESULT HrAddRemoveFolderFromUserFolder(LPIAB lpIAB, LPWABFOLDER lpUFolder,
|
|
LPSBinary lpsbEID, LPTSTR lpName,
|
|
BOOL bRefreshProfiles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulcPropsNew = 0, ulcProps = 0, i = 0;
|
|
LPSPropValue lpPropArrayNew = NULL;
|
|
LPSPropValue lpProps = NULL;
|
|
LPWABFOLDER lpUserFolder = NULL;
|
|
|
|
if(!lpsbEID && lpName)
|
|
{
|
|
LPWABFOLDER lpFolder = FindWABFolder(lpIAB, NULL, lpName, NULL);
|
|
lpsbEID = &lpFolder->sbEID;
|
|
}
|
|
|
|
if(lpIAB->lpWABCurrentUserFolder)
|
|
lpUserFolder = lpIAB->lpWABCurrentUserFolder;
|
|
else if(lpUFolder)
|
|
lpUserFolder = lpUFolder;
|
|
else
|
|
goto out;
|
|
|
|
{
|
|
// open the current user folder
|
|
if(!HR_FAILED(hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore, &(lpUserFolder->sbEID),
|
|
0, &ulcProps, &lpProps)))
|
|
{
|
|
SPropValue spv = {0};
|
|
spv.ulPropTag = PR_NULL;
|
|
// Copy the props into a MAPI proparray
|
|
if(!(ScMergePropValues( 1, &spv, ulcProps, lpProps,
|
|
&ulcPropsNew, &lpPropArrayNew)))
|
|
{
|
|
for(i=0;i<ulcPropsNew;i++)
|
|
{
|
|
if(lpProps[i].ulPropTag == PR_WAB_USER_SUBFOLDERS)
|
|
{
|
|
if(bIsProfileMember(lpIAB, lpsbEID, NULL, lpUserFolder))
|
|
RemovePropFromMVBin( lpPropArrayNew, ulcPropsNew, i, lpsbEID->lpb, lpsbEID->cb);
|
|
else
|
|
AddPropToMVPBin( lpPropArrayNew, i, lpsbEID->lpb, lpsbEID->cb, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(HR_FAILED(hr = HrSaveFolderProps((LPADRBOOK)lpIAB, FALSE, ulcPropsNew, lpPropArrayNew, NULL)))
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if(bRefreshProfiles)
|
|
hr = HrGetWABProfiles(lpIAB);
|
|
|
|
out:
|
|
ReadRecordFreePropArray(NULL, ulcProps, &lpProps);
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
-
|
|
- bDoesThisWABHaveAnyUsers
|
|
*
|
|
* TRUE if some user folders exist .. FALSE if NO user folders exist
|
|
*/
|
|
BOOL bDoesThisWABHaveAnyUsers(LPIAB lpIAB)
|
|
{
|
|
return (lpIAB->lpWABUserFolders != NULL);
|
|
}
|
|
|
|
/*
|
|
-
|
|
- bIsThereACurrentUser
|
|
*
|
|
* TRUE if there is a current user .. FALSE if not
|
|
*/
|
|
BOOL bIsThereACurrentUser(LPIAB lpIAB)
|
|
{
|
|
// Don't change this test since success of this test implies that lpIAB->lpWABCurrentUserFolder is not NULL
|
|
// and can be dereferenced
|
|
return (lpIAB->lpWABCurrentUserFolder != NULL);
|
|
}
|
|
|
|
/*
|
|
-
|
|
- bAreWABAPIProfileAware
|
|
*
|
|
* TRUE if the WAB API should behave with profile-awareness, false if they should revert to old behaviour
|
|
*/
|
|
BOOL bAreWABAPIProfileAware(LPIAB lpIAB)
|
|
{
|
|
return (lpIAB->bProfilesAPIEnabled);
|
|
}
|
|
|
|
/*
|
|
-
|
|
- bIsWABSessionProfileAware
|
|
*
|
|
* TRUE if the WAB should behave with profile-awareness, false if they should revert to old behaviour
|
|
* This is also used to differentiate between Outlook sessions which are not at all profile aware
|
|
*/
|
|
BOOL bIsWABSessionProfileAware(LPIAB lpIAB)
|
|
{
|
|
return (lpIAB->bProfilesEnabled);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************/
|
|
/******* Identity Manager Stuff *******/
|
|
|
|
// Global place to store the account manager object
|
|
//IUserIdentityManager * g_lpUserIdentityManager = NULL;
|
|
//BOOL fCoInitUserIdentityManager = FALSE;
|
|
//ULONG cIdentInit = 0;
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// FUNCTION: HrWrappedCreateIdentityManager
|
|
//
|
|
// PURPOSE: Load identity manager dll and create the object.
|
|
//
|
|
// PARAMETERS: lppIdentityManager -> returned pointer to Identity manager
|
|
// object.
|
|
//
|
|
// RETURNS: HRESULT
|
|
//
|
|
//*******************************************************************
|
|
HRESULT HrWrappedCreateUserIdentityManager(LPIAB lpIAB, IUserIdentityManager **lppUserIdentityManager)
|
|
{
|
|
HRESULT hResult = E_FAIL;
|
|
|
|
if (! lppUserIdentityManager) {
|
|
return(ResultFromScode(E_INVALIDARG));
|
|
}
|
|
|
|
*lppUserIdentityManager = NULL;
|
|
|
|
if (CoInitialize(NULL) == S_FALSE)
|
|
{
|
|
// Already initialized, undo the extra.
|
|
CoUninitialize();
|
|
} else
|
|
{
|
|
lpIAB->fCoInitUserIdentityManager = TRUE;
|
|
}
|
|
|
|
if (HR_FAILED(hResult = CoCreateInstance(&CLSID_UserIdentityManager,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IUserIdentityManager,
|
|
(LPVOID *)lppUserIdentityManager)))
|
|
{
|
|
DebugTrace(TEXT("CoCreateInstance(IID_IUserIdentityManager) -> %x\n"), GetScode(hResult));
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// FUNCTION: InitUserIdentityManager
|
|
//
|
|
// PURPOSE: Load and initialize the account manager
|
|
//
|
|
// PARAMETERS: lppUserIdentityManager -> returned pointer to account manager
|
|
// object.
|
|
//
|
|
// RETURNS: HRESULT
|
|
//
|
|
// COMMENTS: The first time through here, we will save the hResult.
|
|
// On subsequent calls, we will check this saved value
|
|
// and return it right away if there was an error, thus
|
|
// preventing repeated time consuming LoadLibrary calls.
|
|
//
|
|
//*******************************************************************
|
|
HRESULT InitUserIdentityManager(LPIAB lpIAB, IUserIdentityManager ** lppUserIdentityManager)
|
|
{
|
|
static hResultSave = hrSuccess;
|
|
HRESULT hResult = hResultSave;
|
|
|
|
if (! lpIAB->lpUserIdentityManager && ! HR_FAILED(hResultSave))
|
|
{
|
|
#ifdef DEBUG
|
|
DWORD dwTickCount = GetTickCount();
|
|
DebugTrace(TEXT(">>>>> Initializing User Identity Manager...\n"));
|
|
#endif // DEBUG
|
|
|
|
if (hResult = HrWrappedCreateUserIdentityManager(lpIAB, &lpIAB->lpUserIdentityManager))
|
|
{
|
|
DebugTrace(TEXT("HrWrappedCreateUserIdentityManager -> %x\n"), GetScode(hResult));
|
|
goto end;
|
|
}
|
|
Assert(lpIAB->lpUserIdentityManager);
|
|
|
|
lpIAB->cIdentInit++; // +1 here to match the release in IAB_Neuter
|
|
|
|
#ifdef DEBUG
|
|
DebugTrace( TEXT(">>>>> Done Initializing User Identity Manager... %u milliseconds\n"), GetTickCount() - dwTickCount);
|
|
#endif // DEBUG
|
|
}
|
|
|
|
lpIAB->cIdentInit++;
|
|
|
|
end:
|
|
if (HR_FAILED(hResult))
|
|
{
|
|
*lppUserIdentityManager = NULL;
|
|
// Save the result
|
|
hResultSave = hResult;
|
|
} else
|
|
{
|
|
*lppUserIdentityManager = lpIAB->lpUserIdentityManager;
|
|
}
|
|
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// FUNCTION: UninitUserIdentityManager
|
|
//
|
|
// PURPOSE: Release and unLoad the account manager
|
|
//
|
|
// PARAMETERS: none
|
|
//
|
|
// RETURNS: none
|
|
//
|
|
//*******************************************************************
|
|
void UninitUserIdentityManager(LPIAB lpIAB)
|
|
{
|
|
lpIAB->cIdentInit--;
|
|
if (lpIAB->lpUserIdentityManager && lpIAB->cIdentInit==0) {
|
|
#ifdef DEBUG
|
|
DWORD dwTickCount = GetTickCount();
|
|
DebugTrace( TEXT(">>>>> Uninitializing Account Manager...\n"));
|
|
#endif // DEBUG
|
|
|
|
lpIAB->lpUserIdentityManager->lpVtbl->Release(lpIAB->lpUserIdentityManager);
|
|
lpIAB->lpUserIdentityManager = NULL;
|
|
|
|
if (lpIAB->fCoInitUserIdentityManager)
|
|
CoUninitialize();
|
|
#ifdef DEBUG
|
|
DebugTrace( TEXT(">>>>> Done Uninitializing Account Manager... %u milliseconds\n"), GetTickCount() - dwTickCount);
|
|
#endif // DEBUG
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
- HrGetDefaultIdentityInfo
|
|
-
|
|
* Get's the hKey corresponding to the default identity
|
|
*/
|
|
HRESULT HrGetDefaultIdentityInfo(LPIAB lpIAB, ULONG ulFlags, HKEY * lphKey, LPTSTR lpProfileID, ULONG cchProfileID, LPTSTR lpName, ULONG cchName)
|
|
{
|
|
IUserIdentityManager * lpUserIdentityManager = NULL;
|
|
IUserIdentity * lpUserIdentity = NULL;
|
|
HRESULT hr = S_OK;
|
|
BOOL fInit = FALSE;
|
|
|
|
if(HR_FAILED(hr = InitUserIdentityManager(lpIAB, &lpUserIdentityManager)))
|
|
goto out;
|
|
|
|
fInit = TRUE;
|
|
|
|
Assert(lpUserIdentityManager);
|
|
|
|
if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->GetIdentityByCookie(lpUserIdentityManager,
|
|
(GUID *)&UID_GIBC_DEFAULT_USER,
|
|
&lpUserIdentity)))
|
|
goto out;
|
|
|
|
Assert(lpUserIdentity);
|
|
|
|
if(ulFlags & DEFAULT_ID_HKEY && lphKey)
|
|
{
|
|
if(HR_FAILED(hr = lpUserIdentity->lpVtbl->OpenIdentityRegKey(lpUserIdentity,
|
|
KEY_ALL_ACCESS,
|
|
lphKey)))
|
|
goto out;
|
|
}
|
|
if(ulFlags & DEFAULT_ID_PROFILEID && lpProfileID)
|
|
{
|
|
GUID guidCookie = {0};
|
|
TCHAR sz[MAX_PATH];
|
|
// update this key for the account manager
|
|
if(HR_FAILED(hr = lpUserIdentity->lpVtbl->GetCookie(lpUserIdentity, &guidCookie)))
|
|
goto out;
|
|
if(HR_FAILED(hr = HrGetUserProfileID(&guidCookie, sz, CharSizeOf(sz))))
|
|
goto out;
|
|
StrCpyN(lpProfileID, sz, cchProfileID);
|
|
}
|
|
if(ulFlags & DEFAULT_ID_NAME && lpName && lpProfileID)
|
|
{
|
|
if(HR_FAILED(hr = HrGetIdentityName(lpIAB, lpProfileID, lpName, cchName)))
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
if(lpUserIdentity)
|
|
lpUserIdentity->lpVtbl->Release(lpUserIdentity);
|
|
|
|
if(fInit)
|
|
UninitUserIdentityManager(lpIAB);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrGetIdentityName
|
|
-
|
|
* Gets the name string corresponding to the current user unless a specific profile ID is specified
|
|
* (which is nothing but a string version of the GUID to use)
|
|
* szName - buffer long enough for the user name (CCH_IDENTITY_NAME_MAX_LENGTH)
|
|
*/
|
|
HRESULT HrGetIdentityName(LPIAB lpIAB, LPTSTR lpID, LPTSTR szUserName, ULONG cchUserName)
|
|
{
|
|
IUserIdentityManager * lpUserIdentityManager = NULL;
|
|
IUserIdentity * lpUserIdentity = NULL;
|
|
WCHAR szNameW[CCH_IDENTITY_NAME_MAX_LENGTH];
|
|
TCHAR szName[CCH_IDENTITY_NAME_MAX_LENGTH];
|
|
HRESULT hr = S_OK;
|
|
GUID guidCookie = {0};
|
|
BOOL fInit = FALSE;
|
|
|
|
if(!lpID && !bAreWABAPIProfileAware(lpIAB))
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = InitUserIdentityManager(lpIAB, &lpUserIdentityManager)))
|
|
goto out;
|
|
|
|
fInit = TRUE;
|
|
|
|
Assert(lpUserIdentityManager);
|
|
|
|
if(lpIAB && !lpID)
|
|
memcpy(&guidCookie, &lpIAB->guidCurrentUser, sizeof(GUID));
|
|
else
|
|
{
|
|
if( (HR_FAILED(hr = CLSIDFromString(lpID, &guidCookie))) )
|
|
goto out;
|
|
}
|
|
|
|
if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->GetIdentityByCookie(lpUserIdentityManager, &guidCookie, &lpUserIdentity)))
|
|
goto out;
|
|
|
|
Assert(lpUserIdentity);
|
|
|
|
if(HR_FAILED(hr = lpUserIdentity->lpVtbl->GetName(lpUserIdentity, szNameW, CharSizeOf(szNameW))))
|
|
goto out;
|
|
StrCpyN(szName, szNameW, ARRAYSIZE(szName));
|
|
|
|
if(!lstrcmp(szUserName, szName))
|
|
{
|
|
hr = E_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
StrCpyN(szUserName, szName, cchUserName);
|
|
|
|
out:
|
|
if(fInit)
|
|
UninitUserIdentityManager(lpIAB);
|
|
|
|
if(lpUserIdentity)
|
|
lpUserIdentity->lpVtbl->Release(lpUserIdentity);
|
|
|
|
if(HR_FAILED(hr))
|
|
szUserName[0] = TEXT('\0');
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
- HrGetUserProfileID
|
|
-
|
|
* Gets the profile string corresponding to the current user
|
|
* The profile ID is nothing but a string represenatation of the user's Cookie (GUID)
|
|
*
|
|
* szProfileID - buffer long enough for the user name
|
|
*/
|
|
HRESULT HrGetUserProfileID(LPGUID lpguidUser, LPTSTR szProfileID, ULONG cbProfileID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPOLESTR lpszW= 0 ;
|
|
|
|
if (HR_FAILED(hr = StringFromCLSID(lpguidUser, &lpszW)))
|
|
goto out;
|
|
|
|
StrCpyN(szProfileID,(LPCWSTR)lpszW,cbProfileID);
|
|
|
|
out:
|
|
if (lpszW)
|
|
{
|
|
LPMALLOC pMalloc = NULL;
|
|
CoGetMalloc(1, &pMalloc);
|
|
if (pMalloc) {
|
|
pMalloc->lpVtbl->Free(pMalloc, lpszW);
|
|
pMalloc->lpVtbl->Release(pMalloc);
|
|
}
|
|
}
|
|
if(HR_FAILED(hr))
|
|
szProfileID[0] = TEXT('\0');
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
-
|
|
- HrLogonAndGetCurrentUserProfile - Inits the User Identity Manger and calls into the Logon ..
|
|
- Gets a user, either by showing UI or getting the current user and then gets a
|
|
- profile ID ( TEXT("Cookie")) for that user ..
|
|
*
|
|
* bForceUI - forces the Logon dialog so user can switch users .. TRUE only when user wants to switch
|
|
*
|
|
* bSwitchUser - True only after user has switched .. tells us to refresh and get details ont he new user
|
|
*
|
|
*/
|
|
HRESULT HrLogonAndGetCurrentUserProfile(HWND hWndParent, LPIAB lpIAB, BOOL bForceUI, BOOL bSwitchUser)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IUserIdentityManager * lpUserIdentityManager = NULL;
|
|
IUserIdentity * lpUserIdentity = NULL;
|
|
GUID guidCookie = {0};
|
|
BOOL fInit = FALSE;
|
|
if(!bAreWABAPIProfileAware(lpIAB))
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = InitUserIdentityManager(lpIAB, &lpUserIdentityManager)))
|
|
goto out;
|
|
|
|
fInit = TRUE;
|
|
|
|
Assert(lpUserIdentityManager);
|
|
|
|
// Logon will get the currently logged on user, or if there is a single user, it will return
|
|
// that user, or if there are multiple users, it will prompt for a logon
|
|
//
|
|
if(!bSwitchUser)
|
|
{
|
|
hr = lpUserIdentityManager->lpVtbl->Logon(lpUserIdentityManager,
|
|
hWndParent,
|
|
bForceUI ? UIL_FORCE_UI : 0,
|
|
&lpUserIdentity);
|
|
|
|
#ifdef NEED
|
|
if(hr == S_IDENTITIES_DISABLED)
|
|
hr = E_FAIL;
|
|
#endif
|
|
|
|
if(HR_FAILED(hr))
|
|
goto out;
|
|
}
|
|
else
|
|
{
|
|
// just switching users, thats all
|
|
if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->GetIdentityByCookie(lpUserIdentityManager,
|
|
(GUID *)&UID_GIBC_CURRENT_USER,
|
|
&lpUserIdentity)))
|
|
goto out;
|
|
|
|
}
|
|
|
|
Assert(lpUserIdentity);
|
|
|
|
if(lpIAB->hKeyCurrentUser)
|
|
RegCloseKey(lpIAB->hKeyCurrentUser);
|
|
|
|
// get the identity's hkey for the wab
|
|
if(HR_FAILED(hr = lpUserIdentity->lpVtbl->OpenIdentityRegKey(lpUserIdentity, KEY_ALL_ACCESS, &lpIAB->hKeyCurrentUser)))
|
|
goto out;
|
|
|
|
// get anothor one for the account manager (it will free it)
|
|
if(HR_FAILED(hr = lpUserIdentity->lpVtbl->GetCookie(lpUserIdentity, &guidCookie)))
|
|
goto out;
|
|
else
|
|
{
|
|
IImnAccountManager2 * lpAccountManager = NULL;
|
|
// [PaulHi] 1/13/99 Changed to initialize the account manager with
|
|
// user guid cookie inside the InitAccountManager() function.
|
|
InitAccountManager(lpIAB, &lpAccountManager, &guidCookie);
|
|
}
|
|
|
|
if(!memcmp(&lpIAB->guidCurrentUser, &guidCookie, sizeof(GUID)))
|
|
{
|
|
//current user is identical to the one we have so don't update anything here
|
|
return S_OK;
|
|
}
|
|
|
|
memcpy(&lpIAB->guidCurrentUser, &guidCookie, sizeof(GUID));
|
|
|
|
lpIAB->szProfileID[0] = TEXT('\0');
|
|
lpIAB->szProfileName[0] = TEXT('\0');
|
|
|
|
HrGetIdentityName(lpIAB, NULL, lpIAB->szProfileName, ARRAYSIZE(lpIAB->szProfileName));
|
|
HrGetUserProfileID(&lpIAB->guidCurrentUser, lpIAB->szProfileID, CharSizeOf(lpIAB->szProfileID));
|
|
/*
|
|
//register for changes
|
|
if( !bSwitchUser && !bForceUI && !lpIAB->lpWABIDCN
|
|
//&& !memcmp(&lpIAB->guidPSExt, &MPSWab_GUID_V4, sizeof(GUID))
|
|
) // register for notifications only if this is the WAB.exe process
|
|
{
|
|
HrRegisterUnregisterForIDNotifications( lpIAB, TRUE);
|
|
}
|
|
*/
|
|
out:
|
|
if(fInit)
|
|
UninitUserIdentityManager(lpIAB);
|
|
|
|
if(lpUserIdentity)
|
|
lpUserIdentity->lpVtbl->Release(lpUserIdentity);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- HRESULT HrRegisterUnregisterForIDNotifications()
|
|
-
|
|
* Creates/Releases a WABIDENTITYCHANGENOTIFY object
|
|
*
|
|
*/
|
|
HRESULT HrRegisterUnregisterForIDNotifications( LPIAB lpIAB, BOOL bRegister)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
IUserIdentityManager * lpUserIdentityManager = NULL;
|
|
IConnectionPoint * lpConnectionPoint = NULL;
|
|
BOOL fInit = FALSE;
|
|
|
|
// Need to register for notifications even if running under Outlook
|
|
// Assume that relevant tests have occured before this is called ....
|
|
// if(bRegister && !bAreWABAPIProfileAware(lpIAB))
|
|
// goto out;
|
|
|
|
if( (!bRegister && !lpIAB->lpWABIDCN) ||
|
|
(bRegister && lpIAB->lpWABIDCN) )
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = InitUserIdentityManager(lpIAB, &lpUserIdentityManager)))
|
|
goto out;
|
|
|
|
fInit = TRUE;
|
|
|
|
Assert(lpUserIdentityManager);
|
|
|
|
if(HR_FAILED(hr = lpUserIdentityManager->lpVtbl->QueryInterface(lpUserIdentityManager,
|
|
&IID_IConnectionPoint,
|
|
(LPVOID *)&lpConnectionPoint)))
|
|
goto out;
|
|
|
|
if(bRegister)
|
|
{
|
|
if(lpIAB->lpWABIDCN)
|
|
{
|
|
lpIAB->lpWABIDCN->lpVtbl->Release(lpIAB->lpWABIDCN);
|
|
lpIAB->lpWABIDCN = NULL;
|
|
}
|
|
|
|
if(HR_FAILED(hr = HrCreateIdentityChangeNotifyObject(lpIAB, &lpIAB->lpWABIDCN)))
|
|
goto out;
|
|
|
|
if(HR_FAILED(hr = lpConnectionPoint->lpVtbl->Advise(lpConnectionPoint, (LPUNKNOWN) lpIAB->lpWABIDCN, &lpIAB->dwWABIDCN)))
|
|
goto out;
|
|
}
|
|
else
|
|
{
|
|
if(lpIAB->lpWABIDCN)
|
|
{
|
|
if(HR_FAILED(hr = lpConnectionPoint->lpVtbl->Unadvise(lpConnectionPoint, lpIAB->dwWABIDCN)))
|
|
goto out;
|
|
lpIAB->dwWABIDCN = 0;
|
|
lpIAB->lpWABIDCN->lpVtbl->Release(lpIAB->lpWABIDCN);
|
|
lpIAB->lpWABIDCN = NULL;
|
|
}
|
|
}
|
|
out:
|
|
if(fInit)
|
|
UninitUserIdentityManager(lpIAB);
|
|
|
|
if(lpConnectionPoint)
|
|
lpConnectionPoint->lpVtbl->Release(lpConnectionPoint);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------------------------------*/
|
|
|
|
WAB_IDENTITYCHANGENOTIFY_Vtbl vtblWABIDENTITYCHANGENOTIFY = {
|
|
VTABLE_FILL
|
|
WAB_IDENTITYCHANGENOTIFY_QueryInterface,
|
|
WAB_IDENTITYCHANGENOTIFY_AddRef,
|
|
WAB_IDENTITYCHANGENOTIFY_Release,
|
|
WAB_IDENTITYCHANGENOTIFY_QuerySwitchIdentities,
|
|
WAB_IDENTITYCHANGENOTIFY_SwitchIdentities,
|
|
WAB_IDENTITYCHANGENOTIFY_IdentityInformationChanged
|
|
};
|
|
|
|
/*
|
|
- HrCreateIdentityChangeNotifyObject
|
|
-
|
|
* The ChangeNotificationObject is created only on the LPIAB object and on the
|
|
* main browse window. Depending on where it's called from, we will pass in either the
|
|
* lpIAB pointer or the hWnd of the Window.
|
|
* THen when we get the callback notification, we can figure out what we want to do
|
|
* based on which of the 2 are available to us ..
|
|
*
|
|
*/
|
|
HRESULT HrCreateIdentityChangeNotifyObject(LPIAB lpIAB, LPWABIDENTITYCHANGENOTIFY * lppWABIDCN)
|
|
{
|
|
LPWABIDENTITYCHANGENOTIFY lpIWABIDCN = NULL;
|
|
SCODE sc;
|
|
HRESULT hr = hrSuccess;
|
|
|
|
//
|
|
// Allocate space for the IAB structure
|
|
//
|
|
if (FAILED(sc = MAPIAllocateBuffer(sizeof(WABIDENTITYCHANGENOTIFY), (LPVOID *) &lpIWABIDCN)))
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto err;
|
|
}
|
|
|
|
MAPISetBufferName(lpIWABIDCN, TEXT("WAB IdentityChangeNotify Object"));
|
|
|
|
ZeroMemory(lpIWABIDCN, sizeof(WABIDENTITYCHANGENOTIFY));
|
|
|
|
lpIWABIDCN->lpVtbl = &vtblWABIDENTITYCHANGENOTIFY;
|
|
|
|
lpIWABIDCN->lpIAB = lpIAB;
|
|
|
|
lpIWABIDCN->lpVtbl->AddRef(lpIWABIDCN);
|
|
|
|
*lppWABIDCN = lpIWABIDCN;
|
|
|
|
return(hrSuccess);
|
|
|
|
err:
|
|
|
|
FreeBufferAndNull(&lpIWABIDCN);
|
|
return(hr);
|
|
}
|
|
|
|
void ReleaseWABIdentityChangeNotifyObj(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN)
|
|
{
|
|
MAPIFreeBuffer(lpIWABIDCN);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
WAB_IDENTITYCHANGENOTIFY_AddRef(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN)
|
|
{
|
|
return(++(lpIWABIDCN->lcInit));
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
WAB_IDENTITYCHANGENOTIFY_Release(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN)
|
|
{
|
|
ULONG ulc = (--(lpIWABIDCN->lcInit));
|
|
if(ulc==0)
|
|
ReleaseWABIdentityChangeNotifyObj(lpIWABIDCN);
|
|
return(ulc);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
WAB_IDENTITYCHANGENOTIFY_QueryInterface(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN,
|
|
REFIID lpiid,
|
|
LPVOID * lppNewObj)
|
|
{
|
|
LPVOID lp = NULL;
|
|
|
|
if(!lppNewObj)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
*lppNewObj = NULL;
|
|
|
|
if(IsEqualIID(lpiid, &IID_IUnknown))
|
|
lp = (LPVOID) lpIWABIDCN;
|
|
|
|
if(IsEqualIID(lpiid, &IID_IIdentityChangeNotify))
|
|
lp = (LPVOID) lpIWABIDCN;
|
|
|
|
if(!lp)
|
|
return E_NOINTERFACE;
|
|
|
|
((LPWABIDENTITYCHANGENOTIFY) lp)->lpVtbl->AddRef((LPWABIDENTITYCHANGENOTIFY) lp);
|
|
|
|
*lppNewObj = lp;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
WAB_IDENTITYCHANGENOTIFY_QuerySwitchIdentities(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DebugTrace( TEXT("WAB: IDChangeNotify::QuerySwitchIdentities: 0x%.8x\n"), GetCurrentThreadId());
|
|
if(lpIWABIDCN->lpIAB->hWndBrowse)
|
|
{
|
|
// if this relates to a window, then just make sure that the window is not deactivated
|
|
// because that would imply that the window has a dialog in front of it.
|
|
if (!IsWindowEnabled(lpIWABIDCN->lpIAB->hWndBrowse))
|
|
{
|
|
Assert(IsWindowVisible(lpIWABIDCN->lpIAB->hWndBrowse));
|
|
return E_PROCESS_CANCELLED_SWITCH;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// MAJOR HACK WARNING
|
|
// [PaulHi] 12/22/98 See comment below. We need to disable the "close WAB window
|
|
// on identity switch for when the client is OE5. We don't want to change this code
|
|
// at this point for other clients. I copied the OE5 PSExt GUID from the OE5 code
|
|
// base.
|
|
static const GUID OEBAControl_GUID =
|
|
{ 0x233a9694, 0x667e, 0x11d1, { 0x9d, 0xfb, 0x00, 0x60, 0x97, 0xd5, 0x04, 0x08 } };
|
|
|
|
|
|
STDMETHODIMP
|
|
WAB_IDENTITYCHANGENOTIFY_SwitchIdentities(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DebugTrace( TEXT("WAB: IDChangeNotify::SwitchIdentities: 0x%.8x\n"), GetCurrentThreadId());
|
|
|
|
if(memcmp(&lpIWABIDCN->lpIAB->guidPSExt, &MPSWab_GUID_V4, sizeof(GUID)) ) //if not a wab.exe process .. shutdown
|
|
{
|
|
// [PaulHi] 12/22/98 Raid #63231, 48054
|
|
// Don't close the WAB window here when OE is the host. OE needs to shut
|
|
// down the WAB in the correct order during identity switches or serious problems occur.
|
|
if ( memcmp(&lpIWABIDCN->lpIAB->guidPSExt, &OEBAControl_GUID , sizeof(GUID)) != 0 )
|
|
SendMessage(lpIWABIDCN->lpIAB->hWndBrowse, WM_CLOSE, 0, 0);
|
|
return S_OK;
|
|
}
|
|
if(!HR_FAILED(HrLogonAndGetCurrentUserProfile(NULL, lpIWABIDCN->lpIAB, FALSE, TRUE)))
|
|
HrGetWABProfiles(lpIWABIDCN->lpIAB);
|
|
else //they did a logoff
|
|
{
|
|
SendMessage(lpIWABIDCN->lpIAB->hWndBrowse, WM_CLOSE, 0, 0);
|
|
return S_OK;
|
|
}
|
|
|
|
if(lpIWABIDCN->lpIAB->hWndBrowse) //hWndBrowse could be any window (main or find)
|
|
SendMessage(lpIWABIDCN->lpIAB->hWndBrowse, WM_COMMAND, (WPARAM) IDM_NOTIFY_REFRESHUSER, 0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
WAB_IDENTITYCHANGENOTIFY_IdentityInformationChanged(LPWABIDENTITYCHANGENOTIFY lpIWABIDCN, DWORD dwType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DebugTrace( TEXT("WAB: IDChangeNotify::IdentityInformationChanged: %d 0x%.8x\n"), dwType, GetCurrentThreadId());
|
|
if(dwType == IIC_CURRENT_IDENTITY_CHANGED)
|
|
{
|
|
// only thing we care about is a change in the name
|
|
if(!HR_FAILED(HrGetIdentityName(lpIWABIDCN->lpIAB, NULL, lpIWABIDCN->lpIAB->szProfileName, ARRAYSIZE(lpIWABIDCN->lpIAB->szProfileName))))
|
|
{
|
|
UpdateCurrentUserFolderName(lpIWABIDCN->lpIAB);
|
|
if(lpIWABIDCN->lpIAB->hWndBrowse)
|
|
SendMessage(lpIWABIDCN->lpIAB->hWndBrowse, WM_COMMAND, (WPARAM) IDM_NOTIFY_REFRESHUSER, 0);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|