Windows2003-3790/inetcore/outlookexpress/wabw/wabapi/ui_reslv.c
2020-09-30 16:53:55 +02:00

1213 lines
38 KiB
C

/*--------------------------------------------------------------
*
*
* ui_reslv.c - shows the resolve name dialog
*
*
*
*
*
*
*
--------------------------------------------------------------*/
#include "_apipch.h"
extern HINSTANCE ghCommCtrlDLLInst;
#define MAX_RESLV_STRING 52 // Max # of characters to display in the static label ...
enum _ReturnValuesFromResolveDialog
{
RESOLVE_PICKUSER=0,
RESOLVE_CANCEL,
RESOLVE_OK
};
typedef struct _ResolveInfo
{
LPADRLIST * lppAdrList; // Stores the AdrList
ULONG nIndex; // Index of the item of interest
LPTSTR lpszDisplayName;// Preextracted display name for that
LPADRBOOK lpIAB; // Pointer to the IAB object
HWND hWndParent; // Stores hWndParents for dialog generating windows
ULONG ulFlag; // Stores Resolved or Ambiguos state
LPRECIPIENT_INFO lpContentsList;
LPMAPITABLE lpMapiTable;
BOOL bUnicode; // TRUE if MAPI_UNICODE specified in IAB::ResolveName
} RESOLVE_INFO, * LPRESOLVE_INFO;
static DWORD rgReslvHelpIDs[] =
{
IDC_RESOLVE_BUTTON_BROWSE, IDH_WAB_PICK_USER,
IDC_RESOLVE_LIST_MATCHES, IDH_WAB_CHK_NAME_LIST,
IDC_RESOLVE_STATIC_1, IDH_WAB_CHK_NAME_LIST,
IDC_RESOLVE_BUTTON_PROPS, IDH_WAB_PICK_RECIP_NAME_PROPERTIES,
IDC_RESOLVE_BUTTON_NEWCONTACT, IDH_WAB_PICK_RECIP_NAME_NEW,
0,0
};
//forward declarations
HRESULT HrResolveName(LPADRBOOK lpIAB,
HWND hWndParent,
HANDLE hPropertyStore,
ULONG nIndex,
ULONG ulFlag,
BOOL bUnicode,
LPADRLIST * lppAdrList,
LPMAPITABLE lpMapiTable);
INT_PTR CALLBACK fnResolve(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL ProcessResolveLVNotifications(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT HrShowPickUserDialog(LPRESOLVE_INFO lpRI, LPTSTR lpszCaption);
HRESULT HrShowNewEntryFromResolve(LPRESOLVE_INFO lpRI, HWND hWndParent, ULONG ulObjectType);
HRESULT HrFillLVWithMatches( HWND hWndLV,
LPRESOLVE_INFO lpRI);
HRESULT HrMergeSelectionWithOriginal(LPRESOLVE_INFO lpRI,
ULONG cbEID,
LPENTRYID lpEID);
void ExitResolveDialog(HWND hDlg, LPRESOLVE_INFO lpRI, int nRetVal);
BOOL GetLVSelectedItem(HWND hWndLV, LPRESOLVE_INFO lpRI);
///////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// HrShowResolveUI
//
// Wraps the UI for Resolve Names
//
//
//
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT HrShowResolveUI(IN LPADRBOOK lpIAB,
HWND hWndParent,
HANDLE hPropertyStore,
ULONG ulFlags, // WAB_RESOLVE_NO_NOT_FOUND_UI
LPADRLIST * lppAdrList,
LPFlagList *lppFlagList,
LPAMBIGUOUS_TABLES lpAmbiguousTables)
{
HRESULT hr = hrSuccess;
ULONG i=0;
LPFlagList lpFlagList= NULL;
LPMAPITABLE lpMapiTable = NULL;
BOOL bUnicode = (ulFlags & WAB_RESOLVE_UNICODE);
// if no common control, exit
if (NULL == ghCommCtrlDLLInst) {
hr = ResultFromScode(MAPI_E_UNCONFIGURED);
goto out;
}
if(!hPropertyStore || !lppAdrList || !lppFlagList || !(*lppAdrList) || !(*lppFlagList))
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
lpFlagList=(*lppFlagList);
// we need to scan the lpFlagList and look for unresolved entries
for (i = 0; i < lpFlagList->cFlags; i++)
{
//
// Occasionally someone (like athena) may hand us an adrlist with null rgPropVals
// We need to anticipate that.
//
if ( ((*lppAdrList)->aEntries[i].cValues == 0) ||
((*lppAdrList)->aEntries[i].rgPropVals == NULL) )
continue;
switch (lpFlagList->ulFlag[i])
{
case MAPI_RESOLVED:
break;
case MAPI_AMBIGUOUS:
//
// W2 - we now have an Ambiguous Table parameter .. for Unresolved
// entries, there is no Table but for Ambiguous entries, there is
// a corresponding ambiguous table filled in from the LDAP servers
//
if(lpAmbiguousTables)
{
if (lpAmbiguousTables->cEntries != 0)
{
lpMapiTable = lpAmbiguousTables->lpTable[i];
}
}
//Fall through
case MAPI_UNRESOLVED:
//
// We show a dialog asking the user what they want to do ...
// For this version, they can
// (b) browse the list of users or (c) cancel this user ..
// We will assume that we already the AdrList already has
// Recipient_Type and Display_Name and we only need to fill
// in the EntryID of this user ...
//
if ((! (ulFlags & WAB_RESOLVE_NO_NOT_FOUND_UI) ||
lpFlagList->ulFlag[i] == MAPI_AMBIGUOUS)) {
hr = HrResolveName( lpIAB,
hWndParent,
hPropertyStore,
i,
lpFlagList->ulFlag[i],
bUnicode,
lppAdrList,
lpMapiTable);
if (!HR_FAILED(hr))
lpFlagList->ulFlag[i] = MAPI_RESOLVED;
else
{
// Cancels are final .. other errors are not ..
if (hr == MAPI_E_USER_CANCEL)
goto out;
}
}
break;
}
}
out:
return hr;
}
// *** Dont change *** the order of the first 2 properties between here and the similar structure
// in ui_addr.c
enum _lppAdrListReturnedProps
{
propPR_DISPLAY_NAME,
propPR_ENTRYID,
TOTAL_ADRLIST_PROPS
};
////////////////////////////////////////////////////////////////////////////////////////
//
// HrResolveName - tackles one entry at a time ...
//
////////////////////////////////////////////////////////////////////////////////////////
HRESULT HrResolveName( IN LPADRBOOK lpIAB,
HWND hWndParent,
HANDLE hPropertyStore,
ULONG nIndex,
ULONG ulFlag,
BOOL bUnicode,
LPADRLIST * lppAdrList,
LPMAPITABLE lpMapiTable)
{
ULONG i=0;
LPTSTR lpszDisplayName = NULL, lpszEmailAddress = NULL;
int nRetVal = 0;
HRESULT hr = hrSuccess;
RESOLVE_INFO RI = {0};
LPADRLIST lpAdrList = *lppAdrList;
ULONG ulTagDN = PR_DISPLAY_NAME, ulTagEmail = PR_EMAIL_ADDRESS;
if(!bUnicode)
{
ulTagDN = CHANGE_PROP_TYPE(ulTagDN, PT_STRING8);
ulTagEmail = CHANGE_PROP_TYPE(ulTagEmail, PT_STRING8);
}
//Scan this adrlist entries properties
for(i=0;i < lpAdrList->aEntries[nIndex].cValues; i++)
{
if (lpAdrList->aEntries[nIndex].rgPropVals[i].ulPropTag == ulTagDN)
{
lpszDisplayName = bUnicode ?
(LPWSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ :
ConvertAtoW((LPSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ);
}
if (lpAdrList->aEntries[nIndex].rgPropVals[i].ulPropTag == ulTagEmail)
{
lpszEmailAddress = bUnicode ?
(LPWSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ :
ConvertAtoW((LPSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ);
}
}
// we need some display name info to resolve on ...
if (lpszDisplayName == NULL) //we need this info or cant proceed
{
if (lpszEmailAddress)
{
lpszDisplayName = lpszEmailAddress;
lpszEmailAddress = NULL;
}
else
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
}
RI.nIndex = nIndex;
RI.lppAdrList = lppAdrList;
RI.lpszDisplayName = lpszDisplayName;
RI.lpIAB = lpIAB;
RI.hWndParent = hWndParent;
RI.ulFlag = ulFlag;
RI.lpContentsList = NULL;
RI.lpMapiTable = lpMapiTable;
RI.bUnicode = bUnicode;
nRetVal = (int) DialogBoxParam( hinstMapiX,
MAKEINTRESOURCE(IDD_DIALOG_RESOLVENAME),
hWndParent,
fnResolve,
(LPARAM) &RI);
switch(nRetVal)
{
case RESOLVE_CANCEL:
hr = MAPI_E_USER_CANCEL; //Cancel, flag it as pass and dont change anything
goto out;
break;
case RESOLVE_OK:
hr = hrSuccess;
goto out;
case -1: // something went wrong ...
DebugPrintTrace(( TEXT("DialogBoxParam -> %u\n"), GetLastError()));
hr = E_FAIL;
goto out;
break;
} //switch
out:
if(!bUnicode) // <note> assumes UNICODE defined
{
LocalFreeAndNull(&lpszDisplayName);
LocalFreeAndNull(&lpszEmailAddress);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////////
//
// SetResolveUI -
//
//
/////////////////////////////////////////////////////////////////////////////////
BOOL SetResolveUI(HWND hDlg)
{
// This function initializes a list view
HrInitListView( GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES),
LVS_REPORT,
FALSE); // Hide or show column headers
// Set the font of all the children to the default GUI font
EnumChildWindows( hDlg,
SetChildDefaultGUIFont,
(LPARAM) 0);
return TRUE;
}
void SetLabelLDAP(HWND hDlg, HWND hWndLV)
{
// look at an entryid from the hWNdLV
// Use it only if its an LDAP entryid
// if the entryid is something else, we need to get its name and
// fill the structure accordingly
LPRECIPIENT_INFO lpItem;
if(ListView_GetItemCount(hWndLV) <= 0)
goto out;
lpItem = GetItemFromLV(hWndLV, 0);
if(lpItem)
{
LPTSTR lpServer = NULL;
LPTSTR lpDNS = NULL;
LPTSTR lpName = NULL;
TCHAR szName[40]; // we will limit the name to 40 chars so that the whole
// string will fit in the UI for really large chars
// is this an LDAP entryid ?
if (WAB_LDAP_MAILUSER == IsWABEntryID( lpItem->cbEntryID,
lpItem->lpEntryID,
&lpServer,
&lpDNS,
NULL, NULL, NULL))
{
//lpServer contains the server name
LPTSTR lpsz;
TCHAR szBuf[MAX_UI_STR];
TCHAR szTmp[MAX_PATH], *lpszTmp;
CopyTruncate(szName, lpServer, ARRAYSIZE(szName));
lpName = (LPTSTR) szName;
LoadString(hinstMapiX, idsResolveMatchesOnLDAP, szBuf, ARRAYSIZE(szBuf));
CopyTruncate(szTmp, lpName, MAX_PATH - 1);
lpszTmp = szTmp;
if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
szBuf,
0,0, //ignored
(LPTSTR) &lpsz,
MAX_UI_STR,
(va_list *)&lpszTmp))
{
SetDlgItemText(hDlg, IDC_RESOLVE_STATIC_MATCHES, lpsz);
IF_WIN32(LocalFree(lpsz);)
IF_WIN16(FormatMessageFreeMem(lpsz);)
}
}
}
out:
return;
}
void FillUI(HWND hDlg, HWND hWndLV, LPRESOLVE_INFO lpRI)
{
TCHAR szBuf[MAX_UI_STR];
ULONG nLen = 0;
LPTSTR lpszDisplayName = lpRI->lpszDisplayName;
BOOL bNothingFound = FALSE;
LPTSTR lpszBuffer = NULL;
LPTSTR lpName = NULL;
TCHAR szTmp[MAX_PATH], *lpszTmp;
TCHAR szName[40]; // we will limit the name to 40 chars so that the whole
// string will fit in the UI for really large chars
if ( (lpRI->ulFlag == MAPI_UNRESOLVED) ||
(HR_FAILED(HrFillLVWithMatches(hWndLV, lpRI)))
)
bNothingFound = TRUE;
nLen = CopyTruncate(szName, lpszDisplayName, ARRAYSIZE(szName));
lpName = (LPTSTR) szName;
LoadString(hinstMapiX, (bNothingFound ? IDS_RESOLVE_NO_MATCHES_FOR : IDS_ADDRBK_RESOLVE_CAPTION),
szBuf, ARRAYSIZE(szBuf));
// Win9x bug FormatMessage cannot have more than 1023 chars
CopyTruncate(szTmp, lpName, 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))
{
SetDlgItemText(hDlg, IDC_RESOLVE_STATIC_1,lpszBuffer);
IF_WIN32(LocalFreeAndNull(&lpszBuffer);)
IF_WIN16(FormatMessageFreeMem(lpszBuffer);)
}
if(bNothingFound)
{
// If this has already been flagged as unresolved .. or
// the attempt to find fuzzy matches was unsuccessful ...
// tell 'em nothing found ...
LoadString(hinstMapiX, IDS_RESOLVE_NO_MATCHES, szBuf, ARRAYSIZE(szBuf));
{
LV_ITEM lvI = {0};
lvI.mask = LVIF_TEXT;
lvI.cchTextMax = lstrlen(szBuf)+1;
lvI.pszText = szBuf;
ListView_InsertItem(hWndLV, &lvI);
ListView_SetColumnWidth(hWndLV,0,400); //400 is a totally random number, we just want the column to be big enough not to truncate text
}
EnableWindow(hWndLV,FALSE);
EnableWindow(GetDlgItem(hDlg,IDC_RESOLVE_BUTTON_PROPS),FALSE);
EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_RESOLVE_BUTTON_OK*/),FALSE);
ShowWindow(GetDlgItem(hDlg,IDC_RESOLVE_STATIC_MATCHES),SW_HIDE);
}
else
{
// if the search results are from an ldap server, we need
// to set the label on the dialog to say the results are from
// an LDAP server
SetLabelLDAP(hDlg, hWndLV);
// If the list view is filled, select the first item
if (ListView_GetItemCount(hWndLV) > 0)
{
LVSelectItem(hWndLV, 0);
SetFocus(hWndLV);
}
}
return;
}
/*************************************************************************
//
// resolve Dialog - simple implementation for 0.5
//
**************************************************************************/
INT_PTR CALLBACK fnResolve(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR szBuf[MAX_UI_STR];
ULONG nLen = 0, nLenMax = 0, nRetVal=0;
HRESULT hr = hrSuccess;
LPRESOLVE_INFO lpRI = (LPRESOLVE_INFO) GetWindowLongPtr(hDlg,DWLP_USER);
switch(message)
{
case WM_INITDIALOG:
{
HWND hWndLV = GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES);
SetWindowLongPtr(hDlg,DWLP_USER,lParam); //Save this for future reference
lpRI = (LPRESOLVE_INFO) lParam;
SetResolveUI(hDlg);
FillUI(hDlg, hWndLV, lpRI);
}
break;
default:
#ifndef WIN16
if((g_msgMSWheel && message == g_msgMSWheel)
// || message == WM_MOUSEWHEEL
)
{
SendMessage(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES), message, wParam, lParam);
break;
}
#endif // !WIN16
return FALSE;
break;
case WM_SYSCOLORCHANGE:
//Forward any system changes to the list view
SendMessage(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES), message, wParam, lParam);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam,lParam))
{
default:
return ProcessActionCommands((LPIAB) lpRI->lpIAB,
GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),
hDlg, message, wParam, lParam);
break;
case IDM_LVCONTEXT_DELETE: //We renamed the delete on the context menu to say TEXT("Show more Names")
case IDC_RESOLVE_BUTTON_BROWSE:
GetWindowText(hDlg, szBuf, ARRAYSIZE(szBuf));
lpRI->hWndParent = hDlg;
hr = HrShowPickUserDialog(lpRI, szBuf);
if(!HR_FAILED(hr))
{
if(lpRI->lpContentsList)
ClearListView( GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),
&(lpRI->lpContentsList));
ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
// EndDialog( hDlg, RESOLVE_OK);
}
else
{
if(hr != MAPI_E_USER_CANCEL)
{
// Some error occured .. dont know what .. but since this dialog
// will stick around, need to warn the user about it ...
ShowMessageBox(hDlg,idsCouldNotSelectUser,MB_ICONERROR | MB_OK);
}
}
break;
case IDOK:
case IDC_RESOLVE_BUTTON_OK:
if (GetLVSelectedItem(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),lpRI))
ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
break;
case IDCANCEL:
case IDC_RESOLVE_BUTTON_CANCEL:
ExitResolveDialog(hDlg, lpRI, RESOLVE_CANCEL);
break;
case IDM_LVCONTEXT_NEWCONTACT:
case IDC_RESOLVE_BUTTON_NEWCONTACT:
hr = HrShowNewEntryFromResolve(lpRI,hDlg,MAPI_MAILUSER);
if (!HR_FAILED(hr))
ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
break;
case IDM_LVCONTEXT_NEWGROUP:
// case IDC_RESOLVE_BUTTON_NEWCONTACT:
hr = HrShowNewEntryFromResolve(lpRI,hDlg,MAPI_DISTLIST);
if (!HR_FAILED(hr))
ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
break;
case IDM_LVCONTEXT_COPY:
HrCopyItemDataToClipboard(hDlg, lpRI->lpIAB, GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES));
break;
case IDM_LVCONTEXT_PROPERTIES:
case IDC_RESOLVE_BUTTON_PROPS:
EnableWindow(GetDlgItem(hDlg, IDC_RESOLVE_BUTTON_PROPS), FALSE);
HrShowLVEntryProperties(GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES), 0,
lpRI->lpIAB, NULL);
EnableWindow(GetDlgItem(hDlg, IDC_RESOLVE_BUTTON_PROPS), TRUE);
break;
}
break;
case WM_CLOSE:
//treat it like a cancel button
SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_RESOLVE_BUTTON_CANCEL, 0);
break;
case WM_CONTEXTMENU:
if ((HWND)wParam == GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES))
{
ShowLVContextMenu( lvDialogResolve, (HWND)wParam, NULL, lParam, NULL,lpRI->lpIAB, NULL);
}
else
{
WABWinHelp((HWND) wParam,
g_szWABHelpFileName,
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) rgReslvHelpIDs );
}
break;
case WM_HELP:
WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
g_szWABHelpFileName,
HELP_WM_HELP,
(DWORD_PTR)(LPSTR) rgReslvHelpIDs );
break;
case WM_NOTIFY:
switch((int) wParam)
{
case IDC_RESOLVE_LIST_MATCHES:
return ProcessResolveLVNotifications(hDlg,message,wParam,lParam);
}
break;
}
return TRUE;
}
/////////////////////////////////////////////////////////////
//
// Processes Notification messages for the list view control
//
//
////////////////////////////////////////////////////////////
BOOL ProcessResolveLVNotifications(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam;
switch(pNm->hdr.code)
{
case NM_DBLCLK:
// Doubleclick on the list view is equivalent to a OK with a selected item
SendMessage(hDlg, WM_COMMAND, (WPARAM) IDOK/*IDC_RESOLVE_BUTTON_OK*/, 0);
break;
case NM_CUSTOMDRAW:
return (0 != ProcessLVCustomDraw(hDlg, lParam, TRUE));
break;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
// Pops up the New Entry dialog and then replaces the old entry with the
// newly created entry ...
//
//////////////////////////////////////////////////////////////////////////////
HRESULT HrShowNewEntryFromResolve(LPRESOLVE_INFO lpRI, HWND hWndParent, ULONG ulObjectType)
{
ULONG cbEID=0;
LPENTRYID lpEID=NULL;
HRESULT hr = hrSuccess;
ULONG cbTplEID = 0;
LPENTRYID lpTplEID = NULL;
//OutputDebugString( TEXT("HrShowNewEntryFromResolve entry\n"));
if (ulObjectType!=MAPI_MAILUSER && ulObjectType!=MAPI_DISTLIST)
goto out;
if(HR_FAILED(hr = HrGetWABTemplateID( lpRI->lpIAB,
ulObjectType,
&cbTplEID,
&lpTplEID)))
{
DebugPrintError(( TEXT("HrGetWABTemplateID failed: %x\n"), hr));
goto out;
}
if (HR_FAILED(hr = (lpRI->lpIAB)->lpVtbl->NewEntry( lpRI->lpIAB,
(ULONG_PTR) hWndParent,
0,
0,NULL,
cbTplEID,lpTplEID,
&cbEID,&lpEID)))
{
DebugPrintError(( TEXT("NewEntry failed: %x\n"),hr));
goto out;
}
// We created a new entry, and we want to use it to replace the old unresolved entry
hr = HrMergeSelectionWithOriginal(lpRI, cbEID, lpEID);
out:
FreeBufferAndNull(&lpEID);
FreeBufferAndNull(&lpTplEID);
//OutputDebugString( TEXT("HrShowNewEntryFromResolve exit\n"));
return hr;
}
////////////////////////////////////////////////////////////////
//
// Takes entry id of users selection and returns it appropriately ...
//
//
////////////////////////////////////////////////////////////////
HRESULT HrMergeSelectionWithOriginal(LPRESOLVE_INFO lpRI,
ULONG cbEID,
LPENTRYID lpEID)
{
HRESULT hr = hrSuccess;
ULONG cValues = 0;
LPSPropValue lpPropArray = NULL;
LPADRLIST lpAdrList = *(lpRI->lppAdrList);
SCODE sc;
ULONG nIndex = lpRI->nIndex;
//OutputDebugString( TEXT("HrMergeSelectionWithOriginal entry\n"));
hr = HrGetPropArray((lpRI->lpIAB),
(LPSPropTagArray) &ptaResolveDefaults,
cbEID,
lpEID,
lpRI->bUnicode ? MAPI_UNICODE : 0,
&cValues,
&lpPropArray);
if (HR_FAILED(hr)) goto out;
if ((!cValues) || (!lpPropArray))
{
hr = E_FAIL;
goto out;
}
else
{
LPSPropValue lpPropArrayNew = NULL;
ULONG cValuesNew = 0;
sc = ScMergePropValues( lpAdrList->aEntries[nIndex].cValues,
lpAdrList->aEntries[nIndex].rgPropVals,
cValues,
lpPropArray,
&cValuesNew,
&lpPropArrayNew);
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
if ((lpPropArrayNew) && (cValuesNew > 0))
{
// [PaulHi] Raid 69325
// We need to convert these properties to ANSI since we are now the
// UNICODE WAB and if our client is !MAPI_UNICODE
if (!(lpRI->bUnicode))
{
if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0))
goto out;
}
MAPIFreeBuffer(lpAdrList->aEntries[nIndex].rgPropVals);
lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
lpAdrList->aEntries[nIndex].cValues = cValuesNew;
}
}
hr = hrSuccess;
out:
if (lpPropArray)
MAPIFreeBuffer(lpPropArray);
//OutputDebugString( TEXT("HrMergeSelectionWithOriginal exit\n"));
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////
//
// HrShowPickuserDialog - shows the pick user dialog
//
////////////////////////////////////////////////////////////////////////////////////////
HRESULT HrShowPickUserDialog(LPRESOLVE_INFO lpRI,
LPTSTR lpszCaption)
{
LPADRLIST lpAdrList = *(lpRI->lppAdrList);
ULONG nIndex = lpRI->nIndex;
LPTSTR lpszDisplayName = lpRI->lpszDisplayName;
LPADRLIST lpAdrListSingle = NULL;
ADRPARM AdrParms = {0};
SCODE sc;
HRESULT hr = hrSuccess;
DWORD cchSize = 0;
//OutputDebugString( TEXT("HrShowPickUserDialog entry\n"));
// create an AdrList structure which we pass to Address ... to show UI
// We pass in the bare minimum props here which are - Display Name and Entry ID field (which is really NULL)
// The Address UI, if successful, gives us a whole list of props back which we merge with
// the original list, overwriting what we got back fresh ...
sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY), &lpAdrListSingle);
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
lpAdrListSingle->cEntries = 1;
lpAdrListSingle->aEntries[0].ulReserved1 = 0;
lpAdrListSingle->aEntries[0].cValues = TOTAL_ADRLIST_PROPS;
sc = MAPIAllocateBuffer( TOTAL_ADRLIST_PROPS * sizeof(SPropValue),
(LPVOID *) (&(lpAdrListSingle->aEntries[0].rgPropVals)));
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
cchSize = (lstrlen(lpszDisplayName)+1);
sc = MAPIAllocateMore((sizeof(TCHAR) * cchSize),
lpAdrListSingle->aEntries[0].rgPropVals,
(LPVOID *) (&lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].Value.LPSZ));
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
StrCpyN(lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].Value.LPSZ, lpszDisplayName, cchSize);
lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].ulPropTag = PR_ENTRYID;
lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].Value.bin.cb = 0;
lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].Value.bin.lpb = NULL;
AdrParms.cDestFields = 0;
AdrParms.ulFlags = DIALOG_MODAL | ADDRESS_ONE | MAPI_UNICODE;
AdrParms.lpszCaption = lpszCaption;
if (!HR_FAILED(hr = (lpRI->lpIAB)->lpVtbl->Address(
lpRI->lpIAB,
(PULONG_PTR) &(lpRI->hWndParent),
&AdrParms,
&lpAdrListSingle)))
{
// We successfully selected some user and the lpAdrListSingle contains
// a new set of lpProps for that user ...
//
LPSPropValue lpPropArrayNew = NULL;
ULONG cValuesNew = 0;
sc = ScMergePropValues( lpAdrList->aEntries[nIndex].cValues,
lpAdrList->aEntries[nIndex].rgPropVals,
lpAdrListSingle->aEntries[0].cValues,
lpAdrListSingle->aEntries[0].rgPropVals,
&cValuesNew,
&lpPropArrayNew);
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
if ((lpPropArrayNew) && (cValuesNew > 0))
{
// [PaulHi] Raid 69325
// We need to convert these properties to ANSI since we are now the
// UNICODE WAB and if our client is !MAPI_UNICODE
if (!(lpRI->bUnicode))
{
if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0))
goto out;
}
MAPIFreeBuffer(lpAdrList->aEntries[nIndex].rgPropVals);
lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
lpAdrList->aEntries[nIndex].cValues = cValuesNew;
}
}
out:
if (lpAdrListSingle)
{
FreePadrlist(lpAdrListSingle);
}
//OutputDebugString( TEXT("HrShowPickUserDialog exit\n"));
return hr;
}
//$$/////////////////////////////////////////////////////////////////////////////////
//
//
// HrFillLVWithMatches - fills the list view with close matches for the given name
//
// Fails (E_FAIL) if it doesnt find anything to fill in the List View
//
//////////////////////////////////////////////////////////////////////////////////////////
HRESULT HrFillLVWithMatches( HWND hWndLV,
LPRESOLVE_INFO lpRI)
{
HRESULT hr = hrSuccess;
LPSBinary * lprgsbEntryIDs = NULL;
ULONG iolkci=0, colkci = 0;
OlkContInfo *rgolkci;
ULONG * lpcValues = NULL;
ULONG i = 0, j = 0;
LPSRowSet lpSRowSet = NULL;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
ULONG ulFlags = AB_FUZZY_FIND_ALL;
EnterCriticalSection(&(((LPIAB)(lpRI->lpIAB))->cs));
if (pt_bIsWABOpenExSession)
{
colkci = ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->colkci;
Assert(colkci);
rgolkci = ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->rgolkci;
Assert(rgolkci);
}
else
if (bAreWABAPIProfileAware((LPIAB)lpRI->lpIAB))
{
colkci = ((LPIAB)(lpRI->lpIAB))->cwabci;
Assert(colkci);
rgolkci = ((LPIAB)(lpRI->lpIAB))->rgwabci;
Assert(rgolkci);
if(colkci > 1 && !lpRI->lpMapiTable)
ulFlags |= AB_FUZZY_FIND_PROFILEFOLDERONLY;
}
else
colkci = 1;
lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT, colkci*sizeof(LPSBinary));
lpcValues = LocalAlloc(LMEM_ZEROINIT, colkci*sizeof(ULONG));
if(!lprgsbEntryIDs || !lpcValues)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
//
// First search the property store
//
if(!(lpRI->lpMapiTable))
{
// if we dont have a ambiguous table to look in then that means we look in the
// property store for ambiguous stuff ...
while (iolkci < colkci)
{
hr = HrFindFuzzyRecordMatches(
((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
(colkci == 1) ? NULL : rgolkci[iolkci].lpEntryID,
lpRI->lpszDisplayName,
ulFlags, //flags
&(lpcValues[iolkci]),
&(lprgsbEntryIDs[iolkci]));
iolkci++;
}
if (HR_FAILED(hr))
goto out;
if(bAreWABAPIProfileAware((LPIAB)lpRI->lpIAB))
{
// it's possible that nothing in the profile matched but other stuff in the WAB matched
// Doublecheck that if we found nothing in the profile, we can search the whole WAB
ULONG nCount = 0;
for(i=0;i<colkci;i++)
nCount += lpcValues[i];
if(!nCount)
{
// search the whole WAB
hr = HrFindFuzzyRecordMatches(
((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
NULL,
lpRI->lpszDisplayName,
AB_FUZZY_FIND_ALL, //flags
&(lpcValues[0]),
&(lprgsbEntryIDs[0]));
}
}
// Now we have a list of EntryIDs
// Use them to populate the List View
//
// We can
// (a) Read the entryids one by one and fill the list view
// AddWABEntryToListView
// or
// (b) We can create an lpContentsList and fill it in one shot
// HrFillListView
// We'll go with (a) for now
// If performance is bad, do (b)
for(i=0;i<colkci;i++)
{
for(j=0;j<lpcValues[i];j++)
{
AddWABEntryToListView( lpRI->lpIAB,
hWndLV,
lprgsbEntryIDs[i][j].cb,
(LPENTRYID) lprgsbEntryIDs[i][j].lpb,
&(lpRI->lpContentsList));
}
}
}
else if(lpRI->lpMapiTable)
{
// if there is a MAPI ambiguous contents table associated with this display name
// use it to further fill in the lpContentsList
BOOL bUnicode = ((LPVUE)lpRI->lpMapiTable)->lptadParent->bMAPIUnicodeTable;
hr = HrQueryAllRows(lpRI->lpMapiTable,
NULL,
NULL,
NULL,
0,
&lpSRowSet);
if (HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
goto out;
}
for(i=0;i<lpSRowSet->cRows;i++)
{
LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
LPRECIPIENT_INFO lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
if (!lpItem)
{
DebugPrintError(( TEXT("LocalAlloc Failed \n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
if(!bUnicode) // the props are in ANSI - convert to UNICODE for our use
{
if(ScConvertAPropsToW((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArray, ulcPropCount, 0))
goto out;
}
GetRecipItemFromPropArray(ulcPropCount, lpPropArray, &lpItem);
// The critical prop is display name - without it we are nothing ...
// If no display name, junk this entry and continue ..
if (!lstrlen(lpItem->szDisplayName) || (lpItem->cbEntryID == 0)) //This entry id is not allowed
{
FreeRecipItem(&lpItem);
continue;
}
AddSingleItemToListView(hWndLV, lpItem);
//
// Hook in the lpItem into the lpContentsList so we can free it later
//
lpItem->lpPrev = NULL;
lpItem->lpNext = lpRI->lpContentsList;
if (lpRI->lpContentsList)
lpRI->lpContentsList->lpPrev = lpItem;
lpRI->lpContentsList = lpItem;
lpItem = NULL;
} //for i ....
}
//
// If, after all this we still have an empty list box, we will report a failure
//
if(ListView_GetItemCount(hWndLV)<=0)
{
DebugPrintTrace(( TEXT("Empty List View - no matches found\n")));
hr = E_FAIL;
goto out;
}
out:
for(i=0;i<colkci;i++)
{
FreeEntryIDs(((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
lpcValues[i],
lprgsbEntryIDs[i]);
}
if(lpcValues)
LocalFree(lpcValues);
if(lprgsbEntryIDs)
LocalFree(lprgsbEntryIDs);
if (lpSRowSet)
FreeProws(lpSRowSet);
//
// ReSet the ListView SortAscending style off
//
// SetWindowLong(hWndLV, GWL_STYLE, (dwStyle | LVS_SORTASCENDING));
LeaveCriticalSection(&(((LPIAB)(lpRI->lpIAB))->cs));
return hr;
}
//////////////////////////////////////////////////////////////////////////
//
// Returns the item selected in the list view
//
////////////////////////////////////////////////////////////////////////
BOOL GetLVSelectedItem(HWND hWndLV, LPRESOLVE_INFO lpRI)
{
int iItemIndex = 0;
LV_ITEM lvi = {0};
LPRECIPIENT_INFO lpItem;
BOOL bRet = FALSE;
//OutputDebugString( TEXT("GetLVSelectedItem Entry\n"));
if (ListView_GetSelectedCount(hWndLV) != 1)
goto out;
iItemIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
lpItem = GetItemFromLV(hWndLV, iItemIndex);
if(lpItem)
HrMergeSelectionWithOriginal(lpRI,lpItem->cbEntryID,lpItem->lpEntryID);
else
goto out;
bRet = TRUE;
out:
//OutputDebugString( TEXT("GetLVSelectedItem Exit\n"));
return bRet;
}
////////////////////////////////////////////////////////////////////////
//
// Generic exit function
//
////////////////////////////////////////////////////////////////////////
void ExitResolveDialog(HWND hDlg, LPRESOLVE_INFO lpRI, int nRetVal)
{
HWND hWndLV = GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES);
//OutputDebugString( TEXT("ExitResolveDialog Entry\n"));
if(lpRI->lpContentsList)
{
ClearListView(hWndLV,&(lpRI->lpContentsList));
}
if(ListView_GetItemCount(hWndLV) > 0)
ListView_DeleteAllItems(hWndLV);
EndDialog(hDlg, nRetVal);
//OutputDebugString( TEXT("ExitResolveDialog Exit\n"));
return;
}