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.

8807 lines
297 KiB

  1. //*******************************************************************
  2. //
  3. // Copyright(c) Microsoft Corporation, 1996
  4. //
  5. // FILE: LDAPCONT.C
  6. //
  7. // PURPOSE: IMAPIContainer implementation for WAB's LDAP container.
  8. //
  9. // HISTORY:
  10. // 96/07/08 markdu Created.
  11. // 96/08/05 markdu BUG 34023 Always start with a filter that causes
  12. // the search to return only objects of class 'person'.
  13. // If organization is supplied, add it to the base of the
  14. // search instead of the filter to narrow the scope.
  15. // 96/08/06 markdu Changed FindRow to always return the first row.
  16. // This is OK in our current implementation since FindRow
  17. // is used only to create and fill a new table.
  18. // 96/08/07 markdu BUG 34201 If search fails due to undefined
  19. // attribute type, try a second search with different
  20. // attributes.
  21. // 96/08/07 markdu BUG 35326 Added attribute mappings for address.
  22. // 96/08/08 markdu BUG 35481 If search returns no error and no
  23. // results, treat this as "not found".
  24. // 96/08/09 markdu BUG 35604 Use ReAllocString to make sure string
  25. // buffers are large enough to hold the required strings
  26. // before doing wsprintf or lstrcpy.
  27. // 96/09/28 markdu BUG 36766 If the LDAP server says there are
  28. // multiple matches for ResolveName, mark the entry as
  29. // ambiguous if we got some back (these will be displayed
  30. // in the check names box). If we got no results back,
  31. // mark the entry as resolved so we don't display an empty
  32. // list of names.
  33. // 96/09/29 markdu BUG 36529 Search for "OfficePager" attribute
  34. // instead of "pager" since we don't have home pager in the UI.
  35. // 96/09/29 markdu BUG 36528 Fix mappings of home/office fax numbers.
  36. // 96/09/29 markdu BUG 37425 Add "mail" to the simple search.
  37. // 96/10/02 markdu BUG 37426 If the search filter does not include
  38. // common name, add to the filter so that we only get entries
  39. // that have a common name. Otherwise the entry will not be
  40. // displayed.
  41. // 96/10/02 markdu BUG 37424 Improve simple search by breaking the
  42. // search string into multiple components.
  43. // 96/10/09 vikramm - extended the LDAPServerParam structure and
  44. // modified the corresponding Get/Set functions. Added server
  45. // IDs to the server entries
  46. // 96/10/18 markdu Rewrote ParseSRestriction.
  47. // 96/11/10 markdu BUG 9735 Use global handle for cancel dialog.
  48. // 96/11/17 markdu BUG 9846 Only enable the cancel dialog when it is displayed.
  49. // 96/11/18 vikramm - updated params to FixDisplayName
  50. // 96/11/20 markdu Use synchronous bind for Sicily authentication.
  51. // 96/11/22 markdu BUG 10539 Replace dollar signs with line feeds in postalAddress.
  52. // 96/11/27 markdu BUG 6779 Get alternate email addresses.
  53. // 96/11/28 markdu BUG 6779 Do not add primary email address to contacts
  54. // list if it is already present. Also, if not primary address is
  55. // returned, but we have a contacts list, copy one from there to primary.
  56. // 96/12/03 markdu BUG 11941 Don't call lstrlen on NULL pointers.
  57. // 96/12/03 markdu BUG 11924 Restructure return values for cancel dialog.
  58. // 96/12/04 markdu BUG 11923 Escape invalid characters in search filters.
  59. // Also changed all ++ operations on strings to CharNext().
  60. // 96/12/09 markdu BUG 10537 Map error codes returned from ldap_bind to indicate
  61. // that the problem was with the logon credentials.
  62. // 96/12/10 markdu BUG 12699 Call CharNext before setting char to null.
  63. // 96/12/14 markdu Got rid of globals gfUseSynchronousBind and ghDlgCancel.
  64. // 96/12/19 markdu Post- code review clean up.
  65. // 96/12/19 markdu BUG 12608 Commented out temporary work-around for 10537.
  66. // 96/12/22 markdu BUG 11785 Replace wsprintf with lstrcat.
  67. //
  68. // 97/04/30 vikramm Added labeledURI attribute
  69. // 97/05/19 vikramm Exchange DS wont return display-name attribute
  70. // 97/05/19 vikramm Add username,passowrd for ISV DS binding
  71. //*******************************************************************
  72. #include "_apipch.h"
  73. #define LDAP_NTDS_ENTRY 0x80000000 // When doing LDAP searches, we need to identify if certain entries originate
  74. // on an NTDS server so that we can mark them accordingly when corresponding
  75. // LDAP URLs are passed to extension property sheets .. this enables the NTDS
  76. // extension sheets to make performance optimizations as appropriate
  77. // This flag is saved on the LDAP entryID as part of the ulcNumProps param ..
  78. // It's a bit of a hack but requires least number of changes ...just have to be
  79. // careful to negate this flag before using the ulcNumProps ..
  80. void SetAccountStringAW(LPTSTR * lppAcctStr,LPSTR lpszData);
  81. void SetAccountStringWA(LPSTR szStrA, LPTSTR lpszData, int cbsz);
  82. static const TCHAR szBindDNMSFTUser[] = TEXT("client=MS_OutlookAddressBook,o=Microsoft,c=US"); //NULL;
  83. static const TCHAR szBindCredMSFTPass[] = TEXT("wabrules"); //NULL;
  84. extern HRESULT HrGetLDAPSearchRestriction(LDAP_SEARCH_PARAMS LDAPsp, LPSRestriction lpSRes);
  85. static const LPTSTR szNULLString = TEXT("NULL");
  86. // Global handle for LDAP client DLL
  87. HINSTANCE ghLDAPDLLInst = NULL;
  88. ULONG ulLDAPDLLRefCount = 0;
  89. // DLL instance handle for account manager dll
  90. static HINSTANCE g_hInstImnAcct = NULL;
  91. // Global place to store the account manager object
  92. IImnAccountManager2 * g_lpAccountManager = NULL;
  93. // LDAP jump table is defined here...
  94. LDAPCONT_Vtbl vtblLDAPCONT =
  95. {
  96. VTABLE_FILL
  97. (LDAPCONT_QueryInterface_METHOD *) IAB_QueryInterface,
  98. (LDAPCONT_AddRef_METHOD *) WRAP_AddRef,
  99. (LDAPCONT_Release_METHOD *) CONTAINER_Release,
  100. (LDAPCONT_GetLastError_METHOD *) IAB_GetLastError,
  101. (LDAPCONT_SaveChanges_METHOD *) WRAP_SaveChanges,
  102. (LDAPCONT_GetProps_METHOD *) WRAP_GetProps,
  103. (LDAPCONT_GetPropList_METHOD *) WRAP_GetPropList,
  104. (LDAPCONT_OpenProperty_METHOD *) CONTAINER_OpenProperty,
  105. (LDAPCONT_SetProps_METHOD *) WRAP_SetProps,
  106. (LDAPCONT_DeleteProps_METHOD *) WRAP_DeleteProps,
  107. (LDAPCONT_CopyTo_METHOD *) WRAP_CopyTo,
  108. (LDAPCONT_CopyProps_METHOD *) WRAP_CopyProps,
  109. (LDAPCONT_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
  110. (LDAPCONT_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames,
  111. LDAPCONT_GetContentsTable,
  112. LDAPCONT_GetHierarchyTable,
  113. LDAPCONT_OpenEntry,
  114. LDAPCONT_SetSearchCriteria,
  115. LDAPCONT_GetSearchCriteria,
  116. LDAPCONT_CreateEntry,
  117. LDAPCONT_CopyEntries,
  118. LDAPCONT_DeleteEntries,
  119. LDAPCONT_ResolveNames
  120. };
  121. // LDAPVUE (table view class)
  122. // Implementes in-memory IMAPITable class on top of TADs
  123. // This is a copy of vtblVUE with FindRow overridden with the LDAP FindRow.
  124. VUE_Vtbl vtblLDAPVUE =
  125. {
  126. VTABLE_FILL
  127. (VUE_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface,
  128. (VUE_AddRef_METHOD FAR *) UNKOBJ_AddRef,
  129. VUE_Release,
  130. (VUE_GetLastError_METHOD FAR *) UNKOBJ_GetLastError,
  131. VUE_Advise,
  132. VUE_Unadvise,
  133. VUE_GetStatus,
  134. VUE_SetColumns,
  135. VUE_QueryColumns,
  136. VUE_GetRowCount,
  137. VUE_SeekRow,
  138. VUE_SeekRowApprox,
  139. VUE_QueryPosition,
  140. LDAPVUE_FindRow,
  141. LDAPVUE_Restrict,
  142. VUE_CreateBookmark,
  143. VUE_FreeBookmark,
  144. VUE_SortTable,
  145. VUE_QuerySortOrder,
  146. VUE_QueryRows,
  147. VUE_Abort,
  148. VUE_ExpandRow,
  149. VUE_CollapseRow,
  150. VUE_WaitForCompletion,
  151. VUE_GetCollapseState,
  152. VUE_SetCollapseState
  153. };
  154. // Interfaces supported by this object
  155. LPIID LDAPCONT_LPIID[LDAPCONT_cInterfaces] =
  156. {
  157. (LPIID)&IID_IABContainer,
  158. (LPIID)&IID_IMAPIContainer,
  159. (LPIID)&IID_IMAPIProp
  160. };
  161. // LDAP function names
  162. static const TCHAR cszLDAPClientDLL[] = TEXT("WLDAP32.DLL");
  163. static const char cszLDAPSSLInit[] = "ldap_sslinitW";
  164. static const char cszLDAPSetOption[] = "ldap_set_optionW";
  165. static const char cszLDAPOpen[] = "ldap_openW";
  166. static const char cszLDAPBind[] = "ldap_bindW";
  167. static const char cszLDAPBindS[] = "ldap_bind_sW";
  168. static const char cszLDAPUnbind[] = "ldap_unbind";
  169. static const char cszLDAPSearch[] = "ldap_searchW";
  170. static const char cszLDAPSearchS[] = "ldap_search_sW";
  171. static const char cszLDAPSearchST[] = "ldap_search_stW";
  172. static const char cszLDAPAbandon[] = "ldap_abandon";
  173. static const char cszLDAPResult[] = "ldap_result";
  174. static const char cszLDAPResult2Error[] = "ldap_result2error";
  175. static const char cszLDAPMsgFree[] = "ldap_msgfree";
  176. static const char cszLDAPFirstEntry[] = "ldap_first_entry";
  177. static const char cszLDAPNextEntry[] = "ldap_next_entry";
  178. static const char cszLDAPCountEntries[] = "ldap_count_entries";
  179. static const char cszLDAPFirstAttr[] = "ldap_first_attributeW";
  180. static const char cszLDAPNextAttr[] = "ldap_next_attributeW";
  181. static const char cszLDAPGetValues[] = "ldap_get_valuesW";
  182. static const char cszLDAPGetValuesLen[] = "ldap_get_values_lenW";
  183. static const char cszLDAPCountValues[] = "ldap_count_valuesW";
  184. static const char cszLDAPCountValuesLen[] = "ldap_count_values_len";
  185. static const char cszLDAPValueFree[] = "ldap_value_freeW";
  186. static const char cszLDAPValueFreeLen[] = "ldap_value_free_len";
  187. static const char cszLDAPGetDN[] = "ldap_get_dnW";
  188. static const char cszLDAPMemFree[] = "ldap_memfreeW";
  189. static const char cszLDAPConnect[] = "ldap_connect";
  190. static const char cszLDAPInit[] = "ldap_initW";
  191. static const char cszLDAPErr2String[] = "ldap_err2stringW";
  192. static const char cszLDAPCreatePageControl[] = "ldap_create_page_controlW";
  193. static const char cszLDAPSearchExtS[] = "ldap_search_ext_sW";
  194. static const char cszLDAPSearchExt[] = "ldap_search_extW";
  195. static const char cszLDAPParseResult[] = "ldap_parse_resultW";
  196. static const char cszLDAPParsePageControl[] = "ldap_parse_page_controlW";
  197. static const char cszLDAPControlFree[] = "ldap_control_freeW";
  198. static const char cszLDAPControlSFree[] = "ldap_controls_freeW";
  199. // Registry keys
  200. const LPTSTR szAllLDAPServersValueName = TEXT("All LDAP Server Names");
  201. // Global function pointers for LDAP API
  202. LPLDAPOPEN gpfnLDAPOpen = NULL;
  203. LPLDAPINIT gpfnLDAPInit = NULL;
  204. LPLDAPCONNECT gpfnLDAPConnect = NULL;
  205. LPLDAPSSLINIT gpfnLDAPSSLInit = NULL;
  206. LPLDAPSETOPTION gpfnLDAPSetOption = NULL;
  207. LPLDAPBIND gpfnLDAPBind = NULL;
  208. LPLDAPBINDS gpfnLDAPBindS = NULL;
  209. LPLDAPUNBIND gpfnLDAPUnbind = NULL;
  210. LPLDAPSEARCH gpfnLDAPSearch = NULL;
  211. LPLDAPSEARCHS gpfnLDAPSearchS = NULL;
  212. LPLDAPSEARCHST gpfnLDAPSearchST = NULL;
  213. LPLDAPABANDON gpfnLDAPAbandon = NULL;
  214. LPLDAPRESULT gpfnLDAPResult = NULL;
  215. LPLDAPRESULT2ERROR gpfnLDAPResult2Error = NULL;
  216. LPLDAPMSGFREE gpfnLDAPMsgFree = NULL;
  217. LPLDAPFIRSTENTRY gpfnLDAPFirstEntry = NULL;
  218. LPLDAPNEXTENTRY gpfnLDAPNextEntry = NULL;
  219. LPLDAPCOUNTENTRIES gpfnLDAPCountEntries = NULL;
  220. LPLDAPFIRSTATTR gpfnLDAPFirstAttr = NULL;
  221. LPLDAPNEXTATTR gpfnLDAPNextAttr = NULL;
  222. LPLDAPGETVALUES gpfnLDAPGetValues = NULL;
  223. LPLDAPGETVALUESLEN gpfnLDAPGetValuesLen = NULL;
  224. LPLDAPCOUNTVALUES gpfnLDAPCountValues = NULL;
  225. LPLDAPCOUNTVALUESLEN gpfnLDAPCountValuesLen = NULL;
  226. LPLDAPVALUEFREE gpfnLDAPValueFree = NULL;
  227. LPLDAPVALUEFREELEN gpfnLDAPValueFreeLen = NULL;
  228. LPLDAPGETDN gpfnLDAPGetDN = NULL;
  229. LPLDAPMEMFREE gpfnLDAPMemFree = NULL;
  230. LPLDAPERR2STRING gpfnLDAPErr2String = NULL;
  231. LPLDAPCREATEPAGECONTROL gpfnLDAPCreatePageControl = NULL;
  232. LPLDAPSEARCHEXT_S gpfnLDAPSearchExtS = NULL;
  233. LPLDAPSEARCHEXT gpfnLDAPSearchExt = NULL;
  234. LPLDAPPARSERESULT gpfnLDAPParseResult = NULL;
  235. LPLDAPPARSEPAGECONTROL gpfnLDAPParsePageControl = NULL;
  236. LPLDAPCONTROLFREE gpfnLDAPControlFree = NULL;
  237. LPLDAPCONTROLSFREE gpfnLDAPControlsFree = NULL;
  238. // API table for LDAP function addresses to fetch
  239. // BUGBUG this global array should be in data seg
  240. #define NUM_LDAPAPI_PROCS 36
  241. APIFCN LDAPAPIList[NUM_LDAPAPI_PROCS] =
  242. {
  243. { (PVOID *) &gpfnLDAPOpen, cszLDAPOpen },
  244. { (PVOID *) &gpfnLDAPConnect, cszLDAPConnect },
  245. { (PVOID *) &gpfnLDAPInit, cszLDAPInit },
  246. { (PVOID *) &gpfnLDAPSSLInit, cszLDAPSSLInit },
  247. { (PVOID *) &gpfnLDAPSetOption, cszLDAPSetOption },
  248. { (PVOID *) &gpfnLDAPBind, cszLDAPBind },
  249. { (PVOID *) &gpfnLDAPBindS, cszLDAPBindS },
  250. { (PVOID *) &gpfnLDAPUnbind, cszLDAPUnbind },
  251. { (PVOID *) &gpfnLDAPSearch, cszLDAPSearch },
  252. { (PVOID *) &gpfnLDAPSearchS, cszLDAPSearchS },
  253. { (PVOID *) &gpfnLDAPSearchST, cszLDAPSearchST },
  254. { (PVOID *) &gpfnLDAPAbandon, cszLDAPAbandon },
  255. { (PVOID *) &gpfnLDAPResult, cszLDAPResult },
  256. { (PVOID *) &gpfnLDAPResult2Error, cszLDAPResult2Error },
  257. { (PVOID *) &gpfnLDAPMsgFree, cszLDAPMsgFree },
  258. { (PVOID *) &gpfnLDAPFirstEntry, cszLDAPFirstEntry },
  259. { (PVOID *) &gpfnLDAPNextEntry, cszLDAPNextEntry },
  260. { (PVOID *) &gpfnLDAPCountEntries, cszLDAPCountEntries },
  261. { (PVOID *) &gpfnLDAPFirstAttr, cszLDAPFirstAttr },
  262. { (PVOID *) &gpfnLDAPNextAttr, cszLDAPNextAttr },
  263. { (PVOID *) &gpfnLDAPGetValues, cszLDAPGetValues },
  264. { (PVOID *) &gpfnLDAPGetValuesLen, cszLDAPGetValuesLen },
  265. { (PVOID *) &gpfnLDAPCountValues, cszLDAPCountValues },
  266. { (PVOID *) &gpfnLDAPCountValuesLen, cszLDAPCountValuesLen },
  267. { (PVOID *) &gpfnLDAPValueFree, cszLDAPValueFree },
  268. { (PVOID *) &gpfnLDAPValueFreeLen, cszLDAPValueFreeLen },
  269. { (PVOID *) &gpfnLDAPGetDN, cszLDAPGetDN },
  270. { (PVOID *) &gpfnLDAPMemFree, cszLDAPMemFree },
  271. { (PVOID *) &gpfnLDAPErr2String, cszLDAPErr2String },
  272. { (PVOID *) &gpfnLDAPCreatePageControl, cszLDAPCreatePageControl },
  273. { (PVOID *) &gpfnLDAPSearchExtS, cszLDAPSearchExtS },
  274. { (PVOID *) &gpfnLDAPSearchExt, cszLDAPSearchExt },
  275. { (PVOID *) &gpfnLDAPParseResult, cszLDAPParseResult },
  276. { (PVOID *) &gpfnLDAPParsePageControl,cszLDAPParsePageControl },
  277. { (PVOID *) &gpfnLDAPControlFree, cszLDAPControlFree },
  278. { (PVOID *) &gpfnLDAPControlsFree, cszLDAPControlSFree }
  279. };
  280. // LDAP attribute names
  281. static const TCHAR cszAttr_display_name[] = TEXT("display-name");
  282. static const TCHAR cszAttr_cn[] = TEXT("cn");
  283. static const TCHAR cszAttr_commonName[] = TEXT("commonName");
  284. static const TCHAR cszAttr_mail[] = TEXT("mail");
  285. static const TCHAR cszAttr_otherMailbox[] = TEXT("otherMailbox");
  286. static const TCHAR cszAttr_givenName[] = TEXT("givenName");
  287. static const TCHAR cszAttr_sn[] = TEXT("sn");
  288. static const TCHAR cszAttr_surname[] = TEXT("surname");
  289. static const TCHAR cszAttr_st[] = TEXT("st");
  290. static const TCHAR cszAttr_c[] = TEXT("c");
  291. static const TCHAR cszAttr_o[] = TEXT("o");
  292. static const TCHAR cszAttr_organizationName[] = TEXT("organizationName");
  293. static const TCHAR cszAttr_ou[] = TEXT("ou");
  294. static const TCHAR cszAttr_organizationalUnitName[] = TEXT("organizationalUnitName");
  295. static const TCHAR cszAttr_URL[] = TEXT("URL");
  296. static const TCHAR cszAttr_homePhone[] = TEXT("homePhone");
  297. static const TCHAR cszAttr_facsimileTelephoneNumber[] = TEXT("facsimileTelephoneNumber");
  298. static const TCHAR cszAttr_otherFacsimileTelephoneNumber[]= TEXT("otherFacsimileTelephoneNumber");
  299. static const TCHAR cszAttr_OfficeFax[] = TEXT("OfficeFax");
  300. static const TCHAR cszAttr_mobile[] = TEXT("mobile");
  301. static const TCHAR cszAttr_otherPager[] = TEXT("otherPager");
  302. static const TCHAR cszAttr_OfficePager[] = TEXT("OfficePager");
  303. static const TCHAR cszAttr_pager[] = TEXT("pager");
  304. static const TCHAR cszAttr_info[] = TEXT("info");
  305. static const TCHAR cszAttr_title[] = TEXT("title");
  306. static const TCHAR cszAttr_telephoneNumber[] = TEXT("telephoneNumber");
  307. static const TCHAR cszAttr_l[] = TEXT("l");
  308. static const TCHAR cszAttr_homePostalAddress[] = TEXT("homePostalAddress");
  309. static const TCHAR cszAttr_postalAddress[] = TEXT("postalAddress");
  310. static const TCHAR cszAttr_streetAddress[] = TEXT("streetAddress");
  311. static const TCHAR cszAttr_street[] = TEXT("street");
  312. static const TCHAR cszAttr_department[] = TEXT("department");
  313. static const TCHAR cszAttr_comment[] = TEXT("comment");
  314. static const TCHAR cszAttr_co[] = TEXT("co");
  315. static const TCHAR cszAttr_postalCode[] = TEXT("postalCode");
  316. static const TCHAR cszAttr_physicalDeliveryOfficeName[] = TEXT("physicalDeliveryOfficeName");
  317. static const TCHAR cszAttr_initials[] = TEXT("initials");
  318. static const TCHAR cszAttr_userCertificatebinary[] = TEXT("userCertificate;binary");
  319. static const TCHAR cszAttr_userSMIMECertificatebinary[] = TEXT("userSMIMECertificate;binary");
  320. static const TCHAR cszAttr_userCertificate[] = TEXT("userCertificate");
  321. static const TCHAR cszAttr_userSMIMECertificate[] = TEXT("userSMIMECertificate");
  322. static const TCHAR cszAttr_labeledURI[] = TEXT("labeledURI");
  323. static const TCHAR cszAttr_conferenceInformation[] = TEXT("conferenceInformation");
  324. static const TCHAR cszAttr_Manager[] = TEXT("Manager");
  325. static const TCHAR cszAttr_Reports[] = TEXT("Reports");
  326. static const TCHAR cszAttr_IPPhone[] = TEXT("IPPhone");
  327. static const TCHAR cszAttr_anr[] = TEXT("anr");
  328. // List of attributes that we ask the server to return on OpenEntry calls
  329. // This list includes the userCertificates property.
  330. // Also includes the labeledURI property
  331. static const TCHAR *g_rgszOpenEntryAttrs[] =
  332. {
  333. cszAttr_display_name,
  334. cszAttr_cn,
  335. cszAttr_commonName,
  336. cszAttr_mail,
  337. cszAttr_otherMailbox,
  338. cszAttr_givenName,
  339. cszAttr_sn,
  340. cszAttr_surname,
  341. cszAttr_st,
  342. cszAttr_c,
  343. cszAttr_co,
  344. cszAttr_organizationName,
  345. cszAttr_o,
  346. cszAttr_ou,
  347. cszAttr_organizationalUnitName,
  348. cszAttr_URL,
  349. cszAttr_homePhone,
  350. cszAttr_facsimileTelephoneNumber,
  351. cszAttr_otherFacsimileTelephoneNumber,
  352. cszAttr_OfficeFax,
  353. cszAttr_mobile,
  354. cszAttr_otherPager,
  355. cszAttr_OfficePager,
  356. cszAttr_pager,
  357. cszAttr_info,
  358. cszAttr_title,
  359. cszAttr_telephoneNumber,
  360. cszAttr_l,
  361. cszAttr_homePostalAddress,
  362. cszAttr_postalAddress,
  363. cszAttr_streetAddress,
  364. cszAttr_street,
  365. cszAttr_department,
  366. cszAttr_comment,
  367. cszAttr_postalCode,
  368. cszAttr_physicalDeliveryOfficeName,
  369. cszAttr_initials,
  370. cszAttr_conferenceInformation,
  371. cszAttr_userCertificatebinary,
  372. cszAttr_userSMIMECertificatebinary,
  373. cszAttr_labeledURI,
  374. cszAttr_Manager,
  375. cszAttr_Reports,
  376. cszAttr_IPPhone,
  377. NULL
  378. };
  379. // List of attributes that we put in the advanced find combo
  380. //
  381. // This list needs to be kept in sync with the string resources
  382. // idsLDAPFilterField*
  383. //
  384. const TCHAR *g_rgszAdvancedFindAttrs[] =
  385. {
  386. cszAttr_cn,
  387. cszAttr_mail,
  388. cszAttr_givenName,
  389. cszAttr_sn,
  390. cszAttr_o,
  391. /*
  392. cszAttr_homePostalAddress,
  393. cszAttr_postalAddress,
  394. cszAttr_streetAddress,
  395. cszAttr_street,
  396. cszAttr_st,
  397. cszAttr_c,
  398. cszAttr_postalCode,
  399. cszAttr_department,
  400. cszAttr_title,
  401. cszAttr_co,
  402. cszAttr_ou,
  403. cszAttr_homePhone,
  404. cszAttr_telephoneNumber,
  405. cszAttr_facsimileTelephoneNumber,
  406. cszAttr_OfficeFax,
  407. cszAttr_mobile,
  408. cszAttr_pager,
  409. cszAttr_OfficePager,
  410. cszAttr_conferenceInformation,
  411. cszAttr_Manager,
  412. cszAttr_Reports,
  413. */
  414. NULL
  415. };
  416. /* Only use the above list for all kinds of searches since now we do a single
  417. search for all attributes and cache the results
  418. // List of attributes that we ask the server to return on FindRow calls
  419. // This list DOES NOT include the userCertificates property, since when we
  420. // got the certs they would have been added to the WAB store and then would
  421. // have to be deleted. We only get the certs if the user asks for properties.
  422. static const TCHAR *g_rgszFindRowAttrs[] =
  423. {
  424. cszAttr_display_name,
  425. cszAttr_cn,
  426. cszAttr_commonName,
  427. cszAttr_mail,
  428. cszAttr_otherMailbox,
  429. cszAttr_givenName,
  430. cszAttr_sn,
  431. cszAttr_surname,
  432. cszAttr_st,
  433. cszAttr_c,
  434. cszAttr_co,
  435. cszAttr_organizationName,
  436. cszAttr_o,
  437. cszAttr_ou,
  438. cszAttr_organizationalUnitName,
  439. cszAttr_URL,
  440. cszAttr_homePhone,
  441. cszAttr_facsimileTelephoneNumber,
  442. cszAttr_OfficeFax,
  443. cszAttr_mobile,
  444. cszAttr_OfficePager,
  445. cszAttr_pager,
  446. cszAttr_info,
  447. cszAttr_title,
  448. cszAttr_telephoneNumber,
  449. cszAttr_l,
  450. cszAttr_homePostalAddress,
  451. cszAttr_postalAddress,
  452. cszAttr_streetAddress,
  453. cszAttr_street,
  454. cszAttr_department,
  455. cszAttr_comment,
  456. cszAttr_postalCode,
  457. cszAttr_physicalDeliveryOfficeName,
  458. cszAttr_initials,
  459. cszAttr_conferenceInformation,
  460. // DO NOT PUT cszAttr_userCertificatebinary in here!
  461. // Also no need to pu cszAttr_labeledURI here!
  462. NULL
  463. };
  464. */
  465. // MAPI property to LDAP attribute map
  466. // [PaulHi] 3/17/99 We have special PR_PAGER_TELEPHONE_NUMBER parsing code now. If any new
  467. // PR_PAGER_TELEPHONE_NUMBER attributes are added then also add them to the atszPagerAttr[].
  468. // Search on '[PaulHi] 3/17/99' to find the places that use this array.
  469. // BUGBUG this global array should be in data seg
  470. #define NUM_ATTRMAP_ENTRIES 42
  471. ATTRMAP gAttrMap[NUM_ATTRMAP_ENTRIES] =
  472. {
  473. { PR_DISPLAY_NAME, cszAttr_display_name },
  474. { PR_DISPLAY_NAME, cszAttr_cn },
  475. { PR_DISPLAY_NAME, cszAttr_commonName },
  476. { PR_GIVEN_NAME, cszAttr_givenName },
  477. { PR_MIDDLE_NAME, cszAttr_initials },
  478. { PR_SURNAME, cszAttr_sn },
  479. { PR_SURNAME, cszAttr_surname },
  480. { PR_EMAIL_ADDRESS, cszAttr_mail },
  481. { PR_WAB_SECONDARY_EMAIL_ADDRESSES, cszAttr_otherMailbox },
  482. { PR_COUNTRY, cszAttr_co },
  483. { PR_COUNTRY, cszAttr_c },
  484. { PR_STATE_OR_PROVINCE, cszAttr_st },
  485. { PR_LOCALITY, cszAttr_l },
  486. { PR_HOME_ADDRESS_STREET, cszAttr_homePostalAddress },
  487. { PR_STREET_ADDRESS, cszAttr_streetAddress },
  488. { PR_STREET_ADDRESS, cszAttr_street },
  489. { PR_STREET_ADDRESS, cszAttr_postalAddress },
  490. { PR_POSTAL_CODE, cszAttr_postalCode },
  491. { PR_HOME_TELEPHONE_NUMBER, cszAttr_homePhone },
  492. { PR_MOBILE_TELEPHONE_NUMBER, cszAttr_mobile },
  493. { PR_PAGER_TELEPHONE_NUMBER, cszAttr_pager },
  494. { PR_PAGER_TELEPHONE_NUMBER, cszAttr_otherPager },
  495. { PR_PAGER_TELEPHONE_NUMBER, cszAttr_OfficePager },
  496. { PR_BUSINESS_TELEPHONE_NUMBER, cszAttr_telephoneNumber },
  497. { PR_BUSINESS_HOME_PAGE, cszAttr_URL },
  498. { PR_HOME_FAX_NUMBER, cszAttr_otherFacsimileTelephoneNumber},
  499. { PR_BUSINESS_FAX_NUMBER, cszAttr_facsimileTelephoneNumber },
  500. { PR_BUSINESS_FAX_NUMBER, cszAttr_OfficeFax },
  501. { PR_TITLE, cszAttr_title },
  502. { PR_COMPANY_NAME, cszAttr_organizationName },
  503. { PR_COMPANY_NAME, cszAttr_o },
  504. { PR_DEPARTMENT_NAME, cszAttr_ou },
  505. { PR_DEPARTMENT_NAME, cszAttr_organizationalUnitName },
  506. { PR_DEPARTMENT_NAME, cszAttr_department },
  507. { PR_OFFICE_LOCATION, cszAttr_physicalDeliveryOfficeName },
  508. { PR_COMMENT, cszAttr_info },
  509. { PR_COMMENT, cszAttr_comment },
  510. { PR_USER_X509_CERTIFICATE, cszAttr_userCertificatebinary },
  511. { PR_USER_X509_CERTIFICATE, cszAttr_userSMIMECertificatebinary },
  512. { PR_USER_X509_CERTIFICATE, cszAttr_userCertificate },
  513. { PR_USER_X509_CERTIFICATE, cszAttr_userSMIMECertificate },
  514. { PR_WAB_LDAP_LABELEDURI, cszAttr_labeledURI },
  515. };
  516. // Filter strings
  517. static const TCHAR cszDefaultCountry[] = TEXT("US");
  518. static const TCHAR cszBaseFilter[] = TEXT("%s=%s");
  519. static const TCHAR cszAllEntriesFilter[] = TEXT("(objectclass=*)");
  520. static const TCHAR cszCommonNamePresentFilter[] = TEXT("(cn=*)");
  521. static const TCHAR cszStar[] = TEXT("*");
  522. static const TCHAR cszOpenParen[] = TEXT("(");
  523. static const TCHAR cszCloseParen[] = TEXT(")");
  524. static const TCHAR cszEqualSign[] = TEXT("=");
  525. static const TCHAR cszAnd[] = TEXT("&");
  526. static const TCHAR cszOr[] = TEXT("|");
  527. static const TCHAR cszAllPersonFilter[] = TEXT("(objectCategory=person)");
  528. static const TCHAR cszAllGroupFilter[] = TEXT("(objectCategory=group)");
  529. // Set TRUE if CoInitialize is called
  530. BOOL fCoInitialize = FALSE;
  531. enum
  532. {
  533. use_ldap_v3 = 0,
  534. use_ldap_v2
  535. };
  536. // Definitions
  537. #define FIRST_PASS 0
  538. #define SECOND_PASS 1
  539. #define UMICH_PASS SECOND_PASS
  540. // Number of extra characters needed when allocating filters
  541. #define FILTER_EXTRA_BASIC 4 // (, =, ), *
  542. #define FILTER_EXTRA_OP 3 // (, &/|, )
  543. #define FILTER_OP_AND 0 // use AND operator
  544. #define FILTER_OP_OR 1 // use OR operator
  545. // When we allocate a new buffer for the MAPI property array, we will need at most
  546. // as many entries as there were in the input list of LDAP attributes plus a few extras.
  547. // The number of extras is different in each case, but for simplicity (and safety)
  548. // we define NUM_EXTRA_PROPS to be the maximum number of extras that we need to
  549. // allocate space for. Extras are need for:
  550. // PR_ADDRTYPE
  551. // PR_CONTACT_EMAIL_ADDRESSES
  552. // PR_CONTACT_ADDRTYPES
  553. // PR_CONTACT_DEFAULT_ADDRESS_INDEX
  554. // PR_ENTRY_ID
  555. // PR_INSTANCE_KEY
  556. // PR_RECORD_KEY
  557. // PR_WAB_TEMP_CERT_HASH
  558. // PR_WAB_LDAP_RAWCERT
  559. // PR_WAB_LDAP_RAWCERTSMIME
  560. #define NUM_EXTRA_PROPS 10
  561. // Local function prototypes
  562. HRESULT LDAPSearchWithoutContainer(HWND hWnd,
  563. LPLDAPURL lplu,
  564. LPSRestriction lpres,
  565. LPTSTR lpAdvFilter,
  566. BOOL bReturnSinglePropArray,
  567. ULONG ulFlags,
  568. LPRECIPIENT_INFO * lppContentsList,
  569. LPULONG lpulcProps,
  570. LPSPropValue * lppPropArray);
  571. LPTSTR MAPIPropToLDAPAttr(const ULONG ulPropTag);
  572. ULONG LDAPAttrToMAPIProp(const LPTSTR szAttr);
  573. HRESULT ParseSRestriction(LPSRestriction lpRes, LPTSTR FAR * lplpszFilter, LPTSTR * lplpszSimpleFilter, LPTSTR * lplpszNTFilter, DWORD dwPass, BOOL bUnicode);
  574. HRESULT GetLDAPServerName(LPLDAPCONT lpLDAPCont, LPTSTR * lppServer);
  575. BOOL FixPropArray(LPSPropValue lpPropArray, ULONG * lpulcProps);
  576. HRESULT HRFromLDAPError(ULONG ulErr, LDAP* pLDAP, SCODE scDefault);
  577. HRESULT TranslateAttrs(LDAP* pLDAP, LDAPMessage* lpEntry, LPTSTR lpServer, ULONG* pulcProps, LPSPropValue lpPropArray);
  578. ULONG OpenConnection(LPTSTR lpszServer, LDAP** ppLDAP, ULONG* pulTimeout, ULONG* pulMsgID, BOOL* pfSyncBind, ULONG ulLdapType, LPTSTR lpszBindDN, DWORD dwAuthType);
  579. void EncryptDecryptText(LPBYTE lpb, DWORD dwSize);
  580. HRESULT CreateSimpleSearchFilter(LPTSTR FAR * lplpszFilter, LPTSTR FAR * lplpszAltFilter, LPTSTR * lplpszSimpleFilter, LPTSTR lpszInput, DWORD dwPass);
  581. HRESULT GetLDAPSearchBase(LPTSTR FAR * lplpszBase, LPTSTR lpszServer);
  582. INT_PTR CALLBACK DisplayLDAPCancelDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  583. ULONG SearchWithCancel(LDAP** ppLDAP, LPTSTR szBase,ULONG ulScope,LPTSTR szFilter,LPTSTR szNTFilter,
  584. LPTSTR* ppszAttrs,ULONG ulAttrsonly,LDAPMessage** lplpResult,LPTSTR lpszServer,
  585. BOOL fShowAnim,LPTSTR lpszBindDN,DWORD dwAuthType,
  586. BOOL fResolveMultiple,LPADRLIST lpAdrList,LPFlagList lpFlagList,BOOL fUseSynchronousBind, BOOL * lpbIsNTDS, BOOL bUnicode);
  587. BOOL CenterWindow (HWND hwndChild, HWND hwndParent);
  588. BOOL ResolveDoNextSearch(PLDAPSEARCHPARAMS pLDAPSearchParams, HWND hDlg, BOOL bSecondPass);
  589. BOOL ResolveProcessResults(PLDAPSEARCHPARAMS pLDAPSearchParams, HWND hDlg);
  590. BOOL BindProcessResults(PLDAPSEARCHPARAMS pLDAPSearchParams, HWND hDlg, BOOL * lpbNoMoreSearching);
  591. ULONG CountDollars(LPTSTR lpszStr);
  592. void DollarsToLFs(LPTSTR lpszSrcStr, LPTSTR lpszDestStr, DWORD cchDestStr);
  593. BOOL IsSMTPAddress(LPTSTR lpszStr, LPTSTR * lpptszName);
  594. ULONG CountIllegalChars(LPTSTR lpszStr);
  595. void EscapeIllegalChars(LPTSTR lpszSrcStr, LPTSTR lpszDestStr, ULONG cchDestStr);
  596. BOOL bIsSimpleSearch(LPTSTR lpszServer);
  597. BOOL DoSyncLDAPSearch(PLDAPSEARCHPARAMS pLDAPSearchParams);
  598. ULONG CheckErrorResult(PLDAPSEARCHPARAMS pLDALSearchParams, ULONG ulExpectedResult);
  599. #ifdef PAGED_RESULT_SUPPORT
  600. BOOL ProcessLDAPPagedResultCookie(PLDAPSEARCHPARAMS pLDAPSearchParams);
  601. void InitLDAPPagedSearch(BOOL fSynchronous, PLDAPSEARCHPARAMS pLDAPSearchParams, LPTSTR lpFilter);
  602. BOOL bSupportsLDAPPagedResults(PLDAPSEARCHPARAMS pLDAPSearchParams);
  603. #endif //#ifdef PAGED_RESULT_SUPPORT
  604. BOOL bCheckIfNTDS(PLDAPSEARCHPARAMS pLDAPSearchParams);
  605. HRESULT BuildBasicFilter(
  606. LPTSTR FAR* lplpszFilter,
  607. LPTSTR lpszA,
  608. LPTSTR lpszB,
  609. BOOL fStartsWith);
  610. HRESULT BuildOpFilter(
  611. LPTSTR FAR* lplpszFilter,
  612. LPTSTR lpszA,
  613. LPTSTR lpszB,
  614. DWORD dwOp);
  615. //*******************************************************************
  616. //
  617. // FUNCTION: LDAPCONT_GetHierarchyTable
  618. //
  619. // RETURNS: This function is not implemented.
  620. //
  621. // HISTORY:
  622. // 96/07/08 markdu Created.
  623. //
  624. //*******************************************************************
  625. STDMETHODIMP
  626. LDAPCONT_GetHierarchyTable (
  627. LPLDAPCONT lpLDAPCont,
  628. ULONG ulFlags,
  629. LPMAPITABLE * lppTable)
  630. {
  631. LPTSTR lpszMessage = NULL;
  632. ULONG ulLowLevelError = 0;
  633. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  634. DebugTraceResult(LDAPCONT_GetHierarchyTable, hr);
  635. return hr;
  636. }
  637. //*******************************************************************
  638. //
  639. // FUNCTION: LDAPCONT_SetSearchCriteria
  640. //
  641. // RETURNS: This function is not implemented.
  642. //
  643. // HISTORY:
  644. // 96/07/08 markdu Created.
  645. //
  646. //*******************************************************************
  647. STDMETHODIMP
  648. LDAPCONT_SetSearchCriteria(
  649. LPLDAPCONT lpLDAPCont,
  650. LPSRestriction lpRestriction,
  651. LPENTRYLIST lpContainerList,
  652. ULONG ulSearchFlags)
  653. {
  654. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  655. DebugTraceResult(LDAPCONT_SetSearchCriteria, hr);
  656. return hr;
  657. }
  658. //*******************************************************************
  659. //
  660. // FUNCTION: LDAPCONT_GetSearchCriteria
  661. //
  662. // RETURNS: This function is not implemented.
  663. //
  664. // HISTORY:
  665. // 96/07/08 markdu Created.
  666. //
  667. //*******************************************************************
  668. STDMETHODIMP
  669. LDAPCONT_GetSearchCriteria(
  670. LPLDAPCONT lpLDAPCont,
  671. ULONG ulFlags,
  672. LPSRestriction FAR * lppRestriction,
  673. LPENTRYLIST FAR * lppContainerList,
  674. ULONG FAR * lpulSearchState)
  675. {
  676. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  677. DebugTraceResult(LDAPCONT_GetSearchCriteria, hr);
  678. return hr;
  679. }
  680. //*******************************************************************
  681. //
  682. // FUNCTION: LDAPCONT_CreateEntry
  683. //
  684. // RETURNS: This function is not implemented.
  685. //
  686. // HISTORY:
  687. // 96/07/08 markdu Created.
  688. //
  689. //*******************************************************************
  690. STDMETHODIMP
  691. LDAPCONT_CreateEntry(
  692. LPLDAPCONT lpLDAPCont,
  693. ULONG cbEntryID,
  694. LPENTRYID lpEntryID,
  695. ULONG ulCreateFlags,
  696. LPMAPIPROP FAR * lppMAPIPropEntry)
  697. {
  698. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  699. DebugTraceResult(LDAPCONT_CreateEntry, hr);
  700. return hr;
  701. }
  702. //*******************************************************************
  703. //
  704. // FUNCTION: LDAPCONT_CopyEntries
  705. //
  706. // RETURNS: This function is not implemented.
  707. //
  708. // HISTORY:
  709. // 96/07/08 markdu Created.
  710. //
  711. //*******************************************************************
  712. STDMETHODIMP
  713. LDAPCONT_CopyEntries (
  714. LPLDAPCONT lpLDAPCont,
  715. LPENTRYLIST lpEntries,
  716. ULONG_PTR ulUIParam,
  717. LPMAPIPROGRESS lpProgress,
  718. ULONG ulFlags)
  719. {
  720. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  721. DebugTraceResult(LDAPCONT_CopyEntries, hr);
  722. return hr;
  723. }
  724. //*******************************************************************
  725. //
  726. // FUNCTION: LDAPCONT_DeleteEntries
  727. //
  728. // RETURNS: This function is not implemented.
  729. //
  730. // HISTORY:
  731. // 96/07/08 markdu Created.
  732. //
  733. //*******************************************************************
  734. STDMETHODIMP
  735. LDAPCONT_DeleteEntries (
  736. LPLDAPCONT lpLDAPCont,
  737. LPENTRYLIST lpEntries,
  738. ULONG ulFlags)
  739. {
  740. HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  741. DebugTraceResult(LDAPCONT_DeleteEntries, hr);
  742. return hr;
  743. }
  744. //*******************************************************************
  745. //
  746. // FUNCTION: LDAPCONT_GetContentsTable
  747. //
  748. // PURPOSE: Opens a table of the contents of the container
  749. //
  750. // PARAMETERS: lpLDAPCont -> Container object
  751. // ulFlags =
  752. // lppTable -> returned table object
  753. //
  754. // RETURNS: HRESULT
  755. //
  756. // HISTORY:
  757. // 96/07/08 markdu Created.
  758. //
  759. //*******************************************************************
  760. STDMETHODIMP
  761. LDAPCONT_GetContentsTable (
  762. LPLDAPCONT lpLDAPCont,
  763. ULONG ulFlags,
  764. LPMAPITABLE * lppTable)
  765. {
  766. HRESULT hResult = hrSuccess;
  767. LPTABLEDATA lpTableData = NULL;
  768. SCODE sc;
  769. LPTSTR lpszServer = NULL;
  770. #ifdef PARAMETER_VALIDATION
  771. if (IsBadReadPtr(lpLDAPCont, sizeof(LPVOID)))
  772. {
  773. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  774. }
  775. if (lpLDAPCont->lpVtbl != &vtblLDAPCONT)
  776. {
  777. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  778. }
  779. if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE))
  780. {
  781. DebugTraceArg(LDAPCONT_GetContentsTable, TEXT("Unknown flags"));
  782. // return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  783. }
  784. if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE)))
  785. {
  786. DebugTraceArg(LDAPCONT_GetContentsTable, TEXT("Invalid Table parameter"));
  787. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  788. }
  789. #endif // PARAMETER_VALIDATION
  790. if (hResult = GetLDAPServerName(lpLDAPCont,
  791. &lpszServer)) {
  792. DebugTraceResult( TEXT("GetLDAPServerName"), hResult);
  793. goto exit;
  794. }
  795. if (FAILED(sc = CreateTableData(
  796. NULL, // LPCIID
  797. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  798. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  799. MAPIFreeBuffer,
  800. NULL, // lpvReserved,
  801. TBLTYPE_DYNAMIC, // ulTableType,
  802. PR_RECORD_KEY, // ulPropTagIndexCol,
  803. (LPSPropTagArray)&ITableColumns, // LPSPropTagArray lpptaCols,
  804. lpszServer, // server name goes here
  805. sizeof(TCHAR)*(lstrlen(lpszServer) + 1), // size of servername
  806. lpLDAPCont->pmbinOlk,
  807. ulFlags,
  808. &lpTableData)))
  809. { // LPTABLEATA FAR * lplptad
  810. DebugTrace(TEXT("CreateTable failed %x\n"), sc);
  811. hResult = ResultFromScode(sc);
  812. goto exit;
  813. }
  814. if (lpTableData)
  815. {
  816. hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
  817. NULL, // LPSSortOrderSet lpsos,
  818. ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
  819. 0, // ULONG ulReleaseData,
  820. lppTable); // LPMAPITABLE FAR * lplpmt)
  821. // Replace the vtable with our new one that overrides FindRow
  822. (*lppTable)->lpVtbl = (IMAPITableVtbl FAR *) &vtblLDAPVUE;
  823. }
  824. exit:
  825. FreeBufferAndNull(&lpszServer);
  826. // Cleanup table if failure
  827. if (HR_FAILED(hResult))
  828. {
  829. if (lpTableData)
  830. UlRelease(lpTableData);
  831. }
  832. DebugTraceResult(LDAPCONT_GetContentsTable, hResult);
  833. return hResult;
  834. }
  835. //*******************************************************************
  836. //
  837. // FUNCTION: LDAP_OpenMAILUSER
  838. //
  839. // PURPOSE: Opens a LDAP MAILUSER object
  840. //
  841. // PARAMETERS: cbEntryID = size of lpEntryID.
  842. // lpEntryID -> entryid to check.
  843. // The entryid contains all the returned properties on this LDAP
  844. // contact. All we need to do is reverse engineer the decrypted
  845. // props ...
  846. //
  847. // RETURNS: HRESULT
  848. //
  849. // HISTORY:
  850. // 96/07/08 markdu Created.
  851. // 97/09/18 vikramm Revamped totally
  852. //
  853. //*******************************************************************
  854. HRESULT LDAP_OpenMAILUSER(
  855. LPIAB lpIAB,
  856. ULONG cbEntryID,
  857. LPENTRYID lpEntryID,
  858. LPCIID lpInterface,
  859. ULONG ulFlags,
  860. ULONG * lpulObjType,
  861. LPUNKNOWN * lppUnk)
  862. {
  863. HRESULT hr;
  864. HRESULT hrDeferred = hrSuccess;
  865. SCODE sc;
  866. LPMAILUSER lpMailUser = NULL;
  867. LPMAPIPROP lpMapiProp = NULL;
  868. ULONG ulcProps = 0;
  869. LPSPropValue lpPropArray = NULL;
  870. LPTSTR szBase;
  871. ULONG ulResult;
  872. ULONG ulcEntries;
  873. LPTSTR lpServer = NULL;
  874. LPTSTR lpDN = NULL;
  875. LPBYTE lpPropBuf = NULL;
  876. ULONG ulcNumProps = 0;
  877. ULONG cbPropBuf = 0;
  878. ULONG i = 0;
  879. ULONG i2;
  880. LPSPropValue lpPropCert = NULL;
  881. ULONG ulcCert = 0;
  882. #ifdef PARAMETER_VALIDATION
  883. //
  884. // Parameter Validataion
  885. //
  886. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) {
  887. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  888. }
  889. if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
  890. DebugTraceArg(LDAP_OpenMAILUSER, TEXT("Unknown flags"));
  891. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  892. }
  893. if (IsBadWritePtr(lpulObjType, sizeof(ULONG))) {
  894. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  895. }
  896. if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN))) {
  897. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  898. }
  899. #endif
  900. // What interface was requested?
  901. // We've basically got 1 interface here... IMailUser
  902. if (lpInterface != NULL) {
  903. if (! ((! memcmp(lpInterface, &IID_IMailUser, sizeof(IID))) ||
  904. (! memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID))))) {
  905. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  906. goto exit;
  907. }
  908. }
  909. // Make sure the Entry ID is a WAB_LDAP_MAILUSER.
  910. if (WAB_LDAP_MAILUSER != IsWABEntryID( cbEntryID, lpEntryID,
  911. &lpServer, &lpDN, &lpPropBuf,
  912. (LPVOID *) &ulcNumProps, (LPVOID *) &cbPropBuf))
  913. {
  914. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  915. }
  916. // The ulcNumProps entry is overloaded with a flag indicating whether that entry was an NTDS entry or not
  917. // Make sure to clear that flag ...
  918. if(ulcNumProps & LDAP_NTDS_ENTRY)
  919. ulcNumProps &= ~LDAP_NTDS_ENTRY;
  920. ulcProps = ulcNumProps;
  921. hr = HrGetPropArrayFromBuffer( lpPropBuf, cbPropBuf,
  922. ulcNumProps, 3, // add 3 extra props for PR_ENTRYID, RECORD_KEY and INSTANCE_KEY
  923. &lpPropArray);
  924. if(HR_FAILED(hr))
  925. goto exit;
  926. //
  927. // Need to scan these props and see if there is a LDAPCert in there...
  928. // If the LDAP cert exists, need to convert it into a MAPI Cert
  929. //
  930. // Only one of PR_WAB_LDAP_RAWCERT and PR_WAB_LDAP_RAWCERTSMIME should be
  931. // processed. If we find the certsmime then don't do the rawcert version
  932. //
  933. for (i=0, i2=-1;i<ulcNumProps;i++)
  934. {
  935. if( lpPropArray[i].ulPropTag == PR_WAB_LDAP_RAWCERT )
  936. i2 = i;
  937. else if ( lpPropArray[i].ulPropTag == PR_WAB_LDAP_RAWCERTSMIME )
  938. {
  939. if (i2 != -1)
  940. {
  941. DWORD j;
  942. // Clear out PR_WAB_LDAP_RAWCERT as unnecessary
  943. for (j=0; j<lpPropArray[i2].Value.MVbin.cValues; j++) {
  944. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i2].Value.MVbin.lpbin[j].lpb)));
  945. lpPropArray[i2].Value.MVbin.lpbin[j].cb = 0;
  946. }
  947. //
  948. // Free up the RawCert as we dont need it now
  949. //
  950. lpPropArray[i2].ulPropTag = PR_NULL;
  951. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i2].Value.MVbin.lpbin)));
  952. }
  953. // Remember which one is PR_WAB_LDAP_RAWCERTSMIME
  954. i2 = i;
  955. break;
  956. }
  957. }
  958. if (i2 != -1)
  959. {
  960. //
  961. // Find the RAWCERT_COUNT - must be one if there is a raw cert
  962. //
  963. ULONG j = 0, ulRawCount = lpPropArray[i2].Value.MVbin.cValues;
  964. // We are putting the MAPI certs in a seperate MAPIAlloced array
  965. // because 1. LDAPCertToMAPICert expects a MAPIAlloced array
  966. // 2. The lpPropArray is LocalAlloced 3. Mixing them both is a
  967. // recipe for disaster
  968. //
  969. Assert(!lpPropCert);
  970. if(sc = MAPIAllocateBuffer(2 * sizeof(SPropValue), &lpPropCert))
  971. goto NoCert;
  972. lpPropCert[0].ulPropTag = PR_USER_X509_CERTIFICATE;
  973. lpPropCert[0].dwAlignPad = 0;
  974. lpPropCert[0].Value.MVbin.cValues = 0;
  975. lpPropCert[1].ulPropTag = PR_WAB_TEMP_CERT_HASH;
  976. lpPropCert[1].dwAlignPad = 0;
  977. lpPropCert[1].Value.MVbin.cValues = 0;
  978. for(j=0;j<ulRawCount;j++)
  979. {
  980. if(lpPropArray[i2].ulPropTag == PR_WAB_LDAP_RAWCERT)
  981. {
  982. // Put the certs into the prop array.
  983. hr = HrLDAPCertToMAPICert(lpPropCert, 0, 1,
  984. (DWORD)(lpPropArray[i2].Value.MVbin.lpbin[j].cb),
  985. (PBYTE)(lpPropArray[i2].Value.MVbin.lpbin[j].lpb),
  986. 1);
  987. }
  988. else
  989. {
  990. hr = AddPropToMVPBin(lpPropCert, 0,
  991. lpPropArray[i2].Value.MVbin.lpbin[j].lpb,
  992. lpPropArray[i2].Value.MVbin.lpbin[j].cb, TRUE);
  993. }
  994. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i2].Value.MVbin.lpbin[j].lpb)));
  995. lpPropArray[i2].Value.MVbin.lpbin[j].cb = 0;
  996. }
  997. // If no certs were put into PR_USER_X509_CERTIFICATE, then
  998. // set these props to PR_NULL so they will be removed.
  999. if (0 == lpPropCert[0].Value.MVbin.cValues)
  1000. {
  1001. lpPropCert[0].ulPropTag = PR_NULL;
  1002. lpPropCert[1].ulPropTag = PR_NULL;
  1003. }
  1004. else if (0 == lpPropCert[1].Value.MVbin.cValues)
  1005. {
  1006. // It's ok to have no entries in PR_WAB_TEMP_CERT_HASH, but
  1007. // the prop should be set to PR_NULL in that case.
  1008. lpPropCert[1].ulPropTag = PR_NULL;
  1009. }
  1010. //
  1011. // Free up the RawCert as we dont need it now
  1012. //
  1013. lpPropArray[i2].ulPropTag = PR_NULL;
  1014. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i2].Value.MVbin.lpbin)));
  1015. NoCert:
  1016. ;
  1017. }
  1018. // Fill in the entry ID.
  1019. lpPropArray[ulcProps].Value.bin.cb = cbEntryID;
  1020. lpPropArray[ulcProps].Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT, cbEntryID);
  1021. if (!lpPropArray[ulcProps].Value.bin.lpb)
  1022. {
  1023. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1024. goto exit;
  1025. }
  1026. MemCopy(lpPropArray[ulcProps].Value.bin.lpb, lpEntryID, cbEntryID);
  1027. lpPropArray[ulcProps].ulPropTag = PR_ENTRYID;
  1028. lpPropArray[ulcProps].dwAlignPad = 0;
  1029. ulcProps++;
  1030. lpPropArray[ulcProps].ulPropTag = PR_INSTANCE_KEY;
  1031. lpPropArray[ulcProps].Value.bin.cb =
  1032. lpPropArray[ulcProps - 1].Value.bin.cb;
  1033. lpPropArray[ulcProps].Value.bin.lpb =
  1034. lpPropArray[ulcProps - 1].Value.bin.lpb;
  1035. ulcProps++;
  1036. lpPropArray[ulcProps].ulPropTag = PR_RECORD_KEY;
  1037. lpPropArray[ulcProps].Value.bin.cb =
  1038. lpPropArray[ulcProps - 2].Value.bin.cb;
  1039. lpPropArray[ulcProps].Value.bin.lpb =
  1040. lpPropArray[ulcProps - 2].Value.bin.lpb;
  1041. ulcProps++;
  1042. // Create a new MAILUSER object
  1043. hr = HrNewMAILUSER(lpIAB, NULL,
  1044. MAPI_MAILUSER, 0, &lpMapiProp);
  1045. if (HR_FAILED(hr))
  1046. {
  1047. goto exit;
  1048. }
  1049. HrSetMAILUSERAccess((LPMAILUSER)lpMapiProp, MAPI_MODIFY);
  1050. if (ulcProps && lpPropArray)
  1051. {
  1052. // If the entry had properties, set them in our returned object
  1053. if (HR_FAILED(hr = lpMapiProp->lpVtbl->SetProps(lpMapiProp,
  1054. ulcProps, // number of properties to set
  1055. lpPropArray, // property array
  1056. NULL))) // problem array
  1057. {
  1058. goto exit;
  1059. }
  1060. }
  1061. if (lpPropCert)
  1062. {
  1063. // If the entry had properties, set them in our returned object
  1064. if (HR_FAILED(hr = lpMapiProp->lpVtbl->SetProps(lpMapiProp,
  1065. 2, // number of properties to set
  1066. lpPropCert, // property array
  1067. NULL))) // problem array
  1068. {
  1069. goto exit;
  1070. }
  1071. }
  1072. HrSetMAILUSERAccess((LPMAILUSER)lpMapiProp, ulFlags);
  1073. *lpulObjType = MAPI_MAILUSER;
  1074. *lppUnk = (LPUNKNOWN)lpMapiProp;
  1075. /*****
  1076. #ifdef DEBUG
  1077. {
  1078. ULONG i;
  1079. BOOL bFound = FALSE;
  1080. for(i=0;i<ulcProps;i++)
  1081. {
  1082. if(lpPropArray[i].ulPropTag == PR_WAB_LDAP_LABELEDURI)
  1083. {
  1084. DebugPrintTrace(( TEXT("***LABELEDURI: %s\n"),lpPropArray[i].Value.LPSZ));
  1085. bFound = TRUE;
  1086. break;
  1087. }
  1088. }
  1089. if(!bFound)
  1090. {
  1091. // Put in a test URL for testing purposes only
  1092. // Look in the registry for the test URL
  1093. TCHAR szKey[MAX_PATH];
  1094. ULONG cb = CharSizeOf(szKey);
  1095. if(ERROR_SUCCESS == RegQueryValue(HKEY_CURRENT_USER,
  1096. "Software\\Microsoft\\WAB\\TestUrl",
  1097. szKey,
  1098. &cb))
  1099. {
  1100. lpPropArray[ulcProps].ulPropTag = PR_WAB_LDAP_LABELEDURI;
  1101. sc = MAPIAllocateMore(sizeof(TCHAR)*(lstrlen(szKey)+1), lpPropArray,
  1102. (LPVOID *)&(lpPropArray[ulcProps].Value.LPSZ));
  1103. StrCpyN(lpPropArray[ulcProps].Value.LPSZ, szKey, lstrlen(szKey)+1);
  1104. ulcProps++;
  1105. }
  1106. }
  1107. }
  1108. #endif //DEBUG
  1109. *****/
  1110. exit:
  1111. if(ulcProps)
  1112. ulcProps -= 2; // -2 because the last 2 props are fake ones RECORD_KEY and INSTANCE_KEY
  1113. // Free the temp prop value array
  1114. LocalFreePropArray(NULL, ulcProps, &lpPropArray);
  1115. if(lpPropCert)
  1116. MAPIFreeBuffer(lpPropCert);
  1117. // Check if we had a deferred error to return instead of success.
  1118. if (hrSuccess == hr)
  1119. hr = hrDeferred;
  1120. DebugTraceResult(LDAP_OpenMAILUSER, hr);
  1121. return hr;
  1122. }
  1123. //*******************************************************************
  1124. //
  1125. // FUNCTION: LDAPCONT_OpenEntry
  1126. //
  1127. // PURPOSE: Opens an entry. Calls up to IAB's OpenEntry.
  1128. //
  1129. // PARAMETERS: lpLDAPCont -> Container object
  1130. // cbEntryID = size of entryid
  1131. // lpEntryID -> EntryID to open
  1132. // lpInterface -> requested interface or NULL for default.
  1133. // ulFlags =
  1134. // lpulObjType -> returned object type
  1135. // lppUnk -> returned object
  1136. //
  1137. // RETURNS: HRESULT
  1138. //
  1139. // HISTORY:
  1140. // 96/07/08 markdu Created.
  1141. //
  1142. //*******************************************************************
  1143. STDMETHODIMP
  1144. LDAPCONT_OpenEntry(
  1145. LPLDAPCONT lpLDAPCont,
  1146. ULONG cbEntryID,
  1147. LPENTRYID lpEntryID,
  1148. LPCIID lpInterface,
  1149. ULONG ulFlags,
  1150. ULONG * lpulObjType,
  1151. LPUNKNOWN * lppUnk)
  1152. {
  1153. HRESULT hr;
  1154. #ifdef PARAMETER_VALIDATION
  1155. //
  1156. // Parameter Validataion
  1157. //
  1158. // Is this one of mine??
  1159. if (IsBadReadPtr(lpLDAPCont, sizeof(LDAPCONT)))
  1160. {
  1161. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1162. }
  1163. if (lpLDAPCont->lpVtbl != &vtblLDAPCONT)
  1164. {
  1165. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1166. }
  1167. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID)))
  1168. {
  1169. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1170. }
  1171. if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS))
  1172. {
  1173. DebugTraceArg(LDAPCONT_OpenEntry, TEXT("Unknown flags"));
  1174. //return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1175. }
  1176. if (IsBadWritePtr(lpulObjType, sizeof(ULONG)))
  1177. {
  1178. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1179. }
  1180. if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN)))
  1181. {
  1182. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1183. }
  1184. // Check the entryid parameter. It needs to be big enough to hold an entryid.
  1185. // NULL is OK
  1186. /*
  1187. if (lpEntryID)
  1188. {
  1189. if (cbEntryID < sizeof(MAPI_ENTRYID)
  1190. || IsBadReadPtr((LPVOID)lpEntryID, (UINT)cbEntryID))
  1191. {
  1192. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1193. }
  1194. // if (! FValidEntryIDFlags(lpEntryID->abFlags))
  1195. // {
  1196. // DebugTrace(TEXT("LDAPCONT_OpenEntry(): Undefined bits set in EntryID flags\n"));
  1197. // return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1198. // }
  1199. }
  1200. */
  1201. #endif // PARAMETER_VALIDATION
  1202. EnterCriticalSection(&lpLDAPCont->cs);
  1203. // Should just call IAB::OpenEntry()...
  1204. hr = lpLDAPCont->lpIAB->lpVtbl->OpenEntry(lpLDAPCont->lpIAB,
  1205. cbEntryID, lpEntryID,
  1206. lpInterface, ulFlags,
  1207. lpulObjType, lppUnk);
  1208. LeaveCriticalSection(&lpLDAPCont->cs);
  1209. DebugTraceResult(LDAPCONT_OpenEntry, hr);
  1210. return hr;
  1211. }
  1212. //*******************************************************************
  1213. //
  1214. // FUNCTION: LDAPCONT_ResolveNames
  1215. //
  1216. // PURPOSE: Resolve names from this container.
  1217. //
  1218. // PARAMETERS: lpLDAPCont -> Container object
  1219. // lptagColSet -> Set of property tags to get from each
  1220. // resolved match.
  1221. // ulFlags = 0 or MAPI_UNICODE
  1222. // lpAdrList -> [in] set of addresses to resolve, [out] resolved
  1223. // addresses.
  1224. // lpFlagList -> [in/out] resolve flags.
  1225. //
  1226. // RETURNS: HRESULT
  1227. //
  1228. // HISTORY:
  1229. // 96/07/08 markdu Created.
  1230. //
  1231. //*******************************************************************
  1232. STDMETHODIMP
  1233. LDAPCONT_ResolveNames(
  1234. LPLDAPCONT lpLDAPCont,
  1235. LPSPropTagArray lptagaColSet,
  1236. ULONG ulFlags,
  1237. LPADRLIST lpAdrList,
  1238. LPFlagList lpFlagList)
  1239. {
  1240. LPADRENTRY lpAdrEntry;
  1241. SCODE sc;
  1242. ULONG ulAttrIndex;
  1243. ULONG ulEntryIndex;
  1244. LPSPropTagArray lpPropTags;
  1245. LPSPropValue lpPropArray = NULL;
  1246. LPSPropValue lpPropArrayNew = NULL;
  1247. ULONG ulcPropsNew;
  1248. ULONG ulcProps = 0;
  1249. HRESULT hr = hrSuccess;
  1250. LDAP* pLDAP = NULL;
  1251. LDAPMessage* lpResult = NULL;
  1252. LDAPMessage* lpEntry;
  1253. LPTSTR szAttr;
  1254. LPTSTR szDN;
  1255. ULONG ulResult = 0;
  1256. ULONG ulcEntries;
  1257. ULONG ulcAttrs = 0;
  1258. LPTSTR* aszAttrs = NULL;
  1259. LPTSTR lpServer = NULL;
  1260. BOOL fInitDLL = FALSE;
  1261. BOOL fRet = FALSE;
  1262. LPTSTR szFilter = NULL;
  1263. LPTSTR szNameFilter = NULL;
  1264. LPTSTR szEmailFilter = NULL;
  1265. LPTSTR szBase = NULL;
  1266. DWORD dwSzBaseSize = 0;
  1267. DWORD dwSzFilterSize = 0;
  1268. ULONG ulMsgID;
  1269. HWND hDlg;
  1270. MSG msg;
  1271. LDAPSEARCHPARAMS LDAPSearchParams;
  1272. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1273. BOOL bUnicode = (ulFlags & MAPI_UNICODE);
  1274. DebugTrace(TEXT("ldapcont.c::LDAPCONT_ResolveNames()\n"));
  1275. #ifdef PARAMETER_VALIDATION
  1276. if (BAD_STANDARD_OBJ(lpLDAPCont, LDAPCONT_, ResolveNames, lpVtbl))
  1277. {
  1278. // jump table not large enough to support this method
  1279. DebugTraceArg(LDAPCONT_ResolveNames, TEXT("Bad object/vtbl"));
  1280. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1281. }
  1282. // BUGBUG: Should also check lptagColSet, lpAdrList and lpFlagList!
  1283. if (ulFlags & ~MAPI_UNICODE)
  1284. {
  1285. DebugTraceArg(LDAPCONT_ResolveNames, TEXT("Unknown flags used"));
  1286. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1287. }
  1288. #endif // PARAMETER_VALIDATION
  1289. // Load the client functions
  1290. if (! (fInitDLL = InitLDAPClientLib()))
  1291. {
  1292. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  1293. goto exit;
  1294. }
  1295. // open a connection
  1296. hr = GetLDAPServerName(lpLDAPCont, &lpServer);
  1297. if (hrSuccess != hr)
  1298. goto exit;
  1299. Assert(lpServer);
  1300. // Set up the search base now so we only have to do it once.
  1301. hr = GetLDAPSearchBase(&szBase, lpServer);
  1302. if (hrSuccess != hr)
  1303. goto exit;
  1304. // Allocate a new buffer for the attribute array. We will need at most
  1305. // as many entries as there are in the input list of MAPI properties.
  1306. if(lptagaColSet) // use only if requested .. ignore otherwise
  1307. {
  1308. lpPropTags = lptagaColSet;// ? lptagaColSet : (LPSPropTagArray)&ptaResolveDefaults;
  1309. sc = MAPIAllocateBuffer((lpPropTags->cValues + 1) * sizeof(LPTSTR), // +1 as this needs to be NULL terminated array
  1310. (LPVOID *)&aszAttrs);
  1311. if (sc)
  1312. return(ResultFromScode(sc));
  1313. // Cycle through the properties in the array and build a filter to get
  1314. // the equivalent LDAP attributes.
  1315. ulcAttrs = 0;
  1316. for (ulAttrIndex = 0; ulAttrIndex < lpPropTags->cValues; ulAttrIndex++)
  1317. {
  1318. szAttr = (LPTSTR)MAPIPropToLDAPAttr(lpPropTags->aulPropTag[ulAttrIndex]);
  1319. if (szAttr)
  1320. {
  1321. // Add the attribute to the filter
  1322. aszAttrs[ulcAttrs] = szAttr;
  1323. ulcAttrs++;
  1324. }
  1325. }
  1326. aszAttrs[ulcAttrs] = NULL;
  1327. }
  1328. ulResult = SearchWithCancel(&pLDAP, szBase, LDAP_SCOPE_SUBTREE, TEXT(""), NULL,
  1329. aszAttrs ? (LPTSTR*)aszAttrs : (LPTSTR*)g_rgszOpenEntryAttrs,
  1330. 0, &lpResult, lpServer, TRUE, NULL, 0, TRUE, lpAdrList, lpFlagList, FALSE, NULL, bUnicode);
  1331. // Stuff the parameters into the structure to be passed to the dlg proc
  1332. //LDAPSearchParams.ppLDAP = &pLDAP;
  1333. //LDAPSearchParams.szBase = (LPTSTR)szBase;
  1334. //LDAPSearchParams.ulScope = LDAP_SCOPE_SUBTREE;
  1335. //LDAPSearchParams.ulError = LDAP_SUCCESS;
  1336. //LDAPSearchParams.ppszAttrs = aszAttrs ? (LPTSTR*)aszAttrs : (LPTSTR*)g_rgszOpenEntryAttrs; //if specific props requested, ask only for those else ask for everything
  1337. //LDAPSearchParams.ulAttrsonly = 0;
  1338. //LDAPSearchParams.lplpResult = &lpResult;
  1339. //LDAPSearchParams.lpszServer = lpServer;
  1340. //LDAPSearchParams.fShowAnim = TRUE;
  1341. //LDAPSearchParams.fResolveMultiple = TRUE;
  1342. //LDAPSearchParams.lpAdrList = lpAdrList;
  1343. //LDAPSearchParams.lpFlagList = lpFlagList;
  1344. //LDAPSearchParams.fUseSynchronousBind = FALSE;
  1345. //LDAPSearchParams.dwAuthType = 0;
  1346. // Check the return codes. Only report fatal errors that caused the cancellation
  1347. // of the entire search set, not individual errors that occurred on a single search.
  1348. if (LDAP_SUCCESS != ulResult)
  1349. {
  1350. hr = HRFromLDAPError(ulResult, pLDAP, MAPI_E_CALL_FAILED);
  1351. }
  1352. exit:
  1353. FreeBufferAndNull(&lpServer);
  1354. // close the connection
  1355. if (pLDAP)
  1356. {
  1357. gpfnLDAPUnbind(pLDAP);
  1358. pLDAP = NULL;
  1359. }
  1360. // Free the search base memory
  1361. LocalFreeAndNull(&szBase);
  1362. FreeBufferAndNull((LPVOID *)&aszAttrs);
  1363. if (fInitDLL) {
  1364. DeinitLDAPClientLib();
  1365. }
  1366. DebugTraceResult(LDAPCONT_ResolveNames, hr);
  1367. return hr;
  1368. }
  1369. //*******************************************************************
  1370. //
  1371. // FUNCTION: LDAP_Restrict
  1372. //
  1373. // PURPOSE: Uses the supplied restriction to set the contentstable
  1374. // for this LDAP container
  1375. // In reality, we just call find rows and let it do the
  1376. // LDAP search to fill this table ..
  1377. // We only did this because Outlook needed it to be consistent
  1378. // and to do PR_ANR searches. If the search is not a PR_ANR search,
  1379. // we will default to the standard VUE_Restrict Method ..
  1380. //
  1381. // PARAMETERS: lpvue - table view object
  1382. // lpres - restriction to convert into LDAP search
  1383. // ulFlags -
  1384. //
  1385. // RETURNS: HRESULT
  1386. //
  1387. // HISTORY:
  1388. // 97/04/04 vikramm Created.
  1389. //
  1390. //*******************************************************************
  1391. STDMETHODIMP
  1392. LDAPVUE_Restrict(
  1393. LPVUE lpvue,
  1394. LPSRestriction lpres,
  1395. ULONG ulFlags )
  1396. {
  1397. HRESULT hr = E_FAIL;
  1398. SRestriction sRes = {0}, sPropRes = {0};
  1399. SCODE sc;
  1400. LPTSTR lpsz = NULL;
  1401. BOOL bUnicode = TRUE;
  1402. SPropValue SProp = {0};
  1403. #if !defined(NO_VALIDATION)
  1404. VALIDATE_OBJ(lpvue,LDAPVUE_,Restrict,lpVtbl);
  1405. Validate_IMAPITable_Restrict(
  1406. lpvue,
  1407. lpres,
  1408. ulFlags );
  1409. #endif
  1410. if( lpres->res.resProperty.ulPropTag != PR_ANR_A &&
  1411. lpres->res.resProperty.ulPropTag != PR_ANR_W)
  1412. {
  1413. // dont know what this is, so call the default method ..
  1414. return HrVUERestrict(lpvue,
  1415. lpres,
  1416. ulFlags);
  1417. }
  1418. bUnicode = (PROP_TYPE(lpres->res.resProperty.ulPropTag)==PT_UNICODE);
  1419. LockObj(lpvue->lptadParent);
  1420. // Most probably this is an outlook search .. just search and see
  1421. // what we can get to fill this table by calling FindRows
  1422. lpsz = bUnicode ? lpres->res.resProperty.lpProp->Value.lpszW :
  1423. ConvertAtoW(lpres->res.resProperty.lpProp->Value.lpszA);
  1424. // Change the Restriction so FindRows can understand it ..
  1425. if( !lpsz || !lstrlen(lpsz) )
  1426. {
  1427. hr = MAPI_E_INVALID_PARAMETER;
  1428. goto out;
  1429. }
  1430. sRes.rt = RES_AND;
  1431. sRes.res.resAnd.cRes = 1;
  1432. sRes.res.resAnd.lpRes = &sPropRes;
  1433. sPropRes.rt = RES_PROPERTY;
  1434. sPropRes.res.resProperty.relop = RELOP_EQ;
  1435. sPropRes.res.resProperty.lpProp = &SProp;
  1436. if(bUnicode)
  1437. {
  1438. SProp.ulPropTag = sPropRes.res.resProperty.ulPropTag = PR_DISPLAY_NAME_W;
  1439. SProp.Value.lpszW = lpres->res.resProperty.lpProp->Value.lpszW;
  1440. }
  1441. else
  1442. {
  1443. SProp.ulPropTag = sPropRes.res.resProperty.ulPropTag = PR_DISPLAY_NAME_A;
  1444. SProp.Value.lpszA = lpres->res.resProperty.lpProp->Value.lpszA;
  1445. }
  1446. /*
  1447. {
  1448. // create a new restriction based on the PR_ANR displayname
  1449. // passed on to us
  1450. //
  1451. LDAP_SEARCH_PARAMS LDAPsp ={0};
  1452. if(lstrlen(lpsz) < MAX_UI_STR)
  1453. StrCpyN(LDAPsp.szData[ldspDisplayName], lpsz);
  1454. else
  1455. {
  1456. CopyMemory(LDAPsp.szData[ldspDisplayName],lpsz,sizeof(TCHAR)*(MAX_UI_STR-2));
  1457. LDAPsp.szData[ldspDisplayName][MAX_UI_STR-1]='\0';
  1458. }
  1459. hr = HrGetLDAPSearchRestriction(LDAPsp, &sRes);
  1460. }
  1461. */
  1462. hr = lpvue->lpVtbl->FindRow(lpvue,
  1463. &sRes,
  1464. BOOKMARK_BEGINNING,
  1465. 0);
  1466. // Clear out cached rows from before, if any
  1467. {
  1468. /*
  1469. ULONG cDeleted = 0;
  1470. hr = lpvue->lptadParent->lpVtbl->HrDeleteRows(lpvue->lptadParent,
  1471. TAD_ALL_ROWS, // ulFlags
  1472. NULL,
  1473. &cDeleted);
  1474. if (hrSuccess != hr)
  1475. goto out;
  1476. // Also need to release any current views on the object or caller will get
  1477. // hosed ...
  1478. // Replace the row set in the view
  1479. COFree(lpvue, lpvue->parglprows);
  1480. lpvue->parglprows = NULL;
  1481. lpvue->bkEnd.uliRow = 0;
  1482. */
  1483. }
  1484. // Now that we've filled up the table with more entries, set the ANR restriction on it
  1485. hr = HrVUERestrict( lpvue,
  1486. lpres,
  1487. ulFlags);
  1488. out:
  1489. sc = GetScode(hr);
  1490. /*
  1491. if(sRes.res.resAnd.lpRes)
  1492. MAPIFreeBuffer(sRes.res.resAnd.lpRes);
  1493. */
  1494. UnlockObj(lpvue->lptadParent);
  1495. if(!bUnicode)
  1496. LocalFreeAndNull(&lpsz);
  1497. return HrSetLastErrorIds(lpvue, sc, 0);
  1498. }
  1499. //*******************************************************************
  1500. //
  1501. // FUNCTION: HrLDAPEntryToMAPIEntry
  1502. //
  1503. // PURPOSE: Converts an LDAP entry into a MAPI entry
  1504. //
  1505. // PARAMETERS:
  1506. //
  1507. // RETURNS: HRESULT
  1508. //
  1509. //*******************************************************************
  1510. HRESULT HrLDAPEntryToMAPIEntry(LDAP * pLDAP,
  1511. LDAPMessage* lpEntry,
  1512. LPTSTR lpEIDData1, // for creating entryid
  1513. ULONG ulcNumAttrs,
  1514. BOOL bIsNTDSEntry,
  1515. ULONG * lpulcProps,
  1516. LPSPropValue * lppPropArray)
  1517. {
  1518. LPTSTR szDN;
  1519. SCODE sc;
  1520. HRESULT hr = E_FAIL;
  1521. LPSPropValue lpPropArray = NULL;
  1522. ULONG ulcProps = 0;
  1523. LPBYTE lpBuf = NULL;
  1524. ULONG cbBuf = 0;
  1525. LDAPSERVERPARAMS Params = {0};
  1526. LPTSTR lpServer = NULL;
  1527. // initialize search control parameters
  1528. GetLDAPServerParams(lpEIDData1, &Params);
  1529. if(!Params.lpszName || !lstrlen(Params.lpszName))
  1530. {
  1531. DWORD cchSize = (lstrlen(lpEIDData1)+1);
  1532. Params.lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  1533. if(!Params.lpszName)
  1534. goto exit;
  1535. StrCpyN(Params.lpszName, lpEIDData1, cchSize);
  1536. }
  1537. lpServer = Params.lpszName;
  1538. if(!ulcNumAttrs)
  1539. ulcNumAttrs = NUM_ATTRMAP_ENTRIES;
  1540. else
  1541. ulcNumAttrs += 2; //add space for pr_instance_key and pr_record_key
  1542. // Allocate a new buffer for the MAPI property array.
  1543. sc = MAPIAllocateBuffer((ulcNumAttrs+ NUM_EXTRA_PROPS) * sizeof(SPropValue),
  1544. (LPVOID *)&lpPropArray);
  1545. if (sc)
  1546. {
  1547. hr = ResultFromScode(sc);
  1548. goto exit;
  1549. }
  1550. // Cycle through the attributes and store them.
  1551. hr = TranslateAttrs(pLDAP, lpEntry, lpServer, &ulcProps, lpPropArray);
  1552. if (hrSuccess != hr)
  1553. {
  1554. goto exit;
  1555. }
  1556. // Fix up the PR_DISPLAY_NAME
  1557. // MSN's ldap server returns cn = email address.
  1558. // If this is the case, set it to GIVEN_NAME + SURNAME.
  1559. // Exchange DS wont return a display name, just returns a
  1560. // sn + givenName. In that case build a display name
  1561. FixPropArray(lpPropArray, &ulcProps);
  1562. // Generate an Entry ID using the DN of the entry.
  1563. szDN = gpfnLDAPGetDN(pLDAP, lpEntry);
  1564. if (NULL == szDN)
  1565. {
  1566. hr = HRFromLDAPError(LDAP_ERROR, pLDAP, MAPI_E_CALL_FAILED);
  1567. goto exit;
  1568. }
  1569. //
  1570. // Convert the lpPropArray, so far, into a flat buffer which we shall
  1571. // cache inside the LDAP entryid .. Important to note that this
  1572. // cached prop array does not have entryid information in it ...
  1573. // The entryid information will need to be tagged on at such time when
  1574. // we extract the prop array from the flat buffer in LDAP_OpenEntry
  1575. //
  1576. hr = HrGetBufferFromPropArray( ulcProps,
  1577. lpPropArray,
  1578. &cbBuf,
  1579. &lpBuf);
  1580. if (hrSuccess != hr)
  1581. {
  1582. goto exit;
  1583. }
  1584. hr = CreateWABEntryID(WAB_LDAP_MAILUSER,
  1585. (LPTSTR)lpEIDData1,// lpvue->lpvDataSource, // server name
  1586. (LPVOID)szDN,
  1587. (LPVOID)lpBuf,
  1588. (bIsNTDSEntry ? (ulcProps|LDAP_NTDS_ENTRY) : ulcProps),
  1589. cbBuf,
  1590. (LPVOID)lpPropArray,
  1591. (LPULONG) (&lpPropArray[ulcProps].Value.bin.cb),
  1592. (LPENTRYID *)&lpPropArray[ulcProps].Value.bin.lpb);
  1593. // Free the DN memory now that it is copied.
  1594. gpfnLDAPMemFree(szDN);
  1595. if (hrSuccess != hr)
  1596. {
  1597. goto exit;
  1598. }
  1599. lpPropArray[ulcProps].ulPropTag = PR_ENTRYID;
  1600. lpPropArray[ulcProps].dwAlignPad = 0;
  1601. ulcProps++;
  1602. // Make certain we have proper indicies.
  1603. // For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
  1604. lpPropArray[ulcProps].ulPropTag = PR_INSTANCE_KEY;
  1605. lpPropArray[ulcProps].Value.bin.cb =
  1606. lpPropArray[ulcProps - 1].Value.bin.cb;
  1607. lpPropArray[ulcProps].Value.bin.lpb =
  1608. lpPropArray[ulcProps - 1].Value.bin.lpb;
  1609. ulcProps++;
  1610. lpPropArray[ulcProps].ulPropTag = PR_RECORD_KEY;
  1611. lpPropArray[ulcProps].Value.bin.cb =
  1612. lpPropArray[ulcProps - 2].Value.bin.cb;
  1613. lpPropArray[ulcProps].Value.bin.lpb =
  1614. lpPropArray[ulcProps - 2].Value.bin.lpb;
  1615. ulcProps++;
  1616. *lpulcProps = ulcProps;
  1617. *lppPropArray = lpPropArray;
  1618. exit:
  1619. if(HR_FAILED(hr) && lpPropArray)
  1620. MAPIFreeBuffer(lpPropArray);
  1621. if(lpBuf)
  1622. LocalFreeAndNull(&lpBuf);
  1623. FreeLDAPServerParams(Params);
  1624. return hr;
  1625. }
  1626. //*******************************************************************
  1627. //
  1628. // FUNCTION: LDAP_FindRow
  1629. //
  1630. // PURPOSE: Search LDAP server, and add rows to the table object
  1631. // for server entries that match the restriction.
  1632. //
  1633. // PARAMETERS: lpvue - table view object
  1634. // lpres - restriction to convert into LDAP search
  1635. // bkOrigin - current bookmark
  1636. // ulFlags -
  1637. //
  1638. // If we are doing an advanced search, we will hack through an advanced
  1639. // filter instead of lpres and pass a flag of LDAP_USE_ADVANCED_FILTER
  1640. //
  1641. // RETURNS: HRESULT
  1642. //
  1643. // HISTORY:
  1644. // 96/07/10 markdu Created.
  1645. //
  1646. //*******************************************************************
  1647. STDMETHODIMP
  1648. LDAPVUE_FindRow(
  1649. LPVUE lpvue,
  1650. LPSRestriction lpSRes,
  1651. BOOKMARK bkOrigin,
  1652. ULONG ulFlags )
  1653. {
  1654. SCODE sc;
  1655. HRESULT hr;
  1656. HRESULT hrDeferred = hrSuccess;
  1657. LPMAILUSER lpMailUser = NULL;
  1658. LPMAPIPROP lpMapiProp = NULL;
  1659. ULONG ulcProps = 0;
  1660. LPSPropValue lpPropArray = NULL;
  1661. LPSRowSet lpSRowSet = NULL;
  1662. LDAPMessage* lpResult = NULL;
  1663. LDAPMessage* lpEntry;
  1664. LDAP* pLDAP = NULL;
  1665. LPTSTR szDN;
  1666. ULONG ulResult;
  1667. ULONG ulcEntries;
  1668. ULONG ulIndex = 0;
  1669. LPTSTR szFilter = NULL;
  1670. LPTSTR szNTFilter = NULL;
  1671. LPTSTR szSimpleFilter = NULL;
  1672. LPTSTR szBase = NULL;
  1673. BOOL fInitDLL = FALSE;
  1674. BOOL fSimpleSearch = FALSE;
  1675. LPTSTR lpAdvFilter = NULL;
  1676. LPSRestriction lpres = NULL;
  1677. BOOL bIsNTDSEntry = FALSE;
  1678. BOOL bUnicode = lpvue->lptadParent->bMAPIUnicodeTable;
  1679. if (ulFlags & LDAP_USE_ADVANCED_FILTER)
  1680. {
  1681. lpAdvFilter = (LPTSTR) lpSRes;
  1682. ulFlags = ulFlags & ~LDAP_USE_ADVANCED_FILTER;
  1683. }
  1684. else
  1685. {
  1686. lpres = lpSRes;
  1687. }
  1688. #if !defined(NO_VALIDATION)
  1689. VALIDATE_OBJ(lpvue,LDAPVUE_,FindRow,lpVtbl);
  1690. /*
  1691. Validate_IMAPITable_FindRow(
  1692. lpvue,
  1693. lpres,
  1694. bkOrigin,
  1695. ulFlags );
  1696. */
  1697. if ( FBadBookmark(lpvue,bkOrigin) )
  1698. {
  1699. DebugTrace(TEXT("LDAP_FindRow() - Bad parameter(s) passed\n") );
  1700. return HrSetLastErrorIds(lpvue, MAPI_E_INVALID_PARAMETER, 0);
  1701. }
  1702. #endif
  1703. LockObj(lpvue->lptadParent);
  1704. if(lpres)
  1705. {
  1706. // Convert the SRestriction into filters for ldap_search
  1707. hr = ParseSRestriction(lpres, &szFilter, &szSimpleFilter, &szNTFilter, FIRST_PASS, bUnicode);
  1708. if (hrSuccess != hr)
  1709. goto exit;
  1710. }
  1711. else
  1712. szFilter = lpAdvFilter;
  1713. // Set up the search base now so we only have to do it once.
  1714. hr = GetLDAPSearchBase(&szBase, (LPTSTR)lpvue->lpvDataSource);
  1715. if (hrSuccess != hr)
  1716. goto exit;
  1717. fSimpleSearch = bIsSimpleSearch((LPTSTR)lpvue->lpvDataSource);
  1718. if(fSimpleSearch && lpAdvFilter)
  1719. szSimpleFilter = lpAdvFilter;
  1720. // Load the client functions
  1721. if (! (fInitDLL = InitLDAPClientLib()))
  1722. {
  1723. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  1724. goto exit;
  1725. }
  1726. // Read the matching entries
  1727. ulResult = SearchWithCancel(&pLDAP,
  1728. (LPTSTR)szBase, LDAP_SCOPE_SUBTREE,
  1729. (LPTSTR) (fSimpleSearch ? szSimpleFilter : szFilter),
  1730. (LPTSTR)szNTFilter,
  1731. (LPTSTR*)g_rgszOpenEntryAttrs, // Get all the attributes the first time only //g_rgszFindRowAttrs,
  1732. 0, &lpResult, (LPTSTR)lpvue->lpvDataSource,
  1733. FALSE, NULL, 0,
  1734. FALSE, NULL, NULL, FALSE, &bIsNTDSEntry,
  1735. TRUE); //unicode by default
  1736. // BUG 34201 If the search was unsuccessful because of an unknown attribute
  1737. // type, try a second search that does not use givenName. This fixes searches
  1738. // on ldap.itd.umich.edu, which do not recognize givenName.
  1739. if ( lpres &&
  1740. (LDAP_UNDEFINED_TYPE == ulResult || LDAP_UNWILLING_TO_PERFORM == ulResult) )
  1741. {
  1742. // close the connection since we will open a new one
  1743. if (pLDAP)
  1744. {
  1745. gpfnLDAPUnbind(pLDAP);
  1746. pLDAP = NULL;
  1747. }
  1748. if (!bIsNTDSEntry)
  1749. {
  1750. // Free the search filter memory
  1751. LocalFreeAndNull(&szFilter);
  1752. LocalFreeAndNull(&szNTFilter);
  1753. LocalFreeAndNull(&szSimpleFilter);
  1754. DebugTrace(TEXT("First try failed, trying umich semantics...\n"));
  1755. hr = ParseSRestriction(lpres, &szFilter, &szSimpleFilter, &szNTFilter, UMICH_PASS, bUnicode);
  1756. }
  1757. else
  1758. hr = hrSuccess;
  1759. if (hrSuccess == hr)
  1760. {
  1761. ulResult = SearchWithCancel(&pLDAP,
  1762. (LPTSTR)szBase, LDAP_SCOPE_SUBTREE,
  1763. (LPTSTR)(fSimpleSearch ? szSimpleFilter : szFilter),
  1764. NULL,
  1765. (LPTSTR*)g_rgszOpenEntryAttrs, //g_rgszFindRowAttrs,
  1766. 0, &lpResult, (LPTSTR)lpvue->lpvDataSource,
  1767. FALSE, NULL, 0,
  1768. FALSE, NULL, NULL, FALSE, &bIsNTDSEntry,
  1769. TRUE); //unicode by default?
  1770. }
  1771. }
  1772. if (LDAP_SUCCESS != ulResult)
  1773. {
  1774. DebugTrace(TEXT("LDAP_FindRow: ldap_search returned %d.\n"), ulResult);
  1775. hr = HRFromLDAPError(ulResult, pLDAP, MAPI_E_NOT_FOUND);
  1776. // See if the result was the special value that tells us there were more
  1777. // entries than could be returned. If so, we need to check if we got
  1778. // some of the entries or none of the entries.
  1779. if ((ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE) == hr) &&
  1780. (ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult)))
  1781. {
  1782. // We got some results back. Return MAPI_W_PARTIAL_COMPLETION
  1783. // instead of success.
  1784. hrDeferred = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
  1785. hr = hrSuccess;
  1786. }
  1787. else
  1788. {
  1789. goto exit;
  1790. }
  1791. }
  1792. else
  1793. ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult); // Count the entries.
  1794. if (0 == ulcEntries)
  1795. {
  1796. // 96/08/08 markdu BUG 35481 No error and no results means "not found"
  1797. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  1798. goto exit;
  1799. }
  1800. // Allocate an SRowSet to hold the entries.
  1801. sc = MAPIAllocateBuffer(sizeof(SRowSet) + ulcEntries * sizeof(SRow), (LPVOID *)&lpSRowSet);
  1802. if (sc)
  1803. {
  1804. DebugTrace(TEXT("Allocation of SRowSet failed\n"));
  1805. hr = ResultFromScode(sc);
  1806. goto exit;
  1807. }
  1808. // Set the number of rows to zero in case we encounter an error and
  1809. // then try to free the row set before any rows were added.
  1810. lpSRowSet->cRows = 0;
  1811. // get the first entry in the search result
  1812. lpEntry = gpfnLDAPFirstEntry(pLDAP, lpResult);
  1813. if (NULL == lpEntry)
  1814. {
  1815. DebugTrace(TEXT("LDAP_FindRow: No entry found for %s.\n"), szFilter);
  1816. hr = HRFromLDAPError(LDAP_ERROR, pLDAP, MAPI_E_CORRUPT_DATA);
  1817. if (hrSuccess == hr)
  1818. {
  1819. // No error occurred according to LDAP, which in theory means that there
  1820. // were no more entries. However, this should not happen, so return error.
  1821. hr = ResultFromScode(MAPI_E_CORRUPT_DATA);
  1822. }
  1823. goto exit;
  1824. }
  1825. while (lpEntry)
  1826. {
  1827. hr = HrLDAPEntryToMAPIEntry( pLDAP, lpEntry,
  1828. (LPTSTR) lpvue->lpvDataSource,
  1829. 0, // standard number of attributes
  1830. bIsNTDSEntry,
  1831. &ulcProps,
  1832. &lpPropArray);
  1833. if (hrSuccess != hr)
  1834. {
  1835. continue;
  1836. }
  1837. if(!bUnicode) // convert native UNICODE to ANSI if we need to ...
  1838. {
  1839. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArray, ulcProps, 0))
  1840. goto exit;
  1841. }
  1842. // Put it in the RowSet
  1843. lpSRowSet->aRow[ulIndex].cValues = ulcProps; // number of properties
  1844. lpSRowSet->aRow[ulIndex].lpProps = lpPropArray; // LPSPropValue
  1845. // Get the next entry.
  1846. lpEntry = gpfnLDAPNextEntry(pLDAP, lpEntry);
  1847. ulIndex++;
  1848. }
  1849. // Free the search results memory
  1850. gpfnLDAPMsgFree(lpResult);
  1851. lpResult = NULL;
  1852. // Add the rows to the table
  1853. lpSRowSet->cRows = ulIndex;
  1854. hr = lpvue->lptadParent->lpVtbl->HrModifyRows(lpvue->lptadParent, 0, lpSRowSet);
  1855. if (hrSuccess != hr)
  1856. goto exit;
  1857. // Always reset the bookmark to the first row. This is done because the
  1858. // restriction passed in may not match any row in the table since the
  1859. // attributes returned from the LDAP search do not always include the
  1860. // attributes used to perform the search (eg country, organization)
  1861. lpvue->bkCurrent.uliRow = 0;
  1862. exit:
  1863. // free the search results memory
  1864. if (lpResult)
  1865. {
  1866. gpfnLDAPMsgFree(lpResult);
  1867. lpResult = NULL;
  1868. }
  1869. // close the connection
  1870. if (pLDAP)
  1871. {
  1872. gpfnLDAPUnbind(pLDAP);
  1873. pLDAP = NULL;
  1874. }
  1875. // Free the search filter memory
  1876. if(lpres)
  1877. {
  1878. LocalFreeAndNull(&szFilter);
  1879. LocalFreeAndNull(&szNTFilter);
  1880. LocalFreeAndNull(&szSimpleFilter);
  1881. }
  1882. LocalFreeAndNull(&szBase);
  1883. // Free the row set memory
  1884. FreeProws(lpSRowSet);
  1885. if (fInitDLL)
  1886. DeinitLDAPClientLib();
  1887. UnlockObj(lpvue->lptadParent);
  1888. // Check if we had a deferred error to return instead of success.
  1889. if (hrSuccess == hr)
  1890. {
  1891. hr = hrDeferred;
  1892. }
  1893. DebugTraceResult(LDAPCONT_ResolveNames, hr);
  1894. return hr;
  1895. }
  1896. //*******************************************************************
  1897. //
  1898. // FUNCTION: InitLDAPClientLib
  1899. //
  1900. // PURPOSE: Load the LDAP client libray and get the proc addrs.
  1901. //
  1902. // PARAMETERS: None.
  1903. //
  1904. // RETURNS: TRUE if successful, FALSE otherwise.
  1905. //
  1906. // HISTORY:
  1907. // 96/07/05 markdu Created.
  1908. //
  1909. //*******************************************************************
  1910. BOOL InitLDAPClientLib(void)
  1911. {
  1912. #ifdef WIN16
  1913. return FALSE;
  1914. #else // Disable until ldap16.dll is available.
  1915. // See if we already initialized.
  1916. if (NULL == ghLDAPDLLInst)
  1917. {
  1918. Assert(ulLDAPDLLRefCount == 0);
  1919. // open LDAP client library
  1920. // BUGBUG: Requires dll to be in system directory (neilbren)
  1921. ghLDAPDLLInst = LoadLibrary(cszLDAPClientDLL);
  1922. if (!ghLDAPDLLInst)
  1923. {
  1924. DebugTrace(TEXT("InitLDAPClientLib: Failed to LoadLibrary WLDAP32.DLL.\n"));
  1925. return FALSE;
  1926. }
  1927. // cycle through the API table and get proc addresses for all the APIs we
  1928. // need
  1929. if (!GetApiProcAddresses(ghLDAPDLLInst,LDAPAPIList,NUM_LDAPAPI_PROCS))
  1930. {
  1931. DebugTrace(TEXT("InitLDAPClientLib: Failed to load LDAP API.\n"));
  1932. // Unload the library we just loaded.
  1933. if (ghLDAPDLLInst)
  1934. {
  1935. FreeLibrary(ghLDAPDLLInst);
  1936. ghLDAPDLLInst = NULL;
  1937. }
  1938. return FALSE;
  1939. }
  1940. // Add an additional AddRef here so that this library stays loaded once
  1941. // it is loaded. This improves performance.
  1942. // The IAB_Neuter function will take care of calling the matching DeInit()
  1943. ulLDAPDLLRefCount++;
  1944. }
  1945. ulLDAPDLLRefCount++;
  1946. return TRUE;
  1947. #endif
  1948. }
  1949. //*******************************************************************
  1950. //
  1951. // FUNCTION: DeinitLDAPClientLib
  1952. //
  1953. // PURPOSE: decrement refcount on LDAP CLient library and
  1954. // release if 0.
  1955. //
  1956. // PARAMETERS: None.
  1957. //
  1958. // RETURNS: current refcount
  1959. //
  1960. // HISTORY:
  1961. // 96/07/12 BruceK Created.
  1962. //
  1963. //*******************************************************************
  1964. ULONG DeinitLDAPClientLib(void)
  1965. {
  1966. if (0 != ulLDAPDLLRefCount)
  1967. {
  1968. if (-- ulLDAPDLLRefCount == 0)
  1969. {
  1970. UINT nIndex;
  1971. // No clients using the LDAPCLI library. Release it.
  1972. if (ghLDAPDLLInst)
  1973. {
  1974. FreeLibrary(ghLDAPDLLInst);
  1975. ghLDAPDLLInst = NULL;
  1976. }
  1977. // cycle through the API table and NULL proc addresses for all the APIs
  1978. for (nIndex = 0; nIndex < NUM_LDAPAPI_PROCS; nIndex++)
  1979. {
  1980. *LDAPAPIList[nIndex].ppFcnPtr = NULL;
  1981. }
  1982. }
  1983. }
  1984. return(ulLDAPDLLRefCount);
  1985. }
  1986. //*******************************************************************
  1987. //
  1988. // FUNCTION: GetApiProcAddresses
  1989. //
  1990. // PURPOSE: Gets proc addresses for a table of functions
  1991. //
  1992. // PARAMETERS: hModDLL - dll from which to load the procs
  1993. // pApiProcList - array of proc names and pointers
  1994. // nApiProcs - number of procs in array
  1995. //
  1996. // RETURNS: TRUE if successful, FALSE if unable to retrieve
  1997. // any proc address in table
  1998. //
  1999. // HISTORY:
  2000. // 96/07/08 markdu Created.
  2001. //
  2002. //*******************************************************************
  2003. BOOL GetApiProcAddresses(
  2004. HMODULE hModDLL,
  2005. APIFCN * pApiProcList,
  2006. UINT nApiProcs)
  2007. {
  2008. UINT nIndex;
  2009. DebugTrace(TEXT("ldapcont.c::GetApiProcAddresses()\n"));
  2010. // cycle through the API table and get proc addresses for all the APIs we
  2011. // need
  2012. for (nIndex = 0;nIndex < nApiProcs;nIndex++)
  2013. {
  2014. if (!(*pApiProcList[nIndex].ppFcnPtr = (PVOID) GetProcAddress(hModDLL,
  2015. pApiProcList[nIndex].pszName)))
  2016. {
  2017. DebugTrace(TEXT("Unable to get address of function %s\n"),
  2018. pApiProcList[nIndex].pszName);
  2019. for (nIndex = 0;nIndex<nApiProcs;nIndex++)
  2020. *pApiProcList[nIndex].ppFcnPtr = NULL;
  2021. return FALSE;
  2022. }
  2023. }
  2024. return TRUE;
  2025. }
  2026. //*******************************************************************
  2027. //
  2028. // FUNCTION: MAPIPropToLDAPAttr
  2029. //
  2030. // PURPOSE: Get LDAP attribute equivalent to MAPI property.
  2031. //
  2032. // PARAMETERS: ulPropTag - MAPI property to map to LDAP attribute
  2033. //
  2034. // RETURNS: Pointer to string with LDAP attribute name if found,
  2035. // NULL otherwise.
  2036. //
  2037. // HISTORY:
  2038. // 96/06/28 markdu Created.
  2039. //
  2040. //*******************************************************************
  2041. LPTSTR MAPIPropToLDAPAttr(
  2042. const ULONG ulPropTag)
  2043. {
  2044. ULONG ulIndex;
  2045. for (ulIndex=0;ulIndex<NUM_ATTRMAP_ENTRIES;ulIndex++)
  2046. {
  2047. if (ulPropTag == gAttrMap[ulIndex].ulPropTag)
  2048. {
  2049. return (LPTSTR)gAttrMap[ulIndex].pszAttr;
  2050. }
  2051. }
  2052. // PR_WAB_CONF_SERVERS is not a constant but a named prop tag - hence its not
  2053. // part of the array above
  2054. if(ulPropTag == PR_WAB_CONF_SERVERS)
  2055. return (LPTSTR)cszAttr_conferenceInformation;
  2056. if(ulPropTag == PR_WAB_MANAGER)
  2057. return (LPTSTR)cszAttr_Manager;
  2058. if(ulPropTag == PR_WAB_REPORTS)
  2059. return (LPTSTR)cszAttr_Reports;
  2060. if(ulPropTag == PR_WAB_IPPHONE)
  2061. return (LPTSTR)cszAttr_IPPhone;
  2062. // property not found
  2063. return NULL;
  2064. }
  2065. //*******************************************************************
  2066. //
  2067. // FUNCTION: LDAPAttrToMAPIProp
  2068. //
  2069. // PURPOSE: Get MAPI property equivalent to LDAP attribute.
  2070. //
  2071. // PARAMETERS: szAttr - points to LDAP attribute name
  2072. //
  2073. // RETURNS: MAPI property tag if LDAP attribute name is found,
  2074. // PR_NULL otherwise.
  2075. //
  2076. // HISTORY:
  2077. // 96/06/28 markdu Created.
  2078. //
  2079. //*******************************************************************
  2080. ULONG LDAPAttrToMAPIProp(
  2081. const LPTSTR szAttr)
  2082. {
  2083. ULONG ulIndex;
  2084. for (ulIndex=0;ulIndex<NUM_ATTRMAP_ENTRIES;ulIndex++)
  2085. {
  2086. if (!lstrcmpi(szAttr, gAttrMap[ulIndex].pszAttr))
  2087. {
  2088. return gAttrMap[ulIndex].ulPropTag;
  2089. }
  2090. }
  2091. // PR_WAB_CONF_SERVERS is not a constant but a named prop tag - hence its not
  2092. // part of the array above
  2093. if(!lstrcmpi(szAttr, cszAttr_conferenceInformation))
  2094. return PR_WAB_CONF_SERVERS;
  2095. if(!lstrcmpi(szAttr, cszAttr_Manager))
  2096. return PR_WAB_MANAGER;
  2097. if(!lstrcmpi(szAttr, cszAttr_Reports))
  2098. return PR_WAB_REPORTS;
  2099. if(!lstrcmpi(szAttr, cszAttr_IPPhone))
  2100. return PR_WAB_IPPHONE;
  2101. // attribute not found
  2102. return PR_NULL;
  2103. }
  2104. //*******************************************************************
  2105. //
  2106. // FUNCTION: ParseSRestriction
  2107. //
  2108. // PURPOSE: Generate Search Base and Search Filter strings for
  2109. // LDAP search from MAPI SRestriction structure.
  2110. //
  2111. // PARAMETERS: lpRes - MAPI SRestriction structure to "parse"
  2112. // receive the search base string.
  2113. // lplpszFilter - receives buffer to hold search filter string.
  2114. // dwPass - which pass through this function (first pass
  2115. // is zero (0)). This allows
  2116. // reuse of this function with different behaviour each
  2117. // time (for example, to do a backup search with a
  2118. // different filter)
  2119. // bUnicode - TRUE if the Restriction contains UNICODE strings
  2120. // FALSE otherwise
  2121. //
  2122. // RETURNS: MAPI_E_INVALID_PARAMETER if the restriction cannot
  2123. // be converted in to filters, hrSuccess otherwise.
  2124. //
  2125. // HISTORY:
  2126. // 96/07/10 markdu Created.
  2127. // 96/08/05 markdu BUG 34023 Always start with a filter that causes
  2128. // the search to return only objects of class 'person'.
  2129. // If organization is supplied, add it to the base of the
  2130. // search instead of the filter to narrow the scope.
  2131. // 96/08/07 markdu BUG 34201 Added dwPass to allow backup searches.
  2132. // 96/10/18 markdu Removed base string, since it is now in registry.
  2133. //
  2134. //*******************************************************************
  2135. HRESULT ParseSRestriction(
  2136. LPSRestriction lpRes,
  2137. LPTSTR FAR * lplpszFilter,
  2138. LPTSTR * lplpszSimpleFilter,
  2139. LPTSTR * lplpszNTFilter,
  2140. DWORD dwPass,
  2141. BOOL bUnicode)
  2142. {
  2143. HRESULT hr = hrSuccess;
  2144. LPTSTR szTemp = NULL;
  2145. LPTSTR szEmailFilter = NULL;
  2146. LPTSTR szNameFilter = NULL;
  2147. LPTSTR szNTFilter = NULL;
  2148. LPTSTR szAltEmailFilter = NULL;
  2149. LPTSTR szSimpleFilter = NULL;
  2150. LPTSTR lpszInputCopy = NULL;
  2151. LPTSTR lpszInput;
  2152. ULONG ulcIllegalChars = 0;
  2153. ULONG ulcProps;
  2154. ULONG ulIndex;
  2155. ULONG ulcbFilter;
  2156. LPSRestriction lpResArray;
  2157. LPSPropertyRestriction lpPropRes;
  2158. LPTSTR lpsz = NULL;
  2159. ULONG ulPropTag = 0;
  2160. // Make sure we can write to lplpszFilter.
  2161. #ifdef PARAMETER_VALIDATION
  2162. if (IsBadReadPtr(lpRes, sizeof(SRestriction)))
  2163. {
  2164. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2165. }
  2166. if (IsBadWritePtr(lplpszFilter, sizeof(LPTSTR)))
  2167. {
  2168. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2169. }
  2170. #endif // PARAMETER_VALIDATION
  2171. // Currently we only support AND restrictions
  2172. if (RES_AND != lpRes->rt)
  2173. {
  2174. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2175. }
  2176. // We need to have at least one prop
  2177. ulcProps = lpRes->res.resAnd.cRes;
  2178. if (1 > ulcProps)
  2179. {
  2180. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2181. }
  2182. lpResArray = lpRes->res.resAnd.lpRes;
  2183. for (ulIndex=0;ulIndex<ulcProps;ulIndex++)
  2184. {
  2185. // Currently expect only SPropertyRestriction structures.
  2186. if (RES_PROPERTY != lpResArray[ulIndex].rt)
  2187. {
  2188. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2189. }
  2190. // Currently expect only EQ operations.
  2191. lpPropRes = &lpResArray[ulIndex].res.resProperty;
  2192. if (RELOP_EQ != lpPropRes->relop)
  2193. {
  2194. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2195. }
  2196. ulPropTag = lpPropRes->lpProp->ulPropTag;
  2197. if(bUnicode)
  2198. {
  2199. lpsz = lpPropRes->lpProp->Value.lpszW;
  2200. }
  2201. else // <note> assumes UNICODE defined
  2202. {
  2203. LocalFreeAndNull(&lpsz);
  2204. lpsz = ConvertAtoW(lpPropRes->lpProp->Value.lpszA);
  2205. if (NULL == lpsz)
  2206. {
  2207. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2208. goto exit;
  2209. }
  2210. if(PROP_TYPE(ulPropTag) == PT_STRING8)
  2211. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  2212. }
  2213. // 96/12/04 markdu BUG 11923 See if any characters in the input need to be escaped.
  2214. if (lpsz)
  2215. ulcIllegalChars = CountIllegalChars(lpsz);
  2216. if (0 == ulcIllegalChars)
  2217. {
  2218. lpszInput = lpsz;
  2219. }
  2220. else
  2221. {
  2222. ULONG cchSize = lstrlen(lpsz) + ulcIllegalChars*2 + 1;
  2223. // Allocate a copy of the input, large enough to replace the illegal chars
  2224. // with escaped versions - each escaped char needs 2 more spaces '\xx'.
  2225. lpszInputCopy = LocalAlloc( LMEM_ZEROINIT,
  2226. sizeof(TCHAR)*cchSize);
  2227. if (NULL == lpszInputCopy)
  2228. {
  2229. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2230. goto exit;
  2231. }
  2232. EscapeIllegalChars(lpsz, lpszInputCopy, cchSize);
  2233. lpszInput = lpszInputCopy;
  2234. }
  2235. // If this is the display name property,
  2236. // then we make the special filter for SimpleSearch
  2237. if (PR_DISPLAY_NAME == ulPropTag)
  2238. {
  2239. hr = BuildBasicFilter(
  2240. &szNTFilter,
  2241. (LPTSTR)cszAttr_anr,
  2242. lpszInput,
  2243. FALSE);
  2244. if (hrSuccess != hr)
  2245. {
  2246. return hr;
  2247. }
  2248. hr = CreateSimpleSearchFilter(
  2249. &szNameFilter,
  2250. &szAltEmailFilter,
  2251. &szSimpleFilter,
  2252. lpszInput,
  2253. dwPass);
  2254. if (hrSuccess != hr)
  2255. {
  2256. return hr;
  2257. }
  2258. }
  2259. if (PR_EMAIL_ADDRESS == ulPropTag)
  2260. {
  2261. // Only take the text up to the first space, comma, or tab.
  2262. szTemp = lpszInput;
  2263. while(*szTemp != '\0' && (! IsSpace(szTemp)) && *szTemp != '\t' && *szTemp != ',' )
  2264. {
  2265. szTemp = CharNext(szTemp);
  2266. }
  2267. *szTemp = '\0';
  2268. // Note UMich server does not allow wildcards in email search.
  2269. hr = BuildBasicFilter(
  2270. &szEmailFilter,
  2271. (LPTSTR)cszAttr_mail,
  2272. lpszInput,
  2273. (UMICH_PASS != dwPass));
  2274. if (hrSuccess != hr)
  2275. {
  2276. goto exit;
  2277. }
  2278. }
  2279. // We are done with lpszInputCopy.
  2280. LocalFreeAndNull(&lpszInputCopy);
  2281. } // for
  2282. // Put the simple filter togethor
  2283. if (szSimpleFilter)
  2284. {
  2285. if (szEmailFilter)
  2286. {
  2287. // Both fields were filled in, so AND them together
  2288. hr = BuildOpFilter(
  2289. lplpszSimpleFilter,
  2290. szEmailFilter,
  2291. szSimpleFilter,
  2292. FILTER_OP_AND);
  2293. if (hrSuccess != hr)
  2294. {
  2295. goto exit;
  2296. }
  2297. }
  2298. else if (szAltEmailFilter)
  2299. {
  2300. // No email field was given, so OR in the alternate email filter.
  2301. hr = BuildOpFilter( lplpszSimpleFilter,
  2302. szAltEmailFilter,
  2303. szSimpleFilter,
  2304. FILTER_OP_OR);
  2305. if (hrSuccess != hr)
  2306. {
  2307. goto exit;
  2308. }
  2309. }
  2310. else
  2311. {
  2312. DWORD cchSize = (lstrlen(szSimpleFilter) + 1);
  2313. *lplpszSimpleFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR) * cchSize);
  2314. if (NULL == *lplpszSimpleFilter)
  2315. {
  2316. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2317. goto exit;
  2318. }
  2319. StrCpyN(*lplpszSimpleFilter, szSimpleFilter, cchSize);
  2320. }
  2321. }
  2322. else if (szEmailFilter)
  2323. {
  2324. // Email was the only filter we got. This filter will not include common name.
  2325. // 96/10/02 markdu BUG 37426 If the filter does not include common name,
  2326. // add to the filter so that we only get entries that have a common name.
  2327. // Otherwise the entry will not be displayed.
  2328. hr = BuildOpFilter(
  2329. lplpszSimpleFilter,
  2330. (LPTSTR)cszCommonNamePresentFilter,
  2331. szEmailFilter,
  2332. FILTER_OP_AND);
  2333. if (hrSuccess != hr)
  2334. {
  2335. goto exit;
  2336. }
  2337. }
  2338. // Put the filter together.
  2339. if (szNameFilter)
  2340. {
  2341. if (szEmailFilter)
  2342. {
  2343. // Both fields were filled in, so AND them together
  2344. hr = BuildOpFilter(
  2345. lplpszFilter,
  2346. szEmailFilter,
  2347. szNameFilter,
  2348. FILTER_OP_AND);
  2349. if (hrSuccess != hr)
  2350. {
  2351. goto exit;
  2352. }
  2353. hr = BuildOpFilter(
  2354. lplpszNTFilter,
  2355. szEmailFilter,
  2356. szNTFilter,
  2357. FILTER_OP_AND);
  2358. if (hrSuccess != hr)
  2359. {
  2360. goto exit;
  2361. }
  2362. }
  2363. else if (szAltEmailFilter)
  2364. {
  2365. // No email field was given, so OR in the alternate email filter.
  2366. hr = BuildOpFilter(
  2367. lplpszFilter,
  2368. szAltEmailFilter,
  2369. szNameFilter,
  2370. FILTER_OP_OR);
  2371. if (hrSuccess != hr)
  2372. {
  2373. goto exit;
  2374. }
  2375. hr = BuildOpFilter(
  2376. lplpszNTFilter,
  2377. szAltEmailFilter,
  2378. szNTFilter,
  2379. FILTER_OP_OR);
  2380. if (hrSuccess != hr)
  2381. {
  2382. goto exit;
  2383. }
  2384. }
  2385. else
  2386. {
  2387. DWORD cchSize = (lstrlen(szNameFilter) + 1);
  2388. *lplpszFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  2389. if (NULL == *lplpszFilter)
  2390. {
  2391. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2392. goto exit;
  2393. }
  2394. StrCpyN(*lplpszFilter, szNameFilter, cchSize);
  2395. cchSize = lstrlen(szNTFilter) + 1;
  2396. *lplpszNTFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  2397. if (NULL == *lplpszNTFilter)
  2398. {
  2399. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2400. goto exit;
  2401. }
  2402. StrCpyN(*lplpszNTFilter, szNTFilter, cchSize);
  2403. }
  2404. }
  2405. else if (szEmailFilter)
  2406. {
  2407. // Email was the only filter we got. This filter will not include common name.
  2408. // 96/10/02 markdu BUG 37426 If the filter does not include common name,
  2409. // add to the filter so that we only get entries that have a common name.
  2410. // Otherwise the entry will not be displayed.
  2411. hr = BuildOpFilter(
  2412. lplpszFilter,
  2413. (LPTSTR)cszCommonNamePresentFilter,
  2414. szEmailFilter,
  2415. FILTER_OP_AND);
  2416. if (hrSuccess != hr)
  2417. {
  2418. goto exit;
  2419. }
  2420. }
  2421. else
  2422. {
  2423. // We did not generate a filter
  2424. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2425. }
  2426. exit:
  2427. // Free the temporary strings
  2428. LocalFreeAndNull(&szNameFilter);
  2429. LocalFreeAndNull(&szNTFilter);
  2430. LocalFreeAndNull(&szAltEmailFilter);
  2431. LocalFreeAndNull(&szEmailFilter);
  2432. LocalFreeAndNull(&szSimpleFilter);
  2433. if(!bUnicode)
  2434. LocalFreeAndNull(&lpsz);
  2435. if (hrSuccess != hr)
  2436. {
  2437. LocalFreeAndNull(lplpszFilter);
  2438. }
  2439. return hr;
  2440. }
  2441. //*******************************************************************
  2442. //
  2443. // FUNCTION: CreateSimpleSearchFilter
  2444. //
  2445. // PURPOSE: Generate Search Filter strings simple search.
  2446. //
  2447. // PARAMETERS: lplpszFilter - pointer to receive the search filter
  2448. // string buffer.
  2449. // lplpszAltFilter - pointer to receive the alternate
  2450. // filter string buffer.
  2451. // lpszInput - string to put into the filter
  2452. // dwPass - which pass through this function (first pass
  2453. // is zero (0)). This allows
  2454. // reuse of this function with different behaviour each
  2455. // time (for example, to do a backup search with a
  2456. // different filter)
  2457. //
  2458. // RETURNS: HRESULT
  2459. //
  2460. // HISTORY:
  2461. // 96/10/02 markdu Created to fix BUG 37424.
  2462. // 96/10/23 markdu Added UMICH_PASS.
  2463. //
  2464. //*******************************************************************
  2465. HRESULT CreateSimpleSearchFilter(
  2466. LPTSTR FAR * lplpszFilter,
  2467. LPTSTR FAR * lplpszAltFilter,
  2468. LPTSTR FAR * lplpszSimpleFilter,
  2469. LPTSTR lpszInput,
  2470. DWORD dwPass)
  2471. {
  2472. HRESULT hr = hrSuccess;
  2473. DWORD dwSizeOfFirst = 0;
  2474. LPTSTR szFirst = NULL;
  2475. LPTSTR szTemp = NULL;
  2476. LPTSTR szLast;
  2477. LPTSTR szCommonName = NULL;
  2478. LPTSTR szFirstSurname = NULL;
  2479. LPTSTR szLastSurname = NULL;
  2480. LPTSTR szGivenName = NULL;
  2481. LPTSTR szFirstLast = NULL;
  2482. LPTSTR szLastFirst = NULL;
  2483. // Prepare the (cn=Input*) filter
  2484. hr = BuildBasicFilter(
  2485. lplpszSimpleFilter,
  2486. (LPTSTR)cszAttr_cn,
  2487. lpszInput,
  2488. TRUE);
  2489. if (hrSuccess != hr)
  2490. {
  2491. goto exit;
  2492. }
  2493. // Make a copy of the input string
  2494. {
  2495. DWORD cchSize = (lstrlen(lpszInput) + 1);
  2496. szFirst = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  2497. if (NULL == szFirst)
  2498. {
  2499. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2500. goto exit;
  2501. }
  2502. StrCpyN(szFirst, lpszInput, cchSize);
  2503. }
  2504. // Attempt to break the input string into multiple strings.
  2505. // szFirst will be the string up to the first space, tab, or comma.
  2506. // szLast will be the rest of the string.
  2507. szLast = szFirst;
  2508. while(*szLast != '\0' && (! IsSpace(szLast)) && *szLast != '\t' && *szLast != ',' )
  2509. {
  2510. szLast = CharNext(szLast);
  2511. }
  2512. if(*szLast != '\0')
  2513. {
  2514. // Terminate szFirst at this delimiter
  2515. // 96/12/10 markdu BUG 12699 Call CharNext before setting char to null.
  2516. szTemp = szLast;
  2517. szLast = CharNext(szLast);
  2518. *szTemp = '\0';
  2519. // Set beginning of szLast to be first non-space/comma/tab
  2520. while(IsSpace(szLast) || *szLast == '\t' || *szLast == ',')
  2521. {
  2522. szLast = CharNext(szLast);
  2523. }
  2524. }
  2525. // Prepare the (sn=szFirst*) filter
  2526. hr = BuildBasicFilter(
  2527. &szFirstSurname,
  2528. (LPTSTR)cszAttr_sn,
  2529. szFirst,
  2530. TRUE);
  2531. if (hrSuccess != hr)
  2532. {
  2533. goto exit;
  2534. }
  2535. if (UMICH_PASS != dwPass)
  2536. {
  2537. // Prepare the (givenName=szFirst*) filter
  2538. hr = BuildBasicFilter(
  2539. &szGivenName,
  2540. (LPTSTR)cszAttr_givenName,
  2541. szFirst,
  2542. TRUE);
  2543. if (hrSuccess != hr)
  2544. {
  2545. goto exit;
  2546. }
  2547. }
  2548. if(*szLast == '\0')
  2549. {
  2550. // The strings was in just one piece
  2551. // Prepare the (cn=szFirst*) filter
  2552. hr = BuildBasicFilter(
  2553. &szCommonName,
  2554. (LPTSTR)cszAttr_cn,
  2555. szFirst,
  2556. TRUE);
  2557. if (hrSuccess != hr)
  2558. {
  2559. goto exit;
  2560. }
  2561. // The string is all in one piece. Stick it in the filter.
  2562. // Note that we use szFirst instead of szInput, since szFirst
  2563. // will have trailing spaces, commas, and tabs removed.
  2564. if (UMICH_PASS == dwPass)
  2565. {
  2566. // Final result should be:
  2567. // "(|(cn=szFirst*)(sn=szFirst*))"
  2568. // OR the common name and surname filters together
  2569. hr = BuildOpFilter(
  2570. lplpszFilter,
  2571. szCommonName,
  2572. szFirstSurname,
  2573. FILTER_OP_OR);
  2574. if (hrSuccess != hr)
  2575. {
  2576. goto exit;
  2577. }
  2578. }
  2579. else
  2580. {
  2581. // Final result should be:
  2582. // "(|(cn=szFirst*)(|(sn=szFirst*)(givenName=szFirst*)))"
  2583. // OR the given name and surname filters together
  2584. hr = BuildOpFilter(
  2585. &szFirstLast,
  2586. szFirstSurname,
  2587. szGivenName,
  2588. FILTER_OP_OR);
  2589. if (hrSuccess != hr)
  2590. {
  2591. goto exit;
  2592. }
  2593. // OR the common name and first-last filters together
  2594. hr = BuildOpFilter(
  2595. lplpszFilter,
  2596. szCommonName,
  2597. szFirstLast,
  2598. FILTER_OP_OR);
  2599. if (hrSuccess != hr)
  2600. {
  2601. goto exit;
  2602. }
  2603. }
  2604. // Generate the Alternate filter, which contains the email address.
  2605. // Note UMich server does not allow wildcards in email search.
  2606. hr = BuildBasicFilter(
  2607. lplpszAltFilter,
  2608. (LPTSTR)cszAttr_mail,
  2609. szFirst,
  2610. (UMICH_PASS != dwPass));
  2611. if (hrSuccess != hr)
  2612. {
  2613. goto exit;
  2614. }
  2615. }
  2616. else
  2617. {
  2618. // The string is in two pieces. Stick them in the filter.
  2619. // Prepare the (cn=lpszInput*) filter
  2620. hr = BuildBasicFilter(
  2621. &szCommonName,
  2622. (LPTSTR)cszAttr_cn,
  2623. lpszInput,
  2624. TRUE);
  2625. if (hrSuccess != hr)
  2626. {
  2627. goto exit;
  2628. }
  2629. // Prepare the (sn=szLast*) filter
  2630. hr = BuildBasicFilter(
  2631. &szLastSurname,
  2632. (LPTSTR)cszAttr_sn,
  2633. szLast,
  2634. TRUE);
  2635. if (hrSuccess != hr)
  2636. {
  2637. goto exit;
  2638. }
  2639. if (UMICH_PASS == dwPass)
  2640. {
  2641. // Final result should be:
  2642. // "(|(cn=szFirst*)(|(sn=szFirst*)(sn=szLast*)))"
  2643. // OR the first surname and last surname filters together
  2644. hr = BuildOpFilter(
  2645. &szFirstLast,
  2646. szFirstSurname,
  2647. szLastSurname,
  2648. FILTER_OP_OR);
  2649. if (hrSuccess != hr)
  2650. {
  2651. goto exit;
  2652. }
  2653. /*
  2654. // OR the common name and first-last filters together
  2655. hr = BuildOpFilter(
  2656. lplpszFilter,
  2657. szCommonName,
  2658. szFirstLast,
  2659. FILTER_OP_OR);
  2660. if (hrSuccess != hr)
  2661. {
  2662. goto exit;
  2663. }
  2664. */
  2665. {
  2666. DWORD cchSize = (lstrlen(szCommonName)+1);
  2667. *lplpszFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  2668. if(*lplpszFilter)
  2669. StrCpyN(*lplpszFilter, szCommonName, cchSize);
  2670. }
  2671. }
  2672. else
  2673. {
  2674. LPTSTR szFirstLastLastFirst;
  2675. // Final result should be:
  2676. // "(|(cn=lpszInput*)(|(&(sn=szFirst*)(givenName=szLast*))(&(givenName=szFirst*)(sn=szLast*))))"
  2677. // AND the first given name and last surname filters together
  2678. hr = BuildOpFilter(
  2679. &szLastFirst,
  2680. szGivenName,
  2681. szLastSurname,
  2682. FILTER_OP_AND);
  2683. if (hrSuccess != hr)
  2684. {
  2685. goto exit;
  2686. }
  2687. // Prepare the (givenName=szLast*) filter
  2688. LocalFreeAndNull(&szGivenName);
  2689. hr = BuildBasicFilter(
  2690. &szGivenName,
  2691. (LPTSTR)cszAttr_givenName,
  2692. szLast,
  2693. TRUE);
  2694. if (hrSuccess != hr)
  2695. {
  2696. goto exit;
  2697. }
  2698. // AND the last given name and first surname filters together
  2699. hr = BuildOpFilter(
  2700. &szFirstLast,
  2701. szFirstSurname,
  2702. szGivenName,
  2703. FILTER_OP_AND);
  2704. if (hrSuccess != hr)
  2705. {
  2706. goto exit;
  2707. }
  2708. // OR the first-last and last-first filters together
  2709. hr = BuildOpFilter(
  2710. &szFirstLastLastFirst,
  2711. szFirstLast,
  2712. szLastFirst,
  2713. FILTER_OP_OR);
  2714. if (hrSuccess != hr)
  2715. {
  2716. goto exit;
  2717. }
  2718. /****/
  2719. // OR the common name and first-last-last-first filters together
  2720. hr = BuildOpFilter(
  2721. lplpszFilter,
  2722. szCommonName,
  2723. szFirstLastLastFirst,
  2724. FILTER_OP_OR);
  2725. /****
  2726. *lplpszFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szCommonName)+1));
  2727. if(*lplpszFilter)
  2728. StrCpyN(*lplpszFilter, szCommonName);
  2729. ****/
  2730. LocalFreeAndNull(&szFirstLastLastFirst);
  2731. if (hrSuccess != hr)
  2732. {
  2733. goto exit;
  2734. }
  2735. }
  2736. }
  2737. exit:
  2738. LocalFreeAndNull(&szFirst);
  2739. LocalFreeAndNull(&szCommonName);
  2740. LocalFreeAndNull(&szFirstSurname);
  2741. LocalFreeAndNull(&szLastSurname);
  2742. LocalFreeAndNull(&szGivenName);
  2743. LocalFreeAndNull(&szFirstLast);
  2744. LocalFreeAndNull(&szLastFirst);
  2745. return hr;
  2746. }
  2747. //*******************************************************************
  2748. //
  2749. // FUNCTION: GetLDAPServerName
  2750. //
  2751. // PURPOSE: Gets the server name property from the LDAP container
  2752. //
  2753. // PARAMETERS: lpLDAPCont -> LDAP container
  2754. // lppServer -> returned server name. Caller must
  2755. // MAPIFreeBuffer this string.
  2756. //
  2757. // RETURNS: HRESULT
  2758. //
  2759. // HISTORY:
  2760. // 96/07/11 brucek Created.
  2761. //
  2762. //*******************************************************************
  2763. HRESULT GetLDAPServerName(
  2764. LPLDAPCONT lpLDAPCont,
  2765. LPTSTR * lppServer)
  2766. {
  2767. HRESULT hResult;
  2768. SCODE sc;
  2769. ULONG cProps;
  2770. LPSPropValue lpProps = NULL;
  2771. LPTSTR lpServer = NULL;
  2772. if ((hResult = lpLDAPCont->lpVtbl->GetProps(lpLDAPCont,
  2773. (LPSPropTagArray)&ptaLDAPCont,
  2774. MAPI_UNICODE,
  2775. &cProps,
  2776. &lpProps))) {
  2777. DebugTraceResult( TEXT("LDAP Container GetProps"), hResult);
  2778. goto exit;
  2779. }
  2780. Assert(cProps == ildapcMax);
  2781. Assert(lpProps[ildapcPR_WAB_LDAP_SERVER].ulPropTag == PR_WAB_LDAP_SERVER);
  2782. {
  2783. DWORD cchSize = ((lstrlen(lpProps[ildapcPR_WAB_LDAP_SERVER].Value.LPSZ)) + 1);
  2784. if (sc = MAPIAllocateBuffer(sizeof(TCHAR)*cchSize, &lpServer))
  2785. {
  2786. hResult = ResultFromScode(sc);
  2787. goto exit;
  2788. }
  2789. StrCpyN(lpServer, lpProps[ildapcPR_WAB_LDAP_SERVER].Value.LPSZ, cchSize);
  2790. }
  2791. exit:
  2792. FreeBufferAndNull(&lpProps);
  2793. if (hResult) {
  2794. FreeBufferAndNull(&lpServer);
  2795. }
  2796. *lppServer = lpServer;
  2797. return(hResult);
  2798. }
  2799. //*******************************************************************
  2800. //
  2801. // FUNCTION: FixPropArray
  2802. //
  2803. // PURPOSE: Fixes the displayname in a proparray if it is
  2804. // equivalent to the email address.
  2805. // Adds a display name if there isnt one
  2806. //
  2807. // PARAMETERS: lpPropArray = MAPIAllocBuffer'ed property array
  2808. // ulcProps = number of props in lpPropArray
  2809. //
  2810. // RETURNS: TRUE if changes are made, FALSE if not.
  2811. //
  2812. // HISTORY:
  2813. // 96/07/12 brucek Created.
  2814. //
  2815. //*******************************************************************
  2816. BOOL FixPropArray(
  2817. LPSPropValue lpPropArray,
  2818. ULONG * lpulcProps)
  2819. {
  2820. ULONG ulcProps = *lpulcProps;
  2821. BOOL fChanged = FALSE;
  2822. signed int iSurname = NOT_FOUND, iGivenName = NOT_FOUND, iDisplayName = NOT_FOUND,
  2823. iEmailAddress = NOT_FOUND, iCompanyName = NOT_FOUND;
  2824. register signed int i;
  2825. for (i = 0; i < (signed int)ulcProps; i++) {
  2826. switch (lpPropArray[i].ulPropTag) {
  2827. case PR_SURNAME:
  2828. iSurname = i;
  2829. break;
  2830. case PR_GIVEN_NAME:
  2831. iGivenName = i;
  2832. break;
  2833. case PR_COMPANY_NAME:
  2834. iCompanyName = i;
  2835. break;
  2836. case PR_DISPLAY_NAME:
  2837. iDisplayName = i;
  2838. break;
  2839. case PR_EMAIL_ADDRESS:
  2840. iEmailAddress = i;
  2841. break;
  2842. }
  2843. }
  2844. if (((iSurname != NOT_FOUND && iGivenName != NOT_FOUND) || iCompanyName != NOT_FOUND) && iDisplayName != NOT_FOUND && iEmailAddress != NOT_FOUND) {
  2845. // PropArray contains all of the props.
  2846. // If PR_DISPLAY_NAME is same as PR_EMAIL_ADDRESS, regenerate the PR_DISPLAY_NAME from
  2847. // PR_SURNAME and PR_GIVEN_NAME or PR_COMPANY_NAME.
  2848. if (! lstrcmpi(lpPropArray[iDisplayName].Value.LPSZ, lpPropArray[iEmailAddress].Value.LPSZ)) {
  2849. fChanged = FixDisplayName(lpPropArray[iGivenName].Value.LPSZ,
  2850. NULL, //szEmpty, //For LDAP assume there is not middle name for now
  2851. lpPropArray[iSurname].Value.LPSZ,
  2852. iCompanyName == NOT_FOUND ? NULL : lpPropArray[iCompanyName].Value.LPSZ,
  2853. NULL, // NickName
  2854. (LPTSTR *) (&lpPropArray[iDisplayName].Value.LPSZ),
  2855. lpPropArray);
  2856. }
  2857. }
  2858. else if(iSurname != NOT_FOUND && iGivenName != NOT_FOUND && iDisplayName == NOT_FOUND)
  2859. {
  2860. //Exchange DS will sometimes not return a display name returning sn and givenName instead
  2861. iDisplayName = ulcProps; // This is safe as we allocated space for the display Name in the beginning
  2862. lpPropArray[iDisplayName].ulPropTag = PR_DISPLAY_NAME;
  2863. fChanged = FixDisplayName( lpPropArray[iGivenName].Value.LPSZ,
  2864. NULL, //szEmpty, //For LDAP assume there is not middle name for now
  2865. (lpPropArray[iSurname].Value.LPSZ),
  2866. (iCompanyName == NOT_FOUND ? NULL : lpPropArray[iCompanyName].Value.LPSZ),
  2867. NULL, // NickName
  2868. (LPTSTR *) (&lpPropArray[iDisplayName].Value.LPSZ),
  2869. (LPVOID) lpPropArray);
  2870. (*lpulcProps)++;
  2871. }
  2872. return(fChanged);
  2873. }
  2874. typedef HRESULT (* PFNHRCREATEACCOUNTMANAGER)(IImnAccountManager **);
  2875. //*******************************************************************
  2876. //
  2877. // FUNCTION: HrWrappedCreateAccountManager
  2878. //
  2879. // PURPOSE: Load account manager dll and create the object.
  2880. //
  2881. // PARAMETERS: lppAccountManager -> returned pointer to account manager
  2882. // object.
  2883. //
  2884. // RETURNS: HRESULT
  2885. //
  2886. //*******************************************************************
  2887. HRESULT HrWrappedCreateAccountManager(IImnAccountManager2 **lppAccountManager)
  2888. {
  2889. IImnAccountManager *pAccountManager;
  2890. LONG lRes;
  2891. DWORD dw;
  2892. HRESULT hResult;
  2893. TCHAR szPath[MAX_PATH],
  2894. szPathExpand[MAX_PATH],
  2895. szReg[MAX_PATH],
  2896. szGUID[MAX_PATH];
  2897. LPOLESTR lpszW= 0 ;
  2898. PFNHRCREATEACCOUNTMANAGER pfnHrCreateAccountManager = NULL;
  2899. LONG cb = MAX_PATH + 1;
  2900. DWORD dwType = 0;
  2901. HKEY hkey = NULL;
  2902. if (! lppAccountManager) {
  2903. return(ResultFromScode(E_INVALIDARG));
  2904. }
  2905. if (g_hInstImnAcct) {
  2906. return(ResultFromScode(ERROR_ALREADY_INITIALIZED));
  2907. }
  2908. *lppAccountManager = NULL;
  2909. if (HR_FAILED(hResult = StringFromCLSID(&CLSID_ImnAccountManager, &lpszW))) {
  2910. goto error;
  2911. }
  2912. StrCpyN(szGUID, lpszW, ARRAYSIZE(szGUID));
  2913. StrCpyN(szReg, TEXT("CLSID\\"), ARRAYSIZE(szReg));
  2914. StrCatBuff(szReg, szGUID, ARRAYSIZE(szReg));
  2915. StrCatBuff(szReg, TEXT("\\InprocServer32"), ARRAYSIZE(szReg));
  2916. lRes = RegOpenKeyEx(HKEY_CLASSES_ROOT, szReg, 0, KEY_QUERY_VALUE, &hkey);
  2917. if (lRes != ERROR_SUCCESS) {
  2918. hResult = ResultFromScode(CO_E_DLLNOTFOUND);
  2919. goto error;
  2920. }
  2921. cb = ARRAYSIZE(szPath);
  2922. lRes = RegQueryValueEx(hkey, NULL, NULL, &dwType, (LPBYTE)szPath, &cb);
  2923. if (REG_EXPAND_SZ == dwType)
  2924. {
  2925. // szPath is a REG_EXPAND_SZ type, so we need to expand
  2926. // environment strings
  2927. dw = ExpandEnvironmentStrings(szPath, szPathExpand, CharSizeOf(szPathExpand));
  2928. if (dw == 0) {
  2929. hResult = ResultFromScode(CO_E_DLLNOTFOUND);
  2930. goto error;
  2931. }
  2932. StrCpyN(szPath, szPathExpand, ARRAYSIZE(szPath));
  2933. }
  2934. if (lRes != ERROR_SUCCESS)
  2935. {
  2936. hResult = ResultFromScode(CO_E_DLLNOTFOUND);
  2937. goto error;
  2938. }
  2939. if (! (g_hInstImnAcct = LoadLibrary(szPath))) {
  2940. hResult = ResultFromScode(CO_E_DLLNOTFOUND);
  2941. goto error;
  2942. }
  2943. if (! (pfnHrCreateAccountManager = (PFNHRCREATEACCOUNTMANAGER)GetProcAddress(g_hInstImnAcct, "HrCreateAccountManager"))) {
  2944. hResult = ResultFromScode(TYPE_E_DLLFUNCTIONNOTFOUND);
  2945. goto error;
  2946. }
  2947. hResult = pfnHrCreateAccountManager(&pAccountManager);
  2948. if (SUCCEEDED(hResult))
  2949. {
  2950. hResult = pAccountManager->lpVtbl->QueryInterface(pAccountManager, &IID_IImnAccountManager2, (LPVOID *)lppAccountManager);
  2951. pAccountManager->lpVtbl->Release(pAccountManager);
  2952. }
  2953. goto exit;
  2954. error:
  2955. // Failed to init account manager the fast way. Try the S L O W OLE way...
  2956. if (CoInitialize(NULL) == S_FALSE) {
  2957. // Already initialized, undo the extra.
  2958. CoUninitialize();
  2959. } else {
  2960. fCoInitialize = TRUE;
  2961. }
  2962. if (HR_FAILED(hResult = CoCreateInstance(&CLSID_ImnAccountManager,
  2963. NULL,
  2964. CLSCTX_INPROC_SERVER,
  2965. &IID_IImnAccountManager2, (LPVOID *)lppAccountManager))) {
  2966. DebugTrace(TEXT("CoCreateInstance(IID_IImnAccountManager) -> %x\n"), GetScode(hResult));
  2967. }
  2968. exit:
  2969. // Clean up the OLE allocated memory
  2970. if (lpszW) {
  2971. LPMALLOC pMalloc = NULL;
  2972. CoGetMalloc(1, &pMalloc);
  2973. Assert(pMalloc);
  2974. if (pMalloc) {
  2975. pMalloc->lpVtbl->Free(pMalloc, lpszW);
  2976. pMalloc->lpVtbl->Release(pMalloc);
  2977. }
  2978. }
  2979. if (hkey != NULL)
  2980. RegCloseKey(hkey);
  2981. return(hResult);
  2982. }
  2983. //*******************************************************************
  2984. //
  2985. // FUNCTION: InitAccountManager
  2986. //
  2987. // PURPOSE: Load and initialize the account manager
  2988. //
  2989. // PARAMETERS: lppAccountManager -> returned pointer to account manager
  2990. // object.
  2991. //
  2992. // RETURNS: HRESULT
  2993. //
  2994. // COMMENTS: The first time through here, we will save the hResult.
  2995. // On subsequent calls, we will check this saved value
  2996. // and return it right away if there was an error, thus
  2997. // preventing repeated time consuming LoadLibrary calls.
  2998. //
  2999. // With Identity awareness (IE5.0 plus) .. we need to
  3000. // initiate the Account Manager on an identity basis ..
  3001. // We do this by passing it an appropriate regkey ..
  3002. // If this is a non-identity-aware app, then we always get
  3003. // info from the default identity ..
  3004. //
  3005. //*******************************************************************
  3006. HRESULT InitAccountManager(LPIAB lpIAB, IImnAccountManager2 ** lppAccountManager, GUID * pguidUser) {
  3007. static hResultSave = hrSuccess;
  3008. HRESULT hResult = hResultSave;
  3009. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3010. GUID guidNULL = {00000000-0000-0000-0000-000000000000};
  3011. if (! g_lpAccountManager && ! HR_FAILED(hResultSave)) {
  3012. #ifdef DEBUG
  3013. DWORD dwTickCount = GetTickCount();
  3014. DebugTrace(TEXT(">>>>> Initializing Account Manager...\n"));
  3015. #endif // DEBUG
  3016. if (hResult = HrWrappedCreateAccountManager(&g_lpAccountManager)) {
  3017. DebugTrace(TEXT("HrWrappedCreateAccountManager -> %x\n"), GetScode(hResult));
  3018. goto end;
  3019. }
  3020. Assert(g_lpAccountManager);
  3021. if(pt_bIsWABOpenExSession)
  3022. {
  3023. if (hResult = g_lpAccountManager->lpVtbl->InitEx( g_lpAccountManager,
  3024. NULL,
  3025. ACCT_INIT_OUTLOOK))
  3026. {
  3027. DebugTrace(TEXT("AccountManager->InitEx -> %x\n"), GetScode(hResult));
  3028. goto end;
  3029. }
  3030. }
  3031. else
  3032. {
  3033. // [PaulHi] 1/13/99 If a valid user guid pointer is passed in then
  3034. // use it to init the account manager
  3035. if (pguidUser)
  3036. {
  3037. g_lpAccountManager->lpVtbl->InitUser(g_lpAccountManager, NULL, pguidUser, 0);
  3038. }
  3039. else if (lpIAB &&
  3040. memcmp(&(lpIAB->guidCurrentUser), &guidNULL, sizeof(GUID)) )
  3041. {
  3042. // Try the existing user guid stored in the IAB
  3043. g_lpAccountManager->lpVtbl->InitUser(g_lpAccountManager, NULL, &(lpIAB->guidCurrentUser), 0);
  3044. }
  3045. else
  3046. {
  3047. // Default. WARNING If the account manager is not initialized at some point then
  3048. // it is susceptible to crash.
  3049. g_lpAccountManager->lpVtbl->InitUser(g_lpAccountManager, NULL, &UID_GIBC_DEFAULT_USER, 0);
  3050. }
  3051. }
  3052. #ifdef DEBUG
  3053. DebugTrace(TEXT(">>>>> Done Initializing Account Manager... %u milliseconds\n"), GetTickCount() - dwTickCount);
  3054. #endif // DEBUG
  3055. }
  3056. end:
  3057. if (HR_FAILED(hResult)) {
  3058. *lppAccountManager = NULL;
  3059. // Save the result
  3060. hResultSave = hResult;
  3061. } else {
  3062. *lppAccountManager = g_lpAccountManager;
  3063. }
  3064. return(hResult);
  3065. }
  3066. //*******************************************************************
  3067. //
  3068. // FUNCTION: UninitAccountManager
  3069. //
  3070. // PURPOSE: Release and unLoad the account manager
  3071. //
  3072. // PARAMETERS: none
  3073. //
  3074. // RETURNS: none
  3075. //
  3076. //*******************************************************************
  3077. void UninitAccountManager(void) {
  3078. if (g_lpAccountManager) {
  3079. #ifdef DEBUG
  3080. DWORD dwTickCount = GetTickCount();
  3081. DebugTrace(TEXT(">>>>> Uninitializing Account Manager...\n"));
  3082. #endif // DEBUG
  3083. g_lpAccountManager->lpVtbl->Release(g_lpAccountManager);
  3084. g_lpAccountManager = NULL;
  3085. // Unload the acct man dll
  3086. if (g_hInstImnAcct) {
  3087. FreeLibrary(g_hInstImnAcct);
  3088. g_hInstImnAcct=NULL;
  3089. }
  3090. if (fCoInitialize) {
  3091. CoUninitialize();
  3092. }
  3093. #ifdef DEBUG
  3094. DebugTrace(TEXT(">>>>> Done Uninitializing Account Manager... %u milliseconds\n"), GetTickCount() - dwTickCount);
  3095. #endif // DEBUG
  3096. }
  3097. }
  3098. //*******************************************************************
  3099. //
  3100. // FUNCTION: AddToServerList
  3101. //
  3102. // PURPOSE: Insert a server name in the server list
  3103. //
  3104. // PARAMETERS: lppServerNames -> ServerNames pointer
  3105. // szBuf = name of server
  3106. // dwOrder = insertion order of this server
  3107. //
  3108. // RETURNS: HRESULT
  3109. //
  3110. //*******************************************************************
  3111. HRESULT AddToServerList(UNALIGNED LPSERVER_NAME * lppServerNames, LPTSTR szBuf, DWORD dwOrder) {
  3112. HRESULT hResult = hrSuccess;
  3113. LPSERVER_NAME lpServerName = NULL, lpCurrent;
  3114. UNALIGNED LPSERVER_NAME * lppInsert;
  3115. DWORD cbSize = (lstrlen(szBuf) + 1);
  3116. // Create new node
  3117. if (! (lpServerName = LocalAlloc(LPTR, LcbAlignLcb(sizeof(SERVER_NAME))))) {
  3118. DebugTrace(TEXT("Can't allocate new server name structure\n"));
  3119. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3120. goto exit;
  3121. }
  3122. if (! (lpServerName->lpszName = LocalAlloc(LPTR, LcbAlignLcb(sizeof(TCHAR)*cbSize)))) {
  3123. DebugTrace(TEXT("Can't allocate new server name\n"));
  3124. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3125. goto exit;
  3126. }
  3127. StrCpyN(lpServerName->lpszName, szBuf, cbSize);
  3128. lpServerName->dwOrder = dwOrder;
  3129. // Insert in list in correct order
  3130. lppInsert = lppServerNames;
  3131. lpCurrent = *lppServerNames;
  3132. while (lpCurrent && (lpCurrent->dwOrder <= dwOrder)) {
  3133. lpCurrent = (*lppInsert)->lpNext;
  3134. lppInsert = &(*lppInsert)->lpNext;
  3135. }
  3136. lpServerName->lpNext = lpCurrent;
  3137. *lppInsert = lpServerName;
  3138. exit:
  3139. if (hResult && lpServerName) {
  3140. if (lpServerName->lpszName) {
  3141. LocalFree(lpServerName->lpszName);
  3142. }
  3143. LocalFree(lpServerName);
  3144. }
  3145. return(hResult);
  3146. }
  3147. //*******************************************************************
  3148. //
  3149. // FUNCTION: EnumerateLDAPtoServerList
  3150. //
  3151. // PURPOSE: Enumerate the LDAP servers to a server name linked list.
  3152. //
  3153. // PARAMETERS: lpAccountManager -> Account Manager
  3154. // lppServerNames -> returned ServerNames (must be NULL on
  3155. // entry.
  3156. // lpcServers -> returned number of servers. May be NULL
  3157. // if caller doesn't care.
  3158. //
  3159. // RETURNS: HRESULT
  3160. //
  3161. //*******************************************************************
  3162. HRESULT EnumerateLDAPtoServerList(IImnAccountManager2 * lpAccountManager,
  3163. LPSERVER_NAME * lppServerNames, LPULONG lpcServers) {
  3164. IImnEnumAccounts * lpEnumAccounts = NULL;
  3165. IImnAccount * lpAccount = NULL;
  3166. DWORD dwOrder;
  3167. LPSERVER_NAME lpNextServer;
  3168. char szBuf[MAX_UI_STR + 1];
  3169. HRESULT hResult;
  3170. Assert(lpAccountManager);
  3171. Assert(*lppServerNames == NULL);
  3172. if (lpcServers) {
  3173. *lpcServers = 0;
  3174. }
  3175. if (hResult = lpAccountManager->lpVtbl->Enumerate(lpAccountManager,
  3176. SRV_LDAP,
  3177. &lpEnumAccounts)) {
  3178. goto exit;
  3179. }
  3180. while (! lpEnumAccounts->lpVtbl->GetNext(lpEnumAccounts,
  3181. &lpAccount)) {
  3182. // Add this account's name to the list
  3183. if (! lpAccount->lpVtbl->GetPropSz(lpAccount,
  3184. AP_ACCOUNT_NAME,
  3185. szBuf,
  3186. sizeof(szBuf))) {
  3187. // What order in the list?
  3188. if (lpAccount->lpVtbl->GetPropDw(lpAccount,
  3189. AP_LDAP_SERVER_ID,
  3190. &dwOrder)) {
  3191. dwOrder = 0xFFFFFFFF; // last
  3192. }
  3193. // Add it to the linked list of names
  3194. {
  3195. LPTSTR lpServer = ConvertAtoW(szBuf);
  3196. if (lpServer)
  3197. {
  3198. if (hResult = AddToServerList(lppServerNames, lpServer, dwOrder)) {
  3199. goto exit;
  3200. }
  3201. LocalFreeAndNull(&lpServer);
  3202. }
  3203. else
  3204. {
  3205. hResult = E_OUTOFMEMORY;
  3206. goto exit;
  3207. }
  3208. }
  3209. if (lpcServers) {
  3210. (*lpcServers)++;
  3211. }
  3212. }
  3213. lpAccount->lpVtbl->Release(lpAccount);
  3214. lpAccount = NULL;
  3215. }
  3216. exit:
  3217. if (lpAccount) {
  3218. lpAccount->lpVtbl->Release(lpAccount);
  3219. }
  3220. if (lpEnumAccounts) {
  3221. lpEnumAccounts->lpVtbl->Release(lpEnumAccounts);
  3222. }
  3223. return(hResult);
  3224. }
  3225. //*******************************************************************
  3226. //
  3227. // FUNCTION: RegQueryValueExDWORD
  3228. //
  3229. // PURPOSE: Read a DWORD registry value, correcting for value type
  3230. //
  3231. // RETURNS: RegQueryValueEx error code
  3232. //
  3233. //*******************************************************************
  3234. DWORD RegQueryValueExDWORD(HKEY hKey, LPTSTR lpszValueName, LPDWORD lpdwValue)
  3235. {
  3236. DWORD dwType, dwErr;
  3237. DWORD cbData = sizeof(DWORD);
  3238. *lpdwValue = 0;
  3239. dwErr = RegQueryValueEx(hKey, lpszValueName, NULL, &dwType, (LPBYTE)lpdwValue, &cbData);
  3240. return(dwErr);
  3241. }
  3242. //*******************************************************************
  3243. //
  3244. // FUNCTION: GetLDAPNextServerID
  3245. //
  3246. // PURPOSE: To ensure that all server entries in the registry are
  3247. // unique, we will henceforth assign each new entry a
  3248. // unique serverID at the time of creation. This will help
  3249. // us make sure that all registry entries are unique.
  3250. // A running counter is stored in the registry and will
  3251. // give us the next available SeverID
  3252. //
  3253. // PARAMETERS: dwSet = input value to set the next id to. (Optional,
  3254. // ignored if zero.)
  3255. //
  3256. // RETURNS: The next available ID for use. Valid IDs range from 1 upwards.
  3257. // 0 is an invalid ID, as is -1.
  3258. //
  3259. // HISTORY:
  3260. // 96/10/09 vikramm Created
  3261. //*******************************************************************
  3262. DWORD GetLDAPNextServerID(DWORD dwSet) {
  3263. DWORD dwID = 0;
  3264. DWORD dwNextID = 0;
  3265. DWORD dwErr = 0;
  3266. HKEY hKeyWAB;
  3267. LPTSTR szLDAPNextAvailableServerID = TEXT("Server ID");
  3268. // Open the WAB's reg key
  3269. if (! (dwErr = RegOpenKeyEx(HKEY_CURRENT_USER, szWABKey, 0, KEY_ALL_ACCESS, &hKeyWAB)))
  3270. {
  3271. dwNextID = 0; // init in case registry gives < 4 bytes.
  3272. if (dwSet)
  3273. dwNextID = dwSet;
  3274. else
  3275. {
  3276. // Read the next available server id
  3277. if (dwErr = RegQueryValueExDWORD(hKeyWAB, (LPTSTR)szLDAPNextAvailableServerID, &dwNextID))
  3278. {
  3279. // The value wasn't found!!
  3280. // Create a new key, starting at 100
  3281. // (Start high so that we can be guaranteed to be past any
  3282. // pre-configured servers.)
  3283. dwNextID = 500;
  3284. }
  3285. }
  3286. dwID = dwNextID++;
  3287. // Update the ID in the registry
  3288. RegSetValueEx(hKeyWAB, (LPTSTR)szLDAPNextAvailableServerID, 0, REG_DWORD, (LPBYTE)&dwNextID, sizeof(dwNextID));
  3289. RegCloseKey(hKeyWAB);
  3290. }
  3291. return(dwID);
  3292. }
  3293. /*
  3294. -
  3295. - SetAccountStringAW
  3296. *
  3297. * Account manager returns ANSI/DBCS which we need to convert to Unicode as appropriate
  3298. *
  3299. */
  3300. void SetAccountStringAW(LPTSTR * lppAcctStr, LPSTR lpszData)
  3301. {
  3302. *lppAcctStr = ConvertAtoW(lpszData);
  3303. }
  3304. //*******************************************************************
  3305. //
  3306. // FUNCTION: GetLDAPServerParams
  3307. //
  3308. // PURPOSE: Gets the per-server parameters for the given LDAP server.
  3309. // Parameters include limit on number of entries to retrieve in
  3310. // an LDAP search, the max number of seconds to spend on the
  3311. // server, the max number of seconds to wait at the client,
  3312. // and the type of authentication to use with this server.
  3313. //
  3314. // PARAMETERS: lpszServer - name of the server
  3315. // ServerParams - structure containing the per-server parameters
  3316. //
  3317. // RETURNS: TRUE if the lpszServer already existed else returns FALSE
  3318. // If the given server does not exist, still fills in the lspParams struct.
  3319. //
  3320. // HISTORY:
  3321. // 96/07/16 markdu Created.
  3322. // 96/10/09 vikramm Added Server Name and search base. Changed return value
  3323. // from void to BOOL
  3324. // 96/12/16 brucek Added URL.
  3325. //*******************************************************************
  3326. BOOL GetLDAPServerParams(LPTSTR lpszServer, LPLDAPSERVERPARAMS lspParams)
  3327. {
  3328. DWORD dwType;
  3329. HRESULT hResult = hrSuccess;
  3330. IImnAccountManager2 * lpAccountManager = NULL;
  3331. IImnAccount * lpAccount = NULL;
  3332. char szBuffer[513];
  3333. // Set defaults for each value
  3334. lspParams->dwSearchSizeLimit = LDAP_SEARCH_SIZE_LIMIT;
  3335. lspParams->dwSearchTimeLimit = LDAP_SEARCH_TIME_LIMIT;
  3336. lspParams->dwAuthMethod = LDAP_AUTH_METHOD_ANONYMOUS;
  3337. lspParams->lpszUserName = NULL;
  3338. lspParams->lpszPassword = NULL;
  3339. lspParams->lpszURL = NULL;
  3340. lspParams->lpszLogoPath = NULL;
  3341. lspParams->lpszBase = NULL;
  3342. lspParams->lpszName = NULL;
  3343. lspParams->fResolve = FALSE;
  3344. lspParams->dwID = 0;
  3345. lspParams->dwUseBindDN = 0;
  3346. lspParams->dwPort = LDAP_DEFAULT_PORT;
  3347. lspParams->fSimpleSearch = FALSE;
  3348. lspParams->lpszAdvancedSearchAttr = NULL;
  3349. #ifdef PAGED_RESULT_SUPPORT
  3350. lspParams->dwPagedResult = LDAP_PRESULT_UNKNOWN;
  3351. #endif //#ifdef PAGED_RESULT_SUPPORT
  3352. lspParams->dwIsNTDS = LDAP_NTDS_UNKNOWN;
  3353. if (hResult = InitAccountManager(NULL, &lpAccountManager, NULL)) {
  3354. goto exit;
  3355. }
  3356. SetAccountStringWA(szBuffer, lpszServer, CharSizeOf(szBuffer));
  3357. if (hResult = lpAccountManager->lpVtbl->FindAccount(lpAccountManager,
  3358. AP_ACCOUNT_NAME,
  3359. szBuffer,
  3360. &lpAccount)) {
  3361. //DebugTrace(TEXT("FindAccount(%s) -> %x\n"), lpszServer, GetScode(hResult));
  3362. goto exit;
  3363. }
  3364. // have account object, set its properties
  3365. Assert(lpAccount);
  3366. // Server Type: Is it LDAP?
  3367. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetServerTypes(lpAccount,
  3368. &dwType))) {
  3369. DebugTrace(TEXT("GetServerTypes() -> %x\n"), GetScode(hResult));
  3370. goto exit;
  3371. }
  3372. if (! (dwType & SRV_LDAP)) {
  3373. DebugTrace(TEXT("Account manager gave us a non-LDAP server\n"));
  3374. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  3375. goto exit;
  3376. }
  3377. // LDAP Server address
  3378. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3379. AP_LDAP_SERVER,
  3380. szBuffer,
  3381. sizeof(szBuffer)))) {
  3382. // This is a Required property, fail if not there.
  3383. DebugTrace(TEXT("GetPropSz(AP_LDAP_SERVER) -> %x\n"), GetScode(hResult));
  3384. goto exit;
  3385. }
  3386. SetAccountStringAW(&lspParams->lpszName, szBuffer);
  3387. // Username
  3388. if (! (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3389. AP_LDAP_USERNAME,
  3390. szBuffer,
  3391. sizeof(szBuffer))))) {
  3392. SetAccountStringAW(&lspParams->lpszUserName, szBuffer);
  3393. }
  3394. // Password
  3395. if (! (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3396. AP_LDAP_PASSWORD,
  3397. szBuffer,
  3398. sizeof(szBuffer))))) {
  3399. SetAccountStringAW(&lspParams->lpszPassword, szBuffer);
  3400. }
  3401. // Advanced Search Attributes
  3402. if (! (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3403. AP_LDAP_ADVANCED_SEARCH_ATTR,
  3404. szBuffer,
  3405. sizeof(szBuffer))))) {
  3406. SetAccountStringAW(&lspParams->lpszAdvancedSearchAttr, szBuffer);
  3407. }
  3408. // Authentication method
  3409. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3410. AP_LDAP_AUTHENTICATION,
  3411. &lspParams->dwAuthMethod))) {
  3412. // default to anonymous
  3413. lspParams->dwAuthMethod = LDAP_AUTH_METHOD_ANONYMOUS;
  3414. }
  3415. // LDAP Timeout
  3416. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3417. AP_LDAP_TIMEOUT,
  3418. &lspParams->dwSearchTimeLimit))) {
  3419. // default to 60 seconds
  3420. lspParams->dwSearchTimeLimit = LDAP_SEARCH_TIME_LIMIT;
  3421. }
  3422. // LDAP Search Base
  3423. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3424. AP_LDAP_SEARCH_BASE,
  3425. szBuffer,
  3426. sizeof(szBuffer)))) {
  3427. // Don't need to set the default search base here. GetLDAPSearchBase will
  3428. // calculate one if needed.
  3429. } else {
  3430. SetAccountStringAW(&lspParams->lpszBase, szBuffer);
  3431. }
  3432. // Search Limit
  3433. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3434. AP_LDAP_SEARCH_RETURN,
  3435. &lspParams->dwSearchSizeLimit))) {
  3436. // default to 100
  3437. lspParams->dwSearchTimeLimit = LDAP_SEARCH_SIZE_LIMIT;
  3438. }
  3439. // Order
  3440. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3441. AP_LDAP_SERVER_ID,
  3442. &lspParams->dwID))) {
  3443. lspParams->dwID = 0;
  3444. }
  3445. // Make sure we have a valid unique id
  3446. if (lspParams->dwID == 0 || lspParams->dwID == 0xFFFFFFFF) {
  3447. lspParams->dwID = GetLDAPNextServerID(0);
  3448. }
  3449. // Resolve flag
  3450. #ifndef WIN16
  3451. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3452. AP_LDAP_RESOLVE_FLAG,
  3453. &lspParams->fResolve))) {
  3454. #else
  3455. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3456. AP_LDAP_RESOLVE_FLAG,
  3457. (DWORD __RPC_FAR *)&lspParams->fResolve))) {
  3458. #endif
  3459. lspParams->fResolve = FALSE;
  3460. }
  3461. // Server URL
  3462. if (! (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3463. AP_LDAP_URL,
  3464. szBuffer,
  3465. sizeof(szBuffer))))) {
  3466. SetAccountStringAW(&lspParams->lpszURL, szBuffer);
  3467. }
  3468. // Full Path to Logo bitmap
  3469. if (! (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropSz(lpAccount,
  3470. AP_LDAP_LOGO,
  3471. szBuffer,
  3472. sizeof(szBuffer)))))
  3473. {
  3474. SetAccountStringAW(&lspParams->lpszLogoPath, szBuffer);
  3475. }
  3476. // Port
  3477. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3478. AP_LDAP_PORT,
  3479. &lspParams->dwPort))) {
  3480. // default to 100
  3481. lspParams->dwPort = LDAP_DEFAULT_PORT;
  3482. }
  3483. // Use Bind DN
  3484. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3485. AP_LDAP_USE_BIND_DN,
  3486. &lspParams->dwUseBindDN))) {
  3487. lspParams->dwUseBindDN = 0;
  3488. }
  3489. // Use SSL
  3490. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3491. AP_LDAP_SSL,
  3492. &lspParams->dwUseSSL))) {
  3493. lspParams->dwUseSSL = 0;
  3494. }
  3495. // Do Simple Search
  3496. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3497. AP_LDAP_SIMPLE_SEARCH,
  3498. &lspParams->fSimpleSearch))) {
  3499. lspParams->fSimpleSearch = FALSE;
  3500. }
  3501. #ifdef PAGED_RESULT_SUPPORT
  3502. // Paged Result Support
  3503. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3504. AP_LDAP_PAGED_RESULTS,
  3505. &lspParams->dwPagedResult))) {
  3506. lspParams->dwPagedResult = LDAP_PRESULT_UNKNOWN;
  3507. }
  3508. #endif //#ifdef PAGED_RESULT_SUPPORT
  3509. // Is this an NTDS account
  3510. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetPropDw(lpAccount,
  3511. AP_LDAP_NTDS,
  3512. &lspParams->dwIsNTDS))) {
  3513. lspParams->dwIsNTDS = LDAP_NTDS_UNKNOWN;
  3514. }
  3515. exit:
  3516. if (lpAccount) {
  3517. lpAccount->lpVtbl->Release(lpAccount);
  3518. }
  3519. return(!HR_FAILED(hResult));
  3520. }
  3521. /*
  3522. -
  3523. - SetAccountStringWA
  3524. *
  3525. * Account manager needs ANSI/DBCS so if we have UNICODE data we need to convert to ANSI
  3526. *
  3527. * lpStrA should be a big enough buffer to get the ANSI data
  3528. * cb = CharSizeOf(szStrA)
  3529. */
  3530. void SetAccountStringWA(LPSTR szStrA, LPTSTR lpszData, int cbsz)
  3531. {
  3532. LPSTR lpBufA = NULL;
  3533. Assert(szStrA);
  3534. szStrA[0] = '\0';
  3535. // If the source string pointer is NULL then just return
  3536. if (lpszData == NULL)
  3537. return;
  3538. lpBufA = ConvertWtoA(lpszData);
  3539. if (lpBufA)
  3540. {
  3541. StrCpyNA(szStrA, (LPCSTR)lpBufA, cbsz);
  3542. LocalFreeAndNull((LPVOID*)&lpBufA);
  3543. }
  3544. }
  3545. //*******************************************************************
  3546. //
  3547. // FUNCTION: SetLDAPServerParams
  3548. //
  3549. // PURPOSE: Sets the per-server parameters for the given LDAP server.
  3550. // Parameters include limit on number of entries to retrieve in
  3551. // an LDAP search, the max number of seconds to spend on the
  3552. // server, the max number of seconds to wait at the client,
  3553. // and the type of authentication to use with this server.
  3554. //
  3555. // PARAMETERS: lpszServer - name of the server
  3556. // ServerParams - structure containing the per-server parameters
  3557. // Note: if this parameter is NULL, the key with name lpszServer
  3558. // will be deleted if it exists.
  3559. // Note: lpszUserName and lpszPassword are only stored if
  3560. // dwAuthenticationMethod is LDAP_AUTH_METHOD_SIMPLE. Otherwise,
  3561. // these parameters are ignored. To clear one of the strings,
  3562. // set it to a NULL string (ie ""). Setting the parameter to
  3563. // NULL will result in ERROR_INVALID_PARAMETER.
  3564. //
  3565. // RETURNS: HRESULT
  3566. //
  3567. // HISTORY:
  3568. // 96/07/26 markdu Created.
  3569. // 97/01/19 brucek Port to account manager
  3570. //
  3571. //*******************************************************************
  3572. HRESULT SetLDAPServerParams(
  3573. LPTSTR lpszServer,
  3574. LPLDAPSERVERPARAMS lspParams)
  3575. {
  3576. HRESULT hResult = hrSuccess;
  3577. IImnAccountManager2 * lpAccountManager = NULL;
  3578. IImnAccount * lpAccount = NULL;
  3579. DWORD dwType;
  3580. char szBuf[513];
  3581. if (hResult = InitAccountManager(NULL, &lpAccountManager, NULL)) {
  3582. goto exit;
  3583. }
  3584. SetAccountStringWA(szBuf, lpszServer, CharSizeOf(szBuf));
  3585. if (hResult = lpAccountManager->lpVtbl->FindAccount(lpAccountManager,
  3586. AP_ACCOUNT_NAME,
  3587. szBuf,
  3588. &lpAccount)) {
  3589. DebugTrace(TEXT("Creating account %s\n"), lpszServer);
  3590. if (hResult = lpAccountManager->lpVtbl->CreateAccountObject(lpAccountManager,
  3591. ACCT_DIR_SERV,
  3592. &lpAccount)) {
  3593. DebugTrace(TEXT("CreateAccountObject -> %x\n"), GetScode(hResult));
  3594. goto exit;
  3595. }
  3596. } else {
  3597. // Found an account. Is it LDAP?
  3598. if (HR_FAILED(hResult = lpAccount->lpVtbl->GetServerTypes(lpAccount,
  3599. &dwType))) {
  3600. DebugTrace(TEXT("GetServerTypes() -> %x\n"), GetScode(hResult));
  3601. goto exit;
  3602. }
  3603. if (! (dwType & SRV_LDAP)) {
  3604. DebugTrace(TEXT("%s is already a non-LDAP server name\n"), lpszServer);
  3605. hResult = ResultFromScode(MAPI_E_COLLISION);
  3606. goto exit;
  3607. }
  3608. // Yes, at this point, we know that the existing server is LDAP.
  3609. if (NULL == lspParams) {
  3610. // Are there other account types on this account?
  3611. if (dwType == SRV_LDAP) {
  3612. lpAccount->lpVtbl->Delete(lpAccount);
  3613. } else {
  3614. // BUGBUG: If AcctManager ever supports more than one type per account, we
  3615. // should add code here to remove LDAP from the type.
  3616. }
  3617. // Jump past the property settings
  3618. goto exit;
  3619. }
  3620. }
  3621. // have account object, set its properties
  3622. Assert(lpAccount);
  3623. // Account Name
  3624. SetAccountStringWA(szBuf, lpszServer, CharSizeOf(szBuf));
  3625. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3626. AP_ACCOUNT_NAME,
  3627. szBuf))) { // account name = server name
  3628. DebugTrace(TEXT("SetPropSz(AP_ACCOUNT_NAME, %s) -> %x\n"), lpszServer, GetScode(hResult));
  3629. goto exit;
  3630. }
  3631. // LDAP Server address
  3632. SetAccountStringWA(szBuf,
  3633. (!lspParams->lpszName || !lstrlen(lspParams->lpszName)) ? szNULLString : lspParams->lpszName,
  3634. CharSizeOf(szBuf));
  3635. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3636. AP_LDAP_SERVER,
  3637. szBuf)))
  3638. {
  3639. DebugTrace(TEXT("SetPropSz(AP_LDAP_SERVER, %s) -> %x\n"), lspParams->lpszName ? lspParams->lpszName : TEXT("<NULL>"), GetScode(hResult));
  3640. goto exit;
  3641. }
  3642. // Username
  3643. SetAccountStringWA(szBuf, lspParams->lpszUserName, CharSizeOf(szBuf));
  3644. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3645. AP_LDAP_USERNAME,
  3646. szBuf))) {
  3647. DebugTrace(TEXT("SetPropSz(AP_LDAP_USERNAME, %s) -> %x\n"), lspParams->lpszUserName ? lspParams->lpszUserName : TEXT("<NULL>"), GetScode(hResult));
  3648. goto exit;
  3649. }
  3650. // Password
  3651. SetAccountStringWA(szBuf, lspParams->lpszPassword, CharSizeOf(szBuf));
  3652. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3653. AP_LDAP_PASSWORD,
  3654. szBuf))) {
  3655. DebugTrace(TEXT("SetPropSz(AP_LDAP_PASSWORD, %s) -> %x\n"), lspParams->lpszPassword ? lspParams->lpszPassword : TEXT("<NULL>"), GetScode(hResult));
  3656. goto exit;
  3657. }
  3658. // Advanced Search Attributes
  3659. SetAccountStringWA(szBuf, lspParams->lpszAdvancedSearchAttr, CharSizeOf(szBuf));
  3660. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3661. AP_LDAP_ADVANCED_SEARCH_ATTR,
  3662. szBuf))) {
  3663. DebugTrace(TEXT("SetPropSz(AP_LDAP_ADVANCED_SEARCH_ATTR, %s) -> %x\n"), lspParams->lpszAdvancedSearchAttr ? lspParams->lpszAdvancedSearchAttr : TEXT("<NULL>"), GetScode(hResult));
  3664. goto exit;
  3665. }
  3666. // Authentication method
  3667. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3668. AP_LDAP_AUTHENTICATION,
  3669. lspParams->dwAuthMethod))) {
  3670. DebugTrace(TEXT("SetPropDw(AP_LDAP_AUTHENTICATION, %u) -> %x\n"), lspParams->dwAuthMethod, GetScode(hResult));
  3671. goto exit;
  3672. }
  3673. // LDAP Timeout
  3674. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3675. AP_LDAP_TIMEOUT,
  3676. lspParams->dwSearchTimeLimit))) { // account name = server name
  3677. DebugTrace(TEXT("SetPropDw(AP_LDAP_TIMEOUT, %y) -> %x\n"), lspParams->dwSearchTimeLimit, GetScode(hResult));
  3678. goto exit;
  3679. }
  3680. // LDAP Search Base
  3681. SetAccountStringWA(szBuf, lspParams->lpszBase, CharSizeOf(szBuf));
  3682. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3683. AP_LDAP_SEARCH_BASE,
  3684. szBuf))) {
  3685. DebugTrace(TEXT("SetPropSz(AP_LDAP_SEARCH_BASE, %s) -> %x\n"), lspParams->lpszBase ? lspParams->lpszBase : TEXT("<NULL>"), GetScode(hResult));
  3686. goto exit;
  3687. }
  3688. // Search Limit
  3689. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3690. AP_LDAP_SEARCH_RETURN,
  3691. lspParams->dwSearchSizeLimit))) {
  3692. DebugTrace(TEXT("SetPropDw(AP_LDAP_SEARCH_RETURN, %u) -> %x\n"), lspParams->dwSearchSizeLimit, GetScode(hResult));
  3693. goto exit;
  3694. }
  3695. // Order
  3696. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3697. AP_LDAP_SERVER_ID,
  3698. lspParams->dwID))) {
  3699. DebugTrace(TEXT("SetPropDw(AP_LDAP_SERVER_ID, %u) -> %x\n"), lspParams->dwID, GetScode(hResult));
  3700. goto exit;
  3701. }
  3702. // Resolve flag
  3703. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3704. AP_LDAP_RESOLVE_FLAG,
  3705. lspParams->fResolve))) {
  3706. DebugTrace(TEXT("SetPropDw(AP_LDAP_RESOLVE_FLAG) -> %x\n"), GetScode(hResult));
  3707. }
  3708. // Server URL
  3709. SetAccountStringWA(szBuf, lspParams->lpszURL, CharSizeOf(szBuf));
  3710. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3711. AP_LDAP_URL,
  3712. szBuf))) {
  3713. DebugTrace(TEXT("SetPropSz(AP_LDAP_URL, %s) -> %x\n"), lspParams->lpszURL ? lspParams->lpszURL : TEXT("<NULL>"), GetScode(hResult));
  3714. }
  3715. // Server URL
  3716. SetAccountStringWA(szBuf, lspParams->lpszLogoPath, CharSizeOf(szBuf));
  3717. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropSz(lpAccount,
  3718. AP_LDAP_LOGO,
  3719. szBuf))) {
  3720. DebugTrace(TEXT("SetPropSz(AP_LDAP_URL, %s) -> %x\n"), lspParams->lpszLogoPath ? lspParams->lpszLogoPath : TEXT("<NULL>"), GetScode(hResult));
  3721. }
  3722. // Port
  3723. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3724. AP_LDAP_PORT,
  3725. lspParams->dwPort))) {
  3726. DebugTrace(TEXT("SetPropDw(AP_LDAP_PORT, %u) -> %x\n"), lspParams->dwPort, GetScode(hResult));
  3727. goto exit;
  3728. }
  3729. // Bind DN
  3730. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3731. AP_LDAP_USE_BIND_DN,
  3732. lspParams->dwUseBindDN))) {
  3733. DebugTrace(TEXT("SetPropDw(AP_LDAP_USE_BIND_DN, %u) -> %x\n"), lspParams->dwUseBindDN, GetScode(hResult));
  3734. goto exit;
  3735. }
  3736. // Use SSL
  3737. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3738. AP_LDAP_SSL,
  3739. lspParams->dwUseSSL))) {
  3740. DebugTrace(TEXT("SetPropDw(AP_LDAP_SSL, %u) -> %x\n"), lspParams->dwUseSSL, GetScode(hResult));
  3741. goto exit;
  3742. }
  3743. // Simple Search
  3744. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3745. AP_LDAP_SIMPLE_SEARCH,
  3746. lspParams->fSimpleSearch))) {
  3747. DebugTrace(TEXT("SetPropDw(AP_LDAP_SIMPLE_SEARCH, %u) -> %x\n"), lspParams->fSimpleSearch, GetScode(hResult));
  3748. goto exit;
  3749. }
  3750. #ifdef PAGED_RESULT_SUPPORT
  3751. // Paged Result Support
  3752. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3753. AP_LDAP_PAGED_RESULTS,
  3754. lspParams->dwPagedResult))) {
  3755. DebugTrace(TEXT("SetPropDw(AP_LDAP_PAGED_RESULTS, %u) -> %x\n"), lspParams->dwPagedResult, GetScode(hResult));
  3756. goto exit;
  3757. }
  3758. #endif //#ifdef PAGED_RESULT_SUPPORT
  3759. if (HR_FAILED(hResult = lpAccount->lpVtbl->SetPropDw(lpAccount,
  3760. AP_LDAP_NTDS,
  3761. lspParams->dwIsNTDS))) {
  3762. DebugTrace(TEXT("SetPropDw(AP_LDAP_NTDS, %u) -> %x\n"), lspParams->dwIsNTDS, GetScode(hResult));
  3763. goto exit;
  3764. }
  3765. // Save the changes to this account
  3766. if (HR_FAILED(hResult = lpAccount->lpVtbl->SaveChanges(lpAccount))) {
  3767. DebugTrace(TEXT("Account->SaveChanges -> %x\n"), GetScode(hResult));
  3768. goto exit;
  3769. }
  3770. // AP_LAST_UPDATED
  3771. // AP_RAS_CONNECTION_TYPE
  3772. // AP_RAS_CONNECTOID
  3773. // AP_RAS_CONNECTION_FLAGS
  3774. // AP_RAS_CONNECTED
  3775. exit:
  3776. if (lpAccount) {
  3777. lpAccount->lpVtbl->Release(lpAccount);
  3778. }
  3779. return(hResult);
  3780. }
  3781. //*******************************************************************
  3782. //
  3783. // FUNCTION: LDAPResolveName
  3784. //
  3785. // PURPOSE: Resolves against all the LDAP servers. Maintains
  3786. // list of ambiguous resolves for UI.
  3787. //
  3788. // PARAMETERS: lpAdrBook = IADDRBOOK object
  3789. // lpAdrList -> ADRLIST to resolve
  3790. // lpFlagList -> FlagList
  3791. // lpAmbiguousTables -> list of ambiguous match tables [in/out]
  3792. // lpulResolved -> Resolved count [in/out]
  3793. // lpulAmbiguous -> Ambiguous count [in/out]
  3794. // lpulUnresolved -> Unresolved count [in/out]
  3795. //
  3796. // RETURNS: HRESULT
  3797. //
  3798. // HISTORY:
  3799. // 96/07/15 brucek Created.
  3800. //
  3801. //*******************************************************************
  3802. HRESULT LDAPResolveName(
  3803. LPADRBOOK lpAddrBook,
  3804. LPADRLIST lpAdrList,
  3805. LPFlagList lpFlagList,
  3806. LPAMBIGUOUS_TABLES lpAmbiguousTables,
  3807. ULONG ulFlags)
  3808. {
  3809. SCODE sc;
  3810. HRESULT hResult;
  3811. LPMAPITABLE lpRootTable = NULL;
  3812. LPMAPITABLE lpAmbiguousTable = NULL;
  3813. LPABCONT lpRoot = NULL;
  3814. ULONG ulObjType;
  3815. ULONG i;
  3816. LPABCONT lpLDAPContainer = NULL;
  3817. LPFlagList lpFlagListOld = NULL;
  3818. LPSRowSet lpRow = NULL;
  3819. ULONG ulResolved, ulUnresolved, ulAmbiguous;
  3820. BOOL bUnicode = (ulFlags & WAB_RESOLVE_UNICODE);
  3821. // Open Root container
  3822. if (! (hResult = lpAddrBook->lpVtbl->OpenEntry(lpAddrBook,
  3823. 0,
  3824. NULL,
  3825. NULL,
  3826. 0,
  3827. &ulObjType,
  3828. (LPUNKNOWN *)&lpRoot))) {
  3829. if (! (hResult = lpRoot->lpVtbl->GetContentsTable(lpRoot,
  3830. MAPI_UNICODE,
  3831. &lpRootTable))) {
  3832. SRestriction resAnd[2]; // 0 = LDAP, 1 = ResolveFlag
  3833. SRestriction resLDAPResolve;
  3834. SPropValue ResolveFlag;
  3835. ULONG cRows;
  3836. // Set the columns
  3837. lpRootTable->lpVtbl->SetColumns(lpRootTable,
  3838. (LPSPropTagArray)&irnColumns,
  3839. 0);
  3840. // Restrict: Only show LDAP containers with Resolve TRUE
  3841. resAnd[0].rt = RES_EXIST;
  3842. resAnd[0].res.resExist.ulReserved1 = 0;
  3843. resAnd[0].res.resExist.ulReserved2 = 0;
  3844. resAnd[0].res.resExist.ulPropTag = PR_WAB_LDAP_SERVER;
  3845. ResolveFlag.ulPropTag = PR_WAB_RESOLVE_FLAG;
  3846. ResolveFlag.Value.b = TRUE;
  3847. resAnd[1].rt = RES_PROPERTY;
  3848. resAnd[1].res.resProperty.relop = RELOP_EQ;
  3849. resAnd[1].res.resProperty.ulPropTag = PR_WAB_RESOLVE_FLAG;
  3850. resAnd[1].res.resProperty.lpProp = &ResolveFlag;
  3851. resLDAPResolve.rt = RES_AND;
  3852. resLDAPResolve.res.resAnd.cRes = 2;
  3853. resLDAPResolve.res.resAnd.lpRes = resAnd;
  3854. if (HR_FAILED(hResult = lpRootTable->lpVtbl->Restrict(lpRootTable,
  3855. &resLDAPResolve,
  3856. 0))) {
  3857. DebugTraceResult( TEXT("RootTable: Restrict"), hResult);
  3858. goto exit;
  3859. }
  3860. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3861. cRows = 1;
  3862. while (cRows && ulUnresolved) {
  3863. if (hResult = lpRootTable->lpVtbl->QueryRows(lpRootTable,
  3864. 1, // one row at a time
  3865. 0, // ulFlags
  3866. &lpRow)) {
  3867. DebugTraceResult( TEXT("ResolveName:QueryRows"), hResult);
  3868. } else if (lpRow) {
  3869. if (cRows = lpRow->cRows) { // Yes, single '='
  3870. // Open the container
  3871. if (! (hResult = lpAddrBook->lpVtbl->OpenEntry(lpAddrBook,
  3872. lpRow->aRow[0].lpProps[irnPR_ENTRYID].Value.bin.cb,
  3873. (LPENTRYID)lpRow->aRow[0].lpProps[irnPR_ENTRYID].Value.bin.lpb,
  3874. NULL,
  3875. 0,
  3876. &ulObjType,
  3877. (LPUNKNOWN *)&lpLDAPContainer))) {
  3878. ULONG ulAmbiguousOld = ulAmbiguous;
  3879. __UPV * lpv;
  3880. //
  3881. // Create a copy of the current flag list
  3882. //
  3883. // Allocate the lpFlagList first and zero fill it.
  3884. if (sc = MAPIAllocateBuffer((UINT)CbNewSPropTagArray(lpAdrList->cEntries),
  3885. &lpFlagListOld)) {
  3886. hResult = ResultFromScode(sc);
  3887. goto exit;
  3888. }
  3889. MAPISetBufferName(lpFlagListOld, TEXT("WAB: lpFlagListOld in IAB_ResolveNames"));
  3890. lpFlagListOld->cFlags = lpAdrList->cEntries;
  3891. for (i = 0; i < lpFlagListOld->cFlags; i++) {
  3892. lpFlagListOld->ulFlag[i] = lpFlagList->ulFlag[i];
  3893. }
  3894. // Resolve against the LDAP container
  3895. if (! HR_FAILED(hResult = lpLDAPContainer->lpVtbl->ResolveNames(lpLDAPContainer,
  3896. NULL, // tag set
  3897. (bUnicode ? MAPI_UNICODE : 0), // ulFlags
  3898. lpAdrList,
  3899. lpFlagList))) {
  3900. // Ignore warnings
  3901. hResult = hrSuccess;
  3902. }
  3903. // Did this container report Ambiguous on any entries?
  3904. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3905. if (ulAmbiguousOld != ulAmbiguous) {
  3906. // Find which entries were reported as ambiguous and
  3907. // create a table to return.
  3908. for (i = 0; i < lpFlagList->cFlags; i++) {
  3909. if (lpFlagList->ulFlag[i] == MAPI_AMBIGUOUS &&
  3910. lpFlagListOld->ulFlag[i] != MAPI_AMBIGUOUS) {
  3911. // The search got an ambiguous result. Deal with it!
  3912. if (hResult = lpLDAPContainer->lpVtbl->GetContentsTable(lpLDAPContainer,
  3913. (bUnicode ? MAPI_UNICODE : 0),
  3914. &lpAmbiguousTable)) {
  3915. DebugTraceResult( TEXT("LDAPResolveName:GetContentsTable"), hResult);
  3916. // goto exit; // is this fatal?
  3917. hResult = hrSuccess;
  3918. } else {
  3919. // populate the table
  3920. SRestriction resAnd[1]; // 0 = DisplayName
  3921. SRestriction resLDAPFind;
  3922. SPropValue DisplayName;
  3923. ULONG ulPropTag = ( bUnicode ? PR_DISPLAY_NAME : // <note> assumes UNICODE defined
  3924. CHANGE_PROP_TYPE(PR_DISPLAY_NAME, PT_STRING8) );
  3925. if (lpv = FindAdrEntryProp(lpAdrList, i, ulPropTag))
  3926. {
  3927. DisplayName.ulPropTag = ulPropTag;
  3928. if(bUnicode)
  3929. DisplayName.Value.lpszW = lpv->lpszW;
  3930. else
  3931. DisplayName.Value.lpszA = lpv->lpszA;
  3932. resAnd[0].rt = RES_PROPERTY;
  3933. resAnd[0].res.resProperty.relop = RELOP_EQ;
  3934. resAnd[0].res.resProperty.ulPropTag = ulPropTag;
  3935. resAnd[0].res.resProperty.lpProp = &DisplayName;
  3936. resLDAPFind.rt = RES_AND;
  3937. resLDAPFind.res.resAnd.cRes = 1;
  3938. resLDAPFind.res.resAnd.lpRes = resAnd;
  3939. if (hResult = lpAmbiguousTable->lpVtbl->FindRow(lpAmbiguousTable,
  3940. &resLDAPFind,
  3941. BOOKMARK_BEGINNING,
  3942. 0)) {
  3943. DebugTraceResult( TEXT("LDAPResolveName:GetContentsTable"), hResult);
  3944. // goto exit; // is this fatal?
  3945. hResult = hrSuccess;
  3946. UlRelease(lpAmbiguousTable);
  3947. lpAmbiguousTable = NULL;
  3948. } else {
  3949. // Got a contents table; put it in the
  3950. // ambiguity tables list.
  3951. Assert(i < lpAmbiguousTables->cEntries);
  3952. lpAmbiguousTables->lpTable[i] = lpAmbiguousTable;
  3953. }
  3954. }
  3955. }
  3956. }
  3957. }
  3958. }
  3959. FreeBufferAndNull(&lpFlagListOld);
  3960. UlRelease(lpLDAPContainer);
  3961. lpLDAPContainer = NULL;
  3962. }
  3963. }
  3964. FreeProws(lpRow);
  3965. lpRow = NULL;
  3966. }
  3967. }
  3968. UlRelease(lpRootTable);
  3969. lpRootTable = NULL;
  3970. }
  3971. UlRelease(lpRoot);
  3972. lpRoot = NULL;
  3973. }
  3974. exit:
  3975. UlRelease(lpLDAPContainer);
  3976. UlRelease(lpRootTable);
  3977. UlRelease(lpRoot);
  3978. if (lpRow) {
  3979. FreeProws(lpRow);
  3980. }
  3981. FreeBufferAndNull(&lpFlagListOld);
  3982. return(hResult);
  3983. }
  3984. //*******************************************************************
  3985. //
  3986. // FUNCTION: HRFromLDAPError
  3987. //
  3988. // PURPOSE: Convert LDAP error code into an HRESULT.
  3989. //
  3990. // PARAMETERS: ulErr - error code returned by LDAP, or LDAP_ERROR if the
  3991. // LDAP function does not directly return an error code.
  3992. // pLDAP - contains ld_errno member that holds the error
  3993. // if nErr is LDAP_ERROR.
  3994. // scDefault - SCODE for error to default to. If this is
  3995. // NULL, default is MAPI_E_CALL_FAILED.
  3996. //
  3997. // RETURNS: HRESULT that is closest match for the LDAP error.
  3998. //
  3999. // HISTORY:
  4000. // 96/07/22 markdu Created.
  4001. //
  4002. //*******************************************************************
  4003. HRESULT HRFromLDAPError(
  4004. ULONG ulErr,
  4005. LDAP* pLDAP,
  4006. SCODE scDefault)
  4007. {
  4008. HRESULT hr;
  4009. DebugPrintError(( TEXT("LDAP error 0x%.2x: %s\n"), ulErr, gpfnLDAPErr2String(ulErr)));
  4010. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  4011. if ((LDAP_ERROR == ulErr) && pLDAP)
  4012. {
  4013. // Get the error code from the LDAP structure.
  4014. ulErr = pLDAP->ld_errno;
  4015. }
  4016. // Translate the error.
  4017. switch(ulErr)
  4018. {
  4019. case LDAP_SUCCESS:
  4020. hr = hrSuccess;
  4021. break;
  4022. case LDAP_ADMIN_LIMIT_EXCEEDED:
  4023. case LDAP_TIMELIMIT_EXCEEDED:
  4024. case LDAP_SIZELIMIT_EXCEEDED:
  4025. case LDAP_RESULTS_TOO_LARGE:
  4026. // With these error messages it is still possible to get back some
  4027. // valid data. If there is valid data, then the error should be
  4028. // MAPI_W_PARTIAL_COMPLETION instead of MAPI_E_UNABLE_TO_COMPLETE.
  4029. // It is the responibility of the caller to make this change.
  4030. hr = ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE);
  4031. break;
  4032. case LDAP_NO_SUCH_OBJECT:
  4033. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  4034. break;
  4035. case LDAP_AUTH_METHOD_NOT_SUPPORTED:
  4036. case LDAP_STRONG_AUTH_REQUIRED:
  4037. case LDAP_INAPPROPRIATE_AUTH:
  4038. case LDAP_INVALID_CREDENTIALS:
  4039. case LDAP_INSUFFICIENT_RIGHTS:
  4040. hr = ResultFromScode(MAPI_E_NO_ACCESS);
  4041. break;
  4042. case LDAP_SERVER_DOWN:
  4043. hr = ResultFromScode(MAPI_E_NETWORK_ERROR);
  4044. break;
  4045. case LDAP_TIMEOUT:
  4046. hr = ResultFromScode(MAPI_E_TIMEOUT);
  4047. break;
  4048. case LDAP_USER_CANCELLED:
  4049. hr = ResultFromScode(MAPI_E_USER_CANCEL);
  4050. break;
  4051. default:
  4052. if (scDefault)
  4053. {
  4054. hr = ResultFromScode(scDefault);
  4055. }
  4056. break;
  4057. }
  4058. return hr;
  4059. }
  4060. //*******************************************************************
  4061. //
  4062. // DNtoLDAPURL
  4063. //
  4064. // Converts a DN into an LDAP URL
  4065. //
  4066. //
  4067. //
  4068. //*******************************************************************
  4069. static const LPTSTR lpLDAPPrefix = TEXT("ldap://");
  4070. void DNtoLDAPURL(LPTSTR lpServer, LPTSTR lpDN, LPTSTR szURL, ULONG cchURL)
  4071. {
  4072. if(!lpServer || !lpDN || !szURL)
  4073. return;
  4074. StrCpyN(szURL, lpLDAPPrefix, cchURL);
  4075. StrCatBuff(szURL, lpServer, cchURL);
  4076. StrCatBuff(szURL, TEXT("/"), cchURL);
  4077. StrCatBuff(szURL, lpDN, cchURL);
  4078. return;
  4079. }
  4080. //*******************************************************************
  4081. //
  4082. // FUNCTION: TranslateAttrs
  4083. //
  4084. // PURPOSE: Cycle through the attributes in the entry, convert
  4085. // them into MAPI properties and return them.
  4086. //
  4087. // PARAMETERS: pLDAP - LDAP structure for this session
  4088. // lpEntry - Entry whose attributes to translate
  4089. // pulcProps - buffer to hold number of properties returned
  4090. // lpPropArray - buffer to hold returned properties
  4091. //
  4092. // RETURNS: HRESULT error code.
  4093. //
  4094. // HISTORY:
  4095. // 96/07/22 markdu Created.
  4096. //
  4097. //*******************************************************************
  4098. typedef enum
  4099. {
  4100. e_pager = 0, // highest priority
  4101. e_otherPager,
  4102. e_OfficePager, // lowest
  4103. e_pagerMax
  4104. };
  4105. HRESULT TranslateAttrs(
  4106. LDAP* pLDAP,
  4107. LDAPMessage* lpEntry,
  4108. LPTSTR lpServer,
  4109. ULONG* pulcProps,
  4110. LPSPropValue lpPropArray)
  4111. {
  4112. HRESULT hr = hrSuccess;
  4113. ULONG ulcProps = 0;
  4114. ULONG ulPropTag;
  4115. ULONG ulPrimaryEmailIndex = MAX_ULONG;
  4116. ULONG ulContactAddressesIndex = MAX_ULONG;
  4117. ULONG ulContactAddrTypesIndex = MAX_ULONG;
  4118. ULONG ulContactDefAddrIndexIndex = MAX_ULONG;
  4119. ULONG cbValue;
  4120. ULONG i, j;
  4121. SCODE sc;
  4122. LPTSTR szAttr;
  4123. BerElement* ptr;
  4124. LPTSTR* aszValues;
  4125. LPTSTR atszPagerAttr[e_pagerMax] = {0}; // [PaulHi] 3/17/99 Raid 73733 Choose between three pager attributes
  4126. // 0 - "pager", 1 - "otherpager", 2 - "officepager" in this order
  4127. #ifdef PARAMETER_VALIDATION
  4128. if (IsBadReadPtr(pLDAP, sizeof(LDAP)))
  4129. {
  4130. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4131. }
  4132. if (IsBadReadPtr(lpEntry, sizeof(LDAPMessage)))
  4133. {
  4134. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4135. }
  4136. if (IsBadWritePtr(pulcProps, sizeof(ULONG)))
  4137. {
  4138. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4139. }
  4140. if (IsBadReadPtr(lpPropArray, sizeof(SPropValue)))
  4141. {
  4142. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4143. }
  4144. #endif // PARAMETER_VALIDATION
  4145. szAttr = gpfnLDAPFirstAttr(pLDAP, lpEntry, &ptr);
  4146. while (szAttr)
  4147. {
  4148. //DebugTrace(TEXT("%s / "),szAttr);
  4149. ulPropTag = LDAPAttrToMAPIProp(szAttr);
  4150. // [PaulHi] 3/17/99 Raid 73733 Save up to e_pagerMax pager attribute types and skip. Later
  4151. // we need to choose a pager property by order of prioriy, in case there is more than one.
  4152. if (ulPropTag == PR_PAGER_TELEPHONE_NUMBER)
  4153. {
  4154. aszValues = gpfnLDAPGetValues(pLDAP, lpEntry, szAttr);
  4155. if (aszValues && aszValues[0])
  4156. {
  4157. ULONG cchSize = lstrlen(aszValues[0])+1;
  4158. LPTSTR lptszTemp = LocalAlloc(LMEM_ZEROINIT, cchSize * sizeof(TCHAR));
  4159. if (!lptszTemp) goto error;
  4160. StrCpyN(lptszTemp, aszValues[0], cchSize);
  4161. gpfnLDAPValueFree(aszValues);
  4162. if (!lstrcmpi(szAttr, cszAttr_pager))
  4163. {
  4164. LocalFreeAndNull(&(atszPagerAttr[0]));
  4165. atszPagerAttr[e_pager] = lptszTemp;
  4166. }
  4167. else if (!lstrcmpi(szAttr, cszAttr_otherPager))
  4168. {
  4169. LocalFreeAndNull(&(atszPagerAttr[1]));
  4170. atszPagerAttr[e_otherPager] = lptszTemp;
  4171. }
  4172. else
  4173. {
  4174. // If this Assert fires it must mean that the gAttrMap mapping table has changed
  4175. // to include yet another LDAP attribute to be associated with PR_PAGER_TELEPHONE_NUMBER.
  4176. // Increase the atszPagerAttr[] array to include this too.
  4177. Assert(lstrcmpi(szAttr, cszAttr_OfficePager) == 0);
  4178. LocalFreeAndNull(&(atszPagerAttr[2]));
  4179. atszPagerAttr[e_OfficePager] = lptszTemp;
  4180. }
  4181. }
  4182. goto endloop;
  4183. }
  4184. switch (PROP_TYPE(ulPropTag))
  4185. {
  4186. // BUGBUG currently only works for PT_MV_BINARY, PT_TSTRING or PT_MV_TSTRING properties
  4187. case PT_TSTRING:
  4188. {
  4189. // Get the value for this attribute
  4190. aszValues = gpfnLDAPGetValues(pLDAP, lpEntry, szAttr);
  4191. if (aszValues)
  4192. {
  4193. // BUGBUG for now just use first value (aszValues[0] )
  4194. if (aszValues[0] && (cbValue = lstrlen(aszValues[0])))
  4195. {
  4196. ULONG cbExtra = 0;
  4197. #ifdef DEBUG
  4198. if(!lstrcmpi(szAttr, TEXT("cn")))
  4199. {
  4200. DebugTrace(TEXT("cn=%s\n"),aszValues[0]);
  4201. }
  4202. #endif
  4203. lpPropArray[ulcProps].ulPropTag = ulPropTag;
  4204. lpPropArray[ulcProps].dwAlignPad = 0;
  4205. // If this is a postalAddress attribute, we need to replace $'s
  4206. // with \r\n. Add one byte for each $ in the string.
  4207. if ((PR_STREET_ADDRESS == ulPropTag) ||
  4208. (PR_HOME_ADDRESS_STREET == ulPropTag))
  4209. {
  4210. cbExtra = CountDollars(aszValues[0]);
  4211. }
  4212. if (PR_WAB_MANAGER == ulPropTag && lpServer)
  4213. {
  4214. cbExtra = lstrlen(lpLDAPPrefix) + lstrlen(lpServer) + 1;
  4215. }
  4216. // Allocate more space for the data
  4217. sc = MAPIAllocateMore(sizeof(TCHAR)*(cbValue + cbExtra + 1), lpPropArray,
  4218. (LPVOID *)&(lpPropArray[ulcProps].Value.LPSZ));
  4219. if (sc)
  4220. {
  4221. goto error;
  4222. }
  4223. // Copy the data, replacing $'s if necessary.
  4224. if ((0 != cbExtra) &&
  4225. ((PR_STREET_ADDRESS == ulPropTag) ||
  4226. (PR_HOME_ADDRESS_STREET == ulPropTag)))
  4227. {
  4228. DollarsToLFs(aszValues[0], lpPropArray[ulcProps].Value.LPSZ, cbValue + cbExtra + 1);
  4229. }
  4230. else if(PR_WAB_MANAGER == ulPropTag && lpServer)
  4231. {
  4232. DNtoLDAPURL(lpServer, aszValues[0], lpPropArray[ulcProps].Value.LPSZ, cbValue + cbExtra + 1);
  4233. }
  4234. else
  4235. {
  4236. StrCpyN(lpPropArray[ulcProps].Value.LPSZ, aszValues[0], cbValue + cbExtra + 1);
  4237. }
  4238. // If this is PR_EMAIL_ADDRESS, create a PR_ADDRTYPE entry as well
  4239. if (PR_EMAIL_ADDRESS == ulPropTag)
  4240. {
  4241. // Remember where the email value was, so we can add it to
  4242. // PR_CONTACT_EMAIL_ADDRESSES later
  4243. ulPrimaryEmailIndex = ulcProps;
  4244. ulcProps++;
  4245. lpPropArray[ulcProps].ulPropTag = PR_ADDRTYPE;
  4246. lpPropArray[ulcProps].dwAlignPad = 0;
  4247. lpPropArray[ulcProps].Value.LPSZ = (LPTSTR)szSMTP;
  4248. }
  4249. ulcProps++;
  4250. }
  4251. gpfnLDAPValueFree(aszValues);
  4252. } // if aszValues
  4253. break;
  4254. }
  4255. case PT_MV_TSTRING:
  4256. if(ulPropTag == PR_WAB_SECONDARY_EMAIL_ADDRESSES)
  4257. {
  4258. ULONG ulcValues;
  4259. ULONG ulcSMTP = 0;
  4260. ULONG ulProp = 0;
  4261. UNALIGNED LPTSTR FAR *lppszAddrs;
  4262. UNALIGNED LPTSTR FAR *lppszTypes;
  4263. // Only property of this type that we know how to handle is
  4264. // PR_WAB_SECONDARY_EMAIL_ADDRESSES
  4265. Assert(PR_WAB_SECONDARY_EMAIL_ADDRESSES == ulPropTag);
  4266. // Get the value for this attribute
  4267. aszValues = gpfnLDAPGetValues(pLDAP, lpEntry, szAttr);
  4268. if (aszValues)
  4269. {
  4270. // Cycle through the addresses and count the number that are SMTP
  4271. ulcValues = gpfnLDAPCountValues(aszValues);
  4272. for (i=0;i<ulcValues;i++)
  4273. {
  4274. if (TRUE == IsSMTPAddress(aszValues[i], NULL))
  4275. ulcSMTP++;
  4276. }
  4277. // We are done if there were no SMTP addresses.
  4278. if (0 == ulcSMTP)
  4279. break;
  4280. // Set the default address to be the first one for now.
  4281. lpPropArray[ulcProps].ulPropTag = PR_CONTACT_DEFAULT_ADDRESS_INDEX;
  4282. lpPropArray[ulcProps].Value.l = 0;
  4283. ulContactDefAddrIndexIndex = ulcProps;
  4284. ulcProps++;
  4285. // Create the PR_CONTACT_EMAIL_ADDRESSES entry and allocate space for the array.
  4286. // Include space for an extra entry so we can add the PR_EMAIL_ADDRESS later.
  4287. lpPropArray[ulcProps].ulPropTag = PR_CONTACT_EMAIL_ADDRESSES;
  4288. lpPropArray[ulcProps].Value.MVSZ.cValues = ulcSMTP;
  4289. sc = MAPIAllocateMore((ulcSMTP + 1) * sizeof(LPTSTR), lpPropArray,
  4290. (LPVOID *)&(lpPropArray[ulcProps].Value.MVSZ.LPPSZ));
  4291. if (sc)
  4292. goto error;
  4293. lppszAddrs = lpPropArray[ulcProps].Value.MVSZ.LPPSZ;
  4294. ZeroMemory((LPVOID)lppszAddrs, (ulcSMTP + 1) * sizeof(LPTSTR));
  4295. // Create the PR_CONTACT_ADDRTYPES entry and allocate space for the array.
  4296. // Include space for an extra entry so we can add the PR_EMAIL_ADDRESS later.
  4297. lpPropArray[ulcProps + 1].ulPropTag = PR_CONTACT_ADDRTYPES;
  4298. lpPropArray[ulcProps + 1].Value.MVSZ.cValues = ulcSMTP;
  4299. sc = MAPIAllocateMore((ulcSMTP + 1) * sizeof(LPTSTR), lpPropArray,
  4300. (LPVOID *)&(lpPropArray[ulcProps + 1].Value.MVSZ.LPPSZ));
  4301. if (sc)
  4302. goto error;
  4303. lppszTypes = lpPropArray[ulcProps + 1].Value.MVSZ.LPPSZ;
  4304. ZeroMemory((LPVOID)lppszTypes, (ulcSMTP + 1) * sizeof(LPTSTR));
  4305. // Add the SMTP addresses to the list
  4306. for (i=0;i<ulcValues;i++)
  4307. {
  4308. LPTSTR lptszEmailName = NULL;
  4309. if (TRUE == IsSMTPAddress(aszValues[i], &lptszEmailName))
  4310. {
  4311. // Allocate more space for the email address and copy it.
  4312. ULONG cchSize = lstrlen(lptszEmailName) + 1;
  4313. sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropArray,
  4314. (LPVOID *)&(lppszAddrs[ulProp]));
  4315. if (sc)
  4316. goto error;
  4317. StrCpyN(lppszAddrs[ulProp], lptszEmailName, cchSize);
  4318. // Fill in the address type.
  4319. lppszTypes[ulProp] = (LPTSTR)szSMTP;
  4320. // Go on to the next one. Skip the rest if we know we have done all SMTP.
  4321. ulProp++;
  4322. if (ulProp >= ulcSMTP)
  4323. break;
  4324. }
  4325. }
  4326. // Remember where the PR_CONTACT_EMAIL_ADDRESSES value was, so we can
  4327. // add PR_EMAIL_ADDRESS to it later
  4328. ulContactAddressesIndex = ulcProps;
  4329. ulContactAddrTypesIndex = ulcProps + 1;
  4330. ulcProps += 2;
  4331. gpfnLDAPValueFree(aszValues);
  4332. } // if aszValues
  4333. }
  4334. else if(ulPropTag == PR_WAB_CONF_SERVERS)
  4335. {
  4336. // Even though this is MV_TSTRING prop, the ldap server
  4337. // will only really return 1 single item which is of the format
  4338. // server/conf-email
  4339. // All we need to do is put it in the prop with a callto:// prefix ...
  4340. //
  4341. ULONG ulcValues;
  4342. ULONG ulProp = 0;
  4343. ULONG ulPrefixLen;
  4344. UNALIGNED LPTSTR FAR *lppszServers;
  4345. // Get the value for this attribute
  4346. aszValues = gpfnLDAPGetValues(pLDAP, lpEntry, szAttr);
  4347. if (aszValues)
  4348. {
  4349. ULONG cchSize;
  4350. lpPropArray[ulcProps].ulPropTag = PR_WAB_CONF_SERVERS;
  4351. lpPropArray[ulcProps].Value.MVSZ.cValues = 1;
  4352. sc = MAPIAllocateMore(sizeof(LPTSTR), lpPropArray,
  4353. (LPVOID *)&(lpPropArray[ulcProps].Value.MVSZ.LPPSZ));
  4354. if (sc)
  4355. {
  4356. goto error;
  4357. }
  4358. lppszServers = lpPropArray[ulcProps].Value.MVSZ.LPPSZ;
  4359. ulPrefixLen = lstrlen(szCallto) + 1;
  4360. // Allocate more space for the email address and copy it.
  4361. cchSize = lstrlen(aszValues[0]) + ulPrefixLen + 1;
  4362. sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropArray,
  4363. (LPVOID *)&(lppszServers[0]));
  4364. if (sc)
  4365. {
  4366. goto error;
  4367. }
  4368. StrCpyN(lppszServers[0], szCallto, cchSize);
  4369. StrCatBuff(lppszServers[0], (LPTSTR) aszValues[0], cchSize);
  4370. ulcProps++;
  4371. gpfnLDAPValueFree(aszValues);
  4372. } // if aszValues
  4373. }
  4374. else if(ulPropTag == PR_WAB_REPORTS && lpServer)
  4375. {
  4376. ULONG ulcValues = 0;
  4377. ULONG ulLen = 0;
  4378. UNALIGNED LPTSTR FAR *lppszServers = NULL;
  4379. // Get the value for this attribute
  4380. aszValues = gpfnLDAPGetValues(pLDAP, lpEntry, szAttr);
  4381. if (aszValues)
  4382. {
  4383. ulcValues = gpfnLDAPCountValues(aszValues);
  4384. lpPropArray[ulcProps].ulPropTag = PR_WAB_REPORTS;
  4385. lpPropArray[ulcProps].Value.MVSZ.cValues = ulcValues;
  4386. sc = MAPIAllocateMore((ulcValues+1)*sizeof(LPTSTR), lpPropArray,
  4387. (LPVOID *)&(lpPropArray[ulcProps].Value.MVSZ.LPPSZ));
  4388. if (sc)
  4389. goto error;
  4390. lppszServers = lpPropArray[ulcProps].Value.MVSZ.LPPSZ;
  4391. for(i=0;i<ulcValues;i++)
  4392. {
  4393. ulLen = (lstrlen(lpLDAPPrefix) + lstrlen(lpServer) + 1 + lstrlen(aszValues[i]) + 1);
  4394. // Allocate more space for the email address and copy it.
  4395. sc = MAPIAllocateMore(sizeof(TCHAR)*ulLen, lpPropArray,
  4396. (LPVOID *)&(lppszServers[i]));
  4397. if (sc)
  4398. goto error;
  4399. DNtoLDAPURL(lpServer, aszValues[i], lppszServers[i], ulLen);
  4400. }
  4401. ulcProps++;
  4402. gpfnLDAPValueFree(aszValues);
  4403. } // if aszValues
  4404. }
  4405. break;
  4406. case PT_MV_BINARY:
  4407. {
  4408. ULONG ulcValues;
  4409. struct berval** ppberval;
  4410. BOOL bSMIME = FALSE;
  4411. // Only property of this type that we know how to handle is
  4412. // PR_USER_X509_CERTIFICATE
  4413. Assert(PR_USER_X509_CERTIFICATE == ulPropTag);
  4414. DebugTrace(TEXT("%s\n"),szAttr);
  4415. if(!lstrcmpi(szAttr, cszAttr_userSMIMECertificate) || !lstrcmpi(szAttr, cszAttr_userSMIMECertificatebinary))
  4416. bSMIME = TRUE;
  4417. // Get the value for this attribute
  4418. ppberval = gpfnLDAPGetValuesLen(pLDAP, lpEntry, szAttr);
  4419. if (ppberval && (*ppberval) && (*ppberval)->bv_len)
  4420. {
  4421. ulcValues = gpfnLDAPCountValuesLen(ppberval);
  4422. if (0 != ulcValues)
  4423. {
  4424. ULONG cbNew = 0,k=0;
  4425. /* We dont want to translate the LDAP Cert to a MAPI Cert just yet
  4426. For now we will put the raw cert data into PR_WAB_LDAP_RAWCERT and
  4427. do the conversion when the user calls OpenEntry on this LDAP Contact
  4428. */
  4429. lpPropArray[ulcProps].ulPropTag = bSMIME ? PR_WAB_LDAP_RAWCERTSMIME: PR_WAB_LDAP_RAWCERT;
  4430. lpPropArray[ulcProps].dwAlignPad = 0;
  4431. lpPropArray[ulcProps].Value.MVbin.cValues = ulcValues;
  4432. if(!FAILED(sc = MAPIAllocateMore(sizeof(SBinary)*ulcValues,lpPropArray,(LPVOID)&(lpPropArray[ulcProps].Value.MVbin.lpbin))))
  4433. {
  4434. for(k=0;k<ulcValues;k++)
  4435. {
  4436. cbNew = lpPropArray[ulcProps].Value.MVbin.lpbin[k].cb = (DWORD)((ppberval[k])->bv_len);
  4437. if (FAILED(sc = MAPIAllocateMore(cbNew, lpPropArray, (LPVOID)&(lpPropArray[ulcProps].Value.MVbin.lpbin[k].lpb))))
  4438. {
  4439. //hr = ResultFromScode(sc);
  4440. ulcProps--;
  4441. goto endloop;
  4442. }
  4443. CopyMemory(lpPropArray[ulcProps].Value.MVbin.lpbin[k].lpb, (PBYTE)((ppberval[k])->bv_val), cbNew);
  4444. }
  4445. }
  4446. ulcProps++;
  4447. }
  4448. gpfnLDAPValueFreeLen(ppberval);
  4449. } // if ppberval
  4450. }
  4451. break;
  4452. case PT_NULL:
  4453. break;
  4454. default:
  4455. Assert((PROP_TYPE(ulPropTag) == PT_TSTRING) ||
  4456. (PROP_TYPE(ulPropTag) == PT_MV_TSTRING));
  4457. break;
  4458. } // switch
  4459. endloop:
  4460. // Get the next attribute
  4461. szAttr = gpfnLDAPNextAttr(pLDAP, lpEntry, ptr);
  4462. } // while szAttr
  4463. // [PaulHi] 3/17/99 Raid 73733 Add the pager property here, if any. These
  4464. // will have been added in order of priority so just grab the first valid one.
  4465. {
  4466. for (i=0; i<e_pagerMax; i++)
  4467. {
  4468. if (atszPagerAttr[i])
  4469. {
  4470. lpPropArray[ulcProps].ulPropTag = PR_PAGER_TELEPHONE_NUMBER;
  4471. lpPropArray[ulcProps].dwAlignPad = 0;
  4472. cbValue = lstrlen(atszPagerAttr[i]);
  4473. sc = MAPIAllocateMore(sizeof(TCHAR)*(cbValue + 1), lpPropArray,
  4474. (LPVOID *)&(lpPropArray[ulcProps].Value.LPSZ));
  4475. if (sc)
  4476. goto error;
  4477. StrCpyN(lpPropArray[ulcProps].Value.LPSZ, atszPagerAttr[i], cbValue+1);
  4478. ++ulcProps;
  4479. break;
  4480. }
  4481. }
  4482. // Clean up
  4483. for (i=0; i<e_pagerMax; i++)
  4484. LocalFreeAndNull(&(atszPagerAttr[i]));
  4485. }
  4486. if (ulcProps)
  4487. {
  4488. // Remove duplicates.
  4489. for (i=0;i<ulcProps - 1;i++)
  4490. {
  4491. // If there are any entries in the array that have the same
  4492. // type as this one, replace them with PR_NULL.
  4493. ulPropTag = lpPropArray[i].ulPropTag;
  4494. if (PR_NULL != ulPropTag)
  4495. {
  4496. for (j=i+1;j<ulcProps;j++)
  4497. {
  4498. if (ulPropTag == lpPropArray[j].ulPropTag)
  4499. {
  4500. lpPropArray[j].ulPropTag = PR_NULL;
  4501. }
  4502. }
  4503. }
  4504. }
  4505. // Fix up the email address properties
  4506. if ((MAX_ULONG == ulPrimaryEmailIndex) && (ulContactAddressesIndex < ulcProps))
  4507. {
  4508. LPTSTR lpszDefault;
  4509. ULONG cchSize;
  4510. // We got only secondary email addressess. Copy one to the primary address.
  4511. // Take the first one, since it is already set as default anyway.
  4512. lpPropArray[ulcProps].ulPropTag = PR_EMAIL_ADDRESS;
  4513. lpPropArray[ulcProps].dwAlignPad = 0;
  4514. // Allocate more space for the email address and copy it.
  4515. lpszDefault = lpPropArray[ulContactAddressesIndex].Value.MVSZ.LPPSZ[0];
  4516. cchSize = lstrlen(lpszDefault) + 1;
  4517. sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropArray,
  4518. (LPVOID *)&(lpPropArray[ulcProps].Value.LPSZ));
  4519. if (sc)
  4520. {
  4521. goto error;
  4522. }
  4523. StrCpyN(lpPropArray[ulcProps].Value.LPSZ, lpszDefault, cchSize);
  4524. ulcProps++;
  4525. // Create the PR_ADDRTYPE property as well.
  4526. lpPropArray[ulcProps].ulPropTag = PR_ADDRTYPE;
  4527. lpPropArray[ulcProps].dwAlignPad = 0;
  4528. lpPropArray[ulcProps].Value.LPSZ = (LPTSTR)szSMTP;
  4529. ulcProps++;
  4530. // Delete the PR_CONTACT_ properties if that was the only one,
  4531. if (1 == lpPropArray[ulContactAddressesIndex].Value.MVSZ.cValues)
  4532. {
  4533. // We don't need the PR_CONTACT_ properties
  4534. lpPropArray[ulContactAddressesIndex].ulPropTag = PR_NULL;
  4535. lpPropArray[ulContactAddrTypesIndex].ulPropTag = PR_NULL;
  4536. lpPropArray[ulContactDefAddrIndexIndex].ulPropTag = PR_NULL;
  4537. }
  4538. }
  4539. else if ((ulPrimaryEmailIndex < ulcProps) && (ulContactAddressesIndex < ulcProps))
  4540. {
  4541. ULONG ulcEntries;
  4542. LPTSTR lpszDefault;
  4543. // We need to add the primary address to PR_CONTACT_EMAIL_ADDRESSES
  4544. // and set it as the default
  4545. Assert((ulContactAddrTypesIndex < ulcProps) && (ulContactDefAddrIndexIndex < ulcProps));
  4546. // Before adding, see if it is already in the list.
  4547. lpszDefault = lpPropArray[ulPrimaryEmailIndex].Value.LPSZ;
  4548. ulcEntries = lpPropArray[ulContactAddressesIndex].Value.MVSZ.cValues;
  4549. for (i=0;i<ulcEntries;i++)
  4550. {
  4551. if (!lstrcmpi(lpPropArray[ulContactAddressesIndex].Value.MVSZ.LPPSZ[i], lpszDefault))
  4552. {
  4553. // Found a match.
  4554. break;
  4555. }
  4556. }
  4557. if (i < ulcEntries)
  4558. {
  4559. // The default is already in the list at index i
  4560. lpPropArray[ulContactDefAddrIndexIndex].Value.l = i;
  4561. }
  4562. else
  4563. {
  4564. ULONG cchSize;
  4565. // Add the default address to the end of the list.
  4566. lpPropArray[ulContactDefAddrIndexIndex].Value.l = ulcEntries;
  4567. // Allocate more space for the email address and copy it.
  4568. cchSize = lstrlen(lpszDefault) + 1;
  4569. sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropArray,
  4570. (LPVOID *)&(lpPropArray[ulContactAddressesIndex].Value.MVSZ.LPPSZ[ulcEntries]));
  4571. if (sc)
  4572. {
  4573. goto error;
  4574. }
  4575. lpPropArray[ulContactAddressesIndex].Value.MVSZ.cValues++;
  4576. StrCpyN(lpPropArray[ulContactAddressesIndex].Value.MVSZ.LPPSZ[ulcEntries], lpszDefault, cchSize);
  4577. // Fill in the address type.
  4578. lpPropArray[ulContactAddrTypesIndex].Value.MVSZ.LPPSZ[ulcEntries] = (LPTSTR)szSMTP;
  4579. lpPropArray[ulContactAddrTypesIndex].Value.MVSZ.cValues++;
  4580. }
  4581. }
  4582. }
  4583. if (pulcProps)
  4584. {
  4585. *pulcProps = ulcProps;
  4586. }
  4587. else
  4588. {
  4589. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4590. }
  4591. return hr;
  4592. error:
  4593. gpfnLDAPValueFree(aszValues);
  4594. // [PaulHi] clean up
  4595. for (i=0; i<e_pagerMax; i++)
  4596. LocalFreeAndNull(&(atszPagerAttr[i]));
  4597. return ResultFromScode(sc);
  4598. }
  4599. //*******************************************************************
  4600. //
  4601. // FUNCTION: CountDollars
  4602. //
  4603. // PURPOSE: Count the number of $ characters in the string.
  4604. //
  4605. // PARAMETERS: lpszStr - string to count.
  4606. //
  4607. // RETURNS: Number of dollar signs.
  4608. //
  4609. // HISTORY:
  4610. // 96/11/21 markdu Created.
  4611. //
  4612. //*******************************************************************
  4613. ULONG CountDollars(LPTSTR lpszStr)
  4614. {
  4615. ULONG ulcDollars = 0;
  4616. while (*lpszStr)
  4617. {
  4618. if ('$' == *lpszStr)
  4619. {
  4620. ulcDollars++;
  4621. }
  4622. lpszStr = CharNext(lpszStr);
  4623. }
  4624. return ulcDollars;
  4625. }
  4626. //*******************************************************************
  4627. //
  4628. // FUNCTION: DollarsToLFs
  4629. //
  4630. // PURPOSE: Convert all $ characters in the input string to line
  4631. // feeds in the output string. The rest of the output
  4632. // string is just a copy of the input string.
  4633. //
  4634. // PARAMETERS: lpszSrcStr - string to copy.
  4635. // lpszDestStr - output string, previously allocated large
  4636. // enough to hold the input string with $'s replaced.
  4637. //
  4638. // RETURNS: None.
  4639. //
  4640. // HISTORY:
  4641. // 96/11/21 markdu Created.
  4642. //
  4643. //*******************************************************************
  4644. void DollarsToLFs(
  4645. LPTSTR lpszSrcStr,
  4646. LPTSTR lpszDestStr,
  4647. DWORD cchDestStr)
  4648. {
  4649. DWORD dw=0;
  4650. while (*lpszSrcStr && dw < cchDestStr)
  4651. {
  4652. if ('$' == *lpszSrcStr)
  4653. {
  4654. *lpszDestStr++ = '\r';
  4655. dw++;
  4656. if (dw < cchDestStr)
  4657. {
  4658. *lpszDestStr++ = '\n';
  4659. dw++;
  4660. }
  4661. // Eat all whitespace characters that were after the $
  4662. // Also get rid of any more $'s so we don't stick to many LF's
  4663. while(IsSpace(lpszSrcStr) || *lpszSrcStr == '\t' || *lpszSrcStr == '$')
  4664. {
  4665. lpszSrcStr++;
  4666. }
  4667. }
  4668. else
  4669. {
  4670. // we're now natively unicode
  4671. //if (IsDBCSLeadByte((BYTE)*lpszSrcStr))
  4672. //{
  4673. // *lpszDestStr++ = *lpszSrcStr++;
  4674. //}
  4675. *lpszDestStr++ = *lpszSrcStr++;
  4676. dw++;
  4677. }
  4678. }
  4679. *lpszDestStr = '\0';
  4680. return;
  4681. }
  4682. //*******************************************************************
  4683. //
  4684. // FUNCTION: CountIllegalChars
  4685. //
  4686. // PURPOSE: Count the number of "illegal" characters in the string.
  4687. // This consists of the characters that should be escaped
  4688. // according to RFC1558: '*', '(', ')'.
  4689. //
  4690. // PARAMETERS: lpszStr - string to count.
  4691. //
  4692. // RETURNS: Number of illegal characters.
  4693. //
  4694. // HISTORY:
  4695. // 96/12/04 markdu Created.
  4696. //
  4697. //*******************************************************************
  4698. ULONG CountIllegalChars(LPTSTR lpszStr)
  4699. {
  4700. ULONG ulcIllegalChars = 0;
  4701. while (*lpszStr)
  4702. {
  4703. if (('*' == *lpszStr) || ('(' == *lpszStr) || (')' == *lpszStr))
  4704. {
  4705. ulcIllegalChars++;
  4706. }
  4707. lpszStr = CharNext(lpszStr);
  4708. }
  4709. return ulcIllegalChars;
  4710. }
  4711. //*******************************************************************
  4712. //
  4713. // FUNCTION: EscapeIllegalChars
  4714. //
  4715. // PURPOSE: Escape all illegal characters in the input string by
  4716. // replacing them with '\xx' where xx is the hex value
  4717. // representing the char. The rest of the output
  4718. // string is just a copy of the input string.
  4719. // Illegal characters are those that should be escaped
  4720. // according to RFC1558: '*', '(', ')'.
  4721. //
  4722. // PARAMETERS: lpszSrcStr - string to copy.
  4723. // lpszDestStr - output string, previously allocated large
  4724. // enough to hold the input string with illegal chars escaped..
  4725. //
  4726. // RETURNS: None.
  4727. //
  4728. // HISTORY:
  4729. // 96/12/04 markdu Created.
  4730. //
  4731. //*******************************************************************
  4732. static const LPTSTR szStar = TEXT("\\2a"); // '*'
  4733. static const LPTSTR szOBracket = TEXT("\\28"); // '('
  4734. static const LPTSTR szCBracket = TEXT("\\29"); // ')'
  4735. void EscapeIllegalChars(
  4736. LPTSTR lpszSrcStr,
  4737. LPTSTR lpszDestStr,
  4738. ULONG cchDestStr)
  4739. {
  4740. ULONG i=0;
  4741. lpszDestStr[0] = 0;
  4742. while (*lpszSrcStr && i < (cchDestStr-1))
  4743. {
  4744. if ('*' == *lpszSrcStr)
  4745. {
  4746. StrCatBuff(lpszDestStr, szStar, cchDestStr);
  4747. i += lstrlen(szStar);
  4748. lpszSrcStr++;
  4749. }
  4750. else if ('(' == *lpszSrcStr)
  4751. {
  4752. StrCatBuff(lpszDestStr, szOBracket, cchDestStr);
  4753. i += lstrlen(szOBracket);
  4754. lpszSrcStr++;
  4755. }
  4756. else if (')' == *lpszSrcStr)
  4757. {
  4758. StrCatBuff(lpszDestStr, szCBracket, cchDestStr);
  4759. i += lstrlen(szCBracket);
  4760. lpszSrcStr++;
  4761. }
  4762. else
  4763. {
  4764. // we're now natively unicode
  4765. //if (IsDBCSLeadByte((BYTE)*lpszSrcStr))
  4766. //{
  4767. // *lpszDestStr++ = *lpszSrcStr++;
  4768. //}
  4769. lpszDestStr[i++] = *lpszSrcStr++;
  4770. }
  4771. }
  4772. lpszDestStr[i] = '\0';
  4773. return;
  4774. }
  4775. //*******************************************************************
  4776. //
  4777. // FUNCTION: IsSMTPAddress
  4778. //
  4779. // PURPOSE: Checks to see if a given string is an SMTP email address
  4780. // according to draft-ietf-asid-ldapv3-attributes-01.txt
  4781. // section 6.9. For this to be the case, the string must
  4782. // begin with the characters "SMTP$".
  4783. // NOTE: The remainder of the
  4784. // string is not checked to see if it is a valid SMTP email
  4785. // address, so this is not a general-purpose function for
  4786. // determining whether an arbitrary string is SMTP.
  4787. //
  4788. // [PaulHi] Added [out] LPTSTR pointer that points to
  4789. // the beginning of the actual address name.
  4790. //
  4791. // PARAMETERS: lpszStr - string to check.
  4792. // [out] lpptszName, returned pointer in lpszStr for the
  4793. // actual email name part of the string.
  4794. //
  4795. // RETURNS: TRUE if the string is SMTP, FALSE otherwise.
  4796. //
  4797. // HISTORY:
  4798. // 96/11/27 markdu Created.
  4799. // 99/2/5 paulhi Modified.
  4800. //
  4801. //*******************************************************************
  4802. const TCHAR szsmtp[] = TEXT("smtp");
  4803. BOOL IsSMTPAddress(LPTSTR lpszStr, LPTSTR * lpptszName)
  4804. {
  4805. LPTSTR lpszSMTP = (LPTSTR)szSMTP;
  4806. LPTSTR lpszsmtp = (LPTSTR)szsmtp;
  4807. if (lpptszName)
  4808. (*lpptszName) = NULL;
  4809. while (*lpszSMTP && *lpszsmtp && *lpszStr)
  4810. {
  4811. if (*lpszSMTP != *lpszStr && *lpszsmtp != *lpszStr)
  4812. return FALSE;
  4813. lpszSMTP++;
  4814. lpszStr++;
  4815. lpszsmtp++;
  4816. }
  4817. if ('$' != *lpszStr)
  4818. return FALSE;
  4819. // If requested, return pointer to email name
  4820. if (lpptszName)
  4821. (*lpptszName) = lpszStr + 1; // Account for the '$' delimiter
  4822. return TRUE;
  4823. }
  4824. /*
  4825. -
  4826. - GetLDAPConnectionTimeout
  4827. * The default wldap32.dll timeout for connecting is 30-60 secs .. if the server is hung
  4828. * the user thinks they are hung .. so the WAB would downsize this timeout to 10 seconds ..
  4829. * However people using the RAS have a problem that 10 is too short .. so we add a reg setting
  4830. * that can be customized .. this customization is global for all services so it's at the
  4831. * user's own risk. Default, if no reg setting, is 10 seconds
  4832. * Bug 2409 - IE4.0x QFE RAID
  4833. */
  4834. #define LDAP_CONNECTION_TIMEOUT 10 //seconds
  4835. DWORD GetLDAPConnectionTimeout()
  4836. {
  4837. DWORD dwErr = 0, dwTimeout = 0;
  4838. HKEY hKeyWAB;
  4839. LPTSTR szLDAPConnectionTimeout = TEXT("LDAP Connection Timeout");
  4840. // Open the WAB's reg key
  4841. if(!(dwErr=RegOpenKeyEx(HKEY_CURRENT_USER, szWABKey, 0, KEY_ALL_ACCESS, &hKeyWAB)))
  4842. {
  4843. // Read the next available server id
  4844. if (dwErr = RegQueryValueExDWORD(hKeyWAB, (LPTSTR)szLDAPConnectionTimeout, &dwTimeout))
  4845. {
  4846. // The value wasn't found!! .. Create a new key
  4847. dwTimeout = LDAP_CONNECTION_TIMEOUT;
  4848. RegSetValueEx(hKeyWAB, (LPTSTR)szLDAPConnectionTimeout, 0, REG_DWORD, (LPBYTE)&dwTimeout, sizeof(dwTimeout));
  4849. }
  4850. RegCloseKey(hKeyWAB);
  4851. }
  4852. return dwTimeout;
  4853. }
  4854. //*******************************************************************
  4855. //
  4856. // FUNCTION: OpenConnection
  4857. //
  4858. // PURPOSE: Open a connection to the LDAP server, and start an
  4859. // asynchronous bind with the correct authentication method.
  4860. //
  4861. // PARAMETERS: ppLDAP - receives LDAP structure for this session
  4862. // lpszServer - name of LDAP server to open
  4863. // pulTimeout - buffer to hold timeout value for search
  4864. // pulMsgID - message id returned by the bind call
  4865. // pfSyncBind - upon return, this will be set to TRUE if a
  4866. // synchronous bind was used, FALSE otherwise. Not used on input.
  4867. // lpszBindDN - the name with which to bind - most probably passed in
  4868. // through an LDAP URL. Overrides any other setting
  4869. //
  4870. // RETURNS: LDAP error code.
  4871. //
  4872. // HISTORY:
  4873. // 96/07/26 markdu Created.
  4874. // 96/11/02 markdu Made asynchronous.
  4875. // 96/12/14 markdu Added pfSyncBind.
  4876. //
  4877. //*******************************************************************
  4878. ULONG OpenConnection(
  4879. LPTSTR lpszServer,
  4880. LDAP** ppLDAP,
  4881. ULONG* pulTimeout,
  4882. ULONG* pulMsgID,
  4883. BOOL* pfSyncBind,
  4884. ULONG ulLdapType,
  4885. LPTSTR lpszBindDN,
  4886. DWORD dwAuthType)
  4887. {
  4888. LDAPSERVERPARAMS Params = {0};
  4889. LDAP* pLDAP = NULL;
  4890. LDAP* pLDAPSSL = NULL;
  4891. LPTSTR szDN;
  4892. LPTSTR szCred;
  4893. ULONG method;
  4894. ULONG ulResult = LDAP_SUCCESS;
  4895. BOOL fUseSynchronousBind = *pfSyncBind; //FALSE;
  4896. ULONG ulValue = LDAP_VERSION2;
  4897. ZeroMemory(&Params, sizeof(Params));
  4898. // initialize search control parameters
  4899. GetLDAPServerParams(lpszServer, &Params);
  4900. // The LDAP server name can be "NULL" or "" or "xxxx" ..
  4901. // The first 2 cases mean that pass a NULL to wldap32.dll for the server name .. if will go out and
  4902. // find the "closest" possible server - though I think this only works on NT 5 ..
  4903. //
  4904. if(!Params.lpszName ||
  4905. !lstrlen(Params.lpszName))
  4906. {
  4907. // Chances are that if we are here in OpenConnection and the
  4908. // name is NULL, then we are trying to open a LDAP server
  4909. // So quietly fill in the Params.lpszName with the server name
  4910. // <TBD> - fill a flag somewhere so we know the above assumption
  4911. // is try
  4912. if(lpszServer && lstrlen(lpszServer))
  4913. {
  4914. ULONG cchSize = lstrlen(lpszServer)+1;
  4915. Params.lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  4916. if(!Params.lpszName)
  4917. goto exit;
  4918. StrCpyN(Params.lpszName, lpszServer, cchSize);
  4919. }
  4920. else
  4921. Params.lpszName = szEmpty;
  4922. }
  4923. else if(!lstrcmpi(Params.lpszName, szNULLString))
  4924. {
  4925. // The search base is specified as a "NULL" which means use a NULL
  4926. LocalFree(Params.lpszName);
  4927. Params.lpszName = szEmpty;
  4928. }
  4929. if(Params.dwUseSSL)
  4930. {
  4931. pLDAPSSL = gpfnLDAPSSLInit( (Params.lpszName && lstrlen(Params.lpszName))?Params.lpszName:NULL,
  4932. Params.dwPort, TRUE);
  4933. if(NULL == pLDAPSSL)
  4934. {
  4935. DebugTrace(TEXT("ldap_ssl_init failed for this server\n"));
  4936. ulResult = LDAP_AUTH_METHOD_NOT_SUPPORTED;
  4937. goto exit;
  4938. }
  4939. }
  4940. // Open a connection
  4941. // The wldap32.dll has a 30-60 second timeout for the ldapopen call if the call cannot
  4942. // go through. To most users, it looks like the app is hung. WAB wants a lower timeout
  4943. // maybe close to 10 seconds and we can do that by calling ldap_init and then ldap_connect
  4944. // instead of ldapopen
  4945. #ifndef SMALLER_TIMEOUT
  4946. {
  4947. LDAP_TIMEVAL timeout;
  4948. if(!pLDAPSSL)
  4949. pLDAP = gpfnLDAPInit((Params.lpszName && lstrlen(Params.lpszName))?Params.lpszName:NULL,
  4950. Params.dwPort);
  4951. else
  4952. pLDAP = pLDAPSSL;
  4953. timeout.tv_sec = GetLDAPConnectionTimeout();
  4954. timeout.tv_usec = 0;
  4955. ulResult = gpfnLDAPConnect( pLDAP, &timeout );
  4956. if(ulResult != LDAP_SUCCESS)
  4957. goto exit;
  4958. }
  4959. #else
  4960. pLDAP = gpfnLDAPOpen(Params.lpszName, Params.dwPort);
  4961. if (NULL == pLDAP)
  4962. {
  4963. DebugTrace(TEXT("ldap_open failed for server %s.\n"), lpszServer);
  4964. // We could not open the server, so we assume that we could not find it
  4965. ulResult = LDAP_SERVER_DOWN;
  4966. goto exit;
  4967. }
  4968. #endif
  4969. // To do LDAP over SSL we can do:
  4970. // 1. Call ldap_sslinit before calling ldap_open which will always use port 636
  4971. // 2. To use any port number, set the SSL option using the ldap_set_option method
  4972. /*
  4973. // Hmm...option 2 doesnt seem to work ...
  4974. if(Params.dwUseSSL)
  4975. {
  4976. ULONG ulSecure = (ULONG) LDAP_OPT_ON;
  4977. if(gpfnLDAPSetOption( pLDAP, LDAP_OPT_SSL, &ulSecure) != LDAP_SUCCESS)
  4978. {
  4979. DebugTrace(TEXT("ldap_set_option failed to set SSL option"));
  4980. //ulResult = LDAP_AUTH_METHOD_NOT_SUPPORTED;
  4981. //goto exit;
  4982. }
  4983. }
  4984. */
  4985. pLDAP->ld_sizelimit = (ULONG)Params.dwSearchSizeLimit;
  4986. pLDAP->ld_timelimit = (ULONG)Params.dwSearchTimeLimit;
  4987. pLDAP->ld_deref = LDAP_DEREF_ALWAYS;
  4988. // Convert timeout from seconds to milliseconds
  4989. Assert(pulTimeout);
  4990. *pulTimeout = (ULONG)Params.dwSearchTimeLimit * 1000;
  4991. // Set authentication parameters.
  4992. if(lpszBindDN && lstrlen(lpszBindDN))
  4993. {
  4994. szDN = lpszBindDN;
  4995. szCred = NULL;
  4996. method = LDAP_AUTH_SIMPLE;
  4997. }
  4998. else if (dwAuthType == LDAP_AUTH_SICILY || dwAuthType == LDAP_AUTH_NEGOTIATE || LDAP_AUTH_METHOD_SICILY == Params.dwAuthMethod)
  4999. {
  5000. // Use Sicily authentication. We need to do a synchronous bind in this case.
  5001. szDN = NULL;
  5002. szCred = NULL;
  5003. method = LDAP_AUTH_NEGOTIATE;
  5004. fUseSynchronousBind = TRUE;
  5005. }
  5006. else
  5007. if (LDAP_AUTH_METHOD_SIMPLE == Params.dwAuthMethod)
  5008. {
  5009. // Use LDAP simple authentication
  5010. szDN = Params.lpszUserName;
  5011. szCred = Params.lpszPassword;
  5012. method = LDAP_AUTH_SIMPLE;
  5013. }
  5014. else
  5015. {
  5016. // authenticate anonymously
  5017. if(Params.dwUseBindDN)
  5018. {
  5019. szDN = (LPTSTR) szBindDNMSFTUser;
  5020. szCred = (LPTSTR) szBindCredMSFTPass;
  5021. }
  5022. else
  5023. {
  5024. szDN = NULL;
  5025. szCred = NULL;
  5026. }
  5027. method = LDAP_AUTH_SIMPLE;
  5028. }
  5029. // We should try to bind as LDAP v3 client .. only if that fails
  5030. // with an LDAP_OPERATIONS_ERROR should we try to bind as an LDAP 2
  5031. // client
  5032. if(ulLdapType == use_ldap_v3)
  5033. ulValue = LDAP_VERSION3;
  5034. tryLDAPv2:
  5035. gpfnLDAPSetOption(pLDAP, LDAP_OPT_VERSION, &ulValue );
  5036. if (TRUE == fUseSynchronousBind)
  5037. {
  5038. ulResult = gpfnLDAPBindS(pLDAP, szDN, szCred, method);
  5039. // BUGBUG 96/12/09 markdu BUG 10537 Temporary work-around for wldap32.dll returning
  5040. // the wrong error code for invalid password on sicily bind.
  5041. // This should be removed later (BUG 12608).
  5042. // 96/12/19 markdu BUG 12608 Commented out temporary work-around.
  5043. //if ((LDAP_LOCAL_ERROR == ulResult) &&
  5044. // (LDAP_AUTH_SICILY == method))
  5045. //{
  5046. // ulResult = LDAP_INVALID_CREDENTIALS;
  5047. //}
  5048. }
  5049. else
  5050. {
  5051. // Start the asynchronous bind
  5052. *pulMsgID = gpfnLDAPBind(pLDAP, szDN, szCred, method);
  5053. /*
  5054. ulResult = pLDAP->ld_errno;
  5055. if(ulResult == LDAP_SUCCESS)
  5056. {
  5057. // make sure its really a success - some of the directory servers are
  5058. // sending a LDAP_PROTOCOL error after some time which is screwing up
  5059. // searching against those servers ...
  5060. LDAPMessage *lpResult = NULL;
  5061. struct l_timeval PollTimeout;
  5062. // Poll the server for results
  5063. ZeroMemory(&PollTimeout, sizeof(struct l_timeval));
  5064. PollTimeout.tv_sec = 2;
  5065. PollTimeout.tv_usec = 0;
  5066. ulResult = gpfnLDAPResult( pLDAP,
  5067. *pulMsgID,
  5068. LDAP_MSG_ALL, //Get all results before returning
  5069. &PollTimeout, // Timeout immediately (poll)
  5070. &lpResult);
  5071. ulResult = gpfnLDAPResult2Error(pLDAP, lpResult, FALSE);
  5072. // 96/12/09 markdu BUG 10537 If the bind returned one of these error
  5073. // messages, it probably means that the account name (DN) passed to the
  5074. // bind was incorrect or in the wrong format. Map these to an error code
  5075. // that will result in a better error message than "entry not found".
  5076. if ((LDAP_NAMING_VIOLATION == ulResult) || (LDAP_UNWILLING_TO_PERFORM == ulResult))
  5077. ulResult = LDAP_INVALID_CREDENTIALS;
  5078. // free the search results memory
  5079. if (lpResult)
  5080. gpfnLDAPMsgFree(lpResult);
  5081. }
  5082. */
  5083. }
  5084. if(ulValue == LDAP_VERSION3 && (ulResult == LDAP_OPERATIONS_ERROR || ulResult == LDAP_PROTOCOL_ERROR))
  5085. {
  5086. gpfnLDAPAbandon(*ppLDAP, *pulMsgID);
  5087. // [PaulHi] 1/7/99 Since we try a new bind we need to relinquish the old binding,
  5088. // otherwise the server will support two connections until the original V3 attempt
  5089. // times out.
  5090. gpfnLDAPUnbind(*ppLDAP);
  5091. ulValue = LDAP_VERSION2;
  5092. goto tryLDAPv2;
  5093. }
  5094. exit:
  5095. if (LDAP_SUCCESS == ulResult)
  5096. {
  5097. *ppLDAP = pLDAP;
  5098. *pfSyncBind = fUseSynchronousBind;
  5099. }
  5100. FreeLDAPServerParams(Params);
  5101. return ulResult;
  5102. }
  5103. //*******************************************************************
  5104. //
  5105. // FUNCTION: EncryptDecryptText
  5106. //
  5107. // PURPOSE: Perform simple encryption on text so we can store it
  5108. // in the registry. The algorithm is reflexive, so it
  5109. // can also be used to decrypt text that it encrypted.
  5110. //
  5111. // PARAMETERS: lpb - text to encrypt/decrypt.
  5112. // dwSize - number of bytes to encrypt
  5113. //
  5114. // RETURNS: None.
  5115. //
  5116. // HISTORY:
  5117. // 96/07/29 markdu Created.
  5118. //
  5119. //*******************************************************************
  5120. void EncryptDecryptText(
  5121. LPBYTE lpb,
  5122. DWORD dwSize)
  5123. {
  5124. DWORD dw;
  5125. for (dw=0;dw<dwSize;dw++)
  5126. {
  5127. // Simple encryption -- just xor with 'w'
  5128. lpb[dw] ^= 'w';
  5129. }
  5130. }
  5131. //*******************************************************************
  5132. //
  5133. // FUNCTION: FreeLDAPServerParams
  5134. //
  5135. // PURPOSE: Frees allocated strings in the LDAPServerParams struct
  5136. //
  5137. // HISTORY:
  5138. // 96/10/10 vikram Created
  5139. //
  5140. //*******************************************************************
  5141. void FreeLDAPServerParams(LDAPSERVERPARAMS Params)
  5142. {
  5143. LocalFreeAndNull(&Params.lpszUserName);
  5144. LocalFreeAndNull(&Params.lpszPassword);
  5145. LocalFreeAndNull(&Params.lpszURL);
  5146. if(Params.lpszName && lstrlen(Params.lpszName))
  5147. LocalFreeAndNull(&Params.lpszName);
  5148. LocalFreeAndNull(&Params.lpszBase);
  5149. LocalFreeAndNull(&Params.lpszLogoPath);
  5150. LocalFreeAndNull(&Params.lpszAdvancedSearchAttr);
  5151. return;
  5152. }
  5153. //*******************************************************************
  5154. //
  5155. // FUNCTION: GetLDAPSearchBase
  5156. //
  5157. // PURPOSE: Generate Search Base string for LDAP search for the
  5158. // given server.
  5159. //
  5160. // PARAMETERS: lplpszBase - pointer to receive the search base string buffer.
  5161. // lpszServer - name of LDAP server whose base string to get.
  5162. //
  5163. // RETURNS: HRESULT
  5164. //
  5165. // HISTORY:
  5166. // 96/10/18 markdu Created.
  5167. //
  5168. //*******************************************************************
  5169. HRESULT GetLDAPSearchBase(
  5170. LPTSTR FAR * lplpszBase,
  5171. LPTSTR lpszServer)
  5172. {
  5173. LDAPSERVERPARAMS Params;
  5174. HRESULT hr = hrSuccess;
  5175. BOOL fRet;
  5176. TCHAR szCountry[COUNTRY_STR_LEN + 1];
  5177. LPTSTR lpszCountry;
  5178. // Make sure we can write to lplpszBase.
  5179. #ifdef PARAMETER_VALIDATION
  5180. if (IsBadWritePtr(lplpszBase, sizeof(LPTSTR)))
  5181. {
  5182. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5183. }
  5184. if (IsBadReadPtr(lpszServer, sizeof(CHAR)))
  5185. {
  5186. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5187. }
  5188. #endif // PARAMETER_VALIDATION
  5189. LocalFreeAndNull(lplpszBase);
  5190. GetLDAPServerParams((LPTSTR)lpszServer, &Params);
  5191. if(NULL == Params.lpszBase)
  5192. {
  5193. // Generate a default base.
  5194. // Read the default country for the search base from the registry.
  5195. DWORD cchSize = (lstrlen(cszBaseFilter) + lstrlen(cszAttr_c) + lstrlen(cszDefaultCountry) + 1);
  5196. *lplpszBase = (LPTSTR) LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR) * cchSize);
  5197. if (NULL == *lplpszBase)
  5198. {
  5199. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5200. goto exit;
  5201. }
  5202. *szCountry = '\0';
  5203. fRet = ReadRegistryLDAPDefaultCountry(NULL, 0, szCountry, ARRAYSIZE(szCountry));
  5204. if ((fRet) && (COUNTRY_STR_LEN == lstrlen(szCountry)))
  5205. {
  5206. lpszCountry = szCountry;
  5207. }
  5208. else
  5209. {
  5210. lpszCountry = (LPTSTR)cszDefaultCountry;
  5211. }
  5212. wnsprintf(*lplpszBase, cchSize, cszBaseFilter, cszAttr_c, lpszCountry);
  5213. }
  5214. else if(!lstrcmpi(Params.lpszBase, szNULLString))
  5215. {
  5216. // we've explicitly set this search base to NULL which means
  5217. // dont pass in an empty search base
  5218. *lplpszBase = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lstrlen(szEmpty)+1));
  5219. if (NULL == *lplpszBase)
  5220. {
  5221. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5222. goto exit;
  5223. }
  5224. (*lplpszBase)[0] = TEXT('\0');
  5225. }
  5226. else
  5227. {
  5228. ULONG cchSize = lstrlen(Params.lpszBase)+1;
  5229. // The search base is configured for this server.
  5230. *lplpszBase = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  5231. if (NULL == *lplpszBase)
  5232. {
  5233. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5234. goto exit;
  5235. }
  5236. StrCpyN(*lplpszBase, Params.lpszBase, cchSize);
  5237. }
  5238. exit:
  5239. FreeLDAPServerParams(Params);
  5240. return hr;
  5241. }
  5242. //*******************************************************************
  5243. //
  5244. // FUNCTION: SearchWithCancel
  5245. //
  5246. // PURPOSE: Initiates a synchronous of asynchronous LDAP search
  5247. // Asynchronous may have a cancel dialog.
  5248. //
  5249. // PARAMETERS: ppLDAP - receives the LDAP connection handle
  5250. // szBase - The dn of the entry at which to start the search
  5251. // ulScope - The scope of the search
  5252. // szFilter - The search filter
  5253. // szNTFilter - NTDS-specific filter (can be NULL)
  5254. // ppszAttrs - A NULL-terminated array of strings indicating
  5255. // which attributes to return for each matching entry.
  5256. // Passing NULL for this entry causes all available attributes
  5257. // to be retrieved.
  5258. // ulAttrsonly - A boolean value that should be zero if both
  5259. // attribute types and values are to be returned, non-zero
  5260. // if only types are wanted
  5261. // pTimeout - The local search timeout value
  5262. // lplpResult - recieves the result parameter containing the entire
  5263. // search results
  5264. // lpszServer - name of LDAP server on which the search is to be performed
  5265. // fShowAnim - If true, show an animation in the cancel dialog
  5266. //
  5267. // RETURNS: Result of ldap_search call.
  5268. //
  5269. // HISTORY:
  5270. // 96/10/24 markdu Created.
  5271. //
  5272. //*******************************************************************
  5273. ULONG SearchWithCancel(
  5274. LDAP** ppLDAP,
  5275. LPTSTR szBase,
  5276. ULONG ulScope,
  5277. LPTSTR szFilter,
  5278. LPTSTR szNTFilter,
  5279. LPTSTR* ppszAttrs,
  5280. ULONG ulAttrsonly,
  5281. LDAPMessage** lplpResult,
  5282. LPTSTR lpszServer,
  5283. BOOL fShowAnim,
  5284. LPTSTR lpszBindDN,
  5285. DWORD dwAuthType,// to override or set the Authentication type if not 0
  5286. BOOL fResolveMultiple,
  5287. LPADRLIST lpAdrList,
  5288. LPFlagList lpFlagList,
  5289. BOOL fUseSynchronousBind,
  5290. BOOL * lpbIsNTDSEntry,
  5291. BOOL bUnicode)
  5292. {
  5293. ULONG ulMsgID;
  5294. ULONG ulResult;
  5295. HWND hDlg;
  5296. MSG msg;
  5297. LDAPSEARCHPARAMS LDAPSearchParams;
  5298. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5299. // Stuff the parameters into the structure to be passed to the dlg proc
  5300. ZeroMemory(&LDAPSearchParams, sizeof(LDAPSEARCHPARAMS));
  5301. LDAPSearchParams.ppLDAP = ppLDAP;
  5302. LDAPSearchParams.szBase = szBase;
  5303. LDAPSearchParams.ulScope = ulScope;
  5304. LDAPSearchParams.ulError = LDAP_SUCCESS;
  5305. LDAPSearchParams.szFilter = szFilter;
  5306. LDAPSearchParams.szNTFilter = szNTFilter;
  5307. LDAPSearchParams.ppszAttrs = ppszAttrs;
  5308. LDAPSearchParams.ulAttrsonly = ulAttrsonly;
  5309. LDAPSearchParams.lplpResult = lplpResult;
  5310. LDAPSearchParams.lpszServer = lpszServer;
  5311. LDAPSearchParams.lpszBindDN = lpszBindDN;
  5312. LDAPSearchParams.dwAuthType = dwAuthType;
  5313. LDAPSearchParams.lpAdrList = lpAdrList;
  5314. LDAPSearchParams.lpFlagList = lpFlagList;
  5315. LDAPSearchParams.bUnicode = bUnicode;
  5316. if(fShowAnim)
  5317. LDAPSearchParams.ulFlags |= LSP_ShowAnim;
  5318. if(fResolveMultiple)
  5319. LDAPSearchParams.ulFlags |= LSP_ResolveMultiple;
  5320. if(fUseSynchronousBind)
  5321. LDAPSearchParams.ulFlags |= LSP_UseSynchronousBind;
  5322. if(!pt_hWndFind) // no UI
  5323. {
  5324. DoSyncLDAPSearch(&LDAPSearchParams);
  5325. }
  5326. else
  5327. {
  5328. LDAPSearchParams.hDlgCancel = CreateDialogParam(hinstMapiX,
  5329. MAKEINTRESOURCE(IDD_DIALOG_LDAPCANCEL),
  5330. pt_hWndFind,
  5331. DisplayLDAPCancelDlgProc,
  5332. (LPARAM) &LDAPSearchParams);
  5333. // if called from the find dialog, the find dialog needs to be able
  5334. // to cancel the modeless dialog
  5335. pt_hDlgCancel = LDAPSearchParams.hDlgCancel;
  5336. while (LDAPSearchParams.hDlgCancel && GetMessage(&msg, NULL, 0, 0))
  5337. {
  5338. if (!IsDialogMessage(LDAPSearchParams.hDlgCancel, &msg))
  5339. {
  5340. TranslateMessage(&msg);
  5341. DispatchMessage(&msg);
  5342. }
  5343. }
  5344. }
  5345. // If an error occurred in ldap_result, return the error code
  5346. if (LDAP_SUCCESS != LDAPSearchParams.ulError)
  5347. {
  5348. ulResult = LDAPSearchParams.ulError;
  5349. goto exit;
  5350. }
  5351. #ifdef PAGED_RESULT_SUPPORT
  5352. if(bSupportsLDAPPagedResults(&LDAPSearchParams))
  5353. ProcessLDAPPagedResultCookie(&LDAPSearchParams);
  5354. #endif //#ifdef PAGED_RESULT_SUPPORT
  5355. if(lpbIsNTDSEntry)
  5356. *lpbIsNTDSEntry = (LDAPSearchParams.ulFlags & LSP_IsNTDS) ? TRUE : FALSE;
  5357. ulResult = CheckErrorResult(&LDAPSearchParams, LDAP_RES_SEARCH_RESULT);
  5358. exit:
  5359. return ulResult;
  5360. }
  5361. //*******************************************************************
  5362. //
  5363. // FUNCTION: DisplayLDAPCancelDlgProc
  5364. //
  5365. // PURPOSE: Display a cancel dialog while waiting for results from
  5366. // multiple LDAP searches for ResolveNames
  5367. //
  5368. // PARAMETERS: lParam - pointer to structure containing all the
  5369. // search parameters.
  5370. //
  5371. // RETURNS: Returns TRUE if we successfully processed the message,
  5372. // FALSE otherwise.
  5373. //
  5374. // HISTORY:
  5375. // 96/10/24 markdu Created.
  5376. // 96/10/31 markdu Enhanced to allow multiple searches.
  5377. //
  5378. //*******************************************************************
  5379. INT_PTR CALLBACK DisplayLDAPCancelDlgProc(
  5380. HWND hDlg,
  5381. UINT uMsg,
  5382. WPARAM wParam,
  5383. LPARAM lParam)
  5384. {
  5385. switch (uMsg)
  5386. {
  5387. case WM_INITDIALOG:
  5388. {
  5389. PLDAPSEARCHPARAMS pLDAPSearchParams;
  5390. TCHAR szBuf[MAX_UI_STR];
  5391. LPTSTR lpszMsg = NULL;
  5392. HWND hWndAnim;
  5393. {
  5394. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5395. HWND hWndParent = GetParent(hDlg);
  5396. if(hWndParent && !pt_bDontShowCancel) // Find dlg may request not to see the cancel dlg
  5397. EnableWindow(hWndParent, FALSE); // Dont want to disable the find dialog in that event
  5398. }
  5399. // lParam contains pointer to LDAPSEARCHPARAMS struct, set it
  5400. // in window data
  5401. Assert(lParam);
  5402. SetWindowLongPtr(hDlg,DWLP_USER,lParam);
  5403. pLDAPSearchParams = (PLDAPSEARCHPARAMS) lParam;
  5404. if(InitLDAPClientLib())
  5405. pLDAPSearchParams->ulFlags |= LSP_InitDll;
  5406. // Put the dialog in the center of the parent window
  5407. CenterWindow(hDlg, GetParent(hDlg));
  5408. // Put the server name on the dialog.
  5409. LoadString(hinstMapiX, idsLDAPCancelMessage, szBuf, CharSizeOf(szBuf));
  5410. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  5411. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  5412. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  5413. szBuf,
  5414. 0, // stringid
  5415. 0, // dwLanguageId
  5416. (LPTSTR)&lpszMsg, // output buffer
  5417. 0, // MAX_UI_STR
  5418. (va_list *)&pLDAPSearchParams->lpszServer))
  5419. {
  5420. SetDlgItemText(hDlg, IDC_LDAPCANCEL_STATIC_PLEASEWAIT, lpszMsg);
  5421. IF_WIN32(LocalFreeAndNull(&lpszMsg);)
  5422. IF_WIN16(FormatMessageFreeMem(lpszMsg);)
  5423. }
  5424. if(bIsSimpleSearch(pLDAPSearchParams->lpszServer))
  5425. pLDAPSearchParams->ulFlags |= LSP_SimpleSearch;
  5426. if (!(pLDAPSearchParams->ulFlags & LSP_ShowAnim)) // This means search came from the Search dialog
  5427. {
  5428. // While the bind is going on, there is no visual feedback to the user
  5429. // We turn on the hidden static on the Search dialog that says "Connecting..."
  5430. HWND hWndParent = GetParent(hDlg);
  5431. if( hWndParent &&
  5432. GetDlgItem(hWndParent, IDC_TAB_FIND) &&
  5433. GetDlgItem(hWndParent, IDC_FIND_ANIMATE1))
  5434. {
  5435. // Make sure that the parent is the find dialog and nothing else
  5436. TCHAR sz[MAX_PATH];
  5437. LoadString(hinstMapiX, idsFindConnecting, sz, CharSizeOf(sz));
  5438. SetWindowText(hWndParent, sz);
  5439. UpdateWindow(hWndParent);
  5440. }
  5441. }
  5442. // Perform the bind operation.
  5443. Assert(pLDAPSearchParams->lpszServer);
  5444. {
  5445. BOOL fUseSynchronousBind = (pLDAPSearchParams->ulFlags & LSP_UseSynchronousBind);
  5446. pLDAPSearchParams->ulLDAPValue = use_ldap_v3;
  5447. pLDAPSearchParams->ulError = OpenConnection( pLDAPSearchParams->lpszServer,
  5448. pLDAPSearchParams->ppLDAP,
  5449. &pLDAPSearchParams->ulTimeout,
  5450. &pLDAPSearchParams->ulMsgID,
  5451. &fUseSynchronousBind,
  5452. pLDAPSearchParams->ulLDAPValue,
  5453. pLDAPSearchParams->lpszBindDN,
  5454. pLDAPSearchParams->dwAuthType);
  5455. if(fUseSynchronousBind)
  5456. pLDAPSearchParams->ulFlags |= LSP_UseSynchronousBind;
  5457. else
  5458. pLDAPSearchParams->ulFlags &= ~LSP_UseSynchronousBind;
  5459. }
  5460. if (!(pLDAPSearchParams->ulFlags & LSP_ShowAnim)) // This means search came from the Search dialog
  5461. {
  5462. // We turn off the hidden static on the Search dialog that says "Connecting..."
  5463. HWND hWndParent = GetParent(hDlg);
  5464. if( hWndParent &&
  5465. GetDlgItem(hWndParent, IDC_TAB_FIND) &&
  5466. GetDlgItem(hWndParent, IDC_FIND_ANIMATE1))
  5467. {
  5468. // Make sure that the parent is the find dialog and nothing else
  5469. TCHAR sz[MAX_PATH];
  5470. LoadString(hinstMapiX, idsSearchDialogTitle, sz, CharSizeOf(sz));
  5471. SetWindowText(hWndParent, sz);
  5472. UpdateWindow(hWndParent);
  5473. }
  5474. }
  5475. if (LDAP_SUCCESS != pLDAPSearchParams->ulError)
  5476. {
  5477. SendMessage(hDlg, WM_CLOSE, 0, 0);
  5478. return TRUE;
  5479. }
  5480. if (pLDAPSearchParams->ulFlags & LSP_UseSynchronousBind)
  5481. {
  5482. BOOL fRet;
  5483. // The actions that need to be performed after the bind are done
  5484. // in BindProcessResults, so we call this even though there really are
  5485. // no results to process in the synchronous case.
  5486. fRet = BindProcessResults(pLDAPSearchParams, hDlg, NULL);
  5487. if (FALSE == fRet)
  5488. {
  5489. SendMessage(hDlg, WM_CLOSE, 0, 0);
  5490. return TRUE;
  5491. }
  5492. }
  5493. else
  5494. {
  5495. // Start a timer for the server polling.
  5496. if (LDAP_BIND_TIMER_ID != SetTimer( hDlg,LDAP_BIND_TIMER_ID,LDAP_SEARCH_TIMER_DELAY,NULL))
  5497. {
  5498. // Cancel the bind if we couldn't start the timer.
  5499. gpfnLDAPAbandon(*pLDAPSearchParams->ppLDAP,pLDAPSearchParams->ulMsgID);
  5500. pLDAPSearchParams->ulError = LDAP_LOCAL_ERROR;
  5501. SendMessage(hDlg, WM_CLOSE, 0, 0);
  5502. return TRUE;
  5503. }
  5504. pLDAPSearchParams->unTimerID = LDAP_BIND_TIMER_ID;
  5505. }
  5506. // Load the AVI
  5507. hWndAnim = GetDlgItem(hDlg, IDC_LDAPCANCEL_ANIMATE);
  5508. Animate_Open(hWndAnim, MAKEINTRESOURCE(IDR_AVI_WABFIND));
  5509. Animate_Play(hWndAnim, 0, 1, 0);
  5510. Animate_Stop(hWndAnim);
  5511. // Play it only if this is a resolve operation
  5512. if ((pLDAPSearchParams->ulFlags & LSP_ShowAnim))
  5513. {
  5514. Animate_Play(hWndAnim, 0, -1, -1);
  5515. }
  5516. EnableWindow(hDlg, FALSE);
  5517. return TRUE;
  5518. }
  5519. case WM_TIMER:
  5520. {
  5521. struct l_timeval PollTimeout;
  5522. PLDAPSEARCHPARAMS pLDAPSearchParams;
  5523. Assert ((wParam == LDAP_SEARCH_TIMER_ID) || (wParam == LDAP_BIND_TIMER_ID));
  5524. // get data pointer from window data
  5525. pLDAPSearchParams =
  5526. (PLDAPSEARCHPARAMS) GetWindowLongPtr(hDlg,DWLP_USER);
  5527. Assert(pLDAPSearchParams);
  5528. if(pLDAPSearchParams->unTimerID == wParam)
  5529. {
  5530. // Poll the server for results
  5531. ZeroMemory(&PollTimeout, sizeof(struct l_timeval));
  5532. pLDAPSearchParams->ulResult = gpfnLDAPResult(
  5533. *pLDAPSearchParams->ppLDAP,
  5534. pLDAPSearchParams->ulMsgID,
  5535. LDAP_MSG_ALL, //LDAP_MSG_RECEIVED, //LDAP_MSG_ALL, // Get all results before returning
  5536. &PollTimeout, // Timeout immediately (poll)
  5537. pLDAPSearchParams->lplpResult);
  5538. // If the return value was zero, the call timed out
  5539. if (0 == pLDAPSearchParams->ulResult)
  5540. {
  5541. // See if the timeout has expired.
  5542. pLDAPSearchParams->ulTimeElapsed += LDAP_SEARCH_TIMER_DELAY;
  5543. if (pLDAPSearchParams->ulTimeElapsed >= pLDAPSearchParams->ulTimeout)
  5544. {
  5545. pLDAPSearchParams->ulError = LDAP_TIMEOUT;
  5546. }
  5547. else
  5548. {
  5549. // Timeout has not expired, and no results were returned.
  5550. // See if the dialog is supposed to be displayed at this point.
  5551. if (pLDAPSearchParams->ulTimeElapsed >= SEARCH_CANCEL_DIALOG_DELAY)
  5552. {
  5553. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5554. if(pt_hWndFind && !pt_bDontShowCancel) // Find dlg may request not to see the cancel dlg
  5555. {
  5556. ShowWindow(hDlg, SW_SHOW);
  5557. EnableWindow(hDlg, TRUE);
  5558. }
  5559. }
  5560. return TRUE;
  5561. }
  5562. }
  5563. // If the return value was anything but zero, we either have
  5564. // results or an error ocurred
  5565. else
  5566. {
  5567. // See if this is the bind timer or the search timer
  5568. if (LDAP_SEARCH_TIMER_ID == pLDAPSearchParams->unTimerID)
  5569. {
  5570. // Process the results
  5571. KillTimer(hDlg, LDAP_SEARCH_TIMER_ID);
  5572. if (pLDAPSearchParams->ulFlags & LSP_ResolveMultiple)
  5573. {
  5574. if(ResolveProcessResults(pLDAPSearchParams, hDlg))
  5575. return TRUE; // We have more searches to do
  5576. }
  5577. else if(LDAP_ERROR == pLDAPSearchParams->ulResult)
  5578. {
  5579. pLDAPSearchParams->ulError = (*pLDAPSearchParams->ppLDAP)->ld_errno;
  5580. }
  5581. }
  5582. else if (LDAP_BIND_TIMER_ID == pLDAPSearchParams->unTimerID)
  5583. {
  5584. BOOL fRet;
  5585. BOOL bKillTimer = TRUE;
  5586. fRet = BindProcessResults(pLDAPSearchParams, hDlg, &bKillTimer);
  5587. if(bKillTimer)
  5588. KillTimer(hDlg, LDAP_BIND_TIMER_ID);
  5589. if (TRUE == fRet)
  5590. return TRUE; // We have more searches to do
  5591. }
  5592. else
  5593. {
  5594. // Not our timer. Shouldn't happen.
  5595. return FALSE;
  5596. }
  5597. }
  5598. }
  5599. else
  5600. KillTimer(hDlg, wParam);
  5601. //Stop the animation if it is running
  5602. if (pLDAPSearchParams->ulFlags & LSP_ShowAnim)
  5603. Animate_Stop(GetDlgItem(hDlg, IDC_LDAPCANCEL_ANIMATE));
  5604. SendMessage(hDlg, WM_CLOSE, 0, 0);
  5605. return TRUE;
  5606. }
  5607. case WM_CLOSE:
  5608. {
  5609. PLDAPSEARCHPARAMS pLDAPSearchParams;
  5610. // get data pointer from window data
  5611. pLDAPSearchParams = (PLDAPSEARCHPARAMS) GetWindowLongPtr(hDlg,DWLP_USER);
  5612. Assert(pLDAPSearchParams);
  5613. KillTimer(hDlg, pLDAPSearchParams->unTimerID);
  5614. //Stop the animation if it is running
  5615. if (pLDAPSearchParams->ulFlags & LSP_ShowAnim)
  5616. Animate_Stop(GetDlgItem(hDlg, IDC_LDAPCANCEL_ANIMATE));
  5617. if(pLDAPSearchParams->ulFlags & LSP_AbandonSearch)
  5618. {
  5619. // Abandon the search and set the error code to note the cancel
  5620. gpfnLDAPAbandon(*pLDAPSearchParams->ppLDAP,pLDAPSearchParams->ulMsgID);
  5621. pLDAPSearchParams->ulError = LDAP_USER_CANCELLED;
  5622. }
  5623. // Must set hDlgCancel to NULL in order to exit the message loop.
  5624. pLDAPSearchParams->hDlgCancel = NULL;
  5625. if(pLDAPSearchParams->ulFlags & LSP_InitDll)
  5626. DeinitLDAPClientLib();
  5627. {
  5628. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5629. HWND hWndParent = GetParent(hDlg);
  5630. if(hWndParent)
  5631. EnableWindow(hWndParent, TRUE);
  5632. pt_hDlgCancel = NULL;
  5633. }
  5634. DestroyWindow(hDlg);
  5635. return TRUE;
  5636. }
  5637. case WM_COMMAND:
  5638. switch (GET_WM_COMMAND_ID(wParam, lParam))
  5639. {
  5640. case IDCANCEL:
  5641. {
  5642. PLDAPSEARCHPARAMS pLDAPSearchParams = (PLDAPSEARCHPARAMS) GetWindowLongPtr(hDlg,DWLP_USER);
  5643. pLDAPSearchParams->ulFlags |= LSP_AbandonSearch;
  5644. SendMessage(hDlg, WM_CLOSE, 0, 0);
  5645. return TRUE;
  5646. }
  5647. }
  5648. break;
  5649. }
  5650. return FALSE;
  5651. }
  5652. //*******************************************************************
  5653. //
  5654. // FUNCTION: CenterWindow
  5655. //
  5656. // PURPOSE: Center one window over another.
  5657. //
  5658. // PARAMETERS: hwndChild - window to center
  5659. // hwndParent - window to use as center reference
  5660. //
  5661. // RETURNS: Returns result of SetWindowPos
  5662. //
  5663. // HISTORY:
  5664. // 96/10/28 markdu Created.
  5665. //
  5666. //*******************************************************************
  5667. BOOL CenterWindow (
  5668. HWND hwndChild,
  5669. HWND hwndParent)
  5670. {
  5671. RECT rChild, rParent;
  5672. int wChild, hChild, wParent, hParent;
  5673. int wScreen, hScreen, xNew, yNew;
  5674. HDC hdc;
  5675. Assert(hwndChild);
  5676. // Get the Height and Width of the child window
  5677. GetWindowRect (hwndChild, &rChild);
  5678. wChild = rChild.right - rChild.left;
  5679. hChild = rChild.bottom - rChild.top;
  5680. // If there is no parent, put it in the center of the screen
  5681. if ((NULL == hwndParent) || !IsWindow(hwndParent))
  5682. {
  5683. return SetWindowPos(hwndChild, NULL,
  5684. ((GetSystemMetrics(SM_CXSCREEN) - wChild) / 2),
  5685. ((GetSystemMetrics(SM_CYSCREEN) - hChild) / 2),
  5686. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  5687. }
  5688. // Get the Height and Width of the parent window
  5689. GetWindowRect (hwndParent, &rParent);
  5690. wParent = rParent.right - rParent.left;
  5691. hParent = rParent.bottom - rParent.top;
  5692. // Get the display limits
  5693. hdc = GetDC (hwndChild);
  5694. wScreen = GetDeviceCaps (hdc, HORZRES);
  5695. hScreen = GetDeviceCaps (hdc, VERTRES);
  5696. ReleaseDC (hwndChild, hdc);
  5697. // Calculate new X position, then adjust for screen
  5698. xNew = rParent.left + ((wParent - wChild) /2);
  5699. if (xNew < 0) {
  5700. xNew = 0;
  5701. } else if ((xNew+wChild) > wScreen) {
  5702. xNew = wScreen - wChild;
  5703. }
  5704. // Calculate new Y position, then adjust for screen
  5705. yNew = rParent.top + ((hParent - hChild) /2);
  5706. if (yNew < 0) {
  5707. yNew = 0;
  5708. } else if ((yNew+hChild) > hScreen) {
  5709. yNew = hScreen - hChild;
  5710. }
  5711. // Set it, and return
  5712. return SetWindowPos (hwndChild, NULL,
  5713. xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  5714. }
  5715. /*
  5716. -
  5717. - StartLDAPSearch
  5718. -
  5719. * Starts the LDAP Search
  5720. *
  5721. */
  5722. BOOL StartLDAPSearch(HWND hDlg, PLDAPSEARCHPARAMS pLDAPSearchParams, LPTSTR lpFilter)
  5723. {
  5724. BOOL fRet = FALSE;
  5725. LPTSTR szFilterT, szFilter = NULL;
  5726. if (lpFilter)
  5727. szFilterT = lpFilter;
  5728. else
  5729. {
  5730. if ((pLDAPSearchParams->ulFlags & LSP_IsNTDS) && pLDAPSearchParams->szNTFilter)
  5731. szFilterT = pLDAPSearchParams->szNTFilter;
  5732. else
  5733. szFilterT = pLDAPSearchParams->szFilter;
  5734. }
  5735. Assert(szFilterT);
  5736. if (pLDAPSearchParams->ulFlags & LSP_IsNTDS)
  5737. {
  5738. // [PaulHi] 4/20/99 Raid 73205 Allow NTDS group AND people searches.
  5739. LPTSTR tszFilterGP = NULL;
  5740. BOOL bFilterSucceeded = FALSE;
  5741. // Put together person and group categories
  5742. // [PaulHi] 6/21/99 Put together simpler search string
  5743. // ( & ( | (mail=chuck*) (anr=chuck) ) (|(objectcategory=person) (objectcategory=group) ) )
  5744. if (BuildOpFilter(&tszFilterGP, (LPTSTR)cszAllPersonFilter, (LPTSTR)cszAllGroupFilter, FILTER_OP_OR) == hrSuccess)
  5745. {
  5746. // Add to existing filter
  5747. bFilterSucceeded = (BuildOpFilter(&szFilter, szFilterT, tszFilterGP, FILTER_OP_AND) == hrSuccess);
  5748. LocalFreeAndNull(&tszFilterGP);
  5749. }
  5750. if (!bFilterSucceeded)
  5751. goto out;
  5752. }
  5753. else
  5754. szFilter = szFilterT;
  5755. DebugTrace(TEXT("Starting search for%s\n"),szFilter);
  5756. if (pLDAPSearchParams->ulFlags & LSP_UseSynchronousSearch)
  5757. {
  5758. pLDAPSearchParams->ulError = gpfnLDAPSearchS(*pLDAPSearchParams->ppLDAP, pLDAPSearchParams->szBase, pLDAPSearchParams->ulScope,
  5759. szFilter,
  5760. pLDAPSearchParams->ppszAttrs, pLDAPSearchParams->ulAttrsonly, pLDAPSearchParams->lplpResult);
  5761. if(LDAP_SUCCESS != pLDAPSearchParams->ulError)
  5762. {
  5763. DebugTrace(TEXT("LDAP Error: 0x%.2x %s\n"),(*(pLDAPSearchParams->ppLDAP))->ld_errno, gpfnLDAPErr2String((*(pLDAPSearchParams->ppLDAP))->ld_errno));
  5764. goto out;
  5765. }
  5766. }
  5767. else
  5768. {
  5769. #ifdef PAGED_RESULT_SUPPORT
  5770. // WAB's synchronous search calls never need to deal with paged results
  5771. // so for now (11/5/98) we don't do paged results stuff for synchronous calls.
  5772. // Instead we only do that stuff for Async since the UI driven LDAP calls are
  5773. // all Async
  5774. if(bSupportsLDAPPagedResults(pLDAPSearchParams))
  5775. InitLDAPPagedSearch(FALSE, pLDAPSearchParams, lpFilter);
  5776. else
  5777. #endif //#ifdef PAGED_RESULT_SUPPORT
  5778. {
  5779. pLDAPSearchParams->ulMsgID = gpfnLDAPSearch(*pLDAPSearchParams->ppLDAP, pLDAPSearchParams->szBase, pLDAPSearchParams->ulScope,
  5780. szFilter,
  5781. pLDAPSearchParams->ppszAttrs, pLDAPSearchParams->ulAttrsonly);
  5782. }
  5783. if(LDAP_ERROR == pLDAPSearchParams->ulMsgID)
  5784. {
  5785. DebugTrace(TEXT("LDAP Error: 0x%.2x %s\n"),(*(pLDAPSearchParams->ppLDAP))->ld_errno, gpfnLDAPErr2String((*(pLDAPSearchParams->ppLDAP))->ld_errno));
  5786. goto out;
  5787. }
  5788. }
  5789. if(!(pLDAPSearchParams->ulFlags & LSP_UseSynchronousSearch))
  5790. {
  5791. // Start a timer for the server polling.
  5792. if (LDAP_SEARCH_TIMER_ID != SetTimer(hDlg, LDAP_SEARCH_TIMER_ID, LDAP_SEARCH_TIMER_DELAY, NULL))
  5793. {
  5794. // Cancel the search if we couldn't start the timer.
  5795. gpfnLDAPAbandon( *pLDAPSearchParams->ppLDAP, pLDAPSearchParams->ulMsgID);
  5796. pLDAPSearchParams->ulError = LDAP_LOCAL_ERROR;
  5797. goto out;
  5798. }
  5799. pLDAPSearchParams->unTimerID = LDAP_SEARCH_TIMER_ID;
  5800. }
  5801. fRet = TRUE;
  5802. out:
  5803. if (szFilter != szFilterT)
  5804. LocalFreeAndNull(&szFilter);
  5805. return fRet;
  5806. }
  5807. //*******************************************************************
  5808. //
  5809. // FUNCTION: ResolveDoNextSearch
  5810. //
  5811. // PURPOSE: Start an asynchronous search for the next entry in
  5812. // the resolve adrlist.
  5813. //
  5814. // PARAMETERS: pLDAPSearchParams - search information
  5815. // hDlg - cancel dialog window handle
  5816. //
  5817. // RETURNS: Returns TRUE if there is a new search in progress.
  5818. // Returns FALSE if there is no more work left to do.
  5819. //
  5820. // HISTORY:
  5821. // 96/10/31 markdu Created.
  5822. //
  5823. //*******************************************************************
  5824. BOOL ResolveDoNextSearch(
  5825. PLDAPSEARCHPARAMS pLDAPSearchParams,
  5826. HWND hDlg,
  5827. BOOL bSecondPass)
  5828. {
  5829. LPADRENTRY lpAdrEntry;
  5830. ULONG ulAttrIndex;
  5831. ULONG ulEntryIndex;
  5832. ULONG ulcbFilter;
  5833. HRESULT hr = hrSuccess;
  5834. LPTSTR szFilter = NULL;
  5835. LPTSTR szNameFilter = NULL;
  5836. LPTSTR szEmailFilter = NULL;
  5837. LPTSTR szSimpleFilter = NULL;
  5838. LPTSTR lpFilter = NULL;
  5839. BOOL bUnicode = pLDAPSearchParams->bUnicode;
  5840. LPTSTR lpszInput = NULL;
  5841. BOOL bRet = FALSE;
  5842. ULONG cchSize;
  5843. // search for each name in the lpAdrList
  5844. ulEntryIndex = pLDAPSearchParams->ulEntryIndex;
  5845. while (ulEntryIndex < pLDAPSearchParams->lpAdrList->cEntries)
  5846. {
  5847. // Make sure we don't resolve an entry which is already resolved.
  5848. if (pLDAPSearchParams->lpFlagList->ulFlag[ulEntryIndex] != MAPI_RESOLVED)
  5849. {
  5850. // Search for this address
  5851. lpAdrEntry = &(pLDAPSearchParams->lpAdrList->aEntries[ulEntryIndex]);
  5852. // Look through the ADRENTRY for a PR_DISPLAY_NAME
  5853. for (ulAttrIndex = 0; ulAttrIndex < lpAdrEntry->cValues; ulAttrIndex++)
  5854. {
  5855. ULONG ulPropTag = lpAdrEntry->rgPropVals[ulAttrIndex].ulPropTag;
  5856. if(!bUnicode && PROP_TYPE(ulPropTag)==PT_STRING8)
  5857. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  5858. if ( ulPropTag == PR_DISPLAY_NAME || ulPropTag == PR_EMAIL_ADDRESS)
  5859. {
  5860. LPTSTR lpszInputCopy = NULL;
  5861. ULONG ulcIllegalChars = 0;
  5862. LPTSTR lpFilter = NULL;
  5863. BOOL bEmail = (ulPropTag == PR_EMAIL_ADDRESS);
  5864. if(!bUnicode)
  5865. LocalFreeAndNull(&lpszInput);
  5866. else
  5867. lpszInput = NULL;
  5868. lpszInput = bUnicode ? // <note> assumes UNICODE defined
  5869. lpAdrEntry->rgPropVals[ulAttrIndex].Value.lpszW :
  5870. ConvertAtoW(lpAdrEntry->rgPropVals[ulAttrIndex].Value.lpszA);
  5871. if (lpszInput)
  5872. ulcIllegalChars = CountIllegalChars(lpszInput);
  5873. if (ulcIllegalChars)
  5874. {
  5875. // Allocate a copy of the input, large enough to replace the illegal chars
  5876. // with escaped versions .. each escaped char is replaced by '\xx'
  5877. cchSize = lstrlen(lpszInput) + ulcIllegalChars*2 + 1;
  5878. lpszInputCopy = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  5879. if (NULL == lpszInputCopy)
  5880. {
  5881. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5882. break;
  5883. }
  5884. EscapeIllegalChars(lpszInput, lpszInputCopy, cchSize);
  5885. lpszInput = lpszInputCopy;
  5886. }
  5887. // We should have figured this out by now
  5888. Assert(pLDAPSearchParams->ulFlags & (LSP_IsNTDS | LSP_IsNotNTDS));
  5889. // Set up the search filter.
  5890. if (pLDAPSearchParams->ulFlags & LSP_IsNTDS)
  5891. {
  5892. hr = CreateSimpleSearchFilter(&szNameFilter, &szEmailFilter, &szSimpleFilter, lpszInput, FIRST_PASS);
  5893. if ((hrSuccess == hr) && !bSecondPass)
  5894. {
  5895. LocalFreeAndNull(&szNameFilter);
  5896. hr = BuildBasicFilter(&szNameFilter, (LPTSTR)cszAttr_anr, lpszInput, FALSE);
  5897. if (hrSuccess != hr)
  5898. {
  5899. LocalFreeAndNull(&szEmailFilter);
  5900. LocalFreeAndNull(&szSimpleFilter);
  5901. }
  5902. else
  5903. lpFilter = szNameFilter;
  5904. }
  5905. }
  5906. else
  5907. hr = CreateSimpleSearchFilter( &szNameFilter, &szEmailFilter, &szSimpleFilter, lpszInput, (bSecondPass ? UMICH_PASS : FIRST_PASS) );
  5908. if(lpszInputCopy)
  5909. LocalFree(lpszInputCopy);
  5910. if (hrSuccess != hr)
  5911. {
  5912. continue;
  5913. }
  5914. if (!lpFilter)
  5915. lpFilter = (pLDAPSearchParams->ulFlags & LSP_SimpleSearch) ? szSimpleFilter : szNameFilter;
  5916. if (szEmailFilter)
  5917. {
  5918. if (bEmail)
  5919. {
  5920. cchSize = lstrlen(szEmailFilter) + 1;
  5921. if(szFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize))
  5922. StrCpyN(szFilter, szEmailFilter, cchSize);
  5923. }
  5924. else
  5925. {
  5926. // No email field was given, so OR in the alternate email filter.
  5927. hr = BuildOpFilter( &szFilter, szEmailFilter, lpFilter, FILTER_OP_OR);
  5928. }
  5929. if (hrSuccess != hr || !szFilter)
  5930. {
  5931. LocalFreeAndNull(&szNameFilter);
  5932. LocalFreeAndNull(&szEmailFilter);
  5933. LocalFreeAndNull(&szSimpleFilter);
  5934. continue;
  5935. }
  5936. }
  5937. else
  5938. {
  5939. cchSize = lstrlen(lpFilter) + 1;
  5940. szFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  5941. if (NULL == szFilter)
  5942. {
  5943. LocalFreeAndNull(&szNameFilter);
  5944. LocalFreeAndNull(&szEmailFilter);
  5945. LocalFreeAndNull(&szSimpleFilter);
  5946. continue;
  5947. }
  5948. StrCpyN(szFilter, lpFilter, cchSize);
  5949. }
  5950. LocalFreeAndNull(&szNameFilter);
  5951. LocalFreeAndNull(&szEmailFilter);
  5952. LocalFreeAndNull(&szSimpleFilter);
  5953. if(StartLDAPSearch(hDlg, pLDAPSearchParams, szFilter))
  5954. {
  5955. // If no error occurred in ldap_search, return with this as
  5956. // our search. Otherwise, go on to the next entry.
  5957. pLDAPSearchParams->ulEntryIndex = ulEntryIndex;
  5958. // Free the search filter memory
  5959. LocalFreeAndNull(&szFilter);
  5960. bRet = TRUE;
  5961. goto out;
  5962. }
  5963. // Free the search filter memory
  5964. LocalFreeAndNull(&szFilter);
  5965. } // if value is PR_DISPLAY_NAME
  5966. } // for each value
  5967. } // if already resolved
  5968. // Go on to the next entry.
  5969. ulEntryIndex++;
  5970. }
  5971. out:
  5972. if(!bUnicode)
  5973. LocalFreeAndNull(&lpszInput);
  5974. return bRet;
  5975. }
  5976. //*******************************************************************
  5977. //
  5978. // FUNCTION: ResolveProcessResults
  5979. //
  5980. // PURPOSE: Process the results of the last search and put them
  5981. // in the resolve adrlist.
  5982. //
  5983. // PARAMETERS: pLDAPSearchParams - search information
  5984. // hDlg - cancel dialog window handle
  5985. //
  5986. // RETURNS: Returns TRUE if there is a new search in progress.
  5987. // Returns FALSE if there is no more work left to do.
  5988. //
  5989. // HISTORY:
  5990. // 96/10/31 markdu Created.
  5991. //
  5992. //*******************************************************************
  5993. BOOL ResolveProcessResults(
  5994. PLDAPSEARCHPARAMS pLDAPSearchParams,
  5995. HWND hDlg)
  5996. {
  5997. LPADRENTRY lpAdrEntry;
  5998. SCODE sc;
  5999. ULONG ulEntryIndex;
  6000. LPSPropValue lpPropArray = NULL;
  6001. LPSPropValue lpPropArrayNew = NULL;
  6002. ULONG ulcPropsNew;
  6003. ULONG ulcProps = 0;
  6004. HRESULT hr = hrSuccess;
  6005. LDAP* pLDAP = NULL;
  6006. LDAPMessage* lpResult = NULL;
  6007. LDAPMessage* lpEntry;
  6008. LPTSTR szDN;
  6009. ULONG ulResult = LDAP_SUCCESS;
  6010. ULONG ulcEntries;
  6011. ULONG ulcAttrs = 0;
  6012. LPTSTR* ppszAttrs;
  6013. BOOL bUnicode = pLDAPSearchParams->bUnicode;
  6014. // Set up local variables for frequently-accessed structure members
  6015. pLDAP = *pLDAPSearchParams->ppLDAP;
  6016. lpResult = *pLDAPSearchParams->lplpResult;
  6017. ulEntryIndex = pLDAPSearchParams->ulEntryIndex;
  6018. ulResult = CheckErrorResult(pLDAPSearchParams, LDAP_RES_SEARCH_RESULT);
  6019. if (LDAP_SUCCESS != ulResult)
  6020. {
  6021. DebugTrace(TEXT("LDAPCONT_ResolveNames: ldap_search returned %d.\n"), ulResult);
  6022. if (LDAP_UNDEFINED_TYPE == ulResult)
  6023. {
  6024. // the search failed we need to search again with a simplified filter ..
  6025. // This is true mostly for umich and we need to work against them ..
  6026. // free the search results memory
  6027. if (lpResult)
  6028. {
  6029. gpfnLDAPMsgFree(lpResult);
  6030. *pLDAPSearchParams->lplpResult = NULL;
  6031. }
  6032. return ResolveDoNextSearch(pLDAPSearchParams, hDlg, TRUE);
  6033. }
  6034. // If this entry was not found continue without error
  6035. if (LDAP_NO_SUCH_OBJECT != ulResult)
  6036. {
  6037. hr = HRFromLDAPError(ulResult, pLDAP, MAPI_E_NOT_FOUND);
  6038. // See if the result was the special value that tells us there were more
  6039. // entries than could be returned. If so, then there must be more than one
  6040. // entry, so we might just return ambiguous for this one.
  6041. if (ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE) == hr)
  6042. {
  6043. // 96/09/28 markdu BUG 36766
  6044. // If we mark this as ambiguous, the check names dialog will come up.
  6045. // We only want to do this is we actually got some results, otherwise
  6046. // the list will be empty.
  6047. ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult);
  6048. if (0 == ulcEntries)
  6049. {
  6050. // We got back no results, so mark the entry as resolved so we
  6051. // don't display the check names dialog.
  6052. DebugTrace(TEXT("ResolveNames found more than 1 match but got no results back\n"));
  6053. pLDAPSearchParams->lpFlagList->ulFlag[ulEntryIndex] = MAPI_UNRESOLVED;
  6054. }
  6055. else
  6056. {
  6057. // We got back multiple entries, so mark this as ambiguous
  6058. DebugTrace(TEXT("ResolveNames found more than 1 match... MAPI_AMBIGUOUS\n"));
  6059. pLDAPSearchParams->lpFlagList->ulFlag[ulEntryIndex] = MAPI_AMBIGUOUS;
  6060. }
  6061. }
  6062. }
  6063. goto exit;
  6064. }
  6065. // Count the entries.
  6066. ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult);
  6067. if (1 < ulcEntries)
  6068. {
  6069. DebugTrace(TEXT("ResolveNames found more than 1 match... MAPI_AMBIGUOUS\n"));
  6070. pLDAPSearchParams->lpFlagList->ulFlag[ulEntryIndex] = MAPI_AMBIGUOUS;
  6071. }
  6072. else if (1 == ulcEntries)
  6073. {
  6074. // get the first entry in the search result
  6075. lpAdrEntry = &(pLDAPSearchParams->lpAdrList->aEntries[ulEntryIndex]);
  6076. lpEntry = gpfnLDAPFirstEntry(pLDAP, lpResult);
  6077. if (NULL == lpEntry)
  6078. {
  6079. goto exit;
  6080. }
  6081. // Allocate a new buffer for the MAPI property array.
  6082. ppszAttrs = pLDAPSearchParams->ppszAttrs;
  6083. while (NULL != *ppszAttrs)
  6084. {
  6085. ppszAttrs++;
  6086. ulcAttrs++;
  6087. }
  6088. hr = HrLDAPEntryToMAPIEntry( pLDAP, lpEntry,
  6089. (LPTSTR) pLDAPSearchParams->lpszServer,
  6090. ulcAttrs, // standard number of attributes
  6091. (pLDAPSearchParams->ulFlags & LSP_IsNTDS),
  6092. &ulcProps,
  6093. &lpPropArray);
  6094. if (hrSuccess != hr)
  6095. {
  6096. goto exit;
  6097. }
  6098. if(!bUnicode) // convert native UNICODE to ANSI if we need to ...
  6099. {
  6100. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArray, ulcProps, 0))
  6101. goto exit;
  6102. }
  6103. // Merge the new props with the ADRENTRY props
  6104. sc = ScMergePropValues(lpAdrEntry->cValues,
  6105. lpAdrEntry->rgPropVals, // source1
  6106. ulcProps,
  6107. lpPropArray, // source2
  6108. &ulcPropsNew,
  6109. &lpPropArrayNew); // dest
  6110. if (sc)
  6111. {
  6112. goto exit;
  6113. }
  6114. // Free the original prop value array
  6115. FreeBufferAndNull((LPVOID *) (&(lpAdrEntry->rgPropVals)));
  6116. lpAdrEntry->cValues = ulcPropsNew;
  6117. lpAdrEntry->rgPropVals = lpPropArrayNew;
  6118. // Free the temp prop value array
  6119. FreeBufferAndNull(&lpPropArray);
  6120. // Mark this entry as found.
  6121. pLDAPSearchParams->lpFlagList->ulFlag[ulEntryIndex] = MAPI_RESOLVED;
  6122. }
  6123. else
  6124. {
  6125. // 96/08/08 markdu BUG 35481 No error and no results means "not found"
  6126. // If this entry was not found continue without error
  6127. }
  6128. exit:
  6129. // free the search results memory
  6130. if (lpResult)
  6131. {
  6132. gpfnLDAPMsgFree(lpResult);
  6133. *pLDAPSearchParams->lplpResult = NULL;
  6134. }
  6135. // Free the temp prop value array
  6136. FreeBufferAndNull(&lpPropArray);
  6137. // Initiate the next search.
  6138. pLDAPSearchParams->ulEntryIndex++;
  6139. return ResolveDoNextSearch(pLDAPSearchParams, hDlg, FALSE);
  6140. }
  6141. //*******************************************************************
  6142. //
  6143. // FUNCTION: BindProcessResults
  6144. //
  6145. // PURPOSE: Process the results of the bind operation. If successful,
  6146. // launch a search.
  6147. //
  6148. // PARAMETERS: pLDAPSearchParams - search information
  6149. // hDlg - cancel dialog window handle
  6150. //
  6151. // RETURNS: Returns TRUE if the bind was successful and we should
  6152. // go ahead with the searches.
  6153. // Returns FALSE if the bind failed.
  6154. //
  6155. // HISTORY:
  6156. // 96/11/01 markdu Created.
  6157. //
  6158. //*******************************************************************
  6159. BOOL BindProcessResults(PLDAPSEARCHPARAMS pLDAPSearchParams,
  6160. HWND hDlg,
  6161. BOOL * lpbNoMoreSearching)
  6162. {
  6163. LDAPMessage* lpResult = NULL;
  6164. LDAP* pLDAP = NULL;
  6165. ULONG ulResult = LDAP_SUCCESS;
  6166. // Set up local variables for frequently-accessed structure members
  6167. lpResult = *pLDAPSearchParams->lplpResult;
  6168. pLDAP = *pLDAPSearchParams->ppLDAP;
  6169. // Check for error results here if bind was asynchronous. If sync, we have
  6170. // already dealt with this.
  6171. if (!(pLDAPSearchParams->ulFlags & LSP_UseSynchronousBind))
  6172. {
  6173. // If an error occurred in ldap_result, return the error code
  6174. if (LDAP_ERROR == pLDAPSearchParams->ulResult)
  6175. {
  6176. ulResult = pLDAP->ld_errno;
  6177. }
  6178. // Check the result for errors
  6179. else if (NULL != lpResult)
  6180. {
  6181. ulResult = gpfnLDAPResult2Error(pLDAP,lpResult,FALSE);
  6182. }
  6183. ulResult = CheckErrorResult(pLDAPSearchParams, LDAP_RES_BIND);
  6184. // free the search results memory
  6185. if (lpResult)
  6186. {
  6187. gpfnLDAPMsgFree(lpResult);
  6188. *pLDAPSearchParams->lplpResult = NULL;
  6189. }
  6190. if (LDAP_SUCCESS != ulResult)
  6191. {
  6192. if(ulResult == LDAP_PROTOCOL_ERROR && pLDAPSearchParams->ulLDAPValue == use_ldap_v3)
  6193. {
  6194. // This means the server failed the v3 connection
  6195. // abort and try again
  6196. BOOL fUseSynchronousBind = (pLDAPSearchParams->ulFlags & LSP_UseSynchronousBind);
  6197. gpfnLDAPAbandon(*pLDAPSearchParams->ppLDAP, pLDAPSearchParams->ulMsgID);
  6198. gpfnLDAPAbandon(*pLDAPSearchParams->ppLDAP, pLDAPSearchParams->ulMsgID);
  6199. // [PaulHi] 1/7/99 Since we try a new bind we need to relinquish the old binding,
  6200. // otherwise the server will support two connections until the original V3 attempt
  6201. // times out.
  6202. gpfnLDAPUnbind(*pLDAPSearchParams->ppLDAP);
  6203. pLDAPSearchParams->ulLDAPValue = use_ldap_v2;
  6204. pLDAPSearchParams->ulError = OpenConnection( pLDAPSearchParams->lpszServer,
  6205. pLDAPSearchParams->ppLDAP,
  6206. &pLDAPSearchParams->ulTimeout,
  6207. &pLDAPSearchParams->ulMsgID,
  6208. &fUseSynchronousBind,
  6209. pLDAPSearchParams->ulLDAPValue,
  6210. pLDAPSearchParams->lpszBindDN,
  6211. pLDAPSearchParams->dwAuthType);
  6212. if(lpbNoMoreSearching)
  6213. *lpbNoMoreSearching = FALSE;
  6214. return TRUE;
  6215. }
  6216. // 96/12/09 markdu BUG 10537 If the bind returned one of these error
  6217. // messages, it probably means that the account name (DN) passed to the
  6218. // bind was incorrect or in the wrong format. Map these to an error code
  6219. // that will result in a better error message than "entry not found".
  6220. if ((LDAP_NAMING_VIOLATION == ulResult) || (LDAP_UNWILLING_TO_PERFORM == ulResult))
  6221. {
  6222. ulResult = LDAP_INVALID_CREDENTIALS;
  6223. }
  6224. // Bind was unsuccessful.
  6225. pLDAPSearchParams->ulError = ulResult;
  6226. return FALSE;
  6227. }
  6228. } // if (FALSE == pLDAPSearchParams->fUseSynchronousBind)
  6229. // we need to determine if a particular server is NTDS or not .. this is as good
  6230. // a place as any to make the check ...
  6231. bCheckIfNTDS(pLDAPSearchParams);
  6232. // See if we need to do the single search or if we need
  6233. // to launch the multiple searches
  6234. if (pLDAPSearchParams->ulFlags & LSP_ResolveMultiple)
  6235. {
  6236. // Initiate the first search.
  6237. return ResolveDoNextSearch(pLDAPSearchParams, hDlg, FALSE);
  6238. }
  6239. else
  6240. {
  6241. if(!StartLDAPSearch(hDlg, pLDAPSearchParams, NULL))
  6242. return FALSE;
  6243. }
  6244. return TRUE;
  6245. }
  6246. //*******************************************************************
  6247. //
  6248. // FUNCTION: BuildBasicFilter
  6249. //
  6250. // PURPOSE: Build an RFC1558 compliant filter of the form
  6251. // (A=B*) where A is an attribute, B is a value, and
  6252. // the * is optional. The buffer for the filter is
  6253. // allocated here, and must be freed by the caller.
  6254. //
  6255. // PARAMETERS: lplpszFilter - recieves buffer containing the filter
  6256. // lpszA - part A of (A=B*)
  6257. // lpszB - part B of (A=B*)
  6258. // fStartsWith - if TRUE, append the * so the filter
  6259. // will be a "starts with" filter
  6260. //
  6261. // RETURNS: HRESULT
  6262. //
  6263. // HISTORY:
  6264. // 96/12/22 markdu Created.
  6265. //
  6266. //*******************************************************************
  6267. HRESULT BuildBasicFilter(
  6268. LPTSTR FAR* lplpszFilter,
  6269. LPTSTR lpszA,
  6270. LPTSTR lpszB,
  6271. BOOL fStartsWith)
  6272. {
  6273. HRESULT hr = hrSuccess;
  6274. ULONG cchFilter;
  6275. // Allocate enough space for the filter string
  6276. cchFilter =
  6277. (FILTER_EXTRA_BASIC + // includes space for the *
  6278. lstrlen(lpszA) +
  6279. lstrlen(lpszB) + 1);
  6280. *lplpszFilter = LocalAlloc(LMEM_ZEROINIT, cchFilter*sizeof(TCHAR));
  6281. if (NULL == *lplpszFilter)
  6282. {
  6283. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  6284. goto exit;
  6285. }
  6286. StrCatBuff(*lplpszFilter, cszOpenParen, cchFilter);
  6287. StrCatBuff(*lplpszFilter, lpszA, cchFilter);
  6288. StrCatBuff(*lplpszFilter, cszEqualSign, cchFilter);
  6289. StrCatBuff(*lplpszFilter, lpszB, cchFilter);
  6290. if (TRUE == fStartsWith)
  6291. {
  6292. StrCatBuff(*lplpszFilter, cszStar, cchFilter);
  6293. }
  6294. StrCatBuff(*lplpszFilter, cszCloseParen, cchFilter);
  6295. exit:
  6296. return hr;
  6297. }
  6298. //*******************************************************************
  6299. //
  6300. // FUNCTION: BuildOpFilter
  6301. //
  6302. // PURPOSE: Build an RFC1558 compliant filter of the form
  6303. // (xAB) where A is an attribute, B is a value, and
  6304. // x is either & or |. The buffer for the filter is
  6305. // allocated here, and must be freed by the caller.
  6306. //
  6307. // PARAMETERS: lplpszFilter - recieves buffer containing the filter
  6308. // lpszA - part A of (A=B*)
  6309. // lpszB - part B of (A=B*)
  6310. // dwOp - if FILTER_OP_AND, x is &, if FILTER_OP_OR, x is |
  6311. //
  6312. // RETURNS: HRESULT
  6313. //
  6314. // HISTORY:
  6315. // 96/12/22 markdu Created.
  6316. //
  6317. //*******************************************************************
  6318. HRESULT BuildOpFilter(
  6319. LPTSTR FAR* lplpszFilter,
  6320. LPTSTR lpszA,
  6321. LPTSTR lpszB,
  6322. DWORD dwOp)
  6323. {
  6324. HRESULT hr = hrSuccess;
  6325. ULONG cchFilter;
  6326. LPTSTR szOp;
  6327. // Allocate enough space for the filter string
  6328. cchFilter =
  6329. FILTER_EXTRA_OP +
  6330. lstrlen(lpszA) +
  6331. lstrlen(lpszB) + 1;
  6332. *lplpszFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchFilter);
  6333. if (NULL == *lplpszFilter)
  6334. {
  6335. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  6336. goto exit;
  6337. }
  6338. switch (dwOp)
  6339. {
  6340. case FILTER_OP_AND:
  6341. szOp = (LPTSTR)cszAnd;
  6342. break;
  6343. case FILTER_OP_OR:
  6344. szOp = (LPTSTR)cszOr;
  6345. break;
  6346. default:
  6347. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  6348. goto exit;
  6349. }
  6350. StrCatBuff(*lplpszFilter, cszOpenParen, cchFilter);
  6351. StrCatBuff(*lplpszFilter, szOp, cchFilter);
  6352. StrCatBuff(*lplpszFilter, lpszA, cchFilter);
  6353. StrCatBuff(*lplpszFilter, lpszB, cchFilter);
  6354. StrCatBuff(*lplpszFilter, cszCloseParen, cchFilter);
  6355. exit:
  6356. return hr;
  6357. }
  6358. /***************************************************************************
  6359. Name : StrICmpN
  6360. Purpose : Compare strings, ignore case, stop at N characters
  6361. Parameters: szString1 = first string
  6362. szString2 = second string
  6363. N = number of characters to compare
  6364. bCmpI - compare insensitive if TRUE, sensitive if false
  6365. Returns : 0 if first N characters of strings are equivalent.
  6366. Comment :
  6367. ***************************************************************************/
  6368. int StrICmpN(LPTSTR szString1, LPTSTR szString2, ULONG N, BOOL bCmpI) {
  6369. int Result = 0;
  6370. if (szString1 && szString2) {
  6371. if(bCmpI)
  6372. {
  6373. szString1 = CharUpper(szString1);
  6374. szString2 = CharUpper(szString2);
  6375. }
  6376. while (*szString1 && *szString2 && N)
  6377. {
  6378. N--;
  6379. if (*szString1 != *szString2)
  6380. {
  6381. Result = 1;
  6382. break;
  6383. }
  6384. szString1=CharNext(szString1);
  6385. szString2=CharNext(szString2);
  6386. }
  6387. } else {
  6388. Result = -1; // arbitrarily non-equal result
  6389. }
  6390. return(Result);
  6391. }
  6392. //$$*************************************************
  6393. /*
  6394. * FreeLDAPURl - frees the LDAPURL struct
  6395. *
  6396. *
  6397. *///*************************************************
  6398. void FreeLDAPUrl(LPLDAPURL lplu)
  6399. {
  6400. if(lplu->lpszServer && lstrlen(lplu->lpszServer))
  6401. LocalFreeAndNull(&(lplu->lpszServer));
  6402. LocalFreeAndNull(&(lplu->lpszBase));
  6403. LocalFreeAndNull(&(lplu->lpszFilter));
  6404. if(lplu->ppszAttrib)
  6405. {
  6406. ULONG i;
  6407. for(i=0;i<lplu->ulAttribCount;i++)
  6408. {
  6409. if(lplu->ppszAttrib[i])
  6410. LocalFree(lplu->ppszAttrib[i]);
  6411. }
  6412. LocalFree(lplu->ppszAttrib);
  6413. }
  6414. return;
  6415. }
  6416. //$$//////////////////////////////////////////////////////////////
  6417. //
  6418. // Parse the LDAP URL into an LDAPURL struct
  6419. //
  6420. // if the URL has only the server specified, we need to show only the
  6421. // search dialog with the server name filled in .. however since we
  6422. // tend to fill in default values for the items we are not provided,
  6423. // we need a seperate flag to track that only the server existed in the
  6424. // given URL
  6425. //////////////////////////////////////////////////////////////////
  6426. HRESULT ParseLDAPUrl(LPTSTR szLDAPUrl,
  6427. LPLDAPURL lplu)
  6428. {
  6429. HRESULT hr = E_FAIL;
  6430. TCHAR szLDAP[] = TEXT("ldap://");
  6431. TCHAR szScopeBase[] = TEXT("base");
  6432. TCHAR szScopeOne[] = TEXT("one");
  6433. TCHAR szScopeSub[] = TEXT("sub");
  6434. TCHAR szDefBase[32];
  6435. TCHAR szBindName[] = TEXT("bindname=");
  6436. LPTSTR lpsz = NULL;
  6437. LPTSTR lpszTmp = NULL, lpszMem = NULL;
  6438. ULONG cchSize;
  6439. DWORD dwCharCount;
  6440. // Form of the LDAP URL is
  6441. //
  6442. // ldap://[<servername>:<port>][/<dn>[?[<attrib>[?[<scope>[?[<filter>[?[<extension>]]]]]]]]]
  6443. //
  6444. // Translation of above to our parameters is
  6445. //
  6446. // lpszServer = ServerName
  6447. // szBase = dn default = "c=US"
  6448. // ppszAttrib = attrib default = all
  6449. // ulScope = scope default = base
  6450. // szfilter = filter default = (objectclass=*)
  6451. // szExtension = extension default = none
  6452. //
  6453. if(!lplu || !szLDAPUrl)
  6454. goto exit;
  6455. lplu->bServerOnly = FALSE;
  6456. {
  6457. // Fill in the default base as c=DefCountry
  6458. LPTSTR lpszBase = TEXT("c=%s");
  6459. TCHAR szCode[4];
  6460. ReadRegistryLDAPDefaultCountry(NULL, 0, szCode, ARRAYSIZE(szCode));
  6461. wnsprintf(szDefBase, ARRAYSIZE(szDefBase), lpszBase, szCode);
  6462. }
  6463. // Make a copy of our URL
  6464. // [PaulHi] 3/24/99 Leave room for InternetCanonicalizeUrlW adjustment
  6465. {
  6466. dwCharCount = 3 * lstrlen(szLDAPUrl);
  6467. lpsz = LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(dwCharCount+1));
  6468. if(!lpsz)
  6469. goto exit;
  6470. StrCpyN(lpsz, szLDAPUrl, dwCharCount+1);
  6471. // Since this is most likely a URL on an HTML page, we need to translate its escape
  6472. // characters to proper characters .. e.g. %20 becomes ' ' ..
  6473. //
  6474. // [PaulHi] 3/24/99 !!InternetCanonicalizeUrlW takes buffer size in CHARS and not
  6475. // BYTES as the documentation claims. Also doesn't account for the NULL terminator!!
  6476. // DWORD dw = sizeof(TCHAR)*(lstrlen(szLDAPUrl));
  6477. if ( !InternetCanonicalizeUrlW(szLDAPUrl, lpsz, &dwCharCount, ICU_DECODE | ICU_NO_ENCODE) )
  6478. {
  6479. DebugTrace(TEXT("ERROR: ParseLDAPUrl, InternetCanonicalizeUrlW failed.\n"));
  6480. Assert(0);
  6481. }
  6482. }
  6483. lpszMem = lpszTmp = lpsz;
  6484. // Check if this is an LDAP url
  6485. if(StrICmpN(lpsz, szLDAP, CharSizeOf(szLDAP)-1, TRUE))
  6486. goto exit;
  6487. lpszTmp += CharSizeOf(szLDAP)-1;
  6488. StrCpyN(lpsz,lpszTmp, dwCharCount+1);
  6489. lpszTmp = lpsz;
  6490. // If there is no server name, bail ..
  6491. // If the next character after the ldap:// is a '/',
  6492. // we know there is no server name ..
  6493. lplu->bServerOnly = TRUE; // we turn this on for the server and
  6494. // then turn it off if we find a filter or dn
  6495. if(*lpsz == '/')
  6496. {
  6497. // null server name .. which is valid
  6498. lplu->lpszServer = szEmpty; //NULL?
  6499. }
  6500. else
  6501. {
  6502. while( *lpszTmp &&
  6503. *lpszTmp != '/')
  6504. {
  6505. lpszTmp = CharNext(lpszTmp);
  6506. }
  6507. if(*lpszTmp)
  6508. {
  6509. LPTSTR lp = lpszTmp;
  6510. lpszTmp = CharNext(lpszTmp);
  6511. *lp = '\0';
  6512. }
  6513. cchSize = lstrlen(lpsz)+1;
  6514. lplu->lpszServer = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6515. if(!lplu->lpszServer)
  6516. goto exit;
  6517. StrCpyN(lplu->lpszServer, lpsz, cchSize);
  6518. lpsz = lpszTmp;
  6519. }
  6520. // The next item in the filter is the <dn> which is out szBase
  6521. // If the next char is a \0 or a '?', then we didnt get a <dn>
  6522. if(!*lpsz || *lpsz == '?')
  6523. {
  6524. cchSize = lstrlen(szDefBase)+1;
  6525. lplu->lpszBase = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6526. if(!lplu->lpszBase)
  6527. goto exit;
  6528. StrCpyN(lplu->lpszBase, szDefBase, cchSize);
  6529. lpsz = lpszTmp = CharNext(lpsz);
  6530. }
  6531. else
  6532. {
  6533. lplu->bServerOnly = FALSE; // if we found a dn, we have something to search for
  6534. while( *lpszTmp &&
  6535. *lpszTmp != '?')
  6536. {
  6537. lpszTmp = CharNext(lpszTmp);
  6538. }
  6539. if(*lpszTmp)
  6540. {
  6541. LPTSTR lp = lpszTmp;
  6542. lpszTmp = CharNext(lpszTmp);
  6543. *lp = '\0';
  6544. }
  6545. cchSize = lstrlen(lpsz)+1;
  6546. lplu->lpszBase = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6547. if(!lplu->lpszBase)
  6548. goto exit;
  6549. StrCpyN(lplu->lpszBase, lpsz, cchSize);
  6550. lpsz = lpszTmp;
  6551. }
  6552. // NExt on line is the attributes for this search ...
  6553. // There are no attributes if this is the end of the string
  6554. // or the current character is a ?
  6555. if(!*lpsz || *lpsz == '?')
  6556. {
  6557. lplu->ppszAttrib = NULL;
  6558. lpsz = lpszTmp = CharNext(lpsz);
  6559. }
  6560. else
  6561. {
  6562. while( *lpszTmp &&
  6563. *lpszTmp != '?')
  6564. {
  6565. lpszTmp = CharNext(lpszTmp);
  6566. }
  6567. if(*lpszTmp)
  6568. {
  6569. LPTSTR lp = lpszTmp;
  6570. lpszTmp = CharNext(lpszTmp);
  6571. *lp = '\0';
  6572. }
  6573. {
  6574. //Count the commas in the attrib string
  6575. LPTSTR lp = lpsz;
  6576. ULONG i;
  6577. lplu->ulAttribCount = 0;
  6578. while(*lp)
  6579. {
  6580. if(*lp == ',')
  6581. lplu->ulAttribCount++;
  6582. lp=CharNext(lp);
  6583. }
  6584. lplu->ulAttribCount++; // one more attribute than commas
  6585. lplu->ulAttribCount++; // we must get a display name no matter whether its asked for or not
  6586. // otherwise we will fault on NT .. so add a display name param
  6587. lplu->ulAttribCount++; // for terminating NULL
  6588. lplu->ppszAttrib = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * lplu->ulAttribCount);
  6589. if(!lplu->ppszAttrib)
  6590. goto exit;
  6591. lp = lpsz;
  6592. for(i=0;i<lplu->ulAttribCount - 2;i++)
  6593. {
  6594. LPTSTR lp3 = lp;
  6595. while(*lp && *lp!= ',')
  6596. lp = CharNext(lp);
  6597. lp3=CharNext(lp);
  6598. *lp = '\0';
  6599. lp = lp3;
  6600. cchSize = lstrlen(lpsz)+1;
  6601. lplu->ppszAttrib[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6602. if(!lplu->ppszAttrib[i])
  6603. goto exit;
  6604. StrCpyN(lplu->ppszAttrib[i], lpsz, cchSize);
  6605. lpsz = lp;
  6606. }
  6607. cchSize = lstrlen(cszAttr_cn)+1;
  6608. lplu->ppszAttrib[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6609. if(!lplu->ppszAttrib[i])
  6610. goto exit;
  6611. StrCpyN(lplu->ppszAttrib[i], cszAttr_cn, cchSize);
  6612. i++;
  6613. lplu->ppszAttrib[i] = NULL;
  6614. }
  6615. lpsz = lpszTmp;
  6616. }
  6617. // Next is the scope which can be one of 3 values
  6618. if(!*lpsz || *lpsz == '?')
  6619. {
  6620. lplu->ulScope = LDAP_SCOPE_BASE;
  6621. lpsz = lpszTmp = CharNext(lpsz);
  6622. }
  6623. else
  6624. {
  6625. if(!StrICmpN(lpsz, szScopeOne, CharSizeOf(szScopeOne)-1, TRUE))
  6626. {
  6627. lplu->ulScope = LDAP_SCOPE_ONELEVEL;
  6628. lpszTmp += CharSizeOf(szScopeOne);
  6629. }
  6630. else if(!StrICmpN(lpsz, szScopeSub, CharSizeOf(szScopeSub)-1, TRUE))
  6631. {
  6632. lplu->ulScope = LDAP_SCOPE_SUBTREE;
  6633. lpszTmp += CharSizeOf(szScopeSub);
  6634. }
  6635. else
  6636. if(!StrICmpN(lpsz, szScopeBase, CharSizeOf(szScopeBase)-1, TRUE))
  6637. {
  6638. lplu->ulScope = LDAP_SCOPE_BASE;
  6639. lpszTmp += CharSizeOf(szScopeBase);
  6640. }
  6641. lpsz = lpszTmp;
  6642. }
  6643. // Finally the filter
  6644. if(!*lpsz)
  6645. {
  6646. // No filter
  6647. lpsz = (LPTSTR)cszAllEntriesFilter;// TBD this should be c=DefaultCountry
  6648. }
  6649. else
  6650. lplu->bServerOnly = FALSE; // we have something to search for ..
  6651. cchSize = lstrlen(lpsz)+1;
  6652. lplu->lpszFilter = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  6653. if(!lplu->lpszFilter)
  6654. goto exit;
  6655. // Dont set the lpszFilter to NULL at any point of time or we will leak the above memory
  6656. StrCpyN(lplu->lpszFilter, lpsz, cchSize);
  6657. // There may be extensions in the filter itself .. so we check for such extensions by
  6658. // looking for a '?' .. the extensions are a list of comma-seperated type-value pairs
  6659. // e.g bindname=xxx,!sometype=yyy etc ...
  6660. //
  6661. // Extensions may be of 2 types - critical (which start with '!') and non-critical which dont
  6662. // If a handler can't handle the critical extension, then they should decline from handling
  6663. // the complete LDAP URL ..
  6664. // If they can handle the critical extension then they must handle it
  6665. // If the extension is non critical, then its up to us what we do with it ..
  6666. {
  6667. LPTSTR lp = lplu->lpszFilter;
  6668. while(lp && *lp && *lp!='?')
  6669. lp++;
  6670. if(*lp == '?')
  6671. {
  6672. lplu->lpszExtension = lp+1; // point this to the extension part
  6673. *lp = '\0'; // null terminate the middle to isolate the filter from the extension
  6674. }
  6675. // only known extension specified in RFC2255 is the bindname extension which
  6676. // is the name that one should bind with - this is critical only if !bindname=xxx is specified
  6677. if(lplu->lpszExtension)
  6678. {
  6679. LPTSTR lpTemp = lplu->lpszExtension;
  6680. lp = lplu->lpszExtension;
  6681. // walk this list looking at subcomponent extensions
  6682. // if there is more than 1 that is critical and we dont know how to handle it
  6683. // we can bail
  6684. while(lpTemp && *lpTemp)
  6685. {
  6686. BOOL bFoundCritical = FALSE;
  6687. // Check if the current extension is a critical or non-critical bind name
  6688. //
  6689. if(*lpTemp == '!')
  6690. {
  6691. lpTemp++;
  6692. bFoundCritical = TRUE;
  6693. }
  6694. // Check if this starts with "bindname="
  6695. if(lstrlen(lpTemp) >= lstrlen(szBindName) && !StrICmpN(lpTemp, szBindName, lstrlen(szBindName), TRUE))
  6696. {
  6697. // yes this is a bindname
  6698. lpTemp+=lstrlen(szBindName);
  6699. lplu->lpszBindName = lpTemp;
  6700. lplu->lpszExtension = NULL;
  6701. }
  6702. else if(bFoundCritical)
  6703. {
  6704. // it's not a bindname ..
  6705. // if this is critical, whatever it is, then we cant handle it
  6706. DebugTrace(TEXT("Found unsupported Critical Extension in LDAPURL!!!"));
  6707. hr = MAPI_E_NO_SUPPORT;
  6708. goto exit;
  6709. }
  6710. // else // its not critical so we can ignore it
  6711. // check if there are any other extensions - walk to the next one
  6712. while(*lpTemp && *lpTemp!=',')
  6713. lpTemp++;
  6714. if(*lpTemp == ',')
  6715. {
  6716. *lpTemp = '\0'; // terminate current extension
  6717. lpTemp++;
  6718. }
  6719. }
  6720. }
  6721. }
  6722. hr = S_OK;
  6723. exit:
  6724. LocalFreeAndNull(&lpszMem);
  6725. if(HR_FAILED(hr))
  6726. FreeLDAPUrl(lplu);
  6727. return hr;
  6728. }
  6729. //*******************************************************************
  6730. //
  6731. // FUNCTION: HrProcessLDAPUrl
  6732. //
  6733. // PURPOSE:
  6734. // We need to decide what to do with this URL.
  6735. // Depending on how much information is in the URL, we decide to do
  6736. // different things ..
  6737. // If the URL looks complete, we try to do a query
  6738. // If the query has single results, we show details on the result
  6739. // If the query has multiple results, we show a list of results
  6740. // If the URL looks incomplete but has a server name, we will show a
  6741. // find dialog with the server name filled in ...
  6742. //
  6743. // PARAMETERS: ulFLags - 0 or WABOBJECT_LDAPURL_RETURN_MAILUSER
  6744. // if the flag is set, it means that return a mailuser
  6745. // if the URL query returned a single object
  6746. // else return MAPI_E_AMBIGUOUS_RECIPIENT
  6747. // specify MAPI_DIALOG to show mesage dialog boxes
  6748. //
  6749. // RETURNS: HRESULT
  6750. //
  6751. // HISTORY:
  6752. //
  6753. //*******************************************************************
  6754. HRESULT HrProcessLDAPUrl( LPADRBOOK lpAdrBook,
  6755. HWND hWnd,
  6756. ULONG ulFlags,
  6757. LPTSTR szLDAPUrl,
  6758. LPMAILUSER * lppMailUser)
  6759. {
  6760. HRESULT hr = S_OK;
  6761. LDAPURL lu = {0};
  6762. BOOL fInitDll = FALSE;
  6763. LPMAILUSER lpMailUser = NULL;
  6764. if ( (ulFlags & WABOBJECT_LDAPURL_RETURN_MAILUSER) &&
  6765. !lppMailUser)
  6766. {
  6767. hr = MAPI_E_INVALID_PARAMETER;
  6768. goto out;
  6769. }
  6770. if (! (fInitDll = InitLDAPClientLib()))
  6771. {
  6772. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  6773. goto out;
  6774. }
  6775. if(HR_FAILED(hr = ParseLDAPUrl(szLDAPUrl, &lu)))
  6776. goto out;
  6777. /*NULL server is valid .. but only a NULL server is not valid*/
  6778. if( ((!lu.lpszServer || !lstrlen(lu.lpszServer)) && lu.bServerOnly) ||
  6779. ( lstrlen(lu.lpszServer) >= 500 ) ) //bug 21240: the combo box GetItemText fails down the line with really big
  6780. // server names so reject server names > 500
  6781. // which is a completely random number but should be safe (I hope)
  6782. {
  6783. DebugTrace(TEXT("Invalid LDAP URL .. aborting\n"));
  6784. hr = MAPI_E_INVALID_PARAMETER;
  6785. goto out;
  6786. }
  6787. if (ulFlags & LDAP_AUTH_SICILY || ulFlags & LDAP_AUTH_NEGOTIATE)
  6788. lu.dwAuthType = LDAP_AUTH_NEGOTIATE;
  6789. else
  6790. lu.dwAuthType = LDAP_AUTH_ANONYMOUS;
  6791. // Now depending on what we have, we do different things ..
  6792. // If there is a server name, but nothing else, show the find
  6793. // dialog with the server name filled in ...
  6794. //
  6795. if (lu.bServerOnly)
  6796. {
  6797. // we only had a server name
  6798. hr = HrShowSearchDialog(lpAdrBook,
  6799. hWnd,
  6800. (LPADRPARM_FINDINFO) NULL,
  6801. &lu,
  6802. NULL);
  6803. goto out;
  6804. }
  6805. else
  6806. {
  6807. LPSPropValue lpPropArray = NULL;
  6808. ULONG ulcProps = 0;
  6809. LPRECIPIENT_INFO lpList = NULL;
  6810. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  6811. if(hWnd)
  6812. pt_hWndFind = hWnd;
  6813. hr = LDAPSearchWithoutContainer(hWnd,
  6814. &lu,
  6815. (LPSRestriction) NULL,
  6816. NULL,
  6817. TRUE,
  6818. (ulFlags & MAPI_DIALOG) ? MAPI_DIALOG : 0,
  6819. &lpList,
  6820. &ulcProps,
  6821. &lpPropArray);
  6822. if(hWnd)
  6823. pt_hWndFind = NULL;
  6824. if(!(HR_FAILED(hr)) && !lpList && !lpPropArray)
  6825. hr = MAPI_E_NOT_FOUND;
  6826. if(HR_FAILED(hr))
  6827. goto out;
  6828. lu.lpList = lpList;
  6829. if(ulcProps && lpPropArray)
  6830. {
  6831. // there is only one item .. show details on it ..
  6832. // unless we were asked to return a mailuser
  6833. // If we were asked to return a mailuser, then return
  6834. // one ...
  6835. // We should do IAB_OpenEntry with the LDAP EntryID because that
  6836. // will force translation of the UserCertificate property into the
  6837. // X509 certificate
  6838. // first find the entryid
  6839. ULONG i = 0, cbEID = 0, ulObjType = 0;
  6840. LPENTRYID lpEID = NULL;
  6841. for(i=0;i<ulcProps;i++)
  6842. {
  6843. if(lpPropArray[i].ulPropTag == PR_ENTRYID)
  6844. {
  6845. lpEID = (LPENTRYID) lpPropArray[i].Value.bin.lpb;
  6846. cbEID = lpPropArray[i].Value.bin.cb;
  6847. break;
  6848. }
  6849. }
  6850. if(!lpEID || !cbEID)
  6851. goto out;
  6852. if(HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook, cbEID, lpEID,
  6853. NULL, 0, &ulObjType,
  6854. (LPUNKNOWN *)&lpMailUser)))
  6855. {
  6856. DebugPrintError(( TEXT("OpenEntry failed .. %x\n"), hr));
  6857. goto out;
  6858. }
  6859. if(ulFlags & WABOBJECT_LDAPURL_RETURN_MAILUSER)
  6860. {
  6861. *lppMailUser = lpMailUser;
  6862. }
  6863. else
  6864. {
  6865. hr = HrShowOneOffDetails( lpAdrBook,
  6866. hWnd,
  6867. 0, (LPENTRYID) NULL,
  6868. MAPI_MAILUSER,
  6869. (LPMAPIPROP) lpMailUser,
  6870. szLDAPUrl,
  6871. SHOW_ONE_OFF);
  6872. }
  6873. if(lpPropArray)
  6874. MAPIFreeBuffer(lpPropArray);
  6875. }
  6876. else if(lpList)
  6877. {
  6878. // multiple items, display a list of results ..
  6879. // unless MailUser was requested in which case return
  6880. // ambiguous results ...
  6881. if(ulFlags & WABOBJECT_LDAPURL_RETURN_MAILUSER)
  6882. {
  6883. hr = MAPI_E_AMBIGUOUS_RECIP;
  6884. }
  6885. else
  6886. {
  6887. hr = HrShowSearchDialog(lpAdrBook,
  6888. hWnd,
  6889. (LPADRPARM_FINDINFO) NULL,
  6890. &lu,
  6891. NULL);
  6892. }
  6893. }
  6894. while(lu.lpList)
  6895. {
  6896. lpList = lu.lpList->lpNext;
  6897. FreeRecipItem(&(lu.lpList));
  6898. lu.lpList = lpList;
  6899. }
  6900. }
  6901. out:
  6902. if(!(ulFlags & WABOBJECT_LDAPURL_RETURN_MAILUSER) && lpMailUser)
  6903. lpMailUser->lpVtbl->Release(lpMailUser);
  6904. FreeLDAPUrl(&lu);
  6905. if (fInitDll)
  6906. DeinitLDAPClientLib();
  6907. return hr;
  6908. }
  6909. //*******************************************************************
  6910. //
  6911. // FUNCTION: LDAPSearchWithoutContainer
  6912. //
  6913. // PURPOSE: Searchs a LDAP server which is not registered as a
  6914. // container and creates an LPContentList of returned results
  6915. //
  6916. // PARAMETERS: lplu - LDAPUrl parameters
  6917. // lpres - restriction to convert into LDAP search, used if present
  6918. // lppContentsList - returned list of items
  6919. //
  6920. // if bReturnSinglePropArray is set to true, then returns the generated
  6921. // prop array if the search produced a single result
  6922. //
  6923. // RETURNS: HRESULT
  6924. //
  6925. // HISTORY:
  6926. // 97/11/3 created
  6927. //
  6928. //*******************************************************************
  6929. HRESULT LDAPSearchWithoutContainer(HWND hWnd,
  6930. LPLDAPURL lplu,
  6931. LPSRestriction lpres,
  6932. LPTSTR lpAdvFilter,
  6933. BOOL bReturnSinglePropArray,
  6934. ULONG ulFlags,
  6935. LPRECIPIENT_INFO * lppContentsList,
  6936. LPULONG lpulcProps,
  6937. LPSPropValue * lppPropArray)
  6938. {
  6939. SCODE sc;
  6940. HRESULT hr;
  6941. HRESULT hrDeferred = hrSuccess;
  6942. LPMAILUSER lpMailUser = NULL;
  6943. LPMAPIPROP lpMapiProp = NULL;
  6944. ULONG ulcProps = 0;
  6945. LPSPropValue lpPropArray = NULL;
  6946. LDAPMessage* lpResult = NULL;
  6947. LDAPMessage* lpEntry;
  6948. LDAP* pLDAP = NULL;
  6949. LPTSTR szDN;
  6950. ULONG ulResult = 0;
  6951. ULONG ulcEntries;
  6952. ULONG ulIndex = 0;
  6953. LPTSTR szFilter = NULL;
  6954. LPTSTR szNTFilter = NULL;
  6955. LPTSTR szSimpleFilter = NULL;
  6956. LPTSTR szBase = NULL;
  6957. BOOL fInitDLL = FALSE;
  6958. BOOL bIsNTDSEntry = FALSE;
  6959. if(lpAdvFilter)
  6960. {
  6961. // Advanced search, just use this filter as is
  6962. szFilter = lpAdvFilter;
  6963. szNTFilter = lpAdvFilter;
  6964. szSimpleFilter = lpAdvFilter;
  6965. }
  6966. else
  6967. {
  6968. // Convert the SRestriction into filters for ldap_search
  6969. if(lpres)
  6970. {
  6971. // Note Simple Search Filter is ignored in searchwithoutcontiner
  6972. hr = ParseSRestriction(lpres, &szFilter, &szSimpleFilter, &szNTFilter, FIRST_PASS, TRUE); //assumes UNICODE always
  6973. if (hrSuccess != hr)
  6974. goto exit;
  6975. }
  6976. }
  6977. // Load the client functions
  6978. if (! (fInitDLL = InitLDAPClientLib()))
  6979. {
  6980. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  6981. goto exit;
  6982. }
  6983. // Read the matching entries
  6984. ulResult = SearchWithCancel(&pLDAP,
  6985. (LPTSTR)lplu->lpszBase,
  6986. (lpres ? LDAP_SCOPE_SUBTREE : lplu->ulScope),
  6987. (LPTSTR)(lpres ? szFilter : lplu->lpszFilter),
  6988. (LPTSTR)(lpres ? szNTFilter : NULL),
  6989. (LPTSTR*)(lpres ? g_rgszOpenEntryAttrs/*g_rgszFindRowAttrs*/ : lplu->ppszAttrib),
  6990. 0,
  6991. &lpResult,
  6992. (LPTSTR)lplu->lpszServer,
  6993. TRUE,
  6994. lplu->lpszBindName, lplu->dwAuthType,
  6995. FALSE, NULL, NULL, FALSE, &bIsNTDSEntry,
  6996. TRUE); //unicode by default ?
  6997. if (LDAP_SUCCESS != ulResult)
  6998. {
  6999. DebugTrace(TEXT("LDAPSearchWithoutContainer: ldap_search returned %d.\n"), ulResult);
  7000. hr = HRFromLDAPError(ulResult, pLDAP, 0);
  7001. // See if the result was the special value that tells us there were more
  7002. // entries than could be returned. If so, we need to check if we got
  7003. // some of the entries or none of the entries.
  7004. if ( (ResultFromScode(MAPI_E_UNABLE_TO_COMPLETE) == hr) &&
  7005. (ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult)) )
  7006. {
  7007. // We got some results back. Return MAPI_W_PARTIAL_COMPLETION
  7008. // instead of success.
  7009. hrDeferred = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
  7010. hr = hrSuccess;
  7011. }
  7012. else
  7013. goto exit;
  7014. }
  7015. else
  7016. {
  7017. // Count the entries.
  7018. ulcEntries = gpfnLDAPCountEntries(pLDAP, lpResult);
  7019. }
  7020. if (0 == ulcEntries)
  7021. {
  7022. // 96/08/08 markdu BUG 35481 No error and no results means "not found"
  7023. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  7024. goto exit;
  7025. }
  7026. // get the first entry in the search result
  7027. lpEntry = gpfnLDAPFirstEntry(pLDAP, lpResult);
  7028. if (NULL == lpEntry)
  7029. {
  7030. DebugTrace(TEXT("LDAP_FindRow: No entry found for %s.\n"), szFilter);
  7031. hr = HRFromLDAPError(LDAP_ERROR, pLDAP, MAPI_E_CORRUPT_DATA);
  7032. if (hrSuccess == hr)
  7033. {
  7034. // No error occurred according to LDAP, which in theory means that there
  7035. // were no more entries. However, this should not happen, so return error.
  7036. hr = ResultFromScode(MAPI_E_CORRUPT_DATA);
  7037. }
  7038. goto exit;
  7039. }
  7040. while (lpEntry)
  7041. {
  7042. LPRECIPIENT_INFO lpItem = NULL;
  7043. hr = HrLDAPEntryToMAPIEntry( pLDAP, lpEntry,
  7044. (LPTSTR) lplu->lpszServer,
  7045. 0, // standard number of attributes
  7046. bIsNTDSEntry,
  7047. &ulcProps,
  7048. &lpPropArray);
  7049. if (hrSuccess != hr)
  7050. continue;
  7051. // Get the next entry.
  7052. lpEntry = gpfnLDAPNextEntry(pLDAP, lpEntry);
  7053. if(!lpEntry &&
  7054. ulIndex == 0 &&
  7055. bReturnSinglePropArray &&
  7056. lppPropArray &&
  7057. lpulcProps)
  7058. {
  7059. // just return this propArray we created instead of wasting time on
  7060. // other things
  7061. *lppPropArray = lpPropArray;
  7062. *lpulcProps = ulcProps;
  7063. }
  7064. else
  7065. {
  7066. // multiple results or prop array not asked for ,
  7067. // return an lpItem list
  7068. //
  7069. lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  7070. if (!lpItem)
  7071. {
  7072. DebugPrintError(( TEXT("LocalAlloc Failed \n")));
  7073. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  7074. goto exit;
  7075. }
  7076. GetRecipItemFromPropArray(ulcProps, lpPropArray, &lpItem);
  7077. lpItem->lpPrev = NULL;
  7078. if(*lppContentsList)
  7079. (*lppContentsList)->lpPrev = lpItem;
  7080. lpItem->lpNext = *lppContentsList;
  7081. *lppContentsList = lpItem;
  7082. MAPIFreeBuffer(lpPropArray);
  7083. lpPropArray = NULL;
  7084. ulcProps = 0;
  7085. }
  7086. ulIndex++;
  7087. }
  7088. // Free the search results memory
  7089. gpfnLDAPMsgFree(lpResult);
  7090. lpResult = NULL;
  7091. exit:
  7092. // free the search results memory
  7093. if (lpResult)
  7094. {
  7095. gpfnLDAPMsgFree(lpResult);
  7096. lpResult = NULL;
  7097. }
  7098. // close the connection
  7099. if (pLDAP)
  7100. {
  7101. gpfnLDAPUnbind(pLDAP);
  7102. pLDAP = NULL;
  7103. }
  7104. // Free the search filter memory
  7105. if(szFilter != lpAdvFilter)
  7106. LocalFreeAndNull(&szFilter);
  7107. if(szNTFilter != lpAdvFilter)
  7108. LocalFreeAndNull(&szNTFilter);
  7109. if(szSimpleFilter != lpAdvFilter)
  7110. LocalFreeAndNull(&szSimpleFilter);
  7111. LocalFreeAndNull(&szBase);
  7112. if (fInitDLL)
  7113. {
  7114. DeinitLDAPClientLib();
  7115. }
  7116. // Check if we had a deferred error to return instead of success.
  7117. if (hrSuccess == hr)
  7118. {
  7119. hr = hrDeferred;
  7120. }
  7121. if((HR_FAILED(hr)) && (MAPI_E_USER_CANCEL != hr) && (ulFlags & MAPI_DIALOG))
  7122. {
  7123. int ids;
  7124. UINT flags = MB_OK | MB_ICONEXCLAMATION;
  7125. switch(hr)
  7126. {
  7127. case MAPI_E_UNABLE_TO_COMPLETE:
  7128. case MAPI_E_AMBIGUOUS_RECIP:
  7129. ids = idsLDAPAmbiguousRecip;
  7130. break;
  7131. case MAPI_E_NOT_FOUND:
  7132. ids = idsLDAPSearchNoResults;
  7133. break;
  7134. case MAPI_E_NO_ACCESS:
  7135. ids = idsLDAPAccessDenied;
  7136. break;
  7137. case MAPI_E_TIMEOUT:
  7138. ids = idsLDAPSearchTimedOut;
  7139. break;
  7140. case MAPI_E_NETWORK_ERROR:
  7141. ids = idsLDAPCouldNotFindServer;
  7142. break;
  7143. default:
  7144. ids = idsLDAPErrorOccured;
  7145. break;
  7146. }
  7147. ShowMessageBoxParam(hWnd, ids, flags, ulResult ? gpfnLDAPErr2String(ulResult) : szEmpty);
  7148. }
  7149. else
  7150. {
  7151. if(hr == MAPI_W_PARTIAL_COMPLETION)
  7152. ShowMessageBox( hWnd, idsLDAPPartialResults, MB_OK | MB_ICONINFORMATION);
  7153. }
  7154. return hr;
  7155. }
  7156. //*******************************************************************
  7157. //
  7158. // FUNCTION: bIsSimpleSearch
  7159. //
  7160. // PURPOSE: Checks if this server has Simple Search set on it.
  7161. //
  7162. // PARAMETERS: lpszServer - name of LDAP server whose base string to get.
  7163. //
  7164. // RETURNS: BOOL
  7165. //
  7166. //*******************************************************************
  7167. BOOL bIsSimpleSearch(LPTSTR lpszServer)
  7168. {
  7169. LDAPSERVERPARAMS Params;
  7170. BOOL fRet;
  7171. GetLDAPServerParams((LPTSTR)lpszServer, &Params);
  7172. fRet = Params.fSimpleSearch;
  7173. FreeLDAPServerParams(Params);
  7174. return fRet;
  7175. }
  7176. #ifdef PAGED_RESULT_SUPPORT
  7177. /*
  7178. -
  7179. - dwGetPagedResultSupport
  7180. */
  7181. DWORD dwGetPagedResultSupport(LPTSTR lpszServer)
  7182. {
  7183. LDAPSERVERPARAMS Params;
  7184. DWORD dwRet;
  7185. GetLDAPServerParams((LPTSTR)lpszServer, &Params);
  7186. dwRet = Params.dwPagedResult;
  7187. FreeLDAPServerParams(Params);
  7188. return dwRet;
  7189. }
  7190. /*
  7191. -
  7192. - SetPagedResultSupport
  7193. */
  7194. void SetPagedResultSupport(LPTSTR lpszServer, BOOL bSupportsPagedResults)
  7195. {
  7196. LDAPSERVERPARAMS Params;
  7197. DWORD dwRet;
  7198. if(GetLDAPServerParams(lpszServer, &Params))
  7199. {
  7200. Params.dwPagedResult = bSupportsPagedResults ? LDAP_PRESULT_SUPPORTED : LDAP_PRESULT_NOTSUPPORTED;
  7201. SetLDAPServerParams(lpszServer, &Params);
  7202. }
  7203. FreeLDAPServerParams(Params);
  7204. }
  7205. #endif //#ifdef PAGED_RESULT_SUPPORT
  7206. /*
  7207. -
  7208. - dwGetNTDS - checks if this is an NTDS or not
  7209. */
  7210. DWORD dwGetNTDS(LPTSTR lpszServer)
  7211. {
  7212. LDAPSERVERPARAMS Params;
  7213. DWORD dwRet;
  7214. GetLDAPServerParams((LPTSTR)lpszServer, &Params);
  7215. dwRet = Params.dwIsNTDS;
  7216. FreeLDAPServerParams(Params);
  7217. return dwRet;
  7218. }
  7219. /*
  7220. -
  7221. - SetNTDS
  7222. */
  7223. void SetNTDS(LPTSTR lpszServer, BOOL bIsNTDS)
  7224. {
  7225. LDAPSERVERPARAMS Params;
  7226. DWORD dwRet;
  7227. if(GetLDAPServerParams(lpszServer, &Params))
  7228. {
  7229. Params.dwIsNTDS = bIsNTDS ? LDAP_NTDS_IS : LDAP_NTDS_ISNOT;
  7230. SetLDAPServerParams(lpszServer, &Params);
  7231. }
  7232. FreeLDAPServerParams(Params);
  7233. }
  7234. //*******************************************************************
  7235. //
  7236. // FUNCTION: DoSyncLDAPSearch
  7237. //
  7238. // PURPOSE: Does a synchronous LDAP search (this means no cancel dlg)
  7239. //
  7240. // PARAMETERS: .
  7241. //
  7242. // RETURNS: BOOL
  7243. //
  7244. //*******************************************************************
  7245. BOOL DoSyncLDAPSearch(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7246. {
  7247. BOOL fRet = FALSE;
  7248. DebugTrace(TEXT("Doing Synchronous LDAP Search\n"));
  7249. if(bIsSimpleSearch(pLDAPSearchParams->lpszServer))
  7250. pLDAPSearchParams->ulFlags |= LSP_SimpleSearch;
  7251. pLDAPSearchParams->ulFlags |= LSP_UseSynchronousBind;
  7252. pLDAPSearchParams->ulFlags |= LSP_UseSynchronousSearch;
  7253. // Perform the bind operation.
  7254. Assert(pLDAPSearchParams->lpszServer);
  7255. {
  7256. BOOL fUseSynchronousBind = (pLDAPSearchParams->ulFlags & LSP_UseSynchronousBind);
  7257. pLDAPSearchParams->ulLDAPValue = use_ldap_v3;
  7258. pLDAPSearchParams->ulError = OpenConnection(pLDAPSearchParams->lpszServer,
  7259. pLDAPSearchParams->ppLDAP,
  7260. &pLDAPSearchParams->ulTimeout,
  7261. &pLDAPSearchParams->ulMsgID,
  7262. &fUseSynchronousBind,
  7263. pLDAPSearchParams->ulLDAPValue,
  7264. pLDAPSearchParams->lpszBindDN,
  7265. pLDAPSearchParams->dwAuthType);
  7266. if(fUseSynchronousBind)
  7267. pLDAPSearchParams->ulFlags |= LSP_UseSynchronousBind;
  7268. else
  7269. pLDAPSearchParams->ulFlags &= ~LSP_UseSynchronousBind;
  7270. }
  7271. if (LDAP_SUCCESS != pLDAPSearchParams->ulError)
  7272. goto out;
  7273. // The actions that need to be performed after the bind are done
  7274. // in BindProcessResults, so we call this even though there really are
  7275. // no results to process in the synchronous case.
  7276. if(!BindProcessResults(pLDAPSearchParams, NULL, NULL))
  7277. goto out;
  7278. // Process the results
  7279. if (pLDAPSearchParams->ulFlags & LSP_ResolveMultiple)
  7280. while (ResolveProcessResults(pLDAPSearchParams, NULL));
  7281. else if(LDAP_ERROR == pLDAPSearchParams->ulResult)
  7282. {
  7283. pLDAPSearchParams->ulError = (*pLDAPSearchParams->ppLDAP)->ld_errno;
  7284. goto out;
  7285. }
  7286. fRet = TRUE;
  7287. out:
  7288. return fRet;
  7289. }
  7290. /*
  7291. - CreateLDAPURLFromEntryID
  7292. -
  7293. * Takes an EntryID, checks if it is an LDAP EntryID and creates an LDAP URL from it ..
  7294. * Allocates and returns the URL .. caller responsible for freeing ..
  7295. */
  7296. void CreateLDAPURLFromEntryID(ULONG cbEntryID, LPENTRYID lpEntryID, LPTSTR * lppBuf, BOOL * lpbIsNTDSEntry)
  7297. {
  7298. LPTSTR lpServerName = NULL, lpDN = NULL;
  7299. LPTSTR lpURL = NULL, lpURL1 = NULL;
  7300. DWORD dwURL = 0;
  7301. LDAPSERVERPARAMS Params = {0};
  7302. LPTSTR lpServer = NULL;
  7303. ULONG ulcNumProps = 0;
  7304. if(!lppBuf)
  7305. return;
  7306. if (WAB_LDAP_MAILUSER != IsWABEntryID( cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL) )
  7307. return;
  7308. // Deconstruct the entryid into server name and DN
  7309. IsWABEntryID( cbEntryID, lpEntryID, &lpServerName, &lpDN, NULL, (LPVOID *) &ulcNumProps, NULL);
  7310. if(lpbIsNTDSEntry)
  7311. *lpbIsNTDSEntry = (ulcNumProps & LDAP_NTDS_ENTRY) ? TRUE : FALSE;
  7312. if(lpServerName)
  7313. {
  7314. GetLDAPServerParams(lpServerName, &Params);
  7315. if(!Params.lpszName)
  7316. {
  7317. ULONG cchSize = lstrlen(lpServerName)+1;
  7318. if(Params.lpszName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize))
  7319. StrCpyN(Params.lpszName, lpServerName, cchSize);
  7320. }
  7321. }
  7322. // [PaulHi] 12/9/98 Raid NT5 - #26069
  7323. // The account manager provides the server name "NULL" for ActiveDirectory servers
  7324. // We need to make sure this name doesn't become part of the LDAP URL
  7325. lpServer = Params.lpszName ? Params.lpszName : szEmpty;
  7326. if ( !lstrcmpi(lpServer, szNULLString) )
  7327. lpServer = szEmpty;
  7328. if(!lpDN)
  7329. lpDN = szEmpty;
  7330. // [PaulHi] 3/24/99 InternetCanonicalizeUrlW doesn't take buffer count in bytes
  7331. // as stated in documentation, but in characters. Also doesn't account for NULL
  7332. // terminating character.
  7333. dwURL = 3*(lstrlen(lpServer)+lstrlen(lpDN)+10); //worst case - every character needs to be encoded ...
  7334. lpURL = LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(dwURL+1)); //10 is enuff space for 'ldap://' and terminating NULL
  7335. if(lpURL)
  7336. {
  7337. lpURL1 = LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(dwURL+1)); //10 is enuff space for 'ldap://' and terminating NULL
  7338. if(lpURL1)
  7339. {
  7340. DNtoLDAPURL(lpServer, lpDN, lpURL, dwURL+1);
  7341. DebugTrace(TEXT("==> pre-encoded: %s\n"),lpURL);
  7342. if ( !InternetCanonicalizeUrlW(lpURL, lpURL1, &dwURL, 0) )
  7343. {
  7344. DebugTrace(TEXT("ERROR: CreateLDAPURLFromEntryID, InternetCanonicalizeUrlW failed.\n"));
  7345. Assert(0);
  7346. }
  7347. DebugTrace(TEXT("==>post-encoded: %s\n"),lpURL1);
  7348. FreeLDAPServerParams(Params);
  7349. *lppBuf = lpURL1;
  7350. }
  7351. LocalFree(lpURL);
  7352. }
  7353. }
  7354. /*
  7355. -
  7356. - CheckErrorResults - Check for error results here
  7357. *
  7358. * ulExpectedResult - ldap_result returns the type of the result retrieved but not the
  7359. * the actual error code itself. If the expected Result is the same as the last ulResult,
  7360. * only then do we call ldap_result2error to get the actual error code ..
  7361. */
  7362. ULONG CheckErrorResult(PLDAPSEARCHPARAMS pLDAPSearchParams, ULONG ulExpectedResult)
  7363. {
  7364. ULONG ulResult = 0;
  7365. // Upon successful completion, ldap_result returns the type of the result
  7366. // returned in the res parameter. If it is not the type we expect, treat
  7367. // this as an error.
  7368. if(ulExpectedResult == pLDAPSearchParams->ulResult)
  7369. {
  7370. // If an error occurred in ldap_result, return the error code
  7371. if (LDAP_ERROR == pLDAPSearchParams->ulResult)
  7372. ulResult = (*pLDAPSearchParams->ppLDAP)->ld_errno;
  7373. else if (NULL != *pLDAPSearchParams->lplpResult) // Check the result for errors
  7374. {
  7375. ulResult = gpfnLDAPResult2Error(*pLDAPSearchParams->ppLDAP,*pLDAPSearchParams->lplpResult,FALSE);
  7376. }
  7377. }
  7378. else
  7379. if( (LDAP_RES_BIND == pLDAPSearchParams->ulResult) ||
  7380. (LDAP_RES_SEARCH_RESULT == pLDAPSearchParams->ulResult) ||
  7381. (LDAP_RES_SEARCH_ENTRY == pLDAPSearchParams->ulResult) ||
  7382. (LDAP_RES_MODIFY == pLDAPSearchParams->ulResult) ||
  7383. (LDAP_RES_ADD == pLDAPSearchParams->ulResult) ||
  7384. (LDAP_RES_DELETE == pLDAPSearchParams->ulResult) ||
  7385. (LDAP_RES_MODRDN == pLDAPSearchParams->ulResult) ||
  7386. (LDAP_RES_COMPARE == pLDAPSearchParams->ulResult) ||
  7387. (LDAP_RES_SESSION == pLDAPSearchParams->ulResult) ||
  7388. //(LDAP_RES_REFERRAL == pLDAPSearchParams->ulResult)
  7389. (LDAP_RES_EXTENDED == pLDAPSearchParams->ulResult))
  7390. {
  7391. ulResult = LDAP_LOCAL_ERROR;
  7392. }
  7393. else
  7394. ulResult = pLDAPSearchParams->ulResult;
  7395. DebugTrace(TEXT("CheckErrorResult: 0x%.2x, %s\n"), ulResult, gpfnLDAPErr2String(ulResult));
  7396. return ulResult;
  7397. }
  7398. /*
  7399. - bSearchForOID
  7400. -
  7401. * Performs a sync search on the server looking for a specific OID in a
  7402. * specific attribute ..
  7403. */
  7404. BOOL bSearchForOID(PLDAPSEARCHPARAMS pLDAPSearchParams, LPTSTR lpAttr, LPTSTR szOID)
  7405. {
  7406. LDAPMessage * pMsg = NULL;
  7407. LDAPMessage * pMsgCur = NULL;
  7408. BOOL bFound = FALSE;
  7409. DWORD dwRet = 0;
  7410. int nErr = 0;
  7411. LPTSTR AttrList[] = {lpAttr, NULL};
  7412. DebugTrace(TEXT(">>>Looking for %s in attribute %s\n"), szOID, lpAttr);
  7413. if(LDAP_SUCCESS != (nErr = gpfnLDAPSearchS( *pLDAPSearchParams->ppLDAP,
  7414. NULL,
  7415. LDAP_SCOPE_BASE,
  7416. (LPTSTR) cszAllEntriesFilter,
  7417. AttrList, 0, &pMsg)))
  7418. {
  7419. DebugTrace(TEXT("Synchronous OID determination failed: 0x%.2x, %s\n"), nErr, gpfnLDAPErr2String(nErr));
  7420. goto out;
  7421. }
  7422. pMsgCur = gpfnLDAPFirstEntry(*pLDAPSearchParams->ppLDAP, pMsg);
  7423. if(!pMsg || !pMsgCur)
  7424. goto out;
  7425. while( NULL != pMsgCur )
  7426. {
  7427. BerElement* pBerElement;
  7428. TCHAR* attr = gpfnLDAPFirstAttr(*pLDAPSearchParams->ppLDAP, pMsg, &pBerElement );
  7429. while( attr != NULL )
  7430. {
  7431. if( !lstrcmpi( attr, lpAttr ) )
  7432. {
  7433. TCHAR** pptch = gpfnLDAPGetValues(*pLDAPSearchParams->ppLDAP, pMsgCur, attr );
  7434. int i;
  7435. for(i = 0; NULL != pptch[i]; i++ )
  7436. {
  7437. if( !lstrcmpi( pptch[i], szOID ) )
  7438. {
  7439. DebugTrace(TEXT("Found %s [OID:%s]\n"),pLDAPSearchParams->lpszServer, pptch[i]);
  7440. bFound = TRUE;
  7441. goto out;
  7442. }
  7443. }
  7444. }
  7445. attr = gpfnLDAPNextAttr(*pLDAPSearchParams->ppLDAP, pMsgCur, pBerElement );
  7446. }
  7447. pMsgCur = gpfnLDAPNextEntry(*pLDAPSearchParams->ppLDAP, pMsgCur );
  7448. }
  7449. out:
  7450. if( NULL != pMsg )
  7451. gpfnLDAPMsgFree( pMsg );
  7452. return bFound;
  7453. }
  7454. /*
  7455. - bIsNTDS
  7456. -
  7457. * Checks to see if the server is an NTDS or not - if there is no existing info in the registry,
  7458. * then we do a one-time check and write the results into the registry
  7459. *
  7460. */
  7461. #define LDAP_NTDS_DISCOVERY_OID_STRING TEXT("1.2.840.113556.1.4.800")
  7462. BOOL bCheckIfNTDS(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7463. {
  7464. LDAPMessage * pMsg = NULL;
  7465. LDAPMessage * pMsgCur = NULL;
  7466. BOOL bFound = FALSE;
  7467. DWORD dwRet = 0;
  7468. int nErr = 0;
  7469. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7470. if(pLDAPSearchParams->ulFlags & LSP_IsNTDS)
  7471. return TRUE;
  7472. if(pLDAPSearchParams->ulFlags & LSP_IsNotNTDS)
  7473. return FALSE;
  7474. dwRet = dwGetNTDS(pLDAPSearchParams->lpszServer);
  7475. if(dwRet == LDAP_NTDS_IS)
  7476. {
  7477. pLDAPSearchParams->ulFlags |= LSP_IsNTDS;
  7478. return TRUE;
  7479. }
  7480. else if(dwRet == LDAP_NTDS_ISNOT)
  7481. {
  7482. pLDAPSearchParams->ulFlags |= LSP_IsNotNTDS;
  7483. return FALSE;
  7484. }
  7485. if(SubstringSearch(pLDAPSearchParams->lpszServer, TEXT("mich")))
  7486. {
  7487. LDAPSERVERPARAMS Params = {0};
  7488. BOOL bIsUmich = FALSE;
  7489. GetLDAPServerParams(pLDAPSearchParams->lpszServer, &Params);
  7490. if(Params.lpszName && SubstringSearch(Params.lpszName, TEXT("umich.edu")))
  7491. bIsUmich = TRUE;
  7492. else
  7493. if(SubstringSearch(pLDAPSearchParams->lpszServer, TEXT("umich.edu")))
  7494. bIsUmich = TRUE;
  7495. FreeLDAPServerParams(Params);
  7496. if(bIsUmich)
  7497. goto out; // The search below hangs on umich so just skip it
  7498. }
  7499. bFound = bSearchForOID(pLDAPSearchParams, TEXT("supportedCapabilities"), LDAP_NTDS_DISCOVERY_OID_STRING);
  7500. out:
  7501. pLDAPSearchParams->ulFlags |= (bFound ? LSP_IsNTDS : LSP_IsNotNTDS);
  7502. // Any LDAP search failure will mean we won't look for this ever again
  7503. SetNTDS(pLDAPSearchParams->lpszServer, bFound);
  7504. DebugTrace(TEXT(">>>%s %s a NT Directory Service \n"), pLDAPSearchParams->lpszServer, bFound? TEXT("is"): TEXT("is not"));
  7505. return bFound;
  7506. }
  7507. #ifdef PAGED_RESULT_SUPPORT
  7508. /*
  7509. - bSupportsLDAPPagedResults
  7510. -
  7511. * Checks to see if the server supports LDAP paged results or not ...
  7512. *
  7513. */
  7514. BOOL bSupportsLDAPPagedResults(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7515. {
  7516. LDAPMessage * pMsg = NULL;
  7517. LDAPMessage * pMsgCur = NULL;
  7518. BOOL bFound = FALSE;
  7519. DWORD dwRet = 0;
  7520. int nErr = 0;
  7521. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7522. /*--------------------------------------------------------------
  7523. *
  7524. * NOTE: There seems to be an Exchange server problem that if we send
  7525. * the filter (|(cn=XXX*)(mail=XXX*)) AND the number of matches on the
  7526. * server exceed the number of matches requested per page, the
  7527. * search times out. This doesn't happen for other filters so it's
  7528. * quirky and it's unacceptable.
  7529. *
  7530. * Therefore the paged result feature is being disabled. To re-enable it,
  7531. * comment out the line below
  7532. *---------------------------------------------------------------*/
  7533. return FALSE;
  7534. // don't support paged results for non-Outlook
  7535. //if(!pt_bIsWABOpenExSession)
  7536. // return FALSE;
  7537. if(pLDAPSearchParams->ulFlags & LSP_ResolveMultiple) //dont use paged results for name resolution
  7538. return FALSE;
  7539. if(pLDAPSearchParams->ulFlags & LSP_PagedResults)
  7540. return TRUE;
  7541. if(pLDAPSearchParams->ulFlags & LSP_NoPagedResults)
  7542. return FALSE;
  7543. dwRet = dwGetPagedResultSupport(pLDAPSearchParams->lpszServer);
  7544. if(dwRet == LDAP_PRESULT_SUPPORTED)
  7545. {
  7546. pLDAPSearchParams->ulFlags |= LSP_PagedResults;
  7547. return TRUE;
  7548. }
  7549. else if(dwRet == LDAP_PRESULT_NOTSUPPORTED)
  7550. {
  7551. pLDAPSearchParams->ulFlags |= LSP_NoPagedResults;
  7552. return FALSE;
  7553. }
  7554. if(SubstringSearch(pLDAPSearchParams->lpszServer, TEXT("mich")))
  7555. {
  7556. LDAPSERVERPARAMS Params = {0};
  7557. BOOL bIsUmich = FALSE;
  7558. GetLDAPServerParams(pLDAPSearchParams->lpszServer, &Params);
  7559. if(Params.lpszName && SubstringSearch(Params.lpszName, TEXT("umich.edu")))
  7560. bIsUmich = TRUE;
  7561. else
  7562. if(SubstringSearch(pLDAPSearchParams->lpszServer, TEXT("umich.edu")))
  7563. bIsUmich = TRUE;
  7564. FreeLDAPServerParams(Params);
  7565. if(bIsUmich)
  7566. goto out; // The search below hangs on umich so just skip it
  7567. }
  7568. bFound = bSearchForOID(pLDAPSearchParams, TEXT("supportedControl"), LDAP_PAGED_RESULT_OID_STRING);
  7569. out:
  7570. pLDAPSearchParams->ulFlags |= (bFound ? LSP_PagedResults : LSP_NoPagedResults);
  7571. // persist the fact that the paged-result search succeeded or failed so we don't
  7572. // try to do this every single time
  7573. // Any LDAP search failure will mean we won't look for this ever again
  7574. SetPagedResultSupport(pLDAPSearchParams->lpszServer, bFound);
  7575. DebugTrace(TEXT("<<<Paged Result support = %d\n"), bFound);
  7576. return bFound;
  7577. }
  7578. /*
  7579. - bMorePagedResultsAvailable
  7580. -
  7581. * Checks if more paged results are available
  7582. *
  7583. */
  7584. BOOL bMorePagedResultsAvailable()
  7585. {
  7586. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7587. return (pt_pCookie != NULL);
  7588. }
  7589. /*
  7590. - CachePagedResultParams
  7591. -
  7592. * Temporarily stores the PagedResult Params for
  7593. * future paged results
  7594. *
  7595. */
  7596. void CachePagedResultParams(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7597. {
  7598. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7599. pt_pCookie = (pLDAPSearchParams->pCookie && pLDAPSearchParams->pCookie->bv_len) ?
  7600. pLDAPSearchParams->pCookie : NULL;
  7601. }
  7602. /*
  7603. - ClearCachedPagedResultParams
  7604. -
  7605. */
  7606. void ClearCachedPagedResultParams()
  7607. {
  7608. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7609. pt_pCookie = NULL;
  7610. }
  7611. /*
  7612. - GetPagedResultParams
  7613. -
  7614. *
  7615. */
  7616. void GetPagedResultParams(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7617. {
  7618. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  7619. pLDAPSearchParams->pCookie = pt_pCookie;
  7620. }
  7621. /*
  7622. - InitLDAPPagedSearch
  7623. -
  7624. * Initializes and starts a Paged Result search
  7625. *
  7626. *
  7627. */
  7628. void InitLDAPPagedSearch(BOOL fSynchronous, PLDAPSEARCHPARAMS pLDAPSearchParams, LPTSTR lpFilter)
  7629. {
  7630. PLDAPControlA PagedControl[2];
  7631. LDAPSERVERPARAMS Params = {0};
  7632. LPTSTR szFilterT, szFilter = NULL;
  7633. // initialize search control parameters
  7634. GetLDAPServerParams(pLDAPSearchParams->lpszServer, &Params);
  7635. DebugTrace(TEXT("---Initiating paged result search...\n"));
  7636. GetPagedResultParams(pLDAPSearchParams);
  7637. gpfnLDAPCreatePageControl( *pLDAPSearchParams->ppLDAP,
  7638. Params.dwSearchSizeLimit,
  7639. pLDAPSearchParams->pCookie,
  7640. FALSE,
  7641. &(PagedControl[0]));
  7642. PagedControl[1] = NULL;
  7643. if (lpFilter)
  7644. szFilterT = lpFilter;
  7645. else
  7646. {
  7647. if ((pLDAPSearchParams->ulFlags & LSP_IsNTDS) && pLDAPSearchParams->szNTFilter)
  7648. szFilterT = pLDAPSearchParams->szNTFilter;
  7649. else
  7650. szFilterT = pLDAPSearchParams->szFilter;
  7651. }
  7652. Assert(szFilterT);
  7653. if (pLDAPSearchParams->ulFlags & LSP_IsNTDS)
  7654. {
  7655. // [PaulHi] 4/20/99 Raid 73205 Allow NTDS group searches.
  7656. LPTSTR tszFilterPerson = NULL;
  7657. LPTSTR tszFilterGroup = NULL;
  7658. BOOL bFilterSucceeded = FALSE;
  7659. // Put together person side
  7660. if (BuildOpFilter(&tszFilterPerson, szFilterT, (LPTSTR)cszAllPersonFilter, FILTER_OP_AND) == hrSuccess)
  7661. {
  7662. // Put together group side
  7663. if (BuildOpFilter(&tszFilterGroup, szFilterT, (LPTSTR)cszAllGroupFilter, FILTER_OP_AND) == hrSuccess)
  7664. {
  7665. // Put two together
  7666. bFilterSucceeded = (BuildOpFilter(&szFilter, tszFilterPerson, tszFilterGroup, FILTER_OP_OR) == hrSuccess);
  7667. LocalFreeAndNull(&tszFilterGroup);
  7668. }
  7669. LocalFreeAndNull(&tszFilterPerson);
  7670. }
  7671. if (!bFilterSucceeded)
  7672. goto out;
  7673. }
  7674. else
  7675. szFilter = szFilterT;
  7676. if(fSynchronous)
  7677. {
  7678. struct l_timeval Timeout;
  7679. // Poll the server for results
  7680. ZeroMemory(&Timeout, sizeof(struct l_timeval));
  7681. Timeout.tv_sec = Params.dwSearchTimeLimit;
  7682. Timeout.tv_usec = 0;
  7683. pLDAPSearchParams->ulError = gpfnLDAPSearchExtS( *pLDAPSearchParams->ppLDAP,
  7684. pLDAPSearchParams->szBase,
  7685. pLDAPSearchParams->ulScope,
  7686. szFilter,
  7687. pLDAPSearchParams->ppszAttrs,
  7688. 0,
  7689. PagedControl,
  7690. NULL,
  7691. &Timeout,
  7692. 0, // 0 means no limit
  7693. pLDAPSearchParams->lplpResult);
  7694. }
  7695. else
  7696. {
  7697. pLDAPSearchParams->ulError = gpfnLDAPSearchExt( *pLDAPSearchParams->ppLDAP,
  7698. pLDAPSearchParams->szBase,
  7699. pLDAPSearchParams->ulScope,
  7700. szFilter,
  7701. pLDAPSearchParams->ppszAttrs,
  7702. 0,
  7703. PagedControl,
  7704. NULL,
  7705. Params.dwSearchTimeLimit, //timeout
  7706. 0, // 0 means no limit
  7707. &(pLDAPSearchParams->ulMsgID));
  7708. }
  7709. out:
  7710. gpfnLDAPControlFree(PagedControl[0]);
  7711. FreeLDAPServerParams(Params);
  7712. if (szFilter != szFilterT)
  7713. LocalFreeAndNull(&szFilter);
  7714. }
  7715. /*
  7716. - ProcessLDAPPagedResultCookie
  7717. -
  7718. * Processes the cookie returned from one paged result search
  7719. *
  7720. */
  7721. BOOL ProcessLDAPPagedResultCookie(PLDAPSEARCHPARAMS pLDAPSearchParams)
  7722. {
  7723. BOOL fRet = FALSE;
  7724. PLDAPControl *serverReturnedControls = NULL;
  7725. LDAPMessage* lpEntry;
  7726. ULONG ulCount = 0;
  7727. DWORD dwTotal = 0;
  7728. pLDAPSearchParams->ulError = gpfnLDAPParseResult(*pLDAPSearchParams->ppLDAP,
  7729. *pLDAPSearchParams->lplpResult,
  7730. NULL, NULL, NULL, NULL,
  7731. &serverReturnedControls, FALSE);
  7732. if (LDAP_SUCCESS != pLDAPSearchParams->ulError)
  7733. goto out;
  7734. pLDAPSearchParams->ulError = gpfnLDAPParsePageControl( *pLDAPSearchParams->ppLDAP,
  7735. serverReturnedControls,
  7736. &dwTotal, &(pLDAPSearchParams->pCookie));
  7737. if (LDAP_SUCCESS != pLDAPSearchParams->ulError)
  7738. goto out;
  7739. CachePagedResultParams(pLDAPSearchParams);
  7740. fRet = TRUE;
  7741. out:
  7742. if(serverReturnedControls)
  7743. gpfnLDAPControlsFree(serverReturnedControls);
  7744. return fRet;
  7745. }
  7746. #endif //#ifdef PAGED_RESULT_SUPPORT