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

 SlavaNap source code.

 Copyright 2001,2002 by SlavaNap development team
 Released under GNU General Public License

 Latest version is available at
 http://www.slavanap.org

**********************************************************

 Unit: console

 Handler for console user

*********************************************************}
unit console;

interface

uses
 SysUtils, Classes, Classes2, graphics, zlibex, winsock, windows, constants,
 stypes, lang, blcksock, synsock, users, registered, localusers, servers,
 comctrls, slavastrings, mmsystem, class_cmdlist;

procedure ConsoleListRegistered;
procedure ConsoleListUsers;
procedure ConsoleListServers;
procedure ConsoleListChannels;
procedure ConsoleListBans;
procedure ConsoleListHotlist;
procedure ConsoleRefreshLists(switch_page: Boolean);
procedure ConsoleListLists(switch_page: Boolean);
procedure ConsoleReply(id: Integer; str: String);
procedure ConsoleAddServer(str: String);
procedure ConsoleServerProps(str: String);
procedure ConsoleUpdateServerProps(str: String);
procedure SendPrivateMyMessage(cmd: String);
procedure ConsoleSetCompress(cmd: String);
procedure ConsoleSetStartup(cmd: String);
procedure ConsoleSaveShared;

implementation

uses
 vars, mainform, handler, napigator, dagsta, thread, channels, channelform, bans,
 serverattr, chatform, whoisform, invitationform, share, blocks, browseform;

var
 hlist: TMyStringList;
 cmd: TNapCmd;
 im_log_file: TFileStream;

function CheckParams(n: Integer): Boolean;
begin
  SplitString(cmd.cmd,hlist);
  Result:=hlist.count>=n;
end;

procedure PlayChat(new_window: Boolean);
var
 i: Integer;
begin
 tmp_pos:=1312;
 if not SlavaNapWindow.cb_log_sound.Checked then exit;
 if new_window then i:=1
 else i:=2;
 PlaySound(PChar(ApplicationDir+'newmsg'+IntToStr(i)+'.wav'), 0, SND_FILENAME or SND_ASYNC);
 tmp_pos:=1313;
end;


procedure ConsoleSaveShared; // for debug only
var
 i,j: Integer;
 user: TLocalUser;
 sh: PShare;
 f: TFileStream;
 str: String;
begin
 tmp_pos:=1314;
 try
  f:=TFileStream.Create(ApplicationDir+'shared.dat',fmCreate);
  except
   exit;
 end;
 str:='# 形式: user "filename"';
 tmp_pos:=1315;
 for i:=db_local.count-1 downto 0 do
 try
   user:=db_local.Items[i];
   if user.logged then
    if user.shared<>nil then
     if user.shared.Count>0 then
      for j:=0 to user.shared.count-1 do
      begin
        sh:=user.shared.Items[j];
        str:=user.nick+' '+AddStr(user.shared.GetFileName(j))+#10;
        f.Write(str[1],Length(str));
      end;
  except
 end;
 f.Free;
 tmp_pos:=1316;
end;

procedure ConsoleListServers;
var
 item: TListItem;
 srv: TServer;
 i: Integer;
 str: String;
begin
 tmp_pos:=1317;
 if not running then exit;
 SlavaNapWindow.btn_servers_refresh.Enabled:=true;
 SlavaNapWindow.mnu_srv_refresh.Enabled:=true;
 with SlavaNapWindow.list_servers do
 begin
   Items.BeginUpdate;
   Items.Clear;
   tmp_pos:=1318;
   if db_servers<>nil then
   for i:=0 to db_servers.Count-1 do
   begin
     srv:=db_servers.Items[i];
     tmp_pos:=1319;
     item:=Items.Add;
     item.Caption:=srv.host;
     item.SubItems.Add(IntToStr(srv.port));
     str:='';
     tmp_pos:=1320;
     if srv.connected=conNotConnected then str:=GetLangI(LNG_SRV_DISCONNECTED)
     else if srv.connected=conConnected then
     begin
       if srv.logged=false then str:=GetLangI(LNG_SRV_LOGGING)
       else if srv.hub=nil then str:=GetLangI(LNG_SRV_LOGGED)
       else str:=GetLangI(LNG_SRV_HUB,GetServerName(srv.hub));
     end else if srv.connected=conConnecting then str:=GetLangI(LNG_SRV_CONNECTING)
     else str:=GetLangI(LNG_SRV_DISCONNECTED);
     tmp_pos:=1321;
     item.SubItems.Add(str);
     tmp_pos:=1322;
     if (srv.connected=conConnected) and (srv.hub=nil) then item.SubItems.Add(GetLangI(LNG_SLIST_LAGSEC,srv.CountLag))
     else item.SubItems.Add('');
     if srv.logged then item.SubItems.Add(IntToStr(srv.num_users)+'/'+IntToStr(srv.max_users))
     else item.SubItems.Add('');
     tmp_pos:=1323;
     if srv.authentication=authResolve then item.SubItems.Add(GetLangI(LNG_SRV_RESOLVE))
     else item.SubItems.Add(GetLangI(LNG_SRV_PASSWORD));
     if srv.relink=0 then item.SubItems.Add('')
     else item.SubItems.Add(GetLangI(LNG_SRV_RELINKTIME,srv.relink div 60000));
     tmp_pos:=1324;
     item.SubItems.Add(srv.comments);
     item.SubItems.Add(srv.alias);
     item.SubItems.Add(IntToStr(srv.redirects));
     tmp_pos:=1325;
   end;
   AlphaSort;
   tmp_pos:=1326;
   Items.EndUpdate;
 end;
 tmp_pos:=1327;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1328;
end;

procedure ConsoleListChannels;
var
 item: TListItem;
 ch: TChannel;
 i,j: Integer;
 str: String;
begin
 if not running then exit;
 tmp_pos:=1329;
 SlavaNapWindow.btn_ch_refresh.Enabled:=true;
 SlavaNapWindow.mnu_ch_refresh.Enabled:=true;
 with SlavaNapWindow.list_channels do
 begin
   tmp_pos:=1330;
   Items.BeginUpdate;
   Items.Clear;
   tmp_pos:=1331;
   if db_channels<>nil then
   for i:=0 to db_channels.count-1 do
   begin
     ch:=db_channels.Items[i];
     tmp_pos:=1332;
     item:=Items.Add;
     item.Caption:=ch.channel;
     item.SubItems.Add(IntToStr(ch.users.count));
     item.SubItems.Add(IntToStr(ch.limit));
     item.SubItems.Add(Level2Str(ch.level));
     str:='';
     tmp_pos:=1333;
     if chRegistered in ch.state then str:=GetLangI(LNG_CH_REGISTERED);
     if chModerated in ch.state then
     begin
       if str<>'' then str:=str+', ';
       str:=str+GetLangI(LNG_CH_MODERATED);
     end;
     if chPrivate in ch.state then
     begin
       if str<>'' then str:=str+', ';
       str:=str+GetLangI(LNG_CH_PRIVATE);
     end;
     if chTopic in ch.state then
     begin
       if str<>'' then str:=str+', ';
       str:=str+GetLangI(LNG_CH_TOPIC);
     end;
     tmp_pos:=1334;
     item.SubItems.Add(str);
     item.SubItems.Add(ch.topic);
     item.SubItems.Add(JoinString(ch.bans));
     item.SubItems.Add(JoinString(ch.ops));
     item.SubItems.Add(JoinString(ch.voices));
   end;
   tmp_pos:=1335;
   AlphaSort;
   Items.EndUpdate;
 end;
 tmp_pos:=1336;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1337;
end;

procedure ConsoleListBans;
var
 item: TListItem;
 i: Integer;
 b: PBan;
 str: String;
begin
 tmp_pos:=1343;
 if not running then exit;
 if db_bans=nil then exit;
 str:=GetLangI(LNG_BANS_NEVER_EXPIRE);
 tmp_pos:=1344;
 with SlavaNapWindow.list_bans do
 begin
   Items.BeginUpdate;
   Items.Clear;
   tmp_pos:=1345;
   for i:=0 to db_bans.Count-1 do
   begin
     b:=db_bans.Items[i];
     tmp_pos:=1346;
     item:=Items.Add;
     item.Caption:=b^.user;
     item.SubItems.Add(b^.ip);
     item.SubItems.Add(b^.admin);
     item.SubItems.Add(UnixTimeToStr(b^.time));
     tmp_pos:=1347;
     if b^.expires>0 then
      item.SubItems.Add(UnixTimeToStr(b^.expires))
     else
      item.SubItems.Add(str);
     item.SubItems.Add(UnixTimeToStr(b^.lastattempt));
     item.SubItems.Add(b^.using);
     item.SubItems.Add(IntToStr(b^.tries));
     item.SubItems.Add(b^.reason);
   end;
   tmp_pos:=1348;
   AlphaSort;
   Items.EndUpdate;
 end;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1349;
end;

procedure ConsoleRefreshLists(switch_page: Boolean);
begin
 tmp_pos:=1350;
 if not running then exit;
 Blocks2List(cons_blocks);
 tmp_pos:=1352;
 StrHash_Copy(cons.ignored,cons_ignored);
 StrHash_Copy(db_friends,cons_friends);
 ConsoleListLists(switch_page);
 tmp_pos:=1353;
end;

procedure ConsoleListLists(switch_page: Boolean);
var
 item: TListItem;
 i: Integer;
 list: TStringHash;
 t: PStringHashItem;
begin
 tmp_pos:=1354;
 if not running then exit;
 case cons_list of
   consFriends:  list:=cons_friends;
   consIgnored:  list:=cons_ignored;
   consBlocks:   list:=cons_blocks;
 end;
 tmp_pos:=1355;
 if switch_page then SlavaNapWindow.pages.ActivePage:=SlavaNapWindow.sh_list;
 with SlavaNapWindow.list_lists do
 begin
   Items.BeginUpdate;
   Items.Clear;
   tmp_pos:=1356;
   t:=list.first;
   while t<>nil do
   begin
     item:=Items.Add;
     item.Caption:=t^.data;
     t:=t^.next;
   end;
   tmp_pos:=1357;
   AlphaSort;
   Items.EndUpdate;
 end;
 // change items
 tmp_pos:=1358;
 with SlavaNapWindow do
 begin
   case cons_list of
     consFriends: begin
                    tmp_pos:=1359;
                    lbl_list.Caption:=GetLangI(LNG_LBL_FRIENDS);
                    btn_list_refresh.Caption:=GetLangI(LNG_FBTN_REFRESH);
                    btn_list_delete.Caption:=GetLangI(LNG_FBTN_REMOVE);
                    edit_list_item.Hint:=GetLangI(LNG_FEDIT_HINT);
                    btn_list_add.Caption:=GetLangI(LNG_FBTN_ADD);
                    list_lists.Columns.Items[0].Caption:=GetLangI(LNG_FLIST_USER);
                    list_lists.PopupMenu:=popup_friends;
                  end;
     consIgnored: begin
                    tmp_pos:=1360;
                    lbl_list.Caption:=GetLangI(LNG_LBL_IGNORED);
                    btn_list_refresh.Caption:=GetLangI(LNG_IBTN_REFRESH);
                    btn_list_delete.Caption:=GetLangI(LNG_IBTN_REMOVE);
                    edit_list_item.Hint:=GetLangI(LNG_IEDIT_HINT);
                    btn_list_add.Caption:=GetLangI(LNG_IBTN_ADD);
                    list_lists.Columns.Items[0].Caption:=GetLangI(LNG_ILIST_USER);
                    list_lists.PopupMenu:=popup_ignored;
                  end;
     consBlocks:  begin
                    tmp_pos:=1361;
                    if share_matchedfile_only then
                    begin
                      lbl_list.Caption:='これは共有できるキーワードのリストです。'
                                       +'各行は空白で区切られた1つ以上のキーワードを含みます。'
                                       +'大文字小文字は区別しません。';
                      btn_list_refresh.Caption:=GetLangI(LNG_BLBTN_REFRESH);
                      btn_list_delete.Caption:=GetLangI(LNG_BLBTN_REMOVE);
                      edit_list_item.Hint:='共有したいキーワードを入力してください。';
                      btn_list_add.Caption:=GetLangI(LNG_BLBTN_ADD);
                      list_lists.Columns.Items[0].Caption:='共有できるキーワード';
                      list_lists.PopupMenu:=popup_blocks;
                      mnu_win_blocked.Caption:='共有するファイル';
                      btn_tb_blocks.Caption:='共有キー';
                      btn_tb_blocks.Hint:='共有できるキーワードのリスト';
                      mnu_bl_delete.Caption:='共有しない';
                    end
                    else
                    begin
                      lbl_list.Caption:=GetLangI(LNG_LBL_BLOCKS);
                      btn_list_refresh.Caption:=GetLangI(LNG_BLBTN_REFRESH);
                      btn_list_delete.Caption:=GetLangI(LNG_BLBTN_REMOVE);
                      edit_list_item.Hint:=GetLangI(LNG_BLEDIT_HINT);
                      btn_list_add.Caption:=GetLangI(LNG_BLBTN_ADD);
                      list_lists.Columns.Items[0].Caption:=GetLangI(LNG_BLLIST_ITEM);
                      list_lists.PopupMenu:=popup_blocks;
                    end;
                  end;
   end;
   tmp_pos:=1362;
   i:=btn_list_refresh.Left;
   btn_list_refresh.Width:=Canvas.TextWidth(btn_list_refresh.Caption)+20;
   inc(i,btn_list_refresh.Width);
   btn_list_delete.Left:=i;
   btn_list_delete.Width:=Canvas.TextWidth(btn_list_delete.Caption)+20;
   inc(i,btn_list_delete.Width);
   edit_list_item.Left:=i;
   edit_list_item.Text:='';
   inc(i,edit_list_item.Width);
   btn_list_add.Left:=i;
   btn_list_add.Width:=Canvas.TextWidth(btn_list_add.Caption)+20;
   tmp_pos:=1363;
   if cons_list=consFriends then
   begin
     cb_list_sound.visible:=true;
     inc(i,btn_list_add.Width+10);
     cb_list_sound.Left:=i;
     cb_list_sound.Caption:=GetLangI(LNG_LIST_CB_SOUND);
     cb_list_sound.Width:=Canvas.TextWidth(cb_list_sound.Caption)+25;
   end
   else
     cb_list_sound.visible:=false;
   tmp_pos:=1364;
   if cons_list=consBlocks then
   begin
     inc(i,btn_list_add.Width);
     btn_list_reload.visible:=true;
     btn_list_reload.Left:=i;
     btn_list_reload.Caption:=GetLangI(LNG_BLBTN_RELOAD);
     btn_list_reload.Width:=Canvas.TextWidth(btn_list_reload.Caption)+25;
   end
   else
     btn_list_reload.visible:=false;
   toolbarResize(nil);
 end;
 tmp_pos:=1365;
end;

procedure ConsoleListHotlist;
var
 item: TListItem;
 i: Integer;
 user: POnlineUser;
 t: PStringHashItem;
begin
 tmp_pos:=1366;
 if not running then exit;
 with SlavaNapWindow.list_hotlist do
 begin
  tmp_pos:=1367;
  Items.BeginUpdate;
  Items.Clear;
  t:=cons.hotlist.first;
  while t<>nil do
  begin
    tmp_pos:=1368;
    item:=Items.Add;
    item.Caption:=t^.data;
    tmp_pos:=1369;
    user:=db_online.FindUser(t^.data);
    if user=nil then
    begin
      item.SubItems.Add(' '+GetLangI(LNG_HLIST_OFFLINE));
      item.SubItems.Add('');
    end
    else
    begin
      item.SubItems.Add(GetServerName(user^.server));
      item.SubItems.Add(Speed2Str(user^.speed));
    end;
    t:=t^.next;
  end;
  tmp_pos:=1370;
  AlphaSort;
  Items.EndUpdate;
 end;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1371;
end;

procedure ConsoleListUsers;
var
 i,j,k: Integer;
 user: POnlineUser;
 localuser: TLocalUser;
 item: TListItem;
 str,f: String;
 b: Boolean;
 th: TUserListReverseDNSThread;
begin
 tmp_pos:=1372;
 if not running then exit;
 SlavaNapWindow.btn_users_refresh.Enabled:=true;
 SlavaNapWindow.mnu_users_refresh.Enabled:=true;
 if db_online=nil then exit;
 f:=AnsiLowerCase(SlavaNapWindow.edit_users_filter.Text);
 if f='*' then f:='';
 tmp_pos:=1373;
 with SlavaNapWindow.list_users do
 begin
  Items.BeginUpdate;
  Items.Clear;
  tmp_pos:=1374;
  for i:=0 to USERS_NAME_ARRAY-1 do
  for j:=0 to db_online.names[i].count-1 do
  begin
    tmp_pos:=1375;
    user:=db_online.names[i].Items[j];
    b:=true;
    if SlavaNapWindow.cb_users_muzzled.Checked and (not (userMuzzled in user^.state)) then b:=false;
    if user^.level=napUserLeech then if not SlavaNapWindow.cb_users_leeches.Checked then b:=false;
    if user^.level=napUserUser then if not SlavaNapWindow.cb_users_users.Checked then b:=false;
    if user^.level>napUserUser then if not SlavaNapWindow.cb_users_mods.Checked then b:=false;
    if user^.server=nil then if not SlavaNapWindow.cb_users_local.checked then b:=false;
    if user^.server<>nil then if not SlavaNapWindow.cb_users_remote.Checked then b:=false;
    tmp_pos:=1376;
    if b and (f<>'') then b:=MatchesMaskEx(AnsiLowerCase(user^.username),f);
    if b then
    begin // if matches
      tmp_pos:=1377;
      item:=Items.Add;
      item.Caption:=user^.username;
      item.SubItems.Add(Level2Str(user^.level));
      item.SubItems.Add(IntToStr(user^.shared));
      if user^.server=nil then begin//local user
        for k:=0 to db_local.Count-1 do
          if AnsiLowerCase(TlocalUser(db_local.Items[k]).nick)=AnsiLowerCase(user^.username) then
          begin
            localuser:=db_local.Items[k];
            item.SubItems.Add(IntToStr(localuser.shared_size div (1024*1024)));
            if user^.shared>0 then
              item.SubItems.Add(IntToStr(localuser.shared_size div user^.shared div (1024*1024)))
            else
              item.SubItems.Add('0');
            break;
          end;
      end
      else//remote user
      begin
        item.SubItems.Add('remote');
        item.SubItems.Add('remote');
      end;
      item.SubItems.Add(user^.software);
      item.SubItems.Add(Speed2Str(user^.speed));
      item.SubItems.Add(decode_ip(user^.ip));
      item.SubItems.Add('Unresolved');
      if SlavaNapWindow.isColumnVisible(SlavaNapWindow.list_users,UL_REMOTEHOST+1) then
      begin
        th:=TUserListReverseDNSThread.Create(False);
        th.ip:=user^.ip;
        th.item:=item;
      end;
      item.SubItems.Add(IntToStr(user^.dataport));
      item.SubItems.Add(Time2Str(current_time_t-user^.last_seen_t));
      item.SubItems.Add(IntToStr(user^.uploads));
      item.SubItems.Add(IntToStr(user^.downloads));
      str:=IntToStr(user^.uploads);
      if user^.max_up<>-1 then
       str:=str+' ('+IntToStr(user^.max_up)+' max)';
      str:=str+' / '+IntToStr(user^.downloads);
      item.SubItems.Add(str);
      item.SubItems.Add(IntToStr(user^.total_up));
      item.SubItems.Add(IntToStr(user^.total_down));
      item.SubItems.Add(IntToStr(user^.total_up)+' / '+IntToStr(user^.total_down));
      item.SubItems.Add(GetServerName(user^.server));
      item.SubItems.Add(IntToStr(user^.ulrequests));
      item.SubItems.Add(IntToStr(user^.dlrequests));
      item.SubItems.Add(IntToStr(user^.searchreqs));
      item.SubItems.Add(IntToStr(user^.blockfiles));
      str:='';
      tmp_pos:=1378;
      if userMuzzled in user^.state then str:=str+GetLangI(LNG_LIST_MUZZLED);
      if userCloaked in user^.state then
      begin
        if str<>'' then str:=str+', ';
        str:=str+GetLangI(LNG_LIST_CLOAKED);
      end;
      if userChatting in user^.state then
      begin
        if str<>'' then str:=str+', ';
        str:=str+GetLangI(LNG_LIST_CHATTING);
      end;
      if user^.local<>nil then
      begin // adding items that present only for local users
        tmp_pos:=1379;
        if TLocalUser(user^.local).softwareID=softWinMXHidden then
        begin
         if str<>'' then str:=str+', ';
         str:=str+GetLangI(LNG_LIST_WINMXH);
        end
        else
        {if (TLocalUser(user^.local).softwareID<>softWinMXNormal) and (TLocalUser(user^.local).softwareID<>softWinMXJap) and (not (locPingable in TLocalUser(user^.local).localstate)) and ((current_time-20000)>TLocalUser(user^.local).last_seen) then
        begin
         if str<>'' then str:=str+', ';
         str:=str+GetLangI(LNG_LIST_NOPONG);
        end;}
        if str<>'' then str:=str+', ';
        if locPingable in TLocalUser(user^.local).localstate then
        begin
          if loc326 in TLocalUser(user^.local).detector then str:=str+'2get'
          else if loc10300 in TLocalUser(user^.local).detector then str:=str+'XNap';
          //else if not (loc208 in TLocalUser(user^.local).detector) then str:=str+'XNap??';
        end
        else if loc326 in TLocalUser(user^.local).detector then
        begin
          if locMacDir in TLocalUser(user^.local).detector then
            str:=str+'2get'
          else
            str:=str+'MX2.x';
        end
        else if loc110 in TLocalUser(user^.local).detector then str:=str+'Napchan'
        else if loc208 in TLocalUser(user^.local).detector then str:=str+'Utatane'
        else if locMD5Zeros in TLocalUser(user^.local).detector then str:=str+'Utatane'
        else if loc10300 in TLocalUser(user^.local).detector then str:=str+'XNap'
        else if locMD5NonZero in TLocalUser(user^.local).detector then str:=str+'MX3.x'
        else str:=str+'MX3.x??'
      end;
      item.SubItems.Add(str);
      //item.SubItems.Add(IntToStr(TLocalUser(user^.local).shared_blocked));
      str:='';
      if(user^.server=nil) then if TLocalUser(user^.local).shared_blocked>0 then str:=IntToStr(TLocalUser(user^.local).shared_blocked);
      item.SubItems.Add(str);
    end;
  end;
  tmp_pos:=1380;
  AlphaSort;
  Items.EndUpdate;
 end;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1381;
end;

procedure ConsoleListRegistered;
var
 i,j: Integer;
 item: TListItem;
 reg: PRegisteredUser;
 b: Boolean;
 f, str: String;
begin
 tmp_pos:=1382;
 if not running then exit;
 SlavaNapWindow.btn_reg_refresh.Enabled:=true;
 SlavaNapWindow.mnu_reg_refresh.Enabled:=true;
 if db_registered=nil then exit;
 f:=AnsiLowerCase(SlavaNapWindow.edit_reg_filter.Text);
 if f='*' then f:='';
 tmp_pos:=1383;
 with SlavaNapWindow.list_registered do
 begin
   tmp_pos:=1384;
   Items.BeginUpdate;
   Items.Clear;
   for i:=0 to USERS_NAME_ARRAY-1 do
   for j:=0 to db_registered.list[i].Count-1 do
   begin
     tmp_pos:=1385;
     reg:=db_registered.list[i].Items[j];
     if reg^.level=napUserLeech then b:=SlavaNapWindow.cb_reg_leeches.Checked
     else if reg^.level=napUserUser then b:=SlavaNapWindow.cb_reg_users.Checked
     else b:=SlavaNapWindow.cb_reg_mods.Checked;
     if SlavaNapWindow.cb_reg_muzzled.Checked then b:=userMuzzled in reg^.state;
     tmp_pos:=1386;
     if b and (f<>'') then b:=MatchesMaskEx(AnsiLowerCase(reg^.nick),f);
     if b then
     begin
       tmp_pos:=1387;
       item:=Items.Add;
       item.Caption:=reg^.nick;
       item.SubItems.Add(Level2Str(reg^.level));
       item.SubItems.Add(GetLangI(LNG_REG_TRANSFERS,reg^.downloads,reg^.uploads));
       item.SubItems.Add(decode_ip(reg^.last_ip));
       item.SubItems.Add(UnixTimeToStr(reg^.last_seen));
       str:='';
       if userMuzzled in reg^.state then str:=str+GetLangI(LNG_REG_MUZZLED);
       if userCloaked in reg^.state then
       begin
         if str<>'' then str:=str+', ';
         str:=str+GetLangI(LNG_REG_CLOAKED);
       end;
       item.SubItems.Add(str);
       item.SubItems.Add(UnixTimeToStr(reg^.created));
       item.SubItems.Add(reg^.createdby);
       item.SubItems.Add(reg^.lastsetby);
       item.ImageIndex:=Ord(reg^.level);
     end;
   end;
   tmp_pos:=1388;
   AlphaSort;
   Items.EndUpdate;
 end;
 SlavaNapWindow.toolbarResize(nil);
 tmp_pos:=1389;
end;

procedure Handler_JoinChannel;
var
 form: TSlavaNapChannelWindow;
begin
 tmp_pos:=1390;
 if cons_channels=nil then exit;
 if SlavaNapWindow.FindChannelWindow(cmd.cmd)<>nil then exit;
 form:=SlavaNapWindow.CreateChannelWindow(cmd.cmd);
 if form=nil then exit;
 tmp_pos:=1391;
end;

procedure Handler_ChannelAddUser;
var
 form: TSlavaNapChannelWindow;
 i: Integer;
 item: TListItem;
 user: POnlineUser;
begin
 tmp_pos:=1392;
 if not CheckParams(4) then exit;;
 form:=SlavaNapWindow.FindChannelWindow(hlist.Strings[0]);
 if form=nil then exit;
 item:=nil;
 tmp_pos:=1393;
 for i:=0 to form.users.items.count-1 do
  if form.users.items.Item[i].SubItems[0]=hlist.Strings[1] then
   item:=form.users.items.Item[i];
 form.users.Items.Beginupdate;
 if item=nil then
 begin
   item:=form.users.items.Add;
   item.SubItems.Add('');
 end;
 tmp_pos:=1394;
 item.Caption:=GetLangI(LNG_CH_USERLIST,hlist.Strings[1],Speed2Str(TNapSpeed(StrToIntDef(hlist.Strings[3],0))),hlist.Strings[2]);
 item.SubItems[0]:=hlist.Strings[1];
 form.users.Items.Endupdate;
 user:=db_online.FindUser(hlist.Strings[1]);
 if user=nil then exit;
 if cmd.id=MSG_SERVER_JOIN then
  form.AddMessage(slChannelJoin,GetLangI(LNG_CH_JOIN,hlist.Strings[1],Speed2Str(TNapSpeed(StrToIntDef(hlist.Strings[3],0))),hlist.Strings[2],decode_ip(user^.ip)));
 tmp_pos:=1395;
end;

procedure Handler_ChannelRemoveUser;
var
 form: TSlavaNapChannelWindow;
 i: Integer;
begin
 tmp_pos:=1396;
 if not CheckParams(2) then exit;
 form:=SlavaNapWindow.FindchannelWindow(hlist.Strings[0]);
 if form=nil then exit;
 tmp_pos:=1397;
 for i:=form.users.Items.Count-1 downto 0 do
  if form.users.Items.Item[i].SubItems[0]=hlist.Strings[1] then
   form.users.Items.Delete(i);
 form.AddMessage(slChannelPart,GetLangI(LNG_CH_PART,hlist.Strings[1]));
 tmp_pos:=1398;
end;

procedure Handler_ChannelTopic;
var
 form: TSlavaNapChannelWindow;
begin
 tmp_pos:=1399;
 if not CheckParams(1) then exit;
 form:=SlavaNapWindow.findChannelWindow(hlist.Strings[0]);
 if form=nil then exit;
 tmp_pos:=1400;
 form.topic:=NextParamEx(cmd.cmd);
 form.Caption:=form.channel+': '+form.topic;
 form.AddMessage(slTopic,GetLangI(LNG_CH_CHTOPIC,form.topic));
 tmp_pos:=1401;
end;

procedure Handler_ChannelEmote;
var
 form: TSlavaNapChannelWindow;
 str,str1: String;
begin
 tmp_pos:=1402;
 if not CheckParams(3) then exit;
 form:=SlavaNapWindow.findChannelWindow(hlist.Strings[0]);
 if form=nil then exit;
 tmp_pos:=1403;
 str:=hlist.Strings[1];
 if hlist.count=3 then str1:=hlist.Strings[2]
 else str1:=NextParamEx(cmd.cmd,2);
 if Length(str1)>1 then
  if (str1[1]='"') and (str1[Length(str1)]='"') then
   str1:=Copy(str1,2,Length(str1)-2);
 tmp_pos:=1404;
 if str=cons.nick then form.AddMessage(slChannelMyEmote,' '+str+' '+str1)
 else form.AddMessage(slChannelEmote,' '+str+' '+str1);
 tmp_pos:=1405;
end;

procedure Handler_ChannelMessage;
var
 form: TSlavaNapChannelWindow;
 str: String;
begin
 tmp_pos:=1406;
 if not CheckParams(3) then exit;
 form:=SlavaNapWindow.findChannelWindow(hlist.Strings[0]);
 if form=nil then exit;
 tmp_pos:=1407;
 str:=hlist.Strings[1];
 if str=cons.nick then form.AddMessage(slChannelMyMessage,'<'+str+'> '+NextParamEx(cmd.cmd,2))
 else form.AddMessage(slChannelMessage,'<'+str+'> '+NextParamEx(cmd.cmd,2));
 tmp_pos:=1408;
end;

procedure Handler_PartChannel;
var
 form: TSlavaNapChannelWindow;
begin
 tmp_pos:=1409;
 form:=SlavaNapWindow.FindChannelWindow(cmd.cmd);
 if form=nil then exit;
 tmp_pos:=1410;
 form.Close;
 tmp_pos:=1411;
end;

procedure Handler_Wallop;
var
 form: TSlavaNapChatWindow;
begin
 tmp_pos:=1412;
 if not CheckParams(1) then exit;
 if wallop_sound then
  PlaySound(PChar(ApplicationDir+'wallop.wav'), 0, SND_FILENAME or SND_ASYNC);
 if wallop_im then
 if (not SlavaNapWindow.cb_log_away.Checked) or (SlavaNapWindow.cb_log_awaypopup.Checked) then
 begin
   tmp_pos:=1413;
   form:=SlavaNapWindow.FindChatWindow(hlist.Strings[0]);
   if form=nil then
   begin
     if not wallop_sound then PlayChat(true);
     form:=SlavaNapWindow.CreateChatWindow(hlist.Strings[0]);
   end
   else
     PlayChat(false);
   tmp_pos:=1414;
   form.AddMessage(slChatMessage,'<wallop/'+hlist.Strings[0]+'> '+NextParamEx(cmd.cmd));
   tmp_pos:=1415;
   exit;
 end;
 tmp_pos:=1416;
 SlavaNapWindow.LogConsole(slWallop,'<'+FirstParam(cmd.cmd)+'> '+NextParamEx(cmd.cmd));
 tmp_pos:=1417;
end;

procedure Handler_PrivateMessage;
var
 form: TSlavaNapChatWindow;
 str: String;
begin
 tmp_pos:=1418;
 if not CheckParams(1) then exit;
 if not FileExists(ApplicationDir+'im.log') then
   try
    im_log_file:=TFileStream.Create(ApplicationDir+'im.log',fmCreate);
    im_log_file.Free;
    except
     im_log_file:=nil;
     exit;
   end;
 im_log_file:=nil;
 try
  im_log_file:=TFileStream.Create(ApplicationDir+'im.log',fmOpenWrite or fmShareDenyWrite);
  im_log_file.Seek(0,soFromEnd);
  except
   im_log_file:=nil;
   exit;
 end;
 str:='['+DateTimeToStr(now)+'] <'+cons.nick+'←'+hlist.Strings[0]+'> '+NextParam(cmd.cmd)+#13#10;
 im_log_file.Write(str[1],Length(str));
 im_log_file.Free;
 if SlavaNapWindow.cb_log_away.Checked then
 begin
   tmp_pos:=1419;
   if SlavaNapWindow.cb_log_awaypopup.Checked then
    form:=SlavaNapWindow.CreateChatWindow(hlist.Strings[0])
   else
    form:=SlavaNapWindow.FindChatWindow(hlist.Strings[0]);
   tmp_pos:=1420;
   if form<>nil then form.AddMessage(slChatMessage,'<'+hlist.Strings[0]+'> '+NextParamEx(cmd.cmd))
   else SlavaNapWindow.LogConsole(slChatMessage,'<'+hlist.Strings[0]+'> '+NextParamEx(cmd.cmd));
   tmp_pos:=1421;
   if last_away_user=hlist.Strings[0] then
    if (GetTickCount-last_away_time)<15000 then exit;
   last_away_user:=hlist.Strings[0];
   last_away_time:=GetTickCount;
   tmp_pos:=1422;
   cmd_list.AddDoubleCmd(MSG_CLIENT_PRIVMSG,0,hlist.Strings[0]+' '+SlavaNapWindow.edit_log_away.Text,'');
   tmp_pos:=1423;
   exit;
 end;
 tmp_pos:=1424;
 form:=SlavaNapWindow.FindChatWindow(hlist.Strings[0]);
 if form=nil then
 begin
  tmp_pos:=1425;
  PlayChat(true);
  form:=SlavaNapWindow.CreateChatWindow(hlist.Strings[0]);
 end
 else
  PlayChat(false);
 tmp_pos:=1426;
 if form=nil then exit;
 form.AddMessage(slChatMessage,'<'+hlist.Strings[0]+'> '+NextParamEx(cmd.cmd));
 tmp_pos:=1427;
end;

procedure Handler_PrivateMyMessage(user,text: String);
var
 form: TSlavaNapChatWindow;
 str: String;
begin
 tmp_pos:=1428;
 if not CheckParams(1) then exit;;
 if not FileExists(ApplicationDir+'im.log') then
   try
    im_log_file:=TFileStream.Create(ApplicationDir+'im.log',fmCreate);
    im_log_file.Free;
    except
     im_log_file:=nil;
     exit;
   end;
 im_log_file:=nil;
 try
  im_log_file:=TFileStream.Create(ApplicationDir+'im.log',fmOpenWrite or fmShareDenyWrite);
  im_log_file.Seek(0,soFromEnd);
  except
   im_log_file:=nil;
   exit;
 end;
 str:='['+DateTimeToStr(now)+'] <'+cons.nick+'→'+user+'> '+text+#13#10;
 im_log_file.Write(str[1],Length(str));
 im_log_file.Free;

 if FirstParam(text)='[告知]' then exit;

 if SlavaNapWindow.cb_log_away.Checked then
 if text=SlavaNapWindow.edit_log_away.Text then
 begin
   tmp_pos:=1429;
   form:=SlavaNapWindow.FindChatWindow(hlist.Strings[0]);
   if form=nil then exit;
 end;
 tmp_pos:=1430;
 form:=SlavaNapWindow.CreateChatWindow(user);
 if form=nil then exit;
 tmp_pos:=1431;
 form.AddMessage(slChatMyMessage,'<'+cons.nick+'> '+text);
 tmp_pos:=1432;
end;

procedure SendPrivateMyMessage(cmd: String);
var
 str,str1: String;
begin
 tmp_pos:=1433;
 str:=FirstParam(cmd);
 if str='' then exit;
 tmp_pos:=1434;
 str1:=NextParamEx(cmd);
 Handler_PrivateMyMessage(str,str1);
 tmp_pos:=1435;
end;

procedure ConsoleAddServer(str: String);
var
 host,port: String;
 srv: TServer;
 i: Integer;
begin
 tmp_pos:=1436;
 i:=pos(':',str);
 if i=0 then
 begin
   host:=str;
   port:='8888';
 end
 else
 begin
   host:=copy(str,1,i-1);
   port:=copy(str,i+1,5);
 end;
 host:=lowercase(host);
 tmp_pos:=1437;
 srv:=FindServer(host,false);
 if srv<>nil then exit;
 tmp_pos:=1438;
 srv:=TServer.Create;
 srv.host:=host;
 srv.port:=StrToIntDef(port,8888);
 db_servers.Add(srv);
 tmp_pos:=1439;
 ConsoleListServers;
 tmp_pos:=1440;
end;

procedure ConsoleServerProps(str: String);
begin
 if not running then exit;
 tmp_pos:=1441;
 SlavaNapServerAttr.ShowServer(str);
 tmp_pos:=1442;
end;

procedure ConsoleUpdateServerProps(str: String);
var
 srv: TServer;
begin
 if not running then exit;
 tmp_pos:=1443;
 if SlavaNapServerAttr.server<>str then exit;
 srv:=FindServer(str,false);
 if srv=nil then exit;
 tmp_pos:=1444;
 if srv.connected=conNotConnected then
 begin
   str:=lowercase(SlavaNapServerAttr.edit_host.text);
   if str<>srv.host then
    if FindServer(str,false)=nil then
     srv.host:=str;
   srv.port:=SlavaNapServerAttr.edit_port.Value;
 end;
 tmp_pos:=1445;
 srv.forced_ip:=trim(SlavaNapServerAttr.edit_ip.Text);
 if SlavaNapServerAttr.cb_auth_resolve.Checked then srv.authentication:=authResolve
 else srv.authentication:=authPassword;
 tmp_pos:=1446;
 srv.mypassword:=SlavaNapServerAttr.edit_mypass.Text;
 srv.remotepassword:=SlavaNapServerAttr.edit_remotepass.Text;
 if SlavaNapServerAttr.cb_comp_0.Checked then srv.compress:=zcNone
 else if SlavaNapServerAttr.cb_comp_1.Checked then srv.compress:=zcFastest
 else if SlavaNapServerAttr.cb_comp_2.Checked then srv.compress:=zcDefault
 else srv.compress:=zcMax;
 tmp_pos:=1447;
 if SlavaNapServerAttr.cb_relink.Checked then
  srv.relink:=SlavaNapServerAttr.edit_relink.Value * 60000
 else
  srv.relink:=0;
 srv.comments:=SlavaNapServerAttr.edit_comments.Text;
 tmp_pos:=1448;
 ConsoleListServers;
 tmp_pos:=1449;
end;

procedure ConsoleHotListOnline(str: String);
begin
 tmp_pos:=1450;
 if SlavaNapWindow.cb_hotlist_sound.Checked then PlaySound(PChar(ApplicationDir+'hotlistlogin.wav'), 0, SND_FILENAME or SND_ASYNC);
 ConsoleListHotlist;
 tmp_pos:=1451;
end;

procedure ConsoleSetCompress(cmd: String);
var
 srv: TServer;
 comp: TZCompressionLevel;
begin
 tmp_pos:=1452;
 SplitString(cmd,hlist);
 if hlist.count<2 then exit;
 tmp_pos:=1453;
 comp:=TZCompressionLevel(StrToIntDef(hlist.Strings[1],3));
 srv:=FindServer(hlist.Strings[0],false);
 if srv<>nil then srv.compress:=comp;
 tmp_pos:=1454;
end;

procedure ConsoleSetStartup(cmd: String);
var
 srv: TServer;
 t: Cardinal;
begin
 tmp_pos:=1455;
 SplitString(cmd,hlist);
 if hlist.count<2 then exit;
 tmp_pos:=1456;
 t:=StrToIntDef(hlist.Strings[1],0);
 srv:=FindServer(hlist.Strings[0],false);
 if srv<>nil then srv.relink:=t;
 tmp_pos:=1457;
end;

procedure Handler_Whois;
var
 form: TSlavaNapWhois;
 str,str1: String;
 i,j: Integer;
begin
 tmp_pos:=1458;
 SplitString(cmd.cmd,hlist);
 if hlist.count<17 then exit;
 tmp_pos:=1459;
 form:=SlavaNapWindow.CreateWhoisWindow(hlist.Strings[0]);
 form.Caption:=GetLangI(LNG_WHOIS_CAPTION,hlist.Strings[0]);
 form.mnu_close.Caption:=GetLangI(LNG_WMENU_CLOSE);
 form.mnu_hotlist.Caption:=GetLangI(LNG_WMENU_HOTLIST);
 form.mnu_friend.Caption:=GetLangI(LNG_WMENU_FRIEND);
 form.mnu_ignore.Caption:=GetLangI(LNG_WMENU_IGNORE);
 form.mnu_message.caption:=GetLangI(LNG_WMENU_MESSAGE);
 tmp_pos:=1460;
 str:='';
 str:=GetLangI(LNG_WHOIS_USER,hlist.Strings[0]); // user
 str:=str+GetLangI(LNG_WHOIS_LEVEL,hlist.Strings[1]); // level
 i:=StrToIntDef(hlist.Strings[2],0);
 j:=i div 3600; // hours
 i:=i mod 3600;
 if j>0 then str1:=IntToStr(j)+':'
 else str1:='';
 j:=i div 60; // mins
 i:=i mod 60; // sec
 if (str1<>'') and (j<10) then str1:=str1+'0'+IntToStr(j)+':'
 else str1:=str1+IntToStr(j)+':';
 if i<10 then str1:=str1+'0'+IntToStr(i)
 else str1:=str1+IntToStr(i);
 tmp_pos:=1461;
 str:=str+GetLangI(LNG_WHOIS_TIME,str1); // time
 str:=str+GetLangI(LNG_WHOIS_CHANNELS,hlist.Strings[3]); // channels
 str:=str+GetLangI(LNG_WHOIS_STATUS,hlist.Strings[4]); // status
 str:=str+GetLangI(LNG_WHOIS_SHARED,hlist.Strings[5]); // shared
 str:=str+GetLangI(LNG_WHOIS_TRANSFERS,hlist.Strings[6],hlist.Strings[7]); // down/up
 str:=str+GetLangI(LNG_WHOIS_TOTAL,hlist.Strings[10],hlist.Strings[11]); // total
 str:=str+GetLangI(LNG_WHOIS_SPEED,Speed2Str(TNapSpeed(StrToIntDef(hlist.Strings[8],0)))); // speed
 str:=str+GetLangI(LNG_WHOIS_SOFTWARE,hlist.Strings[9]); // software
 str:=str+GetLangI(LNG_WHOIS_IP,hlist.Strings[12]); // IP
 if hlist.Strings[13]<>'0' then
  str:=str+GetLangI(LNG_WHOIS_PORT,hlist.Strings[13]); // port
 str:=str+GetLangI(LNG_WHOIS_DATAPORT,hlist.Strings[14]); // dataport
 str:=str+GetLangI(LNG_WHOIS_SERVER,hlist.Strings[16]); // server
 form.log.text:=str;
 tmp_pos:=1462;
 form.Show;
 tmp_pos:=1463;
end;

procedure Handler_Whowas;
var
 str: String;
begin
 tmp_pos:=1464;
 SplitString(cmd.cmd,hlist);
 if hlist.count<3 then exit;
 tmp_pos:=1465;
 str:=GetLangI(LNG_WHOIS_WHOWAS,hlist.Strings[1],hlist.Strings[0]);
 SlavaNapWindow.LogConsole(slWhowas,str);
 tmp_pos:=1466;
end;

procedure Handler_Invite;
begin
 tmp_pos:=1467;
 SplitString(cmd.cmd,hlist);
 if hlist.count<3 then exit;
 SlavaNapInvitation.user:=hlist.Strings[0];
 SlavaNapInvitation.channel:=hlist.Strings[1];
 SlavaNapInvitation.topic:=hlist.Strings[2];
 tmp_pos:=1468;
 SlavaNapInvitation.Show;
 SlavaNapInvitation.btn_accept.SetFocus;
 tmp_pos:=1469;
end;

procedure Handler_Browse;
var
 form: TSlavaNapBrowseWindow;
 item: TListItem;
 pfilename: PString;
 function FormatSize(SizeStr: String): String;
 begin
   Result:=FormatFloat('0,', StrToInt64Def(SizeStr,-1));
 end;
 function FormatFreq(FreqStr: String): String;
 begin
   Result:=IntToStr(StrToInt64Def(FreqStr,-1) div 1000);
 end;
 function FormatSec(SecStr: String): String;
 begin
   Result:=Time2Str(StrToInt64Def(SecStr,-1));
 end;
begin
 tmp_pos:=122621;
 SplitString(cmd.cmd,hlist);
 //形式: <nick> "<filename>" <md5> <size> <bitrate> <frequency> <time>
 if hlist.count<>7 then exit;
 tmp_pos:=122622;
 form:=SlavaNapWindow.CreateBrowseWindow(hlist.Strings[0]);
 tmp_pos:=122623;
 item:=form.list.Items.Add;
 New(pfilename);
 item.Data:=pfilename;
 pfilename^:=hlist.Strings[1];
 if form.show_fullpath then
   item.Caption:=hlist.Strings[1]
 else
   item.Caption:=ExtractFileName(hlist.Strings[1]);
 item.SubItems.Add(FormatSize(hlist.Strings[3]));//Bytes
 item.SubItems.Add(hlist.Strings[4]);//kbps
 item.SubItems.Add(FormatFreq(hlist.Strings[5]));//kHz
 item.SubItems.Add(FormatSec(hlist.Strings[6]));//Time
 Inc(form.shared);
 Inc(form.size,StrToInt64Def(hlist.Strings[3],0));
 tmp_pos:=122624;
end;

procedure Handler_Browse_End;
var
 form: TSlavaNapBrowseWindow;
 str: String;
begin
 //形式: <nick> [ip] (参照失敗のときはipが返らない)
 tmp_pos:=122626;
 SplitString(cmd.cmd,hlist);
 if hlist.count<2 then exit;
 tmp_pos:=122627;
 form:=SlavaNapWindow.CreateBrowseWindow(hlist.Strings[0]);
 form.ip:=hlist.Strings[1];
 form.Caption:=hlist.Strings[0]+'('+decode_ip(hlist.Strings[1])
   +') - SlavaNap 共有ファイル情報(取得完了)';
 str:='Total: '+IntToStr(form.shared)+' Files, '
               +IntToStr(form.size div MegaByte)+' MB';
 form.status.Panels[0].Text:=str;
 form.status.Panels[0].Width:=form.Canvas.TextWidth(str)+20;
 form.show;
 tmp_pos:=122628;
end;

procedure ConsoleReply(id: Integer; str: String);
begin
 if not running then exit;
 tmp_pos:=1470;
 cmd.cmd:=str;
 cmd.id:=id;
 try
   case id of
     MSG_SERVER_JOIN_ACK: Handler_JoinChannel;
     MSG_SERVER_JOIN, MSG_SERVER_CHANNEL_USER_LIST: Handler_ChannelAddUser;
     MSG_SERVER_TOPIC: Handler_ChannelTopic;
     MSG_SERVER_EMOTE: Handler_ChannelEmote;
     MSG_SERVER_PUBLIC: Handler_ChannelMessage;
     MSG_CLIENT_PART: Handler_PartChannel;
     MSG_SERVER_PART: Handler_ChannelRemoveUser;
     MSG_SERVER_ERROR, MSG_SERVER_NOSUCH: slavaNapWindow.LogConsole(slError,str);
     MSG_SERVER_WALLOP: Handler_Wallop;
     MSG_SERVER_ANNOUNCE: SlavaNapWindow.LogConsole(slAnnounce,'<'+FirstParam(str)+'> '+NextParamEx(str));
     MSG_SERVER_USER_SIGNON: ConsoleHotListOnline(str);
     MSG_SERVER_USER_SIGNOFF: ConsoleListHotlist;
     MSG_CLIENT_PRIVMSG: Handler_PrivateMessage;
     MSG_SERVER_WHOWAS: Handler_Whowas;
     MSG_SERVER_WHOIS_RESPONSE: Handler_Whois;
     MSG_CLIENT_PING: cmd_list.AddDoubleCmd(MSG_CLIENT_PONG,0,str,'');
     MSG_CLIENT_PONG: SlavaNapWindow.LogConsole(slPong,GetLangI(LNG_CONSOLEPONG,FirstParam(str)));
     MSG_CLIENT_CHANNEL_INVITE: Handler_Invite;
     MSG_SERVER_CHANNEL_USER_LIST_END,
     214,207,208,301,322,323: begin end;
     MSG_SERVER_BROWSE_RESPONSE: Handler_Browse;
     MSG_SERVER_BROWSE_END: Handler_Browse_End;
     else SlavaNapWindow.LogConsole(clBlack,'Reply ['+IntToStr(id)+'] : '+str);
   end;
  except
   DebugLog('Exception in ConsoleReply()  pos='+IntToStr(tmp_pos));
 end;
 tmp_pos:=1471;
end;

initialization
begin
 hlist:=TMyStringList.Create;
end;

finalization
begin
 hlist.Free;
 hlist:=nil;
end;
end.
