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.

1782 lines
57 KiB

  1. /*
  2. * MailUser.C - mostly just a copy of WRAP.C
  3. *
  4. * Wrapper for mailuser and distlist objects.
  5. *
  6. * Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  7. *
  8. */
  9. #include "_apipch.h"
  10. extern OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEID, LPENTRYID lpEID);
  11. /*********************************************************************
  12. *
  13. * The actual Wrapped IMAPIProp methods
  14. *
  15. */
  16. //
  17. // Wrapped IMAPIProp jump table is defined here...
  18. // Try to use as much of IAB as possible.
  19. //
  20. MailUser_Vtbl vtblMAILUSER = {
  21. VTABLE_FILL
  22. MailUser_QueryInterface,
  23. (MailUser_AddRef_METHOD *) WRAP_AddRef,
  24. MailUser_Release,
  25. (MailUser_GetLastError_METHOD *) IAB_GetLastError,
  26. MailUser_SaveChanges,
  27. MailUser_GetProps,
  28. MailUser_GetPropList,
  29. MailUser_OpenProperty,
  30. MailUser_SetProps,
  31. MailUser_DeleteProps,
  32. MailUser_CopyTo,
  33. MailUser_CopyProps,
  34. MailUser_GetNamesFromIDs,
  35. MailUser_GetIDsFromNames,
  36. };
  37. //
  38. // Interfaces supported by this object
  39. //
  40. #define MailUser_cInterfaces 2
  41. LPIID MailUser_LPIID[MailUser_cInterfaces] =
  42. {
  43. (LPIID)&IID_IMailUser,
  44. (LPIID)&IID_IMAPIProp
  45. };
  46. //
  47. // Interfaces supported by this object
  48. //
  49. #define DistList_cInterfaces 3
  50. LPIID DistList_LPIID[DistList_cInterfaces] =
  51. {
  52. (LPIID)&IID_IDistList,
  53. (LPIID)&IID_IMailUser,
  54. (LPIID)&IID_IMAPIProp
  55. };
  56. HRESULT HrValidateMailUser(LPMailUser lpMailUser);
  57. void MAILUSERFreeContextData(LPMailUser lpMailUser);
  58. void MAILUSERAssociateContextData(LPMAILUSER lpMailUser, LPWABEXTDISPLAY lpWEC);
  59. const TCHAR szMAPIPDL[] = TEXT("MAPIPDL");
  60. extern BOOL bDNisByLN;
  61. // --------
  62. // IUnknown
  63. STDMETHODIMP
  64. MailUser_QueryInterface(LPMailUser lpMailUser,
  65. REFIID lpiid,
  66. LPVOID * lppNewObj)
  67. {
  68. ULONG iIID;
  69. #ifdef PARAMETER_VALIDATION
  70. // Check to see if it has a jump table
  71. if (IsBadReadPtr(lpMailUser, sizeof(LPVOID))) {
  72. // No jump table found
  73. return(ResultFromScode(E_INVALIDARG));
  74. }
  75. // Check to see if the jump table has at least sizeof IUnknown
  76. if (IsBadReadPtr(lpMailUser->lpVtbl, 3 * sizeof(LPVOID))) {
  77. // Jump table not derived from IUnknown
  78. return(ResultFromScode(E_INVALIDARG));
  79. }
  80. // Check to see that it's MailUser_QueryInterface
  81. if (lpMailUser->lpVtbl->QueryInterface != MailUser_QueryInterface) {
  82. // Not my jump table
  83. return(ResultFromScode(E_INVALIDARG));
  84. }
  85. // Is there enough there for an interface ID?
  86. if (IsBadReadPtr(lpiid, sizeof(IID))) {
  87. DebugTraceSc(MailUser_QueryInterface, E_INVALIDARG);
  88. return(ResultFromScode(E_INVALIDARG));
  89. }
  90. // Is there enough there for a new object?
  91. if (IsBadWritePtr(lppNewObj, sizeof(LPMailUser))) {
  92. DebugTraceSc(MailUser_QueryInterface, E_INVALIDARG);
  93. return(ResultFromScode(E_INVALIDARG));
  94. }
  95. #endif // PARAMETER_VALIDATION
  96. EnterCriticalSection(&lpMailUser->cs);
  97. // See if the requested interface is one of ours
  98. // First check with IUnknown, since we all have to support that one...
  99. if (!memcmp(lpiid, &IID_IUnknown, sizeof(IID))) {
  100. goto goodiid; // GROSS! Jump into a for loop!
  101. }
  102. // Now look through all the iids associated with this object, see if any match
  103. for(iIID = 0; iIID < lpMailUser->cIID; iIID++)
  104. if (!memcmp(lpMailUser->rglpIID[iIID], lpiid, sizeof(IID))) {
  105. goodiid:
  106. //
  107. // It's a match of interfaces, we support this one then...
  108. //
  109. ++lpMailUser->lcInit;
  110. *lppNewObj = lpMailUser;
  111. LeaveCriticalSection(&lpMailUser->cs);
  112. return 0;
  113. }
  114. //
  115. // No interface we've heard of...
  116. //
  117. LeaveCriticalSection(&lpMailUser->cs);
  118. *lppNewObj = NULL; // OLE requires NULLing out parm on failure
  119. DebugTraceSc(MailUser_QueryInterface, E_NOINTERFACE);
  120. return(ResultFromScode(E_NOINTERFACE));
  121. }
  122. STDMETHODIMP_(ULONG)
  123. MailUser_Release (LPMailUser lpMailUser)
  124. {
  125. #if !defined(NO_VALIDATION)
  126. //
  127. // Make sure the object is valid.
  128. //
  129. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, Release, lpVtbl)) {
  130. return(1);
  131. }
  132. #endif
  133. EnterCriticalSection(&lpMailUser->cs);
  134. --lpMailUser->lcInit;
  135. if (lpMailUser->lcInit == 0) {
  136. // Free any context-menu extension data associated with this mailuser
  137. MAILUSERFreeContextData(lpMailUser);
  138. UlRelease(lpMailUser->lpPropData);
  139. //
  140. // Need to free the object
  141. //
  142. LeaveCriticalSection(&lpMailUser->cs);
  143. DeleteCriticalSection(&lpMailUser->cs);
  144. FreeBufferAndNull(&lpMailUser);
  145. return(0);
  146. }
  147. LeaveCriticalSection(&lpMailUser->cs);
  148. return(lpMailUser->lcInit);
  149. }
  150. // IProperty
  151. STDMETHODIMP
  152. MailUser_SaveChanges(LPMailUser lpMailUser,
  153. ULONG ulFlags)
  154. {
  155. HRESULT hr = hrSuccess;
  156. ULONG ulcValues = 0;
  157. LPSPropValue lpPropArray = NULL, lpspv = NULL, lpPropsOld = NULL, lpPropNew = NULL;
  158. LPSPropTagArray lpProps = NULL;
  159. SPropertyRestriction PropRes;
  160. SPropValue Prop = {0};
  161. ULONG i, j;
  162. ULONG iDisplayName = NOT_FOUND;
  163. ULONG iEmailAddress = NOT_FOUND;
  164. ULONG iDuplicate = 0;
  165. ULONG ulObjType = 0;
  166. BOOL bNewRecord = FALSE;
  167. BOOL fReplace = FALSE;
  168. ULONG ulCount = 0, ulcProps = 0, ulcOld = 0, ulcNew;
  169. LPSBinary rgsbEntryIDs = NULL;
  170. SPropValue OneProp;
  171. BOOL fNewEntry = TRUE;
  172. BOOL fDuplicate = FALSE;
  173. SCODE sc;
  174. SBinary sbEID = {0};
  175. LPSBinary lpsbEID = NULL;
  176. FILETIME ftOldModTime = {0};
  177. FILETIME ftCurrentModTime = {0};
  178. BOOL bSwap = FALSE;
  179. #if !defined(NO_VALIDATION)
  180. // Make sure the object is valid.
  181. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, SaveChanges, lpVtbl)) {
  182. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  183. }
  184. #endif
  185. #ifndef DONT_ADDREF_PROPSTORE
  186. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpMailUser->lpIAB->lpPropertyStore)))) {
  187. hr = ResultFromScode(sc);
  188. goto exitNotAddRefed;
  189. }
  190. #endif
  191. //
  192. //$REVIEW how do we handle the FORCE_SAVE flag ?
  193. //
  194. //
  195. // check read write access ...
  196. //
  197. if (lpMailUser->ulObjAccess == IPROP_READONLY) {
  198. // error - cant save changes
  199. hr = MAPI_E_NO_ACCESS;
  200. goto exit;
  201. }
  202. // If this is a One-Off, we cannot save changes
  203. if (! lpMailUser->lpIAB->lpPropertyStore) {
  204. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  205. goto exit;
  206. }
  207. //
  208. // Validate the properties for this item
  209. //
  210. if (HR_FAILED(hr = HrValidateMailUser(lpMailUser))) {
  211. goto exit;
  212. }
  213. // see if this entry has an old modification time .. we would check that time in case of a
  214. // merge ..
  215. {
  216. LPSPropValue lpProp = NULL;
  217. if(!HR_FAILED(HrGetOneProp((LPMAPIPROP)lpMailUser, PR_LAST_MODIFICATION_TIME, &lpProp)))
  218. {
  219. CopyMemory(&ftOldModTime, &(lpProp->Value.ft), sizeof(ftOldModTime));
  220. MAPIFreeBuffer(lpProp);
  221. }
  222. }
  223. // Put in the modification time
  224. OneProp.ulPropTag = PR_LAST_MODIFICATION_TIME;
  225. GetSystemTimeAsFileTime(&OneProp.Value.ft);
  226. if(!ftOldModTime.dwLowDateTime && !ftOldModTime.dwHighDateTime)
  227. CopyMemory(&ftOldModTime, &OneProp.Value.ft, sizeof(ftOldModTime)); // if we dont have a mod time, use NOW
  228. if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(
  229. lpMailUser,
  230. 1, // cValues
  231. &OneProp, // lpPropArray
  232. NULL))) { // lppProblems
  233. DebugTraceResult( TEXT("SetProps(PR_LAST_MODIFICATION_TIME)"), hr);
  234. goto exit;
  235. }
  236. // BUGBUG: If SaveChanges fails after this, the PR_MODIFICATION_TIME on the
  237. // open object will still be updated, even though it no longer matches
  238. // the persistent copy of the object. I can live with this since it
  239. // really simplifies the code.
  240. // if this is a new entry and there is a folder parent for it,
  241. // add the folder parent's entryid to this entry
  242. // This will be persisted when we do the write record
  243. // Once write record returns a valid entryid, we can update the folder to
  244. // make this new item a part of it
  245. if (fNewEntry && bIsWABSessionProfileAware(lpMailUser->lpIAB) &&
  246. //bAreWABAPIProfileAware(lpMailUser->lpIAB) &&
  247. lpMailUser->pmbinOlk&& lpMailUser->pmbinOlk->lpb && lpMailUser->pmbinOlk->cb)
  248. {
  249. AddFolderParentEIDToItem(lpMailUser->lpIAB,
  250. lpMailUser->pmbinOlk->cb,
  251. (LPENTRYID) lpMailUser->pmbinOlk->lpb,
  252. (LPMAPIPROP)lpMailUser, 0, NULL);
  253. }
  254. //
  255. // We want a lpPropArray that contains everything but the PR_SEARCH_KEY
  256. //
  257. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetPropList( lpMailUser, MAPI_UNICODE, &lpProps)))
  258. goto exit;
  259. if(lpProps)
  260. {
  261. for(i=0;i<lpProps->cValues;i++)
  262. {
  263. if(lpProps->aulPropTag[i] == PR_SEARCH_KEY)
  264. {
  265. for(j=i;j<lpProps->cValues-1;j++)
  266. lpProps->aulPropTag[j] = lpProps->aulPropTag[j+1];
  267. lpProps->cValues--;
  268. break;
  269. }
  270. }
  271. }
  272. //
  273. // Get a LPSPropValue array of all the properties pertaining to this
  274. // entry
  275. //
  276. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(
  277. lpMailUser,
  278. lpProps, // LPSPropTagArray - NULL returns all
  279. MAPI_UNICODE, // flags
  280. &ulcValues,
  281. &lpPropArray)))
  282. {
  283. // DebugPrintError(("GetProps -> %x\n", hr));
  284. goto exit;
  285. }
  286. //
  287. // Determine the entryid of this thing
  288. //
  289. for(i = 0; i < ulcValues; i++) {
  290. if (lpPropArray[i].ulPropTag == PR_DISPLAY_NAME) {
  291. // We use DisplayName as our uniqueness key for Strict or Loose match tests
  292. iDisplayName = i;
  293. }
  294. if (lpPropArray[i].ulPropTag == PR_EMAIL_ADDRESS) {
  295. // We use email address as our secondary uniqueness key for Strict match tests
  296. iEmailAddress = i;
  297. }
  298. if (lpPropArray[i].ulPropTag == PR_ENTRYID) {
  299. if ((lpPropArray[i].Value.bin.cb != 0) &&
  300. (lpPropArray[i].Value.bin.lpb != NULL))
  301. {
  302. sbEID.cb = lpPropArray[i].Value.bin.cb;
  303. sbEID.lpb = lpPropArray[i].Value.bin.lpb;
  304. // If this is a One-Off, we cannot save changes
  305. if(WAB_ONEOFF == IsWABEntryID(sbEID.cb,(LPENTRYID)sbEID.lpb,NULL,NULL,NULL, NULL, NULL))
  306. {
  307. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  308. goto exit;
  309. }
  310. fNewEntry = FALSE;
  311. continue;
  312. } else {
  313. lpPropArray[i].Value.bin.cb = 0;
  314. }
  315. }
  316. if (lpPropArray[i].ulPropTag == PR_OBJECT_TYPE) {
  317. switch(lpPropArray[i].Value.l) {
  318. case MAPI_MAILUSER:
  319. ulObjType = RECORD_CONTACT;
  320. break;
  321. case MAPI_DISTLIST:
  322. ulObjType = RECORD_DISTLIST;
  323. break;
  324. case MAPI_ABCONT:
  325. ulObjType = RECORD_CONTAINER;
  326. break;
  327. default:
  328. // DebugPrintError(("Unknown Object Type: %d\n",lpPropArray[i].Value.l));
  329. hr = ResultFromScode(MAPI_E_INVALID_OBJECT);
  330. goto exit;
  331. break;
  332. }
  333. }
  334. }
  335. Assert(iDisplayName != NOT_FOUND);
  336. if (fNewEntry && (lpMailUser->ulCreateFlags & (CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE))) {
  337. // Need to test DisplayName against current store... Use FindRecord.
  338. // Only need to test if this is a new record.
  339. PropRes.lpProp = &(lpPropArray[iDisplayName]);
  340. PropRes.relop = RELOP_EQ;
  341. PropRes.ulPropTag = PR_DISPLAY_NAME;
  342. ulCount = 0; // find them all
  343. // Search the property store
  344. Assert(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore);
  345. if (HR_FAILED(hr = FindRecords(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  346. lpMailUser->pmbinOlk, // pmbinFolder
  347. 0, // ulFlags
  348. TRUE, // Always TRUE
  349. &PropRes, // Propertyrestriction
  350. &ulCount, // IN: number of matches to find, OUT: number found
  351. &rgsbEntryIDs))) {
  352. DebugTraceResult(FindRecords, hr);
  353. goto exit;
  354. }
  355. if (ulCount) { // Was a match found?
  356. fDuplicate = TRUE;
  357. iDuplicate = 0;
  358. if (lpMailUser->ulCreateFlags & CREATE_CHECK_DUP_STRICT && iEmailAddress != NOT_FOUND) {
  359. // Check the primary email address too
  360. fDuplicate = FALSE;
  361. for (i = 0; i < ulCount && ! fDuplicate; i++) {
  362. // Look at each entry until a match for email address is found
  363. // Read the record
  364. if (HR_FAILED(hr = ReadRecord(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  365. &(rgsbEntryIDs[i]), // EntryID
  366. 0, // ulFlags
  367. &ulcProps, // number of props returned
  368. &lpspv))) { // properties returned
  369. DebugTraceResult(MailUser_SaveChanges:ReadRecord, hr);
  370. // ignore it and move on
  371. continue;
  372. }
  373. if (ulcProps) {
  374. Assert(lpspv);
  375. if (lpspv) {
  376. // Look for PR_EMAIL_ADDRESS
  377. for (j = 0; j < ulcProps; j++) {
  378. if (lpspv[j].ulPropTag == PR_EMAIL_ADDRESS) {
  379. // Compare the two:
  380. if (! lstrcmpi(lpspv[j].Value.LPSZ,
  381. lpPropArray[iEmailAddress].Value.LPSZ)) {
  382. fDuplicate = TRUE;
  383. iDuplicate = i; // entry to delete on CREATE_REPLACE
  384. }
  385. break;
  386. }
  387. }
  388. // Free the prop array
  389. ReadRecordFreePropArray( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  390. ulcProps,
  391. &lpspv);
  392. }
  393. }
  394. }
  395. }
  396. if (fDuplicate) {
  397. // Depending on the flags, we should do something special here.
  398. // Found a duplicate.
  399. if (lpMailUser->ulCreateFlags & CREATE_REPLACE) {
  400. fReplace = TRUE;
  401. } else {
  402. // Fail
  403. DebugTrace(TEXT("SaveChanges found collision... failed\n"));
  404. hr = ResultFromScode(MAPI_E_COLLISION);
  405. goto exit;
  406. }
  407. }
  408. }
  409. }
  410. //
  411. // Write the record to the property store
  412. //
  413. if(sbEID.cb)
  414. lpsbEID = &sbEID;
  415. else if(fReplace)
  416. {
  417. lpsbEID = &(rgsbEntryIDs[iDuplicate]);
  418. Prop.ulPropTag = PR_ENTRYID;
  419. Prop.Value.bin = *lpsbEID;
  420. if (lpMailUser->ulCreateFlags & CREATE_MERGE)
  421. {
  422. // We're now asking the user if he wants to replace - ideally we should just merge
  423. // the new entry with the old entry giving priority to the new data over the old
  424. // This way the user doesnt lose information already on the contact and it becomes
  425. // much easier to update the information through vCards and LDAP etc
  426. // TO do the merge, we get all the existing data on the contact
  427. if (HR_FAILED(hr = ReadRecord(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  428. &(rgsbEntryIDs[iDuplicate]),
  429. 0,
  430. &ulcProps,
  431. &lpspv)))
  432. {
  433. DebugTrace(TEXT("SaveChanges: ReadRecord Failed\n"));
  434. goto exit;
  435. }
  436. for(i=0;i<ulcProps;i++)
  437. {
  438. if(lpspv[i].ulPropTag == PR_LAST_MODIFICATION_TIME)
  439. {
  440. CopyMemory(&ftCurrentModTime, &(lpspv[i].Value.ft), sizeof(ftCurrentModTime));
  441. lpspv[i].ulPropTag = PR_NULL;
  442. break;
  443. }
  444. }
  445. sc = ScMergePropValues( 1, &Prop, // these are added just to make sure the ScMerge wont fail
  446. ulcProps, lpspv,
  447. &ulcOld, &lpPropsOld);
  448. ReadRecordFreePropArray( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  449. ulcProps, &lpspv);
  450. if (sc != S_OK)
  451. {
  452. hr = ResultFromScode(sc);
  453. goto exit;
  454. }
  455. }
  456. else
  457. {
  458. ulcOld = 1;
  459. lpPropsOld = &Prop;
  460. }
  461. // Nullify any new PR_ENTRYID prop on the new prop set so that
  462. // we retain the old EID
  463. for(i=0;i<ulcValues;i++)
  464. {
  465. if(lpPropArray[i].ulPropTag == PR_ENTRYID)
  466. {
  467. lpPropArray[i].ulPropTag = PR_NULL;
  468. break;
  469. }
  470. }
  471. if (fReplace && lpMailUser->ulCreateFlags & CREATE_MERGE)
  472. {
  473. // Check the FileTimes to see who stomps on whom
  474. if(CompareFileTime(&ftOldModTime, &ftCurrentModTime)<0) // current changes are later than original ones
  475. {
  476. // swap the 2 prop arrays
  477. ULONG ulTemp = ulcValues;
  478. LPSPropValue lpTemp =lpPropArray;
  479. ulcValues = ulcOld; ulcOld = ulTemp;
  480. lpPropArray = lpPropsOld; lpPropsOld = lpTemp;
  481. bSwap = TRUE;
  482. }
  483. }
  484. // Now merge the new props with the old props
  485. sc = ScMergePropValues( ulcOld, lpPropsOld,
  486. ulcValues, lpPropArray,
  487. &ulcNew, &lpPropNew);
  488. // undo a swap above so we can free memory properly
  489. if(bSwap)
  490. {
  491. // swap the 2 prop arrays
  492. ULONG ulTemp = ulcValues;
  493. LPSPropValue lpTemp =lpPropArray;
  494. ulcValues = ulcOld; ulcOld = ulTemp;
  495. lpPropArray = lpPropsOld; lpPropsOld = lpTemp;
  496. }
  497. if (sc != S_OK)
  498. {
  499. hr = ResultFromScode(sc);
  500. goto exit;
  501. }
  502. MAPIFreeBuffer(lpPropArray);
  503. lpPropArray = lpPropNew;
  504. ulcValues = ulcNew;
  505. lpPropNew = NULL;
  506. ulcNew = 0;
  507. }
  508. Assert(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore);
  509. // One last thing to check is that if this is a new record, it shouldn't have a record key and
  510. // instance key set on it and if it is an existing record, the record key and instance key should
  511. // be identical to the entryid
  512. {
  513. ULONG iEntryID = NOT_FOUND;
  514. ULONG iRecordKey = NOT_FOUND;
  515. ULONG iInstanceKey = NOT_FOUND;
  516. for(i=0;i<ulcValues;i++)
  517. {
  518. switch(lpPropArray[i].ulPropTag)
  519. {
  520. case PR_ENTRYID:
  521. iEntryID = i;
  522. break;
  523. case PR_RECORD_KEY:
  524. iRecordKey = i;
  525. break;
  526. case PR_INSTANCE_KEY:
  527. iInstanceKey = i;
  528. break;
  529. }
  530. }
  531. if(iEntryID == NOT_FOUND || !lpPropArray[iEntryID].Value.bin.cb)
  532. {
  533. if(iRecordKey != NOT_FOUND)
  534. lpPropArray[iRecordKey].ulPropTag = PR_NULL;
  535. if(iInstanceKey != NOT_FOUND)
  536. lpPropArray[iInstanceKey].ulPropTag = PR_NULL;
  537. }
  538. else
  539. {
  540. if(iRecordKey != NOT_FOUND)
  541. {
  542. lpPropArray[iRecordKey].Value.bin.cb = lpPropArray[iEntryID].Value.bin.cb;
  543. lpPropArray[iRecordKey].Value.bin.lpb = lpPropArray[iEntryID].Value.bin.lpb;
  544. }
  545. if(iInstanceKey != NOT_FOUND)
  546. {
  547. lpPropArray[iInstanceKey].Value.bin.cb = lpPropArray[iEntryID].Value.bin.cb;
  548. lpPropArray[iInstanceKey].Value.bin.lpb = lpPropArray[iEntryID].Value.bin.lpb;
  549. }
  550. }
  551. }
  552. // Just to make sure we knock out all the PR_NULL properties,
  553. // recreate a new version of the PropValueArray if any PR_NULL exist
  554. for(i=0;i<ulcValues;i++)
  555. {
  556. if(lpPropArray[i].ulPropTag == PR_NULL)
  557. {
  558. ULONG ulcNew = 0;
  559. LPSPropValue lpPropsNew = NULL;
  560. SPropValue Prop = {0};
  561. Prop.ulPropTag = PR_NULL;
  562. if(!(sc = ScMergePropValues( 1, &Prop, // these are added just to make sure the ScMerge wont fail
  563. ulcValues, lpPropArray,
  564. &ulcNew, &lpPropsNew)))
  565. {
  566. if(lpPropArray)
  567. FreeBufferAndNull(&lpPropArray);
  568. ulcValues = ulcNew;
  569. lpPropArray = lpPropsNew;
  570. }
  571. break;
  572. }
  573. }
  574. {
  575. OlkContInfo * polkci = NULL;
  576. LPSBinary lpsbContEID = NULL;
  577. if(lpMailUser->pmbinOlk)
  578. {
  579. polkci = FindContainer( lpMailUser->lpIAB, lpMailUser->pmbinOlk->cb, (LPENTRYID)lpMailUser->pmbinOlk->lpb);
  580. if(polkci)
  581. lpsbContEID = polkci->lpEntryID;
  582. }
  583. if (HR_FAILED(hr = WriteRecord( lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  584. lpsbContEID,
  585. IN OUT &lpsbEID,
  586. IN 0, //flags - reserved
  587. IN ulObjType,
  588. IN ulcValues,
  589. IN lpPropArray)))
  590. {
  591. // DebugPrintError(("WriteRecord Failed: %x\n",hr));
  592. //$REVIEW writerecord will tell us if MAPI_E_OBJECT_DELETED
  593. // how to get MAPI_E_OBJECT_CHANGED or MAPI_E_OBJECT_DELETED ?
  594. goto exit;
  595. }
  596. }
  597. // if sbEID.cb was 0, we now have a new entryid in the lpsbEID struct
  598. if(!sbEID.cb && !fReplace)
  599. {
  600. sbEID.lpb = lpsbEID->lpb;
  601. sbEID.cb = lpsbEID->cb;
  602. }
  603. // if this is a first time save of a new entry, then if profiles are enabled and this entry
  604. // has a folder parent marked on it, add the new entryid to the folder parent ...
  605. if(fNewEntry && bIsWABSessionProfileAware(lpMailUser->lpIAB) &&
  606. //bAreWABAPIProfileAware(lpMailUser->lpIAB) &&
  607. lpMailUser->pmbinOlk&& lpMailUser->pmbinOlk->lpb && lpMailUser->pmbinOlk->cb)
  608. {
  609. AddItemEIDToFolderParent(lpMailUser->lpIAB,
  610. lpMailUser->pmbinOlk->cb,
  611. (LPENTRYID)lpMailUser->pmbinOlk->lpb,
  612. sbEID.cb,
  613. (LPENTRYID)sbEID.lpb);
  614. }
  615. // If this is a first time save, set the local entryid prop.
  616. if (fReplace || fNewEntry)
  617. {
  618. OneProp.ulPropTag = PR_ENTRYID;
  619. OneProp.Value.bin = (fReplace ? *lpsbEID : sbEID);
  620. // Use the low-level SetProps to avoid the PR_ENTRYID filter.
  621. if (HR_FAILED(hr = lpMailUser->lpPropData->lpVtbl->SetProps(
  622. lpMailUser->lpPropData,
  623. 1, // cValues
  624. &OneProp, // lpPropArray
  625. NULL))) // lppProblems
  626. {
  627. DebugTraceResult( TEXT("SetProps(PR_ENTRYID)"), hr);
  628. goto exit;
  629. }
  630. }
  631. if (ulFlags & KEEP_OPEN_READWRITE) {
  632. lpMailUser->ulObjAccess = IPROP_READWRITE;
  633. } else {
  634. //$REVIEW
  635. // whether the flag was READONLY or there was no flag,
  636. // we'll make the future access now READONLY
  637. //
  638. lpMailUser->ulObjAccess = IPROP_READONLY;
  639. }
  640. exit:
  641. #ifndef DONT_ADDREF_PROPSTORE
  642. ReleasePropertyStore(lpMailUser->lpIAB->lpPropertyStore);
  643. exitNotAddRefed:
  644. #endif
  645. FreeEntryIDs(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  646. ulCount,
  647. rgsbEntryIDs);
  648. FreeBufferAndNull(&lpPropArray);
  649. FreeBufferAndNull(&lpProps);
  650. FreeBufferAndNull(&lpPropNew);
  651. if(lpMailUser->ulCreateFlags & CREATE_MERGE)
  652. FreeBufferAndNull(&lpPropsOld);
  653. if(lpsbEID != &sbEID && !fReplace)
  654. FreeEntryIDs(lpMailUser->lpIAB->lpPropertyStore->hPropertyStore,
  655. 1,
  656. lpsbEID);
  657. if ((HR_FAILED(hr)) && (ulFlags & MAPI_DEFERRED_ERRORS)) {
  658. //$REVIEW : this is a grossly trivial handling of MAPI_DEFERRED_ERRORS ..
  659. // BUGBUG: In fact, it isn't handling the errors at all!
  660. //
  661. hr = hrSuccess;
  662. }
  663. return(hr);
  664. }
  665. STDMETHODIMP
  666. MailUser_GetProps(LPMailUser lpMailUser,
  667. LPSPropTagArray lpPropTagArray,
  668. ULONG ulFlags,
  669. ULONG * lpcValues,
  670. LPSPropValue * lppPropArray)
  671. {
  672. #if !defined(NO_VALIDATION)
  673. // Make sure the object is valid.
  674. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetProps, lpVtbl)) {
  675. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  676. }
  677. #endif
  678. return(lpMailUser->lpPropData->lpVtbl->GetProps(
  679. lpMailUser->lpPropData,
  680. lpPropTagArray,
  681. ulFlags,
  682. lpcValues,
  683. lppPropArray));
  684. }
  685. STDMETHODIMP
  686. MailUser_GetPropList(LPMailUser lpMailUser,
  687. ULONG ulFlags,
  688. LPSPropTagArray * lppPropTagArray)
  689. {
  690. #if !defined(NO_VALIDATION)
  691. /* Make sure the object is valid.
  692. */
  693. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetPropList, lpVtbl))
  694. {
  695. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  696. }
  697. #endif
  698. return lpMailUser->lpPropData->lpVtbl->GetPropList(
  699. lpMailUser->lpPropData,
  700. ulFlags,
  701. lppPropTagArray);
  702. }
  703. STDMETHODIMP
  704. MailUser_OpenProperty(LPMailUser lpMailUser,
  705. ULONG ulPropTag,
  706. LPCIID lpiid,
  707. ULONG ulInterfaceOptions,
  708. ULONG ulFlags,
  709. LPUNKNOWN * lppUnk)
  710. {
  711. #if !defined(NO_VALIDATION)
  712. /* Make sure the object is valid.
  713. */
  714. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, OpenProperty, lpVtbl))
  715. {
  716. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  717. }
  718. #endif
  719. return lpMailUser->lpPropData->lpVtbl->OpenProperty(
  720. lpMailUser->lpPropData,
  721. ulPropTag,
  722. lpiid,
  723. ulInterfaceOptions,
  724. ulFlags,
  725. lppUnk);
  726. }
  727. STDMETHODIMP
  728. MailUser_SetProps(LPMailUser lpMailUser,
  729. ULONG cValues,
  730. LPSPropValue lpPropArray,
  731. LPSPropProblemArray * lppProblems)
  732. {
  733. ULONG i;
  734. #if !defined(NO_VALIDATION)
  735. /* Make sure the object is valid.
  736. */
  737. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, SetProps, lpVtbl))
  738. {
  739. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  740. }
  741. #endif
  742. if (lpMailUser->lpIAB->lpPropertyStore) {
  743. // Filter out any READ-ONLY props.
  744. // Only do this if this is a real, WAB entry. Others, like LDAP
  745. // mailusers should be able to set any props they like.
  746. for (i = 0; i < cValues; i++) {
  747. switch (lpPropArray[i].ulPropTag) {
  748. case PR_ENTRYID:
  749. {
  750. // double check that this is a local entryid before reseting
  751. ULONG cb = lpPropArray[i].Value.bin.cb;
  752. LPENTRYID lp = (LPENTRYID) lpPropArray[i].Value.bin.lpb;
  753. BYTE bType = IsWABEntryID(cb,lp,NULL,NULL,NULL, NULL, NULL);
  754. if(WAB_PAB == bType || WAB_PABSHARED == bType || !cb || !lp)
  755. lpPropArray[i].ulPropTag = PR_NULL;
  756. }
  757. break;
  758. }
  759. }
  760. }
  761. return(lpMailUser->lpPropData->lpVtbl->SetProps(
  762. lpMailUser->lpPropData,
  763. cValues,
  764. lpPropArray,
  765. lppProblems));
  766. }
  767. STDMETHODIMP
  768. MailUser_DeleteProps(LPMailUser lpMailUser,
  769. LPSPropTagArray lpPropTagArray,
  770. LPSPropProblemArray * lppProblems)
  771. {
  772. #if !defined(NO_VALIDATION)
  773. /* Make sure the object is valid.
  774. */
  775. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, DeleteProps, lpVtbl))
  776. {
  777. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  778. }
  779. #endif
  780. return lpMailUser->lpPropData->lpVtbl->DeleteProps(
  781. lpMailUser->lpPropData,
  782. lpPropTagArray,
  783. lppProblems);
  784. }
  785. STDMETHODIMP
  786. MailUser_CopyTo(LPMailUser lpMailUser,
  787. ULONG ciidExclude,
  788. LPCIID rgiidExclude,
  789. LPSPropTagArray lpExcludeProps,
  790. ULONG_PTR ulUIParam,
  791. LPMAPIPROGRESS lpProgress,
  792. LPCIID lpInterface,
  793. LPVOID lpDestObj,
  794. ULONG ulFlags,
  795. LPSPropProblemArray * lppProblems)
  796. {
  797. #if !defined(NO_VALIDATION)
  798. /* Make sure the object is valid.
  799. */
  800. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, CopyTo, lpVtbl))
  801. {
  802. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  803. }
  804. #endif
  805. // Make sure we're not copying to ourselves
  806. if ((LPVOID)lpMailUser == (LPVOID)lpDestObj)
  807. {
  808. DebugTrace(TEXT("OOP MailUser_CopyTo(): Copying to self is not supported\n"));
  809. return ResultFromScode(MAPI_E_NO_ACCESS);
  810. }
  811. return lpMailUser->lpPropData->lpVtbl->CopyTo(
  812. lpMailUser->lpPropData,
  813. ciidExclude,
  814. rgiidExclude,
  815. lpExcludeProps,
  816. ulUIParam,
  817. lpProgress,
  818. lpInterface,
  819. lpDestObj,
  820. ulFlags,
  821. lppProblems);
  822. }
  823. STDMETHODIMP
  824. MailUser_CopyProps(LPMailUser lpMailUser,
  825. LPSPropTagArray lpIncludeProps,
  826. ULONG_PTR ulUIParam,
  827. LPMAPIPROGRESS lpProgress,
  828. LPCIID lpInterface,
  829. LPVOID lpDestObj,
  830. ULONG ulFlags,
  831. LPSPropProblemArray * lppProblems)
  832. {
  833. #if !defined(NO_VALIDATION)
  834. /* Make sure the object is valid.
  835. */
  836. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, CopyProps, lpVtbl))
  837. {
  838. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  839. }
  840. #endif
  841. return lpMailUser->lpPropData->lpVtbl->CopyProps(
  842. lpMailUser->lpPropData,
  843. lpIncludeProps,
  844. ulUIParam,
  845. lpProgress,
  846. lpInterface,
  847. lpDestObj,
  848. ulFlags,
  849. lppProblems);
  850. }
  851. STDMETHODIMP
  852. MailUser_GetNamesFromIDs(LPMailUser lpMailUser,
  853. LPSPropTagArray * lppPropTags,
  854. LPGUID lpPropSetGuid,
  855. ULONG ulFlags,
  856. ULONG * lpcPropNames,
  857. LPMAPINAMEID ** lpppPropNames)
  858. {
  859. #if !defined(NO_VALIDATION)
  860. // Make sure the object is valid.
  861. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetNamesFromIDs, lpVtbl)){
  862. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  863. }
  864. #endif
  865. return lpMailUser->lpPropData->lpVtbl->GetNamesFromIDs(
  866. lpMailUser->lpPropData,
  867. lppPropTags,
  868. lpPropSetGuid,
  869. ulFlags,
  870. lpcPropNames,
  871. lpppPropNames);
  872. }
  873. /***************************************************************************
  874. Name : GetIDsFromNames
  875. Purpose : Map names to property tags
  876. Parameters: lpMAILUSER -> MAILUSER object
  877. cPropNames
  878. lppPropNames
  879. ulFlags
  880. lppPropTags
  881. Returns : HRESULT
  882. Comment :
  883. ***************************************************************************/
  884. STDMETHODIMP
  885. MailUser_GetIDsFromNames(LPMailUser lpMailUser,
  886. ULONG cPropNames,
  887. LPMAPINAMEID * lppPropNames,
  888. ULONG ulFlags,
  889. LPSPropTagArray * lppPropTags)
  890. {
  891. #if !defined(NO_VALIDATION)
  892. // Make sure the object is valid.
  893. if (BAD_STANDARD_OBJ(lpMailUser, MailUser_, GetIDsFromNames, lpVtbl)) {
  894. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  895. }
  896. #endif
  897. return HrGetIDsFromNames(lpMailUser->lpIAB,
  898. cPropNames,
  899. lppPropNames, ulFlags, lppPropTags);
  900. }
  901. /***************************************************************************
  902. Name : HrSetMAILUSERAccess
  903. Purpose : Sets access flags on a MAILUSER object
  904. Parameters: lpMAILUSER -> MAILUSER object
  905. ulOpenFlags = MAPI flags: MAPI_MODIFY | MAPI_BEST_ACCESS
  906. Returns : HRESULT
  907. Comment : Set the access flags on the MAILUSER.
  908. ***************************************************************************/
  909. HRESULT HrSetMAILUSERAccess(LPMAILUSER lpMAILUSER,
  910. ULONG ulFlags)
  911. {
  912. ULONG ulAccess = IPROP_READONLY;
  913. LPMailUser lpMailUser = (LPMailUser)lpMAILUSER;
  914. switch (ulFlags& (MAPI_MODIFY | MAPI_BEST_ACCESS)) {
  915. case MAPI_MODIFY:
  916. case MAPI_BEST_ACCESS:
  917. ulAccess = IPROP_READWRITE;
  918. break;
  919. case 0:
  920. break;
  921. default:
  922. Assert(FALSE);
  923. }
  924. return(lpMailUser->lpPropData->lpVtbl->HrSetObjAccess(lpMailUser->lpPropData, ulAccess));
  925. }
  926. /***************************************************************************
  927. Name : HrNewMAILUSER
  928. Purpose : Creates a new MAILUSER object
  929. Parameters: lpPropertyStore -> property store structure
  930. pmbinOlk = <Outlook> container this entry lives in
  931. If this is a WAB Container, then set the FOLDER_PARENT
  932. prop on the MailUser with this entryid
  933. ulType = type of mailuser to create: {MAPI_MAILUSER, MAPI_DISTLIST}
  934. ulCreateFlags = CreateEntry flags
  935. lppMAILUSER -> Returned MAILUSER object.
  936. Returns : HRESULT
  937. Comment : WAB EID format is MAPI_ENTRYID:
  938. BYTE abFlags[4];
  939. MAPIUID mapiuid; // = WABONEOFFEID
  940. BYTE bData[]; // Contains BYTE type followed by type
  941. // specific data:
  942. // WAB_ONEOFF:
  943. // szDisplayName, szAddrType and szAddress.
  944. // the delimiter is the null between the strings.
  945. //
  946. ***************************************************************************/
  947. enum BaseProps{
  948. propPR_OBJECT_TYPE = 0,
  949. propPR_ENTRYID,
  950. propPR_ADDRTYPE,
  951. propMax
  952. };
  953. HRESULT HrNewMAILUSER(LPIAB lpIAB,
  954. LPSBinary pmbinOlk,
  955. ULONG ulType,
  956. ULONG ulCreateFlags,
  957. LPVOID *lppMAILUSER)
  958. {
  959. LPMailUser lpMailUser = NULL;
  960. SCODE sc;
  961. HRESULT hr = hrSuccess;
  962. LPPROPDATA lpPropData = NULL;
  963. SPropValue spv[propMax];
  964. ULONG cProps;
  965. //
  966. // Allocate space for the MAILUSER structure
  967. //
  968. if (FAILED(sc = MAPIAllocateBuffer(sizeof(MailUser), (LPVOID *) &lpMailUser))) {
  969. hr = ResultFromScode(sc);
  970. goto err;
  971. }
  972. ZeroMemory(lpMailUser, sizeof(MailUser));
  973. switch (ulType) {
  974. case MAPI_MAILUSER:
  975. lpMailUser->cIID = MailUser_cInterfaces;
  976. lpMailUser->rglpIID = MailUser_LPIID;
  977. break;
  978. case MAPI_DISTLIST:
  979. lpMailUser->cIID = DistList_cInterfaces;
  980. lpMailUser->rglpIID = DistList_LPIID;
  981. break;
  982. default:
  983. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  984. goto err;
  985. }
  986. lpMailUser->lpVtbl = &vtblMAILUSER;
  987. lpMailUser->lcInit = 1; // Caller is a reference
  988. lpMailUser->hLastError = hrSuccess;
  989. lpMailUser->idsLastError = 0;
  990. lpMailUser->lpszComponent = NULL;
  991. lpMailUser->ulContext = 0;
  992. lpMailUser->ulLowLevelError = 0;
  993. lpMailUser->ulErrorFlags = 0;
  994. lpMailUser->ulCreateFlags = ulCreateFlags;
  995. lpMailUser->lpMAPIError = NULL;
  996. lpMailUser->ulObjAccess = IPROP_READWRITE;
  997. lpMailUser->lpEntryID = NULL;
  998. lpMailUser->lpIAB = lpIAB;
  999. if(pmbinOlk)
  1000. {
  1001. if (FAILED(sc = MAPIAllocateMore(sizeof(SBinary), lpMailUser, (LPVOID *) &(lpMailUser->pmbinOlk)))) {
  1002. hr = ResultFromScode(sc);
  1003. goto err;
  1004. }
  1005. if (FAILED(sc = MAPIAllocateMore(pmbinOlk->cb, lpMailUser, (LPVOID *) &(lpMailUser->pmbinOlk->lpb)))) {
  1006. hr = ResultFromScode(sc);
  1007. goto err;
  1008. }
  1009. lpMailUser->pmbinOlk->cb = pmbinOlk->cb;
  1010. CopyMemory(lpMailUser->pmbinOlk->lpb, pmbinOlk->lpb, pmbinOlk->cb);
  1011. }
  1012. //
  1013. // Create IPropData
  1014. //
  1015. if (FAILED(sc = CreateIProp((LPIID)&IID_IMAPIPropData,
  1016. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  1017. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  1018. MAPIFreeBuffer,
  1019. NULL,
  1020. &lpPropData))) {
  1021. hr = ResultFromScode(sc);
  1022. goto err;
  1023. }
  1024. // PR_OBJECT_TYPE
  1025. spv[propPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  1026. spv[propPR_OBJECT_TYPE].Value.l = ulType;
  1027. spv[propPR_ENTRYID].ulPropTag = PR_ENTRYID;
  1028. spv[propPR_ENTRYID].Value.bin.lpb = NULL;
  1029. spv[propPR_ENTRYID].Value.bin.cb = 0;
  1030. cProps = 2;
  1031. if (ulType == MAPI_DISTLIST) {
  1032. cProps++;
  1033. Assert(cProps <= propMax);
  1034. spv[propPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE;
  1035. spv[propPR_ADDRTYPE].Value.LPSZ = (LPTSTR)szMAPIPDL;; // All DL's have this addrtype
  1036. }
  1037. //
  1038. // Set the default properties
  1039. //
  1040. if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData,
  1041. cProps,
  1042. spv,
  1043. NULL)))
  1044. {
  1045. goto err;
  1046. }
  1047. lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READWRITE);
  1048. lpMailUser->lpPropData = lpPropData;
  1049. // All we want to do is initialize the MailUsers critical section
  1050. InitializeCriticalSection(&lpMailUser->cs);
  1051. *lppMAILUSER = (LPVOID)lpMailUser;
  1052. return(hrSuccess);
  1053. err:
  1054. FreeBufferAndNull(&lpMailUser);
  1055. UlRelease(lpPropData);
  1056. return(hr);
  1057. }
  1058. /***************************************************************************
  1059. Name : ParseDisplayName
  1060. Purpose : Parses the display name into first/last names
  1061. Parameters: lpDisplayName = input display name
  1062. lppFirstName -> in/out first name string
  1063. lppLastName -> in/out last name string
  1064. lpvRoot = Root object to AllocMore onto (or NULL to use LocalAlloc)
  1065. lppLocalFree -> out: if lpvRoot == NULL, this is the LocalAlloc'ed buffer
  1066. which must be LocalFree'd.
  1067. Returns : TRUE if changes were made
  1068. ***************************************************************************/
  1069. BOOL ParseDisplayName( LPTSTR lpDisplayName,
  1070. LPTSTR * lppFirstName,
  1071. LPTSTR * lppLastName,
  1072. LPVOID lpvRoot,
  1073. LPVOID * lppLocalFree)
  1074. {
  1075. BOOL fChanged = FALSE;
  1076. if (lppLocalFree) {
  1077. *lppLocalFree = NULL;
  1078. }
  1079. //
  1080. // Handle the case where DisplayName exists, First and Last are missing
  1081. //
  1082. if (!(*lppFirstName && lstrlen(*lppFirstName)) &&
  1083. !(*lppLastName && lstrlen(*lppLastName)) &&
  1084. lpDisplayName)
  1085. {
  1086. ULONG nLen = 0;
  1087. BOOL bMatchFound = FALSE;
  1088. ULONG ulBracketCount = 0; //counts any brackets and puts them in last name
  1089. LPTSTR lpFirstName, lpLastName;
  1090. register TCHAR * pch;
  1091. LPTSTR lpBuffer = NULL;
  1092. nLen = (lstrlen(lpDisplayName)+1);
  1093. if (lpvRoot) {
  1094. if (AllocateBufferOrMore(sizeof(TCHAR)*nLen, lpvRoot, &lpBuffer)) {
  1095. DebugTrace(TEXT("ParseDisplayName can't allocate buffer\n"));
  1096. goto exit;
  1097. }
  1098. } else {
  1099. if (lppLocalFree) {
  1100. *lppLocalFree = lpBuffer = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*nLen);
  1101. }
  1102. }
  1103. if(!lpBuffer)
  1104. goto exit;
  1105. StrCpyN(lpBuffer, lpDisplayName, nLen);
  1106. //DebugTrace(TEXT("Parsing: <%s>\n"), lpDisplayName);
  1107. TrimSpaces(lpBuffer);
  1108. nLen = lstrlen(lpBuffer); // recount length
  1109. //
  1110. // Find the last space in the DisplayName string and assume that everything after it
  1111. // is the last name.
  1112. //
  1113. // We know that the string does not end with a space.
  1114. *lppFirstName = lpBuffer;
  1115. lpFirstName = *lppFirstName; // default
  1116. // If there is a comma or semicolon, assume that it is in the form
  1117. // LAST, FIRST and ignore spaces.
  1118. pch = lpBuffer;
  1119. while (pch && *pch) {
  1120. switch (*pch) {
  1121. case '(':
  1122. case '{':
  1123. case '<':
  1124. case '[':
  1125. ulBracketCount++;
  1126. break;
  1127. case ')':
  1128. case '}':
  1129. case '>':
  1130. case ']':
  1131. if (ulBracketCount) {
  1132. ulBracketCount--;
  1133. } else {
  1134. // No matching bracket, assume no spaces
  1135. goto loop_out;
  1136. }
  1137. break;
  1138. case ',':
  1139. case ';':
  1140. // Here's our break. (Assume first comma is it. Later commas
  1141. // are part of first name.)
  1142. if (! ulBracketCount) {
  1143. lpFirstName = CharNext(pch);
  1144. // get past any spaces
  1145. //while (*lpFirstName && IsSpace(lpFirstName)) {
  1146. // lpFirstName = CharNext(lpFirstName);
  1147. //}
  1148. lpLastName = lpBuffer;
  1149. *pch = '\0'; // Terminate lpLastName
  1150. TrimSpaces(lpFirstName);
  1151. TrimSpaces(lpLastName);
  1152. *lppFirstName = lpFirstName;
  1153. *lppLastName = lpLastName;
  1154. goto loop_out;
  1155. }
  1156. break;
  1157. }
  1158. pch = CharNext(pch);
  1159. }
  1160. // No comma or semi-colon, look for spaces.
  1161. if (bDNisByLN) {
  1162. pch = lpBuffer;
  1163. // Start at beginning of DN string, looking for space
  1164. while (pch && *pch && !fChanged) {
  1165. switch (*pch) {
  1166. case '(':
  1167. case '{':
  1168. case '<':
  1169. case '[':
  1170. ulBracketCount++;
  1171. break;
  1172. case ')':
  1173. case '}':
  1174. case '>':
  1175. case ']':
  1176. if (ulBracketCount) {
  1177. ulBracketCount--;
  1178. } else {
  1179. // No matching bracket, assume no spaces
  1180. goto loop_out;
  1181. }
  1182. break;
  1183. default:
  1184. // Space?
  1185. if (IsSpace(pch)) {
  1186. if (! ulBracketCount) {
  1187. lpFirstName = CharNext(pch);
  1188. lpLastName = lpBuffer;
  1189. *pch = '\0'; // Terminate lpLastName
  1190. TrimSpaces(lpFirstName);
  1191. TrimSpaces(lpLastName);
  1192. *lppFirstName = lpFirstName;
  1193. *lppLastName = lpLastName;
  1194. goto loop_out;
  1195. }
  1196. }
  1197. break;
  1198. }
  1199. pch = CharNext(pch);
  1200. }
  1201. } else {
  1202. register TCHAR * pchLast;
  1203. // Point to NULL. This will add one iteration to the loop but is
  1204. // easy and less code than putting it to the previous DBCS char.
  1205. pch = lpBuffer + nLen;
  1206. while (pch >= lpBuffer && !fChanged) {
  1207. switch (*pch) {
  1208. case '(':
  1209. case '{':
  1210. case '<':
  1211. case '[':
  1212. if (ulBracketCount) {
  1213. ulBracketCount--;
  1214. } else {
  1215. // No matching bracket, assume no spaces
  1216. goto loop_out;
  1217. }
  1218. break;
  1219. case ')':
  1220. case '}':
  1221. case '>':
  1222. case ']':
  1223. ulBracketCount++;
  1224. break;
  1225. case ',':
  1226. // This probably means that we have last name first, fix it.
  1227. if (! ulBracketCount) {
  1228. lpFirstName = CharNext(pch);
  1229. lpLastName = lpBuffer;
  1230. *pch = '\0'; // Terminate lpFirstName
  1231. TrimSpaces(lpFirstName);
  1232. TrimSpaces(lpLastName);
  1233. *lppLastName = lpLastName;
  1234. *lppFirstName = lpFirstName;
  1235. goto loop_out;
  1236. }
  1237. break;
  1238. default:
  1239. // Space?
  1240. if (IsSpace(pch)) {
  1241. if (! ulBracketCount)
  1242. {
  1243. // we dont want to break next to a bracket, we
  1244. // want to break at the space after the bracket ..
  1245. // so if the next char is a bracket, we ignore this stop ..
  1246. LPTSTR lpTemp = CharNext(pch);
  1247. if( *lpTemp != '(' &&
  1248. *lpTemp != '<' &&
  1249. *lpTemp != '[' &&
  1250. *lpTemp != '{' )
  1251. {
  1252. lpLastName = CharNext(pch);
  1253. *pch = '\0'; // Terminate lpFirstName
  1254. TrimSpaces(lpFirstName);
  1255. TrimSpaces(lpLastName);
  1256. *lppLastName = lpLastName;
  1257. goto loop_out;
  1258. }
  1259. }
  1260. }
  1261. break;
  1262. }
  1263. if ((pchLast = CharPrev(lpBuffer, pch)) == pch) {
  1264. pch = lpBuffer - 1; // terminate the loop
  1265. } else {
  1266. pch = pchLast;
  1267. }
  1268. }
  1269. }
  1270. loop_out:
  1271. // This will force a save operation on exiting so we
  1272. fChanged = TRUE; // dont have to do this again the next time ...
  1273. }
  1274. exit:
  1275. return(fChanged);
  1276. }
  1277. /***************************************************************************
  1278. Name : FixDisplayName
  1279. Purpose : Creates a display name
  1280. IF there is no data to create the name with,
  1281. sets the name to Unknown
  1282. Parameters: lpFirstName -> in first name string
  1283. lpMiddleName -> in middle name string
  1284. lpLastName -> in last name string
  1285. lpCompanyName -> in company name string
  1286. lpNickName -> in NickName string
  1287. lppDisplayName = in/out display name
  1288. lpvRoot = Root object to AllocMore onto (or NULL to use MAPIAllocateBuffer)
  1289. Returns : TRUE if changes were made
  1290. Comment :
  1291. ***************************************************************************/
  1292. BOOL FixDisplayName( LPTSTR lpFirstName,
  1293. LPTSTR lpMiddleName,
  1294. LPTSTR lpLastName,
  1295. LPTSTR lpCompanyName,
  1296. LPTSTR lpNickName,
  1297. LPTSTR * lppDisplayName,
  1298. LPVOID lpvRoot)
  1299. {
  1300. BOOL fChanged = FALSE;
  1301. LPTSTR lpDisplayName = *lppDisplayName;
  1302. LPTSTR lpszFormattedDisplayName = NULL;
  1303. ULONG nLen=0;
  1304. // First create the correct Display Name
  1305. if(!SetLocalizedDisplayName(lpFirstName,
  1306. lpMiddleName,
  1307. lpLastName,
  1308. lpCompanyName,
  1309. lpNickName,
  1310. NULL,
  1311. 0, // 0 means return a allocated string
  1312. bDNisByLN,
  1313. NULL,
  1314. &lpszFormattedDisplayName))
  1315. {
  1316. DebugPrintError(( TEXT("SetLocalizedDisplayName failed\n")));
  1317. // if all the input strings were blank, then this is a special
  1318. // case of no names. here we set display name = TEXT("Unknown")
  1319. if(lpFirstName || lpMiddleName || lpLastName || lpCompanyName || lpNickName)
  1320. goto exit;
  1321. }
  1322. if(!lpszFormattedDisplayName)
  1323. {
  1324. TCHAR szBuf[MAX_UI_STR];
  1325. DWORD cchSize = 0;
  1326. szBuf[0]='\0';
  1327. LoadString(hinstMapiX, idsUnknownDisplayName, szBuf, CharSizeOf(szBuf));
  1328. cchSize = (lstrlen(szBuf)+1);
  1329. lpszFormattedDisplayName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)* cchSize);
  1330. if(!lpszFormattedDisplayName)
  1331. goto exit;
  1332. StrCpyN(lpszFormattedDisplayName, szBuf, cchSize);
  1333. }
  1334. if(lpszFormattedDisplayName) {
  1335. DWORD cchSize = (lstrlen(lpszFormattedDisplayName) + 1);
  1336. if (AllocateBufferOrMore(sizeof(TCHAR)* cchSize, lpvRoot, lppDisplayName)) {
  1337. DebugTrace(TEXT("FixDisplayName can't allocate buffer\n"));
  1338. goto exit;
  1339. }
  1340. StrCpyN(*lppDisplayName, lpszFormattedDisplayName, cchSize);
  1341. fChanged = TRUE;
  1342. }
  1343. exit:
  1344. LocalFreeAndNull(&lpszFormattedDisplayName);
  1345. return(fChanged);
  1346. }
  1347. /***************************************************************************
  1348. Name : HrValidateMailUser
  1349. Purpose : Validates the properties of a MailUser object
  1350. Parameters: lpMailUser -> mailuser object
  1351. Returns : HRESULT
  1352. Comment :
  1353. ***************************************************************************/
  1354. HRESULT HrValidateMailUser(LPMailUser lpMailUser) {
  1355. HRESULT hResult = hrSuccess;
  1356. ULONG ulcValues, i;
  1357. LPSPropValue lpspv = NULL;
  1358. LPTSTR lpADDRTYPE = NULL;
  1359. BOOL fChanged = FALSE, fDL = FALSE;
  1360. LPTSTR lpGivenName, lpSurname, lpMiddleName, lpCompanyName, lpNickName, lpDisplayName;
  1361. // Get the interesting properties
  1362. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(
  1363. lpMailUser,
  1364. (LPSPropTagArray)&tagaValidate,
  1365. MAPI_UNICODE, // flags
  1366. &ulcValues,
  1367. &lpspv))) {
  1368. DebugTraceResult( TEXT("HrValidateMailUser:GetProps"), hResult);
  1369. goto exit;
  1370. }
  1371. // If there is a PR_ADDRTYPE, there must be a PR_EMAIL_ADDRESS
  1372. if (! PROP_ERROR(lpspv[ivPR_ADDRTYPE])) {
  1373. if (! lstrcmpi(lpspv[ivPR_ADDRTYPE].Value.LPSZ, szMAPIPDL)) {
  1374. fDL = TRUE;
  1375. } else {
  1376. if (PROP_ERROR(lpspv[ivPR_EMAIL_ADDRESS])) {
  1377. hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
  1378. goto exit;
  1379. }
  1380. }
  1381. }
  1382. if (! fDL) {
  1383. // Deal with name properties (not for DLs)
  1384. if (PROP_ERROR(lpspv[ivPR_SURNAME])) {
  1385. lpSurname = NULL;
  1386. } else {
  1387. lpSurname = lpspv[ivPR_SURNAME].Value.LPSZ;
  1388. }
  1389. if (PROP_ERROR(lpspv[ivPR_GIVEN_NAME])) {
  1390. lpGivenName = NULL;
  1391. } else {
  1392. lpGivenName = lpspv[ivPR_GIVEN_NAME].Value.LPSZ;
  1393. }
  1394. if (PROP_ERROR(lpspv[ivPR_MIDDLE_NAME])) {
  1395. lpMiddleName = NULL;
  1396. } else {
  1397. lpMiddleName = lpspv[ivPR_MIDDLE_NAME].Value.LPSZ;
  1398. }
  1399. if (PROP_ERROR(lpspv[ivPR_COMPANY_NAME])) {
  1400. lpCompanyName = NULL;
  1401. } else {
  1402. lpCompanyName = lpspv[ivPR_COMPANY_NAME].Value.LPSZ;
  1403. }
  1404. if (PROP_ERROR(lpspv[ivPR_NICKNAME])) {
  1405. lpNickName = NULL;
  1406. } else {
  1407. lpNickName = lpspv[ivPR_NICKNAME].Value.LPSZ;
  1408. }
  1409. if (PROP_ERROR(lpspv[ivPR_DISPLAY_NAME])) {
  1410. lpDisplayName = NULL;
  1411. } else {
  1412. lpDisplayName = lpspv[ivPR_DISPLAY_NAME].Value.LPSZ;
  1413. }
  1414. // WAB needs a display name otherwise it cannot handle the contact.
  1415. if(!lpDisplayName)
  1416. {
  1417. fChanged |= FixDisplayName( lpGivenName,
  1418. lpMiddleName,
  1419. lpSurname,
  1420. lpCompanyName,
  1421. lpNickName,
  1422. (LPTSTR *) (&lpspv[ivPR_DISPLAY_NAME].Value.LPSZ),
  1423. lpspv);
  1424. }
  1425. if (fChanged) {
  1426. lpspv[ivPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  1427. }
  1428. }
  1429. // Must have a display name and an object type
  1430. if (PROP_ERROR(lpspv[ivPR_DISPLAY_NAME]) || PROP_ERROR(lpspv[ivPR_OBJECT_TYPE]) ||
  1431. lstrlen(lpspv[ivPR_DISPLAY_NAME].Value.LPSZ) == 0) {
  1432. hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
  1433. goto exit;
  1434. }
  1435. // If there is a PR_CONTACT_ADDRTYPES there must be a PR_CONTACT_EMAIL_ADDRESSES
  1436. if (! PROP_ERROR(lpspv[ivPR_CONTACT_ADDRTYPES]) && PROP_ERROR(lpspv[ivPR_CONTACT_EMAIL_ADDRESSES])) {
  1437. hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
  1438. goto exit;
  1439. }
  1440. // Save changes
  1441. if (fChanged) {
  1442. // Null out any error values
  1443. for (i = 0; i < ulcValues; i++) {
  1444. if (PROP_ERROR(lpspv[i])) {
  1445. lpspv[i].ulPropTag = PR_NULL;
  1446. }
  1447. }
  1448. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1449. ulcValues,
  1450. lpspv,
  1451. NULL))) {
  1452. DebugTraceResult( TEXT("HrValidateMailUser:SetProps"), hResult);
  1453. goto exit;
  1454. }
  1455. }
  1456. exit:
  1457. FreeBufferAndNull(&lpspv);
  1458. return(hResult);
  1459. }
  1460. //$$
  1461. /*
  1462. - MAILUSERAssociateContextData
  1463. -
  1464. * With Context Menu extensions, we pass data to other apps and other apps
  1465. * need this data to exsist as long as the corresponding MailUser exists
  1466. */
  1467. void MAILUSERAssociateContextData(LPMAILUSER lpMailUser, LPWABEXTDISPLAY lpWEC)
  1468. {
  1469. ((LPMailUser)lpMailUser)->lpv = (LPVOID) lpWEC;
  1470. }
  1471. //$$
  1472. /*
  1473. - MAILUSERFreeContextData
  1474. -
  1475. * If Context Menu data was associated with this MailUSer, its time to clean it up
  1476. */
  1477. void MAILUSERFreeContextData(LPMailUser lpMailUser)
  1478. {
  1479. LPWABEXTDISPLAY lpWEC = (LPWABEXTDISPLAY) lpMailUser->lpv;
  1480. if(!lpWEC)
  1481. return;
  1482. if(lpWEC->lpv)
  1483. FreePadrlist((LPADRLIST)lpWEC->lpv);
  1484. if(lpWEC->lpsz)
  1485. LocalFree(lpWEC->lpsz);
  1486. LocalFree(lpWEC);
  1487. }