MainForm.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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: 22939: MainForm.pas
  11. {
  12. { Rev 1.0 09/10/2003 3:08:58 PM Jeremy Darling
  13. { Project Checked into TC for the first time
  14. }
  15. {***************************************************************
  16. * Project : <This is the name of your project>
  17. * Unit Name: <This is the name of this unit>
  18. * Purpose : <This is a description of the project>
  19. * Author : <Your Name>
  20. * Date : <Date submitted to indy demo team>
  21. * Other Info : <Anything else>
  22. * History :
  23. * <History list>
  24. ****************************************************************}
  25. unit MainForm;
  26. interface
  27. uses
  28. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  29. IdBaseComponent, IdComponent, IdTCPServer, IdContext, StdCtrls, IdScheduler,
  30. IdSchedulerOfThread, IdSchedulerOfThreadDefault, CheckLst, ComCtrls, ExtCtrls,
  31. IdDsnCoreResourceStrings, IdStack, IdSocketHandle, ShellAPI, IdGlobal,
  32. IniFiles, IdAntiFreezeBase, IdAntiFreeze, IdCustomTCPServer, IdStackWindows,
  33. IdCustomHTTPServer, IdHTTPServer, IdServerIOHandler, IdSSL, IdSSLOpenSSL;
  34. type
  35. TfrmMain = class(TForm)
  36. pnlButtonBar: TPanel;
  37. pcMain: TPageControl;
  38. tsSettings: TTabSheet;
  39. Label2: TLabel;
  40. Label3: TLabel;
  41. Label4: TLabel;
  42. lbIPs: TCheckListBox;
  43. cbPorts: TComboBox;
  44. edPort: TEdit;
  45. tsProcessLog: TTabSheet;
  46. lbProcesses: TListBox;
  47. btnStartStop: TButton;
  48. IdAntiFreeze1: TIdAntiFreeze;
  49. IdSchedulerOfThreadDefault1: TIdSchedulerOfThreadDefault;
  50. Server: TIdHTTPServer;
  51. Label1: TLabel;
  52. edServerRoot: TEdit;
  53. OpenSSL: TIdServerIOHandlerSSLOpenSSL;
  54. tsSSLSetup: TTabSheet;
  55. Label5: TLabel;
  56. Label6: TLabel;
  57. Label7: TLabel;
  58. Label8: TLabel;
  59. Label9: TLabel;
  60. edCertFile: TEdit;
  61. edCipherList: TEdit;
  62. edKeyFile: TEdit;
  63. edRootCertFile: TEdit;
  64. edPassword: TEdit;
  65. cbMaskPass: TCheckBox;
  66. procedure btnStartStopClick(Sender: TObject);
  67. procedure FormCreate(Sender: TObject);
  68. procedure FormDestroy(Sender: TObject);
  69. procedure lbProcessesDrawItem(Control: TWinControl; Index: Integer;
  70. Rect: TRect; State: TOwnerDrawState);
  71. procedure ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  72. const AStatusText: String);
  73. procedure ServerException(AContext: TIdContext; AException: Exception);
  74. procedure FormActivate(Sender: TObject);
  75. procedure ServerConnect(AContext: TIdContext);
  76. procedure ServerDisconnect(AContext: TIdContext);
  77. procedure edPortKeyPress(Sender: TObject; var Key: Char);
  78. procedure ServerCommandGet(AContext: TIdContext;
  79. ARequestInfo: TIdHTTPRequestInfo;
  80. AResponseInfo: TIdHTTPResponseInfo);
  81. procedure OpenSSLGetPassword(
  82. var Password: String);
  83. procedure cbMaskPassClick(Sender: TObject);
  84. procedure ServerQuerySSLPort(APort: Word; var VUseSSL: Boolean);
  85. private
  86. { Private declarations }
  87. function CheckStartOk : Boolean;
  88. function StartServer : Boolean;
  89. function StopServer : Boolean;
  90. procedure PopulateIPAddresses;
  91. function PortDescription(const PortNumber: integer): string;
  92. procedure LoadDefaultValues;
  93. procedure SaveDefaultValues;
  94. procedure CheckOptions;
  95. function GetServerOnline: Boolean;
  96. function InternalServerBeforeStart : Boolean;
  97. procedure InternalServerAfterStart;
  98. function InternalServerBeforeStop : Boolean;
  99. procedure InternalServerAfterStop;
  100. procedure Log(Msg : String; Color : TColor = clBlack);
  101. procedure SetControls;
  102. public
  103. { Public declarations }
  104. property ServerOnline : Boolean read GetServerOnline;
  105. end;
  106. var
  107. frmMain : TfrmMain;
  108. Ini : TIniFile;
  109. implementation
  110. {$R *.DFM}
  111. procedure TfrmMain.btnStartStopClick(Sender: TObject);
  112. begin
  113. // This procedure should never change.
  114. if ServerOnline then
  115. StopServer
  116. else
  117. StartServer;
  118. end;
  119. function TfrmMain.CheckStartOk: Boolean;
  120. var
  121. i, c : Integer;
  122. begin
  123. // This section should stay the same, add your new code below
  124. i := 0;
  125. for c := 0 to lbIPs.Items.Count -1 do
  126. begin
  127. if lbIPs.Checked[c] then
  128. inc(i);
  129. end;
  130. result := i > 0;
  131. if not result then
  132. begin
  133. Log('Can''t start server until you select at least one IP to bind to.', clRed);
  134. MessageDlg('Can''t start server until you select at least one IP to bind to.', mtError, [mbOK], 0);
  135. end;
  136. // Add your code after this comment
  137. end;
  138. procedure TfrmMain.PopulateIPAddresses;
  139. var
  140. i : integer;
  141. begin
  142. // Again this section should not change
  143. with lbIPs do
  144. begin
  145. Clear;
  146. Items := GStack.LocalAddresses;
  147. Items.Insert(0, '127.0.0.1');
  148. end;
  149. try
  150. cbPorts.Items.Add(RSBindingAny);
  151. cbPorts.Items.BeginUpdate;
  152. for i := 0 to IdPorts.Count - 1 do
  153. cbPorts.Items.Add(PortDescription(Integer(IdPorts[i])));
  154. finally
  155. cbPorts.Items.EndUpdate;
  156. end;
  157. end;
  158. function TfrmMain.PortDescription(const PortNumber: integer): string;
  159. begin
  160. // Guess what more code that shouldn't change
  161. with TIdStackWindows(GStack).WSGetServByPort(PortNumber) do
  162. try
  163. if PortNumber = 0 then
  164. begin
  165. Result := Format('%d: %s', [PortNumber, RSBindingAny]);
  166. end
  167. else
  168. begin
  169. Result := ''; {Do not Localize}
  170. if Count > 0 then
  171. begin
  172. Result := Format('%d: %s', [PortNumber, CommaText]); {Do not Localize}
  173. end;
  174. end;
  175. finally
  176. Free;
  177. end;
  178. end;
  179. function TfrmMain.StartServer: Boolean;
  180. var
  181. Binding : TIdSocketHandle;
  182. i : integer;
  183. SL : TStringList;
  184. begin
  185. // This code starts the server up and posts back information about
  186. // the server starting up.
  187. // You should place your pre and post startup code in InternalServerBeforeStart
  188. // and InternalServerAfterStart accordingly.
  189. Result := false;
  190. if not CheckStartOk then
  191. exit;
  192. SL := TStringList.Create;
  193. if not StopServer then
  194. begin
  195. Log( 'Error stopping server', clRed );
  196. Result := false;
  197. exit;
  198. end;
  199. Server.Bindings.Clear; // bindings cannot be cleared until TServer is inactive
  200. try
  201. try
  202. Server.DefaultPort := StrToInt(edPort.Text);
  203. for i := 0 to lbIPs.Items.Count - 1 do
  204. if lbIPs.Checked[i] then
  205. begin
  206. Binding := Server.Bindings.Add;
  207. Binding.IP := lbIPs.Items.Strings[i];
  208. Binding.Port := StrToInt( edPort.Text );
  209. Log( 'Server bound to IP ' + Binding.IP + ' on port ' + edPort.Text );
  210. end;
  211. if InternalServerBeforeStart then
  212. begin
  213. Server.Active := true;
  214. result := Server.Active;
  215. InternalServerAfterStart;
  216. if ServerOnline then
  217. begin
  218. Log( 'Server started', clGreen );
  219. btnStartStop.Caption := 'Stop Server';
  220. SetControls;
  221. end;
  222. end;
  223. except
  224. on E : Exception do
  225. begin
  226. Log( 'Server not started', clRed );
  227. Log( E.Message, clRed );
  228. Result := false;
  229. end;
  230. end;
  231. finally
  232. FreeAndNil( SL );
  233. end;
  234. end;
  235. function TfrmMain.StopServer: Boolean;
  236. var
  237. b : Boolean;
  238. begin
  239. // This code stops the server and posts back information about
  240. // the server shutting down.
  241. // You should place your pre and post shutdown code in InternalServerBeforeStop
  242. // and InternalServerAfterStop accordingly.
  243. Result := false;
  244. b := Server.Active;
  245. if InternalServerBeforeStop then
  246. begin
  247. Server.Active := false;
  248. Server.Bindings.Clear;
  249. Result := not Server.Active;
  250. if result then
  251. begin
  252. if b then
  253. Log( 'Server stopped', clGreen );
  254. end
  255. else
  256. begin
  257. Log( 'Server not stopped', clRed );
  258. end;
  259. InternalServerAfterStop;
  260. btnStartStop.Caption := 'Start Server';
  261. SetControls;
  262. end
  263. else
  264. Log( 'Server not stopped', clRed );
  265. end;
  266. procedure TfrmMain.FormCreate(Sender: TObject);
  267. begin
  268. // Initialization routines. You should find the appropriate procedure
  269. // to initialize your stuff below. The form create should hardly ever
  270. // need to be changed.
  271. Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
  272. pcMain.ActivePageIndex := 0;
  273. pcMain.Align := alClient;
  274. PopulateIPAddresses;
  275. StopServer;
  276. LoadDefaultValues;
  277. CheckOptions;
  278. end;
  279. procedure TfrmMain.FormDestroy(Sender: TObject);
  280. begin
  281. // If you created anything in form create or in one of the other
  282. // initialization routines then get rid of it here.
  283. StopServer;
  284. SaveDefaultValues;
  285. Ini.Free;
  286. end;
  287. procedure TfrmMain.LoadDefaultValues;
  288. var
  289. i, c : Integer;
  290. s : String;
  291. begin
  292. // This is were you get the chance to load values from the global
  293. // Ini file. The section for ports and IP's has been added in here
  294. // for you by default.
  295. edPort.Text := Ini.ReadString('Settings', 'Port', edPort.Text);
  296. c := Ini.ReadInteger('Settings', 'IPs', 0);
  297. for i := 1 to c do
  298. begin
  299. s := Ini.ReadString('Settings', 'IP' + IntToStr(i), '');
  300. if lbIPs.Items.IndexOf(s) > -1 then
  301. lbIPs.Checked[lbIPs.Items.IndexOf(s)] := true;
  302. end;
  303. edServerRoot.Text := Ini.ReadString('Settings', 'ServerRoot', ExtractFilePath(ParamStr(0)) + 'Docs');
  304. edCertFile.Text := Ini.ReadString('SSLSettings', 'CertFile', '');
  305. edCipherList.Text := Ini.ReadString('SSLSettings', 'CipherList', '');
  306. edKeyFile.Text := Ini.ReadString('SSLSettings', 'KeyFile', '');
  307. edRootCertFile.Text := Ini.ReadString('SSLSettings', 'RootCertFile', '');
  308. edPassword.Text := Ini.ReadString('SSLSettings', 'Password', '');
  309. end;
  310. procedure TfrmMain.SaveDefaultValues;
  311. var
  312. i, c : Integer;
  313. begin
  314. // This is were you get the chance to save values to the global
  315. // Ini file. The section for ports and IP's has been added in here
  316. // for you by default.
  317. Ini.WriteString('Settings', 'Port', edPort.Text);
  318. c := 0;
  319. for i := 0 to lbIPs.Items.Count -1 do
  320. if lbIPs.Checked[i] then
  321. begin
  322. inc(c);
  323. Ini.WriteString('Settings', 'IP' + IntToStr(c), lbIPs.Items[i]);
  324. end;
  325. Ini.WriteInteger('Settings', 'IPs', c);
  326. Ini.WriteInteger('Placement', 'Top', Top);
  327. Ini.WriteInteger('Placement', 'Left', Left);
  328. Ini.WriteString('SSLSettings', 'CertFile', edCertFile.Text);
  329. Ini.WriteString('SSLSettings', 'CipherList', edCipherList.Text);
  330. Ini.WriteString('SSLSettings', 'KeyFile', edKeyFile.Text);
  331. Ini.WriteString('SSLSettings', 'RootCertFile', edRootCertFile.Text);
  332. Ini.WriteString('SSLSettings', 'Password', edPassword.Text);
  333. end;
  334. procedure TfrmMain.CheckOptions;
  335. var
  336. i : Integer;
  337. opt : string;
  338. bDoAutoStart : Boolean;
  339. function OptName : String;
  340. begin
  341. if pos('=', opt) > 0 then
  342. begin
  343. result := copy(opt, 1, pos('=', opt) - 1);
  344. if result[1] in ['-', '/', '\'] then
  345. result := copy(result, 2, length(result));
  346. end
  347. else
  348. result := opt;
  349. end;
  350. function OptValue : String;
  351. begin
  352. if pos('=', opt) > 0 then
  353. result := copy(opt, pos('=', opt) + 1, length(opt))
  354. else
  355. result := opt;
  356. end;
  357. begin
  358. // The check options procedure should be used to check commandline options
  359. // if you wish to support command line options then please add it here.
  360. // By default port and autostart are supported.
  361. bDoAutoStart := false;
  362. for i := 1 to ParamCount do
  363. begin
  364. opt := LowerCase(ParamStr(i));
  365. if OptName = 'port' then
  366. edPort.Text := OptValue;
  367. if OptName = 'autostart' then
  368. bDoAutoStart := true;
  369. end;
  370. if bDoAutoStart then
  371. StartServer;
  372. end;
  373. function TfrmMain.GetServerOnline: Boolean;
  374. begin
  375. // Just a faster way then checking server.active for some
  376. result := Server.Active;
  377. end;
  378. procedure TfrmMain.lbProcessesDrawItem(Control: TWinControl;
  379. Index: Integer; Rect: TRect; State: TOwnerDrawState);
  380. begin
  381. // This draws the items in the Process Log in colors to allow quick
  382. // visual inspection
  383. with Control as TListBox do
  384. begin
  385. Canvas.Brush.Color := Color;
  386. Canvas.FillRect(Rect);
  387. Canvas.Font.Color := TColor(Items.Objects[Index]);
  388. Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
  389. end;
  390. end;
  391. procedure TfrmMain.Log(Msg: String; Color: TColor);
  392. begin
  393. // Simply adds a new item to the process log and then makes it the
  394. // currently selected item.
  395. lbProcesses.Items.AddObject(Msg, Pointer(Color));
  396. lbProcesses.ItemIndex := lbProcesses.Items.Count -1;
  397. end;
  398. procedure TfrmMain.ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  399. const AStatusText: String);
  400. begin
  401. // Logs any ServerStatus messages to the Process Log
  402. Log(AStatusText);
  403. end;
  404. procedure TfrmMain.ServerException(AContext: TIdContext;
  405. AException: Exception);
  406. begin
  407. // Logs any server exceptions to the Process Log
  408. Log(AException.Message, clRed);
  409. end;
  410. //***!!!!!NB!!!!!! IF USING NON STD PORT i.e. NOT 443 then this MUST BE SETUP!!!!!!!
  411. //else you get: Project IHTTPServer.exe raised exception class EIdHTTPErrorParsingCommand with message 'Error in parsing command.'.
  412. procedure TfrmMain.ServerQuerySSLPort(APort: Word; var VUseSSL: Boolean);
  413. begin
  414. VUseSSL:=(APort=StrToIntDef(edPort.Text,443));
  415. end;
  416. function TfrmMain.InternalServerBeforeStart: Boolean;
  417. begin
  418. // Perform your startup code here. If you do not wish the server to start
  419. // then simply return false from this function and report back the proper
  420. // error by calling Log(YourMessage, clRed);
  421. result := true;
  422. try
  423. with OpenSSL.SSLOptions do
  424. begin
  425. CertFile := edCertFile.Text;
  426. CipherList := edCipherList.Text;
  427. KeyFile := edKeyFile.Text;
  428. RootCertFile := edRootCertFile.Text;
  429. end;
  430. except
  431. result := false;
  432. end;
  433. end;
  434. procedure TfrmMain.InternalServerAfterStart;
  435. begin
  436. // Your code should go here. At this point the server is active.
  437. // So if you need to stop it then you should call StopServer
  438. // or for a hard halt call Server.Active := false;
  439. end;
  440. procedure TfrmMain.InternalServerAfterStop;
  441. begin
  442. // Your code should go here. At this point the server has been stoped.
  443. // So if you need to start it then you should call StartServer
  444. // or for a force start call Server.Active := true;
  445. end;
  446. function TfrmMain.InternalServerBeforeStop: Boolean;
  447. begin
  448. // Preform your shutdown code here. If you do not wish the server to stop
  449. // then simply return false from this function and report back the proper
  450. // error by calling Log(YourMessage, clRed);
  451. Result := true;
  452. end;
  453. procedure TfrmMain.SetControls;
  454. begin
  455. // Sets up the UI controls to either be enabled or disabled based upon
  456. // the current server state. See below for examples.
  457. lbIPs.Enabled := not ServerOnline;
  458. edPort.Enabled := not ServerOnline;
  459. cbPorts.Enabled := not ServerOnline;
  460. end;
  461. procedure TfrmMain.FormActivate(Sender: TObject);
  462. begin
  463. Top := Ini.ReadInteger('Placement', 'Top', Top);
  464. Left:= Ini.ReadInteger('Placement', 'Left', Left);
  465. end;
  466. procedure TfrmMain.ServerConnect(AContext: TIdContext);
  467. begin
  468. Log('Client connection established from ip: ' + AContext.Connection.Socket.Host, clBlue);
  469. end;
  470. procedure TfrmMain.ServerDisconnect(AContext: TIdContext);
  471. begin
  472. Log('Client connection removed from ip: ' + AContext.Connection.Socket.Host, clBlue);
  473. end;
  474. procedure TfrmMain.edPortKeyPress(Sender: TObject; var Key: Char);
  475. begin
  476. if not (Key in ['0', '1'..'9', #8]) then
  477. Key := #0;
  478. end;
  479. procedure TfrmMain.ServerCommandGet(AContext: TIdContext;
  480. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  481. var
  482. rPage : String;
  483. begin
  484. Log('Serving: ' + ARequestInfo.Document + ' to ' + AContext.Connection.Socket.Host, clBlue);
  485. if (ARequestInfo.Document <> '') and
  486. (ARequestInfo.Document <> '/') and
  487. (ARequestInfo.Document <> '\') then
  488. rPage := Copy(ARequestInfo.Document, 2, Length(ARequestInfo.Document))
  489. else
  490. rPage := 'Index.htm';
  491. if PathDelim = '\' then
  492. rPage := StringReplace(rPage, '/', '\',[rfReplaceAll, rfIgnoreCase])
  493. else
  494. rPage := StringReplace(rPage, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  495. rPage := IncludeTrailingPathDelimiter(edServerRoot.Text) + rPage;
  496. if FileExists(rPage) then
  497. AResponseInfo.ServeFile(AContext, rPage)
  498. else
  499. AResponseInfo.ContentText := '<H1>ERROR</H1>File not found: '+ARequestInfo.Document;
  500. end;
  501. procedure TfrmMain.OpenSSLGetPassword(
  502. var Password: String);
  503. begin
  504. Password := edPassword.Text;
  505. end;
  506. procedure TfrmMain.cbMaskPassClick(Sender: TObject);
  507. begin
  508. if cbMaskPass.Checked then
  509. edPassword.PasswordChar := '*'
  510. else
  511. edPassword.PasswordChar := #0;
  512. end;
  513. end.