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.

4976 lines
164 KiB

  1. /*
  2. * VCard.C - Implement VCard
  3. *
  4. * Wrap VCard in a mailuser object
  5. *
  6. * Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  7. *
  8. */
  9. #include "_apipch.h"
  10. #ifdef VCARD
  11. // This is the current vCard version implemented in this file
  12. //
  13. #define CURRENT_VCARD_VERSION "2.1"
  14. //#define CURRENT_VCARD_VERSION "2.1+" <- The code is really this version, see the URL section in WriteVCard.
  15. typedef enum _VC_STATE_ENUM {
  16. VCS_INITIAL,
  17. VCS_ITEMS,
  18. VCS_FINISHED,
  19. VCS_ERROR,
  20. } VC_STATE_ENUM, *LPVC_STATE_ENUM;
  21. typedef struct _VC_STATE {
  22. VC_STATE_ENUM vce; // state
  23. ULONG ulEmailAddrs; // count of email addresses
  24. BOOL fBusinessURL; // TRUE if we have already got a business URL
  25. BOOL fPersonalURL; // TRUE if we have already got a personal URL
  26. } VC_STATE, *LPVC_STATE;
  27. typedef enum _VCARD_KEY {
  28. VCARD_KEY_NONE = -1, // Always first
  29. VCARD_KEY_BEGIN = 0,
  30. VCARD_KEY_END,
  31. VCARD_KEY_ADR,
  32. VCARD_KEY_ORG,
  33. VCARD_KEY_N,
  34. VCARD_KEY_NICKNAME,
  35. VCARD_KEY_AGENT,
  36. VCARD_KEY_LOGO,
  37. VCARD_KEY_PHOTO,
  38. VCARD_KEY_LABEL,
  39. VCARD_KEY_FADR,
  40. VCARD_KEY_FN,
  41. VCARD_KEY_TITLE,
  42. VCARD_KEY_SOUND,
  43. VCARD_KEY_LANG,
  44. VCARD_KEY_TEL,
  45. VCARD_KEY_EMAIL,
  46. VCARD_KEY_TZ,
  47. VCARD_KEY_GEO,
  48. VCARD_KEY_NOTE,
  49. VCARD_KEY_URL,
  50. VCARD_KEY_BDAY,
  51. VCARD_KEY_ROLE,
  52. VCARD_KEY_REV,
  53. VCARD_KEY_UID,
  54. VCARD_KEY_KEY,
  55. VCARD_KEY_MAILER,
  56. VCARD_KEY_X,
  57. VCARD_KEY_VCARD,
  58. VCARD_KEY_VERSION,
  59. VCARD_KEY_X_WAB_GENDER,
  60. VCARD_KEY_MAX,
  61. } VCARD_KEY, *LPVCARD_KEY;
  62. // MUST be maintained in same order as _VCARD_KEY enum
  63. const LPSTR vckTable[VCARD_KEY_MAX] = {
  64. "BEGIN", // VCARD_KEY_BEGIN
  65. "END", // VCARD_KEY_END
  66. "ADR", // VCARD_KEY_ADR
  67. "ORG", // VCARD_KEY_ORG
  68. "N", // VCARD_KEY_N
  69. "NICKNAME", // VCARD_KEY_NICKNAME
  70. "AGENT", // VCARD_KEY_AGENT
  71. "LOGO", // VCARD_KEY_LOGO
  72. "PHOTO", // VCARD_KEY_PHOTO
  73. "LABEL", // VCARD_KEY_LABEL
  74. "FADR", // VCARD_KEY_FADR
  75. "FN", // VCARD_KEY_FN
  76. "TITLE", // VCARD_KEY_TITLE
  77. "SOUND", // VCARD_KEY_SOUND
  78. "LANG", // VCARD_KEY_LANG
  79. "TEL", // VCARD_KEY_TEL
  80. "EMAIL", // VCARD_KEY_EMAIL
  81. "TZ", // VCARD_KEY_TZ
  82. "GEO", // VCARD_KEY_GEO
  83. "NOTE", // VCARD_KEY_NOTE
  84. "URL", // VCARD_KEY_URL
  85. "BDAY", // VCARD_KEY_BDAY
  86. "ROLE", // VCARD_KEY_ROLE
  87. "REV", // VCARD_KEY_REV
  88. "UID", // VCARD_KEY_UID
  89. "KEY", // VCARD_KEY_KEY
  90. "MAILER", // VCARD_KEY_MAILER
  91. "X-", // VCARD_KEY_X
  92. "VCARD", // VCARD_KEY_VCARD
  93. "VERSION", // VCARD_KEY_VERSION
  94. "X-WAB-GENDER", // VCARD_KEY_X_WAB_GENDER
  95. };
  96. typedef enum _VCARD_TYPE {
  97. VCARD_TYPE_NONE = -1, // always first
  98. VCARD_TYPE_DOM = 0,
  99. VCARD_TYPE_INTL,
  100. VCARD_TYPE_POSTAL,
  101. VCARD_TYPE_PARCEL,
  102. VCARD_TYPE_HOME,
  103. VCARD_TYPE_WORK,
  104. VCARD_TYPE_PREF,
  105. VCARD_TYPE_VOICE,
  106. VCARD_TYPE_FAX,
  107. VCARD_TYPE_MSG,
  108. VCARD_TYPE_CELL,
  109. VCARD_TYPE_PAGER,
  110. VCARD_TYPE_BBS,
  111. VCARD_TYPE_MODEM,
  112. VCARD_TYPE_CAR,
  113. VCARD_TYPE_ISDN,
  114. VCARD_TYPE_VIDEO,
  115. VCARD_TYPE_AOL,
  116. VCARD_TYPE_APPLELINK,
  117. VCARD_TYPE_ATTMAIL,
  118. VCARD_TYPE_CIS,
  119. VCARD_TYPE_EWORLD,
  120. VCARD_TYPE_INTERNET,
  121. VCARD_TYPE_IBMMAIL,
  122. VCARD_TYPE_MSN,
  123. VCARD_TYPE_MCIMAIL,
  124. VCARD_TYPE_POWERSHARE,
  125. VCARD_TYPE_PRODIGY,
  126. VCARD_TYPE_TLX,
  127. VCARD_TYPE_X400,
  128. VCARD_TYPE_GIF,
  129. VCARD_TYPE_CGM,
  130. VCARD_TYPE_WMF,
  131. VCARD_TYPE_BMP,
  132. VCARD_TYPE_MET,
  133. VCARD_TYPE_PMB,
  134. VCARD_TYPE_DIB,
  135. VCARD_TYPE_PICT,
  136. VCARD_TYPE_TIFF,
  137. VCARD_TYPE_ACROBAT,
  138. VCARD_TYPE_PS,
  139. VCARD_TYPE_JPEG,
  140. VCARD_TYPE_QTIME,
  141. VCARD_TYPE_MPEG,
  142. VCARD_TYPE_MPEG2,
  143. VCARD_TYPE_AVI,
  144. VCARD_TYPE_WAVE,
  145. VCARD_TYPE_AIFF,
  146. VCARD_TYPE_PCM,
  147. VCARD_TYPE_X509,
  148. VCARD_TYPE_PGP,
  149. VCARD_TYPE_MAX
  150. } VCARD_TYPE, *LPVCARD_TYPE;
  151. // MUST be maintained in same order as _VCARD_TYPE enum
  152. const LPSTR vctTable[VCARD_TYPE_MAX] = {
  153. "DOM", // VCARD_TYPE_DOM
  154. "INTL", // VCARD_TYPE_INTL
  155. "POSTAL", // VCARD_TYPE_POSTAL
  156. "PARCEL", // VCARD_TYPE_PARCEL
  157. "HOME", // VCARD_TYPE_HOME
  158. "WORK", // VCARD_TYPE_WORK
  159. "PREF", // VCARD_TYPE_PREF
  160. "VOICE", // VCARD_TYPE_VOICE
  161. "FAX", // VCARD_TYPE_FAX
  162. "MSG", // VCARD_TYPE_MSG
  163. "CELL", // VCARD_TYPE_CELL
  164. "PAGER", // VCARD_TYPE_PAGER
  165. "BBS", // VCARD_TYPE_BBS
  166. "MODEM", // VCARD_TYPE_MODEM
  167. "CAR", // VCARD_TYPE_CAR
  168. "ISDN", // VCARD_TYPE_ISDN
  169. "VIDEO", // VCARD_TYPE_VIDEO
  170. "AOL", // VCARD_TYPE_AOL
  171. "APPLELINK", // VCARD_TYPE_APPLELINK
  172. "ATTMAIL", // VCARD_TYPE_ATTMAIL
  173. "CIS", // VCARD_TYPE_CIS
  174. "EWORLD", // VCARD_TYPE_EWORLD
  175. "INTERNET", // VCARD_TYPE_INTERNET
  176. "IBMMAIL", // VCARD_TYPE_IBMMAIL
  177. "MSN", // VCARD_TYPE_MSN
  178. "MCIMAIL", // VCARD_TYPE_MCIMAIL
  179. "POWERSHARE", // VCARD_TYPE_POWERSHARE
  180. "PRODIGY", // VCARD_TYPE_PRODIGY
  181. "TLX", // VCARD_TYPE_TLX
  182. "X400", // VCARD_TYPE_X400
  183. "GIF", // VCARD_TYPE_GIF
  184. "CGM", // VCARD_TYPE_CGM
  185. "WMF", // VCARD_TYPE_WMF
  186. "BMP", // VCARD_TYPE_BMP
  187. "MET", // VCARD_TYPE_MET
  188. "PMB", // VCARD_TYPE_PMB
  189. "DIB", // VCARD_TYPE_DIB
  190. "PICT", // VCARD_TYPE_PICT
  191. "TIFF", // VCARD_TYPE_TIFF
  192. "ACROBAT", // VCARD_TYPE_ACROBAT
  193. "PS", // VCARD_TYPE_PS
  194. "JPEG", // VCARD_TYPE_JPEG
  195. "QTIME", // VCARD_TYPE_QTIME
  196. "MPEG", // VCARD_TYPE_MPEG
  197. "MPEG2", // VCARD_TYPE_MPEG2
  198. "AVI", // VCARD_TYPE_AVI
  199. "WAVE", // VCARD_TYPE_WAVE
  200. "AIFF", // VCARD_TYPE_AIFF
  201. "PCM", // VCARD_TYPE_PCM
  202. "X509", // VCARD_TYPE_X509
  203. "PGP", // VCARD_TYPE_PGP
  204. };
  205. typedef enum _VCARD_PARAM{
  206. VCARD_PARAM_NONE = -1, // always first
  207. VCARD_PARAM_TYPE = 0,
  208. VCARD_PARAM_ENCODING,
  209. VCARD_PARAM_LANGUAGE,
  210. VCARD_PARAM_VALUE,
  211. VCARD_PARAM_CHARSET,
  212. VCARD_PARAM_MAX,
  213. } VCARD_PARAM, *LPVCARD_PARAM;
  214. // MUST be maintained in same order as _VCARD_PARAM enum
  215. const LPSTR vcpTable[VCARD_PARAM_MAX] = {
  216. "TYPE", // VCARD_PARAM_TYPE
  217. "ENCODING", // VCARD_PARAM_ENCODING
  218. "LANGUAGE", // VCARD_PARAM_LANGUAGE
  219. "VALUE", // VCARD_PARAM_VALUE
  220. "CHARSET", // VCARD_PARAM_CHARSET
  221. };
  222. typedef enum _VCARD_ENCODING{
  223. VCARD_ENCODING_NONE = -1, // always first
  224. VCARD_ENCODING_QUOTED_PRINTABLE = 0,
  225. VCARD_ENCODING_BASE64,
  226. VCARD_ENCODING_7BIT,
  227. VCARD_ENCODING_8BIT,
  228. VCARD_ENCODING_X,
  229. VCARD_ENCODING_MAX,
  230. } VCARD_ENCODING, *LPVCARD_ENCODING;
  231. // MUST be maintained in same order as _VCARD_ENCODING enum
  232. const LPSTR vceTable[VCARD_ENCODING_MAX] = {
  233. "QUOTED-PRINTABLE", // VCARD_ENCODING_QUOTED_PRINTABLE
  234. "BASE64", // VCARD_ENCODING_BASE64
  235. "7BIT", // VCARD_ENCODING_7BIT
  236. "8BIT", // VCARD_ENCODING_8BIT
  237. "X-", // VCARD_ENCODING_X
  238. };
  239. const LPTSTR szColon = TEXT(":");
  240. const LPSTR szColonA = ":";
  241. const LPTSTR szSemicolon = TEXT(";");
  242. const LPSTR szEquals = "=";
  243. const LPSTR szCRLFA = "\r\n";
  244. const LPTSTR szCRLF = TEXT("\r\n");
  245. const LPTSTR szCommaSpace = TEXT(", ");
  246. const LPTSTR szSpace = TEXT(" ");
  247. const LPTSTR szX400 = TEXT("X400");
  248. const LPSTR szSMTPA = "SMTP";
  249. typedef struct _VCARD_PARAM_FLAGS {
  250. int fTYPE_DOM:1;
  251. int fTYPE_INTL:1;
  252. int fTYPE_POSTAL:1;
  253. int fTYPE_PARCEL:1;
  254. int fTYPE_HOME:1;
  255. int fTYPE_WORK:1;
  256. int fTYPE_PREF:1;
  257. int fTYPE_VOICE:1;
  258. int fTYPE_FAX:1;
  259. int fTYPE_MSG:1;
  260. int fTYPE_CELL:1;
  261. int fTYPE_PAGER:1;
  262. int fTYPE_BBS:1;
  263. int fTYPE_MODEM:1;
  264. int fTYPE_CAR:1;
  265. int fTYPE_ISDN:1;
  266. int fTYPE_VIDEO:1;
  267. int fTYPE_AOL:1;
  268. int fTYPE_APPLELINK:1;
  269. int fTYPE_ATTMAIL:1;
  270. int fTYPE_CIS:1;
  271. int fTYPE_EWORLD:1;
  272. int fTYPE_INTERNET:1;
  273. int fTYPE_IBMMAIL:1;
  274. int fTYPE_MSN:1;
  275. int fTYPE_MCIMAIL:1;
  276. int fTYPE_POWERSHARE:1;
  277. int fTYPE_PRODIGY:1;
  278. int fTYPE_TLX:1;
  279. int fTYPE_X400:1;
  280. int fTYPE_GIF:1;
  281. int fTYPE_CGM:1;
  282. int fTYPE_WMF:1;
  283. int fTYPE_BMP:1;
  284. int fTYPE_MET:1;
  285. int fTYPE_PMB:1;
  286. int fTYPE_DIB:1;
  287. int fTYPE_PICT:1;
  288. int fTYPE_TIFF:1;
  289. int fTYPE_ACROBAT:1;
  290. int fTYPE_PS:1;
  291. int fTYPE_JPEG:1;
  292. int fTYPE_QTIME:1;
  293. int fTYPE_MPEG:1;
  294. int fTYPE_MPEG2:1;
  295. int fTYPE_AVI:1;
  296. int fTYPE_WAVE:1;
  297. int fTYPE_AIFF:1;
  298. int fTYPE_PCM:1;
  299. int fTYPE_X509:1;
  300. int fTYPE_PGP:1;
  301. int fPARAM_TYPE:1;
  302. int fPARAM_ENCODING:1;
  303. int fPARAM_LANGUAGE:1;
  304. int fPARAM_VALUE:1;
  305. int fPARAM_CHARSET:1;
  306. int fENCODING_QUOTED_PRINTABLE:1;
  307. int fENCODING_BASE64:1;
  308. int fENCODING_7BIT:1;
  309. int fENCODING_X:1;
  310. LPSTR szPARAM_LANGUAGE;
  311. LPSTR szPARAM_CHARSET;
  312. } VCARD_PARAM_FLAGS, *LPVCARD_PARAM_FLAGS;
  313. //
  314. // For WAB clients that use named props and want to get/put their unique data
  315. // in the vCards as extended vCard properties, we will store these extended
  316. // props in a linked list and use it when importing/exporting a vCard
  317. //
  318. typedef struct _ExtVCardProp
  319. {
  320. ULONG ulExtPropTag;
  321. LPSTR lpszExtPropName;
  322. struct _ExtVCardProp * lpNext;
  323. } EXTVCARDPROP, * LPEXTVCARDPROP;
  324. CONST CHAR six2base64[64] = {
  325. 'A','B','C','D','E','F','G','H','I','J','K','L','M',
  326. 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  327. 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  328. 'n','o','p','q','r','s','t','u','v','w','x','y','z',
  329. '0','1','2','3','4','5','6','7','8','9','+','/'
  330. };
  331. CONST INT base642six[256]={
  332. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  333. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  334. 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  335. 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  336. 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  337. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  338. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  339. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  340. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  341. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  342. 64,64,64,64,64,64,64,64,64,64,64,64,64
  343. };
  344. HRESULT ReadLn(HANDLE hVCard, VCARD_READ ReadFn, LPSTR * lppLine, LPULONG lpcbItem,
  345. LPSTR * lppBuffer, LPULONG lpcbBuffer);
  346. HRESULT InterpretVCardItem (LPSTR lpName, LPSTR lpOption, LPSTR lpData,
  347. LPMAILUSER lpMailUser, LPEXTVCARDPROP lpList, LPVC_STATE lpvcs);
  348. void ParseVCardItem(LPSTR lpBuffer, LPSTR * lppName, LPSTR * lppOption, LPSTR * lppData);
  349. HRESULT ParseVCardType(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf);
  350. HRESULT ParseVCardParams(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf);
  351. VCARD_KEY RecognizeVCardKeyWord(LPSTR lpName);
  352. HRESULT ParseVCardEncoding(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf);
  353. HRESULT ReadVCardItem(HANDLE hVCard, VCARD_READ ReadFn, LPSTR * lppBuffer, LPULONG lpcbBuffer);
  354. HRESULT FileWriteFn(HANDLE handle, LPVOID lpBuffer, ULONG uBytes, LPULONG lpcbWritten);
  355. HRESULT ParseCert( LPSTR lpData, ULONG cbData, LPMAILUSER lpMailUser );
  356. HRESULT DecodeBase64(LPSTR bufcoded,LPSTR pbuffdecoded, PDWORD pcbDecoded);
  357. HRESULT WriteVCardValue(HANDLE hVCard, VCARD_WRITE WriteFn, LPBYTE lpData, ULONG cbData);
  358. /***************************************************************************
  359. Name : FreeExtVCardPropList
  360. Purpose : Frees the localalloced list of extended props that we
  361. get/set on a vCard
  362. Parameters: lpList -> list to free up
  363. Returns : void
  364. Comment :
  365. ***************************************************************************/
  366. void FreeExtVCardPropList(LPEXTVCARDPROP lpList)
  367. {
  368. LPEXTVCARDPROP lpTmp = lpList;
  369. while(lpTmp)
  370. {
  371. lpList = lpList->lpNext;
  372. LocalFreeAndNull(&lpTmp->lpszExtPropName);
  373. LocalFree(lpTmp);
  374. lpTmp = lpList;
  375. }
  376. }
  377. /***************************************************************************
  378. Name : HrGetExtVCardPropList
  379. Purpose : Reads the registry for registered named props for VCard
  380. import/export and gets the named prop names and guids
  381. and extended prop strings and turns them into proper tags
  382. and stores these tags and strings in a linked list
  383. Parameters: lppList -> list to return
  384. Returns : HRESULT
  385. Comment :
  386. ***************************************************************************/
  387. static const TCHAR szNamedVCardPropsRegKey[] = TEXT("Software\\Microsoft\\WAB\\WAB4\\NamedVCardProps");
  388. HRESULT HrGetExtVCardPropList(LPMAILUSER lpMailUser, LPEXTVCARDPROP * lppList)
  389. {
  390. HRESULT hr = E_FAIL;
  391. HKEY hKey = NULL;
  392. LPEXTVCARDPROP lpList = NULL;
  393. DWORD dwIndex = 0, dwSize = 0;
  394. TCHAR szGuidName[MAX_PATH];
  395. if(!lppList)
  396. goto out;
  397. *lppList = NULL;
  398. //
  399. // We will look in the registry under HKLM\Software\Microsoft\WAB\WAB4\NamedVCardProps
  400. // If this key exists, we enumerate all sub keys under it
  401. // The format for this key is
  402. //
  403. // HKLM\Software\Microsoft\WAB\WAB4\NamedVCardProps
  404. // Guid1
  405. // PropString1:PropName1
  406. // PropString1:PropName2
  407. // Guid2
  408. // PropString1:PropName1
  409. // etc
  410. //
  411. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  412. szNamedVCardPropsRegKey,
  413. 0, KEY_READ,
  414. &hKey))
  415. {
  416. goto out;
  417. }
  418. *szGuidName = '\0';
  419. dwSize = CharSizeOf(szGuidName);
  420. // Found the key, now enumerate all sub keys ...
  421. while(ERROR_SUCCESS == RegEnumKeyEx(hKey, dwIndex, szGuidName, &dwSize, NULL, NULL, NULL, NULL))
  422. {
  423. GUID guidTmp = {0};
  424. unsigned short szW[MAX_PATH];
  425. StrCpyN(szW, szGuidName, ARRAYSIZE(szW));
  426. if( !(HR_FAILED(hr = CLSIDFromString(szW, &guidTmp))) )
  427. {
  428. HKEY hGuidKey = NULL;
  429. // Open the GUID key
  430. if(ERROR_SUCCESS == RegOpenKeyEx(hKey, szGuidName, 0, KEY_READ, &hGuidKey))
  431. {
  432. TCHAR szValName[MAX_PATH];
  433. DWORD dwValIndex = 0, dwValSize = CharSizeOf(szValName);
  434. DWORD dwType = 0, dwTagName = 0, dwTagSize = sizeof(DWORD);
  435. TCHAR szTagName[MAX_PATH];
  436. *szValName = '\0';
  437. while(ERROR_SUCCESS == RegEnumValue(hGuidKey, dwValIndex,
  438. szValName, &dwValSize,
  439. 0, &dwType,
  440. NULL, NULL))
  441. {
  442. MAPINAMEID mnid = {0};
  443. LPMAPINAMEID lpmnid = NULL;
  444. LPSPropTagArray lpspta = NULL;
  445. *szTagName = '\0';
  446. // Check if this is a NAME or an ID
  447. if(dwType == REG_DWORD)
  448. {
  449. dwTagSize = sizeof(DWORD);
  450. //Read in the Value
  451. if(ERROR_SUCCESS != RegQueryValueEx(hGuidKey, szValName,
  452. 0, &dwType,
  453. (LPBYTE) &dwTagName, &dwTagSize))
  454. {
  455. continue;
  456. }
  457. }
  458. else if(dwType == REG_SZ)
  459. {
  460. dwTagSize = CharSizeOf(szTagName);
  461. //Read in the Value
  462. if(ERROR_SUCCESS != RegQueryValueEx(hGuidKey, szValName,
  463. 0, &dwType,
  464. (LPBYTE) szTagName, &dwTagSize))
  465. {
  466. continue;
  467. }
  468. }
  469. //
  470. // At this point I have the GUID, the name of the named prop, and the
  471. // ExtendedPropString for this prop ..
  472. //
  473. // First get the actual named proptag from this GUID
  474. //
  475. mnid.lpguid = &guidTmp;
  476. if(lstrlen(szTagName))
  477. {
  478. mnid.ulKind = MNID_STRING;
  479. mnid.Kind.lpwstrName = (LPWSTR) szTagName;
  480. }
  481. else
  482. {
  483. mnid.ulKind = MNID_ID;
  484. mnid.Kind.lID = dwTagName;
  485. }
  486. lpmnid = &mnid;
  487. if(!HR_FAILED(lpMailUser->lpVtbl->GetIDsFromNames( lpMailUser,
  488. 1, &lpmnid,
  489. MAPI_CREATE, // Dont create if it dont exist
  490. &lpspta)))
  491. {
  492. // Got the tag
  493. if(lpspta->aulPropTag[0] && lpspta->cValues)
  494. {
  495. LPEXTVCARDPROP lpTmp = LocalAlloc(LMEM_ZEROINIT, sizeof(EXTVCARDPROP));
  496. if(lpTmp)
  497. {
  498. lpTmp->lpszExtPropName = ConvertWtoA(szValName);
  499. if(lpTmp->lpszExtPropName)
  500. {
  501. lpTmp->ulExtPropTag = CHANGE_PROP_TYPE(lpspta->aulPropTag[0],PT_STRING8);
  502. lpTmp->lpNext = lpList;
  503. lpList = lpTmp;
  504. }
  505. else
  506. LocalFree(lpTmp);
  507. }
  508. }
  509. if(lpspta)
  510. MAPIFreeBuffer(lpspta);
  511. }
  512. dwValIndex++;
  513. *szValName = '\0';
  514. dwValSize = CharSizeOf(szValName);
  515. }
  516. }
  517. if(hGuidKey)
  518. RegCloseKey(hGuidKey);
  519. }
  520. dwIndex++;
  521. *szGuidName = '\0';
  522. dwSize = CharSizeOf(szGuidName);
  523. }
  524. *lppList = lpList;
  525. hr = S_OK;
  526. out:
  527. if(hKey)
  528. RegCloseKey(hKey);
  529. if(HR_FAILED(hr) && lpList)
  530. FreeExtVCardPropList(lpList);
  531. return hr;
  532. }
  533. const static int c_cchMaxWin9XBuffer = 1000;
  534. /***************************************************************************
  535. Name : ReadVCard
  536. Purpose : Reads a vCard from a file to a MAILUSER object.
  537. Parameters: hVCard = open handle to VCard object
  538. ReadFn = Read function to read hVCard, looks like ReadFile().
  539. lpMailUser -> open mailuser object
  540. Returns : HRESULT
  541. Comment :
  542. ***************************************************************************/
  543. HRESULT ReadVCard(HANDLE hVCard, VCARD_READ ReadFn, LPMAILUSER lpMailUser) {
  544. HRESULT hResult = hrSuccess;
  545. LPSTR lpBuffer = NULL;
  546. LPSTR lpName, lpOption, lpData;
  547. ULONG cbBuffer;
  548. VC_STATE vcs;
  549. LPEXTVCARDPROP lpList = NULL;
  550. vcs.vce = VCS_INITIAL;
  551. vcs.ulEmailAddrs = 0;
  552. vcs.fBusinessURL = FALSE;
  553. vcs.fPersonalURL = FALSE;
  554. //
  555. // See if there are any named props we need to handle on import
  556. //
  557. HrGetExtVCardPropList(lpMailUser, &lpList);
  558. while ( !HR_FAILED(hResult) &&
  559. !(HR_FAILED(hResult = ReadVCardItem(hVCard, ReadFn, &lpBuffer, &cbBuffer))) &&
  560. lpBuffer &&
  561. (vcs.vce != VCS_FINISHED))
  562. {
  563. ParseVCardItem(lpBuffer, &lpName, &lpOption, &lpData);
  564. // [PaulHi] 5/13/99 Win9X cannot handle strings larger than 1023 characters
  565. // in length (FormatMessage() is one example). And can cause buffer overruns
  566. // and crashes. If we get VCard data greater than this then we must not add
  567. // it to the lpMailUser object, or risk crashing Win9X when trying to display.
  568. // Instead just truncate so user can salvage as much as possible.
  569. //
  570. // YSt 6/25/99 if vCard has certificate then buffer may be more than 1000 bytes, we need to exlude this case
  571. // from this checkin.
  572. // I suppose that certificate has VCARD_KEY_KEY tag
  573. if (!g_bRunningOnNT && (lpName && lstrcmpiA(lpName, vckTable[VCARD_KEY_KEY])) && lpData && (lstrlenA(lpData) > c_cchMaxWin9XBuffer) )
  574. lpData[c_cchMaxWin9XBuffer] = '\0';
  575. if (lpName && lpData)
  576. {
  577. if (hResult = InterpretVCardItem(lpName, lpOption, lpData, lpMailUser, lpList, &vcs))
  578. {
  579. DebugTrace( TEXT("ReadVCard:InterpretVCardItem -> %x"), GetScode(hResult));
  580. }
  581. }
  582. LocalFreeAndNull(&lpBuffer);
  583. }
  584. if (! HR_FAILED(hResult)) {
  585. hResult = hrSuccess;
  586. }
  587. if(lpList)
  588. FreeExtVCardPropList(lpList);
  589. return(hResult);
  590. }
  591. /***************************************************************************
  592. Name : BufferReadFn
  593. Purpose : Read from the supplied buffer
  594. Parameters: handle = pointer to SBinary in which the
  595. lpb contains the source buffer and the
  596. cb param contains how much of the buffer has
  597. been parsed
  598. lpBuffer -> buffer to read to
  599. uBytes = size of lpBuffer
  600. lpcbRead -> returned bytes read
  601. Returns : HRESULT
  602. ***************************************************************************/
  603. HRESULT BufferReadFn(HANDLE handle, LPVOID lpBuffer, ULONG uBytes, LPULONG lpcbRead) {
  604. LPSBinary lpsb = (LPSBinary) handle;
  605. LPSTR lpBuf = (LPSTR) lpsb->lpb;
  606. LPSTR lpSrc = lpBuf + lpsb->cb;
  607. *lpcbRead = 0;
  608. if(!lstrlenA(lpSrc))
  609. return(ResultFromScode(WAB_W_END_OF_DATA));
  610. if(uBytes > (ULONG) lstrlenA(lpSrc))
  611. uBytes = lstrlenA(lpSrc);
  612. CopyMemory(lpBuffer, lpSrc, uBytes);
  613. lpsb->cb += uBytes;
  614. *lpcbRead = uBytes;
  615. return(hrSuccess);
  616. }
  617. /***************************************************************************
  618. Name : FileReadFn
  619. Purpose : Read from the file handle
  620. Parameters: handle = open file handle
  621. lpBuffer -> buffer to read to
  622. uBytes = size of lpBuffer
  623. lpcbRead -> returned bytes read
  624. Returns : HRESULT
  625. Comment : ReadFile callback for ReadVCard
  626. ***************************************************************************/
  627. HRESULT FileReadFn(HANDLE handle, LPVOID lpBuffer, ULONG uBytes, LPULONG lpcbRead) {
  628. *lpcbRead = 0;
  629. if (! ReadFile(handle,
  630. lpBuffer,
  631. uBytes,
  632. lpcbRead,
  633. NULL)) {
  634. DebugTrace( TEXT("FileReadFn:ReadFile -> %u\n"), GetLastError());
  635. return(ResultFromScode(MAPI_E_DISK_ERROR));
  636. }
  637. if (*lpcbRead == 0) {
  638. return(ResultFromScode(WAB_W_END_OF_DATA));
  639. }
  640. return(hrSuccess);
  641. }
  642. /***************************************************************************
  643. Name : TrimLeadingWhitespace
  644. Purpose : Move the pointer past any whitespace.
  645. Parameters: lpBuffer -> string (null terminated)
  646. Returns : pointer to next non-whitespace or NULL if end of line
  647. Comment :
  648. ***************************************************************************/
  649. LPBYTE TrimLeadingWhitespace(LPBYTE lpBuffer) {
  650. while (*lpBuffer) {
  651. switch (*lpBuffer) {
  652. case ' ':
  653. case '\t':
  654. lpBuffer++;
  655. break;
  656. default:
  657. return(lpBuffer);
  658. }
  659. }
  660. return(NULL);
  661. }
  662. /***************************************************************************
  663. Name : TrimTrailingWhiteSpace
  664. Purpose : Trims off the trailing white space
  665. Parameters: lpString = string to trim
  666. Returns : none
  667. Comment : Starts at the end of the string, moving the EOS marker back
  668. until a non-whitespace character is found. Space and Tab
  669. are the only whitespace characters recognized.
  670. ***************************************************************************/
  671. void TrimTrailingWhiteSpace(LPSTR lpString)
  672. {
  673. register LPSTR lpEnd;
  674. lpEnd = lpString + (lstrlenA(lpString) - 1);
  675. while ((lpEnd >= lpString) && ((*lpEnd == ' ') || (*lpEnd == '\t'))) {
  676. *(lpEnd--) = '\0';
  677. }
  678. }
  679. /***************************************************************************
  680. Name : ParseWord
  681. Purpose : Move the pointer to the next word and null the end of the
  682. current word. (null terminated)
  683. Parameters: lpBuffer -> current word
  684. ch = delimiter character
  685. Returns : pointer to next word or NULL if end of line
  686. Comment :
  687. ***************************************************************************/
  688. LPSTR ParseWord(LPSTR lpString, TCHAR ch) {
  689. while (*lpString) {
  690. if (*lpString == ch) {
  691. *lpString++ = '\0';
  692. lpString = (LPSTR)TrimLeadingWhitespace((LPBYTE)lpString);
  693. if (lpString && *lpString) {
  694. return(lpString);
  695. } else {
  696. return(NULL);
  697. }
  698. }
  699. lpString++;
  700. }
  701. // Didn't find another word.
  702. return(NULL);
  703. }
  704. /***************************************************************************
  705. Name : RecognizeVCardKeyWord
  706. Purpose : Recognize the vCard keyword (null terminated)
  707. Parameters: lpName -> start of key name
  708. Returns : VCARD_KEY value
  709. Comment :
  710. ***************************************************************************/
  711. VCARD_KEY RecognizeVCardKeyWord(LPSTR lpName) {
  712. register ULONG i;
  713. // Look for recognized words
  714. for (i = 0; i < VCARD_KEY_MAX; i++) {
  715. if (! lstrcmpiA(vckTable[i], lpName)) {
  716. // Found it
  717. return(i);
  718. }
  719. }
  720. return(VCARD_KEY_NONE); // didn't recognize
  721. }
  722. /***************************************************************************
  723. Name : RecognizeVCardType
  724. Purpose : Recognize the vCard type option (null terminated)
  725. Parameters: lpName -> start of type name
  726. Returns : VCARD_OPTION value
  727. Comment :
  728. ***************************************************************************/
  729. VCARD_TYPE RecognizeVCardType(LPSTR lpName) {
  730. register ULONG i;
  731. // Look for recognized words
  732. for (i = 0; i < VCARD_TYPE_MAX; i++) {
  733. if (! lstrcmpiA(vctTable[i], lpName)) {
  734. // Found it
  735. return(i);
  736. }
  737. }
  738. return(VCARD_TYPE_NONE); // didn't recognize
  739. }
  740. /***************************************************************************
  741. Name : RecognizeVCardParam
  742. Purpose : Recognize the vCard param (null terminated)
  743. Parameters: lpName -> start of param name
  744. Returns : VCARD_PARAM value
  745. Comment :
  746. ***************************************************************************/
  747. VCARD_PARAM RecognizeVCardParam(LPSTR lpName) {
  748. register ULONG i;
  749. // Look for recognized words
  750. for (i = 0; i < VCARD_PARAM_MAX; i++) {
  751. if (! lstrcmpiA(vcpTable[i], lpName)) {
  752. // Found it
  753. return(i);
  754. }
  755. }
  756. return(VCARD_PARAM_NONE);
  757. }
  758. /***************************************************************************
  759. Name : RecognizeVCardEncoding
  760. Purpose : Recognize the vCard encoding (null terminated)
  761. Parameters: lpName -> start of encoding name
  762. Returns : VCARD_ENCODING value
  763. Comment :
  764. ***************************************************************************/
  765. VCARD_ENCODING RecognizeVCardEncoding(LPSTR lpName) {
  766. register ULONG i;
  767. // Look for recognized words
  768. for (i = 0; i < VCARD_ENCODING_MAX; i++) {
  769. if (! lstrcmpiA(vceTable[i], lpName)) {
  770. // Found it
  771. return(i);
  772. }
  773. }
  774. return(VCARD_ENCODING_NONE); // didn't recognize
  775. }
  776. /***************************************************************************
  777. Name : ParseVCardItem
  778. Purpose : Parse the vCard item into components
  779. Parameters: lpBuffer = current input line (null terminated)
  780. lppName -> returned property name pointer
  781. lppOption -> returned options string pointer
  782. lppData -> returned data string pointer
  783. Returns : none
  784. Comment : Expects the keyword to be in the current line (lpBuffer), but
  785. may read more lines as necesary to get a complete item.
  786. ***************************************************************************/
  787. void ParseVCardItem(LPSTR lpBuffer, LPSTR * lppName, LPSTR * lppOption, LPSTR * lppData) {
  788. TCHAR ch;
  789. BOOL fColon = FALSE;
  790. BOOL fSemicolon = FALSE;
  791. *lppName = *lppOption = *lppData = NULL;
  792. // Find the Name
  793. if (lpBuffer = (LPSTR)TrimLeadingWhitespace((LPBYTE)lpBuffer)) {
  794. *lppName = lpBuffer;
  795. while (ch = *lpBuffer) {
  796. switch (ch) {
  797. case ':': // found end of name/options
  798. fColon = TRUE;
  799. // data follows whitespace
  800. *lppData = (LPSTR)TrimLeadingWhitespace((LPBYTE)lpBuffer + 1);
  801. *lpBuffer = '\0'; // null out colon
  802. goto exit;
  803. case ';': // found an option seperator
  804. if (! fSemicolon) {
  805. fSemicolon = TRUE;
  806. // option follows semicolon and whitespace
  807. *lppOption = (LPSTR)TrimLeadingWhitespace((LPBYTE)lpBuffer + 1);
  808. *lpBuffer = '\0'; // null out first semicolon
  809. }
  810. break;
  811. case '.': // end of a group prefix
  812. if (! fColon && ! fSemicolon) {
  813. // Yes, this is a group prefix. Get past it.
  814. *lppName = (LPSTR)TrimLeadingWhitespace((LPBYTE)lpBuffer + 1);
  815. }
  816. break;
  817. default: // normal character
  818. break;
  819. }
  820. lpBuffer++;
  821. }
  822. }
  823. exit:
  824. return;
  825. }
  826. /***************************************************************************
  827. Name : ParseName
  828. Purpose : parse the name into properites
  829. Parameters: lpvcpf = parameter flags
  830. lpData = data string
  831. lpMailUser -> output mailuser object
  832. Returns : hResult
  833. Comment : vCard names are of the form:
  834. TEXT("surname; given name; middle name; prefix; suffix")
  835. ***************************************************************************/
  836. HRESULT ParseName(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser) {
  837. HRESULT hResult = hrSuccess;
  838. SPropValue spv[5] = {0};
  839. register LPSTR lpCurrent;
  840. ULONG i = 0;
  841. // Look for Surname
  842. if (lpData && *lpData) {
  843. lpCurrent = lpData;
  844. lpData = ParseWord(lpData, ';');
  845. if (*lpCurrent) {
  846. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_SURNAME, PT_STRING8);
  847. spv[i].Value.lpszA = lpCurrent;
  848. i++;
  849. }
  850. }
  851. if (lpData && *lpData) {
  852. lpCurrent = lpData;
  853. lpData = ParseWord(lpData, ';');
  854. if (*lpCurrent) {
  855. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_GIVEN_NAME, PT_STRING8);
  856. spv[i].Value.lpszA = lpCurrent;
  857. i++;
  858. }
  859. }
  860. if (lpData && *lpData) {
  861. lpCurrent = lpData;
  862. lpData = ParseWord(lpData, ';');
  863. if (*lpCurrent) {
  864. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_MIDDLE_NAME, PT_STRING8);
  865. spv[i].Value.lpszA = lpCurrent;
  866. i++;
  867. }
  868. }
  869. if (lpData && *lpData) {
  870. lpCurrent = lpData;
  871. lpData = ParseWord(lpData, ';');
  872. if (*lpCurrent) {
  873. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_DISPLAY_NAME_PREFIX, PT_STRING8);
  874. spv[i].Value.lpszA = lpCurrent;
  875. i++;
  876. }
  877. }
  878. if (lpData && *lpData) {
  879. lpCurrent = lpData;
  880. lpData = ParseWord(lpData, ';');
  881. if (*lpCurrent) {
  882. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_GENERATION, PT_STRING8);
  883. spv[i].Value.lpszA = lpCurrent;
  884. i++;
  885. }
  886. }
  887. if (i) {
  888. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  889. i,
  890. spv,
  891. NULL))) {
  892. DebugTrace( TEXT("ParseName:SetProps -> %x\n"), GetScode(hResult));
  893. }
  894. }
  895. return(hResult);
  896. }
  897. /***************************************************************************
  898. Name : ParseAdr
  899. Purpose : parse the address into properites
  900. Parameters: lpvcpf -> parameter flags
  901. lpData = data string
  902. lpMailUser -> output mailuser object
  903. Returns : hResult
  904. Comment : vCard addreses are of the form:
  905. TEXT("PO box; extended addr; street addr; city; region; postal code; country")
  906. Option: DOM; INTL; POSTAL; PARCEL; HOME; WORK; PREF; CHARSET; LANGUAGE
  907. We will combine extended addr and street addr into PR_STREET_ADDRESS.
  908. ***************************************************************************/
  909. HRESULT ParseAdr(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser) {
  910. HRESULT hResult = hrSuccess;
  911. SPropValue spv[7] = {0}; // must keep up with props set from ADR!
  912. register LPSTR lpCurrent;
  913. ULONG i = 0;
  914. LPSTR lpStreetAddr = NULL;
  915. LPSTR lpExtendedAddr = NULL;
  916. ULONG cbAddr = 0;
  917. LPSTR lpAddr = NULL;
  918. SCODE sc;
  919. BOOL fHome = lpvcpf->fTYPE_HOME;
  920. BOOL fBusiness = lpvcpf->fTYPE_WORK;
  921. //
  922. // default is other type of address
  923. // Look for PO box
  924. if (lpData && *lpData) {
  925. lpCurrent = lpData;
  926. lpData = ParseWord(lpData, ';');
  927. if (*lpCurrent) {
  928. if(fBusiness)
  929. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_POST_OFFICE_BOX, PT_STRING8);
  930. else if(fHome)
  931. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_POST_OFFICE_BOX, PT_STRING8);
  932. else
  933. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_POST_OFFICE_BOX, PT_STRING8);
  934. spv[i].Value.lpszA= lpCurrent;
  935. i++;
  936. }
  937. }
  938. // extended addr
  939. if (lpData && *lpData) {
  940. lpCurrent = lpData;
  941. lpData = ParseWord(lpData, ';');
  942. if (*lpCurrent) {
  943. lpExtendedAddr = lpCurrent;
  944. }
  945. }
  946. // Street address
  947. if (lpData && *lpData) {
  948. lpCurrent = lpData;
  949. lpData = ParseWord(lpData, ';');
  950. if (*lpCurrent) {
  951. lpStreetAddr = lpCurrent;
  952. }
  953. }
  954. if (fBusiness) { // BUSINESS
  955. if (lpExtendedAddr) {
  956. // have a business extended addr field
  957. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OFFICE_LOCATION, PT_STRING8);
  958. spv[i].Value.lpszA = lpExtendedAddr;;
  959. i++;
  960. }
  961. if (lpStreetAddr) {
  962. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_ADDRESS_STREET, PT_STRING8);
  963. spv[i].Value.lpszA = lpStreetAddr;;
  964. i++;
  965. }
  966. } else { // HOME
  967. // Don't have extended for home
  968. if (! lpExtendedAddr && lpStreetAddr) {
  969. if(fHome)
  970. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_STREET, PT_STRING8);
  971. else
  972. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_STREET, PT_STRING8);
  973. spv[i].Value.lpszA= lpStreetAddr;
  974. i++;
  975. } else if (lpExtendedAddr && ! lpStreetAddr) {
  976. if(fHome)
  977. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_STREET, PT_STRING8);
  978. else
  979. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_STREET, PT_STRING8);
  980. spv[i].Value.lpszA= lpExtendedAddr;
  981. i++;
  982. } else {
  983. // Have to concatenate Extended and Street address
  984. if (lpExtendedAddr) {
  985. cbAddr = (lstrlenA(lpExtendedAddr)+1);
  986. }
  987. if (lpStreetAddr) {
  988. cbAddr += (lstrlenA(lpStreetAddr)+1);
  989. }
  990. if (cbAddr) {
  991. // room for CR and NULL
  992. if (sc = MAPIAllocateBuffer(cbAddr, &lpAddr)) {
  993. hResult = ResultFromScode(sc);
  994. goto exit;
  995. }
  996. if (lpExtendedAddr) {
  997. StrCpyNA(lpAddr, lpExtendedAddr, (cbAddr / sizeof(lpAddr[0])));
  998. if (lpStreetAddr) {
  999. StrCatBuffA(lpAddr, "\n", (cbAddr / sizeof(lpAddr[0])));
  1000. }
  1001. StrCatBuffA(lpAddr, lpStreetAddr, (cbAddr / sizeof(lpAddr[0])));
  1002. } else if (lpStreetAddr) {
  1003. StrCpyNA(lpAddr, lpStreetAddr, (cbAddr / sizeof(lpAddr[0])));
  1004. }
  1005. if(fHome)
  1006. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_STREET, PT_STRING8);
  1007. else
  1008. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_STREET, PT_STRING8);
  1009. spv[i].Value.lpszA= lpAddr;
  1010. i++;
  1011. }
  1012. }
  1013. }
  1014. // locality (city)
  1015. if (lpData && *lpData) {
  1016. lpCurrent = lpData;
  1017. lpData = ParseWord(lpData, ';');
  1018. if (*lpCurrent) {
  1019. if(fBusiness)
  1020. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_ADDRESS_CITY, PT_STRING8);
  1021. else if(fHome)
  1022. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_CITY, PT_STRING8);
  1023. else
  1024. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_CITY, PT_STRING8);
  1025. spv[i].Value.lpszA= lpCurrent;
  1026. i++;
  1027. }
  1028. }
  1029. // region (state/province)
  1030. if (lpData && *lpData) {
  1031. lpCurrent = lpData;
  1032. lpData = ParseWord(lpData, ';');
  1033. if (*lpCurrent) {
  1034. if(fBusiness)
  1035. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE, PT_STRING8);
  1036. else if(fHome)
  1037. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_STATE_OR_PROVINCE, PT_STRING8);
  1038. else
  1039. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_STATE_OR_PROVINCE, PT_STRING8);
  1040. spv[i].Value.lpszA= lpCurrent;
  1041. i++;
  1042. }
  1043. }
  1044. // postal code
  1045. if (lpData && *lpData) {
  1046. lpCurrent = lpData;
  1047. lpData = ParseWord(lpData, ';');
  1048. if (*lpCurrent) {
  1049. if(fBusiness)
  1050. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_ADDRESS_POSTAL_CODE, PT_STRING8);
  1051. else if(fHome)
  1052. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_POSTAL_CODE, PT_STRING8);
  1053. else
  1054. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_POSTAL_CODE, PT_STRING8);
  1055. spv[i].Value.lpszA= lpCurrent;
  1056. i++;
  1057. }
  1058. }
  1059. // Country
  1060. if (lpData && *lpData) {
  1061. lpCurrent = lpData;
  1062. lpData = ParseWord(lpData, ';');
  1063. if (*lpCurrent) {
  1064. if(fBusiness)
  1065. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_ADDRESS_COUNTRY, PT_STRING8);
  1066. else if(fHome)
  1067. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_ADDRESS_COUNTRY, PT_STRING8);
  1068. else
  1069. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_ADDRESS_COUNTRY, PT_STRING8);
  1070. spv[i].Value.lpszA= lpCurrent;
  1071. i++;
  1072. }
  1073. }
  1074. if (i) {
  1075. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1076. i,
  1077. spv,
  1078. NULL))) {
  1079. DebugTrace( TEXT("ParseAdr:SetProps -> %x\n"), GetScode(hResult));
  1080. }
  1081. }
  1082. exit:
  1083. FreeBufferAndNull(&lpAddr);
  1084. return(hResult);
  1085. }
  1086. enum {
  1087. iphPR_BUSINESS_FAX_NUMBER,
  1088. iphPR_HOME_FAX_NUMBER,
  1089. iphPR_CELLULAR_TELEPHONE_NUMBER,
  1090. iphPR_CAR_TELEPHONE_NUMBER,
  1091. iphPR_ISDN_NUMBER,
  1092. iphPR_PAGER_TELEPHONE_NUMBER,
  1093. iphPR_BUSINESS_TELEPHONE_NUMBER,
  1094. iphPR_BUSINESS2_TELEPHONE_NUMBER,
  1095. iphPR_HOME_TELEPHONE_NUMBER,
  1096. iphPR_HOME2_TELEPHONE_NUMBER,
  1097. iphPR_PRIMARY_TELEPHONE_NUMBER,
  1098. iphPR_OTHER_TELEPHONE_NUMBER,
  1099. iphMax
  1100. };
  1101. SizedSPropTagArray(iphMax, tagaPhone) = {
  1102. iphMax,
  1103. {
  1104. PR_BUSINESS_FAX_NUMBER,
  1105. PR_HOME_FAX_NUMBER,
  1106. PR_CELLULAR_TELEPHONE_NUMBER,
  1107. PR_CAR_TELEPHONE_NUMBER,
  1108. PR_ISDN_NUMBER,
  1109. PR_PAGER_TELEPHONE_NUMBER,
  1110. PR_BUSINESS_TELEPHONE_NUMBER,
  1111. PR_BUSINESS2_TELEPHONE_NUMBER,
  1112. PR_HOME_TELEPHONE_NUMBER,
  1113. PR_HOME2_TELEPHONE_NUMBER,
  1114. PR_PRIMARY_TELEPHONE_NUMBER,
  1115. PR_OTHER_TELEPHONE_NUMBER
  1116. }
  1117. };
  1118. /***************************************************************************
  1119. Name : ParseTel
  1120. Purpose : parse the telephone number into properites
  1121. Parameters: lpvcpf -> parameter flags
  1122. lpData = data string
  1123. lpMailUser -> output mailuser object
  1124. Returns : hResult
  1125. Comment :
  1126. ***************************************************************************/
  1127. HRESULT ParseTel(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser) {
  1128. HRESULT hResult = hrSuccess;
  1129. SPropValue spv[iphMax] = {0};
  1130. ULONG i = 0;
  1131. BOOL fBusiness = lpvcpf->fTYPE_WORK;// || ! lpvcpf->fTYPE_HOME; // default is business
  1132. BOOL fHome = lpvcpf->fTYPE_HOME;
  1133. BOOL fFax = lpvcpf->fTYPE_FAX;
  1134. BOOL fCell = lpvcpf->fTYPE_CELL;
  1135. BOOL fCar = lpvcpf->fTYPE_CAR;
  1136. BOOL fModem = lpvcpf->fTYPE_MODEM;
  1137. BOOL fISDN = lpvcpf->fTYPE_ISDN;
  1138. BOOL fPager = lpvcpf->fTYPE_PAGER;
  1139. BOOL fBBS = lpvcpf->fTYPE_BBS;
  1140. BOOL fVideo = lpvcpf->fTYPE_VIDEO;
  1141. BOOL fMsg = lpvcpf->fTYPE_MSG;
  1142. BOOL fVoice = lpvcpf->fTYPE_VOICE | (! (fMsg | fFax | fModem | fISDN | fPager | fBBS));
  1143. BOOL fPref = lpvcpf->fTYPE_PREF;
  1144. LPSPropValue lpaProps = NULL;
  1145. ULONG ulcProps;
  1146. // if this is not a prefered address, and its not home or business
  1147. // turn it into a business number - we make this exception for the
  1148. // primary_telephone_number which we output with the PREF prefix
  1149. if(!fPref && !fBusiness && !fHome && !fVoice)
  1150. fBusiness = TRUE;
  1151. // FAX #
  1152. if (lpData && *lpData) {
  1153. // What is already there?
  1154. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  1155. (LPSPropTagArray)&tagaPhone,
  1156. 0, //MAPI_UNICODE, // ulFlags,
  1157. &ulcProps,
  1158. &lpaProps))) {
  1159. DebugTraceResult( TEXT("ParseTel:GetProps(DL)\n"), hResult);
  1160. // No properties, not fatal.
  1161. }
  1162. if (fFax) {
  1163. if (fBusiness) {
  1164. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_BUSINESS_FAX_NUMBER])) {
  1165. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_FAX_NUMBER, PT_STRING8);
  1166. spv[i].Value.lpszA= lpData;
  1167. i++;
  1168. }
  1169. }
  1170. if (fHome) {
  1171. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_HOME_FAX_NUMBER])) {
  1172. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_FAX_NUMBER, PT_STRING8);
  1173. spv[i].Value.lpszA= lpData;
  1174. i++;
  1175. }
  1176. }
  1177. }
  1178. // CELL #
  1179. if (fCell) {
  1180. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_CELLULAR_TELEPHONE_NUMBER])) {
  1181. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_CELLULAR_TELEPHONE_NUMBER, PT_STRING8); // not business/home specific
  1182. spv[i].Value.lpszA= lpData;
  1183. i++;
  1184. }
  1185. }
  1186. // CAR #
  1187. if (fCar) {
  1188. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_CAR_TELEPHONE_NUMBER])) {
  1189. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_CAR_TELEPHONE_NUMBER, PT_STRING8); // not business/home specific
  1190. spv[i].Value.lpszA= lpData;
  1191. i++;
  1192. }
  1193. }
  1194. // ISDN #
  1195. if (fISDN) {
  1196. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_ISDN_NUMBER])) {
  1197. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_ISDN_NUMBER, PT_STRING8);
  1198. spv[i].Value.lpszA= lpData;
  1199. i++;
  1200. }
  1201. }
  1202. // PAGER #
  1203. if (fPager) {
  1204. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_PAGER_TELEPHONE_NUMBER])) {
  1205. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_PAGER_TELEPHONE_NUMBER, PT_STRING8);
  1206. spv[i].Value.lpszA= lpData;
  1207. i++;
  1208. }
  1209. }
  1210. // VOICE #
  1211. if (fVoice) {
  1212. if (fBusiness) {
  1213. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_BUSINESS_TELEPHONE_NUMBER])) {
  1214. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS_TELEPHONE_NUMBER, PT_STRING8);
  1215. spv[i].Value.lpszA= lpData;
  1216. i++;
  1217. }
  1218. else if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_BUSINESS2_TELEPHONE_NUMBER])) {
  1219. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_BUSINESS2_TELEPHONE_NUMBER, PT_STRING8);
  1220. spv[i].Value.lpszA= lpData;
  1221. i++;
  1222. }
  1223. }
  1224. else
  1225. if (fHome) {
  1226. if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_HOME_TELEPHONE_NUMBER])) {
  1227. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME_TELEPHONE_NUMBER, PT_STRING8);
  1228. spv[i].Value.lpszA= lpData;
  1229. i++;
  1230. }
  1231. else if (lpvcpf->fTYPE_PREF || PROP_ERROR(lpaProps[iphPR_HOME2_TELEPHONE_NUMBER])) {
  1232. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_HOME2_TELEPHONE_NUMBER, PT_STRING8);
  1233. spv[i].Value.lpszA= lpData;
  1234. i++;
  1235. }
  1236. }
  1237. else
  1238. {
  1239. if (lpvcpf->fTYPE_VOICE && PROP_ERROR(lpaProps[iphPR_OTHER_TELEPHONE_NUMBER])
  1240. && !(fFax | fCell | fCar | fModem | fISDN | fPager | fBBS | fVideo | fMsg) )
  1241. {
  1242. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_TELEPHONE_NUMBER, PT_STRING8);
  1243. spv[i].Value.lpszA= lpData;
  1244. i++;
  1245. }
  1246. }
  1247. }
  1248. if(fPref && !fFax && !fCell && !fCar && !fModem && !fISDN && !fPager && !fBBS && !fMsg)
  1249. {
  1250. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_PRIMARY_TELEPHONE_NUMBER, PT_STRING8);
  1251. spv[i].Value.lpszA= lpData;
  1252. i++;
  1253. }
  1254. // Store the first one of BBS, MODEM, or VIDEO that we get
  1255. //
  1256. if (fMsg || fBBS || fModem || fVideo)
  1257. {
  1258. if (PROP_ERROR(lpaProps[iphPR_OTHER_TELEPHONE_NUMBER]))
  1259. {
  1260. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_OTHER_TELEPHONE_NUMBER, PT_STRING8);
  1261. spv[i].Value.lpszA= lpData;
  1262. i++;
  1263. }
  1264. }
  1265. FreeBufferAndNull(&lpaProps);
  1266. if (i) {
  1267. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1268. i,
  1269. spv,
  1270. NULL))) {
  1271. DebugTrace( TEXT("ParseTel:SetProps -> %x\n"), GetScode(hResult));
  1272. }
  1273. }
  1274. }
  1275. return(hResult);
  1276. }
  1277. enum {
  1278. iemPR_CONTACT_EMAIL_ADDRESSES,
  1279. iemPR_CONTACT_ADDRTYPES,
  1280. iemPR_CONTACT_DEFAULT_ADDRESS_INDEX,
  1281. iemPR_EMAIL_ADDRESS,
  1282. iemPR_ADDRTYPE,
  1283. iemMax
  1284. };
  1285. SizedSPropTagArray(iemMax, tagaEmail) = {
  1286. iemMax,
  1287. {
  1288. PR_CONTACT_EMAIL_ADDRESSES,
  1289. PR_CONTACT_ADDRTYPES,
  1290. PR_CONTACT_DEFAULT_ADDRESS_INDEX,
  1291. PR_EMAIL_ADDRESS,
  1292. PR_ADDRTYPE,
  1293. }
  1294. };
  1295. const char szAtSign[] = "@";
  1296. #define cbAtSign sizeof(szAtSign)
  1297. const char szMSNpostfix[] = "@msn.com";
  1298. #define cbMSNpostfix sizeof(szMSNpostfix)
  1299. const char szAOLpostfix[] = "@aol.com";
  1300. #define cbAOLpostfix sizeof(szAOLpostfix)
  1301. const char szCOMPUSERVEpostfix[] = "@compuserve.com";
  1302. #define cbCOMPUSERVEpostfix sizeof(szCOMPUSERVEpostfix)
  1303. /***************************************************************************
  1304. Name : ParseEmail
  1305. Purpose : parse an email address into properites
  1306. Parameters: lpvcpf -> parameter flags
  1307. lpData = data string
  1308. lpMailUser -> output mailuser object
  1309. lpvcs -> vCard import state
  1310. Returns : hResult
  1311. Comment :
  1312. ***************************************************************************/
  1313. HRESULT ParseEmail(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser, LPVC_STATE lpvcs) {
  1314. HRESULT hResult = hrSuccess;
  1315. ULONG i = 0;
  1316. BOOL fBusiness = ! lpvcpf->fTYPE_HOME; // default is business
  1317. LPSPropValue lpaProps = NULL;
  1318. ULONG ulcProps;
  1319. SCODE sc;
  1320. LPSTR lpAddrType = szSMTPA;
  1321. LPSTR lpEmailAddress = lpData;
  1322. LPSTR lpTemp = NULL;
  1323. LPTSTR lpAddrTypeW = NULL;
  1324. LPTSTR lpEmailAddressW = NULL;
  1325. if (lpData && *lpData) {
  1326. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  1327. (LPSPropTagArray)&tagaEmail,
  1328. MAPI_UNICODE, // ulFlags,
  1329. &ulcProps,
  1330. &lpaProps))) {
  1331. DebugTraceResult( TEXT("ParseEmail:GetProps(DL)\n"), hResult);
  1332. // No property, not fatal.
  1333. // allocate a buffer
  1334. if (sc = MAPIAllocateBuffer(iemMax * sizeof(SPropValue), &lpaProps)) {
  1335. DebugTrace( TEXT("ParseEmail:MAPIAllocateBuffer -> %x\n"), sc);
  1336. sc = ResultFromScode(sc);
  1337. goto exit;
  1338. }
  1339. // fill in with prop errors
  1340. lpaProps[iemPR_EMAIL_ADDRESS].ulPropTag =
  1341. PROP_TAG(PT_ERROR, PROP_ID(PR_EMAIL_ADDRESS));
  1342. lpaProps[iemPR_ADDRTYPE].ulPropTag =
  1343. PROP_TAG(PT_ERROR, PROP_ID(PR_ADDRTYPE));
  1344. lpaProps[iemPR_CONTACT_EMAIL_ADDRESSES].ulPropTag =
  1345. PROP_TAG(PT_ERROR, PROP_ID(PR_CONTACT_EMAIL_ADDRESSES));
  1346. lpaProps[iemPR_CONTACT_ADDRTYPES].ulPropTag =
  1347. PROP_TAG(PT_ERROR, PROP_ID(PR_CONTACT_ADDRTYPES));
  1348. lpaProps[iemPR_CONTACT_DEFAULT_ADDRESS_INDEX].ulPropTag =
  1349. PROP_TAG(PT_ERROR, PROP_ID(PR_CONTACT_DEFAULT_ADDRESS_INDEX));
  1350. }
  1351. if (lpvcpf->fTYPE_INTERNET) {
  1352. // default
  1353. } else if (lpvcpf->fTYPE_MSN) {
  1354. // convert to SMTP
  1355. // Allocate a new, longer string
  1356. DWORD cchSize = (lstrlenA(lpData) + 1 + cbMSNpostfix);
  1357. if (sc = MAPIAllocateBuffer((cchSize * sizeof(lpTemp[0])), &lpTemp))
  1358. {
  1359. DebugTrace( TEXT("ParseEmail:MAPIAllocateBuffer -> %x\n"), sc);
  1360. hResult = ResultFromScode(sc);
  1361. goto exit;
  1362. }
  1363. // append the msn site
  1364. StrCpyNA(lpTemp, lpData, cchSize);
  1365. StrCatBuffA(lpTemp, szMSNpostfix, cchSize);
  1366. lpEmailAddress = lpTemp;
  1367. } else if (lpvcpf->fTYPE_CIS) {
  1368. // convert to SMTP
  1369. // Allocate a new, longer string
  1370. DWORD cchSize2 = (lstrlenA(lpData) + 1 + cbCOMPUSERVEpostfix);
  1371. if (sc = MAPIAllocateBuffer((cchSize2 * sizeof(lpTemp[0])), &lpTemp))
  1372. {
  1373. DebugTrace( TEXT("ParseEmail:MAPIAllocateBuffer -> %x\n"), sc);
  1374. hResult = ResultFromScode(sc);
  1375. goto exit;
  1376. }
  1377. // append the MSN site
  1378. StrCpyNA(lpTemp, lpData, cchSize2);
  1379. StrCatBuffA(lpTemp, szCOMPUSERVEpostfix, cchSize2);
  1380. // I need to convert the ',' to a '.'
  1381. lpEmailAddress = lpTemp;
  1382. while (*lpTemp) {
  1383. if (*lpTemp == ',') {
  1384. *lpTemp = '.';
  1385. break; // should only be one comma
  1386. }
  1387. lpTemp = CharNextA(lpTemp);
  1388. }
  1389. lpTemp = lpEmailAddress;
  1390. } else if (lpvcpf->fTYPE_AOL) {
  1391. // convert to SMTP
  1392. // Allocate a new, longer string
  1393. DWORD cchSize3 = (lstrlenA(lpData) + 1 + cbAOLpostfix);
  1394. if (sc = MAPIAllocateBuffer((cchSize3 * sizeof(lpTemp[0])), &lpTemp))
  1395. {
  1396. DebugTrace( TEXT("ParseEmail:MAPIAllocateBuffer -> %x\n"), sc);
  1397. hResult = ResultFromScode(sc);
  1398. goto exit;
  1399. }
  1400. // append the AOL site
  1401. StrCpyNA(lpTemp, lpData, cchSize3);
  1402. StrCatBuffA(lpTemp, szAOLpostfix, cchSize3);
  1403. lpEmailAddress = lpTemp;
  1404. }
  1405. // Don't know of any mappings to SMTP for these:
  1406. else if (lpvcpf->fTYPE_X400) {
  1407. // Mark as X400
  1408. lpAddrType = vctTable[VCARD_TYPE_X400];
  1409. } else if (lpvcpf->fTYPE_ATTMAIL) {
  1410. // Mark as ATTMAIL
  1411. lpAddrType = vctTable[VCARD_TYPE_ATTMAIL];
  1412. } else if (lpvcpf->fTYPE_EWORLD) {
  1413. // Mark as EWORLD
  1414. lpAddrType = vctTable[VCARD_TYPE_EWORLD];
  1415. } else if (lpvcpf->fTYPE_IBMMAIL) {
  1416. // Mark as IBMMAIL
  1417. lpAddrType = vctTable[VCARD_TYPE_IBMMAIL];
  1418. } else if (lpvcpf->fTYPE_MCIMAIL) {
  1419. // Mark as MCIMAIL
  1420. lpAddrType = vctTable[VCARD_TYPE_MCIMAIL];
  1421. } else if (lpvcpf->fTYPE_POWERSHARE) {
  1422. // Mark as POWERSHARE
  1423. lpAddrType = vctTable[VCARD_TYPE_POWERSHARE];
  1424. } else if (lpvcpf->fTYPE_PRODIGY) {
  1425. // Mark as PRODIGY
  1426. lpAddrType = vctTable[VCARD_TYPE_PRODIGY];
  1427. //
  1428. // Telex Number should go in PR_TELEX_NUMBER
  1429. // } else if (lpvcpf->fTYPE_TLX) {
  1430. // // Mark as TLX
  1431. // lpAddrType = vctTable[VCARD_TYPE_TLX];
  1432. }
  1433. lpEmailAddressW = ConvertAtoW(lpEmailAddress);
  1434. lpAddrTypeW = ConvertAtoW(lpAddrType);
  1435. if (hResult = AddPropToMVPString(lpaProps,
  1436. ulcProps,
  1437. iemPR_CONTACT_EMAIL_ADDRESSES,
  1438. lpEmailAddressW)) {
  1439. goto exit;
  1440. }
  1441. if (hResult = AddPropToMVPString(lpaProps,
  1442. ulcProps,
  1443. iemPR_CONTACT_ADDRTYPES,
  1444. lpAddrTypeW)) {
  1445. goto exit;
  1446. }
  1447. // Is this the default email address?
  1448. if (lpvcpf->fTYPE_PREF || lpvcs->ulEmailAddrs == 0) {
  1449. lpaProps[iemPR_CONTACT_DEFAULT_ADDRESS_INDEX].ulPropTag = PR_CONTACT_DEFAULT_ADDRESS_INDEX;
  1450. lpaProps[iemPR_CONTACT_DEFAULT_ADDRESS_INDEX].Value.l = lpvcs->ulEmailAddrs;
  1451. lpaProps[iemPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS;
  1452. lpaProps[iemPR_EMAIL_ADDRESS].Value.LPSZ = lpEmailAddressW;
  1453. lpaProps[iemPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE;
  1454. lpaProps[iemPR_ADDRTYPE].Value.LPSZ = lpAddrTypeW;
  1455. } else {
  1456. ulcProps = 2; // contact addresses and contact addrtypes
  1457. }
  1458. lpvcs->ulEmailAddrs++;
  1459. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1460. ulcProps,
  1461. lpaProps,
  1462. NULL))) {
  1463. DebugTrace( TEXT("ParseEmail:SetProps -> %x\n"), GetScode(hResult));
  1464. }
  1465. }
  1466. exit:
  1467. FreeBufferAndNull(&lpaProps);
  1468. FreeBufferAndNull(&lpTemp);
  1469. LocalFreeAndNull(&lpAddrTypeW);
  1470. LocalFreeAndNull(&lpEmailAddressW);
  1471. return(hResult);
  1472. }
  1473. /***************************************************************************
  1474. Name : ParseBday
  1475. Purpose : parse the birthday from string into FileTime
  1476. Parameters: lpvcpf -> parameter flags
  1477. lpData = data string
  1478. lpMailUser -> output mailuser object
  1479. Returns : hResult
  1480. Comment :
  1481. ***************************************************************************/
  1482. HRESULT ParseBday(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpDataA, LPMAILUSER lpMailUser)
  1483. {
  1484. HRESULT hResult = hrSuccess;
  1485. SPropValue spv[1] = {0};
  1486. SYSTEMTIME st = {0};
  1487. TCHAR sz[32];
  1488. LPTSTR lpTmp = NULL;
  1489. LPTSTR lpData = ConvertAtoW(lpDataA);
  1490. // Birthday can be in 2 formats:
  1491. // basic ISO 8601: YYYYMMDD
  1492. // or
  1493. // extended ISO 8601: YYYY-MM-DDTHH-MM-SSetc
  1494. //
  1495. // we'll assume that if the strlen == 8, then it is basic
  1496. //
  1497. if (lpData && *lpData && (lstrlen(lpData) >= 8))
  1498. {
  1499. StrCpyN(sz, lpData,ARRAYSIZE(sz));
  1500. sz[31] = '\0';
  1501. if(lstrlen(lpData) == 8) //basic ISO 8601
  1502. {
  1503. lpTmp = &(sz[6]);
  1504. st.wDay = (WORD) my_atoi(lpTmp);
  1505. *lpTmp = '\0';
  1506. lpTmp = &(sz[4]);
  1507. st.wMonth = (WORD) my_atoi(lpTmp);
  1508. *lpTmp = '\0';
  1509. st.wYear = (WORD) my_atoi(sz);
  1510. }
  1511. else //extended ISO 8601
  1512. {
  1513. sz[10]='\0';
  1514. lpTmp = &(sz[8]);
  1515. st.wDay = (WORD) my_atoi(lpTmp);
  1516. sz[7]='\0';
  1517. lpTmp = &(sz[5]);
  1518. st.wMonth = (WORD) my_atoi(lpTmp);
  1519. sz[4]='\0';
  1520. st.wYear = (WORD) my_atoi(sz);
  1521. }
  1522. SystemTimeToFileTime(&st, &(spv[0].Value.ft));
  1523. spv[0].ulPropTag = PR_BIRTHDAY;
  1524. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1525. 1, spv,
  1526. NULL)))
  1527. {
  1528. DebugTrace( TEXT("ParseBday(0x%08x):SetProps -> %x\n"), PR_BIRTHDAY, GetScode(hResult));
  1529. }
  1530. }
  1531. LocalFreeAndNull(&lpData);
  1532. return(hResult);
  1533. }
  1534. /***************************************************************************
  1535. Name : ParseSimple
  1536. Purpose : parse the simple text prop into the property
  1537. Parameters: lpvcpf -> parameter flags
  1538. lpData = data string
  1539. lpMailUser -> output mailuser object
  1540. ulPropTag = property to save
  1541. Returns : hResult
  1542. Comment :
  1543. ***************************************************************************/
  1544. HRESULT ParseSimple(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser,
  1545. ULONG ulPropTag) {
  1546. HRESULT hResult = hrSuccess;
  1547. SPropValue spv[1] = {0};
  1548. if (lpData && *lpData) {
  1549. spv[0].ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
  1550. spv[0].Value.lpszA= lpData;
  1551. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1552. 1,
  1553. spv,
  1554. NULL))) {
  1555. DebugTrace( TEXT("ParseSimple(0x%08x):SetProps -> %x\n"), ulPropTag, GetScode(hResult));
  1556. }
  1557. }
  1558. return(hResult);
  1559. }
  1560. /***************************************************************************
  1561. Name : InterpretVCardEncoding
  1562. Purpose : Recognize the VCard encoding and set the flags
  1563. Parameters: lpType = encoding string
  1564. lpvcpf -> flags structure to fill in
  1565. Returns : HRESULT
  1566. Comment :
  1567. ***************************************************************************/
  1568. HRESULT InterpretVCardEncoding(LPSTR lpEncoding, LPVCARD_PARAM_FLAGS lpvcpf) {
  1569. HRESULT hResult = hrSuccess;
  1570. if (*lpEncoding) {
  1571. // what is it?
  1572. switch (RecognizeVCardEncoding(lpEncoding)) {
  1573. case VCARD_ENCODING_NONE:
  1574. break;
  1575. case VCARD_ENCODING_QUOTED_PRINTABLE:
  1576. lpvcpf->fENCODING_QUOTED_PRINTABLE = TRUE;
  1577. break;
  1578. case VCARD_ENCODING_BASE64:
  1579. lpvcpf->fENCODING_BASE64 = TRUE;
  1580. break;
  1581. case VCARD_ENCODING_7BIT:
  1582. lpvcpf->fENCODING_7BIT = TRUE;
  1583. break;
  1584. default:
  1585. // Assert(FALSE);
  1586. break;
  1587. }
  1588. }
  1589. return(hResult);
  1590. }
  1591. /***************************************************************************
  1592. Name : InterpretVCardType
  1593. Purpose : Recognize the VCard type and set the flags
  1594. Parameters: lpType = type string
  1595. lpvcpf -> flags structure to fill in
  1596. Returns : HRESULT
  1597. Comment :
  1598. ***************************************************************************/
  1599. HRESULT InterpretVCardType(LPSTR lpType, LPVCARD_PARAM_FLAGS lpvcpf) {
  1600. HRESULT hResult = hrSuccess;
  1601. if (*lpType) {
  1602. // what is it?
  1603. switch (RecognizeVCardType(lpType)) {
  1604. case VCARD_TYPE_DOM:
  1605. lpvcpf->fTYPE_DOM = TRUE;
  1606. break;
  1607. case VCARD_TYPE_INTL:
  1608. lpvcpf->fTYPE_INTL = TRUE;
  1609. break;
  1610. case VCARD_TYPE_POSTAL:
  1611. lpvcpf->fTYPE_POSTAL = TRUE;
  1612. break;
  1613. case VCARD_TYPE_PARCEL:
  1614. lpvcpf->fTYPE_PARCEL = TRUE;
  1615. break;
  1616. case VCARD_TYPE_HOME:
  1617. lpvcpf->fTYPE_HOME = TRUE;
  1618. break;
  1619. case VCARD_TYPE_WORK:
  1620. lpvcpf->fTYPE_WORK = TRUE;
  1621. break;
  1622. case VCARD_TYPE_PREF:
  1623. lpvcpf->fTYPE_PREF = TRUE;
  1624. break;
  1625. case VCARD_TYPE_VOICE:
  1626. lpvcpf->fTYPE_VOICE = TRUE;
  1627. break;
  1628. case VCARD_TYPE_FAX:
  1629. lpvcpf->fTYPE_FAX = TRUE;
  1630. break;
  1631. case VCARD_TYPE_MSG:
  1632. lpvcpf->fTYPE_MSG = TRUE;
  1633. break;
  1634. case VCARD_TYPE_CELL:
  1635. lpvcpf->fTYPE_CELL = TRUE;
  1636. break;
  1637. case VCARD_TYPE_PAGER:
  1638. lpvcpf->fTYPE_PAGER = TRUE;
  1639. break;
  1640. case VCARD_TYPE_BBS:
  1641. lpvcpf->fTYPE_BBS = TRUE;
  1642. break;
  1643. case VCARD_TYPE_MODEM:
  1644. lpvcpf->fTYPE_MODEM = TRUE;
  1645. break;
  1646. case VCARD_TYPE_CAR:
  1647. lpvcpf->fTYPE_CAR = TRUE;
  1648. break;
  1649. case VCARD_TYPE_ISDN:
  1650. lpvcpf->fTYPE_ISDN = TRUE;
  1651. break;
  1652. case VCARD_TYPE_VIDEO:
  1653. lpvcpf->fTYPE_VIDEO = TRUE;
  1654. break;
  1655. case VCARD_TYPE_AOL:
  1656. lpvcpf->fTYPE_AOL = TRUE;
  1657. break;
  1658. case VCARD_TYPE_APPLELINK:
  1659. lpvcpf->fTYPE_APPLELINK = TRUE;
  1660. break;
  1661. case VCARD_TYPE_ATTMAIL:
  1662. lpvcpf->fTYPE_ATTMAIL = TRUE;
  1663. break;
  1664. case VCARD_TYPE_CIS:
  1665. lpvcpf->fTYPE_CIS = TRUE;
  1666. break;
  1667. case VCARD_TYPE_EWORLD:
  1668. lpvcpf->fTYPE_EWORLD = TRUE;
  1669. break;
  1670. case VCARD_TYPE_INTERNET:
  1671. lpvcpf->fTYPE_INTERNET = TRUE;
  1672. break;
  1673. case VCARD_TYPE_IBMMAIL:
  1674. lpvcpf->fTYPE_IBMMAIL = TRUE;
  1675. break;
  1676. case VCARD_TYPE_MSN:
  1677. lpvcpf->fTYPE_MSN = TRUE;
  1678. break;
  1679. case VCARD_TYPE_MCIMAIL:
  1680. lpvcpf->fTYPE_MCIMAIL = TRUE;
  1681. break;
  1682. case VCARD_TYPE_POWERSHARE:
  1683. lpvcpf->fTYPE_POWERSHARE = TRUE;
  1684. break;
  1685. case VCARD_TYPE_PRODIGY:
  1686. lpvcpf->fTYPE_PRODIGY = TRUE;
  1687. break;
  1688. case VCARD_TYPE_TLX:
  1689. lpvcpf->fTYPE_TLX = TRUE;
  1690. break;
  1691. case VCARD_TYPE_X400:
  1692. lpvcpf->fTYPE_X400 = TRUE;
  1693. break;
  1694. case VCARD_TYPE_GIF:
  1695. lpvcpf->fTYPE_GIF = TRUE;
  1696. break;
  1697. case VCARD_TYPE_CGM:
  1698. lpvcpf->fTYPE_CGM = TRUE;
  1699. break;
  1700. case VCARD_TYPE_WMF:
  1701. lpvcpf->fTYPE_WMF = TRUE;
  1702. break;
  1703. case VCARD_TYPE_BMP:
  1704. lpvcpf->fTYPE_BMP = TRUE;
  1705. break;
  1706. case VCARD_TYPE_MET:
  1707. lpvcpf->fTYPE_MET = TRUE;
  1708. break;
  1709. case VCARD_TYPE_PMB:
  1710. lpvcpf->fTYPE_PMB = TRUE;
  1711. break;
  1712. case VCARD_TYPE_DIB:
  1713. lpvcpf->fTYPE_DIB = TRUE;
  1714. break;
  1715. case VCARD_TYPE_PICT:
  1716. lpvcpf->fTYPE_PICT = TRUE;
  1717. break;
  1718. case VCARD_TYPE_TIFF:
  1719. lpvcpf->fTYPE_TIFF = TRUE;
  1720. break;
  1721. case VCARD_TYPE_ACROBAT:
  1722. lpvcpf->fTYPE_ACROBAT = TRUE;
  1723. break;
  1724. case VCARD_TYPE_PS:
  1725. lpvcpf->fTYPE_PS = TRUE;
  1726. break;
  1727. case VCARD_TYPE_JPEG:
  1728. lpvcpf->fTYPE_JPEG = TRUE;
  1729. break;
  1730. case VCARD_TYPE_QTIME:
  1731. lpvcpf->fTYPE_QTIME = TRUE;
  1732. break;
  1733. case VCARD_TYPE_MPEG:
  1734. lpvcpf->fTYPE_MPEG = TRUE;
  1735. break;
  1736. case VCARD_TYPE_MPEG2:
  1737. lpvcpf->fTYPE_MPEG2 = TRUE;
  1738. break;
  1739. case VCARD_TYPE_AVI:
  1740. lpvcpf->fTYPE_AVI = TRUE;
  1741. break;
  1742. case VCARD_TYPE_WAVE:
  1743. lpvcpf->fTYPE_WAVE = TRUE;
  1744. break;
  1745. case VCARD_TYPE_AIFF:
  1746. lpvcpf->fTYPE_AIFF = TRUE;
  1747. break;
  1748. case VCARD_TYPE_PCM:
  1749. lpvcpf->fTYPE_PCM = TRUE;
  1750. break;
  1751. case VCARD_TYPE_X509:
  1752. lpvcpf->fTYPE_X509 = TRUE;
  1753. break;
  1754. case VCARD_TYPE_PGP:
  1755. lpvcpf->fTYPE_PGP = TRUE;
  1756. break;
  1757. case VCARD_TYPE_NONE:
  1758. // Wasn't a TYPE, try an encoding
  1759. hResult = InterpretVCardEncoding(lpType, lpvcpf);
  1760. break;
  1761. default:
  1762. // Assert(FALSE);
  1763. break;
  1764. }
  1765. }
  1766. return(hResult);
  1767. }
  1768. /***************************************************************************
  1769. Name : ParseVCardParams
  1770. Purpose : Parse out the vCard's parameters
  1771. Parameters: lpBuffer = option string
  1772. lpvcpf -> flags structure to fill in
  1773. Returns : HRESULT
  1774. Comment : Assumes lpvcpf is initialized to all false.
  1775. ***************************************************************************/
  1776. HRESULT ParseVCardParams(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf) {
  1777. TCHAR ch;
  1778. LPSTR lpOption, lpArgs;
  1779. BOOL fReady;
  1780. HRESULT hResult = hrSuccess;
  1781. // Is there anything here?
  1782. if (lpBuffer) {
  1783. while (*lpBuffer) {
  1784. fReady = FALSE;
  1785. lpOption = lpBuffer;
  1786. lpArgs = NULL;
  1787. while ((ch = *lpBuffer) && ! fReady) {
  1788. switch (ch) {
  1789. case ';': // end of this param
  1790. *lpBuffer = '\0';
  1791. fReady = TRUE;
  1792. break;
  1793. case '=': // found a param with args
  1794. if (! lpArgs) {
  1795. lpArgs = lpBuffer + 1;
  1796. *lpBuffer = '\0';
  1797. }
  1798. break;
  1799. default: // normal character
  1800. break;
  1801. }
  1802. lpBuffer++;
  1803. }
  1804. if (*lpOption) {
  1805. // what is it?
  1806. switch (RecognizeVCardParam(lpOption)) {
  1807. case VCARD_PARAM_TYPE:
  1808. if (lpArgs) {
  1809. ParseVCardType(lpArgs, lpvcpf);
  1810. }
  1811. break;
  1812. case VCARD_PARAM_ENCODING:
  1813. if (lpArgs) {
  1814. ParseVCardEncoding(lpArgs, lpvcpf);
  1815. }
  1816. break;
  1817. case VCARD_PARAM_LANGUAGE:
  1818. lpvcpf->szPARAM_LANGUAGE = lpArgs;
  1819. break;
  1820. case VCARD_PARAM_CHARSET:
  1821. lpvcpf->szPARAM_CHARSET = lpArgs;
  1822. break;
  1823. case VCARD_PARAM_VALUE:
  1824. // BUGBUG: Should reject those that we can't process (like URL)
  1825. break;
  1826. case VCARD_PARAM_NONE:
  1827. if (hResult = InterpretVCardType(lpOption, lpvcpf)) {
  1828. goto exit;
  1829. }
  1830. break;
  1831. default:
  1832. break;
  1833. }
  1834. }
  1835. }
  1836. }
  1837. exit:
  1838. return(hResult);
  1839. }
  1840. /***************************************************************************
  1841. Name : ParseOrg
  1842. Purpose : parse the organization into properites
  1843. Parameters: lpvcpf ->
  1844. lpData = data string
  1845. lpMailUser -> output mailuser object
  1846. Returns : hResult
  1847. Comment : vCard organizations are of the form:
  1848. TEXT("organization; org unit; org unit; ...")
  1849. ***************************************************************************/
  1850. HRESULT ParseOrg(LPVCARD_PARAM_FLAGS lpvcpf, LPSTR lpData, LPMAILUSER lpMailUser) {
  1851. HRESULT hResult = hrSuccess;
  1852. SPropValue spv[2] = {0};
  1853. register LPSTR lpCurrent;
  1854. ULONG i = 0;
  1855. // Look for Organization (company)
  1856. if (lpData && *lpData) {
  1857. lpCurrent = lpData;
  1858. lpData = ParseWord(lpData, ';');
  1859. if (*lpCurrent) {
  1860. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_COMPANY_NAME, PT_STRING8);
  1861. spv[i].Value.lpszA= lpCurrent;
  1862. i++;
  1863. }
  1864. }
  1865. // Everything else goes into PR_DEPARTMENT_NAME
  1866. if (lpData && *lpData) {
  1867. spv[i].ulPropTag = CHANGE_PROP_TYPE(PR_DEPARTMENT_NAME, PT_STRING8);
  1868. spv[i].Value.lpszA= lpData;
  1869. i++;
  1870. }
  1871. if (i) {
  1872. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1873. i,
  1874. spv,
  1875. NULL))) {
  1876. DebugTrace( TEXT("ParseName:SetProps -> %x\n"), GetScode(hResult));
  1877. }
  1878. }
  1879. return(hResult);
  1880. }
  1881. /***************************************************************************
  1882. Name : ParseVCardType
  1883. Purpose : Parse out the vCard's type parameter
  1884. Parameters: lpBuffer = type string
  1885. lpvcpf -> flags structure to fill in
  1886. Returns : HRESULT
  1887. Comment :
  1888. ***************************************************************************/
  1889. HRESULT ParseVCardType(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf) {
  1890. TCHAR ch;
  1891. BOOL fReady;
  1892. LPSTR lpType;
  1893. HRESULT hResult = hrSuccess;
  1894. // Is there anything here?
  1895. if (lpBuffer) {
  1896. while (*lpBuffer) {
  1897. fReady = FALSE;
  1898. lpType = lpBuffer;
  1899. while ((ch = *lpBuffer) && ! fReady) {
  1900. switch (ch) {
  1901. case ',': // end of this type
  1902. *lpBuffer = '\0';
  1903. fReady = TRUE;
  1904. break;
  1905. default: // normal character
  1906. break;
  1907. }
  1908. lpBuffer++;
  1909. }
  1910. hResult = InterpretVCardType(lpType, lpvcpf);
  1911. }
  1912. }
  1913. return(hResult);
  1914. }
  1915. /***************************************************************************
  1916. Name : ParseVCardEncoding
  1917. Purpose : Parse out the vCard encoding parameter
  1918. Parameters: lpBuffer = type string
  1919. lpvcpf -> flags structure to fill in
  1920. Returns : HRESULT
  1921. Comment :
  1922. ***************************************************************************/
  1923. HRESULT ParseVCardEncoding(LPSTR lpBuffer, LPVCARD_PARAM_FLAGS lpvcpf) {
  1924. TCHAR ch;
  1925. BOOL fReady;
  1926. LPSTR lpEncoding;
  1927. HRESULT hResult = hrSuccess;
  1928. // Is there anything here?
  1929. if (lpBuffer) {
  1930. while (*lpBuffer) {
  1931. fReady = FALSE;
  1932. lpEncoding = lpBuffer;
  1933. while ((ch = *lpBuffer) && ! fReady) {
  1934. switch (ch) {
  1935. case ',': // end of this type
  1936. *lpBuffer = '\0';
  1937. fReady = TRUE;
  1938. break;
  1939. default: // normal character
  1940. break;
  1941. }
  1942. lpBuffer++;
  1943. }
  1944. hResult = InterpretVCardEncoding(lpEncoding, lpvcpf);
  1945. }
  1946. }
  1947. return(hResult);
  1948. }
  1949. /***************************************************************************
  1950. Name : Base64DMap
  1951. Purpose : Decoding mapping for Base64
  1952. Parameters: chIn = character from Base64 encoding
  1953. Returns : 6-bit value represented by chIn.
  1954. Comment :
  1955. ***************************************************************************/
  1956. /*
  1957. this function is not necessary any more because of the DecodeBase64 function
  1958. UCHAR Base64DMap(UCHAR chIn) {
  1959. UCHAR chOut;
  1960. // 'A' -> 0, 'B' -> 1, ... 'Z' -> 25
  1961. if (chIn >= 'A' && chIn <= 'Z') {
  1962. chOut = chIn - 'A';
  1963. } else if (chIn >= 'a' && chIn <= 'z') { // 'a' -> 26
  1964. chOut = (chIn - 'a') + 26;
  1965. } else if (chIn >= '0' && chIn <= '9') { // '0' -> 52
  1966. chOut = (chIn - '0') + 52;
  1967. } else if (chIn == '+') {
  1968. chOut = 62;
  1969. } else if (chIn == '/') {
  1970. chOut = 63;
  1971. } else {
  1972. // uh oh
  1973. Assert(FALSE);
  1974. chOut = 0;
  1975. }
  1976. return(chOut);
  1977. }
  1978. */
  1979. /***************************************************************************
  1980. Name : DecodeVCardData
  1981. Purpose : Decode QUOTED_PRINTABLE or BASE64 data
  1982. Parameters: lpData = data string
  1983. cbData = the length of the decoded data string // changed t-jstaj
  1984. lpvcs -> state variable
  1985. Returns : hResult
  1986. Comment : Decode in place is possible since both encodings are
  1987. guaranteed to take at least as much space as the original data.
  1988. ***************************************************************************/
  1989. HRESULT DecodeVCardData(LPSTR lpData, PULONG cbData, LPVCARD_PARAM_FLAGS lpvcpf) {
  1990. HRESULT hResult = hrSuccess;
  1991. LPSTR lpTempIn = lpData;
  1992. LPSTR lpTempOut = lpData;
  1993. char chIn, chOut;
  1994. char chA, chB, chC, chD;
  1995. if (lpvcpf->fENCODING_QUOTED_PRINTABLE) {
  1996. // Look for '=', this is the escape character for QP
  1997. while (chIn = *lpTempIn) {
  1998. if (chIn == '=') {
  1999. chIn = *(++lpTempIn);
  2000. // is it a soft line break or a hex character?
  2001. if (chIn == '\n' || chIn == '\r') {
  2002. // Soft line break
  2003. while (chIn && (chIn == '\n' || chIn == '\r')) {
  2004. chIn = *(++lpTempIn);
  2005. }
  2006. continue; // We're now pointing to next good data or NULL
  2007. } else {
  2008. // hex encoded char
  2009. // high nibble
  2010. if (chIn >= '0' && chIn <= '9') {
  2011. chOut = (chIn - '0') << 4;
  2012. } else if (chIn >= 'A' && chIn <= 'F') {
  2013. chOut = ((chIn - 'A') + 10) << 4;
  2014. } else if (chIn >= 'a' && chIn <= 'f') {
  2015. chOut = ((chIn - 'a') + 10) << 4;
  2016. } else {
  2017. // bogus QUOTED_PRINTABLE data
  2018. // Cut it short right here.
  2019. break;
  2020. }
  2021. chIn = *(++lpTempIn);
  2022. // low nibble
  2023. if (chIn >= '0' && chIn <= '9') {
  2024. chOut |= (chIn - '0');
  2025. } else if (chIn >= 'A' && chIn <= 'F') {
  2026. chOut |= ((chIn - 'A') + 10);
  2027. } else if (chIn >= 'a' && chIn <= 'f') {
  2028. chOut |= ((chIn - 'a') + 10);
  2029. } else {
  2030. // bogus QUOTED_PRINTABLE data
  2031. // Cut it short right here.
  2032. break;
  2033. }
  2034. }
  2035. } else {
  2036. chOut = chIn;
  2037. }
  2038. *(lpTempOut++) = chOut;
  2039. lpTempIn++;
  2040. }
  2041. *lpTempOut = '\0'; // terminate it
  2042. } else if (lpvcpf->fENCODING_BASE64) {
  2043. // eliminate white spaces
  2044. LPSTR lpTempCopyPt;
  2045. for( lpTempCopyPt = lpTempIn = lpData;
  2046. lpTempIn && *lpTempIn;
  2047. lpTempCopyPt++, lpTempIn++ )
  2048. {
  2049. while( /*IsSpace(lpTempIn)*/
  2050. *lpTempIn == ' '
  2051. || *lpTempIn == '\t')
  2052. lpTempIn++;
  2053. if( lpTempCopyPt != lpTempIn )
  2054. *(lpTempCopyPt) = *(lpTempIn);
  2055. }
  2056. *(lpTempCopyPt) = '\0';
  2057. lpTempIn = lpData;
  2058. lpTempOut = lpData;
  2059. if( HR_FAILED(hResult = DecodeBase64(lpTempIn, lpTempOut, cbData) ) )
  2060. {
  2061. DebugTrace( TEXT("couldn't decode buffer\n"));
  2062. }
  2063. /** This is the original code for vcard decoding base64, however, it wasn't working so new decoding is all done
  2064. within DecodeBase64 function.
  2065. lpTempIn = lpData;
  2066. lpTempOut = lpData;
  2067. while (*lpTempIn) {
  2068. chA = Base64DMap(*(PUCHAR)(lpTempIn)++);
  2069. if (! (chB = Base64DMap(*(PUCHAR)(lpTempIn)++) )) {
  2070. chC = chD = 0;
  2071. } else if (chC = Base64DMap(*(PUCHAR)(lpTempIn)++)) {
  2072. chD = 0;
  2073. } else {
  2074. chD = Base64DMap(*(PUCHAR)(lpTempIn)++);
  2075. }
  2076. // chA = high 6 bits
  2077. // chD = low 6 bits
  2078. *(lpTempOut++) = (chA << 0x02) | ((chB & 0x60) >> 6);
  2079. *(lpTempOut++) = ((chB & 0x0F) << 4) | ((chC & 0x3B) >> 2);
  2080. *(lpTempOut++) = ((chC & 0x03) << 6) | (chD & 0x3F);
  2081. }
  2082. *lpTempOut = '\0'; // terminate it
  2083. */
  2084. }
  2085. return(hResult);
  2086. }
  2087. /***************************************************************************
  2088. Name : InterpretVCardItem
  2089. Purpose : Recognize the vCard item
  2090. Parameters: lpName = property name
  2091. lpOption = option string
  2092. lpData = data string
  2093. lpMailUser -> output mailuser object
  2094. lpvcs -> state variable
  2095. Returns : hResult
  2096. Comment : Expects the keyword to be in the current line (lpBuffer), but
  2097. may read more lines as necesary to get a complete item.
  2098. ***************************************************************************/
  2099. HRESULT InterpretVCardItem(LPSTR lpName, LPSTR lpOption, LPSTR lpData,
  2100. LPMAILUSER lpMailUser, LPEXTVCARDPROP lpList, LPVC_STATE lpvcs) {
  2101. HRESULT hResult = hrSuccess;
  2102. VCARD_PARAM_FLAGS vcpf = {0};
  2103. ULONG cbData = 0;
  2104. ParseVCardParams(lpOption, &vcpf);
  2105. #if 0
  2106. #ifdef DEBUG
  2107. if(lstrcmpiA(lpName, "KEY"))
  2108. {
  2109. LPTSTR lpW1 = ConvertAtoW(lpName);
  2110. LPTSTR lpW2 = ConvertAtoW(lpData);
  2111. DebugTrace( TEXT("%s:%s\n"), lpW1, lpW2);
  2112. LocalFreeAndNull(&lpW1);
  2113. LocalFreeAndNull(&lpW2);
  2114. }
  2115. else
  2116. DebugTrace(TEXT("KEY:\n"));
  2117. #endif
  2118. #endif
  2119. if (hResult = DecodeVCardData(lpData, &cbData, &vcpf)) {
  2120. goto exit;
  2121. }
  2122. switch (RecognizeVCardKeyWord(lpName)) {
  2123. case VCARD_KEY_VCARD:
  2124. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2125. break;
  2126. case VCARD_KEY_BEGIN:
  2127. if (lpvcs->vce != VCS_INITIAL) {
  2128. // uh oh, already saw BEGIN
  2129. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2130. } else {
  2131. switch (RecognizeVCardKeyWord(lpData)) {
  2132. case VCARD_KEY_VCARD:
  2133. lpvcs->vce = VCS_ITEMS;
  2134. break;
  2135. default:
  2136. lpvcs->vce = VCS_ERROR;
  2137. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2138. break;
  2139. }
  2140. }
  2141. break;
  2142. case VCARD_KEY_END:
  2143. if (lpvcs->vce != VCS_ITEMS) {
  2144. // uh oh, haven't seen begin yet
  2145. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2146. } else {
  2147. switch (RecognizeVCardKeyWord(lpData)) {
  2148. case VCARD_KEY_VCARD:
  2149. lpvcs->vce = VCS_FINISHED;
  2150. break;
  2151. default:
  2152. lpvcs->vce = VCS_ERROR;
  2153. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2154. break;
  2155. }
  2156. }
  2157. break;
  2158. case VCARD_KEY_N: // structured name
  2159. // Data: surname; given name; middle name; prefix; suffix
  2160. hResult = ParseName(&vcpf, lpData, lpMailUser);
  2161. break;
  2162. case VCARD_KEY_ORG: // organization info
  2163. // Data: company name; org unit; org unit; ...
  2164. hResult = ParseOrg(&vcpf, lpData, lpMailUser);
  2165. break;
  2166. case VCARD_KEY_ADR:
  2167. // Data: TEXT("PO box; extended addr; street addr; city; region; postal code; country")
  2168. // Option: DOM; INTL; POSTAL; PARCEL; HOME; WORK; PREF; CHARSET; LANGUAGE
  2169. hResult = ParseAdr(&vcpf, lpData, lpMailUser);
  2170. break;
  2171. case VCARD_KEY_TEL:
  2172. // Data: canonical form phone number
  2173. // Options: HOME, WORK, MSG, PREF, FAX, CELL, PAGER, VIDEO, BBS, MODEM, ISDN
  2174. hResult = ParseTel(&vcpf, lpData, lpMailUser);
  2175. break;
  2176. case VCARD_KEY_TITLE:
  2177. // Data: job title
  2178. // Options: CHARSET, LANGUAGE
  2179. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_TITLE);
  2180. break;
  2181. case VCARD_KEY_NICKNAME:
  2182. // Data: job title
  2183. // Options: CHARSET, LANGUAGE
  2184. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_NICKNAME);
  2185. break;
  2186. case VCARD_KEY_URL:
  2187. // Data: URL
  2188. // Options: none (though we'd like to see HOME, WORK)
  2189. if (vcpf.fTYPE_HOME) {
  2190. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_PERSONAL_HOME_PAGE);
  2191. lpvcs->fPersonalURL = TRUE;
  2192. } else if (vcpf.fTYPE_WORK) {
  2193. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_BUSINESS_HOME_PAGE);
  2194. lpvcs->fBusinessURL = TRUE;
  2195. } else if (! lpvcs->fPersonalURL) {
  2196. // assume it is HOME page
  2197. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_PERSONAL_HOME_PAGE);
  2198. lpvcs->fPersonalURL = TRUE;
  2199. } else if (! lpvcs->fBusinessURL) {
  2200. // assume it is BUSINESS web page
  2201. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_BUSINESS_HOME_PAGE);
  2202. lpvcs->fBusinessURL = TRUE;
  2203. } // else, toss it
  2204. break;
  2205. case VCARD_KEY_NOTE:
  2206. // Data: note text
  2207. // Options: CHARSET, LANGUAGE
  2208. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_COMMENT);
  2209. break;
  2210. case VCARD_KEY_FN:
  2211. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_DISPLAY_NAME);
  2212. break;
  2213. case VCARD_KEY_EMAIL:
  2214. // since we are forcibly putting the telex value into the EMAIL type,
  2215. // we also need to be able to get it out of there
  2216. if(vcpf.fTYPE_TLX)
  2217. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_TELEX_NUMBER);
  2218. else
  2219. hResult = ParseEmail(&vcpf, lpData, lpMailUser, lpvcs);
  2220. break;
  2221. case VCARD_KEY_ROLE:
  2222. hResult = ParseSimple(&vcpf, lpData, lpMailUser, PR_PROFESSION);
  2223. break;
  2224. case VCARD_KEY_BDAY:
  2225. hResult = ParseBday(&vcpf, lpData, lpMailUser);
  2226. break;
  2227. case VCARD_KEY_AGENT:
  2228. case VCARD_KEY_LOGO:
  2229. case VCARD_KEY_PHOTO:
  2230. case VCARD_KEY_LABEL:
  2231. case VCARD_KEY_FADR:
  2232. case VCARD_KEY_SOUND:
  2233. case VCARD_KEY_LANG:
  2234. case VCARD_KEY_TZ:
  2235. case VCARD_KEY_GEO:
  2236. case VCARD_KEY_REV:
  2237. case VCARD_KEY_UID:
  2238. case VCARD_KEY_MAILER:
  2239. // Not yet implemented: ignore
  2240. #ifdef DEBUG
  2241. {
  2242. LPTSTR lpW = ConvertAtoW(lpName);
  2243. DebugTrace( TEXT("===>>> NYI: %s\n"), lpW);
  2244. LocalFreeAndNull(&lpW);
  2245. }
  2246. #endif
  2247. break;
  2248. case VCARD_KEY_KEY:
  2249. {
  2250. hResult = ParseCert( lpData, cbData, lpMailUser);
  2251. break;
  2252. }
  2253. case VCARD_KEY_X_WAB_GENDER:
  2254. {
  2255. SPropValue spv[1] = {0};
  2256. if (lpData )
  2257. {
  2258. INT fGender = (INT)lpData[0] - '0';
  2259. if( fGender < 0 || fGender > 2 )
  2260. fGender = 0;
  2261. spv[0].Value.l = fGender;
  2262. spv[0].ulPropTag = PR_GENDER;
  2263. if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
  2264. 1, spv,
  2265. NULL)))
  2266. {
  2267. DebugTrace( TEXT("could not set props\n"));
  2268. }
  2269. }
  2270. break;
  2271. }
  2272. case VCARD_KEY_X:
  2273. case VCARD_KEY_NONE:
  2274. //
  2275. // Check if this is an X- named prop that we might care about
  2276. //
  2277. if(lpList)
  2278. {
  2279. LPEXTVCARDPROP lpTemp = lpList;
  2280. while( lpTemp && lpTemp->ulExtPropTag &&
  2281. lpTemp->lpszExtPropName && lstrlenA(lpTemp->lpszExtPropName) )
  2282. {
  2283. if(!lstrcmpiA(lpName, lpTemp->lpszExtPropName))
  2284. {
  2285. hResult = ParseSimple(&vcpf, lpData, lpMailUser, lpTemp->ulExtPropTag);
  2286. break;
  2287. }
  2288. lpTemp = lpTemp->lpNext;
  2289. }
  2290. }
  2291. #ifdef DEBUG
  2292. {
  2293. LPTSTR lpW = ConvertAtoW(lpName);
  2294. DebugTrace( TEXT("Unrecognized or extended vCard key %s\n"), lpW);
  2295. LocalFreeAndNull(&lpW);
  2296. }
  2297. #endif //debug
  2298. break;
  2299. default:
  2300. // Assert(FALSE);
  2301. break;
  2302. }
  2303. if (lpvcs->vce == VCS_INITIAL) {
  2304. // We are still in initial state. This is not a vCard.
  2305. hResult = ResultFromScode(MAPI_E_INVALID_OBJECT);
  2306. }
  2307. exit:
  2308. return(hResult);
  2309. }
  2310. /***************************************************************************
  2311. Name : ReadLn
  2312. Purpose : Read a line from the handle
  2313. Parameters: handle = open file handle
  2314. ReadFn = function to read from handle
  2315. lppLine -> returned pointer to this line's read into.
  2316. lpcbItem -> [in] size of data in lppBuffer. [out] returned size of
  2317. data in lppBuffer. If zero, there is no more data. (Does not
  2318. include terminating NULL)
  2319. lppBuffer -> [in] start of item buffer or NULL if none yet.
  2320. [out] start of allocated item buffer. Caller must
  2321. LocalFree this buffer once the item is read in.
  2322. lpcbBuffer -> [in/out] size of lppBuffer allocation.
  2323. Returns : hResult: 0 on no error (recognized)
  2324. Comment : Reads a line from the handle, discarding any carriage return
  2325. characters and empty lines. Will not overwrite buffer, and
  2326. will always terminate the string with a null. Trims trailing
  2327. white space.
  2328. This is very inefficient since we're reading a byte at a time.
  2329. I think we can get away with it since vCards are typically
  2330. small. If not, we'll have to do some read caching.
  2331. ***************************************************************************/
  2332. #define READ_BUFFER_GROW 256
  2333. HRESULT ReadLn(HANDLE hVCard, VCARD_READ ReadFn, LPSTR * lppLine, LPULONG lpcbItem, LPSTR * lppBuffer, LPULONG lpcbBuffer)
  2334. {
  2335. HRESULT hResult = hrSuccess;
  2336. LPSTR lpBuffer = *lppBuffer;
  2337. LPSTR lpBufferTemp;
  2338. register LPSTR lpRead = NULL;
  2339. ULONG cbRead;
  2340. ULONG cbBuffer;
  2341. char ch;
  2342. ULONG cbItem;
  2343. ULONG cbStart = 0;
  2344. if (! lpBuffer) {
  2345. cbBuffer = READ_BUFFER_GROW;
  2346. cbItem = 0;
  2347. if (! (lpBuffer = LocalAlloc(LPTR, cbBuffer))) {
  2348. DebugTrace( TEXT("ReadLn:LocalAlloc -> %u\n"), GetLastError());
  2349. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2350. goto exit;
  2351. }
  2352. } else {
  2353. cbBuffer = *lpcbBuffer;
  2354. cbItem = *lpcbItem;
  2355. // Make certain we have room for at least one more character.
  2356. if (cbItem >= cbBuffer) {
  2357. // Time to grow the buffer
  2358. cbBuffer += READ_BUFFER_GROW;
  2359. if (! (lpRead = LocalReAlloc(lpBuffer, cbBuffer, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
  2360. DebugTrace( TEXT("ReadLn:LocalReAlloc(%u) -> %u\n"), cbBuffer, GetLastError());
  2361. goto exit;
  2362. }
  2363. lpBuffer = lpRead;
  2364. }
  2365. }
  2366. cbStart = cbItem;
  2367. lpRead = lpBuffer + cbItem; // read pointer
  2368. do {
  2369. // read next character
  2370. if (hResult = ReadFn(hVCard, lpRead, 1, &cbRead)) {
  2371. goto exit;
  2372. }
  2373. if (! cbRead) {
  2374. // End of file
  2375. *lpRead = '\0'; // eol
  2376. goto exit;
  2377. } else {
  2378. // Assert(cbRead == 1);
  2379. ch = *lpRead;
  2380. switch (ch) {
  2381. case '\r': // These are ignored
  2382. break;
  2383. case '\n': // Linefeed terminates string
  2384. *lpRead = '\0'; // eol
  2385. break;
  2386. default: // All other characters are added to string
  2387. cbItem += cbRead;
  2388. if (cbItem >= cbBuffer) {
  2389. // Time to grow the buffer
  2390. cbBuffer += READ_BUFFER_GROW;
  2391. lpBufferTemp = (LPSTR)LocalReAlloc(lpBuffer, cbBuffer, LMEM_MOVEABLE | LMEM_ZEROINIT);
  2392. if (!lpBufferTemp) {
  2393. DebugTrace( TEXT("ReadLn:LocalReAlloc(%u) -> %u\n"), cbBuffer, GetLastError());
  2394. hResult = E_OUTOFMEMORY;
  2395. goto exit;
  2396. }
  2397. else
  2398. {
  2399. lpBuffer = lpBufferTemp;
  2400. }
  2401. lpRead = lpBuffer + cbItem;
  2402. } else {
  2403. lpRead++;
  2404. }
  2405. break;
  2406. }
  2407. }
  2408. } while (ch != '\n');
  2409. exit:
  2410. *lppLine = &lpBuffer[cbStart];
  2411. if (hResult || cbItem == 0) {
  2412. LocalFreeAndNull(&lpBuffer);
  2413. cbItem = 0;
  2414. lpBuffer = NULL;
  2415. } else {
  2416. // If we didn't read anything more, we should return NULL in lppLine.
  2417. if (cbItem == cbStart) {
  2418. *lppLine = NULL;
  2419. } else {
  2420. // DebugTrace( TEXT("ReadLn: \")%s\ TEXT("\n"), *lppLine);
  2421. }
  2422. }
  2423. *lpcbItem = cbItem;
  2424. *lppBuffer = lpBuffer;
  2425. *lpcbBuffer = cbBuffer;
  2426. return(hResult);
  2427. }
  2428. /***************************************************************************
  2429. Name : FindSubstringBefore
  2430. Purpose : Find a substring before a particular character
  2431. Parameters: lpString = full string
  2432. lpSubstring = search string
  2433. chBefore = character to terminate search
  2434. Returns : pointer to substring or NULL if not found
  2435. Comment :
  2436. ***************************************************************************/
  2437. LPSTR FindSubstringBefore(LPSTR lpString, LPSTR lpSubstring, char chBefore) {
  2438. ULONG cbSubstring = lstrlenA(lpSubstring);
  2439. register ULONG i;
  2440. BOOL fFound = FALSE;
  2441. char szU[MAX_PATH];
  2442. char szL[MAX_PATH];
  2443. StrCpyNA(szU, lpSubstring, ARRAYSIZE(szU));
  2444. StrCpyNA(szL, lpSubstring, ARRAYSIZE(szL));
  2445. CharUpperA(szU);
  2446. CharLowerA(szL);
  2447. while (*lpString && *lpString != chBefore) {
  2448. for (i = 0; i < cbSubstring; i++) {
  2449. if (lpString[i] != szU[i] && lpString[i] != szL[i]) {
  2450. goto nomatch;
  2451. }
  2452. }
  2453. return(lpString);
  2454. nomatch:
  2455. lpString++;
  2456. }
  2457. return(NULL);
  2458. }
  2459. /***************************************************************************
  2460. Name : ReadVCardItem
  2461. Purpose : Read the next VCard item
  2462. Parameters: handle = open file handle
  2463. ReadFn = function to read from handle
  2464. lppBuffer -> returned buffer containing the item. Caller must
  2465. LocalFree this buffer. (on input, if this is non-NULL,
  2466. the existing buffer should be used.)
  2467. lpcbBuffer -> returned size of buffer. If zero, there is no
  2468. more data.
  2469. Returns : hResult: 0 on no error (recognized)
  2470. Comment : Reads a vCard item from the handle, discarding any carriage return
  2471. characters and empty lines. Will not overwrite buffer, and
  2472. will always terminate the string with a null. Trims trailing
  2473. white space.
  2474. ***************************************************************************/
  2475. HRESULT ReadVCardItem(HANDLE hVCard, VCARD_READ ReadFn, LPSTR * lppBuffer, LPULONG lpcbBuffer) {
  2476. HRESULT hResult;
  2477. LPSTR lpLine = NULL;
  2478. LPSTR lpBuffer = NULL;
  2479. ULONG cbBuffer = 0;
  2480. ULONG cbItem = 0;
  2481. BOOL fDone = FALSE;
  2482. BOOL fQuotedPrintable = FALSE;
  2483. BOOL fBase64 = FALSE;
  2484. BOOL fFirst = TRUE;
  2485. ULONG cbStart;
  2486. while (! fDone) {
  2487. cbStart = cbItem;
  2488. if (hResult = ReadLn(hVCard, ReadFn, &lpLine, &cbItem, &lpBuffer, &cbBuffer)) {
  2489. if (HR_FAILED(hResult)) {
  2490. DebugTrace( TEXT("ReadVCardItem: ReadLn -> %x\n"), GetScode(hResult));
  2491. } else if (GetScode(hResult) == WAB_W_END_OF_DATA) {
  2492. // EOF
  2493. // all
  2494. }
  2495. fDone = TRUE;
  2496. } else {
  2497. if (lpBuffer) {
  2498. // Do we need to read more data?
  2499. // Look for the following
  2500. if (fFirst) {
  2501. // look for the data type indications in the first line of the item.
  2502. fQuotedPrintable = FindSubstringBefore(lpBuffer, (LPSTR)vceTable[VCARD_ENCODING_QUOTED_PRINTABLE], ':') ? TRUE : FALSE;
  2503. fBase64 = FindSubstringBefore(lpBuffer, (LPSTR)vceTable[VCARD_ENCODING_BASE64], ':') ? TRUE : FALSE;
  2504. fFirst = FALSE;
  2505. }
  2506. if (fQuotedPrintable) {
  2507. // watch for soft line breaks (= before CRLF)
  2508. if (lpBuffer[cbItem - 1] == '=') {
  2509. // overwrite the soft break character
  2510. cbItem--;
  2511. lpBuffer[cbItem] = '\0';
  2512. } else {
  2513. fDone = TRUE;
  2514. }
  2515. } else if (fBase64) {
  2516. // looking for empty line
  2517. if (cbStart == cbItem) {
  2518. fDone = TRUE;
  2519. }
  2520. } else {
  2521. fDone = TRUE;
  2522. }
  2523. } else {
  2524. // BUG Fix - if we set fDone to true here, we will exit out of our
  2525. // vCard reading loop. lpBuffer can also be NULL because the
  2526. // vCard contained blank lines. Better we dont set fDone here.
  2527. //fDone = TRUE;
  2528. }
  2529. }
  2530. }
  2531. if (! HR_FAILED(hResult)) {
  2532. *lppBuffer = lpBuffer;
  2533. if (lpBuffer) {
  2534. TrimTrailingWhiteSpace(lpBuffer);
  2535. }
  2536. }
  2537. return(hResult);
  2538. }
  2539. enum {
  2540. ivcPR_GENERATION,
  2541. ivcPR_GIVEN_NAME,
  2542. ivcPR_SURNAME,
  2543. ivcPR_NICKNAME,
  2544. ivcPR_BUSINESS_TELEPHONE_NUMBER,
  2545. ivcPR_HOME_TELEPHONE_NUMBER,
  2546. ivcPR_LANGUAGE,
  2547. ivcPR_POSTAL_ADDRESS,
  2548. ivcPR_COMPANY_NAME,
  2549. ivcPR_TITLE,
  2550. ivcPR_DEPARTMENT_NAME,
  2551. ivcPR_OFFICE_LOCATION,
  2552. ivcPR_BUSINESS2_TELEPHONE_NUMBER,
  2553. ivcPR_CELLULAR_TELEPHONE_NUMBER,
  2554. ivcPR_RADIO_TELEPHONE_NUMBER,
  2555. ivcPR_CAR_TELEPHONE_NUMBER,
  2556. ivcPR_OTHER_TELEPHONE_NUMBER,
  2557. ivcPR_DISPLAY_NAME,
  2558. ivcPR_PAGER_TELEPHONE_NUMBER,
  2559. ivcPR_BUSINESS_FAX_NUMBER,
  2560. ivcPR_HOME_FAX_NUMBER,
  2561. ivcPR_TELEX_NUMBER,
  2562. ivcPR_ISDN_NUMBER,
  2563. ivcPR_HOME2_TELEPHONE_NUMBER,
  2564. ivcPR_MIDDLE_NAME,
  2565. ivcPR_PERSONAL_HOME_PAGE,
  2566. ivcPR_BUSINESS_HOME_PAGE,
  2567. ivcPR_HOME_ADDRESS_CITY,
  2568. ivcPR_HOME_ADDRESS_COUNTRY,
  2569. ivcPR_HOME_ADDRESS_POSTAL_CODE,
  2570. ivcPR_HOME_ADDRESS_STATE_OR_PROVINCE,
  2571. ivcPR_HOME_ADDRESS_STREET,
  2572. ivcPR_HOME_ADDRESS_POST_OFFICE_BOX,
  2573. ivcPR_POST_OFFICE_BOX,
  2574. ivcPR_BUSINESS_ADDRESS_CITY,
  2575. ivcPR_BUSINESS_ADDRESS_COUNTRY,
  2576. ivcPR_BUSINESS_ADDRESS_POSTAL_CODE,
  2577. ivcPR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  2578. ivcPR_BUSINESS_ADDRESS_STREET,
  2579. ivcPR_COMMENT,
  2580. ivcPR_EMAIL_ADDRESS,
  2581. ivcPR_ADDRTYPE,
  2582. ivcPR_CONTACT_ADDRTYPES,
  2583. ivcPR_CONTACT_DEFAULT_ADDRESS_INDEX,
  2584. ivcPR_CONTACT_EMAIL_ADDRESSES,
  2585. ivcPR_PROFESSION,
  2586. ivcPR_BIRTHDAY,
  2587. ivcPR_PRIMARY_TELEPHONE_NUMBER,
  2588. ivcPR_OTHER_ADDRESS_CITY,
  2589. ivcPR_OTHER_ADDRESS_COUNTRY,
  2590. ivcPR_OTHER_ADDRESS_POSTAL_CODE,
  2591. ivcPR_OTHER_ADDRESS_STATE_OR_PROVINCE,
  2592. ivcPR_OTHER_ADDRESS_STREET,
  2593. ivcPR_OTHER_ADDRESS_POST_OFFICE_BOX,
  2594. ivcPR_DISPLAY_NAME_PREFIX,
  2595. ivcPR_USER_X509_CERTIFICATE,
  2596. ivcPR_GENDER,
  2597. ivcMax
  2598. };
  2599. const SizedSPropTagArray(ivcMax, tagaVCard) = {
  2600. ivcMax,
  2601. {
  2602. PR_GENERATION,
  2603. PR_GIVEN_NAME,
  2604. PR_SURNAME,
  2605. PR_NICKNAME,
  2606. PR_BUSINESS_TELEPHONE_NUMBER,
  2607. PR_HOME_TELEPHONE_NUMBER,
  2608. PR_LANGUAGE,
  2609. PR_POSTAL_ADDRESS,
  2610. PR_COMPANY_NAME,
  2611. PR_TITLE,
  2612. PR_DEPARTMENT_NAME,
  2613. PR_OFFICE_LOCATION,
  2614. PR_BUSINESS2_TELEPHONE_NUMBER,
  2615. PR_CELLULAR_TELEPHONE_NUMBER,
  2616. PR_RADIO_TELEPHONE_NUMBER,
  2617. PR_CAR_TELEPHONE_NUMBER,
  2618. PR_OTHER_TELEPHONE_NUMBER,
  2619. PR_DISPLAY_NAME,
  2620. PR_PAGER_TELEPHONE_NUMBER,
  2621. PR_BUSINESS_FAX_NUMBER,
  2622. PR_HOME_FAX_NUMBER,
  2623. PR_TELEX_NUMBER,
  2624. PR_ISDN_NUMBER,
  2625. PR_HOME2_TELEPHONE_NUMBER,
  2626. PR_MIDDLE_NAME,
  2627. PR_PERSONAL_HOME_PAGE,
  2628. PR_BUSINESS_HOME_PAGE,
  2629. PR_HOME_ADDRESS_CITY,
  2630. PR_HOME_ADDRESS_COUNTRY,
  2631. PR_HOME_ADDRESS_POSTAL_CODE,
  2632. PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  2633. PR_HOME_ADDRESS_STREET,
  2634. PR_HOME_ADDRESS_POST_OFFICE_BOX,
  2635. PR_POST_OFFICE_BOX,
  2636. PR_BUSINESS_ADDRESS_CITY,
  2637. PR_BUSINESS_ADDRESS_COUNTRY,
  2638. PR_BUSINESS_ADDRESS_POSTAL_CODE,
  2639. PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE,
  2640. PR_BUSINESS_ADDRESS_STREET,
  2641. PR_COMMENT,
  2642. PR_EMAIL_ADDRESS,
  2643. PR_ADDRTYPE,
  2644. PR_CONTACT_ADDRTYPES,
  2645. PR_CONTACT_DEFAULT_ADDRESS_INDEX,
  2646. PR_CONTACT_EMAIL_ADDRESSES,
  2647. PR_PROFESSION,
  2648. PR_BIRTHDAY,
  2649. PR_PRIMARY_TELEPHONE_NUMBER,
  2650. PR_OTHER_ADDRESS_CITY,
  2651. PR_OTHER_ADDRESS_COUNTRY,
  2652. PR_OTHER_ADDRESS_POSTAL_CODE,
  2653. PR_OTHER_ADDRESS_STATE_OR_PROVINCE,
  2654. PR_OTHER_ADDRESS_STREET,
  2655. PR_OTHER_ADDRESS_POST_OFFICE_BOX,
  2656. PR_DISPLAY_NAME_PREFIX,
  2657. PR_USER_X509_CERTIFICATE,
  2658. PR_GENDER
  2659. }
  2660. };
  2661. HRESULT WriteOrExit(HANDLE hVCard, LPTSTR lpsz, VCARD_WRITE WriteFn)
  2662. {
  2663. LPSTR lpszA = NULL;
  2664. HRESULT hr = S_OK;
  2665. lpszA = ConvertWtoA(lpsz);
  2666. hr = WriteFn(hVCard, lpszA, lstrlenA(lpszA), NULL);
  2667. LocalFreeAndNull(&lpszA);
  2668. return hr;
  2669. }
  2670. #define WRITE_OR_EXITW(string) {\
  2671. if (hResult = WriteOrExit(hVCard, string, WriteFn)) \
  2672. goto exit; \
  2673. }
  2674. #define WRITE_OR_EXIT(string) {\
  2675. if (hResult = WriteFn(hVCard, string, lstrlenA(string), NULL)) \
  2676. goto exit; \
  2677. }
  2678. HRESULT WriteValueOrExit(HANDLE hVCard, VCARD_WRITE WriteFn, LPBYTE data, ULONG size)
  2679. {
  2680. LPSTR lpszA = NULL;
  2681. HRESULT hr = S_OK;
  2682. if(!size)
  2683. lpszA = ConvertWtoA((LPTSTR)data);
  2684. hr = WriteVCardValue(hVCard, WriteFn, lpszA ? (LPBYTE)lpszA : data, size);
  2685. LocalFreeAndNull(&lpszA);
  2686. return hr;
  2687. }
  2688. #define WRITE_VALUE_OR_EXITW(data, size) {\
  2689. if (hResult = WriteValueOrExit(hVCard, WriteFn, (LPBYTE)data, size)) {\
  2690. goto exit;\
  2691. }\
  2692. }
  2693. #define WRITE_VALUE_OR_EXIT(data, size) {\
  2694. if (hResult = WriteVCardValue(hVCard, WriteFn, (LPBYTE)data, size)) {\
  2695. goto exit;\
  2696. }\
  2697. }
  2698. /***************************************************************************
  2699. Name : EncodeQuotedPrintable
  2700. Purpose : Encodes QUOTED_PRINTABLE
  2701. Parameters: lpBuffer -> input buffer
  2702. Returns : encoded string buffer (must be LocalFree'd by caller)
  2703. Comment :
  2704. ***************************************************************************/
  2705. #define QUOTED_PRINTABLE_MAX_LINE 76
  2706. #define QP_LOWRANGE_MIN ' '
  2707. #define QP_LOWRANGE_MAX '<'
  2708. #define QP_HIGHRANGE_MIN '>'
  2709. #define QP_HIGHRANGE_MAX '~'
  2710. LPSTR EncodeQuotedPrintable(LPBYTE lpInput) {
  2711. LPSTR lpBuffer = NULL;
  2712. register LPBYTE lpTempIn = lpInput;
  2713. register LPSTR lpTempOut;
  2714. ULONG cbBuffer = 0;
  2715. ULONG cbLine;
  2716. BYTE bOut;
  2717. char ch;
  2718. // How big must the buffer be?
  2719. cbLine = 0;
  2720. while (ch = *lpTempIn++) {
  2721. if (ch == '\t' || (ch >= QP_LOWRANGE_MIN && ch <= QP_LOWRANGE_MAX) ||
  2722. (ch >= QP_HIGHRANGE_MIN && ch <= QP_HIGHRANGE_MAX)) {
  2723. cbBuffer++;
  2724. cbLine++;
  2725. if (cbLine >= (QUOTED_PRINTABLE_MAX_LINE)) {
  2726. // 1 chars would overshoot max, wrap here
  2727. cbLine = 0;
  2728. cbBuffer += 3;
  2729. }
  2730. } else {
  2731. if (cbLine >= (QUOTED_PRINTABLE_MAX_LINE - 3)) {
  2732. // 3 chars would overshoot max, wrap here
  2733. cbLine = 0;
  2734. cbBuffer += 3;
  2735. }
  2736. cbLine += 3;
  2737. cbBuffer += 3; // TEXT("=xx")
  2738. }
  2739. }
  2740. // BUGBUG: Should handle terminating spaces
  2741. if (cbBuffer) {
  2742. cbBuffer++; // Room for terminator
  2743. if (lpBuffer = LocalAlloc(LPTR, sizeof(TCHAR)*cbBuffer)) {
  2744. lpTempIn = lpInput;
  2745. lpTempOut = lpBuffer;
  2746. cbLine = 0;
  2747. while (ch = *lpTempIn++) {
  2748. if (ch == '\t' || (ch >= QP_LOWRANGE_MIN && ch <= QP_LOWRANGE_MAX) ||
  2749. (ch >= QP_HIGHRANGE_MIN && ch <= QP_HIGHRANGE_MAX)) {
  2750. if (cbLine >= QUOTED_PRINTABLE_MAX_LINE) {
  2751. // char would overshoot max, wrap here
  2752. *(lpTempOut++) = '=';
  2753. *(lpTempOut++) = '\r';
  2754. *(lpTempOut++) = '\n';
  2755. cbLine = 0;
  2756. }
  2757. *(lpTempOut++) = ch;
  2758. cbLine++;
  2759. } else {
  2760. if (cbLine >= (QUOTED_PRINTABLE_MAX_LINE - 3)) {
  2761. // 3 chars would overshoot max, wrap here
  2762. *(lpTempOut++) = '=';
  2763. *(lpTempOut++) = '\r';
  2764. *(lpTempOut++) = '\n';
  2765. cbLine = 0;
  2766. }
  2767. *(lpTempOut++) = '=';
  2768. if ((bOut = ((ch & 0xF0) >> 4)) > 9) {
  2769. *(lpTempOut++) = bOut + ('A' - 10);
  2770. } else {
  2771. *(lpTempOut++) = bOut + '0';
  2772. }
  2773. if ((bOut = ch & 0x0F) > 9) {
  2774. *(lpTempOut++) = bOut + ('A' - 10);
  2775. } else {
  2776. *(lpTempOut++) = bOut + '0';
  2777. }
  2778. cbLine += 3;
  2779. }
  2780. }
  2781. *lpTempOut = '\0'; // terminate the string
  2782. } // else fail
  2783. }
  2784. return(lpBuffer);
  2785. }
  2786. /***************************************************************************
  2787. Name : EncodeBase64
  2788. Purpose : Encodes BASE64
  2789. Parameters: lpBuffer -> input buffer
  2790. cbBuffer = size of input buffer
  2791. lpcbReturn -> returned size of output buffer
  2792. Returns : encoded string buffer (must be LocalFree'd by caller)
  2793. Comment :
  2794. ***************************************************************************/
  2795. #define BASE64_MAX_LINE 76
  2796. LPSTR EncodeBase64(LPBYTE lpInput, ULONG cbBuffer, LPULONG lpcbReturn) {
  2797. //#ifdef NEW_STUFF
  2798. LPSTR lpBuffer = NULL;
  2799. PUCHAR outptr;
  2800. UINT i, cExtras;
  2801. UINT j, cCount, nBreakPt = ( (BASE64_MAX_LINE/4) - 1 ); // 72 encoded chars per line plus 4 spaces makes 76
  2802. // = (76 - 4)/ 4 for num of non space lines with 4 encoded characters per 3 data chars
  2803. CONST CHAR * rgchDict = six2base64;
  2804. // 4 spaces and 2 chars = 6 for new line
  2805. cExtras = 6 * ((cbBuffer / BASE64_MAX_LINE) + 2); // want to add newline at beginning and end
  2806. lpBuffer = LocalAlloc( LMEM_ZEROINIT, sizeof( TCHAR ) * (3 * cbBuffer + cExtras));
  2807. if (!lpBuffer)
  2808. return NULL;
  2809. // need to add a new line every 76 characters...
  2810. outptr = (UCHAR *)lpBuffer;
  2811. cCount = 0;
  2812. for (i=0; i < cbBuffer; i += 3)
  2813. {// want it to start on next line from tag anyways so it is okay when i=0
  2814. if( cCount++ % nBreakPt == 0 )
  2815. {
  2816. *(outptr++) = (CHAR)(13);
  2817. *(outptr++) = (CHAR)(10);
  2818. // then 4 spaces
  2819. for( j = 0; j < 4; j++)
  2820. *(outptr++) = ' ';
  2821. }
  2822. *(outptr++) = rgchDict[*lpInput >> 2]; /* c1 */
  2823. *(outptr++) = rgchDict[((*lpInput << 4) & 060) | ((lpInput[1] >> 4) & 017)]; /*c2*/
  2824. *(outptr++) = rgchDict[((lpInput[1] << 2) & 074) | ((lpInput[2] >> 6) & 03)];/*c3*/
  2825. *(outptr++) = rgchDict[lpInput[2] & 077]; /* c4 */
  2826. lpInput += 3;
  2827. }
  2828. /* If cbBuffer was not a multiple of 3, then we have encoded too
  2829. * many characters. Adjust appropriately.
  2830. */
  2831. if(i == cbBuffer+1) {
  2832. /* There were only 2 bytes in that last group */
  2833. outptr[-1] = '=';
  2834. } else if(i == cbBuffer+2) {
  2835. /* There was only 1 byte in that last group */
  2836. outptr[-1] = '=';
  2837. outptr[-2] = '=';
  2838. }
  2839. cCount = ((cCount - 1) % nBreakPt != 0) ? 2 : 1; // prevent an extra newline
  2840. for ( i = 0; i < cCount; i++)
  2841. {
  2842. *(outptr++) = (CHAR)(13);
  2843. *(outptr++) = (CHAR)(10);
  2844. }
  2845. *outptr = '\0';
  2846. return lpBuffer;
  2847. }
  2848. /***************************************************************************
  2849. Name : WriteVCardValue
  2850. Purpose : Encode and write the value of a vCard item.
  2851. Parameters: hVCard = open handle to empty VCard file
  2852. WriteFn = Write function to write hVCard
  2853. lpData -> data to be written
  2854. cbData = length of data (or 0 if null-terminated string data)
  2855. Returns : HRESULT
  2856. Comment : Assumes that the Key and any parameters have been written,
  2857. and we are ready for a ':' and some value data.
  2858. ***************************************************************************/
  2859. HRESULT WriteVCardValue(HANDLE hVCard, VCARD_WRITE WriteFn, LPBYTE lpData,
  2860. ULONG cbData) {
  2861. HRESULT hResult = hrSuccess;
  2862. register LPSTR lpTemp = (LPSTR)lpData;
  2863. BOOL fBase64 = FALSE, fQuotedPrintable = FALSE;
  2864. LPSTR lpBuffer = NULL;
  2865. register TCHAR ch;
  2866. if (cbData) {
  2867. // Binary data, use BASE64 encoding
  2868. fBase64 = TRUE;
  2869. // Mark it as BASE64
  2870. WRITE_OR_EXITW(szSemicolon);
  2871. WRITE_OR_EXIT(vcpTable[VCARD_PARAM_ENCODING]);
  2872. WRITE_OR_EXIT(szEquals);
  2873. WRITE_OR_EXIT(vceTable[VCARD_ENCODING_BASE64]);
  2874. lpBuffer = EncodeBase64(lpData, cbData, &cbData);
  2875. } else {
  2876. // Text data, do we need to encode?
  2877. while (ch = *lpTemp++) {
  2878. // If there are characters with the high bit set or control characters,
  2879. // then we must use QUOTED_PRINTABLE
  2880. /* New vCard draft says default type is 8 bit so we should allow non-ASCII chars
  2881. Some confusion about charsets if we need to fill that data in and also if we
  2882. need to covert the current language to UTF-8
  2883. if (ch > 0x7f) { // high bits set. Not ASCII!
  2884. DebugTrace( TEXT("WriteVCardValue found non-ASCII data\n"));
  2885. hResult = ResultFromScode(WAB_E_VCARD_NOT_ASCII);
  2886. goto exit;
  2887. }
  2888. */
  2889. if (ch < 0x20) {
  2890. fQuotedPrintable = TRUE;
  2891. // Mark it as QUOTED_PRINTABLE
  2892. WRITE_OR_EXITW(szSemicolon);
  2893. WRITE_OR_EXIT(vcpTable[VCARD_PARAM_ENCODING]);
  2894. WRITE_OR_EXIT(szEquals);
  2895. WRITE_OR_EXIT(vceTable[VCARD_ENCODING_QUOTED_PRINTABLE]);
  2896. lpBuffer = EncodeQuotedPrintable(lpData);
  2897. break;
  2898. }
  2899. }
  2900. }
  2901. WRITE_OR_EXIT(szColonA);
  2902. WRITE_OR_EXIT(lpBuffer ? lpBuffer : lpData);
  2903. WRITE_OR_EXIT(szCRLFA);
  2904. exit:
  2905. if( lpBuffer)
  2906. LocalFree(lpBuffer);
  2907. return(hResult);
  2908. }
  2909. /***************************************************************************
  2910. Name: bIsValidStrProp
  2911. Purpose: Checks if this is a valid string prop not an empty string
  2912. (Outlook sometimes feeds us blank strings which we print out
  2913. and then other apps go and die ..
  2914. *****************************************************************************/
  2915. BOOL bIsValidStrProp(SPropValue spv)
  2916. {
  2917. return (!PROP_ERROR(spv) && spv.Value.LPSZ && lstrlen(spv.Value.LPSZ));
  2918. }
  2919. /***************************************************************************
  2920. Name : WriteVCardTel
  2921. Purpose : Writes a vCard Telephone entry
  2922. Parameters: hVCard = open handle to empty VCard file
  2923. WriteFn = Write function to write hVCard
  2924. fPref = TRUE if prefered phone number
  2925. fBusiness = TRUE if a work number
  2926. fHome = TRUE if a home number
  2927. fVoice = TRUE if a voice number
  2928. fFax = TRUE if a fax number
  2929. fISDN = TRUE if an ISDN number
  2930. fCell = TRUE if a cellular number
  2931. fPager = TRUE if a pager number
  2932. fCar = TRUE if a car phone
  2933. Returns : HRESULT
  2934. Comment :
  2935. ***************************************************************************/
  2936. HRESULT WriteVCardTel(HANDLE hVCard, VCARD_WRITE WriteFn,
  2937. SPropValue spv,
  2938. BOOL fPref,
  2939. BOOL fBusiness,
  2940. BOOL fHome,
  2941. BOOL fVoice,
  2942. BOOL fFax,
  2943. BOOL fISDN,
  2944. BOOL fCell,
  2945. BOOL fPager,
  2946. BOOL fCar) {
  2947. HRESULT hResult = hrSuccess;
  2948. if (!bIsValidStrProp(spv))
  2949. return hResult;
  2950. if (! PROP_ERROR(spv)) {
  2951. WRITE_OR_EXIT(vckTable[VCARD_KEY_TEL]);
  2952. if (fPref) {
  2953. WRITE_OR_EXITW(szSemicolon);
  2954. WRITE_OR_EXIT(vctTable[VCARD_TYPE_PREF]);
  2955. }
  2956. if (fBusiness) {
  2957. WRITE_OR_EXITW(szSemicolon);
  2958. WRITE_OR_EXIT(vctTable[VCARD_TYPE_WORK]);
  2959. }
  2960. if (fHome) {
  2961. WRITE_OR_EXITW(szSemicolon);
  2962. WRITE_OR_EXIT(vctTable[VCARD_TYPE_HOME]);
  2963. }
  2964. if (fFax) {
  2965. WRITE_OR_EXITW(szSemicolon);
  2966. WRITE_OR_EXIT(vctTable[VCARD_TYPE_FAX]);
  2967. }
  2968. if (fCell) {
  2969. WRITE_OR_EXITW(szSemicolon);
  2970. WRITE_OR_EXIT(vctTable[VCARD_TYPE_CELL]);
  2971. }
  2972. if (fCar) {
  2973. WRITE_OR_EXITW(szSemicolon);
  2974. WRITE_OR_EXIT(vctTable[VCARD_TYPE_CAR]);
  2975. }
  2976. if (fPager) {
  2977. WRITE_OR_EXITW(szSemicolon);
  2978. WRITE_OR_EXIT(vctTable[VCARD_TYPE_PAGER]);
  2979. }
  2980. if (fISDN) {
  2981. WRITE_OR_EXITW(szSemicolon);
  2982. WRITE_OR_EXIT(vctTable[VCARD_TYPE_ISDN]);
  2983. }
  2984. if (fVoice) {
  2985. WRITE_OR_EXITW(szSemicolon);
  2986. WRITE_OR_EXIT(vctTable[VCARD_TYPE_VOICE]);
  2987. }
  2988. WRITE_VALUE_OR_EXITW(spv.Value.LPSZ, 0);
  2989. }
  2990. exit:
  2991. return(hResult);
  2992. }
  2993. /***************************************************************************
  2994. Name : WriteVCardEmail
  2995. Purpose : Writes a vCard Email entry
  2996. Parameters: hVCard = open handle to empty VCard file
  2997. WriteFn = Write function to write hVCard
  2998. lpEmailAddress -> Email address
  2999. lpAddrType -> Addrtype or NULL (Default is SMTP)
  3000. fDefault = TRUE if this is the preferred email address
  3001. Returns : HRESULT
  3002. Comment :
  3003. ***************************************************************************/
  3004. HRESULT WriteVCardEmail(HANDLE hVCard, VCARD_WRITE WriteFn, LPTSTR lpEmailAddress,
  3005. LPTSTR lpAddrType, BOOL fDefault) {
  3006. HRESULT hResult = hrSuccess;
  3007. if (lpEmailAddress && lstrlen(lpEmailAddress)) {
  3008. WRITE_OR_EXIT(vckTable[VCARD_KEY_EMAIL]);
  3009. WRITE_OR_EXITW(szSemicolon);
  3010. if (fDefault) {
  3011. WRITE_OR_EXIT(vctTable[VCARD_TYPE_PREF]);
  3012. WRITE_OR_EXITW(szSemicolon);
  3013. }
  3014. if (lpAddrType && lstrlen(lpAddrType)) {
  3015. if (! lstrcmpi(lpAddrType, szSMTP)) {
  3016. WRITE_OR_EXIT(vctTable[VCARD_TYPE_INTERNET]);
  3017. } else if (! lstrcmpi(lpAddrType, szX400)) {
  3018. WRITE_OR_EXIT(vctTable[VCARD_TYPE_X400]);
  3019. } else {
  3020. // BUGBUG: This is questionable... we should stick to
  3021. // the spec defined types, but what if they don't match?
  3022. // Maybe I should ignore the type in that case.
  3023. WRITE_OR_EXITW(lpAddrType);
  3024. }
  3025. } else {
  3026. // Assume SMTP
  3027. WRITE_OR_EXIT(vctTable[VCARD_TYPE_INTERNET]);
  3028. }
  3029. WRITE_VALUE_OR_EXITW(lpEmailAddress, 0);
  3030. }
  3031. exit:
  3032. return(hResult);
  3033. }
  3034. /***************************************************************************
  3035. Name : PropLength
  3036. Purpose : string length of string property
  3037. Parameters: spv = SPropValue
  3038. lppString -> return pointer to string value or NULL
  3039. Returns : size of string (not including null)
  3040. Comment :
  3041. ***************************************************************************/
  3042. ULONG PropLength(SPropValue spv, LPTSTR * lppString) {
  3043. ULONG cbRet = 0;
  3044. if (! PROP_ERROR(spv) && spv.Value.LPSZ && lstrlen(spv.Value.LPSZ))
  3045. {
  3046. *lppString = spv.Value.LPSZ;
  3047. cbRet = sizeof(TCHAR)*lstrlen(*lppString);
  3048. } else
  3049. {
  3050. *lppString = NULL;
  3051. }
  3052. return(cbRet);
  3053. }
  3054. /***************************************************************************
  3055. Name : WriteVCard
  3056. Purpose : Writes a vCard to a file from a MAILUSER object.
  3057. Parameters: hVCard = open handle to empty VCard file
  3058. WriteFn = Write function to write hVCard
  3059. lpMailUser -> open mailuser object
  3060. Returns : HRESULT
  3061. Comment :
  3062. ***************************************************************************/
  3063. HRESULT WriteVCard(HANDLE hVCard, VCARD_WRITE WriteFn, LPMAILUSER lpMailUser) {
  3064. HRESULT hResult = hrSuccess;
  3065. ULONG ulcValues;
  3066. LPSPropValue lpspv = NULL,
  3067. lpspvAW = NULL;
  3068. ULONG i;
  3069. LPTSTR lpTemp = NULL;
  3070. ULONG cbTemp = 0;
  3071. LPTSTR lpSurname, lpGivenName, lpMiddleName, lpGeneration, lpPrefix;
  3072. ULONG cbSurname, cbGivenName, cbMiddleName, cbGeneration, cbPrefix;
  3073. LPTSTR lpCompanyName, lpDepartmentName;
  3074. LPTSTR lpPOBox, lpOffice, lpStreet, lpCity, lpState, lpPostalCode, lpCountry;
  3075. LPTSTR lpEmailAddress, lpAddrType;
  3076. ULONG iDefaultEmail;
  3077. LPEXTVCARDPROP lpList = NULL;
  3078. LPBYTE lpDataBuffer = NULL;
  3079. LPCERT_DISPLAY_INFO lpCDI = NULL, lpCDITemp = NULL;
  3080. // See if there are any named props we need to export
  3081. //
  3082. HrGetExtVCardPropList(lpMailUser, &lpList);
  3083. // Get the interesting properties from the MailUser object
  3084. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  3085. (LPSPropTagArray)&tagaVCard,
  3086. MAPI_UNICODE, // flags
  3087. &ulcValues,
  3088. &lpspv)))
  3089. {
  3090. // @hack [bobn] {IE5-Raid 90265} Outlook cannot handle MAPI_UNICODE on Win9x
  3091. // lets try not asking for unicode and converting...
  3092. if(HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  3093. (LPSPropTagArray)&tagaVCard,
  3094. 0, // flags
  3095. &ulcValues,
  3096. &lpspv)))
  3097. {
  3098. DebugTrace( TEXT("WriteVCard:GetProps -> %x\n"), GetScode(hResult));
  3099. goto exit;
  3100. }
  3101. if(HR_FAILED(hResult = HrDupeOlkPropsAtoWC(ulcValues, lpspv, &lpspvAW)))
  3102. goto exit;
  3103. FreeBufferAndNull(&lpspv);
  3104. lpspv = lpspvAW;
  3105. }
  3106. if (ulcValues) {
  3107. WRITE_OR_EXIT(vckTable[VCARD_KEY_BEGIN]);
  3108. WRITE_VALUE_OR_EXIT(vckTable[VCARD_KEY_VCARD], 0);
  3109. WRITE_OR_EXIT(vckTable[VCARD_KEY_VERSION]);
  3110. WRITE_VALUE_OR_EXIT(CURRENT_VCARD_VERSION, 0);
  3111. //
  3112. // Required props
  3113. //
  3114. //
  3115. // Name
  3116. //
  3117. // Make sure we have a name.
  3118. // If there is no FML, create them from DN. If no DN, fail.
  3119. cbSurname = PropLength(lpspv[ivcPR_SURNAME], &lpSurname);
  3120. cbGivenName = PropLength(lpspv[ivcPR_GIVEN_NAME], &lpGivenName);
  3121. cbMiddleName = PropLength(lpspv[ivcPR_MIDDLE_NAME], &lpMiddleName);
  3122. cbGeneration = PropLength(lpspv[ivcPR_GENERATION], &lpGeneration);
  3123. cbPrefix = PropLength(lpspv[ivcPR_DISPLAY_NAME_PREFIX], &lpPrefix);
  3124. if (! lpSurname && ! lpGivenName && ! lpMiddleName) {
  3125. // No FML, create them from DN.
  3126. ParseDisplayName(
  3127. lpspv[ivcPR_DISPLAY_NAME].Value.LPSZ,
  3128. &lpGivenName,
  3129. &lpSurname,
  3130. lpspv, // lpvRoot
  3131. NULL); // lppLocalFree
  3132. cbGivenName = lstrlen(lpGivenName);
  3133. cbSurname = lstrlen(lpSurname);
  3134. }
  3135. cbTemp = 0;
  3136. cbTemp += cbSurname;
  3137. cbTemp++; // ';'
  3138. cbTemp += cbGivenName;
  3139. cbTemp++; // ';'
  3140. cbTemp += cbMiddleName;
  3141. cbTemp++; // ';'
  3142. cbTemp += cbPrefix;
  3143. cbTemp++; // ';'
  3144. cbTemp += cbGeneration;
  3145. cbTemp++;
  3146. if (! (lpSurname || lpGivenName || lpMiddleName)) {
  3147. hResult = ResultFromScode(MAPI_E_MISSING_REQUIRED_COLUMN);
  3148. goto exit;
  3149. }
  3150. if (! (lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*cbTemp))) {
  3151. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3152. goto exit;
  3153. }
  3154. *lpTemp = '\0';
  3155. if (lpSurname) {
  3156. StrCatBuff(lpTemp, lpSurname, cbTemp);
  3157. }
  3158. if (lpGivenName || lpMiddleName || lpPrefix || lpGeneration) {
  3159. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3160. }
  3161. if (lpGivenName) {
  3162. StrCatBuff(lpTemp, lpGivenName, cbTemp);
  3163. }
  3164. if (lpMiddleName || lpPrefix || lpGeneration) {
  3165. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3166. }
  3167. if (lpMiddleName) {
  3168. StrCatBuff(lpTemp, lpMiddleName, cbTemp);
  3169. }
  3170. if (lpPrefix || lpGeneration) {
  3171. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3172. }
  3173. if (lpPrefix) {
  3174. StrCatBuff(lpTemp, lpPrefix, cbTemp);
  3175. }
  3176. if (lpGeneration) {
  3177. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3178. StrCatBuff(lpTemp, lpGeneration, cbTemp);
  3179. }
  3180. WRITE_OR_EXIT(vckTable[VCARD_KEY_N]);
  3181. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3182. LocalFreeAndNull(&lpTemp);
  3183. //
  3184. // Optional props
  3185. //
  3186. //
  3187. // Formatted Name: PR_DISPLAY_NAME
  3188. //
  3189. if(bIsValidStrProp(lpspv[ivcPR_DISPLAY_NAME]))
  3190. {
  3191. WRITE_OR_EXIT(vckTable[VCARD_KEY_FN]);
  3192. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_DISPLAY_NAME].Value.LPSZ, 0);
  3193. }
  3194. //
  3195. // Title: PR_NICKNAME
  3196. //
  3197. if(bIsValidStrProp(lpspv[ivcPR_NICKNAME]))
  3198. {
  3199. WRITE_OR_EXIT(vckTable[VCARD_KEY_NICKNAME]);
  3200. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_NICKNAME].Value.LPSZ, 0);
  3201. }
  3202. //
  3203. // Organization: PR_COMPANY_NAME, PR_DEPARTMENT_NAME
  3204. //
  3205. cbTemp = 0;
  3206. cbTemp += PropLength(lpspv[ivcPR_COMPANY_NAME], &lpCompanyName);
  3207. cbTemp++; // semicolon
  3208. cbTemp += PropLength(lpspv[ivcPR_DEPARTMENT_NAME], &lpDepartmentName);
  3209. cbTemp++;
  3210. if (lpCompanyName || lpDepartmentName) {
  3211. if (! (lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*cbTemp))) {
  3212. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3213. goto exit;
  3214. }
  3215. *lpTemp = '\0';
  3216. if (lpCompanyName) {
  3217. StrCatBuff(lpTemp, lpCompanyName, cbTemp);
  3218. }
  3219. if (lpDepartmentName) {
  3220. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3221. StrCatBuff(lpTemp, lpDepartmentName, cbTemp);
  3222. }
  3223. WRITE_OR_EXIT(vckTable[VCARD_KEY_ORG]);
  3224. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3225. LocalFreeAndNull(&lpTemp);
  3226. }
  3227. //
  3228. // Title: PR_TITLE
  3229. //
  3230. if(bIsValidStrProp(lpspv[ivcPR_TITLE]))
  3231. {
  3232. WRITE_OR_EXIT(vckTable[VCARD_KEY_TITLE]);
  3233. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_TITLE].Value.LPSZ, 0);
  3234. }
  3235. //
  3236. // Note: PR_COMMENT
  3237. //
  3238. if(bIsValidStrProp(lpspv[ivcPR_COMMENT]))
  3239. {
  3240. WRITE_OR_EXIT(vckTable[VCARD_KEY_NOTE]);
  3241. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_COMMENT].Value.LPSZ, 0);
  3242. }
  3243. //
  3244. // Phone numbers
  3245. //
  3246. //
  3247. // PR_BUSINESS_TELEPHONE_NUMBER
  3248. //
  3249. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3250. lpspv[ivcPR_BUSINESS_TELEPHONE_NUMBER],
  3251. FALSE, // fPref
  3252. TRUE, // fBusiness
  3253. FALSE, // fHome
  3254. TRUE, // fVoice
  3255. FALSE, // fFax
  3256. FALSE, // fISDN
  3257. FALSE, // fCell
  3258. FALSE, // fPager
  3259. FALSE)) { // fCar
  3260. goto exit;
  3261. }
  3262. //
  3263. // PR_BUSINESS2_TELEPHONE_NUMBER
  3264. //
  3265. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3266. lpspv[ivcPR_BUSINESS2_TELEPHONE_NUMBER],
  3267. FALSE, // fPref
  3268. TRUE, // fBusiness
  3269. FALSE, // fHome
  3270. TRUE, // fVoice
  3271. FALSE, // fFax
  3272. FALSE, // fISDN
  3273. FALSE, // fCell
  3274. FALSE, // fPager
  3275. FALSE)) { // fCar
  3276. goto exit;
  3277. }
  3278. //
  3279. // PR_HOME_TELEPHONE_NUMBER
  3280. //
  3281. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3282. lpspv[ivcPR_HOME_TELEPHONE_NUMBER],
  3283. FALSE, // fPref
  3284. FALSE, // fBusiness
  3285. TRUE, // fHome
  3286. TRUE, // fVoice
  3287. FALSE, // fFax
  3288. FALSE, // fISDN
  3289. FALSE, // fCell
  3290. FALSE, // fPager
  3291. FALSE)) { // fCar
  3292. goto exit;
  3293. }
  3294. //
  3295. // PR_CELLULAR_TELEPHONE_NUMBER
  3296. //
  3297. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3298. lpspv[ivcPR_CELLULAR_TELEPHONE_NUMBER],
  3299. FALSE, // fPref
  3300. FALSE, // fBusiness
  3301. FALSE, // fHome
  3302. TRUE, // fVoice
  3303. FALSE, // fFax
  3304. FALSE, // fISDN
  3305. TRUE, // fCell
  3306. FALSE, // fPager
  3307. FALSE)) { // fCar
  3308. goto exit;
  3309. }
  3310. //
  3311. // PR_CAR_TELEPHONE_NUMBER
  3312. //
  3313. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3314. lpspv[ivcPR_CAR_TELEPHONE_NUMBER],
  3315. FALSE, // fPref
  3316. FALSE, // fBusiness
  3317. FALSE, // fHome
  3318. TRUE, // fVoice
  3319. FALSE, // fFax
  3320. FALSE, // fISDN
  3321. FALSE, // fCell
  3322. FALSE, // fPager
  3323. TRUE)) { // fCar
  3324. goto exit;
  3325. }
  3326. //
  3327. // PR_OTHER_TELEPHONE_NUMBER
  3328. //
  3329. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3330. lpspv[ivcPR_OTHER_TELEPHONE_NUMBER],
  3331. FALSE, // fPref
  3332. FALSE, // fBusiness
  3333. FALSE, // fHome
  3334. TRUE, // fVoice
  3335. FALSE, // fFax
  3336. FALSE, // fISDN
  3337. FALSE, // fCell
  3338. FALSE, // fPager
  3339. FALSE)) { // fCar
  3340. goto exit;
  3341. }
  3342. //
  3343. // PR_PAGER_TELEPHONE_NUMBER
  3344. //
  3345. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3346. lpspv[ivcPR_PAGER_TELEPHONE_NUMBER],
  3347. FALSE, // fPref
  3348. FALSE, // fBusiness
  3349. FALSE, // fHome
  3350. TRUE, // fVoice
  3351. FALSE, // fFax
  3352. FALSE, // fISDN
  3353. FALSE, // fCell
  3354. TRUE, // fPager
  3355. FALSE)) { // fCar
  3356. goto exit;
  3357. }
  3358. //
  3359. // PR_BUSINESS_FAX_NUMBER
  3360. //
  3361. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3362. lpspv[ivcPR_BUSINESS_FAX_NUMBER],
  3363. FALSE, // fPref
  3364. TRUE, // fBusiness
  3365. FALSE, // fHome
  3366. FALSE, // fVoice
  3367. TRUE, // fFax
  3368. FALSE, // fISDN
  3369. FALSE, // fCell
  3370. FALSE, // fPager
  3371. FALSE)) { // fCar
  3372. goto exit;
  3373. }
  3374. //
  3375. // PR_HOME_FAX_NUMBER
  3376. //
  3377. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3378. lpspv[ivcPR_HOME_FAX_NUMBER],
  3379. FALSE, // fPref
  3380. FALSE, // fBusiness
  3381. TRUE, // fHome
  3382. FALSE, // fVoice
  3383. TRUE, // fFax
  3384. FALSE, // fISDN
  3385. FALSE, // fCell
  3386. FALSE, // fPager
  3387. FALSE)) { // fCar
  3388. goto exit;
  3389. }
  3390. //
  3391. // PR_HOME2_TELEPHONE_NUMBER
  3392. //
  3393. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3394. lpspv[ivcPR_HOME2_TELEPHONE_NUMBER],
  3395. FALSE, // fPref
  3396. FALSE, // fBusiness
  3397. TRUE, // fHome
  3398. FALSE, // fVoice
  3399. FALSE, // fFax
  3400. FALSE, // fISDN
  3401. FALSE, // fCell
  3402. FALSE, // fPager
  3403. FALSE)) { // fCar
  3404. goto exit;
  3405. }
  3406. //
  3407. // PR_ISDN_NUMBER
  3408. //
  3409. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3410. lpspv[ivcPR_ISDN_NUMBER],
  3411. FALSE, // fPref
  3412. FALSE, // fBusiness
  3413. FALSE, // fHome
  3414. FALSE, // fVoice
  3415. FALSE, // fFax
  3416. TRUE, // fISDN
  3417. FALSE, // fCell
  3418. FALSE, // fPager
  3419. FALSE)) { // fCar
  3420. goto exit;
  3421. }
  3422. //
  3423. // PR_PRIMARY_TELEPHONE_NUMBER
  3424. //
  3425. if (hResult = WriteVCardTel(hVCard, WriteFn,
  3426. lpspv[ivcPR_PRIMARY_TELEPHONE_NUMBER],
  3427. TRUE, // fPref
  3428. FALSE, // fBusiness
  3429. FALSE, // fHome
  3430. FALSE, // fVoice
  3431. FALSE, // fFax
  3432. FALSE, // fISDN
  3433. FALSE, // fCell
  3434. FALSE, // fPager
  3435. FALSE)) { // fCar
  3436. goto exit;
  3437. }
  3438. //
  3439. // Business Address
  3440. //
  3441. cbTemp = 0;
  3442. cbTemp += PropLength(lpspv[ivcPR_POST_OFFICE_BOX], &lpPOBox);
  3443. cbTemp+= 2; // ';' or CRLF
  3444. cbTemp += PropLength(lpspv[ivcPR_OFFICE_LOCATION], &lpOffice);
  3445. cbTemp+= 2; // ';' or CRLF
  3446. cbTemp += PropLength(lpspv[ivcPR_BUSINESS_ADDRESS_STREET], &lpStreet);
  3447. cbTemp+= 2; // ';' or CRLF
  3448. cbTemp += PropLength(lpspv[ivcPR_BUSINESS_ADDRESS_CITY], &lpCity);
  3449. cbTemp+= 2; // ';' or CRLF
  3450. cbTemp += PropLength(lpspv[ivcPR_BUSINESS_ADDRESS_STATE_OR_PROVINCE], &lpState);
  3451. cbTemp+= 2; // ';' or CRLF
  3452. cbTemp += PropLength(lpspv[ivcPR_BUSINESS_ADDRESS_POSTAL_CODE], &lpPostalCode);
  3453. cbTemp+= 2; // ';' or CRLF
  3454. cbTemp += PropLength(lpspv[ivcPR_BUSINESS_ADDRESS_COUNTRY], &lpCountry);
  3455. cbTemp++;
  3456. if (lpPOBox || lpOffice || lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3457. if (! (lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*cbTemp))) {
  3458. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3459. goto exit;
  3460. }
  3461. *lpTemp = '\0';
  3462. if (lpPOBox) {
  3463. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3464. }
  3465. if (lpOffice || lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3466. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3467. }
  3468. if (lpOffice) {
  3469. StrCatBuff(lpTemp, lpOffice, cbTemp);
  3470. }
  3471. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3472. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3473. }
  3474. if (lpStreet) {
  3475. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3476. }
  3477. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3478. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3479. }
  3480. if (lpCity) {
  3481. StrCatBuff(lpTemp, lpCity, cbTemp);
  3482. }
  3483. if (lpState || lpPostalCode || lpCountry) {
  3484. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3485. }
  3486. if (lpState) {
  3487. StrCatBuff(lpTemp, lpState, cbTemp);
  3488. }
  3489. if (lpPostalCode || lpCountry) {
  3490. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3491. }
  3492. if (lpPostalCode) {
  3493. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3494. }
  3495. if (lpCountry) {
  3496. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3497. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3498. }
  3499. WRITE_OR_EXIT(vckTable[VCARD_KEY_ADR]);
  3500. WRITE_OR_EXITW(szSemicolon);
  3501. WRITE_OR_EXIT(vctTable[VCARD_TYPE_WORK]);
  3502. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3503. // Business Delivery Label
  3504. // Use the same buffer
  3505. *lpTemp = '\0';
  3506. if (lpOffice) {
  3507. StrCatBuff(lpTemp, lpOffice, cbTemp);
  3508. if (lpPOBox || lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3509. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3510. }
  3511. }
  3512. if (lpPOBox) {
  3513. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3514. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3515. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3516. }
  3517. }
  3518. if (lpStreet) {
  3519. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3520. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3521. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3522. }
  3523. }
  3524. if (lpCity) {
  3525. StrCatBuff(lpTemp, lpCity, cbTemp);
  3526. if (lpState) {
  3527. StrCatBuff(lpTemp, szCommaSpace, cbTemp);
  3528. } else if (lpPostalCode) {
  3529. StrCatBuff(lpTemp, szSpace, cbTemp);
  3530. } else if (lpCountry) {
  3531. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3532. }
  3533. }
  3534. if (lpState) {
  3535. StrCatBuff(lpTemp, lpState, cbTemp);
  3536. if (lpPostalCode) {
  3537. StrCatBuff(lpTemp, szSpace, cbTemp);
  3538. } else if (lpCountry) {
  3539. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3540. }
  3541. }
  3542. if (lpPostalCode) {
  3543. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3544. if (lpCountry) {
  3545. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3546. }
  3547. }
  3548. if (lpCountry) {
  3549. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3550. }
  3551. WRITE_OR_EXIT(vckTable[VCARD_KEY_LABEL]);
  3552. WRITE_OR_EXITW(szSemicolon);
  3553. WRITE_OR_EXIT(vctTable[VCARD_TYPE_WORK]);
  3554. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3555. LocalFreeAndNull(&lpTemp);
  3556. }
  3557. //
  3558. // Home Address
  3559. //
  3560. lpPOBox = lpStreet = lpCity = lpState = lpPostalCode = lpCountry = NULL;
  3561. cbTemp = 0;
  3562. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_POST_OFFICE_BOX], &lpPOBox);
  3563. cbTemp+= 2; // ';' or CRLF
  3564. lpOffice = NULL;
  3565. cbTemp+= 2; // ';' or CRLF
  3566. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_STREET], &lpStreet);
  3567. cbTemp+= 2; // ';' or CRLF
  3568. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_CITY], &lpCity);
  3569. cbTemp+= 2; // ';' or CRLF
  3570. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_STATE_OR_PROVINCE], &lpState);
  3571. cbTemp+= 2; // ';' or CRLF
  3572. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_POSTAL_CODE], &lpPostalCode);
  3573. cbTemp+= 2; // ';' or CRLF
  3574. cbTemp += PropLength(lpspv[ivcPR_HOME_ADDRESS_COUNTRY], &lpCountry);
  3575. cbTemp++;
  3576. if (lpPOBox || lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3577. if (! (lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*cbTemp))) {
  3578. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3579. goto exit;
  3580. }
  3581. *lpTemp = '\0';
  3582. if (lpPOBox) {
  3583. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3584. }
  3585. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3586. StrCatBuff(lpTemp, szSemicolon, cbTemp); // WAB doesn't have extended on HOME address
  3587. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3588. }
  3589. if (lpStreet) {
  3590. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3591. }
  3592. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3593. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3594. }
  3595. if (lpCity) {
  3596. StrCatBuff(lpTemp, lpCity, cbTemp);
  3597. }
  3598. if (lpState || lpPostalCode || lpCountry) {
  3599. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3600. }
  3601. if (lpState) {
  3602. StrCatBuff(lpTemp, lpState, cbTemp);
  3603. }
  3604. if (lpPostalCode || lpCountry) {
  3605. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3606. }
  3607. if (lpPostalCode) {
  3608. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3609. }
  3610. if (lpCountry) {
  3611. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3612. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3613. }
  3614. WRITE_OR_EXIT(vckTable[VCARD_KEY_ADR]);
  3615. WRITE_OR_EXITW(szSemicolon);
  3616. WRITE_OR_EXIT(vctTable[VCARD_TYPE_HOME]);
  3617. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3618. // Home Delivery Label
  3619. // Use the same buffer
  3620. *lpTemp = '\0';
  3621. if (lpPOBox) {
  3622. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3623. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3624. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3625. }
  3626. }
  3627. if (lpStreet) {
  3628. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3629. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3630. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3631. }
  3632. }
  3633. if (lpCity) {
  3634. StrCatBuff(lpTemp, lpCity, cbTemp);
  3635. if (lpState) {
  3636. StrCatBuff(lpTemp, szCommaSpace, cbTemp);
  3637. } else if (lpPostalCode) {
  3638. StrCatBuff(lpTemp, szSpace, cbTemp);
  3639. } else if (lpCountry) {
  3640. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3641. }
  3642. }
  3643. if (lpState) {
  3644. StrCatBuff(lpTemp, lpState, cbTemp);
  3645. if (lpPostalCode) {
  3646. StrCatBuff(lpTemp, szSpace, cbTemp);
  3647. } else if (lpCountry) {
  3648. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3649. }
  3650. }
  3651. if (lpPostalCode) {
  3652. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3653. if (lpCountry) {
  3654. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3655. }
  3656. }
  3657. if (lpCountry) {
  3658. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3659. }
  3660. WRITE_OR_EXIT(vckTable[VCARD_KEY_LABEL]);
  3661. WRITE_OR_EXITW(szSemicolon);
  3662. WRITE_OR_EXIT(vctTable[VCARD_TYPE_HOME]);
  3663. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3664. LocalFreeAndNull(&lpTemp);
  3665. }
  3666. //
  3667. // Other Address
  3668. //
  3669. lpPOBox = lpStreet = lpCity = lpState = lpPostalCode = lpCountry = NULL;
  3670. cbTemp = 0;
  3671. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_POST_OFFICE_BOX], &lpPOBox);
  3672. cbTemp+= 2; // ';' or CRLF
  3673. lpOffice = NULL;
  3674. cbTemp+= 2; // ';' or CRLF
  3675. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_STREET], &lpStreet);
  3676. cbTemp+= 2; // ';' or CRLF
  3677. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_CITY], &lpCity);
  3678. cbTemp+= 2; // ';' or CRLF
  3679. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_STATE_OR_PROVINCE], &lpState);
  3680. cbTemp+= 2; // ';' or CRLF
  3681. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_POSTAL_CODE], &lpPostalCode);
  3682. cbTemp+= 2; // ';' or CRLF
  3683. cbTemp += PropLength(lpspv[ivcPR_OTHER_ADDRESS_COUNTRY], &lpCountry);
  3684. cbTemp++;
  3685. if (lpPOBox || lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3686. if (! (lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*cbTemp))) {
  3687. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  3688. goto exit;
  3689. }
  3690. *lpTemp = '\0';
  3691. if (lpPOBox) {
  3692. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3693. }
  3694. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3695. StrCatBuff(lpTemp, szSemicolon, cbTemp); // WAB doesn't have extended on HOME address
  3696. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3697. }
  3698. if (lpStreet) {
  3699. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3700. }
  3701. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3702. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3703. }
  3704. if (lpCity) {
  3705. StrCatBuff(lpTemp, lpCity, cbTemp);
  3706. }
  3707. if (lpState || lpPostalCode || lpCountry) {
  3708. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3709. }
  3710. if (lpState) {
  3711. StrCatBuff(lpTemp, lpState, cbTemp);
  3712. }
  3713. if (lpPostalCode || lpCountry) {
  3714. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3715. }
  3716. if (lpPostalCode) {
  3717. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3718. }
  3719. if (lpCountry) {
  3720. StrCatBuff(lpTemp, szSemicolon, cbTemp);
  3721. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3722. }
  3723. WRITE_OR_EXIT(vckTable[VCARD_KEY_ADR]);
  3724. WRITE_OR_EXITW(szSemicolon);
  3725. WRITE_OR_EXIT(vctTable[VCARD_TYPE_POSTAL]);
  3726. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3727. // Adr Label
  3728. // Use the same buffer
  3729. *lpTemp = '\0';
  3730. if (lpPOBox) {
  3731. StrCatBuff(lpTemp, lpPOBox, cbTemp);
  3732. if (lpStreet || lpCity || lpState || lpPostalCode || lpCountry) {
  3733. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3734. }
  3735. }
  3736. if (lpStreet) {
  3737. StrCatBuff(lpTemp, lpStreet, cbTemp);
  3738. if (lpCity || lpState || lpPostalCode || lpCountry) {
  3739. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3740. }
  3741. }
  3742. if (lpCity) {
  3743. StrCatBuff(lpTemp, lpCity, cbTemp);
  3744. if (lpState) {
  3745. StrCatBuff(lpTemp, szCommaSpace, cbTemp);
  3746. } else if (lpPostalCode) {
  3747. StrCatBuff(lpTemp, szSpace, cbTemp);
  3748. } else if (lpCountry) {
  3749. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3750. }
  3751. }
  3752. if (lpState) {
  3753. StrCatBuff(lpTemp, lpState, cbTemp);
  3754. if (lpPostalCode) {
  3755. StrCatBuff(lpTemp, szSpace, cbTemp);
  3756. } else if (lpCountry) {
  3757. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3758. }
  3759. }
  3760. if (lpPostalCode) {
  3761. StrCatBuff(lpTemp, lpPostalCode, cbTemp);
  3762. if (lpCountry) {
  3763. StrCatBuff(lpTemp, szCRLF, cbTemp);
  3764. }
  3765. }
  3766. if (lpCountry) {
  3767. StrCatBuff(lpTemp, lpCountry, cbTemp);
  3768. }
  3769. WRITE_OR_EXIT(vckTable[VCARD_KEY_LABEL]);
  3770. WRITE_OR_EXITW(szSemicolon);
  3771. WRITE_OR_EXIT(vctTable[VCARD_TYPE_POSTAL]);
  3772. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3773. LocalFreeAndNull(&lpTemp);
  3774. }
  3775. // GENDER
  3776. if(! PROP_ERROR(lpspv[ivcPR_GENDER] ) )
  3777. {
  3778. TCHAR szBuf[4];
  3779. INT fGender = lpspv[ivcPR_GENDER].Value.l;
  3780. // don't want to export gender data if
  3781. // it is unspecified
  3782. if( fGender == 1 || fGender == 2 )
  3783. {
  3784. szBuf[0] = '0' + fGender;
  3785. szBuf[1] = '\0';
  3786. WRITE_OR_EXIT(vckTable[VCARD_KEY_X_WAB_GENDER]);
  3787. WRITE_OR_EXIT(szColonA);
  3788. WRITE_OR_EXITW(szBuf);
  3789. WRITE_OR_EXIT(szCRLFA);
  3790. }
  3791. }
  3792. //
  3793. // URL's. Must do personal first. Note that the vCard 2.0 standard does
  3794. // not distinguish between HOME and WORK URL's. Too bad. Thus, if we export
  3795. // a contact with only a business home page, then import it, we will end up
  3796. // with a contact that has a personal home page. Hopefully, the vCard 3.0 standard
  3797. // will fix this.
  3798. //
  3799. // 62808: The above is really a big problem in Outlook because there is perceived data loss
  3800. // Hence to prevent this, we will take advantage of a bug in WAB code .. blank URLS are not
  3801. // ignored .. we will write out a blank URL for the personal one when only a business URL exists
  3802. // That way, when round-tripping the business URL shows up in the right place
  3803. //
  3804. //
  3805. // It's September of 2000. The European Commission is looking at Outlook for their mail client,
  3806. // one of the things that is hanging them up is this bug, the WORK URL jumps from the WORK URL
  3807. // box to the HOME URL if you export/import the vCard. We need this functioning, so I looked
  3808. // for the vCard 3.0 standard to see how they are handling the URL. Every place I look says that
  3809. // the people in charge of the vCard standard is www.versit.com, this however is a now defunct web
  3810. // site, I queried the other companies that use the vCard, Apple, IBM, AT&T all give press releases
  3811. // telling you to look at the www.versit.com web site, they also give a 1-800 number to call. I've
  3812. // called the 1-800 number and that number is now a yellow pages operator. I can't find a vCard 3.0
  3813. // standard, so......
  3814. //
  3815. // Now, we all wish we could do this: URL;HOME: and URL;WORK:. Well I'm going to do it!
  3816. //
  3817. //
  3818. // URL: PR_PERSONAL_HOME_PAGE
  3819. //
  3820. if(bIsValidStrProp(lpspv[ivcPR_PERSONAL_HOME_PAGE]))
  3821. {
  3822. WRITE_OR_EXIT(vckTable[VCARD_KEY_URL]);
  3823. WRITE_OR_EXITW(szSemicolon);
  3824. WRITE_OR_EXIT(vctTable[VCARD_TYPE_HOME]);
  3825. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_PERSONAL_HOME_PAGE].Value.LPSZ, 0);
  3826. }
  3827. //
  3828. // URL: PR_BUSINESS_HOME_PAGE
  3829. //
  3830. if(bIsValidStrProp(lpspv[ivcPR_BUSINESS_HOME_PAGE]))
  3831. {
  3832. WRITE_OR_EXIT(vckTable[VCARD_KEY_URL]);
  3833. WRITE_OR_EXITW(szSemicolon);
  3834. WRITE_OR_EXIT(vctTable[VCARD_TYPE_WORK]);
  3835. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_BUSINESS_HOME_PAGE].Value.LPSZ, 0);
  3836. }
  3837. //
  3838. // ROLE: PR_PROFESSION
  3839. //
  3840. if(bIsValidStrProp(lpspv[ivcPR_PROFESSION]))
  3841. {
  3842. WRITE_OR_EXIT(vckTable[VCARD_KEY_ROLE]);
  3843. WRITE_VALUE_OR_EXITW(lpspv[ivcPR_PROFESSION].Value.LPSZ, 0);
  3844. }
  3845. //
  3846. // BDAY: PR_BIRTHDAY
  3847. //
  3848. // Format is YYYYMMDD e.g. 19970911 for September 11, 1997
  3849. //
  3850. if (! PROP_ERROR(lpspv[ivcPR_BIRTHDAY]))
  3851. {
  3852. SYSTEMTIME st = {0};
  3853. FileTimeToSystemTime((FILETIME *) (&lpspv[ivcPR_BIRTHDAY].Value.ft), &st);
  3854. lpTemp = LocalAlloc(LPTR, sizeof(TCHAR)*32);
  3855. wnsprintf(lpTemp, 32, TEXT("%.4d%.2d%.2d"), st.wYear, st.wMonth, st.wDay);
  3856. WRITE_OR_EXIT(vckTable[VCARD_KEY_BDAY]);
  3857. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3858. LocalFreeAndNull(&lpTemp);
  3859. }
  3860. //
  3861. // DIGITAL CERTIFICATES
  3862. //
  3863. if(! PROP_ERROR(lpspv[ivcPR_USER_X509_CERTIFICATE] )
  3864. // && ! PROP_ERROR(lpspv[ivcPR_EMAIL_ADDRESS])
  3865. )
  3866. {
  3867. // LPTSTR lpszDefaultEmailAddress = lpspv[ivcPR_EMAIL_ADDRESS].Value.LPSZ;
  3868. LPSPropValue lpSProp = &lpspv[ivcPR_USER_X509_CERTIFICATE];
  3869. lpCDI = lpCDITemp = NULL;
  3870. if( HR_FAILED(hResult = HrGetCertsDisplayInfo( NULL, lpSProp, &lpCDI) ) )
  3871. {
  3872. DebugTrace( TEXT("get cert display info failed\n"));
  3873. }
  3874. else
  3875. {
  3876. lpCDITemp = lpCDI;
  3877. while( lpCDITemp )
  3878. {
  3879. /* if( (lstrcmp(lpCDITemp->lpszEmailAddress, lpszDefaultEmailAddress) == 0)
  3880. && lpCDITemp->bIsDefault )
  3881. break;*/
  3882. if( lpCDITemp ) // found a certificate now export it to buffer and write to file
  3883. {
  3884. ULONG cbBufLen;
  3885. if( HR_SUCCEEDED(hResult = HrExportCertToFile( NULL, lpCDITemp->pccert,
  3886. &lpDataBuffer, &cbBufLen, TRUE) ) )
  3887. {
  3888. WRITE_OR_EXIT(vckTable[VCARD_KEY_KEY]);
  3889. WRITE_OR_EXITW(szSemicolon);
  3890. WRITE_OR_EXIT(vctTable[VCARD_TYPE_X509]);
  3891. WRITE_VALUE_OR_EXITW(lpDataBuffer, cbBufLen);
  3892. }
  3893. else
  3894. {
  3895. DebugTrace( TEXT("unable to write to buffer at address %x\n"), lpDataBuffer);
  3896. }
  3897. LocalFreeAndNull(&lpDataBuffer);
  3898. }
  3899. lpCDITemp = lpCDITemp->lpNext;
  3900. }
  3901. }
  3902. while( lpCDI ) // free the cert info
  3903. {
  3904. lpCDITemp = lpCDI->lpNext;
  3905. FreeCertdisplayinfo(lpCDI);
  3906. lpCDI = lpCDITemp;
  3907. }
  3908. lpCDI = lpCDITemp = NULL;
  3909. }
  3910. //
  3911. // E-Mail addresses
  3912. //
  3913. if (! PROP_ERROR(lpspv[ivcPR_CONTACT_EMAIL_ADDRESSES])) {
  3914. // What's the default?
  3915. if (PROP_ERROR(lpspv[ivcPR_CONTACT_DEFAULT_ADDRESS_INDEX])) {
  3916. iDefaultEmail = 0;
  3917. } else {
  3918. iDefaultEmail = lpspv[ivcPR_CONTACT_DEFAULT_ADDRESS_INDEX].Value.l;
  3919. }
  3920. // for each email address, add an EMAIL key
  3921. for (i = 0; i < lpspv[ivcPR_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.cValues; i++) {
  3922. lpEmailAddress = lpspv[ivcPR_CONTACT_EMAIL_ADDRESSES].Value.MVSZ.LPPSZ[i];
  3923. if (PROP_ERROR(lpspv[ivcPR_CONTACT_ADDRTYPES])) {
  3924. lpAddrType = (LPTSTR)szSMTP;
  3925. } else {
  3926. lpAddrType = lpspv[ivcPR_CONTACT_ADDRTYPES].Value.MVSZ.LPPSZ[i];
  3927. }
  3928. if (hResult = WriteVCardEmail(hVCard, WriteFn, lpEmailAddress, lpAddrType, (iDefaultEmail == i))) {
  3929. goto exit;
  3930. }
  3931. }
  3932. } else {
  3933. // no PR_CONTACT_EMAIL_ADDRESSES, try PR_EMAIL_ADDRESS
  3934. PropLength(lpspv[ivcPR_EMAIL_ADDRESS], &lpEmailAddress);
  3935. PropLength(lpspv[ivcPR_ADDRTYPE], &lpAddrType);
  3936. if (hResult = WriteVCardEmail(hVCard, WriteFn, lpEmailAddress, lpAddrType, TRUE)) {
  3937. goto exit;
  3938. }
  3939. }
  3940. //
  3941. // EMAIL;TLX: PR_TELEX_NUMBER
  3942. //
  3943. // There is no place to put a telex number in a vCard but the EMAIL field
  3944. // allows us to specify any AddrType .. hence under pressure from Outlook,
  3945. // we force this Telex number into email .. Must make sure to filter this out
  3946. // when we read in a vCard
  3947. //
  3948. if(bIsValidStrProp(lpspv[ivcPR_TELEX_NUMBER]))
  3949. {
  3950. if (hResult = WriteVCardEmail(hVCard, WriteFn,
  3951. lpspv[ivcPR_TELEX_NUMBER].Value.LPSZ,
  3952. TEXT("TLX"), FALSE))
  3953. {
  3954. goto exit;
  3955. }
  3956. }
  3957. // Check if there are any outlook specific named properties
  3958. // that need to be written out to the vCard
  3959. if(lpList)
  3960. {
  3961. LPEXTVCARDPROP lpTemp = lpList;
  3962. while( lpTemp && lpTemp->ulExtPropTag &&
  3963. lpTemp->lpszExtPropName && lstrlenA(lpTemp->lpszExtPropName))
  3964. {
  3965. LPSPropValue lpspv = NULL;
  3966. if(!HR_FAILED(HrGetOneProp( (LPMAPIPROP)lpMailUser,
  3967. lpTemp->ulExtPropTag,
  3968. &lpspv ) ))
  3969. {
  3970. if(lpspv->Value.LPSZ && lstrlen(lpspv->Value.LPSZ))
  3971. {
  3972. WRITE_OR_EXIT(lpTemp->lpszExtPropName);
  3973. WRITE_VALUE_OR_EXITW(lpspv->Value.LPSZ, 0);
  3974. }
  3975. FreeBufferAndNull(&lpspv);
  3976. }
  3977. lpTemp = lpTemp->lpNext;
  3978. }
  3979. }
  3980. //
  3981. // REV: Current Modification Time
  3982. //
  3983. // Format is YYYYMMDD e.g. 19970911 for September 11, 1997
  3984. //
  3985. {
  3986. SYSTEMTIME st = {0};
  3987. DWORD ccSize = 32;
  3988. GetSystemTime(&st);
  3989. lpTemp = LocalAlloc(LPTR, sizeof(TCHAR) * ccSize);
  3990. wnsprintf(lpTemp, ccSize, TEXT("%.4d%.2d%.2dT%.2d%.2d%.2dZ"),
  3991. st.wYear, st.wMonth, st.wDay,
  3992. st.wHour,st.wMinute,st.wSecond);
  3993. WRITE_OR_EXIT(vckTable[VCARD_KEY_REV]);
  3994. WRITE_VALUE_OR_EXITW(lpTemp, 0);
  3995. LocalFreeAndNull(&lpTemp);
  3996. }
  3997. // End of VCARD
  3998. WRITE_OR_EXIT(vckTable[VCARD_KEY_END]);
  3999. WRITE_VALUE_OR_EXIT(vckTable[VCARD_KEY_VCARD], 0);
  4000. }
  4001. exit:
  4002. if(lpList)
  4003. FreeExtVCardPropList(lpList);
  4004. while( lpCDI ) // free the cert info
  4005. {
  4006. lpCDITemp = lpCDI->lpNext;
  4007. FreeCertdisplayinfo(lpCDI);
  4008. lpCDI = lpCDITemp;
  4009. }
  4010. lpCDI = lpCDITemp = NULL;
  4011. LocalFreeAndNull(&lpTemp);
  4012. FreeBufferAndNull(&lpspv);
  4013. LocalFreeAndNull(&lpDataBuffer);
  4014. return(hResult);
  4015. }
  4016. /***************************************************************************
  4017. Name : FileWriteFn
  4018. Purpose : write to the file handle
  4019. Parameters: handle = open file handle
  4020. lpBuffer -> buffer to write
  4021. uBytes = size of lpBuffer
  4022. lpcbWritten -> returned bytes written (may be NULL)
  4023. Returns : HRESULT
  4024. Comment : WriteFile callback for WriteVCard
  4025. ***************************************************************************/
  4026. HRESULT FileWriteFn(HANDLE handle, LPVOID lpBuffer, ULONG uBytes, LPULONG lpcbWritten) {
  4027. ULONG cbWritten = 0;
  4028. if (lpcbWritten) {
  4029. *lpcbWritten = 0;
  4030. } else {
  4031. lpcbWritten = &cbWritten;
  4032. }
  4033. #ifdef DEBUG
  4034. {
  4035. LPTSTR lpW = ConvertAtoW((LPCSTR)lpBuffer);
  4036. DebugTrace(lpW);
  4037. LocalFreeAndNull(&lpW);
  4038. }
  4039. #endif
  4040. if (! WriteFile(handle,
  4041. lpBuffer,
  4042. uBytes,
  4043. lpcbWritten,
  4044. NULL)) {
  4045. DebugTrace( TEXT("FileWriteFn:WriteFile -> %u\n"), GetLastError());
  4046. return(ResultFromScode(MAPI_E_DISK_ERROR));
  4047. }
  4048. return(hrSuccess);
  4049. }
  4050. ////////////////////////////////////////////////////////////////
  4051. /*
  4052. -
  4053. - VCardGetBuffer
  4054. -
  4055. * Retreives a vCard Buffer from a given filename or
  4056. * retrieves a copy of a given buffer
  4057. * Also inspects the buffer to see how many vCard
  4058. * files are nested in it
  4059. *
  4060. * lpszFileName - File to open
  4061. * lpszBuf - Stream to open
  4062. * ulFlags - MAPI_DIALOG or none
  4063. * lppBuf - Local Alloced returned buf
  4064. */
  4065. BOOL VCardGetBuffer(LPTSTR lpszFileName, LPSTR lpszBuf, LPSTR * lppBuf)
  4066. {
  4067. BOOL bRet = FALSE;
  4068. LPSTR lpBuf = NULL;
  4069. HANDLE hFile = NULL;
  4070. if(!lpszFileName && !lpszBuf)
  4071. goto out;
  4072. // first look for a buffer and not for the filename
  4073. if(lpszBuf && lstrlenA(lpszBuf))
  4074. {
  4075. ULONG cbBuf = lstrlenA(lpszBuf)+1;
  4076. lpBuf = LocalAlloc(LMEM_ZEROINIT, cbBuf);
  4077. if(!lpBuf)
  4078. goto out;
  4079. StrCpyNA(lpBuf, lpszBuf, cbBuf);
  4080. }
  4081. else
  4082. if(lpszFileName && lstrlen(lpszFileName))
  4083. {
  4084. if (INVALID_HANDLE_VALUE ==
  4085. (hFile = CreateFile(lpszFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
  4086. OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL)))
  4087. {
  4088. goto out;
  4089. }
  4090. // Read the whole file into a buffer
  4091. {
  4092. DWORD dwSize = GetFileSize(hFile, NULL);
  4093. DWORD dwRead = 0;
  4094. if(!dwSize || dwSize == 0xFFFFFFFF)
  4095. goto out; //err
  4096. lpBuf = LocalAlloc(LMEM_ZEROINIT, dwSize+1);
  4097. if(!lpBuf)
  4098. goto out;
  4099. if(!ReadFile(hFile, lpBuf, dwSize, &dwRead, NULL))
  4100. goto out;
  4101. }
  4102. }
  4103. *lppBuf = lpBuf;
  4104. bRet = TRUE;
  4105. out:
  4106. if(hFile)
  4107. IF_WIN32(CloseHandle(hFile);) IF_WIN16(CloseFile(hFile);)
  4108. return bRet;
  4109. }
  4110. /*
  4111. -
  4112. - VCardGetNextBuffer
  4113. -
  4114. * Scans a vCard buffer and returns pointers to the next vCard and the one after that
  4115. *
  4116. */
  4117. static const LPSTR szVBegin = "BEGIN:VCARD";
  4118. static const LPSTR szVEnd = "END:VCARD";
  4119. BOOL VCardGetNextBuffer(LPSTR lpBuf, LPSTR * lppVCard, LPSTR * lppNext)
  4120. {
  4121. LPSTR lpTemp = lpBuf;
  4122. char sz[64];
  4123. int nStr = lstrlenA(szVEnd);
  4124. BOOL bFound = FALSE;
  4125. BOOL bRet = TRUE;
  4126. Assert(lppVCard);
  4127. Assert(lppNext);
  4128. *lppVCard = lpBuf;
  4129. *lppNext = NULL;
  4130. // Scan along lpBuf till we get to END:VCARD
  4131. // After finding END:VCARD - insert a NULL to terminate the string
  4132. // and find the start of the next string
  4133. if (!lpTemp)
  4134. return FALSE;
  4135. while((lstrlenA(lpTemp) >= nStr) && !bFound)
  4136. {
  4137. CopyMemory(sz,lpTemp,nStr);
  4138. sz[nStr] = '\0';
  4139. if(!lstrcmpiA(sz, szVEnd))
  4140. {
  4141. // Add a terminating NULL to isolate the vCard
  4142. *(lpTemp + nStr) = '\0';
  4143. lpTemp += nStr + 1;
  4144. bFound = TRUE;
  4145. }
  4146. // scan to the end of the line
  4147. while(*lpTemp && *lpTemp != '\n')
  4148. lpTemp++;
  4149. // Start from the next line
  4150. if (*lpTemp)
  4151. lpTemp++;
  4152. }
  4153. bFound = FALSE;
  4154. nStr = lstrlenA(szVBegin);
  4155. // Find the starting of the next BEGIN:VCARD
  4156. while((lstrlenA(lpTemp) >= nStr) && !bFound)
  4157. {
  4158. CopyMemory(sz,lpTemp,nStr);
  4159. sz[nStr] = '\0';
  4160. if(!lstrcmpiA(sz, szVBegin))
  4161. {
  4162. *lppNext = lpTemp;
  4163. bFound = TRUE;
  4164. }
  4165. else
  4166. {
  4167. // scan to the end of the line
  4168. while(*lpTemp && *lpTemp != '\n')
  4169. lpTemp++;
  4170. // Start from the next line
  4171. if (*lpTemp)
  4172. lpTemp++;
  4173. }
  4174. }
  4175. return bRet;
  4176. }
  4177. SizedSPropTagArray(2, tagaCerts) = { 2,
  4178. {
  4179. PR_USER_X509_CERTIFICATE,
  4180. PR_WAB_TEMP_CERT_HASH
  4181. }
  4182. };
  4183. /**
  4184. ParseCert: will parse the binary data in the buffer and set the certificate
  4185. as a prop for the specified mailuser.
  4186. [IN] lpData - address of the binary data buffer containing the certificate
  4187. [IN] cbData - length of the binary data buffer
  4188. [IN] lpMailUser - access to the mail user so the certificate can be set
  4189. */
  4190. HRESULT ParseCert( LPSTR lpData, ULONG cbData, LPMAILUSER lpMailUser)
  4191. {
  4192. HRESULT hr = hrSuccess;
  4193. ULONG ulcProps = 0;
  4194. LPSPropValue lpSpv = NULL;
  4195. if( lpData && *lpData )
  4196. {
  4197. if( HR_FAILED( hr = lpMailUser->lpVtbl->GetProps( lpMailUser,
  4198. (LPSPropTagArray)&tagaCerts,
  4199. MAPI_UNICODE,
  4200. &ulcProps,
  4201. &lpSpv) ) )
  4202. {
  4203. DebugTrace( TEXT("could not get Props\n"));
  4204. return hr;
  4205. }
  4206. if(lpSpv[0].ulPropTag != PR_USER_X509_CERTIFICATE )
  4207. {
  4208. MAPIFreeBuffer( lpSpv );
  4209. MAPIAllocateBuffer( sizeof(SPropValue) * 2, &lpSpv);
  4210. if( lpSpv )
  4211. {
  4212. lpSpv[0].ulPropTag = PR_USER_X509_CERTIFICATE;
  4213. lpSpv[0].dwAlignPad = 0;
  4214. lpSpv[0].Value.MVbin.cValues = 0;
  4215. lpSpv[1].ulPropTag = PR_WAB_TEMP_CERT_HASH;
  4216. lpSpv[1].dwAlignPad = 0;
  4217. lpSpv[1].Value.MVbin.cValues = 0;
  4218. }
  4219. else
  4220. {
  4221. DebugTrace( TEXT("could not allocate mem for props\n"));
  4222. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  4223. return hr;
  4224. }
  4225. }
  4226. else
  4227. {
  4228. // [PaulHi] 5/3/99 Check the PR_WAB_TEMP_CERT_HASH to see if it is
  4229. // of type PT_ERROR. If it is then this is Ok, it is just empty of
  4230. // data. We only use this to hold temporary data which is freed below.
  4231. if ( PROP_TYPE(lpSpv[1].ulPropTag) == PT_ERROR )
  4232. {
  4233. lpSpv[1].ulPropTag = PR_WAB_TEMP_CERT_HASH;
  4234. lpSpv[1].Value.MVbin.cValues = 0;
  4235. lpSpv[1].Value.MVbin.lpbin = NULL;
  4236. }
  4237. }
  4238. // Put the certs into the prop array.
  4239. hr = HrLDAPCertToMAPICert( lpSpv, 0, 1, cbData, (LPBYTE)lpData, 1);
  4240. if( HR_SUCCEEDED( hr ) )
  4241. {
  4242. if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser,
  4243. 1,
  4244. lpSpv,
  4245. NULL)))
  4246. {
  4247. DebugTrace( TEXT("failed setting props\n"));
  4248. }
  4249. }
  4250. else
  4251. {
  4252. DebugTrace( TEXT("LDAPCertToMapiCert failed\n"));
  4253. }
  4254. MAPIFreeBuffer( lpSpv );
  4255. }
  4256. else
  4257. {
  4258. DebugTrace( TEXT("lpData was null\n"));
  4259. hr = E_FAIL;
  4260. }
  4261. return hr;
  4262. }
  4263. /**
  4264. DecodeBase64: decode BASE64 data
  4265. [IN] bufcoded - access to the BASE64 encoded data
  4266. [OUT] pbuffdecoded - address of the buffer where decoded data will go
  4267. [OUT] pcbDecode - length of the decoded data buffer
  4268. */
  4269. HRESULT DecodeBase64(LPSTR bufcoded, LPSTR pbuffdecoded, PDWORD pcbDecoded)
  4270. {
  4271. INT nbytesdecoded;
  4272. LPSTR bufin;
  4273. LPSTR bufout;
  4274. INT nprbytes;
  4275. CONST INT *rgiDict = base642six;
  4276. /* Strip leading whitespace. */
  4277. while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  4278. /* Figure out how many characters are in the input buffer.
  4279. * If this would decode into more bytes than would fit into
  4280. * the output buffer, adjust the number of input bytes downwards.
  4281. */
  4282. bufin = bufcoded;
  4283. while(rgiDict[*(bufin++)] <= 63);
  4284. nprbytes = (INT) (bufin - bufcoded - 1);
  4285. nbytesdecoded = ((nprbytes+3)/4) * 3;
  4286. if ( pcbDecoded )
  4287. *pcbDecoded = nbytesdecoded;
  4288. bufout = (LPSTR)pbuffdecoded;
  4289. bufin = bufcoded;
  4290. while (nprbytes > 0) {
  4291. *(bufout++) =
  4292. (char) (rgiDict[*bufin] << 2 | rgiDict[bufin[1]] >> 4);
  4293. *(bufout++) =
  4294. (char) (rgiDict[bufin[1]] << 4 | rgiDict[bufin[2]] >> 2);
  4295. *(bufout++) =
  4296. (char) (rgiDict[bufin[2]] << 6 | rgiDict[bufin[3]]);
  4297. bufin += 4;
  4298. nprbytes -= 4;
  4299. }
  4300. if(nprbytes & 03) {
  4301. if(rgiDict[bufin[-2]] > 63)
  4302. nbytesdecoded -= 2;
  4303. else
  4304. nbytesdecoded -= 1;
  4305. }
  4306. ((LPSTR)pbuffdecoded)[nbytesdecoded] = '\0';
  4307. return S_OK;
  4308. }
  4309. #endif