restemplate/indy/Protocols/IdIPWatch.pas

389 lines
9.7 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.5 10/26/2004 11:08:04 PM JPMugaas
Updated refs.
Rev 1.4 2004.02.03 5:43:54 PM czhower
Name changes
Rev 1.3 2/1/2004 3:33:46 AM JPMugaas
Reenabled. SHould work in DotNET.
Rev 1.2 1/21/2004 3:11:12 PM JPMugaas
InitComponent
Rev 1.1 2003.10.12 4:03:58 PM czhower
compile todos
Rev 1.0 11/13/2002 07:55:32 AM JPMugaas
2000-Dec-22 Kudzu
-Changed from a TTimer to a sleeping thread to eliminate the reference to ExtCtrls. This was the
only unit in all of Indy that used this unit and caused the pkg to rely on extra pkgs.
-Changed Enabled to Active to be more consistent
-Active now also defaults to false to be more consistent
2000-MAY-10 Hadi Hariri
-Added new feature to Force Check of status
2000-Apr-23 Hadi Hariri
-Converted to Indy
2000-Mar-01 Johannes Berg <johannes@sipsolutions.com>
- new property HistoryFilename
- new property MaxHistoryEntries
- new property HistoryEnabled
2000-Jan-13 MTL
-Moved to new Palette Scheme (Winshoes Misc)
}
unit IdIPWatch;
{
Simple component determines Online status,
returns current IP address, and (optionally) keeps history on
IP's issued.
Original Author: Dave Nosker - AfterWave Technologies (allbyte@jetlink.net)
}
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdGlobal,
IdComponent, IdThread;
const
IP_WATCH_HIST_MAX = 25;
IP_WATCH_HIST_FILENAME = 'iphist.dat'; {Do not Localize}
IP_WATCH_INTERVAL = 1000;
type
TIdIPWatchThread = class(TIdThread)
protected
FInterval: Integer;
FTimerEvent: TNotifyEvent;
//
procedure Run; override;
procedure TimerEvent;
end;
TIdIPWatch = class(TIdComponent)
protected
FActive: Boolean;
FCurrentIP: string;
FHistoryEnabled: Boolean;
FHistoryFilename: string;
FIPHistoryList: TStringList;
FIsOnline: Boolean;
FLocalIPHuntBusy: Boolean;
FMaxHistoryEntries: Integer;
FOnLineCount: Integer;
FOnStatusChanged: TNotifyEvent;
FPreviousIP: string;
FThread: TIdIPWatchThread;
FWatchInterval: UInt32;
//
procedure AddToIPHistoryList(Value: string);
procedure CheckStatus(Sender: TObject);
procedure SetActive(Value: Boolean);
procedure SetMaxHistoryEntries(Value: Integer);
procedure SetWatchInterval(Value: UInt32);
procedure InitComponent; override;
public
{$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
constructor Create(AOwner: TComponent); reintroduce; overload;
{$ENDIF}
destructor Destroy; override;
function ForceCheck: Boolean;
procedure LoadHistory;
function LocalIP: string;
procedure SaveHistory;
//
property CurrentIP: string read FCurrentIP;
property IPHistoryList: TStringList read FIPHistoryList;
property IsOnline: Boolean read FIsOnline;
property PreviousIP: string read FPreviousIP;
published
property Active: Boolean read FActive write SetActive;
property HistoryEnabled: Boolean read FHistoryEnabled write FHistoryEnabled default True;
property HistoryFilename: string read FHistoryFilename write FHistoryFilename;
property MaxHistoryEntries: Integer read FMaxHistoryEntries write SetMaxHistoryEntries
default IP_WATCH_HIST_MAX;
property OnStatusChanged: TNotifyEvent read FOnStatusChanged write FOnStatusChanged;
property WatchInterval: UInt32 read FWatchInterval write SetWatchInterval
default IP_WATCH_INTERVAL;
end;
implementation
uses
{$IFDEF DOTNET}
{$IFDEF USE_INLINE}
System.Threading,
System.IO,
{$ENDIF}
{$ENDIF}
{$IFDEF USE_VCL_POSIX}
Posix.SysSelect,
Posix.SysTime,
{$ENDIF}
IdStack, SysUtils;
{ TIdIPWatch }
procedure TIdIPWatch.AddToIPHistoryList(Value: string);
begin
if (Value = '') or (Value = '127.0.0.1') or (Value = '::1') then {Do not Localize}
begin
Exit;
end;
// Make sure the last entry does not allready contain the new one...
if FIPHistoryList.Count > 0 then
begin
if FIPHistoryList[FIPHistoryList.Count-1] = Value then
begin
Exit;
end;
end;
FIPHistoryList.Add(Value);
if FIPHistoryList.Count > MaxHistoryEntries then
begin
FIPHistoryList.Delete(0);
end;
end;
procedure TIdIPWatch.CheckStatus(Sender: TObject);
var
WasOnLine: Boolean;
OldIP: string;
begin
try
if FLocalIPHuntBusy then
begin
Exit;
end;
WasOnLine := FIsOnline;
OldIP := FCurrentIP;
FCurrentIP := LocalIP;
FIsOnline := (FCurrentIP <> '127.0.0.1') and (FCurrentIP <> '::1') and (FCurrentIP <> ''); {Do not Localize}
if (WasOnline) and (not FIsOnline) then
begin
if (OldIP <> '127.0.0.1') and (OldIP <> '::1') and (OldIP <> '') then {Do not Localize}
begin
FPreviousIP := OldIP;
end;
AddToIPHistoryList(FPreviousIP);
end;
if (not WasOnline) and (FIsOnline) then
begin
if FOnlineCount = 0 then
begin
FOnlineCount := 1;
end;
if FOnlineCount = 1 then
begin
if FPreviousIP = FCurrentIP then
begin
// Del last history item...
if FIPHistoryList.Count > 0 then
begin
FIPHistoryList.Delete(FIPHistoryList.Count-1);
end;
// Change the Previous IP# to the remaining last item on the list
// OR to blank if none on list.
if FIPHistoryList.Count > 0 then
begin
FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
end
else
begin
FPreviousIP := ''; {Do not Localize}
end;
end;
end;
FOnlineCount := 2;
end;
if ((WasOnline) and (not FIsOnline)) or ((not WasOnline) and (FIsOnline)) then
begin
if (not IsDesignTime) and Assigned(FOnStatusChanged) then
begin
FOnStatusChanged(Self);
end;
end;
except
end;
end;
{$IFDEF WORKAROUND_INLINE_CONSTRUCTORS}
constructor TIdIPWatch.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
{$ENDIF}
procedure TIdIPWatch.InitComponent;
begin
inherited;
FIPHistoryList := TStringList.Create;
FIsOnLine := False;
FOnLineCount := 0;
FWatchInterval := IP_WATCH_INTERVAL;
FActive := False;
FPreviousIP := ''; {Do not Localize}
FLocalIPHuntBusy := False;
FHistoryEnabled:= True;
FHistoryFilename:= IP_WATCH_HIST_FILENAME;
FMaxHistoryEntries:= IP_WATCH_HIST_MAX;
end;
destructor TIdIPWatch.Destroy;
begin
if FIsOnLine then begin
AddToIPHistoryList(FCurrentIP);
end;
Active := False;
SaveHistory;
FIPHistoryList.Free;
inherited;
end;
function TIdIPWatch.ForceCheck: Boolean;
begin
// Forces a check and doesn't wait for the timer to fire. {Do not Localize}
// It will return true if online.
CheckStatus(nil);
Result := FIsOnline;
end;
procedure TIdIPWatch.LoadHistory;
begin
if not IsDesignTime then begin
FIPHistoryList.Clear;
if FileExists(FHistoryFilename) and FHistoryEnabled then
begin
FIPHistoryList.LoadFromFile(FHistoryFileName);
if FIPHistoryList.Count > 0 then
begin
FPreviousIP := FIPHistoryList[FIPHistoryList.Count-1];
end;
end;
end;
end;
function TIdIPWatch.LocalIP: string;
begin
FLocalIpHuntBusy := True;
try
// TODO: use GStack.GetLocalAddressList() instead, as
// GStack.LocalAddress only supports IPv4 addresses
// at this time...
Result := GStack.LocalAddress;
finally
FLocalIPHuntBusy := False;
end;
end;
procedure TIdIPWatch.SaveHistory;
begin
if (not IsDesignTime) and FHistoryEnabled then begin
FIPHistoryList.SaveToFile(FHistoryFilename);
end;
end;
procedure TIdIPWatch.SetActive(Value: Boolean);
begin
if Value <> FActive then begin
if not IsDesignTime then begin
if Value then begin
FThread := TIdIPWatchThread.Create(True);
FThread.FTimerEvent := CheckStatus;
FThread.FInterval := FWatchInterval;
FThread.Start;
end else begin
if FThread <> nil then begin
FThread.TerminateAndWaitFor;
FreeAndNil(FThread);
end;
end;
end;
FActive := Value;
end;
end;
procedure TIdIPWatch.SetMaxHistoryEntries(Value: Integer);
begin
FMaxHistoryEntries:= Value;
while FIPHistoryList.Count > MaxHistoryEntries do // delete the oldest...
FIPHistoryList.Delete(0);
end;
procedure TIdIPWatch.SetWatchInterval(Value: UInt32);
begin
if Value <> FWatchInterval then begin
FWatchInterval := Value;
end;
// might be necessary even if its the same, for example
// when loading (not 100% sure though)
if Assigned(FThread) then begin
FThread.FInterval := FWatchInterval;
end;
end;
{ TIdIPWatchThread }
procedure TIdIPWatchThread.Run;
var
LInterval: Integer;
begin
LInterval := FInterval;
while LInterval > 0 do begin
if LInterval > 500 then begin
IndySleep(500);
LInterval := LInterval - 500;
end else begin
IndySleep(LInterval);
LInterval := 0;
end;
if Terminated then begin
Exit;
end;
Synchronize(TimerEvent);
end;
end;
procedure TIdIPWatchThread.TimerEvent;
begin
if Assigned(FTimerEvent) then begin
FTimerEvent(Self);
end;
end;
end.