PageRenderTime 46ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdEMailAddress.pas

http://github.com/lookias/ProSnooper
Pascal | 865 lines | 664 code | 45 blank | 156 comment | 65 complexity | 6c905853963e68eade17477991940807 MD5 | raw file
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 13822: IdEMailAddress.pas
  11. {
  12. { Rev 1.13 10/26/2004 9:09:36 PM JPMugaas
  13. { Updated references.
  14. }
  15. {
  16. { Rev 1.12 24/10/2004 21:25:18 ANeillans
  17. { Modifications to allow Username and Domain parts to be set.
  18. }
  19. {
  20. { Rev 1.11 24.08.2004 17:29:30 Andreas Hausladen
  21. { Fixed GetEMailAddresses
  22. { Lots of simple but effective optimizations
  23. }
  24. {
  25. { Rev 1.10 09/08/2004 08:17:08 ANeillans
  26. { Rename username property to user
  27. }
  28. {
  29. { Rev 1.9 08/08/2004 20:58:02 ANeillans
  30. { Added support for Username extraction.
  31. }
  32. {
  33. { Rev 1.8 23/04/2004 20:34:36 CCostelloe
  34. { Clarified a question in the code as to why a code path ended there
  35. }
  36. {
  37. { Rev 1.7 3/6/2004 5:45:00 PM JPMugaas
  38. { Fixed problem obtaining the Text property for an E-Mail address with no
  39. { domain.
  40. }
  41. {
  42. { Rev 1.6 2004.02.03 5:45:08 PM czhower
  43. { Name changes
  44. }
  45. {
  46. { Rev 1.5 24/01/2004 19:12:10 CCostelloe
  47. { Cleaned up warnings
  48. }
  49. {
  50. { Rev 1.4 10/12/2003 7:51:50 PM BGooijen
  51. { Fixed Range Check Error
  52. }
  53. {
  54. { Rev 1.3 10/8/2003 9:50:24 PM GGrieve
  55. { use IdDelete
  56. }
  57. {
  58. { Rev 1.2 6/10/2003 5:48:50 PM SGrobety
  59. { DotNet updates
  60. }
  61. {
  62. { Rev 1.1 5/18/2003 02:30:36 PM JPMugaas
  63. { Added some backdoors for the TIdDirectSMTP processing.
  64. }
  65. {
  66. { Rev 1.0 11/14/2002 02:19:44 PM JPMugaas
  67. }
  68. unit IdEMailAddress;
  69. {
  70. ToDo: look into alterations required for TIdEMailAddressItem.GetText.
  71. }
  72. {
  73. 2001-Aug-30 - Jim Gunkel
  74. - Fixed bugs that would occur with group names containing spaces (box test 19)
  75. and content being located after the email address (box test 33)
  76. 2001-Jul-11 - Allen O'Neill
  77. - Added hack to not allow recipient entries being added that are blank
  78. 2001-Jul-11 - Allen O'Neill
  79. - Added hack to accomodate a PERIOD (#46) in an email address - this whole area needs to be looked at.
  80. 2001-Feb-03 - Peter Mee
  81. - Overhauled TIdEMailAddressItem.GetText to support non-standard textual
  82. elements.
  83. 2001-Jan-29 - Peter Mee
  84. - Overhauled TIdEMailAddressList.SetEMailAddresses to support comments
  85. and escaped characters and to ignore groups.
  86. 2001-Jan-28 - Peter Mee
  87. - Overhauled TIdEMailAddressItem.SetText to support comments and escaped
  88. characters.
  89. 2000-Jun-10 - J. Peter Mugaas
  90. - started this unit to facilitate some Indy work including the
  91. TIdEMailAddressItem and TIdEMailAddressList classes
  92. - The GetText and SetText were originally the ToArpa and FromArpa functions in
  93. the TIdMessage component}
  94. interface
  95. uses
  96. Classes,
  97. IdException,
  98. IdTStrings;
  99. type
  100. EIdEmailParseError = class(EIdException);
  101. TIdEMailAddressItem = class (TCollectionItem)
  102. protected
  103. FAddress: string;
  104. FName: string;
  105. Function GetText: string;
  106. Procedure SetText(AText: string);
  107. function ConvertAddress: string;
  108. function GetDomain: string;
  109. procedure SetDomain(const ADomain: String);
  110. function GetUsername: string;
  111. procedure SetUsername(const AUsername: String);
  112. public
  113. procedure Assign(Source: TPersistent); override;
  114. published
  115. {This is the E-Mail address itself }
  116. property Address: string read FAddress write FAddress;
  117. {This is the person's name} {Do not Localize}
  118. property Name: string read FName write FName;
  119. {This is the combined person's name and E-Mail address} {Do not Localize}
  120. property Text: string read GetText write SetText;
  121. {Extracted domain for some types of E-Mail processing}
  122. property Domain: string read GetDomain write SetDomain;
  123. property User: string read GetUsername write SetUsername;
  124. end;
  125. TIdEMailAddressList = class (TOwnedCollection)
  126. protected
  127. function GetItem(Index: Integer): TIdEMailAddressItem;
  128. procedure SetItem(Index: Integer; const Value: TIdEMailAddressItem);
  129. function GetEMailAddresses: string;
  130. procedure SetEMailAddresses(AList: string);
  131. public
  132. constructor Create(AOwner: TPersistent); reintroduce;
  133. {This returns formatted list of formated
  134. addresses including the names from the collection }
  135. procedure FillTStrings(AStrings: TIdStrings);
  136. function Add: TIdEMailAddressItem;
  137. //get all of the domains in the list so we can process those individually with
  138. //TIdDirectSMTP
  139. procedure GetDomains(AStrings: TIdStrings);
  140. {Sort by domains for making it easier to process E-Mails directly in
  141. TIdDirectSMTP}
  142. procedure SortByDomain;
  143. //Get all of the E-Mail addresses for a particular domain so we can
  144. //send E-Mail to recipients at one domain with only one connection for
  145. //speed with TIdDirectSMTP.
  146. procedure AddressesByDomain(AList: TIdEMailAddressList; const ADomain: string);
  147. property Items[Index: Integer]: TIdEMailAddressItem read GetItem write SetItem; default;
  148. {This is a comma separated list of formated
  149. addresses including the names from the collection }
  150. property EMailAddresses: string read GetEMailAddresses write SetEMailAddresses;
  151. end;
  152. implementation
  153. uses
  154. SysUtils,
  155. IdGlobal, IdGlobalProtocols, IdExceptionCore, IdResourceStringsProtocols;
  156. const
  157. // This is actually the ATEXT without the '"' and space characters... {Do not Localize}
  158. IETF_ATEXT: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' {Do not Localize}
  159. + '1234567890!#$%&''*+-/=?_`{}|~'; {Do not Localize}
  160. // ATEXT without the '"' {Do not Localize}
  161. IETF_ATEXT_SPACE: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' {Do not Localize}
  162. + '1234567890!#$%&''*+-/=?_`{}|~ '; {Do not Localize}
  163. IETF_QUOTABLE: string = '\"'; {Do not Localize}
  164. // Three functions for easier manipulating of strings.
  165. // Don't know of any system functions to perform these actions. {Do not Localize}
  166. // If there aren't & someone can find an optimised way of performing {Do not Localize}
  167. // then please implement...
  168. function FindFirstOf(const AFind, AText: string): Integer;
  169. var
  170. nCount, nPos: Integer;
  171. begin
  172. Result := 0;
  173. for nCount := 1 to Length(AFind) do begin
  174. nPos := IndyPos(AFind[nCount], AText);
  175. if nPos > 0 then begin
  176. if Result = 0 then begin
  177. Result := nPos;
  178. end else if Result > nPos then begin
  179. Result := nPos;
  180. end;
  181. end;
  182. end;
  183. end;
  184. function FindFirstNotOf(const AFind, AText: string): Integer;
  185. var
  186. i: Integer;
  187. begin
  188. Result := 0;
  189. if AFind = '' then
  190. begin
  191. Result := 1;
  192. Exit;
  193. end;
  194. if AText = '' then
  195. begin
  196. Exit;
  197. end;
  198. for i := 1 to Length(AText) do
  199. begin
  200. if IndyPos(AText[i], AFind) = 0 then
  201. begin
  202. Result := i;
  203. Exit;
  204. end;
  205. end;
  206. end;
  207. function TrimAllOf(const ATrim, AText: string): string;
  208. var
  209. Len: Integer;
  210. begin
  211. Result := AText;
  212. Len := Length(Result);
  213. while Len > 0 do
  214. begin
  215. if Pos(Result[1], ATrim) > 0 then
  216. begin
  217. Delete(Result, 1, 1);
  218. Dec(Len);
  219. end else Break;
  220. end;
  221. while Len > 0 do begin
  222. if Pos(Result[Len], ATrim) > 0 then
  223. begin
  224. Delete(Result, Len, 1);
  225. Dec(Len);
  226. end else Break;
  227. end;
  228. end;
  229. { TIdEMailAddressItem }
  230. procedure TIdEMailAddressItem.Assign(Source: TPersistent);
  231. var Addr : TIdEMailAddressItem;
  232. begin
  233. if ClassType <> Source.ClassType then
  234. begin
  235. inherited
  236. end
  237. else
  238. begin
  239. Addr := TIdEMailAddressItem(Source);
  240. Address := Addr.Address;
  241. Name := Addr.Name;
  242. end;
  243. end;
  244. function TIdEMailAddressItem.ConvertAddress: string;
  245. var
  246. i: Integer;
  247. domainPart, tempAddress, localPart: string;
  248. begin
  249. if FAddress = '' then
  250. begin
  251. if FName <> '' then
  252. begin
  253. Result := '<>'; {Do not Localize}
  254. end else
  255. begin
  256. Result := ''; {Do not Localize}
  257. end;
  258. Exit;
  259. end;
  260. // First work backwards to the @ sign.
  261. tempAddress := FAddress;
  262. domainPart := '';
  263. for i := Length(FAddress) downto 1 do
  264. begin
  265. if FAddress[i] = '@' then {Do not Localize}
  266. begin
  267. domainPart := Copy(FAddress, i, MaxInt);
  268. tempAddress := Copy(FAddress, 1, i - 1);
  269. Break;
  270. end;
  271. end;
  272. i := FindFirstNotOf(IETF_ATEXT, tempAddress);
  273. if (i = 0) or (Copy(tempAddress,i,1) = #46) then //hack to accomodate periods in emailaddress
  274. // if i = 0 then
  275. begin
  276. if FName <> '' then
  277. begin
  278. Result := '<' + tempAddress + domainPart + '>'; {Do not Localize}
  279. end else
  280. begin
  281. Result := tempAddress + domainPart;
  282. end;
  283. end else
  284. begin
  285. localPart := '"'; {Do not Localize}
  286. while i > 0 do
  287. begin
  288. localPart := localPart + Copy(tempAddress, 1, i - 1);
  289. if IndyPos(tempAddress[i], IETF_QUOTABLE) > 0 then
  290. begin
  291. localPart := localPart + '\'; {Do not Localize}
  292. end;
  293. localPart := localPart + tempAddress[i];
  294. IdDelete(tempAddress, 1, i);
  295. i := FindFirstNotOf(IETF_ATEXT, tempAddress);
  296. end;
  297. Result := '<' + localPart + tempAddress + '"' + domainPart + '>'; {Do not Localize}
  298. end;
  299. end;
  300. function TIdEMailAddressItem.GetDomain: string;
  301. var i: Integer;
  302. begin
  303. Result := '';
  304. for i := Length(FAddress) downto 1 do
  305. begin
  306. if FAddress[i] = '@' then {Do not Localize}
  307. begin
  308. Result := Copy(FAddress, i + 1, MaxInt);
  309. Break;
  310. end;
  311. end;
  312. end;
  313. procedure TIdEMailAddressItem.SetDomain(const ADomain: String);
  314. Var
  315. Result : String;
  316. begin
  317. Result := FAddress;
  318. Delete(Result, Pos('@', Result)-1, Length(Result));
  319. Result := Result + '@' + ADomain;
  320. FAddress := Result;
  321. end;
  322. function TIdEMailAddressItem.GetUsername: string;
  323. var i: Integer;
  324. begin
  325. Result := '';
  326. for i := Length(FAddress) downto 1 do
  327. begin
  328. if FAddress[i] = '@' then {Do not Localize}
  329. begin
  330. Result := Copy(FAddress, 1, i - 1);
  331. Break;
  332. end;
  333. end;
  334. end;
  335. procedure TIdEMailAddressItem.SetUsername(const AUsername: String);
  336. Var
  337. Result : String;
  338. begin
  339. Result := FAddress;
  340. Delete(Result, 1, Pos('@', Result) + 1);
  341. Result := AUsername + '@' + Result;
  342. FAddress := Result;
  343. end;
  344. function TIdEMailAddressItem.GetText: string;
  345. var
  346. i: Integer;
  347. tempName, resName: string;
  348. begin
  349. if (FName <> '') and (UpperCase(FAddress) <> FName) then
  350. begin
  351. i := FindFirstNotOf(IETF_ATEXT_SPACE, FName);
  352. if i > 0 then
  353. begin
  354. // Need to quote the FName.
  355. resName := '"' + Copy(FName, 1, i - 1); {Do not Localize}
  356. if IndyPos(FName[i], IETF_QUOTABLE) > 0 then
  357. begin
  358. resName := resName + '\'; {Do not Localize}
  359. end;
  360. resName := resName + FName[i];
  361. tempName := Copy(FName, i + 1, MaxInt);
  362. while tempName <> '' do
  363. begin
  364. i := FindFirstNotOf(IETF_ATEXT_SPACE, tempName);
  365. if i = 0 then
  366. begin
  367. Result := resName + tempName + '" ' + ConvertAddress; {Do not Localize}
  368. Exit;
  369. end;
  370. resName := resName + Copy(tempName, 1, i - 1);
  371. if IndyPos(tempName[i], IETF_QUOTABLE) > 0 then
  372. begin
  373. resName := resName + '\'; {Do not Localize}
  374. end;
  375. resName := resName + tempName[i];
  376. IdDelete(tempName, 1, i);
  377. end;
  378. Result := resName + '" ' + ConvertAddress; {Do not Localize}
  379. end else
  380. begin
  381. Result := FName + ' ' + ConvertAddress; {Do not Localize}
  382. end;
  383. end // if
  384. else
  385. begin
  386. Result := ConvertAddress;
  387. end; // else .. if
  388. end;
  389. procedure TIdEMailAddressItem.SetText(AText: string);
  390. var
  391. nFirst,
  392. nBracketCount: Integer;
  393. bInAddress,
  394. bAddressInLT,
  395. bAfterAt,
  396. bInQuote : Boolean;
  397. begin
  398. FAddress := ''; {Do not Localize}
  399. FName := ''; {Do not Localize}
  400. AText := Trim(AText);
  401. if AText = '' then
  402. Exit;
  403. // Find the first known character type.
  404. nFirst := FindFirstOf('("< @' + TAB, AText); {Do not Localize}
  405. if nFirst <> 0 then
  406. begin
  407. nBracketCount := 0;
  408. bInAddress := False;
  409. bAddressInLT := False;
  410. bInQuote := False;
  411. bAfterAt := False;
  412. repeat
  413. case AText[nFirst] of
  414. ' ', TAB : {Do not Localize}
  415. begin
  416. if nFirst = 1 then
  417. begin
  418. Delete(AText, 1, 1);
  419. end else
  420. begin
  421. // Only valid if in a name not contained in quotes - keep the space.
  422. if bAfterAt then begin
  423. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  424. end else begin
  425. FName := FName + Copy(AText, 1, nFirst);
  426. end;
  427. IdDelete(AText, 1, nFirst);
  428. end;
  429. end;
  430. '(' : {Do not Localize}
  431. begin
  432. Inc(nBracketCount);
  433. if (nFirst > 1) then
  434. begin
  435. // There's at least one character to the name {Do not Localize}
  436. if bInAddress then
  437. begin
  438. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  439. end else
  440. begin
  441. if nBracketCount = 1 then
  442. begin
  443. FName := FName + Copy(AText, 1, nFirst - 1);
  444. end;
  445. end;
  446. IdDelete(AText, 1, nFirst);
  447. end else
  448. begin
  449. Delete(AText, 1, 1);
  450. end;
  451. end;
  452. ')' : {Do not Localize}
  453. begin
  454. Dec(nBracketCount);
  455. IdDelete(AText, 1, nFirst);
  456. end;
  457. '"' : {Do not Localize}
  458. begin
  459. if bInQuote then
  460. begin
  461. if bAddressInLT then
  462. begin
  463. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  464. end else
  465. begin
  466. FName := FName + Trim(Copy(AText, 1, nFirst - 1));
  467. end;
  468. IdDelete(AText, 1, nFirst);
  469. bInQuote := False;
  470. end else
  471. begin
  472. bInQuote := True;
  473. Delete(AText, 1, 1);
  474. end;
  475. end;
  476. '<' : {Do not Localize}
  477. begin
  478. if nFirst > 1 then
  479. begin
  480. FName := FName + Copy(AText, 1, nFirst - 1);
  481. end;
  482. FName := TrimAllOf(' ' + TAB, Trim(FName)); {Do not Localize}
  483. bAddressInLT := True;
  484. bInAddress := True;
  485. Delete(AText, 1, nFirst);
  486. end;
  487. '>' : {Do not Localize}
  488. begin
  489. // Only searched for if the address starts with '<' {Do not Localize}
  490. bInAddress := False;
  491. bAfterAt := False;
  492. FAddress := FAddress +
  493. TrimAllOf(' ' + TAB, Trim(Copy(AText, 1, nFirst - 1))); {Do not Localize}
  494. IdDelete(AText, 1, nFirst);
  495. end;
  496. '@' : {Do not Localize}
  497. begin
  498. bAfterAt := True;
  499. if bInAddress then
  500. begin
  501. FAddress := FAddress + Copy(AText, 1, nFirst);
  502. IdDelete(AText, 1, nFirst);
  503. end else
  504. begin
  505. if bAddressInLT then
  506. begin
  507. // Strange use. For now raise an exception until a real-world
  508. // example can be found.
  509. // Basically, it's formatted as follows: {Do not Localize}
  510. // <someguy@domain.example> some-text @ some-text
  511. // or:
  512. // some-text <someguy@domain.example> some-text @ some-text
  513. // where some text may be blank.
  514. //CC: Note you used to arrive here if the From header in an email
  515. //included more than one address (which was subsequently changed)
  516. //because our code did not parse the From header for multiple
  517. //addresses. That may have been the reason for this code.
  518. raise EIdEmailParseError.Create(RSEMailSymbolOutsideAddress);
  519. end else
  520. begin
  521. // If at this point, we're either supporting an e-mail address {Do not Localize}
  522. // on it's own, or the old-style valid format: {Do not Localize}
  523. // "Name" name@domain.example
  524. bInAddress := True;
  525. FAddress := FAddress + Copy(AText, 1, nFirst);
  526. IdDelete(AText, 1, nFirst);
  527. end;
  528. end;
  529. end;
  530. '.' : {Do not Localize}
  531. begin
  532. // Must now be a part of the domain part of the address.
  533. if bAddressInLT then
  534. begin
  535. // Whitespace is possible around the parts of the domain.
  536. FAddress := FAddress +
  537. TrimAllOf(' ' + TAB, Trim(Copy(AText, 1, nFirst - 1))) + '.'; {Do not Localize}
  538. AText := TrimLeft(Copy(AText, nFirst + 1, MaxInt));
  539. end else
  540. begin
  541. // No whitespace is allowed if no wrapping <> characters.
  542. FAddress := FAddress + Copy(AText, 1, nFirst);
  543. IdDelete(AText, 1, nFirst);
  544. end;
  545. end;
  546. '\' : {Do not Localize}
  547. begin
  548. // This will only be discovered in a bracketted or quoted section.
  549. // It's an escape character indicating the next cahracter is {Do not Localize}
  550. // a literal.
  551. if bInQuote then
  552. begin
  553. // Need to retain the second character
  554. if bInAddress then
  555. begin
  556. FAddress := FAddress + Copy(AText, 1, nFirst - 1);
  557. FAddress := FAddress + AText[nFirst + 1];
  558. end else
  559. begin
  560. FName := FName + Copy(AText, 1, nFirst - 1);
  561. FName := FName + AText[nFirst + 1];
  562. end;
  563. end;
  564. IdDelete(AText, 1, nFirst + 1);
  565. end;
  566. end;
  567. // Check for bracketted sections first: ("<>" <> "" <"">) - all is ignored
  568. if nBracketCount > 0 then
  569. begin
  570. // Inside a bracket, only three charatcers are special.
  571. // '(' Opens a nested bracket: (One (Two (Three ))) {Do not Localize}
  572. // ')' Closes a bracket {Do not Localize}
  573. // '/' Escape character: (One /) /( // (Two /) )) {Do not Localize}
  574. nFirst := FindFirstOf('()\', AText); {Do not Localize}
  575. // Check if in quote before address: <"My Name"@domain.example> is valid
  576. end else if bInQuote then
  577. begin
  578. // Inside quotes, only the end quote and escape character are special.
  579. nFirst := FindFirstOf('"\', AText); {Do not Localize}
  580. // Check if after the @ of the address: domain.example>
  581. end else if bAfterAt then
  582. begin
  583. if bAddressInLT then
  584. begin
  585. // If the address is enclosed, then only the '(', '.' & '>' need be {Do not Localize}
  586. // looked for, trimming all content when found: domain . example >
  587. nFirst := FindFirstOf('.>(', AText); {Do not Localize}
  588. end else
  589. begin
  590. nFirst := FindFirstOf('.( ', AText); {Do not Localize}
  591. end;
  592. // Check if in address: <name@domain.example>
  593. end else if bInAddress then
  594. begin
  595. nFirst := FindFirstOf('"(@>', AText); {Do not Localize}
  596. // Not in anything - check for opening charactere
  597. end else
  598. begin
  599. // Outside brackets
  600. nFirst := FindFirstOf('("< @' + TAB, AText); {Do not Localize}
  601. end;
  602. until nFirst = 0;
  603. if bInAddress and not bAddressInLT then
  604. begin
  605. FAddress := FAddress + TrimAllOf(' ' + TAB, Trim(AText)); {Do not Localize}
  606. end;
  607. end else
  608. begin
  609. // No special characters, so assume a simple address
  610. FAddress := AText;
  611. end;
  612. end;
  613. { TIdEMailAddressList }
  614. function TIdEMailAddressList.Add: TIdEMailAddressItem;
  615. begin
  616. Result := TIdEMailAddressItem(inherited Add);
  617. end;
  618. constructor TIdEMailAddressList.Create(AOwner: TPersistent);
  619. begin
  620. inherited Create(AOwner, TIdEMailAddressItem);
  621. end;
  622. procedure TIdEMailAddressList.FillTStrings(AStrings: TIdStrings);
  623. var
  624. idx: Integer;
  625. begin
  626. for idx := 0 to Count - 1 do
  627. begin
  628. AStrings.Add(GetItem(idx).Text);
  629. end;
  630. end;
  631. function TIdEMailAddressList.GetItem(Index: Integer): TIdEMailAddressItem;
  632. begin
  633. Result := TIdEMailAddressItem(inherited Items[Index]);
  634. end;
  635. function TIdEMailAddressList.GetEMailAddresses: string;
  636. var
  637. idx: Integer;
  638. begin
  639. Result := ''; {Do not Localize}
  640. for idx := 0 to Count - 1 do
  641. begin
  642. if Result = '' then
  643. Result := GetItem(idx).Text
  644. else
  645. Result := Result + ', ' + GetItem(idx).Text; {Do not Localize}
  646. end;
  647. end;
  648. procedure TIdEMailAddressList.SetItem(Index: Integer;
  649. const Value: TIdEMailAddressItem);
  650. begin
  651. inherited SetItem(Index, Value);
  652. end;
  653. procedure TIdEMailAddressList.SetEMailAddresses(AList: string);
  654. var
  655. EMail : TIdEMailAddressItem;
  656. iStart: Integer;
  657. sTemp: string;
  658. nInBracket: Integer;
  659. bInQuote : Boolean;
  660. begin
  661. Clear;
  662. if (Trim(AList) = '') then Exit; {Do not Localize}
  663. iStart := FindFirstOf(':;(", ' + TAB, AList); {Do not Localize}
  664. if iStart = 0 then begin
  665. EMail := Add;
  666. EMail.Text := TrimLeft(AList);
  667. end else begin
  668. sTemp := ''; {Do not Localize}
  669. nInBracket := 0;
  670. bInQuote := False;
  671. repeat
  672. case AList[iStart] of
  673. ' ', TAB: begin {Do not Localize}
  674. if iStart = 1 then begin
  675. sTemp := sTemp + AList[iStart];
  676. IdDelete(AList, 1, 1);
  677. end else begin
  678. sTemp := sTemp + Copy(AList, 1, iStart);
  679. IdDelete(AList, 1, iStart);
  680. end;
  681. end;
  682. ':' : {Do not Localize}
  683. begin
  684. // The start of a group - ignore the lot.
  685. IdDelete(AList, 1, iStart);
  686. sTemp := ''; {Do not Localize}
  687. end;
  688. ';' : {Do not Localize}
  689. begin
  690. // End of a group. If we have something (groups can be empty),
  691. // then process it.
  692. sTemp := sTemp + Copy(AList, 1, iStart - 1);
  693. if Trim(sTemp) <> '' then begin
  694. EMail := Add;
  695. EMail.Text := TrimLeft(sTemp);
  696. sTemp := ''; {Do not Localize}
  697. end;
  698. // Now simply remove the end of the group.
  699. IdDelete(AList, 1, iStart);
  700. end;
  701. '(': begin {Do not Localize}
  702. Inc(nInBracket);
  703. sTemp := sTemp + Copy(AList, 1, iStart);
  704. IdDelete(AList, 1, iStart);
  705. end;
  706. ')': begin {Do not Localize}
  707. Dec(nInBracket);
  708. sTemp := sTemp + Copy(AList, 1, iStart);
  709. IdDelete(AList, 1, iStart);
  710. end;
  711. '"': begin {Do not Localize}
  712. sTemp := sTemp + Copy(AList, 1, iStart);
  713. IdDelete(AList, 1, iStart);
  714. bInQuote := not bInQuote;
  715. end;
  716. ',': begin {Do not Localize}
  717. sTemp := sTemp + Copy(AList, 1, iStart - 1);
  718. EMail := Add;
  719. EMail.Text := sTemp;
  720. // added - Allen .. saves blank entries being added
  721. if (Trim(Email.Text) = '') or (Trim(Email.Text) = '<>') then {Do not Localize}
  722. begin
  723. FreeAndNil(Email);
  724. end;
  725. sTemp := ''; {Do not Localize}
  726. IdDelete(AList, 1, iStart);
  727. end;
  728. '\': begin {Do not Localize}
  729. // Escape character - simply copy this char and the next to the buffer.
  730. sTemp := sTemp + Copy(AList, 1, iStart + 1);
  731. IdDelete(AList, 1, iStart + 1);
  732. end;
  733. end;
  734. if nInBracket > 0 then begin
  735. iStart := FindFirstOf('(\)', AList); {Do not Localize}
  736. end else if bInQuote then begin
  737. iStart := FindFirstOf('"\', AList); {Do not Localize}
  738. end else begin
  739. iStart := FindFirstOf(':;(", ' + TAB, AList); {Do not Localize}
  740. end;
  741. until iStart = 0;
  742. // Clean up the content in sTemp
  743. if (Trim(sTemp) <> '') or (Trim(AList) <> '') then begin
  744. sTemp := sTemp + AList;
  745. EMail := Add;
  746. EMail.Text := TrimLeft(sTemp);
  747. // added - Allen .. saves blank entries being added
  748. if (Trim(Email.Text) = '') or (Trim(Email.Text) = '<>') then {Do not Localize}
  749. begin
  750. FreeAndNil(Email);
  751. end;
  752. end;
  753. end;
  754. end;
  755. procedure TIdEMailAddressList.SortByDomain;
  756. var
  757. i, j: Integer;
  758. LTemp: string;
  759. begin
  760. for i := Count -1 downto 0 do
  761. begin
  762. for j := 0 to Count -2 do
  763. begin
  764. if IndyCompareStr(Items[J].Domain , Items[J + 1].Domain)> 0 then begin
  765. LTemp := Items[j].Text;
  766. Items[j].Text := Items[j+1].Text;
  767. Items[j+1].Text := LTemp;
  768. end;
  769. end;
  770. end;
  771. end;
  772. procedure TIdEMailAddressList.GetDomains(AStrings: TIdStrings);
  773. var
  774. i: Integer;
  775. LCurDom: string;
  776. begin
  777. if Assigned(AStrings) then
  778. begin
  779. AStrings.Clear;
  780. for i := 0 to Count-1 do
  781. begin
  782. LCurDom := Lowercase(Items[i].Domain);
  783. if AStrings.IndexOf( LCurDom ) = -1 then
  784. begin
  785. AStrings.Add( LCurDom );
  786. end;
  787. end;
  788. end;
  789. end;
  790. procedure TIdEMailAddressList.AddressesByDomain(AList: TIdEMailAddressList;
  791. const ADomain: string);
  792. var
  793. i: Integer;
  794. LDomain: string;
  795. LCurDom: string;
  796. LEnt : TIdEMailAddressItem;
  797. begin
  798. LDomain := LowerCase(ADomain);
  799. AList.Clear;
  800. for i := 0 to Count-1 do
  801. begin
  802. LCurDom := LowerCase(Items[i].Domain);
  803. if LCurDom = LDomain then
  804. begin
  805. LEnt := AList.Add;
  806. LEnt.Text := Items[i].Text;
  807. end;
  808. end;
  809. end;
  810. end.