{*********************************************************

 Unit: BrowseForm

 Browse Window
 このファイルに関する質問はこちらへ→usj12262@hotmail.com

*********************************************************}
unit BrowseForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, ComCtrls, OfficeToolBar, Classes2, BlckSock,
  ScktComp, WinSock, StringResources;

const
  WM_SOCKET_DISCONNECTED = WM_USER + 1;
  MAX_RETRY = 5;

type
  TSlavaNapBrowseWindow = class(TForm)
    List: TListView;
    Status: TStatusBar;
    Cb_Showpath: TCheckBox;
    Edit_Reason: TComboBox;
    Btn_Kickban: TButton;
    MainMenu1: TMainMenu;
    Mnu_Close: TMenuItem;
    Mnu_Hotlist: TMenuItem;
    Mnu_Friend: TMenuItem;
    Mnu_Ignore: TMenuItem;
    Mnu_Message: TMenuItem;
    Mnu_Whois: TMenuItem;
    Mnu_Refresh: TMenuItem;
    Btn_Kill: TButton;
    ksoOfficeDock1: TksoOfficeDock;
    ksoOfficeToolBar1: TksoOfficeToolBar;
    Btn_Ipwhois: TButton;
    Edit_Whois_Host: TComboBox;
    ksoOfficeToolBar2: TksoOfficeToolBar;
    Edit_Whois_Result: TMemo;
    Edit_Bantime: TComboBox;
    Cb_Whois_Auto: TCheckBox;
    WhoisSocket: TClientSocket;
    Btn_Ipkickban: TButton;
    PopupMenu1: TPopupMenu;
    Mnu_Charset: TMenuItem;
    Mnu_Charset_Shiftjis: TMenuItem;
    Mnu_Charset_Hangeul: TMenuItem;
    Mnu_Charset_Chinesebig5: TMenuItem;
    Mnu_Charset_Easteurope: TMenuItem;
    Mnu_Charset_Russian: TMenuItem;
    Mnu_Charset_Gb2312: TMenuItem;
    procedure Mnu_CloseClick(Sender: TObject);
    procedure Mnu_HotlistClick(Sender: TObject);
    procedure Mnu_FriendClick(Sender: TObject);
    procedure Mnu_IgnoreClick(Sender: TObject);
    procedure Mnu_MessageClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Mnu_WhoisClick(Sender: TObject);
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Mnu_Draw(Sender: TObject; ACanvas: TCanvas; ARect: TRect;
      Selected: Boolean);
    procedure FormResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure listSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure listColumnClick(Sender: TObject; Column: TListColumn);
    procedure listCompare(Sender: TObject; Item1, Item2: TListItem;
      Data: Integer; var Compare: Integer);
    procedure Mnu_RefreshClick(Sender: TObject);
    procedure Cb_ShowpathClick(Sender: TObject);
    procedure Btn_KickbanClick(Sender: TObject);
    procedure Btn_KillClick(Sender: TObject);
    procedure Btn_IpwhoisClick(Sender: TObject);
    procedure WhoisSocketConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure WhoisSocketRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure WhoisSocketDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure Btn_IpkickbanClick(Sender: TObject);
    procedure Edit_ReasonSelect(Sender: TObject);
    procedure Mnu_CharsetClick(Sender: TObject);
  private
    { private 宣言 }
    Tries: Integer;
    NextStr: string;
    NextServer: string;
    WhoisInfo: string;
    procedure WMSocketDisConnected(var Msg: TMessage); Message
      WM_SOCKET_DISCONNECTED;
    procedure TryWhois;
    function FormatResult(Str: string): string;
  public
    { public 宣言 }
    User: string;
    Ip: string;
    Shared: Integer;
    Size: Int64;
    Show_Fullpath: Boolean;
  end;

  TReverseDNSThread = class(TThread)
  private
    Form: TSlavaNapBrowseWindow;
    constructor Create(CreateSuspended: Boolean);
  protected
    procedure Execute; override;
  end;

  TUserListReverseDNSThread = class(TThread)
  protected
    procedure Execute; override;
  public
    Ip: Cardinal;
    Item: TListItem;
    constructor Create(CreateSuspended: Boolean);
  end;

function GetHostByIP(IP: string): string;
var
  SlavaNapBrowseWindow: TSlavaNapBrowseWindow;
  ResolvingCount: Integer; // ホスト名解決中のTUserListReverseDNSThreadの数
implementation

uses Lang, STypes, Vars, MainForm, constants, SlavaMenu, Thread, Handler, Md5,
Memory_Manager;

{$R *.Dfm}

constructor TUserListReverseDNSThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  Priority := tpIdle;
end;

procedure TUserListReverseDNSThread.Execute;
var
  HostName: string;
begin
  FreeOnTerminate := True;
  if Self.Item = nil then Exit;
  if Self.Ip = 0 then Exit;
  while ResolvingCount >= Max_Resolving_Count do
    Sleep(10);
  Inc(ResolvingCount);
  HostName := GetHostByIP(Decode_Ip(Self.Ip));
  if Item.SubItems.Count > UL_REMOTEHOST then
    Item.SubItems[UL_REMOTEHOST] := HostName;
  Dec(ResolvingCount);
end;

constructor TReverseDNSThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  Priority := tpIdle;
end;

function GetHostByIP(IP: string): string;
var
  ulIP: U_Long;
  Phe: PHostEnt;
  // WSAStartError: Integer;
  WSAData: TWSAData;
begin
  // WSAStartError := WSAStartUp($0101, WSAData);
  WSAStartUp($0101, WSAData);
  Result := '';
  ulIP := Inet_Addr(PChar(IP));
  Phe := GetHostByAddr(@ulIP, 4, AF_INET);
  if Phe <> nil then
    Result := Phe^.H_Name
  else
    Result := IP;
  WSACleanUp;
end;

procedure TReverseDNSThread.Execute;
var
  HostName: string;
begin
  FreeOnTerminate := True;
  if Self.Form = nil then Exit;
  while Self.Form.Ip = '' do
    Sleep(10);
  HostName := GetHostByIP(Decode_Ip(Self.Form.Ip));
  Self.Form.Status.Panels[2].Text := HostName;
end;

procedure TSlavaNapBrowseWindow.FormCreate(Sender: TObject);
var
  R: TRect;
  Th: TReverseDNSThread;
begin
  SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0);
  Top := (R.Top + R.Bottom - Height) div 2;
  Left := (R.Right + R.Left - Width - 4) div 2;
  Caption := Format(RS_BrowseForm_Caption, [User]);
  List.Items.Clear;
  Th := TReverseDNSThread.Create(False);
  Th.Form := Self;
end;

procedure TSlavaNapBrowseWindow.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TSlavaNapBrowseWindow.FormDestroy(Sender: TObject);
var
  I: Integer;
begin
  if Cons_Browse <> nil then
    for I := Cons_Browse.Count - 1 downto 0 do
      if Cons_Browse.Items[I] = Self then
        Cons_Browse.Delete(I);
  for I := 0 to List.Items.Count - 1 do
    Dispose(PString(List.Items[I].Data));
end;

procedure TSlavaNapBrowseWindow.FormResize(Sender: TObject);
begin
  try
    List.Invalidate;
  except
  end;
  ksoOfficeToolBar2.Width := Self.Height - 8;
  ksoOfficeToolBar2.Height := Self.Height - 160;
end;

procedure TSlavaNapBrowseWindow.FormShow(Sender: TObject);
begin
  Mnu_Close.Caption := GetLangI(LNG_CMNU_CLOSE);
  Mnu_Refresh.Caption := GetLangI(LNG_LIST_MENU_REFRESH);
  Mnu_Hotlist.Caption := GetLangI(LNG_LIST_MENU_HOTLIST);
  Mnu_Friend.Caption := GetLangI(LNG_LIST_MENU_FRIEND);
  Mnu_Whois.Caption := GetLangI(LNG_LIST_MENU_WHOIS);
  Mnu_Ignore.Caption := GetLangI(LNG_LIST_MENU_IGNORE);
  Mnu_Message.Caption := GetLangI(LNG_LIST_MENU_IM);
  Mnu_Charset.Caption := GetLangI(LNG_BRMNU_CHARSET);
  Mnu_Charset_Shiftjis.Caption := GetLangI(LNG_BRMNU_CHARSET_SHIFTJIS);
  Mnu_Charset_Chinesebig5.Caption := GetLangI(LNG_BRMNU_CHARSET_CHINESEBIG5);
  Mnu_Charset_Gb2312.Caption := GetLangI(LNG_BRMNU_CHARSET_GB2312);
  Mnu_Charset_Hangeul.Caption := GetLangI(LNG_BRMNU_CHARSET_HANGEUL);
  Mnu_Charset_Easteurope.Caption := GetLangI(LNG_BRMNU_CHARSET_EASTEUROPE);
  Mnu_Charset_Russian.Caption := GetLangI(LNG_BRMNU_CHARSET_RUSSIAN);
  List.Color := slBackground;
  List.Font.Color := slText;
  ksoOfficeToolBar2.Rolled := True;
  SlavaNapWindow.SetBanItems(Edit_Bantime);
  Edit_Bantime.ItemIndex := Edit_Bantime.Items.Count - 1;
end;

procedure TSlavaNapBrowseWindow.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle and not WS_EX_TOOLWINDOW or WS_EX_APPWINDOW;
end;

procedure TSlavaNapBrowseWindow.Mnu_Draw(Sender: TObject; ACanvas: TCanvas;
  ARect: TRect; Selected: Boolean);
begin
  SlavaDrawMainMenu(Self, Sender, ACanvas, ARect, Selected);
end;

procedure TSlavaNapBrowseWindow.Mnu_CloseClick(Sender: TObject);
begin
  Close;
end;

prOcedure TSlavaNapBrowseWindow.Mnu_HotlistClick(Sender: TObject);
begin
  if Running then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_ADD_HOTLIST, 0, User, '');
end;

procedure TSlavaNapBrowseWindow.Mnu_FriendClick(Sender: TObject);
begin
  if Running then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_FRIENDS, 0, 'Add ' + User, '');
end;

procedure TSlavaNapBrowseWindow.Mnu_IgnoreClick(Sender: TObject);
begin
  if Running then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_IGNORE_USER, 0, User, '');
end;

procedure TSlavaNapBrowseWindow.Mnu_MessageClick(Sender: TObject);
begin
  if Running then
    SlavaNapWindow.CreateChatWindow(User);
end;

procedure TSlavaNapBrowseWindow.Mnu_WhoisClick(Sender: TObject);
begin
  if Running then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_WHOIS, 0, User, '');
end;

procedure TSlavaNapBrowseWindow.Mnu_RefreshClick(Sender: TObject);
begin
  List.Clear;
  Shared := 0;
  Size := 0;
  Cmd_List.AddDoubleCmd(MSG_CLIENT_BROWSE, 0, User, '');
end;

procedure TSlavaNapBrowseWindow.listSelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
var
  Selitem: TListItem;
  Selsize: Int64;
  Str: string;
  function StripComma(SizeStr: string): string;
  var
    I: Integer;
  begin
    I := 0;
    while I <= Length(SizeStr) do
      if SizeStr[I] = ',' then
        Delete(SizeStr, I, 1)
      else
        Inc(I);
    Result := SizeStr;
  end;
begin
  Selsize := 0;
  Selitem := List.Selected;
  while selitem <> nil do
  begin
    Inc(Selsize, StrToInt64Def(StripComma(Selitem.SubItems[0]), 0));
    Selitem := List.GetNextItem(Selitem, sdAll, [IsSelected]);
  end;
  Str := Format(RS_BrowseForm_ListSelected, [List.SelCount, Selsize div
    MegaByte]);
  Status.Panels[1].Text := Str;
  Status.Panels[1].Width := Canvas.TextWidth(Str) + 20;
end;

procedure TSlavaNapBrowseWindow.listColumnClick(Sender: TObject;
  Column: TListColumn);
var
  Tag: Integer;
begin
  Tag := (Sender as TListView).Tag;
  if Tag = Column.Index then
    (Sender as TListView).Tag := -Tag - 1
  else
    (Sender as TListView).Tag := Column.Index;
  (Sender as TListView).AlphaSort;
end;

procedure TSlavaNapBrowseWindow.ListCompare(Sender: TObject; Item1,
  Item2: TListItem; Data: Integer; var Compare: Integer);
var
  Tag: Integer;
begin
  Tag := (Sender as TListView).Tag;
  if Tag > 0 then
  begin
    if Item1.SubItems.Count < Tag then
      Tag := 0;
    if Item2.SubItems.Count < Tag then
      Tag := 0;
    if Tag > 0 then
      Compare := SlavaNapWindow.DoCompare(Sender as TListView, Tag,
        Item1.SubItems[Tag - 1], Item2.SubItems[Tag - 1]);
  end;
  if Tag < 0 then
  begin
    Tag := -1 - Tag;
    if Item1.SubItems.Count < Tag then
      Tag := 0;
    if Item2.SubItems.Count < Tag then
      Tag := 0;
    if Tag > 0 then
      Compare := SlavaNapWindow.DoCompare(Sender as TListView, Tag,
        Item2.SubItems[Tag - 1], Item1.SubItems[Tag - 1])
    else
      Compare := SlavaNapWindow.DoCompare(Sender as TListView, 0, Item2.Caption,
        Item1.Caption);
    Exit;
  end;
  if Tag = 0 then
    Compare := SlavaNapWindow.DoCompare(Sender as TListView, 0, Item1.Caption,
      Item2.Caption);
end;

procedure TSlavaNapBrowseWindow.Cb_ShowpathClick(Sender: TObject);
var
  I: Integer;
begin
  Show_Fullpath := Cb_Showpath.Checked;
  for I := 0 to List.Items.Count - 1 do
    if Show_Fullpath then
      List.Items[I].Caption := PString(List.Items[I].Data)^
    else
      List.Items[I].Caption := ExtractFileName(PString(List.Items[I].Data)^);
end;

procedure TSlavaNapBrowseWindow.Btn_KickbanClick(Sender: TObject);
var
  T: Integer;
begin
  T := SlavaNapWindow.GetBanID(Edit_Bantime);
  Cmd_List.AddDoubleCmd(MSG_CLIENT_BANEX, 0, User + ' ' + IntToStr(T) + ' ' +
    Edit_Reason.Text, '');
  Cmd_List.AddDoubleCmd(MSG_CLIENT_KILL, 0, User + ' ' + Edit_Reason.Text, '');
end;

procedure TSlavaNapBrowseWindow.Btn_KillClick(Sender: TObject);
begin
  Cmd_List.AddDoubleCmd(MSG_CLIENT_KILL, 0, User + ' ' + Edit_Reason.Text, '');
end;

procedure TSlavaNapBrowseWindow.Btn_IpkickbanClick(Sender: TObject);
var
  T: Integer;
begin
  T := SlavaNapWindow.GetBanID(Edit_Bantime);
  Cmd_List.AddDoubleCmd(MSG_CLIENT_BANEX, 0, Decode_Ip(Ip) + ' ' + IntToStr(T) +
    ' ' + Edit_Reason.Text, '');
  Cmd_List.AddDoubleCmd(MSG_CLIENT_KILL, 0, User + ' ' + Edit_Reason.Text, '');
end;

procedure TSlavaNapBrowseWindow.Edit_ReasonSelect(Sender: TObject);
begin
  if Edit_Reason.Text = RS_BrowseForm_Ban_TooOldXNap then
    Edit_Bantime.ItemIndex := 8 // 3日
  else if Edit_Reason.Text = RS_BrowseForm_Ban_Clone then
    Edit_Bantime.ItemIndex := 7 // 1日
  else if Edit_Reason.Text = RS_BrowseForm_Ban_BadSharing then
    Edit_Bantime.ItemIndex := 8 // 3日
  else if Edit_Reason.Text = RS_BrowseForm_Ban_FakeSharing then
    Edit_Bantime.ItemIndex := 10 // 2週間
  else if Edit_Reason.Text = RS_BrowseForm_Ban_FakeExt then
    Edit_Bantime.ItemIndex := 10 // 2週間
  else
    Edit_Bantime.ItemIndex := 15; // 無期限
  if Pos(RS_BrowseForm_Domain, Edit_Reason.Text) = 0 then
    Btn_Kickban.SetFocus;
end;

function JisToSJis1Char(C0, C1: Char): string;
var
  Offset: Integer;
begin
  Result := '';
  if (C0 < #$21) or (C0 > #$7E) then Exit;
  Offset := $7E;
  if Ord(C0) mod 2 = 1 then
    if C1 < #$60 then
      Offset := $1F
    else
      Offset := $20;
  Inc(C1, Offset);
  if C0 < #$5F then
    Offset := $70
  else
    Offset := $B0;
  C0 := Chr((Ord(C0) + 1) div 2 + Offset);
  Result := C0 + C1;
end;

function EucToSjis(Str: string): string;
var
  I: Integer;
begin
  Result := '';
  I := 1;
  while (I <= Length(Str)) do
  begin
    if (Str[I] >= #$A1) and (Str[I] <= #$FE) then
    begin // EUCコード文字
      Inc(Str[I], -$80);
      Inc(Str[I + 1], -$80);
      Result := Result + JisToSJis1Char(Str[I], Str[I + 1]);
      Inc(I);
    end
    else if (Str[I] = #$8E) and (Str[I + 1] >= #$A1) and (Str[I + 1] <= #$DF)
      then
    begin // 半角カナ
      Result := Result + Str[I + 1];
      Inc(I);
    end
    else
    begin
      Result := Result + Str[I];
    end;
    Inc(I);
  end;
end;

function JisToSJis(Str: string): string;
var
  I: Integer;
  B: Boolean;
begin
  B := False;
  Result := '';
  I := 1;
  while (I <= Length(Str)) do
  begin
    if (Str[I] = #$1B) and (Str[I + 1] = '$') and (Str[I + 2] = 'B') then
    begin
      B := True;
      Inc(I, 3);
      Continue;
    end;
    if (Str[I] = #$1B) and (Str[I + 1] = '(') then
      if (Str[I + 2] = 'B') or (Str[I + 2] = 'J') then
      begin
        B := False;
        Inc(I, 3);
        Continue;
      end;
    if B then // JISコード
    begin
      if Length(Str) > I then
        Result := Result + JisTOSjis1Char(Str[I], Str[I + 1]);
      Inc(I);
    end
    else
      Result := Result + Str[I];
    Inc(I);
  end;
end;

procedure TSlavaNapBrowseWindow.Btn_IpwhoisClick(Sender: TObject);
begin
  Edit_Whois_Result.Clear;
  if Cb_Whois_Auto.Checked then
    Edit_Whois_Host.Text := 'whois.arin.net';
  NextStr := Decode_Ip(Ip);
  WhoisInfo := '';
  Tries := 0;
  TryWhois;
end;

procedure TSlavaNapBrowseWindow.TryWhois;
begin
  Inc(Tries);
  if Tries > MAX_RETRY then
  begin
    Edit_Whois_Result.Lines.Add(WhoisInfo);
    Edit_Whois_Result.Lines.Add(RS_BrowseForm_WhoisLooped);
    Exit;
  end;
  NextServer := Edit_Whois_Host.Text;
  WhoisSocket.Host := Edit_Whois_Host.Text;
  WhoisSocket.Open;
end;

procedure TSlavaNapBrowseWindow.WhoisSocketConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Edit_Whois_Result.Lines.Add(Format(RS_BrowseForm_WhoisConnect,
    [Edit_Whois_Host.Text]));
  Edit_Whois_Result.Lines.Add(Format(RS_BrowseForm_WhoisSend, [NextStr +
    #13#10]));
  Socket.SendText(NextStr + #13#10);
end;

procedure TSlavaNapBrowseWindow.WhoisSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  WhoisInfo := WhoisInfo + Socket.ReceiveText;
end;

procedure TSlavaNapBrowseWindow.WhoisSocketDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Edit_Whois_Result.Lines.Add(RS_BrowseForm_WhoisDisConnect);
  PostMessage(Self.Handle, WM_SOCKET_DISCONNECTED, 0, 0);
end;

function TSlavaNapBrowseWindow.FormatResult(Str: string): string;
var
  I: Integer;
begin
  Result := Str;
  I := 0;
  while I <= Length(Result) do
  begin
    if Result[I] = #10 then
    begin
      Insert(#13, Result, I);
      Inc(I);
    end;
    Inc(I);
  end;
  if NextServer = 'whois.nic.ad.jp' then
    Result := JisToSJis(Result);
end;

procedure TSlavaNapBrowseWindow.WMSocketDisConnected;
var
  I: Integer;
  Str: string;
begin
  // 以下のリストの大部分はwp.cgiをもとにしてます
  if Pos('whois.v6nic.net', WhoisInfo) > 0 then
    NextServer := 'whois.v6nic.net'
  else if Pos('whois.nic.or.kr', WhoisInfo) > 0 then
    NextServer := 'whois.nic.or.kr'
  else if Pos('KRNIC', WhoisInfo) > 0 then
    NextServer := 'whois.nic.or.kr'
  else if Pos('JNIC', WhoisInfo) > 0 then
    NextServer := 'whois.nic.ad.jp'
  else if Pos('JPNIC', WhoisInfo) > 0 then
    NextServer := 'whois.nic.ad.jp'
  else if Pos('rwhois.beanfield', WhoisInfo) > 0 then
    NextServer := 'rwhois.beanfield.net'
  else if Pos('rwhois.cogentco', WhoisInfo) > 0 then
    NextServer := 'rwhois.cogentco.com'
  else if Pos('rwhois.cais', WhoisInfo) > 0 then
    NextServer := 'rwhois.cais.net'
  else if Pos('rwhois.elan', WhoisInfo) > 0 then
    NextServer := 'rwhois.elan.net'
  else if Pos('rwhois.oar', WhoisInfo) > 0 then
    NextServer := 'rwhois.oar.net'
      // Rwhois.eni.net is Currently broken
  // else if Pos('rwhois.eni', WhoisInfo) > 0 then
  //   NextServer := 'rwhois.eni.net'
  else if Pos('rwhois.concentric', WhoisInfo) > 0 then
    NextServer := 'rwhois.concentric.net'
  else if Pos('rwhois.internex', WhoisInfo) > 0 then
    NextServer := 'rwhois.internex.net'
  else if Pos('rwhois.digex', WhoisInfo) > 0 then
    NextServer := 'rwhois.digex.net'
  else if Pos('rwhois.dnai', WhoisInfo) > 0 then
    NextServer := 'rwhois.dnai.com'
  else if Pos('rwhois.verio', WhoisInfo) > 0 then
    NextServer := 'rwhois.verio.net'
  else if Pos('rwhois.exodus', WhoisInfo) > 0 then
    NextServer := 'rwhois.exodus.net'
  else if Pos('whois.telstra', WhoisInfo) > 0 then
    NextServer := 'whois.telstra.net'
  else if Pos('whois.nic.ad.jp', WhoisInfo) > 0 then
    NextServer := 'whois.nic.ad.jp'
  else if Pos('NETBLK-BRAZIL', WhoisInfo) > 0 then
    NextServer := 'whois.nic.br'
  else if Pos('RIPE-', WhoisInfo) > 0 then
    NextServer := 'whois.ripe.net'
  else if Pos('-RIPE', WhoisInfo) > 0 then
    NextServer := 'whois.ripe.net'
  else if Pos('NET-RIPE', WhoisInfo) > 0 then
    NextServer := 'whois.ripe.net'
  else if (Pos('NETBLK-', WhoisInfo) > 0) and
    (Pos('-RIPE', WhoisInfo) > 0) then
    NextServer := 'whois.ripe.net'
  else if Pos('NETBLK-RIPE', WhoisInfo) > 0 then
    NextServer := 'whois.ripe.net'
  else if Pos('AUNIC-AU', WhoisInfo) > 0 then
    NextServer := 'whois.aunic.net'
  else if Pos('APNIC-', WhoisInfo) > 0 then
    NextServer := 'whois.apnic.net'
  else if Pos('APNIC', WhoisInfo) > 0 then
    NextServer := 'whois.apnic.net'
  else if Pos('LACNIC', WhoisInfo) > 0 then
    NextServer := 'whois.lacnic.net';

  I := Pos('(NET-', WhoisInfo);
  if I > 0 then
  begin
    if Pos('NET-', NextStr) = 1 then
      NextStr := Decode_Ip(Ip)
    else
    begin
      Str := WhoisInfo;
      while I <> 0 do
      begin
        Delete(Str, 1, I);
        I := Pos('(NET-', Str);
      end;
      NextStr := Copy(Str, 1, Pos(')', Str) - 1);
    end;
    if NextServer = 'whois.lacnic.net' then
      NextServer := 'whois.arin.net';
  end;

  if (NextServer = 'whois.nic.ad.jp') then
    if Pos('/', NextStr) <> 0 then
      NextStr := Decode_Ip(Ip)
    else
    begin
      I := Pos('/', Copy(WhoisInfo, Length(WhoisInfo) - 10, 10));
      if I > 0 then
        NextStr := Trim(Copy(WhoisInfo, Length(WhoisInfo) - 10 + I - 16,
          Length(WhoisInfo) - 10 + I + 3));
    end;

  if NextServer <> Edit_Whois_Host.Text then
  begin
    WhoisInfo := '';
    Edit_Whois_Host.Text := NextServer;
    TryWhois;
  end
  else
    with Edit_Whois_Result do
    begin
      Lines.Add(FormatResult(WhoisInfo));
      if (NextStr <> Decode_Ip(Ip)) and (NextStr <> '') then
        TryWhois;
      if NextServer = 'whois.nic.or.kr' then
      begin
        Self.Caption := Self.Caption + ' ' + RS_BrowseForm_WhoisCountry + 'KR';
        Font.Charset := HANGEUL_CHARSET;
      end
      else
      begin
        for I := 0 to Lines.Count - 1 do
          if Pos('country', LowerCase(Lines[I])) = 1 then
          begin
            Self.Caption := Self.Caption + ' ' + RS_BrowseForm_WhoisCountry +
              Copy(Lines[I], Length(Lines[I]) - 1, 2);
            Break;
          end;
        Font.Charset := SHIFTJIS_CHARSET;
      end;
    end;
end;

procedure TSlavaNapBrowseWindow.Mnu_CharsetClick(Sender: TObject);
const
  MNU_CHARSET_SHIFTJIS = 0;
  MNU_CHARSET_CHINESEBIG5 = 1;
  MNU_CHARSET_GB2312 = 2;
  MNU_CHARSET_HANGEUL = 3;
  MNU_CHARSET_EASTEUROPE = 4;
  MNU_CHARSET_RUSSIAN = 5;
begin
  case Mnu_Charset.IndexOf(Sender as TMenuItem) of
    MNU_CHARSET_SHIFTJIS: List.Font.Charset := SHIFTJIS_CHARSET;
    MNU_CHARSET_CHINESEBIG5: List.Font.Charset := CHINESEBIG5_CHARSET;
    MNU_CHARSET_GB2312: List.Font.Charset := GB2312_CHARSET;
    MNU_CHARSET_HANGEUL: List.Font.Charset := HANGEUL_CHARSET;
    MNU_CHARSET_EASTEUROPE: List.Font.Charset := EASTEUROPE_CHARSET;
    MNU_CHARSET_RUSSIAN: List.Font.Charset := RUSSIAN_CHARSET;
  end;
end;

end.
