IdVCard.pas 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952
  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. public
  343. constructor Create(AOwner: TComponent); override;
  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. implementation
  408. uses
  409. IdCoderQuotedPrintable,
  410. IdGlobalProtocols, SysUtils;
  411. const VCardProperties : array [0..27] of string = (
  412. 'FN', 'N', 'NICKNAME', 'PHOTO', {Do not Localize}
  413. 'BDAY', 'ADR', 'LABEL', 'TEL', {Do not Localize}
  414. 'EMAIL', 'MAILER', 'TZ', 'GEO', {Do not Localize}
  415. 'TITLE', 'ROLE', 'LOGO', 'AGENT', {Do not Localize}
  416. 'ORG', 'CATEGORIES', 'NOTE', 'PRODID', {Do not Localize}
  417. 'REV', 'SORT-STRING', 'SOUND', 'URL', {Do not Localize}
  418. 'UID', 'VERSION', 'CLASS', 'KEY' {Do not Localize}
  419. );
  420. { These constants are for testing the VCard for E-Mail types.
  421. Don't alter these } {Do not Localize}
  422. const EMailTypePropertyParameter : array [0..11] of string = (
  423. 'AOL', {America On-Line} {Do not Localize}
  424. 'APPLELINK', {AppleLink} {Do not Localize}
  425. 'ATTMAIL', { AT&T Mail } {Do not Localize}
  426. 'CIS', { CompuServe Information Service } {Do not Localize}
  427. 'EWORLD', { eWorld } {Do not Localize}
  428. 'INTERNET', {Internet SMTP (default) } {Do not Localize}
  429. 'IBMMAIL', { IBM Mail } {Do not Localize}
  430. 'MCIMAIL', { MCI Mail } {Do not Localize}
  431. 'POWERSHARE', { PowerShare } {Do not Localize}
  432. 'PRODIGY', { Prodigy information service } {Do not Localize}
  433. 'TLX', { Telex number } {Do not Localize}
  434. 'X400' { X.400 service } {Do not Localize}
  435. );
  436. //This is designed for decimals as written in the English language.
  437. //We require this because some protocols may require this as standard representation
  438. //for floats
  439. function IndyStrToFloat(const AStr: string): Extended;
  440. var
  441. LBuf : String;
  442. LHi, LLo : UInt32;
  443. i : Integer;
  444. begin
  445. LBuf := AStr;
  446. //strip off
  447. for i := Length(LBuf) downto 1 do begin
  448. if LBuf[i] = ',' then begin
  449. IdDelete(LBuf, i, 1);
  450. end;
  451. end;
  452. LHi := IndyStrToInt(Fetch(LBuf,'.'), 0);
  453. LBuf := PadString(LBuf, 2, '0');
  454. LLo := IndyStrToInt(Copy(LBuf,1,2), 0);
  455. Result := LHi + (LLo / 100);
  456. end;
  457. {This only adds Value to strs if it is not zero}
  458. procedure AddValueToStrings(strs : TStrings; Value : String);
  459. begin
  460. if Value <> '' then begin
  461. strs.Add(Value);
  462. end; // if Legnth ( Value ) then
  463. end;
  464. {This parses a delinated string into a TStrings}
  465. procedure ParseDelimiterToStrings(strs : TStrings; str : String; const Delimiter : Char = ','); {Do not Localize}
  466. begin
  467. while str <> '' do begin {Do not Localize}
  468. AddValueToStrings(strs, Fetch(str, Delimiter));
  469. end;
  470. end;
  471. {This parses time stamp from DateString and returns it as TDateTime
  472. Per RFC 2425 Section 5.8.4:
  473. date = date-fullyear ["-"] date-month ["-"] date-mday
  474. date-fullyear = 4 DIGIT
  475. date-month = 2 DIGIT ;01-12
  476. date-mday = 2 DIGIT ;01-28, 01-29, 01-30, 01-31
  477. ;based on month/year
  478. time = time-hour [":"] time-minute [":"] time-second [time-secfrac] [time-zone]
  479. time-hour = 2 DIGIT ;00-23
  480. time-minute = 2 DIGIT ;00-59
  481. time-second = 2 DIGIT ;00-60 (leap second)
  482. time-secfrac = "," 1*DIGIT
  483. time-zone = "Z" / time-numzone
  484. time-numzome = sign time-hour [":"] time-minute
  485. "date", "time", and "date-time": Each of these value types is based
  486. on a subset of the definitions in ISO 8601 standard. Profiles MAY
  487. place further restrictions on "date" and "time" values. Multiple
  488. "date" and "time" values can be specified using the comma-separated
  489. notation, unless restricted by a profile.
  490. Examples for "date":
  491. 1985-04-12
  492. 1996-08-05,1996-11-11
  493. 19850412
  494. Examples for "time":
  495. 10:22:00
  496. 102200
  497. 10:22:00.33
  498. 10:22:00.33Z
  499. 10:22:33,11:22:00
  500. 10:22:00-08:00
  501. Examples for "date-time":
  502. 1996-10-22T14:00:00Z
  503. 1996-08-11T12:34:56Z
  504. 19960811T123456Z
  505. 1996-10-22T14:00:00Z,1996-08-11T12:34:56Z
  506. Per RFC 2426 Section 4:
  507. date-value = <A single date value as defined in [MIME-DIR]>
  508. time-value = <A single time value as defined in [MIME-DIR]>
  509. date-time-value = <A single date-time value as defined in [MIME-DIR]
  510. [MIME-DIR] Howes, T., Smith, M., and F. Dawson, "A MIME Content-
  511. Type for Directory Information", RFC 2425, September
  512. 1998.
  513. Per RFC 6350 Section 4.3:
  514. "date", "time", "date-time", "date-and-or-time", and "timestamp":
  515. Each of these value types is based on the definitions in
  516. [ISO.8601.2004]. Multiple such values can be specified using the
  517. comma-separated notation.
  518. Only the basic format is supported.
  519. 4.3.1. DATE
  520. A calendar date as specified in [ISO.8601.2004], Section 4.1.2.
  521. Reduced accuracy, as specified in [ISO.8601.2004], Sections 4.1.2.3
  522. a) and b), but not c), is permitted.
  523. Expanded representation, as specified in [ISO.8601.2004], Section
  524. 4.1.4, is forbidden.
  525. Truncated representation, as specified in [ISO.8601.2000], Sections
  526. 5.2.1.3 d), e), and f), is permitted.
  527. Examples for "date":
  528. 19850412
  529. 1985-04
  530. 1985
  531. --0412
  532. ---12
  533. Note the use of YYYY-MM in the second example above. YYYYMM is
  534. disallowed to prevent confusion with YYMMDD. Note also that
  535. YYYY-MM-DD is disallowed since we are using the basic format instead
  536. of the extended format.
  537. 4.3.2. TIME
  538. A time of day as specified in [ISO.8601.2004], Section 4.2.
  539. Reduced accuracy, as specified in [ISO.8601.2004], Section 4.2.2.3,
  540. is permitted.
  541. Representation with decimal fraction, as specified in
  542. [ISO.8601.2004], Section 4.2.2.4, is forbidden.
  543. The midnight hour is always represented by 00, never 24 (see
  544. [ISO.8601.2004], Section 4.2.3).
  545. Truncated representation, as specified in [ISO.8601.2000], Sections
  546. 5.3.1.4 a), b), and c), is permitted.
  547. Examples for "time":
  548. 102200
  549. 1022
  550. 10
  551. -2200
  552. --00
  553. 102200Z
  554. 102200-0800
  555. 4.3.3. DATE-TIME
  556. A date and time of day combination as specified in [ISO.8601.2004],
  557. Section 4.3.
  558. Truncation of the date part, as specified in [ISO.8601.2000], Section
  559. 5.4.2 c), is permitted.
  560. Examples for "date-time":
  561. 19961022T140000
  562. --1022T1400
  563. ---22T14
  564. 4.3.4. DATE-AND-OR-TIME
  565. Either a DATE-TIME, a DATE, or a TIME value. To allow unambiguous
  566. interpretation, a stand-alone TIME value is always preceded by a "T".
  567. Examples for "date-and-or-time":
  568. 19961022T140000
  569. --1022T1400
  570. ---22T14
  571. 19850412
  572. 1985-04
  573. 1985
  574. --0412
  575. ---12
  576. T102200
  577. T1022
  578. T10
  579. T-2200
  580. T--00
  581. T102200Z
  582. T102200-0800
  583. 4.3.5. TIMESTAMP
  584. A complete date and time of day combination as specified in
  585. [ISO.8601.2004], Section 4.3.2.
  586. Examples for "timestamp":
  587. 19961022T140000
  588. 19961022T140000Z
  589. 19961022T140000-05
  590. 19961022T140000-0500
  591. }
  592. function ParseISO8601Date(const DateString: string; var VDate: TIdISO8601DateComps): Boolean;
  593. var
  594. Year, Month, Day: UInt16;
  595. Len: Integer;
  596. begin
  597. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  598. Result := False;
  599. VDate.Year := 0;
  600. VDate.Month := 0;
  601. VDate.Day := 0;
  602. Len := Length(DateString);
  603. if (Len >= 10) and
  604. IsNumeric(DateString, 4, 1) and CharEquals(DateString, 5, '-') and
  605. IsNumeric(DateString, 2, 6) and CharEquals(DateString, 8, '-') and
  606. IsNumeric(DateString, 2, 9) then
  607. begin
  608. Year := IndyStrToInt(Copy(DateString, 1, 4));
  609. Month := IndyStrToInt(Copy(DateString, 6, 2));
  610. Day := IndyStrToInt(Copy(DateString, 9, 2));
  611. Dec(Len, 10);
  612. end
  613. else if (Len >= 8) and IsNumeric(DateString, 8, 1) then
  614. begin
  615. Year := IndyStrToInt(Copy(DateString, 1, 4));
  616. Month := IndyStrToInt(Copy(DateString, 5, 2));
  617. Day := IndyStrToInt(Copy(DateString, 7, 2));
  618. Dec(Len, 8);
  619. end else
  620. begin
  621. Day := 1;
  622. if (Len >= 7) and
  623. IsNumeric(DateString, 4, 1) and CharEquals(DateString, 5, '-') and
  624. IsNumeric(DateString, 2, 6) then
  625. begin
  626. Year := IndyStrToInt(Copy(DateString, 1, 4));
  627. Month := IndyStrToInt(Copy(DateString, 6, 2));
  628. Dec(Len, 7);
  629. end
  630. else if (Len >= 4) and IsNumeric(DateString, 4, 1) then
  631. begin
  632. Month := 1;
  633. Year := IndyStrToInt(Copy(DateString, 1, 4));
  634. Dec(Len, 4);
  635. end
  636. else if (Len >= 4) and CharEquals(DateString, 1, '-') and CharEquals(DateString, 2, '-') then
  637. begin
  638. Year := 0;
  639. if (Len >= 7) and IsNumeric(DateString, 2, 3) and CharEquals(DateString, 5, '-') and
  640. IsNumeric(DateString, 2, 6) then
  641. begin
  642. Month := IndyStrToInt(Copy(DateString, 3, 2));
  643. Day := IndyStrToInt(Copy(DateString, 6, 2));
  644. Dec(Len, 7);
  645. end
  646. else if (Len >= 6) and IsNumeric(DateString, 4, 3) then
  647. begin
  648. Month := IndyStrToInt(Copy(DateString, 3, 2));
  649. Day := IndyStrToInt(Copy(DateString, 5, 2));
  650. Dec(Len, 6)
  651. end
  652. else if (Len >= 5) and CharEquals(DateString, 3, '-') and IsNumeric(DateString, 2, 4) then
  653. begin
  654. Month := 1;
  655. Day := IndyStrToInt(Copy(DateString, 4, 2));
  656. Dec(Len, 5);
  657. end
  658. else if (Len >= 4) and IsNumeric(DateString, 2, 3) then
  659. begin
  660. Month := IndyStrToInt(Copy(DateString, 3, 2));
  661. Day := 1;
  662. Dec(Len, 4);
  663. end else begin
  664. Exit;
  665. end;
  666. end else begin
  667. Exit;
  668. end;
  669. end;
  670. if Len > 0 then begin
  671. Exit;
  672. end;
  673. VDate.Year := Year;
  674. VDate.Month := Month;
  675. VDate.Day := Day;
  676. Result := True;
  677. end;
  678. function ParseISO8601Time(const DateString: string; var VTime: TIdISO8601TimeComps): Boolean;
  679. type
  680. eFracComp = (fracMin, fracSec, fracMSec);
  681. var
  682. Hour, Min, Sec, MSec: UInt16;
  683. Len, Offset, TmpOffset, TmpLen, I, Numerator, Denominator: Integer;
  684. LMultiplier: Single;
  685. FracComp: eFracComp;
  686. begin
  687. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  688. Result := False;
  689. VTime.Hour := 0;
  690. VTime.Min := 0;
  691. VTime.Sec := 0;
  692. VTime.MSec := 0;
  693. VTime.UTCOffset := '';
  694. Len := Length(DateString);
  695. MSec := 0;
  696. if (Len >= 8) and
  697. IsNumeric(DateString, 2, 1) and CharEquals(DateString, 3, ':') and
  698. IsNumeric(DateString, 2, 4) and CharEquals(DateString, 6, ':') and
  699. IsNumeric(DateString, 2, 7) then
  700. begin
  701. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  702. Min := IndyStrToInt(Copy(DateString, 4, 2));
  703. Sec := IndyStrToInt(Copy(DateString, 7, 2));
  704. Offset := 9;
  705. Dec(Len, 8);
  706. FracComp := fracMSec;
  707. end
  708. else if (Len >= 6) and IsNumeric(DateString, 6, 1) then
  709. begin
  710. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  711. Min := IndyStrToInt(Copy(DateString, 3, 2));
  712. Sec := IndyStrToInt(Copy(DateString, 5, 2));
  713. Offset := 7;
  714. Dec(Len, 6);
  715. FracComp := fracMSec;
  716. end
  717. else begin
  718. Sec := 0;
  719. if (Len >= 5) and
  720. IsNumeric(DateString, 2, 1) and CharEquals(DateString, 3, ':') and
  721. IsNumeric(DateString, 2, 4) then
  722. begin
  723. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  724. Min := IndyStrToInt(Copy(DateString, 4, 2));
  725. Offset := 6;
  726. Dec(Len, 5);
  727. FracComp := fracSec;
  728. end
  729. else if (Len >= 4) and IsNumeric(DateString, 4, 1) then
  730. begin
  731. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  732. Min := IndyStrToInt(Copy(DateString, 3, 2));
  733. Offset := 5;
  734. Dec(Len, 4);
  735. FracComp := fracSec;
  736. end else
  737. begin
  738. if (Len >= 2) and IsNumeric(DateString, 2, 1) then begin
  739. Min := 0;
  740. Hour := IndyStrToInt(Copy(DateString, 1, 2));
  741. Offset := 3;
  742. Dec(Len, 2);
  743. FracComp := fracMin;
  744. end
  745. else if (Len >= 3) and CharEquals(DateString, 1, '-') then
  746. begin
  747. Hour := 0;
  748. if (Len >= 6) and IsNumeric(DateString, 2, 2) and CharEquals(DateString, 4, ':') and
  749. IsNumeric(DateString, 2, 5) then
  750. begin
  751. Min := IndyStrToInt(Copy(DateString, 2, 2));
  752. Sec := IndyStrToInt(Copy(DateString, 5, 2));
  753. Offset := 7;
  754. Dec(Len, 6);
  755. FracComp := fracMSec;
  756. end
  757. else if (Len >= 5) and IsNumeric(DateString, 4, 2) then
  758. begin
  759. Min := IndyStrToInt(Copy(DateString, 2, 2));
  760. Sec := IndyStrToInt(Copy(DateString, 4, 2));
  761. Offset := 6;
  762. Dec(Len, 5);
  763. FracComp := fracMSec;
  764. end
  765. else if (Len >= 4) and CharEquals(DateString, 2, '-') and IsNumeric(DateString, 2, 3) then
  766. begin
  767. Min := 0;
  768. Sec := IndyStrToInt(Copy(DateString, 3, 2));
  769. Offset := 5;
  770. Dec(Len, 4);
  771. FracComp := fracMSec;
  772. end
  773. else if (Len >= 3) and IsNumeric(DateString, 2, 2) then
  774. begin
  775. Min := IndyStrToInt(Copy(DateString, 3, 2));
  776. Sec := 0;
  777. Offset := 4;
  778. Dec(Len, 3);
  779. FracComp := fracSec;
  780. end else begin
  781. Exit;
  782. end;
  783. end else begin
  784. Exit;
  785. end;
  786. end;
  787. end;
  788. if (Len > 0) and CharIsInSet(DateString, Offset, '.,') then
  789. begin
  790. Inc(Offset);
  791. Dec(Len);
  792. Numerator := 0;
  793. Denominator := 1;
  794. for I := 0 to 8 do
  795. begin
  796. if Len = 0 then begin
  797. Break;
  798. end;
  799. if not IsNumeric(DateString[Offset]) then begin
  800. Break;
  801. end;
  802. Numerator := (Numerator * 10) + (Ord(DateString[Offset]) - Ord('0'));
  803. if Numerator < 0 then begin // overflow
  804. Exit;
  805. end;
  806. Denominator := Denominator * 10;
  807. Inc(Offset);
  808. Dec(Len);
  809. end;
  810. LMultiplier := Numerator / Denominator;
  811. case FracComp of
  812. fracMin: begin
  813. Min := UInt16(Trunc(60 * LMultiplier));
  814. end;
  815. fracSec: begin
  816. Sec := UInt16(Trunc(60 * LMultiplier));
  817. end;
  818. fracMSec: begin
  819. MSec := UInt16(Trunc(1000 * LMultiplier));
  820. end;
  821. end;
  822. end;
  823. if Len > 0 then
  824. begin
  825. TmpOffset := Offset;
  826. TmpLen := Len;
  827. if not CharIsInSet(DateString, Offset, '+-') then
  828. begin
  829. // TODO: parse time zones other than "Z" into offsets
  830. if CharEquals(DateString, Offset, 'Z') then begin
  831. Dec(Len);
  832. end;
  833. end else
  834. begin
  835. Inc(Offset);
  836. Dec(Len);
  837. if (Len >= 5) and
  838. IsNumeric(DateString, 2, Offset) and CharEquals(DateString, Offset+2, ':') and
  839. IsNumeric(DateString, 2, Offset+3) then
  840. begin
  841. Dec(Len, 5);
  842. end
  843. else if (Len >= 4) and IsNumeric(DateString, 4, Offset) then
  844. begin
  845. Dec(Len, 4);
  846. end
  847. else if (Len >= 2) and IsNumeric(DateString, 2, Offset) then
  848. begin
  849. Dec(Len, 2);
  850. end
  851. else begin
  852. Exit;
  853. end;
  854. end;
  855. if Len > 0 then begin
  856. Exit;
  857. end;
  858. Offset := TmpOffset;
  859. Len := TmpLen;
  860. end;
  861. VTime.Hour := Hour;
  862. VTime.Min := Min;
  863. VTime.Sec := Sec;
  864. VTime.MSec := MSec;
  865. VTime.UTCOffset := Copy(DateString, Offset, Len);
  866. Result := True;
  867. end;
  868. function ParseISO8601DateTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  869. var
  870. I: Integer;
  871. begin
  872. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  873. Result := False;
  874. VDate.Year := 0;
  875. VDate.Month := 0;
  876. VDate.Day := 0;
  877. VTime.Hour := 0;
  878. VTime.Min := 0;
  879. VTime.Sec := 0;
  880. VTime.MSec := 0;
  881. VTime.UTCOffset := '';
  882. I := Pos('T', DateString);
  883. if I <> 0 then begin
  884. Result := ParseISO8601Date(Copy(DateString, 1, I-1), VDate) and
  885. ParseISO8601Time(Copy(DateString, I+1, MaxInt), VTime);
  886. end;
  887. end;
  888. function ParseISO8601DateAndOrTime(const DateString: string; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  889. var
  890. I: Integer;
  891. begin
  892. // TODO: move this logic into IdGlobalProtocols.RawStrInternetToDateTime().ParseISO8601()
  893. Result := False;
  894. VDate.Year := 0;
  895. VDate.Month := 0;
  896. VDate.Day := 0;
  897. VTime.Hour := 0;
  898. VTime.Min := 0;
  899. VTime.Sec := 0;
  900. VTime.MSec := 0;
  901. VTime.UTCOffset := '';
  902. I := Pos('T', DateString);
  903. if I = 0 then begin
  904. Result := ParseISO8601Date(DateString, VDate);
  905. Exit;
  906. end;
  907. if I > 1 then begin
  908. if not ParseISO8601Date(Copy(DateString, 1, I-1), VDate) then begin
  909. Exit;
  910. end;
  911. end;
  912. if not ParseISO8601Time(Copy(DateString, I+1, MaxInt), VTime) then begin
  913. Exit;
  914. end;
  915. Result := True;
  916. end;
  917. function ParseISO8601DateTimeStamp(const DateString: String; var VDate: TIdISO8601DateComps; var VTime: TIdISO8601TimeComps): Boolean;
  918. {$IFDEF USE_INLINE}inline;{$ENDIF}
  919. begin
  920. // TODO: how is TIMESTAMP different from DATE-TIME?
  921. Result := ParseISO8601DateTime(DateString, VDate, VTime);
  922. end;
  923. {This function returns a stringList with an item's
  924. attributes and sets value to the value of the item}
  925. function GetAttributesAndValue(Data : String; var Value : String) : TStringList;
  926. var
  927. Buff, Buff2 : String;
  928. begin
  929. Result := TStringList.Create;
  930. try
  931. if IndyPos(':', Data) <> 0 then {Do not Localize}
  932. begin
  933. Buff := Fetch(Data, ':'); {Do not Localize}
  934. {This handles a VCard property attribute delimiter ","}
  935. Buff := ReplaceAll(Buff, ',', ';'); {Do not Localize}
  936. while Buff <> '' do begin {Do not Localize}
  937. Buff2 := Fetch(Buff, ';'); {Do not Localize}
  938. if Buff2 <> '' then begin
  939. Result.Add(Buff2);
  940. end;
  941. end;
  942. end;
  943. Value := Data;
  944. except
  945. Result.Free;
  946. raise;
  947. end;
  948. end;
  949. {This parses the organization line from OrgString into}
  950. procedure ParseOrg(OrgObj : TIdVCardBusinessInfo; OrgStr : String);
  951. begin
  952. { Organization name }
  953. OrgObj.Organization := Fetch(OrgStr, ';');
  954. { Divisions }
  955. ParseDelimiterToStrings(OrgObj.Divisions, OrgStr, ';'); {Do not Localize}
  956. end;
  957. {This parses the geography latitude and longitude from GeogStr and
  958. puts it in Geog}
  959. procedure ParseGeography(Geog : TIdVCardGeog; GeogStr : String);
  960. begin
  961. {Latitude}
  962. Geog.Latitude := IndyStrToFloat(Fetch(GeogStr, ';')); {Do not Localize}
  963. {Longitude}
  964. Geog.Longitude := IndyStrToFloat(Fetch(GeogStr, ';')); {Do not Localize}
  965. end;
  966. {This parses PhoneStr and places the attributes in PhoneObj }
  967. procedure ParseTelephone(PhoneObj : TIdCardPhoneNumber; PhoneStr : String);
  968. const
  969. TelephoneTypePropertyParameter : array [0..13] of string = (
  970. 'HOME', 'MSG', 'WORK', 'PREF', 'VOICE', 'FAX', {Do not Localize}
  971. 'CELL', 'VIDEO', 'BBS', 'MODEM', 'CAR', 'ISDN', {Do not Localize}
  972. 'PCS', 'PAGER' {Do not Localize}
  973. );
  974. var
  975. Value : String;
  976. idx : Integer;
  977. Attribs : TStringList;
  978. begin
  979. attribs := GetAttributesAndValue(PhoneStr, Value);
  980. try
  981. for idx := 0 to Attribs.Count-1 do begin
  982. case PosInStrArray(attribs[idx], TelephoneTypePropertyParameter, False) of
  983. { home }
  984. 0 : Include(PhoneObj.FPhoneAttributes, tpaHome);
  985. { voice messaging }
  986. 1 : Include(PhoneObj.FPhoneAttributes, tpaVoiceMessaging);
  987. { work }
  988. 2 : Include(PhoneObj.FPhoneAttributes, tpaWork);
  989. { preferred }
  990. 3 : Include(PhoneObj.FPhoneAttributes, tpaPreferred);
  991. { Voice }
  992. 4 : Include(PhoneObj.FPhoneAttributes, tpaVoice);
  993. { Fax }
  994. 5 : Include(PhoneObj.FPhoneAttributes, tpaFax);
  995. { Cellular phone }
  996. 6 : Include(PhoneObj.FPhoneAttributes, tpaCellular);
  997. { Video conferancing number }
  998. 7 : Include(PhoneObj.FPhoneAttributes, tpaVideo);
  999. { Bulleton Board System (BBS) telephone number }
  1000. 8 : Include(PhoneObj.FPhoneAttributes, tpaBBS);
  1001. { MODEM Connection number }
  1002. 9 : Include(PhoneObj.FPhoneAttributes, tpaModem);
  1003. { Car phone number }
  1004. 10 : Include(PhoneObj.FPhoneAttributes, tpaCar);
  1005. { ISDN Service Number }
  1006. 11 : Include(PhoneObj.FPhoneAttributes, tpaISDN);
  1007. { personal communication services telephone number }
  1008. 12 : Include(PhoneObj.FPhoneAttributes, tpaPCS);
  1009. { pager }
  1010. 13 : Include(PhoneObj.FPhoneAttributes, tpaPager);
  1011. end;
  1012. end;
  1013. { default telephon number }
  1014. if Attribs.Count = 0 then begin
  1015. PhoneObj.PhoneAttributes := [tpaVoice];
  1016. end;
  1017. PhoneObj.Number := Value;
  1018. finally
  1019. attribs.Free;
  1020. end;
  1021. end;
  1022. {This parses AddressStr and places the attributes in AddressObj }
  1023. procedure ParseAddress(AddressObj : TIdCardAddressItem; AddressStr : String);
  1024. const
  1025. AttribsArray : array[0..6] of String = (
  1026. 'HOME', 'DOM', 'INTL', 'POSTAL', 'PARCEL', 'WORK', 'PREF' {Do not Localize}
  1027. );
  1028. var
  1029. Value : String;
  1030. Attribs : TStringList;
  1031. idx : Integer;
  1032. begin
  1033. Attribs := GetAttributesAndValue(AddressStr, Value);
  1034. try
  1035. for idx := 0 to Attribs.Count-1 do begin
  1036. case PosInStrArray(attribs[idx], AttribsArray, False) of
  1037. { home }
  1038. 0 : Include(AddressObj.FAddressAttributes, tatHome);
  1039. { domestic }
  1040. 1 : Include(AddressObj.FAddressAttributes, tatDomestic);
  1041. { international }
  1042. 2 : Include(AddressObj.FAddressAttributes, tatInternational);
  1043. { Postal }
  1044. 3 : Include(AddressObj.FAddressAttributes, tatPostal);
  1045. { Parcel }
  1046. 4 : Include(AddressObj.FAddressAttributes, tatParcel);
  1047. { Work }
  1048. 5 : Include(AddressObj.FAddressAttributes, tatWork);
  1049. { Preferred }
  1050. 6 : Include(AddressObj.FAddressAttributes, tatPreferred);
  1051. end;
  1052. end;
  1053. if Attribs.Count = 0 then begin
  1054. AddressObj.AddressAttributes := [tatInternational, tatPostal, tatParcel, tatWork];
  1055. end;
  1056. AddressObj.POBox := Fetch(Value, ';'); {Do not Localize}
  1057. AddressObj.ExtendedAddress := Fetch(Value, ';'); {Do not Localize}
  1058. AddressObj.StreetAddress := Fetch(Value, ';'); {Do not Localize}
  1059. AddressObj.Locality := Fetch(Value, ';'); {Do not Localize}
  1060. AddressObj.Region := Fetch (Value, ';'); {Do not Localize}
  1061. AddressObj.PostalCode := Fetch(Value, ';'); {Do not Localize}
  1062. AddressObj.Nation := Fetch (Value, ';'); {Do not Localize}
  1063. finally
  1064. Attribs.Free;
  1065. end;
  1066. end;
  1067. {This parses LabelStr and places the attributes in TIdVCardMailingLabelItem }
  1068. procedure ParseMailingLabel(LabelObj : TIdVCardMailingLabelItem; LabelStr : String);
  1069. const
  1070. AttribsArray : array[0..6] of String = (
  1071. 'HOME', 'DOM', 'INTL', 'POSTAL', 'PARCEL', 'WORK', 'PREF' {Do not Localize}
  1072. );
  1073. var
  1074. Value : String;
  1075. Attribs : TStringList;
  1076. idx : Integer;
  1077. begin
  1078. Attribs := GetAttributesAndValue(LabelStr, Value);
  1079. try
  1080. for idx := 0 to Attribs.Count-1 do begin
  1081. case PosInStrArray(attribs[idx], AttribsArray, False) of
  1082. { home }
  1083. 0 : Include(LabelObj.FAddressAttributes, tatHome);
  1084. { domestic }
  1085. 1 : Include(LabelObj.FAddressAttributes, tatDomestic);
  1086. { international }
  1087. 2 : Include(LabelObj.FAddressAttributes, tatInternational);
  1088. { Postal }
  1089. 3 : Include(LabelObj.FAddressAttributes, tatPostal);
  1090. { Parcel }
  1091. 4 : Include(LabelObj.FAddressAttributes, tatParcel);
  1092. { Work }
  1093. 5 : Include(LabelObj.FAddressAttributes, tatWork);
  1094. { Preferred }
  1095. 6 : Include(LabelObj.FAddressAttributes, tatPreferred);
  1096. end;
  1097. end;
  1098. {Default Values}
  1099. if Attribs.Count = 0 then begin
  1100. LabelObj.AddressAttributes := [tatInternational, tatPostal, tatParcel, tatWork];
  1101. end;
  1102. LabelObj.MailingLabel.Add(Value);
  1103. finally
  1104. Attribs.Free;
  1105. end;
  1106. end;
  1107. {This parses the Name and places the name in the TIdVCardName}
  1108. procedure ParseName(NameObj : TIdVCardName; NameStr : String);
  1109. var
  1110. OtherNames : String;
  1111. begin
  1112. { surname }
  1113. NameObj.SurName := Fetch(NameStr, ';'); {Do not Localize}
  1114. { first name }
  1115. NameObj.FirstName := Fetch(NameStr, ';'); {Do not Localize}
  1116. { middle and other names}
  1117. OtherNames := Fetch(NameStr, ';'); {Do not Localize}
  1118. { Prefix }
  1119. NameObj.Prefix := Fetch(NameStr, ';'); {Do not Localize}
  1120. { Suffix }
  1121. NameObj.Suffix := Fetch(NameStr, ';'); {Do not Localize}
  1122. OtherNames := ReplaceAll(OtherNames, ' ', ','); {Do not Localize}
  1123. ParseDelimiterToStrings(NameObj.OtherNames, OtherNames);
  1124. end;
  1125. {This parses EMailStr and places the attributes in EMailObj }
  1126. procedure ParseEMailAddress(EMailObj : TIdVCardEMailItem; EMailStr : String);
  1127. var
  1128. Value : String;
  1129. Attribs : TStringList;
  1130. idx : Integer;
  1131. {this is for testing the type so we can break out of the loop}
  1132. ps : Integer;
  1133. function IsPreferred: Boolean;
  1134. var
  1135. idx2: Integer;
  1136. begin
  1137. for idx2 := 0 to Attribs.Count-1 do begin
  1138. if TextIsSame(Attribs[idx2], 'PREF') then begin {Do not Localize}
  1139. Result := True;
  1140. Exit;
  1141. end;
  1142. end;
  1143. Result := False;
  1144. end;
  1145. begin
  1146. Attribs := GetAttributesAndValue (EMailStr, Value);
  1147. try
  1148. EMailObj.Address := Value;
  1149. EMailObj.Preferred := IsPreferred;
  1150. for idx := 0 to Attribs.Count-1 do begin
  1151. ps := PosInStrArray(Attribs[idx], EMailTypePropertyParameter);
  1152. if ps <> -1 then begin
  1153. case ps of
  1154. 0 : EMailObj.EMailType := ematAOL; {America On-Line}
  1155. 1 : EMailObj.EMailType := ematAppleLink; {AppleLink}
  1156. 2 : EMailObj.EMailType := ematATT; { AT&T Mail }
  1157. 3 : EMailObj.EMailType := ematCIS; { CompuServe Information Service }
  1158. 4 : EMailObj.EMailType := emateWorld; { eWorld }
  1159. 5 : EMailObj.EMailType := ematInternet; {Internet SMTP (default)}
  1160. 6 : EMailObj.EMailType := ematIBMMail; { IBM Mail }
  1161. 7 : EMailObj.EMailType := ematMCIMail; { Indicates MCI Mail }
  1162. 8 : EMailObj.EMailType := ematPowerShare; { PowerShare }
  1163. 9 : EMailObj.EMailType := ematProdigy; { Prodigy information service }
  1164. 10 : EMailObj.EMailType := ematTelex; { Telex number }
  1165. 11 : EMailObj.EMailType := ematX400; { X.400 service }
  1166. end;
  1167. Break;
  1168. end;
  1169. end;
  1170. finally
  1171. Attribs.Free;
  1172. end;
  1173. end;
  1174. { TIdVCard }
  1175. constructor TIdVCard.Create(AOwner: TComponent);
  1176. begin
  1177. inherited Create(AOwner);
  1178. FPhoto := TIdVCardEmbeddedObject.Create;
  1179. FLogo := TIdVCardEmbeddedObject.Create;
  1180. FSound := TIdVCardEmbeddedObject.Create;
  1181. FKey := TIdVCardEmbeddedObject.Create;
  1182. FComments := TStringList.Create;
  1183. FCategories := TStringList.Create;
  1184. FBusinessInfo := TIdVCardBusinessInfo.Create;
  1185. FGeography := TIdVCardGeog.Create;
  1186. FFullName := TIdVCardName.Create;
  1187. FRawForm := TStringList.Create;
  1188. FEMailAddresses := TIdVCardEMailAddresses.Create(Self);
  1189. FAddresses := TIdVCardAddresses.Create(Self);
  1190. FTelephones := TIdVCardTelephones.Create(Self);
  1191. FURLs := TStringList.Create;
  1192. FMailingLabels := TIdVCardMailingLabels.Create(Self);
  1193. end;
  1194. destructor TIdVCard.Destroy;
  1195. begin
  1196. FKey.Free;
  1197. FPhoto.Free;
  1198. FLogo.Free;
  1199. FSound.Free;
  1200. FComments.Free;
  1201. FMailingLabels.Free;
  1202. FCategories.Free;
  1203. FBusinessInfo.Free;
  1204. FGeography.Free;
  1205. FURLs.Free;
  1206. FTelephones.Free;
  1207. FAddresses.Free;
  1208. FEMailAddresses.Free;
  1209. FFullName.Free;
  1210. FRawForm.Free;
  1211. inherited Destroy;
  1212. end;
  1213. procedure TIdVCard.ReadFromStrings(s: TStrings);
  1214. var
  1215. idx, level : Integer;
  1216. begin
  1217. FRawForm.Clear;
  1218. {Find the begin mark and accomodate broken VCard implemntations}
  1219. level := 0;
  1220. for idx := 0 to s.Count-1 do begin
  1221. if TextIsSame(Trim(s[idx]), 'BEGIN:VCARD') then begin {Do not Localize}
  1222. Break;
  1223. end;
  1224. end;
  1225. {Keep adding until end VCard }
  1226. while idx < s.Count do begin
  1227. if s[idx] <> '' then begin
  1228. case PosInStrArray(Trim(s[idx]), ['BEGIN:VCARD', 'END:VCARD'], False) of {Do not Localize}
  1229. 0: begin
  1230. // Have a new object - increment the counter & add
  1231. Inc(level);
  1232. end;
  1233. 1: begin
  1234. // Have an END:
  1235. Dec(level);
  1236. end;
  1237. end;
  1238. // regardless of content, add it
  1239. FRawForm.Add(s[idx]);
  1240. if level < 1 then begin
  1241. Break;
  1242. end;
  1243. end;
  1244. Inc(idx);
  1245. end;
  1246. SetVariablesAfterRead;
  1247. end;
  1248. procedure TIdVCard.SetCategories(Value: TStrings);
  1249. begin
  1250. FCategories.Assign(Value);
  1251. end;
  1252. procedure TIdVCard.SetComments(Value: TStrings);
  1253. begin
  1254. FComments.Assign(Value);
  1255. end;
  1256. procedure TIdVCard.SetURLs(Value: TStrings);
  1257. begin
  1258. FURLs.Assign(Value);
  1259. end;
  1260. procedure TIdVCard.SetVariablesAfterRead;
  1261. var
  1262. idx : Integer;
  1263. // OrigLine : String;
  1264. Line : String;
  1265. Attribs : String;
  1266. Data : String;
  1267. Test : String;
  1268. Colon : Integer;
  1269. SColon : Integer;
  1270. ColonFind : Integer;
  1271. QPCoder : TIdDecoderQuotedPrintable;
  1272. {These subroutines increment idx to prevent unneded comparisons of folded lines}
  1273. function UnfoldLines : String;
  1274. begin
  1275. Result := ''; {Do not Localize}
  1276. Inc(idx);
  1277. while (idx < FRawForm.Count) and CharIsInSet(FRawForm[idx], 1, ' '#9) do {Do not Localize}
  1278. begin
  1279. Result := Result + Trim(FRawForm[idx]);
  1280. Inc(idx);
  1281. end; // while
  1282. {Correct for increment in the main while loop}
  1283. Dec(idx);
  1284. end;
  1285. procedure ProcessAgent;
  1286. begin
  1287. // The current idx of FRawForm could be an embedded vCard.
  1288. { TODO : Eliminate embedded vCard }
  1289. end;
  1290. procedure ParseEmbeddedObject(EmObj : TIdVCardEmbeddedObject; StLn : String);
  1291. var
  1292. Value : String;
  1293. LAttribs : TStringList;
  1294. idx2 : Integer;
  1295. {this is for testing the type so we can break out of the loop}
  1296. begin
  1297. LAttribs := GetAttributesAndValue(StLn, Value);
  1298. try
  1299. for idx2 := 0 to LAttribs.Count-1 do begin
  1300. if PosInStrArray(LAttribs[idx2], ['ENCODING=BASE64', 'BASE64']) <> -1 then begin {Do not Localize}
  1301. emObj.Base64Encoded := True;
  1302. end
  1303. else if PosInStrArray(LAttribs[idx2], ['VALUE=URI', 'VALUE=URL', 'URI', 'URL']) = -1 then begin {Do not Localize}
  1304. emObj.ObjectType := LAttribs[idx2];
  1305. end;
  1306. end;
  1307. if (LAttribs.IndexOf('VALUE=URI') > -1) or {Do not Localize}
  1308. (LAttribs.IndexOf('VALUE=URL') > -1) or {Do not Localize}
  1309. (LAttribs.IndexOf('URI') > -1) or {Do not Localize}
  1310. (LAttribs.IndexOf('URL') > -1) then {Do not Localize}
  1311. begin
  1312. emObj.ObjectURL := Value + UnfoldLines;
  1313. end else begin
  1314. AddValueToStrings(EmObj.EmbeddedData, Value);
  1315. {Add any folded lines}
  1316. Inc(idx);
  1317. while (idx < FRawForm.Count) and CharIsInSet(FRawForm[idx], 1, ' '#9) do begin {Do not Localize}
  1318. AddValueToStrings(EmObj.EmbeddedData, Trim(FRawForm[idx]));
  1319. Inc(idx);
  1320. end;
  1321. {Correct for increment in the main while loop}
  1322. Dec(idx);
  1323. end;
  1324. finally
  1325. LAttribs.Free;
  1326. end;
  1327. end;
  1328. function GetDateTimeValue(St: String): TDateTime;
  1329. var
  1330. LAttribs: String;
  1331. LDate: TIdISO8601DateComps;
  1332. LTime: TIdISO8601TimeComps;
  1333. begin
  1334. Result := 0.0;
  1335. // TODO: parse the attributes into a proper list
  1336. LAttribs := UpperCase(Attribs);
  1337. if IndyPos('TIMESTAMP', LAttribs) <> 0 then begin {Do not Localize}
  1338. if ParseISO8601DateTimeStamp(St, LDate, LTime) then begin
  1339. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day) + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1340. // TODO: use LTime.UTCOffset if available
  1341. end;
  1342. end
  1343. else if IndyPos('DATE-AND-OR-TIME', LAttribs) <> 0 then begin {Do not Localize}
  1344. if ParseISO8601DateAndOrTime(st, LDate, LTime) then begin
  1345. if (LDate.Year <> 0) or (LDate.Month <> 0) or (LDate.Day <> 0) then begin
  1346. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1347. end;
  1348. if (LTime.Hour <> 0) or (LTime.Min <> 0) or (LTime.Sec <> 0) or (LTime.MSec <> 0) then begin
  1349. Result := Result + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1350. // TODO: use LTime.UTCOffset if available
  1351. end;
  1352. end;
  1353. end
  1354. else if IndyPos('DATE-TIME', LAttribs) <> 0 then begin {Do not Localize}
  1355. if ParseISO8601DateTime(st, LDate, LTime) then begin
  1356. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day) + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1357. // TODO: use LTime.UTCOffset if available
  1358. end;
  1359. end
  1360. else if IndyPos('DATE', LAttribs) <> 0 then begin {Do not Localize}
  1361. if ParseISO8601Date(st, LDate) then begin
  1362. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1363. end;
  1364. end
  1365. else if IndyPos('TIME', LAttribs) <> 0 then begin {Do not Localize}
  1366. if ParseISO8601Time(st, LTime) then begin
  1367. Result := EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1368. // TODO: use LTime.UTCOffset if available
  1369. end;
  1370. end else begin
  1371. if ParseISO8601DateAndOrTime(st, LDate, LTime) then begin
  1372. if (LDate.Year <> 0) or (LDate.Month <> 0) or (LDate.Day <> 0) then begin
  1373. Result := EncodeDate(LDate.Year, LDate.Month, LDate.Day);
  1374. end;
  1375. if (LTime.Hour <> 0) or (LTime.Min <> 0) or (LTime.Sec <> 0) or (LTime.MSec <> 0) then begin
  1376. Result := Result + EncodeTime(LTime.Hour, LTime.Min, LTime.Sec, LTime.MSec);
  1377. // TODO: use LTime.UTCOffset if available
  1378. end;
  1379. end;
  1380. end;
  1381. end;
  1382. begin
  1383. // At this point, FRawForm contains the entire vCard - including possible
  1384. // embedded vCards.
  1385. QPCoder := TIdDecoderQuotedPrintable.Create(Self);
  1386. try
  1387. idx := 0;
  1388. while idx < FRawForm.Count do
  1389. begin
  1390. // Grab the line
  1391. Line := FRawForm[idx];
  1392. {We separate the property name from the parameters and values here.
  1393. We have be careful because sometimes a property in a vCard is separed by a
  1394. ; or : even if the RFC and standards don't permit this
  1395. - broken VCard creation tools }
  1396. Colon := IndyPos(':', Line); {Do not Localize}
  1397. // Store the property & complete attributes
  1398. // TODO: use a TStringList instead...
  1399. Attribs := Copy(Line, 1, Colon - 1);
  1400. // Must now check for Quoted-printable attribute. vCard v2.1 allows
  1401. // QP to be used in any field.
  1402. //**** Begin QP check & decode
  1403. if IndyPos('QUOTED-PRINTABLE', UpperCase(Attribs)) > 0 then begin {Do not Localize}
  1404. // First things first - make a copy of the Line.
  1405. // OrigLine := Line;
  1406. // Set Data to be the data contained on this line of the vCard
  1407. Data := Copy(Line, Colon + 1, MaxInt);
  1408. // The problem with QP-embedded objects is that the Colon character is
  1409. // not standard QP-encoded... however, it is the only reliable way to
  1410. // discover the next property. So loop here until the next property is
  1411. // found (i.e., the next line with a colon).
  1412. Inc(idx);
  1413. ColonFind := IndyPos(':', FRawForm[idx]); {Do not Localize}
  1414. while ColonFind = 0 do begin
  1415. Data := Data + TrimLeft(FRawForm[idx]);
  1416. Inc(idx);
  1417. if idx <> FRawForm.Count then begin
  1418. ColonFind := IndyPos(':', FRawForm[idx]); {Do not Localize}
  1419. end else begin
  1420. ColonFind := 1;
  1421. end;
  1422. end;
  1423. // Return idx to this property's (last) line {Do not Localize}
  1424. Dec(idx);
  1425. Data := QPCoder.DecodeString(Data);
  1426. // Now reorganise property so that it does not have a QP attribute.
  1427. ColonFind := IndyPos(';', Attribs); {Do not Localize}
  1428. Line := ''; {Do not Localize}
  1429. while ColonFind <> 0 do begin
  1430. Test := Copy(Attribs, 1, ColonFind);
  1431. if IndyPos('QUOTED-PRINTABLE', UpperCase(Test)) = 0 then begin {Do not Localize}
  1432. // Add to Line.
  1433. Line := Line + Test;
  1434. end;
  1435. Attribs := Copy(Attribs, ColonFind + 1, MaxInt);
  1436. ColonFind := IndyPos(';', Attribs); {Do not Localize}
  1437. end;
  1438. // Clean up variables
  1439. if Attribs <> '' then begin
  1440. // Does Quoted-Printable occur in what's left? {Do not Localize}
  1441. if IndyPos('QUOTED-PRINTABLE', UpperCase(Attribs)) = 0 then begin {Do not Localize}
  1442. // Add to line
  1443. Line := Line + Attribs;
  1444. end;
  1445. end;
  1446. // Check if the last char of Line is a semi-colon. If so, remove it.
  1447. ColonFind := Length(Line);
  1448. If ColonFind > 0 then
  1449. begin
  1450. if Line[ColonFind] = ';' then begin {Do not Localize}
  1451. Line := Copy(Line, 1, ColonFind - 1);
  1452. end;
  1453. end;
  1454. Line := Line + ':' + Data; {Do not Localize}
  1455. end;
  1456. //**** End QP check & decode
  1457. Colon := IndyPos(':', Line); {Do not Localize}
  1458. SColon := IndyPos(';', Line); {Do not Localize}
  1459. if (Colon < SColon) or (SColon = 0) then begin
  1460. Line := ReplaceOnlyFirst(Line, ':', ';'); {Do not Localize}
  1461. end;
  1462. // Grab the property name
  1463. Test := Fetch(Line, ';'); {Do not Localize}
  1464. // Discover which property it is.
  1465. case PosInStrArray(Test, VCardProperties, False) of
  1466. {'FN'} {Do not Localize}
  1467. 0 : FFullName.FormattedName := Line + UnfoldLines;
  1468. {'N'} {Do not Localize}
  1469. 1 : ParseName(FFullName, Line + UnfoldLines);
  1470. {'NICKNAME'} {Do not Localize}
  1471. 2 : ParseDelimiterToStrings(FFullName.NickNames, Line + UnfoldLines);
  1472. {'PHOTO'} {Do not Localize}
  1473. 3 : ParseEmbeddedObject(FPhoto, Line);
  1474. {'BDAY'} {Do not Localize}
  1475. 4 : FBirthDay := GetDateTimeValue(Line + UnfoldLines);
  1476. {'ADR'} {Do not Localize}
  1477. 5 : ParseAddress(FAddresses.Add, Line + UnfoldLines);
  1478. {'LABEL'} {Do not Localize}
  1479. 6 : ParseMailingLabel(FMailingLabels.Add, Line + UnfoldLines);
  1480. {'TEL'} {Do not Localize}
  1481. 7 : ParseTelephone(FTelephones.Add, Line + UnfoldLines);
  1482. {'EMAIL'} {Do not Localize}
  1483. 8 : ParseEMailAddress(FEMailAddresses.Add, Line + UnfoldLines);
  1484. {'MAILER'} {Do not Localize}
  1485. 9 : FEMailProgram := Line + UnfoldLines;
  1486. {'TZ'} {Do not Localize}
  1487. 10 : FGeography.TimeZoneStr := Line + UnfoldLines;
  1488. {'GEO'} {Do not Localize}
  1489. 11 : ParseGeography(FGeography, Line + UnfoldLines);
  1490. {'TITLE'} {Do not Localize}
  1491. 12 : FBusinessInfo.Title := Line + UnfoldLines;
  1492. {'ROLE'} {Do not Localize}
  1493. 13 : FBusinessInfo.Role := Line + UnfoldLines;
  1494. {'LOGO'} {Do not Localize}
  1495. 14 : ParseEmbeddedObject (FLogo, Line);
  1496. {'AGENT'} {Do not Localize}
  1497. 15 : ProcessAgent;
  1498. {'ORG'} {Do not Localize}
  1499. 16 : ParseOrg(FBusinessInfo, Line + UnfoldLines);
  1500. {'CATEGORIES'} {Do not Localize}
  1501. 17 : ParseDelimiterToStrings(FCategories, Line + UnfoldLines);
  1502. {'NOTE'} {Do not Localize}
  1503. 18 : FComments.Add(Line + UnfoldLines);
  1504. {'PRODID' } {Do not Localize}
  1505. 19 : FProductID := Line + UnfoldLines;
  1506. {'REV'} {Do not Localize}
  1507. 20 : FLastRevised := GetDateTimeValue(Line + UnfoldLines);
  1508. {'SORT-STRING'} {Do not Localize}
  1509. 21 : FFullName.SortName := Line + UnfoldLines;
  1510. {'SOUND'} {Do not Localize}
  1511. 22 : ParseEmbeddedObject(FSound, Line);
  1512. {'URL'} {Do not Localize}
  1513. 23 : AddValueToStrings(FURLs, Line + UnfoldLines);
  1514. {'UID'} {Do not Localize}
  1515. 24 : FUniqueID := Line + UnfoldLines;
  1516. {'VERSION'} {Do not Localize}
  1517. 25 : FVCardVersion := IndyStrToFloat(Line + UnfoldLines);
  1518. {'CLASS'} {Do not Localize}
  1519. 26 : FClassification := Line + UnfoldLines;
  1520. {'KEY'} {Do not Localize}
  1521. 27 : ParseEmbeddedObject(FKey, Line);
  1522. end;
  1523. Inc(idx);
  1524. end;
  1525. finally
  1526. QPCoder.Free;
  1527. end;
  1528. end;
  1529. { TIdVCardEMailAddresses }
  1530. function TIdVCardEMailAddresses.Add: TIdVCardEMailItem;
  1531. begin
  1532. Result := TIdVCardEMailItem(inherited Add);
  1533. end;
  1534. constructor TIdVCardEMailAddresses.Create(AOwner : TPersistent);
  1535. begin
  1536. inherited Create(AOwner, TIdVCardEMailItem);
  1537. end;
  1538. function TIdVCardEMailAddresses.GetItem(Index: Integer): TIdVCardEMailItem;
  1539. begin
  1540. Result := TIdVCardEMailItem(inherited Items[Index]);
  1541. end;
  1542. procedure TIdVCardEMailAddresses.SetItem(Index: Integer; const Value: TIdVCardEMailItem);
  1543. begin
  1544. inherited SetItem(Index, Value);
  1545. end;
  1546. { TIdVCardEMailItem }
  1547. procedure TIdVCardEMailItem.Assign(Source: TPersistent);
  1548. var
  1549. EMail : TIdVCardEMailItem;
  1550. begin
  1551. if Source is TIdVCardEMailItem then begin
  1552. EMail := Source as TIdVCardEMailItem;
  1553. EMailType := EMail.EMailType;
  1554. Preferred := EMail.Preferred;
  1555. Address := EMail.Address;
  1556. end else begin
  1557. inherited Assign(Source);
  1558. end;
  1559. end;
  1560. constructor TIdVCardEMailItem.Create(Collection: TCollection);
  1561. begin
  1562. inherited Create(Collection);
  1563. FEMailType := ematInternet;
  1564. end;
  1565. { TIdVCardAddresses }
  1566. function TIdVCardAddresses.Add: TIdCardAddressItem;
  1567. begin
  1568. Result := TIdCardAddressItem(inherited Add);
  1569. end;
  1570. constructor TIdVCardAddresses.Create(AOwner : TPersistent);
  1571. begin
  1572. inherited Create(AOwner, TIdCardAddressItem);
  1573. end;
  1574. function TIdVCardAddresses.GetItem(Index: Integer): TIdCardAddressItem;
  1575. begin
  1576. Result := TIdCardAddressItem(inherited Items[Index]);
  1577. end;
  1578. procedure TIdVCardAddresses.SetItem(Index: Integer; const Value: TIdCardAddressItem);
  1579. begin
  1580. inherited SetItem(Index, Value);
  1581. end;
  1582. { TIdVCardTelephones }
  1583. function TIdVCardTelephones.Add: TIdCardPhoneNumber;
  1584. begin
  1585. Result := TIdCardPhoneNumber(inherited Add);
  1586. end;
  1587. constructor TIdVCardTelephones.Create(AOwner : TPersistent);
  1588. begin
  1589. inherited Create(AOwner, TIdCardPhoneNumber);
  1590. end;
  1591. function TIdVCardTelephones.GetItem(Index: Integer): TIdCardPhoneNumber;
  1592. begin
  1593. Result := TIdCardPhoneNumber(inherited Items[Index]);
  1594. end;
  1595. procedure TIdVCardTelephones.SetItem(Index: Integer; const Value: TIdCardPhoneNumber);
  1596. begin
  1597. inherited SetItem(Index, Value);
  1598. end;
  1599. { TIdVCardName }
  1600. constructor TIdVCardName.Create;
  1601. begin
  1602. inherited Create;
  1603. FOtherNames := TStringList.Create;
  1604. FNickNames := TStringList.Create;
  1605. end;
  1606. destructor TIdVCardName.Destroy;
  1607. begin
  1608. FNickNames.Free;
  1609. FOtherNames.Free;
  1610. inherited Destroy;
  1611. end;
  1612. procedure TIdVCardName.SetNickNames(Value: TStrings);
  1613. begin
  1614. FNickNames.Assign(Value);
  1615. end;
  1616. procedure TIdVCardName.SetOtherNames(Value: TStrings);
  1617. begin
  1618. FOtherNames.Assign(Value);
  1619. end;
  1620. { TIdVCardBusinessInfo }
  1621. constructor TIdVCardBusinessInfo.Create;
  1622. begin
  1623. inherited Create;
  1624. FDivisions := TStringList.Create;
  1625. end;
  1626. destructor TIdVCardBusinessInfo.Destroy;
  1627. begin
  1628. FDivisions.Free;
  1629. inherited Destroy;
  1630. end;
  1631. procedure TIdVCardBusinessInfo.SetDivisions(Value: TStrings);
  1632. begin
  1633. FDivisions.Assign(Value);
  1634. end;
  1635. { TIdVCardMailingLabelItem }
  1636. procedure TIdVCardMailingLabelItem.Assign(Source: TPersistent);
  1637. var
  1638. lbl : TIdVCardMailingLabelItem;
  1639. begin
  1640. if Source is TIdVCardMailingLabelItem then begin
  1641. lbl := Source as TIdVCardMailingLabelItem;
  1642. AddressAttributes := lbl.AddressAttributes;
  1643. MailingLabel.Assign(lbl.MailingLabel);
  1644. end else begin
  1645. inherited Assign(Source);
  1646. end;
  1647. end;
  1648. constructor TIdVCardMailingLabelItem.Create(Collection: TCollection);
  1649. begin
  1650. inherited Create(Collection);
  1651. FMailingLabel := TStringList.Create;
  1652. end;
  1653. destructor TIdVCardMailingLabelItem.Destroy;
  1654. begin
  1655. FMailingLabel.Free;
  1656. inherited Destroy;
  1657. end;
  1658. procedure TIdVCardMailingLabelItem.SetMailingLabel(Value: TStrings);
  1659. begin
  1660. FMailingLabel.Assign(Value);
  1661. end;
  1662. { TIdVCardMailingLabels }
  1663. function TIdVCardMailingLabels.Add: TIdVCardMailingLabelItem;
  1664. begin
  1665. Result := TIdVCardMailingLabelItem(inherited Add);
  1666. end;
  1667. constructor TIdVCardMailingLabels.Create(AOwner: TPersistent);
  1668. begin
  1669. inherited Create(AOwner, TIdVCardMailingLabelItem);
  1670. end;
  1671. function TIdVCardMailingLabels.GetItem(Index: Integer): TIdVCardMailingLabelItem;
  1672. begin
  1673. Result := TIdVCardMailingLabelItem(inherited GetItem(Index));
  1674. end;
  1675. procedure TIdVCardMailingLabels.SetItem(Index: Integer; const Value: TIdVCardMailingLabelItem);
  1676. begin
  1677. inherited SetItem(Index, Value);
  1678. end;
  1679. { TIdEmbeddedObject }
  1680. constructor TIdVCardEmbeddedObject.Create;
  1681. begin
  1682. inherited Create;
  1683. FEmbeddedData := TStringList.Create;
  1684. end;
  1685. destructor TIdVCardEmbeddedObject.Destroy;
  1686. begin
  1687. FEmbeddedData.Free;
  1688. inherited Destroy;
  1689. end;
  1690. procedure TIdVCardEmbeddedObject.SetEmbeddedData(const Value: TStrings);
  1691. begin
  1692. FEmbeddedData.Assign(Value);
  1693. end;
  1694. { TIdCardPhoneNumber }
  1695. procedure TIdCardPhoneNumber.Assign(Source: TPersistent);
  1696. var
  1697. Phone : TIdCardPhoneNumber;
  1698. begin
  1699. if Source is TIdCardPhoneNumber then begin
  1700. Phone := Source as TIdCardPhoneNumber;
  1701. PhoneAttributes := Phone.PhoneAttributes;
  1702. Number := Phone.Number;
  1703. end else begin
  1704. inherited Assign(Source);
  1705. end;
  1706. end;
  1707. { TIdCardAddressItem }
  1708. procedure TIdCardAddressItem.Assign(Source: TPersistent);
  1709. var
  1710. LAddr : TIdCardAddressItem;
  1711. begin
  1712. if Source is TIdCardAddressItem then begin
  1713. LAddr := Source as TIdCardAddressItem;
  1714. AddressAttributes := LAddr.AddressAttributes;
  1715. POBox := LAddr.POBox;
  1716. ExtendedAddress := LAddr.ExtendedAddress;
  1717. StreetAddress := LAddr.StreetAddress;
  1718. Locality := LAddr.Locality;
  1719. Region := LAddr.Region;
  1720. PostalCode := LAddr.PostalCode;
  1721. Nation := LAddr.Nation;
  1722. end else begin
  1723. inherited Assign(Source);
  1724. end;
  1725. end;
  1726. end.