unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls, IniFiles, Snoop, Winsock;

type
  TMainForm = class(TForm)
    Panel1: TPanel;
    cbxAdapter: TComboBox;
    btnOpen: TButton;
    btnClose: TButton;
    btnClear: TButton;
    chkViewHexa: TCheckBox;
    ListView1: TListView;
    Splitter1: TSplitter;
    mmData: TMemo;
    SnoopUDP1: TSnoopUDP;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure cbxAdapterChange(Sender: TObject);
    procedure btnOpenClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure SnoopUDP1CaptureUDP(Sender: TObject; IPHeader: PIP_RHDR;
      UDPHeader: PUDP_RHDR; Data: PChar);
    procedure ListView1Change(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure chkViewHexaClick(Sender: TObject);
  private
	{ Private declarations }
	LastListItem: TListItem;
	procedure LoadControl;
	procedure SaveControl;
	procedure ViewHexa(Data: PChar; Length: Integer);
	function IsNormalChar(ch: Char): Boolean;
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.LoadControl;
var
	IniFile: TIniFile;
begin
	IniFile := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'SnoopeUDPTest.ini');
	Left := IniFile.ReadInteger('Coord', 'Left', 0);
	Top := IniFile.ReadInteger('Coord', 'Top', 0);
	Width := IniFile.ReadInteger('Coord', 'Width', 640);
	Height := IniFile.ReadInteger('Coord', 'Height', 480);
	ListView1.Height := IniFile.ReadInteger('Coord', 'ListViewHeight', 220);
	cbxAdapter.ItemIndex := IniFile.ReadInteger('Option', 'AdapterIndex', 0);
	chkViewHexa.Checked := IniFile.ReadBool('Option', 'ViewHexa', false);
	IniFile.Free;
end;

procedure TMainForm.SaveControl;
var
	IniFile: TIniFile;
begin
	IniFile := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'SnoopeUDPTest.ini');
	try
		IniFile.WriteInteger('Coord', 'Left', Left);
		IniFile.WriteInteger('Coord', 'Top', Top);
		IniFile.WriteInteger('Coord', 'Width', Width);
		IniFile.WriteInteger('Coord', 'Height', Height);
		IniFile.WriteInteger('Coord', 'ListViewHeight', ListView1.Height);
		IniFile.WriteInteger('Option', 'AdapterIndex', cbxAdapter.ItemIndex);
		IniFile.WriteBool('Option', 'ViewHexa', chkViewHexa.Checked);
	except
		IniFile.Free;
	end;
end;

procedure TMainForm.ViewHexa(Data: PChar; Length: Integer);
const
	LINE_WIDTH = 16;
var
	i: Integer;
	Ascii, Hexa: String;
begin
	mmData.Lines.Clear;
	while Length > 0 do
	begin
		Ascii := '';
		Hexa := ' ';
		for i := 0 to LINE_WIDTH - 1 do
		begin
			if (i <> 0) and (i mod 4 = 0) then
				Hexa := Hexa + '| ';
			Hexa := Hexa + Format('%2x ', [Ord(Data^)]);

			if IsNormalChar(Data^) then
				Ascii := Ascii + Data^
			else
				Ascii := Ascii + '.';
			dec(Length);
			inc(Data);
			if Length <= 0 then break;
		end;
		Ascii := Copy(Ascii + '               ', 1, LINE_WIDTH);
		mmData.Lines.Add(Ascii + ' [' + Hexa+ ']');
	end;
end;

function TMainForm.IsNormalChar(ch: Char): Boolean;
begin
	Result := true;
	if (Ord(ch) < 31) or (Ord(ch) >= 128) then Result := false;
end;



procedure TMainForm.FormCreate(Sender: TObject);
begin
	cbxAdapter.Items := SnoopUDP1.AdapterNames;
	LoadControl;
	SnoopUDP1.AdapterIndex := cbxAdapter.ItemIndex;
	LastListItem := nil;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
	SaveControl;
end;

procedure TMainForm.cbxAdapterChange(Sender: TObject);
begin
	SnoopUDP1.AdapterIndex := cbxAdapter.ItemIndex;
end;

procedure TMainForm.btnOpenClick(Sender: TObject);
begin
	SnoopUDP1.Open;
	btnOpen.Enabled := false;
	btnClose.Enabled := true;
	cbxAdapter.Enabled := false;
end;

procedure TMainForm.btnCloseClick(Sender: TObject);
begin
	SnoopUDP1.Close;
	btnOpen.Enabled := true;
	btnClose.Enabled := false;
	cbxAdapter.Enabled := true;
end;

procedure TMainForm.btnClearClick(Sender: TObject);
begin
	ListView1.Items.Clear;
	mmData.Lines.Clear;
end;

procedure TMainForm.SnoopUDP1CaptureUDP(Sender: TObject;
  IPHeader: PIP_RHDR; UDPHeader: PUDP_RHDR; Data: PChar);
var
	ListItem: TListItem;
	Length: WORD;
	i: Integer;
	s: String;
begin
	ListView1.OnChange := nil;
	ListItem := ListView1.Items.Add;
	// IP Header Information
	ListItem.Caption := IntToStr(IPHeader.VerLen);
	ListItem.SubItems.Add(IntToStr(IPHeader.Service));
	ListItem.SubItems.Add(IntToStr(htons(IPHeader.Length)));
	ListItem.SubItems.Add(IntToStr(ntohs(IPHeader.Ident)));
	ListItem.SubItems.Add(IntToHex(ntohs(IPHeader.FlagOff), 4));
	ListItem.SubItems.Add(IntToStr(ntohs(IPHeader.TimeLive)));
	ListItem.SubItems.Add(IntToHex(ntohs(IPHeader.Protocol), 4));
	ListItem.SubItems.Add(IntToStr(ntohs(IPHeader.Checksum)));
	ListItem.SubItems.Add(IP2Str(ntohl(IPHeader.Source)));
	ListItem.SubItems.Add(IP2Str(ntohl(IPHeader.Destination)));
	// UDP Header Information
	ListItem.SubItems.Add(IntToStr(ntohs(UDPHeader.Source)));
	ListItem.SubItems.Add(IntToStr(ntohs(UDPHeader.Destination)));
	ListItem.SubItems.Add(IntToStr(ntohs(UDPHeader.Length)));
	ListItem.SubItems.Add(IntToStr(ntohs(UDPHeader.Checksum)));

	Length := ntohs(IPHeader.Length) - sizeof(IP_RHDR) - sizeof(UDP_RHDR);

	s := '';
	for i := 0 to Length - 1 do
		s := s + Data[i];
	ListItem.SubItems.Add(s);
	ListView1.OnChange := ListView1Change;
	LastListItem := nil;
end;

procedure TMainForm.ListView1Change(Sender: TObject; Item: TListItem;
  Change: TItemChange);
var
	ListItem: TListItem;
	DataIndex: Integer;
begin
	ListItem := ListView1.Selected;
	if (ListItem <> nil) and (ListItem <> LastListItem) then
	begin
		DataIndex := ListView1.Columns.Count - 2;
		if not chkViewHexa.Checked then
			mmData.Lines.Text := ListItem.SubItems[DataIndex]
		else
		begin
			ViewHexa(@ListItem.SubItems[DataIndex][1], 
				Length(ListItem.SubItems[DataIndex]));
		end;
		LastListItem := ListItem;
	end else
	begin
		mmData.Lines.Clear;
	end;
end;


procedure TMainForm.chkViewHexaClick(Sender: TObject);
begin
	LastListItem := nil;
	ListView1Change(nil, nil, ctText);
end;

end.
