unit arpmethod;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, tlntsend;

type

  { TFormARPmethod }

  TFormARPmethod = class(TForm)
    ARPStatusMemo: TMemo;
    AssignCommand: TEdit;
    BasicParametersMemo: TListBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    BasicParametersGroupBox: TGroupBox;
    SaveBasicParametersButton: TButton;
    RefreshBasicParametersButton: TButton;
    TelnetFirstCommand: TEdit;
    TelnetOpenCommand: TEdit;
    FixXPortButton: TButton;
    FixXPortGroupBox: TGroupBox;
    IPEdit: TEdit;
    ChooseIPGroupBox: TGroupBox;
    InstructionsMemo: TMemo;
    InstructionsLabel: TLabel;
    FreeIPsListBox: TListBox;
    SelectedMACEdit: TLabeledEdit;
    SelectedIPEdit: TLabeledEdit;
    StatusLabel: TLabel;
    IPsInUseGroupBox: TGroupBox;
    FindIPsButton: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FixXPortButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FindIPsButtonClick(Sender: TObject);
    procedure FreeIPsListBoxClick(Sender: TObject);
    procedure IPEditChange(Sender: TObject);
    procedure RefreshBasicParametersButtonClick(Sender: TObject);
    procedure SelectedIPEditChange(Sender: TObject);
    procedure SelectedMACEditChange(Sender: TObject);
  private
  public

  end;


procedure UpdateCommands();
function FormatMACAddress(const MAC: string): string;

var
  FormARPmethod: TFormARPmethod;

implementation
uses
  Unit1,Process,StrUtils;

{ TFormARPmethod }

procedure TFormARPmethod.FindIPsButtonClick(Sender: TObject);
var
  Output : ansistring;
  Line : ansistring;
  ActiveRow: Integer = 0;
begin
  //Todo: See if Nmap command is available

   ARPStatusMemo.Clear;
   ARPStatusMemo.Lines.Add('Running nmap');
   Application.ProcessMessages;
   //if RunCommand('nmap',['-sn','192.168.1.0/24'],s) then begin
   if RunCommand('/bin/sh', ['-c', 'nmap -v -sn -n 192.168.1.0/24 -oG - | awk ''/Status: Down/{print $2}'''], Output) then begin

     begin
         for Line in Output.Split(LineEnding) do
         begin
           // Process each line
             if (not (AnsiEndsStr('.0',Line) or AnsiEndsStr('.255',Line))) then begin   {Ignore .0 and .255}
               FreeIPsListBox.Items.Add(Line);
               Inc(ActiveRow);
             end;
         end;
       end;

   end else
     ARPStatusMemo.Lines.Add('The nmap command cannot be accessed. Install it, or check the PATH.');

end;

procedure TFormARPmethod.FreeIPsListBoxClick(Sender: TObject);
begin
  IPEdit.Text:=FreeIPsListBox.Items[FreeIPsListBox.ItemIndex];
  UpdateCommands();
end;

procedure TFormARPmethod.IPEditChange(Sender: TObject);
begin
  UpdateCommands();
end;

procedure TFormARPmethod.RefreshBasicParametersButtonClick(Sender: TObject);
var
  AProcess: TProcess;
begin
  tsend:= TTelnetSend.Create;
  tsend.TargetHost:=SelectedIPEdit.Text;
  tsend.TargetPort:='9999';
  //CR is sent after each TelnetExpect.
  tsend.Login;
  WriteLnDebug('Sending XPort defaults to: '+tsend.TargetHost+' '+tsend.TargetPort);

{ // *** some problems compiling, try later
  if (not Unit1.TelnetExpect('Press Enter for Setup Mode', '')) then begin
    WriteLnDebug('Failed to: telnet '+tsend.TargetHost+' '+tsend.TargetPort);
    tsend.Destroy;
  end
  else begin
  Unit1.TelnetExpect('Your choice ?', '8');
  BasicParametersMemo.Items.Add(tsend.RecvString);
  Unit1.TelnetWaitFor('Connection closed by foreign host.'); // Added mainly for timeout, seems to properly save using the new XPort circa 20230723
  WriteLnDebug('Finished Sending XPort defaults using: telnet '+tsend.TargetHost+' '+tsend.TargetPort);
  tsend.Logout;
  tsend.Destroy;

  //Reset unit command resets unit for three seconds.
  WriteLnDebug('Resetting XPort ...');
  Application.ProcessMessages;
  //Wait about ten seconds for XPort to reset before moving on.
  //for i:=0 to 200 do
  //  begin
  //    sleep(50);
  //    FinalResetForXPortProgressBar.Position:=i;
  //    Application.ProcessMessages;
  //  end;
  // WriteLnDebug('XPort should have been reset, and ready to use now. Press FIND now');
  end;
}

end;

procedure TFormARPmethod.SelectedIPEditChange(Sender: TObject);
begin
  UpdateCommands();
end;

procedure TFormARPmethod.SelectedMACEditChange(Sender: TObject);
begin
  UpdateCommands();
end;

procedure TFormARPmethod.FormShow(Sender: TObject);
begin
    SelectedMACEdit.Text:=SelectedHardwareID;
    SelectedIPEdit.Text:=SelectedIP;
    UpdateCommands();
end;

procedure TFormARPmethod.FormCreate(Sender: TObject);
begin
   ARPStatusMemo.Clear;
   ARPStatusMemo.Font.Name:=FixedFont;
end;

procedure TFormARPmethod.FixXPortButtonClick(Sender: TObject);
begin
end;

procedure TFormARPmethod.Button1Click(Sender: TObject);
var
  AProcess: TProcess;
  I: Integer;
  CommandLine: string;
begin

  AProcess := TProcess.Create(nil);
  try
    AProcess.Executable := 'pkexec';
    AProcess.Parameters.Add('/usr/bin/arp');
    AProcess.Parameters.Add('-s');
    AProcess.Parameters.Add(FormARPmethod.IPEdit.Text);
    AProcess.Parameters.Add(FormatMACAddress(FormARPmethod.SelectedMACEdit.Text));

    CommandLine := AProcess.Executable;
     for I := 0 to AProcess.Parameters.Count - 1 do
       CommandLine := CommandLine + ' "' + AProcess.Parameters[I] + '"';

     // Write to status memo
     ARPStatusMemo.Lines.Add(Format('[%s] Executing: %s', [DateTimeToStr(Now), CommandLine]));



    AProcess.Options := [poWaitOnExit];
    AProcess.Execute;


    // Log the exit status
    ARPStatusMemo.Lines.Add(Format('[%s] Exit code: %d %s', [DateTimeToStr(Now), AProcess.ExitStatus,ifthen(AProcess.ExitStatus=0,'(successful)','(failed)')]));

  finally
    AProcess.Free;
  end;

end;

procedure TFormARPmethod.Button2Click(Sender: TObject);
var
  AProcess: TProcess;
begin
  //run 1st telnet command
    AProcess := TProcess.Create(nil);
    try
      //AProcess.Executable := 'pkexec';
      //AProcess.Parameters.Add('/usr/bin/telnet');
      AProcess.Executable :='/usr/bin/telnet';
      AProcess.Parameters.Add(FormARPmethod.IPEdit.Text);
      AProcess.Parameters.Add('1');

      AProcess.Options := [poWaitOnExit];
      AProcess.Execute;

      if AProcess.ExitStatus = 0 then
        ShowMessage('Command executed successfully!')
      else
        ShowMessage('Command failed.');
    finally
      AProcess.Free;
    end;

end;

procedure TFormARPmethod.Button3Click(Sender: TObject);
begin
  //run telnet open command
end;

procedure UpdateCommands();
begin
  FormARPmethod.AssignCommand.Text:='/usr/bin/arp -s '+
    FormARPmethod.IPEdit.Text + ' ' +
    FormatMACAddress(FormARPmethod.SelectedMACEdit.Text);

  FormARPmethod.TelnetFirstCommand.Text:='telnet '+
    FormARPmethod.IPEdit.Text + ' 1';

  FormARPmethod.TelnetOpenCommand.Text:='telnet '+
    FormARPmethod.IPEdit.Text + ' 9999';

end;

function FormatMACAddress(const MAC: string): string;
var
  i: integer;
  SepString:string;
begin
  Result := '';
  {$IFDEF LINUX}
    SepString := ':';
  {$ENDIF}
  {$IFDEF WINDOWS}
    SepString := '-';
  {$ENDIF}
  for i := 1 to Length(MAC) do
  begin
    if (i mod 2 = 0) and (i < Length(MAC)) then
      Result := Result + MAC[i] + SepString
    else
      Result := Result + MAC[i];
  end;
end;


initialization
  {$I arpmethod.lrs}

end.

