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

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // UIMISC.C - common miscellaneous functions used by the UI
  4. //
  5. //
  6. ////////////////////////////////////////////////////////////////////////////////
  7. #include "_apipch.h"
  8. const LPTSTR szLDAPDefaultCountryValue = TEXT("LDAP Default Country");
  9. const LPTSTR szTrailingDots = TEXT("...");
  10. const LPTSTR szArrow = TEXT(" ->");
  11. const LPTSTR szBackSlash = TEXT("\\");
  12. extern BOOL bDNisByLN;
  13. extern BOOL bIsPasteData();
  14. HINSTANCE ghCommDlgInst = NULL;
  15. extern HINSTANCE ghCommCtrlDLLInst;
  16. extern ULONG gulCommCtrlDLLRefCount;
  17. extern void SetVirtualPABEID(LPIAB lpIAB, ULONG * lpcb, LPENTRYID * lppb);
  18. extern void vTurnOffAllNotifications();
  19. extern void vTurnOnAllNotifications();
  20. LP_INITCOMMONCONTROLSEX gpfnInitCommonControlsEx = NULL;
  21. LPIMAGELIST_SETBKCOLOR gpfnImageList_SetBkColor = NULL;
  22. LPIMAGELIST_DRAW gpfnImageList_Draw = NULL;
  23. LPIMAGELIST_DESTROY gpfnImageList_Destroy = NULL;
  24. LPIMAGELIST_LOADIMAGE_A gpfnImageList_LoadImageA = NULL;
  25. LPPROPERTYSHEET_A gpfnPropertySheetA = NULL;
  26. LP_CREATEPROPERTYSHEETPAGE_A gpfnCreatePropertySheetPageA = NULL;
  27. LPIMAGELIST_LOADIMAGE_W gpfnImageList_LoadImageW = NULL;
  28. LPPROPERTYSHEET_W gpfnPropertySheetW = NULL;
  29. LP_CREATEPROPERTYSHEETPAGE_W gpfnCreatePropertySheetPageW = NULL;
  30. // CommCtrl function names
  31. static const TCHAR cszCommCtrlClientDLL[] = TEXT("COMCTL32.DLL");
  32. static const char cszInitCommonControlsEx[] = "InitCommonControlsEx";
  33. static const char cszImageList_SetBkColor[] = "ImageList_SetBkColor";
  34. static const char cszImageList_LoadImageA[] = "ImageList_LoadImageA";
  35. static const char cszPropertySheetA[] = "PropertySheetA";
  36. static const char cszCreatePropertySheetPageA[] = "CreatePropertySheetPageA";
  37. static const char cszImageList_LoadImageW[] = "ImageList_LoadImageW";
  38. static const char cszPropertySheetW[] = "PropertySheetW";
  39. static const char cszCreatePropertySheetPageW[] = "CreatePropertySheetPageW";
  40. static const char cszImageList_Draw[] = "ImageList_Draw";
  41. static const char cszImageList_Destroy[] = "ImageList_Destroy";
  42. // API table for CommonControl function addresses to fetch
  43. #define NUM_CommCtrlAPI_PROCS 10
  44. APIFCN CommCtrlAPIList[NUM_CommCtrlAPI_PROCS] =
  45. {
  46. { (PVOID *) &gpfnInitCommonControlsEx, cszInitCommonControlsEx},
  47. { (PVOID *) &gpfnImageList_SetBkColor, cszImageList_SetBkColor},
  48. { (PVOID *) &gpfnImageList_Draw, cszImageList_Draw},
  49. { (PVOID *) &gpfnImageList_Destroy, cszImageList_Destroy},
  50. { (PVOID *) &gpfnImageList_LoadImageA, cszImageList_LoadImageA},
  51. { (PVOID *) &gpfnPropertySheetA, cszPropertySheetA},
  52. { (PVOID *) &gpfnCreatePropertySheetPageA, cszCreatePropertySheetPageA},
  53. { (PVOID *) &gpfnImageList_LoadImageW, cszImageList_LoadImageW},
  54. { (PVOID *) &gpfnPropertySheetW, cszPropertySheetW},
  55. { (PVOID *) &gpfnCreatePropertySheetPageW, cszCreatePropertySheetPageW}
  56. };
  57. #ifdef COLSEL_MENU
  58. // for menu->column selection mapping
  59. #define MAXNUM_MENUPROPS 12
  60. const ULONG MenuToPropTagMap[] = {
  61. PR_HOME_TELEPHONE_NUMBER,
  62. PR_BUSINESS_TELEPHONE_NUMBER,
  63. PR_PAGER_TELEPHONE_NUMBER,
  64. PR_CELLULAR_TELEPHONE_NUMBER,
  65. PR_BUSINESS_FAX_NUMBER,
  66. PR_HOME_FAX_NUMBER,
  67. PR_COMPANY_NAME,
  68. PR_TITLE,
  69. PR_DEPARTMENT_NAME,
  70. PR_OFFICE_LOCATION,
  71. PR_BIRTHDAY,
  72. PR_WEDDING_ANNIVERSARY
  73. };
  74. #endif // COLSEL_MENU
  75. void CleanAddressString(TCHAR * szAddress);
  76. static const LPTSTR g_szComDlg32 = TEXT("COMDLG32.DLL");
  77. // Delay load substitutes for commdlg functions
  78. //
  79. BOOL (*pfnGetOpenFileNameA)(LPOPENFILENAMEA pof);
  80. BOOL (*pfnGetOpenFileNameW)(LPOPENFILENAMEW pof);
  81. BOOL GetOpenFileName(LPOPENFILENAME pof)
  82. {
  83. // static BOOL (*pfnGetOpenFileName)(LPOPENFILENAME pof);
  84. if(!ghCommDlgInst)
  85. ghCommDlgInst = LoadLibrary(g_szComDlg32);
  86. if(ghCommDlgInst)
  87. {
  88. if ( pfnGetOpenFileNameA == NULL )
  89. pfnGetOpenFileNameA = (BOOL (*)(LPOPENFILENAMEA))GetProcAddress(ghCommDlgInst, "GetOpenFileNameA");
  90. if ( pfnGetOpenFileNameW == NULL )
  91. pfnGetOpenFileNameW = (BOOL (*)(LPOPENFILENAMEW))GetProcAddress(ghCommDlgInst, "GetOpenFileNameW");
  92. if (pfnGetOpenFileNameA && pfnGetOpenFileNameW)
  93. return pfnGetOpenFileName(pof);
  94. }
  95. return -1;
  96. }
  97. BOOL (*pfnGetSaveFileNameA)(LPOPENFILENAMEA pof);
  98. BOOL (*pfnGetSaveFileNameW)(LPOPENFILENAMEW pof);
  99. BOOL GetSaveFileName(LPOPENFILENAME pof)
  100. {
  101. // static BOOL (*pfnGetSaveFileName)(LPOPENFILENAME pof);
  102. if(!ghCommDlgInst)
  103. ghCommDlgInst = LoadLibrary(g_szComDlg32);
  104. if(ghCommDlgInst)
  105. {
  106. if ( pfnGetSaveFileNameA == NULL )
  107. pfnGetSaveFileNameA = (BOOL (*)(LPOPENFILENAMEA))GetProcAddress(ghCommDlgInst, "GetSaveFileNameA");
  108. if ( pfnGetSaveFileNameW == NULL )
  109. pfnGetSaveFileNameW = (BOOL (*)(LPOPENFILENAMEW))GetProcAddress(ghCommDlgInst, "GetSaveFileNameW");
  110. if ( pfnGetSaveFileNameA && pfnGetSaveFileNameW )
  111. return pfnGetSaveFileName(pof);
  112. }
  113. return -1;
  114. }
  115. BOOL (*pfnPrintDlgA)(LPPRINTDLGA lppd);
  116. BOOL (*pfnPrintDlgW)(LPPRINTDLGW lppd);
  117. BOOL PrintDlg(LPPRINTDLG lppd)
  118. {
  119. // static BOOL (*pfnPrintDlg)(LPPRINTDLG lppd);
  120. if(!ghCommDlgInst)
  121. ghCommDlgInst = LoadLibrary(g_szComDlg32);
  122. if(ghCommDlgInst)
  123. {
  124. if ( pfnPrintDlgA == NULL )
  125. pfnPrintDlgA = (BOOL (*)(LPPRINTDLGA))GetProcAddress(ghCommDlgInst, "PrintDlgA");
  126. if ( pfnPrintDlgW == NULL )
  127. pfnPrintDlgW = (BOOL (*)(LPPRINTDLGW))GetProcAddress(ghCommDlgInst, "PrintDlgW");
  128. if ( pfnPrintDlgA && pfnPrintDlgW )
  129. return pfnPrintDlg(lppd);
  130. }
  131. return -1;
  132. }
  133. /*
  134. - PrintDlgEx
  135. -
  136. - Loads the PrintDlgEx from the ComDlg32.dll
  137. - If lppdex is NULL, then just loads and returns S_OK (this way we test for support for PrintDlgEx
  138. - on the current system .. instead of trying to look at the OS version etc)
  139. -
  140. - Returns MAPI_E_NOT_FOUND if no support on OS
  141. -
  142. */
  143. HRESULT (*pfnPrintDlgExA)(LPPRINTDLGEXA lppdex);
  144. HRESULT (*pfnPrintDlgExW)(LPPRINTDLGEXW lppdex);
  145. HRESULT PrintDlgEx(LPPRINTDLGEX lppdex)
  146. {
  147. // static HRESULT (*pfnPrintDlgEx)(LPPRINTDLGEX lppdex);
  148. if(!ghCommDlgInst)
  149. ghCommDlgInst = LoadLibrary(g_szComDlg32);
  150. if(ghCommDlgInst)
  151. {
  152. if ( pfnPrintDlgExA == NULL )
  153. pfnPrintDlgExA = (HRESULT (*)(LPPRINTDLGEXA))GetProcAddress(ghCommDlgInst, "PrintDlgExA");
  154. if ( pfnPrintDlgExW == NULL )
  155. pfnPrintDlgExW = (HRESULT (*)(LPPRINTDLGEXW))GetProcAddress(ghCommDlgInst, "PrintDlgExW");
  156. if (!pfnPrintDlgExA || !pfnPrintDlgExW)
  157. {
  158. DebugTrace( TEXT("PrintDlgEx not found - %d\n"),GetLastError());
  159. return MAPI_E_NOT_FOUND;
  160. }
  161. if(!lppdex)
  162. return S_OK; //just testing for presence of this function
  163. return pfnPrintDlgEx(lppdex);
  164. }
  165. return E_FAIL;
  166. }
  167. extern void DeinitCommDlgLib()
  168. {
  169. if(ghCommDlgInst)
  170. {
  171. FreeLibrary(ghCommDlgInst);
  172. ghCommDlgInst = NULL;
  173. }
  174. }
  175. //$$
  176. //
  177. // HandleSaveChangedInsufficientDiskSpace - Called when savechanges returns
  178. // insufficient disk space. If user selects to proceed
  179. //
  180. //
  181. HRESULT HandleSaveChangedInsufficientDiskSpace(HWND hWnd, LPMAILUSER lpMailUser)
  182. {
  183. HRESULT hr = MAPI_E_NOT_ENOUGH_DISK;
  184. while(hr == MAPI_E_NOT_ENOUGH_DISK)
  185. {
  186. if(IDOK == ShowMessageBox( hWnd,
  187. idsNotEnoughDiskSpace,
  188. MB_OKCANCEL | MB_ICONEXCLAMATION))
  189. {
  190. // try saving again
  191. hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
  192. KEEP_OPEN_READWRITE);
  193. }
  194. else
  195. hr = MAPI_E_USER_CANCEL;
  196. }
  197. return hr;
  198. }
  199. //$$////////////////////////////////////////////////////////////////
  200. //
  201. // SetRecipColumns - sets the columns we want to populate the
  202. // RECIPIENTINFO item structures with
  203. //
  204. //////////////////////////////////////////////////////////////////
  205. #define RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES 7 // Keep this in sync with ptaRecipArray below
  206. HRESULT SetRecipColumns(LPMAPITABLE lpContentsTable)
  207. {
  208. HRESULT hr = S_OK;
  209. SizedSPropTagArray(16, ptaRecipArray) =
  210. {
  211. 16,
  212. {
  213. PR_DISPLAY_NAME,
  214. PR_SURNAME,
  215. PR_GIVEN_NAME,
  216. PR_MIDDLE_NAME,
  217. PR_COMPANY_NAME,
  218. PR_NICKNAME,
  219. PR_EMAIL_ADDRESS,
  220. PR_CONTACT_EMAIL_ADDRESSES, // [PaulHi] Use for PR_EMAIL_ADDRESS if no PR_EMAIL_ADDRESS exists
  221. PR_ENTRYID,
  222. PR_OBJECT_TYPE,
  223. PR_USER_X509_CERTIFICATE,
  224. PR_HOME_TELEPHONE_NUMBER,
  225. PR_OFFICE_TELEPHONE_NUMBER,
  226. PR_WAB_THISISME,
  227. PR_WAB_YOMI_FIRSTNAME, //keep these ruby props at the end of the list
  228. PR_WAB_YOMI_LASTNAME,
  229. }
  230. };
  231. if(PR_WAB_CUSTOMPROP1)
  232. ptaRecipArray.aulPropTag[11] = PR_WAB_CUSTOMPROP1;
  233. if(PR_WAB_CUSTOMPROP2)
  234. ptaRecipArray.aulPropTag[12] = PR_WAB_CUSTOMPROP2;
  235. if(!bIsRubyLocale()) // Don't ask for Ruby Props if we don't need em
  236. ptaRecipArray.cValues -= 2;
  237. hr =lpContentsTable->lpVtbl->SetColumns(lpContentsTable,
  238. (LPSPropTagArray)&ptaRecipArray, 0);
  239. return hr;
  240. }
  241. //$$////////////////////////////////////////////////////////////////
  242. //
  243. // GetABContentsList Gets a contents list
  244. //
  245. // hPropertyStore handle to property store - this can be null for
  246. // non-property store containers
  247. // cbContEntryID entryid of container
  248. // lpContEntryID cont entry id
  249. // lpPTA, Array of prop tags to fill in the list view
  250. // Can be null - in which case default array will be used
  251. // lpPropRes Filter which caller can supply - if null TEXT("DisplayName") is the default
  252. // ulFlags Used with Filter - either 0 or AB_MATCH_PROP_ONLY
  253. // bGetProfileContents - If TRUE and profiles, gets full list of profile contents - if false
  254. // IF FALSE, checks if profiles are ON and gets container contents..
  255. // lppContentsList Returned Contents list pointing off to entries
  256. //
  257. //////////////////////////////////////////////////////////////////
  258. HRESULT HrGetWABContentsList( LPIAB lpIAB,
  259. SORT_INFO SortInfo,
  260. LPSPropTagArray lpPTA,
  261. LPSPropertyRestriction lpPropRes,
  262. ULONG ulFlags,
  263. LPSBinary lpsbContainer,
  264. BOOL bGetProfileContents,
  265. LPRECIPIENT_INFO * lppContentsList)
  266. {
  267. HRESULT hr = hrSuccess;
  268. ULONG i = 0,j=0;
  269. LPRECIPIENT_INFO lpItem = NULL;
  270. LPRECIPIENT_INFO lpLastListItem = NULL;
  271. HANDLE hPropertyStore = lpIAB->lpPropertyStore->hPropertyStore;
  272. SPropertyRestriction PropRes = {0};
  273. ULONG ulContentsTableFlags = MAPI_UNICODE | WAB_CONTENTTABLE_NODATA;
  274. ULONG ulcPropCount = 0;
  275. LPULONG lpPropTagArray = NULL;
  276. LPCONTENTLIST lpContentList = NULL;
  277. /****/
  278. LPCONTAINER lpContainer = NULL;
  279. LPMAPITABLE lpContentsTable = NULL;
  280. LPSRowSet lpSRowSet = NULL;
  281. ULONG cbContainerEID = 0;
  282. LPENTRYID lpContainerEID = NULL;
  283. ULONG ulObjectType = 0;
  284. if(lpsbContainer)
  285. {
  286. cbContainerEID = lpsbContainer->cb;
  287. lpContainerEID = (LPENTRYID)lpsbContainer->lpb;
  288. }
  289. if(!cbContainerEID || !lpContainerEID)
  290. {
  291. // When calling GetPAB, this will normally return the users contact folder
  292. // In this case (where we havent been asked to get all the profile contents,
  293. // this implies that without container info, we should get the virtual
  294. // folder contents
  295. if(!bGetProfileContents)
  296. SetVirtualPABEID((LPIAB)lpIAB, &cbContainerEID, &lpContainerEID);
  297. hr = lpIAB->lpVtbl->GetPAB(lpIAB, &cbContainerEID, &lpContainerEID);
  298. if(HR_FAILED(hr))
  299. goto out;
  300. }
  301. //
  302. // First we need to open the container object corresponding to this Container EntryID
  303. //
  304. hr = lpIAB->lpVtbl->OpenEntry(
  305. lpIAB,
  306. cbContainerEID,
  307. lpContainerEID,
  308. NULL,
  309. 0,
  310. &ulObjectType,
  311. (LPUNKNOWN *) &lpContainer);
  312. if(HR_FAILED(hr))
  313. {
  314. DebugPrintError(( TEXT("OpenEntry Failed: %x\n"),hr));
  315. goto out;
  316. }
  317. if(bIsWABSessionProfileAware(lpIAB))
  318. {
  319. ulContentsTableFlags |= WAB_ENABLE_PROFILES;
  320. if(bGetProfileContents)
  321. ulContentsTableFlags |= WAB_PROFILE_CONTENTS;
  322. }
  323. //
  324. // Now we do a get contents table on this container ...
  325. //
  326. hr = lpContainer->lpVtbl->GetContentsTable(
  327. lpContainer,
  328. ulContentsTableFlags,
  329. &lpContentsTable);
  330. if(HR_FAILED(hr))
  331. {
  332. DebugPrintError(( TEXT("GetContentsTable Failed: %x\n"),hr));
  333. goto out;
  334. }
  335. // the default set of columns does not have all the information we are seeking
  336. // so we do a set columns
  337. hr = SetRecipColumns(lpContentsTable);
  338. if(HR_FAILED(hr))
  339. goto out;
  340. if(lpPropRes)
  341. {
  342. SRestriction sr = {0};
  343. sr.rt = RES_PROPERTY;
  344. sr.res.resProperty = *lpPropRes;
  345. if(HR_FAILED(hr = lpContentsTable->lpVtbl->Restrict(lpContentsTable,&sr,0)))
  346. goto out;
  347. }
  348. hr = HrQueryAllRows(lpContentsTable, NULL, NULL, NULL, 0, &lpSRowSet);
  349. if (HR_FAILED(hr))
  350. {
  351. DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
  352. goto out;
  353. }
  354. //
  355. // if there's anything in the contents list flush it away
  356. //
  357. if (*lppContentsList)
  358. {
  359. lpItem = (*lppContentsList);
  360. (*lppContentsList) = lpItem->lpNext;
  361. FreeRecipItem(&lpItem);
  362. }
  363. *lppContentsList = NULL;
  364. lpItem = NULL;
  365. for(i=0;i<lpSRowSet->cRows;i++)
  366. {
  367. LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
  368. ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
  369. lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  370. if (!lpItem)
  371. {
  372. DebugPrintError(( TEXT("LocalAlloc Failed \n")));
  373. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  374. goto out;
  375. }
  376. GetRecipItemFromPropArray(ulcPropCount, lpPropArray, &lpItem);
  377. // The critical prop is display name - without it we are nothing ...
  378. // If no display name, junk this entry and continue ..
  379. if (!lstrlen(lpItem->szDisplayName) || (lpItem->cbEntryID == 0)) //This entry id is not allowed
  380. {
  381. FreeRecipItem(&lpItem);
  382. continue;
  383. }
  384. // The entryids are in sorted order by display name
  385. // Depending on the sort order - we want this list to also be sorted by display
  386. // name or by reverse display name ...
  387. if (SortInfo.bSortByLastName)
  388. StrCpyN(lpItem->szDisplayName,lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
  389. if(!SortInfo.bSortAscending)
  390. {
  391. //Add it to the contents linked list
  392. lpItem->lpNext = (*lppContentsList);
  393. if (*lppContentsList)
  394. (*lppContentsList)->lpPrev = lpItem;
  395. lpItem->lpPrev = NULL;
  396. *lppContentsList = lpItem;
  397. }
  398. else
  399. {
  400. if(*lppContentsList == NULL)
  401. (*lppContentsList) = lpItem;
  402. if(lpLastListItem)
  403. lpLastListItem->lpNext = lpItem;
  404. lpItem->lpPrev = lpLastListItem;
  405. lpItem->lpNext = NULL;
  406. lpLastListItem = lpItem;
  407. }
  408. lpItem = NULL;
  409. } //for i ....
  410. /*****/
  411. out:
  412. /****/
  413. if(lpSRowSet)
  414. FreeProws(lpSRowSet);
  415. if(lpContentsTable)
  416. lpContentsTable->lpVtbl->Release(lpContentsTable);
  417. if(lpContainer)
  418. lpContainer->lpVtbl->Release(lpContainer);
  419. if( (!lpsbContainer || !lpsbContainer->lpb) && lpContainerEID)
  420. MAPIFreeBuffer(lpContainerEID);
  421. /****/
  422. if (lpContentList)
  423. FreePcontentlist(hPropertyStore, lpContentList);
  424. if (HR_FAILED(hr))
  425. {
  426. while(*lppContentsList)
  427. {
  428. lpItem = *lppContentsList;
  429. *lppContentsList=lpItem->lpNext;
  430. FreeRecipItem(&lpItem);
  431. }
  432. }
  433. return hr;
  434. }
  435. //$$////////////////////////////////////////////////////////////////
  436. //
  437. // FreeRecipItem - frees a RECIPIENT_INFO structure
  438. //
  439. // lppItem - pointer to the lpItem to free. It is set to NULL
  440. //
  441. //////////////////////////////////////////////////////////////////
  442. void FreeRecipItem(LPRECIPIENT_INFO * lppItem)
  443. {
  444. LocalFreeAndNull(&(*lppItem)->lpEntryID);
  445. LocalFreeAndNull(&(*lppItem)->lpByRubyFirstName);
  446. LocalFreeAndNull(&(*lppItem)->lpByRubyLastName);
  447. LocalFreeAndNull((lppItem));
  448. return;
  449. }
  450. //$$////////////////////////////////////////////////////////////////
  451. //
  452. // InitListView - initializes a list view with style, columns,
  453. // image lists, headers etc
  454. //
  455. //
  456. // HWND hWndLV - Handle of ListView Control
  457. // dwStyle - style for list view
  458. // bShowHeaders - Show or hide the headers
  459. //
  460. //////////////////////////////////////////////////////////////////
  461. HRESULT HrInitListView( HWND hWndLV,
  462. DWORD dwStyle,
  463. BOOL bShowHeaders)
  464. {
  465. HRESULT hr = hrSuccess;
  466. LV_COLUMN lvC; // list view column structure
  467. TCHAR szText [MAX_PATH]; // place to store some text
  468. RECT rc;
  469. HIMAGELIST hSmall=NULL,hLarge=NULL;
  470. HFONT hFnt = GetStockObject(DEFAULT_GUI_FONT);
  471. DWORD dwLVStyle;
  472. ULONG nCols=0;
  473. ULONG index=0;
  474. if (!hWndLV)
  475. {
  476. hr = MAPI_E_INVALID_PARAMETER;
  477. goto out;
  478. }
  479. SendMessage(hWndLV, WM_SETFONT, (WPARAM) hFnt, (LPARAM) TRUE);
  480. ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
  481. dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
  482. if(( dwLVStyle & LVS_TYPEMASK) != dwStyle)
  483. SetWindowLong(hWndLV,GWL_STYLE,(dwLVStyle & ~LVS_TYPEMASK) | dwStyle);
  484. dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
  485. if(( dwLVStyle & LVS_EDITLABELS) != dwStyle)
  486. SetWindowLong(hWndLV,GWL_STYLE,(dwLVStyle & ~LVS_EDITLABELS) | dwStyle);
  487. hSmall = gpfnImageList_LoadImage( hinstMapiX,
  488. MAKEINTRESOURCE(IDB_BITMAP_SMALL),
  489. //(LPCTSTR) ((DWORD) ((WORD) (IDB_BITMAP_SMALL))),
  490. S_BITMAP_WIDTH,
  491. 0,
  492. RGB_TRANSPARENT,
  493. IMAGE_BITMAP,
  494. 0);
  495. hLarge = gpfnImageList_LoadImage( hinstMapiX,
  496. MAKEINTRESOURCE(IDB_BITMAP_LARGE),
  497. //(LPCTSTR) ((DWORD) ((WORD) (IDB_BITMAP_LARGE))),
  498. L_BITMAP_WIDTH,
  499. 0,
  500. RGB_TRANSPARENT,
  501. IMAGE_BITMAP,
  502. 0);
  503. // Associate the image lists with the list view control.
  504. ListView_SetImageList (hWndLV, hSmall, LVSIL_SMALL);
  505. ListView_SetImageList (hWndLV, hLarge, LVSIL_NORMAL);
  506. // <TBD> make the columns all the same width
  507. // Later on in life we will make it so users preferences are stored and then
  508. // played back ...
  509. nCols = NUM_COLUMNS;
  510. if (nCols==0)
  511. {
  512. DebugPrintError(( TEXT("Zero number of cols??\n")));
  513. hr = E_FAIL;
  514. goto out;
  515. }
  516. GetWindowRect(hWndLV,&rc);
  517. lvC.mask = LVCF_FMT | LVCF_WIDTH;
  518. lvC.fmt = LVCFMT_LEFT; // left-align column
  519. if (bShowHeaders)
  520. {
  521. lvC.mask |= LVCF_TEXT | LVCF_SUBITEM;
  522. // lvC.cx = (rc.right-rc.left)/nCols; // width of column in pixels
  523. // if (lvC.cx == 0)
  524. lvC.cx = 150; // <TBD> fix these limits somewhere ...
  525. lvC.pszText = szText;
  526. }
  527. else
  528. {
  529. // if no headers, we want these to be wide enough to fit all the info
  530. lvC.cx = 250; //<TBD> - change this hardcoding
  531. lvC.pszText = NULL;
  532. }
  533. // Add the columns.
  534. for (index = 0; index < nCols; index++)
  535. {
  536. lvC.iSubItem = index;
  537. LoadString (hinstMapiX, lprgAddrBookColHeaderIDs[index], szText, ARRAYSIZE(szText));
  538. if(index == colHomePhone && PR_WAB_CUSTOMPROP1 && lstrlen(szCustomProp1))
  539. StrCpyN(szText, szCustomProp1,ARRAYSIZE(szText));
  540. if(index == colOfficePhone && PR_WAB_CUSTOMPROP2 && lstrlen(szCustomProp2))
  541. StrCpyN(szText, szCustomProp2,ARRAYSIZE(szText));
  542. if((index == colDisplayName) || (index == colEmailAddress))
  543. lvC.cx = 150;
  544. else
  545. lvC.cx = 100;
  546. if (ListView_InsertColumn (hWndLV, index, &lvC) == -1)
  547. {
  548. DebugPrintError(( TEXT("ListView_InsertColumn Failed\n")));
  549. hr = E_FAIL;
  550. goto out;
  551. }
  552. }
  553. out:
  554. return hr;
  555. }
  556. //$$////////////////////////////////////////////////////////////////
  557. ///
  558. /// HrFillListView - fills a list view from an lpcontentslist
  559. ///
  560. /// hWndLV - Handle of List View control to fill
  561. /// lpContentsList - LPRECIPIENT_INFO linked list. We walk the list and
  562. /// add each item to the list view
  563. ///
  564. //////////////////////////////////////////////////////////////////
  565. HRESULT HrFillListView( HWND hWndLV,
  566. LPRECIPIENT_INFO lpContentsList)
  567. {
  568. LPRECIPIENT_INFO lpItem = lpContentsList;
  569. LV_ITEM lvI = {0};
  570. int index = 0;
  571. if ((!hWndLV) || (!lpContentsList))
  572. return MAPI_E_INVALID_PARAMETER;
  573. lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM ;
  574. lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
  575. lvI.iItem = 0;
  576. while(lpItem)
  577. {
  578. lvI.iImage = GetWABIconImage(lpItem);
  579. lvI.iSubItem = colDisplayName;
  580. lvI.lParam = (LPARAM) lpItem;
  581. lvI.pszText = lpItem->szDisplayName;
  582. index = ListView_InsertItem (hWndLV, &lvI);
  583. if (index != -1)
  584. {
  585. if(lstrlen(lpItem->szOfficePhone))
  586. ListView_SetItemText (hWndLV, index, colOfficePhone, lpItem->szOfficePhone);
  587. if(lstrlen(lpItem->szHomePhone))
  588. ListView_SetItemText (hWndLV, index, colHomePhone, lpItem->szHomePhone);
  589. if(lstrlen(lpItem->szEmailAddress))
  590. ListView_SetItemText (hWndLV, index, colEmailAddress, lpItem->szEmailAddress);
  591. }
  592. lpItem = lpItem->lpNext;
  593. lvI.iItem++;
  594. }
  595. LVSelectItem(hWndLV, 0);
  596. return S_OK;
  597. }
  598. //$$//////////////////////////////////////////////////////////////////////////////
  599. //
  600. // TrimSpaces - strips a string of leading and trailing blanks
  601. //
  602. // szBuf - pointer to buffer containing the string we want to strip spaces off.
  603. //
  604. ////////////////////////////////////////////////////////////////////////////////
  605. BOOL TrimSpaces(TCHAR * szBuf)
  606. {
  607. register LPTSTR lpTemp = szBuf;
  608. if(!szBuf || !lstrlen(szBuf))
  609. return FALSE;
  610. // Trim leading spaces
  611. while (IsSpace(lpTemp)) {
  612. lpTemp = CharNext(lpTemp);
  613. }
  614. if (lpTemp != szBuf) {
  615. // Leading spaces to trim
  616. StrCpyN(szBuf, lpTemp, lstrlen(lpTemp)+1);
  617. lpTemp = szBuf;
  618. }
  619. if (*lpTemp == '\0') {
  620. // empty string
  621. return(TRUE);
  622. }
  623. // Move to the end
  624. lpTemp += lstrlen(lpTemp);
  625. lpTemp--;
  626. // Walk backwards, triming spaces
  627. while (IsSpace(lpTemp) && lpTemp > szBuf) {
  628. *lpTemp = '\0';
  629. lpTemp = CharPrev(szBuf, lpTemp);
  630. }
  631. return(TRUE);
  632. }
  633. //$$/****************************************************************************
  634. /*
  635. * FUNCTION: ListViewSort(LPARAM, LPARAM, LPARAM)
  636. *
  637. * PURPOSE: Callback function that sorts depending on the column click
  638. *
  639. * lParam1, lParam2 - lParam of the elements being compared
  640. * lParamSort - User defined data that identifies the sort criteria
  641. *
  642. ****************************************************************************/
  643. int CALLBACK ListViewSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  644. {
  645. LPRECIPIENT_INFO lp1 = (LPRECIPIENT_INFO)lParam1;
  646. LPRECIPIENT_INFO lp2 = (LPRECIPIENT_INFO)lParam2;
  647. LPTSTR lpStr1, lpStr2, lpF1, lpL1, lpF2, lpL2;
  648. int iResult = 0;
  649. LPSORT_INFO lpSortInfo = (LPSORT_INFO) lParamSort;
  650. if (lp1 && lp2)
  651. {
  652. switch( lpSortInfo->iOldSortCol)
  653. {
  654. case colDisplayName: // sort by Address
  655. lpF1 = lp1->lpByRubyFirstName ? lp1->lpByRubyFirstName : lp1->szByFirstName;
  656. lpL1 = lp1->lpByRubyLastName ? lp1->lpByRubyLastName : lp1->szByLastName;
  657. lpF2 = lp2->lpByRubyFirstName ? lp2->lpByRubyFirstName : lp2->szByFirstName;
  658. lpL2 = lp2->lpByRubyLastName ? lp2->lpByRubyLastName : lp2->szByLastName;
  659. lpStr1 = lpSortInfo->bSortByLastName ? lpL1 : lpF1;
  660. lpStr2 = lpSortInfo->bSortByLastName ? lpL2 : lpF2;
  661. iResult = lstrcmpi(lpStr1, lpStr2);
  662. break;
  663. case colEmailAddress: // sort by Address
  664. lpStr1 = lp1->szEmailAddress;
  665. lpStr2 = lp2->szEmailAddress;
  666. iResult = lstrcmpi(lpStr1, lpStr2);
  667. break;
  668. case colHomePhone: // sort by Address
  669. lpStr1 = lp1->szHomePhone;
  670. lpStr2 = lp2->szHomePhone;
  671. iResult = lstrcmpi(lpStr1, lpStr2);
  672. break;
  673. case colOfficePhone: // sort by Address
  674. lpStr1 = lp1->szOfficePhone;
  675. lpStr2 = lp2->szOfficePhone;
  676. iResult = lstrcmpi(lpStr1, lpStr2);
  677. break;
  678. default:
  679. iResult = 0;
  680. break;
  681. }
  682. }
  683. return(lpSortInfo->bSortAscending ? iResult : -1*iResult);
  684. }
  685. //$$****************************************************************************
  686. /*
  687. * SetColumnHeaderBmp
  688. *
  689. * PURPOSE: Sets the bmp on the ListView Column header to indicate sorting
  690. *
  691. * hWndLV - handle of List View
  692. * SortInfo - The current Sort Information structure. It is used to determine
  693. * where to put the sort header bitmap
  694. ****************************************************************************/
  695. void SetColumnHeaderBmp(HWND hWndLV, SORT_INFO SortInfo)
  696. {
  697. LV_COLUMN lvc = {0};
  698. HIMAGELIST hHeader = NULL;
  699. HWND hWndLVHeader = NULL;
  700. //POINT pt;
  701. // we will try to get the hWnd for the ListView header and set its image lists
  702. //pt.x = 1;
  703. //pt.y = 1;
  704. //hWndLVHeader = ChildWindowFromPoint (hWndLV, pt);
  705. hWndLVHeader = ListView_GetHeader(hWndLV);
  706. // NULL hChildWnd means R-CLICKED outside the listview.
  707. // hChildWnd == ghwndLV means listview got clicked: NOT the
  708. // header.
  709. if ((hWndLVHeader) /*&& (hWndLVHeader != hWndLV)*/)
  710. {
  711. hHeader = (HIMAGELIST) SendMessage(hWndLVHeader,HDM_GETIMAGELIST,0,0);
  712. gpfnImageList_SetBkColor(hHeader, GetSysColor(COLOR_BTNFACE));
  713. SendMessage(hWndLVHeader, HDM_SETIMAGELIST, 0, (LPARAM) hHeader);
  714. }
  715. if (SortInfo.iOlderSortCol != SortInfo.iOldSortCol)
  716. {
  717. //Get rid of image from old column
  718. lvc.mask = LVCF_FMT;
  719. lvc.fmt = LVCFMT_LEFT;
  720. ListView_SetColumn(hWndLV, SortInfo.iOlderSortCol, &lvc);
  721. }
  722. // Set new column icon.
  723. lvc.mask = LVCF_IMAGE | LVCF_FMT;
  724. lvc.fmt = LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
  725. lvc.iImage = SortInfo.bSortAscending ? imageSortAscending : imageSortDescending;
  726. ListView_SetColumn(hWndLV, SortInfo.iOldSortCol, &lvc);
  727. return;
  728. }
  729. //$$//////////////////////////////////////////////////////////////////////////
  730. ///
  731. /// ClearListView - Clears all the list view items and associated contents list
  732. ///
  733. /// hWndLV - list view to clear out
  734. /// lppContentsList - contents list correponding to the contents in the
  735. /// list view
  736. ///
  737. ///////////////////////////////////////////////////////////////////////////////
  738. void ClearListView(HWND hWndLV, LPRECIPIENT_INFO * lppContentsList)
  739. {
  740. /*
  741. LPRECIPIENT_INFO lpItem = *lppContentsList;
  742. int i =0;
  743. int iItemIndex = ListView_GetItemCount(hWndLV);
  744. //OutputDebugString( TEXT("ClearListView entry\n"));
  745. if (iItemIndex <=0 )
  746. goto out;
  747. for(i=0;i<iItemIndex;i++)
  748. {
  749. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, i);
  750. if (lpItem)
  751. {
  752. if(lpItem->lpNext)
  753. lpItem->lpNext->lpPrev = lpItem->lpPrev;
  754. if(lpItem->lpPrev)
  755. lpItem->lpPrev->lpNext = lpItem->lpNext;
  756. if (*lppContentsList == lpItem)
  757. *lppContentsList = lpItem->lpNext;
  758. if (lpItem)
  759. FreeRecipItem(&lpItem);
  760. }
  761. }
  762. ListView_DeleteAllItems(hWndLV);
  763. *lppContentsList = NULL;
  764. out:
  765. //OutputDebugString( TEXT("ClearListView exit\n"));
  766. */
  767. ListView_DeleteAllItems(hWndLV);
  768. FreeRecipList(lppContentsList);
  769. return;
  770. };
  771. //$$//////////////////////////////////////////////////////////////////////
  772. //
  773. // DeleteSelectedItems - Delete all the selected items from the List View
  774. //
  775. // hWndLV -handle of List View
  776. // lpIAB - handle to current AdrBook object - used for certificate stuff
  777. // hPropertyStore - Handle of PropertyStore - <TBD> change this function to
  778. // call deleteEntries instead of delete record.
  779. // lpftLast - WAB file time at last update
  780. //
  781. //////////////////////////////////////////////////////////////////////////
  782. void DeleteSelectedItems(HWND hWndLV, LPADRBOOK lpAdrBook, HANDLE hPropertyStore, LPFILETIME lpftLast)
  783. {
  784. int iItemIndex;
  785. int nSelected;
  786. LV_ITEM LVItem;
  787. HWND hDlg = GetParent(hWndLV);
  788. HRESULT hr = hrSuccess;
  789. ULONG cbWABEID = 0;
  790. LPENTRYID lpWABEID = NULL;
  791. LPABCONT lpWABCont = NULL;
  792. ULONG ulObjType,i=0;
  793. SBinaryArray SBA = {0};
  794. nSelected = ListView_GetSelectedCount(hWndLV);
  795. if (nSelected <= 0)
  796. {
  797. ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEMS_DELETE, MB_ICONEXCLAMATION);
  798. hr = E_FAIL;
  799. goto out;
  800. }
  801. hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID);
  802. if(HR_FAILED(hr))
  803. goto out;
  804. hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  805. cbWABEID, // size of EntryID to open
  806. lpWABEID, // EntryID to open
  807. NULL, // interface
  808. 0, // flags
  809. &ulObjType,
  810. (LPUNKNOWN *)&lpWABCont);
  811. if(HR_FAILED(hr))
  812. goto out;
  813. if (IDYES == ShowMessageBox(hDlg, IDS_ADDRBK_MESSAGE_DELETE, MB_ICONEXCLAMATION | MB_YESNO))
  814. {
  815. int iLastDeletedItemIndex;
  816. BOOL bDeletedItem = FALSE;
  817. DWORD dwLVStyle = 0;
  818. BOOL bWasShowSelAlwaysStyle = FALSE;
  819. HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
  820. ULONG ulCount = 0;
  821. SendMessage(hWndLV, WM_SETREDRAW, FALSE, 0);
  822. // The list view may be set to ShowSelAlways style -
  823. // When deleting, we normally look for the selected entries and
  824. // delete them - but with this style, the list view automatically selects the
  825. // next entry - which is problematic because then we end up deleting that
  826. // one also ... so we need to unset the style now and set it later
  827. dwLVStyle = GetWindowLong(hWndLV,GWL_STYLE);
  828. if( dwLVStyle & LVS_SHOWSELALWAYS)
  829. {
  830. SetWindowLong(hWndLV,GWL_STYLE,dwLVStyle & ~LVS_SHOWSELALWAYS);
  831. bWasShowSelAlwaysStyle = TRUE;
  832. }
  833. if(!(SBA.lpbin = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary)*nSelected)))
  834. goto out;
  835. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  836. do
  837. {
  838. // otherwise get the entry id of this thing
  839. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);
  840. if (lpItem)
  841. {
  842. SetSBinary(&(SBA.lpbin[ulCount]), lpItem->cbEntryID, (LPBYTE)lpItem->lpEntryID);
  843. ulCount++;
  844. }
  845. iLastDeletedItemIndex = iItemIndex;
  846. iItemIndex = ListView_GetNextItem(hWndLV,iItemIndex,LVNI_SELECTED);
  847. }
  848. while (iItemIndex != -1);
  849. SBA.cValues = ulCount;
  850. hr = lpWABCont->lpVtbl->DeleteEntries( lpWABCont, (LPENTRYLIST) &SBA, 0);
  851. // Ideally DeleteEntries will skip over errors silently so we have a dilemma here
  852. // that if there are errors,do we knock out the corresponding items out of the UI or not ..
  853. // For now, lets knock them out of the UI .. when the UI refreshes, this will sort itself out ..
  854. //
  855. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  856. do
  857. {
  858. ListView_DeleteItem(hWndLV,iItemIndex);
  859. iLastDeletedItemIndex = iItemIndex;
  860. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  861. }
  862. while (iItemIndex != -1);
  863. bDeletedItem = TRUE;
  864. /* 33751 - need to fail silently here ..
  865. else
  866. {
  867. ShowMessageBoxParam(hDlg, IDS_ADDRBK_MESSAGE_DELETING_ERROR, MB_ICONERROR, lpItem->szDisplayName);
  868. iLastDeletedItemIndex = iItemIndex;
  869. break;
  870. }
  871. */
  872. // reset the style if we changed it
  873. if(bWasShowSelAlwaysStyle )
  874. SetWindowLong(hWndLV,GWL_STYLE,dwLVStyle);
  875. SetCursor(hOldCur);
  876. // select the previous or next item ...
  877. if (iLastDeletedItemIndex >= ListView_GetItemCount(hWndLV))
  878. iLastDeletedItemIndex = ListView_GetItemCount(hWndLV)-1;
  879. LVSelectItem(hWndLV, iLastDeletedItemIndex);
  880. }
  881. out:
  882. SendMessage(hWndLV, WM_SETREDRAW, TRUE, 0);
  883. if(SBA.lpbin && SBA.cValues)
  884. {
  885. for(i=0;i<SBA.cValues;i++)
  886. LocalFreeAndNull((LPVOID *) (&(SBA.lpbin[i].lpb)));
  887. LocalFreeAndNull(&SBA.lpbin);
  888. }
  889. if(lpWABCont)
  890. UlRelease(lpWABCont);
  891. if(lpWABEID)
  892. FreeBufferAndNull(&lpWABEID);
  893. return;
  894. }
  895. //$$//////////////////////////////////////////////////////////////////////
  896. //
  897. // LoadAllocString - Loads a string resource and allocates enough
  898. // memory to hold it.
  899. //
  900. // StringID - String identifier to load
  901. //
  902. // returns the LocalAlloc'd, null terminated string. Caller is responsible
  903. // for LocalFree'ing this buffer. If the string can't be loaded or memory
  904. // can't be allocated, returns NULL.
  905. //
  906. //////////////////////////////////////////////////////////////////////////
  907. LPTSTR LoadAllocString(int StringID) {
  908. ULONG ulSize = 0;
  909. LPTSTR lpBuffer = NULL;
  910. TCHAR szBuffer[261]; // Big enough? Strings better be smaller than 260!
  911. ulSize = LoadString(hinstMapiX, StringID, szBuffer, ARRAYSIZE(szBuffer));
  912. if (ulSize && (lpBuffer = LocalAlloc(LPTR, sizeof(TCHAR)*(ulSize + 1)))) {
  913. StrCpyN(lpBuffer, szBuffer, ulSize+1);
  914. }
  915. return(lpBuffer);
  916. }
  917. #ifdef VCARD
  918. /***************************************************************************
  919. Name : FormatAllocFilter
  920. Purpose : Loads file filter name string resources and
  921. formats them with their file extension filters
  922. Parameters: StringID1 - String identifier to load (required)
  923. szFilter1 - file name filter, ie, TEXT("*.vcf") (required)
  924. StringID2 - String identifier (optional)
  925. szFilter2 - file name filter (optional)
  926. StringID3 - String identifier (optional)
  927. szFilter3 - file name filter (optional)
  928. Returns : LocalAlloc'd, Double null terminated string. Caller is
  929. responsible for LocalFree'ing this buffer. If the string
  930. can't be loaded or memory can't be allocated, returns NULL.
  931. ***************************************************************************/
  932. LPTSTR FormatAllocFilter(int StringID1, LPCTSTR lpFilter1,
  933. int StringID2, LPCTSTR lpFilter2,
  934. int StringID3, LPCTSTR lpFilter3) {
  935. LPTSTR lpFileType1 = NULL, lpFileType2 = NULL, lpFileType3 = NULL;
  936. LPTSTR lpTemp = NULL;
  937. LPTSTR lpBuffer = NULL;
  938. // All string sizes include null
  939. ULONG cchFileType1 = 0, cchFileType2 = 0, cchFileType3 = 0;
  940. ULONG cchFilter1 = 0, cchFilter2 = 0, cchFilter3 = 0;
  941. ULONG cchBuffer, cchTemp = 0;
  942. cchBuffer = cchFilter1 = (lstrlen(lpFilter1) + 1);
  943. if (! (lpFileType1 = LoadAllocString(StringID1))) {
  944. DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID1);
  945. return(NULL);
  946. }
  947. cchBuffer += (cchFileType1 = (lstrlen(lpFileType1) + 1));
  948. if (lpFilter2 && StringID2) {
  949. cchBuffer += (cchFilter2 = (lstrlen(lpFilter2) + 1));
  950. if (! (lpFileType2 = LoadAllocString(StringID2))) {
  951. DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID2);
  952. } else {
  953. cchBuffer += (cchFileType2 = (lstrlen(lpFileType2) + 1));
  954. }
  955. }
  956. if (lpFilter3 && StringID3) {
  957. cchBuffer += (cchFilter3 = (lstrlen(lpFilter3) + 1));
  958. if (! (lpFileType3 = LoadAllocString(StringID3))) {
  959. DebugTrace( TEXT("LoadAllocString(%u) failed\n"), StringID3);
  960. } else {
  961. cchBuffer += (cchFileType3 = (lstrlen(lpFileType3) + 1));
  962. }
  963. }
  964. cchBuffer += 1; //terminating null
  965. Assert(cchBuffer == cchFilter1 + cchFilter2 + cchFilter3 + cchFileType1 + cchFileType2 + cchFileType3 + 1);
  966. if (lpBuffer = LocalAlloc(LPTR, sizeof(lpBuffer[0])*cchBuffer)) {
  967. lpTemp = lpBuffer;
  968. cchTemp = cchBuffer;
  969. Assert(cchTemp >= cchFileType1);
  970. if (cchTemp >= cchFileType1)
  971. {
  972. StrCpyN(lpTemp, lpFileType1, cchFileType1);
  973. lpTemp += cchFileType1;
  974. cchTemp -= cchFileType1;
  975. Assert(cchTemp >= cchFilter1);
  976. if (cchTemp >= cchFilter1)
  977. {
  978. StrCpyN(lpTemp, lpFilter1, cchFilter1);
  979. lpTemp += cchFilter1;
  980. cchTemp -= cchFilter1;
  981. LocalFree(lpFileType1);
  982. if (cchFileType2 && cchFilter2)
  983. {
  984. Assert(cchTemp >= (cchFileType2 + cchFilter2));
  985. if (cchTemp >= (cchFileType2 + cchFilter2))
  986. {
  987. StrCpyN(lpTemp, lpFileType2, cchFileType2);
  988. lpTemp += cchFileType2;
  989. cchTemp -= cchFileType2;
  990. StrCpyN(lpTemp, lpFilter2, cchFilter2);
  991. lpTemp += cchFilter2;
  992. cchTemp -= cchFilter2;
  993. LocalFree(lpFileType2);
  994. }
  995. }
  996. if (cchFileType3 && cchFilter3)
  997. {
  998. Assert(cchTemp >= (cchFileType3 + cchFilter3));
  999. if (cchTemp >= (cchFileType3 + cchFilter3))
  1000. {
  1001. StrCpyN(lpTemp, lpFileType3, cchFileType3);
  1002. lpTemp += cchFileType3;
  1003. cchTemp -= cchFileType3;
  1004. StrCpyN(lpTemp, lpFilter3, cchFilter3);
  1005. lpTemp += cchFilter3;
  1006. cchTemp -= cchFilter3;
  1007. LocalFree(lpFileType3);
  1008. }
  1009. }
  1010. }
  1011. }
  1012. }
  1013. if (lpTemp)
  1014. {
  1015. if ((cchTemp >0) && (cchTemp < cchBuffer)) // ensure we have room and didn't wrap
  1016. *lpTemp = '\0';
  1017. else
  1018. {
  1019. Assert(FALSE);
  1020. LocalFree(lpBuffer);
  1021. lpBuffer = NULL;
  1022. }
  1023. }
  1024. return(lpBuffer);
  1025. }
  1026. const LPTSTR szVCardFilter = TEXT("*.vcf");
  1027. /***************************************************************************
  1028. Name : VCardCreate
  1029. Purpose : Creates a vCard file from the given Mailuser and filename
  1030. Parameters: hwnd = hwndParent
  1031. lpIAB -> IAddrBook object,
  1032. ulFlags can be 0 or MAPI_DIALOG - MAPI_DIALOG means report
  1033. error messages in a dialog box, else
  1034. work silently ..
  1035. lpszFileNAme - vCard file name to create
  1036. lpMailUser - object to create vCard file from
  1037. Returns : HRESULT
  1038. Comment :
  1039. ***************************************************************************/
  1040. HRESULT VCardCreate( LPADRBOOK lpAdrBook,
  1041. HWND hWndParent,
  1042. ULONG ulFlags,
  1043. LPTSTR lpszFileName,
  1044. LPMAILUSER lpMailUser)
  1045. {
  1046. HRESULT hr = E_FAIL;
  1047. HANDLE hVCard = NULL;
  1048. if (INVALID_HANDLE_VALUE == (hVCard = CreateFile( lpszFileName,
  1049. GENERIC_WRITE,
  1050. 0, // sharing
  1051. NULL,
  1052. CREATE_ALWAYS,
  1053. FILE_FLAG_SEQUENTIAL_SCAN,
  1054. NULL)))
  1055. {
  1056. if(ulFlags & MAPI_DIALOG)
  1057. {
  1058. ShowMessageBoxParam(hWndParent,
  1059. IDE_VCARD_EXPORT_FILE_ERROR,
  1060. MB_ICONERROR,
  1061. lpszFileName);
  1062. }
  1063. goto out;
  1064. }
  1065. if (hr = WriteVCard(hVCard, FileWriteFn, lpMailUser))
  1066. {
  1067. switch (GetScode(hr))
  1068. {
  1069. case WAB_E_VCARD_NOT_ASCII:
  1070. if(ulFlags & MAPI_DIALOG)
  1071. {
  1072. ShowMessageBoxParam(hWndParent,
  1073. IDS_VCARD_EXPORT_NOT_ASCII,
  1074. MB_ICONEXCLAMATION,
  1075. lpszFileName);
  1076. }
  1077. CloseHandle(hVCard);
  1078. hVCard = NULL;
  1079. DeleteFile(lpszFileName);
  1080. hr = E_FAIL;
  1081. break;
  1082. default:
  1083. if(ulFlags & MAPI_DIALOG)
  1084. {
  1085. ShowMessageBoxParam(hWndParent,
  1086. IDE_VCARD_EXPORT_FILE_ERROR,
  1087. MB_ICONERROR,
  1088. lpszFileName);
  1089. }
  1090. break;
  1091. }
  1092. }
  1093. out:
  1094. if (hVCard)
  1095. CloseHandle(hVCard);
  1096. return hr;
  1097. }
  1098. //$$//////////////////////////////////////////////////////////////////////
  1099. //
  1100. // VCardExportSelectedItems - Export all the selected items from the List View
  1101. // to vCard files.
  1102. //
  1103. // hWndLV - handle of List view. We look up the selected item in this list
  1104. // view, get its lParam structure, then get its EntryID and
  1105. // call details
  1106. // lpIAB - handle to current AdrBook object - used for calling details
  1107. //
  1108. //////////////////////////////////////////////////////////////////////////
  1109. HRESULT VCardExportSelectedItems(HWND hWndLV, LPADRBOOK lpAdrBook)
  1110. {
  1111. HRESULT hr = E_FAIL;
  1112. int iItemIndex;
  1113. HWND hWndParent = GetParent(hWndLV);
  1114. HANDLE hVCard = NULL;
  1115. OPENFILENAME ofn;
  1116. LPMAILUSER lpEntry = NULL;
  1117. LPTSTR lpFilter = NULL;
  1118. TCHAR szFileName[MAX_PATH + 1] = TEXT("");
  1119. LPTSTR lpTitle = NULL;
  1120. LPTSTR lpTitleFormat = NULL;
  1121. ULONG ulObjType;
  1122. LPTSTR lpszArg[1];
  1123. TCHAR szTmp[MAX_PATH];
  1124. // Open props if only 1 item is selected
  1125. iItemIndex = ListView_GetSelectedCount(hWndLV);
  1126. if (iItemIndex == 1)
  1127. {
  1128. // Get index of selected item
  1129. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  1130. if (iItemIndex != -1)
  1131. {
  1132. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  1133. if(lpItem && lpItem->cbEntryID != 0)
  1134. {
  1135. StrCpyN(szFileName, lpItem->szDisplayName, ARRAYSIZE(szFileName));
  1136. TrimIllegalFileChars(szFileName);
  1137. if(lstrlen(szFileName))
  1138. StrCatBuff(szFileName, TEXT(".vcf"), ARRAYSIZE(szFileName));
  1139. if (hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  1140. lpItem->cbEntryID,
  1141. lpItem->lpEntryID,
  1142. NULL, // interface
  1143. 0, // flags
  1144. &ulObjType,
  1145. (LPUNKNOWN *)&lpEntry))
  1146. {
  1147. DebugTraceResult( TEXT("VCardExportSelectedItems:OpenEntry"), hr);
  1148. goto exit;
  1149. }
  1150. if (ulObjType == MAPI_DISTLIST)
  1151. {
  1152. ShowMessageBox(hWndParent, IDE_VCARD_EXPORT_DISTLIST, MB_ICONEXCLAMATION);
  1153. goto exit;
  1154. }
  1155. lpFilter = FormatAllocFilter(IDS_VCARD_FILE_SPEC, szVCardFilter, 0, NULL, 0, NULL);
  1156. lpTitleFormat = LoadAllocString(IDS_VCARD_EXPORT_TITLE);
  1157. // Win9x bug FormatMessage cannot have more than 1023 chars
  1158. CopyTruncate(szTmp, lpItem->szDisplayName, MAX_PATH - 1);
  1159. lpszArg[0] = szTmp;
  1160. if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  1161. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1162. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1163. lpTitleFormat,
  1164. 0, // stringid
  1165. 0, // dwLanguageId
  1166. (LPTSTR)&lpTitle, // output buffer
  1167. 0, //MAX_UI_STR
  1168. (va_list *)lpszArg))
  1169. {
  1170. DebugTrace( TEXT("FormatMessage -> %u\n"), GetLastError());
  1171. }
  1172. ofn.lStructSize = sizeof(ofn);
  1173. ofn.hwndOwner = hWndParent;
  1174. ofn.hInstance = hinstMapiX;
  1175. ofn.lpstrFilter = lpFilter;
  1176. ofn.lpstrCustomFilter = NULL;
  1177. ofn.nMaxCustFilter = 0;
  1178. ofn.nFilterIndex = 0;
  1179. ofn.lpstrFile = szFileName;
  1180. ofn.nMaxFile = ARRAYSIZE(szFileName);
  1181. ofn.lpstrFileTitle = NULL;
  1182. ofn.nMaxFileTitle = 0;
  1183. ofn.lpstrInitialDir = NULL;
  1184. ofn.lpstrTitle = lpTitle;
  1185. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
  1186. ofn.nFileOffset = 0;
  1187. ofn.nFileExtension = 0;
  1188. ofn.lpstrDefExt = TEXT("vcf");
  1189. ofn.lCustData = 0;
  1190. ofn.lpfnHook = NULL;
  1191. ofn.lpTemplateName = NULL;
  1192. if (GetSaveFileName(&ofn))
  1193. {
  1194. //Check if file already exists ..
  1195. if(0xFFFFFFFF != GetFileAttributes(szFileName))
  1196. {
  1197. // Ask user if they want to overwrite
  1198. if(IDNO == ShowMessageBoxParam(hWndParent,
  1199. IDE_VCARD_EXPORT_FILE_EXISTS,
  1200. MB_ICONEXCLAMATION | MB_YESNO | MB_SETFOREGROUND,
  1201. szFileName))
  1202. {
  1203. hr = MAPI_E_USER_CANCEL;
  1204. goto exit;
  1205. }
  1206. }
  1207. // Go ahead and overwrite the file if user said yes..
  1208. if(hr = VCardCreate(lpAdrBook,
  1209. hWndParent,
  1210. MAPI_DIALOG,
  1211. szFileName,
  1212. lpEntry))
  1213. {
  1214. goto exit;
  1215. }
  1216. } // if GetSaveFileName...
  1217. } // if (lpItem->cbEntryID)...
  1218. }
  1219. } else {
  1220. if (iItemIndex <= 0) {
  1221. // nothing selected
  1222. ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
  1223. } else {
  1224. //multiple selected
  1225. ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_ACTION, MB_ICONEXCLAMATION);
  1226. }
  1227. hr = E_FAIL;
  1228. goto exit;
  1229. }
  1230. hr = S_OK;
  1231. exit:
  1232. UlRelease(lpEntry);
  1233. LocalFreeAndNull(&lpFilter);
  1234. LocalFree(lpTitleFormat);
  1235. if(lpTitle)
  1236. LocalFree(lpTitle);
  1237. return(hr);
  1238. }
  1239. /***************************************************************************
  1240. Name : VCardRetrive
  1241. Purpose : Retrieves a MailUser object from a given file name
  1242. Parameters: hwnd = hwndParent
  1243. lpIAB -> IAddrBook object,
  1244. ulFlags can be 0 or MAPI_DIALOG - MAPI_DIALOG means report
  1245. error messages in a dialog box, else
  1246. work silently ..
  1247. lpszFileNAme - vCard file name (file must exist)
  1248. lpszBuf - a memory buffer containing the vCard file
  1249. which can be specified instead of the filename
  1250. Must be a null terminated string
  1251. lppMailUser, returned MailUser ...
  1252. Returns : HRESULT
  1253. Comment :
  1254. ***************************************************************************/
  1255. HRESULT VCardRetrieve(LPADRBOOK lpAdrBook,
  1256. HWND hWndParent,
  1257. ULONG ulFlags,
  1258. LPTSTR lpszFileName,
  1259. LPSTR lpszBuf,
  1260. LPMAILUSER * lppMailUser)
  1261. {
  1262. HRESULT hResult = E_FAIL;
  1263. HANDLE hFile = NULL;
  1264. LPSTR lpBuf = NULL;
  1265. SBinary sb = {0};
  1266. LPMAILUSER lpMailUser = NULL;
  1267. // We will convert the vCard to a memory buffer and parse that buffer as needed
  1268. // Somewhere in the buffer we need to track how much of the buffer has already
  1269. // been parsed .. we'll polymorph a SBinary struct here so we can use the cb param
  1270. // to track how much buffer has been parsed and the lpb to store the buffer
  1271. SBinary buf = {0};
  1272. if(!VCardGetBuffer(lpszFileName, lpszBuf, &lpBuf))
  1273. {
  1274. if(ulFlags & MAPI_DIALOG)
  1275. {
  1276. // couldn't open file.
  1277. ShowMessageBoxParam(hWndParent, IDE_VCARD_IMPORT_FILE_ERROR,
  1278. MB_ICONEXCLAMATION, lpszFileName);
  1279. }
  1280. goto out;
  1281. }
  1282. if(hResult = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &sb.cb, (LPENTRYID *)&sb.lpb))
  1283. goto out;
  1284. if (hResult = HrCreateNewObject( lpAdrBook, &sb,
  1285. MAPI_MAILUSER,
  1286. CREATE_CHECK_DUP_STRICT,
  1287. (LPMAPIPROP *) &lpMailUser))
  1288. {
  1289. goto out;
  1290. }
  1291. buf.cb = 0;
  1292. buf.lpb = (LPBYTE) lpBuf;
  1293. //if (hResult = ReadVCard(hFile, FileReadFn, *lppMailUser))
  1294. if (hResult = ReadVCard((HANDLE) &buf, BufferReadFn, lpMailUser))
  1295. {
  1296. if(ulFlags & MAPI_DIALOG)
  1297. {
  1298. switch (GetScode(hResult))
  1299. {
  1300. case MAPI_E_INVALID_OBJECT:
  1301. ShowMessageBoxParam(hWndParent,
  1302. IDE_VCARD_IMPORT_FILE_BAD,
  1303. MB_ICONEXCLAMATION,
  1304. lpszFileName);
  1305. goto out;
  1306. default:
  1307. ShowMessageBoxParam(hWndParent,
  1308. IDE_VCARD_IMPORT_PARTIAL,
  1309. MB_ICONEXCLAMATION,
  1310. lpszFileName);
  1311. break;
  1312. }
  1313. }
  1314. }
  1315. out:
  1316. if(lpBuf)
  1317. LocalFree(lpBuf);
  1318. if(sb.lpb)
  1319. MAPIFreeBuffer(sb.lpb);
  1320. if(lpMailUser)
  1321. {
  1322. if(HR_FAILED(hResult))
  1323. lpMailUser->lpVtbl->Release(lpMailUser);
  1324. else
  1325. *lppMailUser = lpMailUser;
  1326. }
  1327. return hResult;
  1328. }
  1329. /***************************************************************************
  1330. Name : VCardImport
  1331. Purpose : Reads a vCard from a file to a new MAILUSER object.
  1332. Parameters: hwnd = hwnd
  1333. lpIAB -> IAddrBook object
  1334. szVCardFile - name of the file to import if we already know it
  1335. in which case there is no OpenFileName dialog
  1336. The entryids of the newly added objects are added to the
  1337. SPropValue which is a dummy prop of type MV_BINARY
  1338. Returns : HRESULT
  1339. Comment :
  1340. ***************************************************************************/
  1341. HRESULT VCardImport(HWND hWnd, LPADRBOOK lpAdrBook, LPTSTR szVCardFile, LPSPropValue * lppProp)
  1342. {
  1343. HRESULT hResult = hrSuccess;
  1344. OPENFILENAME ofn;
  1345. LPTSTR lpFilter = FormatAllocFilter(IDS_VCARD_FILE_SPEC, szVCardFilter, 0, NULL, 0, NULL);
  1346. TCHAR szFileName[MAX_PATH + 1] = TEXT("");
  1347. HANDLE hFile = NULL;
  1348. ULONG ulObjType;
  1349. ULONG cProps;
  1350. LPMAILUSER lpMailUser = NULL, lpMailUserNew = NULL;
  1351. ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
  1352. BOOL bChangesMade = FALSE;
  1353. LPSPropValue lpspvEID = NULL;
  1354. LPSTR lpBuf = NULL, lpVCardStart = NULL;
  1355. LPSTR lpVCard = NULL, lpNext = NULL;
  1356. LPSPropValue lpProp = NULL;
  1357. ofn.lStructSize = sizeof(ofn);
  1358. ofn.hwndOwner = hWnd;
  1359. ofn.hInstance = hinstMapiX;
  1360. ofn.lpstrFilter = lpFilter;
  1361. ofn.lpstrCustomFilter = NULL;
  1362. ofn.nMaxCustFilter = 0;
  1363. ofn.nFilterIndex = 0;
  1364. ofn.lpstrFile = szFileName;
  1365. ofn.nMaxFile = ARRAYSIZE(szFileName);
  1366. ofn.lpstrFileTitle = NULL;
  1367. ofn.nMaxFileTitle = 0;
  1368. ofn.lpstrInitialDir = NULL;
  1369. ofn.lpstrTitle = LoadAllocString(IDS_VCARD_IMPORT_TITLE);
  1370. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  1371. ofn.nFileOffset = 0;
  1372. ofn.nFileExtension = 0;
  1373. ofn.lpstrDefExt = TEXT("vcf");
  1374. ofn.lCustData = 0;
  1375. ofn.lpfnHook = NULL;
  1376. ofn.lpTemplateName = NULL;
  1377. if(szVCardFile && lstrlen(szVCardFile))
  1378. StrCpyN(szFileName, szVCardFile, ARRAYSIZE(szFileName));
  1379. else
  1380. if (!GetOpenFileName(&ofn))
  1381. goto exit;
  1382. if(lstrlen(szFileName))
  1383. {
  1384. if(!VCardGetBuffer(szFileName, NULL, &lpBuf))
  1385. {
  1386. // couldn't open file.
  1387. ShowMessageBoxParam(hWnd, IDE_VCARD_IMPORT_FILE_ERROR, MB_ICONEXCLAMATION, szFileName);
  1388. goto exit;
  1389. }
  1390. lpVCardStart = lpBuf;
  1391. // Loop through showing all the nested vCards one by one ..
  1392. while(VCardGetNextBuffer(lpVCardStart, &lpVCard, &lpNext) && lpVCard)
  1393. {
  1394. if(!HR_FAILED( hResult = VCardRetrieve( lpAdrBook, hWnd, MAPI_DIALOG, szFileName, lpVCard, &lpMailUser)))
  1395. {
  1396. if (!HR_FAILED(hResult = HrShowDetails(lpAdrBook, hWnd, NULL, 0, NULL, NULL, NULL,
  1397. (LPMAPIPROP)lpMailUser, SHOW_OBJECT, MAPI_MAILUSER, &bChangesMade)))
  1398. {
  1399. if (hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READONLY))
  1400. {
  1401. switch(hResult)
  1402. {
  1403. case MAPI_E_COLLISION:
  1404. {
  1405. LPSPropValue lpspv1 = NULL, lpspv2 = NULL;
  1406. if (! (hResult = HrGetOneProp((LPMAPIPROP)lpMailUser, PR_DISPLAY_NAME, &lpspv1)))
  1407. {
  1408. switch (ShowMessageBoxParam(hWnd, IDS_VCARD_IMPORT_COLLISION, MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_APPLMODAL | MB_SETFOREGROUND, lpspv1->Value.LPSZ, szFileName))
  1409. {
  1410. case IDYES:
  1411. // Yes, replace
  1412. // Create a new one with the right flags, copy the old one's props and save.
  1413. ulCreateFlags |= ( CREATE_REPLACE | CREATE_MERGE );
  1414. if(!HR_FAILED(hResult = HrCreateNewObject(lpAdrBook, ((LPMailUser)lpMailUser)->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, (LPMAPIPROP *)&lpMailUserNew)))
  1415. {
  1416. if (!HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,NULL,MAPI_UNICODE,&cProps,&lpspv2)))
  1417. {
  1418. if (!HR_FAILED(hResult = lpMailUserNew->lpVtbl->SetProps(lpMailUserNew,cProps,lpspv2,NULL)))
  1419. {
  1420. hResult = lpMailUserNew->lpVtbl->SaveChanges(lpMailUserNew,KEEP_OPEN_READONLY);
  1421. }
  1422. }
  1423. }
  1424. break;
  1425. case IDCANCEL:
  1426. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  1427. break; // no, don't replace
  1428. default:
  1429. hResult = E_FAIL;
  1430. break;
  1431. }
  1432. }
  1433. FreeBufferAndNull(&lpspv1);
  1434. FreeBufferAndNull(&lpspv2);
  1435. }
  1436. break;
  1437. case MAPI_E_NOT_ENOUGH_DISK:
  1438. hResult = HandleSaveChangedInsufficientDiskSpace(hWnd, lpMailUser);
  1439. break;
  1440. default:
  1441. if(HR_FAILED(hResult))
  1442. ShowMessageBoxParam(hWnd, IDE_VCARD_IMPORT_FILE_BAD, MB_ICONEXCLAMATION, szFileName);
  1443. break;
  1444. }
  1445. }
  1446. }
  1447. }
  1448. if(!lpProp && !HR_FAILED(hResult))
  1449. {
  1450. SCODE sc;
  1451. if(sc = MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpProp))
  1452. {
  1453. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  1454. goto exit;
  1455. }
  1456. lpProp->ulPropTag = PR_WAB_DL_ENTRIES; // Doesnt matter what we set this to as long as its MV_BINARY
  1457. lpProp->Value.MVbin.cValues = 0;
  1458. lpProp->Value.MVbin.lpbin = NULL;
  1459. }
  1460. if(lpProp && !HR_FAILED(hResult))
  1461. {
  1462. LPMAILUSER lpMU = (lpMailUserNew) ? lpMailUserNew : lpMailUser;
  1463. if (! (hResult = HrGetOneProp((LPMAPIPROP)lpMU, PR_ENTRYID, &lpspvEID)))
  1464. {
  1465. AddPropToMVPBin(lpProp, 0 , lpspvEID->Value.bin.lpb, lpspvEID->Value.bin.cb, TRUE);
  1466. FreeBufferAndNull(&lpspvEID);
  1467. }
  1468. }
  1469. if(lpMailUserNew)
  1470. lpMailUserNew->lpVtbl->Release(lpMailUserNew);
  1471. if(lpMailUser)
  1472. lpMailUser->lpVtbl->Release(lpMailUser);
  1473. lpMailUser = NULL;
  1474. lpMailUserNew = NULL;
  1475. if(hResult == MAPI_E_USER_CANCEL)
  1476. break;
  1477. lpVCard = NULL;
  1478. lpVCardStart = lpNext;
  1479. }
  1480. } // getopenfilename ...
  1481. *lppProp = lpProp;
  1482. exit:
  1483. LocalFreeAndNull(&lpBuf);
  1484. LocalFree(lpFilter);
  1485. LocalFree((LPVOID)ofn.lpstrTitle);
  1486. if (hFile)
  1487. CloseHandle(hFile);
  1488. if(lpMailUser)
  1489. UlRelease(lpMailUser);
  1490. if(lpMailUserNew)
  1491. UlRelease(lpMailUserNew);
  1492. return(hResult);
  1493. }
  1494. #endif
  1495. //$$//////////////////////////////////////////////////////////////////////
  1496. // HrShowLVEntryProperties
  1497. //
  1498. // Shows the properties of an entry in the list view ...
  1499. // Assumes that all list views are based on lpRecipientInfo Structures
  1500. //
  1501. // hWndLV - handle of List view. We look up the selected item in this list
  1502. // view, get its lParam structure, then get its EntryID and
  1503. // call details
  1504. // lpIAB - handle to current AdrBook object - used for calling details
  1505. // lpftLast - WAB file time at last update
  1506. //
  1507. // Returns:MAPI_E_USER_CANCEL on cancel
  1508. // MAPI_E_OBJECT_CHANGED if object was modified
  1509. // S_OK if no changes and nothing modified
  1510. //////////////////////////////////////////////////////////////////////////
  1511. HRESULT HrShowLVEntryProperties(HWND hWndLV, ULONG ulFlags, LPADRBOOK lpAdrBook, LPFILETIME lpftLast)
  1512. {
  1513. HRESULT hr = E_FAIL;
  1514. int iItemIndex;
  1515. HWND hWndParent = GetParent(hWndLV);
  1516. LPRECIPIENT_INFO lpNewItem=NULL;
  1517. // Open props if only 1 item is selected
  1518. iItemIndex = ListView_GetSelectedCount(hWndLV);
  1519. if (iItemIndex == 1)
  1520. {
  1521. // Get index of selected item
  1522. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  1523. if (iItemIndex != -1)
  1524. {
  1525. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  1526. if(lpItem && lpItem->cbEntryID != 0)
  1527. {
  1528. hr = lpAdrBook->lpVtbl->Details(lpAdrBook,
  1529. (PULONG_PTR) &hWndParent, // ulUIParam
  1530. NULL,
  1531. NULL,
  1532. lpItem->cbEntryID,
  1533. lpItem->lpEntryID,
  1534. NULL,
  1535. NULL,
  1536. NULL,
  1537. ulFlags);
  1538. // if details changed something - our event and semaphores should
  1539. // notify us so we can update ourselves from the property store or
  1540. // whatever ...
  1541. // this is TBD - at this point there is no way to refresh anything ..
  1542. if(HR_FAILED(hr))
  1543. {
  1544. goto out;
  1545. }
  1546. else //if(!HR_FAILED(hr))
  1547. {
  1548. //Open the item again and compare its UI props to see
  1549. //if anything changed ...
  1550. if(0 != IsWABEntryID(lpItem->cbEntryID,
  1551. lpItem->lpEntryID,
  1552. NULL, NULL, NULL, NULL, NULL))
  1553. {
  1554. // <TBD> the above test may not be good enough ..
  1555. // we really need to check if its a wab entryid ..
  1556. //
  1557. // This is not a WAB entry ID
  1558. // For now assume this is a read only contact and so
  1559. // we dont need to check it again for changes
  1560. //
  1561. goto out;
  1562. }
  1563. if(!ReadSingleContentItem( lpAdrBook,
  1564. lpItem->cbEntryID,
  1565. lpItem->lpEntryID,
  1566. &lpNewItem))
  1567. goto out;
  1568. // Compare the new item with the old item
  1569. // If anything changed, we need to update the item in the list view
  1570. if (lstrcmp(lpItem->szDisplayName,lpNewItem->szDisplayName))
  1571. {
  1572. hr = MAPI_E_OBJECT_CHANGED;
  1573. ListView_SetItemText(hWndLV,iItemIndex,colDisplayName,lpNewItem->szDisplayName);
  1574. StrCpyN(lpItem->szDisplayName,lpNewItem->szDisplayName,ARRAYSIZE(lpItem->szDisplayName));
  1575. }
  1576. if (lstrcmp(lpItem->szEmailAddress,lpNewItem->szEmailAddress))
  1577. {
  1578. hr = MAPI_E_OBJECT_CHANGED;
  1579. ListView_SetItemText(hWndLV,iItemIndex,colEmailAddress,lpNewItem->szEmailAddress);
  1580. StrCpyN(lpItem->szEmailAddress,lpNewItem->szEmailAddress,ARRAYSIZE(lpItem->szEmailAddress));
  1581. }
  1582. if (lstrcmp(lpItem->szHomePhone,lpNewItem->szHomePhone))
  1583. {
  1584. hr = MAPI_E_OBJECT_CHANGED;
  1585. ListView_SetItemText(hWndLV,iItemIndex,colHomePhone,lpNewItem->szHomePhone);
  1586. StrCpyN(lpItem->szHomePhone,lpNewItem->szHomePhone,ARRAYSIZE(lpItem->szHomePhone));
  1587. }
  1588. if (lstrcmp(lpItem->szOfficePhone,lpNewItem->szOfficePhone))
  1589. {
  1590. hr = MAPI_E_OBJECT_CHANGED;
  1591. ListView_SetItemText(hWndLV,iItemIndex,colOfficePhone,lpNewItem->szOfficePhone);
  1592. StrCpyN(lpItem->szOfficePhone,lpNewItem->szOfficePhone,ARRAYSIZE(lpItem->szOfficePhone));
  1593. }
  1594. if (lstrcmp(lpItem->szByLastName,lpNewItem->szByLastName))
  1595. {
  1596. hr = MAPI_E_OBJECT_CHANGED;
  1597. StrCpyN(lpItem->szByLastName,lpNewItem->szByLastName,ARRAYSIZE(lpItem->szByLastName));
  1598. }
  1599. if (lstrcmp(lpItem->szByFirstName,lpNewItem->szByFirstName))
  1600. {
  1601. hr = MAPI_E_OBJECT_CHANGED;
  1602. StrCpyN(lpItem->szByFirstName,lpNewItem->szByFirstName,ARRAYSIZE(lpItem->szByFirstName));
  1603. }
  1604. {
  1605. LVITEM lvI = {0};
  1606. lvI.mask = LVIF_IMAGE;
  1607. lvI.iItem = iItemIndex;
  1608. lvI.iSubItem = 0;
  1609. lpItem->bHasCert = lpNewItem->bHasCert;
  1610. lpItem->bIsMe = lpNewItem->bIsMe;
  1611. lvI.iImage = GetWABIconImage(lpItem);
  1612. ListView_SetItem(hWndLV, &lvI);
  1613. }
  1614. // Update the wab file write time so the timer doesn't
  1615. // catch this change and refresh.
  1616. //if (lpftLast &&
  1617. // lpItem->ulObjectType == MAPI_MAILUSER) // refresh for distlists not for mailusers (because distlists can cause further modifications)
  1618. //{
  1619. // CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
  1620. //}
  1621. }
  1622. }
  1623. }
  1624. }
  1625. else
  1626. {
  1627. if (iItemIndex <= 0)
  1628. {
  1629. // nothing selected
  1630. ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
  1631. }
  1632. else
  1633. {
  1634. //multiple selected
  1635. ShowMessageBox(GetParent(hWndLV), IDS_ADDRBK_MESSAGE_ACTION, MB_ICONEXCLAMATION);
  1636. }
  1637. hr = E_FAIL;
  1638. goto out;
  1639. }
  1640. out:
  1641. if(hr == MAPI_E_NOT_FOUND)
  1642. ShowMessageBox(GetParent(hWndLV), idsEntryNotFound, MB_OK | MB_ICONEXCLAMATION);
  1643. if(lpNewItem)
  1644. FreeRecipItem(&lpNewItem);
  1645. return hr;
  1646. }
  1647. //$$//////////////////////////////////////////////////////////////////////
  1648. //
  1649. // LVSelectItem - Selects a list view item and ensures it is visible
  1650. //
  1651. // hWndList - handle of list view control
  1652. // iItemIndex - index of item to select
  1653. //
  1654. ////////////////////////////////////////////////////////////////////////
  1655. void LVSelectItem(HWND hWndList, int iItemIndex)
  1656. {
  1657. DWORD dwStyle;
  1658. // Hopefully, we only want to select a single item
  1659. // So we cheat by making the ListView single select and
  1660. // set our item, reseting everything else
  1661. dwStyle = GetWindowLong(hWndList, GWL_STYLE);
  1662. SetWindowLong(hWndList, GWL_STYLE, dwStyle | LVS_SINGLESEL);
  1663. ListView_SetItemState ( hWndList, // handle to listview
  1664. iItemIndex, // index to listview item
  1665. LVIS_FOCUSED | LVIS_SELECTED, // item state
  1666. LVIS_FOCUSED | LVIS_SELECTED); // mask
  1667. ListView_EnsureVisible (hWndList, // handle to listview
  1668. iItemIndex,
  1669. FALSE);
  1670. //reset back to the original style ..
  1671. SetWindowLong(hWndList, GWL_STYLE, dwStyle);
  1672. return;
  1673. }
  1674. //$$//////////////////////////////////////////////////////////////////////////////
  1675. ///
  1676. /// AddWABEntryToListView - Adds a wab entry to a list view given a entryid
  1677. ///
  1678. /// lpIAB - handle to AdrBook object
  1679. /// hWndLV - list view of interest
  1680. /// lpEID - EntryID of entry. Assumes size of entryid is WAB_ENTRY_ID
  1681. /// lppContentsList - List into which the entry is also linked
  1682. ///
  1683. ///
  1684. ////////////////////////////////////////////////////////////////////////////////
  1685. BOOL AddWABEntryToListView( LPADRBOOK lpAdrBook,
  1686. HWND hWndLV,
  1687. ULONG cbEID,
  1688. LPENTRYID lpEID,
  1689. LPRECIPIENT_INFO * lppContentsList)
  1690. {
  1691. BOOL bRet = FALSE;
  1692. LPRECIPIENT_INFO lpItem = NULL;
  1693. LV_ITEM lvi = {0};
  1694. int index = 0;
  1695. if (!lpEID)
  1696. goto out;
  1697. if (!ReadSingleContentItem( lpAdrBook, cbEID, lpEID, &lpItem))
  1698. goto out;
  1699. AddSingleItemToListView(hWndLV, lpItem);
  1700. //we added to the end - so this is the last item
  1701. //select it ...
  1702. index = ListView_GetItemCount(hWndLV);
  1703. LVSelectItem(hWndLV, index-1);
  1704. //
  1705. // Hook in the lpItem into the lpContentsList so we can free it later
  1706. //
  1707. lpItem->lpPrev = NULL;
  1708. lpItem->lpNext = *lppContentsList;
  1709. if (*lppContentsList)
  1710. (*lppContentsList)->lpPrev = lpItem;
  1711. (*lppContentsList) = lpItem;
  1712. bRet = TRUE;
  1713. out:
  1714. if (!bRet && lpItem)
  1715. FreeRecipItem(&lpItem);
  1716. return bRet;
  1717. }
  1718. //$$////////////////////////////////////////////////////////////////////////////
  1719. //
  1720. // AddSingleItemToListView - Takes a single lpItem and adds it to alist view
  1721. //
  1722. // hWndLV - handle of List View
  1723. // lpItem - Recipient Info corresponding to a single entry
  1724. //
  1725. //////////////////////////////////////////////////////////////////////////////
  1726. void AddSingleItemToListView(HWND hWndLV, LPRECIPIENT_INFO lpItem)
  1727. {
  1728. LV_ITEM lvI = {0};
  1729. int index = 0;
  1730. // Add just a single item ...
  1731. lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM ;
  1732. lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
  1733. lvI.iImage = GetWABIconImage(lpItem);
  1734. lvI.iItem = ListView_GetItemCount(hWndLV);
  1735. lvI.iSubItem = colDisplayName;
  1736. lvI.lParam = (LPARAM) lpItem;
  1737. lvI.pszText = lpItem->szDisplayName;
  1738. index = ListView_InsertItem (hWndLV, &lvI);
  1739. if (index == -1)
  1740. {
  1741. DebugPrintError(( TEXT("ListView_InsertItem Failed\n")));
  1742. goto out;
  1743. }
  1744. // TBD - this is assuming that all the fields exist and are filled in
  1745. if(lstrlen(lpItem->szOfficePhone))
  1746. ListView_SetItemText (hWndLV, index, colOfficePhone, lpItem->szOfficePhone);
  1747. if(lstrlen(lpItem->szHomePhone))
  1748. ListView_SetItemText (hWndLV, index, colHomePhone, lpItem->szHomePhone);
  1749. if(lstrlen(lpItem->szEmailAddress))
  1750. ListView_SetItemText (hWndLV, index, colEmailAddress, lpItem->szEmailAddress);
  1751. out:
  1752. return;
  1753. }
  1754. //$$////////////////////////////////////////////////////////////////////////////
  1755. //
  1756. // ReadSingeContentItem - reads a specified record from the prop store
  1757. // and creates a single pointer item for the Address Linked list and
  1758. // content window.
  1759. //
  1760. // lpIAB - pointer to AdrBook Object
  1761. // cbEntryID - EntryID byte count of object of interest
  1762. // lpEntryID - EntryID of object of interest
  1763. // lppItem - returned lppItem
  1764. //
  1765. //////////////////////////////////////////////////////////////////////////////
  1766. BOOL ReadSingleContentItem( LPADRBOOK lpAdrBook,
  1767. ULONG cbEntryID,
  1768. LPENTRYID lpEntryID,
  1769. LPRECIPIENT_INFO * lppItem)
  1770. {
  1771. LPSPropValue lpPropArray = NULL;
  1772. ULONG ulcProps = 0;
  1773. ULONG nLen = 0;
  1774. ULONG i = 0;
  1775. BOOL bDisplayNameSet = FALSE;
  1776. BOOL bEmailAddressSet = FALSE;
  1777. BOOL bRet = FALSE;
  1778. (*lppItem) = LocalAlloc(LMEM_ZEROINIT,sizeof(RECIPIENT_INFO));
  1779. if(!(*lppItem))
  1780. {
  1781. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1782. goto out;
  1783. }
  1784. (*lppItem)->lpNext = NULL;
  1785. (*lppItem)->lpPrev = NULL;
  1786. if (HR_FAILED( HrGetPropArray( lpAdrBook,
  1787. NULL,
  1788. cbEntryID,
  1789. lpEntryID,
  1790. MAPI_UNICODE,
  1791. &ulcProps,
  1792. &lpPropArray) ) )
  1793. {
  1794. DebugPrintError(( TEXT("HrGetPropArray failed\n")));
  1795. goto out;
  1796. }
  1797. GetRecipItemFromPropArray(ulcProps, lpPropArray, lppItem);
  1798. //Bug-
  1799. // 3/31/97 - vikramm
  1800. // on NTDSDC5.0, we are getting no attributes back in some cases
  1801. // and later on gpf when we try to look at the attributes ..
  1802. // make a check here
  1803. if (!lstrlen((*lppItem)->szDisplayName) || ((*lppItem)->cbEntryID == 0)) //This entry id is not allowed
  1804. {
  1805. goto out;
  1806. }
  1807. bRet = TRUE;
  1808. out:
  1809. if (lpPropArray)
  1810. MAPIFreeBuffer(lpPropArray);
  1811. if (!bRet)
  1812. {
  1813. if (*lppItem)
  1814. FreeRecipItem(lppItem);
  1815. }
  1816. return bRet;
  1817. }
  1818. /*
  1819. -
  1820. - bIsRubyLocale - Checks if the current locale is Rubyenabled
  1821. -
  1822. */
  1823. BOOL bIsRubyLocale()
  1824. {
  1825. static LCID lcid = 0;
  1826. if(!lcid)
  1827. {
  1828. lcid = GetUserDefaultLCID();
  1829. //DebugTrace( TEXT("UserDefaultLCID = 0x%.4x\n"), lcid);
  1830. }
  1831. switch(lcid)
  1832. {
  1833. //case 0x0409: // us for testing
  1834. case 0x0804: //chinese
  1835. case 0x0411: //japanese
  1836. // case 0x0412: //korean - not use Ruby (YST)
  1837. case 0x0404: //chinese - taiwan
  1838. case 0x0c04: //chinese - hongkong
  1839. return TRUE;
  1840. break;
  1841. }
  1842. return FALSE;
  1843. }
  1844. /*
  1845. - TimeToString
  1846. -
  1847. * Converts a FileTime prop into a short string
  1848. */
  1849. void TimeToString(LPTSTR szTime, FILETIME ft,ULONG cb )
  1850. {
  1851. SYSTEMTIME st = {0};
  1852. static TCHAR szFormat[64];
  1853. szTime[0] = TEXT('\0');
  1854. if(!lstrlen(szFormat))
  1855. LoadString(hinstMapiX, idsLVDateFormatString, szFormat, ARRAYSIZE(szFormat));
  1856. if(FileTimeToSystemTime(&ft, &st))
  1857. GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, szFormat, szTime, cb);
  1858. }
  1859. //$$////////////////////////////////////////////////////////////////////////////
  1860. //
  1861. // GetRcipItemFromPropArray - Scans a lpPropArray structure for the props of
  1862. // interest and puts them in an recipientInfo structure
  1863. //
  1864. // ulcPropCount - count of Props in the LPSPropValue array
  1865. // rgPropVals - LPSPropValue array
  1866. // lppItem - returned lppItem
  1867. //
  1868. //////////////////////////////////////////////////////////////////////////////
  1869. void GetRecipItemFromPropArray( ULONG ulcPropCount,
  1870. LPSPropValue rgPropVals,
  1871. LPRECIPIENT_INFO * lppItem)
  1872. {
  1873. ULONG j=0,nLen=0;
  1874. LPRECIPIENT_INFO lpItem = *lppItem;
  1875. LPTSTR lpszDisplayName = NULL, lpszNickName = NULL, lpszCompanyName = NULL;
  1876. LPTSTR lpszFirstName = NULL, lpszLastName = NULL, lpszMiddleName = NULL;
  1877. LPTSTR lpszRubyFirstName = NULL, lpszRubyLastName = NULL;
  1878. TCHAR szBufDisplayName[MAX_DISPLAY_NAME_LENGTH];
  1879. TCHAR szBufOppositeName[MAX_DISPLAY_NAME_LENGTH];
  1880. LPVOID lpBuffer = NULL;
  1881. ULONG ulProp1, ulProp2;
  1882. BOOL bRuby = bIsRubyLocale();
  1883. ulProp1 = (PR_WAB_CUSTOMPROP1 ? PR_WAB_CUSTOMPROP1 : PR_HOME_TELEPHONE_NUMBER);
  1884. ulProp2 = (PR_WAB_CUSTOMPROP2 ? PR_WAB_CUSTOMPROP2 : PR_OFFICE_TELEPHONE_NUMBER);
  1885. for(j=0;j<ulcPropCount;j++)
  1886. {
  1887. // Check Custom Props first in case these are dupes of other props already in the switch statement
  1888. //
  1889. if(rgPropVals[j].ulPropTag == ulProp1)
  1890. {
  1891. if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_TSTRING)
  1892. {
  1893. nLen = CopyTruncate(lpItem->szHomePhone, rgPropVals[j].Value.LPSZ,
  1894. MAX_DISPLAY_NAME_LENGTH);
  1895. }
  1896. else // for birthday, anniversary etc
  1897. if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_SYSTIME)
  1898. TimeToString(lpItem->szHomePhone, rgPropVals[j].Value.ft, MAX_DISPLAY_NAME_LENGTH-1);
  1899. }
  1900. else if(rgPropVals[j].ulPropTag == ulProp2)
  1901. {
  1902. if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_TSTRING)
  1903. {
  1904. nLen = CopyTruncate(lpItem->szOfficePhone, rgPropVals[j].Value.LPSZ,
  1905. MAX_DISPLAY_NAME_LENGTH);
  1906. }
  1907. else // for birthday, anniversary etc
  1908. if(PROP_TYPE(rgPropVals[j].ulPropTag) == PT_SYSTIME)
  1909. TimeToString(lpItem->szOfficePhone, rgPropVals[j].Value.ft,MAX_DISPLAY_NAME_LENGTH-1);
  1910. }
  1911. switch(rgPropVals[j].ulPropTag)
  1912. {
  1913. case PR_DISPLAY_NAME:
  1914. lpszDisplayName = rgPropVals[j].Value.LPSZ;
  1915. break;
  1916. case PR_SURNAME:
  1917. lpszLastName = rgPropVals[j].Value.LPSZ;
  1918. break;
  1919. case PR_GIVEN_NAME:
  1920. lpszFirstName = rgPropVals[j].Value.LPSZ;
  1921. break;
  1922. case PR_MIDDLE_NAME:
  1923. lpszMiddleName = rgPropVals[j].Value.LPSZ;
  1924. break;
  1925. case PR_COMPANY_NAME:
  1926. lpszCompanyName = rgPropVals[j].Value.LPSZ;
  1927. break;
  1928. case PR_NICKNAME:
  1929. lpszNickName = rgPropVals[j].Value.LPSZ;
  1930. break;
  1931. case PR_EMAIL_ADDRESS:
  1932. nLen = CopyTruncate(lpItem->szEmailAddress, rgPropVals[j].Value.LPSZ,
  1933. MAX_DISPLAY_NAME_LENGTH);
  1934. break;
  1935. case PR_ENTRYID:
  1936. lpItem->cbEntryID = rgPropVals[j].Value.bin.cb;
  1937. lpItem->lpEntryID = LocalAlloc(LMEM_ZEROINIT,lpItem->cbEntryID);
  1938. if(!(lpItem->lpEntryID))
  1939. {
  1940. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1941. goto out;
  1942. }
  1943. CopyMemory(lpItem->lpEntryID,rgPropVals[j].Value.bin.lpb,lpItem->cbEntryID);
  1944. break;
  1945. case PR_OBJECT_TYPE:
  1946. lpItem->ulObjectType = rgPropVals[j].Value.l;
  1947. break;
  1948. case PR_USER_X509_CERTIFICATE:
  1949. lpItem->bHasCert = TRUE;
  1950. break;
  1951. default:
  1952. if(rgPropVals[j].ulPropTag == PR_WAB_THISISME)
  1953. lpItem->bIsMe = TRUE;
  1954. else if(rgPropVals[j].ulPropTag == PR_WAB_YOMI_FIRSTNAME)
  1955. lpszRubyFirstName = rgPropVals[j].Value.LPSZ;
  1956. else if(rgPropVals[j].ulPropTag == PR_WAB_YOMI_LASTNAME)
  1957. lpszRubyLastName = rgPropVals[j].Value.LPSZ;
  1958. break;
  1959. }
  1960. }
  1961. // [PaulHi] 3/12/99 Raid 63006 Use the PR_CONTACT_EMAIL_ADDRESSES email
  1962. // name if a PR_EMAIL_ADDRESS doesn't exist
  1963. if ( lpItem->szEmailAddress && (*lpItem->szEmailAddress == '\0') )
  1964. {
  1965. if (rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
  1966. {
  1967. // Just grap the first one in multi-valued list
  1968. if (rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.cValues != 0)
  1969. {
  1970. nLen = CopyTruncate(lpItem->szEmailAddress,
  1971. rgPropVals[RECIPCOLUMN_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.LPPSZ[0],
  1972. MAX_DISPLAY_NAME_LENGTH);
  1973. }
  1974. }
  1975. }
  1976. // Reduce display name to 32 char or less ...
  1977. if(!lpszDisplayName) // should never happen
  1978. lpszDisplayName = szEmpty;
  1979. nLen = CopyTruncate(szBufDisplayName, lpszDisplayName, MAX_DISPLAY_NAME_LENGTH);
  1980. // The display name will be either by first name or last name
  1981. // so all we have to do is generate the other name and we'll
  1982. // be all set
  1983. szBufOppositeName[0]='\0';
  1984. if(lpItem->ulObjectType == MAPI_DISTLIST)
  1985. {
  1986. StrCpyN(szBufOppositeName, szBufDisplayName, ARRAYSIZE(szBufOppositeName));
  1987. }
  1988. else
  1989. {
  1990. // if there is no first/middle/last (there will always be a display name)
  1991. // and the display name does not match company name or nick name,
  1992. // then we shall try to parse the display name into first/middle/last
  1993. if( !lpszFirstName &&
  1994. !lpszMiddleName &&
  1995. !lpszLastName &&
  1996. !(lpszCompanyName && !lstrcmp(lpszDisplayName, lpszCompanyName)) &&
  1997. !(lpszNickName && !lstrcmp(lpszDisplayName, lpszNickName)) )
  1998. {
  1999. ParseDisplayName( lpszDisplayName,
  2000. &lpszFirstName,
  2001. &lpszLastName,
  2002. NULL, // Root WAB allocation
  2003. &lpBuffer); // lppLocalFree
  2004. }
  2005. if (lpszFirstName ||
  2006. lpszMiddleName ||
  2007. lpszLastName)
  2008. {
  2009. LPTSTR lpszTmp = szBufOppositeName;
  2010. SetLocalizedDisplayName( lpszFirstName,
  2011. bRuby ? NULL : lpszMiddleName,
  2012. lpszLastName,
  2013. NULL, //company
  2014. NULL, //nickname
  2015. (LPTSTR *) &lpszTmp, //&szBufOppositeName,
  2016. MAX_DISPLAY_NAME_LENGTH,
  2017. !bDNisByLN,
  2018. NULL,
  2019. NULL);
  2020. }
  2021. }
  2022. if(!lstrlen(szBufOppositeName))
  2023. {
  2024. // There is only 1 type of name so use it everywhere
  2025. StrCpyN(lpItem->szByFirstName,szBufDisplayName,ARRAYSIZE(lpItem->szByFirstName));
  2026. StrCpyN(lpItem->szByLastName,szBufDisplayName,ARRAYSIZE(lpItem->szByLastName));
  2027. }
  2028. else if(bDNisByLN)
  2029. {
  2030. // Display Name is by Last Name
  2031. StrCpyN(lpItem->szByFirstName,szBufOppositeName,ARRAYSIZE(lpItem->szByFirstName));
  2032. StrCpyN(lpItem->szByLastName,szBufDisplayName,ARRAYSIZE(lpItem->szByLastName));
  2033. }
  2034. else
  2035. {
  2036. // Display Name is by First Name
  2037. StrCpyN(lpItem->szByLastName,szBufOppositeName,ARRAYSIZE(lpItem->szByLastName));
  2038. StrCpyN(lpItem->szByFirstName,szBufDisplayName,ARRAYSIZE(lpItem->szByFirstName));
  2039. }
  2040. StrCpyN(lpItem->szDisplayName, szBufDisplayName,ARRAYSIZE(lpItem->szDisplayName));
  2041. if(bRuby)
  2042. {
  2043. if(lpszRubyFirstName)
  2044. SetLocalizedDisplayName(lpszRubyFirstName, NULL,
  2045. lpszRubyLastName ? lpszRubyLastName : (lpszLastName ? lpszLastName : szEmpty),
  2046. NULL, NULL, NULL, 0,
  2047. FALSE, //DNbyFN
  2048. NULL,
  2049. &lpItem->lpByRubyFirstName);
  2050. if(lpszRubyLastName)
  2051. SetLocalizedDisplayName(lpszRubyFirstName ? lpszRubyFirstName : (lpszFirstName ? lpszFirstName : szEmpty),
  2052. NULL,
  2053. lpszRubyLastName,
  2054. NULL, NULL, NULL, 0,
  2055. TRUE, //DNbyFN
  2056. NULL,
  2057. &lpItem->lpByRubyLastName);
  2058. }
  2059. // default object type to mailuser
  2060. if(!lpItem->ulObjectType)
  2061. lpItem->ulObjectType = MAPI_MAILUSER;
  2062. out:
  2063. if(lpBuffer)
  2064. LocalFree(lpBuffer);
  2065. return;
  2066. }
  2067. /*
  2068. - AddEntryToGroupEx
  2069. -
  2070. * Adds an entry to a group
  2071. *
  2072. */
  2073. HRESULT AddEntryToGroupEx(LPADRBOOK lpAdrBook,
  2074. ULONG cbGroupEntryID,
  2075. LPENTRYID lpGroupEntryID,
  2076. DWORD cbEID,
  2077. LPENTRYID lpEID)
  2078. {
  2079. HRESULT hr = E_FAIL;
  2080. LPMAPIPROP lpMailUser = NULL;
  2081. ULONG ulObjType;
  2082. ULONG cValues = 0;
  2083. LPSPropValue lpPropArray = NULL;
  2084. LPSPropValue lpSProp = NULL;
  2085. ULONG ulcNewProp = 0;
  2086. LPSPropValue lpNewProp = NULL;
  2087. SCODE sc;
  2088. ULONG i,j;
  2089. BOOL bDLFound = FALSE;
  2090. BOOL bIsOneOff = (WAB_ONEOFF == IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL));
  2091. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  2092. if(pt_bIsWABOpenExSession)
  2093. bIsOneOff = FALSE;
  2094. // [PaulHi] Raid 67581 First thing to do is check for cyclical references.
  2095. // This was done as a special case below and is now moved up to the top of
  2096. // the function.
  2097. if(!bIsOneOff)
  2098. {
  2099. if(CheckForCycle(lpAdrBook, lpEID, cbEID, lpGroupEntryID, cbGroupEntryID))
  2100. {
  2101. hr = MAPI_E_FOLDER_CYCLE;
  2102. goto out;
  2103. }
  2104. }
  2105. if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry( lpAdrBook,
  2106. cbGroupEntryID, // cbEntryID
  2107. lpGroupEntryID, // entryid
  2108. NULL, // interface
  2109. MAPI_MODIFY, // ulFlags
  2110. &ulObjType, // returned object type
  2111. (LPUNKNOWN *)&lpMailUser)))
  2112. {
  2113. // Failed! Hmmm.
  2114. DebugPrintError(( TEXT("IAB->OpenEntry: %x"), hr));
  2115. goto out;
  2116. }
  2117. Assert(lpMailUser);
  2118. if(ulObjType != MAPI_DISTLIST)
  2119. goto out;
  2120. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, // this
  2121. NULL,
  2122. MAPI_UNICODE,
  2123. &cValues, // cValues
  2124. &lpPropArray)))
  2125. {
  2126. DebugPrintError(( TEXT("lpMailUser->Getprops failed: %x\n"),hr));
  2127. goto out;
  2128. }
  2129. for(i=0;i<cValues;i++)
  2130. {
  2131. // For the DistList, the prop may not exist and if it doesnt exist,
  2132. // we make sure we can handle that case by adding the prop to the group..
  2133. //
  2134. if(lpPropArray[i].ulPropTag == (bIsOneOff ? PR_WAB_DL_ONEOFFS : PR_WAB_DL_ENTRIES) )
  2135. {
  2136. bDLFound = TRUE;
  2137. // before we add the item to the distlist, we want to check for
  2138. // duplicates
  2139. for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
  2140. {
  2141. if( cbEID == lpPropArray[i].Value.MVbin.lpbin[j].cb
  2142. && !memcmp(lpEID, lpPropArray[i].Value.MVbin.lpbin[j].lpb, cbEID))
  2143. {
  2144. // yes its the same item
  2145. hr = S_OK;
  2146. goto out;
  2147. }
  2148. }
  2149. if (HR_FAILED(hr = AddPropToMVPBin( lpPropArray, i, lpEID, cbEID, FALSE)))
  2150. {
  2151. DebugPrintError(( TEXT("AddPropToMVPBin -> %x\n"), GetScode(hr)));
  2152. goto out;
  2153. }
  2154. break;
  2155. }
  2156. }
  2157. if(!bDLFound)
  2158. {
  2159. // This item is empty and doesnt have a PR_WAB_DL_PROPS or PR_WAB_FOLDER_PROPS..
  2160. // Add a new prop to this object ..
  2161. MAPIAllocateBuffer(sizeof(SPropValue), &lpSProp);
  2162. lpSProp->ulPropTag = (bIsOneOff ? PR_WAB_DL_ONEOFFS : PR_WAB_DL_ENTRIES);
  2163. lpSProp->Value.MVbin.cValues = 0;
  2164. lpSProp->Value.MVbin.lpbin = NULL;
  2165. if (HR_FAILED(hr = AddPropToMVPBin( lpSProp, 0, lpEID, cbEID, FALSE)))
  2166. {
  2167. DebugPrintError(( TEXT("AddPropToMVPBin -> %x\n"), GetScode(hr)));
  2168. goto out;
  2169. }
  2170. sc = ScMergePropValues( 1, lpSProp,
  2171. cValues, lpPropArray,
  2172. &ulcNewProp, &lpNewProp);
  2173. if (sc != S_OK)
  2174. {
  2175. hr = ResultFromScode(sc);
  2176. goto out;
  2177. }
  2178. if(lpPropArray)
  2179. MAPIFreeBuffer(lpPropArray);
  2180. lpPropArray = lpNewProp;
  2181. cValues = ulcNewProp;
  2182. lpNewProp = NULL;
  2183. }
  2184. if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, cValues, lpPropArray, NULL)))
  2185. {
  2186. DebugPrintError(( TEXT("lpMailUser->Setprops failed\n")));
  2187. goto out;
  2188. }
  2189. hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser, KEEP_OPEN_READWRITE);
  2190. if (HR_FAILED(hr))
  2191. {
  2192. DebugPrintError(( TEXT("SaveChanges failed\n")));
  2193. goto out;
  2194. }
  2195. out:
  2196. if(lpPropArray)
  2197. MAPIFreeBuffer(lpPropArray);
  2198. if(lpNewProp)
  2199. MAPIFreeBuffer(lpNewProp);
  2200. if(lpSProp)
  2201. MAPIFreeBuffer(lpSProp);
  2202. if(lpMailUser)
  2203. lpMailUser->lpVtbl->Release(lpMailUser);
  2204. return hr;
  2205. }
  2206. /*
  2207. - RemoveEntryFromFolder
  2208. -
  2209. *
  2210. *
  2211. */
  2212. HRESULT RemoveEntryFromFolder(LPIAB lpIAB,
  2213. LPSBinary lpsbFolder,
  2214. ULONG cbEIDItem, LPENTRYID lpEIDItem)
  2215. {
  2216. HRESULT hr = E_FAIL;
  2217. ULONG ulObjType = 0, cValues = 0, i = 0, j = 0, k =0;
  2218. int nIndex = -1;
  2219. BOOL bRemoved = TRUE;
  2220. LPSPropValue lpPropArray = NULL;
  2221. // open the Folder
  2222. if(HR_FAILED(hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore,
  2223. lpsbFolder, 0, &cValues, &lpPropArray)))
  2224. goto out;
  2225. for(i=0;i<cValues;i++)
  2226. {
  2227. if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES)
  2228. {
  2229. for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
  2230. {
  2231. if(lpPropArray[i].Value.MVbin.lpbin[j].cb == cbEIDItem)
  2232. {
  2233. if(!memcmp(lpPropArray[i].Value.MVbin.lpbin[j].lpb, lpEIDItem, cbEIDItem))
  2234. {
  2235. //knock this item out of the list
  2236. LocalFree(lpPropArray[i].Value.MVbin.lpbin[j].lpb);
  2237. // move everything 1 up in the array
  2238. for(k=j;k<lpPropArray[i].Value.MVbin.cValues-1;k++)
  2239. {
  2240. lpPropArray[i].Value.MVbin.lpbin[k].lpb = lpPropArray[i].Value.MVbin.lpbin[k+1].lpb;
  2241. lpPropArray[i].Value.MVbin.lpbin[k].cb = lpPropArray[i].Value.MVbin.lpbin[k+1].cb;
  2242. }
  2243. lpPropArray[i].Value.MVbin.cValues--;
  2244. bRemoved = TRUE;
  2245. break;
  2246. }
  2247. }
  2248. }
  2249. }
  2250. }
  2251. if(bRemoved)
  2252. {
  2253. // write this back to the store
  2254. hr = WriteRecord(lpIAB->lpPropertyStore->hPropertyStore,
  2255. NULL, &lpsbFolder, 0, RECORD_CONTAINER,
  2256. cValues, lpPropArray);
  2257. }
  2258. out:
  2259. ReadRecordFreePropArray(NULL, cValues, &lpPropArray);
  2260. return hr;
  2261. }
  2262. /*
  2263. - AddEIDToNewFolderParent
  2264. -
  2265. * Adds the given EID to a given Folder
  2266. */
  2267. HRESULT AddItemEIDToFolderParent( LPIAB lpIAB,
  2268. ULONG cbFolderEntryId,
  2269. LPENTRYID lpFolderEntryId,
  2270. ULONG cbEID, LPENTRYID lpEID)
  2271. {
  2272. HRESULT hr = S_OK;
  2273. SBinary sb = {0};
  2274. ULONG cValues = 0,i;
  2275. LPSPropValue lpPropArray = NULL;
  2276. // ignore additions to folders in non-profile mode ...
  2277. if(!bIsWABSessionProfileAware(lpIAB))
  2278. return S_OK;
  2279. sb.cb = cbFolderEntryId;
  2280. sb.lpb = (LPBYTE)lpFolderEntryId;
  2281. if(HR_FAILED(hr = ReadRecord( lpIAB->lpPropertyStore->hPropertyStore,
  2282. &sb, 0, &cValues, &lpPropArray)))
  2283. goto out;
  2284. for(i=0;i<cValues;i++)
  2285. {
  2286. // For the folder, the PR_WAB_FOLDER_ENTRIES will always exist
  2287. //
  2288. if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES)
  2289. {
  2290. // This is a local alloced prop array so we can just tag the entry to
  2291. // the existing prop
  2292. LPSBinary lpbin = LocalAlloc(LMEM_ZEROINIT, (lpPropArray[i].Value.MVbin.cValues+1)*sizeof(SBinary));
  2293. ULONG j = 0;
  2294. // First make sure this entry is not already a part of this folder
  2295. // If it is, we dont need to do anything
  2296. for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
  2297. {
  2298. if(cbEID == lpPropArray[i].Value.MVbin.lpbin[j].cb)
  2299. {
  2300. if(!memcmp(lpEID, lpPropArray[i].Value.MVbin.lpbin[j].lpb, cbEID))
  2301. {
  2302. // yes its the same item
  2303. LocalFreeAndNull(&lpbin);
  2304. hr = S_OK;
  2305. goto out;
  2306. }
  2307. }
  2308. }
  2309. // no match - so add it
  2310. for(j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
  2311. {
  2312. lpbin[j].cb = lpPropArray[i].Value.MVbin.lpbin[j].cb;
  2313. lpbin[j].lpb = lpPropArray[i].Value.MVbin.lpbin[j].lpb;
  2314. }
  2315. SetSBinary(&(lpbin[j]), cbEID, (LPBYTE)lpEID);
  2316. if(lpPropArray[i].Value.MVbin.lpbin)
  2317. LocalFree(lpPropArray[i].Value.MVbin.lpbin);
  2318. lpPropArray[i].Value.MVbin.lpbin = lpbin;
  2319. lpPropArray[i].Value.MVbin.cValues++;
  2320. break;
  2321. }
  2322. }
  2323. // Write this folder item back to the store
  2324. {
  2325. LPSBinary lpsb = &sb;
  2326. if(HR_FAILED(hr = WriteRecord( lpIAB->lpPropertyStore->hPropertyStore,
  2327. NULL, &lpsb, 0, RECORD_CONTAINER,
  2328. cValues, lpPropArray)))
  2329. goto out;
  2330. }
  2331. out:
  2332. ReadRecordFreePropArray(NULL, cValues, &lpPropArray);
  2333. return hr;
  2334. }
  2335. /*
  2336. - AddFolderParentEIDToItem
  2337. -
  2338. * Adds the Folders EID to given Item
  2339. *
  2340. */
  2341. HRESULT AddFolderParentEIDToItem(LPIAB lpIAB,
  2342. ULONG cbFolderEntryID,
  2343. LPENTRYID lpFolderEntryID,
  2344. LPMAPIPROP lpMU,
  2345. ULONG cbEID, LPENTRYID lpEID)
  2346. {
  2347. LPSPropValue lpspvMU = NULL;
  2348. ULONG ulcPropsMU = 0,i;
  2349. HRESULT hr = S_OK;
  2350. // ignore additions to folders in non-profile mode ...
  2351. if(!bIsWABSessionProfileAware(lpIAB))
  2352. return S_OK;
  2353. if(!HR_FAILED(hr = lpMU->lpVtbl->GetProps(lpMU, NULL, MAPI_UNICODE, &ulcPropsMU, &lpspvMU)))
  2354. {
  2355. // Look for PR_WAB_FOLDER_PARENT
  2356. BOOL bFound = FALSE;
  2357. if(cbEID && lpEID) // means this is a preexisting entry not a new one
  2358. {
  2359. for(i=0;i<ulcPropsMU;i++)
  2360. {
  2361. if(lpspvMU[i].ulPropTag == PR_WAB_FOLDER_PARENT || lpspvMU[i].ulPropTag == PR_WAB_FOLDER_PARENT_OLDPROP)
  2362. {
  2363. LPSBinary lpsbOldParent = &(lpspvMU[i].Value.MVbin.lpbin[0]);
  2364. // an item can only have one folder parent
  2365. if( lpFolderEntryID && cbFolderEntryID &&
  2366. cbFolderEntryID == lpsbOldParent->cb &&
  2367. !memcmp(lpFolderEntryID, lpsbOldParent->lpb, cbFolderEntryID))
  2368. {
  2369. //old is same as new .. don't need to do anything
  2370. hr = S_OK;
  2371. goto out;
  2372. }
  2373. // Remove this item from its old Parents list of contents
  2374. RemoveEntryFromFolder(lpIAB, lpsbOldParent, cbEID, lpEID);
  2375. // an item can only have one folder parent
  2376. if(lpFolderEntryID && cbFolderEntryID)
  2377. {
  2378. LPBYTE lpb = NULL;
  2379. // overwrite the old setting
  2380. if(!MAPIAllocateMore(cbFolderEntryID, lpspvMU, (LPVOID *)&lpb))
  2381. {
  2382. lpspvMU[i].Value.MVbin.lpbin[0].cb = cbFolderEntryID;
  2383. lpspvMU[i].Value.MVbin.lpbin[0].lpb = lpb;
  2384. CopyMemory(lpspvMU[i].Value.MVbin.lpbin[0].lpb, lpFolderEntryID, cbFolderEntryID);
  2385. lpMU->lpVtbl->SetProps(lpMU, ulcPropsMU, lpspvMU, NULL);
  2386. }
  2387. }
  2388. bFound = TRUE;
  2389. break;
  2390. }
  2391. }
  2392. }
  2393. if(!bFound)
  2394. {
  2395. // Didnt find an old parent in which case, if this is a valid folder we
  2396. // are dropping it on (and not a root item) then add a new property
  2397. // with new parent
  2398. if(lpFolderEntryID && cbFolderEntryID)
  2399. {
  2400. LPSPropValue lpPropFP = NULL;
  2401. if(!MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpPropFP))
  2402. {
  2403. lpPropFP->ulPropTag = PR_WAB_FOLDER_PARENT;
  2404. lpPropFP->Value.MVbin.cValues = 0;
  2405. lpPropFP->Value.MVbin.lpbin = NULL;
  2406. if(!HR_FAILED(AddPropToMVPBin( lpPropFP, 0, lpFolderEntryID, cbFolderEntryID, FALSE)))
  2407. lpMU->lpVtbl->SetProps(lpMU, 1, lpPropFP, NULL);
  2408. }
  2409. if(lpPropFP)
  2410. MAPIFreeBuffer(lpPropFP);
  2411. }
  2412. }
  2413. else
  2414. {
  2415. // We did find an old parent
  2416. // If the new parent is the root, then we basically need to remove the
  2417. // old parent property
  2418. SizedSPropTagArray(2, tagaFolderParent) =
  2419. {
  2420. 2,
  2421. {
  2422. PR_WAB_FOLDER_PARENT,
  2423. PR_WAB_FOLDER_PARENT_OLDPROP
  2424. }
  2425. };
  2426. if(!lpFolderEntryID || !cbFolderEntryID)
  2427. lpMU->lpVtbl->DeleteProps(lpMU, (LPSPropTagArray) &tagaFolderParent, NULL);
  2428. }
  2429. }
  2430. out:
  2431. FreeBufferAndNull(&lpspvMU);
  2432. return hr;
  2433. }
  2434. /*
  2435. - AddEntryToFolder
  2436. -
  2437. *
  2438. *
  2439. */
  2440. HRESULT AddEntryToFolder(LPADRBOOK lpAdrBook,
  2441. LPMAPIPROP lpMailUser,
  2442. ULONG cbFolderEntryId,
  2443. LPENTRYID lpFolderEntryId,
  2444. DWORD cbEID,
  2445. LPENTRYID lpEID)
  2446. {
  2447. HRESULT hr = E_FAIL;
  2448. ULONG ulObjType;
  2449. SCODE sc;
  2450. ULONG i;
  2451. SBinary sb = {0};
  2452. LPIAB lpIAB = (LPIAB) lpAdrBook;
  2453. // ignore additions to folders in non-profile mode ...
  2454. if(!bIsWABSessionProfileAware(lpIAB))
  2455. return S_OK;
  2456. // Check for a cycle of a folder being added to itself .. this is possible
  2457. if(cbEID && lpEID && cbFolderEntryId && lpFolderEntryId)
  2458. {
  2459. SBinary sb = {0};
  2460. IsWABEntryID(cbFolderEntryId, lpFolderEntryId,
  2461. (LPVOID*)&sb.lpb,(LPVOID*)&sb.cb,NULL,NULL,NULL);
  2462. if( sb.cb == cbEID && !memcmp(lpEID, sb.lpb, cbEID) )
  2463. return S_OK;
  2464. }
  2465. if(cbFolderEntryId && lpFolderEntryId)
  2466. {
  2467. if(HR_FAILED(hr = AddItemEIDToFolderParent(lpIAB,
  2468. cbFolderEntryId,
  2469. lpFolderEntryId,
  2470. cbEID, lpEID)))
  2471. goto out;
  2472. }
  2473. // 2. Open the object we added to this folder
  2474. // Need to update its folder parent and also need to remove it from the old folder parent
  2475. //
  2476. if(lpMailUser || (cbEID && lpEID))
  2477. {
  2478. LPMAPIPROP lpMU = NULL;
  2479. if(lpMailUser)
  2480. lpMU = lpMailUser;
  2481. else
  2482. {
  2483. if (HR_FAILED(hr = lpIAB->lpVtbl->OpenEntry( lpIAB, cbEID, lpEID,
  2484. NULL, MAPI_MODIFY, &ulObjType,
  2485. (LPUNKNOWN *)&lpMU)))
  2486. {
  2487. DebugPrintError(( TEXT("IAB->OpenEntry: %x"), hr));
  2488. goto out;
  2489. }
  2490. }
  2491. if(!HR_FAILED(hr = AddFolderParentEIDToItem(lpIAB, cbFolderEntryId, lpFolderEntryId, lpMU,
  2492. cbEID, lpEID)))
  2493. {
  2494. // if we were given a mailuser to work with, don't bother calling SaveChanges from here just yet
  2495. if(lpMU && lpMU!=lpMailUser)
  2496. {
  2497. lpMU->lpVtbl->SaveChanges(lpMU, KEEP_OPEN_READWRITE);
  2498. lpMU->lpVtbl->Release(lpMU);
  2499. }
  2500. }
  2501. }
  2502. out:
  2503. return hr;
  2504. }
  2505. //$$////////////////////////////////////////////////////////////////////////////
  2506. //
  2507. // AddEntryToGroup - Adds given entryID to given group or folder
  2508. //
  2509. // cbGroupEntryID,cbGroupEntryID - entryid of group
  2510. // cbEID, lpEID, - entryid of new entry
  2511. // ulObjectType = MAPI_ABCONT or MAPI_DISTLIST
  2512. //
  2513. //////////////////////////////////////////////////////////////////////////////
  2514. HRESULT AddEntryToContainer(LPADRBOOK lpAdrBook,
  2515. ULONG ulObjectType,
  2516. ULONG cbGEID,
  2517. LPENTRYID lpGEID,
  2518. DWORD cbEID,
  2519. LPENTRYID lpEID)
  2520. {
  2521. if(ulObjectType == MAPI_ABCONT)
  2522. return AddEntryToFolder(lpAdrBook, NULL, cbGEID, lpGEID, cbEID, lpEID);
  2523. else
  2524. return AddEntryToGroupEx(lpAdrBook, cbGEID, lpGEID, cbEID, lpEID);
  2525. }
  2526. //$$////////////////////////////////////////////////////////////////////////////
  2527. //
  2528. // AddNewObjectTOListViewEx - Triggered by the NewContact menus and buttons -
  2529. // calls newentry and then adds the returned item to
  2530. // the list view
  2531. //
  2532. // lpIAB - AddrBook object
  2533. // hWndLV - handle of List View
  2534. // ulObjectType - MailUser or DistList
  2535. // SortInfo - Current Sort parameters
  2536. // lppContentsList - Current ContentsList
  2537. // lpftLast - WAB file time at last update
  2538. // LPULONG - lpcbEID
  2539. // LPPENTRYID - lppEntryID
  2540. //////////////////////////////////////////////////////////////////////////////
  2541. HRESULT AddNewObjectToListViewEx(LPADRBOOK lpAdrBook,
  2542. HWND hWndLV,
  2543. HWND hWndTV,
  2544. HTREEITEM hSelItem,
  2545. LPSBinary lpsbContainerEID,
  2546. ULONG ulObjectType,
  2547. SORT_INFO * lpSortInfo,
  2548. LPRECIPIENT_INFO * lppContentsList,
  2549. LPFILETIME lpftLast,
  2550. LPULONG lpcbEID,
  2551. LPENTRYID * lppEID)
  2552. {
  2553. ULONG cbEID=0, cbEIDContainer = 0;
  2554. LPENTRYID lpEID=NULL, lpEIDContainer = NULL;
  2555. HRESULT hr = hrSuccess;
  2556. ULONG cbTplEID = 0;
  2557. LPENTRYID lpTplEID = NULL;
  2558. ULONG ulObjTypeCont = 0;
  2559. SBinary sbContEID = {0};
  2560. SBinary sbGroupEID = {0};
  2561. LPIAB lpIAB = (LPIAB)lpAdrBook;
  2562. ULONG ulEIDPAB = 0;
  2563. LPENTRYID lpEIDPAB = NULL;
  2564. if (ulObjectType!=MAPI_MAILUSER && ulObjectType!=MAPI_DISTLIST)
  2565. goto out;
  2566. // Check if the currently selected TV item is a container or a group
  2567. // and get the corresponding entryid
  2568. //
  2569. if(lpsbContainerEID)
  2570. {
  2571. SetSBinary(&sbContEID, lpsbContainerEID->cb, lpsbContainerEID->lpb);
  2572. }
  2573. else if(hWndTV)
  2574. {
  2575. HTREEITEM hItem = hSelItem ? hSelItem : TreeView_GetSelection(hWndTV);
  2576. TV_ITEM tvI = {0};
  2577. tvI.mask = TVIF_PARAM | TVIF_HANDLE;
  2578. tvI.hItem = hItem;
  2579. TreeView_GetItem(hWndTV, &tvI);
  2580. if(tvI.lParam)
  2581. {
  2582. LPTVITEM_STUFF lptvStuff = (LPTVITEM_STUFF) tvI.lParam;
  2583. if(lptvStuff)
  2584. {
  2585. ulObjTypeCont = lptvStuff->ulObjectType;
  2586. if(lptvStuff->ulObjectType == MAPI_DISTLIST)
  2587. {
  2588. // Bug 50029
  2589. if(lptvStuff->lpsbEID)
  2590. SetSBinary(&sbGroupEID, lptvStuff->lpsbEID->cb, lptvStuff->lpsbEID->lpb);
  2591. if(lptvStuff->lpsbParent)
  2592. SetSBinary(&sbContEID, lptvStuff->lpsbParent->cb, lptvStuff->lpsbParent->lpb);
  2593. }
  2594. else // current selection is a container
  2595. {
  2596. if(lptvStuff->lpsbEID)
  2597. SetSBinary(&sbContEID, lptvStuff->lpsbEID->cb, lptvStuff->lpsbEID->lpb);
  2598. }
  2599. }
  2600. }
  2601. }
  2602. else
  2603. {
  2604. if(HR_FAILED(hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &ulEIDPAB, &lpEIDPAB)))
  2605. goto out;
  2606. sbContEID.cb = ulEIDPAB;
  2607. sbContEID.lpb = (LPBYTE)lpEIDPAB;
  2608. }
  2609. if(HR_FAILED(hr = HrGetWABTemplateID( lpAdrBook,
  2610. ulObjectType,
  2611. &cbTplEID,
  2612. &lpTplEID)))
  2613. {
  2614. DebugPrintError(( TEXT("HrGetWABTemplateID failed: %x\n"), hr));
  2615. goto out;
  2616. }
  2617. if(sbContEID.cb && sbContEID.lpb)
  2618. {
  2619. cbEIDContainer = sbContEID.cb;
  2620. lpEIDContainer = (LPENTRYID) sbContEID.lpb;
  2621. }
  2622. if (HR_FAILED(hr = lpAdrBook->lpVtbl->NewEntry( lpAdrBook,
  2623. (ULONG_PTR) GetParent(hWndLV),
  2624. 0,
  2625. cbEIDContainer,
  2626. lpEIDContainer,
  2627. cbTplEID,lpTplEID,
  2628. &cbEID,&lpEID)))
  2629. {
  2630. DebugPrintError(( TEXT("NewEntry failed: %x\n"),hr));
  2631. goto out;
  2632. }
  2633. // Update the wab file write time so the timer doesn't
  2634. // catch this change and refresh.
  2635. //if (lpftLast) {
  2636. // CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
  2637. //}
  2638. if (cbEID && lpEID)
  2639. {
  2640. if( AddWABEntryToListView( lpAdrBook, hWndLV, cbEID, lpEID, lppContentsList))
  2641. {
  2642. if(lpSortInfo)
  2643. SortListViewColumn( lpIAB, hWndLV, 0, lpSortInfo, TRUE);
  2644. }
  2645. }
  2646. if(sbGroupEID.cb != 0 && ulObjectType==MAPI_MAILUSER)
  2647. {
  2648. // Need to add this new object to the currently selected distribution list
  2649. // Only if this item is a mailuser
  2650. AddEntryToGroupEx(lpAdrBook, sbGroupEID.cb, (LPENTRYID) sbGroupEID.lpb, cbEID, lpEID);
  2651. }
  2652. if(lpcbEID)
  2653. *lpcbEID = cbEID;
  2654. if(lppEID)
  2655. *lppEID = lpEID; // Callers responsibility to free
  2656. out:
  2657. LocalFreeAndNull((LPVOID *) (&sbGroupEID.lpb));
  2658. // [PaulHi] 12/16/98 Crash fix hack. If lpEIDPAB is non-NULL then
  2659. // this means lpEIDPAB == sbContEID.lpb and is MAPIAllocBuffer allocated.
  2660. // Don't deallocate twice and make sure we deallocate with correct function.
  2661. // Otherwise sbContEID.lpb is a LocalAlloc allocation.
  2662. if (lpEIDPAB)
  2663. {
  2664. FreeBufferAndNull(&lpEIDPAB);
  2665. sbContEID.lpb = NULL;
  2666. }
  2667. else
  2668. LocalFreeAndNull((LPVOID *) (&sbContEID.lpb));
  2669. if(!lppEID)
  2670. FreeBufferAndNull(&lpEID);
  2671. FreeBufferAndNull(&lpTplEID);
  2672. return hr;
  2673. }
  2674. /*
  2675. - AddExtendedSendMailToItems
  2676. -
  2677. * If there is only 1 item selected in the ListView and that item has
  2678. * multiple email addresses, we populate the Send Mail To item with
  2679. * the multiple email addresses ..
  2680. * If there is more than 1 item selected or the item doesn't have
  2681. * multiple email addresses, we will hide the Send Mail To item
  2682. * The SendMailTo item should be the second last in the list ...
  2683. *
  2684. * bAddItems - if TRUE means attempt to add items; if FALSE means remove the SendMailTo item
  2685. */
  2686. void AddExtendedSendMailToItems(LPADRBOOK lpAdrBook, HWND hWndLV, HMENU hMenuAction, BOOL bAddItems)
  2687. {
  2688. int nSendMailToPos = 1; // assumes IDM_SENDMAILTO is the second item in the list
  2689. int nSelected = ListView_GetSelectedCount(hWndLV);
  2690. HMENU hMenuSMT = GetSubMenu(hMenuAction, nSendMailToPos);
  2691. int nMenuSMT = GetMenuItemCount(hMenuSMT);
  2692. BOOL bEnable = FALSE;
  2693. if(nMenuSMT > 0) // Assumes there is only 1 default item in the SendMailTO popup menu
  2694. {
  2695. // there is some left over garbage here which we need to clear
  2696. int j = 0;
  2697. for(j=nMenuSMT-1;j>=0;j--)
  2698. RemoveMenu(hMenuSMT, j, MF_BYPOSITION);
  2699. }
  2700. if(bAddItems && nSelected == 1)
  2701. {
  2702. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
  2703. if (lpItem)
  2704. {
  2705. ULONG ulcValues = 0;
  2706. LPSPropValue lpPropArray = NULL;
  2707. SizedSPropTagArray(3, MUContactAddresses)=
  2708. {
  2709. 3, { PR_CONTACT_EMAIL_ADDRESSES, PR_OBJECT_TYPE, PR_EMAIL_ADDRESS }
  2710. };
  2711. if(!HR_FAILED(HrGetPropArray(lpAdrBook, (LPSPropTagArray)&MUContactAddresses,
  2712. lpItem->cbEntryID, lpItem->lpEntryID,
  2713. MAPI_UNICODE,
  2714. &ulcValues, &lpPropArray)))
  2715. {
  2716. if(ulcValues && lpPropArray)
  2717. {
  2718. if( lpPropArray[1].ulPropTag == PR_OBJECT_TYPE &&
  2719. lpPropArray[1].Value.l == MAPI_MAILUSER )
  2720. {
  2721. if( lpPropArray[0].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES &&
  2722. lpPropArray[0].Value.MVbin.cValues > 1)
  2723. {
  2724. ULONG i;
  2725. LPTSTR lpDefEmail = (lpPropArray[2].ulPropTag == PR_EMAIL_ADDRESS) ? lpPropArray[2].Value.LPSZ : szEmpty;
  2726. for(i=0;i<lpPropArray[0].Value.MVSZ.cValues;i++)
  2727. {
  2728. TCHAR sz[MAX_PATH * 2];
  2729. LPTSTR lpEmail = lpPropArray[0].Value.MVSZ.LPPSZ[i];
  2730. if(!lstrcmpi(lpEmail, lpDefEmail))
  2731. {
  2732. TCHAR sz1[MAX_PATH];
  2733. LoadString(hinstMapiX, idsDefaultEmail, sz1, ARRAYSIZE(sz1));
  2734. CopyTruncate(sz, lpEmail, ARRAYSIZE(sz)-lstrlen(sz1)-10);
  2735. StrCatBuff(sz, TEXT(" "), ARRAYSIZE(sz));
  2736. StrCatBuff(sz, sz1, ARRAYSIZE(sz));
  2737. lpEmail = sz;
  2738. }
  2739. if(i < IDM_SENDMAILTO_MAX)
  2740. InsertMenu( hMenuSMT, nMenuSMT+1, MF_STRING | MF_BYPOSITION,
  2741. IDM_SENDMAILTO_START+1+i, // we add an extra 1 here because IDM_SENDMAILTO_START is not a allowed ID here
  2742. lpEmail);
  2743. }
  2744. bEnable = TRUE;
  2745. }
  2746. }
  2747. MAPIFreeBuffer(lpPropArray);
  2748. }
  2749. }
  2750. }
  2751. }
  2752. EnableMenuItem(hMenuAction, nSendMailToPos, MF_BYPOSITION | (bEnable ? MF_ENABLED : MF_GRAYED));
  2753. //RemoveMenu(hMenuAction, nSendMailToPos, MF_BYPOSITION);
  2754. }
  2755. /*
  2756. -
  2757. - AddFolderListToMenu - Creates a FOlder menu from which we can choose folder items
  2758. * Items are checked if they are shared and unchecked if they are not shared ..
  2759. * The user can choose to share or un-share any particular folder
  2760. *
  2761. */
  2762. void AddFolderListToMenu(HMENU hMenu, LPIAB lpIAB)
  2763. {
  2764. LPWABFOLDER lpFolder = lpIAB->lpWABFolders;
  2765. int nPos = 0;
  2766. int nCount = GetMenuItemCount(hMenu);
  2767. if(!bDoesThisWABHaveAnyUsers(lpIAB))
  2768. return;
  2769. while(nCount>0)
  2770. RemoveMenu(hMenu, --nCount, MF_BYPOSITION);
  2771. while(lpFolder)
  2772. {
  2773. BOOL bChecked = lpFolder->bShared;
  2774. InsertMenu( hMenu, nPos, MF_STRING | MF_BYPOSITION | (bChecked ? MF_CHECKED : MF_UNCHECKED),
  2775. lpFolder->nMenuCmdID, lpFolder->lpFolderName);
  2776. lpFolder = lpFolder->lpNext;
  2777. nPos++;
  2778. }
  2779. }
  2780. //$$////////////////////////////////////////////////////////////////////////////
  2781. //
  2782. // ShowLVContextMenu - Customizes and displays the context menu for various list
  2783. // views in the UI
  2784. //
  2785. // LV - app defined constant identifing the List View
  2786. // hWndLV - Handle of List View
  2787. // hWndLVContainer - Handle of the List containing the containers
  2788. // lParam - WM_CONTEXTMENU lParam passed on to this function
  2789. // lpVoid - some List Views need more parameters than other list views - pass them
  2790. // in this parameter
  2791. // lpIAB - AdrBook object
  2792. //
  2793. //////////////////////////////////////////////////////////////////////////////
  2794. int ShowLVContextMenu(int LV, // idicates which list view this is
  2795. HWND hWndLV,
  2796. HWND hWndLVContainer,
  2797. LPARAM lParam, // contains the mouse pos info when called from WM_CONTEXTMENU
  2798. LPVOID lpVoid,
  2799. LPADRBOOK lpAdrBook,
  2800. HWND hWndTV) //misc stuff we want to pass in
  2801. {
  2802. int idMenu = 0, nPosAction = 0, nPosNew = 0;
  2803. LPIAB lpIAB = (LPIAB) lpAdrBook;
  2804. HMENU hMenu = NULL;//LoadMenu(hinstMapiX, MAKEINTRESOURCE(IDR_MENU_LVCONTEXT));
  2805. HMENU hMenuTrackPopUp = NULL;//GetSubMenu(hMenu, 0);
  2806. HMENU hMenuAction = NULL;//GetSubMenu(hMenuTrackPopUp, posAction);
  2807. HMENU hMenuNewEntry = NULL;//GetSubMenu(hMenuTrackPopUp, posNew);
  2808. HMENU hm = NULL;
  2809. int nret = 0;
  2810. BOOL bState[tbMAX];
  2811. int i=0;
  2812. TCHAR tszBuf[MAX_UI_STR];
  2813. switch(LV) /**WARNING - these menu sub pop up positions are HARDCODED so should be in sync with the resource**/
  2814. {
  2815. case lvToolBarAction:
  2816. case lvToolBarNewEntry:
  2817. case lvMainABView:
  2818. idMenu = IDR_MENU_LVCONTEXT_BROWSE_LV;
  2819. nPosAction = 5;
  2820. nPosNew = 0;
  2821. break;
  2822. case lvDialogABContents: // Modeless address view LV
  2823. case lvDialogModalABContents: // Modal addres vuew LV
  2824. idMenu = IDR_MENU_LVCONTEXT_SELECT_LIST;
  2825. nPosAction = 6;
  2826. nPosNew = 4;
  2827. break;
  2828. case lvDialogABTo: // To Well LV
  2829. case lvDialogABCC: // CC Well LV
  2830. case lvDialogABBCC: // BCC Well LV
  2831. case lvDialogDistList: // Disttribution list UI LV
  2832. case lvDialogResolve:
  2833. idMenu = IDR_MENU_LVCONTEXT_DL_LV;
  2834. nPosAction = 0;
  2835. nPosNew = -1;
  2836. break;
  2837. case lvDialogFind: // Find dialog results LV
  2838. idMenu = IDR_MENU_LVCONTEXT_FIND_LV;
  2839. nPosNew = -1;
  2840. nPosAction = 0;
  2841. break;
  2842. case lvMainABTV:
  2843. idMenu = IDR_MENU_LVCONTEXT_TV;
  2844. nPosNew = 0;
  2845. nPosAction = -1;
  2846. break;
  2847. #ifdef COLSEL_MENU
  2848. case lvMainABHeader:
  2849. idMenu = IDR_MENU_LVCONTEXTMENU_COLSEL;
  2850. nPosNew = 0;
  2851. nPosAction = -1;
  2852. #endif
  2853. }
  2854. hMenu = LoadMenu(hinstMapiX, MAKEINTRESOURCE(idMenu));
  2855. hMenuTrackPopUp = GetSubMenu(hMenu, 0);
  2856. if (!hMenu || !hMenuTrackPopUp)
  2857. {
  2858. DebugPrintError(( TEXT("LoadMenu failed: %x\n"),GetLastError()));
  2859. goto out;
  2860. }
  2861. if(nPosAction != -1)
  2862. hMenuAction = GetSubMenu(hMenuTrackPopUp, nPosAction);
  2863. if(nPosNew != -1)
  2864. hMenuNewEntry = GetSubMenu(hMenuTrackPopUp, nPosNew);
  2865. if(hMenuAction)
  2866. AddExtendedMenuItems(lpAdrBook, hWndLV, hMenuAction, FALSE,
  2867. (LV != lvMainABTV)); // this is the condition for updating SendMailTo items
  2868. if(LV == lvMainABTV)
  2869. {
  2870. // everything on except Copy
  2871. for(i=0;i<tbMAX;i++)
  2872. bState[i] = TRUE;
  2873. if(ListView_GetItemCount(hWndLV) <= 0)
  2874. bState[tbPrint] = /*bState[tbAction] =*/ FALSE;
  2875. // [PaulHi] 12/1/98 New Paste context menu item
  2876. bState[tbPaste] = bIsPasteData();
  2877. }
  2878. else
  2879. // get the current dialog state based on the current container and the
  2880. // current list view - this is basically important only for the address
  2881. // book views ...
  2882. GetCurrentOptionsState( hWndLVContainer, hWndLV, bState);
  2883. // we now customize the menu depending on which list box this is
  2884. switch(LV)
  2885. {
  2886. case lvDialogFind: // Find Dialog List View
  2887. // Set Add to Address Book to grey if this was a local search
  2888. if(!bState[tbAddToWAB])
  2889. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_ADDTOWAB,MF_BYCOMMAND | MF_GRAYED);
  2890. // Set Delete to grey if this was a LDAP search
  2891. if(!bState[tbDelete])
  2892. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
  2893. break;
  2894. case lvMainABTV:
  2895. // [PaulHi] 12/1/98 Enable/disable Paste item, as required
  2896. if(!bState[tbPaste])
  2897. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PASTE,MF_BYCOMMAND | MF_GRAYED);
  2898. // Do folder stuff here
  2899. {
  2900. LPWABFOLDER lpUserFolder = (LPWABFOLDER) lpVoid;
  2901. if(lpUserFolder || !bDoesThisWABHaveAnyUsers(lpIAB)) // if a user folder was clicked or if this wab doesn't have user folder, no sense in sharing ..
  2902. {
  2903. #ifdef FUTURE
  2904. RemoveMenu(hMenuTrackPopUp, 3, MF_BYPOSITION); //Folders seperator
  2905. RemoveMenu(hMenuTrackPopUp, 2, MF_BYPOSITION); //Folder seperator
  2906. #endif // FUTURE
  2907. }
  2908. else if(!lpIAB->lpWABFolders) // no sub-folders at all
  2909. {
  2910. EnableMenuItem(hMenuTrackPopUp, 2, MF_BYPOSITION | MF_GRAYED); //Folder item
  2911. EnableMenuItem(hMenuTrackPopUp, 3, MF_BYPOSITION | MF_GRAYED); //Folder item
  2912. }
  2913. else
  2914. {
  2915. int nFolder = 2;
  2916. #ifdef FUTURE
  2917. HMENU hMenuFolders = GetSubMenu(hMenuTrackPopUp, nFolder); //idmFolders
  2918. AddFolderListToMenu(hMenuFolders, lpIAB);
  2919. #endif // FUTURE
  2920. }
  2921. }
  2922. break;
  2923. case lvMainABView: //main view
  2924. // For this one - we dont need the wells and
  2925. if(!bState[tbPaste])
  2926. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PASTE,MF_BYCOMMAND | MF_GRAYED);
  2927. if(!bState[tbCopy])
  2928. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
  2929. if ((!bState[tbProperties]))
  2930. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
  2931. if((!bState[tbDelete]))
  2932. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
  2933. break;
  2934. case lvDialogModalABContents:
  2935. case lvDialogABContents: //address book dialog contents list view
  2936. //here we want the option to put it in to,cc,bcc
  2937. //in the menu - we also want new contact/new group/properties
  2938. // no delete unless this is DialogModal
  2939. if(LV != lvDialogModalABContents)
  2940. RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_DELETE, MF_BYCOMMAND);
  2941. // figure out some way to read the items on the dlg to figure out
  2942. // how many wells to show and what to put in them ...
  2943. {
  2944. LPADRPARM lpAP = (LPADRPARM) lpVoid;
  2945. if (lpAP)
  2946. {
  2947. switch(lpAP->cDestFields)
  2948. {
  2949. case 0:
  2950. RemoveMenu(hMenuTrackPopUp, 3, MF_BYPOSITION); //seperator
  2951. RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL1, MF_BYCOMMAND);
  2952. case 1:
  2953. RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL2, MF_BYCOMMAND);
  2954. case 2:
  2955. RemoveMenu(hMenuTrackPopUp, IDM_LVCONTEXT_ADDWELL3, MF_BYCOMMAND);
  2956. break;
  2957. }
  2958. if((lpAP->cDestFields > 0) && lpAP->lppszDestTitles)
  2959. {
  2960. ULONG i;
  2961. // update the text of the menu with the button text
  2962. for(i=0;i<lpAP->cDestFields;i++)
  2963. {
  2964. int id;
  2965. switch(i)
  2966. {
  2967. case 0:
  2968. id = IDM_LVCONTEXT_ADDWELL1;
  2969. break;
  2970. case 1:
  2971. id = IDM_LVCONTEXT_ADDWELL2;
  2972. break;
  2973. case 2:
  2974. id = IDM_LVCONTEXT_ADDWELL3;
  2975. break;
  2976. }
  2977. // [PaulHi] 2/15/99 Check whether lpAP is ANSI or UNICODE
  2978. {
  2979. LPTSTR lptszDestTitle = NULL;
  2980. BOOL bDestAllocated = FALSE;
  2981. if (lpAP->ulFlags & MAPI_UNICODE)
  2982. lptszDestTitle = lpAP->lppszDestTitles[i];
  2983. else
  2984. {
  2985. // Convert single byte string to double byte
  2986. lptszDestTitle = ConvertAtoW((LPSTR)lpAP->lppszDestTitles[i]);
  2987. bDestAllocated = TRUE;
  2988. }
  2989. if (lptszDestTitle)
  2990. {
  2991. ULONG iLen = TruncatePos(lptszDestTitle, MAX_UI_STR - 5);
  2992. CopyMemory(tszBuf, lptszDestTitle, sizeof(TCHAR)*iLen);
  2993. tszBuf[iLen] = '\0';
  2994. StrCatBuff(tszBuf, szArrow, ARRAYSIZE(tszBuf));
  2995. if (bDestAllocated)
  2996. LocalFreeAndNull(&lptszDestTitle);
  2997. }
  2998. else
  2999. *tszBuf = '\0';
  3000. }
  3001. ModifyMenu( hMenuTrackPopUp, /*posTo + */i, MF_BYPOSITION | MF_STRING, id, tszBuf);
  3002. }
  3003. }
  3004. }
  3005. }
  3006. break;
  3007. case lvDialogABTo: //address book dialog To well
  3008. case lvDialogABCC: //CC well
  3009. case lvDialogABBCC: //BCC well
  3010. {
  3011. int iItemIndex = 0;
  3012. iItemIndex = ListView_GetSelectedCount(hWndLV);
  3013. if (iItemIndex!=1)
  3014. {
  3015. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
  3016. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_SENDMAIL,MF_BYCOMMAND | MF_GRAYED);
  3017. }
  3018. if (iItemIndex<=0)
  3019. {
  3020. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_DELETE,MF_BYCOMMAND | MF_GRAYED);
  3021. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
  3022. }
  3023. //
  3024. // The wells may contain unresolved items without entryids ..
  3025. // If the item does not have an entryid, we want to disable properties
  3026. //
  3027. if (iItemIndex == 1)
  3028. {
  3029. // we are potentially looking at the properties of this thing
  3030. // get the items lParam
  3031. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  3032. if(iItemIndex != -1)
  3033. {
  3034. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  3035. if(lpItem &&
  3036. ((lpItem->cbEntryID == 0) || (lpItem->lpEntryID == NULL)))
  3037. {
  3038. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_PROPERTIES,MF_BYCOMMAND | MF_GRAYED);
  3039. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_COPY,MF_BYCOMMAND | MF_GRAYED);
  3040. EnableMenuItem(hMenuTrackPopUp,IDM_LVCONTEXT_SENDMAIL,MF_BYCOMMAND | MF_GRAYED);
  3041. }
  3042. }
  3043. }
  3044. }
  3045. break;
  3046. case lvDialogResolve: //Resolve dialog list view
  3047. //Rename the TEXT("delete") to TEXT("Show More Names .. ")
  3048. LoadString(hinstMapiX, idsShowMoreNames, tszBuf, ARRAYSIZE(tszBuf));
  3049. ModifyMenu( hMenuTrackPopUp,
  3050. IDM_LVCONTEXT_DELETE,
  3051. MF_BYCOMMAND | MF_STRING,
  3052. IDM_LVCONTEXT_DELETE,
  3053. tszBuf);
  3054. //And we want a seperator before TEXT("Show More Names")
  3055. InsertMenu( hMenuTrackPopUp,
  3056. IDM_LVCONTEXT_DELETE,
  3057. MF_BYCOMMAND | MF_SEPARATOR,
  3058. IDM_LVCONTEXT_DELETE,
  3059. NULL);
  3060. break;
  3061. #ifdef COLSEL_MENU
  3062. case lvMainABHeader:
  3063. {
  3064. UINT iIndex = PtrToUlong(lpVoid);
  3065. ULONG ulShowingColTag;
  3066. ULONG ulOtherColTag;
  3067. UINT i = 0, j;
  3068. // this will always be called with iIndex == colHomePhone or colOfficePhone
  3069. Assert( iIndex == colHomePhone || iIndex == colOfficePhone );
  3070. if( PR_WAB_CUSTOMPROP1 == 0 )
  3071. PR_WAB_CUSTOMPROP1 = PR_HOME_TELEPHONE_NUMBER;
  3072. if( PR_WAB_CUSTOMPROP2 == 0)
  3073. PR_WAB_CUSTOMPROP2 = PR_OFFICE_TELEPHONE_NUMBER;
  3074. ulShowingColTag = (colHomePhone == iIndex) ? PR_WAB_CUSTOMPROP1 : PR_WAB_CUSTOMPROP2;
  3075. ulOtherColTag = (ulShowingColTag == PR_WAB_CUSTOMPROP1) ? PR_WAB_CUSTOMPROP2 : PR_WAB_CUSTOMPROP1;
  3076. // lets remove the tag that is displayed in the other col
  3077. for( i = 0; i < MAXNUM_MENUPROPS; i++)
  3078. {
  3079. if( MenuToPropTagMap[i] == ulOtherColTag )
  3080. {
  3081. if( RemoveMenu( hMenuTrackPopUp, i, MF_BYPOSITION) )
  3082. break;
  3083. else
  3084. DebugTrace( TEXT("could not remove menu: %x\n"), GetLastError() );
  3085. }
  3086. }
  3087. if( i == MAXNUM_MENUPROPS )
  3088. DebugTrace( TEXT("Did not find other col's prop tag\n"));
  3089. if( ulShowingColTag != ulOtherColTag )
  3090. {
  3091. UINT iMenuEntry;
  3092. // potential bug, if someone sets value in registry
  3093. // then could have two columns with the same name and that
  3094. // would be bad because we would be looking for an entry
  3095. // that does not exist
  3096. for( j = 0; j < MAXNUM_MENUPROPS; j++)
  3097. {
  3098. if( ulShowingColTag == MenuToPropTagMap[j] )
  3099. {
  3100. // num of items that can be in column heads
  3101. Assert( j != i ); // both cols have same value, bad!
  3102. iMenuEntry = ( j > i ) ? j - 1 : j;
  3103. CheckMenuRadioItem( hMenuTrackPopUp,
  3104. 0,
  3105. MAXNUM_MENUPROPS - 1, // minus one because there will be one missing
  3106. iMenuEntry,
  3107. MF_BYPOSITION);
  3108. break;
  3109. }
  3110. }
  3111. if( j == MAXNUM_MENUPROPS )
  3112. {
  3113. DebugTrace( TEXT("Did not find match for checkbutton \n"));
  3114. }
  3115. }
  3116. }
  3117. #endif // COLSEL_MENU
  3118. }
  3119. //
  3120. // Popup the menu - if this was a toolbar action just pop up the submenu
  3121. //
  3122. if(LV == lvToolBarAction)
  3123. hm = hMenuAction;
  3124. else if(LV == lvToolBarNewEntry)
  3125. hm = hMenuNewEntry;
  3126. else
  3127. hm = hMenuTrackPopUp;
  3128. if(hMenuNewEntry)
  3129. {
  3130. if(!bIsWABSessionProfileAware((LPIAB)lpIAB) ||
  3131. LV == lvDialogABTo || LV == lvDialogABCC ||
  3132. LV == lvDialogABBCC || LV == lvDialogModalABContents ||
  3133. LV == lvDialogABContents )
  3134. {
  3135. RemoveMenu(hMenuNewEntry, 2, MF_BYPOSITION); // remove new folder option
  3136. }
  3137. else
  3138. {
  3139. // Since this could be a rt-click menu, check the drophighlight else the selection
  3140. //EnableMenuItem(hMenuNewEntry,2,MF_BYPOSITION | MF_ENABLED);
  3141. //if(hWndTV && bDoesThisWABHaveAnyUsers((LPIAB)lpIAB))
  3142. //{
  3143. // if(TreeView_GetDropHilight(hWndTV))
  3144. // EnableMenuItem( hMenuNewEntry,2,
  3145. // MF_BYPOSITION | (TreeView_GetDropHilight(hWndTV)!=TreeView_GetRoot(hWndTV) ? MF_ENABLED : MF_GRAYED));
  3146. //else if(TreeView_GetSelection(hWndTV) == TreeView_GetRoot(hWndTV))
  3147. // EnableMenuItem(hMenuNewEntry,2,MF_BYPOSITION | MF_GRAYED);
  3148. //}
  3149. }
  3150. }
  3151. nret = TrackPopupMenu( hm, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  3152. LOWORD(lParam), HIWORD(lParam),
  3153. 0, GetParent(hWndLV), NULL);
  3154. DestroyMenu(hMenu);
  3155. /*
  3156. nret = TrackPopupMenuEx(hm, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  3157. LOWORD(lParam), HIWORD(lParam), GetParent(hWndLV), NULL);
  3158. DestroyMenu(hMenu);
  3159. */
  3160. out:
  3161. return nret;
  3162. }
  3163. //$$/////////////////////////////////////////////////////////////
  3164. //
  3165. // GetChildClientRect - Gets the child's coordinates in its parents
  3166. // client units
  3167. //
  3168. // hWndChild - handle of child
  3169. // lprc - returned RECT.
  3170. //
  3171. ///////////////////////////////////////////////////////////////
  3172. void GetChildClientRect(HWND hWndChild, LPRECT lprc)
  3173. {
  3174. RECT rc;
  3175. POINT ptTop,ptBottom;
  3176. HWND hWndParent;
  3177. ZeroMemory(lprc, sizeof(*lprc));
  3178. if(!hWndChild)
  3179. goto out;
  3180. hWndParent = GetParent(hWndChild);
  3181. if(!hWndParent)
  3182. goto out;
  3183. GetWindowRect(hWndChild,&rc);
  3184. //
  3185. //This api working in both mirrored and unmirrored windows.
  3186. //
  3187. MapWindowPoints(NULL, hWndParent, (LPPOINT)&rc, 2);
  3188. ptTop.x = rc.left;
  3189. ptTop.y = rc.top;
  3190. ptBottom.x = rc.right;
  3191. ptBottom.y = rc.bottom;
  3192. (*lprc).left = ptTop.x;
  3193. (*lprc).top = ptTop.y;
  3194. (*lprc).right = ptBottom.x;
  3195. (*lprc).bottom = ptBottom.y;
  3196. out:
  3197. return;
  3198. }
  3199. //$$/////////////////////////////////////////////////////////////
  3200. //
  3201. // DoLVQuickFind - Simple quick find routine for matching edit box contents to
  3202. // List view entries
  3203. //
  3204. // hWndEdit - handle of Edit Box
  3205. // hWndLV - handle of List View
  3206. //
  3207. ///////////////////////////////////////////////////////////////
  3208. void DoLVQuickFind(HWND hWndEdit, HWND hWndLV)
  3209. {
  3210. TCHAR szBuf[MAX_PATH] = TEXT("");
  3211. int iItemIndex = 0;
  3212. LV_FINDINFO lvF = {0};
  3213. lvF.flags = LVFI_PARTIAL | LVFI_STRING | LVFI_WRAP;
  3214. if(!GetWindowText(hWndEdit,szBuf,ARRAYSIZE(szBuf)))
  3215. return;
  3216. TrimSpaces(szBuf);
  3217. if(lstrlen(szBuf))
  3218. {
  3219. lvF.psz = szBuf;
  3220. iItemIndex = ListView_FindItem(hWndLV,-1, &lvF);
  3221. //if (iItemIndex < 0) iItemIndex = 0;
  3222. if(iItemIndex != -1)
  3223. {
  3224. ULONG cSel=0;
  3225. cSel = ListView_GetSelectedCount(hWndLV);
  3226. if(cSel)
  3227. {
  3228. // is there anything else selected ? - deselect and and
  3229. // select this item ...
  3230. int iOldItem = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  3231. while(iOldItem != -1)
  3232. {
  3233. ListView_SetItemState ( hWndLV, // handle to listview
  3234. iOldItem, // index to listview item
  3235. 0, // item state
  3236. LVIS_FOCUSED | LVIS_SELECTED);
  3237. iOldItem = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  3238. }
  3239. }
  3240. LVSelectItem ( hWndLV, iItemIndex);
  3241. }
  3242. }
  3243. return;
  3244. }
  3245. //$$////////////////////////////////////////////////////////////////////////////////////////////////
  3246. //
  3247. // HrGetPropArray - for a selected resolved property (either in select_recipient or
  3248. // pick_user mode ... get the list of minimum required props as well
  3249. // as desired props (if they exist)
  3250. //
  3251. // lpIAB - AddrBook Object
  3252. // hPropertyStore - handle to prop store
  3253. // lpPTA - Array of props to return - NULL to return ALL the props
  3254. // cbEntryID, lpEntryID - id of object
  3255. // ulFlags - 0 or MAPI_UNICODE
  3256. // cValues, lppPropArray - returned props
  3257. //
  3258. //////////////////////////////////////////////////////////////////////////////////////////////////
  3259. HRESULT HrGetPropArray( LPADRBOOK lpAdrBook,
  3260. LPSPropTagArray lpPTA,
  3261. ULONG cbEntryID,
  3262. LPENTRYID lpEntryID,
  3263. ULONG ulFlags,
  3264. ULONG * lpcValues,
  3265. LPSPropValue * lppPropArray)
  3266. {
  3267. HRESULT hr = hrSuccess;
  3268. LPMAPIPROP lpMailUser = NULL;
  3269. LPSPropValue lpPropArray = NULL;
  3270. ULONG ulObjType;
  3271. ULONG cValues;
  3272. *lppPropArray = NULL;
  3273. if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  3274. cbEntryID, // cbEntryID
  3275. lpEntryID, // entryid
  3276. NULL, // interface
  3277. 0, // ulFlags
  3278. &ulObjType, // returned object type
  3279. (LPUNKNOWN *)&lpMailUser)))
  3280. {
  3281. // Failed! Hmmm.
  3282. DebugTraceResult( TEXT("Address: IAB->OpenEntry:"), hr);
  3283. goto exit;
  3284. }
  3285. Assert(lpMailUser);
  3286. //TBD - Check ObjectType here
  3287. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser,
  3288. (LPSPropTagArray)lpPTA, // lpPropTagArray
  3289. ulFlags,
  3290. &cValues, // how many properties were there?
  3291. &lpPropArray)))
  3292. {
  3293. DebugTraceResult( TEXT("Address: IAB->GetProps:"), hr);
  3294. goto exit;
  3295. }
  3296. *lppPropArray = lpPropArray;
  3297. *lpcValues = cValues;
  3298. exit:
  3299. if (HR_FAILED(hr))
  3300. {
  3301. if (lpPropArray)
  3302. MAPIFreeBuffer(lpPropArray);
  3303. }
  3304. if (lpMailUser)
  3305. lpMailUser->lpVtbl->Release(lpMailUser);
  3306. return hr;
  3307. }
  3308. //$$///////////////////////////////////////////////////////////////
  3309. //
  3310. // SubStringSearchEx - Same as SubStringSearch except it does some
  3311. // language related processing and mapping of dbcs input
  3312. // strings etc
  3313. //
  3314. // pszTarget - Target string
  3315. // pszSearch - SubString to Search for
  3316. //
  3317. // returns - TRUE if match found
  3318. // FALSE if no match
  3319. //
  3320. /////////////////////////////////////////////////////////////////
  3321. BOOL SubstringSearchEx(LPTSTR pszTarget, LPTSTR pszSearch, LCID lcid)
  3322. {
  3323. if(!pszTarget && !pszSearch)
  3324. return TRUE;
  3325. if(!pszTarget || !pszSearch)
  3326. return FALSE;
  3327. if(lcid)
  3328. {
  3329. LPTSTR lpTH = NULL, lpSH = NULL;
  3330. int nLenTH = 0, nLenSH = 0;
  3331. LPTSTR lpT = NULL, lpS = NULL;
  3332. BOOL bRet = FALSE;
  3333. // Looks like this will have to be a two step process
  3334. // First convert all half-width characters to full-width characters
  3335. // Then convert all full-width katakana to full-width hirangana
  3336. // Step 1. Convert half width and full width katakana to hiragana to full width
  3337. int nLenT = LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszTarget, lstrlen(pszTarget)+1, lpT, 0);
  3338. int nLenS = LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszSearch, lstrlen(pszSearch)+1, lpS, 0);
  3339. lpT = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenT+1));
  3340. lpS = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenS+1));
  3341. if(!lpT || !lpS)
  3342. goto err;
  3343. LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszTarget, lstrlen(pszTarget)+1, lpT, nLenT);
  3344. LCMapString(lcid, LCMAP_FULLWIDTH | LCMAP_HIRAGANA, pszSearch, lstrlen(pszSearch)+1, lpS, nLenS);
  3345. lpS[nLenS]=lpT[nLenT]='\0';
  3346. // Step 2. Convert all to Half Width Hirangana
  3347. nLenTH = LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpT, lstrlen(lpT)+1, lpTH, 0);
  3348. nLenSH = LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpS, lstrlen(lpS)+1, lpSH, 0);
  3349. lpTH = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenTH+1));
  3350. lpSH = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(nLenSH+1));
  3351. if(!lpTH || !lpSH)
  3352. goto err;
  3353. LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpT, lstrlen(lpT)+1, lpTH, nLenTH);
  3354. LCMapString(lcid, LCMAP_HALFWIDTH | LCMAP_HIRAGANA, lpS, lstrlen(lpS)+1, lpSH, nLenSH);
  3355. lpSH[nLenSH]=lpTH[nLenTH]='\0';
  3356. // by now, all strings should be in Full Width Hirangana ..
  3357. bRet = SubstringSearch(lpTH, lpSH);
  3358. err:
  3359. if(lpT)
  3360. LocalFree(lpT);
  3361. if(lpS)
  3362. LocalFree(lpS);
  3363. if(lpTH)
  3364. LocalFree(lpTH);
  3365. if(lpSH)
  3366. LocalFree(lpSH);
  3367. return bRet;
  3368. }
  3369. else
  3370. return(SubstringSearch(pszTarget, pszSearch));
  3371. }
  3372. //$$///////////////////////////////////////////////////////////////
  3373. //
  3374. // SubStringSearch - Used for doing partial resolves - Brute force
  3375. // search routine stolen from Athena
  3376. //
  3377. // TBD - Is this DBCS safe .. ???
  3378. //
  3379. // pszTarget - Target string
  3380. // pszSearch - SubString to Search for
  3381. //
  3382. // returns - TRUE if match found
  3383. // FALSE if no match
  3384. //
  3385. /////////////////////////////////////////////////////////////////
  3386. BOOL SubstringSearch(LPTSTR pszTarget, LPTSTR pszSearch)
  3387. {
  3388. LPTSTR pszT = pszTarget;
  3389. LPTSTR pszS = pszSearch;
  3390. if(!pszTarget && !pszSearch)
  3391. return TRUE;
  3392. if(!pszTarget || !pszSearch)
  3393. return FALSE;
  3394. if(!lstrlen(pszTarget) && !lstrlen(pszSearch))
  3395. return TRUE;
  3396. if(!lstrlen(pszTarget) || !lstrlen(pszSearch))
  3397. return FALSE;
  3398. while (*pszT && *pszS)
  3399. {
  3400. if (*pszT != *pszS &&
  3401. (TCHAR) CharLower((LPTSTR)(DWORD_PTR)MAKELONG(*pszT, 0)) != *pszS &&
  3402. (TCHAR) CharUpper((LPTSTR)(DWORD_PTR)MAKELONG(*pszT, 0)) != *pszS)
  3403. {
  3404. pszT -= (pszS - pszSearch);
  3405. pszT = CharNext(pszT); // dont start searching at half chars
  3406. pszS = pszSearch;
  3407. }
  3408. else
  3409. {
  3410. pszS++;
  3411. pszT++; // as long as the search is going on, do byte comparisons
  3412. }
  3413. }
  3414. return (*pszS == 0);
  3415. }
  3416. //$$
  3417. /****************************************************************************
  3418. FUNCTION: GetThreadStoragePointer()
  3419. PURPOSE: gets the private storage pointer for a thread, allocating one
  3420. if it does not exist (i.e. the thread didn't go through LibMain
  3421. THREAD_ATTACH)
  3422. PARAMETERS: none
  3423. RETURNS: a pointer to the thread's private storage
  3424. NULL, if there was a failure (usually memory allocation failure)
  3425. ****************************************************************************/
  3426. LPPTGDATA __fastcall GetThreadStoragePointer()
  3427. {
  3428. LPPTGDATA lpPTGData=TlsGetValue(dwTlsIndex);
  3429. // if the thread does not have a private storage, it did not go through
  3430. // THREAD_ATTACH and we need to do this here.
  3431. if (!lpPTGData)
  3432. {
  3433. DebugPrintTrace(( TEXT("GetThreadStoragePointer: no private storage for this thread 0x%.8x\n"),GetCurrentThreadId()));
  3434. lpPTGData = (LPPTGDATA) LocalAlloc(LPTR, sizeof(PTGDATA));
  3435. if (lpPTGData)
  3436. TlsSetValue(dwTlsIndex, lpPTGData);
  3437. }
  3438. return lpPTGData;
  3439. }
  3440. //$$////////////////////////////////////////////////////////////////////////
  3441. //
  3442. // HrCreateNewEntry - Creates a new mailuser or DistList
  3443. //
  3444. // lpIAB - handle to AdrBook object
  3445. // hWndParent - hWnd for showing dialogs
  3446. // ulCreateObjectType - MailUser or DistList
  3447. // ulFlags = CREATE_DUP_CHECK_STRICT or 0
  3448. // cValues - PropCount of New properties from which to create
  3449. // the object
  3450. // lpPropArray - Props for this new object
  3451. // lpcbEntryID, lppEntryID - returned, new entryid for newly created object
  3452. // cbEIDContainer, lpEIDContainer - container in which to create this entry
  3453. // ulContObjType - The container object type - this could be a DISTLIST of an ABCONT
  3454. // if this is an ABCONT, we open the container and create the entry in the container
  3455. // If it is a DISTLIST, we open the PAB, create the entry in the PAB and then
  3456. // add the entry to the specified entryid
  3457. //
  3458. ////////////////////////////////////////////////////////////////////////////
  3459. HRESULT HrCreateNewEntry( LPADRBOOK lpIAB, // AdrBook Object
  3460. HWND hWndParent, // hWnd for Dialogs
  3461. ULONG ulCreateObjectType, //MAILUSER or DISTLIST
  3462. ULONG cbEIDCont,
  3463. LPENTRYID lpEIDCont,
  3464. ULONG ulContObjType,
  3465. ULONG ulFlags,
  3466. BOOL bShowBeforeAdding,
  3467. ULONG cValues,
  3468. LPSPropValue lpPropArray,
  3469. ULONG *lpcbEntryID,
  3470. LPENTRYID *lppEntryID )
  3471. {
  3472. LPABCONT lpContainer = NULL;
  3473. LPMAPIPROP lpMailUser = NULL;
  3474. HRESULT hr = hrSuccess;
  3475. ULONG ulObjType = 0;
  3476. ULONG cbWABEID = 0;
  3477. LPENTRYID lpWABEID = NULL;
  3478. LPSPropValue lpCreateEIDs = NULL;
  3479. LPSPropValue lpNewProps = NULL;
  3480. ULONG cNewProps;
  3481. SCODE sc = S_OK;
  3482. ULONG nIndex;
  3483. ULONG cbTplEID = 0;
  3484. LPENTRYID lpTplEID = NULL;
  3485. BOOL bFirst = TRUE;
  3486. BOOL bChangesMade = FALSE;
  3487. ULONG cbEIDContainer = 0;
  3488. LPENTRYID lpEIDContainer = NULL;
  3489. DebugPrintTrace(( TEXT("HrCreateNewEntry: entry\n")));
  3490. if ( (!lpIAB) ||
  3491. ((ulFlags != 0) && (ulFlags != CREATE_CHECK_DUP_STRICT)) ||
  3492. ((ulCreateObjectType != MAPI_MAILUSER) && (ulCreateObjectType != MAPI_DISTLIST)) )
  3493. {
  3494. hr = MAPI_E_INVALID_PARAMETER;
  3495. goto out;
  3496. }
  3497. if(lpcbEntryID)
  3498. *lpcbEntryID = 0;
  3499. if(lppEntryID)
  3500. *lppEntryID = NULL;
  3501. if(ulContObjType == MAPI_ABCONT && cbEIDCont && lpEIDCont)
  3502. {
  3503. cbEIDContainer = cbEIDCont;
  3504. lpEIDContainer = lpEIDCont;
  3505. }
  3506. if(!cbEIDContainer || !lpEIDContainer)
  3507. {
  3508. SetVirtualPABEID((LPIAB)lpIAB, &cbWABEID, &lpWABEID);
  3509. if (HR_FAILED(hr = lpIAB->lpVtbl->GetPAB( lpIAB, &cbWABEID, &lpWABEID)))
  3510. {
  3511. DebugPrintError(( TEXT("GetPAB Failed\n")));
  3512. goto out;
  3513. }
  3514. }
  3515. if (HR_FAILED(hr = lpIAB->lpVtbl->OpenEntry(lpIAB,
  3516. (cbWABEID ? cbWABEID : cbEIDContainer),
  3517. (lpWABEID ? lpWABEID : lpEIDContainer), // EntryID to open
  3518. NULL, // interface
  3519. 0, // flags
  3520. &ulObjType,
  3521. (LPUNKNOWN *)&lpContainer)))
  3522. {
  3523. DebugPrintError(( TEXT("OpenEntry Failed\n")));
  3524. goto out;
  3525. }
  3526. // Opened PAB container OK
  3527. // Get us the default creation entryids
  3528. if (HR_FAILED(hr = lpContainer->lpVtbl->GetProps( lpContainer,
  3529. (LPSPropTagArray)&ptaCreate,
  3530. MAPI_UNICODE,
  3531. &cNewProps,
  3532. &lpCreateEIDs) ) )
  3533. {
  3534. DebugPrintError(( TEXT("Can't get container properties for WAB\n")));
  3535. // Bad stuff here!
  3536. goto out;
  3537. }
  3538. // Validate the properites
  3539. if ( lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
  3540. lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
  3541. {
  3542. DebugPrintError(( TEXT("Container Property Errors\n")));
  3543. goto out;
  3544. }
  3545. if(ulCreateObjectType == MAPI_DISTLIST)
  3546. nIndex = icrPR_DEF_CREATE_DL;
  3547. else
  3548. nIndex = icrPR_DEF_CREATE_MAILUSER;
  3549. cbTplEID = lpCreateEIDs[nIndex].Value.bin.cb;
  3550. lpTplEID = (LPENTRYID) lpCreateEIDs[nIndex].Value.bin.lpb;
  3551. //Retry:
  3552. if (HR_FAILED(hr = lpContainer->lpVtbl->CreateEntry( lpContainer,
  3553. cbTplEID,
  3554. lpTplEID,
  3555. ulFlags,
  3556. &lpMailUser)))
  3557. {
  3558. DebugPrintError(( TEXT("Creating DISTLIST failed\n")));
  3559. goto out;
  3560. }
  3561. if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, // this
  3562. cValues, // cValues
  3563. lpPropArray, // property array
  3564. NULL)))
  3565. {
  3566. DebugPrintError(( TEXT("Setprops failed\n")));
  3567. goto out;
  3568. }
  3569. if ( bFirst &&
  3570. bShowBeforeAdding &&
  3571. HR_FAILED(hr = HrShowDetails( lpIAB,
  3572. hWndParent,
  3573. NULL,
  3574. 0, NULL,
  3575. NULL, NULL,
  3576. (LPMAPIPROP)lpMailUser,
  3577. SHOW_OBJECT,
  3578. MAPI_MAILUSER,
  3579. &bChangesMade)))
  3580. {
  3581. goto out;
  3582. }
  3583. hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
  3584. KEEP_OPEN_READWRITE);
  3585. if(HR_FAILED(hr))
  3586. {
  3587. switch(hr)
  3588. {
  3589. case MAPI_E_NOT_ENOUGH_DISK:
  3590. hr = HandleSaveChangedInsufficientDiskSpace(hWndParent, (LPMAILUSER) lpMailUser);
  3591. break;
  3592. case MAPI_E_COLLISION:
  3593. {
  3594. LPSPropValue lpspv = NULL;
  3595. if (bFirst &&
  3596. !HR_FAILED(HrGetOneProp((LPMAPIPROP)lpMailUser,
  3597. PR_DISPLAY_NAME,
  3598. &lpspv)))
  3599. {
  3600. switch( ShowMessageBoxParam( hWndParent,
  3601. idsEntryAlreadyExists,
  3602. MB_YESNO | MB_ICONEXCLAMATION,
  3603. lpspv->Value.LPSZ))
  3604. {
  3605. /***/
  3606. case IDNO:
  3607. FreeBufferAndNull(&lpspv);
  3608. hr = MAPI_W_ERRORS_RETURNED; //S_OK;
  3609. goto out;
  3610. break;
  3611. /***/
  3612. case IDYES:
  3613. // At this point the user may have modified the properties
  3614. // of this MailUser. Hence we can't discard the mailuser
  3615. // Instead we'll just cheat a little, change the save
  3616. // flag on the mailuser directly and do a SaveChanges
  3617. ((LPMailUser) lpMailUser)->ulCreateFlags |= (CREATE_REPLACE | CREATE_MERGE);
  3618. hr = lpMailUser->lpVtbl->SaveChanges( lpMailUser,
  3619. KEEP_OPEN_READWRITE);
  3620. if(hr == MAPI_E_NOT_ENOUGH_DISK)
  3621. hr = HandleSaveChangedInsufficientDiskSpace(hWndParent, (LPMAILUSER) lpMailUser);
  3622. FreeBufferAndNull(&lpspv);
  3623. //UlRelease(lpMailUser);
  3624. //lpMailUser = NULL;
  3625. //bFirst = FALSE;
  3626. //goto Retry;
  3627. break;
  3628. }
  3629. }
  3630. }
  3631. break;
  3632. default:
  3633. DebugPrintError(( TEXT("SaveChanges failed: %x\n"),hr));
  3634. goto out;
  3635. break;
  3636. }
  3637. }
  3638. DebugObjectProps((LPMAPIPROP)lpMailUser, TEXT("New Entry"));
  3639. // Get the EntryID so we can return it...
  3640. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps( lpMailUser,
  3641. (LPSPropTagArray)&ptaEid,
  3642. MAPI_UNICODE,
  3643. &cNewProps,
  3644. &lpNewProps)))
  3645. {
  3646. DebugPrintError(( TEXT("Can't get EntryID\n")));
  3647. // Bad stuff here!
  3648. goto out;
  3649. }
  3650. if(lpcbEntryID && lppEntryID)
  3651. {
  3652. *lpcbEntryID = lpNewProps[ieidPR_ENTRYID].Value.bin.cb;
  3653. sc = MAPIAllocateBuffer(*lpcbEntryID, lppEntryID);
  3654. if (sc != S_OK)
  3655. {
  3656. DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
  3657. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3658. goto out;
  3659. }
  3660. CopyMemory(*lppEntryID, lpNewProps[ieidPR_ENTRYID].Value.bin.lpb, *lpcbEntryID);
  3661. }
  3662. if(ulContObjType == MAPI_DISTLIST && *lpcbEntryID && *lppEntryID && cbEIDContainer && lpEIDContainer)
  3663. AddEntryToGroupEx(lpIAB, *lpcbEntryID, *lppEntryID, cbEIDCont, lpEIDCont);
  3664. hr = hrSuccess;
  3665. out:
  3666. if (lpMailUser)
  3667. lpMailUser->lpVtbl->Release(lpMailUser);
  3668. if (lpNewProps)
  3669. MAPIFreeBuffer(lpNewProps);
  3670. if (lpCreateEIDs)
  3671. MAPIFreeBuffer(lpCreateEIDs);
  3672. if (lpContainer)
  3673. lpContainer->lpVtbl->Release(lpContainer);
  3674. if (lpWABEID)
  3675. MAPIFreeBuffer(lpWABEID);
  3676. return hr;
  3677. }
  3678. //$$/////////////////////////////////////////////////////////////////////
  3679. //
  3680. // HrGetWABTemplateID - Gets the WABs default Template ID for MailUsers
  3681. // or DistLists
  3682. //
  3683. // lpIAB - AdrBook Object
  3684. // ulObjectType - MailUser or DistList
  3685. // cbEntryID, lpEntryID - returned EntryID of this template
  3686. //
  3687. /////////////////////////////////////////////////////////////////////////
  3688. HRESULT HrGetWABTemplateID( LPADRBOOK lpAdrBook,
  3689. ULONG ulObjectType,
  3690. ULONG * lpcbEID,
  3691. LPENTRYID * lppEID)
  3692. {
  3693. LPABCONT lpContainer = NULL;
  3694. HRESULT hr = hrSuccess;
  3695. SCODE sc = ERROR_SUCCESS;
  3696. ULONG ulObjType = 0;
  3697. ULONG cbWABEID = 0;
  3698. LPENTRYID lpWABEID = NULL;
  3699. LPSPropValue lpCreateEIDs = NULL;
  3700. LPSPropValue lpNewProps = NULL;
  3701. ULONG cNewProps;
  3702. ULONG nIndex;
  3703. DebugPrintTrace(( TEXT("HrGetWABTemplateID: entry\n")));
  3704. if ( (!lpAdrBook) ||
  3705. ((ulObjectType != MAPI_MAILUSER) && (ulObjectType != MAPI_DISTLIST)) )
  3706. {
  3707. hr = MAPI_E_INVALID_PARAMETER;
  3708. goto out;
  3709. }
  3710. *lpcbEID = 0;
  3711. *lppEID = NULL;
  3712. if (HR_FAILED(hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID)))
  3713. {
  3714. DebugPrintError(( TEXT("GetPAB Failed\n")));
  3715. goto out;
  3716. }
  3717. if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  3718. cbWABEID, // size of EntryID to open
  3719. lpWABEID, // EntryID to open
  3720. NULL, // interface
  3721. 0, // flags
  3722. &ulObjType,
  3723. (LPUNKNOWN *)&lpContainer)))
  3724. {
  3725. DebugPrintError(( TEXT("OpenEntry Failed\n")));
  3726. goto out;
  3727. }
  3728. // Opened PAB container OK
  3729. // Get us the default creation entryids
  3730. if (HR_FAILED(hr = lpContainer->lpVtbl->GetProps( lpContainer,
  3731. (LPSPropTagArray)&ptaCreate,
  3732. MAPI_UNICODE,
  3733. &cNewProps,
  3734. &lpCreateEIDs) ) )
  3735. {
  3736. DebugPrintError(( TEXT("Can't get container properties for WAB\n")));
  3737. // Bad stuff here!
  3738. goto out;
  3739. }
  3740. // Validate the properites
  3741. if ( lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
  3742. lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
  3743. {
  3744. DebugPrintError(( TEXT("Container Property Errors\n")));
  3745. goto out;
  3746. }
  3747. if(ulObjectType == MAPI_DISTLIST)
  3748. nIndex = icrPR_DEF_CREATE_DL;
  3749. else
  3750. nIndex = icrPR_DEF_CREATE_MAILUSER;
  3751. *lpcbEID = lpCreateEIDs[nIndex].Value.bin.cb;
  3752. sc = MAPIAllocateBuffer(*lpcbEID,lppEID);
  3753. if (sc != S_OK)
  3754. {
  3755. DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
  3756. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3757. goto out;
  3758. }
  3759. CopyMemory(*lppEID,lpCreateEIDs[nIndex].Value.bin.lpb,*lpcbEID);
  3760. out:
  3761. if (lpCreateEIDs)
  3762. MAPIFreeBuffer(lpCreateEIDs);
  3763. if (lpContainer)
  3764. lpContainer->lpVtbl->Release(lpContainer);
  3765. if (lpWABEID)
  3766. MAPIFreeBuffer(lpWABEID);
  3767. return hr;
  3768. }
  3769. //$$/////////////////////////////////////////////////////////////////////
  3770. //
  3771. // UpdateListViewItemsByName - Updates the displayed name corresponding to
  3772. // each entry - by First Name or by Last Name depending on Sort criteria
  3773. // Called by the Sort routine ...
  3774. //
  3775. //
  3776. /////////////////////////////////////////////////////////////////////////
  3777. void UpdateListViewItemsByName(HWND hWndLV, BOOL bSortByLastName)
  3778. {
  3779. LV_ITEM lvi = {0};
  3780. ULONG ulCount = 0;
  3781. ULONG i;
  3782. lvi.mask = LVIF_PARAM;
  3783. lvi.iSubItem = colDisplayName;
  3784. lvi.lParam = 0;
  3785. ulCount = ListView_GetItemCount(hWndLV);
  3786. if (ulCount<=0)
  3787. return;
  3788. for(i=0;i<ulCount;i++)
  3789. {
  3790. LPRECIPIENT_INFO lpItem = NULL;
  3791. lvi.iItem = i;
  3792. if(!ListView_GetItem(hWndLV, &lvi))
  3793. continue;
  3794. lpItem = (LPRECIPIENT_INFO) lvi.lParam;
  3795. if (bSortByLastName)
  3796. StrCpyN(lpItem->szDisplayName, lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
  3797. else
  3798. StrCpyN(lpItem->szDisplayName, lpItem->szByFirstName,ARRAYSIZE(lpItem->szDisplayName));
  3799. ListView_SetItem(hWndLV, &lvi);
  3800. ListView_SetItemText(hWndLV,i,colDisplayName,lpItem->szDisplayName);
  3801. }
  3802. return;
  3803. }
  3804. //$$-----------------------------------------------------------------------
  3805. //|
  3806. //| SortListViewColumn - Sorting Routine for the List View
  3807. //|
  3808. //| HWndLV - handle of List View
  3809. //| iSortCol - ColumnSorted by ...
  3810. //| lpSortInfo - this particular dialogs sort info structure ...
  3811. //| bUseCurrentSettings - sometimes we want to call this function but dont want
  3812. //| to change the sort settings - those times we set this to true, in which
  3813. //| case, the iSortCol parameter is ignored
  3814. //|
  3815. //*------------------------------------------------------------------------
  3816. void SortListViewColumn(LPIAB lpIAB, HWND hWndLV, int iSortCol, LPSORT_INFO lpSortInfo, BOOL bUseCurrentSettings)
  3817. {
  3818. HCURSOR hOldCur = NULL;
  3819. if(!bUseCurrentSettings)
  3820. {
  3821. lpSortInfo->iOlderSortCol = lpSortInfo->iOldSortCol;
  3822. if (lpSortInfo->iOldSortCol == iSortCol)
  3823. {
  3824. // if we previously sorted by this column then toggle the sort mode
  3825. if(iSortCol == colDisplayName)
  3826. {
  3827. // For Display Name, the sort order is
  3828. // LastName Ascending
  3829. // False True
  3830. // False False
  3831. // True True
  3832. // True False
  3833. if(lpSortInfo->bSortByLastName && !lpSortInfo->bSortAscending)
  3834. lpSortInfo->bSortByLastName = FALSE;
  3835. else if(!lpSortInfo->bSortByLastName && !lpSortInfo->bSortAscending)
  3836. lpSortInfo->bSortByLastName = TRUE;
  3837. }
  3838. lpSortInfo->bSortAscending = !lpSortInfo->bSortAscending;
  3839. }
  3840. else
  3841. {
  3842. // this is a new column - sort ascending
  3843. lpSortInfo->bSortAscending = TRUE;
  3844. lpSortInfo->iOldSortCol = iSortCol;
  3845. }
  3846. }
  3847. hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  3848. UpdateListViewItemsByName(hWndLV,lpSortInfo->bSortByLastName);
  3849. ListView_SortItems( hWndLV, ListViewSort, (LPARAM) lpSortInfo);
  3850. SetColumnHeaderBmp(hWndLV, *lpSortInfo);
  3851. SetCursor(hOldCur);
  3852. // Highlight the first selected item we can find
  3853. if (ListView_GetSelectedCount(hWndLV) > 0)
  3854. ListView_EnsureVisible(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED), FALSE);
  3855. WriteRegistrySortInfo(lpIAB, *lpSortInfo);
  3856. return;
  3857. }
  3858. const LPTSTR lpszRegSortKeyName = TEXT("Software\\Microsoft\\WAB\\WAB Sort State");
  3859. const LPTSTR lpszRegSortKeyValueName = TEXT("State");
  3860. const LPTSTR lpszRegPositionKeyValueName = TEXT("Position");
  3861. const LPTSTR lpszRegFindPositionKeyValueName = TEXT("FindPosition");
  3862. //$$
  3863. /************************************************************************************
  3864. - ReadRegistrySortInfo
  3865. -
  3866. * Purpose:
  3867. * Getss the previously stored Sort Info into the registry so we can have
  3868. * persistence between sessions.
  3869. *
  3870. * Arguments:
  3871. * LPSORT_INFO lpSortInfo
  3872. *
  3873. * Returns:
  3874. * BOOL
  3875. *
  3876. *************************************************************************************/
  3877. BOOL ReadRegistrySortInfo(LPIAB lpIAB, LPSORT_INFO lpSortInfo)
  3878. {
  3879. BOOL bRet = FALSE;
  3880. HKEY hKey = NULL;
  3881. HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
  3882. DWORD dwLenName = sizeof(SORT_INFO);
  3883. DWORD dwDisposition = 0;
  3884. DWORD dwType = 0;
  3885. if (!lpSortInfo)
  3886. goto out;
  3887. // default value
  3888. //
  3889. lpSortInfo->iOldSortCol = colDisplayName;
  3890. lpSortInfo->iOlderSortCol = colDisplayName;
  3891. lpSortInfo->bSortAscending = TRUE;
  3892. lpSortInfo->bSortByLastName = bDNisByLN;
  3893. // Open key
  3894. if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
  3895. lpszRegSortKeyName,
  3896. 0, //reserved
  3897. NULL,
  3898. REG_OPTION_NON_VOLATILE,
  3899. KEY_READ,
  3900. NULL,
  3901. &hKey,
  3902. &dwDisposition))
  3903. {
  3904. goto out;
  3905. }
  3906. if(dwDisposition == REG_CREATED_NEW_KEY)
  3907. goto out;
  3908. // Now Read this key
  3909. if (ERROR_SUCCESS != RegQueryValueEx(hKey,
  3910. lpszRegSortKeyValueName,
  3911. NULL,
  3912. &dwType,
  3913. (LPBYTE) lpSortInfo,
  3914. &dwLenName))
  3915. {
  3916. DebugTrace( TEXT("RegQueryValueEx failed\n"));
  3917. goto out;
  3918. }
  3919. bRet = TRUE;
  3920. out:
  3921. if (hKey)
  3922. RegCloseKey(hKey);
  3923. return(bRet);
  3924. }
  3925. //$$
  3926. /*************************************************************************************
  3927. - WriteRegistrySortInfo
  3928. -
  3929. * Purpose:
  3930. * Write the current Sort Info into the registry so we can have
  3931. * persistence between sessions.
  3932. *
  3933. * Arguments:
  3934. * SORT_INFO SortInfo
  3935. *
  3936. * Returns:
  3937. * BOOL
  3938. *
  3939. *************************************************************************************/
  3940. BOOL WriteRegistrySortInfo(LPIAB lpIAB, SORT_INFO SortInfo)
  3941. {
  3942. BOOL bRet = FALSE;
  3943. // const LPTSTR lpszRegSortKeyName = TEXT( TEXT("Software\\Microsoft\\WAB\\WAB Sort State"));
  3944. HKEY hKey = NULL;
  3945. HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
  3946. DWORD dwLenName = sizeof(SORT_INFO);
  3947. DWORD dwDisposition =0;
  3948. // Open key
  3949. if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
  3950. lpszRegSortKeyName,
  3951. 0, //reserved
  3952. NULL,
  3953. REG_OPTION_NON_VOLATILE,
  3954. KEY_ALL_ACCESS,
  3955. NULL,
  3956. &hKey,
  3957. &dwDisposition))
  3958. {
  3959. DebugTrace( TEXT("RegCreateKeyEx failed\n"));
  3960. goto out;
  3961. }
  3962. // Now Write this key
  3963. if (ERROR_SUCCESS != RegSetValueEx( hKey,
  3964. lpszRegSortKeyValueName,
  3965. 0,
  3966. REG_BINARY,
  3967. (LPBYTE) &SortInfo,
  3968. dwLenName))
  3969. {
  3970. DebugTrace( TEXT("RegSetValue failed\n"));
  3971. goto out;
  3972. }
  3973. bRet = TRUE;
  3974. out:
  3975. if (hKey)
  3976. RegCloseKey(hKey);
  3977. return(bRet);
  3978. }
  3979. //$$************************************************************\
  3980. //*
  3981. //* SetLocalizedDisplayName - sets the localized display name as
  3982. //* per localization information/
  3983. //*
  3984. //* szBuf points to a predefined buffer of length ulzBuf.
  3985. //* lpszFirst/Middle/Last/Company can be NULL
  3986. //* If szBuffer is null and ulszBuf=0, then we return the lpszBuffer
  3987. //* created here in the lppRetBuf parameter...
  3988. //* Caller has to LocalFree lppszRetBuf
  3989. //*
  3990. //
  3991. // Rules for creating DisplayName
  3992. //
  3993. // - If there is no display name, and there is a first/middle/last name,
  3994. // we make display name = localized(First/Middle/Last)
  3995. // - If there is no DN or FML, but NN, we make DN = NickName
  3996. // - If there is no DN, FML, NN but Company Name, we make
  3997. // DN = Company Name
  3998. // - If there is no DN, FML, NN, CN, we fail
  3999. //\***************************************************************/
  4000. BOOL SetLocalizedDisplayName(
  4001. LPTSTR lpszFirstName,
  4002. LPTSTR lpszMiddleName,
  4003. LPTSTR lpszLastName,
  4004. LPTSTR lpszCompanyName,
  4005. LPTSTR lpszNickName,
  4006. LPTSTR * lppszBuf,
  4007. ULONG ulszBuf,
  4008. BOOL bDNbyLN,
  4009. LPTSTR lpTemplate,
  4010. LPTSTR * lppszRetBuf)
  4011. {
  4012. LPTSTR szBuf = NULL;
  4013. LPTSTR szResource = NULL;
  4014. LPTSTR lpszArg[3];
  4015. LPTSTR lpszFormatName = NULL;
  4016. LPVOID lpszBuffer = NULL;
  4017. BOOL bRet = FALSE;
  4018. int idResource =0;
  4019. if (!lpszFirstName && !lpszMiddleName && !lpszLastName && !lpszNickName && !lpszCompanyName)
  4020. goto out;
  4021. if (lppszBuf)
  4022. szBuf = *lppszBuf;
  4023. if(lpTemplate)
  4024. szResource = lpTemplate;
  4025. else
  4026. szResource = bDNbyLN ?
  4027. (bDNisByLN ? szResourceDNByLN : szResourceDNByCommaLN)
  4028. : szResourceDNByFN;
  4029. if (!lpszFirstName && !lpszMiddleName && !lpszLastName)
  4030. {
  4031. if(lpszNickName)
  4032. {
  4033. DWORD cchSize=lstrlen(lpszNickName) + 1;
  4034. // Use the NickName
  4035. if (! (lpszFormatName = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize)))
  4036. goto out;
  4037. StrCpyN(lpszFormatName, lpszNickName, cchSize);
  4038. }
  4039. else if(lpszCompanyName)
  4040. {
  4041. DWORD cchSize=lstrlen(lpszCompanyName) + 1;
  4042. // just use company name
  4043. if (! (lpszFormatName = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize)))
  4044. goto out;
  4045. StrCpyN(lpszFormatName, lpszCompanyName, cchSize);
  4046. }
  4047. else
  4048. goto out; //shouldnt happen
  4049. }
  4050. else
  4051. {
  4052. //Bug #101350 - (erici) lstrlen will AV (and handle it) if passed a NULL
  4053. if( (lpszFirstName && (lstrlen(lpszFirstName) >= MAX_UI_STR)) ||
  4054. (lpszMiddleName && (lstrlen(lpszMiddleName) >= MAX_UI_STR)) ||
  4055. (lpszLastName && (lstrlen(lpszLastName) >= MAX_UI_STR)) )
  4056. goto out;
  4057. lpszArg[0] = lpszFirstName ? lpszFirstName : szEmpty;
  4058. lpszArg[1] = lpszMiddleName? lpszMiddleName : szEmpty;
  4059. lpszArg[2] = lpszLastName ? lpszLastName : szEmpty;
  4060. // FormatMessage doesnt do partial copying .. so we need to assimilate the name
  4061. // first and then squeeze it into our buffer ...
  4062. //
  4063. if(!FormatMessage( FORMAT_MESSAGE_FROM_STRING |
  4064. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  4065. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  4066. szResource,
  4067. 0, //ignored
  4068. 0, //ignored
  4069. (LPTSTR) &lpszBuffer,
  4070. MAX_UI_STR,
  4071. (va_list *)lpszArg))
  4072. {
  4073. DebugPrintError(( TEXT("FormatStringFailed: %d\n"),GetLastError()));
  4074. goto out;
  4075. }
  4076. lpszFormatName = (LPTSTR) lpszBuffer;
  4077. TrimSpaces(lpszFormatName);
  4078. // If we dont have a last name and the sort is by last name, then
  4079. // we will get an ugly looking comma in the beginning for the english
  4080. // version only .. special case cheating here to remove that coma
  4081. //
  4082. if(bDNbyLN && (!lpszLastName || !lstrlen(lpszLastName)))
  4083. {
  4084. BOOL bSkipChar = FALSE;
  4085. if (lpszFormatName[0]==',')
  4086. {
  4087. bSkipChar = TRUE;
  4088. }
  4089. else
  4090. {
  4091. LPTSTR lp = lpszFormatName;
  4092. if(*lp == 0x81 && *(lp+1) == 0x41) // Japanese Comma is 0x810x41.. will this work ??
  4093. bSkipChar = TRUE;
  4094. }
  4095. if(bSkipChar)
  4096. {
  4097. LPTSTR lpszTmp = CharNext(lpszFormatName);
  4098. StrCpyN(lpszFormatName, lpszTmp, MAX_UI_STR);
  4099. TrimSpaces(lpszFormatName);
  4100. }
  4101. }
  4102. // Whatever the localizers combination of first middle last names for the
  4103. // display name (eg FML, LMF, LFM etc), if the middle element is missing,
  4104. // we'll get 2 blank spaces in the display name and we need to remove that.
  4105. // Search and replace double blanks.
  4106. {
  4107. LPTSTR lpsz=lpszFormatName,lpsz1=NULL;
  4108. while(lpsz && (*lpsz!='\0'))
  4109. {
  4110. lpsz1 = CharNext(lpsz);
  4111. if (IsSpace(lpsz) && IsSpace(lpsz1)) {
  4112. StrCpyN(lpsz, lpsz1, lstrlen(lpsz1)+1); // this is safe because we are
  4113. // copying the string over itself
  4114. continue; // use same lpsz
  4115. } else {
  4116. lpsz = lpsz1;
  4117. }
  4118. }
  4119. }
  4120. }
  4121. // If we were provided a buffer, use it ...
  4122. if((lppszRetBuf) && (szBuf == NULL) && (ulszBuf == 0))
  4123. {
  4124. *lppszRetBuf = lpszFormatName;
  4125. }
  4126. else
  4127. {
  4128. CopyTruncate(szBuf, lpszFormatName, ulszBuf);
  4129. }
  4130. bRet = TRUE;
  4131. out:
  4132. if((lpszFormatName) && (lppszRetBuf == NULL) && (ulszBuf != 0))
  4133. LocalFreeAndNull(&lpszFormatName);
  4134. return bRet;
  4135. }
  4136. //$$
  4137. //*------------------------------------------------------------------------
  4138. //| SetChildDefaultGUIFont: Callback function that sets all the children of
  4139. //| any window to the default GUI font -
  4140. //| needed for localization.
  4141. //|
  4142. //| hWndChild - handle to child
  4143. //| lParam - ignored
  4144. //|
  4145. //*------------------------------------------------------------------------
  4146. STDAPI_(BOOL) SetChildDefaultGUIFont(HWND hWndChild, LPARAM lParam)
  4147. {
  4148. // Code below is stolen from Shlwapi.dll
  4149. //
  4150. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  4151. HFONT hfont;
  4152. HFONT hfontDefault;
  4153. LOGFONT lf;
  4154. LOGFONT lfDefault;
  4155. HWND hWndParent = GetParent(hWndChild);
  4156. hfont = GetWindowFont(hWndParent ? hWndParent : hWndChild);
  4157. GetObject(hfont, sizeof(LOGFONT), &lf);
  4158. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lfDefault, 0);
  4159. if ( (lfDefault.lfCharSet == lf.lfCharSet) &&
  4160. (lfDefault.lfHeight == lf.lfHeight) &&
  4161. (PARENT_IS_DIALOG == lParam) )
  4162. {
  4163. // if the dialog already has the correct character set and size
  4164. // don't do anything.
  4165. return TRUE;
  4166. }
  4167. if(PARENT_IS_DIALOG == lParam)
  4168. hfontDefault = pt_hDlgFont;
  4169. else
  4170. hfontDefault = pt_hDefFont;
  4171. // If we already have hfont created, use it.
  4172. if(!hfontDefault)
  4173. {
  4174. // [bobn] Raid #88470: We should use the default size on dialogs
  4175. if(PARENT_IS_DIALOG == lParam)
  4176. lfDefault.lfHeight = lf.lfHeight;
  4177. if (!(hfontDefault=CreateFontIndirect(&lfDefault)))
  4178. {
  4179. // restore back in failure
  4180. hfontDefault = hfont;
  4181. }
  4182. if (hfontDefault != hfont)
  4183. {
  4184. if(PARENT_IS_DIALOG == lParam)
  4185. pt_hDlgFont = hfontDefault;
  4186. else
  4187. pt_hDefFont = hfontDefault;
  4188. }
  4189. }
  4190. if(!hfontDefault)
  4191. hfontDefault = GetStockObject(DEFAULT_GUI_FONT);
  4192. SetWindowFont(hWndChild, hfontDefault, FALSE);
  4193. return TRUE;
  4194. }
  4195. //$$
  4196. //*------------------------------------------------------------------------
  4197. //| HrGetLDAPContentsList: Gets ContentsList from an LDAP container - Opens
  4198. //| a container - populates it using the given restriction,
  4199. //| and puts its contents in the List View
  4200. //|
  4201. //| lpIAB - Address Book object
  4202. //| cbContainerEID, lpContainerEID - LDAP Container EntryID
  4203. //| SortInfo - Current Sort State
  4204. //| lpPropRes - Property Restriction with which to do the Search
  4205. //| lpPTA - PropTagArray to return - currently ignored
  4206. //| ulFlags - 0 - currently ignored
  4207. //| lppContentsList - Returned, filled Contents List
  4208. //| lpAdvFilter - alternate advanced filter used in place of the property restriction
  4209. //*------------------------------------------------------------------------
  4210. HRESULT HrGetLDAPContentsList(LPADRBOOK lpAdrBook,
  4211. ULONG cbContainerEID,
  4212. LPENTRYID lpContainerEID,
  4213. SORT_INFO SortInfo,
  4214. LPSRestriction lpPropRes,
  4215. LPTSTR lpAdvFilter,
  4216. LPSPropTagArray lpPTA,
  4217. ULONG ulFlags,
  4218. LPRECIPIENT_INFO * lppContentsList)
  4219. {
  4220. HRESULT hr = hrSuccess;
  4221. HRESULT hrSaveTmp = E_FAIL; // temporarily saves partial completion error so it can be propogated to calling funtion
  4222. ULONG ulObjectType = 0;
  4223. LPCONTAINER lpContainer = NULL;
  4224. LPMAPITABLE lpContentsTable = NULL;
  4225. LPSRowSet lpSRowSet = NULL;
  4226. ULONG i = 0,j=0;
  4227. LPRECIPIENT_INFO lpItem = NULL;
  4228. LPRECIPIENT_INFO lpLastListItem = NULL;
  4229. DebugPrintTrace(( TEXT("-----HrGetLDAPContentsList: entry\n")));
  4230. if(!lpPropRes && !lpAdvFilter)
  4231. {
  4232. DebugPrintError(( TEXT("No search restriction created\n")));
  4233. hr = E_FAIL;
  4234. goto out;
  4235. }
  4236. //
  4237. // First we need to open the container object corresponding to this Container EntryID
  4238. //
  4239. hr = lpAdrBook->lpVtbl->OpenEntry(
  4240. lpAdrBook,
  4241. cbContainerEID,
  4242. lpContainerEID,
  4243. NULL,
  4244. 0,
  4245. &ulObjectType,
  4246. (LPUNKNOWN *) &lpContainer);
  4247. if(HR_FAILED(hr))
  4248. {
  4249. DebugPrintError(( TEXT("OpenEntry Failed: %x\n"),hr));
  4250. goto out;
  4251. }
  4252. //
  4253. // Now we do a get contents table on this container ...
  4254. //
  4255. hr = lpContainer->lpVtbl->GetContentsTable(
  4256. lpContainer,
  4257. MAPI_UNICODE,
  4258. &lpContentsTable);
  4259. if(HR_FAILED(hr))
  4260. {
  4261. DebugPrintError(( TEXT("GetContentsTable Failed: %x\n"),hr));
  4262. goto out;
  4263. }
  4264. /****
  4265. //$$$$$$$$$$$$
  4266. // Test code
  4267. {
  4268. SPropValue valAnr;
  4269. SRestriction resAnr;
  4270. LPSRowSet prws;
  4271. LPTSTR lpsz = TEXT("Vikram");
  4272. // Set up the Ambiguous Name Resolution property value.
  4273. valAnr.ulPropTag = PR_ANR;
  4274. valAnr.Value.LPSZ = lpsz;
  4275. // Set up the Ambiguous Name Resolution restriction.
  4276. resAnr.rt = RES_PROPERTY;
  4277. resAnr.res.resProperty.relop = RELOP_EQ;
  4278. resAnr.res.resProperty.ulPropTag = valAnr.ulPropTag;
  4279. resAnr.res.resProperty.lpProp = &valAnr;
  4280. // Restrict the contents table.
  4281. // Set columns and query rows to see what state we fall in. We ask for one more
  4282. // row than the value of the Few/Many threshold. This allows us to tell whether
  4283. // we are a Few/Many ambiguity.
  4284. hr = lpContentsTable->lpVtbl->Restrict(lpContentsTable,
  4285. &resAnr,
  4286. TBL_BATCH);
  4287. hr = lpContentsTable->lpVtbl->SetColumns(lpContentsTable,
  4288. (LPSPropTagArray)&ptaResolveDefaults,
  4289. TBL_BATCH);
  4290. hr = lpContentsTable->lpVtbl->SeekRow(lpContentsTable,
  4291. BOOKMARK_BEGINNING,
  4292. 0, 0);
  4293. hr = lpContentsTable->lpVtbl->QueryRows(lpContentsTable,
  4294. 1,
  4295. 0,
  4296. &prws);
  4297. FreeProws(prws);
  4298. }
  4299. //$$$$$$$$$$$$
  4300. /*****/
  4301. // If the user has specified an advanced filter, we need to figure out some way to
  4302. // pass it to the LDAP routines while still taking advantage of our LDAP contents table
  4303. // To do this we will do a hack and pass in the lpAdvFilter cast to a LPPropRes and then
  4304. // recast back at the other end
  4305. // This may break if any changes are made to the table implementation
  4306. //
  4307. // We now do the find rows
  4308. hr = lpContentsTable->lpVtbl->FindRow(
  4309. lpContentsTable,
  4310. lpAdvFilter ? (LPSRestriction) lpAdvFilter : lpPropRes,
  4311. BOOKMARK_BEGINNING,
  4312. lpAdvFilter ? LDAP_USE_ADVANCED_FILTER : 0); //flags
  4313. if(HR_FAILED(hr))
  4314. {
  4315. DebugPrintError(( TEXT("FindRow Failed: %x\n"),hr));
  4316. goto out;
  4317. }
  4318. // if this was a partial completion error - we want to treat it as success
  4319. // but also propogate it to the calling function
  4320. if(hr == MAPI_W_PARTIAL_COMPLETION)
  4321. hrSaveTmp = hr;
  4322. // If we got this far, then we have a populated table
  4323. // We should be able to do a Query Rows here ...
  4324. hr = SetRecipColumns(lpContentsTable);
  4325. if(HR_FAILED(hr))
  4326. goto out;
  4327. hr = HrQueryAllRows(lpContentsTable,
  4328. NULL,
  4329. NULL,
  4330. NULL,
  4331. 0,
  4332. &lpSRowSet);
  4333. if (HR_FAILED(hr))
  4334. {
  4335. DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
  4336. goto out;
  4337. }
  4338. //
  4339. // if there's anything in the contents list flush it away
  4340. //
  4341. if (*lppContentsList)
  4342. {
  4343. lpItem = (*lppContentsList);
  4344. (*lppContentsList) = lpItem->lpNext;
  4345. FreeRecipItem(&lpItem);
  4346. }
  4347. *lppContentsList = NULL;
  4348. lpItem = NULL;
  4349. for(i=0;i<lpSRowSet->cRows;i++)
  4350. {
  4351. LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
  4352. ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
  4353. lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  4354. if (!lpItem)
  4355. {
  4356. DebugPrintError(( TEXT("LocalAlloc Failed \n")));
  4357. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4358. goto out;
  4359. }
  4360. GetRecipItemFromPropArray(ulcPropCount, lpPropArray, &lpItem);
  4361. // The critical prop is display name - without it we are nothing ...
  4362. // If no display name, junk this entry and continue ..
  4363. if (!lstrlen(lpItem->szDisplayName) || (lpItem->cbEntryID == 0)) //This entry id is not allowed
  4364. {
  4365. FreeRecipItem(&lpItem);
  4366. continue;
  4367. }
  4368. // Tag this as an item from the contents and not from the original AdrList
  4369. lpItem->ulOldAdrListEntryNumber = 0;
  4370. // The entryids are in sorted order by display name
  4371. // Depending on the sort order - we want this list to also be sorted by display
  4372. // name or by reverse display name ...
  4373. if (SortInfo.bSortByLastName)
  4374. StrCpyN(lpItem->szDisplayName,lpItem->szByLastName,ARRAYSIZE(lpItem->szDisplayName));
  4375. if(!SortInfo.bSortAscending)
  4376. {
  4377. //Add it to the contents linked list
  4378. lpItem->lpNext = (*lppContentsList);
  4379. if (*lppContentsList)
  4380. (*lppContentsList)->lpPrev = lpItem;
  4381. lpItem->lpPrev = NULL;
  4382. *lppContentsList = lpItem;
  4383. }
  4384. else
  4385. {
  4386. if(*lppContentsList == NULL)
  4387. (*lppContentsList) = lpItem;
  4388. if(lpLastListItem)
  4389. lpLastListItem->lpNext = lpItem;
  4390. lpItem->lpPrev = lpLastListItem;
  4391. lpItem->lpNext = NULL;
  4392. lpLastListItem = lpItem;
  4393. }
  4394. lpItem = NULL;
  4395. } //for i ....
  4396. // reset this error if applicable so calling function can treat it correctly
  4397. if(hrSaveTmp == MAPI_W_PARTIAL_COMPLETION)
  4398. hr = hrSaveTmp;
  4399. out:
  4400. if(lpSRowSet)
  4401. FreeProws(lpSRowSet);
  4402. if(lpContentsTable)
  4403. lpContentsTable->lpVtbl->Release(lpContentsTable);
  4404. if(lpContainer)
  4405. lpContainer->lpVtbl->Release(lpContainer);
  4406. if (HR_FAILED(hr))
  4407. {
  4408. while(*lppContentsList)
  4409. {
  4410. lpItem = *lppContentsList;
  4411. *lppContentsList=lpItem->lpNext;
  4412. FreeRecipItem(&lpItem);
  4413. }
  4414. }
  4415. return hr;
  4416. }
  4417. //$$
  4418. /******************************************************************************
  4419. //
  4420. // HrGetWABContents - Gets and fills the current list view with contents from the
  4421. // local store.
  4422. //
  4423. // hWndList - Handle to List View which we will populate
  4424. // lpIAB - Handle to Address Bok object
  4425. // SortInfo - Current Sort State
  4426. // lppContentsList - linked list in which we will store info about entries
  4427. //
  4428. /******************************************************************************/
  4429. HRESULT HrGetWABContents( HWND hWndList,
  4430. LPADRBOOK lpAdrBook,
  4431. LPSBinary lpsbContainer,
  4432. SORT_INFO SortInfo,
  4433. LPRECIPIENT_INFO * lppContentsList)
  4434. {
  4435. HRESULT hr = hrSuccess;
  4436. LPIAB lpIAB = (LPIAB) lpAdrBook;
  4437. int nSelectedItem = ListView_GetNextItem(hWndList, -1, LVNI_SELECTED);
  4438. if(nSelectedItem < 0)
  4439. nSelectedItem = 0;
  4440. SendMessage(hWndList, WM_SETREDRAW, FALSE, 0L);
  4441. ClearListView(hWndList, lppContentsList);
  4442. if (HR_FAILED(hr = HrGetWABContentsList(
  4443. lpIAB,
  4444. SortInfo,
  4445. NULL,
  4446. NULL,
  4447. 0,
  4448. lpsbContainer,
  4449. FALSE,
  4450. lppContentsList)))
  4451. {
  4452. goto out;
  4453. }
  4454. // There is a performance issue of filling names
  4455. // If names are sorted by first name and are by first col,
  4456. // we can show them updated - otherwise we cant
  4457. if (HR_FAILED(hr = HrFillListView( hWndList,
  4458. *lppContentsList)))
  4459. {
  4460. goto out;
  4461. }
  4462. /*
  4463. if((SortInfo.iOldSortCol == colDisplayName) &&
  4464. (!SortInfo.bSortByLastName))
  4465. {
  4466. // Already Sorted
  4467. SetColumnHeaderBmp(hWndList, SortInfo);
  4468. }
  4469. else
  4470. */ {
  4471. // Otherwise sort
  4472. SortListViewColumn(lpIAB, hWndList, colDisplayName, &SortInfo, TRUE);
  4473. }
  4474. /*
  4475. if (ListView_GetSelectedCount(hWndList) <= 0)
  4476. {
  4477. // nothing selected - so select 1st item
  4478. // Select the first item in the List View
  4479. LVSelectItem(hWndList, 0);
  4480. }
  4481. else
  4482. {
  4483. LVSelectItem(hWndList, ListView_GetNextItem(hWndList, -1, LVNI_SELECTED));
  4484. }
  4485. */
  4486. LVSelectItem(hWndList, nSelectedItem);
  4487. out:
  4488. SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
  4489. return(hr);
  4490. }
  4491. //$$
  4492. /******************************************************************************/
  4493. //
  4494. // HrGetLDAPSearchRestriction -
  4495. //
  4496. //
  4497. // For a simple search we have the following data to work with
  4498. // Country - PR_COUNTRY
  4499. // DisplayName - PR_DISPLAY_NAME
  4500. //
  4501. // For a detailed search
  4502. // We have the following data to work with
  4503. // Country - PR_COUNTRY
  4504. // FirstName - PR_GIVEN_NAME
  4505. // LastName - PR_SURNAME
  4506. // EMail - PR_EMAIL_ADDRESS
  4507. // Organization - PR_COMPANY_NAME
  4508. //
  4509. //
  4510. /******************************************************************************/
  4511. HRESULT HrGetLDAPSearchRestriction(LDAP_SEARCH_PARAMS LDAPsp, LPSRestriction lpSRes)
  4512. {
  4513. SRestriction SRes = {0};
  4514. LPSRestriction lpPropRes = NULL;
  4515. ULONG ulcPropCount = 0;
  4516. HRESULT hr = E_FAIL;
  4517. ULONG i = 0;
  4518. SCODE sc = ERROR_SUCCESS;
  4519. lpSRes->rt = RES_AND;
  4520. ulcPropCount = 0;
  4521. if (lstrlen(LDAPsp.szData[ldspDisplayName]))
  4522. ulcPropCount++; //PR_EMAIL_ADDRESS and PR_DISPLAY_NAME
  4523. if (lstrlen(LDAPsp.szData[ldspEmail]))
  4524. ulcPropCount++;
  4525. if (!ulcPropCount)
  4526. {
  4527. DebugPrintError(( TEXT("No Search Props!\n")));
  4528. goto out;
  4529. }
  4530. lpSRes->res.resAnd.cRes = ulcPropCount;
  4531. lpSRes->res.resAnd.lpRes = NULL;
  4532. sc = MAPIAllocateBuffer(ulcPropCount * sizeof(SRestriction), (LPVOID *) &(lpSRes->res.resAnd.lpRes));
  4533. if (sc != S_OK)
  4534. {
  4535. DebugPrintError(( TEXT("MAPIAllocateBuffer failed\n")));
  4536. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4537. goto out;
  4538. }
  4539. if(!(lpSRes->res.resAnd.lpRes))
  4540. {
  4541. DebugPrintError(( TEXT("Error Allocating Memory\n")));
  4542. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4543. goto out;
  4544. }
  4545. lpPropRes = lpSRes->res.resAnd.lpRes;
  4546. ulcPropCount = 0;
  4547. for(i=0;i<ldspMAX;i++)
  4548. {
  4549. if(lstrlen(LDAPsp.szData[i]))
  4550. {
  4551. ULONG ulPropTag = 0;
  4552. DWORD cchSize;
  4553. LPSPropValue lpPropArray = NULL;
  4554. switch(i)
  4555. {
  4556. case ldspEmail:
  4557. ulPropTag = PR_EMAIL_ADDRESS;
  4558. break;
  4559. case ldspDisplayName:
  4560. ulPropTag = PR_DISPLAY_NAME;
  4561. break;
  4562. default:
  4563. continue;
  4564. }
  4565. lpPropRes[ulcPropCount].rt = RES_PROPERTY;
  4566. lpPropRes[ulcPropCount].res.resProperty.relop = RELOP_EQ;
  4567. lpPropRes[ulcPropCount].res.resProperty.ulPropTag = ulPropTag;
  4568. lpPropRes[ulcPropCount].res.resProperty.lpProp = NULL;
  4569. MAPIAllocateMore(sizeof(SPropValue),lpPropRes, (LPVOID *) &(lpPropRes[ulcPropCount].res.resProperty.lpProp));
  4570. lpPropArray = lpPropRes[ulcPropCount].res.resProperty.lpProp;
  4571. if(!lpPropArray)
  4572. {
  4573. DebugPrintError(( TEXT("Error allocating memory\n")));
  4574. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4575. goto out;
  4576. }
  4577. lpPropArray->ulPropTag = ulPropTag;
  4578. lpPropArray->Value.LPSZ = NULL;
  4579. cchSize=lstrlen(LDAPsp.szData[i])+1;
  4580. MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropRes, (LPVOID *) (&(lpPropArray->Value.LPSZ)));
  4581. if(!lpPropArray->Value.LPSZ)
  4582. {
  4583. DebugPrintError(( TEXT("Error allocating memory\n")));
  4584. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4585. goto out;
  4586. }
  4587. StrCpyN(lpPropArray->Value.LPSZ,LDAPsp.szData[i], cchSize);
  4588. ulcPropCount++;
  4589. }
  4590. }
  4591. hr = S_OK;
  4592. out:
  4593. return hr;
  4594. }
  4595. //$$/////////////////////////////////////////////////////////////////////////
  4596. //
  4597. // ShowMessageBoxParam - Generic MessageBox displayer .. saves space all over
  4598. //
  4599. // hWndParent - Handle of Message Box Parent
  4600. // MsgID - resource id of message string
  4601. // ulFlags - MessageBox flags
  4602. // ... - format parameters
  4603. //
  4604. ///////////////////////////////////////////////////////////////////////////
  4605. int __cdecl ShowMessageBoxParam(HWND hWndParent, int MsgId, int ulFlags, ...)
  4606. {
  4607. TCHAR szBuf[MAX_BUF_STR] = TEXT("");
  4608. TCHAR szCaption[MAX_PATH] = TEXT("");
  4609. LPTSTR lpszBuffer = NULL;
  4610. int iRet = 0;
  4611. va_list vl;
  4612. va_start(vl, ulFlags);
  4613. LoadString(hinstMapiX, MsgId, szBuf, ARRAYSIZE(szBuf));
  4614. // if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  4615. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  4616. szBuf,
  4617. 0,0, //ignored
  4618. (LPTSTR)&lpszBuffer,
  4619. MAX_BUF_STR, //MAX_UI_STR
  4620. // (LPTSTR *)&(lpParam))) {
  4621. (va_list *)&vl)) {
  4622. TCHAR szCaption[MAX_PATH];
  4623. *szCaption = '\0';
  4624. if(hWndParent)
  4625. GetWindowText(hWndParent, szCaption, ARRAYSIZE(szCaption));
  4626. if(!lstrlen(szCaption)) // if no caption get the parents caption - this is necessary for property sheets
  4627. {
  4628. if(hWndParent)
  4629. GetWindowText(GetParent(hWndParent), szCaption, ARRAYSIZE(szCaption));
  4630. if(!lstrlen(szCaption)) //if still not caption, get the generic title
  4631. LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szCaption, ARRAYSIZE(szCaption));
  4632. }
  4633. iRet = MessageBox(hWndParent, lpszBuffer, szCaption, ulFlags);
  4634. LocalFreeAndNull(&lpszBuffer);
  4635. }
  4636. va_end(vl);
  4637. return(iRet);
  4638. }
  4639. //$$/////////////////////////////////////////////////////////////////////////
  4640. //
  4641. // ShowMessageBox - Generic MessageBox displayer .. saves space all over
  4642. //
  4643. // hWndParent - Handle of Message Box Parent
  4644. // MsgID - resource id of message string
  4645. // ulFlags - MessageBox flags
  4646. //
  4647. ///////////////////////////////////////////////////////////////////////////
  4648. int ShowMessageBox(HWND hWndParent, int MsgId, int ulFlags)
  4649. {
  4650. TCHAR szBuf[MAX_BUF_STR];
  4651. TCHAR szCaption[MAX_PATH];
  4652. szCaption[0]='\0';
  4653. szBuf[0]='\0';
  4654. LoadString(hinstMapiX, MsgId, szBuf, ARRAYSIZE(szBuf));
  4655. if(hWndParent)
  4656. {
  4657. GetWindowText(hWndParent, szCaption, ARRAYSIZE(szCaption));
  4658. if(!lstrlen(szCaption))
  4659. {
  4660. // if we cant get a caption, get the windows parents caption
  4661. HWND hWnd = GetParent(hWndParent);
  4662. GetWindowText(hWnd, szCaption, ARRAYSIZE(szCaption));
  4663. }
  4664. }
  4665. if(!lstrlen(szCaption))
  4666. {
  4667. //if we cant get the parents caption, get a generic title
  4668. LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szCaption, ARRAYSIZE(szCaption));
  4669. }
  4670. return MessageBox(hWndParent, szBuf, szCaption, ulFlags);
  4671. }
  4672. //$$/////////////////////////////////////////////////////////////////////////////
  4673. //
  4674. // my_atoi - personal version of atoi function
  4675. //
  4676. // lpsz - string to parse into numbers - non numeral characters are ignored
  4677. //
  4678. /////////////////////////////////////////////////////////////////////////////////
  4679. int my_atoi(LPTSTR lpsz)
  4680. {
  4681. int i=0;
  4682. int nValue = 0;
  4683. if(lpsz)
  4684. {
  4685. if (lstrlen(lpsz))
  4686. {
  4687. nValue = 0;
  4688. while((lpsz[i]!='\0')&&(i<=lstrlen(lpsz)))
  4689. {
  4690. int tmp = lpsz[i]-'0';
  4691. if(tmp <= 9)
  4692. nValue = nValue*10 + tmp;
  4693. i++;
  4694. }
  4695. }
  4696. }
  4697. return nValue;
  4698. }
  4699. #ifdef OLD_STUFF
  4700. //$$/////////////////////////////////////////////////////////////////////////////
  4701. //
  4702. // FillComboLDAPCountryNames - Fills a dropdown conbo with LDAP country names
  4703. //
  4704. // hWndCombo - Handle of Combo
  4705. //
  4706. /////////////////////////////////////////////////////////////////////////////////
  4707. void FillComboLDAPCountryNames(HWND hWndCombo)
  4708. {
  4709. TCHAR szBuf[MAX_UI_STR];
  4710. int nCountrys = 0;
  4711. int i=0;
  4712. LoadString(hinstMapiX, idsCountryCount,szBuf,ARRAYSIZE(szBuf));
  4713. nCountrys = my_atoi(szBuf);
  4714. if(nCountrys == 0)
  4715. nCountrys = MAX_COUNTRY_NUM;
  4716. for(i=0;i<nCountrys;i++)
  4717. {
  4718. LoadString(hinstMapiX, idsCountry1+i,szBuf,ARRAYSIZE(szBuf));
  4719. SendMessage(hWndCombo,CB_ADDSTRING, 0, (LPARAM) szBuf);
  4720. }
  4721. // Look in the regsitry for a default specfied country ...
  4722. ReadRegistryLDAPDefaultCountry(szBuf, ARRAYSIZE(szBuf), NULL, 0);
  4723. // set the selection to default from registry
  4724. i = SendMessage(hWndCombo, CB_FINDSTRING, (WPARAM) -1, (LPARAM) szBuf);
  4725. if(i==CB_ERR)
  4726. {
  4727. i = SendMessage(hWndCombo, CB_FINDSTRING, (WPARAM) -1, (LPARAM) TEXT("United States"));
  4728. }
  4729. SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) i, 0);
  4730. return;
  4731. }
  4732. #endif
  4733. //$$/////////////////////////////////////////////////////////////////////////////
  4734. //
  4735. // ReadRegistryLDAPDefaultCountry - Reads the default country name or code from the
  4736. // registry
  4737. //
  4738. // szCountry, szCountryCode - buffers that will recieve the country and/or country
  4739. // code. These can be NULL if no country or countrycode is
  4740. // required.
  4741. //
  4742. /////////////////////////////////////////////////////////////////////////////////
  4743. BOOL ReadRegistryLDAPDefaultCountry(LPTSTR szCountry, DWORD cchCountry, LPTSTR szCountryCode, DWORD cchCountryCode)
  4744. {
  4745. BOOL bRet = FALSE;
  4746. DWORD dwErr;
  4747. HKEY hKey = NULL;
  4748. ULONG ulSize = MAX_UI_STR;
  4749. DWORD dwType;
  4750. TCHAR szTemp[MAX_UI_STR];
  4751. if(!szCountry && !szCountryCode)
  4752. goto out;
  4753. if (szCountry)
  4754. szCountry[0]='\0';
  4755. if (szCountryCode)
  4756. szCountryCode[0]='\0';
  4757. dwErr = RegOpenKeyEx( HKEY_CURRENT_USER,
  4758. szWABKey,
  4759. 0,
  4760. KEY_READ,
  4761. &hKey);
  4762. if(dwErr)
  4763. goto out;
  4764. dwErr = RegQueryValueEx( hKey,
  4765. (LPTSTR)szLDAPDefaultCountryValue,
  4766. NULL,
  4767. &dwType,
  4768. (LPBYTE)szTemp,
  4769. &ulSize);
  4770. if(dwErr)
  4771. {
  4772. // We dont have a registry setting .. or there was some error
  4773. // In this case we need to get the Default Country for this locale
  4774. // using the NLS API
  4775. ulSize = GetLocaleInfo( LOCALE_USER_DEFAULT,
  4776. LOCALE_SENGCOUNTRY,
  4777. (LPTSTR) szTemp,
  4778. ARRAYSIZE(szTemp));
  4779. if(ulSize>0)
  4780. {
  4781. // We got a valid country but it obviously doesnt have a code
  4782. if(szCountry)
  4783. StrCpyN(szCountry, szTemp, cchCountry);
  4784. if(szCountryCode)
  4785. {
  4786. int i =0;
  4787. int cMax=0;
  4788. TCHAR szBufCountry[MAX_UI_STR];
  4789. szBufCountry[0]='\0';
  4790. StrCpyN(szBufCountry,szTemp,ARRAYSIZE(szBufCountry));
  4791. LoadString(hinstMapiX, idsCountryCount,szTemp,ARRAYSIZE(szTemp));
  4792. cMax = my_atoi(szTemp);
  4793. for(i=0;i<cMax;i++)
  4794. {
  4795. LoadString(hinstMapiX, idsCountry1+i, szTemp, ARRAYSIZE(szTemp));
  4796. if(lstrlen(szTemp) < lstrlen(szBufCountry))
  4797. continue;
  4798. if( !memcmp(szTemp, szBufCountry, (lstrlen(szBufCountry) * sizeof(TCHAR))) )
  4799. {
  4800. //Found our match
  4801. LPTSTR lpszTmp = szTemp;
  4802. szCountryCode[0]='\0';
  4803. while(*lpszTmp && (*lpszTmp != '('))
  4804. lpszTmp = CharNext(lpszTmp);
  4805. if(*lpszTmp && (*lpszTmp == '('))
  4806. {
  4807. lpszTmp = CharNext(lpszTmp);
  4808. CopyMemory(szCountryCode,lpszTmp,sizeof(TCHAR)*2);
  4809. szCountryCode[2] = '\0';
  4810. }
  4811. break;
  4812. }
  4813. }
  4814. if(!lstrlen(szCountryCode))
  4815. {
  4816. // default to US
  4817. StrCpyN(szCountryCode, TEXT("US"), cchCountryCode);
  4818. }
  4819. }
  4820. bRet = TRUE;
  4821. goto out;
  4822. }
  4823. }
  4824. else
  4825. {
  4826. // Otherwise - do our normal processing
  4827. if(szCountry)
  4828. StrCpyN(szCountry, szTemp, cchCountry);
  4829. if(szCountryCode)
  4830. {
  4831. LPTSTR lpszTmp = szTemp;
  4832. szCountryCode[0]='\0';
  4833. while(*lpszTmp && (*lpszTmp != '('))
  4834. lpszTmp = CharNext(lpszTmp);
  4835. if(*lpszTmp && (*lpszTmp == '('))
  4836. {
  4837. lpszTmp = CharNext(lpszTmp);
  4838. CopyMemory(szCountryCode,lpszTmp,sizeof(TCHAR)*2);
  4839. szCountryCode[2] = '\0';
  4840. }
  4841. if(!lstrlen(szCountryCode))
  4842. {
  4843. // default to US
  4844. StrCpyN(szCountryCode, TEXT("US"), cchCountryCode);
  4845. }
  4846. }
  4847. }
  4848. bRet = TRUE;
  4849. out:
  4850. if(hKey)
  4851. RegCloseKey(hKey);
  4852. return bRet;
  4853. }
  4854. #ifdef OLD_STUFF
  4855. //$$/////////////////////////////////////////////////////////////////////////////
  4856. //
  4857. // WriteRegistryLDAPDefaultCountry - Writes the default country name to the
  4858. // registry
  4859. //
  4860. // szCountry - default country code to write
  4861. //
  4862. /////////////////////////////////////////////////////////////////////////////////
  4863. BOOL WriteRegistryLDAPDefaultCountry(LPTSTR szCountry)
  4864. {
  4865. BOOL bRet = FALSE;
  4866. DWORD dwErr;
  4867. HKEY hKey = NULL;
  4868. ULONG ulSize = 0;
  4869. if(!szCountry)
  4870. goto out;
  4871. if(!lstrlen(szCountry))
  4872. goto out;
  4873. dwErr = RegOpenKeyEx( HKEY_CURRENT_USER,
  4874. szWABKey,
  4875. 0,
  4876. KEY_READ | KEY_WRITE,
  4877. &hKey);
  4878. if(dwErr)
  4879. goto out;
  4880. dwErr = RegSetValueEx( hKey,
  4881. (LPTSTR) szLDAPDefaultCountryValue,
  4882. 0,
  4883. REG_SZ,
  4884. szCountry,
  4885. (lstrlen(szCountry)+1) * sizeof(TCHAR) );
  4886. if(dwErr)
  4887. goto out;
  4888. bRet = TRUE;
  4889. out:
  4890. return bRet;
  4891. }
  4892. #endif //OLD_STUFF
  4893. BOOL bIsGroupSelected(HWND hWndLV, LPSBinary lpsbEID)
  4894. {
  4895. LPRECIPIENT_INFO lpItem;
  4896. if(ListView_GetSelectedCount(hWndLV) != 1)
  4897. return FALSE;
  4898. lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
  4899. if(lpItem && lpItem->ulObjectType == MAPI_DISTLIST)
  4900. {
  4901. if(lpsbEID)
  4902. {
  4903. lpsbEID->cb = lpItem->cbEntryID;
  4904. lpsbEID->lpb = (LPBYTE)lpItem->lpEntryID;
  4905. }
  4906. return TRUE;
  4907. }
  4908. return FALSE;
  4909. }
  4910. //$$
  4911. ////////////////////////////////////////////////////////////////////////////////
  4912. //
  4913. // GetCurrentOptionsState - looks at the current state based on the ListView and
  4914. // the Combo and decides which options should be enabled or disabled
  4915. //
  4916. // hWndCombo - handle of Show Names combo
  4917. // hWndLV - handle of ListView to look at
  4918. // lpbState - points to a predefined array of BOOL bState[tbMAX]
  4919. //
  4920. ////////////////////////////////////////////////////////////////////////////////
  4921. void GetCurrentOptionsState(HWND hWndLVContainer,
  4922. HWND hWndLV,
  4923. LPBOOL lpbState)
  4924. {
  4925. int i = 0;
  4926. ULONG cbEID = 0;
  4927. LPENTRYID lpEID = NULL;
  4928. BYTE bType = 0;
  4929. int nItemCount = ListView_GetItemCount(hWndLV);
  4930. int nSelectedCount = ListView_GetSelectedCount(hWndLV);
  4931. for(i=0;i<tbMAX;i++)
  4932. lpbState[i] = FALSE;
  4933. lpbState[tbPaste] = bIsPasteData();// && ( (nSelectedCount<=0) || (bIsGroupSelected(hWndLV, NULL)) );
  4934. lpbState[tbCopy] = lpbState[tbFind] = lpbState[tbAction] = TRUE;
  4935. if(hWndLVContainer)
  4936. {
  4937. // in the rare event that we have LDAP containers ...
  4938. GetCurrentContainerEID( hWndLVContainer,
  4939. &cbEID,
  4940. &lpEID);
  4941. bType = IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL);
  4942. }
  4943. else
  4944. {
  4945. bType = WAB_PAB;
  4946. }
  4947. if(bType == WAB_PAB || bType == WAB_PABSHARED)
  4948. {
  4949. lpbState[tbNew] = lpbState[tbNewEntry] = lpbState[tbNewGroup] = lpbState[tbNewFolder] = TRUE;
  4950. lpbState[tbAddToWAB] = FALSE;
  4951. if(nItemCount > 0)
  4952. lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = TRUE;
  4953. else
  4954. lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
  4955. if(nSelectedCount <= 0)
  4956. lpbState[tbCopy] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
  4957. else if(nSelectedCount > 1)
  4958. //lpbState[tbaction] =
  4959. lpbState[tbProperties] = FALSE;
  4960. }
  4961. else if(bType == WAB_LDAP_CONTAINER)
  4962. {
  4963. lpbState[tbDelete] = lpbState[tbNew] = lpbState[tbNewEntry] = lpbState[tbNewGroup] = lpbState[tbNewFolder] = FALSE;
  4964. if(nItemCount > 0)
  4965. lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbAddToWAB] = TRUE;
  4966. else
  4967. lpbState[tbPrint] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbAddToWAB] = FALSE;
  4968. if(nSelectedCount <= 0)
  4969. lpbState[tbPaste] = lpbState[tbCopy] = /*lpbState[tbAction] =*/ lpbState[tbProperties] = lpbState[tbDelete] = FALSE;
  4970. else if(nSelectedCount > 1)
  4971. //lpbState[tbAction] =
  4972. lpbState[tbProperties] = FALSE;
  4973. }
  4974. else
  4975. {
  4976. // cant handle this case so turn everything off ....
  4977. for(i=0;i<tbMAX;i++)
  4978. lpbState[i] = FALSE;
  4979. }
  4980. return;
  4981. }
  4982. //$$////////////////////////////////////////////////////////////////////////////////
  4983. //
  4984. // HrEntryAddToWAB - Adds an entry to the Address Book given an entryid
  4985. //
  4986. //
  4987. //
  4988. //
  4989. ////////////////////////////////////////////////////////////////////////////////////
  4990. HRESULT HrEntryAddToWAB( LPADRBOOK lpAdrBook,
  4991. HWND hWndParent,
  4992. ULONG cbInputEID,
  4993. LPENTRYID lpInputEID,
  4994. ULONG * lpcbOutputEID,
  4995. LPENTRYID * lppOutputEID)
  4996. {
  4997. HRESULT hr = E_FAIL;
  4998. ULONG ulcProps = 0;
  4999. LPSPropValue lpPropArray = NULL;
  5000. ULONG i;
  5001. hr = HrGetPropArray(lpAdrBook,
  5002. NULL,
  5003. cbInputEID,
  5004. lpInputEID,
  5005. MAPI_UNICODE,
  5006. &ulcProps,
  5007. &lpPropArray);
  5008. if(HR_FAILED(hr))
  5009. {
  5010. DebugPrintError(( TEXT("HrGetPropArray failed:%x\n")));
  5011. goto out;
  5012. }
  5013. //
  5014. // This lpPropArray will have a non-zero entryid ... it will have the
  5015. // LDAP entry id .. we want to remove that value so we can store this
  5016. // lpPropArray as a fresh lpPropArray...
  5017. //
  5018. for(i=0;i<ulcProps;i++)
  5019. {
  5020. if(lpPropArray[i].ulPropTag == PR_ENTRYID)
  5021. {
  5022. lpPropArray[i].Value.bin.cb = 0;
  5023. break;
  5024. }
  5025. }
  5026. // Since this function exclusively adds people to the local WAB from LDAP
  5027. // we need to filter out non-storable properties here if they exist ...
  5028. for(i=0;i<ulcProps;i++)
  5029. {
  5030. switch(lpPropArray[i].ulPropTag)
  5031. {
  5032. case PR_WAB_MANAGER:
  5033. case PR_WAB_REPORTS:
  5034. case PR_WAB_LDAP_LABELEDURI:
  5035. lpPropArray[i].ulPropTag = PR_NULL;
  5036. break;
  5037. }
  5038. }
  5039. {
  5040. ULONG cbContEID = 0;
  5041. LPENTRYID lpContEID = NULL;
  5042. LPIAB lpIAB = (LPIAB) lpAdrBook;
  5043. if(bIsThereACurrentUser(lpIAB))
  5044. {
  5045. cbContEID = lpIAB->lpWABCurrentUserFolder->sbEID.cb;
  5046. lpContEID = (LPENTRYID)(lpIAB->lpWABCurrentUserFolder->sbEID.lpb);
  5047. }
  5048. hr = HrCreateNewEntry( lpAdrBook,
  5049. hWndParent,
  5050. MAPI_MAILUSER, //MAILUSER or DISTLIST
  5051. cbContEID, lpContEID,
  5052. MAPI_ABCONT,//add to root container only
  5053. CREATE_CHECK_DUP_STRICT,
  5054. TRUE,
  5055. ulcProps,
  5056. lpPropArray,
  5057. lpcbOutputEID,
  5058. lppOutputEID);
  5059. }
  5060. if(HR_FAILED(hr))
  5061. {
  5062. DebugPrintError(( TEXT("HrCreateNewEntry failed:%x\n")));
  5063. goto out;
  5064. }
  5065. out:
  5066. if (lpPropArray)
  5067. MAPIFreeBuffer(lpPropArray);
  5068. return hr;
  5069. }
  5070. //$$////////////////////////////////////////////////////////////////////////////////
  5071. //
  5072. // HrAddToWAB - Adds an LDAP or one-off entry to the Address Book
  5073. // All such items will be added to the root container only
  5074. //
  5075. // lpIAB - ADRBOOK object
  5076. // hWndLV - Listview window handle
  5077. // lpftLast - WAB file time at last update
  5078. //
  5079. //
  5080. ////////////////////////////////////////////////////////////////////////////////////
  5081. HRESULT HrAddToWAB( LPADRBOOK lpIAB,
  5082. HWND hWndLV,
  5083. LPFILETIME lpftLast)
  5084. {
  5085. HRESULT hr = hrSuccess;
  5086. HRESULT hrDeferred = hrSuccess;
  5087. int nSelectedCount = 0;
  5088. LPRECIPIENT_INFO lpItem = NULL;
  5089. ULONG cbEID = 0;
  5090. LPENTRYID lpEID = NULL;
  5091. ULONG i = 0;
  5092. HCURSOR hOldCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
  5093. //
  5094. // Looks at the selected item in the List View,
  5095. // gets its entry id, gets its props, creates a new item with those props
  5096. //
  5097. if (!lpIAB || !hWndLV)
  5098. {
  5099. hr = MAPI_E_INVALID_PARAMETER;
  5100. goto out;
  5101. }
  5102. nSelectedCount = ListView_GetSelectedCount(hWndLV);
  5103. if(nSelectedCount <= 0)
  5104. {
  5105. ShowMessageBox(GetParent(hWndLV), idsNoItemsSelectedForAdding, MB_ICONEXCLAMATION | MB_OK);
  5106. hr = E_FAIL;
  5107. goto out;
  5108. }
  5109. else
  5110. {
  5111. // Walk through all the items processing the one by one
  5112. int iItemIndex = 0;
  5113. int iLastItemIndex = -1;
  5114. iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
  5115. while(iItemIndex != -1)
  5116. {
  5117. iLastItemIndex = iItemIndex;
  5118. lpItem = GetItemFromLV(hWndLV, iItemIndex);
  5119. if(lpItem)
  5120. {
  5121. nSelectedCount--; //now tracks how many are left
  5122. hr = HrEntryAddToWAB( lpIAB,
  5123. GetParent(hWndLV),
  5124. lpItem->cbEntryID,
  5125. lpItem->lpEntryID,
  5126. &cbEID,
  5127. &lpEID);
  5128. if(HR_FAILED(hr))
  5129. {
  5130. DebugPrintError(( TEXT("HrEntryAddToWAB failed:%x\n")));
  5131. if(hr != MAPI_E_USER_CANCEL)
  5132. hrDeferred = hr;
  5133. if (lpEID)
  5134. MAPIFreeBuffer(lpEID);
  5135. lpEID = NULL;
  5136. if(hr == MAPI_E_USER_CANCEL && nSelectedCount)
  5137. {
  5138. // user canceled this one and some other remain ..
  5139. // Ask if he wants to cancel the whole import operation
  5140. if(IDYES == ShowMessageBox(GetParent(hWndLV),
  5141. idsContinueAddingToWAB,
  5142. MB_YESNO | MB_ICONEXCLAMATION))
  5143. {
  5144. goto out;
  5145. }
  5146. }
  5147. // just keep going on if there are any remaining entries
  5148. goto end_loop;
  5149. }
  5150. // Update the wab file write time so the timer doesn't
  5151. // catch this change and refresh.
  5152. //if (lpftLast) {
  5153. // CheckChangedWAB(((LPIAB)lpIAB)->lpPropertyStore, lpftLast);
  5154. //}
  5155. if (lpEID)
  5156. MAPIFreeBuffer(lpEID);
  5157. lpEID = NULL;
  5158. }
  5159. end_loop:
  5160. // Get the next selected item ...
  5161. iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
  5162. }
  5163. }
  5164. out:
  5165. if (lpEID)
  5166. MAPIFreeBuffer(lpEID);
  5167. if(hr != MAPI_E_USER_CANCEL)
  5168. {
  5169. if (!hrDeferred) //hr could be MAPI_W_ERRORS_RETURNED in which case it wasnt all roses so dont give this message ...
  5170. {
  5171. if(nSelectedCount)
  5172. ShowMessageBox(GetParent(hWndLV), idsSuccessfullyAddedUsers, MB_ICONINFORMATION | MB_OK);
  5173. }
  5174. else if(hrDeferred == MAPI_E_NOT_FOUND)
  5175. ShowMessageBox(GetParent(hWndLV), idsCouldNotAddSomeEntries, MB_ICONINFORMATION | MB_OK);
  5176. }
  5177. SetCursor(hOldCursor);
  5178. return hr;
  5179. }
  5180. //$$
  5181. /************************************************************************************
  5182. - ReadRegistryPositionInfo
  5183. -
  5184. * Purpose:
  5185. * Getss the previously stored modeless window size and column width info
  5186. * for persistence between sessions.
  5187. *
  5188. * Arguments:
  5189. * LPABOOK_POSCOLSIZE lpABPosColSize
  5190. * LPTSTR szPosKey - key to store it under
  5191. *
  5192. * Returns:
  5193. * BOOL
  5194. *
  5195. *************************************************************************************/
  5196. BOOL ReadRegistryPositionInfo(LPIAB lpIAB,
  5197. LPABOOK_POSCOLSIZE lpABPosColSize,
  5198. LPTSTR szPosKey)
  5199. {
  5200. BOOL bRet = FALSE;
  5201. HKEY hKey = NULL;
  5202. HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
  5203. DWORD dwLenName = sizeof(ABOOK_POSCOLSIZE);
  5204. DWORD dwDisposition = 0;
  5205. DWORD dwType = 0;
  5206. if(!lpABPosColSize)
  5207. goto out;
  5208. tryReadingAgain:
  5209. // Open key
  5210. if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
  5211. lpszRegSortKeyName,
  5212. 0, //reserved
  5213. NULL,
  5214. REG_OPTION_NON_VOLATILE,
  5215. KEY_READ,
  5216. NULL,
  5217. &hKey,
  5218. &dwDisposition))
  5219. {
  5220. goto out;
  5221. }
  5222. if(dwDisposition == REG_CREATED_NEW_KEY)
  5223. goto out;
  5224. // Now Read the key
  5225. if (ERROR_SUCCESS != RegQueryValueEx(hKey,
  5226. szPosKey,
  5227. NULL,
  5228. &dwType,
  5229. (LPBYTE) lpABPosColSize,
  5230. &dwLenName))
  5231. {
  5232. DebugTrace( TEXT("RegQueryValueEx failed\n"));
  5233. if(hKeyRoot != HKEY_CURRENT_USER)
  5234. {
  5235. // with identities .. this will fail the first time ..so recover old HKCU settings for upgrades
  5236. hKeyRoot = HKEY_CURRENT_USER;
  5237. if(hKey)
  5238. RegCloseKey(hKey);
  5239. goto tryReadingAgain;
  5240. }
  5241. goto out;
  5242. }
  5243. bRet = TRUE;
  5244. out:
  5245. if (hKey)
  5246. RegCloseKey(hKey);
  5247. return(bRet);
  5248. }
  5249. //$$
  5250. /*************************************************************************************
  5251. - WriteRegistryPostionInfo
  5252. -
  5253. * Purpose:
  5254. * Write the given window position to the registry
  5255. *
  5256. * Arguments:
  5257. * LPABOOK_POSCOLSIZE lpABPosColSize
  5258. * LPTSTR szPosKey - key to write it in
  5259. *
  5260. * Returns:
  5261. * BOOL
  5262. *
  5263. *************************************************************************************/
  5264. BOOL WriteRegistryPositionInfo(LPIAB lpIAB,
  5265. LPABOOK_POSCOLSIZE lpABPosColSize,
  5266. LPTSTR szPosKey)
  5267. {
  5268. BOOL bRet = FALSE;
  5269. HKEY hKey = NULL;
  5270. HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ? lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
  5271. DWORD dwLenName = sizeof(ABOOK_POSCOLSIZE);
  5272. DWORD dwDisposition =0;
  5273. if(!lpABPosColSize)
  5274. goto out;
  5275. // Open key
  5276. if (ERROR_SUCCESS != RegCreateKeyEx(hKeyRoot,
  5277. lpszRegSortKeyName,
  5278. 0, //reserved
  5279. NULL,
  5280. REG_OPTION_NON_VOLATILE,
  5281. KEY_ALL_ACCESS,
  5282. NULL,
  5283. &hKey,
  5284. &dwDisposition))
  5285. {
  5286. DebugTrace( TEXT("RegCreateKeyEx failed\n"));
  5287. goto out;
  5288. }
  5289. // Now Write this key
  5290. if (ERROR_SUCCESS != RegSetValueEx( hKey,
  5291. szPosKey,
  5292. 0,
  5293. REG_BINARY,
  5294. (LPBYTE) lpABPosColSize,
  5295. dwLenName))
  5296. {
  5297. DebugTrace( TEXT("RegSetValue failed\n"));
  5298. goto out;
  5299. }
  5300. bRet = TRUE;
  5301. out:
  5302. if (hKey)
  5303. RegCloseKey(hKey);
  5304. return(bRet);
  5305. }
  5306. //$$////////////////////////////////////////////////////////////////////////////////
  5307. //
  5308. // ProcessLVCustomDraw - Processes the NMCustomDraw message for the various list views
  5309. //
  5310. // Used for setting the DistLists to a bolder font
  5311. //
  5312. // Parameters -
  5313. //
  5314. // lParam - lParam of original message
  5315. // hDlg - handle of dialog if the relevant window is a dialog, null otherwise
  5316. // bIsDialog - flag that tells us if this is a dialog or not
  5317. //
  5318. ////////////////////////////////////////////////////////////////////////////////////
  5319. LRESULT ProcessLVCustomDraw(HWND hDlg, LPARAM lParam, BOOL bIsDialog)
  5320. {
  5321. NMCUSTOMDRAW *pnmcd = (NMCUSTOMDRAW *) lParam;
  5322. if(pnmcd->dwDrawStage==CDDS_PREPAINT)
  5323. {
  5324. if(bIsDialog)
  5325. {
  5326. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW|CDRF_DODEFAULT);
  5327. return TRUE;
  5328. }
  5329. else
  5330. return CDRF_NOTIFYITEMDRAW|CDRF_DODEFAULT;
  5331. }
  5332. else if(pnmcd->dwDrawStage==CDDS_ITEMPREPAINT)
  5333. {
  5334. LPRECIPIENT_INFO lpItem = (LPRECIPIENT_INFO) pnmcd->lItemlParam;
  5335. if(lpItem)
  5336. {
  5337. if(lpItem->ulObjectType == MAPI_DISTLIST)
  5338. {
  5339. SelectObject(((NMLVCUSTOMDRAW *)lParam)->nmcd.hdc, GetFont(fntsSysIconBold));
  5340. if(bIsDialog)
  5341. {
  5342. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
  5343. return TRUE;
  5344. }
  5345. else
  5346. return CDRF_NEWFONT;
  5347. }
  5348. }
  5349. }
  5350. if(bIsDialog)
  5351. {
  5352. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, CDRF_DODEFAULT);
  5353. return TRUE;
  5354. }
  5355. else
  5356. return CDRF_DODEFAULT;
  5357. }
  5358. /*****
  5359. //$$/////////////////////////////////////////////////////////////
  5360. //
  5361. // DoLVQuickFilter - Simple quick find routine for matching edit box contents to
  5362. // List view entries
  5363. //
  5364. // lpIAB - lpAdrBook object
  5365. // hWndEdit - handle of Edit Box
  5366. // hWndLV - handle of List View
  5367. // lppContentsList - ContentsList
  5368. //
  5369. // ulFlags - AB_FUZZY_FIND_NAME | AB_FUZZY_FIND_EMAIL or Both
  5370. // int minLen - we may not want to trigger a search with 1 char or 2 char or less etc
  5371. //
  5372. ///////////////////////////////////////////////////////////////
  5373. void DoLVQuickFilter( LPADRBOOK lpAdrBook,
  5374. HWND hWndEdit,
  5375. HWND hWndLV,
  5376. LPSORT_INFO lpSortInfo,
  5377. ULONG ulFlags,
  5378. int nMinLen,
  5379. LPRECIPIENT_INFO * lppContentsList)
  5380. {
  5381. TCHAR szBuf[MAX_PATH];
  5382. HRESULT hr = hrSuccess;
  5383. LPSBinary rgsbEntryIDs = NULL;
  5384. ULONG cValues = 0;
  5385. ULONG i =0;
  5386. HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  5387. LPIAB lpIAB = (LPIAB)lpIAB;
  5388. GetWindowText(hWndEdit,szBuf,ARRAYSIZE(szBuf));
  5389. TrimSpaces(szBuf);
  5390. if(lstrlen(szBuf))
  5391. {
  5392. if(lstrlen(szBuf) < nMinLen)
  5393. goto out;
  5394. // BUGBUG <JasonSo>: Need to pass in the correct container here...
  5395. hr = HrFindFuzzyRecordMatches(
  5396. lpIAB->lpPropertyStore->hPropertyStore,
  5397. NULL,
  5398. szBuf,
  5399. ulFlags, //flags
  5400. &cValues,
  5401. &rgsbEntryIDs);
  5402. if(HR_FAILED(hr))
  5403. goto out;
  5404. SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) FALSE, 0);
  5405. ClearListView(hWndLV, lppContentsList);
  5406. if(cValues <= 0)
  5407. {
  5408. goto out;
  5409. }
  5410. for(i=0;i<cValues;i++)
  5411. {
  5412. LPRECIPIENT_INFO lpItem = NULL;
  5413. if(!ReadSingleContentItem( lpAdrBook,
  5414. rgsbEntryIDs[i].cb,
  5415. (LPENTRYID) rgsbEntryIDs[i].lpb,
  5416. &lpItem))
  5417. continue;
  5418. if(!lpItem)
  5419. continue;
  5420. //
  5421. // Hook in the lpItem into the lpContentsList so we can free it later
  5422. //
  5423. lpItem->lpPrev = NULL;
  5424. lpItem->lpNext = *lppContentsList;
  5425. if (*lppContentsList)
  5426. (*lppContentsList)->lpPrev = lpItem;
  5427. (*lppContentsList) = lpItem;
  5428. }
  5429. HrFillListView(hWndLV,
  5430. *lppContentsList);
  5431. SortListViewColumn( hWndLV, 0, lpSortInfo, TRUE);
  5432. LVSelectItem(hWndLV, 0);
  5433. SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) TRUE, 0);
  5434. }
  5435. else
  5436. {
  5437. hr = HrGetWABContents( hWndLV,
  5438. lpAdrBook,
  5439. NULL,
  5440. *lpSortInfo,
  5441. lppContentsList);
  5442. }
  5443. out:
  5444. FreeEntryIDs(((LPIAB)lpIAB)->lpPropertyStore->hPropertyStore,
  5445. cValues,
  5446. rgsbEntryIDs);
  5447. SetCursor(hOldCur);
  5448. return;
  5449. }
  5450. /*******/
  5451. //$$/////////////////////////////////////////////////////////////
  5452. //
  5453. // SetWindowPropertiesTitle - puts the objects name in front of the
  5454. // TEXT(" Properties") and puts it in the title
  5455. //
  5456. // e.g. Viewing properties on Vikram Madan would show a window
  5457. // with TEXT("Vikram Madan Properties") in the title as per
  5458. // Windows guidelines.
  5459. // if bProperties is false, shows TEXT("Vikram Madan Reports")
  5460. ///////////////////////////////////////////////////////////////
  5461. void SetWindowPropertiesTitle(HWND hWnd, LPTSTR lpszName)
  5462. {
  5463. LPTSTR lpszBuffer = NULL;
  5464. TCHAR szBuf[MAX_UI_STR];
  5465. TCHAR szTmp[MAX_PATH], *lpszTmp;
  5466. LoadString( hinstMapiX,
  5467. idsWindowTitleProperties,
  5468. szBuf, ARRAYSIZE(szBuf));
  5469. // Win9x bug FormatMessage cannot have more than 1023 chars
  5470. CopyTruncate(szTmp, lpszName, MAX_PATH - 1);
  5471. lpszTmp = szTmp;
  5472. if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
  5473. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  5474. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  5475. szBuf,
  5476. 0,0, //ignored
  5477. (LPTSTR) &lpszBuffer,
  5478. MAX_UI_STR,
  5479. (va_list *)&lpszTmp))
  5480. {
  5481. SetWindowText(hWnd, lpszBuffer);
  5482. LocalFreeAndNull(&lpszBuffer);
  5483. }
  5484. return;
  5485. }
  5486. /**** Dont mess with the order of these arrays (especially the address components street,city,zip etc ****/
  5487. static const SizedSPropTagArray(25, ToolTipsProps)=
  5488. {
  5489. 25,
  5490. {
  5491. PR_DISPLAY_NAME,
  5492. PR_EMAIL_ADDRESS,
  5493. PR_HOME_ADDRESS_STREET,
  5494. PR_HOME_ADDRESS_CITY,
  5495. PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  5496. PR_HOME_ADDRESS_POSTAL_CODE,
  5497. PR_HOME_ADDRESS_COUNTRY,
  5498. PR_HOME_TELEPHONE_NUMBER,
  5499. PR_HOME_FAX_NUMBER,
  5500. PR_CELLULAR_TELEPHONE_NUMBER,
  5501. PR_PERSONAL_HOME_PAGE,
  5502. PR_TITLE,
  5503. PR_DEPARTMENT_NAME,
  5504. PR_OFFICE_LOCATION,
  5505. PR_COMPANY_NAME,
  5506. PR_BUSINESS_ADDRESS_STREET,
  5507. PR_BUSINESS_ADDRESS_CITY,
  5508. PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  5509. PR_BUSINESS_ADDRESS_POSTAL_CODE,
  5510. PR_BUSINESS_ADDRESS_COUNTRY,
  5511. PR_BUSINESS_TELEPHONE_NUMBER,
  5512. PR_BUSINESS_FAX_NUMBER,
  5513. PR_PAGER_TELEPHONE_NUMBER,
  5514. PR_BUSINESS_HOME_PAGE,
  5515. PR_COMMENT,
  5516. }
  5517. };
  5518. enum _prop
  5519. {
  5520. txtDisplayName=0,
  5521. txtEmailAddress,
  5522. txtHomeAddress,
  5523. txtHomeCity,
  5524. txtHomeState,
  5525. txtHomeZip,
  5526. txtHomeCountry,
  5527. txtHomePhone,
  5528. txtHomeFax,
  5529. txtHomeCellular,
  5530. txtHomeWeb,
  5531. txtBusinessTitle,
  5532. txtBusinessDept,
  5533. txtBusinessOffice,
  5534. txtBusinessCompany,
  5535. txtBusinessAddress,
  5536. txtBusinessCity,
  5537. txtBusinessState,
  5538. txtBusinessZip,
  5539. txtBusinessCountry,
  5540. txtBusinessPhone,
  5541. txtBusinessFax,
  5542. txtBusinessPager,
  5543. txtBusinessWeb,
  5544. txtNotes
  5545. };
  5546. static const int idsString[] =
  5547. {
  5548. 0,
  5549. idsContactTextEmail,
  5550. idsContactTextHomeAddress,
  5551. 0,
  5552. 0,
  5553. 0,
  5554. 0,
  5555. idsContactTextHomePhone,
  5556. idsContactTextHomeFax,
  5557. idsContactTextHomeCellular,
  5558. idsContactTextPersonalWebPage,
  5559. idsContactTextTitle,
  5560. idsContactTextDepartment,
  5561. idsContactTextOffice,
  5562. idsContactTextCompany,
  5563. idsContactTextBusinessAddress,
  5564. 0,
  5565. 0,
  5566. 0,
  5567. 0,
  5568. idsContactTextBusinessPhone,
  5569. idsContactTextBusinessFax,
  5570. idsContactTextBusinessPager,
  5571. idsContactTextBusinessWebPage,
  5572. idsContactTextNotes,
  5573. };
  5574. //
  5575. // The routine that generates data for tooltips, clipboard, and printing
  5576. // creates a localized version of the address for the contact. This
  5577. // localized formatmessage string may contain ugly blank spaces due to
  5578. // missing data hence we need to cleanup the address string
  5579. // This works for US build - hopefully the localizers wont break it
  5580. //
  5581. void CleanAddressString(TCHAR * szAddress)
  5582. {
  5583. LPTSTR lpTemp = szAddress;
  5584. LPTSTR lpTemp2 = NULL;
  5585. // we search for these 2 substrings
  5586. LPTSTR szText1 = TEXT(" \r\n");
  5587. LPTSTR szText2 = TEXT(" ");
  5588. ULONG nSpaceCount = 0;
  5589. //
  5590. // BUGBUG: This routine is not DBCS smart!
  5591. // It should use IsSpace and CharNext to parse these strings.
  5592. //
  5593. if(SubstringSearch(szAddress, szText2))
  5594. {
  5595. //First remove continuous blanks beyond 4
  5596. while(*lpTemp)
  5597. {
  5598. if(*lpTemp == ' ')
  5599. {
  5600. nSpaceCount++;
  5601. if(nSpaceCount == 5)
  5602. {
  5603. lpTemp2 = lpTemp+1;
  5604. StrCpyN(lpTemp, lpTemp2, lstrlen(lpTemp2)+1);
  5605. nSpaceCount = 0;
  5606. lpTemp = lpTemp - 4;
  5607. continue;
  5608. }
  5609. }
  5610. else
  5611. nSpaceCount = 0;
  5612. lpTemp++;
  5613. }
  5614. }
  5615. while(SubstringSearch(szAddress, szText1))
  5616. {
  5617. lpTemp = szAddress;
  5618. lpTemp2 = szText1;
  5619. while (*lpTemp && *lpTemp2)
  5620. {
  5621. if (*lpTemp != *lpTemp2)
  5622. {
  5623. lpTemp -= (lpTemp2 - szText1);
  5624. lpTemp2 = szText1;
  5625. }
  5626. else
  5627. {
  5628. lpTemp2++;
  5629. }
  5630. lpTemp++;
  5631. }
  5632. if(*lpTemp2 == '\0')
  5633. {
  5634. //match found
  5635. LPTSTR lpTemp3 = lpTemp;
  5636. lpTemp -= (lpTemp2-szText1);
  5637. StrCpyN(lpTemp, lpTemp3, lstrlen(lpTemp3)+1);
  5638. }
  5639. }
  5640. // also need to strip out the \r\n at the end of the address string
  5641. nSpaceCount = lstrlen(szAddress);
  5642. if(nSpaceCount >= 2)
  5643. szAddress[nSpaceCount-2] = '\0';
  5644. return;
  5645. }
  5646. //$$/////////////////////////////////////////////////////////////////////////////
  5647. //
  5648. // void HrGetLVItemDataString - Gets the item's data for the currently selected
  5649. // item in the list view and puts it in a string
  5650. //
  5651. // lpIAB - Pointer to AddrBook object
  5652. // hWndLV - Handle of list view
  5653. // nItem - item in list view whose properties we are retrieving
  5654. // lpszData - returned string containing item properties - a buffer is allocated
  5655. // to hold the data and the user needs to LocalFree the buffer
  5656. //
  5657. ////////////////////////////////////////////////////////////////////////////////
  5658. HRESULT HrGetLVItemDataString(LPADRBOOK lpAdrBook, HWND hWndLV, int iItemIndex, LPTSTR * lppszData)
  5659. {
  5660. HRESULT hr = E_FAIL;
  5661. LPRECIPIENT_INFO lpItem = NULL;
  5662. LPSPropValue lpPropArray = NULL;
  5663. ULONG ulcProps = 0;
  5664. ULONG i =0,j=0;
  5665. ULONG ulBufSize = 0;
  5666. LPTSTR lpszData = NULL;
  5667. LPTSTR szParanStart = TEXT(" (");
  5668. LPTSTR szParanEnd = TEXT(")");
  5669. LPTSTR szLineBreakDL = TEXT("\r\n ");
  5670. LPTSTR lpszHomeAddress = NULL, lpszBusinessAddress = NULL;
  5671. LPTSTR lpszEmailAddresses = NULL;
  5672. LPTSTR * lpsz = NULL;
  5673. BOOL bBusinessTitle = FALSE, bPersonalTitle = FALSE;
  5674. ULONG * lpulPropTagArray = NULL;
  5675. ULONG cchSize;
  5676. // Some items will have both the PR_CONTACT_EMAIL_ADDRESSES and PR_EMAIL_ADDRESS
  5677. // while others will have only PR_EMAIL_ADDRESS
  5678. // In case of the former, we want to avoid duplication by ignoring email-address
  5679. // when contact-email-addresses exist. For this we use a flag.
  5680. BOOL bFoundContactAddresses = FALSE;
  5681. ULONG ulObjectType = 0;
  5682. SizedSPropTagArray(3, DLToolTipsProps)=
  5683. {
  5684. 3,
  5685. {
  5686. PR_DISPLAY_NAME,
  5687. PR_WAB_DL_ENTRIES,
  5688. PR_WAB_DL_ONEOFFS,
  5689. }
  5690. };
  5691. *lppszData = NULL;
  5692. lpItem = GetItemFromLV(hWndLV, iItemIndex);
  5693. if(lpItem)
  5694. {
  5695. hr = HrGetPropArray(lpAdrBook, NULL,
  5696. lpItem->cbEntryID,
  5697. lpItem->lpEntryID,
  5698. MAPI_UNICODE,
  5699. &ulcProps, &lpPropArray);
  5700. if(HR_FAILED(hr))
  5701. goto out;
  5702. // is this a MailUser or a Distribution List
  5703. ulObjectType = lpItem->ulObjectType;
  5704. if(ulObjectType == MAPI_DISTLIST)
  5705. {
  5706. LPTSTR * lppszNameCache = NULL, * lppDLName = NULL, * lppDLOneOffName = NULL;
  5707. LPTSTR * lppszEmailCache = NULL, * lppDLEmail = NULL, * lppDLOneOffEmail = NULL;
  5708. ULONG ulNumNames = 0, ulNames = 0, ulOneOffNames = 0;
  5709. // First we count the data to get a buffer size for our buffer
  5710. for(j=0;j<DLToolTipsProps.cValues;j++)
  5711. {
  5712. for(i=0;i<ulcProps;i++)
  5713. {
  5714. if(lpPropArray[i].ulPropTag == DLToolTipsProps.aulPropTag[j])
  5715. {
  5716. if(lpPropArray[i].ulPropTag == PR_DISPLAY_NAME)
  5717. {
  5718. if(ulBufSize)
  5719. ulBufSize += sizeof(TCHAR)*(lstrlen(szCRLF));
  5720. // we may fdo some overcounting here but its harmless
  5721. ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ) + 1);
  5722. break;
  5723. }
  5724. else if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES || lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS)
  5725. {
  5726. ULONG k;
  5727. ulNumNames = lpPropArray[i].Value.MVbin.cValues;
  5728. lppszNameCache = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulNumNames);
  5729. if(!lppszNameCache)
  5730. break;
  5731. lppszEmailCache = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulNumNames);
  5732. if(!lppszEmailCache)
  5733. break;
  5734. // TBD - check this localalloc value
  5735. for (k = 0; k < ulNumNames; k++)
  5736. {
  5737. LPSPropValue lpProps = NULL;
  5738. ULONG ulcVal = 0;
  5739. ULONG n = 0;
  5740. lppszNameCache[k] = NULL;
  5741. lppszEmailCache[k] = NULL;
  5742. hr = HrGetPropArray(lpAdrBook, NULL,
  5743. lpPropArray[i].Value.MVbin.lpbin[k].cb,
  5744. (LPENTRYID)lpPropArray[i].Value.MVbin.lpbin[k].lpb,
  5745. MAPI_UNICODE,
  5746. &ulcVal,
  5747. &lpProps);
  5748. if(HR_FAILED(hr))
  5749. continue;
  5750. for(n=0;n<ulcVal;n++)
  5751. {
  5752. switch(lpProps[n].ulPropTag)
  5753. {
  5754. case PR_DISPLAY_NAME:
  5755. {
  5756. LPTSTR lpsz = lpProps[n].Value.LPSZ;
  5757. if(ulBufSize)
  5758. ulBufSize += sizeof(TCHAR)*(lstrlen(szLineBreakDL));
  5759. ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz)+1);
  5760. // cache away this name so we dont have to open the property store again
  5761. cchSize=lstrlen(lpsz)+1;
  5762. lppszNameCache[k] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  5763. StrCpyN(lppszNameCache[k], lpsz, cchSize);
  5764. }
  5765. break;
  5766. case PR_EMAIL_ADDRESS:
  5767. {
  5768. LPTSTR lpsz = lpProps[n].Value.LPSZ;
  5769. if(ulBufSize)
  5770. {
  5771. ulBufSize += sizeof(TCHAR)*(lstrlen(szParanStart));
  5772. ulBufSize += sizeof(TCHAR)*(lstrlen(szParanEnd));
  5773. }
  5774. ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz)+1);
  5775. // cache away this name so we dont have to open the property store again
  5776. cchSize=lstrlen(lpsz)+1;
  5777. lppszEmailCache[k] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  5778. StrCpyN(lppszEmailCache[k], lpsz, cchSize);
  5779. }
  5780. break;
  5781. }
  5782. }
  5783. if(lpProps)
  5784. MAPIFreeBuffer(lpProps);
  5785. lpProps = NULL;
  5786. }
  5787. if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES)
  5788. {
  5789. lppDLName = lppszNameCache;
  5790. lppDLEmail = lppszEmailCache;
  5791. ulNames = ulNumNames;
  5792. }
  5793. else
  5794. {
  5795. lppDLOneOffName = lppszNameCache;
  5796. lppDLOneOffEmail = lppszEmailCache;
  5797. ulOneOffNames = ulNumNames;
  5798. }
  5799. break;
  5800. } //if
  5801. }
  5802. } //for i
  5803. } // for j
  5804. lpszData = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
  5805. for(j=0;j<DLToolTipsProps.cValues;j++)
  5806. {
  5807. for(i=0;i<ulcProps;i++)
  5808. {
  5809. if(lpPropArray[i].ulPropTag == DLToolTipsProps.aulPropTag[j])
  5810. {
  5811. if(lpPropArray[i].ulPropTag == PR_DISPLAY_NAME)
  5812. {
  5813. if (lstrlen(lpszData))
  5814. StrCatBuff(lpszData,szCRLF,ulBufSize/sizeof(TCHAR));
  5815. StrCatBuff(lpszData,lpPropArray[i].Value.LPSZ,ulBufSize/sizeof(TCHAR));
  5816. break;
  5817. }
  5818. else if(lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES ||
  5819. lpPropArray[i].ulPropTag == PR_WAB_DL_ONEOFFS)
  5820. {
  5821. ULONG k;
  5822. lppszNameCache = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? lppDLName : lppDLOneOffName;
  5823. lppszEmailCache = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? lppDLEmail : lppDLOneOffEmail;
  5824. ulNumNames = (lpPropArray[i].ulPropTag == PR_WAB_DL_ENTRIES) ? ulNames : ulOneOffNames;
  5825. for (k = 0; k < ulNumNames; k++)
  5826. {
  5827. if (lppszNameCache[k])
  5828. {
  5829. StrCatBuff(lpszData,szLineBreakDL,ulBufSize/sizeof(TCHAR));
  5830. StrCatBuff(lpszData,lppszNameCache[k],ulBufSize/sizeof(TCHAR));
  5831. if(lppszEmailCache[k])
  5832. {
  5833. StrCatBuff(lpszData,szParanStart,ulBufSize/sizeof(TCHAR));
  5834. StrCatBuff(lpszData,lppszEmailCache[k],ulBufSize/sizeof(TCHAR));
  5835. StrCatBuff(lpszData,szParanEnd,ulBufSize/sizeof(TCHAR));
  5836. }
  5837. }
  5838. }
  5839. break;
  5840. }
  5841. }
  5842. } // for i
  5843. } // for j
  5844. // cleanup memory
  5845. if(ulNames)
  5846. {
  5847. for(i=0;i<ulNames;i++)
  5848. {
  5849. LocalFreeAndNull(&lppDLName[i]);
  5850. LocalFreeAndNull(&lppDLEmail[i]);
  5851. }
  5852. LocalFreeAndNull((LPVOID *)&lppDLName);
  5853. LocalFreeAndNull((LPVOID *)&lppDLEmail);
  5854. }
  5855. if(ulOneOffNames)
  5856. {
  5857. for(i=0;i<ulOneOffNames;i++)
  5858. {
  5859. LocalFreeAndNull(&lppDLOneOffName[i]);
  5860. LocalFreeAndNull(&lppDLOneOffEmail[i]);
  5861. }
  5862. LocalFreeAndNull((LPVOID *)&lppDLOneOffName);
  5863. LocalFreeAndNull((LPVOID *)&lppDLOneOffEmail);
  5864. }
  5865. lppszNameCache = NULL;
  5866. lppszEmailCache = NULL;
  5867. }
  5868. else
  5869. {
  5870. // Do MailUser Processing
  5871. lpsz = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ToolTipsProps.cValues);
  5872. if(!lpsz)
  5873. {
  5874. DebugPrintError(( TEXT("Local Alloc failed\n")));
  5875. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  5876. goto out;
  5877. }
  5878. lpulPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG) * ToolTipsProps.cValues);
  5879. if(!lpulPropTagArray)
  5880. {
  5881. DebugPrintError(( TEXT("Local Alloc failed\n")));
  5882. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  5883. goto out;
  5884. }
  5885. // if we dont have PR_CONTACT_EMAIL_ADDRESSES we want PR_EMAIL_ADDRESS
  5886. // and vice versa
  5887. for(j=0;j<ToolTipsProps.cValues;j++)
  5888. {
  5889. lpulPropTagArray[j] = ToolTipsProps.aulPropTag[j];
  5890. if(ToolTipsProps.aulPropTag[j] == PR_EMAIL_ADDRESS)
  5891. {
  5892. for(i=0;i<ulcProps;i++)
  5893. {
  5894. if(lpPropArray[i].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES)
  5895. {
  5896. lpulPropTagArray[j] = PR_CONTACT_EMAIL_ADDRESSES;
  5897. break;
  5898. }
  5899. }
  5900. }
  5901. }
  5902. for(j=0;j<ToolTipsProps.cValues;j++)
  5903. {
  5904. lpsz[j]=NULL;
  5905. for(i=0;i<ulcProps;i++)
  5906. {
  5907. if(lpPropArray[i].ulPropTag == lpulPropTagArray[j])
  5908. {
  5909. if(PROP_TYPE(lpPropArray[i].ulPropTag) == PT_TSTRING)
  5910. {
  5911. if(lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS)
  5912. {
  5913. ulBufSize = sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.LPSZ)+lstrlen(szLineBreakDL)+1);
  5914. lpszEmailAddresses = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
  5915. if(!lpszEmailAddresses)
  5916. {
  5917. DebugPrintError(( TEXT("Local Alloc Failed\n")));
  5918. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  5919. goto out;
  5920. }
  5921. StrCpyN(lpszEmailAddresses, szLineBreakDL,ulBufSize/sizeof(TCHAR));
  5922. StrCatBuff(lpszEmailAddresses, lpPropArray[i].Value.LPSZ,ulBufSize/sizeof(TCHAR));
  5923. lpsz[j] = lpszEmailAddresses;
  5924. }
  5925. else
  5926. lpsz[j] = lpPropArray[i].Value.LPSZ;
  5927. }
  5928. else if(PROP_TYPE(lpPropArray[i].ulPropTag) == PT_MV_TSTRING)
  5929. {
  5930. ULONG k,ulBufSize=0;
  5931. for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
  5932. {
  5933. ulBufSize += sizeof(TCHAR)*(lstrlen(szLineBreakDL));
  5934. ulBufSize += sizeof(TCHAR)*(lstrlen(lpPropArray[i].Value.MVSZ.LPPSZ[k])+1);
  5935. }
  5936. lpszEmailAddresses = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
  5937. if(!lpszEmailAddresses)
  5938. {
  5939. DebugPrintError(( TEXT("Local Alloc Failed\n")));
  5940. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  5941. goto out;
  5942. }
  5943. lpszEmailAddresses[0]=TEXT('\0');
  5944. for (k=0;k<lpPropArray[i].Value.MVSZ.cValues;k++)
  5945. {
  5946. StrCatBuff(lpszEmailAddresses,szLineBreakDL,ulBufSize/sizeof(TCHAR));
  5947. StrCatBuff(lpszEmailAddresses,lpPropArray[i].Value.MVSZ.LPPSZ[k],ulBufSize/sizeof(TCHAR));
  5948. }
  5949. lpsz[j]=lpszEmailAddresses;
  5950. break;
  5951. } //if
  5952. }//if
  5953. }//for i
  5954. }// for j
  5955. //
  5956. // Making this an elegant solution is really hard - just hack it for now
  5957. //
  5958. ulBufSize = 0;
  5959. // Set the display name to the displayed name (whether it is
  5960. // by first name or last name)
  5961. lpsz[txtDisplayName] = lpItem->szDisplayName;
  5962. // Set the localized versions of the addresses if any
  5963. for(i=txtHomeAddress;i<=txtHomeCountry;i++)
  5964. {
  5965. if(lpsz[i])
  5966. {
  5967. TCHAR szBuf[MAX_UI_STR];
  5968. {
  5969. //Bug 1115995 - TEXT("(null)")s produced by Format message for null pointers
  5970. // in the va_list .. replace these with szEmpty
  5971. for(j=txtHomeAddress;j<=txtHomeCountry;j++)
  5972. if(!lpsz[j])
  5973. lpsz[j]=szEmpty;
  5974. }
  5975. LoadString(hinstMapiX, idsContactAddress, szBuf, ARRAYSIZE(szBuf));
  5976. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  5977. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5978. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  5979. szBuf,
  5980. 0, // stringid
  5981. 0, // dwLanguageId
  5982. (LPTSTR)&lpszHomeAddress, // output buffer
  5983. 0, //MAX_UI_STR
  5984. (va_list *)&lpsz[txtHomeAddress]))
  5985. {
  5986. for(j=txtHomeAddress;j<=txtHomeCountry;j++)
  5987. lpsz[j]=NULL;
  5988. CleanAddressString(lpszHomeAddress);
  5989. lpsz[txtHomeAddress] = lpszHomeAddress;
  5990. break;
  5991. }
  5992. }
  5993. }
  5994. for(i=txtHomeAddress;i<=txtHomeWeb;i++)
  5995. {
  5996. if(lpsz[i])
  5997. {
  5998. TCHAR szBuf[MAX_UI_STR];
  5999. bPersonalTitle = TRUE;
  6000. LoadString(hinstMapiX, idsContactTextPersonal, szBuf, ARRAYSIZE(szBuf));
  6001. ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
  6002. break;
  6003. }
  6004. }
  6005. for(i=txtBusinessAddress;i<=txtBusinessCountry;i++)
  6006. {
  6007. if(lpsz[i])
  6008. {
  6009. TCHAR szBuf[MAX_UI_STR];
  6010. {
  6011. //Bug 1115995 - TEXT("(null)")s produced by Format message for null pointers
  6012. // in the va_list .. replace these with szEmpty
  6013. for(j=txtBusinessAddress;j<=txtBusinessCountry;j++)
  6014. if(!lpsz[j])
  6015. lpsz[j]=szEmpty;
  6016. }
  6017. LoadString(hinstMapiX, idsContactAddress, szBuf, ARRAYSIZE(szBuf));
  6018. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  6019. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  6020. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  6021. szBuf,
  6022. 0, // stringid
  6023. 0, // dwLanguageId
  6024. (LPTSTR)&lpszBusinessAddress, // output buffer
  6025. 0, //MAX_UI_STR
  6026. (va_list *)&lpsz[txtBusinessAddress]))
  6027. {
  6028. for(j=txtBusinessAddress;j<=txtBusinessCountry;j++)
  6029. lpsz[j]=NULL;
  6030. CleanAddressString(lpszBusinessAddress);
  6031. lpsz[txtBusinessAddress] = lpszBusinessAddress;
  6032. break;
  6033. }
  6034. }
  6035. }
  6036. for(i=txtBusinessAddress;i<=txtBusinessWeb;i++)
  6037. {
  6038. if(lpsz[i])
  6039. {
  6040. TCHAR szBuf[MAX_UI_STR];
  6041. bBusinessTitle = TRUE;
  6042. LoadString(hinstMapiX, idsContactTextBusiness, szBuf, ARRAYSIZE(szBuf));
  6043. ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
  6044. break;
  6045. }
  6046. }
  6047. for(i=0;i<ToolTipsProps.cValues;i++)
  6048. {
  6049. if(lpsz[i])
  6050. {
  6051. TCHAR szBuf[MAX_UI_STR];
  6052. if(idsString[i] != 0)
  6053. {
  6054. LoadString(hinstMapiX, idsString[i], szBuf, ARRAYSIZE(szBuf));
  6055. ulBufSize += sizeof(TCHAR)*(lstrlen(szBuf));
  6056. }
  6057. ulBufSize += sizeof(TCHAR)*(lstrlen(lpsz[i])+lstrlen(szCRLF));
  6058. }
  6059. }
  6060. ulBufSize += sizeof(TCHAR); // space for trailing zero
  6061. lpszData = LocalAlloc(LMEM_ZEROINIT, ulBufSize);
  6062. if(!lpszData)
  6063. {
  6064. DebugPrintError(( TEXT("Local Alloc failed\n")));
  6065. goto out;
  6066. }
  6067. *lpszData = TEXT('\0');
  6068. for(i=0;i<ToolTipsProps.cValues;i++)
  6069. {
  6070. if(lpsz[i])
  6071. {
  6072. TCHAR szBuf[MAX_UI_STR];
  6073. switch(i)
  6074. {
  6075. case txtHomeAddress:
  6076. case txtHomePhone:
  6077. case txtHomeFax:
  6078. case txtHomeCellular:
  6079. case txtHomeWeb:
  6080. if(bPersonalTitle)
  6081. {
  6082. bPersonalTitle = FALSE;
  6083. LoadString(hinstMapiX, idsContactTextPersonal, szBuf, ARRAYSIZE(szBuf));
  6084. StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
  6085. }
  6086. break;
  6087. case txtBusinessTitle:
  6088. case txtBusinessDept:
  6089. case txtBusinessOffice:
  6090. case txtBusinessCompany:
  6091. case txtBusinessAddress:
  6092. case txtBusinessPhone:
  6093. case txtBusinessFax:
  6094. case txtBusinessPager:
  6095. case txtBusinessWeb:
  6096. if(bBusinessTitle)
  6097. {
  6098. bBusinessTitle = FALSE;
  6099. LoadString(hinstMapiX, idsContactTextBusiness, szBuf, ARRAYSIZE(szBuf));
  6100. StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
  6101. }
  6102. break;
  6103. }
  6104. if(idsString[i] != 0)
  6105. {
  6106. LoadString(hinstMapiX, idsString[i], szBuf, ARRAYSIZE(szBuf));
  6107. StrCatBuff(lpszData, szBuf, ulBufSize/sizeof(TCHAR));
  6108. }
  6109. StrCatBuff(lpszData, lpsz[i], ulBufSize/sizeof(TCHAR));
  6110. StrCatBuff(lpszData, szCRLF, ulBufSize/sizeof(TCHAR));
  6111. }
  6112. }
  6113. //There is a spurious szCRLF at the end. Negate it
  6114. ulBufSize = lstrlen(lpszData);
  6115. lpszData[ulBufSize-2]='\0';
  6116. } // mailuser or dist list
  6117. }
  6118. *lppszData = lpszData;
  6119. hr = hrSuccess;
  6120. out:
  6121. if(lpPropArray)
  6122. MAPIFreeBuffer(lpPropArray);
  6123. if(lpszHomeAddress)
  6124. LocalFree(lpszHomeAddress);
  6125. if(lpszBusinessAddress)
  6126. LocalFree(lpszBusinessAddress);
  6127. if(lpszEmailAddresses)
  6128. LocalFree(lpszEmailAddresses);
  6129. if(lpsz)
  6130. LocalFree(lpsz);
  6131. if(lpulPropTagArray)
  6132. LocalFree(lpulPropTagArray);
  6133. if(HR_FAILED(hr))
  6134. {
  6135. LocalFreeAndNull(&lpszData);
  6136. LocalFreeAndNull(lppszData);
  6137. }
  6138. return hr;
  6139. }
  6140. //$$////////////////////////////////////////////////////////////////////////////////
  6141. //
  6142. // HrCopyItemDataToClipboard - Copies text from selected items in a List View
  6143. // into the clipboard
  6144. //
  6145. //////////////////////////////////////////////////////////////////////////////////////
  6146. HRESULT HrCopyItemDataToClipboard(HWND hWnd, LPADRBOOK lpAdrBook, HWND hWndLV)
  6147. {
  6148. HRESULT hr = E_FAIL;
  6149. int iItemIndex = 0, i = 0;
  6150. int iLastItemIndex = -1;
  6151. int nItemCount = ListView_GetSelectedCount(hWndLV);
  6152. LPTSTR lpszClipBoardData = NULL;
  6153. if( nItemCount <= 0)
  6154. goto out;
  6155. // TBD - messagebox here or item should be grayed
  6156. for(i=0;i<nItemCount;i++)
  6157. {
  6158. LPTSTR lpszData = NULL;
  6159. LPTSTR lpszData2 = NULL;
  6160. ULONG ulMemSize = 0;
  6161. iItemIndex = ListView_GetNextItem(hWndLV, iLastItemIndex, LVNI_SELECTED);
  6162. hr = HrGetLVItemDataString(
  6163. lpAdrBook,
  6164. hWndLV,
  6165. iItemIndex,
  6166. &lpszData);
  6167. if(HR_FAILED(hr))
  6168. {
  6169. goto out;
  6170. }
  6171. else
  6172. {
  6173. if(lpszData)
  6174. {
  6175. // Take the existing clipboard data and add
  6176. // a linebreak and the new data and another linebreak
  6177. if(lpszClipBoardData)
  6178. ulMemSize = sizeof(TCHAR)*(lstrlen(lpszClipBoardData)+lstrlen(szCRLF));
  6179. ulMemSize += sizeof(TCHAR)*(lstrlen(lpszData) + lstrlen(szCRLF) + 1);
  6180. lpszData2 = LocalAlloc(LMEM_ZEROINIT, ulMemSize);
  6181. if(!lpszData2)
  6182. {
  6183. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  6184. goto out;
  6185. }
  6186. if(lpszClipBoardData)
  6187. {
  6188. StrCpyN(lpszData2, lpszClipBoardData, ulMemSize/sizeof(TCHAR));
  6189. StrCatBuff(lpszData2, szCRLF, ulMemSize/sizeof(TCHAR));
  6190. }
  6191. StrCatBuff(lpszData2, lpszData, ulMemSize/sizeof(TCHAR));
  6192. StrCatBuff(lpszData2, szCRLF, ulMemSize/sizeof(TCHAR));
  6193. LocalFreeAndNull(&lpszClipBoardData);
  6194. LocalFreeAndNull(&lpszData);
  6195. lpszClipBoardData = lpszData2;
  6196. }
  6197. }
  6198. iLastItemIndex = iItemIndex;
  6199. }
  6200. if(lpszClipBoardData)
  6201. {
  6202. LPSTR lpszA = ConvertWtoA(lpszClipBoardData);
  6203. OpenClipboard(hWnd);
  6204. EmptyClipboard();
  6205. // We now hand over ownership of the clipboard data to the clipboard
  6206. // which means that we dont have to free this pointer anymore
  6207. SetClipboardData(CF_TEXT, lpszA);
  6208. SetClipboardData(CF_UNICODETEXT, lpszClipBoardData);
  6209. LocalFreeAndNull(&lpszA);
  6210. CloseClipboard();
  6211. }
  6212. hr = hrSuccess;
  6213. out:
  6214. return hr;
  6215. }
  6216. //*******************************************************************
  6217. //
  6218. // FUNCTION: InitCommonControlLib
  6219. //
  6220. // PURPOSE: Load the CommCtrl client libray and get the proc addrs.
  6221. //
  6222. // PARAMETERS: None.
  6223. //
  6224. // RETURNS: TRUE if successful, FALSE otherwise.
  6225. //
  6226. //*******************************************************************
  6227. BOOL InitCommonControlLib(void)
  6228. {
  6229. // See if we already initialized.
  6230. if (NULL == ghCommCtrlDLLInst)
  6231. {
  6232. Assert(gulCommCtrlDLLRefCount == 0);
  6233. // open LDAP client library
  6234. ghCommCtrlDLLInst = LoadLibrary(cszCommCtrlClientDLL);
  6235. if (!ghCommCtrlDLLInst)
  6236. {
  6237. DebugTraceResult( TEXT("InitCommCtrlClientLib: Failed to LoadLibrary CommCtrl"),GetLastError());
  6238. return FALSE;
  6239. }
  6240. // cycle through the API table and get proc addresses for all the APIs we
  6241. // need
  6242. if (!GetApiProcAddresses(ghCommCtrlDLLInst,CommCtrlAPIList,NUM_CommCtrlAPI_PROCS))
  6243. {
  6244. DebugTrace( TEXT("InitCommCTrlLib: Failed to load LDAP API.\n"));
  6245. // Unload the library we just loaded.
  6246. if (ghCommCtrlDLLInst)
  6247. {
  6248. FreeLibrary(ghCommCtrlDLLInst);
  6249. ghCommCtrlDLLInst = NULL;
  6250. }
  6251. return FALSE;
  6252. }
  6253. // Initialize the CommonControl classes
  6254. {
  6255. INITCOMMONCONTROLSEX iccex;
  6256. iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  6257. iccex.dwICC = //ICC_ALL_CLASSES;
  6258. ICC_LISTVIEW_CLASSES |
  6259. ICC_TREEVIEW_CLASSES |
  6260. ICC_BAR_CLASSES |
  6261. ICC_COOL_CLASSES |
  6262. ICC_ANIMATE_CLASS |
  6263. ICC_WIN95_CLASSES |
  6264. ICC_DATE_CLASSES;
  6265. iccex.dwICC |= ICC_NATIVEFNTCTL_CLASS;
  6266. if(!gpfnInitCommonControlsEx(&iccex))
  6267. {
  6268. //Couldnt initialize
  6269. DebugTrace( TEXT("InitCommCTrlLib: Failed to InitCommonControlsEx\n"));
  6270. // Unload the library we just loaded.
  6271. if (ghCommCtrlDLLInst)
  6272. {
  6273. FreeLibrary(ghCommCtrlDLLInst);
  6274. ghCommCtrlDLLInst = NULL;
  6275. }
  6276. return FALSE;
  6277. }
  6278. }
  6279. }
  6280. gulCommCtrlDLLRefCount++;
  6281. return TRUE;
  6282. }
  6283. //$$*****************************************************************
  6284. //
  6285. // FUNCTION: DeinitCommCtrlClientLib
  6286. //
  6287. // PURPOSE: decrement refcount on LDAP CLient library and
  6288. // release if 0.
  6289. //
  6290. // PARAMETERS: None.
  6291. //
  6292. // RETURNS: current refcount
  6293. //
  6294. //*******************************************************************
  6295. ULONG DeinitCommCtrlClientLib(void) {
  6296. if (-- gulCommCtrlDLLRefCount == 0) {
  6297. UINT nIndex;
  6298. // No clients using the CommCtrl library. Release it.
  6299. if (ghCommCtrlDLLInst) {
  6300. FreeLibrary(ghCommCtrlDLLInst);
  6301. ghCommCtrlDLLInst = NULL;
  6302. }
  6303. // cycle through the API table and NULL proc addresses for all the APIs
  6304. for (nIndex = 0; nIndex < NUM_CommCtrlAPI_PROCS; nIndex++) {
  6305. *CommCtrlAPIList[nIndex].ppFcnPtr = NULL;
  6306. }
  6307. }
  6308. return(gulCommCtrlDLLRefCount);
  6309. }
  6310. //$$*****************************************************************
  6311. //
  6312. // FUNCTION: HelpAboutDialogProc
  6313. //
  6314. // PURPOSE: minimal help/about dialog proc
  6315. //
  6316. //
  6317. //*******************************************************************
  6318. INT_PTR CALLBACK HelpAboutDialogProc( HWND hDlg,
  6319. UINT message,
  6320. WPARAM wParam,
  6321. LPARAM lParam)
  6322. {
  6323. switch(message)
  6324. {
  6325. case WM_INITDIALOG:
  6326. {
  6327. // Easiest to keep this version info stuff in ANSI than to write wrappers for it ..
  6328. //
  6329. DWORD dwSize = 0, dwh = 0;
  6330. ULONG i = 0;
  6331. char szFile[MAX_PATH];
  6332. LPTSTR lpDataFile = NULL;
  6333. GetModuleFileNameA(hinstMapiXWAB, szFile, sizeof(szFile));
  6334. if(dwSize = GetFileVersionInfoSizeA(szFile, &dwh))
  6335. {
  6336. LPWORD lpwTrans = NULL;
  6337. LPVOID lpInfo = LocalAlloc(LMEM_ZEROINIT, dwSize+1);
  6338. if(lpInfo)
  6339. {
  6340. if(GetFileVersionInfoA( szFile, dwh, dwSize, lpInfo))
  6341. {
  6342. LPVOID lpVersion = NULL, lpszT = NULL;
  6343. DWORD uLen;
  6344. char szBuf[MAX_UI_STR];
  6345. if (VerQueryValueA(lpInfo, "\\VarFileInfo\\Translation", (LPVOID *)&lpwTrans, &uLen) &&
  6346. uLen >= (2 * sizeof(WORD)))
  6347. {
  6348. // set up buffer for calls to VerQueryValue()
  6349. CHAR *rgszVer[] = { "FileVersion", "LegalCopyright" };
  6350. int rgId[] = { IDC_ABOUT_LABEL_VERSION, IDC_ABOUT_COPYRIGHT };
  6351. DWORD cch;
  6352. wnsprintfA(szBuf, ARRAYSIZE(szBuf), "\\StringFileInfo\\%04X%04X\\", lpwTrans[0], lpwTrans[1]);
  6353. lpszT = szBuf + lstrlenA(szBuf);
  6354. cch = ARRAYSIZE(szBuf) - lstrlenA(szBuf);
  6355. // Walk through the dialog items that we want to replace:
  6356. for (i = 0; i <= 1; i++)
  6357. {
  6358. StrCpyNA(lpszT, rgszVer[i], cch);
  6359. if (VerQueryValueA(lpInfo, szBuf, (LPVOID *)&lpVersion, &uLen) && uLen)
  6360. {
  6361. LPTSTR lp = ConvertAtoW((LPSTR) lpVersion);
  6362. SetDlgItemText(hDlg, rgId[i], lp);
  6363. LocalFreeAndNull(&lp);
  6364. }
  6365. }
  6366. }
  6367. }
  6368. LocalFree(lpInfo);
  6369. }
  6370. }
  6371. else
  6372. DebugPrintTrace(( TEXT("GetFileVersionSize failed: %d\n"),GetLastError()));
  6373. {
  6374. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  6375. if(pt_lpIAB && !pt_bIsWABOpenExSession)
  6376. {
  6377. // hack
  6378. lpDataFile = GetWABFileName(((LPIAB)pt_lpIAB)->lpPropertyStore->hPropertyStore, FALSE);
  6379. }
  6380. if(lpDataFile && lstrlen(lpDataFile))
  6381. SetDlgItemText(hDlg, IDC_ABOUT_EDIT_FILENAME, lpDataFile);
  6382. else
  6383. {
  6384. ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_EDIT_FILENAME), SW_HIDE);
  6385. ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_STATIC_FILENAME), SW_HIDE);
  6386. }
  6387. }
  6388. }
  6389. break;
  6390. case WM_COMMAND:
  6391. switch (GET_WM_COMMAND_ID(wParam, lParam))
  6392. {
  6393. case IDCANCEL:
  6394. case IDOK:
  6395. EndDialog(hDlg, 0);
  6396. break;
  6397. }
  6398. break;
  6399. default:
  6400. return FALSE;
  6401. break;
  6402. }
  6403. return TRUE;
  6404. }
  6405. //$$////////////////////////////////////////////////////////////////////
  6406. //
  6407. // nTruncatePos
  6408. //
  6409. // With DBCS strings we want to truncate the string at the beginning of
  6410. // a TCHAR and not in the middle of the double TCHAR.
  6411. // Hence we take a string, take in the maximum length we want, scan the
  6412. // string and return the length of the string at which we can safely
  6413. // truncate
  6414. //
  6415. // PARAMETERS:
  6416. // lpsz - input string
  6417. // nMaxLen - maximum allowed length of the string
  6418. //
  6419. ////////////////////////////////////////////////////////////////////////
  6420. ULONG TruncatePos(LPTSTR lpsz, ULONG nMaxLen)
  6421. {
  6422. ULONG nLen = 0;
  6423. ULONG nDesiredLen = 0;
  6424. if(!lpsz || !lstrlen(lpsz) || !nMaxLen)
  6425. goto out;
  6426. nLen = lstrlen(lpsz);
  6427. if (nLen >= nMaxLen)
  6428. {
  6429. ULONG nCharsSteppedOverCount = 0;
  6430. ULONG nLastCharCount = 0;
  6431. ULONG nTotalLen = nLen; //lstrlen(lpsz);
  6432. nDesiredLen = nMaxLen;
  6433. while(*lpsz)
  6434. {
  6435. nLastCharCount = nCharsSteppedOverCount;
  6436. lpsz = CharNext(lpsz);
  6437. nCharsSteppedOverCount = nTotalLen - lstrlen(lpsz); // + 1;
  6438. if(nCharsSteppedOverCount > nDesiredLen)
  6439. break;
  6440. }
  6441. if (nCharsSteppedOverCount < nDesiredLen)
  6442. nLen = nCharsSteppedOverCount;
  6443. else
  6444. nLen = nLastCharCount;
  6445. }
  6446. out:
  6447. return nLen;
  6448. }
  6449. //$$////////////////////////////////////////////////////////////////////
  6450. //
  6451. // FreeRecipList - frees allocated memory in a RecipientInfo List
  6452. //
  6453. //
  6454. // PARAMETERS:
  6455. // lppList - list to free
  6456. //
  6457. ////////////////////////////////////////////////////////////////////////
  6458. void FreeRecipList(LPRECIPIENT_INFO * lppList)
  6459. {
  6460. if(lppList)
  6461. {
  6462. LPRECIPIENT_INFO lpItem = NULL;
  6463. lpItem = *lppList;
  6464. while(lpItem)
  6465. {
  6466. *lppList = lpItem->lpNext;
  6467. FreeRecipItem(&lpItem);
  6468. lpItem = *lppList;
  6469. }
  6470. *lppList = NULL;
  6471. }
  6472. return;
  6473. }
  6474. //$$////////////////////////////////////////////////////////////////////
  6475. //
  6476. // HrCreateNewObject - Creates a new object in the wab
  6477. //
  6478. //
  6479. // PARAMETERS:
  6480. // lpIAB - lpAdrbook
  6481. // &lpMailUser - MailUser to return
  6482. //
  6483. ////////////////////////////////////////////////////////////////////////
  6484. HRESULT HrCreateNewObject(LPADRBOOK lpAdrBook,
  6485. LPSBinary lpsbContainer,
  6486. ULONG ulObjectType,
  6487. ULONG ulCreateFlags,
  6488. LPMAPIPROP * lppPropObj)
  6489. {
  6490. HRESULT hResult = hrSuccess;
  6491. LPENTRYID lpWABEID = NULL;
  6492. ULONG cbWABEID = 0;
  6493. ULONG ulObjType = 0;
  6494. ULONG cProps = 0;
  6495. LPABCONT lpContainer = NULL;
  6496. LPSPropValue lpCreateEIDs = NULL;
  6497. LPMAPIPROP lpPropObj = NULL;
  6498. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  6499. LPIAB lpIAB = (LPIAB) lpAdrBook;
  6500. if(!lpsbContainer || !lpsbContainer->cb || !lpsbContainer->lpb)
  6501. {
  6502. SetVirtualPABEID(lpIAB, &cbWABEID, &lpWABEID);
  6503. if (hResult = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbWABEID, &lpWABEID))
  6504. goto exit;
  6505. }
  6506. else
  6507. {
  6508. cbWABEID = lpsbContainer->cb;
  6509. lpWABEID = (LPENTRYID) lpsbContainer->lpb;
  6510. }
  6511. if (hResult = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  6512. cbWABEID, // size of EntryID to open
  6513. lpWABEID, // EntryID to open
  6514. NULL, // interface
  6515. 0, // flags
  6516. &ulObjType,
  6517. (LPUNKNOWN *)&lpContainer)) {
  6518. goto exit;
  6519. }
  6520. // Get us the creation entryids
  6521. if (hResult = lpContainer->lpVtbl->GetProps(lpContainer,
  6522. (LPSPropTagArray)&ptaCreate,
  6523. MAPI_UNICODE,
  6524. &cProps,
  6525. &lpCreateEIDs)) {
  6526. DebugTrace( TEXT("Can't get container properties for PAB\n"));
  6527. // Bad stuff here!
  6528. goto exit;
  6529. }
  6530. if (hResult = lpContainer->lpVtbl->CreateEntry(lpContainer,
  6531. (ulObjectType == MAPI_MAILUSER ?
  6532. lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].Value.bin.cb : lpCreateEIDs[icrPR_DEF_CREATE_DL].Value.bin.cb),
  6533. (ulObjectType == MAPI_MAILUSER ?
  6534. (LPENTRYID)lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].Value.bin.lpb : (LPENTRYID)lpCreateEIDs[icrPR_DEF_CREATE_DL].Value.bin.lpb),
  6535. ulCreateFlags,
  6536. &lpPropObj)) {
  6537. DebugTraceResult( TEXT("CreateMailUser:CreateEntry"), hResult);
  6538. goto exit;
  6539. }
  6540. *lppPropObj = lpPropObj;
  6541. exit:
  6542. if(HR_FAILED(hResult) && lpPropObj)
  6543. lpPropObj->lpVtbl->Release(lpPropObj);
  6544. if(lpWABEID && (!lpsbContainer || lpsbContainer->lpb != (LPBYTE) lpWABEID))
  6545. FreeBufferAndNull(&lpWABEID);
  6546. UlRelease(lpContainer);
  6547. FreeBufferAndNull(&lpCreateEIDs);
  6548. return hResult;
  6549. }
  6550. const LPTSTR szDefMailKey = TEXT("Software\\Clients\\Mail");
  6551. const LPTSTR szOEDllPathKey = TEXT("DllPath");
  6552. const LPTSTR szOEName = TEXT("Outlook Express");
  6553. //$$///////////////////////////////////////////////////////////////////////
  6554. //
  6555. // CheckForOutlookExpress
  6556. //
  6557. // szDllPath - is a big enough buffer that will contain the path for
  6558. // the OE dll ..
  6559. //
  6560. //////////////////////////////////////////////////////////////////////////
  6561. BOOL CheckForOutlookExpress(LPTSTR szDllPath, DWORD cchDllPath)
  6562. {
  6563. HKEY hKeyMail = NULL;
  6564. HKEY hKeyOE = NULL;
  6565. DWORD dwErr = 0;
  6566. DWORD dwSize = 0;
  6567. TCHAR szBuf[MAX_PATH];
  6568. TCHAR szPathExpand[MAX_PATH];
  6569. DWORD dwType = 0;
  6570. BOOL bRet = FALSE;
  6571. szDllPath[0] = TEXT('\0');
  6572. szPathExpand[0] = TEXT('\0');
  6573. // Open the key for default internet mail client
  6574. // HKLM\Software\Clients\Mail
  6575. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szDefMailKey, 0, KEY_READ, &hKeyMail);
  6576. if(dwErr != ERROR_SUCCESS)
  6577. {
  6578. DebugTrace( TEXT("RegopenKey %s Failed -> %u\n"), szDefMailKey, dwErr);
  6579. goto out;
  6580. }
  6581. dwSize = ARRAYSIZE(szBuf); // Expect ERROR_MORE_DATA
  6582. dwErr = RegQueryValueEx( hKeyMail, NULL, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
  6583. if(dwErr != ERROR_SUCCESS)
  6584. {
  6585. goto out;
  6586. }
  6587. if(!lstrcmpi(szBuf, szOEName))
  6588. {
  6589. // Yes its outlook express ..
  6590. bRet = TRUE;
  6591. }
  6592. //Get the DLL Path anyway whether this is the default key or not
  6593. // Get the DLL Path
  6594. dwErr = RegOpenKeyEx(hKeyMail, szOEName, 0, KEY_READ, &hKeyOE);
  6595. if(dwErr != ERROR_SUCCESS)
  6596. {
  6597. DebugTrace( TEXT("RegopenKey %s Failed -> %u\n"), szDefMailKey, dwErr);
  6598. goto out;
  6599. }
  6600. dwSize = ARRAYSIZE(szBuf);
  6601. szBuf[0]=TEXT('\0');
  6602. dwErr = RegQueryValueEx(hKeyOE, szOEDllPathKey, NULL, &dwType, (LPBYTE)szBuf, &dwSize);
  6603. if (REG_EXPAND_SZ == dwType)
  6604. {
  6605. ExpandEnvironmentStrings(szBuf, szPathExpand, ARRAYSIZE(szPathExpand));
  6606. StrCpyN(szBuf, szPathExpand,ARRAYSIZE(szBuf));
  6607. }
  6608. if(dwErr != ERROR_SUCCESS)
  6609. {
  6610. goto out;
  6611. }
  6612. if(lstrlen(szBuf))
  6613. StrCpyN(szDllPath, szBuf, cchDllPath);
  6614. out:
  6615. if(hKeyOE)
  6616. RegCloseKey(hKeyOE);
  6617. if(hKeyMail)
  6618. RegCloseKey(hKeyMail);
  6619. return bRet;
  6620. }
  6621. static const SizedSPropTagArray(1, ptaMailToExItemType)=
  6622. {
  6623. 1,
  6624. {
  6625. PR_OBJECT_TYPE,
  6626. }
  6627. };
  6628. // We will create a linked list of all selected entries that have an
  6629. // email address and then use that to create the recip list for sendmail
  6630. typedef struct _RecipList
  6631. {
  6632. LPTSTR lpszName;
  6633. LPTSTR lpszEmail;
  6634. LPSBinary lpSB;
  6635. struct _RecipList * lpNext;
  6636. } RECIPLIST, * LPRECIPLIST;
  6637. //$$/////////////////////////////////////////////////////////////////////
  6638. //
  6639. // FreeLPRecipList
  6640. //
  6641. // Frees a linked list containing the above structures
  6642. //
  6643. /////////////////////////////////////////////////////////////////////////
  6644. void FreeLPRecipList(LPRECIPLIST lpList)
  6645. {
  6646. if(lpList)
  6647. {
  6648. LPRECIPLIST lpTemp = lpList;
  6649. while(lpTemp)
  6650. {
  6651. lpList = lpTemp->lpNext;
  6652. if(lpTemp->lpszName)
  6653. LocalFree(lpTemp->lpszName);
  6654. if(lpTemp->lpszEmail)
  6655. LocalFree(lpTemp->lpszEmail);
  6656. if(lpTemp->lpSB)
  6657. MAPIFreeBuffer(lpTemp->lpSB);
  6658. LocalFree(lpTemp);
  6659. lpTemp = lpList;
  6660. }
  6661. }
  6662. }
  6663. //$$/////////////////////////////////////////////////////////////////////
  6664. //
  6665. // GetItemNameEmail
  6666. //
  6667. // Gets the name and email address of the specified item
  6668. // and appends it to the provided linked list ..
  6669. //
  6670. /////////////////////////////////////////////////////////////////////////
  6671. HRESULT HrGetItemNameEmail( LPADRBOOK lpAdrBook,
  6672. BOOL bIsOE,
  6673. ULONG cbEntryID,
  6674. LPENTRYID lpEntryID,
  6675. int nExtEmail,
  6676. LPRECIPLIST * lppList)
  6677. {
  6678. HRESULT hr = E_FAIL;
  6679. ULONG cValues;
  6680. LPRECIPLIST lpTemp = NULL;
  6681. LPSPropValue lpspv = NULL;
  6682. LPRECIPLIST lpList = *lppList;
  6683. LPTSTR lpEmail = NULL, lpAddrType = NULL, lpName = NULL;
  6684. SizedSPropTagArray(5, ptaMailToEx)=
  6685. {
  6686. 5, {
  6687. PR_DISPLAY_NAME,
  6688. PR_EMAIL_ADDRESS,
  6689. PR_ADDRTYPE,
  6690. PR_CONTACT_EMAIL_ADDRESSES,
  6691. PR_CONTACT_ADDRTYPES
  6692. }
  6693. };
  6694. // Open the entry and read the email address.
  6695. // NOTE: We can't just take the address out of the listbox
  6696. // because it may be truncated!
  6697. if (HR_FAILED(hr = HrGetPropArray( lpAdrBook,
  6698. (LPSPropTagArray)&ptaMailToEx,
  6699. cbEntryID,
  6700. lpEntryID,
  6701. MAPI_UNICODE,
  6702. &cValues,
  6703. &lpspv)))
  6704. {
  6705. goto out;
  6706. }
  6707. lpName = (lpspv[0].ulPropTag == PR_DISPLAY_NAME) ? lpspv[0].Value.LPSZ : szEmpty;
  6708. if( nExtEmail &&
  6709. lpspv[3].ulPropTag == PR_CONTACT_EMAIL_ADDRESSES &&
  6710. lpspv[4].ulPropTag == PR_CONTACT_ADDRTYPES &&
  6711. lpspv[3].Value.MVSZ.cValues >= (ULONG)nExtEmail)
  6712. {
  6713. lpEmail = lpspv[3].Value.MVSZ.LPPSZ[nExtEmail-1];
  6714. lpAddrType = lpspv[4].Value.MVSZ.LPPSZ[nExtEmail-1];
  6715. }
  6716. if(!lpEmail)
  6717. lpEmail = (lpspv[1].ulPropTag == PR_EMAIL_ADDRESS) ? lpspv[1].Value.LPSZ : szEmpty;
  6718. if(!lpAddrType)
  6719. lpAddrType = (lpspv[2].ulPropTag == PR_ADDRTYPE) ? lpspv[2].Value.LPSZ : szEmpty;
  6720. if(lstrlen(lpEmail) && lstrlen(lpName)) //only if this item has a email address do we include it
  6721. {
  6722. lpTemp = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPLIST));
  6723. if(lpTemp)
  6724. {
  6725. DWORD cchEmail;
  6726. DWORD cchName=lstrlen(lpName) + 1;
  6727. lpTemp->lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchName);
  6728. if (lpTemp->lpszName)
  6729. {
  6730. StrCpyN(lpTemp->lpszName, lpName, cchName);
  6731. }
  6732. cchEmail=(lstrlen(lpEmail) + lstrlen(lpAddrType) + 2);
  6733. lpTemp->lpszEmail = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchEmail);
  6734. if (lpTemp->lpszEmail)
  6735. {
  6736. if(bIsOE)
  6737. {
  6738. lpTemp->lpszEmail[0]=TEXT('\0');
  6739. }
  6740. else
  6741. {
  6742. StrCpyN(lpTemp->lpszEmail, lpAddrType, cchEmail);
  6743. StrCatBuff(lpTemp->lpszEmail, szColon, cchEmail);
  6744. }
  6745. StrCatBuff(lpTemp->lpszEmail, lpEmail, cchEmail);
  6746. }
  6747. MAPIAllocateBuffer(sizeof(SBinary), (LPVOID) &(lpTemp->lpSB));
  6748. // Create a one off entry id for this buffer
  6749. CreateWABEntryID(WAB_ONEOFF,
  6750. lpTemp->lpszName,
  6751. lpAddrType,
  6752. lpEmail,
  6753. 0, 0,
  6754. (LPVOID) lpTemp->lpSB,
  6755. (LPULONG) (&(lpTemp->lpSB->cb)),
  6756. (LPENTRYID *) &(lpTemp->lpSB->lpb));
  6757. lpTemp->lpNext = lpList;
  6758. lpList = lpTemp;
  6759. }
  6760. }
  6761. FreeBufferAndNull(&lpspv);
  6762. *lppList = lpList;
  6763. hr = S_OK;
  6764. out:
  6765. return hr;
  6766. }
  6767. //$$//////////////////////////////////////////////////////////////////
  6768. //
  6769. // Function that opens an item and adds it to the recip list
  6770. // If the opened item is a group, calls itself recursively for all
  6771. // subgroups ..
  6772. //
  6773. // lpnRecipCount - returns the number of items in lppList
  6774. // lppList - dynamically allocated - must be freed by caller
  6775. // bIsOE - tells us to follow a slightly different code-path to handle OE
  6776. // inconsistencies - ** warning ** - this will break when they
  6777. // fix their inconsistencies
  6778. // nExtEmail - this is non-zero when there is a single selection and the
  6779. // user chose a non-default email address which should be used for
  6780. // sending mail
  6781. //
  6782. //////////////////////////////////////////////////////////////////////
  6783. HRESULT GetRecipListFromSelection(LPADRBOOK lpAdrBook,
  6784. BOOL bIsOE,
  6785. ULONG cbEntryID,
  6786. LPENTRYID lpEntryID,
  6787. int nExtEmail,
  6788. ULONG * lpnRecipCount,
  6789. ULONG * lpnNoEmailCount,
  6790. LPRECIPLIST * lppList)
  6791. {
  6792. ULONG ulObjectType = 0;
  6793. HRESULT hr = E_FAIL;
  6794. {
  6795. ULONG cValues = 0;
  6796. LPSPropValue lpspv = NULL;
  6797. // First check if this item is a mailuser or a group
  6798. if (HR_FAILED(hr = HrGetPropArray( lpAdrBook,
  6799. (LPSPropTagArray)&ptaMailToExItemType,
  6800. cbEntryID,
  6801. lpEntryID,
  6802. MAPI_UNICODE,
  6803. &cValues,
  6804. &lpspv)))
  6805. {
  6806. return hr;
  6807. }
  6808. ulObjectType = lpspv[0].Value.l;
  6809. FreeBufferAndNull(&lpspv);
  6810. }
  6811. if(ulObjectType == MAPI_MAILUSER)
  6812. {
  6813. LPRECIPLIST lpTemp = *lppList;
  6814. if (!HR_FAILED(hr = HrGetItemNameEmail(lpAdrBook, bIsOE, cbEntryID,lpEntryID, nExtEmail, lppList)))
  6815. {
  6816. if(lpTemp != *lppList) // means an item was added to the list ..
  6817. (*lpnRecipCount)++;
  6818. else
  6819. (*lpnNoEmailCount)++;
  6820. }
  6821. }
  6822. else if(ulObjectType == MAPI_DISTLIST)
  6823. {
  6824. ULONG cValues = 0;
  6825. LPSPropValue lpspv = NULL;
  6826. SizedSPropTagArray(2, tagaDLEntriesOneOffs) =
  6827. {
  6828. 2,
  6829. {
  6830. PR_WAB_DL_ENTRIES,
  6831. PR_WAB_DL_ONEOFFS,
  6832. }
  6833. };
  6834. if (HR_FAILED(hr = HrGetPropArray( lpAdrBook, (LPSPropTagArray)&tagaDLEntriesOneOffs,
  6835. cbEntryID, lpEntryID,
  6836. MAPI_UNICODE,
  6837. &cValues, &lpspv)))
  6838. {
  6839. return hr;
  6840. }
  6841. {
  6842. ULONG i,j;
  6843. for(i=0;i<2;i++)
  6844. {
  6845. if(lpspv[i].ulPropTag == PR_WAB_DL_ENTRIES || lpspv[i].ulPropTag == PR_WAB_DL_ONEOFFS)
  6846. {
  6847. // Look at each entry in the PR_WAB_DL_ENTRIES and PR_WAB_DL_ONEOFFS
  6848. for (j = 0; j < lpspv[i].Value.MVbin.cValues; j++)
  6849. {
  6850. ULONG cbEID = lpspv[i].Value.MVbin.lpbin[j].cb;
  6851. LPENTRYID lpEID = (LPENTRYID)lpspv[i].Value.MVbin.lpbin[j].lpb;
  6852. GetRecipListFromSelection(lpAdrBook, bIsOE, cbEID, lpEID, 0, lpnRecipCount, lpnNoEmailCount, lppList);
  6853. }
  6854. }
  6855. }
  6856. }
  6857. FreeBufferAndNull(&lpspv);
  6858. }
  6859. return hr;
  6860. }
  6861. //$$//////////////////////////////////////////////////////////////////////
  6862. //
  6863. // HrSendMail - does the actual mail sending
  6864. // Our first priority is to Outlook Express which currently has a
  6865. // different code path than the regular MAPI client .. so we look
  6866. // under HKLM\Software\Clients\Mail .. if the client is OE then
  6867. // we just loadlibrary and getprocaddress for sendmail
  6868. // If its not OE, then we call the mapi32.dll and load it ..
  6869. // If both fail we will not be able to send mail ...
  6870. //
  6871. // This function will free the lpList no matter what happens
  6872. // so caller should not expect to reuse it (This is so we can
  6873. // give the pointer to a seperate thread and not worry about it)
  6874. //
  6875. //////////////////////////////////////////////////////////////////////////
  6876. HRESULT HrSendMail(HWND hWndParent, ULONG nRecipCount, LPRECIPLIST lpList, LPIAB lpIAB, BOOL bUseOEForSendMail)
  6877. {
  6878. HRESULT hr = E_FAIL;
  6879. HINSTANCE hLibMapi = NULL;
  6880. BOOL bIsOE = FALSE; // right now there is a different code path
  6881. // for OE vs other MAPI clients
  6882. TCHAR szBuf[MAX_PATH];
  6883. LPMAPISENDMAIL lpfnMAPISendMail = NULL;
  6884. LHANDLE hMapiSession = 0;
  6885. LPMAPILOGON lpfnMAPILogon = NULL;
  6886. LPMAPILOGOFF lpfnMAPILogoff = NULL;
  6887. LPBYTE lpbName, lpbAddrType, lpbEmail;
  6888. ULONG ulMapiDataType;
  6889. ULONG cbEntryID = 0;
  6890. LPENTRYID lpEntryID = NULL;
  6891. MapiMessage Msg = {0};
  6892. MapiRecipDesc * lprecips = NULL;
  6893. if(!nRecipCount)
  6894. {
  6895. hr = MAPI_W_ERRORS_RETURNED;
  6896. goto out;
  6897. }
  6898. // Check if OutlookExpress is the default current client ..
  6899. bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
  6900. // Turn off all notifications for simple MAPI send mail, if the default
  6901. // email client is Outlook. This is necessary because Outlook changes the
  6902. // WAB MAPI allocation functions during simple MAPI and we don't want any
  6903. // internal WAB functions using these allocators.
  6904. if (!bIsOE && !bUseOEForSendMail)
  6905. vTurnOffAllNotifications();
  6906. // if OE is the default client or OE launched this WAB, use OE for SendMail
  6907. if(lstrlen(szBuf) && (bIsOE||bUseOEForSendMail))
  6908. {
  6909. hLibMapi = LoadLibrary(szBuf);
  6910. }
  6911. else
  6912. {
  6913. // Check if simple mapi is installed
  6914. if(GetProfileInt( TEXT("mail"), TEXT("mapi"), 0) == 1)
  6915. hLibMapi = LoadLibrary( TEXT("mapi32.dll"));
  6916. if(!hLibMapi) // try loading the OE MAPI dll directly
  6917. {
  6918. // Load the path to the msimnui.dll
  6919. CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
  6920. if(lstrlen(szBuf)) // Load the dll directly - dont bother going through msoemapi.dll
  6921. hLibMapi = LoadLibrary(szBuf);
  6922. }
  6923. }
  6924. if(!hLibMapi)
  6925. {
  6926. DebugPrintError(( TEXT("Could not load/find simple mapi\n")));
  6927. hr = MAPI_E_NOT_FOUND;
  6928. goto out;
  6929. }
  6930. else if(hLibMapi)
  6931. {
  6932. lpfnMAPILogon = (LPMAPILOGON) GetProcAddress (hLibMapi, "MAPILogon");
  6933. lpfnMAPILogoff= (LPMAPILOGOFF)GetProcAddress (hLibMapi, "MAPILogoff");
  6934. lpfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress (hLibMapi, "MAPISendMail");
  6935. if(!lpfnMAPISendMail || !lpfnMAPILogon || !lpfnMAPILogoff)
  6936. {
  6937. DebugPrintError(( TEXT("MAPI proc not found\n")));
  6938. hr = MAPI_E_NOT_FOUND;
  6939. goto out;
  6940. }
  6941. hr = lpfnMAPILogon( (ULONG_PTR)hWndParent, NULL,
  6942. NULL, // No password needed.
  6943. 0L, // Use shared session.
  6944. 0L, // Reserved; must be 0.
  6945. &hMapiSession); // Session handle.
  6946. if(hr != SUCCESS_SUCCESS)
  6947. {
  6948. DebugTrace( TEXT("MAPILogon failed\n"));
  6949. // its possible the logon failed since there was no shared logon session
  6950. // Try again to create a new session with UI
  6951. hr = lpfnMAPILogon( (ULONG_PTR)hWndParent, NULL,
  6952. NULL, // No password needed.
  6953. MAPI_LOGON_UI | MAPI_NEW_SESSION, // Use shared session.
  6954. 0L, // Reserved; must be 0.
  6955. &hMapiSession); // Session handle.
  6956. if(hr != SUCCESS_SUCCESS)
  6957. {
  6958. DebugTrace( TEXT("MAPILogon failed\n"));
  6959. goto out;
  6960. }
  6961. }
  6962. }
  6963. // Load the MAPI functions here ...
  6964. //
  6965. lprecips = LocalAlloc(LMEM_ZEROINIT, sizeof(MapiRecipDesc) * nRecipCount);
  6966. {
  6967. LPRECIPLIST lpTemp = lpList;
  6968. ULONG count = 0;
  6969. while(lpTemp)
  6970. {
  6971. lprecips[count].ulRecipClass = MAPI_TO;
  6972. lprecips[count].lpszName = ConvertWtoA(lpTemp->lpszName);
  6973. lprecips[count].lpszAddress = ConvertWtoA(lpTemp->lpszEmail);
  6974. // [PaulHi] 4/20/99 Raid 73455
  6975. // Convert Unicode EID OneOff strings to ANSI
  6976. if ( IsWABEntryID(lpTemp->lpSB->cb, (LPVOID)lpTemp->lpSB->lpb,
  6977. &lpbName, &lpbAddrType, &lpbEmail, (LPVOID *)&ulMapiDataType, NULL) == WAB_ONEOFF )
  6978. {
  6979. #ifndef _WIN64 // As I founf from RAID this part only for Outlook
  6980. if (ulMapiDataType & MAPI_UNICODE)
  6981. {
  6982. hr = CreateWABEntryIDEx(
  6983. FALSE, // Don't want Unicode EID strings
  6984. WAB_ONEOFF, // EID type
  6985. (LPWSTR)lpbName,
  6986. (LPWSTR)lpbAddrType,
  6987. (LPWSTR)lpbEmail,
  6988. 0,
  6989. 0,
  6990. NULL,
  6991. &cbEntryID,
  6992. &lpEntryID);
  6993. if (FAILED(hr))
  6994. goto out;
  6995. lprecips[count].ulEIDSize = cbEntryID;
  6996. lprecips[count].lpEntryID = lpEntryID;
  6997. }
  6998. else
  6999. #endif // _WIN64
  7000. {
  7001. lprecips[count].ulEIDSize = lpTemp->lpSB->cb;
  7002. lprecips[count].lpEntryID = (LPVOID)lpTemp->lpSB->lpb;
  7003. }
  7004. }
  7005. lpTemp = lpTemp->lpNext;
  7006. count++;
  7007. }
  7008. }
  7009. Msg.nRecipCount = nRecipCount;
  7010. Msg.lpRecips = lprecips;
  7011. hr = lpfnMAPISendMail (hMapiSession, (ULONG_PTR)hWndParent,
  7012. &Msg, // the message being sent
  7013. MAPI_DIALOG, // allow the user to edit the message
  7014. 0L); // reserved; must be 0
  7015. if(hr != SUCCESS_SUCCESS)
  7016. goto out;
  7017. hr = S_OK;
  7018. out:
  7019. // This must be freed within the Outlook simple MAPI session, since it was
  7020. // allocated within this session (i.e., with Outlook allocators).
  7021. if (lpEntryID)
  7022. MAPIFreeBuffer(lpEntryID);
  7023. // The simple MAPI session should end after this
  7024. if(hMapiSession && lpfnMAPILogoff)
  7025. lpfnMAPILogoff(hMapiSession,0L,0L,0L);
  7026. if(hLibMapi)
  7027. FreeLibrary(hLibMapi);
  7028. // Turn all notifications back on and refresh the WAB UI (just in case)
  7029. if (!bIsOE && !bUseOEForSendMail)
  7030. {
  7031. vTurnOnAllNotifications();
  7032. if (lpIAB->hWndBrowse)
  7033. PostMessage(lpIAB->hWndBrowse, WM_COMMAND, (WPARAM) IDM_VIEW_REFRESH, 0);
  7034. }
  7035. if(lprecips)
  7036. {
  7037. ULONG i = 0;
  7038. for(i=0;i<nRecipCount;i++)
  7039. {
  7040. LocalFreeAndNull(&lprecips[i].lpszName);
  7041. LocalFreeAndNull(&lprecips[i].lpszAddress);
  7042. }
  7043. LocalFree(lprecips);
  7044. }
  7045. // The one-off here was allocated before the simple MAPI session and so used
  7046. // the default WAB allocators.
  7047. if(lpList)
  7048. FreeLPRecipList(lpList);
  7049. switch(hr)
  7050. {
  7051. case S_OK:
  7052. case MAPI_E_USER_CANCEL:
  7053. case MAPI_E_USER_ABORT:
  7054. break;
  7055. case MAPI_W_ERRORS_RETURNED:
  7056. ShowMessageBox(hWndParent, idsSendMailToNoEmail, MB_ICONEXCLAMATION | MB_OK);
  7057. break;
  7058. case MAPI_E_NOT_FOUND:
  7059. ShowMessageBox(hWndParent, idsSendMailNoMapi, MB_ICONEXCLAMATION | MB_OK);
  7060. break;
  7061. default:
  7062. ShowMessageBox(hWndParent, idsSendMailError, MB_ICONEXCLAMATION | MB_OK);
  7063. break;
  7064. }
  7065. return hr;
  7066. }
  7067. typedef struct _MailParams
  7068. {
  7069. HWND hWnd;
  7070. ULONG nRecipCount;
  7071. LPRECIPLIST lpList;
  7072. LPIAB lpIAB;
  7073. BOOL bUseOEForSendMail; // True means check and use OE before checking for Simple MAPI client
  7074. } MAIL_PARAMS, * LPMAIL_PARAMS;
  7075. //$$//////////////////////////////////////////////////////////////////////
  7076. //
  7077. // MailThreadProc - does the actual sendmail and cleans up
  7078. //
  7079. //////////////////////////////////////////////////////////////////////////
  7080. DWORD WINAPI MailThreadProc( LPVOID lpParam )
  7081. {
  7082. LPMAIL_PARAMS lpMP = (LPMAIL_PARAMS) lpParam;
  7083. LPPTGDATA lpPTGData = GetThreadStoragePointer(); // Bug - if this new thread accesses the WAB we lose a hunka memory
  7084. // So add this thing here ourselves and free it when this thread's work is done
  7085. if(!lpMP)
  7086. return 0;
  7087. DebugTrace( TEXT("Mail Thread ID = 0x%.8x\n"),GetCurrentThreadId());
  7088. HrSendMail(lpMP->hWnd, lpMP->nRecipCount, lpMP->lpList, lpMP->lpIAB, lpMP->bUseOEForSendMail);
  7089. LocalFree(lpMP);
  7090. return 0;
  7091. }
  7092. //$$//////////////////////////////////////////////////////////////////////
  7093. //
  7094. // HrStartMailThread
  7095. //
  7096. // Starts a seperate thread to send mapi based mail from
  7097. //
  7098. //////////////////////////////////////////////////////////////////////////
  7099. HRESULT HrStartMailThread(HWND hWndParent, ULONG nRecipCount, LPRECIPLIST lpList, LPIAB lpIAB, BOOL bUseOEForSendMail)
  7100. {
  7101. LPMAIL_PARAMS lpMP = NULL;
  7102. HRESULT hr = E_FAIL;
  7103. lpMP = LocalAlloc(LMEM_ZEROINIT, sizeof(MAIL_PARAMS));
  7104. if(!lpMP)
  7105. goto out;
  7106. {
  7107. HANDLE hThread = NULL;
  7108. DWORD dwThreadID = 0;
  7109. lpMP->hWnd = hWndParent;
  7110. lpMP->nRecipCount = nRecipCount;
  7111. lpMP->lpList = lpList;
  7112. lpMP->bUseOEForSendMail = bUseOEForSendMail;
  7113. lpMP->lpIAB = lpIAB;
  7114. hThread = CreateThread(
  7115. NULL, // no security attributes
  7116. 0, // use default stack size
  7117. MailThreadProc, // thread function
  7118. (LPVOID) lpMP, // argument to thread function
  7119. 0, // use default creation flags
  7120. &dwThreadID); // returns the thread identifier
  7121. if(hThread == NULL)
  7122. goto out;
  7123. hr = S_OK;
  7124. CloseHandle(hThread);
  7125. }
  7126. out:
  7127. if(HR_FAILED(hr))
  7128. {
  7129. ShowMessageBox(hWndParent, idsSendMailError, MB_OK | MB_ICONEXCLAMATION);
  7130. // we can assume that HrSendMail never got called so we should free lpList & lpMP
  7131. if(lpMP)
  7132. LocalFree(lpMP);
  7133. if(lpList)
  7134. FreeLPRecipList(lpList);
  7135. }
  7136. return hr;
  7137. }
  7138. //$$//////////////////////////////////////////////////////////////////////
  7139. //
  7140. // HrSendMailToSelectedContacts
  7141. //
  7142. // Uses simple MAPI to send mail to the selected contacts
  7143. //
  7144. // hWndLV - handle of List view. We look up the all the selected items in
  7145. // this list view, get their lParam structure, then get its
  7146. // EntryID and get the email address .. in the case of a group
  7147. // we get all the email addresses of all the members
  7148. // All these are put into a recip list and given to
  7149. // MAPISendMail ...
  7150. //
  7151. // lpIAB - handle to current AdrBook object - used for calling details
  7152. // nExtEmail - if this is a non-zero positive number, then it is the index of an
  7153. // e-mail address in the PR_CONTACT_EMAIL_ADDRESSES property and means that
  7154. // the user specified a non-default e-mail address to send mail to in which case
  7155. // that particular email address should be used for sending mail. nExtEmail will be
  7156. // non-zero only if one item is selected and a specific email is chosen for that item.
  7157. //
  7158. // Returns:S_OK
  7159. // E_FAIL
  7160. //
  7161. //////////////////////////////////////////////////////////////////////////
  7162. HRESULT HrSendMailToSelectedContacts(HWND hWndLV, LPADRBOOK lpAdrBook, int nExtEmail)
  7163. {
  7164. HRESULT hr = E_FAIL;
  7165. int nSelected = ListView_GetSelectedCount(hWndLV);
  7166. int iItemIndex = 0;
  7167. HWND hWndParent = GetParent(hWndLV);
  7168. TCHAR szBuf[MAX_PATH];
  7169. LPIAB lpIAB = (LPIAB) lpAdrBook;
  7170. LPRECIPLIST lpList = NULL;
  7171. ULONG nRecipCount = 0, nNoEmailCount = 0;
  7172. HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  7173. // Check if OutlookExpress is the current client ..need to know this to workaround a bug
  7174. // in what they expect right now as recipients
  7175. BOOL bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
  7176. // Create a recipients list to put in the new message ...
  7177. if(nSelected > 0)
  7178. {
  7179. // Get index of selected item
  7180. iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED);
  7181. while (iItemIndex != -1)
  7182. {
  7183. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  7184. // Get item lParam LPRECIPIENT_INFO structure
  7185. if (lpItem)
  7186. {
  7187. GetRecipListFromSelection(lpAdrBook, bIsOE,
  7188. lpItem->cbEntryID,
  7189. lpItem->lpEntryID,
  7190. nExtEmail,
  7191. &nRecipCount, &nNoEmailCount,
  7192. &lpList);
  7193. }
  7194. iItemIndex = ListView_GetNextItem(hWndLV,iItemIndex,LVNI_SELECTED);
  7195. }
  7196. if(nRecipCount > 0 && nNoEmailCount > 0)
  7197. {
  7198. if(IDNO == ShowMessageBox(hWndParent, idsSomeHaveNoEmail, MB_ICONEXCLAMATION | MB_YESNO))
  7199. {
  7200. hr = MAPI_E_USER_CANCEL;
  7201. goto out;
  7202. }
  7203. }
  7204. }
  7205. else
  7206. {
  7207. // nothing selected
  7208. ShowMessageBox(hWndParent, IDS_ADDRBK_MESSAGE_NO_ITEM, MB_ICONEXCLAMATION);
  7209. goto out;
  7210. }
  7211. hr = HrStartMailThread( hWndParent, nRecipCount,
  7212. lpList, // HrSendMail frees lpList so dont reuse
  7213. lpIAB,
  7214. lpIAB->bUseOEForSendMail);
  7215. out:
  7216. SetCursor(hOldCur);
  7217. return hr;
  7218. }
  7219. /*
  7220. const LPTSTR szClients = TEXT( TEXT("Software\\Clients\\%s"));
  7221. //
  7222. // FUNCTION: ShellUtil_RunIndirectRegCommand()
  7223. //
  7224. // PURPOSE: find the default value under HKLM\Software\Clients\pszClient
  7225. // tack on shell\open\command
  7226. // then runreg that
  7227. //
  7228. void ShellUtil_RunClientRegCommand(HWND hwnd, LPCTSTR pszClient)
  7229. {
  7230. TCHAR szDefApp[MAX_PATH];
  7231. TCHAR szKey[MAX_PATH];
  7232. LONG cbSize = ARRAYSIZE(szDefApp);
  7233. wnsprintf(szKey, ARRAYSIZE(szKey), szClients, pszClient);
  7234. if (RegQueryValue(HKEY_LOCAL_MACHINE, szKey, szDefApp, &cbSize) == ERROR_SUCCESS)
  7235. {
  7236. TCHAR szFullKey[MAX_PATH];
  7237. // tack on shell\open\command
  7238. wnsprintf(szFullKey, ARRAYSIZE(szFullKey), TEXT("%s\\%s\\shell\\open\\command"), szKey, szDefApp);
  7239. cbSize = ARRAYSIZE(szDefApp);
  7240. if (RegQueryValue(HKEY_LOCAL_MACHINE, szFullKey, szDefApp, &cbSize) == ERROR_SUCCESS)
  7241. {
  7242. LPSTR pszArgs = NULL;
  7243. SHELLEXECUTEINFO ExecInfo;
  7244. LPTSTR lp = szDefApp;
  7245. // if we have long file names in this string, we need to skip past the qoutes
  7246. if(lp)
  7247. {
  7248. if(*lp == '"')
  7249. {
  7250. lp = CharNext(lp);
  7251. while(lp && *lp && *lp!='"')
  7252. lp = CharNext(lp);
  7253. }
  7254. // Now find the next blank space because this is where the parameters start ..
  7255. while(lp && *lp && *lp!=' ') // No DBCS spaces here
  7256. lp = CharNext(lp);
  7257. if(*lp == ' ')
  7258. {
  7259. pszArgs = CharNext(lp);
  7260. *lp = '\0';
  7261. TrimSpaces(pszArgs);
  7262. }
  7263. //Now remove the quotes from lp
  7264. lp = szDefApp;
  7265. while(lp && *lp)
  7266. {
  7267. if(*lp == '"')
  7268. *lp = ' ';
  7269. lp = CharNext(lp);
  7270. }
  7271. TrimSpaces(szDefApp);
  7272. }
  7273. ExecInfo.hwnd = hwnd;
  7274. ExecInfo.lpVerb = NULL;
  7275. ExecInfo.lpFile = szDefApp;
  7276. ExecInfo.lpParameters = pszArgs;
  7277. ExecInfo.lpDirectory = NULL;
  7278. ExecInfo.nShow = SW_SHOWNORMAL;
  7279. ExecInfo.fMask = 0;
  7280. ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  7281. ShellExecuteEx(&ExecInfo);
  7282. }
  7283. }
  7284. }
  7285. */
  7286. /*
  7287. //$$//////////////////////////////////////////////////////////////////////
  7288. //
  7289. // HrSendMailToSingleContact
  7290. //
  7291. // Uses simple MAPI to send mail to the specified contact
  7292. //
  7293. // Returns:S_OK
  7294. // E_FAIL
  7295. //
  7296. //////////////////////////////////////////////////////////////////////////
  7297. HRESULT HrSendMailToSingleContact(HWND hWnd, LPIAB lpIAB, ULONG cbEntryID, LPENTRYID lpEntryID)
  7298. {
  7299. HRESULT hr = E_FAIL;
  7300. TCHAR szBuf[MAX_PATH];
  7301. LPRECIPLIST lpList = NULL;
  7302. ULONG nRecipCount = 0;
  7303. HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  7304. // Check if OutlookExpress is the current client ..need to know this to workaround a bug
  7305. // in what they expect right now as recipients
  7306. BOOL bIsOE = CheckForOutlookExpress(szBuf, ARRAYSIZE(szBuf));
  7307. // Create a recipients list to put in the new message ...
  7308. GetRecipListFromSelection((LPADRBOOK) lpIAB,
  7309. bIsOE,
  7310. cbEntryID,
  7311. lpEntryID,
  7312. 0,
  7313. &nRecipCount,
  7314. &lpList);
  7315. //hr = HrSendMail(hWnd, nRecipCount, lpList); // HrSendMail frees the lpList so dont reuse ..
  7316. hr = HrStartMailThread(hWnd, nRecipCount, lpList); // HrSendMail frees lpList so dont reuse
  7317. SetCursor(hOldCur);
  7318. return hr;
  7319. }
  7320. */
  7321. //$$///////////////////////////////////////////////////////////////////
  7322. //
  7323. // Removes all characters from input string that are not allowed by the
  7324. // file system
  7325. //
  7326. ///////////////////////////////////////////////////////////////////////
  7327. void TrimIllegalFileChars(LPTSTR sz)
  7328. {
  7329. LPTSTR lpCurrent = sz;
  7330. if(!lpCurrent)
  7331. return;
  7332. // Escape illegal chars in the file name
  7333. while (*lpCurrent)
  7334. {
  7335. switch (*lpCurrent)
  7336. {
  7337. case '\\':
  7338. case '/':
  7339. case '<':
  7340. case '>':
  7341. case ':':
  7342. case '"':
  7343. case '|':
  7344. case '?':
  7345. case '*':
  7346. //case '.':
  7347. *lpCurrent = '_'; // replace with underscore
  7348. break;
  7349. default:
  7350. break;
  7351. }
  7352. lpCurrent = CharNext(lpCurrent);
  7353. }
  7354. return;
  7355. }
  7356. /***************************************************************************
  7357. Name : IsSpace
  7358. Purpose : Does the single or DBCS character represent a space?
  7359. Parameters: lpChar -> SBCS or DBCS character
  7360. Returns : TRUE if this character is a space
  7361. Comment :
  7362. ***************************************************************************/
  7363. BOOL __fastcall IsSpace(LPTSTR lpChar) {
  7364. Assert(lpChar);
  7365. if (*lpChar)
  7366. {
  7367. /*
  7368. * [PaulHi] 3/31/99 Raid 73845. DBCS is not valid for UNICODE app.
  7369. if (IsDBCSLeadByte((BYTE)*lpChar))
  7370. {
  7371. WORD CharType[2] = {0};
  7372. GetStringTypeW(CT_CTYPE1,lpChar,2,// Double-Byte
  7373. CharType);
  7374. return(CharType[0] & C1_SPACE);
  7375. }
  7376. */
  7377. return(*lpChar == ' ');
  7378. }
  7379. return(FALSE); // end of string
  7380. }
  7381. /***************************************************************************
  7382. Name : SetRegistryUseOutlook
  7383. Purpose : Sets the registry flag that makes us use Outlook
  7384. Parameters: bUseOutlook or not
  7385. Returns : TRUE if it was correctly changed
  7386. Comment :
  7387. ***************************************************************************/
  7388. BOOL SetRegistryUseOutlook(BOOL bUseOutlook)
  7389. {
  7390. HKEY hKey = NULL;
  7391. DWORD dwUseOutlook = (DWORD) bUseOutlook;
  7392. BOOL bRet = FALSE;
  7393. // We'll probably never have to create the key since Outlook will do that at setup
  7394. //
  7395. if(ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER,
  7396. lpNewWABRegKey,
  7397. 0, NULL,
  7398. REG_OPTION_NON_VOLATILE,
  7399. KEY_ALL_ACCESS,
  7400. NULL, &hKey, NULL))
  7401. {
  7402. if(ERROR_SUCCESS == RegSetValueEx( hKey,
  7403. lpRegUseOutlookVal,
  7404. 0, REG_DWORD,
  7405. (LPBYTE) &dwUseOutlook,
  7406. sizeof(DWORD) ))
  7407. {
  7408. bRet = TRUE;
  7409. }
  7410. }
  7411. if(hKey)
  7412. RegCloseKey(hKey);
  7413. return bRet;
  7414. }
  7415. const LPTSTR lpRegOffice = TEXT("Software\\Microsoft\\Office\\8.0");
  7416. const LPTSTR lpRegOffice9 = TEXT("Software\\Microsoft\\Office\\9.0");
  7417. const LPTSTR lpRegOutlWAB = TEXT("Software\\Microsoft\\WAB\\OutlWABDLLPath");
  7418. const LPTSTR lpRegOfficeBin = TEXT("BinDirPath");
  7419. const LPTSTR lpOUTLWAB_DLL_NAME = TEXT("Outlwab.dll");
  7420. BOOL bFindOutlWABDll(LPTSTR sz, DWORD cchSz, LPTSTR szDLLPath, DWORD cchDLLPath, BOOL bAppendName)
  7421. {
  7422. BOOL bRet = FALSE;
  7423. if(bAppendName)
  7424. {
  7425. if(*(sz+lstrlen(sz)-1) != '\\')
  7426. StrCatBuff(sz, szBackSlash, cchSz);
  7427. StrCatBuff(sz, lpOUTLWAB_DLL_NAME, cchSz);
  7428. }
  7429. if(GetFileAttributes(sz) != 0xFFFFFFFF)
  7430. {
  7431. if(szDLLPath)
  7432. StrCpyN(szDLLPath, sz, cchDLLPath);
  7433. bRet = TRUE;
  7434. }
  7435. return bRet;
  7436. }
  7437. //$$/////////////////////////////////////////////////////////////////////////////
  7438. //
  7439. // bCheckForOutlookWABDll
  7440. //
  7441. // Search for the Outlook WAB DLL .. if found, we
  7442. // can use that as na indicator that outlook is installed
  7443. //
  7444. // szDLLPath should be a big enough buffer
  7445. //
  7446. //////////////////////////////////////////////////////////////////////////////////
  7447. BOOL bCheckForOutlookWABDll(LPTSTR szDLLPath, DWORD cchDLLPath)
  7448. {
  7449. // Check in the Office Bin directory
  7450. TCHAR sz[MAX_PATH];
  7451. BOOL bRet = FALSE;
  7452. DWORD dwType = REG_SZ;
  7453. DWORD dwSize = ARRAYSIZE(sz);
  7454. HKEY hKey = NULL;
  7455. *sz = '\0';
  7456. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOutlWAB, 0, KEY_READ, &hKey))
  7457. {
  7458. if(ERROR_SUCCESS == RegQueryValueEx(hKey, szEmpty, NULL, &dwType, (LPBYTE) sz, &dwSize))
  7459. {
  7460. if(lstrlen(sz))
  7461. bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, FALSE);
  7462. }
  7463. RegCloseKey(hKey);
  7464. }
  7465. if (!bRet)
  7466. {
  7467. *sz = '\0';
  7468. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOffice9, 0, KEY_READ, &hKey))
  7469. {
  7470. if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpRegOfficeBin, NULL, &dwType, (LPBYTE) sz, &dwSize))
  7471. {
  7472. if(lstrlen(sz))
  7473. bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
  7474. }
  7475. }
  7476. RegCloseKey(hKey);
  7477. }
  7478. if(!bRet)
  7479. {
  7480. *sz = '\0';
  7481. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegOffice, 0, KEY_READ, &hKey))
  7482. {
  7483. if(ERROR_SUCCESS == RegQueryValueEx(hKey, lpRegOfficeBin, NULL, &dwType, (LPBYTE) sz, &dwSize))
  7484. {
  7485. if(lstrlen(sz))
  7486. bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
  7487. }
  7488. }
  7489. RegCloseKey(hKey);
  7490. }
  7491. // Check in the Windows System Directory
  7492. if(!bRet)
  7493. {
  7494. *sz = '\0';
  7495. GetSystemDirectory(sz, ARRAYSIZE(sz));
  7496. if(lstrlen(sz))
  7497. bRet = bFindOutlWABDll(sz, ARRAYSIZE(sz), szDLLPath, cchDLLPath, TRUE);
  7498. }
  7499. return bRet;
  7500. }
  7501. /***************************************************************************
  7502. Name : bUseOutlookStore
  7503. Purpose : Determines if we are supposed to be using Outlook
  7504. Parameters: none
  7505. Returns : TRUE if we are supposed to use outlook AND we can find the
  7506. outlook installation
  7507. Comment :
  7508. ***************************************************************************/
  7509. BOOL bUseOutlookStore()
  7510. {
  7511. HKEY hKey = NULL;
  7512. DWORD dwUseOutlook = 0;
  7513. BOOL bRet = FALSE;
  7514. DWORD dwType = REG_DWORD;
  7515. DWORD dwSize = sizeof(DWORD);
  7516. if(ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER,
  7517. lpNewWABRegKey,
  7518. 0, KEY_READ,
  7519. &hKey))
  7520. {
  7521. if(ERROR_SUCCESS == RegQueryValueEx(hKey,
  7522. lpRegUseOutlookVal,
  7523. NULL,
  7524. &dwType,
  7525. (LPBYTE) &dwUseOutlook,
  7526. &dwSize))
  7527. {
  7528. bRet = (BOOL) dwUseOutlook;
  7529. }
  7530. }
  7531. if(hKey)
  7532. RegCloseKey(hKey);
  7533. if(bRet)
  7534. {
  7535. // just double check that we can actually find the OutlookWABSPI dll
  7536. bRet = bCheckForOutlookWABDll(NULL, 0);
  7537. }
  7538. return bRet;
  7539. }
  7540. //$$//////////////////////////////////////////////////////////
  7541. //
  7542. // Copies Src to Dest. If Src is longer than Dest,
  7543. // truncates the src and trails it with 3 dots
  7544. //
  7545. //////////////////////////////////////////////////////////////
  7546. int CopyTruncate(LPTSTR szDest, LPTSTR szSrc, int nMaxLen)
  7547. {
  7548. int nLen = lstrlen(szSrc)+1;
  7549. if (nLen >= nMaxLen)
  7550. {
  7551. ULONG iLenDots = lstrlen(szTrailingDots) + 1;
  7552. ULONG iLen = TruncatePos(szSrc, nMaxLen - iLenDots);
  7553. CopyMemory(szDest,szSrc, sizeof(TCHAR)*(nMaxLen - iLenDots));
  7554. szDest[iLen]='\0';
  7555. StrCatBuff(szDest,szTrailingDots, nMaxLen);
  7556. //DebugTrace("%s = %s\n", szDest, szSrc);
  7557. }
  7558. else
  7559. {
  7560. StrCpyN(szDest,szSrc,nMaxLen);
  7561. }
  7562. return nLen;
  7563. }
  7564. ///////////////////////////////////////////////////////////////////
  7565. //
  7566. // HrShowDSProps - shows Directory Service properties UI
  7567. //
  7568. // hWndParent - hWnd of Parent
  7569. // lpszName - pointer to a buffer ... also contains name of LDAP
  7570. // server to view prperties on - this name can be modified so
  7571. // lpszName should point to a big enough buffer
  7572. // bAddNew - TRUE if this is a new entry, false if this is props
  7573. ///////////////////////////////////////////////////////////////////
  7574. HRESULT HrShowDSProps(HWND hWndParent,
  7575. LPTSTR ptszAcct,
  7576. LPTSTR *pptszName,
  7577. BOOL bAddNew)
  7578. {
  7579. HRESULT hr = hrSuccess;
  7580. IImnAccountManager2 * lpAccountManager = NULL;
  7581. IImnAccount * lpAccount = NULL;
  7582. LPSTR lpAcct = ConvertWtoA(ptszAcct);
  7583. // init account manager
  7584. // Make sure there is an account manager
  7585. if (hr = InitAccountManager(NULL, &lpAccountManager, NULL)) {
  7586. ShowMessageBox(hWndParent, idsLDAPUnconfigured, MB_ICONEXCLAMATION | MB_OK);
  7587. goto out;
  7588. }
  7589. // find this account
  7590. if (hr = lpAccountManager->lpVtbl->FindAccount(lpAccountManager,
  7591. AP_ACCOUNT_NAME,
  7592. lpAcct,
  7593. &lpAccount)) {
  7594. DebugTrace( TEXT("FindAccount(%s) -> %x\n"), lpAcct, GetScode(hr));
  7595. goto out;
  7596. }
  7597. // show properties
  7598. if (hr = lpAccount->lpVtbl->ShowProperties(lpAccount,
  7599. hWndParent,
  7600. 0)) {
  7601. DebugTrace( TEXT("ShowProperties(%s) -> %x\n"), lpAcct, GetScode(hr));
  7602. goto out;
  7603. }
  7604. {
  7605. char szBuf[MAX_UI_STR];
  7606. // Get the friendly name (== account name if this changed)
  7607. if (! (HR_FAILED(hr = lpAccount->lpVtbl->GetPropSz(lpAccount, AP_ACCOUNT_NAME, szBuf, ARRAYSIZE(szBuf)))))
  7608. {
  7609. LPTSTR lp = ConvertAtoW(szBuf);
  7610. if(lp)
  7611. {
  7612. *pptszName = lp;
  7613. }
  7614. }
  7615. }
  7616. out:
  7617. if (lpAccount) {
  7618. lpAccount->lpVtbl->Release(lpAccount);
  7619. }
  7620. LocalFreeAndNull(&lpAcct);
  7621. // Don't release the account manager. It will be done when the IAdrBook is released.
  7622. // if (lpAccountManager) {
  7623. // lpAccountManager->lpVtbl->Release(lpAccountManager);
  7624. // }
  7625. return hr;
  7626. }
  7627. //$$///////////////////////////////////////////////////////////////////////////////
  7628. //
  7629. // HrShowDirectoryServiceModificationDlg - Shows the main dialog with the list
  7630. // of directory services and with a prop sheet for changing check order
  7631. //
  7632. // hWndParent - Parent for this dialog
  7633. /////////////////////////////////////////////////////////////////////////////////
  7634. HRESULT HrShowDirectoryServiceModificationDlg(HWND hWndParent, LPIAB lpIAB)
  7635. {
  7636. ACCTLISTINFO ali;
  7637. HRESULT hr = hrSuccess;
  7638. IImnAccountManager2 * lpAccountManager;
  7639. // Make sure there is an account manager
  7640. if (hr = InitAccountManager(lpIAB, &lpAccountManager, NULL)) {
  7641. ShowMessageBox(hWndParent, idsLDAPUnconfigured, MB_ICONEXCLAMATION | MB_OK);
  7642. goto out;
  7643. }
  7644. ali.cbSize = sizeof(ACCTLISTINFO);
  7645. ali.AcctTypeInit = (ACCTTYPE)-1;
  7646. ali.dwAcctFlags = ACCT_FLAG_DIR_SERV;
  7647. ali.dwFlags = 0;
  7648. hr = lpAccountManager->lpVtbl->AccountListDialog(lpAccountManager,
  7649. hWndParent,
  7650. &ali);
  7651. out:
  7652. return hr;
  7653. }
  7654. /*
  7655. - HrShellExecInternetCall
  7656. -
  7657. *
  7658. * Checks if the selected, single item has PR_SERVERS set on it and has a default
  7659. * callto item - if yes, shell-exects this item ..
  7660. */
  7661. HRESULT HrShellExecInternetCall(LPADRBOOK lpAdrBook, HWND hWndLV)
  7662. {
  7663. HRESULT hr = E_FAIL;
  7664. LPRECIPIENT_INFO lpItem = NULL;
  7665. LPSPropValue lpPropArray = NULL;
  7666. ULONG ulcProps = 0;
  7667. int nCount = ListView_GetSelectedCount(hWndLV);
  7668. if(nCount != 1)
  7669. {
  7670. ShowMessageBox(GetParent(hWndLV),
  7671. (nCount > 1) ? IDS_ADDRBK_MESSAGE_ACTION : IDS_ADDRBK_MESSAGE_NO_ITEM,
  7672. MB_ICONEXCLAMATION);
  7673. goto out;
  7674. }
  7675. lpItem = GetItemFromLV(hWndLV, ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED));
  7676. if(lpItem)
  7677. {
  7678. if(!HR_FAILED(hr = HrGetPropArray( lpAdrBook, NULL,
  7679. lpItem->cbEntryID, lpItem->lpEntryID,
  7680. MAPI_UNICODE,
  7681. &ulcProps, &lpPropArray)))
  7682. {
  7683. ULONG i = 0, nConf = 0xffffffff, nDef = 0xffffffff;
  7684. LPTSTR lpsz = NULL;
  7685. for(i=0;i<ulcProps;i++)
  7686. {
  7687. if(lpPropArray[i].ulPropTag == PR_WAB_CONF_SERVERS)
  7688. nConf = i;
  7689. else if(lpPropArray[i].ulPropTag == PR_WAB_CONF_DEFAULT_INDEX)
  7690. nDef = i;
  7691. }
  7692. if(nConf != 0xffffffff)
  7693. {
  7694. TCHAR sz[MAX_PATH];
  7695. if(nDef != 0xffffffff)
  7696. {
  7697. ULONG iDef = lpPropArray[nDef].Value.l;
  7698. lpsz = lpPropArray[nConf].Value.MVSZ.LPPSZ[iDef];
  7699. }
  7700. else
  7701. {
  7702. // no default .. find the first call to and use that
  7703. for(i=0;i<lpPropArray[nConf].Value.MVSZ.cValues;i++)
  7704. {
  7705. if(lstrlen(lpPropArray[nConf].Value.MVSZ.LPPSZ[i]) >= lstrlen(szCallto))
  7706. {
  7707. int nLen = lstrlen(szCallto);
  7708. CopyMemory(sz, lpPropArray[nConf].Value.MVSZ.LPPSZ[i], sizeof(TCHAR)*nLen);
  7709. sz[nLen] = '\0';
  7710. if(!lstrcmpi(sz, szCallto))
  7711. {
  7712. lpsz = lpPropArray[nConf].Value.MVSZ.LPPSZ[i];
  7713. break;
  7714. }
  7715. }
  7716. }
  7717. }
  7718. if(lpsz)
  7719. if(!ShellExecute(GetParent(hWndLV), TEXT("open"), lpsz, NULL, NULL, SW_SHOWNORMAL))
  7720. ShowMessageBox(GetParent(hWndLV), idsCouldNotSelectUser, MB_ICONEXCLAMATION);
  7721. }
  7722. if(nConf == 0xffffffff || !lpsz)
  7723. ShowMessageBox(GetParent(hWndLV), idsInternetCallNoCallTo, MB_ICONEXCLAMATION);
  7724. }
  7725. }
  7726. out:
  7727. if(lpPropArray)
  7728. MAPIFreeBuffer(lpPropArray);
  7729. return hr;
  7730. }
  7731. /*
  7732. - GetItemFromLV
  7733. -
  7734. * utility function for returning the recipient item from the LV
  7735. */
  7736. LPRECIPIENT_INFO GetItemFromLV(HWND hWndLV, int iItem)
  7737. {
  7738. LPRECIPIENT_INFO lpItem = NULL;
  7739. LV_ITEM LVItem;
  7740. LVItem.mask = LVIF_PARAM;
  7741. LVItem.iItem = iItem;
  7742. LVItem.iSubItem = 0;
  7743. LVItem.lParam = 0;
  7744. // Get item lParam LPRECIPIENT_INFO structure
  7745. if (ListView_GetItem(hWndLV,&LVItem))
  7746. lpItem = ((LPRECIPIENT_INFO) LVItem.lParam);
  7747. return lpItem;
  7748. }
  7749. /*
  7750. - Helper function
  7751. -
  7752. */
  7753. void SetSBinary(LPSBinary lpsb, ULONG cb, LPBYTE lpb)
  7754. {
  7755. if(!lpsb || !cb || !lpb)
  7756. return;
  7757. if(lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, cb))
  7758. {
  7759. lpsb->cb = cb;
  7760. CopyMemory(lpsb->lpb, lpb, cb);
  7761. }
  7762. }
  7763. /*
  7764. - GetWABIconImage
  7765. -
  7766. *
  7767. */
  7768. int GetWABIconImage(LPRECIPIENT_INFO lpItem)
  7769. {
  7770. if(lpItem->cbEntryID == 0)
  7771. return imageUnknown;
  7772. if(lpItem->ulObjectType == MAPI_DISTLIST)
  7773. {
  7774. return imageDistList;
  7775. }
  7776. else
  7777. {
  7778. BYTE bType;
  7779. if(lpItem->bIsMe)
  7780. return imageMailUserMe;
  7781. else if(lpItem->bHasCert)
  7782. return imageMailUserWithCert;
  7783. bType = IsWABEntryID(lpItem->cbEntryID, lpItem->lpEntryID, NULL,NULL,NULL, NULL, NULL);
  7784. if(bType == WAB_LDAP_MAILUSER)
  7785. return imageMailUserLDAP;
  7786. else if(bType == WAB_ONEOFF)
  7787. return imageMailUserOneOff;
  7788. }
  7789. return imageMailUser;
  7790. }
  7791. enum
  7792. {
  7793. IE401_DONTKNOW=0,
  7794. IE401_TRUE,
  7795. IE401_FALSE
  7796. };
  7797. static int g_nIE401 = IE401_DONTKNOW;
  7798. /*
  7799. - bIsIE401
  7800. -
  7801. * Checks if this installation has IE4.01 or greater so we can decide what flags to pass to the prop sheets
  7802. *
  7803. */
  7804. BOOL bIsIE401OrGreater()
  7805. {
  7806. BOOL bRet = FALSE;
  7807. if(g_nIE401 == IE401_TRUE)
  7808. return TRUE;
  7809. if(g_nIE401 == IE401_FALSE)
  7810. return FALSE;
  7811. g_nIE401 = IE401_FALSE;
  7812. // else we need to check
  7813. InitCommonControlLib();
  7814. //load the DLL
  7815. if(ghCommCtrlDLLInst)
  7816. {
  7817. LPDLLGETVERSIONPROCOE lpfnDllGetVersionProc = NULL;
  7818. lpfnDllGetVersionProc = (LPDLLGETVERSIONPROCOE) GetProcAddress(ghCommCtrlDLLInst, "DllGetVersion");
  7819. if(lpfnDllGetVersionProc)
  7820. {
  7821. // Check the version number
  7822. DLLVERSIONINFO dvi = {0};
  7823. dvi.cbSize = sizeof(dvi);
  7824. lpfnDllGetVersionProc(&dvi);
  7825. // we are looking for IE4 version 4.72 or more
  7826. if( (dvi.dwMajorVersion > 4) ||
  7827. (dvi.dwMajorVersion == 4 && dvi.dwMinorVersion >= 72) )
  7828. {
  7829. g_nIE401 = IE401_TRUE;
  7830. bRet = TRUE;
  7831. }
  7832. }
  7833. }
  7834. DeinitCommCtrlClientLib();
  7835. return bRet;
  7836. }
  7837. #ifdef COLSEL_MENU
  7838. /**
  7839. ColSel_PropTagToString: This function will convert a propertytag to a string
  7840. */
  7841. BOOL ColSel_PropTagToString( ULONG ulPropTag, LPTSTR lpszString, ULONG cchString)
  7842. {
  7843. UINT i, j;
  7844. UINT iIndex;
  7845. HMENU hMainMenu;
  7846. HMENU hMenu;
  7847. MENUITEMINFO mii;
  7848. BOOL fRet = FALSE;
  7849. hMainMenu = LoadMenu(hinstMapiX, MAKEINTRESOURCE(IDR_MENU_LVCONTEXTMENU_COLSEL));
  7850. if( !hMainMenu )
  7851. {
  7852. DebugTrace( TEXT("unable to load main colsel menu\n"));
  7853. goto exit;
  7854. }
  7855. hMenu = GetSubMenu( hMainMenu, 0);
  7856. if( !hMenu )
  7857. {
  7858. DebugTrace( TEXT("unable to load submenu from colsel main menu\n"));
  7859. goto exit;
  7860. }
  7861. if( !lpszString )
  7862. {
  7863. DebugTrace( TEXT("illegal argument -- lpszString must be valid mem\n"));
  7864. goto exit;
  7865. }
  7866. mii.fMask = MIIM_TYPE;
  7867. mii.cbSize = sizeof( MENUITEMINFO );
  7868. mii.dwTypeData = lpszString;
  7869. mii.cch = cchString;
  7870. for( i = 0; i < MAXNUM_MENUPROPS; i++)
  7871. {
  7872. if( MenuToPropTagMap[i] == ulPropTag )
  7873. {
  7874. if( !GetMenuItemInfo( hMenu, i, TRUE, &mii) )
  7875. {
  7876. DebugTrace( TEXT("unable to get menu item info: %x\n"), GetLastError() );
  7877. goto exit;
  7878. }
  7879. fRet = TRUE;
  7880. }
  7881. }
  7882. exit:
  7883. if ( hMainMenu != NULL )
  7884. DestroyMenu( hMainMenu );
  7885. if( !fRet )
  7886. DebugTrace( TEXT("unable to find property tag\n"));
  7887. return fRet;
  7888. }
  7889. #endif // COLSEL_MENU
  7890. /*
  7891. - IsWindowOnScreen
  7892. -
  7893. * Checks if a window is onscreen so that if it is not entirely onscreen we can push it back
  7894. * into a viewable area .. this way if the user changes screen resolution or switches multi-monitors
  7895. * around, we don't lose the app
  7896. */
  7897. BOOL IsWindowOnScreen(LPRECT lprc)
  7898. {
  7899. HDC hDC = GetDC(NULL);
  7900. BOOL fRet = RectVisible(hDC, lprc);
  7901. ReleaseDC(NULL, hDC);
  7902. return fRet;
  7903. }
  7904. /*
  7905. - IsHTTPMailEnabled
  7906. -
  7907. * Checks if HTTP is enabled so that we can hide UI if its not.
  7908. */
  7909. static TCHAR c_szRegRootAthenaV2[] = TEXT("Software\\Microsoft\\Outlook Express");
  7910. static TCHAR c_szEnableHTTPMail[] = TEXT("HTTP Mail Enabled");
  7911. BOOL IsHTTPMailEnabled(LPIAB lpIAB)
  7912. {
  7913. #ifdef NOHTTPMAIL
  7914. return FALSE;
  7915. #else
  7916. DWORD cb, bEnabled = FALSE;
  7917. HKEY hkey = NULL;
  7918. // [PaulHi] 1/5/98 Raid #64160
  7919. // Hotmail synchronization is disabled if the WAB is not in "identity aware"
  7920. // mode. So, we need to check for this too.
  7921. bEnabled = lpIAB->bProfilesIdent;
  7922. // @todo [PaulHi] 12/1/98
  7923. // We really shouldn't be doing a registry query every time the user
  7924. // opens up the Tools menu, i.e., in update menu.
  7925. // Check this registry sometime during start up and save per instance.
  7926. // open the OE5.0 key
  7927. if ( bEnabled &&
  7928. (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegRootAthenaV2, 0, KEY_QUERY_VALUE, &hkey)) )
  7929. {
  7930. cb = sizeof(bEnabled);
  7931. RegQueryValueEx(hkey, c_szEnableHTTPMail, 0, NULL, (LPBYTE)&bEnabled, &cb);
  7932. RegCloseKey(hkey);
  7933. }
  7934. //
  7935. // [PaulHi] 12/1/98 Raid #57739
  7936. // HACK WARNING
  7937. // Since the Hotmail server is currently hard coded to the U.S. 1252
  7938. // codepage, any other system codepage will result in corrupted data
  7939. // after a round sync trip to the Hotmail server and back, for any fields
  7940. // with DB characters (i.e., international). The temporary solution is
  7941. // to simply disable Hotmail synchronization if a codepage other than
  7942. // 1252 is detected on the client machine.
  7943. //
  7944. #define USLatin1CodePage 1252
  7945. if (bEnabled)
  7946. {
  7947. DWORD dwCodepage = GetACP();
  7948. if (dwCodepage != USLatin1CodePage)
  7949. bEnabled = FALSE;
  7950. }
  7951. return bEnabled;
  7952. #endif
  7953. }
  7954. /*
  7955. -
  7956. - WriteRegistryDeletedHotsyncItem
  7957. *
  7958. * Writes the Hotmail Contact/ID/Modtime info to the registry so we can track deletions for
  7959. * Hotmail syncing
  7960. *
  7961. */
  7962. extern LPTSTR g_lpszSyncKey;
  7963. void WriteRegistryDeletedHotsyncItem(LPTSTR lpServerID, LPTSTR lpContactID, LPTSTR lpModTime)
  7964. {
  7965. HKEY hKey = NULL,hSubKey = NULL;
  7966. DWORD dwDisposition = 0;
  7967. if( !lpServerID || !lstrlen(lpServerID) ||
  7968. !lpContactID || !lstrlen(lpContactID) ||
  7969. !lpModTime || !lstrlen(lpModTime) )
  7970. return;
  7971. // Open key
  7972. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, g_lpszSyncKey, 0, //reserved
  7973. NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  7974. &hKey, &dwDisposition))
  7975. {
  7976. if (ERROR_SUCCESS == RegCreateKeyEx(hKey,lpContactID, 0,
  7977. NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  7978. &hSubKey, &dwDisposition))
  7979. {
  7980. // Create a value here .. the value name is the Contact ID and the Value Data is the ModTime
  7981. // Now Write this key
  7982. RegSetValueEx( hSubKey, lpServerID, 0, REG_SZ, (LPBYTE) lpModTime, (lstrlen(lpModTime)+1) * sizeof(TCHAR) );
  7983. }
  7984. }
  7985. if(hSubKey)
  7986. RegCloseKey(hSubKey);
  7987. if(hKey)
  7988. RegCloseKey(hKey);
  7989. }
  7990. /*
  7991. - HrSaveHotmailSyncInfoOnDeletion
  7992. -
  7993. * If the user has ever done any hotmail syncing, we need to track deletions in the WAB
  7994. * so that after you delete an entry in the WAB, the corresponding hotmail entry will
  7995. * be deleted on Sync.
  7996. *
  7997. * We store the hotmail sync info in the registry, hopefully there won't be too much of it
  7998. * Whenever the hotmail sync happens, the info gets cleaned out.
  7999. */
  8000. HRESULT HrSaveHotmailSyncInfoOnDeletion(LPADRBOOK lpAdrBook, LPSBinary lpEID)
  8001. {
  8002. // Basically we will open the object being deleted, look for it's Hotmail
  8003. // properties and if these properties exist, we will put them into the registry
  8004. //
  8005. HRESULT hr = S_OK;
  8006. ULONG ulcValues = 0,i=0;
  8007. LPSPropValue lpProps = NULL;
  8008. SizedSPropTagArray(3, ptaHotProps) =
  8009. {
  8010. 3,
  8011. {
  8012. PR_WAB_HOTMAIL_CONTACTIDS,
  8013. PR_WAB_HOTMAIL_MODTIMES,
  8014. PR_WAB_HOTMAIL_SERVERIDS,
  8015. }
  8016. };
  8017. hr = HrGetPropArray(lpAdrBook,
  8018. (LPSPropTagArray) &ptaHotProps,
  8019. lpEID->cb,(LPENTRYID) lpEID->lpb,
  8020. MAPI_UNICODE,
  8021. &ulcValues,&lpProps);
  8022. if(HR_FAILED(hr) || !ulcValues || !lpProps)
  8023. goto out;
  8024. // The three props are supposed to be in sync, so if one exists, the other 2 will also exist
  8025. // and if this is not true, then don't write the data to the registry
  8026. if( lpProps[0].ulPropTag != PR_WAB_HOTMAIL_CONTACTIDS ||
  8027. !lpProps[0].Value.MVSZ.cValues ||
  8028. lpProps[1].ulPropTag != PR_WAB_HOTMAIL_MODTIMES ||
  8029. !lpProps[1].Value.MVSZ.cValues ||
  8030. lpProps[2].ulPropTag != PR_WAB_HOTMAIL_SERVERIDS ||
  8031. !lpProps[2].Value.MVSZ.cValues ||
  8032. lpProps[0].Value.MVSZ.cValues != lpProps[1].Value.MVSZ.cValues ||
  8033. lpProps[0].Value.MVSZ.cValues != lpProps[2].Value.MVSZ.cValues ||
  8034. lpProps[1].Value.MVSZ.cValues != lpProps[2].Value.MVSZ.cValues)
  8035. goto out;
  8036. for(i=0;i<lpProps[0].Value.MVSZ.cValues;i++)
  8037. {
  8038. WriteRegistryDeletedHotsyncItem( lpProps[2].Value.MVSZ.LPPSZ[i], //server id
  8039. lpProps[0].Value.MVSZ.LPPSZ[i], //contact id
  8040. lpProps[1].Value.MVSZ.LPPSZ[i]); //mod time
  8041. }
  8042. out:
  8043. FreeBufferAndNull(&lpProps);
  8044. return hr;
  8045. }