IdEMailAddress.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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: 10153: IdEMailAddress.pas
  11. {
  12. { Rev 1.0 2002.11.12 10:37:40 PM czhower
  13. }
  14. unit IdEMailAddress;
  15. {
  16. ToDo: look into alterations required for TIdEMailAddressItem.GetText.
  17. }
  18. {
  19. 2001-Aug-30 - Jim Gunkel
  20. - Fixed bugs that would occur with group names containing spaces (box test 19)
  21. and content being located after the email address (box test 33)
  22. 2001-Jul-11 - Allen O'Neill
  23. - Added hack to not allow recipient entries being added that are blank
  24. 2001-Jul-11 - Allen O'Neill
  25. - Added hack to accomodate a PERIOD (#46) in an email address - this whole area needs to be looked at.
  26. 2001-Feb-03 - Peter Mee
  27. - Overhauled TIdEMailAddressItem.GetText to support non-standard textual
  28. elements.
  29. 2001-Jan-29 - Peter Mee
  30. - Overhauled TIdEMailAddressList.SetEMailAddresses to support comments
  31. and escaped characters and to ignore groups.
  32. 2001-Jan-28 - Peter Mee
  33. - Overhauled TIdEMailAddressItem.SetText to support comments and escaped
  34. characters.
  35. 2000-Jun-10 - J. Peter Mugaas
  36. - started this unit to facilitate some Indy work including the
  37. TIdEMailAddressItem and TIdEMailAddressList classes
  38. - The GetText and SetText were originally the ToArpa and FromArpa functions in
  39. the TIdMessage component}
  40. interface
  41. uses
  42. Classes,
  43. IdException;
  44. type
  45. EIdEmailParseError = class(EIdException);
  46. TIdEMailAddressItem = class (TCollectionItem)
  47. protected
  48. FAddress : String;
  49. FName : String;
  50. Function GetText : String;
  51. Procedure SetText(AText : String);
  52. function ConvertAddress : String;
  53. public
  54. procedure Assign(Source: TPersistent); override;
  55. published
  56. {This is the E-Mail address itself }
  57. property Address: string read FAddress write FAddress;
  58. {This is the person's name} {Do not Localize}
  59. property Name: string read FName write FName;
  60. {This is the combined person's name and E-Mail address} {Do not Localize}
  61. property Text: String read GetText write SetText;
  62. end;
  63. TIdEMailAddressList = class (TOwnedCollection)
  64. protected
  65. function GetItem ( Index: Integer ) : TIdEMailAddressItem;
  66. procedure SetItem ( Index: Integer; const Value: TIdEMailAddressItem );
  67. function GetEMailAddresses : String;
  68. procedure SetEMailAddresses( AList : String);
  69. public
  70. constructor Create ( AOwner : TPersistent ); reintroduce;
  71. {This returns formatted list of formated
  72. addresses including the names from the collection }
  73. procedure FillTStrings(AStrings : TStrings);
  74. function Add: TIdEMailAddressItem;
  75. property Items [ Index: Integer ] : TIdEMailAddressItem read GetItem write SetItem; default;
  76. {This is a comma separated list of formated
  77. addresses including the names from the collection }
  78. property EMailAddresses : String read GetEMailAddresses
  79. write SetEMailAddresses;
  80. end;
  81. implementation
  82. uses
  83. IdGlobal,
  84. IdResourceStrings,
  85. SysUtils;
  86. const
  87. // This is actually the ATEXT without the '"' and space characters... {Do not Localize}
  88. IETF_ATEXT: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' {Do not Localize}
  89. + '1234567890!#$%&''*+-/=?_`{}|~'; {Do not Localize}
  90. // ATEXT without the '"' {Do not Localize}
  91. IETF_ATEXT_SPACE: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' {Do not Localize}
  92. + '1234567890!#$%&''*+-/=?_`{}|~ '; {Do not Localize}
  93. IETF_QUOTABLE: string = '\"'; {Do not Localize}
  94. // Three functions for easier manipulating of strings.
  95. // Don't know of any system functions to perform these actions. {Do not Localize}
  96. // If there aren't & someone can find an optimised way of performing {Do not Localize}
  97. // then please implement...
  98. function FindFirstOf(AFind, AText: string): Integer;
  99. var
  100. nCount, nPos: Integer;
  101. begin
  102. Result := 0;
  103. for nCount := 1 to Length(AFind) do begin
  104. nPos := IndyPos(AFind[nCount], AText);
  105. if nPos > 0 then begin
  106. if Result = 0 then begin
  107. Result := nPos;
  108. end else if Result > nPos then begin
  109. Result := nPos;
  110. end;
  111. end;
  112. end;
  113. end;
  114. function FindFirstNotOf(AFind, AText : String) : Integer;
  115. var
  116. i : Integer;
  117. begin
  118. result := 0;
  119. if length(AFind) = 0 then
  120. begin
  121. result := 1;
  122. exit;
  123. end;
  124. if length(AText) = 0 then
  125. begin
  126. exit;
  127. end;
  128. for i := 1 to length(AText) do
  129. begin
  130. if IndyPos(AText[i], AFind) = 0 then
  131. begin
  132. result := i;
  133. exit;
  134. end;
  135. end;
  136. end;
  137. function TrimAllOf(ATrim, AText : String) : String;
  138. begin
  139. while Length(AText) > 0 do
  140. begin
  141. if Pos(AText[1], ATrim) > 0 then
  142. begin
  143. System.Delete(AText, 1, 1);
  144. end else break;
  145. end;
  146. while Length(AText) > 0 do begin
  147. if Pos(AText[length(AText)], ATrim) > 0 then
  148. begin
  149. System.Delete(AText, Length(AText), 1);
  150. end else break;
  151. end;
  152. result := AText;
  153. end;
  154. { TIdEMailAddressItem }
  155. procedure TIdEMailAddressItem.Assign(Source: TPersistent);
  156. var Addr : TIdEMailAddressItem;
  157. begin
  158. if ClassType <> Source.ClassType then
  159. begin
  160. inherited
  161. end
  162. else
  163. begin
  164. Addr := TIdEMailAddressItem(Source);
  165. Address := Addr.Address;
  166. Name := Addr.Name;
  167. end;
  168. end;
  169. function TIdEMailAddressItem.ConvertAddress : String;
  170. var
  171. i : Integer;
  172. domainPart, tempAddress, localPart : String;
  173. begin
  174. if length(FAddress) = 0 then
  175. begin
  176. if Length(FName) > 0 then
  177. begin
  178. result := '<>'; {Do not Localize}
  179. end else
  180. begin
  181. result := ''; {Do not Localize}
  182. end;
  183. exit;
  184. end;
  185. // First work backwards to the @ sign.
  186. for i := length(FAddress) downto 1 do
  187. begin
  188. if FAddress[i] = '@' then {Do not Localize}
  189. begin
  190. domainPart := Copy(FAddress, i, length(FAddress));
  191. tempAddress := Copy(FAddress, 1, i - 1);
  192. break;
  193. end;
  194. end;
  195. i := FindFirstNotOf(IETF_ATEXT, tempAddress);
  196. if (i = 0) or (tempAddress[i] = #46) then //hack to accomodate periods in emailaddress
  197. // if i = 0 then
  198. begin
  199. if length(FName) > 0 then
  200. begin
  201. result := '<' + tempAddress + domainPart + '>'; {Do not Localize}
  202. end else
  203. begin
  204. result := tempAddress + domainPart;
  205. end;
  206. end else
  207. begin
  208. localPart := '"'; {Do not Localize}
  209. while i > 0 do
  210. begin
  211. localPart := localPart + Copy(tempAddress, 1, i - 1);
  212. if IndyPos(tempAddress[i], IETF_QUOTABLE) > 0 then
  213. begin
  214. localPart := localPart + '\'; {Do not Localize}
  215. end;
  216. localPart := localPart + tempAddress[i];
  217. tempAddress := Copy(tempAddress, i + 1, length(tempAddress));
  218. i := FindFirstNotOf(IETF_ATEXT, tempAddress);
  219. end;
  220. result := '<' + localPart + tempAddress + '"' + domainPart + '>'; {Do not Localize}
  221. end;
  222. end;
  223. function TIdEMailAddressItem.GetText: String;
  224. var
  225. i : Integer;
  226. tempName, resName : String;
  227. begin
  228. if ( Length ( FName ) > 0 ) and ( UpperCase ( FAddress ) <> FName ) then
  229. begin
  230. i := FindFirstNotOf(IETF_ATEXT_SPACE, FName);
  231. if i > 0 then
  232. begin
  233. // Need to quote the FName.
  234. resName := '"' + Copy(FName, 1, i - 1); {Do not Localize}
  235. if IndyPos(FName[i], IETF_QUOTABLE) > 0 then
  236. begin
  237. resName := resName + '\'; {Do not Localize}
  238. end;
  239. resName := resName + FName[i];
  240. tempName := Copy(FName, i + 1, length(FName));
  241. while length(tempName) <> 0 do
  242. begin
  243. i := FindFirstNotOf(IETF_ATEXT_SPACE, tempName);
  244. if i = 0 then
  245. begin
  246. Result := resName + tempName + '" ' + ConvertAddress; {Do not Localize}
  247. exit;
  248. end;
  249. resName := resName + Copy(tempName, 1, i-1);
  250. if IndyPos(tempName[i], IETF_QUOTABLE) > 0 then
  251. begin
  252. resName := resName + '\'; {Do not Localize}
  253. end;
  254. resName := resName + tempName[i];
  255. tempName := Copy(tempName, i + 1, length(tempName));
  256. end;
  257. Result := resName + '" ' + ConvertAddress; {Do not Localize}
  258. end else
  259. begin
  260. Result := FName + ' ' + ConvertAddress; {Do not Localize}
  261. end;
  262. end // if
  263. else
  264. begin
  265. Result := ConvertAddress;
  266. end; // else .. if
  267. end;
  268. procedure TIdEMailAddressItem.SetText(AText: String);
  269. var
  270. nFirst,
  271. nBracketCount : Integer;
  272. bInAddress,
  273. bAddressInLT,
  274. bAfterAt,
  275. bInQuote : Boolean;
  276. begin
  277. FAddress := ''; {Do not Localize}
  278. FName := ''; {Do not Localize}
  279. AText := Trim(AText);
  280. if Length(AText) = 0 then exit;
  281. // Find the first known character type.
  282. nFirst := FindFirstOf('("< @' + TAB, AText); {Do not Localize}
  283. if nFirst <> 0 then
  284. begin
  285. nBracketCount := 0;
  286. bInAddress := False;
  287. bAddressInLT := False;
  288. bInQuote := False;
  289. bAfterAt := False;
  290. repeat
  291. case AText[nFirst] of
  292. ' ', TAB : {Do not Localize}
  293. begin
  294. if nFirst = 1 then
  295. begin
  296. System.Delete(AText, 1, 1);
  297. end else
  298. begin
  299. // Only valid if in a name not contained in quotes - keep the space.
  300. if bAfterAt then begin
  301. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  302. end else begin
  303. FName := FName + Copy(AText, 1, nFirst);
  304. end;
  305. AText := Copy(AText, nFirst + 1, Length(AText));
  306. end;
  307. end;
  308. '(' : {Do not Localize}
  309. begin
  310. Inc(nBracketCount);
  311. if (nFirst > 1) then
  312. begin
  313. // There's at least one character to the name {Do not Localize}
  314. if bInAddress then
  315. begin
  316. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  317. end else
  318. begin
  319. if nBracketCount = 1 then
  320. begin
  321. FName := FName + Copy(AText, 1, nFirst - 1);
  322. end;
  323. end;
  324. AText := Copy(AText, nFirst + 1, length(AText));
  325. end else
  326. begin
  327. System.Delete(AText, 1, 1);
  328. end;
  329. end;
  330. ')' : {Do not Localize}
  331. begin
  332. Dec(nBracketCount);
  333. AText := Copy(AText, nFirst + 1, Length(AText));
  334. end;
  335. '"' : {Do not Localize}
  336. begin
  337. if bInQuote then
  338. begin
  339. if bAddressInLT then
  340. begin
  341. FAddress := FAddress + Trim(Copy(AText, 1, nFirst - 1));
  342. end else
  343. begin
  344. FName := FName + Trim(Copy(AText, 1, nFirst - 1));
  345. end;
  346. AText := Copy(AText, nFirst + 1, length(AText));
  347. bInQuote := False;
  348. end else
  349. begin
  350. bInQuote := True;
  351. System.Delete(AText, 1, 1);
  352. end;
  353. end;
  354. '<' : {Do not Localize}
  355. begin
  356. if nFirst > 1 then
  357. begin
  358. FName := FName + Copy(AText,1,nFirst - 1);
  359. end;
  360. FName := TrimAllOf(' ' + TAB, Trim(FName)); {Do not Localize}
  361. bAddressInLT := True;
  362. bInAddress := True;
  363. System.Delete(AText, 1, nFirst);
  364. end;
  365. '>' : {Do not Localize}
  366. begin
  367. // Only searched for if the address starts with '<' {Do not Localize}
  368. bInAddress := False;
  369. bAfterAt := False;
  370. FAddress := FAddress +
  371. TrimAllOf(' ' + TAB, Trim(Copy(AText, 1, nFirst -1))); {Do not Localize}
  372. AText := Copy(AText, nFirst + 1, length(AText));
  373. end;
  374. '@' : {Do not Localize}
  375. begin
  376. bAfterAt := True;
  377. if bInAddress then
  378. begin
  379. FAddress := FAddress + Copy(AText, 1, nFirst);
  380. AText := Copy(AText, nFirst + 1, Length(AText));
  381. end else
  382. begin
  383. if bAddressInLT then
  384. begin
  385. // Strange use. For now raise an exception until a real-world
  386. // example can be found.
  387. // Basically, it's formatted as follows: {Do not Localize}
  388. // <[email protected]> some-text @ some-text
  389. // or:
  390. // some-text <[email protected]> some-text @ some-text
  391. // where some text may be blank.
  392. raise EIdEmailParseError.Create(RSEMailSymbolOutsideAddress);
  393. end else
  394. begin
  395. // If at this point, we're either supporting an e-mail address {Do not Localize}
  396. // on it's own, or the old-style valid format: {Do not Localize}
  397. // "Name" [email protected]
  398. bInAddress := true;
  399. FAddress := FAddress + Copy(AText, 1, nFirst);
  400. AText := Copy(AText, nFirst + 1, length(AText));
  401. end;
  402. end;
  403. end;
  404. '.' : {Do not Localize}
  405. begin
  406. // Must now be a part of the domain part of the address.
  407. if bAddressInLT then
  408. begin
  409. // Whitespace is possible around the parts of the domain.
  410. FAddress := FAddress +
  411. TrimAllOf(' ' + TAB, Trim(Copy(AText, 1, nFirst - 1))) + '.'; {Do not Localize}
  412. AText := TrimLeft(Copy(AText, nFirst + 1, length(AText)));
  413. end else
  414. begin
  415. // No whitespace is allowed if no wrapping <> characters.
  416. FAddress := FAddress + Copy(AText, 1, nFirst);
  417. AText := Copy(AText, nFirst + 1, length(AText));
  418. end;
  419. end;
  420. '\' : {Do not Localize}
  421. begin
  422. // This will only be discovered in a bracketted or quoted section.
  423. // It's an escape character indicating the next cahracter is {Do not Localize}
  424. // a literal.
  425. if bInQuote then
  426. begin
  427. // Need to retain the second character
  428. if bInAddress then
  429. begin
  430. FAddress := FAddress + Copy(AText, 1, nFirst - 1);
  431. FAddress := FAddress + AText[nFirst + 1];
  432. end else
  433. begin
  434. FName := FName + Copy(AText, 1, nFirst - 1);
  435. FName := FName + AText[nFirst + 1];
  436. end;
  437. end;
  438. AText := Copy(AText, nFirst + 2, length(AText));
  439. end;
  440. end;
  441. // Check for bracketted sections first: ("<>" <> "" <"">) - all is ignored
  442. if nBracketCount > 0 then
  443. begin
  444. // Inside a bracket, only three charatcers are special.
  445. // '(' Opens a nested bracket: (One (Two (Three ))) {Do not Localize}
  446. // ')' Closes a bracket {Do not Localize}
  447. // '/' Escape character: (One /) /( // (Two /) )) {Do not Localize}
  448. nFirst := FindFirstOf('()\', AText); {Do not Localize}
  449. // Check if in quote before address: <"My Name"@domain.example> is valid
  450. end else if bInQuote then
  451. begin
  452. // Inside quotes, only the end quote and escape character are special.
  453. nFirst := FindFirstOf('"\', AText); {Do not Localize}
  454. // Check if after the @ of the address: domain.example>
  455. end else if bAfterAt then
  456. begin
  457. if bAddressInLT then
  458. begin
  459. // If the address is enclosed, then only the '(', '.' & '>' need be {Do not Localize}
  460. // looked for, trimming all content when found: domain . example >
  461. nFirst := FindFirstOf('.>(', AText); {Do not Localize}
  462. end else
  463. begin
  464. nFirst := FindFirstOf('.( ', AText); {Do not Localize}
  465. end;
  466. // Check if in address: <[email protected]>
  467. end else if bInAddress then
  468. begin
  469. nFirst := FindFirstOf('"(@>', AText); {Do not Localize}
  470. // Not in anything - check for opening charactere
  471. end else
  472. begin
  473. // Outside brackets
  474. nFirst := FindFirstOf('("< @' + TAB, AText); {Do not Localize}
  475. end;
  476. until nFirst = 0;
  477. if bInAddress and not bAddressInLT then
  478. begin
  479. FAddress := FAddress + TrimAllOf(' ' + TAB, Trim(AText)); {Do not Localize}
  480. end;
  481. end else
  482. begin
  483. // No special characters, so assume a simple address
  484. FAddress := AText;
  485. end;
  486. end;
  487. { TIdEMailAddressList }
  488. function TIdEMailAddressList.Add: TIdEMailAddressItem;
  489. begin
  490. Result := TIdEMailAddressItem ( inherited Add );
  491. end;
  492. constructor TIdEMailAddressList.Create(AOwner: TPersistent);
  493. begin
  494. inherited Create(AOwner, TIdEMailAddressItem);
  495. end;
  496. procedure TIdEMailAddressList.FillTStrings(AStrings: TStrings);
  497. var idx : Integer;
  498. begin
  499. idx := 0;
  500. while ( idx < Count ) do
  501. begin
  502. AStrings.Add ( GetItem ( idx ).Text );
  503. Inc ( idx );
  504. end; // while ( idx < Count ) do
  505. end;
  506. function TIdEMailAddressList.GetItem(Index: Integer): TIdEMailAddressItem;
  507. begin
  508. Result := TIdEMailAddressItem ( inherited Items [ Index ] );
  509. end;
  510. function TIdEMailAddressList.GetEMailAddresses: String;
  511. var idx : Integer;
  512. begin
  513. Result := ''; {Do not Localize}
  514. idx := 0;
  515. while ( idx < Count ) do
  516. begin
  517. Result := Result + ', ' + GetItem ( idx ).Text; {Do not Localize}
  518. Inc ( idx );
  519. end; // while ( idx < Count ) do
  520. {Remove the first comma and the following space ', ' } {Do not Localize}
  521. System.Delete ( Result, 1, 2 );
  522. end;
  523. procedure TIdEMailAddressList.SetItem(Index: Integer;
  524. const Value: TIdEMailAddressItem);
  525. begin
  526. inherited SetItem(Index, Value );
  527. end;
  528. procedure TIdEMailAddressList.SetEMailAddresses(AList: String);
  529. var
  530. EMail : TIdEMailAddressItem;
  531. iStart : integer ;
  532. sTemp : string ;
  533. nInBracket : Integer;
  534. bInQuote : Boolean;
  535. begin
  536. Clear;
  537. if (trim(Alist) = '') then exit; {Do not Localize}
  538. iStart := FindFirstOf(':;(", ' + TAB, AList); {Do not Localize}
  539. if iStart = 0 then begin
  540. EMail := Add;
  541. EMail.Text := TrimLeft(AList);
  542. end else begin
  543. sTemp := ''; {Do not Localize}
  544. nInBracket := 0;
  545. bInQuote := False;
  546. repeat
  547. case AList[iStart] of
  548. ' ', TAB: begin {Do not Localize}
  549. if iStart = 1 then begin
  550. sTemp := sTemp + AList[iStart];
  551. System.Delete(AList, 1, 1);
  552. end else begin
  553. sTemp := sTemp + Copy(AList, 1, iStart);
  554. AList := Copy(AList, iStart + 1, Length(AList));
  555. end;
  556. end;
  557. ':' : {Do not Localize}
  558. begin
  559. // The start of a group - ignore the lot.
  560. AList := Copy(AList, iStart + 1, Length(AList));
  561. sTemp := ''; {Do not Localize}
  562. end;
  563. ';' : {Do not Localize}
  564. begin
  565. // End of a group. If we have something (groups can be empty),
  566. // then process it.
  567. sTemp := sTemp + Copy(AList, 1, iStart - 1);
  568. if Length(Trim(sTemp)) > 0 then begin
  569. EMail := Add;
  570. EMail.Text := TrimLeft(sTemp);
  571. sTemp := ''; {Do not Localize}
  572. end;
  573. // Now simply remove the end of the group.
  574. AList := Copy(AList, iStart + 1, length(AList));
  575. end;
  576. '(': begin {Do not Localize}
  577. Inc(nInBracket);
  578. sTemp := sTemp + Copy(AList, 1, iStart);
  579. AList := Copy(AList, iStart + 1, length(AList));
  580. end;
  581. ')': begin {Do not Localize}
  582. Dec(nInBracket);
  583. sTemp := sTemp + Copy(AList, 1, iStart);
  584. AList := Copy(AList, iStart + 1, length(AList));
  585. end;
  586. '"': begin {Do not Localize}
  587. sTemp := sTemp + Copy(AList, 1, iStart);
  588. AList := Copy(AList, iStart + 1, Length(AList));
  589. bInQuote := not bInQuote;
  590. end;
  591. ',': begin {Do not Localize}
  592. sTemp := sTemp + Copy(AList, 1, iStart - 1);
  593. EMail := Add;
  594. EMail.Text := sTemp;
  595. // added - Allen .. saves blank entries being added
  596. if (trim(Email.Text) = '') or (trim(Email.Text) = '<>') then {Do not Localize}
  597. begin
  598. FreeAndNil(Email);
  599. end;
  600. sTemp := ''; {Do not Localize}
  601. AList := Copy(AList, iStart + 1, length(AList));
  602. end;
  603. '\': begin {Do not Localize}
  604. // Escape character - simply copy this char and the next to the buffer.
  605. sTemp := sTemp + Copy(AList, 1, iStart + 1);
  606. AList := Copy(AList, iStart + 2, length(AList));
  607. end;
  608. end;
  609. if nInBracket > 0 then begin
  610. iStart := FindFirstOf('(\)', AList); {Do not Localize}
  611. end else if bInQuote then begin
  612. iStart := FindFirstOf('"\', AList); {Do not Localize}
  613. end else begin
  614. iStart := FindFirstOf(':;(", ' + TAB, AList); {Do not Localize}
  615. end;
  616. until iStart = 0;
  617. // Clean up the content in sTemp
  618. if (Length(Trim(sTemp)) > 0) or (Length(Trim(AList)) > 0) then begin
  619. sTemp := sTemp + AList;
  620. EMail := Add;
  621. EMail.Text := TrimLeft(sTemp);
  622. // added - Allen .. saves blank entries being added
  623. if (trim(Email.Text) = '') or (trim(Email.Text) = '<>') then {Do not Localize}
  624. begin
  625. FreeAndNil(Email);
  626. end;
  627. end;
  628. end;
  629. end;
  630. end.