IdIPWatch.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.5 10/26/2004 11:08:04 PM JPMugaas
  18. Updated refs.
  19. Rev 1.4 2004.02.03 5:43:54 PM czhower
  20. Name changes
  21. Rev 1.3 2/1/2004 3:33:46 AM JPMugaas
  22. Reenabled. SHould work in DotNET.
  23. Rev 1.2 1/21/2004 3:11:12 PM JPMugaas
  24. InitComponent
  25. Rev 1.1 2003.10.12 4:03:58 PM czhower
  26. compile todos
  27. Rev 1.0 11/13/2002 07:55:32 AM JPMugaas
  28. 2000-Dec-22 Kudzu
  29. -Changed from a TTimer to a sleeping thread to eliminate the reference to ExtCtrls. This was the
  30. only unit in all of Indy that used this unit and caused the pkg to rely on extra pkgs.
  31. -Changed Enabled to Active to be more consistent
  32. -Active now also defaults to false to be more consistent
  33. 2000-MAY-10 Hadi Hariri
  34. -Added new feature to Force Check of status
  35. 2000-Apr-23 Hadi Hariri
  36. -Converted to Indy
  37. 2000-Mar-01 Johannes Berg <[email protected]>
  38. - new property HistoryFilename
  39. - new property MaxHistoryEntries
  40. - new property HistoryEnabled
  41. 2000-Jan-13 MTL
  42. -Moved to new Palette Scheme (Winshoes Misc)
  43. }
  44. unit IdIPWatch;
  45. {
  46. Simple component determines Online status,
  47. returns current IP address, and (optionally) keeps history on
  48. IP's issued.
  49. Original Author: Dave Nosker - AfterWave Technologies ([email protected])
  50. }
  51. interface
  52. {$i IdCompilerDefines.inc}
  53. uses
  54. Classes,
  55. IdGlobal,
  56. IdComponent, IdThread;
  57. const
  58. IP_WATCH_HIST_MAX = 25;
  59. IP_WATCH_HIST_FILENAME = 'iphist.dat'; {Do not Localize}
  60. IP_WATCH_INTERVAL = 1000;
  61. type
  62. TIdIPWatchThread = class(TIdThread)
  63. protected
  64. FInterval: Integer;
  65. FTimerEvent: TNotifyEvent;
  66. //
  67. procedure Run; override;
  68. procedure TimerEvent;
  69. end;
  70. TIdIPWatch = class(TIdComponent)
  71. protected
  72. FActive: Boolean;
  73. FCurrentIP: string;
  74. FHistoryEnabled: Boolean;
  75. FHistoryFilename: string;
  76. FIPHistoryList: TStringList;
  77. FIsOnline: Boolean;
  78. FLocalIPHuntBusy: Boolean;
  79. FMaxHistoryEntries: Integer;
  80. FOnLineCount: Integer;
  81. FOnStatusChanged: TNotifyEvent;
  82. FPreviousIP: string;
  83. FThread: TIdIPWatchThread;
  84. FWatchInterval: UInt32;
  85. //
  86. procedure AddToIPHistoryList(Value: string);
  87. procedure CheckStatus(Sender: TObject);
  88. procedure Loaded; override;
  89. procedure SetActive(Value: Boolean);
  90. procedure SetMaxHistoryEntries(Value: Integer);
  91. procedure SetWatchInterval(Value: UInt32);
  92. public
  93. constructor Create(AOwner: TComponent); override;
  94. destructor Destroy; override;
  95. function ForceCheck: Boolean;
  96. procedure LoadHistory;
  97. function LocalIP: string;
  98. procedure SaveHistory;
  99. //
  100. property CurrentIP: string read FCurrentIP;
  101. property IPHistoryList: TStringList read FIPHistoryList;
  102. property IsOnline: Boolean read FIsOnline;
  103. property PreviousIP: string read FPreviousIP;
  104. published
  105. property Active: Boolean read FActive write SetActive;
  106. property HistoryEnabled: Boolean read FHistoryEnabled write FHistoryEnabled default True;
  107. property HistoryFilename: string read FHistoryFilename write FHistoryFilename;
  108. property MaxHistoryEntries: Integer read FMaxHistoryEntries write SetMaxHistoryEntries
  109. default IP_WATCH_HIST_MAX;
  110. property OnStatusChanged: TNotifyEvent read FOnStatusChanged write FOnStatusChanged;
  111. property WatchInterval: UInt32 read FWatchInterval write SetWatchInterval
  112. default IP_WATCH_INTERVAL;
  113. end;
  114. implementation
  115. uses
  116. {$IFDEF USE_VCL_POSIX}
  117. Posix.SysSelect,
  118. Posix.SysTime,
  119. {$ENDIF}
  120. IdStack, SysUtils;
  121. { TIdIPWatch }
  122. constructor TIdIPWatch.Create(AOwner: TComponent);
  123. begin
  124. inherited Create(AOwner);
  125. FIPHistoryList := TStringList.Create;
  126. FIsOnLine := False;
  127. FOnLineCount := 0;
  128. FWatchInterval := IP_WATCH_INTERVAL;
  129. FActive := False;
  130. FPreviousIP := ''; {Do not Localize}
  131. FLocalIPHuntBusy := False;
  132. FHistoryEnabled:= True;
  133. FHistoryFilename:= IP_WATCH_HIST_FILENAME;
  134. FMaxHistoryEntries:= IP_WATCH_HIST_MAX;
  135. end;
  136. destructor TIdIPWatch.Destroy;
  137. begin
  138. if FIsOnLine then begin
  139. AddToIPHistoryList(FCurrentIP);
  140. end;
  141. Active := False;
  142. SaveHistory;
  143. FIPHistoryList.Free;
  144. inherited;
  145. end;
  146. procedure TIdIPWatch.AddToIPHistoryList(Value: string);
  147. begin
  148. if (Value = '') or (Value = '127.0.0.1') or (Value = '::1') then {Do not Localize}
  149. begin
  150. Exit;
  151. end;
  152. // Make sure the last entry does not allready contain the new one...
  153. if FIPHistoryList.Count > 0 then
  154. begin
  155. if FIPHistoryList[FIPHistoryList.Count-1] = Value then
  156. begin
  157. Exit;
  158. end;
  159. end;
  160. FIPHistoryList.Add(Value);
  161. if FIPHistoryList.Count > MaxHistoryEntries then
  162. begin
  163. FIPHistoryList.Delete(0);
  164. end;
  165. end;
  166. procedure TIdIPWatch.CheckStatus(Sender: TObject);
  167. var
  168. WasOnLine: Boolean;
  169. OldIP: string;
  170. begin
  171. try
  172. if FLocalIPHuntBusy then
  173. begin
  174. Exit;
  175. end;
  176. WasOnLine := FIsOnline;
  177. OldIP := FCurrentIP;
  178. FCurrentIP := LocalIP;
  179. FIsOnline := (FCurrentIP <> '127.0.0.1') and (FCurrentIP <> '::1') and (FCurrentIP <> ''); {Do not Localize}
  180. if (WasOnline) and (not FIsOnline) then
  181. begin
  182. if (OldIP <> '127.0.0.1') and (OldIP <> '::1') and (OldIP <> '') then {Do not Localize}
  183. begin
  184. FPreviousIP := OldIP;
  185. end;
  186. AddToIPHistoryList(FPreviousIP);
  187. end;
  188. if (not WasOnline) and (FIsOnline) then
  189. begin
  190. if FOnlineCount = 0 then
  191. begin
  192. FOnlineCount := 1;
  193. end;
  194. if FOnlineCount = 1 then
  195. begin
  196. if FPreviousIP = FCurrentIP then
  197. begin
  198. // Del last history item...
  199. if FIPHistoryList.Count > 0 then
  200. begin
  201. FIPHistoryList.Delete(FIPHistoryList.Count-1);
  202. end;
  203. // Change the Previous IP# to the remaining last item on the list
  204. // OR to blank if none on list.
  205. if FIPHistoryList.Count > 0 then
  206. begin
  207. FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
  208. end
  209. else
  210. begin
  211. FPreviousIP := ''; {Do not Localize}
  212. end;
  213. end;
  214. end;
  215. FOnlineCount := 2;
  216. end;
  217. if ((WasOnline) and (not FIsOnline)) or ((not WasOnline) and (FIsOnline)) then
  218. begin
  219. if (not IsDesignTime) and Assigned(FOnStatusChanged) then
  220. begin
  221. FOnStatusChanged(Self);
  222. end;
  223. end;
  224. except
  225. end;
  226. end;
  227. function TIdIPWatch.ForceCheck: Boolean;
  228. begin
  229. // Forces a check and doesn't wait for the timer to fire. {Do not Localize}
  230. // It will return true if online.
  231. CheckStatus(nil);
  232. Result := FIsOnline;
  233. end;
  234. procedure TIdIPWatch.Loaded;
  235. var
  236. b: Boolean;
  237. begin
  238. inherited Loaded;
  239. b := FActive;
  240. FActive := False;
  241. Active := b;
  242. end;
  243. procedure TIdIPWatch.LoadHistory;
  244. begin
  245. if not IsDesignTime then begin
  246. FIPHistoryList.Clear;
  247. if FileExists(FHistoryFilename) and FHistoryEnabled then
  248. begin
  249. FIPHistoryList.LoadFromFile(FHistoryFileName);
  250. if FIPHistoryList.Count > 0 then
  251. begin
  252. FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
  253. end;
  254. end;
  255. end;
  256. end;
  257. function TIdIPWatch.LocalIP: string;
  258. begin
  259. FLocalIpHuntBusy := True;
  260. try
  261. // TODO: use GStack.GetLocalAddressList() instead, as
  262. // GStack.LocalAddress only supports IPv4 addresses
  263. // at this time...
  264. Result := GStack.LocalAddress;
  265. finally
  266. FLocalIPHuntBusy := False;
  267. end;
  268. end;
  269. procedure TIdIPWatch.SaveHistory;
  270. begin
  271. if (not IsDesignTime) and FHistoryEnabled then begin
  272. FIPHistoryList.SaveToFile(FHistoryFilename);
  273. end;
  274. end;
  275. procedure TIdIPWatch.SetActive(Value: Boolean);
  276. begin
  277. if IsDesignTime or IsLoading then begin
  278. FActive := Value;
  279. end
  280. else if Value <> FActive then begin
  281. if Value then begin
  282. FThread := TIdIPWatchThread.Create(True);
  283. FThread.FTimerEvent := CheckStatus;
  284. FThread.FInterval := FWatchInterval;
  285. FThread.Start;
  286. end
  287. else if FThread <> nil then begin
  288. FThread.TerminateAndWaitFor;
  289. FreeAndNil(FThread);
  290. end;
  291. FActive := Value;
  292. end;
  293. end;
  294. procedure TIdIPWatch.SetMaxHistoryEntries(Value: Integer);
  295. begin
  296. FMaxHistoryEntries:= Value;
  297. while FIPHistoryList.Count > MaxHistoryEntries do // delete the oldest...
  298. FIPHistoryList.Delete(0);
  299. end;
  300. procedure TIdIPWatch.SetWatchInterval(Value: UInt32);
  301. begin
  302. if Value <> FWatchInterval then begin
  303. FWatchInterval := Value;
  304. end;
  305. // might be necessary even if its the same, for example
  306. // when loading (not 100% sure though)
  307. if Assigned(FThread) then begin
  308. FThread.FInterval := FWatchInterval;
  309. end;
  310. end;
  311. { TIdIPWatchThread }
  312. procedure TIdIPWatchThread.Run;
  313. var
  314. LInterval: Integer;
  315. begin
  316. LInterval := FInterval;
  317. while LInterval > 0 do begin
  318. if LInterval > 500 then begin
  319. IndySleep(500);
  320. LInterval := LInterval - 500;
  321. end else begin
  322. IndySleep(LInterval);
  323. LInterval := 0;
  324. end;
  325. if Terminated then begin
  326. Exit;
  327. end;
  328. Synchronize(TimerEvent);
  329. end;
  330. end;
  331. procedure TIdIPWatchThread.TimerEvent;
  332. begin
  333. if Assigned(FTimerEvent) then begin
  334. FTimerEvent(Self);
  335. end;
  336. end;
  337. end.