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.
2651 lines
102 KiB
2651 lines
102 KiB
/*--------------------------------------------------------------
|
|
*
|
|
*
|
|
* ui_addr.c - contains stuff for showing the :Address UI
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
--------------------------------------------------------------*/
|
|
#include "_apipch.h"
|
|
|
|
extern HINSTANCE ghCommCtrlDLLInst;
|
|
|
|
#define SET_UNICODE_STR(lp1,lp2,lpAdrParms) if(lpAdrParms->ulFlags & MAPI_UNICODE)\
|
|
lp1 = (LPWSTR)lp2; \
|
|
else \
|
|
lp1 = ConvertAtoW((LPSTR)lp2); \
|
|
|
|
#define FREE_UNICODE_STR(lp1,lp2) if(lp1 != lp2) LocalFreeAndNull(&lp1);
|
|
|
|
typedef struct _AddressParms
|
|
{
|
|
LPADRBOOK lpIAB; //Stores a pointer to the ADRBOOK object
|
|
LPADRPARM lpAdrParms; //AdrParms structure passed into Address
|
|
LPADRLIST *lppAdrList; //AdrList of input names
|
|
HANDLE hPropertyStore; //pointer to the property store
|
|
int DialogState; //Identifies the ongoing function
|
|
LPRECIPIENT_INFO lpContentsList;//Contains a list of entries in the contents structure
|
|
LPRECIPIENT_INFO lpListTo; //Entries in the To Well
|
|
LPRECIPIENT_INFO lpListCC; //Entries in the CC well
|
|
LPRECIPIENT_INFO lpListBCC; //Entries in the BCC well
|
|
SORT_INFO SortInfo; //Contains current sort info
|
|
int nContextID; //identifies which list view called the context menu
|
|
BOOL bDontRefresh; //Used to ensure that nothing refreshes during modal operations
|
|
BOOL bLDAPinProgress;
|
|
HCURSOR hWaitCur;
|
|
int nRetVal;
|
|
LPMAPIADVISESINK lpAdviseSink;
|
|
ULONG ulAdviseConnection;
|
|
BOOL bDeferNotification; // Used to defer next notification request
|
|
HWND hDlg;
|
|
HWND hWndAddr;
|
|
} ADDRESS_PARMS, *LPADDRESS_PARMS;
|
|
|
|
|
|
enum _lppAdrListReturnedProps
|
|
{
|
|
propPR_DISPLAY_NAME,
|
|
propPR_ENTRYID,
|
|
propPR_RECIPIENT_TYPE,
|
|
TOTAL_ADRLIST_PROPS
|
|
};
|
|
|
|
|
|
static DWORD rgAddrHelpIDs[] =
|
|
{
|
|
IDC_ADDRBK_EDIT_QUICKFIND, IDH_WAB_PICK_RECIP_TYPE_NAME,
|
|
IDC_ADDRBK_STATIC_CONTENTS, IDH_WAB_PICK_RECIP_NAME_LIST,
|
|
IDC_ADDRBK_LIST_ADDRESSES, IDH_WAB_PICK_RECIP_NAME_LIST,
|
|
IDC_ADDRBK_BUTTON_PROPS, IDH_WAB_PICK_RECIP_NAME_PROPERTIES,
|
|
IDC_ADDRBK_BUTTON_NEW, IDH_WAB_PICK_RECIP_NAME_NEW,
|
|
IDC_ADDRBK_BUTTON_TO, IDH_WAB_PICK_RECIP_NAME_TO_BUTTON,
|
|
IDC_ADDRBK_BUTTON_CC, IDH_WAB_PICK_RECIP_NAME_CC_BUTTON,
|
|
IDC_ADDRBK_BUTTON_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_BUTTON,
|
|
IDC_ADDRBK_LIST_TO, IDH_WAB_PICK_RECIP_NAME_TO_LIST,
|
|
IDC_ADDRBK_LIST_CC, IDH_WAB_PICK_RECIP_NAME_CC_LIST,
|
|
IDC_ADDRBK_LIST_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_LIST,
|
|
IDC_ADDRBK_BUTTON_DELETE, IDH_WAB_PICK_RECIP_NAME_DELETE,
|
|
IDC_ADDRBK_BUTTON_NEWGROUP, IDH_WAB_PICK_RECIP_NAME_NEW_GROUP,
|
|
IDC_ADDRBK_STATIC_RECIP_TITLE, IDH_WAB_COMM_GROUPBOX,
|
|
IDC_ADDRBK_BUTTON_FIND, IDH_WAB_PICK_RECIP_NAME_FIND,
|
|
IDC_ADDRBK_COMBO_CONT, IDH_WAB_GROUPS_CONTACTS_FOLDER,
|
|
0,0
|
|
};
|
|
|
|
// forward declarations
|
|
|
|
INT_PTR CALLBACK fnAddress(HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam);
|
|
|
|
|
|
BOOL SetAddressBookUI(HWND hDlg,
|
|
LPADDRESS_PARMS lpAP);
|
|
|
|
void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP);
|
|
|
|
BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC);
|
|
|
|
BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList);
|
|
|
|
BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType);
|
|
|
|
void UpdateLVItems(HWND hWndLV,LPTSTR lpszName);
|
|
|
|
void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr, LPADDRESS_PARMS lpAP, LPFILETIME lpftLast);
|
|
|
|
HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB,
|
|
LPENTRYID lpEntryID,
|
|
ULONG cbEntryID,
|
|
ULONG ulFlags,
|
|
LPADRLIST * lppAdrList);
|
|
|
|
enum _AddressDialogReturnValues
|
|
{
|
|
ADDRESS_RESET = 0, //Blank initialization value
|
|
ADDRESS_CANCEL,
|
|
ADDRESS_OK,
|
|
};
|
|
|
|
|
|
//$$/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FillContainerCombo - Fills the container combo with container names
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
void FillContainerCombo(HWND hWndCombo, LPIAB lpIAB)
|
|
{
|
|
ULONG iolkci, colkci;
|
|
OlkContInfo *rgolkci;
|
|
int nPos, nDefault=0;
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
|
|
// Clear out the combo
|
|
SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0);
|
|
|
|
Assert(lpIAB);
|
|
|
|
EnterCriticalSection(&lpIAB->cs);
|
|
if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware(lpIAB))
|
|
{
|
|
colkci = pt_bIsWABOpenExSession ? lpIAB->lpPropertyStore->colkci : lpIAB->cwabci;
|
|
Assert(colkci);
|
|
rgolkci = lpIAB->lpPropertyStore->colkci ? lpIAB->lpPropertyStore->rgolkci : lpIAB->rgwabci;
|
|
Assert(rgolkci);
|
|
|
|
// Add the multiple folders here
|
|
for(iolkci = 0; iolkci < colkci; iolkci++)
|
|
{
|
|
nPos = (int) SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) rgolkci[iolkci].lpszName);
|
|
if(nPos != CB_ERR)
|
|
SendMessage(hWndCombo, CB_SETITEMDATA, (WPARAM)nPos, (LPARAM) (DWORD_PTR)(iolkci==0 ? NULL : rgolkci[iolkci].lpEntryID));
|
|
if( bIsThereACurrentUser(lpIAB) &&
|
|
!lstrcmpi(lpIAB->lpWABCurrentUserFolder->lpFolderName, rgolkci[iolkci].lpszName) &&//folder names are unique
|
|
nPos != CB_ERR)
|
|
{
|
|
nDefault = nPos;
|
|
}
|
|
}
|
|
}
|
|
LeaveCriticalSection(&lpIAB->cs);
|
|
SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nDefault, 0);
|
|
}
|
|
|
|
|
|
|
|
//$$*------------------------------------------------------------------------
|
|
//| IAddrBook::Advise::OnNotify handler
|
|
//|
|
|
//*------------------------------------------------------------------------
|
|
ULONG AddrAdviseOnNotify(LPVOID lpvContext, ULONG cNotif, LPNOTIFICATION lpNotif)
|
|
{
|
|
LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS) lpvContext;
|
|
|
|
DebugTrace( TEXT("+++ AddrAdviseOnNotify ===\n"));
|
|
|
|
if(lpAP->bDeferNotification)
|
|
{
|
|
DebugTrace( TEXT("+++ Advise Defered ===\n"));
|
|
lpAP->bDeferNotification = FALSE;
|
|
return S_OK;
|
|
}
|
|
if(!lpAP->bDontRefresh)
|
|
{
|
|
DebugTrace( TEXT("+++ Calling FillListFromCurrentContainer ===\n"));
|
|
FillListFromCurrentContainer(lpAP->hDlg, lpAP);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ShowAddressUI - does some parameter checking and calls the PropertySheets
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT HrShowAddressUI(IN LPADRBOOK lpIAB,
|
|
IN HANDLE hPropertyStore,
|
|
IN ULONG_PTR * lpulUIParam,
|
|
IN LPADRPARM lpAdrParms,
|
|
IN LPADRLIST *lppAdrList)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
//ADDRESS_PARMS AP = {0};
|
|
LPADDRESS_PARMS lpAP = NULL;
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
|
|
HWND hWndParent = NULL;
|
|
int nRetVal = 0;
|
|
int DialogState = 0;
|
|
|
|
//Addref the AdrBook object to make sure it stays valid throughout ..
|
|
// Remember to release before leaving ...
|
|
// NOTE: Must be before any jumps to out!
|
|
UlAddRef(lpIAB);
|
|
|
|
// if no common control, exit
|
|
if (NULL == ghCommCtrlDLLInst) {
|
|
hr = ResultFromScode(MAPI_E_UNCONFIGURED);
|
|
goto out;
|
|
}
|
|
|
|
if (lpulUIParam)
|
|
hWndParent = (HWND) *lpulUIParam;
|
|
|
|
if ( // Can't pick-user with wells
|
|
((lpAdrParms->ulFlags & ADDRESS_ONE) && (lpAdrParms->cDestFields != 0)) ||
|
|
// cDestFields has limited for tier 0.5
|
|
(lpAdrParms->cDestFields > 3) ||
|
|
// Cant pick user without an input lpAdrList
|
|
//((lpAdrParms->ulFlags & ADDRESS_ONE) && (*lppAdrList == NULL)) ||
|
|
((lpAdrParms->ulFlags & DIALOG_SDI) && (lpAdrParms->cDestFields != 0)) )
|
|
{
|
|
hr = MAPI_E_INVALID_PARAMETER;
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// The possible states of this dialog box are
|
|
// 1. Select recipients Wells shown, returns an AdrList of picked up entries, Cant delete entries
|
|
// 2. Select a single user, No wells shown, single selection, cannot delete, must have input Adrlist
|
|
// 3. Open for browsing only, multiple selection, can create delete, create, view details
|
|
|
|
// Determine what the dialog state is
|
|
if (lpAdrParms->cDestFields > 0)
|
|
{
|
|
//lpAP->DialogState = STATE_SELECT_RECIPIENTS;
|
|
DialogState = STATE_SELECT_RECIPIENTS;
|
|
}
|
|
else if (lpAdrParms->ulFlags & ADDRESS_ONE)
|
|
{
|
|
DialogState = STATE_PICK_USER;
|
|
}
|
|
else if (lpAdrParms->ulFlags & DIALOG_MODAL)
|
|
{
|
|
DialogState = STATE_BROWSE_MODAL;
|
|
}
|
|
else if (lpAdrParms->ulFlags & DIALOG_SDI)
|
|
{
|
|
DialogState = STATE_BROWSE;
|
|
}
|
|
|
|
|
|
if (DialogState == STATE_BROWSE)
|
|
{
|
|
// Show the browse window and leave
|
|
//
|
|
HWND hWndAB = NULL;
|
|
hWndAB = hCreateAddressBookWindow( lpIAB,
|
|
hWndParent,
|
|
lpAdrParms);
|
|
if (hWndAB)
|
|
{
|
|
*lpulUIParam = (ULONG_PTR) hWndAB;
|
|
hr = S_OK;
|
|
}
|
|
goto out;
|
|
|
|
}
|
|
|
|
lpAP = LocalAlloc(LMEM_ZEROINIT, sizeof(ADDRESS_PARMS));
|
|
|
|
if (!lpAP)
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
lpAP->DialogState = DialogState;
|
|
|
|
|
|
lpAP->lpIAB = lpIAB;
|
|
lpAP->lpAdrParms = lpAdrParms;
|
|
lpAP->lppAdrList = lppAdrList;
|
|
lpAP->hPropertyStore = hPropertyStore;
|
|
|
|
ReadRegistrySortInfo((LPIAB)lpIAB, &(lpAP->SortInfo));
|
|
|
|
lpAP->lpContentsList = NULL;
|
|
|
|
lpAP->bDontRefresh = FALSE;
|
|
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
lpAP->hWaitCur = NULL;
|
|
|
|
HrAllocAdviseSink(&AddrAdviseOnNotify, (LPVOID) lpAP, &(lpAP->lpAdviseSink));
|
|
|
|
nRetVal = (int) DialogBoxParam( hinstMapiX,
|
|
MAKEINTRESOURCE(IDD_DIALOG_ADDRESSBOOK),
|
|
hWndParent,
|
|
fnAddress,
|
|
(LPARAM) lpAP);
|
|
switch(nRetVal)
|
|
{
|
|
case -1: //some error occured
|
|
hr = E_FAIL;
|
|
break;
|
|
case ADDRESS_CANCEL:
|
|
hr = MAPI_E_USER_CANCEL;
|
|
break;
|
|
case ADDRESS_OK:
|
|
default:
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
if(lpAP->lpAdviseSink)
|
|
{
|
|
lpAP->lpIAB->lpVtbl->Unadvise(lpAP->lpIAB, lpAP->ulAdviseConnection);
|
|
lpAP->lpAdviseSink->lpVtbl->Release(lpAP->lpAdviseSink);
|
|
lpAP->lpAdviseSink = NULL;
|
|
lpAP->ulAdviseConnection = 0;
|
|
}
|
|
|
|
out:
|
|
|
|
lpIAB->lpVtbl->Release(lpIAB);
|
|
|
|
LocalFreeAndNull(&lpAP);
|
|
return hr;
|
|
}
|
|
|
|
|
|
#define lpAP_lppContentsList (&(lpAP->lpContentsList))
|
|
#define lpAP_lppListTo (&(lpAP->lpListTo))
|
|
#define lpAP_lppListCC (&(lpAP->lpListCC))
|
|
#define lpAP_lppListBCC (&(lpAP->lpListBCC))
|
|
#define lpAP_bDontRefresh (lpAP->bDontRefresh)
|
|
#define _hWndAddr lpAP->hWndAddr
|
|
|
|
|
|
//$$/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetCurrentComboSelection - Get the current selection from the combo
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
LPSBinary GetCurrentComboSelection(HWND hWndCombo)
|
|
{
|
|
int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0);
|
|
LPSBinary lpsbCont = NULL;
|
|
|
|
if(nPos == CB_ERR)
|
|
nPos = 0;
|
|
lpsbCont = (LPSBinary) SendMessage(hWndCombo, CB_GETITEMDATA, (WPARAM) nPos, 0);
|
|
if(CB_ERR == (DWORD_PTR) lpsbCont)
|
|
lpsbCont = NULL;
|
|
|
|
return lpsbCont;
|
|
}
|
|
//$$/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FillListFromCurrentContainer - Get the selection from the combo and fill it
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP)
|
|
{
|
|
HWND hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES);
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
LPSBinary lpsbCont = NULL;
|
|
|
|
if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
|
|
{
|
|
HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
|
|
int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
if(nPos != CB_ERR)
|
|
{
|
|
// Refill the combo in case the folder list changed
|
|
FillContainerCombo(hWndCombo, (LPIAB)lpAP->lpIAB);
|
|
nPos = (int) SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nPos, 0);
|
|
}
|
|
lpsbCont = GetCurrentComboSelection(hWndCombo);
|
|
}
|
|
|
|
HrGetWABContents( hWndAddr,
|
|
lpAP->lpIAB, lpsbCont,
|
|
lpAP->SortInfo, lpAP_lppContentsList);
|
|
}
|
|
|
|
|
|
extern BOOL APIENTRY_16 fnFolderDlgProc(HWND hDlg, UINT message, UINT wParam, LPARAM lParam);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// fnAddress - the PropertySheet Message Handler
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR CALLBACK fnAddress(HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
static FILETIME ftLast = {0};
|
|
|
|
LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS ) GetWindowLongPtr(hDlg,DWLP_USER);
|
|
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetWindowLongPtr(hDlg,DWLP_USER,lParam); //Save this for future reference
|
|
lpAP = (LPADDRESS_PARMS) lParam;
|
|
|
|
lpAP->hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES);
|
|
lpAP->hDlg = hDlg;
|
|
lpAP_bDontRefresh = FALSE;
|
|
|
|
lpAP->nContextID = IDC_ADDRBK_LIST_ADDRESSES;
|
|
|
|
SetAddressBookUI(hDlg,lpAP);
|
|
|
|
// if this is a pick-user dialog, need to have the names by
|
|
// first name so we can find the closest match ..
|
|
if(lpAP->DialogState == STATE_PICK_USER)
|
|
(lpAP->SortInfo).bSortByLastName = FALSE;
|
|
|
|
|
|
FillListFromCurrentContainer(hDlg, lpAP);
|
|
|
|
|
|
if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
|
|
{
|
|
FillWells(hDlg,*(lpAP->lppAdrList),(lpAP->lpAdrParms),lpAP_lppListTo,lpAP_lppListCC,lpAP_lppListBCC);
|
|
|
|
// we want to highlight the first item in the list
|
|
if (ListView_GetItemCount(_hWndAddr) > 0)
|
|
LVSelectItem( _hWndAddr, 0);
|
|
}
|
|
else if (lpAP->DialogState == STATE_PICK_USER &&
|
|
*(lpAP->lppAdrList) )
|
|
{
|
|
// if this is a pick user dialog, then try to match the supplied name to the
|
|
// closest entry in the List Box
|
|
if (ListView_GetItemCount(_hWndAddr) > 0)
|
|
{
|
|
LPTSTR lpszDisplayName = NULL;
|
|
ULONG i;
|
|
|
|
// Scan only the first entry in the lpAdrList for a display name
|
|
for(i=0;i< (*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
|
|
{
|
|
ULONG ulPropTag = PR_DISPLAY_NAME;
|
|
if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
|
|
ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
|
|
if((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
|
|
{
|
|
SET_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lpszDisplayName)
|
|
{
|
|
// We have Something to search for
|
|
TCHAR szBuf[MAX_UI_STR];
|
|
ULONG nLen;
|
|
LV_FINDINFO lvF = {0};
|
|
|
|
// Typically, we are not going to get a full match ...
|
|
// Instead we want to make a partial match on disply name.
|
|
// The ListViewFindItem does an exact partial match if the supplied
|
|
// string matches the first few entries of an existing item
|
|
// Hence, to obtain a semi-partial match, we start with the
|
|
// original Display Name working our way backwards from last
|
|
// character to first character until we get a match or run
|
|
// out of characters.
|
|
|
|
int iItemIndex = -1;
|
|
nLen = lstrlen(lpszDisplayName);
|
|
|
|
if (nLen >= CharSizeOf(szBuf))
|
|
nLen = CharSizeOf(szBuf)-1;
|
|
lvF.flags = LVFI_PARTIAL | LVFI_STRING;
|
|
|
|
while((nLen > 0) && (iItemIndex == -1))
|
|
{
|
|
nLen = TruncatePos(lpszDisplayName, nLen);
|
|
if (nLen==0) break;
|
|
|
|
CopyMemory(szBuf, lpszDisplayName, sizeof(TCHAR)*nLen);
|
|
szBuf[nLen] = '\0';
|
|
|
|
lvF.psz = szBuf;
|
|
iItemIndex = ListView_FindItem(_hWndAddr,-1, &lvF);
|
|
|
|
nLen--;
|
|
}
|
|
|
|
// Set focus to the selected item or to the first item in the list
|
|
|
|
if (iItemIndex < 0) iItemIndex = 0;
|
|
|
|
LVSelectItem(_hWndAddr, iItemIndex);
|
|
|
|
FREE_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(lpAP->lpAdviseSink)
|
|
{
|
|
// Register for notifications
|
|
lpAP->lpIAB->lpVtbl->Advise(lpAP->lpIAB, 0, NULL, fnevObjectModified,
|
|
lpAP->lpAdviseSink, &lpAP->ulAdviseConnection);
|
|
}
|
|
|
|
if (ListView_GetSelectedCount(_hWndAddr) <= 0)
|
|
LVSelectItem(_hWndAddr, 0);
|
|
|
|
// if we want the user to pick something actively, we disable OK until they click on something
|
|
// or do something specific ..
|
|
if( lpAP->DialogState == STATE_PICK_USER )
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
|
|
SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
|
|
}
|
|
|
|
SetFocus(GetDlgItem(hDlg,IDC_ADDRBK_EDIT_QUICKFIND));
|
|
return FALSE;
|
|
// return TRUE;
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
//Forward any system changes to the list view
|
|
SendMessage(_hWndAddr, message, wParam, lParam);
|
|
SetColumnHeaderBmp(_hWndAddr, lpAP->SortInfo);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
|
|
g_szWABHelpFileName,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPSTR) rgAddrHelpIDs );
|
|
break;
|
|
|
|
case WM_SETCURSOR:
|
|
if (lpAP->bLDAPinProgress)
|
|
{
|
|
SetCursor(lpAP->hWaitCur);
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0));
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(GET_WM_COMMAND_CMD(wParam,lParam)) //check the notification code
|
|
{
|
|
case CBN_SELCHANGE:
|
|
FillListFromCurrentContainer(hDlg, lpAP);
|
|
break;
|
|
}
|
|
switch(GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
default:
|
|
if (lpAP->nContextID != -1)
|
|
{
|
|
LRESULT fRet = FALSE;
|
|
lpAP_bDontRefresh = TRUE;
|
|
fRet = ProcessActionCommands((LPIAB) lpAP->lpIAB,_hWndAddr,
|
|
hDlg, message, wParam, lParam);
|
|
lpAP_bDontRefresh = FALSE;
|
|
return fRet;
|
|
}
|
|
break;
|
|
|
|
|
|
case IDC_ADDRBK_BUTTON_DELETE:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
lpAP_bDontRefresh = TRUE;
|
|
DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast);
|
|
lpAP->bDeferNotification = TRUE;
|
|
lpAP_bDontRefresh = FALSE;
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_DELETE:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
switch(lpAP->nContextID)
|
|
{
|
|
case IDC_ADDRBK_LIST_ADDRESSES:
|
|
lpAP_bDontRefresh = TRUE;
|
|
DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast);
|
|
lpAP->bDeferNotification = TRUE;
|
|
lpAP_bDontRefresh = FALSE;
|
|
break;
|
|
case IDC_ADDRBK_LIST_TO:
|
|
ListDeleteItem(hDlg, IDC_ADDRBK_LIST_TO, lpAP_lppListTo);
|
|
break;
|
|
case IDC_ADDRBK_LIST_CC:
|
|
ListDeleteItem(hDlg, IDC_ADDRBK_LIST_CC, lpAP_lppListCC);
|
|
break;
|
|
case IDC_ADDRBK_LIST_BCC:
|
|
ListDeleteItem(hDlg, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_COPY:
|
|
lpAP_bDontRefresh = TRUE;
|
|
HrCopyItemDataToClipboard(hDlg, lpAP->lpIAB, GetDlgItem(hDlg,lpAP->nContextID));
|
|
lpAP_bDontRefresh = FALSE;
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_PROPERTIES:
|
|
case IDC_ADDRBK_BUTTON_PROPS:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
if (lpAP->nContextID != -1)
|
|
{
|
|
lpAP_bDontRefresh = TRUE;
|
|
ShowAddrBkLVProps((LPIAB)lpAP->lpIAB, hDlg, GetDlgItem(hDlg, lpAP->nContextID), lpAP, &ftLast);
|
|
lpAP->bDeferNotification = TRUE;
|
|
lpAP_bDontRefresh = FALSE;
|
|
}
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
/* Uncomment to enable NEW_FOLDER functionality from this dialog
|
|
|
|
case IDM_LVCONTEXT_NEWFOLDER:
|
|
{
|
|
TCHAR sz[MAX_UI_STR];
|
|
LPTSTR lpsz = NULL;
|
|
*sz = '\0';
|
|
if( IDCANCEL != DialogBoxParam( hinstMapiX, MAKEINTRESOURCE(IDD_DIALOG_FOLDER),
|
|
hDlg, fnFolderDlgProc, (LPARAM) sz)
|
|
&& lstrlen(sz))
|
|
{
|
|
// if we're here we have a valid folder name ..
|
|
if(!HR_FAILED(HrCreateNewFolder((LPIAB)lpAP->lpIAB, sz, NULL, FALSE, NULL, NULL)))
|
|
{
|
|
int i,nTotal;
|
|
HWND hWndC = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
|
|
// Fill in the Combo with the container names
|
|
FillContainerCombo(hWndC, (LPIAB)lpAP->lpIAB);
|
|
nTotal = SendMessage(hWndC, CB_GETCOUNT, 0, 0);
|
|
if(nTotal != CB_ERR)
|
|
{
|
|
// Find the item we just added in the combo and set the sel on it
|
|
TCHAR szC[MAX_UI_STR];
|
|
for(i=0;i<nTotal;i++)
|
|
{
|
|
*szC = '\0';
|
|
SendMessage(hWndC, CB_GETLBTEXT, (WPARAM) i, (LPARAM) szC);
|
|
if(!lstrcmpi(sz, szC))
|
|
{
|
|
SendMessage(hWndC, CB_SETCURSEL, (WPARAM) i, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FillListFromCurrentContainer(hDlg, lpAP);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
*/
|
|
|
|
case IDM_LVCONTEXT_NEWCONTACT:
|
|
case IDC_ADDRBK_BUTTON_NEW:
|
|
// only difference between contact and group is the object being added
|
|
case IDM_LVCONTEXT_NEWGROUP:
|
|
case IDC_ADDRBK_BUTTON_NEWGROUP:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
ULONG cbEID = 0;
|
|
LPENTRYID lpEID = NULL;
|
|
int nID = GET_WM_COMMAND_ID(wParam, lParam);
|
|
ULONG ulObjType = (nID == IDM_LVCONTEXT_NEWCONTACT || nID == IDC_ADDRBK_BUTTON_NEW) ? MAPI_MAILUSER : MAPI_DISTLIST;
|
|
LPSBinary lpsbContEID = NULL;
|
|
|
|
if(bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
|
|
lpsbContEID = GetCurrentComboSelection(GetDlgItem(hDlg,IDC_ADDRBK_COMBO_CONT));
|
|
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
lpAP_bDontRefresh = TRUE;
|
|
|
|
AddNewObjectToListViewEx( lpAP->lpIAB, _hWndAddr, NULL, NULL,
|
|
lpsbContEID,
|
|
ulObjType,
|
|
&(lpAP->SortInfo), lpAP_lppContentsList, &ftLast, &cbEID, &lpEID);
|
|
|
|
FreeBufferAndNull(&lpEID);
|
|
SetFocus(_hWndAddr);
|
|
lpAP->bDeferNotification = TRUE;
|
|
lpAP_bDontRefresh = FALSE;
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
|
|
case IDM_LVCONTEXT_ADDWELL1:
|
|
case IDC_ADDRBK_BUTTON_TO:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
ULONG ulMapiTo = MAPI_TO;
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
|
|
{
|
|
ulMapiTo = lpAP->lpAdrParms->lpulDestComps[0];
|
|
}
|
|
if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_TO, lpAP_lppListTo, ulMapiTo))
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_ADDWELL2:
|
|
case IDC_ADDRBK_BUTTON_CC:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
ULONG ulMapiCC = MAPI_CC;
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
|
|
{
|
|
ulMapiCC = lpAP->lpAdrParms->lpulDestComps[1];
|
|
}
|
|
if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_CC, lpAP_lppListCC, ulMapiCC))
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_ADDWELL3:
|
|
case IDC_ADDRBK_BUTTON_BCC:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
ULONG ulMapiBCC = MAPI_BCC;
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
|
|
{
|
|
ulMapiBCC = lpAP->lpAdrParms->lpulDestComps[2];
|
|
}
|
|
if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC, ulMapiBCC))
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDM_LVCONTEXT_FIND:
|
|
case IDC_ADDRBK_BUTTON_FIND:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
ADRPARM_FINDINFO apfi = {0};
|
|
LPADRPARM_FINDINFO lpapfi = NULL;
|
|
ULONG ulOldFlags = lpAP->lpAdrParms->ulFlags;
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
|
|
apfi.DialogState = lpAP->DialogState;
|
|
|
|
if (lpAP->DialogState==STATE_SELECT_RECIPIENTS)
|
|
{
|
|
apfi.lpAdrParms = lpAP->lpAdrParms;
|
|
apfi.lppTo = lpAP_lppListTo;
|
|
apfi.lppCC = lpAP_lppListCC;
|
|
apfi.lppBCC = lpAP_lppListBCC;
|
|
lpapfi = &apfi;
|
|
}
|
|
else if (lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
TCHAR sz[MAX_UI_STR];
|
|
LPTSTR lpsz = NULL;
|
|
|
|
LoadString(hinstMapiX, idsPickUserSelect, sz, CharSizeOf(sz));
|
|
lpsz = (LPTSTR) sz;
|
|
|
|
apfi.lpAdrParms = lpAP->lpAdrParms;
|
|
apfi.lpAdrParms->cDestFields = 1;
|
|
apfi.lpAdrParms->lppszDestTitles = &lpsz; // <TBD> use resource
|
|
apfi.lpAdrParms->ulFlags |= MAPI_UNICODE;
|
|
apfi.cbEntryID = 0;
|
|
apfi.lpEntryID = NULL;
|
|
apfi.nRetVal = 0;
|
|
lpapfi = &apfi;
|
|
{
|
|
// Setup the Find persistent info to show the name we are trying to resolve
|
|
ULONG i;
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
for(i=0;i<ldspMAX;i++)
|
|
{
|
|
pt_LDAPsp.szData[i][0] = TEXT('\0');
|
|
}
|
|
if(*(lpAP->lppAdrList))
|
|
{
|
|
for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
|
|
{
|
|
ULONG ulPropTag = PR_DISPLAY_NAME;
|
|
if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
|
|
ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
|
|
if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
|
|
{
|
|
LPTSTR lpTitle = NULL;
|
|
SET_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
|
|
StrCpyN(pt_LDAPsp.szData[ldspDisplayName], lpTitle, ARRAYSIZE(pt_LDAPsp.szData[ldspDisplayName]));
|
|
FREE_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//lpAP_bDontRefresh = TRUE;
|
|
HrShowSearchDialog(lpAP->lpIAB,
|
|
hDlg,
|
|
lpapfi,
|
|
(LPLDAPURL) NULL,
|
|
&(lpAP->SortInfo));
|
|
|
|
//lpAP_bDontRefresh = FALSE;
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
|
|
// reset
|
|
lpAP->lpAdrParms->ulFlags = ulOldFlags;
|
|
|
|
if (lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
// Reset these fake values
|
|
lpAP->lpAdrParms->cDestFields = 0;
|
|
lpAP->lpAdrParms->lppszDestTitles = NULL; // <TBD> use resource
|
|
|
|
// If the above dialog was CANCELed or CLOSEd, we dont do anything
|
|
// If the above dialog was closed with the Use button, then we basically
|
|
// have the person we were looking for .. we will just return that name
|
|
// and EntryID because that is all we need to return
|
|
if((lpapfi->nRetVal == SEARCH_USE) &&
|
|
lpapfi->lpEntryID &&
|
|
lpapfi->cbEntryID)
|
|
{
|
|
HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
// Prevent the user from doing anything on this window ..
|
|
EnableWindow(hDlg, FALSE);
|
|
|
|
// Figure out what to do here ...
|
|
// We could add a hidden item to the listview, select it and send
|
|
// an ok message to the dialog which would then do the needful.
|
|
if(HR_FAILED(HrUpdateAdrListEntry(
|
|
lpAP->lpIAB,
|
|
lpapfi->lpEntryID,
|
|
lpapfi->cbEntryID,
|
|
(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0,
|
|
lpAP->lppAdrList)))
|
|
{
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
else
|
|
{
|
|
lpAP->nRetVal = ADDRESS_OK;
|
|
}
|
|
LocalFreeAndNull(&(lpapfi->lpEntryID));
|
|
lpapfi->cbEntryID = 0;
|
|
// Since we've done our processing, we'll fall thru to
|
|
// the cancel dialog
|
|
SetCursor(hOldCur);
|
|
SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case IDC_ADDRBK_EDIT_QUICKFIND:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
switch(HIWORD(wParam)) //check the notification code
|
|
{
|
|
case EN_CHANGE: //edit box changed
|
|
/***/
|
|
DoLVQuickFind((HWND)lParam,_hWndAddr);
|
|
/***
|
|
DoLVQuickFilter(lpAP->lpIAB,
|
|
(HWND)lParam,
|
|
_hWndAddr,
|
|
&(lpAP->SortInfo),
|
|
AB_FUZZY_FIND_NAME | AB_FUZZY_FIND_EMAIL,
|
|
1,
|
|
lpAP_lppContentsList);
|
|
***/
|
|
break;
|
|
}
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDC_ADDRBK_BUTTON_OK:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
HCURSOR hOldCur;
|
|
|
|
lpAP->nRetVal = ADDRESS_OK;
|
|
|
|
lpAP->hWaitCur = LoadCursor(NULL, IDC_WAIT);
|
|
hOldCur = SetCursor(lpAP->hWaitCur);
|
|
lpAP->bLDAPinProgress = TRUE;
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0));
|
|
|
|
//ShowWindow(hDlg, SW_HIDE);
|
|
|
|
//EnableWindow(hDlg, FALSE);
|
|
//SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_FIND), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), FALSE);
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), FALSE);
|
|
EnableWindow(_hWndAddr, FALSE);
|
|
|
|
//
|
|
// Do TEXT("OK") stuff here and then Fall Thru to the cancel stuff
|
|
// in PSN_RESET where we clean up
|
|
//
|
|
|
|
// if the ADDRESS_ONE flag was set we're supposed to return the
|
|
// selected entry
|
|
//
|
|
// else if wells were displayed we return the recipients in the AdrList
|
|
//
|
|
// else we dont change the AdrList ..
|
|
//
|
|
|
|
if (lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
// We have been asked to return an entry in the LpAdrList,
|
|
// we dont care about recipient type - just Display Name and EntryID
|
|
|
|
// First check if anything is selected at all
|
|
int iItemIndex = ListView_GetNextItem(_hWndAddr,-1,LVNI_SELECTED);
|
|
if (iItemIndex != -1)
|
|
{
|
|
LPRECIPIENT_INFO lpItem = GetItemFromLV(_hWndAddr, iItemIndex);
|
|
if (lpItem)
|
|
{
|
|
if(HR_FAILED(HrUpdateAdrListEntry(
|
|
lpAP->lpIAB,
|
|
lpItem->lpEntryID,
|
|
lpItem->cbEntryID,
|
|
(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0,
|
|
lpAP->lppAdrList)))
|
|
{
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)||(*lpAP_lppListCC)||(*lpAP_lppListBCC)))
|
|
{
|
|
//
|
|
//if user selected something in the TO/CC wells, we want to return
|
|
//a relevant AdrList back ...
|
|
//
|
|
ULONG ulcEntryCount = 0;
|
|
LPRECIPIENT_INFO lpItem = NULL;
|
|
|
|
//
|
|
// get a count of how many elements we need to return
|
|
//
|
|
lpItem = (*lpAP_lppListTo);
|
|
while(lpItem)
|
|
{
|
|
ulcEntryCount++;
|
|
lpItem = lpItem->lpNext;
|
|
}
|
|
|
|
lpItem = (*lpAP_lppListCC);
|
|
while(lpItem)
|
|
{
|
|
ulcEntryCount++;
|
|
lpItem = lpItem->lpNext;
|
|
}
|
|
|
|
lpItem = (*lpAP_lppListBCC);
|
|
while(lpItem)
|
|
{
|
|
ulcEntryCount++;
|
|
lpItem = lpItem->lpNext;
|
|
}
|
|
|
|
if (ulcEntryCount != 0)
|
|
{
|
|
ULONG nIndex = 0;
|
|
LPADRENTRY lpAdrEntryTemp = NULL;
|
|
LPADRLIST lpAdrList = NULL;
|
|
SCODE sc;
|
|
BOOL bProcessingCC = FALSE;
|
|
|
|
//
|
|
// if there was something in the passed in AdrList, free it and
|
|
// create a new list
|
|
//
|
|
|
|
if(!FAILED(sc = MAPIAllocateBuffer( sizeof(ADRLIST) + ulcEntryCount * sizeof(ADRENTRY),
|
|
&lpAdrList)))
|
|
{
|
|
lpAdrList->cEntries = ulcEntryCount;
|
|
|
|
nIndex = 0;
|
|
|
|
// Start getting items from the TO list
|
|
lpItem = (*lpAP_lppListTo);
|
|
|
|
while(nIndex < ulcEntryCount)
|
|
{
|
|
if (lpItem == NULL)
|
|
{
|
|
if (bProcessingCC == FALSE)
|
|
{
|
|
lpItem = (*lpAP_lppListCC);
|
|
bProcessingCC = TRUE;
|
|
}
|
|
else
|
|
lpItem = (*lpAP_lppListBCC);
|
|
}
|
|
|
|
if (lpItem != NULL)
|
|
{
|
|
LPSPropValue rgProps = NULL;
|
|
ULONG cValues = 0;
|
|
LPSPropValue lpPropArrayNew = NULL;
|
|
ULONG cValuesNew = 0;
|
|
LPTSTR lpszTemp = NULL;
|
|
LPVOID lpbTemp = NULL;
|
|
ULONG i = 0;
|
|
SCODE sc;
|
|
HRESULT hr = hrSuccess;
|
|
|
|
//reset hr
|
|
hr = hrSuccess;
|
|
|
|
|
|
// We are walking through our linked lists representing the TO and CC
|
|
// selected recipients. We want to return proper set of existing props
|
|
// for all the resolved users and the passed in set of props for the
|
|
// unresolved user. Hence we compare to see what we can get for each
|
|
// individual user. For unresolved users, the only distinctive criteria is
|
|
// their display name .. we have no other information .. <TBD> this is
|
|
// problematic because if there are 2 entries in the input adrlist with the
|
|
// same unresolved display name, even if they have difference rgPropVals
|
|
// we might end up giving them identical ones back .... what to do .. <TBD>
|
|
|
|
|
|
// Items that have entry ids are resolved ... items that dont have entryids
|
|
// are not resolved ...
|
|
|
|
if (lpItem->cbEntryID != 0)
|
|
{
|
|
// if this was an item from the original list .. we dont really
|
|
// want to mess with it irrespective of whether it is a resolved
|
|
// or unresolved entry.
|
|
// However, if this is a new entry, then we want to get its
|
|
// minimum props from the store ...
|
|
|
|
if (lpItem->ulOldAdrListEntryNumber == 0)
|
|
{
|
|
|
|
//resolved entry
|
|
hr = HrGetPropArray(lpAP->lpIAB,
|
|
(LPSPropTagArray) &ptaResolveDefaults,
|
|
lpItem->cbEntryID,
|
|
lpItem->lpEntryID,
|
|
(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) ? MAPI_UNICODE : 0,
|
|
&cValues,
|
|
&rgProps);
|
|
}
|
|
else
|
|
{
|
|
rgProps = NULL;
|
|
cValues = 0;
|
|
}
|
|
|
|
if (!HR_FAILED(hr))
|
|
{
|
|
if(lpItem->ulOldAdrListEntryNumber != 0)
|
|
{
|
|
ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember the increment-by-one ..
|
|
|
|
// This is from the original entry list ...
|
|
// We want to merge the newly generated properties with the old
|
|
// original properties .. the original properties will include a
|
|
// PR_RECIPIENT_TYPE (or this entry would have been rejected)
|
|
|
|
sc = ScMergePropValues( (*(lpAP->lppAdrList))->aEntries[index].cValues,
|
|
(*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
|
|
cValues,
|
|
rgProps,
|
|
&cValuesNew,
|
|
&lpPropArrayNew);
|
|
|
|
if (sc != S_OK)
|
|
{
|
|
// If errors then dont merge .. just take the temp set of props
|
|
// in rgProps
|
|
if (lpPropArrayNew)
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
lpPropArrayNew = rgProps;
|
|
cValuesNew = cValues;
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
else
|
|
{
|
|
// merged successfully, discard the temp sets of props
|
|
if (rgProps)
|
|
MAPIFreeBuffer(rgProps);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// totally new item
|
|
// we have to give it a valid PR_RECIPIENT_TYPE
|
|
// so create a new one and merge it with the above props
|
|
SPropValue Prop = {0};
|
|
Prop.ulPropTag = PR_RECIPIENT_TYPE;
|
|
Prop.Value.l = lpItem->ulRecipientType;
|
|
|
|
sc = ScMergePropValues( 1,
|
|
&Prop,
|
|
cValues,
|
|
rgProps,
|
|
&cValuesNew,
|
|
&lpPropArrayNew);
|
|
if (sc != S_OK)
|
|
{
|
|
// oops this failed
|
|
if (lpPropArrayNew)
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
lpPropArrayNew = NULL;
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
|
|
//free rgProps
|
|
if (rgProps)
|
|
MAPIFreeBuffer(rgProps);
|
|
|
|
} // end have previous adr list items
|
|
|
|
// [PaulHi] 2/15/99 Make sure that the new property string
|
|
// values are converted to ANSI if our client is non-UNICODE.
|
|
if ( !FAILED(sc) && !(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) && lpPropArrayNew )
|
|
{
|
|
sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0);
|
|
if (FAILED(sc))
|
|
{
|
|
if (lpPropArrayNew)
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
lpPropArrayNew = NULL;
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
}
|
|
|
|
} // end GetProps succeeded
|
|
}
|
|
else
|
|
{
|
|
// this is an unresolved entry
|
|
// we need to get its original sets of props from the original AdrList
|
|
if (lpItem->ulOldAdrListEntryNumber == 0)
|
|
{
|
|
// ouch - this kind of error shouldnt have happened
|
|
DebugPrintError(( TEXT("Address: Unresolved entry has no index number!!!\n")));
|
|
lpAP->nRetVal = -1; //error code
|
|
}
|
|
else
|
|
{
|
|
ULONG cb = 0;
|
|
ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember to decrement the +1 increment
|
|
|
|
cValuesNew = (*(lpAP->lppAdrList))->aEntries[index].cValues;
|
|
// copy over the props from our old array into a new one
|
|
if (!(FAILED(sc = ScCountProps( cValuesNew,
|
|
(*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
|
|
&cb))))
|
|
{
|
|
if (!(FAILED(sc = MAPIAllocateBuffer(cb, &lpPropArrayNew))))
|
|
{
|
|
|
|
if (FAILED(sc = ScCopyProps( cValuesNew,
|
|
(*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
|
|
lpPropArrayNew,
|
|
NULL)))
|
|
{
|
|
DebugPrintError(( TEXT("Address: ScCopyProps fails!!!\n")));
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpAP->nRetVal = -1;
|
|
}
|
|
}
|
|
}
|
|
// At this point, if we've still got no errors,
|
|
// we should have a valid lpPropArrayNew and cValuesNew which we should
|
|
// be able to add to our new AdrList
|
|
if (lpAP->nRetVal != -1)
|
|
{
|
|
lpAdrList->aEntries[nIndex].cValues = cValuesNew;
|
|
lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
|
|
}
|
|
else
|
|
{
|
|
// some error
|
|
if (lpPropArrayNew)
|
|
{
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
lpPropArrayNew = NULL;
|
|
}
|
|
}
|
|
|
|
lpItem = lpItem->lpNext;
|
|
nIndex++;
|
|
}
|
|
}
|
|
|
|
if (*(lpAP->lppAdrList))
|
|
{
|
|
FreePadrlist(*(lpAP->lppAdrList));
|
|
}
|
|
|
|
*(lpAP->lppAdrList) = lpAdrList;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)==NULL) && ((*lpAP_lppListCC)==NULL) && ((*lpAP_lppListBCC)==NULL))
|
|
{
|
|
// we were asked to select recipients but if these pointers are null
|
|
// then the user deleted the entries in the wells and we thus dont
|
|
// want to return anything. So free the lpaddrlist
|
|
// and make it NULL
|
|
|
|
if (*(lpAP->lppAdrList))
|
|
{
|
|
// Bug 27483 - dont NULL the lpAdrList - just set cEntries to 0
|
|
ULONG iEntry = 0;
|
|
for (iEntry = 0; iEntry < (*(lpAP->lppAdrList))->cEntries; iEntry++)
|
|
{
|
|
MAPIFreeBuffer((*(lpAP->lppAdrList))->aEntries[iEntry].rgPropVals);
|
|
}
|
|
(*(lpAP->lppAdrList))->cEntries = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the sort info to the registry
|
|
//
|
|
if(lpAP->DialogState != STATE_PICK_USER)
|
|
WriteRegistrySortInfo((LPIAB)lpAP->lpIAB, lpAP->SortInfo);
|
|
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
lpAP->hWaitCur = NULL;
|
|
SetCursor(hOldCur);
|
|
}
|
|
// fall thru to cleanup code
|
|
|
|
case IDCANCEL:
|
|
case IDC_ADDRBK_BUTTON_CANCEL:
|
|
if(!lpAP->bLDAPinProgress)
|
|
{
|
|
if ((lpAP->nRetVal != ADDRESS_OK) && // Are we falling thru from above ??
|
|
(lpAP->nRetVal != -1) ) // or did someone trigger an error above ??
|
|
{
|
|
// if not ..
|
|
lpAP->nRetVal = ADDRESS_CANCEL;
|
|
}
|
|
|
|
if ((*lpAP_lppContentsList))
|
|
ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES),
|
|
lpAP_lppContentsList);
|
|
|
|
if ((*lpAP_lppListTo))
|
|
ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO),
|
|
lpAP_lppListTo);
|
|
|
|
if ((*lpAP_lppListCC))
|
|
ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC),
|
|
lpAP_lppListCC);
|
|
|
|
if ((*lpAP_lppListBCC))
|
|
ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC),
|
|
lpAP_lppListBCC);
|
|
|
|
lpAP->bLDAPinProgress = FALSE;
|
|
|
|
EndDialog(hDlg,lpAP->nRetVal);
|
|
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
//treat it like a cancel button
|
|
SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
{
|
|
int id = GetDlgCtrlID((HWND)wParam);
|
|
//
|
|
//This call to the context menu may generate any one of several
|
|
//command messages - for properties and for delete, we need to
|
|
//know which List View initiated the command ...
|
|
//
|
|
lpAP->nContextID = id;
|
|
switch(id)
|
|
{
|
|
case IDC_ADDRBK_LIST_ADDRESSES:
|
|
if (lpAP->DialogState == STATE_BROWSE_MODAL)
|
|
ShowLVContextMenu( lvDialogModalABContents,
|
|
(HWND)wParam,
|
|
NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES),
|
|
lParam,
|
|
(LPVOID) lpAP->lpAdrParms,
|
|
lpAP->lpIAB, NULL);
|
|
else
|
|
ShowLVContextMenu( lvDialogABContents,
|
|
(HWND)wParam,
|
|
NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES),
|
|
lParam,
|
|
(LPVOID) lpAP->lpAdrParms,
|
|
lpAP->lpIAB, NULL);
|
|
break;
|
|
|
|
case IDC_ADDRBK_LIST_TO:
|
|
ShowLVContextMenu(lvDialogABTo,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
|
|
break;
|
|
case IDC_ADDRBK_LIST_BCC:
|
|
ShowLVContextMenu(lvDialogABCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
|
|
break;
|
|
case IDC_ADDRBK_LIST_CC:
|
|
ShowLVContextMenu(lvDialogABBCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
|
|
break;
|
|
default:
|
|
//reset it ..
|
|
lpAP->nContextID = -1;
|
|
WABWinHelp((HWND) wParam,
|
|
g_szWABHelpFileName,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPVOID) rgAddrHelpIDs );
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
LV_DISPINFO * pLvdi = (LV_DISPINFO *)lParam;
|
|
NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam;
|
|
|
|
switch((int) wParam)
|
|
{
|
|
case IDC_ADDRBK_LIST_TO:
|
|
case IDC_ADDRBK_LIST_CC:
|
|
case IDC_ADDRBK_LIST_BCC:
|
|
switch(((LV_DISPINFO *)lParam)->hdr.code)
|
|
{
|
|
case LVN_KEYDOWN:
|
|
switch(((LV_KEYDOWN FAR *) lParam)->wVKey)
|
|
{
|
|
case VK_DELETE:
|
|
if ((int) wParam == IDC_ADDRBK_LIST_TO)
|
|
ListDeleteItem(hDlg, (int) wParam, lpAP_lppListTo);
|
|
else if ((int) wParam == IDC_ADDRBK_LIST_CC)
|
|
ListDeleteItem(hDlg, (int) wParam, lpAP_lppListCC);
|
|
else
|
|
ListDeleteItem(hDlg, (int) wParam, lpAP_lppListBCC);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NM_SETFOCUS:
|
|
lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom);
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
//properties of the item ...
|
|
lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom);
|
|
SendMessage (hDlg, WM_COMMAND, (WPARAM) IDM_LVCONTEXT_PROPERTIES, 0);
|
|
break;
|
|
|
|
case NM_CUSTOMDRAW:
|
|
return ProcessLVCustomDraw(hDlg, lParam, TRUE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case IDC_ADDRBK_LIST_ADDRESSES:
|
|
|
|
switch(pLvdi->hdr.code)
|
|
{
|
|
case LVN_KEYDOWN:
|
|
switch(((LV_KEYDOWN FAR *) lParam)->wVKey)
|
|
{
|
|
case VK_DELETE:
|
|
if (lpAP->DialogState == STATE_BROWSE_MODAL)
|
|
SendMessage(hDlg, WM_COMMAND, IDC_ADDRBK_BUTTON_DELETE, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case LVN_COLUMNCLICK:
|
|
SortListViewColumn((LPIAB)lpAP->lpIAB, pNm->hdr.hwndFrom, pNm->iSubItem, &(lpAP->SortInfo), FALSE);
|
|
break;
|
|
|
|
case NM_CLICK:
|
|
case NM_RCLICK:
|
|
if(lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
|
|
if (iItemIndex == -1)
|
|
{
|
|
//Nothing is selected .. dont let them say OK
|
|
EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE);
|
|
SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE);
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case NM_SETFOCUS:
|
|
lpAP->nContextID = GetDlgCtrlID(pNm->hdr.hwndFrom);
|
|
if(lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
|
|
if (iItemIndex == -1)
|
|
{
|
|
//Nothing is selected .. dont let them say OK
|
|
EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE);
|
|
SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE);
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
{
|
|
//if an entry is selected - do this - otherwise dont do anything
|
|
int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
|
|
if (iItemIndex == -1)
|
|
break;
|
|
{
|
|
//DWORD dwDefId = SendMessage(hDlg, DM_GETDEFID, 0, 0);
|
|
//if(dwDefId)
|
|
// SendMessage(hDlg, WM_COMMAND, (WPARAM) LOWORD(dwDefId), 0);
|
|
SendMessage(hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_TO + lpAP->lpAdrParms->nDestFieldFocus, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NM_CUSTOMDRAW:
|
|
return ProcessLVCustomDraw(hDlg, lParam, TRUE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if( (g_msgMSWheel && message == g_msgMSWheel)
|
|
// || message == WM_MOUSEWHEEL
|
|
)
|
|
{
|
|
if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO))
|
|
SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam);
|
|
else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC))
|
|
SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), message, wParam, lParam);
|
|
else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC))
|
|
SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam);
|
|
else
|
|
SendMessage(_hWndAddr, message, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ListAddItem - Adds an item to the wells
|
|
//
|
|
// hDlg - HWND of parent
|
|
// hWndAddr - HWND of source ListView from which the item will be added
|
|
// CtlID - control ID of the target list view
|
|
// lppList - Item list corresponding to the target list view to which this item will be appended
|
|
// RecipientType - Specified recipient type to tag the new item with
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
int iItemIndex = 0;
|
|
HWND hWndList = GetDlgItem(hDlg,CtlID);
|
|
|
|
|
|
iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
|
|
if (iItemIndex != -1)
|
|
{
|
|
int iLastIndex = 0;
|
|
do
|
|
{
|
|
// otherwise get the entry id of this thing
|
|
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndAddr, iItemIndex);
|
|
if (lpItem)
|
|
{
|
|
LV_ITEM lvI;
|
|
LPRECIPIENT_INFO lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
|
|
|
|
if(!lpNew)
|
|
{
|
|
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
|
|
goto out;
|
|
}
|
|
|
|
lpNew->ulObjectType = lpItem->ulObjectType;
|
|
StrCpyN(lpNew->szDisplayName, lpItem->szDisplayName, ARRAYSIZE(lpNew->szDisplayName));
|
|
StrCpyN(lpNew->szByFirstName, lpItem->szByFirstName, ARRAYSIZE(lpNew->szByFirstName));
|
|
StrCpyN(lpNew->szByLastName, lpItem->szByLastName, ARRAYSIZE(lpNew->szByLastName));
|
|
StrCpyN(lpNew->szEmailAddress, lpItem->szEmailAddress, ARRAYSIZE(lpNew->szEmailAddress));
|
|
StrCpyN(lpNew->szHomePhone, lpItem->szHomePhone, ARRAYSIZE(lpNew->szHomePhone));
|
|
StrCpyN(lpNew->szOfficePhone, lpItem->szOfficePhone, ARRAYSIZE(lpNew->szOfficePhone));
|
|
lpNew->bHasCert = lpItem->bHasCert;
|
|
lpNew->ulRecipientType = RecipientType;
|
|
lpNew->ulOldAdrListEntryNumber = 0; //Flag this as not from the original AdrList
|
|
if (lpItem->cbEntryID)
|
|
{
|
|
lpNew->cbEntryID = lpItem->cbEntryID;
|
|
lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT, lpItem->cbEntryID);
|
|
if(!lpNew->lpEntryID)
|
|
{
|
|
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
|
|
LocalFree(lpNew);
|
|
goto out;
|
|
}
|
|
CopyMemory(lpNew->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID);
|
|
}
|
|
|
|
lpNew->lpNext = (*lppList);
|
|
if (*lppList)
|
|
(*lppList)->lpPrev = lpNew;
|
|
lpNew->lpPrev = NULL;
|
|
(*lppList) = lpNew;
|
|
|
|
lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
|
lvI.state = 0;
|
|
lvI.stateMask = 0;
|
|
lvI.iSubItem = 0;
|
|
lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
|
|
|
|
lvI.iImage = GetWABIconImage(lpNew);
|
|
|
|
// now fill in the List
|
|
lvI.iItem = ListView_GetItemCount(hWndList);
|
|
lvI.pszText = lpNew->szDisplayName;
|
|
lvI.lParam = (LPARAM) lpNew;
|
|
ListView_InsertItem(hWndList, &lvI);
|
|
ListView_EnsureVisible(hWndList,ListView_GetItemCount(hWndList)-1,FALSE);
|
|
}
|
|
iLastIndex = iItemIndex;
|
|
// Get next selected item ...
|
|
iItemIndex = ListView_GetNextItem(hWndAddr,iLastIndex,LVNI_SELECTED);
|
|
} while (iItemIndex != -1);
|
|
//SetFocus(hWndAddr);
|
|
}
|
|
else
|
|
{
|
|
ShowMessageBox(hDlg, IDS_ADDRBK_MESSAGE_NO_ITEMS_ADD, MB_ICONEXCLAMATION);
|
|
goto out;
|
|
}
|
|
|
|
if((ListView_GetItemCount(hWndList) > 0) &&
|
|
(ListView_GetSelectedCount(hWndList) <= 0))
|
|
LVSelectItem(hWndList, 0);
|
|
|
|
bRet = TRUE;
|
|
|
|
out:
|
|
return bRet;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ListDeleteItem - deletes an item from the Wells - unlike the Address COntents list we
|
|
// make sure to delete it here because we want the linked lists to only have valid entries
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
LPRECIPIENT_INFO lpItem = NULL;
|
|
HWND hWndAddr = GetDlgItem(hDlg,CtlID);
|
|
int iItemIndex=0;
|
|
|
|
iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
|
|
if (iItemIndex != -1)
|
|
{
|
|
int iLastItem = 0;
|
|
do
|
|
{
|
|
// otherwise get the entry id of this thing
|
|
lpItem = GetItemFromLV(hWndAddr, iItemIndex);
|
|
if (lpItem)
|
|
{
|
|
// remove this item from our linked list of arrays
|
|
// if this is the first item in the list then handle that special case too
|
|
|
|
if ((*lppList) == lpItem)
|
|
(*lppList) = lpItem->lpNext;
|
|
if (lpItem->lpNext)
|
|
lpItem->lpNext->lpPrev = lpItem->lpPrev;
|
|
if (lpItem->lpPrev)
|
|
lpItem->lpPrev->lpNext = lpItem->lpNext;
|
|
|
|
// we need to update our display
|
|
ListView_DeleteItem(hWndAddr,iItemIndex);
|
|
//UpdateWindow(hWndAddr);
|
|
|
|
FreeRecipItem(&lpItem);
|
|
}
|
|
iLastItem = iItemIndex;
|
|
// Get next selected item ...
|
|
iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
|
|
}while (iItemIndex != -1);
|
|
|
|
// select the previous or next item ...
|
|
if (iLastItem >= ListView_GetItemCount(hWndAddr))
|
|
iLastItem = ListView_GetItemCount(hWndAddr) - 1;
|
|
LVSelectItem(hWndAddr, iLastItem);
|
|
}
|
|
SetFocus(hWndAddr);
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FillWells - Dismembers the lpAdrList to create the To and CC wells
|
|
//
|
|
// Scans the AdrEntry Structures in the LpAdrList, looks at PR_RECIPIENT_TYPE,
|
|
// ignores entries which it cant understand ... creates a temporary linked
|
|
// list of To and CC recipient lists which are used to populate the
|
|
// To and CC List boxes
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPRECIPIENT_INFO lpNew = NULL;
|
|
LPADRENTRY lpAdrEntry = NULL;
|
|
ULONG i=0,j=0,nLen=0;
|
|
int index=0;
|
|
LV_ITEM lvI;
|
|
HWND hWndAddr = NULL;
|
|
ULONG ulMapiTo = MAPI_TO;
|
|
ULONG ulMapiCC = MAPI_CC;
|
|
ULONG ulMapiBCC = MAPI_BCC;
|
|
BOOL bUnicode = (lpAdrParms->ulFlags & MAPI_UNICODE);
|
|
|
|
*lppListTo = NULL;
|
|
*lppListCC = NULL;
|
|
*lppListBCC = NULL;
|
|
|
|
if (lpAdrList == NULL) //nothing to do
|
|
{
|
|
bRet = TRUE;
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// The Input AdrParms structure has a lpulDestComps field that lets the
|
|
// caller specify his own recipient types. If this is missing, we are supposed
|
|
// to use the default recipient types.
|
|
//
|
|
if ((lpAdrParms->cDestFields > 0) && (lpAdrParms->lpulDestComps))
|
|
{
|
|
ULONG i=0;
|
|
for (i=0;i<lpAdrParms->cDestFields;i++)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
ulMapiTo = lpAdrParms->lpulDestComps[i];
|
|
break;
|
|
case 1:
|
|
ulMapiCC = lpAdrParms->lpulDestComps[i];
|
|
break;
|
|
case 2:
|
|
ulMapiBCC = lpAdrParms->lpulDestComps[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for(i=0; i < lpAdrList->cEntries; i++)
|
|
{
|
|
lpAdrEntry = &(lpAdrList->aEntries[i]);
|
|
if (lpAdrEntry->cValues != 0)
|
|
{
|
|
TCHAR szBuf[MAX_DISPLAY_NAME_LENGTH];
|
|
ULONG ulRecipientType = 0;
|
|
ULONG ulObjectType = 0;
|
|
ULONG cbEntryID = 0;
|
|
BOOL bHasCert = FALSE;
|
|
LPENTRYID lpEntryID = NULL;
|
|
szBuf[0]='\0';
|
|
|
|
for(j=0;j<lpAdrEntry->cValues;j++)
|
|
{
|
|
ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
|
|
|
|
if(!bUnicode && PROP_TYPE(ulPropTag) == PT_STRING8)
|
|
ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
|
|
|
|
switch(ulPropTag)
|
|
{
|
|
case(PR_DISPLAY_NAME):
|
|
{
|
|
LPTSTR lpNameW = NULL;
|
|
SET_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ,lpAdrParms);
|
|
nLen = CopyTruncate(szBuf, lpNameW, MAX_DISPLAY_NAME_LENGTH);
|
|
FREE_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ);
|
|
}
|
|
break;
|
|
case(PR_RECIPIENT_TYPE):
|
|
ulRecipientType = lpAdrEntry->rgPropVals[j].Value.l;
|
|
break;
|
|
case(PR_OBJECT_TYPE):
|
|
ulObjectType = lpAdrEntry->rgPropVals[j].Value.l;
|
|
break;
|
|
case(PR_ENTRYID):
|
|
cbEntryID = lpAdrEntry->rgPropVals[j].Value.bin.cb;
|
|
lpEntryID = (LPENTRYID) lpAdrEntry->rgPropVals[j].Value.bin.lpb;
|
|
break;
|
|
case PR_USER_X509_CERTIFICATE:
|
|
bHasCert = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (lstrlen(szBuf) && ((ulRecipientType == ulMapiBCC) || (ulRecipientType == ulMapiTo) || (ulRecipientType == ulMapiCC)))
|
|
{
|
|
lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
|
|
if(!lpNew)
|
|
{
|
|
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
|
|
goto out;
|
|
}
|
|
|
|
// ***NOTE***
|
|
// Store this index number, ie 1st item in AdrList is 1, then 2, 3, so on
|
|
// we do a plus 1 here because 0 value means it wasnt passed in and thus the
|
|
// minimum valid value is 1
|
|
lpNew->ulOldAdrListEntryNumber = i+1;
|
|
|
|
lpNew->bHasCert = bHasCert;
|
|
StrCpyN(lpNew->szDisplayName,szBuf,ARRAYSIZE(lpNew->szDisplayName));
|
|
lpNew->ulRecipientType = ulRecipientType;
|
|
lpNew->ulObjectType = ulObjectType;
|
|
|
|
if (cbEntryID != 0)
|
|
{
|
|
lpNew->cbEntryID = cbEntryID;
|
|
lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT,cbEntryID);
|
|
if(!lpNew->lpEntryID)
|
|
{
|
|
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
|
|
goto out;
|
|
}
|
|
CopyMemory(lpNew->lpEntryID,lpEntryID,cbEntryID);
|
|
}
|
|
|
|
if (ulRecipientType == ulMapiTo)
|
|
{
|
|
lpNew->lpNext = *lppListTo;
|
|
if (*lppListTo)
|
|
(*lppListTo)->lpPrev = lpNew;
|
|
lpNew->lpPrev = NULL;
|
|
*lppListTo = lpNew;
|
|
}
|
|
else if (ulRecipientType == ulMapiCC)
|
|
{
|
|
lpNew->lpNext = *lppListCC;
|
|
if (*lppListCC)
|
|
(*lppListCC)->lpPrev = lpNew;
|
|
lpNew->lpPrev = NULL;
|
|
*lppListCC = lpNew;
|
|
}
|
|
else if (ulRecipientType == ulMapiBCC)
|
|
{
|
|
lpNew->lpNext = *lppListBCC;
|
|
if (*lppListBCC)
|
|
(*lppListBCC)->lpPrev = lpNew;
|
|
lpNew->lpPrev = NULL;
|
|
*lppListBCC = lpNew;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
|
lvI.state = 0;
|
|
lvI.stateMask = 0;
|
|
lvI.iSubItem = 0;
|
|
lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
|
|
|
|
for(i=0;i<3;i++)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
lpNew = *lppListTo;
|
|
break;
|
|
case 1:
|
|
lpNew = *lppListCC;
|
|
break;
|
|
case 2:
|
|
lpNew = *lppListBCC;
|
|
break;
|
|
}
|
|
|
|
hWndAddr = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i);
|
|
index = 0;
|
|
while(lpNew)
|
|
{
|
|
lvI.iItem = index;
|
|
lvI.pszText = lpNew->szDisplayName;
|
|
lvI.lParam = (LPARAM) lpNew;
|
|
|
|
lvI.iImage = GetWABIconImage(lpNew);
|
|
|
|
ListView_InsertItem(hWndAddr, &lvI);
|
|
|
|
index++;
|
|
lpNew = lpNew->lpNext;
|
|
}
|
|
}
|
|
|
|
// We will highlight the first item in any filled list box
|
|
// because basically that looks good when tabbing through them ...
|
|
for(i=0;i<lpAdrParms->cDestFields;i++)
|
|
{
|
|
HWND hWndLV = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i);
|
|
|
|
if (ListView_GetItemCount(hWndLV) > 0)
|
|
LVSelectItem(hWndLV,0);
|
|
}
|
|
|
|
|
|
bRet = TRUE;
|
|
|
|
out:
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetAddressBookUI - juggles the address book UI in response to various parameters
|
|
//
|
|
// This function will probably be more complex with each tier
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
BOOL SetAddressBookUI(HWND hDlg,
|
|
LPADDRESS_PARMS lpAP)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
//LV_COLUMN lvC;
|
|
RECT rc, rc1, rc2;
|
|
POINT ptLU1,ptRB1;
|
|
int nButtonsVisible = 0;
|
|
int nButtonSpacing = 7;
|
|
int nButtonWidth = 0;
|
|
ULONG nLen = 0;
|
|
TCHAR szBuf[MAX_UI_STR*4];
|
|
LPPTGDATA lpPTGData=GetThreadStoragePointer();
|
|
HWND hWndListAddresses = GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES);
|
|
|
|
LPTSTR szCaption = NULL;
|
|
|
|
SET_UNICODE_STR(szCaption, lpAP->lpAdrParms->lpszCaption,lpAP->lpAdrParms);
|
|
|
|
if(!szCaption || !lstrlen(szCaption))
|
|
{
|
|
LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuf, CharSizeOf(szBuf));
|
|
szCaption = szBuf;
|
|
}
|
|
// Set the font of all the children to the default GUI font
|
|
EnumChildWindows( hDlg,
|
|
SetChildDefaultGUIFont,
|
|
(LPARAM) 0);
|
|
|
|
if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
|
|
{
|
|
// Fill in the Combo with the container names
|
|
FillContainerCombo(GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT), (LPIAB)lpAP->lpIAB);
|
|
}
|
|
else
|
|
{
|
|
HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
|
|
EnableWindow(hWndCombo, FALSE);
|
|
ShowWindow(hWndCombo, SW_HIDE);
|
|
|
|
// resize the listview to take place of the hidden combo
|
|
GetWindowRect(hWndCombo,&rc2);
|
|
GetWindowRect(hWndListAddresses,&rc);
|
|
//
|
|
//This api works for both mirrored and unmirrored windows.
|
|
//
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
|
|
ptLU1.x = rc2.left;
|
|
ptLU1.y = rc2.top;
|
|
ptRB1.x = rc.right;
|
|
ptRB1.y = rc.bottom;
|
|
MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
|
|
}
|
|
|
|
//
|
|
// There are only two states that need configuration -
|
|
// Pick User - in which we have to hide the wells
|
|
// and
|
|
// Select Recipients, in which we have to hide the wells
|
|
// as per the input criteria and resize accordingly and
|
|
// also set the labels based on the input criteria
|
|
//
|
|
if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
|
|
{
|
|
SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_TO, 0);
|
|
|
|
// in case the nDestFieldFocus parameter is supplied, use it ..
|
|
if (
|
|
(lpAP->lpAdrParms->nDestFieldFocus < lpAP->lpAdrParms->cDestFields))
|
|
{
|
|
if (lpAP->lpAdrParms->nDestFieldFocus == 1)
|
|
SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_CC, 0);
|
|
else if (lpAP->lpAdrParms->nDestFieldFocus == 2)
|
|
SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_BCC, 0);
|
|
}
|
|
}
|
|
else if (lpAP->DialogState == STATE_PICK_USER)
|
|
SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
|
|
else if (lpAP->DialogState == STATE_BROWSE_MODAL)
|
|
SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_PROPS, 0);
|
|
|
|
// Set the window caption
|
|
if (szCaption)
|
|
SetWindowText(hDlg,szCaption);
|
|
|
|
// Set the caption over the destination wells
|
|
if (lpAP->lpAdrParms->lpszDestWellsTitle)
|
|
{
|
|
LPWSTR lpTitle = NULL; // <note> assumes UNICODE defined
|
|
SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lpszDestWellsTitle,lpAP->lpAdrParms);
|
|
SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_RECIP_TITLE,lpTitle);
|
|
FREE_UNICODE_STR(lpTitle, lpAP->lpAdrParms->lpszDestWellsTitle);
|
|
}
|
|
|
|
if (lpAP->DialogState == STATE_PICK_USER &&
|
|
*(lpAP->lppAdrList) )
|
|
{
|
|
ULONG i=0;
|
|
LPTSTR lpszRecipName = NULL;
|
|
|
|
//Get the user whose name we are trying to find
|
|
for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
|
|
{
|
|
ULONG ulPropTag = PR_DISPLAY_NAME;
|
|
if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
|
|
ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
|
|
if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
|
|
{
|
|
SET_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(lpszRecipName)
|
|
{
|
|
LPTSTR lpszBuffer = NULL;
|
|
TCHAR szTmp[MAX_PATH], *lpszTmp;
|
|
|
|
LoadString(hinstMapiX, IDS_ADDRBK_RESOLVE_CAPTION, szBuf, CharSizeOf(szBuf));
|
|
|
|
CopyTruncate(szTmp, lpszRecipName, MAX_PATH - 1);
|
|
lpszTmp = szTmp;
|
|
|
|
if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
szBuf,
|
|
0,0, //ignored
|
|
(LPTSTR) &lpszBuffer,
|
|
MAX_UI_STR,
|
|
(va_list *)&lpszTmp))
|
|
{
|
|
// if the display name is too long, it doesnt show up properly in the UI ..
|
|
// so we will purposely limit the visible portion to 64 characters - arbitarily defined limit..
|
|
szBuf[0]='\0';
|
|
nLen = CopyTruncate(szBuf, lpszBuffer, 2 * MAX_DISPLAY_NAME_LENGTH);
|
|
|
|
LocalFreeAndNull(&lpszBuffer);
|
|
}
|
|
|
|
//Increase the size of the static control to = what the Contents List width will be
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),&rc2);
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc);
|
|
//
|
|
//This api working in both mirrored and unmirrored windows.
|
|
//
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
|
|
ptLU1.x = rc2.left;
|
|
ptLU1.y = rc2.top;
|
|
ptRB1.x = rc.right;
|
|
ptRB1.y = rc2.bottom;
|
|
MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
|
|
|
|
SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_CONTENTS,szBuf);
|
|
|
|
FREE_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (lpAP->DialogState == STATE_PICK_USER)
|
|
{
|
|
// If ADDRESS_ONE has been selected, then make the IDC_ADDRBK_LIST_ADDRESSES
|
|
// single selection only
|
|
DWORD dwStyle;
|
|
dwStyle = GetWindowLong(hWndListAddresses, GWL_STYLE);
|
|
SetWindowLong(hWndListAddresses, GWL_STYLE, dwStyle | LVS_SINGLESEL);
|
|
}
|
|
|
|
if ((lpAP->DialogState == STATE_PICK_USER)||(lpAP->DialogState == STATE_BROWSE_MODAL))
|
|
{
|
|
int i = 0;
|
|
// Dont show wells which means we have to do some rearranging
|
|
// * Hide the wells and the To, CC, BCC buttons
|
|
// * Resize the IDC_ADDRBK_LIST_ADDRESSES to fill the whole dialog
|
|
// * Move the 3 buttons below it to the left side of the dialog
|
|
//
|
|
|
|
// Get the dimensions of the ToListBox
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc2);
|
|
GetWindowRect(hWndListAddresses,&rc);
|
|
//
|
|
//This api works for in both mirrored and unmirrored windows.
|
|
//
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
|
|
ptLU1.x = rc.left;
|
|
ptLU1.y = rc.top;
|
|
ptRB1.x = rc2.right;
|
|
ptRB1.y = rc.bottom;
|
|
|
|
MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
|
|
|
|
for(i=0;i<3;i++)
|
|
{
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO + i), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO + i), SW_HIDE);
|
|
}
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_STATIC_RECIP_TITLE), SW_HIDE); // TEXT("Message Recipients") label
|
|
|
|
}
|
|
|
|
// other things to do
|
|
|
|
// Load Headers for List box
|
|
GetWindowRect(hWndListAddresses,&rc);
|
|
HrInitListView(hWndListAddresses, LVS_REPORT, TRUE);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),&rc2);
|
|
nButtonsVisible = 2;
|
|
|
|
nButtonWidth = (rc2.right - rc2.left);
|
|
|
|
// get the new coordinates of the 1st visible button
|
|
//
|
|
//This api working in both mirrored and unmirrored windows.
|
|
//
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
|
|
ptLU1.x = rc.left;
|
|
ptLU1.y = rc2.top;
|
|
ptRB1.x = ptLU1.x + nButtonWidth;
|
|
ptRB1.y = rc2.bottom;
|
|
|
|
MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
|
|
ptLU1.x += nButtonWidth + nButtonSpacing;
|
|
ptRB1.x = ptLU1.x + nButtonWidth;
|
|
if (lpAP->DialogState == STATE_BROWSE_MODAL)
|
|
{
|
|
MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEWGROUP),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
|
|
ptLU1.x += nButtonWidth + nButtonSpacing;
|
|
ptRB1.x = ptLU1.x + nButtonWidth;
|
|
}
|
|
else
|
|
{
|
|
// The NewGroup button is visible only in the DialogModalView
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), SW_HIDE);
|
|
}
|
|
MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
|
|
ptLU1.x += nButtonWidth + nButtonSpacing;
|
|
ptRB1.x = ptLU1.x + nButtonWidth;
|
|
MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_DELETE),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
|
|
|
|
|
|
// The delete button is visible only in the DialogModalView
|
|
if (lpAP->DialogState != STATE_BROWSE_MODAL)
|
|
{
|
|
EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), FALSE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), SW_HIDE);
|
|
}
|
|
|
|
//
|
|
// We now need to customize this window if we are selecting
|
|
// recipients ...
|
|
//
|
|
if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
|
|
{
|
|
// We need to see which wells are visible and
|
|
// then we need to resize the buttons based on their captions
|
|
//
|
|
int i=0;
|
|
int nLen=0;
|
|
int cDF = lpAP->lpAdrParms->cDestFields;
|
|
int iLeft=0,iTop=0;
|
|
|
|
SIZE size={0};
|
|
ULONG MaxWidth=0;
|
|
ULONG maxHeightPerLV = 0;
|
|
HWND hw;
|
|
HDC hdc=GetDC(hDlg);
|
|
|
|
if (lpAP->lpAdrParms->lppszDestTitles)
|
|
{
|
|
for(i=0; i < cDF; i++)
|
|
{
|
|
LPTSTR lpTitle = NULL;
|
|
ULONG Len = 0;
|
|
SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i],lpAP->lpAdrParms);
|
|
if(!lpTitle)
|
|
continue;
|
|
Len = lstrlen(lpTitle);
|
|
if (Len > CharSizeOf(szBuf) - 4)
|
|
{
|
|
ULONG iLen = TruncatePos(lpTitle, CharSizeOf(szBuf) - 4);
|
|
CopyMemory(szBuf,lpTitle,iLen*sizeof(TCHAR));
|
|
szBuf[iLen] = '\0';
|
|
}
|
|
else
|
|
{
|
|
StrCpyN(szBuf,lpTitle,ARRAYSIZE(szBuf));
|
|
}
|
|
StrCatBuff(szBuf,szArrow,ARRAYSIZE(szBuf));
|
|
if (lstrlen(szBuf) >= nLen)
|
|
{
|
|
nLen = lstrlen(szBuf);
|
|
GetTextExtentPoint32(hdc, szBuf, nLen, &size);
|
|
MaxWidth = size.cx;
|
|
}
|
|
// Set the new text
|
|
SetDlgItemText(hDlg,IDC_ADDRBK_BUTTON_TO+i,szBuf);
|
|
FREE_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i]);
|
|
}
|
|
|
|
}
|
|
|
|
ReleaseDC(hDlg,hdc);
|
|
|
|
if (MaxWidth == 0)
|
|
{
|
|
//get the default width
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO),&rc1);
|
|
MaxWidth = rc1.right - rc1.left;
|
|
}
|
|
|
|
//Get the maximum allowable height per well
|
|
GetWindowRect(hWndListAddresses,&rc);
|
|
GetChildClientRect(hWndListAddresses, &rc);
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),&rc1);
|
|
GetChildClientRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW), &rc1);
|
|
maxHeightPerLV = (rc1.bottom-rc.top - (cDF - 1)*CONTROL_SPACING)/cDF;
|
|
iTop = rc.top;
|
|
|
|
for(i=0;i<cDF;i++)
|
|
{
|
|
hw = GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO + i);
|
|
|
|
// resize the buttons to fit the text
|
|
GetWindowRect(hw,&rc1);
|
|
GetChildClientRect(hw,&rc1);
|
|
MoveWindow(hw,rc1.left,iTop,MaxWidth,rc1.bottom - rc1.top,FALSE);
|
|
|
|
iLeft = rc1.left + MaxWidth + 2*CONTROL_SPACING;
|
|
|
|
// Move the list boxes to accomodate the resized buttons
|
|
hw = GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO + i);
|
|
GetWindowRect(hw, &rc1);
|
|
GetChildClientRect(hw, &rc1);
|
|
MoveWindow(hw,iLeft,iTop,rc1.right-iLeft,maxHeightPerLV,FALSE);
|
|
|
|
ListView_SetExtendedListViewStyle(hw,LVS_EX_FULLROWSELECT);
|
|
|
|
iTop += maxHeightPerLV + CONTROL_SPACING;
|
|
|
|
}
|
|
|
|
//Move the label over the wells and restrict it's size
|
|
hw = GetDlgItem(hDlg,IDC_ADDRBK_STATIC_RECIP_TITLE);
|
|
GetWindowRect(hw, &rc2);
|
|
GetChildClientRect(hw, &rc2);
|
|
if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB)) // need to move this to the same height as combo
|
|
{
|
|
int ht = rc2.bottom - rc2.top;
|
|
rc2.bottom = rc.top - CONTROL_SPACING;
|
|
rc2.top = rc2.bottom - ht;
|
|
}
|
|
MoveWindow(hw,iLeft,rc2.top,rc1.right-iLeft,rc2.bottom-rc2.top,FALSE);
|
|
|
|
|
|
// Now we have the position and width of the list boxes .. need to get their height
|
|
if (cDF!=3) //if not the default preset position, reposition
|
|
{
|
|
switch(cDF)
|
|
{
|
|
case 1:
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), SW_HIDE);
|
|
case 2:
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), SW_HIDE);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
for(i=0;i<cDF;i++)
|
|
HrInitListView(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO + i), LVS_REPORT, FALSE);
|
|
|
|
/***
|
|
// Add a column to the To,CC,BCC List Boxes
|
|
GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc);
|
|
|
|
lvC.mask = LVCF_FMT | LVCF_WIDTH;// | LVCF_TEXT;
|
|
lvC.fmt = LVCFMT_LEFT;
|
|
lvC.cx = (rc.right - rc.left)-20;
|
|
lvC.iSubItem = 0;
|
|
lvC.pszText = NULL; // TEXT(" 'TO' Recipients");
|
|
|
|
ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),lvC.iSubItem, &lvC);
|
|
ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_CC),lvC.iSubItem, &lvC);
|
|
ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_BCC),lvC.iSubItem, &lvC);
|
|
/***/
|
|
for (i=0;i<cDF;i++)
|
|
{
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO+i), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO+i));
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO+i), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO+i));
|
|
}
|
|
}
|
|
|
|
// The window is taking too long to display with several 100 entries in the
|
|
// property store ... so we force all the contents to visible so that we
|
|
// can view the fill contents ...
|
|
//ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES), SW_SHOWNORMAL);
|
|
//UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES));
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS));
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW));
|
|
ShowWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/));
|
|
ShowWindow(GetDlgItem(hDlg,IDCANCEL/*IDC_ADDRBK_BUTTON_CANCEL*/), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDCANCEL/*IDC_ADDRBK_BUTTON_CANCEL*/));
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS));
|
|
ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_15), SW_SHOWNORMAL);
|
|
UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_15));
|
|
ShowWindow(hDlg,SW_SHOWNORMAL);
|
|
UpdateWindow(hDlg);
|
|
|
|
|
|
{
|
|
// HICON hIcon = LoadIcon(hinstMapiX,MAKEINTRESOURCE(IDI_ICON_FIND));
|
|
// associate the icon with the button.
|
|
// SendMessage(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_FIND),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)(HANDLE)hIcon);
|
|
}
|
|
bRet = TRUE;
|
|
|
|
if( szCaption != lpAP->lpAdrParms->lpszCaption &&
|
|
szCaption != szBuf)
|
|
LocalFreeAndNull(&szCaption);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//$$///////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateLVItems ....
|
|
// When we call properties on an object, its props can change ...
|
|
// Since the particular user may appear in any of the 4 list views,
|
|
// we have to make sure that all views are updated for that entry
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UpdateLVItems(HWND hWndLV,LPTSTR lpszName)
|
|
{
|
|
// We have the handle to the list view initiating the Properties call
|
|
// We know the old name to look for
|
|
//
|
|
// We know which item is selected - we can get its entryid and lParam
|
|
// We then search all the list views for the old display name
|
|
// if the old display name matches, we compare the entry id
|
|
// if the entryid matches, then we update that item ...
|
|
|
|
int iItemIndex = 0, iLastItemIndex = 0;
|
|
LPRECIPIENT_INFO lpOriginalItem;
|
|
ULONG i=0;
|
|
ULONG nCount = 0;
|
|
int id = 0;
|
|
HWND hDlg = GetParent(hWndLV);
|
|
HWND hw = NULL;
|
|
LV_FINDINFO lvf={0};
|
|
|
|
if ( (ListView_GetSelectedCount(hWndLV) != 1) ||
|
|
(lpszName == NULL) )
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
iItemIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
|
|
|
|
lpOriginalItem = GetItemFromLV(hWndLV, iItemIndex);
|
|
|
|
if(!lpOriginalItem)
|
|
goto out;
|
|
|
|
|
|
// There can be upto 4 list view boxes in the view, each of which can
|
|
// contain a displayed copy of this item ..
|
|
// We want to go through all 4 and update all entries that match this item
|
|
|
|
// Our strategy is to search for each and every item that
|
|
// matches the display name - check its entry ID and if
|
|
// the entry ID matches, update it ...
|
|
|
|
lvf.flags = LVFI_STRING;
|
|
lvf.psz = lpszName;
|
|
|
|
for(i=0;i<4;i++)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
id = IDC_ADDRBK_LIST_ADDRESSES;
|
|
break;
|
|
case 1:
|
|
id = IDC_ADDRBK_LIST_TO;
|
|
break;
|
|
case 2:
|
|
id = IDC_ADDRBK_LIST_CC;
|
|
break;
|
|
case 3:
|
|
id = IDC_ADDRBK_LIST_BCC;
|
|
break;
|
|
}
|
|
|
|
hw = GetDlgItem(hDlg,id);
|
|
|
|
// if its hidden, ignore it
|
|
if (!IsWindowVisible(hw))
|
|
continue;
|
|
|
|
// if its empty, ignore it
|
|
nCount = ListView_GetItemCount(hw);
|
|
if (nCount <= 0)
|
|
continue;
|
|
|
|
// The contents list view wont have duplicates so ignore it if its the original
|
|
if ((id == IDC_ADDRBK_LIST_ADDRESSES) &&
|
|
(hw == hWndLV))
|
|
continue;
|
|
|
|
// see if we can find the matching items
|
|
iLastItemIndex = -1;
|
|
iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf);
|
|
while (iItemIndex != -1)
|
|
{
|
|
// inspect this item
|
|
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);
|
|
if (lpItem && (lpItem->cbEntryID != 0) && (lpOriginalItem->cbEntryID == lpItem->cbEntryID))
|
|
{
|
|
if(!memcmp(lpOriginalItem->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID))
|
|
{
|
|
// this is the same item ... update it
|
|
if (lstrcmpi(lpItem->szDisplayName,lpOriginalItem->szDisplayName))
|
|
{
|
|
ListView_SetItemText(hw,iItemIndex,colDisplayName,lpOriginalItem->szDisplayName);
|
|
StrCpyN(lpItem->szDisplayName,lpOriginalItem->szDisplayName,ARRAYSIZE(lpItem->szDisplayName));
|
|
}
|
|
|
|
if (lstrcmpi(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress))
|
|
{
|
|
ListView_SetItemText(hw,iItemIndex,colEmailAddress,lpOriginalItem->szEmailAddress);
|
|
StrCpyN(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress,ARRAYSIZE(lpItem->szEmailAddress));
|
|
}
|
|
|
|
if (lstrcmpi(lpItem->szHomePhone,lpOriginalItem->szHomePhone))
|
|
{
|
|
ListView_SetItemText(hw,iItemIndex,colHomePhone,lpOriginalItem->szHomePhone);
|
|
StrCpyN(lpItem->szHomePhone,lpOriginalItem->szHomePhone,ARRAYSIZE(lpItem->szHomePhone));
|
|
}
|
|
|
|
if (lstrcmpi(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone))
|
|
{
|
|
ListView_SetItemText(hw,iItemIndex,colOfficePhone,lpOriginalItem->szOfficePhone);
|
|
StrCpyN(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone,ARRAYSIZE(lpItem->szOfficePhone));
|
|
}
|
|
|
|
if (lstrcmpi(lpItem->szByFirstName,lpOriginalItem->szByFirstName))
|
|
StrCpyN(lpItem->szByFirstName,lpOriginalItem->szByFirstName,ARRAYSIZE(lpItem->szByFirstName));
|
|
|
|
if (lstrcmpi(lpItem->szByLastName,lpOriginalItem->szByLastName))
|
|
StrCpyN(lpItem->szByLastName,lpOriginalItem->szByLastName,ARRAYSIZE(lpItem->szByLastName));
|
|
}
|
|
}
|
|
|
|
iLastItemIndex = iItemIndex;
|
|
iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf);
|
|
}
|
|
}
|
|
out:
|
|
return;
|
|
}
|
|
|
|
|
|
//$$///////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ShowAddrBkLVProps ....
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr,LPADDRESS_PARMS lpAP, LPFILETIME lpftLast)
|
|
{
|
|
// get the display name of this item
|
|
TCHAR szName[MAX_DISPLAY_NAME_LENGTH];
|
|
szName[0]='\0';
|
|
if (ListView_GetSelectedCount(hWndAddr) == 1)
|
|
{
|
|
ListView_GetItemText( hWndAddr,
|
|
ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED),
|
|
0,
|
|
szName,
|
|
CharSizeOf(szName));
|
|
}
|
|
if( (MAPI_E_OBJECT_CHANGED == HrShowLVEntryProperties(hWndAddr, 0, lpAP->lpIAB, lpftLast)) &&
|
|
(szName) &&
|
|
(lpAP->DialogState == STATE_SELECT_RECIPIENTS)
|
|
)
|
|
{
|
|
// if the entry has changed and we have multiple list views visible,
|
|
// we need to update all instances of the entry in all the list views
|
|
//
|
|
UpdateLVItems(hWndAddr,szName);
|
|
SortListViewColumn(lpIAB, GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES), colDisplayName, &(lpAP->SortInfo), TRUE);
|
|
|
|
}
|
|
SetFocus(hWndAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//$$///////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrUpdateAdrListEntry ....
|
|
//
|
|
// When returning from a PickUser operation, updates the
|
|
// entry in the lpAdrList with the newly found item
|
|
//
|
|
// ulFLags 0 or MAPI_UNICODE passed down to GetProps
|
|
//
|
|
// Returns: Hr
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB,
|
|
LPENTRYID lpEntryID,
|
|
ULONG cbEntryID,
|
|
ULONG ulFlags,
|
|
LPADRLIST * lppAdrList)
|
|
{
|
|
|
|
LPSPropValue rgProps = NULL;
|
|
ULONG cValues = 0;
|
|
LPSPropValue lpPropArrayNew = NULL;
|
|
ULONG cValuesNew = 0;
|
|
LPTSTR lpszTemp = NULL;
|
|
LPVOID lpbTemp = NULL;
|
|
ULONG i = 0;
|
|
SCODE sc;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (!lppAdrList || !lpEntryID || !lpIAB || !cbEntryID)
|
|
goto out;
|
|
|
|
hr = HrGetPropArray(lpIAB,
|
|
(LPSPropTagArray) &ptaResolveDefaults,
|
|
cbEntryID,
|
|
lpEntryID,
|
|
ulFlags,
|
|
&cValues,
|
|
&rgProps);
|
|
if (!HR_FAILED(hr))
|
|
{
|
|
|
|
if(!*lppAdrList)
|
|
{
|
|
// Allocate one ..
|
|
LPADRLIST lpAdrList = NULL;
|
|
|
|
sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY),
|
|
&lpAdrList);
|
|
|
|
if(FAILED(sc))
|
|
{
|
|
hr = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
*lppAdrList = lpAdrList;
|
|
(*lppAdrList)->cEntries = 1;
|
|
(*lppAdrList)->aEntries[0].ulReserved1 = 0;
|
|
(*lppAdrList)->aEntries[0].cValues = 0;
|
|
(*lppAdrList)->aEntries[0].rgPropVals = NULL;
|
|
}
|
|
|
|
//Merge the new list with the old list
|
|
sc = ScMergePropValues( (*lppAdrList)->aEntries[0].cValues,
|
|
(*lppAdrList)->aEntries[0].rgPropVals,
|
|
cValues,
|
|
rgProps,
|
|
&cValuesNew,
|
|
&lpPropArrayNew);
|
|
if (sc == S_OK)
|
|
{
|
|
// if OK replace the lpspropvalue array
|
|
// if not we havent changed anything
|
|
(*lppAdrList)->aEntries[0].cValues = cValuesNew;
|
|
if((*lppAdrList)->aEntries[0].rgPropVals)
|
|
MAPIFreeBuffer((*lppAdrList)->aEntries[0].rgPropVals);
|
|
(*lppAdrList)->aEntries[0].rgPropVals = lpPropArrayNew;
|
|
}
|
|
else
|
|
{
|
|
// If errors Free up the allocated memory
|
|
if (lpPropArrayNew)
|
|
MAPIFreeBuffer(lpPropArrayNew);
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
}
|
|
|
|
// we free this anyway whether the above succeeded or not
|
|
if (rgProps)
|
|
MAPIFreeBuffer(rgProps);
|
|
|
|
out:
|
|
|
|
return hr;
|
|
}
|