Leaked source code of windows server 2003
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.
 
 
 
 
 
 

9426 lines
312 KiB

////////////////////////////////////////////////////////////////////////////////
//
// UIMISC.C - common miscellaneous functions used by the UI
//
//
////////////////////////////////////////////////////////////////////////////////
#include "_apipch.h"
const LPTSTR szLDAPDefaultCountryValue = TEXT("LDAP Default Country");
const LPTSTR szTrailingDots = TEXT("...");
const LPTSTR szArrow = TEXT(" ->");
const LPTSTR szBackSlash = TEXT("\\");
extern BOOL bDNisByLN;
extern BOOL bIsPasteData();
HINSTANCE ghCommDlgInst = NULL;
extern HINSTANCE ghCommCtrlDLLInst;
extern ULONG gulCommCtrlDLLRefCount;
extern void SetVirtualPABEID(LPIAB lpIAB, ULONG * lpcb, LPENTRYID * lppb);
extern void vTurnOffAllNotifications();
extern void vTurnOnAllNotifications();
LP_INITCOMMONCONTROLSEX gpfnInitCommonControlsEx = NULL;
LPIMAGELIST_SETBKCOLOR gpfnImageList_SetBkColor = NULL;
LPIMAGELIST_DRAW gpfnImageList_Draw = NULL;
LPIMAGELIST_DESTROY gpfnImageList_Destroy = NULL;
LPIMAGELIST_LOADIMAGE_A gpfnImageList_LoadImageA = NULL;
LPPROPERTYSHEET_A gpfnPropertySheetA = NULL;
LP_CREATEPROPERTYSHEETPAGE_A gpfnCreatePropertySheetPageA = NULL;
LPIMAGELIST_LOADIMAGE_W gpfnImageList_LoadImageW = NULL;
LPPROPERTYSHEET_W gpfnPropertySheetW = NULL;
LP_CREATEPROPERTYSHEETPAGE_W gpfnCreatePropertySheetPageW = NULL;
// CommCtrl function names
static const TCHAR cszCommCtrlClientDLL[] = TEXT("COMCTL32.DLL");
static const char cszInitCommonControlsEx[] = "InitCommonControlsEx";
static const char cszImageList_SetBkColor[] = "ImageList_SetBkColor";
static const char cszImageList_LoadImageA[] = "ImageList_LoadImageA";
static const char cszPropertySheetA[] = "PropertySheetA";
static const char cszCreatePropertySheetPageA[] = "CreatePropertySheetPageA";
static const char cszImageList_LoadImageW[] = "ImageList_LoadImageW";
static const char cszPropertySheetW[] = "PropertySheetW";
static const char cszCreatePropertySheetPageW[] = "CreatePropertySheetPageW";
static const char cszImageList_Draw[] = "ImageList_Draw";
static const char cszImageList_Destroy[] = "ImageList_Destroy";
// API table for CommonControl function addresses to fetch
#define NUM_CommCtrlAPI_PROCS 10
APIFCN CommCtrlAPIList[NUM_CommCtrlAPI_PROCS] =
{
{ (PVOID *) &gpfnInitCommonControlsEx, cszInitCommonControlsEx},
{ (PVOID *) &gpfnImageList_SetBkColor, cszImageList_SetBkColor},
{ (PVOID *) &gpfnImageList_Draw, cszImageList_Draw},
{ (PVOID *) &gpfnImageList_Destroy, cszImageList_Destroy},
{ (PVOID *) &gpfnImageList_LoadImageA, cszImageList_LoadImageA},
{ (PVOID *) &gpfnPropertySheetA, cszPropertySheetA},
{ (PVOID *) &gpfnCreatePropertySheetPageA, cszCreatePropertySheetPageA},
{ (PVOID *) &gpfnImageList_LoadImageW, cszImageList_LoadImageW},
{ (PVOID *) &gpfnPropertySheetW, cszPropertySheetW},
{ (PVOID *) &gpfnCreatePropertySheetPageW, cszCreatePropertySheetPageW}
};
#ifdef COLSEL_MENU
// for menu->column selection mapping
#define MAXNUM_MENUPROPS 12
const ULONG MenuToPropTagMap[] = {
PR_HOME_TELEPHONE_NUMBER,
PR_BUSINESS_TELEPHONE_NUMBER,
PR_PAGER_TELEPHONE_NUMBER,
PR_CELLULAR_TELEPHONE_NUMBER,
PR_BUSINESS_FAX_NUMBER,
PR_HOME_FAX_NUMBER,
PR_COMPANY_NAME,
PR_TITLE,
PR_DEPARTMENT_NAME,
PR_OFFICE_LOCATION,
PR_BIRTHDAY,
PR_WEDDING_ANNIVERSARY
};
#endif // COLSEL_MENU
void CleanAddressString(TCHAR * szAddress);
static const LPTSTR g_szComDlg32 = TEXT("COMDLG32.DLL");
// Delay load substitutes for commdlg functions
//
BOOL (*pfnGetOpenFileNameA)(LPOPENFILENAMEA pof);
BOOL (*pfnGetOpenFileNameW)(LPOPENFILENAMEW pof);
BOOL GetOpenFileName(LPOPENFILENAME pof)
{
// static BOOL (*pfnGetOpenFileName)(LPOPENFILENAME pof);
if(!ghCommDlgInst)
ghCommDlgInst = LoadLibrary(g_szComDlg32);
if(ghCommDlgInst)
{
if ( pfnGetOpenFileNameA == NULL )
pfnGetOpenFileNameA = (BOOL (*)(LPOPENFILENAMEA))GetProcAddress(ghCommDlgInst, "GetOpenFileNameA");
if ( pfnGetOpenFileNameW == NULL )
pfnGetOpenFileNameW = (BOOL (*)(LPOPENFILENAMEW))GetProcAddress(ghCommDlgInst, "GetOpenFileNameW");
if (pfnGetOpenFileNameA && pfnGetOpenFileNameW)
return pfnGetOpenFileName(pof);
}
return -1;
}
BOOL (*pfnGetSaveFileNameA)(LPOPENFILENAMEA pof);
BOOL (*pfnGetSaveFileNameW)(LPOPENFILENAMEW pof);
BOOL GetSaveFileName(LPOPENFILENAME pof)
{
// static BOOL (*pfnGetSaveFileName)(LPOPENFILENAME pof);
if(!ghCommDlgInst)
ghCommDlgInst = LoadLibrary(g_szComDlg32);
if(ghCommDlgInst)
{
if ( pfnGetSaveFileNameA == NULL )
pfnGetSaveFileNameA = (BOOL (*)(LPOPENFILENAMEA))GetProcAddress(ghCommDlgInst, "GetSaveFileNameA");
if ( pfnGetSaveFileNameW == NULL )
pfnGetSaveFileNameW = (BOOL (*)(LPOPENFILENAMEW))GetProcAddress(ghCommDlgInst, "GetSaveFileNameW");
if ( pfnGetSaveFileNameA && pfnGetSaveFileNameW )
return pfnGetSaveFileName(pof);
}
return -1;
}
BOOL (*pfnPrintDlgA)(LPPRINTDLGA lppd);
BOOL (*pfnPrintDlgW)(LPPRINTDLGW lppd);
BOOL PrintDlg(LPPRINTDLG lppd)
{
// static BOOL (*pfnPrintDlg)(LPPRINTDLG lppd);
if(!ghCommDlgInst)
ghCommDlgInst = LoadLibrary(g_szComDlg32);
if(ghCommDlgInst)
{
if ( pfnPrintDlgA == NULL )
pfnPrintDlgA = (BOOL (*)(LPPRINTDLGA))GetProcAddress(ghCommDlgInst, "PrintDlgA");
if ( pfnPrintDlgW == NULL )
pfnPrintDlgW = (BOOL (*)(LPPRINTDLGW))GetProcAddress(ghCommDlgInst, "PrintDlgW");
if ( pfnPrintDlgA && pfnPrintDlgW )
return pfnPrintDlg(lppd);
}
return -1;
}
/*
- PrintDlgEx
-
- Loads the PrintDlgEx from the ComDlg32.dll
- If lppdex is NULL, then just loads and returns S_OK (this way we test for support for PrintDlgEx
- on the current system .. instead of trying to look at the OS version etc)
-
- Returns MAPI_E_NOT_FOUND if no support on OS
-
*/
HRESULT (*pfnPrintDlgExA)(LPPRINTDLGEXA lppdex);
HRESULT (*pfnPrintDlgExW)(LPPRINTDLGEXW lppdex);
HRESULT PrintDlgEx(LPPRINTDLGEX lppdex)
{
// static HRESULT (*pfnPrintDlgEx)(LPPRINTDLGEX lppdex);
if(!ghCommDlgInst)
ghCommDlgInst = LoadLibrary(g_szComDlg32);
if(ghCommDlgInst)
{
if ( pfnPrintDlgExA == NULL )
pfnPrintDlgExA = (HRESULT (*)(LPPRINTDLGEXA))GetProcAddress(ghCommDlgInst, "PrintDlgExA");
if ( pfnPrintDlgExW == NULL )
pfnPrintDlgExW = (HRESULT (*)(LPPRINTDLGEXW))GetProcAddress(ghCommDlgInst, "PrintDlgExW");
if (!pfnPrintDlgExA || !pfnPrintDlgExW)
{
DebugTrace( TEXT("PrintDlgEx not found - %d\n"),GetLastError());
return MAPI_E_NOT_FOUND;
}
if(!lppdex)
return S_OK; //just testing for presence of this function
return pfnPrintDlgEx(lppdex);
}
return E_FAIL;
}
extern void DeinitCommDlgLib()
{
if(ghCommDlgInst)
{
FreeLibrary(ghCommDlgInst);
ghCommDlgInst = NULL;
}
}
//$$
//
// HandleSaveChangedInsufficientDiskSpace - Called when savechanges returns
// insufficient disk space. If user selects to proceed
//
//
HRESULT HandleSaveChangedInsufficientDiskSpace(HWND hWnd, LPMAILUSER lpMailUser)
{
HRESULT hr = MAPI_E_NOT_ENOUGH_DISK;
while(hr == MAPI_E_NOT_ENOUGH_DISK)
{
if(IDOK == ShowMessageBox( hWnd,
idsNotEnoughDiskSpace,
MB_OKCANCEL | MB_ICONEXCLAMATION))
{
// try saving again
hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
KEEP_OPEN_READWRITE);
}
else
hr = MAPI_E_USER_CANCEL;
}
return hr;
}
//$$////////////////////////////////////////////////////////////////
//
// SetRecipColumns - sets the columns we want to populate the
// RECIPIENTINFO item structures with
//
//////////////////////////////////////////////////////////////////
#define RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES 7 // Keep this in sync with ptaRecipArray below
HRESULT SetRecipColumns(LPMAPITABLE lpContentsTable)
{
HRESULT hr = S_OK;
SizedSPropTagArray(16, ptaRecipArray) =
{
16,
{
PR_DISPLAY_NAME,
PR_SURNAME,
PR_GIVEN_NAME,
PR_MIDDLE_NAME,
PR_COMPANY_NAME,
PR_NICKNAME,
PR_EMAIL_ADDRESS,
PR_CONTACT_EMAIL_ADDRESSES, // [PaulHi] Use for PR_EMAIL_ADDRESS if no PR_EMAIL_ADDRESS exists
PR_ENTRYID,
PR_OBJECT_TYPE,
PR_USER_X509_CERTIFICATE,
PR_HOME_TELEPHONE_NUMBER,
PR_OFFICE_TELEPHONE_NUMBER,
PR_WAB_THISISME,
PR_WAB_YOMI_FIRSTNAME, //keep these ruby props at the end of the list
PR_WAB_YOMI_LASTNAME,
}
};
if(PR_WAB_CUSTOMPROP1)
ptaRecipArray.aulPropTag[11] = PR_WAB_CUSTOMPROP1;
if(PR_WAB_CUSTOMPROP2)
ptaRecipArray.aulPropTag[12] = PR_WAB_CUSTOMPROP2;
if(!bIsRubyLocale()) // Don't ask for Ruby Props if we don't need em
ptaRecipArray.cValues -= 2;
hr =lpContentsTable->lpVtbl->SetColumns(lpContentsTable,
(LPSPropTagArray)&ptaRecipArray, 0);
return hr;
}
//$$////////////////////////////////////////////////////////////////
//
// GetABContentsList Gets a contents list
//
// hPropertyStore handle to property store - this can be null for
// non-property store containers
// cbContEntryID entryid of container
// lpContEntryID cont entry id
// lpPTA, Array of prop tags to fill in the list view
// Can be null - in which case default array will be used
// lpPropRes Filter which caller can supply - if null TEXT("DisplayName") is the default
// ulFlags Used with Filter - either 0 or AB_MATCH_PROP_ONLY
// bGetProfileContents - If TRUE and profiles, gets full list of profile contents - if false
// IF FALSE, checks if profiles are ON and gets container contents..
// lppContentsList Returned Contents list pointing off to entries
//
//////////////////////////////////////////////////////////////////
HRESULT HrGetWABContentsList( LPIAB lpIAB,
SORT_INFO SortInfo,
LPSPropTagArray lpPTA,
LPSPropertyRestriction lpPropRes,
ULONG ulFlags,
LPSBinary lpsbContainer,
BOOL bGetProfileContents,
LPRECIPIENT_INFO * lppContentsList)
{
HRESULT hr = hrSuccess;
ULONG i = 0,j=0;
LPRECIPIENT_INFO lpItem = NULL;
LPRECIPIENT_INFO lpLastListItem = NULL;
HANDLE hPropertyStore = lpIAB->lpPropertyStore->hPropertyStore;
SPropertyRestriction PropRes = {0};
ULONG ulContentsTableFlags = MAPI_UNICODE | WAB_CONTENTTABLE_NODATA;
ULONG ulcPropCount = 0;
LPULONG lpPropTagArray = NULL;
LPCONTENTLIST lpContentList = NULL;
/****/
LPCONTAINER lpContainer = NULL;
LPMAPITABLE lpContentsTable = NULL;
LPSRowSet lpSRowSet = NULL;
ULONG cbContainerEID = 0;
LPENTRYID lpContainerEID = NULL;
ULONG ulObjectType = 0;
if(lpsbContainer)
{
cbContainerEID = lpsbContainer->cb;
lpContainerEID = (LPENTRYID)lpsbContainer->lpb;
}
if(!cbContainerEID || !lpContainerEID)
{
// When calling GetPAB, this will normally return the users contact folder
// In this case (where we havent been asked to get all the profile contents,
// this implies that without container info, we should get the virtual
// folder contents
if(!bGetProfileContents)
SetVirtualPABEID((LPIAB)lpIAB, &cbContainerEID, &lpContainerEID);
hr = lpIAB->lpVtbl->GetPAB(lpIAB, &cbContainerEID, &lpContainerEID);
if(HR_FAILED(hr))
goto out;
}
//
// First we need to open the container object corresponding to this Container EntryID
//
hr = lpIAB->lpVtbl->OpenEntry(
lpIAB,
cbContainerEID,
lpContainerEID,
NULL,
0,
&ulObjectType,
(LPUNKNOWN *) &lpContainer);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("OpenEntry Failed: %x\n"),hr));
goto out;
}
if(bIsWABSessionProfileAware(lpIAB))
{
ulContentsTableFlags |= WAB_ENABLE_PROFILES;
if(bGetProfileContents)
ulContentsTableFlags |= WAB_PROFILE_CONTENTS;
}
//
// Now we do a get contents table on this container ...
//
hr = lpContainer->lpVtbl->GetContentsTable(
lpContainer,
ulContentsTableFlags,
&lpContentsTable);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("GetContentsTable Failed: %x\n"),hr));
goto out;
}
// the default set of columns does not have all the information we are seeking
// so we do a set columns
hr = SetRecipColumns(lpContentsTable);
if(HR_FAILED(hr))
goto out;
if(lpPropRes)
{
SRestriction sr = {0};
sr.rt = RES_PROPERTY;
sr.res.resProperty = *lpPropRes;
if(HR_FAILED(hr = lpContentsTable->lpVtbl->Restrict(lpContentsTable,&sr,0)))
goto out;
}
hr = HrQueryAllRows(lpContentsTable, NULL, NULL, NULL, 0, &lpSRowSet);
if (HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
goto out;
}
//
// if there's anything in the contents list flush it away
//
if (*lppContentsList)
{
lpItem = (*lppContentsList);
(*lppContentsList) = lpItem->lpNext;
FreeRecipItem(&lpItem);
}
*lppContentsList = NULL;
lpItem = NULL;
for(i=0;i<lpSRowSet->cRows;i++)
{
LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
if (!lpItem)
{
DebugPrintError(( TEXT("LocalAlloc Failed \n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
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;
}
// The entryids are in sorted order by display name
// Depending on the sort order - we want this list to also be sorted by display
// name or by reverse display name ...
if (SortInfo.bSortByLastName)
StrCpyN(lpItem->szDisplayName,lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
if(!SortInfo.bSortAscending)
{
//Add it to the contents linked list
lpItem->lpNext = (*lppContentsList);
if (*lppContentsList)
(*lppContentsList)->lpPrev = lpItem;
lpItem->lpPrev = NULL;
*lppContentsList = lpItem;
}
else
{
if(*lppContentsList == NULL)
(*lppContentsList) = lpItem;
if(lpLastListItem)
lpLastListItem->lpNext = lpItem;
lpItem->lpPrev = lpLastListItem;
lpItem->lpNext = NULL;
lpLastListItem = lpItem;
}
lpItem = NULL;
} //for i ....
/*****/
out:
/****/
if(lpSRowSet)
FreeProws(lpSRowSet);
if(lpContentsTable)
lpContentsTable->lpVtbl->Release(lpContentsTable);
if(lpContainer)
lpContainer->lpVtbl->Release(lpContainer);
if( (!lpsbContainer || !lpsbContainer->lpb) && lpContainerEID)
MAPIFreeBuffer(lpContainerEID);
/****/
if (lpContentList)
FreePcontentlist(hPropertyStore, lpContentList);
if (HR_FAILED(hr))
{
while(*lppContentsList)
{
lpItem = *lppContentsList;
*lppContentsList=lpItem->lpNext;
FreeRecipItem(&lpItem);
}
}
return hr;
}
//$$////////////////////////////////////////////////////////////////
//
// FreeRecipItem - frees a RECIPIENT_INFO structure
//
// lppItem - pointer to the lpItem to free. It is set to NULL
//
//////////////////////////////////////////////////////////////////
void FreeRecipItem(LPRECIPIENT_INFO * lppItem)
{
LocalFreeAndNull(&(*lppItem)->lpEntryID);
LocalFreeAndNull(&(*lppItem)->lpByRubyFirstName);
LocalFreeAndNull(&(*lppItem)->lpByRubyLastName);
LocalFreeAndNull((lppItem));
return;
}
//$$////////////////////////////////////////////////////////////////
//
// InitListView - initializes a list view with style, columns,
// image lists, headers etc
//
//
// HWND hWndLV - Handle of ListView Control
// dwStyle - style for list view
// bShowHeaders - Show or hide the headers
//
//////////////////////////////////////////////////////////////////
HRESULT HrInitListView( HWND hWndLV,
DWORD dwStyle,
BOOL bShowHeaders)
{
HRESULT hr = hrSuccess;
LV_COLUMN lvC; // list view column structure
TCHAR szText [MAX_PATH]; // place to store some text
RECT rc;
HIMAGELIST hSmall=NULL,hLarge=NULL;
HFONT hFnt = GetStockObject(DEFAULT_GUI_FONT);
DWORD dwLVStyle;
ULONG nCols=0;
ULONG index=0;
if (!hWndLV)
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
SendMessage(hWndLV, WM_SETFONT, (WPARAM) hFnt, (LPARAM) TRUE);
ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
if(( dwLVStyle & LVS_TYPEMASK) != dwStyle)
SetWindowLong(hWndLV,GWL_STYLE,(dwLVStyle & ~LVS_TYPEMASK) | dwStyle);
dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
if(( dwLVStyle & LVS_EDITLABELS) != dwStyle)
SetWindowLong(hWndLV,GWL_STYLE,(dwLVStyle & ~LVS_EDITLABELS) | dwStyle);
hSmall = gpfnImageList_LoadImage( hinstMapiX,
MAKEINTRESOURCE(IDB_BITMAP_SMALL),
//(LPCTSTR) ((DWORD) ((WORD) (IDB_BITMAP_SMALL))),
S_BITMAP_WIDTH,
0,
RGB_TRANSPARENT,
IMAGE_BITMAP,
0);
hLarge = gpfnImageList_LoadImage( hinstMapiX,
MAKEINTRESOURCE(IDB_BITMAP_LARGE),
//(LPCTSTR) ((DWORD) ((WORD) (IDB_BITMAP_LARGE))),
L_BITMAP_WIDTH,
0,
RGB_TRANSPARENT,
IMAGE_BITMAP,
0);
// Associate the image lists with the list view control.
ListView_SetImageList (hWndLV, hSmall, LVSIL_SMALL);
ListView_SetImageList (hWndLV, hLarge, LVSIL_NORMAL);
// <TBD> make the columns all the same width
// Later on in life we will make it so users preferences are stored and then
// played back ...
nCols = NUM_COLUMNS;
if (nCols==0)
{
DebugPrintError(( TEXT("Zero number of cols??\n")));
hr = E_FAIL;
goto out;
}
GetWindowRect(hWndLV,&rc);
lvC.mask = LVCF_FMT | LVCF_WIDTH;
lvC.fmt = LVCFMT_LEFT; // left-align column
if (bShowHeaders)
{
lvC.mask |= LVCF_TEXT | LVCF_SUBITEM;
// lvC.cx = (rc.right-rc.left)/nCols; // width of column in pixels
// if (lvC.cx == 0)
lvC.cx = 150; // <TBD> fix these limits somewhere ...
lvC.pszText = szText;
}
else
{
// if no headers, we want these to be wide enough to fit all the info
lvC.cx = 250; //<TBD> - change this hardcoding
lvC.pszText = NULL;
}
// Add the columns.
for (index = 0; index < nCols; index++)
{
lvC.iSubItem = index;
LoadString (hinstMapiX, lprgAddrBookColHeaderIDs[index], szText, ARRAYSIZE(szText));
if(index == colHomePhone && PR_WAB_CUSTOMPROP1 && lstrlen(szCustomProp1))
StrCpyN(szText, szCustomProp1,ARRAYSIZE(szText));
if(index == colOfficePhone && PR_WAB_CUSTOMPROP2 && lstrlen(szCustomProp2))
StrCpyN(szText, szCustomProp2,ARRAYSIZE(szText));
if((index == colDisplayName) || (index == colEmailAddress))
lvC.cx = 150;
else
lvC.cx = 100;
if (ListView_InsertColumn (hWndLV, index, &lvC) == -1)
{
DebugPrintError(( TEXT("ListView_InsertColumn Failed\n")));
hr = E_FAIL;
goto out;
}
}
out:
return hr;
}
//$$////////////////////////////////////////////////////////////////
///
/// HrFillListView - fills a list view from an lpcontentslist
///
/// hWndLV - Handle of List View control to fill
/// lpContentsList - LPRECIPIENT_INFO linked list. We walk the list and
/// add each item to the list view
///
//////////////////////////////////////////////////////////////////
HRESULT HrFillListView( HWND hWndLV,
LPRECIPIENT_INFO lpContentsList)
{
LPRECIPIENT_INFO lpItem = lpContentsList;
LV_ITEM lvI = {0};
int index = 0;
if ((!hWndLV) || (!lpContentsList))
return MAPI_E_INVALID_PARAMETER;
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM ;
lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
lvI.iItem = 0;
while(lpItem)
{
lvI.iImage = GetWABIconImage(lpItem);
lvI.iSubItem = colDisplayName;
lvI.lParam = (LPARAM) lpItem;
lvI.pszText = lpItem->szDisplayName;
index = ListView_InsertItem (hWndLV, &lvI);
if (index != -1)
{
if(lstrlen(lpItem->szOfficePhone))
ListView_SetItemText (hWndLV, index, colOfficePhone, lpItem->szOfficePhone);
if(lstrlen(lpItem->szHomePhone))
ListView_SetItemText (hWndLV, index, colHomePhone, lpItem->szHomePhone);
if(lstrlen(lpItem->szEmailAddress))
ListView_SetItemText (hWndLV, index, colEmailAddress, lpItem->szEmailAddress);
}
lpItem = lpItem->lpNext;
lvI.iItem++;
}
LVSelectItem(hWndLV, 0);
return S_OK;
}
//$$//////////////////////////////////////////////////////////////////////////////
//
// TrimSpaces - strips a string of leading and trailing blanks
//
// szBuf - pointer to buffer containing the string we want to strip spaces off.
//
////////////////////////////////////////////////////////////////////////////////
BOOL TrimSpaces(TCHAR * szBuf)
{
register LPTSTR lpTemp = szBuf;
if(!szBuf || !lstrlen(szBuf))
return FALSE;
// Trim leading spaces
while (IsSpace(lpTemp)) {
lpTemp = CharNext(lpTemp);
}
if (lpTemp != szBuf) {
// Leading spaces to trim
StrCpyN(szBuf, lpTemp, lstrlen(lpTemp)+1);
lpTemp = szBuf;
}
if (*lpTemp == '\0') {
// empty string
return(TRUE);
}
// Move to the end
lpTemp += lstrlen(lpTemp);
lpTemp--;
// Walk backwards, triming spaces
while (IsSpace(lpTemp) && lpTemp > szBuf) {
*lpTemp = '\0';
lpTemp = CharPrev(szBuf, lpTemp);
}
return(TRUE);
}
//$$/****************************************************************************
/*
* FUNCTION: ListViewSort(LPARAM, LPARAM, LPARAM)
*
* PURPOSE: Callback function that sorts depending on the column click
*
* lParam1, lParam2 - lParam of the elements being compared
* lParamSort - User defined data that identifies the sort criteria
*
****************************************************************************/
int CALLBACK ListViewSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
LPRECIPIENT_INFO lp1 = (LPRECIPIENT_INFO)lParam1;
LPRECIPIENT_INFO lp2 = (LPRECIPIENT_INFO)lParam2;
LPTSTR lpStr1, lpStr2, lpF1, lpL1, lpF2, lpL2;
int iResult = 0;
LPSORT_INFO lpSortInfo = (LPSORT_INFO) lParamSort;
if (lp1 && lp2)
{
switch( lpSortInfo->iOldSortCol)
{
case colDisplayName: // sort by Address
lpF1 = lp1->lpByRubyFirstName ? lp1->lpByRubyFirstName : lp1->szByFirstName;
lpL1 = lp1->lpByRubyLastName ? lp1->lpByRubyLastName : lp1->szByLastName;
lpF2 = lp2->lpByRubyFirstName ? lp2->lpByRubyFirstName : lp2->szByFirstName;
lpL2 = lp2->lpByRubyLastName ? lp2->lpByRubyLastName : lp2->szByLastName;
lpStr1 = lpSortInfo->bSortByLastName ? lpL1 : lpF1;
lpStr2 = lpSortInfo->bSortByLastName ? lpL2 : lpF2;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case colEmailAddress: // sort by Address
lpStr1 = lp1->szEmailAddress;
lpStr2 = lp2->szEmailAddress;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case colHomePhone: // sort by Address
lpStr1 = lp1->szHomePhone;
lpStr2 = lp2->szHomePhone;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case colOfficePhone: // sort by Address
lpStr1 = lp1->szOfficePhone;
lpStr2 = lp2->szOfficePhone;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
default:
iResult = 0;
break;
}
}
return(lpSortInfo->bSortAscending ? iResult : -1*iResult);
}
//$$****************************************************************************
/*
* SetColumnHeaderBmp
*
* PURPOSE: Sets the bmp on the ListView Column header to indicate sorting
*
* hWndLV - handle of List View
* SortInfo - The current Sort Information structure. It is used to determine
* where to put the sort header bitmap
****************************************************************************/
void SetColumnHeaderBmp(HWND hWndLV, SORT_INFO SortInfo)
{
LV_COLUMN lvc = {0};
HIMAGELIST hHeader = NULL;
HWND hWndLVHeader = NULL;
//POINT pt;
// we will try to get the hWnd for the ListView header and set its image lists
//pt.x = 1;
//pt.y = 1;
//hWndLVHeader = ChildWindowFromPoint (hWndLV, pt);
hWndLVHeader = ListView_GetHeader(hWndLV);
// NULL hChildWnd means R-CLICKED outside the listview.
// hChildWnd == ghwndLV means listview got clicked: NOT the
// header.
if ((hWndLVHeader) /*&& (hWndLVHeader != hWndLV)*/)
{
hHeader = (HIMAGELIST) SendMessage(hWndLVHeader,HDM_GETIMAGELIST,0,0);
gpfnImageList_SetBkColor(hHeader, GetSysColor(COLOR_BTNFACE));
SendMessage(hWndLVHeader, HDM_SETIMAGELIST, 0, (LPARAM) hHeader);
}
if (SortInfo.iOlderSortCol != SortInfo.iOldSortCol)
{
//Get rid of image from old column
lvc.mask = LVCF_FMT;
lvc.fmt = LVCFMT_LEFT;
ListView_SetColumn(hWndLV, SortInfo.iOlderSortCol, &lvc);
}
// Set new column icon.
lvc.mask = LVCF_IMAGE | LVCF_FMT;
lvc.fmt = LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
lvc.iImage = SortInfo.bSortAscending ? imageSortAscending : imageSortDescending;
ListView_SetColumn(hWndLV, SortInfo.iOldSortCol, &lvc);
return;
}
//$$//////////////////////////////////////////////////////////////////////////
///
/// ClearListView - Clears all the list view items and associated contents list
///
/// hWndLV - list view to clear out
/// lppContentsList - contents list correponding to the contents in the
/// list view
///
///////////////////////////////////////////////////////////////////////////////
void ClearListView(HWND hWndLV, LPRECIPIENT_INFO * lppContentsList)
{
/*
LPRECIPIENT_INFO lpItem = *lppContentsList;
int i =0;
int iItemIndex = ListView_GetItemCount(hWndLV);
//OutputDebugString( TEXT("ClearListView entry\n"));
if (iItemIndex <=0 )
goto out;
for(i=0;i<iItemIndex;i++)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, i);
if (lpItem)
{
if(lpItem->lpNext)
lpItem->lpNext->lpPrev = lpItem->lpPrev;
if(lpItem->lpPrev)
lpItem->lpPrev->lpNext = lpItem->lpNext;
if (*lppContentsList == lpItem)
*lppContentsList = lpItem->lpNext;
if (lpItem)
FreeRecipItem(&lpItem);
}
}
ListView_DeleteAllItems(hWndLV);
*lppContentsList = NULL;
out:
//OutputDebugString( TEXT("ClearListView exit\n"));
*/
ListView_DeleteAllItems(hWndLV);
FreeRecipList(lppContentsList);
return;
};
//$$//////////////////////////////////////////////////////////////////////
//
// DeleteSelectedItems - Delete all the selected items from the List View
//
// hWndLV -handle of List View
// lpIAB - handle to current AdrBook object - used for certificate stuff
// hPropertyStore - Handle of PropertyStore - <TBD> change this function to
// call deleteEntries instead of delete record.
// lpftLast - WAB file time at last update
//
//////////////////////////////////////////////////////////////////////////
void DeleteSelectedItems(HWND hWndLV, LPADRBOOK lpAdrBook, HANDLE hPropertyStore, LPFILETIME lpftLast)
{
int iItemIndex;
int nSelected;
LV_ITEM LVItem;
HWND hDlg = GetParent(hWndLV);
HRESULT hr = hrSuccess;
ULONG cbWABEID = 0;
LPENTRYID lpWABEID = NULL;
LPABCONT lpWABCont = NULL;
ULONG ulObjType,i=0;
SBinaryArray SBA = {0};
nSelected = ListView_GetSelectedCount(hWndLV);
if (nSelected <= 0)
{
ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEMS_DELETE, MB_ICONEXCLAMATION);
hr = E_FAIL;
goto out;
}
hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID);
if(HR_FAILED(hr))
goto out;
hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
cbWABEID, // size of EntryID to open
lpWABEID, // EntryID to open
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *)&lpWABCont);
if(HR_FAILED(hr))
goto out;
if (IDYES == ShowMessageBox(hDlg, IDS_ADDRBK_MESSAGE_DELETE, MB_ICONEXCLAMATION | MB_YESNO))
{
int iLastDeletedItemIndex;
BOOL bDeletedItem = FALSE;
DWORD dwLVStyle = 0;
BOOL bWasShowSelAlwaysStyle = FALSE;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
ULONG ulCount = 0;
SendMessage(hWndLV, WM_SETREDRAW, FALSE, 0);
// The list view may be set to ShowSelAlways style -
// When deleting, we normally look for the selected entries and
// delete them - but with this style, the list view automatically selects the
// next entry - which is problematic because then we end up deleting that
// one also ... so we need to unset the style now and set it later
dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
if( dwLVStyle & LVS_SHOWSELALWAYS)
{
SetWindowLong(hWndLV,GWL_STYLE,dwLVStyle & ~LVS_SHOWSELALWAYS);
bWasShowSelAlwaysStyle = TRUE;
}
if(!(SBA.lpbin = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary)*nSelected)))
goto out;
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
do
{
// otherwise get the entry id of this thing
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);
if (lpItem)
{
SetSBinary(&(SBA.lpbin[ulCount]), lpItem->cbEntryID, (LPBYTE)lpItem->lpEntryID);
ulCount++;
}
iLastDeletedItemIndex = iItemIndex;
iItemIndex = ListView_GetNextItem(hWndLV,iItemIndex,LVNI_SELECTED);
}
while (iItemIndex != -1);
SBA.cValues = ulCount;
hr = lpWABCont->lpVtbl->DeleteEntries( lpWABCont, (LPENTRYLIST) &SBA, 0);
// Ideally DeleteEntries will skip over errors silently so we have a dilemma here
// that if there are errors,do we knock out the corresponding items out of the UI or not ..
// For now, lets knock them out of the UI .. when the UI refreshes, this will sort itself out ..
//
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
do
{
ListView_DeleteItem(hWndLV,iItemIndex);
iLastDeletedItemIndex = iItemIndex;
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
}
while (iItemIndex != -1);
bDeletedItem = TRUE;
/* 33751 - need to fail silently here ..
else
{
ShowMessageBoxParam(hDlg, IDS_ADDRBK_MESSAGE_DELETING_ERROR, MB_ICONERROR, lpItem->szDisplayName);
iLastDeletedItemIndex = iItemIndex;
break;
}
*/
// reset the style if we changed it
if(bWasShowSelAlwaysStyle )
SetWindowLong(hWndLV,GWL_STYLE,dwLVStyle);
SetCursor(hOldCur);
// select the previous or next item ...
if (iLastDeletedItemIndex >= ListView_GetItemCount(hWndLV))
iLastDeletedItemIndex = ListView_GetItemCount(hWndLV)-1;
LVSelectItem(hWndLV, iLastDeletedItemIndex);
}
out:
SendMessage(hWndLV, WM_SETREDRAW, TRUE, 0);
if(SBA.lpbin && SBA.cValues)
{
for(i=0;i<SBA.cValues;i++)
LocalFreeAndNull((LPVOID *) (&(SBA.lpbin[i].lpb)));
LocalFreeAndNull(&SBA.lpbin);
}
if(lpWABCont)
UlRelease(lpWABCont);
if(lpWABEID)
FreeBufferAndNull(&lpWABEID);
return;
}
//$$//////////////////////////////////////////////////////////////////////
//
// LoadAllocString - Loads a string resource and allocates enough
// memory to hold it.
//
// StringID - String identifier to load
//
// returns the LocalAlloc'd, null terminated string. Caller is responsible
// for LocalFree'ing this buffer. If the string can't be loaded or memory
// can't be allocated, returns NULL.
//
//////////////////////////////////////////////////////////////////////////
LPTSTR LoadAllocString(int StringID) {
ULONG ulSize = 0;
LPTSTR lpBuffer = NULL;
TCHAR szBuffer[261]; // Big enough? Strings better be smaller than 260!
ulSize = LoadString(hinstMapiX, StringID, szBuffer, ARRAYSIZE(szBuffer));
if (ulSize && (lpBuffer = LocalAlloc(LPTR, sizeof(TCHAR)*(ulSize + 1)))) {
StrCpyN(lpBuffer, szBuffer, ulSize+1);
}
return(lpBuffer);
}
#ifdef VCARD
/***************************************************************************
Name : FormatAllocFilter
Purpose : Loads file filter name string resources and
formats them with their file extension filters
Parameters: StringID1 - String identifier to load (required)
szFilter1 - file name filter, ie, TEXT("*.vcf") (required)
StringID2 - String identifier (optional)
szFilter2 - file name filter (optional)
StringID3 - String identifier (optional)
szFilter3 - file name filter (optional)
Returns : LocalAlloc'd, Double null terminated string. Caller is
responsible for LocalFree'ing this buffer. If the string
can't be loaded or memory can't be allocated, returns NULL.
***************************************************************************/
LPTSTR FormatAllocFilter(int StringID1, LPCTSTR lpFilter1,
int StringID2, LPCTSTR lpFilter2,
int StringID3, LPCTSTR lpFilter3) {
LPTSTR lpFileType1 = NULL, lpFileType2 = NULL, lpFileType3 = NULL;
LPTSTR lpTemp = NULL;
LPTSTR lpBuffer = NULL;
// All string sizes include null
ULONG cchFileType1 = 0, cchFileType2 = 0, cchFileType3 = 0;
ULONG cchFilter1 = 0, cchFilter2 = 0, cchFilter3 = 0;
ULONG cchBuffer, cchTemp = 0;
cchBuffer = cchFilter1 = (lstrlen(lpFilter1) + 1);
if (! (lpFileType1 = LoadAllocString(StringID1))) {
DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID1);
return(NULL);
}
cchBuffer += (cchFileType1 = (lstrlen(lpFileType1) + 1));
if (lpFilter2 && StringID2) {
cchBuffer += (cchFilter2 = (lstrlen(lpFilter2) + 1));
if (! (lpFileType2 = LoadAllocString(StringID2))) {
DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID2);
} else {
cchBuffer += (cchFileType2 = (lstrlen(lpFileType2) + 1));
}
}
if (lpFilter3 && StringID3) {
cchBuffer += (cchFilter3 = (lstrlen(lpFilter3) + 1));
if (! (lpFileType3 = LoadAllocString(StringID3))) {
DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID3);
} else {
cchBuffer += (cchFileType3 = (lstrlen(lpFileType3) + 1));
}
}
cchBuffer += 1; //terminating null
Assert(cchBuffer == cchFilter1 + cchFilter2 + cchFilter3 + cchFileType1 + cchFileType2 + cchFileType3 + 1);
if (lpBuffer = LocalAlloc(LPTR, sizeof(lpBuffer[0])*cchBuffer)) {
lpTemp = lpBuffer;
cchTemp = cchBuffer;
Assert(cchTemp >= cchFileType1);
if (cchTemp >= cchFileType1)
{
StrCpyN(lpTemp, lpFileType1, cchFileType1);
lpTemp += cchFileType1;
cchTemp -= cchFileType1;
Assert(cchTemp >= cchFilter1);
if (cchTemp >= cchFilter1)
{
StrCpyN(lpTemp, lpFilter1, cchFilter1);
lpTemp += cchFilter1;
cchTemp -= cchFilter1;
LocalFree(lpFileType1);
if (cchFileType2 && cchFilter2)
{
Assert(cchTemp >= (cchFileType2 + cchFilter2));
if (cchTemp >= (cchFileType2 + cchFilter2))
{
StrCpyN(lpTemp, lpFileType2, cchFileType2);
lpTemp += cchFileType2;
cchTemp -= cchFileType2;
StrCpyN(lpTemp, lpFilter2, cchFilter2);
lpTemp += cchFilter2;
cchTemp -= cchFilter2;
LocalFree(lpFileType2);
}
}
if (cchFileType3 && cchFilter3)
{
Assert(cchTemp >= (cchFileType3 + cchFilter3));
if (cchTemp >= (cchFileType3 + cchFilter3))
{
StrCpyN(lpTemp, lpFileType3, cchFileType3);
lpTemp += cchFileType3;
cchTemp -= cchFileType3;
StrCpyN(lpTemp, lpFilter3, cchFilter3);
lpTemp += cchFilter3;
cchTemp -= cchFilter3;
LocalFree(lpFileType3);
}
}
}
}
}
if (lpTemp)
{
if ((cchTemp >0) && (cchTemp < cchBuffer)) // ensure we have room and didn't wrap
*lpTemp = '\0';
else
{
Assert(FALSE);
LocalFree(lpBuffer);
lpBuffer = NULL;
}
}
return(lpBuffer);
}
const LPTSTR szVCardFilter = TEXT("*.vcf");
/***************************************************************************
Name : VCardCreate
Purpose : Creates a vCard file from the given Mailuser and filename
Parameters: hwnd = hwndParent
lpIAB -> IAddrBook object,
ulFlags can be 0 or MAPI_DIALOG - MAPI_DIALOG means report
error messages in a dialog box, else
work silently ..
lpszFileNAme - vCard file name to create
lpMailUser - object to create vCard file from
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT VCardCreate( LPADRBOOK lpAdrBook,
HWND hWndParent,
ULONG ulFlags,
LPTSTR lpszFileName,
LPMAILUSER lpMailUser)
{
HRESULT hr = E_FAIL;
HANDLE hVCard = NULL;
if (INVALID_HANDLE_VALUE == (hVCard = CreateFile( lpszFileName,
GENERIC_WRITE,
0, // sharing
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL)))
{
if(ulFlags & MAPI_DIALOG)
{
ShowMessageBoxParam(hWndParent,
IDE_VCARD_EXPORT_FILE_ERROR,
MB_ICONERROR,
lpszFileName);
}
goto out;
}
if (hr = WriteVCard(hVCard, FileWriteFn, lpMailUser))
{
switch (GetScode(hr))
{
case WAB_E_VCARD_NOT_ASCII:
if(ulFlags & MAPI_DIALOG)
{
ShowMessageBoxParam(hWndParent,
IDS_VCARD_EXPORT_NOT_ASCII,
MB_ICONEXCLAMATION,
lpszFileName);
}
CloseHandle(hVCard);
hVCard = NULL;
DeleteFile(lpszFileName);
hr = E_FAIL;
break;
default:
if(ulFlags & MAPI_DIALOG)
{
ShowMessageBoxParam(hWndParent,
IDE_VCARD_EXPORT_FILE_ERROR,
MB_ICONERROR,
lpszFileName);
}
break;
}
}
out:
if (hVCard)
CloseHandle(hVCard);
return hr;
}
//$$//////////////////////////////////////////////////////////////////////
//
// VCardExportSelectedItems - Export all the selected items from the List View
// to vCard files.
//
// hWndLV - handle of List view. We look up the selected item in this list
// view, get its lParam structure, then get its EntryID and
// call details
// lpIAB - handle to current AdrBook object - used for calling details
//
//////////////////////////////////////////////////////////////////////////
HRESULT VCardExportSelectedItems(HWND hWndLV, LPADRBOOK lpAdrBook)
{
HRESULT hr = E_FAIL;
int iItemIndex;
HWND hWndParent = GetParent(hWndLV);
HANDLE hVCard = NULL;
OPENFILENAME ofn;
LPMAILUSER lpEntry = NULL;
LPTSTR lpFilter = NULL;
TCHAR szFileName[MAX_PATH + 1] = TEXT("");
LPTSTR lpTitle = NULL;
LPTSTR lpTitleFormat = NULL;
ULONG ulObjType;
LPTSTR lpszArg[1];
TCHAR szTmp[MAX_PATH];
// Open props if only 1 item is selected
iItemIndex = ListView_GetSelectedCount(hWndLV);
if (iItemIndex == 1)
{
// Get index of selected item
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
if (iItemIndex != -1)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
if(lpItem && lpItem->cbEntryID != 0)
{
StrCpyN(szFileName, lpItem->szDisplayName, ARRAYSIZE(szFileName));
TrimIllegalFileChars(szFileName);
if(lstrlen(szFileName))
StrCatBuff(szFileName, TEXT(".vcf"), ARRAYSIZE(szFileName));
if (hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
lpItem->cbEntryID,
lpItem->lpEntryID,
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *)&lpEntry))
{
DebugTraceResult( TEXT("VCardExportSelectedItems:OpenEntry"), hr);
goto exit;
}
if (ulObjType == MAPI_DISTLIST)
{
ShowMessageBox(hWndParent, IDE_VCARD_EXPORT_DISTLIST, MB_ICONEXCLAMATION);
goto exit;
}
lpFilter = FormatAllocFilter(IDS_VCARD_FILE_SPEC, szVCardFilter, 0, NULL, 0, NULL);
lpTitleFormat = LoadAllocString(IDS_VCARD_EXPORT_TITLE);
// Win9x bug FormatMessage cannot have more than 1023 chars
CopyTruncate(szTmp, lpItem->szDisplayName, MAX_PATH - 1);
lpszArg[0] = szTmp;
if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
lpTitleFormat,
0, // stringid
0, // dwLanguageId
(LPTSTR)&lpTitle, // output buffer
0, //MAX_UI_STR
(va_list *)lpszArg))
{
DebugTrace( TEXT("FormatMessage -> %u\n"), GetLastError());
}
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWndParent;
ofn.hInstance = hinstMapiX;
ofn.lpstrFilter = lpFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 0;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = ARRAYSIZE(szFileName);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = lpTitle;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = TEXT("vcf");
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
if (GetSaveFileName(&ofn))
{
//Check if file already exists ..
if(0xFFFFFFFF != GetFileAttributes(szFileName))
{
// Ask user if they want to overwrite
if(IDNO == ShowMessageBoxParam(hWndParent,
IDE_VCARD_EXPORT_FILE_EXISTS,
MB_ICONEXCLAMATION | MB_YESNO | MB_SETFOREGROUND,
szFileName))
{
hr = MAPI_E_USER_CANCEL;
goto exit;
}
}
// Go ahead and overwrite the file if user said yes..
if(hr = VCardCreate(lpAdrBook,
hWndParent,
MAPI_DIALOG,
szFileName,
lpEntry))
{
goto exit;
}
} // if GetSaveFileName...
} // if (lpItem->cbEntryID)...
}
} else {
if (iItemIndex <= 0) {
// nothing selected
ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
} else {
//multiple selected
ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_ACTION, MB_ICONEXCLAMATION);
}
hr = E_FAIL;
goto exit;
}
hr = S_OK;
exit:
UlRelease(lpEntry);
LocalFreeAndNull(&lpFilter);
LocalFree(lpTitleFormat);
if(lpTitle)
LocalFree(lpTitle);
return(hr);
}
/***************************************************************************
Name : VCardRetrive
Purpose : Retrieves a MailUser object from a given file name
Parameters: hwnd = hwndParent
lpIAB -> IAddrBook object,
ulFlags can be 0 or MAPI_DIALOG - MAPI_DIALOG means report
error messages in a dialog box, else
work silently ..
lpszFileNAme - vCard file name (file must exist)
lpszBuf - a memory buffer containing the vCard file
which can be specified instead of the filename
Must be a null terminated string
lppMailUser, returned MailUser ...
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT VCardRetrieve(LPADRBOOK lpAdrBook,
HWND hWndParent,
ULONG ulFlags,
LPTSTR lpszFileName,
LPSTR lpszBuf,
LPMAILUSER * lppMailUser)
{
HRESULT hResult = E_FAIL;
HANDLE hFile = NULL;
LPSTR lpBuf = NULL;
SBinary sb = {0};
LPMAILUSER lpMailUser = NULL;
// We will convert the vCard to a memory buffer and parse that buffer as needed
// Somewhere in the buffer we need to track how much of the buffer has already
// been parsed .. we'll polymorph a SBinary struct here so we can use the cb param
// to track how much buffer has been parsed and the lpb to store the buffer
SBinary buf = {0};
if(!VCardGetBuffer(lpszFileName, lpszBuf, &lpBuf))
{
if(ulFlags & MAPI_DIALOG)
{
// couldn't open file.
ShowMessageBoxParam(hWndParent, IDE_VCARD_IMPORT_FILE_ERROR,
MB_ICONEXCLAMATION, lpszFileName);
}
goto out;
}
if(hResult = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &sb.cb, (LPENTRYID *)&sb.lpb))
goto out;
if (hResult = HrCreateNewObject( lpAdrBook, &sb,
MAPI_MAILUSER,
CREATE_CHECK_DUP_STRICT,
(LPMAPIPROP *) &lpMailUser))
{
goto out;
}
buf.cb = 0;
buf.lpb = (LPBYTE) lpBuf;
//if (hResult = ReadVCard(hFile, FileReadFn, *lppMailUser))
if (hResult = ReadVCard((HANDLE) &buf, BufferReadFn, lpMailUser))
{
if(ulFlags & MAPI_DIALOG)
{
switch (GetScode(hResult))
{
case MAPI_E_INVALID_OBJECT:
ShowMessageBoxParam(hWndParent,
IDE_VCARD_IMPORT_FILE_BAD,
MB_ICONEXCLAMATION,
lpszFileName);
goto out;
default:
ShowMessageBoxParam(hWndParent,
IDE_VCARD_IMPORT_PARTIAL,
MB_ICONEXCLAMATION,
lpszFileName);
break;
}
}
}
out:
if(lpBuf)
LocalFree(lpBuf);
if(sb.lpb)
MAPIFreeBuffer(sb.lpb);
if(lpMailUser)
{
if(HR_FAILED(hResult))
lpMailUser->lpVtbl->Release(lpMailUser);
else
*lppMailUser = lpMailUser;
}
return hResult;
}
/***************************************************************************
Name : VCardImport
Purpose : Reads a vCard from a file to a new MAILUSER object.
Parameters: hwnd = hwnd
lpIAB -> IAddrBook object
szVCardFile - name of the file to import if we already know it
in which case there is no OpenFileName dialog
The entryids of the newly added objects are added to the
SPropValue which is a dummy prop of type MV_BINARY
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT VCardImport(HWND hWnd, LPADRBOOK lpAdrBook, LPTSTR szVCardFile, LPSPropValue * lppProp)
{
HRESULT hResult = hrSuccess;
OPENFILENAME ofn;
LPTSTR lpFilter = FormatAllocFilter(IDS_VCARD_FILE_SPEC, szVCardFilter, 0, NULL, 0, NULL);
TCHAR szFileName[MAX_PATH + 1] = TEXT("");
HANDLE hFile = NULL;
ULONG ulObjType;
ULONG cProps;
LPMAILUSER lpMailUser = NULL, lpMailUserNew = NULL;
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
BOOL bChangesMade = FALSE;
LPSPropValue lpspvEID = NULL;
LPSTR lpBuf = NULL, lpVCardStart = NULL;
LPSTR lpVCard = NULL, lpNext = NULL;
LPSPropValue lpProp = NULL;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.hInstance = hinstMapiX;
ofn.lpstrFilter = lpFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 0;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = ARRAYSIZE(szFileName);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = LoadAllocString(IDS_VCARD_IMPORT_TITLE);
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = TEXT("vcf");
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
if(szVCardFile && lstrlen(szVCardFile))
StrCpyN(szFileName, szVCardFile, ARRAYSIZE(szFileName));
else
if (!GetOpenFileName(&ofn))
goto exit;
if(lstrlen(szFileName))
{
if(!VCardGetBuffer(szFileName, NULL, &lpBuf))
{
// couldn't open file.
ShowMessageBoxParam(hWnd, IDE_VCARD_IMPORT_FILE_ERROR, MB_ICONEXCLAMATION, szFileName);
goto exit;
}
lpVCardStart = lpBuf;
// Loop through showing all the nested vCards one by one ..
while(VCardGetNextBuffer(lpVCardStart, &lpVCard, &lpNext) && lpVCard)
{
if(!HR_FAILED( hResult = VCardRetrieve( lpAdrBook, hWnd, MAPI_DIALOG, szFileName, lpVCard, &lpMailUser)))
{
if (!HR_FAILED(hResult = HrShowDetails(lpAdrBook, hWnd, NULL, 0, NULL, NULL, NULL,
(LPMAPIPROP)lpMailUser, SHOW_OBJECT, MAPI_MAILUSER, &bChangesMade)))
{
if (hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READONLY))
{
switch(hResult)
{
case MAPI_E_COLLISION:
{
LPSPropValue lpspv1 = NULL, lpspv2 = NULL;
if (! (hResult = HrGetOneProp((LPMAPIPROP)lpMailUser, PR_DISPLAY_NAME, &lpspv1)))
{
switch (ShowMessageBoxParam(hWnd, IDS_VCARD_IMPORT_COLLISION, MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_APPLMODAL | MB_SETFOREGROUND, lpspv1->Value.LPSZ, szFileName))
{
case IDYES:
// Yes, replace
// Create a new one with the right flags, copy the old one's props and save.
ulCreateFlags |= ( CREATE_REPLACE | CREATE_MERGE );
if(!HR_FAILED(hResult = HrCreateNewObject(lpAdrBook, ((LPMailUser)lpMailUser)->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, (LPMAPIPROP *)&lpMailUserNew)))
{
if (!HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,NULL,MAPI_UNICODE,&cProps,&lpspv2)))
{
if (!HR_FAILED(hResult = lpMailUserNew->lpVtbl->SetProps(lpMailUserNew,cProps,lpspv2,NULL)))
{
hResult = lpMailUserNew->lpVtbl->SaveChanges(lpMailUserNew,KEEP_OPEN_READONLY);
}
}
}
break;
case IDCANCEL:
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
break; // no, don't replace
default:
hResult = E_FAIL;
break;
}
}
FreeBufferAndNull(&lpspv1);
FreeBufferAndNull(&lpspv2);
}
break;
case MAPI_E_NOT_ENOUGH_DISK:
hResult = HandleSaveChangedInsufficientDiskSpace(hWnd, lpMailUser);
break;
default:
if(HR_FAILED(hResult))
ShowMessageBoxParam(hWnd, IDE_VCARD_IMPORT_FILE_BAD, MB_ICONEXCLAMATION, szFileName);
break;
}
}
}
}
if(!lpProp && !HR_FAILED(hResult))
{
SCODE sc;
if(sc = MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpProp))
{
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
goto exit;
}
lpProp->ulPropTag = PR_WAB_DL_ENTRIES; // Doesnt matter what we set this to as long as its MV_BINARY
lpProp->Value.MVbin.cValues = 0;
lpProp->Value.MVbin.lpbin = NULL;
}
if(lpProp && !HR_FAILED(hResult))
{
LPMAILUSER lpMU = (lpMailUserNew) ? lpMailUserNew : lpMailUser;
if (! (hResult = HrGetOneProp((LPMAPIPROP)lpMU, PR_ENTRYID, &lpspvEID)))
{
AddPropToMVPBin(lpProp, 0 , lpspvEID->Value.bin.lpb, lpspvEID->Value.bin.cb, TRUE);
FreeBufferAndNull(&lpspvEID);
}
}
if(lpMailUserNew)
lpMailUserNew->lpVtbl->Release(lpMailUserNew);
if(lpMailUser)
lpMailUser->lpVtbl->Release(lpMailUser);
lpMailUser = NULL;
lpMailUserNew = NULL;
if(hResult == MAPI_E_USER_CANCEL)
break;
lpVCard = NULL;
lpVCardStart = lpNext;
}
} // getopenfilename ...
*lppProp = lpProp;
exit:
LocalFreeAndNull(&lpBuf);
LocalFree(lpFilter);
LocalFree((LPVOID)ofn.lpstrTitle);
if (hFile)
CloseHandle(hFile);
if(lpMailUser)
UlRelease(lpMailUser);
if(lpMailUserNew)
UlRelease(lpMailUserNew);
return(hResult);
}
#endif
//$$//////////////////////////////////////////////////////////////////////
// HrShowLVEntryProperties
//
// Shows the properties of an entry in the list view ...
// Assumes that all list views are based on lpRecipientInfo Structures
//
// hWndLV - handle of List view. We look up the selected item in this list
// view, get its lParam structure, then get its EntryID and
// call details
// lpIAB - handle to current AdrBook object - used for calling details
// lpftLast - WAB file time at last update
//
// Returns:MAPI_E_USER_CANCEL on cancel
// MAPI_E_OBJECT_CHANGED if object was modified
// S_OK if no changes and nothing modified
//////////////////////////////////////////////////////////////////////////
HRESULT HrShowLVEntryProperties(HWND hWndLV, ULONG ulFlags, LPADRBOOK lpAdrBook, LPFILETIME lpftLast)
{
HRESULT hr = E_FAIL;
int iItemIndex;
HWND hWndParent = GetParent(hWndLV);
LPRECIPIENT_INFO lpNewItem=NULL;
// Open props if only 1 item is selected
iItemIndex = ListView_GetSelectedCount(hWndLV);
if (iItemIndex == 1)
{
// Get index of selected item
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
if (iItemIndex != -1)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
if(lpItem && lpItem->cbEntryID != 0)
{
hr = lpAdrBook->lpVtbl->Details(lpAdrBook,
(PULONG_PTR) &hWndParent, // ulUIParam
NULL,
NULL,
lpItem->cbEntryID,
lpItem->lpEntryID,
NULL,
NULL,
NULL,
ulFlags);
// if details changed something - our event and semaphores should
// notify us so we can update ourselves from the property store or
// whatever ...
// this is TBD - at this point there is no way to refresh anything ..
if(HR_FAILED(hr))
{
goto out;
}
else //if(!HR_FAILED(hr))
{
//Open the item again and compare its UI props to see
//if anything changed ...
if(0 != IsWABEntryID(lpItem->cbEntryID,
lpItem->lpEntryID,
NULL, NULL, NULL, NULL, NULL))
{
// <TBD> the above test may not be good enough ..
// we really need to check if its a wab entryid ..
//
// This is not a WAB entry ID
// For now assume this is a read only contact and so
// we dont need to check it again for changes
//
goto out;
}
if(!ReadSingleContentItem( lpAdrBook,
lpItem->cbEntryID,
lpItem->lpEntryID,
&lpNewItem))
goto out;
// Compare the new item with the old item
// If anything changed, we need to update the item in the list view
if (lstrcmp(lpItem->szDisplayName,lpNewItem->szDisplayName))
{
hr = MAPI_E_OBJECT_CHANGED;
ListView_SetItemText(hWndLV,iItemIndex,colDisplayName,lpNewItem->szDisplayName);
StrCpyN(lpItem->szDisplayName,lpNewItem->szDisplayName,ARRAYSIZE(lpItem->szDisplayName));
}
if (lstrcmp(lpItem->szEmailAddress,lpNewItem->szEmailAddress))
{
hr = MAPI_E_OBJECT_CHANGED;
ListView_SetItemText(hWndLV,iItemIndex,colEmailAddress,lpNewItem->szEmailAddress);
StrCpyN(lpItem->szEmailAddress,lpNewItem->szEmailAddress,ARRAYSIZE(lpItem->szEmailAddress));
}
if (lstrcmp(lpItem->szHomePhone,lpNewItem->szHomePhone))
{
hr = MAPI_E_OBJECT_CHANGED;
ListView_SetItemText(hWndLV,iItemIndex,colHomePhone,lpNewItem->szHomePhone);
StrCpyN(lpItem->szHomePhone,lpNewItem->szHomePhone,ARRAYSIZE(lpItem->szHomePhone));
}
if (lstrcmp(lpItem->szOfficePhone,lpNewItem->szOfficePhone))
{
hr = MAPI_E_OBJECT_CHANGED;
ListView_SetItemText(hWndLV,iItemIndex,colOfficePhone,lpNewItem->szOfficePhone);
StrCpyN(lpItem->szOfficePhone,lpNewItem->szOfficePhone,ARRAYSIZE(lpItem->szOfficePhone));
}
if (lstrcmp(lpItem->szByLastName,lpNewItem->szByLastName))
{
hr = MAPI_E_OBJECT_CHANGED;
StrCpyN(lpItem->szByLastName,lpNewItem->szByLastName,ARRAYSIZE(lpItem->szByLastName));
}
if (lstrcmp(lpItem->szByFirstName,lpNewItem->szByFirstName))
{
hr = MAPI_E_OBJECT_CHANGED;
StrCpyN(lpItem->szByFirstName,lpNewItem->szByFirstName,ARRAYSIZE(lpItem->szByFirstName));
}
{
LVITEM lvI = {0};
lvI.mask = LVIF_IMAGE;
lvI.iItem = iItemIndex;
lvI.iSubItem = 0;
lpItem->bHasCert = lpNewItem->bHasCert;
lpItem->bIsMe = lpNewItem->bIsMe;
lvI.iImage = GetWABIconImage(lpItem);
ListView_SetItem(hWndLV, &lvI);
}
// Update the wab file write time so the timer doesn't
// catch this change and refresh.
//if (lpftLast &&
// lpItem->ulObjectType == MAPI_MAILUSER) // refresh for distlists not for mailusers (because distlists can cause further modifications)
//{
// CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
//}
}
}
}
}
else
{
if (iItemIndex <= 0)
{
// nothing selected
ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
}
else
{
//multiple selected
ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_ACTION, MB_ICONEXCLAMATION);
}
hr = E_FAIL;
goto out;
}
out:
if(hr == MAPI_E_NOT_FOUND)
ShowMessageBox(GetParent(hWndLV), idsEntryNotFound, MB_OK | MB_ICONEXCLAMATION);
if(lpNewItem)
FreeRecipItem(&lpNewItem);
return hr;
}
//$$//////////////////////////////////////////////////////////////////////
//
// LVSelectItem - Selects a list view item and ensures it is visible
//
// hWndList - handle of list view control
// iItemIndex - index of item to select
//
////////////////////////////////////////////////////////////////////////
void LVSelectItem(HWND hWndList, int iItemIndex)
{
DWORD dwStyle;
// Hopefully, we only want to select a single item
// So we cheat by making the ListView single select and
// set our item, reseting everything else
dwStyle = GetWindowLong(hWndList, GWL_STYLE);
SetWindowLong(hWndList, GWL_STYLE, dwStyle | LVS_SINGLESEL);
ListView_SetItemState ( hWndList, // handle to listview
iItemIndex, // index to listview item
LVIS_FOCUSED | LVIS_SELECTED, // item state
LVIS_FOCUSED | LVIS_SELECTED); // mask
ListView_EnsureVisible (hWndList, // handle to listview
iItemIndex,
FALSE);
//reset back to the original style ..
SetWindowLong(hWndList, GWL_STYLE, dwStyle);
return;
}
//$$//////////////////////////////////////////////////////////////////////////////
///
/// AddWABEntryToListView - Adds a wab entry to a list view given a entryid
///
/// lpIAB - handle to AdrBook object
/// hWndLV - list view of interest
/// lpEID - EntryID of entry. Assumes size of entryid is WAB_ENTRY_ID
/// lppContentsList - List into which the entry is also linked
///
///
////////////////////////////////////////////////////////////////////////////////
BOOL AddWABEntryToListView( LPADRBOOK lpAdrBook,
HWND hWndLV,
ULONG cbEID,
LPENTRYID lpEID,
LPRECIPIENT_INFO * lppContentsList)
{
BOOL bRet = FALSE;
LPRECIPIENT_INFO lpItem = NULL;
LV_ITEM lvi = {0};
int index = 0;
if (!lpEID)
goto out;
if (!ReadSingleContentItem( lpAdrBook, cbEID, lpEID, &lpItem))
goto out;
AddSingleItemToListView(hWndLV, lpItem);
//we added to the end - so this is the last item
//select it ...
index = ListView_GetItemCount(hWndLV);
LVSelectItem(hWndLV, index-1);
//
// Hook in the lpItem into the lpContentsList so we can free it later
//
lpItem->lpPrev = NULL;
lpItem->lpNext = *lppContentsList;
if (*lppContentsList)
(*lppContentsList)->lpPrev = lpItem;
(*lppContentsList) = lpItem;
bRet = TRUE;
out:
if (!bRet && lpItem)
FreeRecipItem(&lpItem);
return bRet;
}
//$$////////////////////////////////////////////////////////////////////////////
//
// AddSingleItemToListView - Takes a single lpItem and adds it to alist view
//
// hWndLV - handle of List View
// lpItem - Recipient Info corresponding to a single entry
//
//////////////////////////////////////////////////////////////////////////////
void AddSingleItemToListView(HWND hWndLV, LPRECIPIENT_INFO lpItem)
{
LV_ITEM lvI = {0};
int index = 0;
// Add just a single item ...
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM ;
lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
lvI.iImage = GetWABIconImage(lpItem);
lvI.iItem = ListView_GetItemCount(hWndLV);
lvI.iSubItem = colDisplayName;
lvI.lParam = (LPARAM) lpItem;
lvI.pszText = lpItem->szDisplayName;
index = ListView_InsertItem (hWndLV, &lvI);
if (index == -1)
{
DebugPrintError(( TEXT("ListView_InsertItem Failed\n")));
goto out;
}
// TBD - this is assuming that all the fields exist and are filled in
if(lstrlen(lpItem->szOfficePhone))
ListView_SetItemText (hWndLV, index, colOfficePhone, lpItem->szOfficePhone);
if(lstrlen(lpItem->szHomePhone))
ListView_SetItemText (hWndLV, index, colHomePhone, lpItem->szHomePhone);
if(lstrlen(lpItem->szEmailAddress))
ListView_SetItemText (hWndLV, index, colEmailAddress, lpItem->szEmailAddress);
out:
return;
}
//$$////////////////////////////////////////////////////////////////////////////
//
// ReadSingeContentItem - reads a specified record from the prop store
// and creates a single pointer item for the Address Linked list and
// content window.
//
// lpIAB - pointer to AdrBook Object
// cbEntryID - EntryID byte count of object of interest
// lpEntryID - EntryID of object of interest
// lppItem - returned lppItem
//
//////////////////////////////////////////////////////////////////////////////
BOOL ReadSingleContentItem( LPADRBOOK lpAdrBook,
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPRECIPIENT_INFO * lppItem)
{
LPSPropValue lpPropArray = NULL;
ULONG ulcProps = 0;
ULONG nLen = 0;
ULONG i = 0;
BOOL bDisplayNameSet = FALSE;
BOOL bEmailAddressSet = FALSE;
BOOL bRet = FALSE;
(*lppItem) = LocalAlloc(LMEM_ZEROINIT,sizeof(RECIPIENT_INFO));
if(!(*lppItem))
{
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
goto out;
}
(*lppItem)->lpNext = NULL;
(*lppItem)->lpPrev = NULL;
if (HR_FAILED( HrGetPropArray( lpAdrBook,
NULL,
cbEntryID,
lpEntryID,
MAPI_UNICODE,
&ulcProps,
&lpPropArray) ) )
{
DebugPrintError(( TEXT("HrGetPropArray failed\n")));
goto out;
}
GetRecipItemFromPropArray(ulcProps, lpPropArray, lppItem);
//Bug-
// 3/31/97 - vikramm
// on NTDSDC5.0, we are getting no attributes back in some cases
// and later on gpf when we try to look at the attributes ..
// make a check here
if (!lstrlen((*lppItem)->szDisplayName) || ((*lppItem)->cbEntryID == 0)) //This entry id is not allowed
{
goto out;
}
bRet = TRUE;
out:
if (lpPropArray)
MAPIFreeBuffer(lpPropArray);
if (!bRet)
{
if (*lppItem)
FreeRecipItem(lppItem);
}
return bRet;
}
/*
-
- bIsRubyLocale - Checks if the current locale is Rubyenabled
-
*/
BOOL bIsRubyLocale()
{
static LCID lcid = 0;
if(!lcid)
{
lcid = GetUserDefaultLCID();
//DebugTrace( TEXT("UserDefaultLCID = 0x%.4x\n"), lcid);
}
switch(lcid)
{
//case 0x0409: // us for testing
case 0x0804: //chinese
case 0x0411: //japanese
// case 0x0412: //korean - not use Ruby (YST)
case 0x0404: //chinese - taiwan
case 0x0c04: //chinese - hongkong
return TRUE;
break;
}
return FALSE;
}
/*
- TimeToString
-
* Converts a FileTime prop into a short string
*/
void TimeToString(LPTSTR szTime, FILETIME ft,ULONG cb )
{
SYSTEMTIME st = {0};
static TCHAR szFormat[64];
szTime[0] = TEXT('\0');
if(!lstrlen(szFormat))
LoadString(hinstMapiX, idsLVDateFormatString, szFormat, ARRAYSIZE(szFormat));
if(FileTimeToSystemTime(&ft, &st))
GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, szFormat, szTime, cb);
}
//$$////////////////////////////////////////////////////////////////////////////
//
// GetRcipItemFromPropArray - Scans a lpPropArray structure for the props of
// interest and puts them in an recipientInfo structure
//
// ulcPropCount - count of Props in the LPSPropValue array
// rgPropVals - LPSPropValue array
// lppItem - returned lppItem
//
//////////////////////////////////////////////////////////////////////////////
void GetRecipItemFromPropArray( ULONG ulcPropCount,
LPSPropValue rgPropVals,
LPRECIPIENT_INFO * lppItem)
{
ULONG j=0,nLen=0;
LPRECIPIENT_INFO lpItem = *lppItem;
LPTSTR lpszDisplayName = NULL, lpszNickName = NULL, lpszCompanyName = NULL;
LPTSTR lpszFirstName = NULL, lpszLastName = NULL, lpszMiddleName = NULL;
LPTSTR lpszRubyFirstName = NULL, lpszRubyLastName = NULL;
TCHAR szBufDisplayName[MAX_DISPLAY_NAME_LENGTH];
TCHAR szBufOppositeName[MAX_DISPLAY_NAME_LENGTH];
LPVOID lpBuffer = NULL;
ULONG ulProp1, ulProp2;
BOOL bRuby = bIsRubyLocale();
ulProp1 = (PR_WAB_CUSTOMPROP1 ? PR_WAB_CUSTOMPROP1 : PR_HOME_TELEPHONE_NUMBER);
ulProp2 = (PR_WAB_CUSTOMPROP2 ? PR_WAB_CUSTOMPROP2 : PR_OFFICE_TELEPHONE_NUMBER);
for(j=0;j<ulcPropCount;j++)
{
// Check Custom Props first in case these are dupes of other props already in the switch statement
//
if(rgPropVals[j].ulPropTag == ulProp1)
{
if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_TSTRING)
{
nLen = CopyTruncate(lpItem->szHomePhone, rgPropVals[j].Value.LPSZ,
MAX_DISPLAY_NAME_LENGTH);
}
else // for birthday, anniversary etc
if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_SYSTIME)
TimeToString(lpItem->szHomePhone, rgPropVals[j].Value.ft, MAX_DISPLAY_NAME_LENGTH-1);
}
else if(rgPropVals[j].ulPropTag == ulProp2)
{
if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_TSTRING)
{
nLen = CopyTruncate(lpItem->szOfficePhone, rgPropVals[j].Value.LPSZ,
MAX_DISPLAY_NAME_LENGTH);
}
else // for birthday, anniversary etc
if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_SYSTIME)
TimeToString(lpItem->szOfficePhone, rgPropVals[j].Value.ft,MAX_DISPLAY_NAME_LENGTH-1);
}
switch(rgPropVals[j].ulPropTag)
{
case PR_DISPLAY_NAME:
lpszDisplayName = rgPropVals[j].Value.LPSZ;
break;
case PR_SURNAME:
lpszLastName = rgPropVals[j].Value.LPSZ;
break;
case PR_GIVEN_NAME:
lpszFirstName = rgPropVals[j].Value.LPSZ;
break;
case PR_MIDDLE_NAME:
lpszMiddleName = rgPropVals[j].Value.LPSZ;
break;
case PR_COMPANY_NAME:
lpszCompanyName = rgPropVals[j].Value.LPSZ;
break;
case PR_NICKNAME:
lpszNickName = rgPropVals[j].Value.LPSZ;
break;
case PR_EMAIL_ADDRESS:
nLen = CopyTruncate(lpItem->szEmailAddress, rgPropVals[j].Value.LPSZ,
MAX_DISPLAY_NAME_LENGTH);
break;
case PR_ENTRYID:
lpItem->cbEntryID = rgPropVals[j].Value.bin.cb;
lpItem->lpEntryID = LocalAlloc(LMEM_ZEROINIT,lpItem->cbEntryID);
if(!(lpItem->lpEntryID))
{
DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
goto out;
}
CopyMemory(lpItem->lpEntryID,rgPropVals[j].Value.bin.lpb,lpItem->cbEntryID);
break;
case PR_OBJECT_TYPE:
lpItem->ulObjectType = rgPropVals[j].Value.l;
break;
case PR_USER_X509_CERTIFICATE:
lpItem->bHasCert = TRUE;
break;
default:
if(rgPropVals[j].ulPropTag == PR_WAB_THISISME)
lpItem->bIsMe = TRUE;
else if(rgPropVals[j].ulPropTag == PR_WAB_YOMI_FIRSTNAME)
lpszRubyFirstName = rgPropVals[j].Value.LPSZ;
else if(rgPropVals[j].ulPropTag == PR_WAB_YOMI_LASTNAME)
lpszRubyLastName = rgPropVals[j].Value.LPSZ;
break;
}
}
// [PaulHi] 3/12/99 Raid 63006 Use the PR_CONTACT_EMAIL_ADDRESSES email
// name if a PR_EMAIL_ADDRESS doesn't exist
if ( lpItem->szEmailAddress && (*lpItem->szEmailAddress == '\0') )
{
if (rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
{
// Just grap the first one in multi-valued list
if (rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.cValues != 0)
{
nLen = CopyTruncate(lpItem->szEmailAddress,
rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.LPPSZ[0],
MAX_DISPLAY_NAME_LENGTH);
}
}
}
// Reduce display name to 32 char or less ...
if(!lpszDisplayName) // should never happen
lpszDisplayName = szEmpty;
nLen = CopyTruncate(szBufDisplayName, lpszDisplayName, MAX_DISPLAY_NAME_LENGTH);
// The display name will be either by first name or last name
// so all we have to do is generate the other name and we'll
// be all set
szBufOppositeName[0]='\0';
if(lpItem->ulObjectType == MAPI_DISTLIST)
{
StrCpyN(szBufOppositeName, szBufDisplayName, ARRAYSIZE(szBufOppositeName));
}
else
{
// if there is no first/middle/last (there will always be a display name)
// and the display name does not match company name or nick name,
// then we shall try to parse the display name into first/middle/last
if( !lpszFirstName &&
!lpszMiddleName &&
!lpszLastName &&
!(lpszCompanyName && !lstrcmp(lpszDisplayName, lpszCompanyName)) &&
!(lpszNickName && !lstrcmp(lpszDisplayName, lpszNickName)) )
{
ParseDisplayName( lpszDisplayName,
&lpszFirstName,
&lpszLastName,
NULL, // Root WAB allocation
&lpBuffer); // lppLocalFree
}
if (lpszFirstName ||
lpszMiddleName ||
lpszLastName)
{
LPTSTR lpszTmp = szBufOppositeName;
SetLocalizedDisplayName( lpszFirstName,
bRuby ? NULL : lpszMiddleName,
lpszLastName,
NULL, //company
NULL, //nickname
(LPTSTR *) &lpszTmp, //&szBufOppositeName,
MAX_DISPLAY_NAME_LENGTH,
!bDNisByLN,
NULL,
NULL);
}
}
if(!lstrlen(szBufOppositeName))
{
// There is only 1 type of name so use it everywhere
StrCpyN(lpItem->szByFirstName,szBufDisplayName,ARRAYSIZE(lpItem->szByFirstName));
StrCpyN(lpItem->szByLastName,szBufDisplayName,ARRAYSIZE(lpItem->szByLastName));
}
else if(bDNisByLN)
{
// Display Name is by Last Name
StrCpyN(lpItem->szByFirstName,szBufOppositeName,ARRAYSIZE(lpItem->szByFirstName));
StrCpyN(lpItem->szByLastName,szBufDisplayName,ARRAYSIZE(lpItem->szByLastName));
}
else
{
// Display Name is by First Name
StrCpyN(lpItem->szByLastName,szBufOppositeName,ARRAYSIZE(lpItem->szByLastName));
StrCpyN(lpItem->szByFirstName,szBufDisplayName,ARRAYSIZE(lpItem->szByFirstName));
}
StrCpyN(lpItem->szDisplayName, szBufDisplayName,ARRAYSIZE(lpItem->szDisplayName));
if(bRuby)
{
if(lpszRubyFirstName)
SetLocalizedDisplayName(lpszRubyFirstName, NULL,
lpszRubyLastName ? lpszRubyLastName : (lpszLastName ? lpszLastName : szEmpty),
NULL, NULL, NULL, 0,
FALSE, //DNbyFN
NULL,
&lpItem->lpByRubyFirstName);
if(lpszRubyLastName)
SetLocalizedDisplayName(lpszRubyFirstName ? lpszRubyFirstName : (lpszFirstName ? lpszFirstName : szEmpty),
NULL,
lpszRubyLastName,
NULL, NULL, NULL, 0,
TRUE, //DNbyFN
NULL,
&lpItem->lpByRubyLastName);
}
// default object type to mailuser
if(!lpItem->ulObjectType)
lpItem->ulObjectType = MAPI_MAILUSER;
out:
if(lpBuffer)
LocalFree(lpBuffer);
return;
}
/*
- AddEntryToGroupEx
-
* Adds an entry to a group
*
*/
HRESULT AddEntryToGroupEx(LPADRBOOK lpAdrBook,
ULONG cbGroupEntryID,
LPENTRYID lpGroupEntryID,
DWORD cbEID,
LPENTRYID lpEID)
{
HRESULT hr = E_FAIL;
LPMAPIPROP lpMailUser = NULL;
ULONG ulObjType;
ULONG cValues = 0;
LPSPropValue lpPropArray = NULL;
LPSPropValue lpSProp = NULL;
ULONG ulcNewProp = 0;
LPSPropValue lpNewProp = NULL;
SCODE sc;
ULONG i,j;
BOOL bDLFound = FALSE;
BOOL bIsOneOff = (WAB_ONEOFF == IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL));
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession)
bIsOneOff = FALSE;
// [PaulHi] Raid 67581 First thing to do is check for cyclical references.
// This was done as a special case below and is now moved up to the top of
// the function.
if(!bIsOneOff)
{
if(CheckForCycle(lpAdrBook, lpEID, cbEID, lpGroupEntryID, cbGroupEntryID))
{
hr = MAPI_E_FOLDER_CYCLE;
goto out;
}
}
if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry( lpAdrBook,
cbGroupEntryID, // cbEntryID
lpGroupEntryID, // entryid
NULL, // interface
MAPI_MODIFY, // ulFlags
&ulObjType, // returned object type
(LPUNKNOWN *)&lpMailUser)))
{
// Failed! Hmmm.
DebugPrintError(( TEXT("IAB->OpenEntry: %x"), hr));
goto out;
}
Assert(lpMailUser);
if(ulObjType != MAPI_DISTLIST)
goto out;
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, // this
NULL,
MAPI_UNICODE,
&cValues, // cValues
&lpPropArray)))
{
DebugPrintError(( TEXT("lpMailUser->Getprops failed: %x\n"),hr));
goto out;
}
for(i=0;i<cValues;i++)
{
// For the DistList, the prop may not exist and if it doesnt exist,
// we make sure we can handle that case by adding the prop to the group..
//
if(lpPropArray[i].ulPropTag == (bIsOneOff ? PR_WAB_DL_ONEOFFS : PR_WAB_DL_ENTRIES) )
{
bDLFound = TRUE;
// before we add the item to the distlist, we want to check for
// duplicates
for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
{
if( cbEID == lpPropArray[i].Value.MVbin.lpbin[j].cb
&& !memcmp(lpEID, lpPropArray[i].Value.MVbin.lpbin[j].lpb, cbEID))
{
// yes its the same item
hr = S_OK;
goto out;
}
}
if (HR_FAILED(hr = AddPropToMVPBin( lpPropArray, i, lpEID, cbEID, FALSE)))
{
DebugPrintError(( TEXT("AddPropToMVPBin -> %x\n"), GetScode(hr)));
goto out;
}
break;
}
}
if(!bDLFound)
{
// This item is empty and doesnt have a PR_WAB_DL_PROPS or PR_WAB_FOLDER_PROPS..
// Add a new prop to this object ..
MAPIAllocateBuffer(sizeof(SPropValue), &lpSProp);
lpSProp->ulPropTag = (bIsOneOff ? PR_WAB_DL_ONEOFFS : PR_WAB_DL_ENTRIES);
lpSProp->Value.MVbin.cValues = 0;
lpSProp->Value.MVbin.lpbin = NULL;
if (HR_FAILED(hr = AddPropToMVPBin( lpSProp, 0, lpEID, cbEID, FALSE)))
{
DebugPrintError(( TEXT("AddPropToMVPBin -> %x\n"), GetScode(hr)));
goto out;
}
sc = ScMergePropValues( 1, lpSProp,
cValues, lpPropArray,
&ulcNewProp, &lpNewProp);
if (sc != S_OK)
{
hr = ResultFromScode(sc);
goto out;
}
if(lpPropArray)
MAPIFreeBuffer(lpPropArray);
lpPropArray = lpNewProp;
cValues = ulcNewProp;
lpNewProp = NULL;
}
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, cValues, lpPropArray, NULL)))
{
DebugPrintError(( TEXT("lpMailUser->Setprops failed\n")));
goto out;
}
hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser, KEEP_OPEN_READWRITE);
if (HR_FAILED(hr))
{
DebugPrintError(( TEXT("SaveChanges failed\n")));
goto out;
}
out:
if(lpPropArray)
MAPIFreeBuffer(lpPropArray);
if(lpNewProp)
MAPIFreeBuffer(lpNewProp);
if(lpSProp)
MAPIFreeBuffer(lpSProp);
if(lpMailUser)
lpMailUser->lpVtbl->Release(lpMailUser);
return hr;
}
/*
- RemoveEntryFromFolder
-
*
*
*/
HRESULT RemoveEntryFromFolder(LPIAB lpIAB,
LPSBinary lpsbFolder,
ULONG cbEIDItem, LPENTRYID lpEIDItem)
{
HRESULT hr = E_FAIL;
ULONG ulObjType = 0, cValues = 0, i = 0, j = 0, k =0;
int nIndex = -1;
BOOL bRemoved = TRUE;
LPSPropValue lpPropArray = NULL;
// open the Folder
if(HR_FAILED(hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore,
lpsbFolder, 0, &cValues, &lpPropArray)))
goto out;
for(i=0;i<cValues;i++)
{
if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES)
{
for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
{
if(lpPropArray[i].Value.MVbin.lpbin[j].cb == cbEIDItem)
{
if(!memcmp(lpPropArray[i].Value.MVbin.lpbin[j].lpb, lpEIDItem, cbEIDItem))
{
//knock this item out of the list
LocalFree(lpPropArray[i].Value.MVbin.lpbin[j].lpb);
// move everything 1 up in the array
for(k=j;k<lpPropArray[i].Value.MVbin.cValues-1;k++)
{
lpPropArray[i].Value.MVbin.lpbin[k].lpb = lpPropArray[i].Value.MVbin.lpbin[k+1].lpb;
lpPropArray[i].Value.MVbin.lpbin[k].cb = lpPropArray[i].Value.MVbin.lpbin[k+1].cb;
}
lpPropArray[i].Value.MVbin.cValues--;
bRemoved = TRUE;
break;
}
}
}
}
}
if(bRemoved)
{
// write this back to the store
hr = WriteRecord(lpIAB->lpPropertyStore->hPropertyStore,
NULL, &lpsbFolder, 0, RECORD_CONTAINER,
cValues, lpPropArray);
}
out:
ReadRecordFreePropArray(NULL, cValues, &lpPropArray);
return hr;
}
/*
- AddEIDToNewFolderParent
-
* Adds the given EID to a given Folder
*/
HRESULT AddItemEIDToFolderParent( LPIAB lpIAB,
ULONG cbFolderEntryId,
LPENTRYID lpFolderEntryId,
ULONG cbEID, LPENTRYID lpEID)
{
HRESULT hr = S_OK;
SBinary sb = {0};
ULONG cValues = 0,i;
LPSPropValue lpPropArray = NULL;
// ignore additions to folders in non-profile mode ...
if(!bIsWABSessionProfileAware(lpIAB))
return S_OK;
sb.cb = cbFolderEntryId;
sb.lpb = (LPBYTE)lpFolderEntryId;
if(HR_FAILED(hr = ReadRecord( lpIAB->lpPropertyStore->hPropertyStore,
&sb, 0, &cValues, &lpPropArray)))
goto out;
for(i=0;i<cValues;i++)
{
// For the folder, the PR_WAB_FOLDER_ENTRIES will always exist
//
if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES)
{
// This is a local alloced prop array so we can just tag the entry to
// the existing prop
LPSBinary lpbin = LocalAlloc(LMEM_ZEROINIT, (lpPropArray[i].Value.MVbin.cValues+1)*sizeof(SBinary));
ULONG j = 0;
// First make sure this entry is not already a part of this folder
// If it is, we dont need to do anything
for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
{
if(cbEID == lpPropArray[i].Value.MVbin.lpbin[j].cb)
{
if(!memcmp(lpEID, lpPropArray[i].Value.MVbin.lpbin[j].lpb, cbEID))
{
// yes its the same item
LocalFreeAndNull(&lpbin);
hr = S_OK;
goto out;
}
}
}
// no match - so add it
for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
{
lpbin[j].cb = lpPropArray[i].Value.MVbin.lpbin[j].cb;
lpbin[j].lpb = lpPropArray[i].Value.MVbin.lpbin[j].lpb;
}
SetSBinary(&(lpbin[j]), cbEID, (LPBYTE)lpEID);
if(lpPropArray[i].Value.MVbin.lpbin)
LocalFree(lpPropArray[i].Value.MVbin.lpbin);
lpPropArray[i].Value.MVbin.lpbin = lpbin;
lpPropArray[i].Value.MVbin.cValues++;
break;
}
}
// Write this folder item back to the store
{
LPSBinary lpsb = &sb;
if(HR_FAILED(hr = WriteRecord( lpIAB->lpPropertyStore->hPropertyStore,
NULL, &lpsb, 0, RECORD_CONTAINER,
cValues, lpPropArray)))
goto out;
}
out:
ReadRecordFreePropArray(NULL, cValues, &lpPropArray);
return hr;
}
/*
- AddFolderParentEIDToItem
-
* Adds the Folders EID to given Item
*
*/
HRESULT AddFolderParentEIDToItem(LPIAB lpIAB,
ULONG cbFolderEntryID,
LPENTRYID lpFolderEntryID,
LPMAPIPROP lpMU,
ULONG cbEID, LPENTRYID lpEID)
{
LPSPropValue lpspvMU = NULL;
ULONG ulcPropsMU = 0,i;
HRESULT hr = S_OK;
// ignore additions to folders in non-profile mode ...
if(!bIsWABSessionProfileAware(lpIAB))
return S_OK;
if(!HR_FAILED(hr = lpMU->lpVtbl->GetProps(lpMU, NULL, MAPI_UNICODE, &ulcPropsMU, &lpspvMU)))
{
// Look for PR_WAB_FOLDER_PARENT
BOOL bFound = FALSE;
if(cbEID && lpEID) // means this is a preexisting entry not a new one
{
for(i=0;i<ulcPropsMU;i++)
{
if(lpspvMU[i].ulPropTag == PR_WAB_FOLDER_PARENT || lpspvMU[i].ulPropTag == PR_WAB_FOLDER_PARENT_OLDPROP)
{
LPSBinary lpsbOldParent = &(lpspvMU[i].Value.MVbin.lpbin[0]);
// an item can only have one folder parent
if( lpFolderEntryID && cbFolderEntryID &&
cbFolderEntryID == lpsbOldParent->cb &&
!memcmp(lpFolderEntryID, lpsbOldParent->lpb, cbFolderEntryID))
{
//old is same as new .. don't need to do anything
hr = S_OK;
goto out;
}
// Remove this item from its old Parents list of contents
RemoveEntryFromFolder(lpIAB, lpsbOldParent, cbEID, lpEID);
// an item can only have one folder parent
if(lpFolderEntryID && cbFolderEntryID)
{
LPBYTE lpb = NULL;
// overwrite the old setting
if(!MAPIAllocateMore(cbFolderEntryID, lpspvMU, (LPVOID *)&lpb))
{
lpspvMU[i].Value.MVbin.lpbin[0].cb = cbFolderEntryID;
lpspvMU[i].Value.MVbin.lpbin[0].lpb = lpb;
CopyMemory(lpspvMU[i].Value.MVbin.lpbin[0].lpb, lpFolderEntryID, cbFolderEntryID);
lpMU->lpVtbl->SetProps(lpMU, ulcPropsMU, lpspvMU, NULL);
}
}
bFound = TRUE;
break;
}
}
}
if(!bFound)
{
// Didnt find an old parent in which case, if this is a valid folder we
// are dropping it on (and not a root item) then add a new property
// with new parent
if(lpFolderEntryID && cbFolderEntryID)
{
LPSPropValue lpPropFP = NULL;
if(!MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpPropFP))
{
lpPropFP->ulPropTag = PR_WAB_FOLDER_PARENT;
lpPropFP->Value.MVbin.cValues = 0;
lpPropFP->Value.MVbin.lpbin = NULL;
if(!HR_FAILED(AddPropToMVPBin( lpPropFP, 0, lpFolderEntryID, cbFolderEntryID, FALSE)))
lpMU->lpVtbl->SetProps(lpMU, 1, lpPropFP, NULL);
}
if(lpPropFP)
MAPIFreeBuffer(lpPropFP);
}
}
else
{
// We did find an old parent
// If the new parent is the root, then we basically need to remove the
// old parent property
SizedSPropTagArray(2, tagaFolderParent) =
{
2,
{
PR_WAB_FOLDER_PARENT,
PR_WAB_FOLDER_PARENT_OLDPROP
}
};
if(!lpFolderEntryID || !cbFolderEntryID)
lpMU->lpVtbl->DeleteProps(lpMU, (LPSPropTagArray) &tagaFolderParent, NULL);
}
}
out:
FreeBufferAndNull(&lpspvMU);
return hr;
}
/*
- AddEntryToFolder
-
*
*
*/
HRESULT AddEntryToFolder(LPADRBOOK lpAdrBook,
LPMAPIPROP lpMailUser,
ULONG cbFolderEntryId,
LPENTRYID lpFolderEntryId,
DWORD cbEID,
LPENTRYID lpEID)
{
HRESULT hr = E_FAIL;
ULONG ulObjType;
SCODE sc;
ULONG i;
SBinary sb = {0};
LPIAB lpIAB = (LPIAB) lpAdrBook;
// ignore additions to folders in non-profile mode ...
if(!bIsWABSessionProfileAware(lpIAB))
return S_OK;
// Check for a cycle of a folder being added to itself .. this is possible
if(cbEID && lpEID && cbFolderEntryId && lpFolderEntryId)
{
SBinary sb = {0};
IsWABEntryID(cbFolderEntryId, lpFolderEntryId,
(LPVOID*)&sb.lpb,(LPVOID*)&sb.cb,NULL,NULL,NULL);
if( sb.cb == cbEID && !memcmp(lpEID, sb.lpb, cbEID) )
return S_OK;
}
if(cbFolderEntryId && lpFolderEntryId)
{
if(HR_FAILED(hr = AddItemEIDToFolderParent(lpIAB,
cbFolderEntryId,
lpFolderEntryId,
cbEID, lpEID)))
goto out;
}
// 2. Open the object we added to this folder
// Need to update its folder parent and also need to remove it from the old folder parent
//
if(lpMailUser || (cbEID && lpEID))
{
LPMAPIPROP lpMU = NULL;
if(lpMailUser)
lpMU = lpMailUser;
else
{
if (HR_FAILED(hr = lpIAB->lpVtbl->OpenEntry( lpIAB, cbEID, lpEID,
NULL, MAPI_MODIFY, &ulObjType,
(LPUNKNOWN *)&lpMU)))
{
DebugPrintError(( TEXT("IAB->OpenEntry: %x"), hr));
goto out;
}
}
if(!HR_FAILED(hr = AddFolderParentEIDToItem(lpIAB, cbFolderEntryId, lpFolderEntryId, lpMU,
cbEID, lpEID)))
{
// if we were given a mailuser to work with, don't bother calling SaveChanges from here just yet
if(lpMU && lpMU!=lpMailUser)
{
lpMU->lpVtbl->SaveChanges(lpMU, KEEP_OPEN_READWRITE);
lpMU->lpVtbl->Release(lpMU);
}
}
}
out:
return hr;
}
//$$////////////////////////////////////////////////////////////////////////////
//
// AddEntryToGroup - Adds given entryID to given group or folder
//
// cbGroupEntryID,cbGroupEntryID - entryid of group
// cbEID, lpEID, - entryid of new entry
// ulObjectType = MAPI_ABCONT or MAPI_DISTLIST
//
//////////////////////////////////////////////////////////////////////////////
HRESULT AddEntryToContainer(LPADRBOOK lpAdrBook,
ULONG ulObjectType,
ULONG cbGEID,
LPENTRYID lpGEID,
DWORD cbEID,
LPENTRYID lpEID)
{
if(ulObjectType == MAPI_ABCONT)
return AddEntryToFolder(lpAdrBook, NULL, cbGEID, lpGEID, cbEID, lpEID);
else
return AddEntryToGroupEx(lpAdrBook, cbGEID, lpGEID, cbEID, lpEID);
}
//$$////////////////////////////////////////////////////////////////////////////
//
// AddNewObjectTOListViewEx - Triggered by the NewContact menus and buttons -
// calls newentry and then adds the returned item to
// the list view
//
// lpIAB - AddrBook object
// hWndLV - handle of List View
// ulObjectType - MailUser or DistList
// SortInfo - Current Sort parameters
// lppContentsList - Current ContentsList
// lpftLast - WAB file time at last update
// LPULONG - lpcbEID
// LPPENTRYID - lppEntryID
//////////////////////////////////////////////////////////////////////////////
HRESULT AddNewObjectToListViewEx(LPADRBOOK lpAdrBook,
HWND hWndLV,
HWND hWndTV,
HTREEITEM hSelItem,
LPSBinary lpsbContainerEID,
ULONG ulObjectType,
SORT_INFO * lpSortInfo,
LPRECIPIENT_INFO * lppContentsList,
LPFILETIME lpftLast,
LPULONG lpcbEID,
LPENTRYID * lppEID)
{
ULONG cbEID=0, cbEIDContainer = 0;
LPENTRYID lpEID=NULL, lpEIDContainer = NULL;
HRESULT hr = hrSuccess;
ULONG cbTplEID = 0;
LPENTRYID lpTplEID = NULL;
ULONG ulObjTypeCont = 0;
SBinary sbContEID = {0};
SBinary sbGroupEID = {0};
LPIAB lpIAB = (LPIAB)lpAdrBook;
ULONG ulEIDPAB = 0;
LPENTRYID lpEIDPAB = NULL;
if (ulObjectType!=MAPI_MAILUSER && ulObjectType!=MAPI_DISTLIST)
goto out;
// Check if the currently selected TV item is a container or a group
// and get the corresponding entryid
//
if(lpsbContainerEID)
{
SetSBinary(&sbContEID, lpsbContainerEID->cb, lpsbContainerEID->lpb);
}
else if(hWndTV)
{
HTREEITEM hItem = hSelItem ? hSelItem : TreeView_GetSelection(hWndTV);
TV_ITEM tvI = {0};
tvI.mask = TVIF_PARAM | TVIF_HANDLE;
tvI.hItem = hItem;
TreeView_GetItem(hWndTV, &tvI);
if(tvI.lParam)
{
LPTVITEM_STUFF lptvStuff = (LPTVITEM_STUFF) tvI.lParam;
if(lptvStuff)
{
ulObjTypeCont = lptvStuff->ulObjectType;
if(lptvStuff->ulObjectType == MAPI_DISTLIST)
{
// Bug 50029
if(lptvStuff->lpsbEID)
SetSBinary(&sbGroupEID, lptvStuff->lpsbEID->cb, lptvStuff->lpsbEID->lpb);
if(lptvStuff->lpsbParent)
SetSBinary(&sbContEID, lptvStuff->lpsbParent->cb, lptvStuff->lpsbParent->lpb);
}
else // current selection is a container
{
if(lptvStuff->lpsbEID)
SetSBinary(&sbContEID, lptvStuff->lpsbEID->cb, lptvStuff->lpsbEID->lpb);
}
}
}
}
else
{
if(HR_FAILED(hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &ulEIDPAB, &lpEIDPAB)))
goto out;
sbContEID.cb = ulEIDPAB;
sbContEID.lpb = (LPBYTE)lpEIDPAB;
}
if(HR_FAILED(hr = HrGetWABTemplateID( lpAdrBook,
ulObjectType,
&cbTplEID,
&lpTplEID)))
{
DebugPrintError(( TEXT("HrGetWABTemplateID failed: %x\n"), hr));
goto out;
}
if(sbContEID.cb && sbContEID.lpb)
{
cbEIDContainer = sbContEID.cb;
lpEIDContainer = (LPENTRYID) sbContEID.lpb;
}
if (HR_FAILED(hr = lpAdrBook->lpVtbl->NewEntry( lpAdrBook,
(ULONG_PTR) GetParent(hWndLV),
0,
cbEIDContainer,
lpEIDContainer,
cbTplEID,lpTplEID,
&cbEID,&lpEID)))
{
DebugPrintError(( TEXT("NewEntry failed: %x\n"),hr));
goto out;
}
// Update the wab file write time so the timer doesn't
// catch this change and refresh.
//if (lpftLast) {
// CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
//}
if (cbEID && lpEID)
{
if( AddWABEntryToListView( lpAdrBook, hWndLV, cbEID, lpEID, lppContentsList))
{
if(lpSortInfo)
SortListViewColumn( lpIAB, hWndLV, 0, lpSortInfo, TRUE);
}
}
if(sbGroupEID.cb != 0 && ulObjectType==MAPI_MAILUSER)
{
// Need to add this new object to the currently selected distribution list
// Only if this item is a mailuser
AddEntryToGroupEx(lpAdrBook, sbGroupEID.cb, (LPENTRYID) sbGroupEID.lpb, cbEID, lpEID);
}
if(lpcbEID)
*lpcbEID = cbEID;
if(lppEID)
*lppEID = lpEID; // Callers responsibility to free
out:
LocalFreeAndNull((LPVOID *) (&sbGroupEID.lpb));
// [PaulHi] 12/16/98 Crash fix hack. If lpEIDPAB is non-NULL then
// this means lpEIDPAB == sbContEID.lpb and is MAPIAllocBuffer allocated.
// Don't deallocate twice and make sure we deallocate with correct function.
// Otherwise sbContEID.lpb is a LocalAlloc allocation.
if (lpEIDPAB)
{
FreeBufferAndNull(&lpEIDPAB);
sbContEID.lpb = NULL;
}
else
LocalFreeAndNull((LPVOID *) (&sbContEID.lpb));
if(!lppEID)
FreeBufferAndNull(&lpEID);
FreeBufferAndNull(&lpTplEID);
return hr;
}
/*
- AddExtendedSendMailToItems
-
* If there is only 1 item selected in the ListView and that item has
* multiple email addresses, we populate the Send Mail To item with
* the multiple email addresses ..
* If there is more than 1 item selected or the item doesn't have
* multiple email addresses, we will hide the Send Mail To item
* The SendMailTo item should be the second last in the list ...
*
* bAddItems - if TRUE means attempt to add items; if FALSE means remove the SendMailTo item
*/
void AddExtendedSendMailToItems(LPADRBOOK lpAdrBook, HWND hWndLV, HMENU hMenuAction, BOOL bAddItems)
{
int nSendMailToPos = 1; // assumes IDM_SENDMAILTO is the second item in the list
int nSelected = ListView_GetSelectedCount(hWndLV);
HMENU hMenuSMT = GetSubMenu(hMenuAction, nSendMailToPos);
int nMenuSMT = GetMenuItemCount(hMenuSMT);
BOOL bEnable = FALSE;
if(nMenuSMT > 0) // Assumes there is only 1 default item in the SendMailTO popup menu
{
// there is some left over garbage here which we need to clear
int j = 0;
for(j=nMenuSMT-1;j>=0;j--)
RemoveMenu(hMenuSMT, j, MF_BYPOSITION);
}
if(bAddItems && nSelected == 1)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
if (lpItem)
{
ULONG ulcValues = 0;
LPSPropValue lpPropArray = NULL;
SizedSPropTagArray(3, MUContactAddresses)=
{
3, { PR_CONTACT_EMAIL_ADDRESSES, PR_OBJECT_TYPE, PR_EMAIL_ADDRESS }
};
if(!HR_FAILED(HrGetPropArray(lpAdrBook, (LPSPropTagArray)&MUContactAddresses,
lpItem->cbEntryID, lpItem->lpEntryID,
MAPI_UNICODE,
&ulcValues, &lpPropArray)))
{
if(ulcValues && lpPropArray)
{
if( lpPropArray[1].ulPropTag == PR_OBJECT_TYPE &&
lpPropArray[1].Value.l == MAPI_MAILUSER )
{
if( lpPropArray[0].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES &&
lpPropArray[0].Value.MVbin.cValues > 1)
{
ULONG i;
LPTSTR lpDefEmail = (lpPropArray[2].ulPropTag == PR_EMAIL_ADDRESS) ? lpPropArray[2].Value.LPSZ : szEmpty;
for(i=0;i<lpPropArray[0].Value.MVSZ.cValues;i++)
{
TCHAR sz[MAX_PATH * 2];
LPTSTR lpEmail = lpPropArray[0].Value.MVSZ.LPPSZ[i];
if(!lstrcmpi(lpEmail, lpDefEmail))
{
TCHAR sz1[MAX_PATH];
LoadString(hinstMapiX, idsDefaultEmail, sz1, ARRAYSIZE(sz1));
CopyTruncate(sz, lpEmail, ARRAYSIZE(sz)-lstrlen(sz1)-10);
StrCatBuff(sz, TEXT(" "), ARRAYSIZE(sz));
StrCatBuff(sz, sz1, ARRAYSIZE(sz));
lpEmail = sz;
}
if(i < IDM_SENDMAILTO_MAX)
InsertMenu( hMenuSMT, nMenuSMT+1, MF_STRING | MF_BYPOSITION,
IDM_SENDMAILTO_START+1+i, // we add an extra 1 here because IDM_SENDMAILTO_START is not a allowed ID here
lpEmail);
}
bEnable = TRUE;
}
}
MAPIFreeBuffer(lpPropArray);
}
}
}
}
EnableMenuItem(hMenuAction, nSendMailToPos, MF_BYPOSITION | (bEnable ? MF_ENABLED : MF_GRAYED));
//RemoveMenu(hMenuAction, nSendMailToPos, MF_BYPOSITION);
}
/*
-
- AddFolderListToMenu - Creates a FOlder menu from which we can choose folder items
* Items are checked if they are shared and unchecked if they are not shared ..
* The user can choose to share or un-share any particular folder
*
*/
void AddFolderListToMenu(HMENU hMenu, LPIAB lpIAB)
{
LPWABFOLDER lpFolder = lpIAB->lpWABFolders;
int nPos = 0;
int nCount = GetMenuItemCount(hMenu);
if(!bDoesThisWABHaveAnyUsers(lpIAB))
return;
while(nCount>0)
RemoveMenu(hMenu, --nCount, MF_BYPOSITION);
while(lpFolder)
{
BOOL bChecked = lpFolder->bShared;
InsertMenu( hMenu, nPos, MF_STRING | MF_BYPOSITION | (bChecked ? MF_CHECKED : MF_UNCHECKED),
lpFolder->nMenuCmdID, lpFolder->lpFolderName);
lpFolder = lpFolder->lpNext;
nPos++;
}
}
//$$////////////////////////////////////////////////////////////////////////////
//
// ShowLVContextMenu - Customizes and displays the context menu for various list
// views in the UI
//
// LV - app defined constant identifing the List View
// hWndLV - Handle of List View
// hWndLVContainer - Handle of the List containing the containers
// lParam - WM_CONTEXTMENU lParam passed on to this function
// lpVoid - some List Views need more parameters than other list views - pass them
// in this parameter
// lpIAB - AdrBook object
//
//////////////////////////////////////////////////////////////////////////////
int ShowLVContextMenu(int LV, // idicates which list view this is
HWND hWndLV,
HWND hWndLVContainer,
LPARAM lParam, // contains the mouse pos info when called from WM_CONTEXTMENU
LPVOID lpVoid,
LPADRBOOK lpAdrBook,
HWND hWndTV) //misc stuff we want to pass in
{
int idMenu = 0, nPosAction = 0, nPosNew = 0;
LPIAB lpIAB = (LPIAB) lpAdrBook;
HMENU hMenu = NULL;//LoadMenu(hinstMapiX, MAKEINTRESOURCE(IDR_MENU_LVCONTEXT));
HMENU hMenuTrackPopUp = NULL;//GetSubMenu(hMenu, 0);
HMENU hMenuAction = NULL;//GetSubMenu(hMenuTrackPopUp, posAction);
HMENU hMenuNewEntry = NULL;//GetSubMenu(hMenuTrackPopUp, posNew);
HMENU hm = NULL;
int nret = 0;
BOOL bState[tbMAX];
int i=0;
TCHAR tszBuf[MAX_UI_STR];
switch(LV) /**WARNING - these menu sub pop up positions are HARDCODED so should be in sync with the resource**/
{
case lvToolBarAction:
case lvToolBarNewEntry:
case lvMainABView:
idMenu = IDR_MENU_LVCONTEXT_BROWSE_LV;
nPosAction = 5;
nPosNew = 0;
break;
case lvDialogABContents: // Modeless address view LV
case lvDialogModalABContents: // Modal addres vuew LV
idMenu = IDR_MENU_LVCONTEXT_SELECT_LIST;
nPosAction = 6;
nPosNew = 4;
break;
case lvDialogABTo: // To Well LV
case lvDialogABCC: // CC Well LV
case lvDialogABBCC: // BCC Well LV
case lvDialogDistList: // Disttribution list UI LV
case lvDialogResolve:
idMenu = IDR_MENU_LVCONTEXT_DL_LV;
nPosAction = 0;
nPosNew = -1;
break;
case lvDialogFind: // Find dialog results LV
idMenu = IDR_MENU_LVCONTEXT_FIND_LV;
nPosNew = -1;
nPosAction = 0;
break;
case lvMainABTV:
idMenu = IDR_MENU_LVCONTEXT_TV;
nPosNew = 0;
nPosAction = -1;
break;
#ifdef COLSEL_MENU
case lvMainABHeader:
idMenu = IDR_MENU_LVCONTEXTMENU_COLSEL;
nPosNew = 0;
nPosAction = -1;
#endif
}
hMenu = LoadMenu(hinstMapiX, MAKEINTRESOURCE(idMenu));
hMenuTrackPopUp = GetSubMenu(hMenu, 0);
if (!hMenu || !hMenuTrackPopUp)
{
DebugPrintError(( TEXT("LoadMenu failed: %x\n"),GetLastError()));
goto out;
}
if(nPosAction != -1)
hMenuAction = GetSubMenu(hMenuTrackPopUp, nPosAction);
if(nPosNew != -1)
hMenuNewEntry = GetSubMenu(hMenuTrackPopUp, nPosNew);
if(hMenuAction)
AddExtendedMenuItems(lpAdrBook, hWndLV, hMenuAction, FALSE,
(LV != lvMainABTV)); // this is the condition for updating SendMailTo items
if(LV == lvMainABTV)
{
// everything on except Copy
for(i=0;i<tbMAX;i++)
bState[i] = TRUE;
if(ListView_GetItemCount(hWndLV) <= 0)
bState[tbPrint] = /*bState[tbAction] =*/ FALSE;
// [PaulHi] 12/1/98 New Paste context menu item
bState[tbPaste] = bIsPasteData();
}
else
// get the current dialog state based on the current container and the
// current list view - this is basically important only for the address
// book views ...
GetCurrentOptionsState( hWndLVContainer, hWndLV, bState);
// we now customize the menu depending on which list box this is
switch(LV)
{
case lvDialogFind: // Find Dialog List View
// Set Add to Address Book to grey if this was a local search
if(!bState[tbAddToWAB])
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_ADDTOWAB,MF_BYCOMMAND | MF_GRAYED);
// Set Delete to grey if this was a LDAP search
if(!bState[tbDelete])
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
break;
case lvMainABTV:
// [PaulHi] 12/1/98 Enable/disable Paste item, as required
if(!bState[tbPaste])
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PASTE,MF_BYCOMMAND | MF_GRAYED);
// Do folder stuff here
{
LPWABFOLDER lpUserFolder = (LPWABFOLDER) lpVoid;
if(lpUserFolder || !bDoesThisWABHaveAnyUsers(lpIAB)) // if a user folder was clicked or if this wab doesn't have user folder, no sense in sharing ..
{
#ifdef FUTURE
RemoveMenu(hMenuTrackPopUp, 3, MF_BYPOSITION); //Folders seperator
RemoveMenu(hMenuTrackPopUp, 2, MF_BYPOSITION); //Folder seperator
#endif // FUTURE
}
else if(!lpIAB->lpWABFolders) // no sub-folders at all
{
EnableMenuItem(hMenuTrackPopUp, 2, MF_BYPOSITION | MF_GRAYED); //Folder item
EnableMenuItem(hMenuTrackPopUp, 3, MF_BYPOSITION | MF_GRAYED); //Folder item
}
else
{
int nFolder = 2;
#ifdef FUTURE
HMENU hMenuFolders = GetSubMenu(hMenuTrackPopUp, nFolder); //idmFolders
AddFolderListToMenu(hMenuFolders, lpIAB);
#endif // FUTURE
}
}
break;
case lvMainABView: //main view
// For this one - we dont need the wells and
if(!bState[tbPaste])
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PASTE,MF_BYCOMMAND | MF_GRAYED);
if(!bState[tbCopy])
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
if ((!bState[tbProperties]))
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
if((!bState[tbDelete]))
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
break;
case lvDialogModalABContents:
case lvDialogABContents: //address book dialog contents list view
//here we want the option to put it in to,cc,bcc
//in the menu - we also want new contact/new group/properties
// no delete unless this is DialogModal
if(LV != lvDialogModalABContents)
RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_DELETE, MF_BYCOMMAND);
// figure out some way to read the items on the dlg to figure out
// how many wells to show and what to put in them ...
{
LPADRPARM lpAP = (LPADRPARM) lpVoid;
if (lpAP)
{
switch(lpAP->cDestFields)
{
case 0:
RemoveMenu(hMenuTrackPopUp, 3, MF_BYPOSITION); //seperator
RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL1, MF_BYCOMMAND);
case 1:
RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL2, MF_BYCOMMAND);
case 2:
RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL3, MF_BYCOMMAND);
break;
}
if((lpAP->cDestFields > 0) && lpAP->lppszDestTitles)
{
ULONG i;
// update the text of the menu with the button text
for(i=0;i<lpAP->cDestFields;i++)
{
int id;
switch(i)
{
case 0:
id = IDM_LVCONTEXT_ADDWELL1;
break;
case 1:
id = IDM_LVCONTEXT_ADDWELL2;
break;
case 2:
id = IDM_LVCONTEXT_ADDWELL3;
break;
}
// [PaulHi] 2/15/99 Check whether lpAP is ANSI or UNICODE
{
LPTSTR lptszDestTitle = NULL;
BOOL bDestAllocated = FALSE;
if (lpAP->ulFlags & MAPI_UNICODE)
lptszDestTitle = lpAP->lppszDestTitles[i];
else
{
// Convert single byte string to double byte
lptszDestTitle = ConvertAtoW((LPSTR)lpAP->lppszDestTitles[i]);
bDestAllocated = TRUE;
}
if (lptszDestTitle)
{
ULONG iLen = TruncatePos(lptszDestTitle, MAX_UI_STR - 5);
CopyMemory(tszBuf, lptszDestTitle, sizeof(TCHAR)*iLen);
tszBuf[iLen] = '\0';
StrCatBuff(tszBuf, szArrow, ARRAYSIZE(tszBuf));
if (bDestAllocated)
LocalFreeAndNull(&lptszDestTitle);
}
else
*tszBuf = '\0';
}
ModifyMenu( hMenuTrackPopUp, /*posTo + */i, MF_BYPOSITION | MF_STRING, id, tszBuf);
}
}
}
}
break;
case lvDialogABTo: //address book dialog To well
case lvDialogABCC: //CC well
case lvDialogABBCC: //BCC well
{
int iItemIndex = 0;
iItemIndex = ListView_GetSelectedCount(hWndLV);
if (iItemIndex!=1)
{
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_SENDMAIL,MF_BYCOMMAND | MF_GRAYED);
}
if (iItemIndex<=0)
{
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
}
//
// The wells may contain unresolved items without entryids ..
// If the item does not have an entryid, we want to disable properties
//
if (iItemIndex == 1)
{
// we are potentially looking at the properties of this thing
// get the items lParam
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
if(iItemIndex != -1)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
if(lpItem &&
((lpItem->cbEntryID == 0) || (lpItem->lpEntryID == NULL)))
{
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_SENDMAIL,MF_BYCOMMAND | MF_GRAYED);
}
}
}
}
break;
case lvDialogResolve: //Resolve dialog list view
//Rename the TEXT("delete") to TEXT("Show More Names .. ")
LoadString(hinstMapiX, idsShowMoreNames, tszBuf, ARRAYSIZE(tszBuf));
ModifyMenu( hMenuTrackPopUp,
IDM_LVCONTEXT_DELETE,
MF_BYCOMMAND | MF_STRING,
IDM_LVCONTEXT_DELETE,
tszBuf);
//And we want a seperator before TEXT("Show More Names")
InsertMenu( hMenuTrackPopUp,
IDM_LVCONTEXT_DELETE,
MF_BYCOMMAND | MF_SEPARATOR,
IDM_LVCONTEXT_DELETE,
NULL);
break;
#ifdef COLSEL_MENU
case lvMainABHeader:
{
UINT iIndex = PtrToUlong(lpVoid);
ULONG ulShowingColTag;
ULONG ulOtherColTag;
UINT i = 0, j;
// this will always be called with iIndex == colHomePhone or colOfficePhone
Assert( iIndex == colHomePhone || iIndex == colOfficePhone );
if( PR_WAB_CUSTOMPROP1 == 0 )
PR_WAB_CUSTOMPROP1 = PR_HOME_TELEPHONE_NUMBER;
if( PR_WAB_CUSTOMPROP2 == 0)
PR_WAB_CUSTOMPROP2 = PR_OFFICE_TELEPHONE_NUMBER;
ulShowingColTag = (colHomePhone == iIndex) ? PR_WAB_CUSTOMPROP1 : PR_WAB_CUSTOMPROP2;
ulOtherColTag = (ulShowingColTag == PR_WAB_CUSTOMPROP1) ? PR_WAB_CUSTOMPROP2 : PR_WAB_CUSTOMPROP1;
// lets remove the tag that is displayed in the other col
for( i = 0; i < MAXNUM_MENUPROPS; i++)
{
if( MenuToPropTagMap[i] == ulOtherColTag )
{
if( RemoveMenu( hMenuTrackPopUp, i, MF_BYPOSITION) )
break;
else
DebugTrace( TEXT("could not remove menu: %x\n"), GetLastError() );
}
}
if( i == MAXNUM_MENUPROPS )
DebugTrace( TEXT("Did not find other col's prop tag\n"));
if( ulShowingColTag != ulOtherColTag )
{
UINT iMenuEntry;
// potential bug, if someone sets value in registry
// then could have two columns with the same name and that
// would be bad because we would be looking for an entry
// that does not exist
for( j = 0; j < MAXNUM_MENUPROPS; j++)
{
if( ulShowingColTag == MenuToPropTagMap[j] )
{
// num of items that can be in column heads
Assert( j != i ); // both cols have same value, bad!
iMenuEntry = ( j > i ) ? j - 1 : j;
CheckMenuRadioItem( hMenuTrackPopUp,
0,
MAXNUM_MENUPROPS - 1, // minus one because there will be one missing
iMenuEntry,
MF_BYPOSITION);
break;
}
}
if( j == MAXNUM_MENUPROPS )
{
DebugTrace( TEXT("Did not find match for checkbutton \n"));
}
}
}
#endif // COLSEL_MENU
}
//
// Popup the menu - if this was a toolbar action just pop up the submenu
//
if(LV == lvToolBarAction)
hm = hMenuAction;
else if(LV == lvToolBarNewEntry)
hm = hMenuNewEntry;
else
hm = hMenuTrackPopUp;
if(hMenuNewEntry)
{
if(!bIsWABSessionProfileAware((LPIAB)lpIAB) ||
LV == lvDialogABTo || LV == lvDialogABCC ||
LV == lvDialogABBCC || LV == lvDialogModalABContents ||
LV == lvDialogABContents )
{
RemoveMenu(hMenuNewEntry, 2, MF_BYPOSITION); // remove new folder option
}
else
{
// Since this could be a rt-click menu, check the drophighlight else the selection
//EnableMenuItem(hMenuNewEntry,2,MF_BYPOSITION | MF_ENABLED);
//if(hWndTV && bDoesThisWABHaveAnyUsers((LPIAB)lpIAB))
//{
// if(TreeView_GetDropHilight(hWndTV))
// EnableMenuItem( hMenuNewEntry,2,
// MF_BYPOSITION | (TreeView_GetDropHilight(hWndTV)!=TreeView_GetRoot(hWndTV) ? MF_ENABLED : MF_GRAYED));
//else if(TreeView_GetSelection(hWndTV) == TreeView_GetRoot(hWndTV))
// EnableMenuItem(hMenuNewEntry,2,MF_BYPOSITION | MF_GRAYED);
//}
}
}
nret = TrackPopupMenu( hm, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
LOWORD(lParam), HIWORD(lParam),
0, GetParent(hWndLV), NULL);
DestroyMenu(hMenu);
/*
nret = TrackPopupMenuEx(hm, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON,
LOWORD(lParam), HIWORD(lParam), GetParent(hWndLV), NULL);
DestroyMenu(hMenu);
*/
out:
return nret;
}
//$$/////////////////////////////////////////////////////////////
//
// GetChildClientRect - Gets the child's coordinates in its parents
// client units
//
// hWndChild - handle of child
// lprc - returned RECT.
//
///////////////////////////////////////////////////////////////
void GetChildClientRect(HWND hWndChild, LPRECT lprc)
{
RECT rc;
POINT ptTop,ptBottom;
HWND hWndParent;
ZeroMemory(lprc, sizeof(*lprc));
if(!hWndChild)
goto out;
hWndParent = GetParent(hWndChild);
if(!hWndParent)
goto out;
GetWindowRect(hWndChild,&rc);
//
//This api working in both mirrored and unmirrored windows.
//
MapWindowPoints(NULL, hWndParent, (LPPOINT)&rc, 2);
ptTop.x = rc.left;
ptTop.y = rc.top;
ptBottom.x = rc.right;
ptBottom.y = rc.bottom;
(*lprc).left = ptTop.x;
(*lprc).top = ptTop.y;
(*lprc).right = ptBottom.x;
(*lprc).bottom = ptBottom.y;
out:
return;
}
//$$/////////////////////////////////////////////////////////////
//
// DoLVQuickFind - Simple quick find routine for matching edit box contents to
// List view entries
//
// hWndEdit - handle of Edit Box
// hWndLV - handle of List View
//
///////////////////////////////////////////////////////////////
void DoLVQuickFind(HWND hWndEdit, HWND hWndLV)
{
TCHAR szBuf[MAX_PATH] = TEXT("");
int iItemIndex = 0;
LV_FINDINFO lvF = {0};
lvF.flags = LVFI_PARTIAL | LVFI_STRING | LVFI_WRAP;
if(!GetWindowText(hWndEdit,szBuf,ARRAYSIZE(szBuf)))
return;
TrimSpaces(szBuf);
if(lstrlen(szBuf))
{
lvF.psz = szBuf;
iItemIndex = ListView_FindItem(hWndLV,-1, &lvF);
//if (iItemIndex < 0) iItemIndex = 0;
if(iItemIndex != -1)
{
ULONG cSel=0;
cSel = ListView_GetSelectedCount(hWndLV);
if(cSel)
{
// is there anything else selected ? - deselect and and
// select this item ...
int iOldItem = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
while(iOldItem != -1)
{
ListView_SetItemState ( hWndLV, // handle to listview
iOldItem, // index to listview item
0, // item state
LVIS_FOCUSED | LVIS_SELECTED);
iOldItem = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
}
}
LVSelectItem ( hWndLV, iItemIndex);
}
}
return;
}
//$$////////////////////////////////////////////////////////////////////////////////////////////////
//
// HrGetPropArray - for a selected resolved property (either in select_recipient or
// pick_user mode ... get the list of minimum required props as well
// as desired props (if they exist)
//
// lpIAB - AddrBook Object
// hPropertyStore - handle to prop store
// lpPTA - Array of props to return - NULL to return ALL the props
// cbEntryID, lpEntryID - id of object
// ulFlags - 0 or MAPI_UNICODE
// cValues, lppPropArray - returned props
//
//////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT HrGetPropArray( LPADRBOOK lpAdrBook,
LPSPropTagArray lpPTA,
ULONG cbEntryID,
LPENTRYID lpEntryID,
ULONG ulFlags,
ULONG * lpcValues,
LPSPropValue * lppPropArray)
{
HRESULT hr = hrSuccess;
LPMAPIPROP lpMailUser = NULL;
LPSPropValue lpPropArray = NULL;
ULONG ulObjType;
ULONG cValues;
*lppPropArray = NULL;
if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
cbEntryID, // cbEntryID
lpEntryID, // entryid
NULL, // interface
0, // ulFlags
&ulObjType, // returned object type
(LPUNKNOWN *)&lpMailUser)))
{
// Failed! Hmmm.
DebugTraceResult( TEXT("Address: IAB->OpenEntry:"), hr);
goto exit;
}
Assert(lpMailUser);
//TBD - Check ObjectType here
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser,
(LPSPropTagArray)lpPTA, // lpPropTagArray
ulFlags,
&cValues, // how many properties were there?
&lpPropArray)))
{
DebugTraceResult( TEXT("Address: IAB->GetProps:"), hr);
goto exit;
}
*lppPropArray = lpPropArray;
*lpcValues = cValues;
exit:
if (HR_FAILED(hr))
{
if (lpPropArray)
MAPIFreeBuffer(lpPropArray);
}
if (lpMailUser)
lpMailUser->lpVtbl->Release(lpMailUser);
return hr;
}
//$$///////////////////////////////////////////////////////////////
//
// SubStringSearchEx - Same as SubStringSearch except it does some
// language related processing and mapping of dbcs input
// strings etc
//
// pszTarget - Target string
// pszSearch - SubString to Search for
//
// returns - TRUE if match found
// FALSE if no match
//
/////////////////////////////////////////////////////////////////
BOOL SubstringSearchEx(LPTSTR pszTarget, LPTSTR pszSearch, LCID lcid)
{
if(!pszTarget && !pszSearch)
return TRUE;
if(!pszTarget || !pszSearch)
return FALSE;
if(lcid)
{
LPTSTR lpTH = NULL, lpSH = NULL;
int nLenTH = 0, nLenSH = 0;
LPTSTR lpT = NULL, lpS = NULL;
BOOL bRet = FALSE;
// Looks like this will have to be a two step process
// First convert all half-width characters to full-width characters
// Then convert all full-width katakana to full-width hirangana
// Step 1. Convert half width and full width katakana to hiragana to full width
int nLenT = LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszTarget, lstrlen(pszTarget)+1, lpT, 0);
int nLenS = LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszSearch, lstrlen(pszSearch)+1, lpS, 0);
lpT = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenT+1));
lpS = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenS+1));
if(!lpT || !lpS)
goto err;
LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszTarget, lstrlen(pszTarget)+1, lpT, nLenT);
LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszSearch, lstrlen(pszSearch)+1, lpS, nLenS);
lpS[nLenS]=lpT[nLenT]='\0';
// Step 2. Convert all to Half Width Hirangana
nLenTH = LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpT, lstrlen(lpT)+1, lpTH, 0);
nLenSH = LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpS, lstrlen(lpS)+1, lpSH, 0);
lpTH = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenTH+1));
lpSH = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenSH+1));
if(!lpTH || !lpSH)
goto err;
LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpT, lstrlen(lpT)+1, lpTH, nLenTH);
LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpS, lstrlen(lpS)+1, lpSH, nLenSH);
lpSH[nLenSH]=lpTH[nLenTH]='\0';
// by now, all strings should be in Full Width Hirangana ..
bRet = SubstringSearch(lpTH, lpSH);
err:
if(lpT)
LocalFree(lpT);
if(lpS)
LocalFree(lpS);
if(lpTH)
LocalFree(lpTH);
if(lpSH)
LocalFree(lpSH);
return bRet;
}
else
return(SubstringSearch(pszTarget, pszSearch));
}
//$$///////////////////////////////////////////////////////////////
//
// SubStringSearch - Used for doing partial resolves - Brute force
// search routine stolen from Athena
//
// TBD - Is this DBCS safe .. ???
//
// pszTarget - Target string
// pszSearch - SubString to Search for
//
// returns - TRUE if match found
// FALSE if no match
//
/////////////////////////////////////////////////////////////////
BOOL SubstringSearch(LPTSTR pszTarget, LPTSTR pszSearch)
{
LPTSTR pszT = pszTarget;
LPTSTR pszS = pszSearch;
if(!pszTarget && !pszSearch)
return TRUE;
if(!pszTarget || !pszSearch)
return FALSE;
if(!lstrlen(pszTarget) && !lstrlen(pszSearch))
return TRUE;
if(!lstrlen(pszTarget) || !lstrlen(pszSearch))
return FALSE;
while (*pszT && *pszS)
{
if (*pszT != *pszS &&
(TCHAR) CharLower((LPTSTR)(DWORD_PTR)MAKELONG(*pszT, 0)) != *pszS &&
(TCHAR) CharUpper((LPTSTR)(DWORD_PTR)MAKELONG(*pszT, 0)) != *pszS)
{
pszT -= (pszS - pszSearch);
pszT = CharNext(pszT); // dont start searching at half chars
pszS = pszSearch;
}
else
{
pszS++;
pszT++; // as long as the search is going on, do byte comparisons
}
}
return (*pszS == 0);
}
//$$
/****************************************************************************
FUNCTION: GetThreadStoragePointer()
PURPOSE: gets the private storage pointer for a thread, allocating one
if it does not exist (i.e. the thread didn't go through LibMain
THREAD_ATTACH)
PARAMETERS: none
RETURNS: a pointer to the thread's private storage
NULL, if there was a failure (usually memory allocation failure)
****************************************************************************/
LPPTGDATA __fastcall GetThreadStoragePointer()
{
LPPTGDATA lpPTGData=TlsGetValue(dwTlsIndex);
// if the thread does not have a private storage, it did not go through
// THREAD_ATTACH and we need to do this here.
if (!lpPTGData)
{
DebugPrintTrace(( TEXT("GetThreadStoragePointer: no private storage for this thread 0x%.8x\n"),GetCurrentThreadId()));
lpPTGData = (LPPTGDATA) LocalAlloc(LPTR, sizeof(PTGDATA));
if (lpPTGData)
TlsSetValue(dwTlsIndex, lpPTGData);
}
return lpPTGData;
}
//$$////////////////////////////////////////////////////////////////////////
//
// HrCreateNewEntry - Creates a new mailuser or DistList
//
// lpIAB - handle to AdrBook object
// hWndParent - hWnd for showing dialogs
// ulCreateObjectType - MailUser or DistList
// ulFlags = CREATE_DUP_CHECK_STRICT or 0
// cValues - PropCount of New properties from which to create
// the object
// lpPropArray - Props for this new object
// lpcbEntryID, lppEntryID - returned, new entryid for newly created object
// cbEIDContainer, lpEIDContainer - container in which to create this entry
// ulContObjType - The container object type - this could be a DISTLIST of an ABCONT
// if this is an ABCONT, we open the container and create the entry in the container
// If it is a DISTLIST, we open the PAB, create the entry in the PAB and then
// add the entry to the specified entryid
//
////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateNewEntry( LPADRBOOK lpIAB, // AdrBook Object
HWND hWndParent, // hWnd for Dialogs
ULONG ulCreateObjectType, //MAILUSER or DISTLIST
ULONG cbEIDCont,
LPENTRYID lpEIDCont,
ULONG ulContObjType,
ULONG ulFlags,
BOOL bShowBeforeAdding,
ULONG cValues,
LPSPropValue lpPropArray,
ULONG *lpcbEntryID,
LPENTRYID *lppEntryID )
{
LPABCONT lpContainer = NULL;
LPMAPIPROP lpMailUser = NULL;
HRESULT hr = hrSuccess;
ULONG ulObjType = 0;
ULONG cbWABEID = 0;
LPENTRYID lpWABEID = NULL;
LPSPropValue lpCreateEIDs = NULL;
LPSPropValue lpNewProps = NULL;
ULONG cNewProps;
SCODE sc = S_OK;
ULONG nIndex;
ULONG cbTplEID = 0;
LPENTRYID lpTplEID = NULL;
BOOL bFirst = TRUE;
BOOL bChangesMade = FALSE;
ULONG cbEIDContainer = 0;
LPENTRYID lpEIDContainer = NULL;
DebugPrintTrace(( TEXT("HrCreateNewEntry: entry\n")));
if ( (!lpIAB) ||
((ulFlags != 0) && (ulFlags != CREATE_CHECK_DUP_STRICT)) ||
((ulCreateObjectType != MAPI_MAILUSER) && (ulCreateObjectType != MAPI_DISTLIST)) )
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
if(lpcbEntryID)
*lpcbEntryID = 0;
if(lppEntryID)
*lppEntryID = NULL;
if(ulContObjType == MAPI_ABCONT && cbEIDCont && lpEIDCont)
{
cbEIDContainer = cbEIDCont;
lpEIDContainer = lpEIDCont;
}
if(!cbEIDContainer || !lpEIDContainer)
{
SetVirtualPABEID((LPIAB)lpIAB, &cbWABEID, &lpWABEID);
if (HR_FAILED(hr = lpIAB->lpVtbl->GetPAB( lpIAB, &cbWABEID, &lpWABEID)))
{
DebugPrintError(( TEXT("GetPAB Failed\n")));
goto out;
}
}
if (HR_FAILED(hr = lpIAB->lpVtbl->OpenEntry(lpIAB,
(cbWABEID ? cbWABEID : cbEIDContainer),
(lpWABEID ? lpWABEID : lpEIDContainer), // EntryID to open
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *)&lpContainer)))
{
DebugPrintError(( TEXT("OpenEntry Failed\n")));
goto out;
}
// Opened PAB container OK
// Get us the default creation entryids
if (HR_FAILED(hr = lpContainer->lpVtbl->GetProps( lpContainer,
(LPSPropTagArray)&ptaCreate,
MAPI_UNICODE,
&cNewProps,
&lpCreateEIDs) ) )
{
DebugPrintError(( TEXT("Can't get container properties for WAB\n")));
// Bad stuff here!
goto out;
}
// Validate the properites
if ( lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
{
DebugPrintError(( TEXT("Container Property Errors\n")));
goto out;
}
if(ulCreateObjectType == MAPI_DISTLIST)
nIndex = icrPR_DEF_CREATE_DL;
else
nIndex = icrPR_DEF_CREATE_MAILUSER;
cbTplEID = lpCreateEIDs[nIndex].Value.bin.cb;
lpTplEID = (LPENTRYID) lpCreateEIDs[nIndex].Value.bin.lpb;
//Retry:
if (HR_FAILED(hr = lpContainer->lpVtbl->CreateEntry( lpContainer,
cbTplEID,
lpTplEID,
ulFlags,
&lpMailUser)))
{
DebugPrintError(( TEXT("Creating DISTLIST failed\n")));
goto out;
}
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, // this
cValues, // cValues
lpPropArray, // property array
NULL)))
{
DebugPrintError(( TEXT("Setprops failed\n")));
goto out;
}
if ( bFirst &&
bShowBeforeAdding &&
HR_FAILED(hr = HrShowDetails( lpIAB,
hWndParent,
NULL,
0, NULL,
NULL, NULL,
(LPMAPIPROP)lpMailUser,
SHOW_OBJECT,
MAPI_MAILUSER,
&bChangesMade)))
{
goto out;
}
hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
KEEP_OPEN_READWRITE);
if(HR_FAILED(hr))
{
switch(hr)
{
case MAPI_E_NOT_ENOUGH_DISK:
hr = HandleSaveChangedInsufficientDiskSpace(hWndParent, (LPMAILUSER) lpMailUser);
break;
case MAPI_E_COLLISION:
{
LPSPropValue lpspv = NULL;
if (bFirst &&
!HR_FAILED(HrGetOneProp((LPMAPIPROP)lpMailUser,
PR_DISPLAY_NAME,
&lpspv)))
{
switch( ShowMessageBoxParam( hWndParent,
idsEntryAlreadyExists,
MB_YESNO | MB_ICONEXCLAMATION,
lpspv->Value.LPSZ))
{
/***/
case IDNO:
FreeBufferAndNull(&lpspv);
hr = MAPI_W_ERRORS_RETURNED; //S_OK;
goto out;
break;
/***/
case IDYES:
// At this point the user may have modified the properties
// of this MailUser. Hence we can't discard the mailuser
// Instead we'll just cheat a little, change the save
// flag on the mailuser directly and do a SaveChanges
((LPMailUser) lpMailUser)->ulCreateFlags |= (CREATE_REPLACE | CREATE_MERGE);
hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
KEEP_OPEN_READWRITE);
if(hr == MAPI_E_NOT_ENOUGH_DISK)
hr = HandleSaveChangedInsufficientDiskSpace(hWndParent, (LPMAILUSER) lpMailUser);
FreeBufferAndNull(&lpspv);
//UlRelease(lpMailUser);
//lpMailUser = NULL;
//bFirst = FALSE;
//goto Retry;
break;
}
}
}
break;
default:
DebugPrintError(( TEXT("SaveChanges failed: %x\n"),hr));
goto out;
break;
}
}
DebugObjectProps((LPMAPIPROP)lpMailUser, TEXT("New Entry"));
// Get the EntryID so we can return it...
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps( lpMailUser,
(LPSPropTagArray)&ptaEid,
MAPI_UNICODE,
&cNewProps,
&lpNewProps)))
{
DebugPrintError(( TEXT("Can't get EntryID\n")));
// Bad stuff here!
goto out;
}
if(lpcbEntryID && lppEntryID)
{
*lpcbEntryID = lpNewProps[ieidPR_ENTRYID].Value.bin.cb;
sc = MAPIAllocateBuffer(*lpcbEntryID, lppEntryID);
if (sc != S_OK)
{
DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
CopyMemory(*lppEntryID, lpNewProps[ieidPR_ENTRYID].Value.bin.lpb, *lpcbEntryID);
}
if(ulContObjType == MAPI_DISTLIST && *lpcbEntryID && *lppEntryID && cbEIDContainer && lpEIDContainer)
AddEntryToGroupEx(lpIAB, *lpcbEntryID, *lppEntryID, cbEIDCont, lpEIDCont);
hr = hrSuccess;
out:
if (lpMailUser)
lpMailUser->lpVtbl->Release(lpMailUser);
if (lpNewProps)
MAPIFreeBuffer(lpNewProps);
if (lpCreateEIDs)
MAPIFreeBuffer(lpCreateEIDs);
if (lpContainer)
lpContainer->lpVtbl->Release(lpContainer);
if (lpWABEID)
MAPIFreeBuffer(lpWABEID);
return hr;
}
//$$/////////////////////////////////////////////////////////////////////
//
// HrGetWABTemplateID - Gets the WABs default Template ID for MailUsers
// or DistLists
//
// lpIAB - AdrBook Object
// ulObjectType - MailUser or DistList
// cbEntryID, lpEntryID - returned EntryID of this template
//
/////////////////////////////////////////////////////////////////////////
HRESULT HrGetWABTemplateID( LPADRBOOK lpAdrBook,
ULONG ulObjectType,
ULONG * lpcbEID,
LPENTRYID * lppEID)
{
LPABCONT lpContainer = NULL;
HRESULT hr = hrSuccess;
SCODE sc = ERROR_SUCCESS;
ULONG ulObjType = 0;
ULONG cbWABEID = 0;
LPENTRYID lpWABEID = NULL;
LPSPropValue lpCreateEIDs = NULL;
LPSPropValue lpNewProps = NULL;
ULONG cNewProps;
ULONG nIndex;
DebugPrintTrace(( TEXT("HrGetWABTemplateID: entry\n")));
if ( (!lpAdrBook) ||
((ulObjectType != MAPI_MAILUSER) && (ulObjectType != MAPI_DISTLIST)) )
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
*lpcbEID = 0;
*lppEID = NULL;
if (HR_FAILED(hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID)))
{
DebugPrintError(( TEXT("GetPAB Failed\n")));
goto out;
}
if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
cbWABEID, // size of EntryID to open
lpWABEID, // EntryID to open
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *)&lpContainer)))
{
DebugPrintError(( TEXT("OpenEntry Failed\n")));
goto out;
}
// Opened PAB container OK
// Get us the default creation entryids
if (HR_FAILED(hr = lpContainer->lpVtbl->GetProps( lpContainer,
(LPSPropTagArray)&ptaCreate,
MAPI_UNICODE,
&cNewProps,
&lpCreateEIDs) ) )
{
DebugPrintError(( TEXT("Can't get container properties for WAB\n")));
// Bad stuff here!
goto out;
}
// Validate the properites
if ( lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
{
DebugPrintError(( TEXT("Container Property Errors\n")));
goto out;
}
if(ulObjectType == MAPI_DISTLIST)
nIndex = icrPR_DEF_CREATE_DL;
else
nIndex = icrPR_DEF_CREATE_MAILUSER;
*lpcbEID = lpCreateEIDs[nIndex].Value.bin.cb;
sc = MAPIAllocateBuffer(*lpcbEID,lppEID);
if (sc != S_OK)
{
DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
CopyMemory(*lppEID,lpCreateEIDs[nIndex].Value.bin.lpb,*lpcbEID);
out:
if (lpCreateEIDs)
MAPIFreeBuffer(lpCreateEIDs);
if (lpContainer)
lpContainer->lpVtbl->Release(lpContainer);
if (lpWABEID)
MAPIFreeBuffer(lpWABEID);
return hr;
}
//$$/////////////////////////////////////////////////////////////////////
//
// UpdateListViewItemsByName - Updates the displayed name corresponding to
// each entry - by First Name or by Last Name depending on Sort criteria
// Called by the Sort routine ...
//
//
/////////////////////////////////////////////////////////////////////////
void UpdateListViewItemsByName(HWND hWndLV, BOOL bSortByLastName)
{
LV_ITEM lvi = {0};
ULONG ulCount = 0;
ULONG i;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = colDisplayName;
lvi.lParam = 0;
ulCount = ListView_GetItemCount(hWndLV);
if (ulCount<=0)
return;
for(i=0;i<ulCount;i++)
{
LPRECIPIENT_INFO lpItem = NULL;
lvi.iItem = i;
if(!ListView_GetItem(hWndLV, &lvi))
continue;
lpItem = (LPRECIPIENT_INFO) lvi.lParam;
if (bSortByLastName)
StrCpyN(lpItem->szDisplayName, lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
else
StrCpyN(lpItem->szDisplayName, lpItem->szByFirstName,ARRAYSIZE(lpItem->szDisplayName));
ListView_SetItem(hWndLV, &lvi);
ListView_SetItemText(hWndLV,i,colDisplayName,lpItem->szDisplayName);
}
return;
}
//$$-----------------------------------------------------------------------
//|
//| SortListViewColumn - Sorting Routine for the List View
//|
//| HWndLV - handle of List View
//| iSortCol - ColumnSorted by ...
//| lpSortInfo - this particular dialogs sort info structure ...
//| bUseCurrentSettings - sometimes we want to call this function but dont want
//| to change the sort settings - those times we set this to true, in which
//| case, the iSortCol parameter is ignored
//|
//*------------------------------------------------------------------------
void SortListViewColumn(LPIAB lpIAB, HWND hWndLV, int iSortCol, LPSORT_INFO lpSortInfo, BOOL bUseCurrentSettings)
{
HCURSOR hOldCur = NULL;
if(!bUseCurrentSettings)
{
lpSortInfo->iOlderSortCol = lpSortInfo->iOldSortCol;
if (lpSortInfo->iOldSortCol == iSortCol)
{
// if we previously sorted by this column then toggle the sort mode
if(iSortCol == colDisplayName)
{
// For Display Name, the sort order is
// LastName Ascending
// False True
// False False
// True True
// True False
if(lpSortInfo->bSortByLastName && !lpSortInfo->bSortAscending)
lpSortInfo->bSortByLastName = FALSE;
else if(!lpSortInfo->bSortByLastName && !lpSortInfo->bSortAscending)
lpSortInfo->bSortByLastName = TRUE;
}
lpSortInfo->bSortAscending = !lpSortInfo->bSortAscending;
}
else
{
// this is a new column - sort ascending
lpSortInfo->bSortAscending = TRUE;
lpSortInfo->iOldSortCol = iSortCol;
}
}
hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
UpdateListViewItemsByName(hWndLV,lpSortInfo->bSortByLastName);
ListView_SortItems( hWndLV, ListViewSort, (LPARAM) lpSortInfo);
SetColumnHeaderBmp(hWndLV, *lpSortInfo);
SetCursor(hOldCur);
// Highlight the first selected item we can find
if (ListView_GetSelectedCount(hWndLV) > 0)
ListView_EnsureVisible(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED), FALSE);
WriteRegistrySortInfo(lpIAB, *lpSortInfo);
return;
}
const LPTSTR lpszRegSortKeyName = TEXT("Software\\Microsoft\\WAB\\WAB Sort State");
const LPTSTR lpszRegSortKeyValueName = TEXT("State");
const LPTSTR lpszRegPositionKeyValueName = TEXT("Position");
const LPTSTR lpszRegFindPositionKeyValueName = TEXT("FindPosition");
//$$
/************************************************************************************
- ReadRegistrySortInfo
-
* Purpose:
* Getss the previously stored Sort Info into the registry so we can have
* persistence between sessions.
*
* Arguments:
* LPSORT_INFO lpSortInfo
*
* Returns:
* BOOL
*
*************************************************************************************/
BOOL ReadRegistrySortInfo(LPIAB lpIAB, LPSORT_INFO lpSortInfo)
{
BOOL bRet = FALSE;
HKEY hKey = NULL;
HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
DWORD dwLenName = sizeof(SORT_INFO);
DWORD dwDisposition = 0;
DWORD dwType = 0;
if (!lpSortInfo)
goto out;
// default value
//
lpSortInfo->iOldSortCol = colDisplayName;
lpSortInfo->iOlderSortCol = colDisplayName;
lpSortInfo->bSortAscending = TRUE;
lpSortInfo->bSortByLastName = bDNisByLN;
// Open key
if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
lpszRegSortKeyName,
0, //reserved
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&dwDisposition))
{
goto out;
}
if(dwDisposition == REG_CREATED_NEW_KEY)
goto out;
// Now Read this key
if (ERROR_SUCCESS != RegQueryValueEx(hKey,
lpszRegSortKeyValueName,
NULL,
&dwType,
(LPBYTE) lpSortInfo,
&dwLenName))
{
DebugTrace( TEXT("RegQueryValueEx failed\n"));
goto out;
}
bRet = TRUE;
out:
if (hKey)
RegCloseKey(hKey);
return(bRet);
}
//$$
/*************************************************************************************
- WriteRegistrySortInfo
-
* Purpose:
* Write the current Sort Info into the registry so we can have
* persistence between sessions.
*
* Arguments:
* SORT_INFO SortInfo
*
* Returns:
* BOOL
*
*************************************************************************************/
BOOL WriteRegistrySortInfo(LPIAB lpIAB, SORT_INFO SortInfo)
{
BOOL bRet = FALSE;
// const LPTSTR lpszRegSortKeyName = TEXT( TEXT("Software\\Microsoft\\WAB\\WAB Sort State"));
HKEY hKey = NULL;
HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
DWORD dwLenName = sizeof(SORT_INFO);
DWORD dwDisposition =0;
// Open key
if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
lpszRegSortKeyName,
0, //reserved
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition))
{
DebugTrace( TEXT("RegCreateKeyEx failed\n"));
goto out;
}
// Now Write this key
if (ERROR_SUCCESS != RegSetValueEx( hKey,
lpszRegSortKeyValueName,
0,
REG_BINARY,
(LPBYTE) &SortInfo,
dwLenName))
{
DebugTrace( TEXT("RegSetValue failed\n"));
goto out;
}
bRet = TRUE;
out:
if (hKey)
RegCloseKey(hKey);
return(bRet);
}
//$$************************************************************\
//*
//* SetLocalizedDisplayName - sets the localized display name as
//* per localization information/
//*
//* szBuf points to a predefined buffer of length ulzBuf.
//* lpszFirst/Middle/Last/Company can be NULL
//* If szBuffer is null and ulszBuf=0, then we return the lpszBuffer
//* created here in the lppRetBuf parameter...
//* Caller has to LocalFree lppszRetBuf
//*
//
// Rules for creating DisplayName
//
// - If there is no display name, and there is a first/middle/last name,
// we make display name = localized(First/Middle/Last)
// - If there is no DN or FML, but NN, we make DN = NickName
// - If there is no DN, FML, NN but Company Name, we make
// DN = Company Name
// - If there is no DN, FML, NN, CN, we fail
//\***************************************************************/
BOOL SetLocalizedDisplayName(
LPTSTR lpszFirstName,
LPTSTR lpszMiddleName,
LPTSTR lpszLastName,
LPTSTR lpszCompanyName,
LPTSTR lpszNickName,
LPTSTR * lppszBuf,
ULONG ulszBuf,
BOOL bDNbyLN,
LPTSTR lpTemplate,
LPTSTR * lppszRetBuf)
{
LPTSTR szBuf = NULL;
LPTSTR szResource = NULL;
LPTSTR lpszArg[3];
LPTSTR lpszFormatName = NULL;
LPVOID lpszBuffer = NULL;
BOOL bRet = FALSE;
int idResource =0;
if (!lpszFirstName && !lpszMiddleName && !lpszLastName && !lpszNickName && !lpszCompanyName)
goto out;
if (lppszBuf)
szBuf = *lppszBuf;
if(lpTemplate)
szResource = lpTemplate;
else
szResource = bDNbyLN ?
(bDNisByLN ? szResourceDNByLN : szResourceDNByCommaLN)
: szResourceDNByFN;
if (!lpszFirstName && !lpszMiddleName && !lpszLastName)
{
if(lpszNickName)
{
DWORD cchSize=lstrlen(lpszNickName) + 1;
// Use the NickName
if (! (lpszFormatName = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize)))
goto out;
StrCpyN(lpszFormatName, lpszNickName, cchSize);
}
else if(lpszCompanyName)
{
DWORD cchSize=lstrlen(lpszCompanyName) + 1;
// just use company name
if (! (lpszFormatName = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize)))
goto out;
StrCpyN(lpszFormatName, lpszCompanyName, cchSize);
}
else
goto out; //shouldnt happen
}
else
{
//Bug #101350 - (erici) lstrlen will AV (and handle it) if passed a NULL
if( (lpszFirstName && (lstrlen(lpszFirstName) >= MAX_UI_STR)) ||
(lpszMiddleName && (lstrlen(lpszMiddleName) >= MAX_UI_STR)) ||
(lpszLastName && (lstrlen(lpszLastName) >= MAX_UI_STR)) )
goto out;
lpszArg[0] = lpszFirstName ? lpszFirstName : szEmpty;
lpszArg[1] = lpszMiddleName? lpszMiddleName : szEmpty;
lpszArg[2] = lpszLastName ? lpszLastName : szEmpty;
// FormatMessage doesnt do partial copying .. so we need to assimilate the name
// first and then squeeze it into our buffer ...
//
if(!FormatMessage( FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
szResource,
0, //ignored
0, //ignored
(LPTSTR) &lpszBuffer,
MAX_UI_STR,
(va_list *)lpszArg))
{
DebugPrintError(( TEXT("FormatStringFailed: %d\n"),GetLastError()));
goto out;
}
lpszFormatName = (LPTSTR) lpszBuffer;
TrimSpaces(lpszFormatName);
// If we dont have a last name and the sort is by last name, then
// we will get an ugly looking comma in the beginning for the english
// version only .. special case cheating here to remove that coma
//
if(bDNbyLN && (!lpszLastName || !lstrlen(lpszLastName)))
{
BOOL bSkipChar = FALSE;
if (lpszFormatName[0]==',')
{
bSkipChar = TRUE;
}
else
{
LPTSTR lp = lpszFormatName;
if(*lp == 0x81 && *(lp+1) == 0x41) // Japanese Comma is 0x810x41.. will this work ??
bSkipChar = TRUE;
}
if(bSkipChar)
{
LPTSTR lpszTmp = CharNext(lpszFormatName);
StrCpyN(lpszFormatName, lpszTmp, MAX_UI_STR);
TrimSpaces(lpszFormatName);
}
}
// Whatever the localizers combination of first middle last names for the
// display name (eg FML, LMF, LFM etc), if the middle element is missing,
// we'll get 2 blank spaces in the display name and we need to remove that.
// Search and replace double blanks.
{
LPTSTR lpsz=lpszFormatName,lpsz1=NULL;
while(lpsz && (*lpsz!='\0'))
{
lpsz1 = CharNext(lpsz);
if (IsSpace(lpsz) && IsSpace(lpsz1)) {
StrCpyN(lpsz, lpsz1, lstrlen(lpsz1)+1); // this is safe because we are
// copying the string over itself
continue; // use same lpsz
} else {
lpsz = lpsz1;
}
}
}
}
// If we were provided a buffer, use it ...
if((lppszRetBuf) && (szBuf == NULL) && (ulszBuf == 0))
{
*lppszRetBuf = lpszFormatName;
}
else
{
CopyTruncate(szBuf, lpszFormatName, ulszBuf);
}
bRet = TRUE;
out:
if((lpszFormatName) && (lppszRetBuf == NULL) && (ulszBuf != 0))
LocalFreeAndNull(&lpszFormatName);
return bRet;
}
//$$
//*------------------------------------------------------------------------
//| SetChildDefaultGUIFont: Callback function that sets all the children of
//| any window to the default GUI font -
//| needed for localization.
//|
//| hWndChild - handle to child
//| lParam - ignored
//|
//*------------------------------------------------------------------------
STDAPI_(BOOL) SetChildDefaultGUIFont(HWND hWndChild, LPARAM lParam)
{
// Code below is stolen from Shlwapi.dll
//
LPPTGDATA lpPTGData=GetThreadStoragePointer();
HFONT hfont;
HFONT hfontDefault;
LOGFONT lf;
LOGFONT lfDefault;
HWND hWndParent = GetParent(hWndChild);
hfont = GetWindowFont(hWndParent ? hWndParent : hWndChild);
GetObject(hfont, sizeof(LOGFONT), &lf);
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lfDefault, 0);
if ( (lfDefault.lfCharSet == lf.lfCharSet) &&
(lfDefault.lfHeight == lf.lfHeight) &&
(PARENT_IS_DIALOG == lParam) )
{
// if the dialog already has the correct character set and size
// don't do anything.
return TRUE;
}
if(PARENT_IS_DIALOG == lParam)
hfontDefault = pt_hDlgFont;
else
hfontDefault = pt_hDefFont;
// If we already have hfont created, use it.
if(!hfontDefault)
{
// [bobn] Raid #88470: We should use the default size on dialogs
if(PARENT_IS_DIALOG == lParam)
lfDefault.lfHeight = lf.lfHeight;
if (!(hfontDefault=CreateFontIndirect(&lfDefault)))
{
// restore back in failure
hfontDefault = hfont;
}
if (hfontDefault != hfont)
{
if(PARENT_IS_DIALOG == lParam)
pt_hDlgFont = hfontDefault;
else
pt_hDefFont = hfontDefault;
}
}
if(!hfontDefault)
hfontDefault = GetStockObject(DEFAULT_GUI_FONT);
SetWindowFont(hWndChild, hfontDefault, FALSE);
return TRUE;
}
//$$
//*------------------------------------------------------------------------
//| HrGetLDAPContentsList: Gets ContentsList from an LDAP container - Opens
//| a container - populates it using the given restriction,
//| and puts its contents in the List View
//|
//| lpIAB - Address Book object
//| cbContainerEID, lpContainerEID - LDAP Container EntryID
//| SortInfo - Current Sort State
//| lpPropRes - Property Restriction with which to do the Search
//| lpPTA - PropTagArray to return - currently ignored
//| ulFlags - 0 - currently ignored
//| lppContentsList - Returned, filled Contents List
//| lpAdvFilter - alternate advanced filter used in place of the property restriction
//*------------------------------------------------------------------------
HRESULT HrGetLDAPContentsList(LPADRBOOK lpAdrBook,
ULONG cbContainerEID,
LPENTRYID lpContainerEID,
SORT_INFO SortInfo,
LPSRestriction lpPropRes,
LPTSTR lpAdvFilter,
LPSPropTagArray lpPTA,
ULONG ulFlags,
LPRECIPIENT_INFO * lppContentsList)
{
HRESULT hr = hrSuccess;
HRESULT hrSaveTmp = E_FAIL; // temporarily saves partial completion error so it can be propogated to calling funtion
ULONG ulObjectType = 0;
LPCONTAINER lpContainer = NULL;
LPMAPITABLE lpContentsTable = NULL;
LPSRowSet lpSRowSet = NULL;
ULONG i = 0,j=0;
LPRECIPIENT_INFO lpItem = NULL;
LPRECIPIENT_INFO lpLastListItem = NULL;
DebugPrintTrace(( TEXT("-----HrGetLDAPContentsList: entry\n")));
if(!lpPropRes && !lpAdvFilter)
{
DebugPrintError(( TEXT("No search restriction created\n")));
hr = E_FAIL;
goto out;
}
//
// First we need to open the container object corresponding to this Container EntryID
//
hr = lpAdrBook->lpVtbl->OpenEntry(
lpAdrBook,
cbContainerEID,
lpContainerEID,
NULL,
0,
&ulObjectType,
(LPUNKNOWN *) &lpContainer);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("OpenEntry Failed: %x\n"),hr));
goto out;
}
//
// Now we do a get contents table on this container ...
//
hr = lpContainer->lpVtbl->GetContentsTable(
lpContainer,
MAPI_UNICODE,
&lpContentsTable);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("GetContentsTable Failed: %x\n"),hr));
goto out;
}
/****
//$$$$$$$$$$$$
// Test code
{
SPropValue valAnr;
SRestriction resAnr;
LPSRowSet prws;
LPTSTR lpsz = TEXT("Vikram");
// Set up the Ambiguous Name Resolution property value.
valAnr.ulPropTag = PR_ANR;
valAnr.Value.LPSZ = lpsz;
// Set up the Ambiguous Name Resolution restriction.
resAnr.rt = RES_PROPERTY;
resAnr.res.resProperty.relop = RELOP_EQ;
resAnr.res.resProperty.ulPropTag = valAnr.ulPropTag;
resAnr.res.resProperty.lpProp = &valAnr;
// Restrict the contents table.
// Set columns and query rows to see what state we fall in. We ask for one more
// row than the value of the Few/Many threshold. This allows us to tell whether
// we are a Few/Many ambiguity.
hr = lpContentsTable->lpVtbl->Restrict(lpContentsTable,
&resAnr,
TBL_BATCH);
hr = lpContentsTable->lpVtbl->SetColumns(lpContentsTable,
(LPSPropTagArray)&ptaResolveDefaults,
TBL_BATCH);
hr = lpContentsTable->lpVtbl->SeekRow(lpContentsTable,
BOOKMARK_BEGINNING,
0, 0);
hr = lpContentsTable->lpVtbl->QueryRows(lpContentsTable,
1,
0,
&prws);
FreeProws(prws);
}
//$$$$$$$$$$$$
/*****/
// If the user has specified an advanced filter, we need to figure out some way to
// pass it to the LDAP routines while still taking advantage of our LDAP contents table
// To do this we will do a hack and pass in the lpAdvFilter cast to a LPPropRes and then
// recast back at the other end
// This may break if any changes are made to the table implementation
//
// We now do the find rows
hr = lpContentsTable->lpVtbl->FindRow(
lpContentsTable,
lpAdvFilter ? (LPSRestriction) lpAdvFilter : lpPropRes,
BOOKMARK_BEGINNING,
lpAdvFilter ? LDAP_USE_ADVANCED_FILTER : 0); //flags
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("FindRow Failed: %x\n"),hr));
goto out;
}
// if this was a partial completion error - we want to treat it as success
// but also propogate it to the calling function
if(hr == MAPI_W_PARTIAL_COMPLETION)
hrSaveTmp = hr;
// If we got this far, then we have a populated table
// We should be able to do a Query Rows here ...
hr = SetRecipColumns(lpContentsTable);
if(HR_FAILED(hr))
goto out;
hr = HrQueryAllRows(lpContentsTable,
NULL,
NULL,
NULL,
0,
&lpSRowSet);
if (HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
goto out;
}
//
// if there's anything in the contents list flush it away
//
if (*lppContentsList)
{
lpItem = (*lppContentsList);
(*lppContentsList) = lpItem->lpNext;
FreeRecipItem(&lpItem);
}
*lppContentsList = NULL;
lpItem = NULL;
for(i=0;i<lpSRowSet->cRows;i++)
{
LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
if (!lpItem)
{
DebugPrintError(( TEXT("LocalAlloc Failed \n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
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;
}
// Tag this as an item from the contents and not from the original AdrList
lpItem->ulOldAdrListEntryNumber = 0;
// The entryids are in sorted order by display name
// Depending on the sort order - we want this list to also be sorted by display
// name or by reverse display name ...
if (SortInfo.bSortByLastName)
StrCpyN(lpItem->szDisplayName,lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
if(!SortInfo.bSortAscending)
{
//Add it to the contents linked list
lpItem->lpNext = (*lppContentsList);
if (*lppContentsList)
(*lppContentsList)->lpPrev = lpItem;
lpItem->lpPrev = NULL;
*lppContentsList = lpItem;
}
else
{
if(*lppContentsList == NULL)
(*lppContentsList) = lpItem;
if(lpLastListItem)
lpLastListItem->lpNext = lpItem;
lpItem->lpPrev = lpLastListItem;
lpItem->lpNext = NULL;
lpLastListItem = lpItem;
}
lpItem = NULL;
} //for i ....
// reset this error if applicable so calling function can treat it correctly
if(hrSaveTmp == MAPI_W_PARTIAL_COMPLETION)
hr = hrSaveTmp;
out:
if(lpSRowSet)
FreeProws(lpSRowSet);
if(lpContentsTable)
lpContentsTable->lpVtbl->Release(lpContentsTable);
if(lpContainer)
lpContainer->lpVtbl->Release(lpContainer);
if (HR_FAILED(hr))
{
while(*lppContentsList)
{
lpItem = *lppContentsList;
*lppContentsList=lpItem->lpNext;
FreeRecipItem(&lpItem);
}
}
return hr;
}
//$$
/******************************************************************************
//
// HrGetWABContents - Gets and fills the current list view with contents from the
// local store.
//
// hWndList - Handle to List View which we will populate
// lpIAB - Handle to Address Bok object
// SortInfo - Current Sort State
// lppContentsList - linked list in which we will store info about entries
//
/******************************************************************************/
HRESULT HrGetWABContents( HWND hWndList,
LPADRBOOK lpAdrBook,
LPSBinary lpsbContainer,
SORT_INFO SortInfo,
LPRECIPIENT_INFO * lppContentsList)
{
HRESULT hr = hrSuccess;
LPIAB lpIAB = (LPIAB) lpAdrBook;
int nSelectedItem = ListView_GetNextItem(hWndList, -1, LVNI_SELECTED);
if(nSelectedItem < 0)
nSelectedItem = 0;
SendMessage(hWndList, WM_SETREDRAW, FALSE, 0L);
ClearListView(hWndList, lppContentsList);
if (HR_FAILED(hr = HrGetWABContentsList(
lpIAB,
SortInfo,
NULL,
NULL,
0,
lpsbContainer,
FALSE,
lppContentsList)))
{
goto out;
}
// There is a performance issue of filling names
// If names are sorted by first name and are by first col,
// we can show them updated - otherwise we cant
if (HR_FAILED(hr = HrFillListView( hWndList,
*lppContentsList)))
{
goto out;
}
/*
if((SortInfo.iOldSortCol == colDisplayName) &&
(!SortInfo.bSortByLastName))
{
// Already Sorted
SetColumnHeaderBmp(hWndList, SortInfo);
}
else
*/ {
// Otherwise sort
SortListViewColumn(lpIAB, hWndList, colDisplayName, &SortInfo, TRUE);
}
/*
if (ListView_GetSelectedCount(hWndList) <= 0)
{
// nothing selected - so select 1st item
// Select the first item in the List View
LVSelectItem(hWndList, 0);
}
else
{
LVSelectItem(hWndList, ListView_GetNextItem(hWndList, -1, LVNI_SELECTED));
}
*/
LVSelectItem(hWndList, nSelectedItem);
out:
SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
return(hr);
}
//$$
/******************************************************************************/
//
// HrGetLDAPSearchRestriction -
//
//
// For a simple search we have the following data to work with
// Country - PR_COUNTRY
// DisplayName - PR_DISPLAY_NAME
//
// For a detailed search
// We have the following data to work with
// Country - PR_COUNTRY
// FirstName - PR_GIVEN_NAME
// LastName - PR_SURNAME
// EMail - PR_EMAIL_ADDRESS
// Organization - PR_COMPANY_NAME
//
//
/******************************************************************************/
HRESULT HrGetLDAPSearchRestriction(LDAP_SEARCH_PARAMS LDAPsp, LPSRestriction lpSRes)
{
SRestriction SRes = {0};
LPSRestriction lpPropRes = NULL;
ULONG ulcPropCount = 0;
HRESULT hr = E_FAIL;
ULONG i = 0;
SCODE sc = ERROR_SUCCESS;
lpSRes->rt = RES_AND;
ulcPropCount = 0;
if (lstrlen(LDAPsp.szData[ldspDisplayName]))
ulcPropCount++; //PR_EMAIL_ADDRESS and PR_DISPLAY_NAME
if (lstrlen(LDAPsp.szData[ldspEmail]))
ulcPropCount++;
if (!ulcPropCount)
{
DebugPrintError(( TEXT("No Search Props!\n")));
goto out;
}
lpSRes->res.resAnd.cRes = ulcPropCount;
lpSRes->res.resAnd.lpRes = NULL;
sc = MAPIAllocateBuffer(ulcPropCount * sizeof(SRestriction), (LPVOID *) &(lpSRes->res.resAnd.lpRes));
if (sc != S_OK)
{
DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
if(!(lpSRes->res.resAnd.lpRes))
{
DebugPrintError(( TEXT("Error Allocating Memory\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
lpPropRes = lpSRes->res.resAnd.lpRes;
ulcPropCount = 0;
for(i=0;i<ldspMAX;i++)
{
if(lstrlen(LDAPsp.szData[i]))
{
ULONG ulPropTag = 0;
DWORD cchSize;
LPSPropValue lpPropArray = NULL;
switch(i)
{
case ldspEmail:
ulPropTag = PR_EMAIL_ADDRESS;
break;
case ldspDisplayName:
ulPropTag = PR_DISPLAY_NAME;
break;
default:
continue;
}
lpPropRes[ulcPropCount].rt = RES_PROPERTY;
lpPropRes[ulcPropCount].res.resProperty.relop = RELOP_EQ;
lpPropRes[ulcPropCount].res.resProperty.ulPropTag = ulPropTag;
lpPropRes[ulcPropCount].res.resProperty.lpProp = NULL;
MAPIAllocateMore(sizeof(SPropValue),lpPropRes, (LPVOID *) &(lpPropRes[ulcPropCount].res.resProperty.lpProp));
lpPropArray = lpPropRes[ulcPropCount].res.resProperty.lpProp;
if(!lpPropArray)
{
DebugPrintError(( TEXT("Error allocating memory\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
lpPropArray->ulPropTag = ulPropTag;
lpPropArray->Value.LPSZ = NULL;
cchSize=lstrlen(LDAPsp.szData[i])+1;
MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropRes, (LPVOID *) (&(lpPropArray->Value.LPSZ)));
if(!lpPropArray->Value.LPSZ)
{
DebugPrintError(( TEXT("Error allocating memory\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
StrCpyN(lpPropArray->Value.LPSZ,LDAPsp.szData[i], cchSize);
ulcPropCount++;
}
}
hr = S_OK;
out:
return hr;
}
//$$/////////////////////////////////////////////////////////////////////////
//
// ShowMessageBoxParam - Generic MessageBox displayer .. saves space all over
//
// hWndParent - Handle of Message Box Parent
// MsgID - resource id of message string
// ulFlags - MessageBox flags
// ... - format parameters
//
///////////////////////////////////////////////////////////////////////////
int __cdecl ShowMessageBoxParam(HWND hWndParent, int MsgId, int ulFlags, ...)
{
TCHAR szBuf[MAX_BUF_STR] = TEXT("");
TCHAR szCaption[MAX_PATH] = TEXT("");
LPTSTR lpszBuffer = NULL;
int iRet = 0;
va_list vl;
va_start(vl, ulFlags);
LoadString(hinstMapiX, MsgId, szBuf, ARRAYSIZE(szBuf));
// if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
szBuf,
0,0, //ignored
(LPTSTR)&lpszBuffer,
MAX_BUF_STR, //MAX_UI_STR
// (LPTSTR *)&(lpParam))) {
(va_list *)&vl)) {
TCHAR szCaption[MAX_PATH];
*szCaption = '\0';
if(hWndParent)
GetWindowText(hWndParent, szCaption, ARRAYSIZE(szCaption));
if(!lstrlen(szCaption)) // if no caption get the parents caption - this is necessary for property sheets
{
if(hWndParent)
GetWindowText(GetParent(hWndParent), szCaption, ARRAYSIZE(szCaption));
if(!lstrlen(szCaption)) //if still not caption, get the generic title
LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szCaption, ARRAYSIZE(szCaption));
}
iRet = MessageBox(hWndParent, lpszBuffer, szCaption, ulFlags);
LocalFreeAndNull(&lpszBuffer);
}
va_end(vl);
return(iRet);
}
//$$/////////////////////////////////////////////////////////////////////////
//
// ShowMessageBox - Generic MessageBox displayer .. saves space all over
//
// hWndParent - Handle of Message Box Parent
// MsgID - resource id of message string
// ulFlags - MessageBox flags
//
///////////////////////////////////////////////////////////////////////////
int ShowMessageBox(HWND hWndParent, int MsgId, int ulFlags)
{
TCHAR szBuf[MAX_BUF_STR];
TCHAR szCaption[MAX_PATH];
szCaption[0]='\0';
szBuf[0]='\0';
LoadString(hinstMapiX, MsgId, szBuf, ARRAYSIZE(szBuf));
if(hWndParent)
{
GetWindowText(hWndParent, szCaption, ARRAYSIZE(szCaption));
if(!lstrlen(szCaption))
{
// if we cant get a caption, get the windows parents caption
HWND hWnd = GetParent(hWndParent);
GetWindowText(hWnd, szCaption, ARRAYSIZE(szCaption));
}
}
if(!lstrlen(szCaption))
{
//if we cant get the parents caption, get a generic title
LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szCaption, ARRAYSIZE(szCaption));
}
return MessageBox(hWndParent, szBuf, szCaption, ulFlags);
}
//$$/////////////////////////////////////////////////////////////////////////////
//
// my_atoi - personal version of atoi function
//
// lpsz - string to parse into numbers - non numeral characters are ignored
//
/////////////////////////////////////////////////////////////////////////////////
int my_atoi(LPTSTR lpsz)
{
int i=0;
int nValue = 0;
if(lpsz)
{
if (lstrlen(lpsz))
{
nValue = 0;
while((lpsz[i]!='\0')&&(i<=lstrlen(lpsz)))
{
int tmp = lpsz[i]-'0';
if(tmp <= 9)
nValue = nValue*10 + tmp;
i++;
}
}
}
return nValue;
}
#ifdef OLD_STUFF
//$$/////////////////////////////////////////////////////////////////////////////
//
// FillComboLDAPCountryNames - Fills a dropdown conbo with LDAP country names
//
// hWndCombo - Handle of Combo
//
/////////////////////////////////////////////////////////////////////////////////
void FillComboLDAPCountryNames(HWND hWndCombo)
{
TCHAR szBuf[MAX_UI_STR];
int nCountrys = 0;
int i=0;
LoadString(hinstMapiX, idsCountryCount,szBuf,ARRAYSIZE(szBuf));
nCountrys = my_atoi(szBuf);
if(nCountrys == 0)
nCountrys = MAX_COUNTRY_NUM;
for(i=0;i<nCountrys;i++)
{
LoadString(hinstMapiX, idsCountry1+i,szBuf,ARRAYSIZE(szBuf));
SendMessage(hWndCombo,CB_ADDSTRING, 0, (LPARAM) szBuf);
}
// Look in the regsitry for a default specfied country ...
ReadRegistryLDAPDefaultCountry(szBuf, ARRAYSIZE(szBuf), NULL, 0);
// set the selection to default from registry
i = SendMessage(hWndCombo, CB_FINDSTRING, (WPARAM) -1, (LPARAM) szBuf);
if(i==CB_ERR)
{
i = SendMessage(hWndCombo, CB_FINDSTRING, (WPARAM) -1, (LPARAM) TEXT("United States"));
}
SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) i, 0);
return;
}
#endif
//$$/////////////////////////////////////////////////////////////////////////////
//
// ReadRegistryLDAPDefaultCountry - Reads the default country name or code from the
// registry
//
// szCountry, szCountryCode - buffers that will recieve the country and/or country
// code. These can be NULL if no country or countrycode is
// required.
//
/////////////////////////////////////////////////////////////////////////////////
BOOL ReadRegistryLDAPDefaultCountry(LPTSTR szCountry, DWORD cchCountry, LPTSTR szCountryCode, DWORD cchCountryCode)
{
BOOL bRet = FALSE;
DWORD dwErr;
HKEY hKey = NULL;
ULONG ulSize = MAX_UI_STR;
DWORD dwType;
TCHAR szTemp[MAX_UI_STR];
if(!szCountry && !szCountryCode)
goto out;
if (szCountry)
szCountry[0]='\0';
if (szCountryCode)
szCountryCode[0]='\0';
dwErr = RegOpenKeyEx( HKEY_CURRENT_USER,
szWABKey,
0,
KEY_READ,
&hKey);
if(dwErr)
goto out;
dwErr = RegQueryValueEx( hKey,
(LPTSTR)szLDAPDefaultCountryValue,
NULL,
&dwType,
(LPBYTE)szTemp,
&ulSize);
if(dwErr)
{
// We dont have a registry setting .. or there was some error
// In this case we need to get the Default Country for this locale
// using the NLS API
ulSize = GetLocaleInfo( LOCALE_USER_DEFAULT,
LOCALE_SENGCOUNTRY,
(LPTSTR) szTemp,
ARRAYSIZE(szTemp));
if(ulSize>0)
{
// We got a valid country but it obviously doesnt have a code
if(szCountry)
StrCpyN(szCountry, szTemp, cchCountry);
if(szCountryCode)
{
int i =0;
int cMax=0;
TCHAR szBufCountry[MAX_UI_STR];
szBufCountry[0]='\0';
StrCpyN(szBufCountry,szTemp,ARRAYSIZE(szBufCountry));
LoadString(hinstMapiX, idsCountryCount,szTemp,ARRAYSIZE(szTemp));
cMax = my_atoi(szTemp);
for(i=0;i<cMax;i++)
{
LoadString(hinstMapiX, idsCountry1+i, szTemp, ARRAYSIZE(szTemp));
if(lstrlen(szTemp) < lstrlen(szBufCountry))
continue;
if( !memcmp(szTemp, szBufCountry, (lstrlen(szBufCountry) * sizeof(TCHAR))) )
{
//Found our match
LPTSTR lpszTmp = szTemp;
szCountryCode[0]='\0';
while(*lpszTmp && (*lpszTmp != '('))
lpszTmp = CharNext(lpszTmp);
if(*lpszTmp && (*lpszTmp == '('))
{
lpszTmp = CharNext(lpszTmp);
CopyMemory(szCountryCode,lpszTmp,sizeof(TCHAR)*2);
szCountryCode[2] = '\0';
}
break;
}
}
if(!lstrlen(szCountryCode))
{
// default to US
StrCpyN(szCountryCode, TEXT("US"), cchCountryCode);
}
}
bRet = TRUE;
goto out;
}
}
else
{
// Otherwise - do our normal processing
if(szCountry)
StrCpyN(szCountry, szTemp, cchCountry);
if(szCountryCode)
{
LPTSTR lpszTmp = szTemp;
szCountryCode[0]='\0';
while(*lpszTmp && (*lpszTmp != '('))
lpszTmp = CharNext(lpszTmp);
if(*lpszTmp && (*lpszTmp == '('))
{
lpszTmp = CharNext(lpszTmp);
CopyMemory(szCountryCode,lpszTmp,sizeof(TCHAR)*2);
szCountryCode[2] = '\0';
}
if(!lstrlen(szCountryCode))
{
// default to US
StrCpyN(szCountryCode, TEXT("US"), cchCountryCode);
}
}
}
bRet = TRUE;
out:
if(hKey)
RegCloseKey(hKey);
return bRet;
}
#ifdef OLD_STUFF
//$$/////////////////////////////////////////////////////////////////////////////
//
// WriteRegistryLDAPDefaultCountry - Writes the default country name to the
// registry
//
// szCountry - default country code to write
//
/////////////////////////////////////////////////////////////////////////////////
BOOL WriteRegistryLDAPDefaultCountry(LPTSTR szCountry)
{
BOOL bRet = FALSE;
DWORD dwErr;
HKEY hKey = NULL;
ULONG ulSize = 0;
if(!szCountry)
goto out;
if(!lstrlen(szCountry))
goto out;
dwErr = RegOpenKeyEx( HKEY_CURRENT_USER,
szWABKey,
0,
KEY_READ | KEY_WRITE,
&hKey);
if(dwErr)
goto out;
dwErr = RegSetValueEx( hKey,
(LPTSTR) szLDAPDefaultCountryValue,
0,
REG_SZ,
szCountry,
(lstrlen(szCountry)+1) * sizeof(TCHAR) );
if(dwErr)
goto out;
bRet = TRUE;
out:
return bRet;
}
#endif //OLD_STUFF
BOOL bIsGroupSelected(HWND hWndLV, LPSBinary lpsbEID)
{
LPRECIPIENT_INFO lpItem;
if(ListView_GetSelectedCount(hWndLV) != 1)
return FALSE;
lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
if(lpItem && lpItem->ulObjectType == MAPI_DISTLIST)
{
if(lpsbEID)
{
lpsbEID->cb = lpItem->cbEntryID;
lpsbEID->lpb = (LPBYTE)lpItem->lpEntryID;
}
return TRUE;
}
return FALSE;
}
//$$
////////////////////////////////////////////////////////////////////////////////
//
// GetCurrentOptionsState - looks at the current state based on the ListView and
// the Combo and decides which options should be enabled or disabled
//
// hWndCombo - handle of Show Names combo
// hWndLV - handle of ListView to look at
// lpbState - points to a predefined array of BOOL bState[tbMAX]
//
////////////////////////////////////////////////////////////////////////////////
void GetCurrentOptionsState(HWND hWndLVContainer,
HWND hWndLV,
LPBOOL lpbState)
{
int i = 0;
ULONG cbEID = 0;
LPENTRYID lpEID = NULL;
BYTE bType = 0;
int nItemCount = ListView_GetItemCount(hWndLV);
int nSelectedCount = ListView_GetSelectedCount(hWndLV);
for(i=0;i<tbMAX;i++)
lpbState[i] = FALSE;
lpbState[tbPaste] = bIsPasteData();// && ( (nSelectedCount<=0) || (bIsGroupSelected(hWndLV, NULL)) );
lpbState[tbCopy] = lpbState[tbFind] = lpbState[tbAction] = TRUE;
if(hWndLVContainer)
{
// in the rare event that we have LDAP containers ...
GetCurrentContainerEID( hWndLVContainer,
&cbEID,
&lpEID);
bType = IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL);
}
else
{
bType = WAB_PAB;
}
if(bType == WAB_PAB || bType == WAB_PABSHARED)
{
lpbState[tbNew] = lpbState[tbNewEntry] = lpbState[tbNewGroup] = lpbState[tbNewFolder] = TRUE;
lpbState[tbAddToWAB] = FALSE;
if(nItemCount > 0)
lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = TRUE;
else
lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
if(nSelectedCount <= 0)
lpbState[tbCopy] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
else if(nSelectedCount > 1)
//lpbState[tbaction] =
lpbState[tbProperties] = FALSE;
}
else if(bType == WAB_LDAP_CONTAINER)
{
lpbState[tbDelete] = lpbState[tbNew] = lpbState[tbNewEntry] = lpbState[tbNewGroup] = lpbState[tbNewFolder] = FALSE;
if(nItemCount > 0)
lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbAddToWAB] = TRUE;
else
lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbAddToWAB] = FALSE;
if(nSelectedCount <= 0)
lpbState[tbPaste] = lpbState[tbCopy] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
else if(nSelectedCount > 1)
//lpbState[tbAction] =
lpbState[tbProperties] = FALSE;
}
else
{
// cant handle this case so turn everything off ....
for(i=0;i<tbMAX;i++)
lpbState[i] = FALSE;
}
return;
}
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrEntryAddToWAB - Adds an entry to the Address Book given an entryid
//
//
//
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrEntryAddToWAB( LPADRBOOK lpAdrBook,
HWND hWndParent,
ULONG cbInputEID,
LPENTRYID lpInputEID,
ULONG * lpcbOutputEID,
LPENTRYID * lppOutputEID)
{
HRESULT hr = E_FAIL;
ULONG ulcProps = 0;
LPSPropValue lpPropArray = NULL;
ULONG i;
hr = HrGetPropArray(lpAdrBook,
NULL,
cbInputEID,
lpInputEID,
MAPI_UNICODE,
&ulcProps,
&lpPropArray);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrGetPropArray failed:%x\n")));
goto out;
}
//
// This lpPropArray will have a non-zero entryid ... it will have the
// LDAP entry id .. we want to remove that value so we can store this
// lpPropArray as a fresh lpPropArray...
//
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == PR_ENTRYID)
{
lpPropArray[i].Value.bin.cb = 0;
break;
}
}
// Since this function exclusively adds people to the local WAB from LDAP
// we need to filter out non-storable properties here if they exist ...
for(i=0;i<ulcProps;i++)
{
switch(lpPropArray[i].ulPropTag)
{
case PR_WAB_MANAGER:
case PR_WAB_REPORTS:
case PR_WAB_LDAP_LABELEDURI:
lpPropArray[i].ulPropTag = PR_NULL;
break;
}
}
{
ULONG cbContEID = 0;
LPENTRYID lpContEID = NULL;
LPIAB lpIAB = (LPIAB) lpAdrBook;
if(bIsThereACurrentUser(lpIAB))
{
cbContEID = lpIAB->lpWABCurrentUserFolder->sbEID.cb;
lpContEID = (LPENTRYID)(lpIAB->lpWABCurrentUserFolder->sbEID.lpb);
}
hr = HrCreateNewEntry( lpAdrBook,
hWndParent,
MAPI_MAILUSER, //MAILUSER or DISTLIST
cbContEID, lpContEID,
MAPI_ABCONT,//add to root container only
CREATE_CHECK_DUP_STRICT,
TRUE,
ulcProps,
lpPropArray,
lpcbOutputEID,
lppOutputEID);
}
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrCreateNewEntry failed:%x\n")));
goto out;
}
out:
if (lpPropArray)
MAPIFreeBuffer(lpPropArray);
return hr;
}
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrAddToWAB - Adds an LDAP or one-off entry to the Address Book
// All such items will be added to the root container only
//
// lpIAB - ADRBOOK object
// hWndLV - Listview window handle
// lpftLast - WAB file time at last update
//
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrAddToWAB( LPADRBOOK lpIAB,
HWND hWndLV,
LPFILETIME lpftLast)
{
HRESULT hr = hrSuccess;
HRESULT hrDeferred = hrSuccess;
int nSelectedCount = 0;
LPRECIPIENT_INFO lpItem = NULL;
ULONG cbEID = 0;
LPENTRYID lpEID = NULL;
ULONG i = 0;
HCURSOR hOldCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
//
// Looks at the selected item in the List View,
// gets its entry id, gets its props, creates a new item with those props
//
if (!lpIAB || !hWndLV)
{
hr = MAPI_E_INVALID_PARAMETER;
goto out;
}
nSelectedCount = ListView_GetSelectedCount(hWndLV);
if(nSelectedCount <= 0)
{
ShowMessageBox(GetParent(hWndLV), idsNoItemsSelectedForAdding, MB_ICONEXCLAMATION | MB_OK);
hr = E_FAIL;
goto out;
}
else
{
// Walk through all the items processing the one by one
int iItemIndex = 0;
int iLastItemIndex = -1;
iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
while(iItemIndex != -1)
{
iLastItemIndex = iItemIndex;
lpItem = GetItemFromLV(hWndLV, iItemIndex);
if(lpItem)
{
nSelectedCount--; //now tracks how many are left
hr = HrEntryAddToWAB( lpIAB,
GetParent(hWndLV),
lpItem->cbEntryID,
lpItem->lpEntryID,
&cbEID,
&lpEID);
if(HR_FAILED(hr))
{
DebugPrintError(( TEXT("HrEntryAddToWAB failed:%x\n")));
if(hr != MAPI_E_USER_CANCEL)
hrDeferred = hr;
if (lpEID)
MAPIFreeBuffer(lpEID);
lpEID = NULL;
if(hr == MAPI_E_USER_CANCEL && nSelectedCount)
{
// user canceled this one and some other remain ..
// Ask if he wants to cancel the whole import operation
if(IDYES == ShowMessageBox(GetParent(hWndLV),
idsContinueAddingToWAB,
MB_YESNO | MB_ICONEXCLAMATION))
{
goto out;
}
}
// just keep going on if there are any remaining entries
goto end_loop;
}
// Update the wab file write time so the timer doesn't
// catch this change and refresh.
//if (lpftLast) {
// CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
//}
if (lpEID)
MAPIFreeBuffer(lpEID);
lpEID = NULL;
}
end_loop:
// Get the next selected item ...
iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
}
}
out:
if (lpEID)
MAPIFreeBuffer(lpEID);
if(hr != MAPI_E_USER_CANCEL)
{
if (!hrDeferred) //hr could be MAPI_W_ERRORS_RETURNED in which case it wasnt all roses so dont give this message ...
{
if(nSelectedCount)
ShowMessageBox(GetParent(hWndLV), idsSuccessfullyAddedUsers, MB_ICONINFORMATION | MB_OK);
}
else if(hrDeferred == MAPI_E_NOT_FOUND)
ShowMessageBox(GetParent(hWndLV), idsCouldNotAddSomeEntries, MB_ICONINFORMATION | MB_OK);
}
SetCursor(hOldCursor);
return hr;
}
//$$
/************************************************************************************
- ReadRegistryPositionInfo
-
* Purpose:
* Getss the previously stored modeless window size and column width info
* for persistence between sessions.
*
* Arguments:
* LPABOOK_POSCOLSIZE lpABPosColSize
* LPTSTR szPosKey - key to store it under
*
* Returns:
* BOOL
*
*************************************************************************************/
BOOL ReadRegistryPositionInfo(LPIAB lpIAB,
LPABOOK_POSCOLSIZE lpABPosColSize,
LPTSTR szPosKey)
{
BOOL bRet = FALSE;
HKEY hKey = NULL;
HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
DWORD dwLenName = sizeof(ABOOK_POSCOLSIZE);
DWORD dwDisposition = 0;
DWORD dwType = 0;
if(!lpABPosColSize)
goto out;
tryReadingAgain:
// Open key
if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
lpszRegSortKeyName,
0, //reserved
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&dwDisposition))
{
goto out;
}
if(dwDisposition == REG_CREATED_NEW_KEY)
goto out;
// Now Read the key
if (ERROR_SUCCESS != RegQueryValueEx(hKey,
szPosKey,
NULL,
&dwType,
(LPBYTE) lpABPosColSize,
&dwLenName))
{
DebugTrace( TEXT("RegQueryValueEx failed\n"));
if(hKeyRoot != HKEY_CURRENT_USER)
{
// with identities .. this will fail the first time ..so recover old HKCU settings for upgrades
hKeyRoot = HKEY_CURRENT_USER;
if(hKey)
RegCloseKey(hKey);
goto tryReadingAgain;
}
goto out;
}
bRet = TRUE;
out:
if (hKey)
RegCloseKey(hKey);
return(bRet);
}
//$$
/*************************************************************************************
- WriteRegistryPostionInfo
-
* Purpose:
* Write the given window position to the registry
*
* Arguments:
* LPABOOK_POSCOLSIZE lpABPosColSize
* LPTSTR szPosKey - key to write it in
*
* Returns:
* BOOL
*
*************************************************************************************/
BOOL WriteRegistryPositionInfo(LPIAB lpIAB,
LPABOOK_POSCOLSIZE lpABPosColSize,
LPTSTR szPosKey)
{
BOOL bRet = FALSE;
HKEY hKey = NULL;
HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
DWORD dwLenName = sizeof(ABOOK_POSCOLSIZE);
DWORD dwDisposition =0;
if(!lpABPosColSize)
goto out;
// Open key
if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
lpszRegSortKeyName,
0, //reserved
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition))
{
DebugTrace( TEXT("RegCreateKeyEx failed\n"));
goto out;
}
// Now Write this key
if (ERROR_SUCCESS != RegSetValueEx( hKey,
szPosKey,
0,
REG_BINARY,
(LPBYTE) lpABPosColSize,
dwLenName))
{
DebugTrace( TEXT("RegSetValue failed\n"));
goto out;
}
bRet = TRUE;
out:
if (hKey)
RegCloseKey(hKey);
return(bRet);
}
//$$////////////////////////////////////////////////////////////////////////////////
//
// ProcessLVCustomDraw - Processes the NMCustomDraw message for the various list views
//
// Used for setting the DistLists to a bolder font
//
// Parameters -
//
// lParam - lParam of original message
// hDlg - handle of dialog if the relevant window is a dialog, null otherwise
// bIsDialog - flag that tells us if this is a dialog or not
//
////////////////////////////////////////////////////////////////////////////////////
LRESULT ProcessLVCustomDraw(HWND hDlg, LPARAM lParam, BOOL bIsDialog)
{
NMCUSTOMDRAW *pnmcd = (NMCUSTOMDRAW *) lParam;
if(pnmcd->dwDrawStage==CDDS_PREPAINT)
{
if(bIsDialog)
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW|CDRF_DODEFAULT);
return TRUE;
}
else
return CDRF_NOTIFYITEMDRAW|CDRF_DODEFAULT;
}
else if(pnmcd->dwDrawStage==CDDS_ITEMPREPAINT)
{
LPRECIPIENT_INFO lpItem = (LPRECIPIENT_INFO) pnmcd->lItemlParam;
if(lpItem)
{
if(lpItem->ulObjectType == MAPI_DISTLIST)
{
SelectObject(((NMLVCUSTOMDRAW *)lParam)->nmcd.hdc, GetFont(fntsSysIconBold));
if(bIsDialog)
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
return TRUE;
}
else
return CDRF_NEWFONT;
}
}
}
if(bIsDialog)
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_DODEFAULT);
return TRUE;
}
else
return CDRF_DODEFAULT;
}
/*****
//$$/////////////////////////////////////////////////////////////
//
// DoLVQuickFilter - Simple quick find routine for matching edit box contents to
// List view entries
//
// lpIAB - lpAdrBook object
// hWndEdit - handle of Edit Box
// hWndLV - handle of List View
// lppContentsList - ContentsList
//
// ulFlags - AB_FUZZY_FIND_NAME | AB_FUZZY_FIND_EMAIL or Both
// int minLen - we may not want to trigger a search with 1 char or 2 char or less etc
//
///////////////////////////////////////////////////////////////
void DoLVQuickFilter( LPADRBOOK lpAdrBook,
HWND hWndEdit,
HWND hWndLV,
LPSORT_INFO lpSortInfo,
ULONG ulFlags,
int nMinLen,
LPRECIPIENT_INFO * lppContentsList)
{
TCHAR szBuf[MAX_PATH];
HRESULT hr = hrSuccess;
LPSBinary rgsbEntryIDs = NULL;
ULONG cValues = 0;
ULONG i =0;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
LPIAB lpIAB = (LPIAB)lpIAB;
GetWindowText(hWndEdit,szBuf,ARRAYSIZE(szBuf));
TrimSpaces(szBuf);
if(lstrlen(szBuf))
{
if(lstrlen(szBuf) < nMinLen)
goto out;
// BUGBUG <JasonSo>: Need to pass in the correct container here...
hr = HrFindFuzzyRecordMatches(
lpIAB->lpPropertyStore->hPropertyStore,
NULL,
szBuf,
ulFlags, //flags
&cValues,
&rgsbEntryIDs);
if(HR_FAILED(hr))
goto out;
SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) FALSE, 0);
ClearListView(hWndLV, lppContentsList);
if(cValues <= 0)
{
goto out;
}
for(i=0;i<cValues;i++)
{
LPRECIPIENT_INFO lpItem = NULL;
if(!ReadSingleContentItem( lpAdrBook,
rgsbEntryIDs[i].cb,
(LPENTRYID) rgsbEntryIDs[i].lpb,
&lpItem))
continue;
if(!lpItem)
continue;
//
// Hook in the lpItem into the lpContentsList so we can free it later
//
lpItem->lpPrev = NULL;
lpItem->lpNext = *lppContentsList;
if (*lppContentsList)
(*lppContentsList)->lpPrev = lpItem;
(*lppContentsList) = lpItem;
}
HrFillListView(hWndLV,
*lppContentsList);
SortListViewColumn( hWndLV, 0, lpSortInfo, TRUE);
LVSelectItem(hWndLV, 0);
SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) TRUE, 0);
}
else
{
hr = HrGetWABContents( hWndLV,
lpAdrBook,
NULL,
*lpSortInfo,
lppContentsList);
}
out:
FreeEntryIDs(((LPIAB)lpIAB)->lpPropertyStore->hPropertyStore,
cValues,
rgsbEntryIDs);
SetCursor(hOldCur);
return;
}
/*******/
//$$/////////////////////////////////////////////////////////////
//
// SetWindowPropertiesTitle - puts the objects name in front of the
// TEXT(" Properties") and puts it in the title
//
// e.g. Viewing properties on Vikram Madan would show a window
// with TEXT("Vikram Madan Properties") in the title as per
// Windows guidelines.
// if bProperties is false, shows TEXT("Vikram Madan Reports")
///////////////////////////////////////////////////////////////
void SetWindowPropertiesTitle(HWND hWnd, LPTSTR lpszName)
{
LPTSTR lpszBuffer = NULL;
TCHAR szBuf[MAX_UI_STR];
TCHAR szTmp[MAX_PATH], *lpszTmp;
LoadString( hinstMapiX,
idsWindowTitleProperties,
szBuf, ARRAYSIZE(szBuf));
// Win9x bug FormatMessage cannot have more than 1023 chars
CopyTruncate(szTmp, lpszName, 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))
{
SetWindowText(hWnd, lpszBuffer);
LocalFreeAndNull(&lpszBuffer);
}
return;
}
/**** Dont mess with the order of these arrays (especially the address components street,city,zip etc ****/
static const SizedSPropTagArray(25, ToolTipsProps)=
{
25,
{
PR_DISPLAY_NAME,
PR_EMAIL_ADDRESS,
PR_HOME_ADDRESS_STREET,
PR_HOME_ADDRESS_CITY,
PR_HOME_ADDRESS_STATE_OR_PROVINCE,
PR_HOME_ADDRESS_POSTAL_CODE,
PR_HOME_ADDRESS_COUNTRY,
PR_HOME_TELEPHONE_NUMBER,
PR_HOME_FAX_NUMBER,
PR_CELLULAR_TELEPHONE_NUMBER,
PR_PERSONAL_HOME_PAGE,
PR_TITLE,
PR_DEPARTMENT_NAME,
PR_OFFICE_LOCATION,
PR_COMPANY_NAME,
PR_BUSINESS_ADDRESS_STREET,
PR_BUSINESS_ADDRESS_CITY,
PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
PR_BUSINESS_ADDRESS_POSTAL_CODE,
PR_BUSINESS_ADDRESS_COUNTRY,
PR_BUSINESS_TELEPHONE_NUMBER,
PR_BUSINESS_FAX_NUMBER,
PR_PAGER_TELEPHONE_NUMBER,
PR_BUSINESS_HOME_PAGE,
PR_COMMENT,
}
};
enum _prop
{
txtDisplayName=0,
txtEmailAddress,
txtHomeAddress,
txtHomeCity,
txtHomeState,
txtHomeZip,
txtHomeCountry,
txtHomePhone,
txtHomeFax,
txtHomeCellular,
txtHomeWeb,
txtBusinessTitle,
txtBusinessDept,
txtBusinessOffice,
txtBusinessCompany,
txtBusinessAddress,
txtBusinessCity,
txtBusinessState,
txtBusinessZip,
txtBusinessCountry,
txtBusinessPhone,
txtBusinessFax,
txtBusinessPager,
txtBusinessWeb,
txtNotes
};
static const int idsString[] =
{
0,
idsContactTextEmail,
idsContactTextHomeAddress,
0,
0,
0,
0,
idsContactTextHomePhone,
idsContactTextHomeFax,
idsContactTextHomeCellular,
idsContactTextPersonalWebPage,
idsContactTextTitle,
idsContactTextDepartment,
idsContactTextOffice,
idsContactTextCompany,
idsContactTextBusinessAddress,
0,
0,
0,
0,
idsContactTextBusinessPhone,
idsContactTextBusinessFax,
idsContactTextBusinessPager,
idsContactTextBusinessWebPage,
idsContactTextNotes,
};
//
// The routine that generates data for tooltips, clipboard, and printing
// creates a localized version of the address for the contact. This
// localized formatmessage string may contain ugly blank spaces due to
// missing data hence we need to cleanup the address string
// This works for US build - hopefully the localizers wont break it
//
void CleanAddressString(TCHAR * szAddress)
{
LPTSTR lpTemp = szAddress;
LPTSTR lpTemp2 = NULL;
// we search for these 2 substrings
LPTSTR szText1 = TEXT(" \r\n");
LPTSTR szText2 = TEXT(" ");
ULONG nSpaceCount = 0;
//
// BUGBUG: This routine is not DBCS smart!
// It should use IsSpace and CharNext to parse these strings.
//
if(SubstringSearch(szAddress, szText2))
{
//First remove continuous blanks beyond 4
while(*lpTemp)
{
if(*lpTemp == ' ')
{
nSpaceCount++;
if(nSpaceCount == 5)
{
lpTemp2 = lpTemp+1;
StrCpyN(lpTemp, lpTemp2, lstrlen(lpTemp2)+1);
nSpaceCount = 0;
lpTemp = lpTemp - 4;
continue;
}
}
else
nSpaceCount = 0;
lpTemp++;
}
}
while(SubstringSearch(szAddress, szText1))
{
lpTemp = szAddress;
lpTemp2 = szText1;
while (*lpTemp && *lpTemp2)
{
if (*lpTemp != *lpTemp2)
{
lpTemp -= (lpTemp2 - szText1);
lpTemp2 = szText1;
}
else
{
lpTemp2++;
}
lpTemp++;
}
if(*lpTemp2 == '\0')
{
//match found
LPTSTR lpTemp3 = lpTemp;
lpTemp -= (lpTemp2-szText1);
StrCpyN(lpTemp, lpTemp3, lstrlen(lpTemp3)+1);
}
}
// also need to strip out the \r\n at the end of the address string
nSpaceCount = lstrlen(szAddress);
if(nSpaceCount >= 2)
szAddress[nSpaceCount-2] = '\0';
return;
}
//$$/////////////////////////////////////////////////////////////////////////////
//
// void HrGetLVItemDataString - Gets the item's data for the currently selected
// item in the list view and puts it in a string
//
// lpIAB - Pointer to AddrBook object
// hWndLV - Handle of list view
// nItem - item in list view whose properties we are retrieving
// lpszData - returned string containing item properties - a buffer is allocated
// to hold the data and the user needs to LocalFree the buffer
//
////////////////////////////////////////////////////////////////////////////////
HRESULT HrGetLVItemDataString(LPADRBOOK lpAdrBook, HWND hWndLV, int iItemIndex, LPTSTR * lppszData)
{
HRESULT hr = E_FAIL;
LPRECIPIENT_INFO lpItem = NULL;
LPSPropValue lpPropArray = NULL;
ULONG ulcProps = 0;
ULONG i =0,j=0;
ULONG ulBufSize = 0;
LPTSTR lpszData = NULL;
LPTSTR szParanStart = TEXT(" (");
LPTSTR szParanEnd = TEXT(")");
LPTSTR szLineBreakDL = TEXT("\r\n ");
LPTSTR lpszHomeAddress = NULL, lpszBusinessAddress = NULL;
LPTSTR lpszEmailAddresses = NULL;
LPTSTR * lpsz = NULL;
BOOL bBusinessTitle = FALSE, bPersonalTitle = FALSE;
ULONG * lpulPropTagArray = NULL;
ULONG cchSize;
// Some items will have both the PR_CONTACT_EMAIL_ADDRESSES and PR_EMAIL_ADDRESS
// while others will have only PR_EMAIL_ADDRESS
// In case of the former, we want to avoid duplication by ignoring email-address
// when contact-email-addresses exist. For this we use a flag.
BOOL bFoundContactAddresses = FALSE;
ULONG ulObjectType = 0;
SizedSPropTagArray(3, DLToolTipsProps)=
{
3,
{
PR_DISPLAY_NAME,
PR_WAB_DL_ENTRIES,
PR_WAB_DL_ONEOFFS,
}
};
*lppszData = NULL;
lpItem = GetItemFromLV(hWndLV, iItemIndex);
if(lpItem)
{
hr = HrGetPropArray(lpAdrBook, NULL,
lpItem->cbEntryID,
lpItem->lpEntryID,
MAPI_UNICODE,
&ulcProps, &lpPropArray);
if(HR_FAILED(hr))
goto out;
// is this a MailUser or a Distribution List
ulObjectType = lpItem->ulObjectType;
if(ulObjectType == MAPI_DISTLIST)
{
LPTSTR * lppszNameCache = NULL, * lppDLName = NULL, * lppDLOneOffName = NULL;
LPTSTR * lppszEmailCache = NULL, * lppDLEmail = NULL, * lppDLOneOffEmail = NULL;
ULONG ulNumNames = 0, ulNames = 0, ulOneOffNames = 0;
// First we count the data to get a buffer size for our buffer
for(j=0;j<DLToolTipsProps.cValues;j++)
{
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == DLToolTipsProps.aulPropTag[j])
{
if(lpPropArray[i].ulPropTag == PR_DISPLAY_NAME)
{
if(ulBufSize)
ulBufSize += sizeof(TCHAR)*(lstrlen(szCRLF));
// we may fdo some overcounting here but its harmless
ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ) + 1);
break;
}
else if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES || lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS)
{
ULONG k;
ulNumNames = lpPropArray[i].Value.MVbin.cValues;
lppszNameCache = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulNumNames);
if(!lppszNameCache)
break;
lppszEmailCache = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulNumNames);
if(!lppszEmailCache)
break;
// TBD - check this localalloc value
for (k = 0; k < ulNumNames; k++)
{
LPSPropValue lpProps = NULL;
ULONG ulcVal = 0;
ULONG n = 0;
lppszNameCache[k] = NULL;
lppszEmailCache[k] = NULL;
hr = HrGetPropArray(lpAdrBook, NULL,
lpPropArray[i].Value.MVbin.lpbin[k].cb,
(LPENTRYID)lpPropArray[i].Value.MVbin.lpbin[k].lpb,
MAPI_UNICODE,
&ulcVal,
&lpProps);
if(HR_FAILED(hr))
continue;
for(n=0;n<ulcVal;n++)
{
switch(lpProps[n].ulPropTag)
{
case PR_DISPLAY_NAME:
{
LPTSTR lpsz = lpProps[n].Value.LPSZ;
if(ulBufSize)
ulBufSize += sizeof(TCHAR)*(lstrlen(szLineBreakDL));
ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz)+1);
// cache away this name so we dont have to open the property store again
cchSize=lstrlen(lpsz)+1;
lppszNameCache[k] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
StrCpyN(lppszNameCache[k], lpsz, cchSize);
}
break;
case PR_EMAIL_ADDRESS:
{
LPTSTR lpsz = lpProps[n].Value.LPSZ;
if(ulBufSize)
{
ulBufSize += sizeof(TCHAR)*(lstrlen(szParanStart));
ulBufSize += sizeof(TCHAR)*(lstrlen(szParanEnd));
}
ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz)+1);
// cache away this name so we dont have to open the property store again
cchSize=lstrlen(lpsz)+1;
lppszEmailCache[k] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
StrCpyN(lppszEmailCache[k], lpsz, cchSize);
}
break;
}
}
if(lpProps)
MAPIFreeBuffer(lpProps);
lpProps = NULL;
}
if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES)
{
lppDLName = lppszNameCache;
lppDLEmail = lppszEmailCache;
ulNames = ulNumNames;
}
else
{
lppDLOneOffName = lppszNameCache;
lppDLOneOffEmail = lppszEmailCache;
ulOneOffNames = ulNumNames;
}
break;
} //if
}
} //for i
} // for j
lpszData = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
for(j=0;j<DLToolTipsProps.cValues;j++)
{
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == DLToolTipsProps.aulPropTag[j])
{
if(lpPropArray[i].ulPropTag == PR_DISPLAY_NAME)
{
if (lstrlen(lpszData))
StrCatBuff(lpszData,szCRLF,ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszData,lpPropArray[i].Value.LPSZ,ulBufSize/sizeof(TCHAR));
break;
}
else if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES ||
lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS)
{
ULONG k;
lppszNameCache = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? lppDLName : lppDLOneOffName;
lppszEmailCache = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? lppDLEmail : lppDLOneOffEmail;
ulNumNames = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? ulNames : ulOneOffNames;
for (k = 0; k < ulNumNames; k++)
{
if (lppszNameCache[k])
{
StrCatBuff(lpszData,szLineBreakDL,ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszData,lppszNameCache[k],ulBufSize/sizeof(TCHAR));
if(lppszEmailCache[k])
{
StrCatBuff(lpszData,szParanStart,ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszData,lppszEmailCache[k],ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszData,szParanEnd,ulBufSize/sizeof(TCHAR));
}
}
}
break;
}
}
} // for i
} // for j
// cleanup memory
if(ulNames)
{
for(i=0;i<ulNames;i++)
{
LocalFreeAndNull(&lppDLName[i]);
LocalFreeAndNull(&lppDLEmail[i]);
}
LocalFreeAndNull((LPVOID *)&lppDLName);
LocalFreeAndNull((LPVOID *)&lppDLEmail);
}
if(ulOneOffNames)
{
for(i=0;i<ulOneOffNames;i++)
{
LocalFreeAndNull(&lppDLOneOffName[i]);
LocalFreeAndNull(&lppDLOneOffEmail[i]);
}
LocalFreeAndNull((LPVOID *)&lppDLOneOffName);
LocalFreeAndNull((LPVOID *)&lppDLOneOffEmail);
}
lppszNameCache = NULL;
lppszEmailCache = NULL;
}
else
{
// Do MailUser Processing
lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ToolTipsProps.cValues);
if(!lpsz)
{
DebugPrintError(( TEXT("Local Alloc failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
lpulPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG) * ToolTipsProps.cValues);
if(!lpulPropTagArray)
{
DebugPrintError(( TEXT("Local Alloc failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
// if we dont have PR_CONTACT_EMAIL_ADDRESSES we want PR_EMAIL_ADDRESS
// and vice versa
for(j=0;j<ToolTipsProps.cValues;j++)
{
lpulPropTagArray[j] = ToolTipsProps.aulPropTag[j];
if(ToolTipsProps.aulPropTag[j] == PR_EMAIL_ADDRESS)
{
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
{
lpulPropTagArray[j] = PR_CONTACT_EMAIL_ADDRESSES;
break;
}
}
}
}
for(j=0;j<ToolTipsProps.cValues;j++)
{
lpsz[j]=NULL;
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == lpulPropTagArray[j])
{
if(PROP_TYPE(lpPropArray[i].ulPropTag) == PT_TSTRING)
{
if(lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS)
{
ulBufSize = sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ)+lstrlen(szLineBreakDL)+1);
lpszEmailAddresses = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
if(!lpszEmailAddresses)
{
DebugPrintError(( TEXT("Local Alloc Failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
StrCpyN(lpszEmailAddresses, szLineBreakDL,ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszEmailAddresses, lpPropArray[i].Value.LPSZ,ulBufSize/sizeof(TCHAR));
lpsz[j] = lpszEmailAddresses;
}
else
lpsz[j] = lpPropArray[i].Value.LPSZ;
}
else if(PROP_TYPE(lpPropArray[i].ulPropTag) == PT_MV_TSTRING)
{
ULONG k,ulBufSize=0;
for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
{
ulBufSize += sizeof(TCHAR)*(lstrlen(szLineBreakDL));
ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.MVSZ.LPPSZ[k])+1);
}
lpszEmailAddresses = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
if(!lpszEmailAddresses)
{
DebugPrintError(( TEXT("Local Alloc Failed\n")));
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
lpszEmailAddresses[0]=TEXT('\0');
for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
{
StrCatBuff(lpszEmailAddresses,szLineBreakDL,ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszEmailAddresses,lpPropArray[i].Value.MVSZ.LPPSZ[k],ulBufSize/sizeof(TCHAR));
}
lpsz[j]=lpszEmailAddresses;
break;
} //if
}//if
}//for i
}// for j
//
// Making this an elegant solution is really hard - just hack it for now
//
ulBufSize = 0;
// Set the display name to the displayed name (whether it is
// by first name or last name)
lpsz[txtDisplayName] = lpItem->szDisplayName;
// Set the localized versions of the addresses if any
for(i=txtHomeAddress;i<=txtHomeCountry;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
{
//Bug 1115995 - TEXT("(null)")s produced by Format message for null pointers
// in the va_list .. replace these with szEmpty
for(j=txtHomeAddress;j<=txtHomeCountry;j++)
if(!lpsz[j])
lpsz[j]=szEmpty;
}
LoadString(hinstMapiX, idsContactAddress, szBuf, ARRAYSIZE(szBuf));
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
szBuf,
0, // stringid
0, // dwLanguageId
(LPTSTR)&lpszHomeAddress, // output buffer
0, //MAX_UI_STR
(va_list *)&lpsz[txtHomeAddress]))
{
for(j=txtHomeAddress;j<=txtHomeCountry;j++)
lpsz[j]=NULL;
CleanAddressString(lpszHomeAddress);
lpsz[txtHomeAddress] = lpszHomeAddress;
break;
}
}
}
for(i=txtHomeAddress;i<=txtHomeWeb;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
bPersonalTitle = TRUE;
LoadString(hinstMapiX, idsContactTextPersonal, szBuf, ARRAYSIZE(szBuf));
ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
break;
}
}
for(i=txtBusinessAddress;i<=txtBusinessCountry;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
{
//Bug 1115995 - TEXT("(null)")s produced by Format message for null pointers
// in the va_list .. replace these with szEmpty
for(j=txtBusinessAddress;j<=txtBusinessCountry;j++)
if(!lpsz[j])
lpsz[j]=szEmpty;
}
LoadString(hinstMapiX, idsContactAddress, szBuf, ARRAYSIZE(szBuf));
if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
szBuf,
0, // stringid
0, // dwLanguageId
(LPTSTR)&lpszBusinessAddress, // output buffer
0, //MAX_UI_STR
(va_list *)&lpsz[txtBusinessAddress]))
{
for(j=txtBusinessAddress;j<=txtBusinessCountry;j++)
lpsz[j]=NULL;
CleanAddressString(lpszBusinessAddress);
lpsz[txtBusinessAddress] = lpszBusinessAddress;
break;
}
}
}
for(i=txtBusinessAddress;i<=txtBusinessWeb;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
bBusinessTitle = TRUE;
LoadString(hinstMapiX, idsContactTextBusiness, szBuf, ARRAYSIZE(szBuf));
ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
break;
}
}
for(i=0;i<ToolTipsProps.cValues;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
if(idsString[i] != 0)
{
LoadString(hinstMapiX, idsString[i], szBuf, ARRAYSIZE(szBuf));
ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
}
ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz[i])+lstrlen(szCRLF));
}
}
ulBufSize += sizeof(TCHAR); // space for trailing zero
lpszData = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
if(!lpszData)
{
DebugPrintError(( TEXT("Local Alloc failed\n")));
goto out;
}
*lpszData = TEXT('\0');
for(i=0;i<ToolTipsProps.cValues;i++)
{
if(lpsz[i])
{
TCHAR szBuf[MAX_UI_STR];
switch(i)
{
case txtHomeAddress:
case txtHomePhone:
case txtHomeFax:
case txtHomeCellular:
case txtHomeWeb:
if(bPersonalTitle)
{
bPersonalTitle = FALSE;
LoadString(hinstMapiX, idsContactTextPersonal, szBuf, ARRAYSIZE(szBuf));
StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
}
break;
case txtBusinessTitle:
case txtBusinessDept:
case txtBusinessOffice:
case txtBusinessCompany:
case txtBusinessAddress:
case txtBusinessPhone:
case txtBusinessFax:
case txtBusinessPager:
case txtBusinessWeb:
if(bBusinessTitle)
{
bBusinessTitle = FALSE;
LoadString(hinstMapiX, idsContactTextBusiness, szBuf, ARRAYSIZE(szBuf));
StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
}
break;
}
if(idsString[i] != 0)
{
LoadString(hinstMapiX, idsString[i], szBuf, ARRAYSIZE(szBuf));
StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
}
StrCatBuff(lpszData, lpsz[i], ulBufSize/sizeof(TCHAR));
StrCatBuff(lpszData, szCRLF, ulBufSize/sizeof(TCHAR));
}
}
//There is a spurious szCRLF at the end. Negate it
ulBufSize = lstrlen(lpszData);
lpszData[ulBufSize-2]='\0';
} // mailuser or dist list
}
*lppszData = lpszData;
hr = hrSuccess;
out:
if(lpPropArray)
MAPIFreeBuffer(lpPropArray);
if(lpszHomeAddress)
LocalFree(lpszHomeAddress);
if(lpszBusinessAddress)
LocalFree(lpszBusinessAddress);
if(lpszEmailAddresses)
LocalFree(lpszEmailAddresses);
if(lpsz)
LocalFree(lpsz);
if(lpulPropTagArray)
LocalFree(lpulPropTagArray);
if(HR_FAILED(hr))
{
LocalFreeAndNull(&lpszData);
LocalFreeAndNull(lppszData);
}
return hr;
}
//$$////////////////////////////////////////////////////////////////////////////////
//
// HrCopyItemDataToClipboard - Copies text from selected items in a List View
// into the clipboard
//
//////////////////////////////////////////////////////////////////////////////////////
HRESULT HrCopyItemDataToClipboard(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV)
{
HRESULT hr = E_FAIL;
int iItemIndex = 0, i = 0;
int iLastItemIndex = -1;
int nItemCount = ListView_GetSelectedCount(hWndLV);
LPTSTR lpszClipBoardData = NULL;
if( nItemCount <= 0)
goto out;
// TBD - messagebox here or item should be grayed
for(i=0;i<nItemCount;i++)
{
LPTSTR lpszData = NULL;
LPTSTR lpszData2 = NULL;
ULONG ulMemSize = 0;
iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
hr = HrGetLVItemDataString(
lpAdrBook,
hWndLV,
iItemIndex,
&lpszData);
if(HR_FAILED(hr))
{
goto out;
}
else
{
if(lpszData)
{
// Take the existing clipboard data and add
// a linebreak and the new data and another linebreak
if(lpszClipBoardData)
ulMemSize = sizeof(TCHAR)*(lstrlen(lpszClipBoardData)+lstrlen(szCRLF));
ulMemSize += sizeof(TCHAR)*(lstrlen(lpszData) + lstrlen(szCRLF) + 1);
lpszData2 = LocalAlloc(LMEM_ZEROINIT, ulMemSize);
if(!lpszData2)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
if(lpszClipBoardData)
{
StrCpyN(lpszData2, lpszClipBoardData, ulMemSize/sizeof(TCHAR));
StrCatBuff(lpszData2, szCRLF, ulMemSize/sizeof(TCHAR));
}
StrCatBuff(lpszData2, lpszData, ulMemSize/sizeof(TCHAR));
StrCatBuff(lpszData2, szCRLF, ulMemSize/sizeof(TCHAR));
LocalFreeAndNull(&lpszClipBoardData);
LocalFreeAndNull(&lpszData);
lpszClipBoardData = lpszData2;
}
}
iLastItemIndex = iItemIndex;
}
if(lpszClipBoardData)
{
LPSTR lpszA = ConvertWtoA(lpszClipBoardData);
OpenClipboard(hWnd);
EmptyClipboard();
// We now hand over ownership of the clipboard data to the clipboard
// which means that we dont have to free this pointer anymore
SetClipboardData(CF_TEXT, lpszA);
SetClipboardData(CF_UNICODETEXT, lpszClipBoardData);
LocalFreeAndNull(&lpszA);
CloseClipboard();
}
hr = hrSuccess;
out:
return hr;
}
//*******************************************************************
//
// FUNCTION: InitCommonControlLib
//
// PURPOSE: Load the CommCtrl client libray and get the proc addrs.
//
// PARAMETERS: None.
//
// RETURNS: TRUE if successful, FALSE otherwise.
//
//*******************************************************************
BOOL InitCommonControlLib(void)
{
// See if we already initialized.
if (NULL == ghCommCtrlDLLInst)
{
Assert(gulCommCtrlDLLRefCount == 0);
// open LDAP client library
ghCommCtrlDLLInst = LoadLibrary(cszCommCtrlClientDLL);
if (!ghCommCtrlDLLInst)
{
DebugTraceResult( TEXT("InitCommCtrlClientLib: Failed to LoadLibrary CommCtrl"),GetLastError());
return FALSE;
}
// cycle through the API table and get proc addresses for all the APIs we
// need
if (!GetApiProcAddresses(ghCommCtrlDLLInst,CommCtrlAPIList,NUM_CommCtrlAPI_PROCS))
{
DebugTrace( TEXT("InitCommCTrlLib: Failed to load LDAP API.\n"));
// Unload the library we just loaded.
if (ghCommCtrlDLLInst)
{
FreeLibrary(ghCommCtrlDLLInst);
ghCommCtrlDLLInst = NULL;
}
return FALSE;
}
// Initialize the CommonControl classes
{
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = //ICC_ALL_CLASSES;
ICC_LISTVIEW_CLASSES |
ICC_TREEVIEW_CLASSES |
ICC_BAR_CLASSES |
ICC_COOL_CLASSES |
ICC_ANIMATE_CLASS |
ICC_WIN95_CLASSES |
ICC_DATE_CLASSES;
iccex.dwICC |= ICC_NATIVEFNTCTL_CLASS;
if(!gpfnInitCommonControlsEx(&iccex))
{
//Couldnt initialize
DebugTrace( TEXT("InitCommCTrlLib: Failed to InitCommonControlsEx\n"));
// Unload the library we just loaded.
if (ghCommCtrlDLLInst)
{
FreeLibrary(ghCommCtrlDLLInst);
ghCommCtrlDLLInst = NULL;
}
return FALSE;
}
}
}
gulCommCtrlDLLRefCount++;
return TRUE;
}
//$$*****************************************************************
//
// FUNCTION: DeinitCommCtrlClientLib
//
// PURPOSE: decrement refcount on LDAP CLient library and
// release if 0.
//
// PARAMETERS: None.
//
// RETURNS: current refcount
//
//*******************************************************************
ULONG DeinitCommCtrlClientLib(void) {
if (-- gulCommCtrlDLLRefCount == 0) {
UINT nIndex;
// No clients using the CommCtrl library. Release it.
if (ghCommCtrlDLLInst) {
FreeLibrary(ghCommCtrlDLLInst);
ghCommCtrlDLLInst = NULL;
}
// cycle through the API table and NULL proc addresses for all the APIs
for (nIndex = 0; nIndex < NUM_CommCtrlAPI_PROCS; nIndex++) {
*CommCtrlAPIList[nIndex].ppFcnPtr = NULL;
}
}
return(gulCommCtrlDLLRefCount);
}
//$$*****************************************************************
//
// FUNCTION: HelpAboutDialogProc
//
// PURPOSE: minimal help/about dialog proc
//
//
//*******************************************************************
INT_PTR CALLBACK HelpAboutDialogProc( HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
{
// Easiest to keep this version info stuff in ANSI than to write wrappers for it ..
//
DWORD dwSize = 0, dwh = 0;
ULONG i = 0;
char szFile[MAX_PATH];
LPTSTR lpDataFile = NULL;
GetModuleFileNameA(hinstMapiXWAB, szFile, sizeof(szFile));
if(dwSize = GetFileVersionInfoSizeA(szFile, &dwh))
{
LPWORD lpwTrans = NULL;
LPVOID lpInfo = LocalAlloc(LMEM_ZEROINIT, dwSize+1);
if(lpInfo)
{
if(GetFileVersionInfoA( szFile, dwh, dwSize, lpInfo))
{
LPVOID lpVersion = NULL, lpszT = NULL;
DWORD uLen;
char szBuf[MAX_UI_STR];
if (VerQueryValueA(lpInfo, "\\VarFileInfo\\Translation", (LPVOID *)&lpwTrans, &uLen) &&
uLen >= (2 * sizeof(WORD)))
{
// set up buffer for calls to VerQueryValue()
CHAR *rgszVer[] = { "FileVersion", "LegalCopyright" };
int rgId[] = { IDC_ABOUT_LABEL_VERSION, IDC_ABOUT_COPYRIGHT };
DWORD cch;
wnsprintfA(szBuf, ARRAYSIZE(szBuf), "\\StringFileInfo\\%04X%04X\\", lpwTrans[0], lpwTrans[1]);
lpszT = szBuf + lstrlenA(szBuf);
cch = ARRAYSIZE(szBuf) - lstrlenA(szBuf);
// Walk through the dialog items that we want to replace:
for (i = 0; i <= 1; i++)
{
StrCpyNA(lpszT, rgszVer[i], cch);
if (VerQueryValueA(lpInfo, szBuf, (LPVOID *)&lpVersion, &uLen) && uLen)
{
LPTSTR lp = ConvertAtoW((LPSTR) lpVersion);
SetDlgItemText(hDlg, rgId[i], lp);
LocalFreeAndNull(&lp);
}
}
}
}
LocalFree(lpInfo);
}
}
else
DebugPrintTrace(( TEXT("GetFileVersionSize failed: %d\n"),GetLastError()));
{
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_lpIAB && !pt_bIsWABOpenExSession)
{
// hack
lpDataFile = GetWABFileName(((LPIAB)pt_lpIAB)->lpPropertyStore->hPropertyStore, FALSE);
}
if(lpDataFile && lstrlen(lpDataFile))
SetDlgItemText(hDlg, IDC_ABOUT_EDIT_FILENAME, lpDataFile);
else
{
ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_EDIT_FILENAME), SW_HIDE);
ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_STATIC_FILENAME), SW_HIDE);
}
}
}
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hDlg, 0);
break;
}
break;
default:
return FALSE;
break;
}
return TRUE;
}
//$$////////////////////////////////////////////////////////////////////
//
// nTruncatePos
//
// With DBCS strings we want to truncate the string at the beginning of
// a TCHAR and not in the middle of the double TCHAR.
// Hence we take a string, take in the maximum length we want, scan the
// string and return the length of the string at which we can safely
// truncate
//
// PARAMETERS:
// lpsz - input string
// nMaxLen - maximum allowed length of the string
//
////////////////////////////////////////////////////////////////////////
ULONG TruncatePos(LPTSTR lpsz, ULONG nMaxLen)
{
ULONG nLen = 0;
ULONG nDesiredLen = 0;
if(!lpsz || !lstrlen(lpsz) || !nMaxLen)
goto out;
nLen = lstrlen(lpsz);
if (nLen >= nMaxLen)
{
ULONG nCharsSteppedOverCount = 0;
ULONG nLastCharCount = 0;
ULONG nTotalLen = nLen; //lstrlen(lpsz);
nDesiredLen = nMaxLen;
while(*lpsz)
{
nLastCharCount = nCharsSteppedOverCount;
lpsz = CharNext(lpsz);
nCharsSteppedOverCount = nTotalLen - lstrlen(lpsz); // + 1;
if(nCharsSteppedOverCount > nDesiredLen)
break;
}
if (nCharsSteppedOverCount < nDesiredLen)
nLen = nCharsSteppedOverCount;
else
nLen = nLastCharCount;
}
out:
return nLen;
}
//$$////////////////////////////////////////////////////////////////////
//
// FreeRecipList - frees allocated memory in a RecipientInfo List
//
//
// PARAMETERS:
// lppList - list to free
//
////////////////////////////////////////////////////////////////////////
void FreeRecipList(LPRECIPIENT_INFO * lppList)
{
if(lppList)
{
LPRECIPIENT_INFO lpItem = NULL;
lpItem = *lppList;
while(lpItem)
{
*lppList = lpItem->lpNext;
FreeRecipItem(&lpItem);
lpItem = *lppList;
}
*lppList = NULL;
}
return;
}
//$$////////////////////////////////////////////////////////////////////
//
// HrCreateNewObject - Creates a new object in the wab
//
//
// PARAMETERS:
// lpIAB - lpAdrbook
// &lpMailUser - MailUser to return
//
////////////////////////////////////////////////////////////////////////
HRESULT HrCreateNewObject(LPADRBOOK lpAdrBook,
LPSBinary lpsbContainer,
ULONG ulObjectType,
ULONG ulCreateFlags,
LPMAPIPROP * lppPropObj)
{
HRESULT hResult = hrSuccess;
LPENTRYID lpWABEID = NULL;
ULONG cbWABEID = 0;
ULONG ulObjType = 0;
ULONG cProps = 0;
LPABCONT lpContainer = NULL;
LPSPropValue lpCreateEIDs = NULL;
LPMAPIPROP lpPropObj = NULL;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
LPIAB lpIAB = (LPIAB) lpAdrBook;
if(!lpsbContainer || !lpsbContainer->cb || !lpsbContainer->lpb)
{
SetVirtualPABEID(lpIAB, &cbWABEID, &lpWABEID);
if (hResult = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID))
goto exit;
}
else
{
cbWABEID = lpsbContainer->cb;
lpWABEID = (LPENTRYID) lpsbContainer->lpb;
}
if (hResult = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
cbWABEID, // size of EntryID to open
lpWABEID, // EntryID to open
NULL, // interface
0, // flags
&ulObjType,
(LPUNKNOWN *)&lpContainer)) {
goto exit;
}
// Get us the creation entryids
if (hResult = lpContainer->lpVtbl->GetProps(lpContainer,
(LPSPropTagArray)&ptaCreate,
MAPI_UNICODE,
&cProps,
&lpCreateEIDs)) {
DebugTrace( TEXT("Can't get container properties for PAB\n"));
// Bad stuff here!
goto exit;
}
if (hResult = lpContainer->lpVtbl->CreateEntry(lpContainer,
(ulObjectType == MAPI_MAILUSER ?
lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].Value.bin.cb : lpCreateEIDs[icrPR_DEF_CREATE_DL].Value.bin.cb),
(ulObjectType == MAPI_MAILUSER ?
(LPENTRYID)lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].Value.bin.lpb : (LPENTRYID)lpCreateEIDs[icrPR_DEF_CREATE_DL].Value.bin.lpb),
ulCreateFlags,
&lpPropObj)) {
DebugTraceResult( TEXT("CreateMailUser:CreateEntry"), hResult);
goto exit;
}
*lppPropObj = lpPropObj;
exit:
if(HR_FAILED(hResult) && lpPropObj)
lpPropObj->lpVtbl->Release(lpPropObj);
if(lpWABEID && (!lpsbContainer || lpsbContainer->lpb != (LPBYTE) lpWABEID))
FreeBufferAndNull(&lpWABEID);
UlRelease(lpContainer);
FreeBufferAndNull(&lpCreateEIDs);
return hResult;
}
const LPTSTR szDefMailKey = TEXT("Software\\Clients\\Mail");
const LPTSTR szOEDllPathKey = TEXT("DllPath");
const LPTSTR szOEName = TEXT("Outlook Express");
//$$///////////////////////////////////////////////////////////////////////
//
// CheckForOutlookExpress
//
// szDllPath - is a big enough buffer that will contain the path for
// the OE dll ..
//
//////////////////////////////////////////////////////////////////////////
BOOL CheckForOutlookExpress(LPTSTR szDllPath, DWORD cchDllPath)
{
HKEY hKeyMail = NULL;
HKEY hKeyOE = NULL;
DWORD dwErr = 0;
DWORD dwSize = 0;
TCHAR szBuf[MAX_PATH];
TCHAR szPathExpand[MAX_PATH];
DWORD dwType = 0;
BOOL bRet = FALSE;
szDllPath[0] = TEXT('\0');
szPathExpand[0] = TEXT('\0');
// Open the key for default internet mail client
// HKLM\Software\Clients\Mail
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szDefMailKey, 0, KEY_READ, &hKeyMail);
if(dwErr != ERROR_SUCCESS)
{
DebugTrace( TEXT("RegopenKey %s Failed -> %u\n"), szDefMailKey, dwErr);
goto out;
}
dwSize = ARRAYSIZE(szBuf); // Expect ERROR_MORE_DATA
dwErr = RegQueryValueEx( hKeyMail, NULL, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
if(dwErr != ERROR_SUCCESS)
{
goto out;
}
if(!lstrcmpi(szBuf, szOEName))
{
// Yes its outlook express ..
bRet = TRUE;
}
//Get the DLL Path anyway whether this is the default key or not
// Get the DLL Path
dwErr = RegOpenKeyEx(hKeyMail, szOEName, 0, KEY_READ, &hKeyOE);
if(dwErr != ERROR_SUCCESS)
{
DebugTrace( TEXT("RegopenKey %s Failed -> %u\n"), szDefMailKey, dwErr);
goto out;
}
dwSize = ARRAYSIZE(szBuf);
szBuf[0]=TEXT('\0');
dwErr = RegQueryValueEx(hKeyOE, szOEDllPathKey, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
if (REG_EXPAND_SZ == dwType)
{
ExpandEnvironmentStrings(szBuf, szPathExpand, ARRAYSIZE(szPathExpand));
StrCpyN(szBuf, szPathExpand,ARRAYSIZE(szBuf));
}
if(dwErr != ERROR_SUCCESS)
{
goto out;
}
if(lstrlen(szBuf))
StrCpyN(szDllPath, szBuf, cchDllPath);
out:
if(hKeyOE)
RegCloseKey(hKeyOE);
if(hKeyMail)
RegCloseKey(hKeyMail);
return bRet;
}
static const SizedSPropTagArray(1, ptaMailToExItemType)=
{
1,
{
PR_OBJECT_TYPE,
}
};
// We will create a linked list of all selected entries that have an
// email address and then use that to create the recip list for sendmail
typedef struct _RecipList
{
LPTSTR lpszName;
LPTSTR lpszEmail;
LPSBinary lpSB;
struct _RecipList * lpNext;
} RECIPLIST, * LPRECIPLIST;
//$$/////////////////////////////////////////////////////////////////////
//
// FreeLPRecipList
//
// Frees a linked list containing the above structures
//
/////////////////////////////////////////////////////////////////////////
void FreeLPRecipList(LPRECIPLIST lpList)
{
if(lpList)
{
LPRECIPLIST lpTemp = lpList;
while(lpTemp)
{
lpList = lpTemp->lpNext;
if(lpTemp->lpszName)
LocalFree(lpTemp->lpszName);
if(lpTemp->lpszEmail)
LocalFree(lpTemp->lpszEmail);
if(lpTemp->lpSB)
MAPIFreeBuffer(lpTemp->lpSB);
LocalFree(lpTemp);
lpTemp = lpList;
}
}
}
//$$/////////////////////////////////////////////////////////////////////
//
// GetItemNameEmail
//
// Gets the name and email address of the specified item
// and appends it to the provided linked list ..
//
/////////////////////////////////////////////////////////////////////////
HRESULT HrGetItemNameEmail( LPADRBOOK lpAdrBook,
BOOL bIsOE,
ULONG cbEntryID,
LPENTRYID lpEntryID,
int nExtEmail,
LPRECIPLIST * lppList)
{
HRESULT hr = E_FAIL;
ULONG cValues;
LPRECIPLIST lpTemp = NULL;
LPSPropValue lpspv = NULL;
LPRECIPLIST lpList = *lppList;
LPTSTR lpEmail = NULL, lpAddrType = NULL, lpName = NULL;
SizedSPropTagArray(5, ptaMailToEx)=
{
5, {
PR_DISPLAY_NAME,
PR_EMAIL_ADDRESS,
PR_ADDRTYPE,
PR_CONTACT_EMAIL_ADDRESSES,
PR_CONTACT_ADDRTYPES
}
};
// Open the entry and read the email address.
// NOTE: We can't just take the address out of the listbox
// because it may be truncated!
if (HR_FAILED(hr = HrGetPropArray( lpAdrBook,
(LPSPropTagArray)&ptaMailToEx,
cbEntryID,
lpEntryID,
MAPI_UNICODE,
&cValues,
&lpspv)))
{
goto out;
}
lpName = (lpspv[0].ulPropTag == PR_DISPLAY_NAME) ? lpspv[0].Value.LPSZ : szEmpty;
if( nExtEmail &&
lpspv[3].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES &&
lpspv[4].ulPropTag == PR_CONTACT_ADDRTYPES &&
lpspv[3].Value.MVSZ.cValues >= (ULONG)nExtEmail)
{
lpEmail = lpspv[3].Value.MVSZ.LPPSZ[nExtEmail-1];
lpAddrType = lpspv[4].Value.MVSZ.LPPSZ[nExtEmail-1];
}
if(!lpEmail)
lpEmail = (lpspv[1].ulPropTag == PR_EMAIL_ADDRESS) ? lpspv[1].Value.LPSZ : szEmpty;
if(!lpAddrType)
lpAddrType = (lpspv[2].ulPropTag == PR_ADDRTYPE) ? lpspv[2].Value.LPSZ : szEmpty;
if(lstrlen(lpEmail) && lstrlen(lpName)) //only if this item has a email address do we include it
{
lpTemp = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPLIST));
if(lpTemp)
{
DWORD cchEmail;
DWORD cchName=lstrlen(lpName) + 1;
lpTemp->lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchName);
if (lpTemp->lpszName)
{
StrCpyN(lpTemp->lpszName, lpName, cchName);
}
cchEmail=(lstrlen(lpEmail) + lstrlen(lpAddrType) + 2);
lpTemp->lpszEmail = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchEmail);
if (lpTemp->lpszEmail)
{
if(bIsOE)
{
lpTemp->lpszEmail[0]=TEXT('\0');
}
else
{
StrCpyN(lpTemp->lpszEmail, lpAddrType, cchEmail);
StrCatBuff(lpTemp->lpszEmail, szColon, cchEmail);
}
StrCatBuff(lpTemp->lpszEmail, lpEmail, cchEmail);
}
MAPIAllocateBuffer(sizeof(SBinary), (LPVOID) &(lpTemp->lpSB));
// Create a one off entry id for this buffer
CreateWABEntryID(WAB_ONEOFF,
lpTemp->lpszName,
lpAddrType,
lpEmail,
0, 0,
(LPVOID) lpTemp->lpSB,
(LPULONG) (&(lpTemp->lpSB->cb)),
(LPENTRYID *) &(lpTemp->lpSB->lpb));
lpTemp->lpNext = lpList;
lpList = lpTemp;
}
}
FreeBufferAndNull(&lpspv);
*lppList = lpList;
hr = S_OK;
out:
return hr;
}
//$$//////////////////////////////////////////////////////////////////
//
// Function that opens an item and adds it to the recip list
// If the opened item is a group, calls itself recursively for all
// subgroups ..
//
// lpnRecipCount - returns the number of items in lppList
// lppList - dynamically allocated - must be freed by caller
// bIsOE - tells us to follow a slightly different code-path to handle OE
// inconsistencies - ** warning ** - this will break when they
// fix their inconsistencies
// nExtEmail - this is non-zero when there is a single selection and the
// user chose a non-default email address which should be used for
// sending mail
//
//////////////////////////////////////////////////////////////////////
HRESULT GetRecipListFromSelection(LPADRBOOK lpAdrBook,
BOOL bIsOE,
ULONG cbEntryID,
LPENTRYID lpEntryID,
int nExtEmail,
ULONG * lpnRecipCount,
ULONG * lpnNoEmailCount,
LPRECIPLIST * lppList)
{
ULONG ulObjectType = 0;
HRESULT hr = E_FAIL;
{
ULONG cValues = 0;
LPSPropValue lpspv = NULL;
// First check if this item is a mailuser or a group
if (HR_FAILED(hr = HrGetPropArray( lpAdrBook,
(LPSPropTagArray)&ptaMailToExItemType,
cbEntryID,
lpEntryID,
MAPI_UNICODE,
&cValues,
&lpspv)))
{
return hr;
}
ulObjectType = lpspv[0].Value.l;
FreeBufferAndNull(&lpspv);
}
if(ulObjectType == MAPI_MAILUSER)
{
LPRECIPLIST lpTemp = *lppList;
if (!HR_FAILED(hr = HrGetItemNameEmail(lpAdrBook, bIsOE, cbEntryID,lpEntryID, nExtEmail, lppList)))
{
if(lpTemp != *lppList) // means an item was added to the list ..
(*lpnRecipCount)++;
else
(*lpnNoEmailCount)++;
}
}
else if(ulObjectType == MAPI_DISTLIST)
{
ULONG cValues = 0;
LPSPropValue lpspv = NULL;
SizedSPropTagArray(2, tagaDLEntriesOneOffs) =
{
2,
{
PR_WAB_DL_ENTRIES,
PR_WAB_DL_ONEOFFS,
}
};
if (HR_FAILED(hr = HrGetPropArray( lpAdrBook, (LPSPropTagArray)&tagaDLEntriesOneOffs,
cbEntryID, lpEntryID,
MAPI_UNICODE,
&cValues, &lpspv)))
{
return hr;
}
{
ULONG i,j;
for(i=0;i<2;i++)
{
if(lpspv[i].ulPropTag == PR_WAB_DL_ENTRIES || lpspv[i].ulPropTag == PR_WAB_DL_ONEOFFS)
{
// Look at each entry in the PR_WAB_DL_ENTRIES and PR_WAB_DL_ONEOFFS
for (j = 0; j < lpspv[i].Value.MVbin.cValues; j++)
{
ULONG cbEID = lpspv[i].Value.MVbin.lpbin[j].cb;
LPENTRYID lpEID = (LPENTRYID)lpspv[i].Value.MVbin.lpbin[j].lpb;
GetRecipListFromSelection(lpAdrBook, bIsOE, cbEID, lpEID, 0, lpnRecipCount, lpnNoEmailCount, lppList);
}
}
}
}
FreeBufferAndNull(&lpspv);
}
return hr;
}
//$$//////////////////////////////////////////////////////////////////////
//
// HrSendMail - does the actual mail sending
// Our first priority is to Outlook Express which currently has a
// different code path than the regular MAPI client .. so we look
// under HKLM\Software\Clients\Mail .. if the client is OE then
// we just loadlibrary and getprocaddress for sendmail
// If its not OE, then we call the mapi32.dll and load it ..
// If both fail we will not be able to send mail ...
//
// This function will free the lpList no matter what happens
// so caller should not expect to reuse it (This is so we can
// give the pointer to a seperate thread and not worry about it)
//
//////////////////////////////////////////////////////////////////////////
HRESULT HrSendMail(HWND hWndParent, ULONG nRecipCount, LPRECIPLIST lpList, LPIAB lpIAB, BOOL bUseOEForSendMail)
{
HRESULT hr = E_FAIL;
HINSTANCE hLibMapi = NULL;
BOOL bIsOE = FALSE; // right now there is a different code path
// for OE vs other MAPI clients
TCHAR szBuf[MAX_PATH];
LPMAPISENDMAIL lpfnMAPISendMail = NULL;
LHANDLE hMapiSession = 0;
LPMAPILOGON lpfnMAPILogon = NULL;
LPMAPILOGOFF lpfnMAPILogoff = NULL;
LPBYTE lpbName, lpbAddrType, lpbEmail;
ULONG ulMapiDataType;
ULONG cbEntryID = 0;
LPENTRYID lpEntryID = NULL;
MapiMessage Msg = {0};
MapiRecipDesc * lprecips = NULL;
if(!nRecipCount)
{
hr = MAPI_W_ERRORS_RETURNED;
goto out;
}
// Check if OutlookExpress is the default current client ..
bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
// Turn off all notifications for simple MAPI send mail, if the default
// email client is Outlook. This is necessary because Outlook changes the
// WAB MAPI allocation functions during simple MAPI and we don't want any
// internal WAB functions using these allocators.
if (!bIsOE && !bUseOEForSendMail)
vTurnOffAllNotifications();
// if OE is the default client or OE launched this WAB, use OE for SendMail
if(lstrlen(szBuf) && (bIsOE||bUseOEForSendMail))
{
hLibMapi = LoadLibrary(szBuf);
}
else
{
// Check if simple mapi is installed
if(GetProfileInt( TEXT("mail"), TEXT("mapi"), 0) == 1)
hLibMapi = LoadLibrary( TEXT("mapi32.dll"));
if(!hLibMapi) // try loading the OE MAPI dll directly
{
// Load the path to the msimnui.dll
CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
if(lstrlen(szBuf)) // Load the dll directly - dont bother going through msoemapi.dll
hLibMapi = LoadLibrary(szBuf);
}
}
if(!hLibMapi)
{
DebugPrintError(( TEXT("Could not load/find simple mapi\n")));
hr = MAPI_E_NOT_FOUND;
goto out;
}
else if(hLibMapi)
{
lpfnMAPILogon = (LPMAPILOGON) GetProcAddress (hLibMapi, "MAPILogon");
lpfnMAPILogoff= (LPMAPILOGOFF)GetProcAddress (hLibMapi, "MAPILogoff");
lpfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress (hLibMapi, "MAPISendMail");
if(!lpfnMAPISendMail || !lpfnMAPILogon || !lpfnMAPILogoff)
{
DebugPrintError(( TEXT("MAPI proc not found\n")));
hr = MAPI_E_NOT_FOUND;
goto out;
}
hr = lpfnMAPILogon( (ULONG_PTR)hWndParent, NULL,
NULL, // No password needed.
0L, // Use shared session.
0L, // Reserved; must be 0.
&hMapiSession); // Session handle.
if(hr != SUCCESS_SUCCESS)
{
DebugTrace( TEXT("MAPILogon failed\n"));
// its possible the logon failed since there was no shared logon session
// Try again to create a new session with UI
hr = lpfnMAPILogon( (ULONG_PTR)hWndParent, NULL,
NULL, // No password needed.
MAPI_LOGON_UI | MAPI_NEW_SESSION, // Use shared session.
0L, // Reserved; must be 0.
&hMapiSession); // Session handle.
if(hr != SUCCESS_SUCCESS)
{
DebugTrace( TEXT("MAPILogon failed\n"));
goto out;
}
}
}
// Load the MAPI functions here ...
//
lprecips = LocalAlloc(LMEM_ZEROINIT, sizeof(MapiRecipDesc) * nRecipCount);
{
LPRECIPLIST lpTemp = lpList;
ULONG count = 0;
while(lpTemp)
{
lprecips[count].ulRecipClass = MAPI_TO;
lprecips[count].lpszName = ConvertWtoA(lpTemp->lpszName);
lprecips[count].lpszAddress = ConvertWtoA(lpTemp->lpszEmail);
// [PaulHi] 4/20/99 Raid 73455
// Convert Unicode EID OneOff strings to ANSI
if ( IsWABEntryID(lpTemp->lpSB->cb, (LPVOID)lpTemp->lpSB->lpb,
&lpbName, &lpbAddrType, &lpbEmail, (LPVOID *)&ulMapiDataType, NULL) == WAB_ONEOFF )
{
#ifndef _WIN64 // As I founf from RAID this part only for Outlook
if (ulMapiDataType & MAPI_UNICODE)
{
hr = CreateWABEntryIDEx(
FALSE, // Don't want Unicode EID strings
WAB_ONEOFF, // EID type
(LPWSTR)lpbName,
(LPWSTR)lpbAddrType,
(LPWSTR)lpbEmail,
0,
0,
NULL,
&cbEntryID,
&lpEntryID);
if (FAILED(hr))
goto out;
lprecips[count].ulEIDSize = cbEntryID;
lprecips[count].lpEntryID = lpEntryID;
}
else
#endif // _WIN64
{
lprecips[count].ulEIDSize = lpTemp->lpSB->cb;
lprecips[count].lpEntryID = (LPVOID)lpTemp->lpSB->lpb;
}
}
lpTemp = lpTemp->lpNext;
count++;
}
}
Msg.nRecipCount = nRecipCount;
Msg.lpRecips = lprecips;
hr = lpfnMAPISendMail (hMapiSession, (ULONG_PTR)hWndParent,
&Msg, // the message being sent
MAPI_DIALOG, // allow the user to edit the message
0L); // reserved; must be 0
if(hr != SUCCESS_SUCCESS)
goto out;
hr = S_OK;
out:
// This must be freed within the Outlook simple MAPI session, since it was
// allocated within this session (i.e., with Outlook allocators).
if (lpEntryID)
MAPIFreeBuffer(lpEntryID);
// The simple MAPI session should end after this
if(hMapiSession && lpfnMAPILogoff)
lpfnMAPILogoff(hMapiSession,0L,0L,0L);
if(hLibMapi)
FreeLibrary(hLibMapi);
// Turn all notifications back on and refresh the WAB UI (just in case)
if (!bIsOE && !bUseOEForSendMail)
{
vTurnOnAllNotifications();
if (lpIAB->hWndBrowse)
PostMessage(lpIAB->hWndBrowse, WM_COMMAND, (WPARAM) IDM_VIEW_REFRESH, 0);
}
if(lprecips)
{
ULONG i = 0;
for(i=0;i<nRecipCount;i++)
{
LocalFreeAndNull(&lprecips[i].lpszName);
LocalFreeAndNull(&lprecips[i].lpszAddress);
}
LocalFree(lprecips);
}
// The one-off here was allocated before the simple MAPI session and so used
// the default WAB allocators.
if(lpList)
FreeLPRecipList(lpList);
switch(hr)
{
case S_OK:
case MAPI_E_USER_CANCEL:
case MAPI_E_USER_ABORT:
break;
case MAPI_W_ERRORS_RETURNED:
ShowMessageBox(hWndParent, idsSendMailToNoEmail, MB_ICONEXCLAMATION | MB_OK);
break;
case MAPI_E_NOT_FOUND:
ShowMessageBox(hWndParent, idsSendMailNoMapi, MB_ICONEXCLAMATION | MB_OK);
break;
default:
ShowMessageBox(hWndParent, idsSendMailError, MB_ICONEXCLAMATION | MB_OK);
break;
}
return hr;
}
typedef struct _MailParams
{
HWND hWnd;
ULONG nRecipCount;
LPRECIPLIST lpList;
LPIAB lpIAB;
BOOL bUseOEForSendMail; // True means check and use OE before checking for Simple MAPI client
} MAIL_PARAMS, * LPMAIL_PARAMS;
//$$//////////////////////////////////////////////////////////////////////
//
// MailThreadProc - does the actual sendmail and cleans up
//
//////////////////////////////////////////////////////////////////////////
DWORD WINAPI MailThreadProc( LPVOID lpParam )
{
LPMAIL_PARAMS lpMP = (LPMAIL_PARAMS) lpParam;
LPPTGDATA lpPTGData = GetThreadStoragePointer(); // Bug - if this new thread accesses the WAB we lose a hunka memory
// So add this thing here ourselves and free it when this thread's work is done
if(!lpMP)
return 0;
DebugTrace( TEXT("Mail Thread ID = 0x%.8x\n"),GetCurrentThreadId());
HrSendMail(lpMP->hWnd, lpMP->nRecipCount, lpMP->lpList, lpMP->lpIAB, lpMP->bUseOEForSendMail);
LocalFree(lpMP);
return 0;
}
//$$//////////////////////////////////////////////////////////////////////
//
// HrStartMailThread
//
// Starts a seperate thread to send mapi based mail from
//
//////////////////////////////////////////////////////////////////////////
HRESULT HrStartMailThread(HWND hWndParent, ULONG nRecipCount, LPRECIPLIST lpList, LPIAB lpIAB, BOOL bUseOEForSendMail)
{
LPMAIL_PARAMS lpMP = NULL;
HRESULT hr = E_FAIL;
lpMP = LocalAlloc(LMEM_ZEROINIT, sizeof(MAIL_PARAMS));
if(!lpMP)
goto out;
{
HANDLE hThread = NULL;
DWORD dwThreadID = 0;
lpMP->hWnd = hWndParent;
lpMP->nRecipCount = nRecipCount;
lpMP->lpList = lpList;
lpMP->bUseOEForSendMail = bUseOEForSendMail;
lpMP->lpIAB = lpIAB;
hThread = CreateThread(
NULL, // no security attributes
0, // use default stack size
MailThreadProc, // thread function
(LPVOID) lpMP, // argument to thread function
0, // use default creation flags
&dwThreadID); // returns the thread identifier
if(hThread == NULL)
goto out;
hr = S_OK;
CloseHandle(hThread);
}
out:
if(HR_FAILED(hr))
{
ShowMessageBox(hWndParent, idsSendMailError, MB_OK | MB_ICONEXCLAMATION);
// we can assume that HrSendMail never got called so we should free lpList & lpMP
if(lpMP)
LocalFree(lpMP);
if(lpList)
FreeLPRecipList(lpList);
}
return hr;
}
//$$//////////////////////////////////////////////////////////////////////
//
// HrSendMailToSelectedContacts
//
// Uses simple MAPI to send mail to the selected contacts
//
// hWndLV - handle of List view. We look up the all the selected items in
// this list view, get their lParam structure, then get its
// EntryID and get the email address .. in the case of a group
// we get all the email addresses of all the members
// All these are put into a recip list and given to
// MAPISendMail ...
//
// lpIAB - handle to current AdrBook object - used for calling details
// nExtEmail - if this is a non-zero positive number, then it is the index of an
// e-mail address in the PR_CONTACT_EMAIL_ADDRESSES property and means that
// the user specified a non-default e-mail address to send mail to in which case
// that particular email address should be used for sending mail. nExtEmail will be
// non-zero only if one item is selected and a specific email is chosen for that item.
//
// Returns:S_OK
// E_FAIL
//
//////////////////////////////////////////////////////////////////////////
HRESULT HrSendMailToSelectedContacts(HWND hWndLV, LPADRBOOK lpAdrBook, int nExtEmail)
{
HRESULT hr = E_FAIL;
int nSelected = ListView_GetSelectedCount(hWndLV);
int iItemIndex = 0;
HWND hWndParent = GetParent(hWndLV);
TCHAR szBuf[MAX_PATH];
LPIAB lpIAB = (LPIAB) lpAdrBook;
LPRECIPLIST lpList = NULL;
ULONG nRecipCount = 0, nNoEmailCount = 0;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Check if OutlookExpress is the current client ..need to know this to workaround a bug
// in what they expect right now as recipients
BOOL bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
// Create a recipients list to put in the new message ...
if(nSelected > 0)
{
// Get index of selected item
iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
while (iItemIndex != -1)
{
LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
// Get item lParam LPRECIPIENT_INFO structure
if (lpItem)
{
GetRecipListFromSelection(lpAdrBook, bIsOE,
lpItem->cbEntryID,
lpItem->lpEntryID,
nExtEmail,
&nRecipCount, &nNoEmailCount,
&lpList);
}
iItemIndex = ListView_GetNextItem(hWndLV,iItemIndex,LVNI_SELECTED);
}
if(nRecipCount > 0 && nNoEmailCount > 0)
{
if(IDNO == ShowMessageBox(hWndParent, idsSomeHaveNoEmail, MB_ICONEXCLAMATION | MB_YESNO))
{
hr = MAPI_E_USER_CANCEL;
goto out;
}
}
}
else
{
// nothing selected
ShowMessageBox(hWndParent, IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
goto out;
}
hr = HrStartMailThread( hWndParent, nRecipCount,
lpList, // HrSendMail frees lpList so dont reuse
lpIAB,
lpIAB->bUseOEForSendMail);
out:
SetCursor(hOldCur);
return hr;
}
/*
const LPTSTR szClients = TEXT( TEXT("Software\\Clients\\%s"));
//
// FUNCTION: ShellUtil_RunIndirectRegCommand()
//
// PURPOSE: find the default value under HKLM\Software\Clients\pszClient
// tack on shell\open\command
// then runreg that
//
void ShellUtil_RunClientRegCommand(HWND hwnd, LPCTSTR pszClient)
{
TCHAR szDefApp[MAX_PATH];
TCHAR szKey[MAX_PATH];
LONG cbSize = ARRAYSIZE(szDefApp);
wnsprintf(szKey, ARRAYSIZE(szKey), szClients, pszClient);
if (RegQueryValue(HKEY_LOCAL_MACHINE, szKey, szDefApp, &cbSize) == ERROR_SUCCESS)
{
TCHAR szFullKey[MAX_PATH];
// tack on shell\open\command
wnsprintf(szFullKey, ARRAYSIZE(szFullKey), TEXT("%s\\%s\\shell\\open\\command"), szKey, szDefApp);
cbSize = ARRAYSIZE(szDefApp);
if (RegQueryValue(HKEY_LOCAL_MACHINE, szFullKey, szDefApp, &cbSize) == ERROR_SUCCESS)
{
LPSTR pszArgs = NULL;
SHELLEXECUTEINFO ExecInfo;
LPTSTR lp = szDefApp;
// if we have long file names in this string, we need to skip past the qoutes
if(lp)
{
if(*lp == '"')
{
lp = CharNext(lp);
while(lp && *lp && *lp!='"')
lp = CharNext(lp);
}
// Now find the next blank space because this is where the parameters start ..
while(lp && *lp && *lp!=' ') // No DBCS spaces here
lp = CharNext(lp);
if(*lp == ' ')
{
pszArgs = CharNext(lp);
*lp = '\0';
TrimSpaces(pszArgs);
}
//Now remove the quotes from lp
lp = szDefApp;
while(lp && *lp)
{
if(*lp == '"')
*lp = ' ';
lp = CharNext(lp);
}
TrimSpaces(szDefApp);
}
ExecInfo.hwnd = hwnd;
ExecInfo.lpVerb = NULL;
ExecInfo.lpFile = szDefApp;
ExecInfo.lpParameters = pszArgs;
ExecInfo.lpDirectory = NULL;
ExecInfo.nShow = SW_SHOWNORMAL;
ExecInfo.fMask = 0;
ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShellExecuteEx(&ExecInfo);
}
}
}
*/
/*
//$$//////////////////////////////////////////////////////////////////////
//
// HrSendMailToSingleContact
//
// Uses simple MAPI to send mail to the specified contact
//
// Returns:S_OK
// E_FAIL
//
//////////////////////////////////////////////////////////////////////////
HRESULT HrSendMailToSingleContact(HWND hWnd, LPIAB lpIAB, ULONG cbEntryID, LPENTRYID lpEntryID)
{
HRESULT hr = E_FAIL;
TCHAR szBuf[MAX_PATH];
LPRECIPLIST lpList = NULL;
ULONG nRecipCount = 0;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Check if OutlookExpress is the current client ..need to know this to workaround a bug
// in what they expect right now as recipients
BOOL bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
// Create a recipients list to put in the new message ...
GetRecipListFromSelection((LPADRBOOK) lpIAB,
bIsOE,
cbEntryID,
lpEntryID,
0,
&nRecipCount,
&lpList);
//hr = HrSendMail(hWnd, nRecipCount, lpList); // HrSendMail frees the lpList so dont reuse ..
hr = HrStartMailThread(hWnd, nRecipCount, lpList); // HrSendMail frees lpList so dont reuse
SetCursor(hOldCur);
return hr;
}
*/
//$$///////////////////////////////////////////////////////////////////
//
// Removes all characters from input string that are not allowed by the
// file system
//
///////////////////////////////////////////////////////////////////////
void TrimIllegalFileChars(LPTSTR sz)
{
LPTSTR lpCurrent = sz;
if(!lpCurrent)
return;
// Escape illegal chars in the file name
while (*lpCurrent)
{
switch (*lpCurrent)
{
case '\\':
case '/':
case '<':
case '>':
case ':':
case '"':
case '|':
case '?':
case '*':
//case '.':
*lpCurrent = '_'; // replace with underscore
break;
default:
break;
}
lpCurrent = CharNext(lpCurrent);
}
return;
}
/***************************************************************************
Name : IsSpace
Purpose : Does the single or DBCS character represent a space?
Parameters: lpChar -> SBCS or DBCS character
Returns : TRUE if this character is a space
Comment :
***************************************************************************/
BOOL __fastcall IsSpace(LPTSTR lpChar) {
Assert(lpChar);
if (*lpChar)
{
/*
* [PaulHi] 3/31/99 Raid 73845. DBCS is not valid for UNICODE app.
if (IsDBCSLeadByte((BYTE)*lpChar))
{
WORD CharType[2] = {0};
GetStringTypeW(CT_CTYPE1,lpChar,2,// Double-Byte
CharType);
return(CharType[0] & C1_SPACE);
}
*/
return(*lpChar == ' ');
}
return(FALSE); // end of string
}
/***************************************************************************
Name : SetRegistryUseOutlook
Purpose : Sets the registry flag that makes us use Outlook
Parameters: bUseOutlook or not
Returns : TRUE if it was correctly changed
Comment :
***************************************************************************/
BOOL SetRegistryUseOutlook(BOOL bUseOutlook)
{
HKEY hKey = NULL;
DWORD dwUseOutlook = (DWORD) bUseOutlook;
BOOL bRet = FALSE;
// We'll probably never have to create the key since Outlook will do that at setup
//
if(ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER,
lpNewWABRegKey,
0, NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL, &hKey, NULL))
{
if(ERROR_SUCCESS == RegSetValueEx( hKey,
lpRegUseOutlookVal,
0, REG_DWORD,
(LPBYTE) &dwUseOutlook,
sizeof(DWORD) ))
{
bRet = TRUE;
}
}
if(hKey)
RegCloseKey(hKey);
return bRet;
}
const LPTSTR lpRegOffice = TEXT("Software\\Microsoft\\Office\\8.0");
const LPTSTR lpRegOffice9 = TEXT("Software\\Microsoft\\Office\\9.0");
const LPTSTR lpRegOutlWAB = TEXT("Software\\Microsoft\\WAB\\OutlWABDLLPath");
const LPTSTR lpRegOfficeBin = TEXT("BinDirPath");
const LPTSTR lpOUTLWAB_DLL_NAME = TEXT("Outlwab.dll");
BOOL bFindOutlWABDll(LPTSTR sz, DWORD cchSz, LPTSTR szDLLPath, DWORD cchDLLPath, BOOL bAppendName)
{
BOOL bRet = FALSE;
if(bAppendName)
{
if(*(sz+lstrlen(sz)-1) != '\\')
StrCatBuff(sz, szBackSlash, cchSz);
StrCatBuff(sz, lpOUTLWAB_DLL_NAME, cchSz);
}
if(GetFileAttributes(sz) != 0xFFFFFFFF)
{
if(szDLLPath)
StrCpyN(szDLLPath, sz, cchDLLPath);
bRet = TRUE;
}
return bRet;
}
//$$/////////////////////////////////////////////////////////////////////////////
//
// bCheckForOutlookWABDll
//
// Search for the Outlook WAB DLL .. if found, we
// can use that as na indicator that outlook is installed
//
// szDLLPath should be a big enough buffer
//
//////////////////////////////////////////////////////////////////////////////////
BOOL bCheckForOutlookWABDll(LPTSTR szDLLPath, DWORD cchDLLPath)
{
// Check in the Office Bin directory
TCHAR sz[MAX_PATH];
BOOL bRet = FALSE;
DWORD dwType = REG_SZ;
DWORD dwSize = ARRAYSIZE(sz);
HKEY hKey = NULL;
*sz = '\0';
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOutlWAB, 0, KEY_READ, &hKey))
{
if(ERROR_SUCCESS == RegQueryValueEx(hKey, szEmpty, NULL, &dwType, (LPBYTE) sz, &dwSize))
{
if(lstrlen(sz))
bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, FALSE);
}
RegCloseKey(hKey);
}
if (!bRet)
{
*sz = '\0';
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOffice9, 0, KEY_READ, &hKey))
{
if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpRegOfficeBin, NULL, &dwType, (LPBYTE) sz, &dwSize))
{
if(lstrlen(sz))
bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
}
}
RegCloseKey(hKey);
}
if(!bRet)
{
*sz = '\0';
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOffice, 0, KEY_READ, &hKey))
{
if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpRegOfficeBin, NULL, &dwType, (LPBYTE) sz, &dwSize))
{
if(lstrlen(sz))
bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
}
}
RegCloseKey(hKey);
}
// Check in the Windows System Directory
if(!bRet)
{
*sz = '\0';
GetSystemDirectory(sz, ARRAYSIZE(sz));
if(lstrlen(sz))
bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
}
return bRet;
}
/***************************************************************************
Name : bUseOutlookStore
Purpose : Determines if we are supposed to be using Outlook
Parameters: none
Returns : TRUE if we are supposed to use outlook AND we can find the
outlook installation
Comment :
***************************************************************************/
BOOL bUseOutlookStore()
{
HKEY hKey = NULL;
DWORD dwUseOutlook = 0;
BOOL bRet = FALSE;
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
if(ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER,
lpNewWABRegKey,
0, KEY_READ,
&hKey))
{
if(ERROR_SUCCESS == RegQueryValueEx(hKey,
lpRegUseOutlookVal,
NULL,
&dwType,
(LPBYTE) &dwUseOutlook,
&dwSize))
{
bRet = (BOOL) dwUseOutlook;
}
}
if(hKey)
RegCloseKey(hKey);
if(bRet)
{
// just double check that we can actually find the OutlookWABSPI dll
bRet = bCheckForOutlookWABDll(NULL, 0);
}
return bRet;
}
//$$//////////////////////////////////////////////////////////
//
// Copies Src to Dest. If Src is longer than Dest,
// truncates the src and trails it with 3 dots
//
//////////////////////////////////////////////////////////////
int CopyTruncate(LPTSTR szDest, LPTSTR szSrc, int nMaxLen)
{
int nLen = lstrlen(szSrc)+1;
if (nLen >= nMaxLen)
{
ULONG iLenDots = lstrlen(szTrailingDots) + 1;
ULONG iLen = TruncatePos(szSrc, nMaxLen - iLenDots);
CopyMemory(szDest,szSrc, sizeof(TCHAR)*(nMaxLen - iLenDots));
szDest[iLen]='\0';
StrCatBuff(szDest,szTrailingDots, nMaxLen);
//DebugTrace("%s = %s\n", szDest, szSrc);
}
else
{
StrCpyN(szDest,szSrc,nMaxLen);
}
return nLen;
}
///////////////////////////////////////////////////////////////////
//
// HrShowDSProps - shows Directory Service properties UI
//
// hWndParent - hWnd of Parent
// lpszName - pointer to a buffer ... also contains name of LDAP
// server to view prperties on - this name can be modified so
// lpszName should point to a big enough buffer
// bAddNew - TRUE if this is a new entry, false if this is props
///////////////////////////////////////////////////////////////////
HRESULT HrShowDSProps(HWND hWndParent,
LPTSTR ptszAcct,
LPTSTR *pptszName,
BOOL bAddNew)
{
HRESULT hr = hrSuccess;
IImnAccountManager2 * lpAccountManager = NULL;
IImnAccount * lpAccount = NULL;
LPSTR lpAcct = ConvertWtoA(ptszAcct);
// init account manager
// Make sure there is an account manager
if (hr = InitAccountManager(NULL, &lpAccountManager, NULL)) {
ShowMessageBox(hWndParent, idsLDAPUnconfigured, MB_ICONEXCLAMATION | MB_OK);
goto out;
}
// find this account
if (hr = lpAccountManager->lpVtbl->FindAccount(lpAccountManager,
AP_ACCOUNT_NAME,
lpAcct,
&lpAccount)) {
DebugTrace( TEXT("FindAccount(%s) -> %x\n"), lpAcct, GetScode(hr));
goto out;
}
// show properties
if (hr = lpAccount->lpVtbl->ShowProperties(lpAccount,
hWndParent,
0)) {
DebugTrace( TEXT("ShowProperties(%s) -> %x\n"), lpAcct, GetScode(hr));
goto out;
}
{
char szBuf[MAX_UI_STR];
// Get the friendly name (== account name if this changed)
if (! (HR_FAILED(hr = lpAccount->lpVtbl->GetPropSz(lpAccount, AP_ACCOUNT_NAME, szBuf, ARRAYSIZE(szBuf)))))
{
LPTSTR lp = ConvertAtoW(szBuf);
if(lp)
{
*pptszName = lp;
}
}
}
out:
if (lpAccount) {
lpAccount->lpVtbl->Release(lpAccount);
}
LocalFreeAndNull(&lpAcct);
// Don't release the account manager. It will be done when the IAdrBook is released.
// if (lpAccountManager) {
// lpAccountManager->lpVtbl->Release(lpAccountManager);
// }
return hr;
}
//$$///////////////////////////////////////////////////////////////////////////////
//
// HrShowDirectoryServiceModificationDlg - Shows the main dialog with the list
// of directory services and with a prop sheet for changing check order
//
// hWndParent - Parent for this dialog
/////////////////////////////////////////////////////////////////////////////////
HRESULT HrShowDirectoryServiceModificationDlg(HWND hWndParent, LPIAB lpIAB)
{
ACCTLISTINFO ali;
HRESULT hr = hrSuccess;
IImnAccountManager2 * lpAccountManager;
// Make sure there is an account manager
if (hr = InitAccountManager(lpIAB, &lpAccountManager, NULL)) {
ShowMessageBox(hWndParent, idsLDAPUnconfigured, MB_ICONEXCLAMATION | MB_OK);
goto out;
}
ali.cbSize = sizeof(ACCTLISTINFO);
ali.AcctTypeInit = (ACCTTYPE)-1;
ali.dwAcctFlags = ACCT_FLAG_DIR_SERV;
ali.dwFlags = 0;
hr = lpAccountManager->lpVtbl->AccountListDialog(lpAccountManager,
hWndParent,
&ali);
out:
return hr;
}
/*
- HrShellExecInternetCall
-
*
* Checks if the selected, single item has PR_SERVERS set on it and has a default
* callto item - if yes, shell-exects this item ..
*/
HRESULT HrShellExecInternetCall(LPADRBOOK lpAdrBook, HWND hWndLV)
{
HRESULT hr = E_FAIL;
LPRECIPIENT_INFO lpItem = NULL;
LPSPropValue lpPropArray = NULL;
ULONG ulcProps = 0;
int nCount = ListView_GetSelectedCount(hWndLV);
if(nCount != 1)
{
ShowMessageBox(GetParent(hWndLV),
(nCount > 1) ? IDS_ADDRBK_MESSAGE_ACTION : IDS_ADDRBK_MESSAGE_NO_ITEM,
MB_ICONEXCLAMATION);
goto out;
}
lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
if(lpItem)
{
if(!HR_FAILED(hr = HrGetPropArray( lpAdrBook, NULL,
lpItem->cbEntryID, lpItem->lpEntryID,
MAPI_UNICODE,
&ulcProps, &lpPropArray)))
{
ULONG i = 0, nConf = 0xffffffff, nDef = 0xffffffff;
LPTSTR lpsz = NULL;
for(i=0;i<ulcProps;i++)
{
if(lpPropArray[i].ulPropTag == PR_WAB_CONF_SERVERS)
nConf = i;
else if(lpPropArray[i].ulPropTag == PR_WAB_CONF_DEFAULT_INDEX)
nDef = i;
}
if(nConf != 0xffffffff)
{
TCHAR sz[MAX_PATH];
if(nDef != 0xffffffff)
{
ULONG iDef = lpPropArray[nDef].Value.l;
lpsz = lpPropArray[nConf].Value.MVSZ.LPPSZ[iDef];
}
else
{
// no default .. find the first call to and use that
for(i=0;i<lpPropArray[nConf].Value.MVSZ.cValues;i++)
{
if(lstrlen(lpPropArray[nConf].Value.MVSZ.LPPSZ[i]) >= lstrlen(szCallto))
{
int nLen = lstrlen(szCallto);
CopyMemory(sz, lpPropArray[nConf].Value.MVSZ.LPPSZ[i], sizeof(TCHAR)*nLen);
sz[nLen] = '\0';
if(!lstrcmpi(sz, szCallto))
{
lpsz = lpPropArray[nConf].Value.MVSZ.LPPSZ[i];
break;
}
}
}
}
if(lpsz)
if(!ShellExecute(GetParent(hWndLV), TEXT("open"), lpsz, NULL, NULL, SW_SHOWNORMAL))
ShowMessageBox(GetParent(hWndLV), idsCouldNotSelectUser, MB_ICONEXCLAMATION);
}
if(nConf == 0xffffffff || !lpsz)
ShowMessageBox(GetParent(hWndLV), idsInternetCallNoCallTo, MB_ICONEXCLAMATION);
}
}
out:
if(lpPropArray)
MAPIFreeBuffer(lpPropArray);
return hr;
}
/*
- GetItemFromLV
-
* utility function for returning the recipient item from the LV
*/
LPRECIPIENT_INFO GetItemFromLV(HWND hWndLV, int iItem)
{
LPRECIPIENT_INFO lpItem = NULL;
LV_ITEM LVItem;
LVItem.mask = LVIF_PARAM;
LVItem.iItem = iItem;
LVItem.iSubItem = 0;
LVItem.lParam = 0;
// Get item lParam LPRECIPIENT_INFO structure
if (ListView_GetItem(hWndLV,&LVItem))
lpItem = ((LPRECIPIENT_INFO) LVItem.lParam);
return lpItem;
}
/*
- Helper function
-
*/
void SetSBinary(LPSBinary lpsb, ULONG cb, LPBYTE lpb)
{
if(!lpsb || !cb || !lpb)
return;
if(lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, cb))
{
lpsb->cb = cb;
CopyMemory(lpsb->lpb, lpb, cb);
}
}
/*
- GetWABIconImage
-
*
*/
int GetWABIconImage(LPRECIPIENT_INFO lpItem)
{
if(lpItem->cbEntryID == 0)
return imageUnknown;
if(lpItem->ulObjectType == MAPI_DISTLIST)
{
return imageDistList;
}
else
{
BYTE bType;
if(lpItem->bIsMe)
return imageMailUserMe;
else if(lpItem->bHasCert)
return imageMailUserWithCert;
bType = IsWABEntryID(lpItem->cbEntryID, lpItem->lpEntryID, NULL,NULL,NULL, NULL, NULL);
if(bType == WAB_LDAP_MAILUSER)
return imageMailUserLDAP;
else if(bType == WAB_ONEOFF)
return imageMailUserOneOff;
}
return imageMailUser;
}
enum
{
IE401_DONTKNOW=0,
IE401_TRUE,
IE401_FALSE
};
static int g_nIE401 = IE401_DONTKNOW;
/*
- bIsIE401
-
* Checks if this installation has IE4.01 or greater so we can decide what flags to pass to the prop sheets
*
*/
BOOL bIsIE401OrGreater()
{
BOOL bRet = FALSE;
if(g_nIE401 == IE401_TRUE)
return TRUE;
if(g_nIE401 == IE401_FALSE)
return FALSE;
g_nIE401 = IE401_FALSE;
// else we need to check
InitCommonControlLib();
//load the DLL
if(ghCommCtrlDLLInst)
{
LPDLLGETVERSIONPROCOE lpfnDllGetVersionProc = NULL;
lpfnDllGetVersionProc = (LPDLLGETVERSIONPROCOE) GetProcAddress(ghCommCtrlDLLInst, "DllGetVersion");
if(lpfnDllGetVersionProc)
{
// Check the version number
DLLVERSIONINFO dvi = {0};
dvi.cbSize = sizeof(dvi);
lpfnDllGetVersionProc(&dvi);
// we are looking for IE4 version 4.72 or more
if( (dvi.dwMajorVersion > 4) ||
(dvi.dwMajorVersion == 4 && dvi.dwMinorVersion >= 72) )
{
g_nIE401 = IE401_TRUE;
bRet = TRUE;
}
}
}
DeinitCommCtrlClientLib();
return bRet;
}
#ifdef COLSEL_MENU
/**
ColSel_PropTagToString: This function will convert a propertytag to a string
*/
BOOL ColSel_PropTagToString( ULONG ulPropTag, LPTSTR lpszString, ULONG cchString)
{
UINT i, j;
UINT iIndex;
HMENU hMainMenu;
HMENU hMenu;
MENUITEMINFO mii;
BOOL fRet = FALSE;
hMainMenu = LoadMenu(hinstMapiX, MAKEINTRESOURCE(IDR_MENU_LVCONTEXTMENU_COLSEL));
if( !hMainMenu )
{
DebugTrace( TEXT("unable to load main colsel menu\n"));
goto exit;
}
hMenu = GetSubMenu( hMainMenu, 0);
if( !hMenu )
{
DebugTrace( TEXT("unable to load submenu from colsel main menu\n"));
goto exit;
}
if( !lpszString )
{
DebugTrace( TEXT("illegal argument -- lpszString must be valid mem\n"));
goto exit;
}
mii.fMask = MIIM_TYPE;
mii.cbSize = sizeof( MENUITEMINFO );
mii.dwTypeData = lpszString;
mii.cch = cchString;
for( i = 0; i < MAXNUM_MENUPROPS; i++)
{
if( MenuToPropTagMap[i] == ulPropTag )
{
if( !GetMenuItemInfo( hMenu, i, TRUE, &mii) )
{
DebugTrace( TEXT("unable to get menu item info: %x\n"), GetLastError() );
goto exit;
}
fRet = TRUE;
}
}
exit:
if ( hMainMenu != NULL )
DestroyMenu( hMainMenu );
if( !fRet )
DebugTrace( TEXT("unable to find property tag\n"));
return fRet;
}
#endif // COLSEL_MENU
/*
- IsWindowOnScreen
-
* Checks if a window is onscreen so that if it is not entirely onscreen we can push it back
* into a viewable area .. this way if the user changes screen resolution or switches multi-monitors
* around, we don't lose the app
*/
BOOL IsWindowOnScreen(LPRECT lprc)
{
HDC hDC = GetDC(NULL);
BOOL fRet = RectVisible(hDC, lprc);
ReleaseDC(NULL, hDC);
return fRet;
}
/*
- IsHTTPMailEnabled
-
* Checks if HTTP is enabled so that we can hide UI if its not.
*/
static TCHAR c_szRegRootAthenaV2[] = TEXT("Software\\Microsoft\\Outlook Express");
static TCHAR c_szEnableHTTPMail[] = TEXT("HTTP Mail Enabled");
BOOL IsHTTPMailEnabled(LPIAB lpIAB)
{
#ifdef NOHTTPMAIL
return FALSE;
#else
DWORD cb, bEnabled = FALSE;
HKEY hkey = NULL;
// [PaulHi] 1/5/98 Raid #64160
// Hotmail synchronization is disabled if the WAB is not in "identity aware"
// mode. So, we need to check for this too.
bEnabled = lpIAB->bProfilesIdent;
// @todo [PaulHi] 12/1/98
// We really shouldn't be doing a registry query every time the user
// opens up the Tools menu, i.e., in update menu.
// Check this registry sometime during start up and save per instance.
// open the OE5.0 key
if ( bEnabled &&
(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegRootAthenaV2, 0, KEY_QUERY_VALUE, &hkey)) )
{
cb = sizeof(bEnabled);
RegQueryValueEx(hkey, c_szEnableHTTPMail, 0, NULL, (LPBYTE)&bEnabled, &cb);
RegCloseKey(hkey);
}
//
// [PaulHi] 12/1/98 Raid #57739
// HACK WARNING
// Since the Hotmail server is currently hard coded to the U.S. 1252
// codepage, any other system codepage will result in corrupted data
// after a round sync trip to the Hotmail server and back, for any fields
// with DB characters (i.e., international). The temporary solution is
// to simply disable Hotmail synchronization if a codepage other than
// 1252 is detected on the client machine.
//
#define USLatin1CodePage 1252
if (bEnabled)
{
DWORD dwCodepage = GetACP();
if (dwCodepage != USLatin1CodePage)
bEnabled = FALSE;
}
return bEnabled;
#endif
}
/*
-
- WriteRegistryDeletedHotsyncItem
*
* Writes the Hotmail Contact/ID/Modtime info to the registry so we can track deletions for
* Hotmail syncing
*
*/
extern LPTSTR g_lpszSyncKey;
void WriteRegistryDeletedHotsyncItem(LPTSTR lpServerID, LPTSTR lpContactID, LPTSTR lpModTime)
{
HKEY hKey = NULL,hSubKey = NULL;
DWORD dwDisposition = 0;
if( !lpServerID || !lstrlen(lpServerID) ||
!lpContactID || !lstrlen(lpContactID) ||
!lpModTime || !lstrlen(lpModTime) )
return;
// Open key
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, g_lpszSyncKey, 0, //reserved
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hKey, &dwDisposition))
{
if (ERROR_SUCCESS == RegCreateKeyEx(hKey,lpContactID, 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hSubKey, &dwDisposition))
{
// Create a value here .. the value name is the Contact ID and the Value Data is the ModTime
// Now Write this key
RegSetValueEx( hSubKey, lpServerID, 0, REG_SZ, (LPBYTE) lpModTime, (lstrlen(lpModTime)+1) * sizeof(TCHAR) );
}
}
if(hSubKey)
RegCloseKey(hSubKey);
if(hKey)
RegCloseKey(hKey);
}
/*
- HrSaveHotmailSyncInfoOnDeletion
-
* If the user has ever done any hotmail syncing, we need to track deletions in the WAB
* so that after you delete an entry in the WAB, the corresponding hotmail entry will
* be deleted on Sync.
*
* We store the hotmail sync info in the registry, hopefully there won't be too much of it
* Whenever the hotmail sync happens, the info gets cleaned out.
*/
HRESULT HrSaveHotmailSyncInfoOnDeletion(LPADRBOOK lpAdrBook, LPSBinary lpEID)
{
// Basically we will open the object being deleted, look for it's Hotmail
// properties and if these properties exist, we will put them into the registry
//
HRESULT hr = S_OK;
ULONG ulcValues = 0,i=0;
LPSPropValue lpProps = NULL;
SizedSPropTagArray(3, ptaHotProps) =
{
3,
{
PR_WAB_HOTMAIL_CONTACTIDS,
PR_WAB_HOTMAIL_MODTIMES,
PR_WAB_HOTMAIL_SERVERIDS,
}
};
hr = HrGetPropArray(lpAdrBook,
(LPSPropTagArray) &ptaHotProps,
lpEID->cb,(LPENTRYID) lpEID->lpb,
MAPI_UNICODE,
&ulcValues,&lpProps);
if(HR_FAILED(hr) || !ulcValues || !lpProps)
goto out;
// The three props are supposed to be in sync, so if one exists, the other 2 will also exist
// and if this is not true, then don't write the data to the registry
if( lpProps[0].ulPropTag != PR_WAB_HOTMAIL_CONTACTIDS ||
!lpProps[0].Value.MVSZ.cValues ||
lpProps[1].ulPropTag != PR_WAB_HOTMAIL_MODTIMES ||
!lpProps[1].Value.MVSZ.cValues ||
lpProps[2].ulPropTag != PR_WAB_HOTMAIL_SERVERIDS ||
!lpProps[2].Value.MVSZ.cValues ||
lpProps[0].Value.MVSZ.cValues != lpProps[1].Value.MVSZ.cValues ||
lpProps[0].Value.MVSZ.cValues != lpProps[2].Value.MVSZ.cValues ||
lpProps[1].Value.MVSZ.cValues != lpProps[2].Value.MVSZ.cValues)
goto out;
for(i=0;i<lpProps[0].Value.MVSZ.cValues;i++)
{
WriteRegistryDeletedHotsyncItem( lpProps[2].Value.MVSZ.LPPSZ[i], //server id
lpProps[0].Value.MVSZ.LPPSZ[i], //contact id
lpProps[1].Value.MVSZ.LPPSZ[i]); //mod time
}
out:
FreeBufferAndNull(&lpProps);
return hr;
}