MainForm.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  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;
  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. procedure btnStartStopClick(Sender: TObject);
  54. procedure FormCreate(Sender: TObject);
  55. procedure FormDestroy(Sender: TObject);
  56. procedure lbProcessesDrawItem(Control: TWinControl; Index: Integer;
  57. Rect: TRect; State: TOwnerDrawState);
  58. procedure ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  59. const AStatusText: String);
  60. procedure ServerException(AContext: TIdContext; AException: Exception);
  61. procedure FormActivate(Sender: TObject);
  62. procedure ServerExecute(AContext: TIdContext);
  63. procedure ServerConnect(AContext: TIdContext);
  64. procedure ServerDisconnect(AContext: TIdContext);
  65. procedure edPortKeyPress(Sender: TObject; var Key: Char);
  66. procedure ServerCommandGet(AContext: TIdContext;
  67. ARequestInfo: TIdHTTPRequestInfo;
  68. AResponseInfo: TIdHTTPResponseInfo);
  69. private
  70. { Private declarations }
  71. function CheckStartOk : Boolean;
  72. function StartServer : Boolean;
  73. function StopServer : Boolean;
  74. procedure PopulateIPAddresses;
  75. function PortDescription(const PortNumber: integer): string;
  76. procedure LoadDefaultValues;
  77. procedure SaveDefaultValues;
  78. procedure CheckOptions;
  79. function GetServerOnline: Boolean;
  80. function InternalServerBeforeStart : Boolean;
  81. procedure InternalServerAfterStart;
  82. function InternalServerBeforeStop : Boolean;
  83. procedure InternalServerAfterStop;
  84. procedure Log(Msg : String; Color : TColor = clBlack);
  85. procedure SetControls;
  86. public
  87. { Public declarations }
  88. property ServerOnline : Boolean read GetServerOnline;
  89. end;
  90. var
  91. frmMain : TfrmMain;
  92. Ini : TIniFile;
  93. implementation
  94. {$R *.DFM}
  95. procedure TfrmMain.btnStartStopClick(Sender: TObject);
  96. begin
  97. // This procedure should never change.
  98. if ServerOnline then
  99. StopServer
  100. else
  101. StartServer;
  102. end;
  103. function TfrmMain.CheckStartOk: Boolean;
  104. var
  105. i, c : Integer;
  106. begin
  107. // This section should stay the same, add your new code below
  108. i := 0;
  109. for c := 0 to lbIPs.Items.Count -1 do
  110. begin
  111. if lbIPs.Checked[c] then
  112. inc(i);
  113. end;
  114. result := i > 0;
  115. if not result then
  116. begin
  117. Log('Can''t start server until you select at least one IP to bind to.', clRed);
  118. MessageDlg('Can''t start server until you select at least one IP to bind to.', mtError, [mbOK], 0);
  119. end;
  120. // Add your code after this comment
  121. end;
  122. procedure TfrmMain.PopulateIPAddresses;
  123. var
  124. i : integer;
  125. begin
  126. // Again this section should not change
  127. with lbIPs do
  128. begin
  129. Clear;
  130. Items := GStack.LocalAddresses;
  131. Items.Insert(0, '127.0.0.1');
  132. end;
  133. try
  134. cbPorts.Items.Add(RSBindingAny);
  135. cbPorts.Items.BeginUpdate;
  136. for i := 0 to IdPorts.Count - 1 do
  137. cbPorts.Items.Add(PortDescription(Integer(IdPorts[i])));
  138. finally
  139. cbPorts.Items.EndUpdate;
  140. end;
  141. end;
  142. function TfrmMain.PortDescription(const PortNumber: integer): string;
  143. begin
  144. // Guess what more code that shouldn't change
  145. with TIdStackWindows(GStack).WSGetServByPort(PortNumber) do
  146. try
  147. if PortNumber = 0 then
  148. begin
  149. Result := Format('%d: %s', [PortNumber, RSBindingAny]);
  150. end
  151. else
  152. begin
  153. Result := ''; {Do not Localize}
  154. if Count > 0 then
  155. begin
  156. Result := Format('%d: %s', [PortNumber, CommaText]); {Do not Localize}
  157. end;
  158. end;
  159. finally
  160. Free;
  161. end;
  162. end;
  163. function TfrmMain.StartServer: Boolean;
  164. var
  165. Binding : TIdSocketHandle;
  166. i : integer;
  167. SL : TStringList;
  168. begin
  169. // This code starts the server up and posts back information about
  170. // the server starting up.
  171. // You should place your pre and post startup code in InternalServerBeforeStart
  172. // and InternalServerAfterStart accordingly.
  173. Result := false;
  174. if not CheckStartOk then
  175. exit;
  176. SL := TStringList.Create;
  177. if not StopServer then
  178. begin
  179. Log( 'Error stopping server', clRed );
  180. Result := false;
  181. exit;
  182. end;
  183. Server.Bindings.Clear; // bindings cannot be cleared until TServer is inactive
  184. try
  185. try
  186. Server.DefaultPort := StrToInt(edPort.Text);
  187. for i := 0 to lbIPs.Items.Count - 1 do
  188. if lbIPs.Checked[i] then
  189. begin
  190. Binding := Server.Bindings.Add;
  191. Binding.IP := lbIPs.Items.Strings[i];
  192. Binding.Port := StrToInt( edPort.Text );
  193. Log( 'Server bound to IP ' + Binding.IP + ' on port ' + edPort.Text );
  194. end;
  195. if InternalServerBeforeStart then
  196. begin
  197. Server.Active := true;
  198. result := Server.Active;
  199. InternalServerAfterStart;
  200. if ServerOnline then
  201. begin
  202. Log( 'Server started', clGreen );
  203. btnStartStop.Caption := 'Stop Server';
  204. SetControls;
  205. end;
  206. end;
  207. except
  208. on E : Exception do
  209. begin
  210. Log( 'Server not started', clRed );
  211. Log( E.Message, clRed );
  212. Result := false;
  213. end;
  214. end;
  215. finally
  216. FreeAndNil( SL );
  217. end;
  218. end;
  219. function TfrmMain.StopServer: Boolean;
  220. var
  221. b : Boolean;
  222. begin
  223. // This code stops the server and posts back information about
  224. // the server shutting down.
  225. // You should place your pre and post shutdown code in InternalServerBeforeStop
  226. // and InternalServerAfterStop accordingly.
  227. Result := false;
  228. b := Server.Active;
  229. if InternalServerBeforeStop then
  230. begin
  231. Server.Active := false;
  232. Server.Bindings.Clear;
  233. Result := not Server.Active;
  234. if result then
  235. begin
  236. if b then
  237. Log( 'Server stopped', clGreen );
  238. end
  239. else
  240. begin
  241. Log( 'Server not stopped', clRed );
  242. end;
  243. InternalServerAfterStop;
  244. btnStartStop.Caption := 'Start Server';
  245. SetControls;
  246. end
  247. else
  248. Log( 'Server not stopped', clRed );
  249. end;
  250. procedure TfrmMain.FormCreate(Sender: TObject);
  251. begin
  252. // Initialization routines. You should find the appropriate procedure
  253. // to initialize your stuff below. The form create should hardly ever
  254. // need to be changed.
  255. Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
  256. pcMain.ActivePageIndex := 0;
  257. pcMain.Align := alClient;
  258. PopulateIPAddresses;
  259. StopServer;
  260. LoadDefaultValues;
  261. CheckOptions;
  262. end;
  263. procedure TfrmMain.FormDestroy(Sender: TObject);
  264. begin
  265. // If you created anything in form create or in one of the other
  266. // initialization routines then get rid of it here.
  267. StopServer;
  268. SaveDefaultValues;
  269. Ini.Free;
  270. end;
  271. procedure TfrmMain.LoadDefaultValues;
  272. var
  273. i, c : Integer;
  274. s : String;
  275. begin
  276. // This is were you get the chance to load values from the global
  277. // Ini file. The section for ports and IP's has been added in here
  278. // for you by default.
  279. edPort.Text := Ini.ReadString('Settings', 'Port', edPort.Text);
  280. c := Ini.ReadInteger('Settings', 'IPs', 0);
  281. for i := 1 to c do
  282. begin
  283. s := Ini.ReadString('Settings', 'IP' + IntToStr(i), '');
  284. if lbIPs.Items.IndexOf(s) > -1 then
  285. lbIPs.Checked[lbIPs.Items.IndexOf(s)] := true;
  286. end;
  287. edServerRoot.Text := Ini.ReadString('Settings', 'ServerRoot', ExtractFilePath(ParamStr(0)) + 'Docs');
  288. end;
  289. procedure TfrmMain.SaveDefaultValues;
  290. var
  291. i, c : Integer;
  292. begin
  293. // This is were you get the chance to save values to the global
  294. // Ini file. The section for ports and IP's has been added in here
  295. // for you by default.
  296. Ini.WriteString('Settings', 'Port', edPort.Text);
  297. c := 0;
  298. for i := 0 to lbIPs.Items.Count -1 do
  299. if lbIPs.Checked[i] then
  300. begin
  301. inc(c);
  302. Ini.WriteString('Settings', 'IP' + IntToStr(c), lbIPs.Items[i]);
  303. end;
  304. Ini.WriteInteger('Settings', 'IPs', c);
  305. Ini.WriteInteger('Placement', 'Top', Top);
  306. Ini.WriteInteger('Placement', 'Left', Left);
  307. end;
  308. procedure TfrmMain.CheckOptions;
  309. var
  310. i : Integer;
  311. opt : string;
  312. bDoAutoStart : Boolean;
  313. function OptName : String;
  314. begin
  315. if pos('=', opt) > 0 then
  316. begin
  317. result := copy(opt, 1, pos('=', opt) - 1);
  318. if result[1] in ['-', '/', '\'] then
  319. result := copy(result, 2, length(result));
  320. end
  321. else
  322. result := opt;
  323. end;
  324. function OptValue : String;
  325. begin
  326. if pos('=', opt) > 0 then
  327. result := copy(opt, pos('=', opt) + 1, length(opt))
  328. else
  329. result := opt;
  330. end;
  331. begin
  332. // The check options procedure should be used to check commandline options
  333. // if you wish to support command line options then please add it here.
  334. // By default port and autostart are supported.
  335. bDoAutoStart := false;
  336. for i := 1 to ParamCount do
  337. begin
  338. opt := LowerCase(ParamStr(i));
  339. if OptName = 'port' then
  340. edPort.Text := OptValue;
  341. if OptName = 'autostart' then
  342. bDoAutoStart := true;
  343. end;
  344. if bDoAutoStart then
  345. StartServer;
  346. end;
  347. function TfrmMain.GetServerOnline: Boolean;
  348. begin
  349. // Just a faster way then checking server.active for some
  350. result := Server.Active;
  351. end;
  352. procedure TfrmMain.lbProcessesDrawItem(Control: TWinControl;
  353. Index: Integer; Rect: TRect; State: TOwnerDrawState);
  354. begin
  355. // This draws the items in the Process Log in colors to allow quick
  356. // visual inspection
  357. with Control as TListBox do
  358. begin
  359. Canvas.Brush.Color := Color;
  360. Canvas.FillRect(Rect);
  361. Canvas.Font.Color := TColor(Items.Objects[Index]);
  362. Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
  363. end;
  364. end;
  365. procedure TfrmMain.Log(Msg: String; Color: TColor);
  366. begin
  367. // Simply adds a new item to the process log and then makes it the
  368. // currently selected item.
  369. lbProcesses.Items.AddObject(Msg, Pointer(Color));
  370. lbProcesses.ItemIndex := lbProcesses.Items.Count -1;
  371. end;
  372. procedure TfrmMain.ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  373. const AStatusText: String);
  374. begin
  375. // Logs any ServerStatus messages to the Process Log
  376. Log(AStatusText);
  377. end;
  378. procedure TfrmMain.ServerException(AContext: TIdContext;
  379. AException: Exception);
  380. begin
  381. // Logs any server exceptions to the Process Log
  382. Log(AException.Message, clRed);
  383. end;
  384. function TfrmMain.InternalServerBeforeStart: Boolean;
  385. begin
  386. // Preform your startup code here. If you do not wish the server to start
  387. // then simply return false from this function and report back the proper
  388. // error by calling Log(YourMessage, clRed);
  389. result := true;
  390. end;
  391. procedure TfrmMain.InternalServerAfterStart;
  392. begin
  393. // Your code should go here. At this point the server is active.
  394. // So if you need to stop it then you should call StopServer
  395. // or for a hard halt call Server.Active := false;
  396. end;
  397. procedure TfrmMain.InternalServerAfterStop;
  398. begin
  399. // Your code should go here. At this point the server has been stoped.
  400. // So if you need to start it then you should call StartServer
  401. // or for a force start call Server.Active := true;
  402. end;
  403. function TfrmMain.InternalServerBeforeStop: Boolean;
  404. begin
  405. // Preform your shutdown code here. If you do not wish the server to stop
  406. // then simply return false from this function and report back the proper
  407. // error by calling Log(YourMessage, clRed);
  408. Result := true;
  409. end;
  410. procedure TfrmMain.SetControls;
  411. begin
  412. // Sets up the UI controls to either be enabled or disabled based upon
  413. // the current server state. See below for examples.
  414. lbIPs.Enabled := not ServerOnline;
  415. edPort.Enabled := not ServerOnline;
  416. cbPorts.Enabled := not ServerOnline;
  417. end;
  418. procedure TfrmMain.FormActivate(Sender: TObject);
  419. begin
  420. Top := Ini.ReadInteger('Placement', 'Top', Top);
  421. Left:= Ini.ReadInteger('Placement', 'Left', Left);
  422. end;
  423. procedure TfrmMain.ServerExecute(AContext: TIdContext);
  424. begin
  425. // Your stuff for OnExecute goes here.
  426. end;
  427. procedure TfrmMain.ServerConnect(AContext: TIdContext);
  428. begin
  429. Log('Client connection established from ip: ' + AContext.Connection.Socket.Host, clBlue);
  430. end;
  431. procedure TfrmMain.ServerDisconnect(AContext: TIdContext);
  432. begin
  433. Log('Client connection removed from ip: ' + AContext.Connection.Socket.Host, clBlue);
  434. end;
  435. procedure TfrmMain.edPortKeyPress(Sender: TObject; var Key: Char);
  436. begin
  437. if not (Key in ['0', '1'..'9', #8]) then
  438. Key := #0;
  439. end;
  440. procedure TfrmMain.ServerCommandGet(AContext: TIdContext;
  441. ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  442. var
  443. rPage : String;
  444. begin
  445. Log('Serving: ' + ARequestInfo.Document + ' to ' + AContext.Connection.Socket.Host, clBlue);
  446. if (ARequestInfo.Document <> '') and
  447. (ARequestInfo.Document <> '/') and
  448. (ARequestInfo.Document <> '\') then
  449. rPage := Copy(ARequestInfo.Document, 2, Length(ARequestInfo.Document))
  450. else
  451. rPage := 'Index.htm';
  452. rPage := StringReplace(rPage, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  453. rPage := IncludeTrailingBackslash(edServerRoot.Text) + rPage;
  454. if FileExists(rPage) then
  455. AResponseInfo.ServeFile(AContext, rPage)
  456. else
  457. AResponseInfo.ContentText := '<H1>ERROR</H1>File not found: '+ARequestInfo.Document;
  458. end;
  459. end.