IdVCard.pas 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.7 2004.10.27 9:17:52 AM czhower
  18. For TIdStrings
  19. Rev 1.6 10/26/2004 10:54:16 PM JPMugaas
  20. Updated refs.
  21. Rev 1.5 2004.02.08 2:43:32 PM czhower
  22. Fixed compile error.
  23. Rev 1.4 2/7/2004 12:47:16 PM JPMugaas
  24. Should work in DotNET and not touch the system settings at all.
  25. Rev 1.3 2004.02.03 5:44:42 PM czhower
  26. Name changes
  27. Rev 1.2 1/21/2004 4:21:10 PM JPMugaas
  28. InitComponent
  29. Rev 1.1 6/13/2003 08:19:52 AM JPMugaas
  30. Should now compile with new codders.
  31. Rev 1.0 11/13/2002 08:04:32 AM JPMugaas
  32. }
  33. unit IdVCard;
  34. {*******************************************************}
  35. { }
  36. { Indy VCardObject TIdCard }
  37. { }
  38. { Copyright (C) 2000 Winshoes Working Group }
  39. { Original author J. Peter Mugaas }
  40. { 2000-May-06 }
  41. { Based on RFC 2425, 2426 }
  42. { }
  43. {*******************************************************}
  44. {
  45. 2002-Jan-20 DOn Siders
  46. - Corrected spelling errors in Categories properties, members, methods
  47. 2000-07-24 Peter Mee
  48. - Added preliminary embedded vCard checking
  49. - Added QP Check & Decode of individual properties
  50. }
  51. interface
  52. {$i IdCompilerDefines.inc}
  53. uses
  54. Classes,
  55. IdGlobal,
  56. IdBaseComponent;
  57. { TODO:
  58. Agent property does not work and the current parsing stops whenever it
  59. sees END:VCard meaning that the VCard will be truncated if AGENT is
  60. used to embed a VCard.
  61. I omitted a property for spelling out a sound. Appearently VCard 2.1
  62. permitted a charactor representation of sound in addition to an embedded
  63. sound, and a URL.
  64. I am not sure how well the KEY property works. That is used for
  65. embedding some encryption keys into a VCard such as PGP public-key or
  66. something from Versign.
  67. VCard does not have any Quoted Printable decoding or Base64 encoding
  68. and decoding. Some routines may have to be changed to accomodate
  69. this although I don't have the where-with-all.
  70. VCards can not be saved. }
  71. type
  72. {This contains the object for Sound, Logo, Photo, Key, and Agent property}
  73. TIdVCardEmbeddedObject = class(TPersistent)
  74. protected
  75. FObjectType : String;
  76. FObjectURL : String;
  77. FBase64Encoded : Boolean;
  78. FEmbeddedData : TStrings;
  79. {Embeded data property set method}
  80. procedure SetEmbeddedData(const Value: TStrings);
  81. public
  82. constructor Create;
  83. destructor Destroy; override;
  84. published
  85. {this indicates the type of media such as the file type or key type}
  86. property ObjectType : String read FObjectType write FObjectType;
  87. {pointer to the URL where the object is located if it is NOT in this card
  88. itself}
  89. property ObjectURL : String read FObjectURL write FObjectURL;
  90. {The object }
  91. property Base64Encoded : Boolean read FBase64Encoded write FBase64Encoded;
  92. {The data for the object if it is in the VCard. This is usually in an
  93. encoded format such as BASE64 although some keys may not require encoding}
  94. property EmbeddedData : TStrings read FEmbeddedData write SetEmbeddedData;
  95. end;
  96. {VCard business information}
  97. TIdVCardBusinessInfo = class(TPersistent)
  98. protected
  99. FTitle : String;
  100. FRole : String;
  101. FOrganization : String;
  102. FDivisions : TStrings;
  103. procedure SetDivisions(Value : TStrings);
  104. public
  105. constructor Create;
  106. destructor Destroy; override;
  107. published
  108. {The organization name such as XYZ Corp. }
  109. property Organization : String read FOrganization write FOrganization;
  110. { The divisions in the orginization the person is in - e.g.
  111. West Virginia Office, Computing Service}
  112. property Divisions: TStrings read FDivisions write SetDivisions;
  113. {The person's formal title in the business such
  114. "Director of Computing Services"}
  115. property Title : String read FTitle write FTitle;
  116. {The person's role in an organization such as "system administrator" }
  117. property Role : String read FRole write FRole;
  118. end;
  119. {Geographical information such as Latitude/Longitude and Time Zone}
  120. TIdVCardGeog = class(TPersistent)
  121. protected
  122. FLatitude : Real;
  123. FLongitude : Real;
  124. FTimeZoneStr : String;
  125. published
  126. {Geographical latitude the person is in}
  127. property Latitude : Real read FLatitude write FLatitude;
  128. {Geographical longitude the person is in}
  129. property Longitude : Real read FLongitude write FLongitude;
  130. {The time zone the person is in}
  131. property TimeZoneStr : String read FTimeZoneStr write FTimeZoneStr;
  132. end;
  133. TIdPhoneAttribute = ( tpaHome, tpaVoiceMessaging, tpaWork, tpaPreferred,
  134. tpaVoice, tpaFax, tpaCellular, tpaVideo, tpaBBS, tpaModem, tpaCar,
  135. tpaISDN, tpaPCS, tpaPager );
  136. TIdPhoneAttributes = set of TIdPhoneAttribute;
  137. { This encapsolates a telephone number }
  138. TIdCardPhoneNumber = class(TCollectionItem)
  139. protected
  140. FPhoneAttributes: TIdPhoneAttributes;
  141. FNumber : String;
  142. public
  143. procedure Assign(Source: TPersistent); override;
  144. published
  145. {This is a descriptor for the phone number }
  146. property PhoneAttributes: TIdPhoneAttributes read FPhoneAttributes write FPhoneAttributes;
  147. { the telephone number itself}
  148. property Number : String read FNumber write FNumber;
  149. end;
  150. {Since a person can have more than one address, we put them into this collection}
  151. TIdVCardTelephones = class(TOwnedCollection)
  152. protected
  153. function GetItem(Index: Integer) : TIdCardPhoneNumber;
  154. procedure SetItem(Index: Integer; const Value: TIdCardPhoneNumber);
  155. public
  156. constructor Create(AOwner : TPersistent); reintroduce;
  157. function Add: TIdCardPhoneNumber;
  158. property Items[Index: Integer] : TIdCardPhoneNumber read GetItem write SetItem; default;
  159. end;
  160. TIdCardAddressAttribute = ( tatHome, tatDomestic, tatInternational, tatPostal, tatParcel, tatWork, tatPreferred );
  161. TIdCardAddressAttributes = set of TIdCardAddressAttribute;
  162. {This encapsulates a person's address} {Do not Localize}
  163. TIdCardAddressItem = class(TCollectionItem)
  164. protected
  165. FAddressAttributes : TIdCardAddressAttributes;
  166. FPOBox : String;
  167. FExtendedAddress : String;
  168. FStreetAddress : String;
  169. FLocality : String;
  170. FRegion : String;
  171. FPostalCode : String;
  172. FNation : String;
  173. public
  174. procedure Assign(Source: TPersistent); override;
  175. published
  176. { attributes for this address such as Home or Work, postal, parcel, etc.}
  177. property AddressAttributes : TIdCardAddressAttributes read FAddressAttributes write FAddressAttributes;
  178. { This is the P. O. Box for an address}
  179. property POBox : String read FPOBox write FPOBox;
  180. { This could be something such as an Office identifier for a building or
  181. an appartment number }
  182. property ExtendedAddress : String read FExtendedAddress write FExtendedAddress;
  183. {This is the streat address such as "101 Sample Avenue" }
  184. property StreetAddress : String read FStreetAddress write FStreetAddress;
  185. { This is a city or town (e.g. Chicago, New York City, Montreol }
  186. property Locality : String read FLocality write FLocality;
  187. { This is the political subdivision of a nation such as a Providence in Canda - Quebec,
  188. a State in US such as "West Virginia", or a county in England such as "Kent"}
  189. property Region : String read FRegion write FRegion;
  190. { This is the postal code for the locality such as a ZIP Code in the US }
  191. property PostalCode : String read FPostalCode write FPostalCode;
  192. { This is the nation such as Canada, U.S.A., Mexico, Russia, etc }
  193. property Nation : String read FNation write FNation;
  194. end;
  195. {Since a person can have more than one address, we put them into this collection}
  196. TIdVCardAddresses = class(TOwnedCollection)
  197. protected
  198. function GetItem(Index: Integer) : TIdCardAddressItem;
  199. procedure SetItem(Index: Integer; const Value: TIdCardAddressItem);
  200. public
  201. constructor Create(AOwner : TPersistent); reintroduce;
  202. function Add: TIdCardAddressItem;
  203. property Items[Index: Integer] : TIdCardAddressItem read GetItem write SetItem; default;
  204. end;
  205. {This type holds a mailing label }
  206. TIdVCardMailingLabelItem = class(TCollectionItem)
  207. private
  208. FAddressAttributes : TIdCardAddressAttributes;
  209. FMailingLabel : TStrings;
  210. procedure SetMailingLabel(Value : TStrings);
  211. public
  212. constructor Create(Collection: TCollection); override;
  213. destructor Destroy; override;
  214. procedure Assign(Source: TPersistent); override;
  215. published
  216. { attributes for this mailing label such as Home or Work, postal, parcel,
  217. etc.}
  218. property AddressAttributes : TIdCardAddressAttributes read FAddressAttributes write FAddressAttributes;
  219. { The mailing label itself}
  220. property MailingLabel : TStrings read FMailingLabel write SetMailingLabel;
  221. end;
  222. {This type holds the }
  223. TIdVCardMailingLabels = class(TOwnedCollection)
  224. protected
  225. function GetItem(Index: Integer) : TIdVCardMailingLabelItem;
  226. procedure SetItem(Index: Integer; const Value: TIdVCardMailingLabelItem);
  227. public
  228. constructor Create(AOwner : TPersistent); reintroduce;
  229. function Add : TIdVCardMailingLabelItem;
  230. property Items[Index: Integer] : TIdVCardMailingLabelItem read GetItem write SetItem; default;
  231. end;
  232. { This type is used to indicate the type E-Mail indicated in the VCard
  233. which can be of several types }
  234. TIdVCardEMailType = (
  235. ematAOL, {America On-Line}
  236. ematAppleLink, {AppleLink}
  237. ematATT, { AT&T Mail }
  238. ematCIS, { CompuServe Information Service }
  239. emateWorld, { eWorld }
  240. ematInternet, {Internet SMTP (default)}
  241. ematIBMMail, { IBM Mail }
  242. ematMCIMail, { Indicates MCI Mail }
  243. ematPowerShare, { PowerShare }
  244. ematProdigy, { Prodigy information service }
  245. ematTelex, { Telex number }
  246. ematX400 { X.400 service }
  247. );
  248. {This object encapsolates an E-Mail address in a Collection}
  249. TIdVCardEMailItem = class(TCollectionItem)
  250. protected
  251. FEMailType : TIdVCardEMailType;
  252. FPreferred : Boolean;
  253. FAddress : String;
  254. public
  255. constructor Create(Collection: TCollection); override;
  256. { This is the type of E-Mail address which defaults to Internet }
  257. procedure Assign(Source: TPersistent); override;
  258. published
  259. property EMailType : TIdVCardEMailType read FEMailType write FEMailType;
  260. { Is this the person's prefered E-Mail address? } {Do not Localize}
  261. property Preferred : Boolean read FPreferred write FPreferred;
  262. { The user's E-Mail address itself } {Do not Localize}
  263. property Address : String read FAddress write FAddress;
  264. end;
  265. TIdVCardEMailAddresses = class(TOwnedCollection)
  266. protected
  267. function GetItem(Index: Integer) : TIdVCardEMailItem;
  268. procedure SetItem(Index: Integer; const Value: TIdVCardEMailItem);
  269. public
  270. constructor Create(AOwner : TPersistent); reintroduce;
  271. function Add: TIdVCardEMailItem;
  272. property Items[Index: Integer] : TIdVCardEMailItem read GetItem write SetItem; default;
  273. end;
  274. TIdVCardName = class(TPersistent)
  275. protected
  276. FFirstName : String;
  277. FSurName : String;
  278. FOtherNames : TStrings;
  279. FPrefix : String;
  280. FSuffix : String;
  281. FFormattedName : String;
  282. FSortName : String;
  283. FNickNames : TStrings;
  284. procedure SetOtherNames(Value : TStrings);
  285. procedure SetNickNames(Value : TStrings);
  286. public
  287. constructor Create;
  288. destructor Destroy; override;
  289. published
  290. {This is the person's first name, in the case of "J. Peter Mugaas",
  291. this would be "J."}
  292. property FirstName : String read FFirstName write FFirstName;
  293. {This is the person's last name, in the case of "J. Peter Mugaas",
  294. this would be "Mugaas"}
  295. property SurName : String read FSurName write FSurName;
  296. {This is a place for a middle name and some other names such as a woman's
  297. maiden name. In the case of "J. Peter Mugaas", this would be "Peter".}
  298. property OtherNames : TStrings read FOtherNames write SetOtherNames;
  299. {This is a properly formatted name which was listed in the VCard}
  300. property FormattedName : String read FFormattedName write FFormattedName;
  301. {This is a prefix added to a name such as
  302. "Mr.", "Dr.", "Hon.", "Prof.", "Reverend", etc.}
  303. property Prefix : String read FPrefix write FPrefix;
  304. {This is a suffix added to a name such as
  305. "Ph.D.", "M.D.", "Esq.", "Jr.", "Sr.", "III", etc.}
  306. property Suffix : String read FSuffix write FSuffix;
  307. {The string used for sorting a name. It may not always be the person's last
  308. name}
  309. property SortName : String read FSortName write FSortName;
  310. { Nick names which a person may have such as "Bill" or "Billy" for Wiliam.}
  311. property NickNames : TStrings read FNickNames write SetNickNames;
  312. end;
  313. TIdVCard = class(TIdBaseComponent)
  314. protected
  315. FComments : TStrings;
  316. FCategories : TStrings;
  317. FBusinessInfo : TIdVCardBusinessInfo;
  318. FGeography : TIdVCardGeog;
  319. FFullName : TIdVCardName;
  320. FRawForm : TStrings;
  321. FURLs : TStrings;
  322. FEMailProgram : String;
  323. FEMailAddresses : TIdVCardEMailAddresses;
  324. FAddresses : TIdVCardAddresses;
  325. FMailingLabels : TIdVCardMailingLabels;
  326. FTelephones : TIdVCardTelephones;
  327. FVCardVersion : Real;
  328. FProductID : String;
  329. FUniqueID : String;
  330. FClassification : String;
  331. FLastRevised : TDateTime;
  332. FBirthDay : TDateTime;
  333. FPhoto : TIdVCardEmbeddedObject;
  334. FLogo : TIdVCardEmbeddedObject;
  335. FSound : TIdVCardEmbeddedObject;
  336. FKey : TIdVCardEmbeddedObject;
  337. procedure SetComments(Value : TStrings);
  338. procedure SetCategories(Value : TStrings);
  339. procedure SetURLs(Value : TStrings);
  340. {This processes some types of variables after reading the string}
  341. procedure SetVariablesAfterRead;
  342. procedure InitComponent; override;
  343. public
  344. destructor Destroy; override;
  345. { This reads a VCard from a TStrings object }
  346. procedure ReadFromStrings(s : TStrings);
  347. { This is the raw form of the VCard }
  348. property RawForm : TStrings read FRawForm;
  349. published
  350. { This is the VCard specification version used }
  351. property VCardVersion : Real read FVCardVersion;
  352. { URL's associated with the VCard such as the person's or organication's
  353. webpage. There can be more than one.}
  354. property URLs : TStrings read FURLs write SetURLs;
  355. { This is the product ID for the program which created this VCard}
  356. property ProductID : String read FProductID write FProductID;
  357. { This is a unique indentifier for the VCard }
  358. property UniqueID : String read FUniqueID write FUniqueID;
  359. { Intent of the VCard owner for general access to information described by the vCard
  360. VCard.}
  361. property Classification : String read FClassification write FClassification;
  362. { This is the person's birthday and possibly, time of birth} {Do not Localize}
  363. property BirthDay : TDateTime read FBirthDay write FBirthDay;
  364. { This is the person's name } {Do not Localize}
  365. property FullName : TIdVCardName read FFullName write FFullName;
  366. { This is the E-Mail program used by the card's owner} {Do not Localize}
  367. property EMailProgram : String read FEMailProgram write FEMailProgram;
  368. { This is a list of the person's E-Mail address } {Do not Localize}
  369. property EMailAddresses : TIdVCardEMailAddresses read FEMailAddresses;
  370. { This is a list of telephone numbers }
  371. property Telephones : TIdVCardTelephones read FTelephones;
  372. { This is busines related information on a VCard}
  373. property BusinessInfo : TIdVCardBusinessInfo read FBusinessInfo;
  374. { This is a list of Categories used for classification }
  375. property Categories : TStrings read FCategories write SetCategories;
  376. { This is a list of addresses }
  377. property Addresses : TIdVCardAddresses read FAddresses;
  378. { This is a list of mailing labels }
  379. property MailingLabels : TIdVCardMailingLabels read FMailingLabels;
  380. { This is a miscellaneous comments, additional information, or whatever the
  381. VCard wishes to say }
  382. property Comments : TStrings read FComments write SetComments;
  383. { The owner's photograph} {Do not Localize}
  384. property Photo : TIdVCardEmbeddedObject read FPhoto;
  385. { Organization's logo} {Do not Localize}
  386. property Logo : TIdVCardEmbeddedObject read FLogo;
  387. { A sound associated with the VCard such as how to pronounce a person's name
  388. or something cute }
  389. property Sound : TIdVCardEmbeddedObject read FSound;
  390. { This is for an encryption key such as S/MIME, VeriSign, or PGP }
  391. property Key : TIdVCardEmbeddedObject read FKey;
  392. end;
  393. //public for testing
  394. type
  395. TIdISO8601DateComps = record
  396. Year, Month, Day: UInt16;
  397. end;
  398. TIdISO8601TimeComps = record
  399. Hour, Min, Sec, MSec: UInt16;
  400. UTCOffset: String;
  401. end;
  402. function ParseISO8601Date(const DateString: string; var VDate: TIdISO8601DateComps): Boolean;
  403. function ParseISO8601Time(const DateString: string; var VTime: TIdISO8601TimeComps): Boolean;
  404. function ParseISO8601DateTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  405. function ParseISO8601DateAndOrTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  406. function ParseISO8601DateTimeStamp(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  407. function ParseDateTimeStamp(const DateString: string): TDateTime; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use ParseISO8601DateTimeStamp()'{$ENDIF};{$ENDIF}
  408. implementation
  409. uses
  410. IdCoderQuotedPrintable,
  411. IdGlobalProtocols, SysUtils;
  412. const VCardProperties : array [0..27] of string = (
  413. 'FN', 'N', 'NICKNAME', 'PHOTO', {Do not Localize}
  414. 'BDAY', 'ADR', 'LABEL', 'TEL', {Do not Localize}
  415. 'EMAIL', 'MAILER', 'TZ', 'GEO', {Do not Localize}
  416. 'TITLE', 'ROLE', 'LOGO', 'AGENT', {Do not Localize}
  417. 'ORG', 'CATEGORIES', 'NOTE', 'PRODID', {Do not Localize}
  418. 'REV', 'SORT-STRING', 'SOUND', 'URL', {Do not Localize}
  419. 'UID', 'VERSION', 'CLASS', 'KEY' {Do not Localize}
  420. );
  421. { These constants are for testing the VCard for E-Mail types.
  422. Don't alter these } {Do not Localize}
  423. const EMailTypePropertyParameter : array [0..11] of string = (
  424. 'AOL', {America On-Line} {Do not Localize}
  425. 'APPLELINK', {AppleLink} {Do not Localize}
  426. 'ATTMAIL', { AT&T Mail } {Do not Localize}
  427. 'CIS', { CompuServe Information Service } {Do not Localize}
  428. 'EWORLD', { eWorld } {Do not Localize}
  429. 'INTERNET', {Internet SMTP (default) } {Do not Localize}
  430. 'IBMMAIL', { IBM Mail } {Do not Localize}
  431. 'MCIMAIL', { MCI Mail } {Do not Localize}
  432. 'POWERSHARE', { PowerShare } {Do not Localize}
  433. 'PRODIGY', { Prodigy information service } {Do not Localize}
  434. 'TLX', { Telex number } {Do not Localize}
  435. 'X400' { X.400 service } {Do not Localize}
  436. );
  437. //This is designed for decimals as written in the English language.
  438. //We require this because some protocols may require this as standard representation
  439. //for floats
  440. function IndyStrToFloat(const AStr: string): Extended;
  441. var
  442. LBuf : String;
  443. LHi, LLo : UInt32;
  444. i : Integer;
  445. begin
  446. LBuf := AStr;
  447. //strip off
  448. for i := Length(LBuf) downto 1 do begin
  449. if LBuf[i] = ',' then begin
  450. IdDelete(LBuf, i, 1);
  451. end;
  452. end;
  453. LHi := IndyStrToInt(Fetch(LBuf,'.'), 0);
  454. LBuf := PadString(LBuf, 2, '0');
  455. LLo := IndyStrToInt(Copy(LBuf,1,2), 0);
  456. Result := LHi + (LLo / 100);
  457. end;
  458. {This only adds Value to strs if it is not zero}
  459. procedure AddValueToStrings(strs : TStrings; Value : String);
  460. begin
  461. if Length(Value) > 0 then begin
  462. strs.Add(Value);
  463. end; // if Legnth ( Value ) then
  464. end;
  465. {This parses a delinated string into a TStrings}
  466. procedure ParseDelimiterToStrings(strs : TStrings; str : String; const Delimiter : Char = ','); {Do not Localize}
  467. begin
  468. while str <> '' do begin {Do not Localize}
  469. AddValueToStrings(strs, Fetch(str, Delimiter));
  470. end;
  471. end;
  472. {This parses time stamp from DateString and returns it as TDateTime
  473. Per RFC 2425 Section 5.8.4:
  474. date = date-fullyear ["-"] date-month ["-"] date-mday
  475. date-fullyear = 4 DIGIT
  476. date-month = 2 DIGIT ;01-12
  477. date-mday = 2 DIGIT ;01-28, 01-29, 01-30, 01-31
  478. ;based on month/year
  479. time = time-hour [":"] time-minute [":"] time-second [time-secfrac] [time-zone]
  480. time-hour = 2 DIGIT ;00-23
  481. time-minute = 2 DIGIT ;00-59
  482. time-second = 2 DIGIT ;00-60 (leap second)
  483. time-secfrac = "," 1*DIGIT
  484. time-zone = "Z" / time-numzone
  485. time-numzome = sign time-hour [":"] time-minute
  486. "date", "time", and "date-time": Each of these value types is based
  487. on a subset of the definitions in ISO 8601 standard. Profiles MAY
  488. place further restrictions on "date" and "time" values. Multiple
  489. "date" and "time" values can be specified using the comma-separated
  490. notation, unless restricted by a profile.
  491. Examples for "date":
  492. 1985-04-12
  493. 1996-08-05,1996-11-11
  494. 19850412
  495. Examples for "time":
  496. 10:22:00
  497. 102200
  498. 10:22:00.33
  499. 10:22:00.33Z
  500. 10:22:33,11:22:00
  501. 10:22:00-08:00
  502. Examples for "date-time":
  503. 1996-10-22T14:00:00Z
  504. 1996-08-11T12:34:56Z
  505. 19960811T123456Z
  506. 1996-10-22T14:00:00Z,1996-08-11T12:34:56Z
  507. Per RFC 2426 Section 4:
  508. date-value = <A single date value as defined in [MIME-DIR]>
  509. time-value = <A single time value as defined in [MIME-DIR]>
  510. date-time-value = <A single date-time value as defined in [MIME-DIR]
  511. [MIME-DIR] Howes, T., Smith, M., and F. Dawson, "A MIME Content-
  512. Type for Directory Information", RFC 2425, September
  513. 1998.
  514. Per RFC 6350 Section 4.3:
  515. "date", "time", "date-time", "date-and-or-time", and "timestamp":
  516. Each of these value types is based on the definitions in
  517. [ISO.8601.2004]. Multiple such values can be specified using the
  518. comma-separated notation.
  519. Only the basic format is supported.
  520. 4.3.1. DATE
  521. A calendar date as specified in [ISO.8601.2004], Section 4.1.2.
  522. Reduced accuracy, as specified in [ISO.8601.2004], Sections 4.1.2.3
  523. a) and b), but not c), is permitted.
  524. Expanded representation, as specified in [ISO.8601.2004], Section
  525. 4.1.4, is forbidden.
  526. Truncated representation, as specified in [ISO.8601.2000], Sections
  527. 5.2.1.3 d), e), and f), is permitted.
  528. Examples for "date":
  529. 19850412
  530. 1985-04
  531. 1985
  532. --0412
  533. ---12
  534. Note the use of YYYY-MM in the second example above. YYYYMM is
  535. disallowed to prevent confusion with YYMMDD. Note also that
  536. YYYY-MM-DD is disallowed since we are using the basic format instead
  537. of the extended format.
  538. 4.3.2. TIME
  539. A time of day as specified in [ISO.8601.2004], Section 4.2.
  540. Reduced accuracy, as specified in [ISO.8601.2004], Section 4.2.2.3,
  541. is permitted.
  542. Representation with decimal fraction, as specified in
  543. [ISO.8601.2004], Section 4.2.2.4, is forbidden.
  544. The midnight hour is always represented by 00, never 24 (see
  545. [ISO.8601.2004], Section 4.2.3).
  546. Truncated representation, as specified in [ISO.8601.2000], Sections
  547. 5.3.1.4 a), b), and c), is permitted.
  548. Examples for "time":
  549. 102200
  550. 1022
  551. 10
  552. -2200
  553. --00
  554. 102200Z
  555. 102200-0800
  556. 4.3.3. DATE-TIME
  557. A date and time of day combination as specified in [ISO.8601.2004],
  558. Section 4.3.
  559. Truncation of the date part, as specified in [ISO.8601.2000], Section
  560. 5.4.2 c), is permitted.
  561. Examples for "date-time":
  562. 19961022T140000
  563. --1022T1400
  564. ---22T14
  565. 4.3.4. DATE-AND-OR-TIME
  566. Either a DATE-TIME, a DATE, or a TIME value. To allow unambiguous
  567. interpretation, a stand-alone TIME value is always preceded by a "T".
  568. Examples for "date-and-or-time":
  569. 19961022T140000
  570. --1022T1400
  571. ---22T14
  572. 19850412
  573. 1985-04
  574. 1985
  575. --0412
  576. ---12
  577. T102200
  578. T1022
  579. T10
  580. T-2200
  581. T--00
  582. T102200Z
  583. T102200-0800
  584. 4.3.5. TIMESTAMP
  585. A complete date and time of day combination as specified in
  586. [ISO.8601.2004], Section 4.3.2.
  587. Examples for "timestamp":
  588. 19961022T140000
  589. 19961022T140000Z
  590. 19961022T140000-05
  591. 19961022T140000-0500
  592. }
  593. function ParseISO8601Date(const DateString: string; var VDate: TIdISO8601DateComps): Boolean;
  594. var
  595. Year, Month, Day: UInt16;
  596. Len: Integer;
  597. begin
  598. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  599. Result := False;
  600. VDate.Year := 0;
  601. VDate.Month := 0;
  602. VDate.Day := 0;
  603. Len := Length(DateString);
  604. if (Len >= 10) and
  605. IsNumeric(DateString, 4, 1) and CharEquals(DateString, 5, '-') and
  606. IsNumeric(DateString, 2, 6) and CharEquals(DateString, 8, '-') and
  607. IsNumeric(DateString, 2, 9) then
  608. begin
  609. Year := IndyStrToInt(Copy(DateString, 1, 4));
  610. Month := IndyStrToInt(Copy(DateString, 6, 2));
  611. Day := IndyStrToInt(Copy(DateString, 9, 2));
  612. Dec(Len, 10);
  613. end
  614. else if (Len >= 8) and IsNumeric(DateString, 8, 1) then
  615. begin
  616. Year := IndyStrToInt(Copy(DateString, 1, 4));
  617. Month := IndyStrToInt(Copy(DateString, 5, 2));
  618. Day := IndyStrToInt(Copy(DateString, 7, 2));
  619. Dec(Len, 8);
  620. end else
  621. begin
  622. Day := 1;
  623. if (Len >= 7) and
  624. IsNumeric(DateString, 4, 1) and CharEquals(DateString, 5, '-') and
  625. IsNumeric(DateString, 2, 6) then
  626. begin
  627. Year := IndyStrToInt(Copy(DateString, 1, 4));
  628. Month := IndyStrToInt(Copy(DateString, 6, 2));
  629. Dec(Len, 7);
  630. end
  631. else if (Len >= 4) and IsNumeric(DateString, 4, 1) then
  632. begin
  633. Month := 1;
  634. Year := IndyStrToInt(Copy(DateString, 1, 4));
  635. Dec(Len, 4);
  636. end
  637. else if (Len >= 4) and CharEquals(DateString, 1, '-') and CharEquals(DateString, 2, '-') then
  638. begin
  639. Year := 0;
  640. if (Len >= 7) and IsNumeric(DateString, 2, 3) and CharEquals(DateString, 5, '-') and
  641. IsNumeric(DateString, 2, 6) then
  642. begin
  643. Month := IndyStrToInt(Copy(DateString, 3, 2));
  644. Day := IndyStrToInt(Copy(DateString, 6, 2));
  645. Dec(Len, 7);
  646. end
  647. else if (Len >= 6) and IsNumeric(DateString, 4, 3) then
  648. begin
  649. Month := IndyStrToInt(Copy(DateString, 3, 2));
  650. Day := IndyStrToInt(Copy(DateString, 5, 2));
  651. Dec(Len, 6)
  652. end
  653. else if (Len >= 5) and CharEquals(DateString, 3, '-') and IsNumeric(DateString, 2, 4) then
  654. begin
  655. Month := 1;
  656. Day := IndyStrToInt(Copy(DateString, 4, 2));
  657. Dec(Len, 5);
  658. end
  659. else if (Len >= 4) and IsNumeric(DateString, 2, 3) then
  660. begin
  661. Month := IndyStrToInt(Copy(DateString, 3, 2));
  662. Day := 1;
  663. Dec(Len, 4);
  664. end else begin
  665. Exit;
  666. end;
  667. end else begin
  668. Exit;
  669. end;
  670. end;
  671. if Len > 0 then begin
  672. Exit;
  673. end;
  674. VDate.Year := Year;
  675. VDate.Month := Month;
  676. VDate.Day := Day;
  677. Result := True;
  678. end;
  679. function ParseISO8601Time(const DateString: string; var VTime: TIdISO8601TimeComps): Boolean;
  680. type
  681. eFracComp = (fracMin, fracSec, fracMSec);
  682. var
  683. Hour, Min, Sec, MSec: UInt16;
  684. Len, Offset, TmpOffset, TmpLen, I, Numerator, Denominator: Integer;
  685. LMultiplier: Single;
  686. FracComp: eFracComp;
  687. begin
  688. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  689. Result := False;
  690. VTime.Hour := 0;
  691. VTime.Min := 0;
  692. VTime.Sec := 0;
  693. VTime.MSec := 0;
  694. VTime.UTCOffset := '';
  695. Len := Length(DateString);
  696. MSec := 0;
  697. if (Len >= 8) and
  698. IsNumeric(DateString, 2, 1) and CharEquals(DateString, 3, ':') and
  699. IsNumeric(DateString, 2, 4) and CharEquals(DateString, 6, ':') and
  700. IsNumeric(DateString, 2, 7) then
  701. begin
  702. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  703. Min := IndyStrToInt(Copy(DateString, 4, 2));
  704. Sec := IndyStrToInt(Copy(DateString, 7, 2));
  705. Offset := 9;
  706. Dec(Len, 8);
  707. FracComp := fracMSec;
  708. end
  709. else if (Len >= 6) and IsNumeric(DateString, 6, 1) then
  710. begin
  711. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  712. Min := IndyStrToInt(Copy(DateString, 3, 2));
  713. Sec := IndyStrToInt(Copy(DateString, 5, 2));
  714. Offset := 7;
  715. Dec(Len, 6);
  716. FracComp := fracMSec;
  717. end
  718. else begin
  719. Sec := 0;
  720. if (Len >= 5) and
  721. IsNumeric(DateString, 2, 1) and CharEquals(DateString, 3, ':') and
  722. IsNumeric(DateString, 2, 4) then
  723. begin
  724. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  725. Min := IndyStrToInt(Copy(DateString, 4, 2));
  726. Offset := 6;
  727. Dec(Len, 5);
  728. FracComp := fracSec;
  729. end
  730. else if (Len >= 4) and IsNumeric(DateString, 4, 1) then
  731. begin
  732. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  733. Min := IndyStrToInt(Copy(DateString, 3, 2));
  734. Offset := 5;
  735. Dec(Len, 4);
  736. FracComp := fracSec;
  737. end else
  738. begin
  739. if (Len >= 2) and IsNumeric(DateString, 2, 1) then begin
  740. Min := 0;
  741. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  742. Offset := 3;
  743. Dec(Len, 2);
  744. FracComp := fracMin;
  745. end
  746. else if (Len >= 3) and CharEquals(DateString, 1, '-') then
  747. begin
  748. Hour := 0;
  749. if (Len >= 6) and IsNumeric(DateString, 2, 2) and CharEquals(DateString, 4, ':') and
  750. IsNumeric(DateString, 2, 5) then
  751. begin
  752. Min := IndyStrToInt(Copy(DateString, 2, 2));
  753. Sec := IndyStrToInt(Copy(DateString, 5, 2));
  754. Offset := 7;
  755. Dec(Len, 6);
  756. FracComp := fracMSec;
  757. end
  758. else if (Len >= 5) and IsNumeric(DateString, 4, 2) then
  759. begin
  760. Min := IndyStrToInt(Copy(DateString, 2, 2));
  761. Sec := IndyStrToInt(Copy(DateString, 4, 2));
  762. Offset := 6;
  763. Dec(Len, 5);
  764. FracComp := fracMSec;
  765. end
  766. else if (Len >= 4) and CharEquals(DateString, 2, '-') and IsNumeric(DateString, 2, 3) then
  767. begin
  768. Min := 0;
  769. Sec := IndyStrToInt(Copy(DateString, 3, 2));
  770. Offset := 5;
  771. Dec(Len, 4);
  772. FracComp := fracMSec;
  773. end
  774. else if (Len >= 3) and IsNumeric(DateString, 2, 2) then
  775. begin
  776. Min := IndyStrToInt(Copy(DateString, 3, 2));
  777. Sec := 0;
  778. Offset := 4;
  779. Dec(Len, 3);
  780. FracComp := fracSec;
  781. end else begin
  782. Exit;
  783. end;
  784. end else begin
  785. Exit;
  786. end;
  787. end;
  788. end;
  789. if (Len > 0) and CharIsInSet(DateString, Offset, '.,') then
  790. begin
  791. Inc(Offset);
  792. Dec(Len);
  793. Numerator := 0;
  794. Denominator := 1;
  795. for I := 0 to 8 do
  796. begin
  797. if Len = 0 then begin
  798. Break;
  799. end;
  800. if not IsNumeric(DateString[Offset]) then begin
  801. Break;
  802. end;
  803. Numerator := (Numerator * 10) + (Ord(DateString[Offset]) - Ord('0'));
  804. if Numerator < 0 then begin // overflow
  805. Exit;
  806. end;
  807. Denominator := Denominator * 10;
  808. Inc(Offset);
  809. Dec(Len);
  810. end;
  811. LMultiplier := Numerator / Denominator;
  812. case FracComp of
  813. fracMin: begin
  814. Min := UInt16(Trunc(60 * LMultiplier));
  815. end;
  816. fracSec: begin
  817. Sec := UInt16(Trunc(60 * LMultiplier));
  818. end;
  819. fracMSec: begin
  820. MSec := UInt16(Trunc(1000 * LMultiplier));
  821. end;
  822. end;
  823. end;
  824. if Len > 0 then
  825. begin
  826. TmpOffset := Offset;
  827. TmpLen := Len;
  828. if not CharIsInSet(DateString, Offset, '+-') then
  829. begin
  830. // TODO: parse time zones other than "Z" into offsets
  831. if CharEquals(DateString, Offset, 'Z') then begin
  832. Dec(Len);
  833. end;
  834. end else
  835. begin
  836. Inc(Offset);
  837. Dec(Len);
  838. if (Len >= 5) and
  839. IsNumeric(DateString, 2, Offset) and CharEquals(DateString, Offset+2, ':') and
  840. IsNumeric(DateString, 2, Offset+3) then
  841. begin
  842. Dec(Len, 5);
  843. end
  844. else if (Len >= 4) and IsNumeric(DateString, 4, Offset) then
  845. begin
  846. Dec(Len, 4);
  847. end
  848. else if (Len >= 2) and IsNumeric(DateString, 2, Offset) then
  849. begin
  850. Dec(Len, 2);
  851. end
  852. else begin
  853. Exit;
  854. end;
  855. end;
  856. if Len > 0 then begin
  857. Exit;
  858. end;
  859. Offset := TmpOffset;
  860. Len := TmpLen;
  861. end;
  862. VTime.Hour := Hour;
  863. VTime.Min := Min;
  864. VTime.Sec := Sec;
  865. VTime.MSec := MSec;
  866. VTime.UTCOffset := Copy(DateString, Offset, Len);
  867. Result := True;
  868. end;
  869. function ParseISO8601DateTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  870. var
  871. I: Integer;
  872. begin
  873. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  874. Result := False;
  875. VDate.Year := 0;
  876. VDate.Month := 0;
  877. VDate.Day := 0;
  878. VTime.Hour := 0;
  879. VTime.Min := 0;
  880. VTime.Sec := 0;
  881. VTime.MSec := 0;
  882. VTime.UTCOffset := '';
  883. I := Pos('T', DateString);
  884. if I <> 0 then begin
  885. Result := ParseISO8601Date(Copy(DateString, 1, I-1), VDate) and
  886. ParseISO8601Time(Copy(DateString, I+1, MaxInt), VTime);
  887. end;
  888. end;
  889. function ParseISO8601DateAndOrTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  890. var
  891. I: Integer;
  892. begin
  893. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  894. Result := False;
  895. VDate.Year := 0;
  896. VDate.Month := 0;
  897. VDate.Day := 0;
  898. VTime.Hour := 0;
  899. VTime.Min := 0;
  900. VTime.Sec := 0;
  901. VTime.MSec := 0;
  902. VTime.UTCOffset := '';
  903. I := Pos('T', DateString);
  904. if I = 0 then begin
  905. Result := ParseISO8601Date(DateString, VDate);
  906. Exit;
  907. end;
  908. if I > 1 then begin
  909. if not ParseISO8601Date(Copy(DateString, 1, I-1), VDate) then begin
  910. Exit;
  911. end;
  912. end;
  913. if not ParseISO8601Time(Copy(DateString, I+1, MaxInt), VTime) then begin
  914. Exit;
  915. end;
  916. Result := True;
  917. end;
  918. function ParseISO8601DateTimeStamp(const DateString: String; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  919. {$IFDEF USE_INLINE}inline;{$ENDIF}
  920. begin
  921. // TODO: how is TIMESTAMP different from DATE-TIME?
  922. Result := ParseISO8601DateTime(DateString, VDate, VTime);
  923. end;
  924. function ParseDateTimeStamp(const DateString: string): TDateTime;
  925. var
  926. LDate: TIdISO8601DateComps;
  927. LTime: TIdISO8601TimeComps;
  928. begin
  929. if ParseISO8601DateTimeStamp(DateString, LDate, LTime) then begin
  930. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day) + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  931. end else begin
  932. Result := 0.0;
  933. end;
  934. end;
  935. {This function returns a stringList with an item's
  936. attributes and sets value to the value of the item}
  937. function GetAttributesAndValue(Data : String; var Value : String) : TStringList;
  938. var
  939. Buff, Buff2 : String;
  940. begin
  941. Result := TStringList.Create;
  942. try
  943. if IndyPos(':', Data) <> 0 then {Do not Localize}
  944. begin
  945. Buff := Fetch(Data, ':'); {Do not Localize}
  946. {This handles a VCard property attribute delimiter ","}
  947. Buff := ReplaceAll(Buff, ',', ';'); {Do not Localize}
  948. while Buff <> '' do begin {Do not Localize}
  949. Buff2 := Fetch(Buff, ';'); {Do not Localize}
  950. if Length(Buff2) > 0 then begin
  951. Result.Add(Buff2);
  952. end;
  953. end;
  954. end;
  955. Value := Data;
  956. except
  957. FreeAndNil(Result);
  958. raise;
  959. end;
  960. end;
  961. {This parses the organization line from OrgString into}
  962. procedure ParseOrg(OrgObj : TIdVCardBusinessInfo; OrgStr : String);
  963. begin
  964. { Organization name }
  965. OrgObj.Organization := Fetch(OrgStr, ';');
  966. { Divisions }
  967. ParseDelimiterToStrings(OrgObj.Divisions, OrgStr, ';'); {Do not Localize}
  968. end;
  969. {This parses the geography latitude and longitude from GeogStr and
  970. puts it in Geog}
  971. procedure ParseGeography(Geog : TIdVCardGeog; GeogStr : String);
  972. begin
  973. {Latitude}
  974. Geog.Latitude := IndyStrToFloat(Fetch(GeogStr, ';')); {Do not Localize}
  975. {Longitude}
  976. Geog.Longitude := IndyStrToFloat(Fetch(GeogStr, ';')); {Do not Localize}
  977. end;
  978. {This parses PhoneStr and places the attributes in PhoneObj }
  979. procedure ParseTelephone(PhoneObj : TIdCardPhoneNumber; PhoneStr : String);
  980. const
  981. TelephoneTypePropertyParameter : array [0..13] of string = (
  982. 'HOME', 'MSG', 'WORK', 'PREF', 'VOICE', 'FAX', {Do not Localize}
  983. 'CELL', 'VIDEO', 'BBS', 'MODEM', 'CAR', 'ISDN', {Do not Localize}
  984. 'PCS', 'PAGER' {Do not Localize}
  985. );
  986. var
  987. Value : String;
  988. idx : Integer;
  989. Attribs : TStringList;
  990. begin
  991. attribs := GetAttributesAndValue(PhoneStr, Value);
  992. try
  993. for idx := 0 to Attribs.Count-1 do begin
  994. case PosInStrArray(attribs[idx], TelephoneTypePropertyParameter, False) of
  995. { home }
  996. 0 : Include(PhoneObj.FPhoneAttributes, tpaHome);
  997. { voice messaging }
  998. 1 : Include(PhoneObj.FPhoneAttributes, tpaVoiceMessaging);
  999. { work }
  1000. 2 : Include(PhoneObj.FPhoneAttributes, tpaWork);
  1001. { preferred }
  1002. 3 : Include(PhoneObj.FPhoneAttributes, tpaPreferred);
  1003. { Voice }
  1004. 4 : Include(PhoneObj.FPhoneAttributes, tpaVoice);
  1005. { Fax }
  1006. 5 : Include(PhoneObj.FPhoneAttributes, tpaFax);
  1007. { Cellular phone }
  1008. 6 : Include(PhoneObj.FPhoneAttributes, tpaCellular);
  1009. { Video conferancing number }
  1010. 7 : Include(PhoneObj.FPhoneAttributes, tpaVideo);
  1011. { Bulleton Board System (BBS) telephone number }
  1012. 8 : Include(PhoneObj.FPhoneAttributes, tpaBBS);
  1013. { MODEM Connection number }
  1014. 9 : Include(PhoneObj.FPhoneAttributes, tpaModem);
  1015. { Car phone number }
  1016. 10 : Include(PhoneObj.FPhoneAttributes, tpaCar);
  1017. { ISDN Service Number }
  1018. 11 : Include(PhoneObj.FPhoneAttributes, tpaISDN);
  1019. { personal communication services telephone number }
  1020. 12 : Include(PhoneObj.FPhoneAttributes, tpaPCS);
  1021. { pager }
  1022. 13 : Include(PhoneObj.FPhoneAttributes, tpaPager);
  1023. end;
  1024. end;
  1025. { default telephon number }
  1026. if Attribs.Count = 0 then begin
  1027. PhoneObj.PhoneAttributes := [tpaVoice];
  1028. end;
  1029. PhoneObj.Number := Value;
  1030. finally
  1031. FreeAndNil(attribs);
  1032. end;
  1033. end;
  1034. {This parses AddressStr and places the attributes in AddressObj }
  1035. procedure ParseAddress(AddressObj : TIdCardAddressItem; AddressStr : String);
  1036. const
  1037. AttribsArray : array[0..6] of String = (
  1038. 'HOME', 'DOM', 'INTL', 'POSTAL', 'PARCEL', 'WORK', 'PREF' {Do not Localize}
  1039. );
  1040. var
  1041. Value : String;
  1042. Attribs : TStringList;
  1043. idx : Integer;
  1044. begin
  1045. Attribs := GetAttributesAndValue(AddressStr, Value);
  1046. try
  1047. for idx := 0 to Attribs.Count-1 do begin
  1048. case PosInStrArray(attribs[idx], AttribsArray, False) of
  1049. { home }
  1050. 0 : Include(AddressObj.FAddressAttributes, tatHome);
  1051. { domestic }
  1052. 1 : Include(AddressObj.FAddressAttributes, tatDomestic);
  1053. { international }
  1054. 2 : Include(AddressObj.FAddressAttributes, tatInternational);
  1055. { Postal }
  1056. 3 : Include(AddressObj.FAddressAttributes, tatPostal);
  1057. { Parcel }
  1058. 4 : Include(AddressObj.FAddressAttributes, tatParcel);
  1059. { Work }
  1060. 5 : Include(AddressObj.FAddressAttributes, tatWork);
  1061. { Preferred }
  1062. 6 : Include(AddressObj.FAddressAttributes, tatPreferred);
  1063. end;
  1064. end;
  1065. if Attribs.Count = 0 then begin
  1066. AddressObj.AddressAttributes := [tatInternational, tatPostal, tatParcel, tatWork];
  1067. end;
  1068. AddressObj.POBox := Fetch(Value, ';'); {Do not Localize}
  1069. AddressObj.ExtendedAddress := Fetch(Value, ';'); {Do not Localize}
  1070. AddressObj.StreetAddress := Fetch(Value, ';'); {Do not Localize}
  1071. AddressObj.Locality := Fetch(Value, ';'); {Do not Localize}
  1072. AddressObj.Region := Fetch (Value, ';'); {Do not Localize}
  1073. AddressObj.PostalCode := Fetch(Value, ';'); {Do not Localize}
  1074. AddressObj.Nation := Fetch (Value, ';'); {Do not Localize}
  1075. finally
  1076. FreeAndNil(Attribs);
  1077. end;
  1078. end;
  1079. {This parses LabelStr and places the attributes in TIdVCardMailingLabelItem }
  1080. procedure ParseMailingLabel(LabelObj : TIdVCardMailingLabelItem; LabelStr : String);
  1081. const
  1082. AttribsArray : array[0..6] of String = (
  1083. 'HOME', 'DOM', 'INTL', 'POSTAL', 'PARCEL', 'WORK', 'PREF' {Do not Localize}
  1084. );
  1085. var
  1086. Value : String;
  1087. Attribs : TStringList;
  1088. idx : Integer;
  1089. begin
  1090. Attribs := GetAttributesAndValue(LabelStr, Value);
  1091. try
  1092. for idx := 0 to Attribs.Count-1 do begin
  1093. case PosInStrArray(attribs[idx], AttribsArray, False) of
  1094. { home }
  1095. 0 : Include(LabelObj.FAddressAttributes, tatHome);
  1096. { domestic }
  1097. 1 : Include(LabelObj.FAddressAttributes, tatDomestic);
  1098. { international }
  1099. 2 : Include(LabelObj.FAddressAttributes, tatInternational);
  1100. { Postal }
  1101. 3 : Include(LabelObj.FAddressAttributes, tatPostal);
  1102. { Parcel }
  1103. 4 : Include(LabelObj.FAddressAttributes, tatParcel);
  1104. { Work }
  1105. 5 : Include(LabelObj.FAddressAttributes, tatWork);
  1106. { Preferred }
  1107. 6 : Include(LabelObj.FAddressAttributes, tatPreferred);
  1108. end;
  1109. end;
  1110. {Default Values}
  1111. if Attribs.Count = 0 then begin
  1112. LabelObj.AddressAttributes := [tatInternational, tatPostal, tatParcel, tatWork];
  1113. end;
  1114. LabelObj.MailingLabel.Add(Value);
  1115. finally
  1116. FreeAndNil(Attribs);
  1117. end;
  1118. end;
  1119. {This parses the Name and places the name in the TIdVCardName}
  1120. procedure ParseName(NameObj : TIdVCardName; NameStr : String);
  1121. var
  1122. OtherNames : String;
  1123. begin
  1124. { surname }
  1125. NameObj.SurName := Fetch(NameStr, ';'); {Do not Localize}
  1126. { first name }
  1127. NameObj.FirstName := Fetch(NameStr, ';'); {Do not Localize}
  1128. { middle and other names}
  1129. OtherNames := Fetch(NameStr, ';'); {Do not Localize}
  1130. { Prefix }
  1131. NameObj.Prefix := Fetch(NameStr, ';'); {Do not Localize}
  1132. { Suffix }
  1133. NameObj.Suffix := Fetch(NameStr, ';'); {Do not Localize}
  1134. OtherNames := ReplaceAll(OtherNames, ' ', ','); {Do not Localize}
  1135. ParseDelimiterToStrings(NameObj.OtherNames, OtherNames);
  1136. end;
  1137. {This parses EMailStr and places the attributes in EMailObj }
  1138. procedure ParseEMailAddress(EMailObj : TIdVCardEMailItem; EMailStr : String);
  1139. var
  1140. Value : String;
  1141. Attribs : TStringList;
  1142. idx : Integer;
  1143. {this is for testing the type so we can break out of the loop}
  1144. ps : Integer;
  1145. function IsPreferred: Boolean;
  1146. var
  1147. idx2: Integer;
  1148. begin
  1149. for idx2 := 0 to Attribs.Count-1 do begin
  1150. if TextIsSame(Attribs[idx2], 'PREF') then begin {Do not Localize}
  1151. Result := True;
  1152. Exit;
  1153. end;
  1154. end;
  1155. Result := False;
  1156. end;
  1157. begin
  1158. Attribs := GetAttributesAndValue (EMailStr, Value);
  1159. try
  1160. EMailObj.Address := Value;
  1161. EMailObj.Preferred := IsPreferred;
  1162. for idx := 0 to Attribs.Count-1 do begin
  1163. ps := PosInStrArray(Attribs[idx], EMailTypePropertyParameter);
  1164. if ps <> -1 then begin
  1165. case ps of
  1166. 0 : EMailObj.EMailType := ematAOL; {America On-Line}
  1167. 1 : EMailObj.EMailType := ematAppleLink; {AppleLink}
  1168. 2 : EMailObj.EMailType := ematATT; { AT&T Mail }
  1169. 3 : EMailObj.EMailType := ematCIS; { CompuServe Information Service }
  1170. 4 : EMailObj.EMailType := emateWorld; { eWorld }
  1171. 5 : EMailObj.EMailType := ematInternet; {Internet SMTP (default)}
  1172. 6 : EMailObj.EMailType := ematIBMMail; { IBM Mail }
  1173. 7 : EMailObj.EMailType := ematMCIMail; { Indicates MCI Mail }
  1174. 8 : EMailObj.EMailType := ematPowerShare; { PowerShare }
  1175. 9 : EMailObj.EMailType := ematProdigy; { Prodigy information service }
  1176. 10 : EMailObj.EMailType := ematTelex; { Telex number }
  1177. 11 : EMailObj.EMailType := ematX400; { X.400 service }
  1178. end;
  1179. Break;
  1180. end;
  1181. end;
  1182. finally
  1183. FreeAndNil(Attribs);
  1184. end;
  1185. end;
  1186. { TIdVCard }
  1187. procedure TIdVCard.InitComponent;
  1188. begin
  1189. inherited InitComponent;
  1190. FPhoto := TIdVCardEmbeddedObject.Create;
  1191. FLogo := TIdVCardEmbeddedObject.Create;
  1192. FSound := TIdVCardEmbeddedObject.Create;
  1193. FKey := TIdVCardEmbeddedObject.Create;
  1194. FComments := TStringList.Create;
  1195. FCategories := TStringList.Create;
  1196. FBusinessInfo := TIdVCardBusinessInfo.Create;
  1197. FGeography := TIdVCardGeog.Create;
  1198. FFullName := TIdVCardName.Create;
  1199. FRawForm := TStringList.Create;
  1200. FEMailAddresses := TIdVCardEMailAddresses.Create(Self);
  1201. FAddresses := TIdVCardAddresses.Create(Self);
  1202. FTelephones := TIdVCardTelephones.Create(Self);
  1203. FURLs := TStringList.Create;
  1204. FMailingLabels := TIdVCardMailingLabels.Create(Self);
  1205. end;
  1206. destructor TIdVCard.Destroy;
  1207. begin
  1208. FreeAndNil(FKey);
  1209. FreeAndNil(FPhoto);
  1210. FreeAndNil(FLogo);
  1211. FreeAndNil(FSound);
  1212. FreeAndNil(FComments);
  1213. FreeAndNil(FMailingLabels);
  1214. FreeAndNil(FCategories);
  1215. FreeAndNil(FBusinessInfo);
  1216. FreeAndNil(FGeography);
  1217. FreeAndNil(FURLs);
  1218. FreeAndNil(FTelephones);
  1219. FreeAndNil(FAddresses);
  1220. FreeAndNil(FEMailAddresses);
  1221. FreeAndNil(FFullName);
  1222. FreeAndNil(FRawForm);
  1223. inherited Destroy;
  1224. end;
  1225. procedure TIdVCard.ReadFromStrings(s: TStrings);
  1226. var
  1227. idx, level : Integer;
  1228. begin
  1229. FRawForm.Clear;
  1230. {Find the begin mark and accomodate broken VCard implemntations}
  1231. level := 0;
  1232. for idx := 0 to s.Count-1 do begin
  1233. if TextIsSame(Trim(s[idx]), 'BEGIN:VCARD') then begin {Do not Localize}
  1234. Break;
  1235. end;
  1236. end;
  1237. {Keep adding until end VCard }
  1238. while idx < s.Count do begin
  1239. if Length(s[idx]) > 0 then begin
  1240. case PosInStrArray(Trim(s[idx]), ['BEGIN:VCARD', 'END:VCARD'], False) of {Do not Localize}
  1241. 0: begin
  1242. // Have a new object - increment the counter & add
  1243. Inc(level);
  1244. end;
  1245. 1: begin
  1246. // Have an END:
  1247. Dec(level);
  1248. end;
  1249. end;
  1250. // regardless of content, add it
  1251. FRawForm.Add(s[idx]);
  1252. if level < 1 then begin
  1253. Break;
  1254. end;
  1255. end;
  1256. Inc(idx);
  1257. end;
  1258. SetVariablesAfterRead;
  1259. end;
  1260. procedure TIdVCard.SetCategories(Value: TStrings);
  1261. begin
  1262. FCategories.Assign(Value);
  1263. end;
  1264. procedure TIdVCard.SetComments(Value: TStrings);
  1265. begin
  1266. FComments.Assign(Value);
  1267. end;
  1268. procedure TIdVCard.SetURLs(Value: TStrings);
  1269. begin
  1270. FURLs.Assign(Value);
  1271. end;
  1272. procedure TIdVCard.SetVariablesAfterRead;
  1273. var
  1274. idx : Integer;
  1275. // OrigLine : String;
  1276. Line : String;
  1277. Attribs : String;
  1278. Data : String;
  1279. Test : String;
  1280. Colon : Integer;
  1281. SColon : Integer;
  1282. ColonFind : Integer;
  1283. QPCoder : TIdDecoderQuotedPrintable;
  1284. {These subroutines increment idx to prevent unneded comparisons of folded lines}
  1285. function UnfoldLines : String;
  1286. begin
  1287. Result := ''; {Do not Localize}
  1288. Inc(idx);
  1289. while (idx < FRawForm.Count) and CharIsInSet(FRawForm[idx], 1, ' '#9) do {Do not Localize}
  1290. begin
  1291. Result := Result + Trim(FRawForm[idx]);
  1292. Inc(idx);
  1293. end; // while
  1294. {Correct for increment in the main while loop}
  1295. Dec(idx);
  1296. end;
  1297. procedure ProcessAgent;
  1298. begin
  1299. // The current idx of FRawForm could be an embedded vCard.
  1300. { TODO : Eliminate embedded vCard }
  1301. end;
  1302. procedure ParseEmbeddedObject(EmObj : TIdVCardEmbeddedObject; StLn : String);
  1303. var
  1304. Value : String;
  1305. LAttribs : TStringList;
  1306. idx2 : Integer;
  1307. {this is for testing the type so we can break out of the loop}
  1308. begin
  1309. LAttribs := GetAttributesAndValue(StLn, Value);
  1310. try
  1311. for idx2 := 0 to LAttribs.Count-1 do begin
  1312. if PosInStrArray(LAttribs[idx2], ['ENCODING=BASE64', 'BASE64']) <> -1 then begin {Do not Localize}
  1313. emObj.Base64Encoded := True;
  1314. end
  1315. else if PosInStrArray(LAttribs[idx2], ['VALUE=URI', 'VALUE=URL', 'URI', 'URL']) = -1 then begin {Do not Localize}
  1316. emObj.ObjectType := LAttribs[idx2];
  1317. end;
  1318. end;
  1319. if (LAttribs.IndexOf('VALUE=URI') > -1) or {Do not Localize}
  1320. (LAttribs.IndexOf('VALUE=URL') > -1) or {Do not Localize}
  1321. (LAttribs.IndexOf('URI') > -1) or {Do not Localize}
  1322. (LAttribs.IndexOf('URL') > -1) then {Do not Localize}
  1323. begin
  1324. emObj.ObjectURL := Value + UnfoldLines;
  1325. end else begin
  1326. AddValueToStrings(EmObj.EmbeddedData, Value);
  1327. {Add any folded lines}
  1328. Inc(idx);
  1329. while (idx < FRawForm.Count) and CharIsInSet(FRawForm[idx], 1, ' '#9) do begin {Do not Localize}
  1330. AddValueToStrings(EmObj.EmbeddedData, Trim(FRawForm[idx]));
  1331. Inc(idx);
  1332. end;
  1333. {Correct for increment in the main while loop}
  1334. Dec(idx);
  1335. end;
  1336. finally
  1337. FreeAndNil(LAttribs);
  1338. end;
  1339. end;
  1340. function GetDateTimeValue(St: String): TDateTime;
  1341. var
  1342. LAttribs: String;
  1343. LDate: TIdISO8601DateComps;
  1344. LTime: TIdISO8601TimeComps;
  1345. begin
  1346. Result := 0.0;
  1347. // TODO: parse the attributes into a proper list
  1348. LAttribs := UpperCase(Attribs);
  1349. if IndyPos('TIMESTAMP', LAttribs) <> 0 then begin {Do not Localize}
  1350. if ParseISO8601DateTimeStamp(St, LDate, LTime) then begin
  1351. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day) + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1352. // TODO: use LTime.UTCOffset if available
  1353. end;
  1354. end
  1355. else if IndyPos('DATE-AND-OR-TIME', LAttribs) <> 0 then begin {Do not Localize}
  1356. if ParseISO8601DateAndOrTime(st, LDate, LTime) then begin
  1357. if (LDate.Year <> 0) or (LDate.Month <> 0) or (LDate.Day <> 0) then begin
  1358. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1359. end;
  1360. if (LTime.Hour <> 0) or (LTime.Min <> 0) or (LTime.Sec <> 0) or (LTime.MSec <> 0) then begin
  1361. Result := Result + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1362. // TODO: use LTime.UTCOffset if available
  1363. end;
  1364. end;
  1365. end
  1366. else if IndyPos('DATE-TIME', LAttribs) <> 0 then begin {Do not Localize}
  1367. if ParseISO8601DateTime(st, LDate, LTime) then begin
  1368. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day) + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1369. // TODO: use LTime.UTCOffset if available
  1370. end;
  1371. end
  1372. else if IndyPos('DATE', LAttribs) <> 0 then begin {Do not Localize}
  1373. if ParseISO8601Date(st, LDate) then begin
  1374. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1375. end;
  1376. end
  1377. else if IndyPos('TIME', LAttribs) <> 0 then begin {Do not Localize}
  1378. if ParseISO8601Time(st, LTime) then begin
  1379. Result := EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1380. // TODO: use LTime.UTCOffset if available
  1381. end;
  1382. end else begin
  1383. if ParseISO8601DateAndOrTime(st, LDate, LTime) then begin
  1384. if (LDate.Year <> 0) or (LDate.Month <> 0) or (LDate.Day <> 0) then begin
  1385. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1386. end;
  1387. if (LTime.Hour <> 0) or (LTime.Min <> 0) or (LTime.Sec <> 0) or (LTime.MSec <> 0) then begin
  1388. Result := Result + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1389. // TODO: use LTime.UTCOffset if available
  1390. end;
  1391. end;
  1392. end;
  1393. end;
  1394. begin
  1395. // At this point, FRawForm contains the entire vCard - including possible
  1396. // embedded vCards.
  1397. QPCoder := TIdDecoderQuotedPrintable.Create(Self);
  1398. try
  1399. idx := 0;
  1400. while idx < FRawForm.Count do
  1401. begin
  1402. // Grab the line
  1403. Line := FRawForm[idx];
  1404. {We separate the property name from the parameters and values here.
  1405. We have be careful because sometimes a property in a vCard is separed by a
  1406. ; or : even if the RFC and standards don't permit this
  1407. - broken VCard creation tools }
  1408. Colon := IndyPos(':', Line); {Do not Localize}
  1409. // Store the property & complete attributes
  1410. // TODO: use a TStringList instead...
  1411. Attribs := Copy(Line, 1, Colon - 1);
  1412. // Must now check for Quoted-printable attribute. vCard v2.1 allows
  1413. // QP to be used in any field.
  1414. //**** Begin QP check & decode
  1415. if IndyPos('QUOTED-PRINTABLE', UpperCase(Attribs)) > 0 then begin {Do not Localize}
  1416. // First things first - make a copy of the Line.
  1417. // OrigLine := Line;
  1418. // Set Data to be the data contained on this line of the vCard
  1419. Data := Copy(Line, Colon + 1, MaxInt);
  1420. // The problem with QP-embedded objects is that the Colon character is
  1421. // not standard QP-encoded... however, it is the only reliable way to
  1422. // discover the next property. So loop here until the next property is
  1423. // found (i.e., the next line with a colon).
  1424. Inc(idx);
  1425. ColonFind := IndyPos(':', FRawForm[idx]); {Do not Localize}
  1426. while ColonFind = 0 do begin
  1427. Data := Data + TrimLeft(FRawForm[idx]);
  1428. Inc(idx);
  1429. if idx <> FRawForm.Count then begin
  1430. ColonFind := IndyPos(':', FRawForm[idx]); {Do not Localize}
  1431. end else begin
  1432. ColonFind := 1;
  1433. end;
  1434. end;
  1435. // Return idx to this property's (last) line {Do not Localize}
  1436. Dec(idx);
  1437. Data := QPCoder.DecodeString(Data);
  1438. // Now reorganise property so that it does not have a QP attribute.
  1439. ColonFind := IndyPos(';', Attribs); {Do not Localize}
  1440. Line := ''; {Do not Localize}
  1441. while ColonFind <> 0 do begin
  1442. Test := Copy(Attribs, 1, ColonFind);
  1443. if IndyPos('QUOTED-PRINTABLE', UpperCase(Test)) = 0 then begin {Do not Localize}
  1444. // Add to Line.
  1445. Line := Line + Test;
  1446. end;
  1447. Attribs := Copy(Attribs, ColonFind + 1, MaxInt);
  1448. ColonFind := IndyPos(';', Attribs); {Do not Localize}
  1449. end;
  1450. // Clean up variables
  1451. if Length(Attribs) <> 0 then begin
  1452. // Does Quoted-Printable occur in what's left? {Do not Localize}
  1453. if IndyPos('QUOTED-PRINTABLE', UpperCase(Attribs)) = 0 then begin {Do not Localize}
  1454. // Add to line
  1455. Line := Line + Attribs;
  1456. end;
  1457. end;
  1458. // Check if the last char of Line is a semi-colon. If so, remove it.
  1459. ColonFind := Length(Line);
  1460. If ColonFind > 0 then
  1461. begin
  1462. if Line[ColonFind] = ';' then begin {Do not Localize}
  1463. Line := Copy(Line, 1, ColonFind - 1);
  1464. end;
  1465. end;
  1466. Line := Line + ':' + Data; {Do not Localize}
  1467. end;
  1468. //**** End QP check & decode
  1469. Colon := IndyPos(':', Line); {Do not Localize}
  1470. SColon := IndyPos(';', Line); {Do not Localize}
  1471. if (Colon < SColon) or (SColon = 0) then begin
  1472. Line := ReplaceOnlyFirst(Line, ':', ';'); {Do not Localize}
  1473. end;
  1474. // Grab the property name
  1475. Test := Fetch(Line, ';'); {Do not Localize}
  1476. // Discover which property it is.
  1477. case PosInStrArray(Test, VCardProperties, False) of
  1478. {'FN'} {Do not Localize}
  1479. 0 : FFullName.FormattedName := Line + UnfoldLines;
  1480. {'N'} {Do not Localize}
  1481. 1 : ParseName(FFullName, Line + UnfoldLines);
  1482. {'NICKNAME'} {Do not Localize}
  1483. 2 : ParseDelimiterToStrings(FFullName.NickNames, Line + UnfoldLines);
  1484. {'PHOTO'} {Do not Localize}
  1485. 3 : ParseEmbeddedObject(FPhoto, Line);
  1486. {'BDAY'} {Do not Localize}
  1487. 4 : FBirthDay := GetDateTimeValue(Line + UnfoldLines);
  1488. {'ADR'} {Do not Localize}
  1489. 5 : ParseAddress(FAddresses.Add, Line + UnfoldLines);
  1490. {'LABEL'} {Do not Localize}
  1491. 6 : ParseMailingLabel(FMailingLabels.Add, Line + UnfoldLines);
  1492. {'TEL'} {Do not Localize}
  1493. 7 : ParseTelephone(FTelephones.Add, Line + UnfoldLines);
  1494. {'EMAIL'} {Do not Localize}
  1495. 8 : ParseEMailAddress(FEMailAddresses.Add, Line + UnfoldLines);
  1496. {'MAILER'} {Do not Localize}
  1497. 9 : FEMailProgram := Line + UnfoldLines;
  1498. {'TZ'} {Do not Localize}
  1499. 10 : FGeography.TimeZoneStr := Line + UnfoldLines;
  1500. {'GEO'} {Do not Localize}
  1501. 11 : ParseGeography(FGeography, Line + UnfoldLines);
  1502. {'TITLE'} {Do not Localize}
  1503. 12 : FBusinessInfo.Title := Line + UnfoldLines;
  1504. {'ROLE'} {Do not Localize}
  1505. 13 : FBusinessInfo.Role := Line + UnfoldLines;
  1506. {'LOGO'} {Do not Localize}
  1507. 14 : ParseEmbeddedObject (FLogo, Line);
  1508. {'AGENT'} {Do not Localize}
  1509. 15 : ProcessAgent;
  1510. {'ORG'} {Do not Localize}
  1511. 16 : ParseOrg(FBusinessInfo, Line + UnfoldLines);
  1512. {'CATEGORIES'} {Do not Localize}
  1513. 17 : ParseDelimiterToStrings(FCategories, Line + UnfoldLines);
  1514. {'NOTE'} {Do not Localize}
  1515. 18 : FComments.Add(Line + UnfoldLines);
  1516. {'PRODID' } {Do not Localize}
  1517. 19 : FProductID := Line + UnfoldLines;
  1518. {'REV'} {Do not Localize}
  1519. 20 : FLastRevised := GetDateTimeValue(Line + UnfoldLines);
  1520. {'SORT-STRING'} {Do not Localize}
  1521. 21 : FFullName.SortName := Line + UnfoldLines;
  1522. {'SOUND'} {Do not Localize}
  1523. 22 : ParseEmbeddedObject(FSound, Line);
  1524. {'URL'} {Do not Localize}
  1525. 23 : AddValueToStrings(FURLs, Line + UnfoldLines);
  1526. {'UID'} {Do not Localize}
  1527. 24 : FUniqueID := Line + UnfoldLines;
  1528. {'VERSION'} {Do not Localize}
  1529. 25 : FVCardVersion := IndyStrToFloat(Line + UnfoldLines);
  1530. {'CLASS'} {Do not Localize}
  1531. 26 : FClassification := Line + UnfoldLines;
  1532. {'KEY'} {Do not Localize}
  1533. 27 : ParseEmbeddedObject(FKey, Line);
  1534. end;
  1535. Inc(idx);
  1536. end;
  1537. finally
  1538. FreeAndNil(QPCoder);
  1539. end;
  1540. end;
  1541. { TIdVCardEMailAddresses }
  1542. function TIdVCardEMailAddresses.Add: TIdVCardEMailItem;
  1543. begin
  1544. Result := TIdVCardEMailItem(inherited Add);
  1545. end;
  1546. constructor TIdVCardEMailAddresses.Create(AOwner : TPersistent);
  1547. begin
  1548. inherited Create(AOwner, TIdVCardEMailItem);
  1549. end;
  1550. function TIdVCardEMailAddresses.GetItem(Index: Integer): TIdVCardEMailItem;
  1551. begin
  1552. Result := TIdVCardEMailItem(inherited Items[Index]);
  1553. end;
  1554. procedure TIdVCardEMailAddresses.SetItem(Index: Integer; const Value: TIdVCardEMailItem);
  1555. begin
  1556. inherited SetItem(Index, Value);
  1557. end;
  1558. { TIdVCardEMailItem }
  1559. procedure TIdVCardEMailItem.Assign(Source: TPersistent);
  1560. var
  1561. EMail : TIdVCardEMailItem;
  1562. begin
  1563. if Source is TIdVCardEMailItem then begin
  1564. EMail := Source as TIdVCardEMailItem;
  1565. EMailType := EMail.EMailType;
  1566. Preferred := EMail.Preferred;
  1567. Address := EMail.Address;
  1568. end else begin
  1569. inherited Assign(Source);
  1570. end;
  1571. end;
  1572. constructor TIdVCardEMailItem.Create(Collection: TCollection);
  1573. begin
  1574. inherited Create(Collection);
  1575. FEMailType := ematInternet;
  1576. end;
  1577. { TIdVCardAddresses }
  1578. function TIdVCardAddresses.Add: TIdCardAddressItem;
  1579. begin
  1580. Result := TIdCardAddressItem(inherited Add);
  1581. end;
  1582. constructor TIdVCardAddresses.Create(AOwner : TPersistent);
  1583. begin
  1584. inherited Create(AOwner, TIdCardAddressItem);
  1585. end;
  1586. function TIdVCardAddresses.GetItem(Index: Integer): TIdCardAddressItem;
  1587. begin
  1588. Result := TIdCardAddressItem(inherited Items[Index]);
  1589. end;
  1590. procedure TIdVCardAddresses.SetItem(Index: Integer; const Value: TIdCardAddressItem);
  1591. begin
  1592. inherited SetItem(Index, Value);
  1593. end;
  1594. { TIdVCardTelephones }
  1595. function TIdVCardTelephones.Add: TIdCardPhoneNumber;
  1596. begin
  1597. Result := TIdCardPhoneNumber(inherited Add);
  1598. end;
  1599. constructor TIdVCardTelephones.Create(AOwner : TPersistent);
  1600. begin
  1601. inherited Create(AOwner, TIdCardPhoneNumber);
  1602. end;
  1603. function TIdVCardTelephones.GetItem(Index: Integer): TIdCardPhoneNumber;
  1604. begin
  1605. Result := TIdCardPhoneNumber(inherited Items[Index]);
  1606. end;
  1607. procedure TIdVCardTelephones.SetItem(Index: Integer; const Value: TIdCardPhoneNumber);
  1608. begin
  1609. inherited SetItem(Index, Value);
  1610. end;
  1611. { TIdVCardName }
  1612. constructor TIdVCardName.Create;
  1613. begin
  1614. inherited Create;
  1615. FOtherNames := TStringList.Create;
  1616. FNickNames := TStringList.Create;
  1617. end;
  1618. destructor TIdVCardName.Destroy;
  1619. begin
  1620. FreeAndNil(FNickNames);
  1621. FreeAndNil(FOtherNames);
  1622. inherited Destroy;
  1623. end;
  1624. procedure TIdVCardName.SetNickNames(Value: TStrings);
  1625. begin
  1626. FNickNames.Assign(Value);
  1627. end;
  1628. procedure TIdVCardName.SetOtherNames(Value: TStrings);
  1629. begin
  1630. FOtherNames.Assign(Value);
  1631. end;
  1632. { TIdVCardBusinessInfo }
  1633. constructor TIdVCardBusinessInfo.Create;
  1634. begin
  1635. inherited Create;
  1636. FDivisions := TStringList.Create;
  1637. end;
  1638. destructor TIdVCardBusinessInfo.Destroy;
  1639. begin
  1640. FreeAndNil(FDivisions);
  1641. inherited Destroy;
  1642. end;
  1643. procedure TIdVCardBusinessInfo.SetDivisions(Value: TStrings);
  1644. begin
  1645. FDivisions.Assign(Value);
  1646. end;
  1647. { TIdVCardMailingLabelItem }
  1648. procedure TIdVCardMailingLabelItem.Assign(Source: TPersistent);
  1649. var
  1650. lbl : TIdVCardMailingLabelItem;
  1651. begin
  1652. if Source is TIdVCardMailingLabelItem then begin
  1653. lbl := Source as TIdVCardMailingLabelItem;
  1654. AddressAttributes := lbl.AddressAttributes;
  1655. MailingLabel.Assign(lbl.MailingLabel);
  1656. end else begin
  1657. inherited Assign(Source);
  1658. end;
  1659. end;
  1660. constructor TIdVCardMailingLabelItem.Create(Collection: TCollection);
  1661. begin
  1662. inherited Create(Collection);
  1663. FMailingLabel := TStringList.Create;
  1664. end;
  1665. destructor TIdVCardMailingLabelItem.Destroy;
  1666. begin
  1667. FreeAndNil(FMailingLabel);
  1668. inherited Destroy;
  1669. end;
  1670. procedure TIdVCardMailingLabelItem.SetMailingLabel(Value: TStrings);
  1671. begin
  1672. FMailingLabel.Assign(Value);
  1673. end;
  1674. { TIdVCardMailingLabels }
  1675. function TIdVCardMailingLabels.Add: TIdVCardMailingLabelItem;
  1676. begin
  1677. Result := TIdVCardMailingLabelItem(inherited Add);
  1678. end;
  1679. constructor TIdVCardMailingLabels.Create(AOwner: TPersistent);
  1680. begin
  1681. inherited Create(AOwner, TIdVCardMailingLabelItem);
  1682. end;
  1683. function TIdVCardMailingLabels.GetItem(Index: Integer): TIdVCardMailingLabelItem;
  1684. begin
  1685. Result := TIdVCardMailingLabelItem(inherited GetItem(Index));
  1686. end;
  1687. procedure TIdVCardMailingLabels.SetItem(Index: Integer; const Value: TIdVCardMailingLabelItem);
  1688. begin
  1689. inherited SetItem(Index, Value);
  1690. end;
  1691. { TIdEmbeddedObject }
  1692. constructor TIdVCardEmbeddedObject.Create;
  1693. begin
  1694. inherited Create;
  1695. FEmbeddedData := TStringList.Create;
  1696. end;
  1697. destructor TIdVCardEmbeddedObject.Destroy;
  1698. begin
  1699. FreeAndNil(FEmbeddedData);
  1700. inherited Destroy;
  1701. end;
  1702. procedure TIdVCardEmbeddedObject.SetEmbeddedData(const Value: TStrings);
  1703. begin
  1704. FEmbeddedData.Assign(Value);
  1705. end;
  1706. { TIdCardPhoneNumber }
  1707. procedure TIdCardPhoneNumber.Assign(Source: TPersistent);
  1708. var
  1709. Phone : TIdCardPhoneNumber;
  1710. begin
  1711. if Source is TIdCardPhoneNumber then begin
  1712. Phone := Source as TIdCardPhoneNumber;
  1713. PhoneAttributes := Phone.PhoneAttributes;
  1714. Number := Phone.Number;
  1715. end else begin
  1716. inherited Assign(Source);
  1717. end;
  1718. end;
  1719. { TIdCardAddressItem }
  1720. procedure TIdCardAddressItem.Assign(Source: TPersistent);
  1721. var
  1722. LAddr : TIdCardAddressItem;
  1723. begin
  1724. if Source is TIdCardAddressItem then begin
  1725. LAddr := Source as TIdCardAddressItem;
  1726. AddressAttributes := LAddr.AddressAttributes;
  1727. POBox := LAddr.POBox;
  1728. ExtendedAddress := LAddr.ExtendedAddress;
  1729. StreetAddress := LAddr.StreetAddress;
  1730. Locality := LAddr.Locality;
  1731. Region := LAddr.Region;
  1732. PostalCode := LAddr.PostalCode;
  1733. Nation := LAddr.Nation;
  1734. end else begin
  1735. inherited Assign(Source);
  1736. end;
  1737. end;
  1738. end.