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

 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;

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);
  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:=user+' - SlavaNap 共有ファイル情報(取得中...)';
 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(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:='Selected: '+IntToStr(list.SelCount)+' Files, '
                   +IntToStr(selsize div MegaByte)+' MB';
  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='Too old XNap'      then edit_bantime.ItemIndex:=8 //3日
  else if edit_reason.Text='clone'        then edit_bantime.ItemIndex:=7 //1日
  else if edit_reason.Text='bad sharing'  then edit_bantime.ItemIndex:=8 //3日
  else if edit_reason.Text='fake sharing' then edit_bantime.ItemIndex:=10//2週間
  else if edit_reason.Text='fake ext'     then edit_bantime.ItemIndex:=10//2週間
  else edit_bantime.ItemIndex:=15;//無期限
  if Pos('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('Whois Looped.');
    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('Connected to '+edit_whois_host.Text);
  edit_whois_result.Lines.Add('Sending Text: '+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('Disconnected.');
  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+' Country: 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+' Country: '+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.
