PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/ProSnooperFx_src/ics/Delphi/Internet/PopTst1.pas

http://github.com/lookias/ProSnooper
Pascal | 558 lines | 353 code | 92 blank | 113 comment | 10 complexity | e3152e3a73dd53c0f969470bf115c7e7 MD5 | raw file
  1. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2. +-------------------------------------------------------------------+
  3. | THIS IS AN OUTDATED APPLICATION USING AN OUTDATED COMPONENT. |
  4. | NEW COMPONENT IS IN POP3PROT.PAS FILE. NEW DEMO IS MAILRCV.DPR. |
  5. +-------------------------------------------------------------------+
  6. Author: François PIETTE
  7. Object: Show how to use TPop3Cli (POP3 protocol, RFC-1225)
  8. Creation: 03 october 1997
  9. Version: 1.02
  10. EMail: francois.piette@pophost.eunet.be
  11. francois.piette@rtfm.be http://www.rtfm.be/fpiette
  12. Support: Use the mailing list twsocket@rtfm.be See website for details.
  13. Legal issues: Copyright (C) 1997, 1998 by François PIETTE
  14. Rue de Grady 24, 4053 Embourg, Belgium. Fax: +32-4-365.74.56
  15. <francois.piette@pophost.eunet.be>
  16. This software is provided 'as-is', without any express or
  17. implied warranty. In no event will the author be held liable
  18. for any damages arising from the use of this software.
  19. Permission is granted to anyone to use this software for any
  20. purpose, including commercial applications, and to alter it
  21. and redistribute it freely, subject to the following
  22. restrictions:
  23. 1. The origin of this software must not be misrepresented,
  24. you must not claim that you wrote the original software.
  25. If you use this software in a product, an acknowledgment
  26. in the product documentation would be appreciated but is
  27. not required.
  28. 2. Altered source versions must be plainly marked as such, and
  29. must not be misrepresented as being the original software.
  30. 3. This notice may not be removed or altered from any source
  31. distribution.
  32. 4. You must register this software by sending a picture postcard
  33. to the author. Use a nice stamp and mention your name, street
  34. address, EMail address and any comment you like to say.
  35. Updates:
  36. Nov 12, 1997 V1.01 Added a GetAll button to get all messages waiting in the
  37. POP3 server, copying them to a file using the UIDL to build
  38. the file name (sorry, wont work with D1 because of long file
  39. name). The message is *NOT* deleted from the POP3 server.
  40. Jan 10, 1998 V1.02 Added port selection
  41. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  42. unit PopTst1;
  43. interface
  44. uses
  45. WinTypes, WinProcs, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  46. Dialogs, WSocket, pop3cli, StdCtrls, Wait, IniFiles, ExtCtrls;
  47. const
  48. PopTstVersion = 102;
  49. type
  50. TPOP3ExcercizerForm = class(TForm)
  51. Pop3Client: TPop3Client;
  52. DisplayMemo: TMemo;
  53. Panel1: TPanel;
  54. InfoLabel: TLabel;
  55. Label1: TLabel;
  56. Label2: TLabel;
  57. Label3: TLabel;
  58. Label4: TLabel;
  59. Label5: TLabel;
  60. ConnectButton: TButton;
  61. Wait1: TWait;
  62. DisconnectButton: TButton;
  63. UserButton: TButton;
  64. HostEdit: TEdit;
  65. UserNameEdit: TEdit;
  66. PassWordEdit: TEdit;
  67. PassButton: TButton;
  68. MsgNumEdit: TEdit;
  69. RetrButton: TButton;
  70. StatButton: TButton;
  71. ListAllButton: TButton;
  72. ListButton: TButton;
  73. DeleteButton: TButton;
  74. NoopButton: TButton;
  75. LastButton: TButton;
  76. ResetButton: TButton;
  77. TopButton: TButton;
  78. MsgLinesEdit: TEdit;
  79. RpopButton: TButton;
  80. UidlButton: TButton;
  81. ApopButton: TButton;
  82. NextButton: TButton;
  83. GetAllButton: TButton;
  84. PortEdit: TEdit;
  85. Label6: TLabel;
  86. procedure ConnectButtonClick(Sender: TObject);
  87. procedure FormCreate(Sender: TObject);
  88. procedure DisconnectButtonClick(Sender: TObject);
  89. procedure UserButtonClick(Sender: TObject);
  90. procedure PassButtonClick(Sender: TObject);
  91. procedure Pop3ClientMessageBegin(Sender: TObject);
  92. procedure Pop3ClientMessageEnd(Sender: TObject);
  93. procedure Pop3ClientMessageLine(Sender: TObject);
  94. procedure RetrButtonClick(Sender: TObject);
  95. procedure StatButtonClick(Sender: TObject);
  96. procedure ListAllButtonClick(Sender: TObject);
  97. procedure ListButtonClick(Sender: TObject);
  98. procedure Pop3ClientListBegin(Sender: TObject);
  99. procedure Pop3ClientListEnd(Sender: TObject);
  100. procedure Pop3ClientListLine(Sender: TObject);
  101. procedure DeleteButtonClick(Sender: TObject);
  102. procedure NoopButtonClick(Sender: TObject);
  103. procedure LastButtonClick(Sender: TObject);
  104. procedure ResetButtonClick(Sender: TObject);
  105. procedure TopButtonClick(Sender: TObject);
  106. procedure RpopButtonClick(Sender: TObject);
  107. procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  108. procedure Pop3ClientDisplay(Sender: TObject; Msg: String);
  109. procedure UidlButtonClick(Sender: TObject);
  110. procedure Pop3ClientUidlBegin(Sender: TObject);
  111. procedure Pop3ClientUidlEnd(Sender: TObject);
  112. procedure Pop3ClientUidlLine(Sender: TObject);
  113. procedure ApopButtonClick(Sender: TObject);
  114. procedure NextButtonClick(Sender: TObject);
  115. procedure GetAllButtonClick(Sender: TObject);
  116. private
  117. FFile : TextFile;
  118. FFileName : String;
  119. function DoTheJob(MethodPtr : TPop3Method; MethodName : String) : Boolean;
  120. procedure MessageBegin(Sender: TObject);
  121. procedure MessageLine(Sender: TObject);
  122. procedure GetAllMessageLine(Sender: TObject);
  123. public
  124. { Déclarations publiques }
  125. end;
  126. var
  127. POP3ExcercizerForm: TPOP3ExcercizerForm;
  128. implementation
  129. {$R *.DFM}
  130. uses
  131. PopTst2;
  132. const
  133. IniFileName = 'POPTST.INI';
  134. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  135. { Restore some data from the INI file }
  136. procedure TPOP3ExcercizerForm.FormCreate(Sender: TObject);
  137. var
  138. IniFile : TIniFile;
  139. begin
  140. IniFile := TIniFile.Create(IniFileName);
  141. HostEdit.Text := IniFile.ReadString('Data', 'Host', '');
  142. PortEdit.Text := IniFile.ReadString('Data', 'Port', '');
  143. UserNameEdit.Text := IniFile.ReadString('Data', 'UserName', '');
  144. PassWordEdit.Text := IniFile.ReadString('Data', 'Password', '');
  145. IniFile.Free;
  146. InfoLabel.Caption := '';
  147. end;
  148. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  149. { Save data to INI file }
  150. procedure TPOP3ExcercizerForm.FormCloseQuery(Sender: TObject;
  151. var CanClose: Boolean);
  152. var
  153. IniFile : TIniFile;
  154. begin
  155. IniFile := TIniFile.Create(IniFileName);
  156. IniFile.WriteString('Data', 'Host', HostEdit.Text);
  157. IniFile.WriteString('Data', 'Port', PortEdit.Text);
  158. IniFile.WriteString('Data', 'UserName', UserNameEdit.Text);
  159. IniFile.WriteString('Data', 'Password', PassWordEdit.Text);
  160. IniFile.Free;
  161. end;
  162. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  163. { This event handler is called when the TPop3Client object wants to display }
  164. { some information such as connection progress or errors. }
  165. procedure TPOP3ExcercizerForm.Pop3ClientDisplay(Sender: TObject;
  166. Msg: String);
  167. begin
  168. DisplayMemo.Lines.Add(Msg);
  169. end;
  170. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  171. { All the TPop3Client method are of the same type. To simplify this demo }
  172. { application, DoTheJob transfert the parameters form the various EditBoxes }
  173. { to the Pop3Client instance and then call the appropriate method, showing }
  174. { the result in the InfoLabel.Caption. }
  175. function TPOP3ExcercizerForm.DoTheJob(
  176. MethodPtr : TPop3Method;
  177. MethodName : String) : Boolean;
  178. begin
  179. Pop3Client.Host := HostEdit.Text;
  180. Pop3Client.Port := PortEdit.Text;
  181. Pop3Client.UserName := UserNameEdit.Text;
  182. Pop3Client.PassWord := PassWordEdit.Text;
  183. Pop3Client.MsgNum := StrToInt(MsgNumEdit.Text);
  184. Pop3Client.MsgLines := StrToInt(MsgLinesEdit.Text);
  185. InfoLabel.Caption := MethodName + ' started';
  186. Result := MethodPtr;
  187. if Result then
  188. InfoLabel.Caption := MethodName + ' ok'
  189. else
  190. InfoLabel.Caption := MethodName + ' failed';
  191. end;
  192. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  193. procedure TPOP3ExcercizerForm.ConnectButtonClick(Sender: TObject);
  194. begin
  195. DoTheJob(Pop3Client.Connect, 'Connect');
  196. end;
  197. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  198. procedure TPOP3ExcercizerForm.DisconnectButtonClick(Sender: TObject);
  199. begin
  200. DoTheJob(Pop3Client.Quit, 'Quit');
  201. end;
  202. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  203. procedure TPOP3ExcercizerForm.UserButtonClick(Sender: TObject);
  204. begin
  205. DoTheJob(Pop3Client.User, 'User');
  206. end;
  207. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  208. procedure TPOP3ExcercizerForm.PassButtonClick(Sender: TObject);
  209. begin
  210. DoTheJob(Pop3Client.Pass, 'Pass');
  211. end;
  212. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  213. procedure TPOP3ExcercizerForm.RetrButtonClick(Sender: TObject);
  214. begin
  215. DoTheJob(Pop3Client.Retr, 'Retr');
  216. end;
  217. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  218. procedure TPOP3ExcercizerForm.StatButtonClick(Sender: TObject);
  219. begin
  220. if DoTheJob(Pop3Client.Stat, 'Stat') then
  221. InfoLabel.Caption := 'Stat ok, ' +
  222. IntToStr(Pop3Client.MsgCount) + ' messages ' +
  223. IntToStr(Pop3Client.MsgSize) + ' bytes'
  224. end;
  225. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  226. procedure TPOP3ExcercizerForm.ListAllButtonClick(Sender: TObject);
  227. begin
  228. MsgNumEdit.Text := '0';
  229. DoTheJob(Pop3Client.List, 'List All');
  230. end;
  231. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  232. procedure TPOP3ExcercizerForm.ListButtonClick(Sender: TObject);
  233. begin
  234. DoTheJob(Pop3Client.List, 'List');
  235. end;
  236. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  237. procedure TPOP3ExcercizerForm.DeleteButtonClick(Sender: TObject);
  238. begin
  239. DoTheJob(Pop3Client.Dele, 'Delete');
  240. end;
  241. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  242. procedure TPOP3ExcercizerForm.NoopButtonClick(Sender: TObject);
  243. begin
  244. DoTheJob(Pop3Client.Noop, 'Noop');
  245. end;
  246. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  247. procedure TPOP3ExcercizerForm.LastButtonClick(Sender: TObject);
  248. begin
  249. if DoTheJob(Pop3Client.Last, 'Last') then
  250. InfoLabel.caption := 'Last = ' + IntToStr(Pop3Client.MsgNum);
  251. end;
  252. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  253. procedure TPOP3ExcercizerForm.ResetButtonClick(Sender: TObject);
  254. begin
  255. DoTheJob(Pop3Client.Rset, 'Rset');
  256. end;
  257. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  258. procedure TPOP3ExcercizerForm.TopButtonClick(Sender: TObject);
  259. begin
  260. DoTheJob(Pop3Client.Top, 'Top');
  261. end;
  262. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  263. procedure TPOP3ExcercizerForm.RpopButtonClick(Sender: TObject);
  264. begin
  265. DoTheJob(Pop3Client.Rpop, 'Rpop');
  266. end;
  267. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  268. procedure TPOP3ExcercizerForm.UidlButtonClick(Sender: TObject);
  269. begin
  270. DoTheJob(Pop3Client.Uidl, 'Uidl');
  271. end;
  272. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  273. procedure TPOP3ExcercizerForm.ApopButtonClick(Sender: TObject);
  274. begin
  275. DoTheJob(Pop3Client.Apop, 'Apop');
  276. end;
  277. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  278. { This event handler is called when TPop3Client is about to receive a }
  279. { message. The MsgNum property gives the message number. }
  280. { This event handler could be used to open the file used to store the msg. }
  281. { The file handle could be stored in the TPop3Client.Tag property to be }
  282. { easily retrieved by the OnMessageLine and OnMessageEnd event handlers. }
  283. procedure TPOP3ExcercizerForm.Pop3ClientMessageBegin(Sender: TObject);
  284. begin
  285. DisplayMemo.Lines.Add('*** Message ' +
  286. IntToStr((Sender as TPop3Client).MsgNum) +
  287. ' begin ***');
  288. end;
  289. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  290. { This event handler is called when TPop3Client has detected the end of a }
  291. { message, even if there is an error or exception, this event gets called. }
  292. { This event handler could be used to close the file used to store the msg. }
  293. procedure TPOP3ExcercizerForm.Pop3ClientMessageEnd(Sender: TObject);
  294. begin
  295. DisplayMemo.Lines.Add('*** Message ' +
  296. IntToStr((Sender as TPop3Client).MsgNum) +
  297. ' end ***');
  298. end;
  299. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  300. { This event handler is called for each message line that TPop3Client is }
  301. { receiveing. This could be used to write the message lines to a file. }
  302. procedure TPOP3ExcercizerForm.Pop3ClientMessageLine(Sender: TObject);
  303. begin
  304. DisplayMemo.Lines.Add((Sender as TPop3Client).LastResponse);
  305. end;
  306. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  307. { This event handler is called when TPop3Client is about to receive a }
  308. { list line. The MsgNum property gives the message number. }
  309. procedure TPOP3ExcercizerForm.Pop3ClientListBegin(Sender: TObject);
  310. begin
  311. DisplayMemo.Lines.Add('*** List begin ***');
  312. end;
  313. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  314. { This event handler is called when TPop3Client has received the last list }
  315. { line. }
  316. procedure TPOP3ExcercizerForm.Pop3ClientListEnd(Sender: TObject);
  317. begin
  318. DisplayMemo.Lines.Add('*** List End ***');
  319. end;
  320. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  321. { This event handler is called for each list line received by TPop3Client. }
  322. procedure TPOP3ExcercizerForm.Pop3ClientListLine(Sender: TObject);
  323. var
  324. Buffer : String;
  325. begin
  326. Buffer := 'MsgNum = ' + IntToStr((Sender as TPop3Client).MsgNum) + ' ' +
  327. 'MsgSize = ' + IntToStr((Sender as TPop3Client).MsgSize) + ' ' +
  328. 'Line = ''' + (Sender as TPop3Client).LastResponse + '''';
  329. DisplayMemo.Lines.Add(Buffer);
  330. end;
  331. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  332. procedure TPOP3ExcercizerForm.Pop3ClientUidlBegin(Sender: TObject);
  333. begin
  334. DisplayMemo.Lines.Add('*** Uidl begin ***');
  335. end;
  336. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  337. procedure TPOP3ExcercizerForm.Pop3ClientUidlEnd(Sender: TObject);
  338. begin
  339. DisplayMemo.Lines.Add('*** Uidl end ***');
  340. end;
  341. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  342. procedure TPOP3ExcercizerForm.Pop3ClientUidlLine(Sender: TObject);
  343. var
  344. Buffer : String;
  345. begin
  346. Buffer := 'MsgNum = ' + IntToStr((Sender as TPop3Client).MsgNum) + ' ' +
  347. 'MsgUidl = ' + (Sender as TPop3Client).MsgUidl + '''';
  348. DisplayMemo.Lines.Add(Buffer);
  349. end;
  350. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  351. procedure TPOP3ExcercizerForm.MessageBegin(Sender: TObject);
  352. begin
  353. MessageForm.Caption := 'Message ' +
  354. IntToStr((Sender as TPop3Client).MsgNum);
  355. MessageForm.Show;
  356. end;
  357. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  358. procedure TPOP3ExcercizerForm.MessageLine(Sender: TObject);
  359. begin
  360. MessageForm.DisplayMemo.Lines.Add((Sender as TPop3Client).LastResponse);
  361. end;
  362. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  363. procedure TPOP3ExcercizerForm.NextButtonClick(Sender: TObject);
  364. var
  365. OldBegin : TNotifyEvent;
  366. OldEnd : TNotifyEvent;
  367. OldLine : TNotifyEvent;
  368. begin
  369. OldBegin := Pop3Client.OnMessageBegin;
  370. OldEnd := Pop3Client.OnMessageEnd;
  371. OldLine := Pop3Client.OnMessageLine;
  372. Pop3Client.OnMessageBegin := MessageBegin;
  373. Pop3Client.OnMessageEnd := nil;
  374. Pop3Client.OnMessageLine := MessageLine;
  375. MessageForm.DisplayMemo.Clear;
  376. MessageForm.Caption := 'Message';
  377. DoTheJob(Pop3Client.Retr, 'Retr');
  378. if (Length(Pop3Client.LastResponse) > 0) and
  379. (Pop3Client.LastResponse[1] = '-') then
  380. MessageForm.DisplayMemo.Lines.Add(Pop3Client.LastResponse)
  381. else
  382. MsgNumEdit.Text := IntToStr(StrToInt(MsgNumEdit.Text) + 1);
  383. MessageForm.DisplayMemo.SelStart := 0;
  384. MessageForm.DisplayMemo.SelLength := 0;
  385. Pop3Client.OnMessageBegin := OldBegin;
  386. Pop3Client.OnMessageEnd := OldEnd;
  387. Pop3Client.OnMessageLine := OldLine;
  388. end;
  389. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  390. procedure TPOP3ExcercizerForm.GetAllMessageLine(Sender: TObject);
  391. begin
  392. Writeln(FFile, (Sender as TPop3Client).LastResponse);
  393. end;
  394. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  395. procedure TPOP3ExcercizerForm.GetAllButtonClick(Sender: TObject);
  396. var
  397. MsgCnt : Integer;
  398. MsgNum : Integer;
  399. Uidl : String;
  400. OldBegin : TNotifyEvent;
  401. OldEnd : TNotifyEvent;
  402. OldLine : TNotifyEvent;
  403. IniFile : TIniFile;
  404. Path : String;
  405. begin
  406. if not DoTheJob(Pop3Client.Stat, 'Stat') then
  407. Exit;
  408. InfoLabel.Caption := 'Stat ok, ' +
  409. IntToStr(Pop3Client.MsgCount) + ' messages ' +
  410. IntToStr(Pop3Client.MsgSize) + ' bytes';
  411. if Pop3Client.MsgCount < 1 then
  412. Exit;
  413. { Get path from INI file }
  414. IniFile := TIniFile.Create(IniFileName);
  415. Path := IniFile.ReadString('Data', 'MsgPath',
  416. ExtractFilePath(Application.ExeName));
  417. IniFile.Free;
  418. { Be sure to have an ending backslash }
  419. if (Length(Path) > 0) and (Path[Length(Path)] <> '\') then
  420. Path := Path + '\';
  421. OldBegin := Pop3Client.OnMessageBegin;
  422. OldEnd := Pop3Client.OnMessageEnd;
  423. OldLine := Pop3Client.OnMessageLine;
  424. Pop3Client.OnMessageBegin := nil;
  425. Pop3Client.OnMessageEnd := nil;
  426. Pop3Client.OnMessageLine := GetAllMessageLine;
  427. try
  428. MsgCnt := Pop3Client.MsgCount;
  429. for MsgNum := 1 to MsgCnt do begin
  430. Pop3Client.MsgNum := MsgNum;
  431. if not Pop3Client.Uidl then
  432. continue;
  433. Uidl := Pop3Client.MsgUidl;
  434. FFileName := Path + 'Msg ' + Uidl + '.txt';
  435. if FileExists(FFileName) then begin
  436. DisplayMemo.Lines.Add('Message ' + IntToStr(MsgNum) + ' already here');
  437. continue;
  438. end;
  439. DisplayMemo.Lines.Add('Message ' + IntToStr(Pop3Client.MsgNum));
  440. AssignFile(FFile, FFileName);
  441. Rewrite(FFile);
  442. try
  443. Pop3Client.Retr;
  444. finally
  445. CloseFile(FFile);
  446. end;
  447. end;
  448. DoTheJob(Pop3Client.Quit, 'Quit');
  449. finally
  450. Pop3Client.OnMessageBegin := OldBegin;
  451. Pop3Client.OnMessageEnd := OldEnd;
  452. Pop3Client.OnMessageLine := OldLine;
  453. end;
  454. end;
  455. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  456. end.