IdIPWatch.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. procedure InitComponent; override;
  93. public
  94. {$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
  95. constructor Create(AOwner: TComponent); reintroduce; overload;
  96. {$ENDIF}
  97. destructor Destroy; override;
  98. function ForceCheck: Boolean;
  99. procedure LoadHistory;
  100. function LocalIP: string;
  101. procedure SaveHistory;
  102. //
  103. property CurrentIP: string read FCurrentIP;
  104. property IPHistoryList: TStringList read FIPHistoryList;
  105. property IsOnline: Boolean read FIsOnline;
  106. property PreviousIP: string read FPreviousIP;
  107. published
  108. property Active: Boolean read FActive write SetActive;
  109. property HistoryEnabled: Boolean read FHistoryEnabled write FHistoryEnabled default True;
  110. property HistoryFilename: string read FHistoryFilename write FHistoryFilename;
  111. property MaxHistoryEntries: Integer read FMaxHistoryEntries write SetMaxHistoryEntries
  112. default IP_WATCH_HIST_MAX;
  113. property OnStatusChanged: TNotifyEvent read FOnStatusChanged write FOnStatusChanged;
  114. property WatchInterval: UInt32 read FWatchInterval write SetWatchInterval
  115. default IP_WATCH_INTERVAL;
  116. end;
  117. implementation
  118. uses
  119. {$IFDEF DOTNET}
  120. {$IFDEF USE_INLINE}
  121. System.Threading,
  122. System.IO,
  123. {$ENDIF}
  124. {$ENDIF}
  125. {$IFDEF USE_VCL_POSIX}
  126. Posix.SysSelect,
  127. Posix.SysTime,
  128. {$ENDIF}
  129. IdStack, SysUtils;
  130. { TIdIPWatch }
  131. procedure TIdIPWatch.AddToIPHistoryList(Value: string);
  132. begin
  133. if (Value = '') or (Value = '127.0.0.1') or (Value = '::1') then {Do not Localize}
  134. begin
  135. Exit;
  136. end;
  137. // Make sure the last entry does not allready contain the new one...
  138. if FIPHistoryList.Count > 0 then
  139. begin
  140. if FIPHistoryList[FIPHistoryList.Count-1] = Value then
  141. begin
  142. Exit;
  143. end;
  144. end;
  145. FIPHistoryList.Add(Value);
  146. if FIPHistoryList.Count > MaxHistoryEntries then
  147. begin
  148. FIPHistoryList.Delete(0);
  149. end;
  150. end;
  151. procedure TIdIPWatch.CheckStatus(Sender: TObject);
  152. var
  153. WasOnLine: Boolean;
  154. OldIP: string;
  155. begin
  156. try
  157. if FLocalIPHuntBusy then
  158. begin
  159. Exit;
  160. end;
  161. WasOnLine := FIsOnline;
  162. OldIP := FCurrentIP;
  163. FCurrentIP := LocalIP;
  164. FIsOnline := (FCurrentIP <> '127.0.0.1') and (FCurrentIP <> '::1') and (FCurrentIP <> ''); {Do not Localize}
  165. if (WasOnline) and (not FIsOnline) then
  166. begin
  167. if (OldIP <> '127.0.0.1') and (OldIP <> '::1') and (OldIP <> '') then {Do not Localize}
  168. begin
  169. FPreviousIP := OldIP;
  170. end;
  171. AddToIPHistoryList(FPreviousIP);
  172. end;
  173. if (not WasOnline) and (FIsOnline) then
  174. begin
  175. if FOnlineCount = 0 then
  176. begin
  177. FOnlineCount := 1;
  178. end;
  179. if FOnlineCount = 1 then
  180. begin
  181. if FPreviousIP = FCurrentIP then
  182. begin
  183. // Del last history item...
  184. if FIPHistoryList.Count > 0 then
  185. begin
  186. FIPHistoryList.Delete(FIPHistoryList.Count-1);
  187. end;
  188. // Change the Previous IP# to the remaining last item on the list
  189. // OR to blank if none on list.
  190. if FIPHistoryList.Count > 0 then
  191. begin
  192. FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
  193. end
  194. else
  195. begin
  196. FPreviousIP := ''; {Do not Localize}
  197. end;
  198. end;
  199. end;
  200. FOnlineCount := 2;
  201. end;
  202. if ((WasOnline) and (not FIsOnline)) or ((not WasOnline) and (FIsOnline)) then
  203. begin
  204. if (not IsDesignTime) and Assigned(FOnStatusChanged) then
  205. begin
  206. FOnStatusChanged(Self);
  207. end;
  208. end;
  209. except
  210. end;
  211. end;
  212. {$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
  213. constructor TIdIPWatch.Create(AOwner: TComponent);
  214. begin
  215. inherited Create(AOwner);
  216. end;
  217. {$ENDIF}
  218. procedure TIdIPWatch.InitComponent;
  219. begin
  220. inherited;
  221. FIPHistoryList := TStringList.Create;
  222. FIsOnLine := False;
  223. FOnLineCount := 0;
  224. FWatchInterval := IP_WATCH_INTERVAL;
  225. FActive := False;
  226. FPreviousIP := ''; {Do not Localize}
  227. FLocalIPHuntBusy := False;
  228. FHistoryEnabled:= True;
  229. FHistoryFilename:= IP_WATCH_HIST_FILENAME;
  230. FMaxHistoryEntries:= IP_WATCH_HIST_MAX;
  231. end;
  232. destructor TIdIPWatch.Destroy;
  233. begin
  234. if FIsOnLine then begin
  235. AddToIPHistoryList(FCurrentIP);
  236. end;
  237. Active := False;
  238. SaveHistory;
  239. FIPHistoryList.Free;
  240. inherited;
  241. end;
  242. function TIdIPWatch.ForceCheck: Boolean;
  243. begin
  244. // Forces a check and doesn't wait for the timer to fire. {Do not Localize}
  245. // It will return true if online.
  246. CheckStatus(nil);
  247. Result := FIsOnline;
  248. end;
  249. procedure TIdIPWatch.Loaded;
  250. var
  251. b: Boolean;
  252. begin
  253. inherited Loaded;
  254. b := FActive;
  255. FActive := False;
  256. Active := b;
  257. end;
  258. procedure TIdIPWatch.LoadHistory;
  259. begin
  260. if not IsDesignTime then begin
  261. FIPHistoryList.Clear;
  262. if FileExists(FHistoryFilename) and FHistoryEnabled then
  263. begin
  264. FIPHistoryList.LoadFromFile(FHistoryFileName);
  265. if FIPHistoryList.Count > 0 then
  266. begin
  267. FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
  268. end;
  269. end;
  270. end;
  271. end;
  272. function TIdIPWatch.LocalIP: string;
  273. begin
  274. FLocalIpHuntBusy := True;
  275. try
  276. // TODO: use GStack.GetLocalAddressList() instead, as
  277. // GStack.LocalAddress only supports IPv4 addresses
  278. // at this time...
  279. Result := GStack.LocalAddress;
  280. finally
  281. FLocalIPHuntBusy := False;
  282. end;
  283. end;
  284. procedure TIdIPWatch.SaveHistory;
  285. begin
  286. if (not IsDesignTime) and FHistoryEnabled then begin
  287. FIPHistoryList.SaveToFile(FHistoryFilename);
  288. end;
  289. end;
  290. procedure TIdIPWatch.SetActive(Value: Boolean);
  291. begin
  292. if IsDesignTime or IsLoading then begin
  293. FActive := Value;
  294. end
  295. else if Value <> FActive then begin
  296. if Value then begin
  297. FThread := TIdIPWatchThread.Create(True);
  298. FThread.FTimerEvent := CheckStatus;
  299. FThread.FInterval := FWatchInterval;
  300. FThread.Start;
  301. end
  302. else if FThread <> nil then begin
  303. FThread.TerminateAndWaitFor;
  304. FreeAndNil(FThread);
  305. end;
  306. FActive := Value;
  307. end;
  308. end;
  309. procedure TIdIPWatch.SetMaxHistoryEntries(Value: Integer);
  310. begin
  311. FMaxHistoryEntries:= Value;
  312. while FIPHistoryList.Count > MaxHistoryEntries do // delete the oldest...
  313. FIPHistoryList.Delete(0);
  314. end;
  315. procedure TIdIPWatch.SetWatchInterval(Value: UInt32);
  316. begin
  317. if Value <> FWatchInterval then begin
  318. FWatchInterval := Value;
  319. end;
  320. // might be necessary even if its the same, for example
  321. // when loading (not 100% sure though)
  322. if Assigned(FThread) then begin
  323. FThread.FInterval := FWatchInterval;
  324. end;
  325. end;
  326. { TIdIPWatchThread }
  327. procedure TIdIPWatchThread.Run;
  328. var
  329. LInterval: Integer;
  330. begin
  331. LInterval := FInterval;
  332. while LInterval > 0 do begin
  333. if LInterval > 500 then begin
  334. IndySleep(500);
  335. LInterval := LInterval - 500;
  336. end else begin
  337. IndySleep(LInterval);
  338. LInterval := 0;
  339. end;
  340. if Terminated then begin
  341. Exit;
  342. end;
  343. Synchronize(TimerEvent);
  344. end;
  345. end;
  346. procedure TIdIPWatchThread.TimerEvent;
  347. begin
  348. if Assigned(FTimerEvent) then begin
  349. FTimerEvent(Self);
  350. end;
  351. end;
  352. end.