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

 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: Thread

 class for main thread

*********************************************************}
unit Thread;

interface

{$I Defines.pas}

uses
  SysUtils, Classes, Classes2, Graphics, ZLibEx, WinSock, Windows, Constants,
  STypes, Lang, BlckSock, SynSock, Users, Registered, Keywords, LocalUsers,
  Servers, SlavaStrings, Share, Class_DoubleCmdList, Blocks, Class_Cmd2List,
  StringResources;

type
  TMainThread = class(TThread)
    Last_Sync: Cardinal;
    Last_Stats: Cardinal;
    Last_Period: Cardinal;
    Last_Period30: Cardinal;
    Last_Period180: Cardinal;
    Cycle_Start, Cycle_Delay: Cardinal;
    constructor Create;
    destructor Destroy; override;
    procedure Execute; override;
    procedure ShutDown;
    procedure SyncClose;
    //  procedure DoSync(T: Integer);
    procedure SyncData;
    procedure Check60;
    procedure Check30;
    procedure Check180;
    procedure CheckMinShare;
    procedure CheckBots;
    procedure SyncLog;
    procedure CreateSockets;
    function Listen(var Socket: HSocket; Port: Integer): Boolean;
    procedure Accept; overload;
    procedure Accept(Server: HSocket); overload;
    procedure AcceptOldReport;
    procedure AcceptNewReport;
    procedure AcceptMeta(Server: HSocket);
    procedure CheckTimeouts;
    procedure CheckServers;
    procedure ReceiveData; overload;
    procedure ReceiveData(User: TLocalUser; Counter, Recurse: Integer);
      overload;
    procedure ProcessCmd(DCmd: TNapDoubleCmd);
    procedure SendWebPage(User: TLocalUser);
    procedure ResetSearchControl;
    procedure CloseSockets;
    procedure SynchronizeConsole;
    procedure ResetWantQueueControl;
    procedure ResetDLRequestControl;
    procedure CheckBlockedShare;
    procedure CheckForceEnter;
    procedure KillIdleUser;
  end;

var
  MainThread: TMainThread;
  Quiet_Listen: Boolean;

implementation

uses
  Vars, MainForm, Handler, Napigator, Dagsta, Console, Channels, ChanAttr,
  ModeForm, Memory_Manager, Ips;

constructor TMainThread.Create;
begin
  try
    if (not Log_To_File) and (Log_File <> nil) then
      Log_File.Free;
  except
    Log_File := nil;
    LogStartup('Thread::Create: Cannot close "server.log" !!!');
    DebugLog('Error: Cannot close file "server.log"');
  end;
  LogStartup('Thread::Create: Resetting debug.log');
  try
    Debug_File := TFileStream.Create(ApplicationDir + 'debug.log', fmCreate);
    Debug_File.Free;
  except
  end;
  Debug_File := nil;
  try
    //  if Log_To_File then
    Debug_File := TFileStream.Create(ApplicationDir + 'debug.log', fmOpenWrite or
      fmShareDenyWrite);
  except
    Debug_File := nil;
    DebugLog('Error: Cannot open file "debug.log"');
    LogStartup('Thread::Create: Cannot open "debug.log" !!!"');
  end;
  LogStartup('Thread::Create: Opening "serverstats"');
  if Clear_Serverstats or (not FileExists(ApplicationDir + 'serverstats')) then
  try
    DeleteFile(PChar(ApplicationDir + 'serverstats'));
  except
  end;
  LogStartup('Thread::Create: Loading blocked files');
  LoadBlocks;
  LogStartup('Thread::Create: Loading ips');
  LoadIPs;
  LogStartup('Thread::Create: Loading blocked directories');
  LoadDirs;
  LogStartup('Thread::Create: inherited Create(False);');
  inherited Create(False);
end;

destructor TMainThread.Destroy;
begin
  inherited Destroy;
end;

procedure TMainThread.ShutDown;
var
  I: Integer;
  User: TLocalUser;
  Srv: TServer;
  Ch: TChannel;
begin
  SlavaNapWindow.Visible := False;
  DebugLog('ShutDown - Start debug', True);
  try
    DisconnectNapigator(0);
    DisconnectDagsta(0);
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - 0: ' + E.Message);
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - 1', True);
  try
    StrHash_SaveToFile(Cons.Hotlist, ApplicationDir + 'hotlist');
    StrHash_SaveToFile(Cons.Ignored, ApplicationDir + 'ignored');
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - 1: ' + E.Message);
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - 2', True);
  try
    for I := DB_Local.Count - 1 downto 0 do
    begin
      User := DB_Local.Items[I];
      if User.Logged then
        DisconnectUser(User, '', '', 'ShutDown', True);
      if (I mod 10) = 0 then
      begin
{$I CheckSync.pas}
      end;
    end;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - 2: ' + E.Message);
  end;
  DebugLog('ShutDown - 3', True);
  try
    for I := 0 to DB_Local.Count - 1 do
    begin
      User := DB_Local.Items[I];
      User.Free;
      if (I mod 10) = 0 then
      begin
{$I CheckSync.pas}
      end;
    end;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - 3: ' + E.Message);
  end;
  DebugLog('ShutDown - 4', True);
  try
    DB_Local.Free;
    DB_Local := nil;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - DB_Local.Free: ' + E.Message);
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - 4.5', True);
  try
    DB_Login.Free;
    DB_Login := nil;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - DB_Login.Free: ' + E.Message);
  end;
{$I CheckSync.pas}
  try
    for I := 0 to MAX_LISTEN_SOCKET do
      if Server_Socket[I] <> INVALID_SOCKET then
      begin
        SynSock.ShutDown(Server_Socket[I], SD_BOTH);
        SynSock.CloseSocket(Server_Socket[I]);
        Server_Socket[I] := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    for I := 0 to MAX_LISTEN_TRAPSOCKET do
      if Trap_Socket[I] <> INVALID_SOCKET then
      begin
        SynSock.ShutDown(Trap_Socket[I], SD_BOTH);
        SynSock.CloseSocket(Trap_Socket[I]);
        Trap_Socket[I] := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    DebugLog('ShutDown - 5', True);
    if Old_Report_Socket <> INVALID_SOCKET then
    begin
      SynSock.ShutDown(Old_Report_Socket, SD_BOTH);
      SynSock.CloseSocket(Old_Report_Socket);
      Old_Report_Socket := INVALID_SOCKET;
      Dec(Sockets_Count);
    end;
    if New_Report_Socket <> INVALID_SOCKET then
    begin
      SynSock.ShutDown(New_Report_Socket, SD_BOTH);
      SynSock.CloseSocket(New_Report_Socket);
      New_Report_Socket := INVALID_SOCKET;
      Dec(Sockets_Count);
    end;
    {if Meta_Socket <> INVALID_SOCKET then
    begin
      SynSock.ShutDown(Meta_Socket, SD_BOTH);
      SynSock.CloseSocket(Meta_Socket);
      Meta_Socket := INVALID_SOCKET;
      Dec(Sockets_Count);
    end;}
    SetLength(Metasocket_List, Length(MetaPort_List));
    for I := 0 to Length(Metasocket_List) - 1 do
      if Metasocket_List[I] <> INVALID_SOCKET then
      begin
        SynSock.ShutDown(Metasocket_List[I], SD_BOTH);
        SynSock.CloseSocket(Metasocket_List[I]);
        Metasocket_List[I] := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    DebugLog('ShutDown - 6', True);
{$I CheckSync.pas}
    if Napigator_Socket <> INVALID_SOCKET then
    begin
      SynSock.ShutDown(Napigator_Socket, SD_BOTH);
      SynSock.CloseSocket(Napigator_Socket);
      Napigator_Socket := INVALID_SOCKET;
      Dec(Sockets_Count);
    end;
    if Dagsta_Socket <> INVALID_SOCKET then
    begin
      SynSock.ShutDown(Dagsta_Socket, SD_BOTH);
      SynSock.CloseSocket(Dagsta_Socket);
      Dagsta_Socket := INVALID_SOCKET;
      Dec(Sockets_Count);
    end;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - Closing sockets: ' + E.Message);
  end;
  try
    SaveServers;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - SaveServers: ' + E.Message);
  end;
  DebugLog('ShutDown - 7', True);
{$I CheckSync.pas}
  try
    for I := 0 to DB_Servers.Count - 1 do
    begin
      Srv := DB_Servers.Items[I];
      Srv.Free;
    end;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - Srv.Free: ' + E.Message);
  end;
{$I CheckSync.pas}
  try
    SaveChannels(ApplicationDir + 'channels');
  except
  end;
  DebugLog('ShutDown - 8', True);
{$I CheckSync.pas}
  try
    for I := 0 to DB_Channels.Count - 1 do
    begin
      Ch := DB_Channels.Items[I];
      Ch.Free;
    end;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - Ch.Free: ' + E.Message);
  end;
{$I CheckSync.pas}
  try
    DB_Registered.SaveToFile(ApplicationDir + 'users');
  except
  end;
  DebugLog('ShutDown - 9', True);
  try
    DB_Bans.SaveToFile(ApplicationDir + 'bans');
  except
  end;
  try
    StrHash_SaveToFile(DB_Motd, ApplicationDir + 'motd');
  except
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - 10', True);
  try
    StrHash_SaveToFileSorted(DB_Friends, ApplicationDir + 'friends');
  except
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - Saving dengon', True);
  try
    // StrHash_SaveToFile(DB_MsgServ, ApplicationDir + 'dengon');
    MataParaEncrypt(DB_MsgServ, DefaultCryptPass, ApplicationDir + 'dengon');
  except
  end;
  try
    SaveBlocks;
  except
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - Saving IPs', True);
  try
    SaveIPs;
  except
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - Saving dirs', True);
  try
    SaveDirs;
    FreeDirs;
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - Saving dirs: ' + E.Message);
  end;
{$I CheckSync.pas}
  DebugLog('ShutDown - Saving clientstats', True);
  try
    DB_Software.SortByID1;
    DB_Software.SaveToFile(ApplicationDir + 'clientstats', Cmd2ID2CRCLC);
  except
    on E: Exception do
      DebugLog('Exception on ShutDown - DB_Software.Save: ' + E.Message);
  end;
  DebugLog('ShutDown - 11', True);
{$I CheckSync.pas}
  try
    DB_Channels.Free;
    DB_Channels := nil;
    DebugLog('ShutDown - 11.0', True);
    DB_Servers.Free;
    DB_Servers := nil;
    DebugLog('ShutDown - 11.1', True);
    DB_Online.Free;
    DB_Online := nil;
    DebugLog('ShutDown - 11.2', True);
    DB_Registered.Free;
    DB_Registered := nil;
    DebugLog('ShutDown - 11.3(FreeKeywords)', True);
{$I CheckSync.pas}
    FreeKeywords;
{$I CheckSync.pas}
    DebugLog('ShutDown - 12', True);
    DB_Bans.Free;
    DB_Bans := nil;
    DebugLog('ShutDown - 12.0', True);
    StrHash_Clear(DB_Motd);
    Sleep(5);
    StrHash_Clear(DB_Friends);
    Sleep(5);
    StrHash_Clear(DB_MsgServ);
    DebugLog('ShutDown - 12.1', True);
{$I CheckSync.pas}
    Sync_Reply_List.Free;
    Sync_Reply_List := nil;
    DebugLog('ShutDown - 13', True);
{$I CheckSync.pas}
    StrHash_Clear(Ext_Mp3_List);
    StrHash_Clear(Ext_Audio_List);
    StrHash_Clear(Ext_Video_List);
    StrHash_Clear(Ext_Text_List);
    StrHash_Clear(Ext_Image_List);
    StrHash_Clear(Ext_App_List);
    StrHash_Clear(Ext_Cd_List);
    StrHash_Clear(Fakeext_List);
    StrHash_Clear(Blocked_TransferPort_List);
    StrHash_Clear(Force_Enter_Channel_List);
{$I CheckSync.pas}
    FreeBlocks;
    DebugLog('ShutDown - 14', True);
{$I CheckSync.pas}
    DB_Software.Free;
    DB_Software := nil;
    DB_Invitations.Free;
    DB_Invitations := nil;
    DB_Whowas.Free;
    DB_Whowas := nil;
    DB_Reconnect.Free;
    DB_Reconnect := nil;
    Redirected_Servers.Free;
    Redirected_Servers := nil;
    DebugLog('ShutDown - 15', True);
{$I CheckSync.pas}
    Cmd_List.Free;
    Cmd_List := nil;
    DebugLog('ShutDown - Ok', True);
  except
    on E: Exception do
      DebugLog('Exception on ShutDown end: ' + E.Message);
  end;
  if Log_File <> nil then
  try
    Log_File.Free;
    Log_File := nil;
  except
  end;
  if Debug_File <> nil then
  try
    Debug_File.Free;
    Debug_File := nil;
  except
  end;
  try
    for I := 0 to DB_Closed.Count - 1 do
      SynSock.CloseSocket(PNapCmd2(DB_Closed.Items[I])^.Id1);
    DB_Closed.Free;
  except
  end;
end;

procedure TMainThread.Execute;
begin
  Current_Time := GetTickCount;
  Current_Time_T := GetTickCountT;
  LogStartup('Thread::Execute: starting main thread');
  FreeOnTerminate := True;
  Priority := tpHigher;
  Last_Sync := Current_Time;
  //  Last_Sync_Check := Current_Time;
  Last_Stats := Current_Time;
  Cycle_Start := Current_Time;
  Last_Period := Current_Time;
  Last_Period30 := Current_Time;
  Last_Period180 := Current_Time;
  Last_Announcement := Current_Time;
  Last_Force_Enter := Current_Time;
  Bandwidth_Lastcheck := Current_Time;
  Bandwidth_Up := 0;
  Bandwidth_Down := 0;
  Users_Per_Minute := 0;
  LogStartup('Thread::Execute: first Synchronize(SyncLog);');
  try
    Synchronize(SyncLog);
  except
    on E: Exception do
      DebugLog('Exception on Synchronize(Synclog1) Pos=' + IntToStr(Tmp_Pos) +
        ' : ' + E.Message);
  end;
  LogStartup('Thread::Execute: creating sockets');
  CreateSockets;
{$I CheckSync.pas}
  LogStartup('Thread::Execute: InitKeywords');
  InitKeywords;
  LogStartup('Thread::Execute: InitNapigator');
  InitNapigator;
  LogStartup('Thread::Execute: InitDagsta');
  InitDagsta;
  LogStartup('Thread::Execute: SyncLog');
  try
    Synchronize(SyncLog);
  except
    on E: Exception do
      DebugLog('Exception on Synchronize(Synclog2) Pos=' + IntToStr(Tmp_Pos) +
        ' : ' + E.Message);
  end;
  LogStartup('Thread::Execute: CountStats');
  CountStats;
  LogStartup('Thread::Execute: CheckBandwidthTime');
  CheckBandwidthTime;
  Linking := False;
  if GetLangT(LNG_LNGFILE_VERSION) <> SLAVANAP_BUILD then
    SlavaNapWindow.LogMain(slError, GetLangT(LNG_INVALIDLNGFILE, Language +
      '.lng'));
  if GetLangT(LNG_MSGFILE_VERSION) <> SLAVANAP_BUILD then
    SlavaNapWindow.LogMain(slError, GetLangT(LNG_INVALIDLNGFILE,
      'slavanap.msg'));
  if Cons_Autojoin3 <> '' then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_JOIN, 0, Cons_Autojoin3, '');
  if Cons_Autojoin2 <> '' then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_JOIN, 0, Cons_Autojoin2, '');
  if Cons_Autojoin1 <> '' then
    Cmd_List.AddDoubleCmd(MSG_CLIENT_JOIN, 0, Cons_Autojoin1, '');
  LogStartup('Thread::Execute: starting loop');
  while not Terminated do
  try
    Tmp_Pos := 1479;
    Current_Time := GetTickCount;
    Current_Time_T := GetTickCountT;
    if (Current_Time - Bandwidth_Lastcheck) > BANDWIDTH_TIMEOUT then
      CheckBandwidthTime;
    Sleep(5);
    Tmp_Pos := 1480;
    if Running then
      SynchronizeConsole;
    Tmp_Pos := 1603;
    if Running then
      Accept;
    if Running then
      CheckServers;
    if Running then
      ReceiveData;
    Sleep(10);
    Tmp_Pos := 1481;
    if Running then
      Accept;
    if Running then
      Check30;
    if Running then
      CheckServers;
    if Running then
      Accept;
    Tmp_Pos := 1482;
    Current_Time := GetTickCount;
    Current_Time_T := GetTickCountT;
    Tmp_Pos := 1483;
    if Running then
      CheckNapigator;
    if Running then
      CheckDagsta;
    if Running then
      CheckTimeouts;
    Sleep(5);
    Tmp_Pos := 1484;
    if Running then
      CheckBots;
    if Running then
      CheckForceEnter;
    if Running then
      CheckServers;
    Tmp_Pos := 1485;
    if Running then
      Check60;
    if Running then
      CloseSockets;
    Tmp_Pos := 1486;
    if not Running then
      Terminate;
  except
    DebugLog('Exception in TMainThread.Execute()  Pos=' + IntToStr(Tmp_Pos));
  end;
  try
    WriteAllServers(MSG_SRV_SHUTDOWN, '', Restart_User);
    if Num_Servers > 0 then
      CheckServers;
    LogStartup('Thread::Execute: ShutDown');
    ShutDown;
    LogStartup('Thread::Execute: SyncClose');
    try
      Synchronize(SyncClose);
    except
      on E: Exception do
        DebugLog('Exception on Synchronize(Syncclose) Pos=' + IntToStr(Tmp_Pos) +
          ' : ' + E.Message);
    end;
    LogStartup('Thread::Execute: end;');
  except
    DebugLog('Exception on shutdown in TMainThread.Execute. Pos=' +
      IntToStr(Tmp_Pos), True);
  end;
end;

procedure TMainThread.SyncClose;
begin
  try
    SlavaNapWindow.Close;
  except
  end;
end;

procedure TMainThread.SyncLog;
var
  DCmd: TNapDoubleCmd;
begin
  if not Running then Exit;
  try
    Tmp_Pos := 1487;
    while Sync_Reply_List.Count > 0 do
    begin
      Tmp_Pos := 1488;
      DCmd := Sync_Reply_List.Cmd(0);
      Sync_Reply_List.Delete(0);
      Tmp_Pos := 1489;
      case DCmd.Id1 of
        MSG_SR_LOG: SlavaNapWindow.LogMain(DCmd.Id2, DCmd.Cmd2, False);
        MSG_SR_CONSOLELOG: SlavaNapWindow.LogConsole(DCmd.Id2, DCmd.Cmd2,
          False);
        MSG_SR_RESTART: SlavaNapWindow.Mnu_Tray_RestartClick(nil);
        MSG_SR_CONSOLEREPLY: ConsoleReply(DCmd.Id2, DCmd.Cmd1);
      end;
      Tmp_Pos := 1490;
    end;
  except
    try
      SlavaNapWindow.LogMain(slDebugData, 'Exception in SyncLog. Pos=' +
        IntToStr(Tmp_Pos));
    except
    end;
  end;
  Tmp_Pos := 1491;
end;

procedure TMainThread.SyncData;
var
  DCmd: TNapDoubleCmd;
begin
  try
    Tmp_Pos := 1472;
    if not Running then Exit;
    if not SlavaNapWindow.Timer1.Enabled then
      SlavaNapWindow.Timer1Timer(nil);
    Tmp_Pos := 1473;
    SyncLog;
    Tmp_Pos := 1474;
    while Cmd_List.Count > 0 do
    begin
      DCmd := Cmd_List.Cmd(0);
      Cmd_List.Delete(0);
      Tmp_Pos := 1475;
      try
        ProcessCmd(DCmd);
      except
        on E: Exception do
          DebugLog('Exception in SyncData (Id1=' + IntToStr(DCmd.Id1) + ', Pos='
            + IntToStr(Tmp_Pos) + ') : ' + E.Message);
      end;
      Tmp_Pos := 1476;
    end;
    Tmp_Pos := 1477;
  except
    try
      SlavaNapWindow.LogMain(slDebugData, 'Exception in SyncData. Pos=' +
        IntToStr(Tmp_Pos));
    except
    end;
  end;
  Tmp_Pos := 1478;
end;

procedure TMainThread.ProcessCmd(DCmd: TNapDoubleCmd);
var
  Ch: TChannel;
  LogFileName: string;
begin
  Tmp_Pos := 1492;
  case DCmd.Id1 of
    MSG_CMD_SAVEDATA:
      begin
        if not Running then Exit;
        Tmp_Pos := 1493;
        SlavaNapWindow.Mnu_Save.Enabled := True;
        Log(slDebugData, GetLangI(LNG_SAVINGDATA));
        Synchronize(SyncLog);
        Tmp_Pos := 1494;
        DB_Registered.SaveToFile(ApplicationDir + 'users');
        DB_Bans.SaveToFile(ApplicationDir + 'bans');
        DB_Software.SortByID1;
        DB_Software.SaveToFile(ApplicationDir + 'clientstats', Cmd2ID2CRCLC);
        Tmp_Pos := 1495;
        StrHash_SaveToFileSorted(DB_Friends, ApplicationDir + 'friends');
        SaveChannels(ApplicationDir + 'channels');
        Tmp_Pos := 1496;
        StrHash_SaveToFile(DB_Motd, ApplicationDir + 'motd');
        // StrHash_SaveToFile(DB_MsgServ, ApplicationDir + 'dengon');
        MataParaEncrypt(DB_MsgServ, 'himitsu', ApplicationDir + 'dengon');
        StrHash_SaveToFile(Cons.Hotlist, ApplicationDir + 'hotlist');
        Tmp_Pos := 1497;
        StrHash_SaveToFile(Cons.Ignored, ApplicationDir + 'ignored');
        SaveBlocks;
        SaveServers;
        Tmp_Pos := 1498;
      end;
    MSG_CMD_RESETLOG:
      begin
        Tmp_Pos := 1499;
        ShortDateFormat := 'yyyymmdd';
        // LogFileName := ApplicationDir + 'server-' + DateToStr(Now) + '.log';
        LogFileName := Log_Folder + 'server-' + DateToStr(Now) + '.log';
        ShortDateFormat := 'yyyy/mm/dd';
        try
          if Log_File <> nil then
            Log_File.Free;
          Log_File := nil;
        except
        end;
        try
          Log_File := TFileStream.Create(LogFileName, fmCreate);
          Log_File.Free;
        except
        end;
        Log_File := nil;
        Tmp_Pos := 1500;
        try
          if Log_To_File then
            Log_File := TFileStream.Create(LogFileName, fmOpenWrite or
              fmShareDenyWrite);
        except
          Log_File := nil;
          DebugLog('Error: Cannot reset File ' + LogFileName);
        end;
        // Resetting debug File
        try
          if Debug_File <> nil then
            Debug_File.Free;
          Debug_File := nil;
        except
        end;
        try
          Debug_File := TFileStream.Create(ApplicationDir + 'debug.log',
            fmCreate);
          Debug_File.Free;
        except
        end;
        Debug_File := nil;
        try
          // if Log_To_File then
          Debug_File := TFileStream.Create(ApplicationDir + 'debug.log',
            fmOpenWrite or fmShareDenyWrite);
        except
          Debug_File := nil;
          DebugLog('Error: Cannot reset File "Debug.Log"');
        end;
        Tmp_Pos := 1501;
      end;
    MSG_CMD_RELOADCHMOTD:
      begin
        Tmp_Pos := 1502;
        Ch := FindChannel(DCmd.Cmd1);
        Tmp_Pos := 1503;
        if Ch <> nil then
        begin
          if not StrHash_LoadFromFile(Ch.Motd, ApplicationDir + 'chmotd.' +
            Ch.Channel) then
            Ch.DefaultMotd;
        end;
        Tmp_Pos := 1504;
      end;
    MSG_CMD_REFRESHTYPES:
      begin
        Tmp_Pos := 1505;
        SplitString(LowerCase(Ext_Mp3), Ext_Mp3_List);
        SplitString(LowerCase(Ext_Audio), Ext_Audio_List);
        SplitString(LowerCase(Ext_Video), Ext_Video_List);
        SplitString(LowerCase(Ext_Text), Ext_Text_List);
        SplitString(LowerCase(Ext_Image), Ext_Image_List);
        SplitString(LowerCase(Ext_App), Ext_App_List);
        SplitString(LowerCase(Ext_Cd), Ext_Cd_List);
        SplitString(AnsiLowerCase(Fakeext), Fakeext_List);
        Tmp_Pos := 1506;
      end;
    MSG_CMD_GETMODE: if Running then
      begin
        Tmp_Pos := 1507;
        SlavaNapWindow.Btn_Log_Mode.Enabled := True;
        SlavaNapMode.ShowForm;
        Tmp_Pos := 1508;
      end;
    MSG_CMD_MOTDCHANGE: StrHash_LoadFromFile(DB_Motd, ApplicationDir + 'motd');
    MSG_CMD_LIStrEGISTERED: ConsoleListRegistered;
    MSG_CMD_LISTUSERS: ConsoleListUsers;
    MSG_CMD_LISTSERVERS: ConsoleListServers;
    MSG_CMD_LISTCHANNELS: ConsoleListChannels;
    MSG_CMD_LISTBANS: ConsoleListBans;
    MSG_CMD_LISTHOTLIST: ConsoleListHotlist;
    MSG_CMD_REFRESHLISTS: ConsoleRefreshLists(DCmd.Cmd1 = '');
    MSG_CMD_SETNAPIGATORPASS: Napigator_Password := DCmd.Cmd1;
    MSG_CMD_SETDAGSTAPASS: Dagsta_Password := DCmd.Cmd1;
    MSG_CMD_CHANNELPROPS: SlavaNapChannelAttr.ShowChannel(DCmd.Cmd1);
    MSG_CMD_WALLOP: Wallop(MSG_SERVER_NOSUCH, wallopServer, DCmd.Cmd1, True);
    MSG_CMD_ADDSERVER: ConsoleAddServer(DCmd.Cmd1);
    MSG_CMD_SERVERPROPS: ConsoleServerProps(DCmd.Cmd1);
    MSG_CMD_UPDATESERVERPROPS: ConsoleUpdateServerProps(DCmd.Cmd1);
    MSG_CLIENT_PRIVMSG:
      begin
        Tmp_Pos := 1509;
        GCmd.Id := DCmd.Id1;
        GCmd.Cmd := DCmd.Cmd1;
        ProcessCommand(Cons, queryNormal);
        SendPrivateMyMessage(DCmd.Cmd1);
        Tmp_Pos := 1510;
      end;
    MSG_CMD_SETCOMPRESS: ConsoleSetCompress(DCmd.Cmd1);
    MSG_CMD_SETSTARTUP: ConsoleSetStartup(DCmd.Cmd1);
    MSG_CMD_SAVESHARED: ConsoleSaveShared;
  else
    GCmd.Id := DCmd.Id1;
    GCmd.Cmd := DCmd.Cmd1;
    Tmp_Pos := 1511;
    ProcessCommand(Cons, queryNormal);
  end;
  Tmp_Pos := 1512;
end;

procedure TMainThread.CreateSockets;
var
  I: Integer;
begin
  DB_Closed := TNapCmd2List.Create;
  Quiet_Listen := False;
  Tmp_Pos := 1513;
  for I := 0 to MAX_LISTEN_SOCKET do
    if Server_Port[I] <> 0 then
    try
      Tmp_Pos := 1514;
      Server_Socket[I] := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM),
        IPPROTO_TCP);
      Inc(Sockets_Count);
      Tmp_Pos := 1515;
      if not Listen(Server_Socket[I], Server_Port[I]) then
        if Server_Socket[I] <> INVALID_SOCKET then
        begin
          Tmp_Pos := 1516;
          SynSock.ShutDown(Server_Socket[I], SD_BOTH);
          SynSock.CloseSocket(Server_Socket[I]);
          Server_Socket[I] := INVALID_SOCKET;
          Tmp_Pos := 1517;
          Dec(Sockets_Count);
        end;
      Tmp_Pos := 1518;
      Synchronize(SyncLog);
    except
      on E: Exception do
        DebugLog('Exception in TMainThread::CreateSockets (Pos=' +
          IntToStr(Tmp_Pos) + ') : ' + E.Message);
    end;
  Tmp_Pos := 12262;
  if Enable_TrapPort then
    for I := 0 to MAX_LISTEN_TRAPSOCKET do
      if Trap_Port[I] <> 0 then
      try
        Trap_Socket[I] := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM),
          IPPROTO_TCP);
        Inc(Sockets_Count);
        if not Listen(Trap_Socket[I], Trap_Port[I]) then
          if Trap_Socket[I] <> INVALID_SOCKET then
          begin
            SynSock.ShutDown(Trap_Socket[I], SD_BOTH);
            SynSock.CloseSocket(Trap_Socket[I]);
            Trap_Socket[I] := INVALID_SOCKET;
            Dec(Sockets_Count);
          end;
        Synchronize(SyncLog);
      except
        on E: Exception do
          DebugLog('Exception in TMainThread::CreateSockets (Pos=' +
            IntToStr(Tmp_Pos) + ') : ' + E.Message);
      end;
  if Old_Report_enableD then
  try
    Tmp_Pos := 1519;
    Old_Report_Socket := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM),
      IPPROTO_TCP);
    Inc(Sockets_Count);
    Tmp_Pos := 1520;
    if not Listen(Old_Report_Socket, Old_Report_Port) then
      if Old_Report_Socket <> INVALID_SOCKET then
      begin
        Tmp_Pos := 1521;
        SynSock.ShutDown(Old_Report_Socket, SD_BOTH);
        SynSock.CloseSocket(Old_Report_Socket);
        Old_Report_Socket := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    Tmp_Pos := 1522;
    Synchronize(SyncLog);
  except
    on E: Exception do
      DebugLog('Exception in TMainThread::CreateSockets (2) (Pos=' +
        IntToStr(Tmp_Pos) + ') : ' + E.Message);
  end;
  if New_Report_Enabled then
  try
    Tmp_Pos := 1523;
    New_Report_Socket := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM),
      IPPROTO_TCP);
    Inc(Sockets_Count);
    Tmp_Pos := 1524;
    if not Listen(New_Report_Socket, New_Report_Port) then
      if New_Report_Socket <> INVALID_SOCKET then
      begin
        Tmp_Pos := 1525;
        SynSock.ShutDown(New_Report_Socket, SD_BOTH);
        SynSock.CloseSocket(New_Report_Socket);
        New_Report_Socket := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    Tmp_Pos := 1526;
    Synchronize(SyncLog);
  except
    on E: Exception do
      DebugLog('Exception in TMainThread::CreateSockets (3) (Pos=' +
        IntToStr(Tmp_Pos) + ') : ' + E.Message);
  end;
  {if Meta_Enabled then
  try
    Tmp_Pos := 1527;
    Meta_Socket := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM), IPPROTO_TCP);
    Inc(Sockets_Count);
    if not Listen(Meta_Socket, Meta_Port) then
      if Meta_Socket <> INVALID_SOCKET then
      begin
        Tmp_Pos := 1528;
        SynSock.ShutDown(Meta_Socket, SD_BOTH);
        SynSock.CloseSocket(Meta_Socket);
        Meta_Socket := INVALID_SOCKET;
        Dec(Sockets_Count);
      end;
    Tmp_Pos := 1529;
    Synchronize(SyncLog);
  except
    on E:Exception do
      DebugLog('Exception in TMainThread::CreateSockets (4) (Pos=' +
        IntToStr(Tmp_Pos) + ') : ' + E.Message);
  end;}
  if Enable_Metaserver then
  try
    Tmp_Pos := 1527;
    SetLength(Metasocket_List, Length(MetaPort_List));
    for I := 0 to Length(Metasocket_List) - 1 do
    begin
      Metasocket_List[I] := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM),
        IPPROTO_TCP);
      Inc(Sockets_Count);
      if not Listen(Metasocket_List[I], MetaPort_List[I]) then
        if Metasocket_List[I] <> INVALID_SOCKET then
        begin
          Tmp_Pos := 1528;
          SynSock.ShutDown(Metasocket_List[I], SD_BOTH);
          SynSock.CloseSocket(Metasocket_List[I]);
          Metasocket_List[I] := INVALID_SOCKET;
          Dec(Sockets_Count);
        end;
      Tmp_Pos := 1529;
      Synchronize(SyncLog);
    end;
  except
    on E: Exception do
      DebugLog('Exception in TMainThread::CreateSockets (4) (Pos=' +
        IntToStr(Tmp_Pos) + ') : ' + E.Message);
  end;
  Tmp_Pos := 1530;
  Synchronize(SyncLog);
  Quiet_Listen := True;
  Tmp_Pos := 1531;
end;

function TMainThread.Listen(var Socket: HSocket; Port: Integer): Boolean;
var
  Last_Error: Integer;
begin
  Tmp_Pos := 1531;
  if Socket = INVALID_SOCKET then
  begin
    Socket := SynSock.Socket(PF_INET, Integer(SOCK_StrEAM), IPPROTO_TCP);
    Inc(Sockets_Count);
  end;
  // TCPSocket_SetLinger(Socket, True, 0);
  TCPSocket_Bind(Socket, Listen_Interface, IntToStr(Port));
  Last_Error := TCPSocket_SockCheck(SynSock.Listen(Socket, SOMAXCONN));
  Tmp_Pos := 1532;
  if Last_Error = 0 then
  begin
    if not (Quiet_Listen) then
      if (Socket = New_Report_Socket) or (Socket = Old_Report_Socket) then
        Log(slText, GetLangT(LNG_SERVER_LISTENSTATS, Port))
      else
        Log(slText, GetLangT(LNG_SERVER_LISTEN, Port));
    TCPSocket_Block(Socket, False);
    Result := True;
  end
  else
  begin
    Log(slError, GetLangT(LNG_SERVER_LISTENERR, Port));
    Result := False;
  end;
  Tmp_Pos := 1533;
end;

procedure TMainThread.Accept;
var
  I, Last_Error: Integer;
begin
  try
    Tmp_Pos := 1534;
    if Old_Report_Socket <> INVALID_SOCKET then
      while TCPSocket_CanRead(Old_Report_sockeT, 0, Last_Error) do
        AcceptOldReport;
    if New_Report_Socket <> INVALID_SOCKET then
      while TCPSocket_CanRead(New_Report_Socket, 0, Last_Error) do
        AcceptNewReport;
    {if Meta_Socket <> INVALID_SOCKET then
      while TCPSocket_CanRead(Meta_Socket, 0, Last_Error) do
        AcceptMeta;}
    for I := 0 to Length(Metasocket_List) - 1 do
      if Metasocket_List[I] <> INVALID_SOCKET then
        while TCPSocket_CanRead(Metasocket_List[I], 0, Last_Error) do
          AcceptMeta(Metasocket_List[I]);
{$I CheckSync.pas}
    Tmp_Pos := 1535;
    for I := 0 to MAX_LISTEN_SOCKET do
      if Server_Socket[I] <> INVALID_SOCKET then
        while TCPSocket_CanRead(Server_Socket[I], 0, Last_Error) do
        begin
          Accept(Server_Socket[I]);
{$I CheckSync.pas}
        end;
    if Enable_TrapPort then
      for I := 0 to MAX_LISTEN_TRAPSOCKET do
        if Trap_Socket[I] <> INVALID_SOCKET then
          while TCPSocket_CanRead(Trap_Socket[I], 0, Last_Error) do
          begin
            Accept(Trap_Socket[I]);
{$I CheckSync.pas}
          end;
  except
    DebugLog('Exception in Accept 1. Pos=' + IntToStr(Tmp_Pos));
  end;
  Tmp_Pos := 1536;
end;

procedure TMainThread.Accept(Server: HSocket);
var
  User: TLocalUser;
  H: HSocket;
  I: Integer;
  Local_Ip: Cardinal;
  Sin: TSockAddrIn;
begin
  I := 0;
  try
    H := SynSock.Accept(Server, nil, nil);
    I := 1;
    if H = SOCKET_ERROR then Exit;
    if H = INVALID_SOCKET then Exit;
    Inc(Sockets_Count);
    I := 2;
    //   Sin := TCPSocket_GetRemoteSin(H);
    //   Remote_Ip := Decode_Ip(Sin.Sin_Addr.S_Addr);
    Sin := TCPSocket_GetLocalSin(H);
    Local_Ip := Sin.Sin_Addr.S_Addr;
    I := 3;
    User := CreateLocalUser;
    User.Socket := H;
    if not Sockets_Users_default then
    begin
      TCPSocket_SetSizeRecvBuffer(H, Sockets_Users_Recv);
      TCPSocket_SetSizeSendBuffer(H, Sockets_Users_Send);
    end;
    I := 4;
    TCPSocket_Block(H, False);
    TCPSocket_KeepAlive(H, True);
    I := 6;
    if Cons.Data^.Ip = 0 then
    begin
      I := 8;
      Cons.Data^.Ip := Local_Ip;
      I := 9;
    end;
    I := 10;
    DB_Local.Add(User);
    I := 11;
{$I CheckSync.pas}
  except
    DebugLog('Exception in Accept 2.  I=' + IntToStr(I));
  end;
end;

procedure TMainThread.AcceptOldReport;
var
  User: TLocalUser;
  H: TSocket;
  I: Integer;
  Str: string;
  Sin: TSockAddrIn;
begin
  I := 0;
  try
    H := SynSock.Accept(Old_Report_Socket, nil, nil);
    I := 1;
    if H = SOCKET_ERROR then Exit;
    if H = INVALID_SOCKET then Exit;
    Inc(Sockets_Count);
    I := 2;
    User := CreateLocalUser;
    I := 3;
    User.Socket := H;
    I := 5;
    TCPSocket_Block(H, False);
    I := 6;
    Sin := TCPSocket_GetLocalSin(H);
    I := 7;
    {   if Cons.Data^.Ip = 0 then
       begin
        I := 8;
        Cons.Data^.Ip := Sin.Sin_Addr.S_Addr;
        I := 9;
       end;}
    I := 10;
    DB_Local.Add(User);
    I := 11;
    User.LocalState := User.LocalState + [locWriteOnly];
    I := 12;
    Str := IntToStr(Total_Users) + ' ' + IntToStr(Total_Files) + ' 0.00 ' +
      IntToStr(Total_Bytes) + ' 0';
    I := 13;
    User.WriteData(Str);
  except
    DebugLog('Exception in AcceptOldReport.  I=' + IntToStr(I));
  end;
end;

procedure TMainThread.AcceptNewReport;
var
  User: TLocalUser;
  H: TSocket;
  I, J: Integer;
  Str, Str2: string;
  Srv: TServer;
  List: TMyStringList;
  Sin: TSockAddrIn;
begin
  I := 0;
  try
    H := SynSock.Accept(New_Report_Socket, nil, nil);
    I := 1;
    if H = SOCKET_ERROR then Exit;
    if H = INVALID_SOCKET then Exit;
    Inc(Sockets_Count);
    I := 2;
    User := CreateLocalUser;
    I := 4;
    User.Socket := H;
    I := 5;
    TCPSocket_Block(H, False);
    I := 6;
    Sin := TCPSocket_GetLocalSin(H);
    I := 7;
    {   if Cons.Data^.Ip = 0 then
       begin
        I := 8;
        Cons.Data^.Ip := Sin.Sin_Addr.S_Addr;
        I := 9;
       end;}
    I := 10;
    DB_Local.Add(User);
    I := 11;
    User.LocalState := User.LocalState + [locWriteOnly];
    I := 12;
    List := CreateStringList;
    if (Max_usErs > 9) or (not New_Report_Hide_Hub) then
    begin
      if True_Stats = True then
        Str2 := ServerName_T
      else
        Str2 := ServerAlias;
      Str := Str2 + ' ' + IntToStr(Napigator_MyPort) + ' ' +
        IntToStr(Local_Users) + ' ' + IntToStr(Max_Users) + ' ' +
        IntToStr(Local_Files) + ' ' + IntToStr(Local_Bytes div GigaByte) + ' ' +
        Cons.Nick;
      List.Add(Str);
    end;
    for J := 0 to DB_Servers.Count - 1 do
    begin
      Str2 := '';
      Srv := DB_Servers.Items[J];
      if Srv.Logged then
        if (Srv.Max_Users > 9) or (not New_Report_Hide_Hub) then
        begin
          if Srv.TrueStats then
            Str2 := GetServerName(Srv)
          else
            Str2 := GetServerAlias(Srv);
          Str := Str2 + ' ' + IntToStr(Srv.Port) + ' ' + IntToStr(Srv.Num_Users)
            + ' ' + IntToStr(Srv.Max_Users) + ' ' + IntToStr(Srv.Num_Files) + ' '
            + IntToStr(Srv.Num_Bytes div GigaByte) + ' ' + Srv.Console;
          List.Add(Str);
        end;
    end;
    List.Sort;
    Str := IntToStr(List.Count) + ' ' + IntToStr(Total_Users) + ' ' +
      IntToStr(Total_Users_Limit) + ' ' + IntToStr(Total_Files) + ' ' +
      IntToStr(Total_Bytes div GigaByte);
    List.Insert(0, Str);
    I := 13;
    User.WriteData(List.Text);
    I := 14;
    FreeStringList(List);
  except
    DebugLog('Exception in AcceptNewReport.  I=' + IntToStr(I));
  end;
end;

procedure TMainThread.AcceptMeta(Server: HSocket);
var
  H: TSocket;
  J: Integer;
  Str: string;
  Srv, Srv1: TServer;
  List: TMyStringList;
  Diff: Integer;
  HostPort: string;
begin
  try
    Tmp_Pos := 1537;
    // H := SynSock.Accept(Meta_Socket, nil, nil);
    H := SynSock.Accept(Server, nil, nil);
    if (H = SOCKET_ERROR) or (H = INVALID_SOCKET) then Exit;
    Inc(Sockets_Count);
    Diff := 0;
    if Max_Users > Local_Users then
      Diff := Max_Users - Local_Users;
    Srv1 := nil;
    Tmp_Pos := 1538;
    for J := 0 to DB_Servers.Count - 1 do
    begin
      Srv := DB_Servers.Items[J];
      if Srv.Logged and
        (Srv.Max_Users > Srv.Num_Users) and
        ((Srv.Max_Users - Srv.Num_Users) > Diff) then
      begin
        HostPort := LowerCase(Srv.Host) + ':' + IntToStr(Srv.Port);
        if Redirected_Servers.FindItem(Integer(False), HostPort) <> -1 then
          Continue;
        Diff := Srv.Max_Users - Srv.Num_Users;
        Srv1 := Srv;
      end;
    end;
    Tmp_Pos := 1539;
    Str := '';
    if Srv1 <> nil then
    begin
      Inc(Srv1.Redirects);
      List := TMyStringList.Create;
      ResolveNameToIp(Srv1.Host, List);
      if List.Count > 0 then
        Str := List.Strings[0] + ':' + IntToStr(Srv1.Port);
      List.Free;
    end;
    Tmp_Pos := 1540;
    if Str = '' then
    begin
      List := TMyStringList.Create;
      ResolveNameToIp(ServerName_T, List);
      if List.Count > 0 then
        Str := List.Strings[0] + ':' + IntToStr(Server_Port[0])
      else
        Str := '127.0.0.1:8888';
      List.Free;
    end;
    Tmp_Pos := 1541;
    Str := Str + #13;
    SynSock.Send(H, Str[1], Length(Str), 0);
    SynSock.ShutDown(H, SD_BOTH);
    SynSock.CloseSocket(H);
    Dec(Sockets_Count);
    Tmp_Pos := 1542;
  except
    DebugLog('Exception in AcceptMeta. Pos=' + IntToStr(Tmp_Pos));
  end;
end;

procedure TMainThread.SendWebPage(User: TLocalUser);
begin
  Tmp_Pos := 1543;
  User.LocalState := User.LocalState + [locWriteOnly];
  if Redirect_Url = '' then
  begin
    Tmp_Pos := 1544;
    User.WriteData('HTTP/1.0 200 OK'#13#10'Server: Apache/1.3.22'#13#10'Connection: close'#13#10);
    User.WriteData('Content-Type: text/html'#13#10#13#10);
    User.WriteData('<HTML><HEAD>'#13#10 +
      '<TITLE>403 Forbidden</TITLE>'#13#10 +
      '</HEAD><BODY>'#13#10 +
      '<H1>Forbidden</H1>'#13#10 +
      'You don''t have permission to access this server.<P>'#13#10 +
      '<HR>'#13#10 +
      '<ADDRESS>Apache/1.3.22 Server at localhost Port ' +
        IntToStr(Server_Port[0]) + '</ADDRESS>'#13#10 +
      '</BODY></HTML>');
  end
  else
  begin
    Tmp_Pos := 1545;
    User.WriteData('HTTP/1.0 301 Moved Permanently'#13#10'Server: Apache/1.3.22'#13#10'Connection: close'#13#10);
    User.WriteData('Location: ' + Redirect_Url + #13#10#13#10);
    {User.WriteData('Content-Type: text/html'#13#10#13#10);
    User.WriteData('<HTML><HEAD>'#13#10+
          '<TITLE>Moved</TITLE>'#13#10+
          '</HEAD><BODY>'#13#10+
          'This site moved to <a href="' + Redirect_Url + '">' + Redirect_Url + '</a>.' +
          '</BODY></HTML>');}
  end;
  Tmp_Pos := 1546;
end;

procedure TMainThread.CheckBots;
var
  Str: string;
  Loc: TLocalUser;
  I, J, K: Integer;
begin
  Tmp_Pos := 1547;
  if (Current_Time - Last_Announcement) > (Ann_Delay * 1000) then
  begin // announcements bot
    Last_Announcement := Current_Time;
    if Ann_Enabled then
    begin
      Tmp_Pos := 1548;
      J := 0;
      for I := 0 to Max_Announcement do
        if Ann_Messages[I] <> '' then
          Inc(J);
      if J > 0 then
      begin
        Tmp_Pos := 1549;
        repeat
          K := Random(J);
          if K = J then
            K := 0;
        until (Ann_Messages[K] <> '') and ((Ann_Messages[K])[1] <> '#');
        Str := Ann_Messages[K];
        Tmp_Pos := 1550;
        for I := 0 to DB_Local.Count - 1 do
        begin
          Loc := DB_Local.Items[I];
          if ((I mod 20) = 0) then
          begin
{$I CheckSync.pas}
          end;
          if Loc.Logged then
            if not (userHideAnnouncements in Loc.Data^.State) then
              Loc.Exec(MSG_SERVER_ANNOUNCE, Ann_User + ' ' + Str);
        end;
      end;
    end;
  end;
  Tmp_Pos := 1551;
end;

procedure TMainThread.CheckMinShare;
var
  I, J, Num: Integer;
  Loc: TLocalUser;
  T: Cardinal;
begin
  Tmp_Pos := 1552;
  if MinShare_Fullonly and (Local_Users < (Max_Users - 5)) then Exit;
  if (MinShare < 1) and (MinShare_Size < 1) then Exit;
  T := Current_Time - MinShare_Delay;
  Num := 0;
  Tmp_Pos := 1553;
  for I := 0 to DB_Local.Count - 1 do
  begin
    Loc := DB_Local.Items[I];
    if ((I mod 30) = 0) then
    begin
{$I CheckSync.pas}
    end;
    Tmp_Pos := 1554;
    if Loc.Logged then
      if Loc.Last_Seen < T then
        if Loc.Level < napUserModerator then
          if MinShare_Kickchat or (not (userChatting in Loc.Data^.State)) then
          begin
            J := 0;
            if (MinShare_Size > 0) and (Loc.Shared_Size < MinShare_Size) then
              J := 1;
            if (MinShare > 0) and (Loc.Data^.Shared < MinShare) then
              J := 2;
            if J <> 0 then
              if not StrHash_FindString(DB_Friends, Loc.Nick, True) then
                // if not StrHash_FindString(DB_Friends, Decode_Ip(Loc.Ip), False) then
              begin
                Tmp_Pos := 1555;
                if J = 1 then
                begin // minshare by size
                  Loc.Exec(MSG_SERVER_NOSUCH, GetLangT(LNG_MINSHARE3,
                    MinShare_Size div MegaByte, Loc.Shared_Size div MegaByte));
                  if MinShare_Ban then
                  begin
                    if MinShare_Banip then
                      BanUser(Decode_Ip(Loc.Ip), ServerAlias, MinShare_Bantime,
                        GetLangT(LNG_MINSHARE_REASON2, Loc.Shared_Size div
                        MegaByte, ServerAlias) + ': ' + Loc.Nick, True)
                    else
                      BanUser(Loc.Nick, ServerAlias, MinShare_Bantime,
                        GetLangT(LNG_MINSHARE_REASON2, Loc.Shared_Size div
                        MegaByte, ServerAlias), True);
                  end;
                  Tmp_Pos := 1556;
                  AddReconnector(Decode_Ip(Loc.Ip));
                  DisconnectUser(Loc, '', GetLangT(LNG_MINSHARE4, Loc.Nick,
                    Loc.Software, Loc.Shared_Size div MegaByte), 'CheckMinShare',
                    False);
                end
                else
                begin // minshare by number of files
                  Tmp_Pos := 1557;
                  Loc.Exec(MSG_SERVER_NOSUCH, GetLangT(LNG_MINSHARE, MinShare,
                    Loc.Data^.Shared));
                  if MinShare_Ban then
                  begin
                    if MinShare_Banip then
                      BanUser(Decode_Ip(Loc.Ip), ServerAlias, MinShare_Bantime,
                        GetLangT(LNG_MINSHARE_REASON, Loc.Data^.Shared,
                        ServerAlias) + ': ' + Loc.Nick, True)
                    else
                      BanUser(Loc.Nick, ServerAlias, MinShare_Bantime,
                        GetLangT(LNG_MINSHARE_REASON, Loc.Data^.Shared,
                        ServerAlias), True);
                  end;
                  Tmp_Pos := 1558;
                  AddReconnector(Decode_Ip(Loc.Ip));
                  DisconnectUser(Loc, '', GetLangT(LNG_MINSHARE2, Loc.Nick,
                    Loc.Software, Loc.Data^.Shared), 'CheckMinShare', False);
                end;
                Inc(Num);
                if MinShare_Fullonly and MinShare_Only10 then
                  if Num >= 10 then Exit;
                Tmp_Pos := 1559;
              end;
          end;
  end;
  Tmp_Pos := 1560;
end;

procedure TMainThread.Check180;
var
  Loc: TLocalUser;
  I: Integer;
begin
  Tmp_Pos := 1561;
  if (Current_Time - Last_Period180) < 180000 then Exit;
  Inc(Last_Period180, 180000);
  DB_Whowas.Clear;
  DB_Reconnect.Clear;
  ResetWantQueueControl;
  ResetDLRequestControl;
  Tmp_Pos := 1562;
  if Num_Servers > 0 then
    for I := 0 to DB_Local.Count - 1 do
    begin
      Loc := DB_Local.Items[I];
      if ((I mod 50) = 0) then
      begin
{$I CheckSync.pas}
      end;
      Tmp_Pos := 1563;
      if Loc.Logged then
      begin
        if locNeedsUpdate in Loc.LocalState then
          if Loc.Data <> nil then
            UpdateUser(Loc.Data);
        Loc.LocalState := Loc.LocalState - [locNeedsUpdate];
      end;
    end;
  Tmp_Pos := 1564;
  ExpireLists;
  Tmp_Pos := 1565;
end;

procedure TMainThread.Check30;
var
  I: Integer;
  Srv: TServer;
  Linking: Boolean;
begin
  Tmp_Pos := 1566;
  if (Current_Time - Last_Period30) < 30000 then Exit;
  Inc(Last_Period30, 30000);
  CheckMinShare;
  CheckBlockedShare;
  CountStats;
  Tmp_Pos := 1567;
  if (not AutoLink_Only1) or (Num_Servers = 0) then
  begin
    Linking := False;
    for I := 0 to DB_Servers.Count - 1 do
    begin
      Srv := DB_Servers.Items[I];
      // if TServer(DB_Servers.Items[I]).Thread <> nil then
      if Srv.Thread <> nil then
        Linking := True
      else if (Current_Time - Srv.Login_Start) < 30000 then
        Linking := True;
    end;
    for I := 0 to DB_Servers.Count - 1 do
      if not Linking then
      begin
        Srv := DB_Servers.Items[I];
        if Srv.Connected = conNotConnected then
          if Srv.Relink > 0 then
            if (Current_Time - Srv.Login_Start) > Srv.Relink then
            begin
              Tmp_Pos := 1568;
              Handler_ServerConnect(Srv, True);
              Tmp_Pos := 1569;
              Linking := True;
            end;
      end;
  end;
  Tmp_Pos := 1571;
  Check180;
  Tmp_Pos := 1572;
end;

procedure TMainThread.Check60;
var
  Str: string;
  List: TMyStringList;
  I: Integer;
  F: TFileStream;
  Srv: TServer;
  Loc: TLocalUser;
begin
  Tmp_Pos := 1573;
  if (Current_Time - Last_Period) < 60000 then Exit;
  Inc(Last_Period, 60000);
  Users_Per_Minute := 0;
  DB_Bans.Expire;
  CountStats;
  Tmp_Pos := 1574;
  WriteAllServers(MSG_SERVER_STATS, '', IntToStr(Local_Users) + ' ' +
    IntToStr(Local_Files) + ' ' + IntToStr(Local_Bytes) + ' ' +
    IntToStr(Max_Users));
{$I CheckSync.pas}
  ResetSearchControl;
  Tmp_Pos := 1575;
  // if Mx_UsePing then
  if Blocked_Clients[softWinMXHidden] then
    for I := 0 to DB_Local.Count - 1 do
    begin
      Loc := DB_Local.Items[I];
      if (I mod 20) = 0 then
      begin
{$I CheckSync.pas}
      end;
      if (Loc.Shared <> nil) and
        (Loc.Shared.ReIndex = True) then
        Loc.Shared.DoReindex;
      if Loc.Logged and (not (locPingable in Loc.LocalState))
        and (Loc.SoftwareId <> softWinMXNormal) and (Loc.SoftwareId <>
          softWinMXJap) then
        if (Current_Time - WINMX_DETECT_TIME) > Loc.Last_Seen then
          CheckWinMX(Loc);
    end;
  KillIdleUser;
  Tmp_Pos := 1576;
  Linking := False;
  for I := 0 to DB_Servers.Count - 1 do
  begin
    Srv := DB_Servers.Items[I];
    if Srv.Connected = conConnecting then
      Linking := True
    else if (Srv.Connected = conConnected) and (Srv.Logged = False) then
      Linking := True;
  end;
  Tmp_Pos := 1577;
  Inc(Total_Bytes_in, Bytes_in);
  Last_Bytes_in := Bytes_in;
  Bytes_in := 0;
  Inc(Total_Bytes_Out, Bytes_Out);
  Last_Bytes_Out := Bytes_Out;
  Bytes_Out := 0;
  Inc(Total_Searches, Num_Searches);
  Last_Searches := Num_Searches;
  Num_Searches := 0;
  Inc(Total_Browses, Num_Browses);
  Last_Browses := Num_Browses;
  Num_Browses := 0;
  Inc(Total_Transfers, Num_Transfers);
  Last_Transfers := Num_Transfers;
  Num_Transfers := 0;
  Last_Login := Num_Login;
  Num_Login := 0;
  Last_Rejects := Num_Rejects;
  Num_Rejects := 0;
  if not Save_Stats then Exit;
  try
    if not FileExists(ApplicationDir + 'serverstats') then
      F := TFileStream.Create(ApplicationDir + 'serverstats', fmCreate)
    else
      F := TFileStream.Create(ApplicationDir + 'serverstats', fmOpenWrite or
        fmShareDenyWrite);
    F.Seek(0, soFromEnd);
  except
    DebugLog('Error: Cannot open File "Serverstats"');
    Exit;
  end;
  Tmp_Pos := 1578;
  List := CreateStringList;
  List.Add(DateToStr(Now)); // Date
  List.Add(TimeToStr(Now)); // Time
  List.Add(IntToStr(Current_Time_T - Start_Time_T)); // Time online in seconds
  List.Add(IntToStr(Local_Users)); // Local Users
  List.Add(IntToStr(Local_Files)); // Local Files
  List.Add(IntToStr(Local_Bytes)); // Local Size
  List.Add(IntToStr(Total_Users)); // Total users
  List.Add(IntToStr(Total_Files)); // Total files
  List.Add(IntToStr(Total_Bytes)); // Total bytes
  List.Add(IntToStr(Last_Login)); // Logins for The last Minute
  List.Add(IntToStr(Last_Rejects)); // Rejects for The last Minute
  List.Add(IntToStr(Last_Searches)); // Searches for The last Minute
  List.Add(IntToStr(Last_Transfers)); // Transfers for The last Minute
  List.Add(IntToStr(AllocMemSize)); // Memory used in bytes
  List.Add(IntToStr(Sockets_Count)); // Used sockets
  List.Add(IntToStr(Last_Bytes_in)); // Bytes in
  List.Add(IntToStr(Last_Bytes_Out)); // Bytes out
  List.Add(IntToStr(Num_Servers)); // Linked servers
  Str := List.Strings[0];
  for I := 1 to List.Count - 1 do
    Str := Str + ',' + Trim(List.Strings[I]);
  Str := Str + #10;
  Tmp_Pos := 1579;
  FreeStringList(List);
  try
    F.write(Str[1], Length(Str));
    F.Free;
  except
  end;
  Tmp_Pos := 1580;
end;

procedure TMainThread.CheckServers;
var
  I: Integer;
  Srv: TServer;
begin
  Tmp_Pos := 1581;
  for I := 0 to DB_Servers.Count - 1 do
    if TServer(DB_Servers.ITems[I]).Connected = conConnected then
    begin
      Tmp_Pos := 1582;
{$I CheckSync.pas}
      Srv := DB_Servers.Items[I];
      Num_Processed := 0;
      // Send
      Srv.Compile;
      Srv.Flush;
      // Receive
      Srv.Receive(0);
      // Send
      Srv.Compile;
      Srv.Flush;
      Tmp_Pos := 1583;
      if (Srv.Connected = conConnected) and (Srv.Logged = False) then
        if (Current_Time - Srv.Login_Start) > MAX_LOGIN_TIMEOUT then
        begin
          DisconnectServer(Srv, False, False, 'CheckServers');
          Wallop(MSG_SERVER_NOSUCH, wallopServer, GetLangT(LNG_LINKERRLOGIN,
            Srv.Host), True);
        end;
    end;
  Tmp_Pos := 1584;
end;

procedure TMainThread.CheckTimeouts;
var
  I: Integer;
  User: TLocalUser;
begin
  try
    Tmp_Pos := 1585;
    for I := DB_Local.Count - 1 downto 0 do
    begin
      Tmp_Pos := 1586;
      User := DB_Local.Items[I];
      if ((I mod 30) = 0) then
      begin
{$I CheckSync.pas}
      end;
      Tmp_Pos := 1587;
      if User <> Cons then
      begin
        if User.Socket = INVALID_SOCKET then
        try
          FreeLocalUser(User);
          DB_Local.Delete(I);
        except
          on E: Exception do
            DebugLog('Exception in TMainThread::CheckData (1) : ' + E.Message);
        end
        else if not User.Logged then
          if (Current_Time - User.Last_Seen) > TimeOut_Login then
          try
            FreeLocalUser(User);
            DB_Local.Delete(I);
          except
            on E: Exception do
              DebugLog('Exception in TMainThread::CheckData (2) : ' +
                E.Message);
          end;
      end;
    end;
  except
    DebugLog('Exception in CheckTimeouts. Pos=' + IntToStr(Tmp_Pos));
  end;
  Tmp_Pos := 1588;
end;

procedure TMainThread.ReceiveData;
var
  I: Integer;
  User: TLocalUser;
  Str: string;
begin
  try
    for I := 0 to DB_Local.Count - 1 do
    begin
      if (I mod 20) = 10 then
      begin
{$I CheckSync.pas}
      end;
      if (I mod 100) = 30 then
        CheckServers;
      User := DB_Local.Items[I];
      if User <> Cons then
      begin
        if User.Last_Seen <> 0 then
          ReceiveData(User, 0, 0);
        if not Running then Exit;
      end;
    end;
    if (Current_Time - Last_Stats) > Stats_Delay then
    begin
      Last_Stats := Current_Time;
      CountStats;
      Str := IntToStr(Total_Users) + ' ' + IntToStr(Total_Files) + ' ' +
        IntToStr(Total_Bytes div 1073741824);
      for I := 0 to DB_Local.Count - 1 do
      begin
        if (I mod 50) = 10 then
        begin
{$I CheckSync.pas}
        end;
        User := DB_Local.Items[I];
        if User <> Cons then
          if User.Logged then
            User.Exec(MSG_SERVER_STATS, Str);
      end;
    end;
  except
    DebugLog('Exception in ReceiveData 1');
  end;
end;

procedure TMainThread.ReceiveData(User: TLocalUser; Counter, Recurse: Integer);
var
  I, Num, Len, Recv_Max, Rev, Tag (*, Old_Mem, New_Mem*): Integer;
  Last_Error: Integer;
begin
  Num := 0; // Debug variable
  Len := 0;
  Tag := 0;
  Rev := 0;
  Recv_Max := 0;
  I := 0;
  try
    if User = nil then Exit;
    Num := 1;
    if User.Socket = INVALID_SOCKET then Exit;
    if User.Last_Seen = 0 then Exit;
    if User.Logged then
      if User.Searches_Count > 0 then
        if (Current_Time - User.Last_Search_Time) > TimeOut_Remote_Search then
        begin
          Num := 2;
          User.Searches_Count := 0;
          User.Exec(MSG_SERVER_SEARCH_END, '');
          Num := 3;
        end;
    Num := 4;
    User.Flush;
    Num := 5;
    if (User.Logged = True) and (CanReceive(False) = False) then Exit;
    if User.Last_Seen = 0 then Exit;
    if locWriteOnly in User.LocalState then Exit;
    Num := 6;
    if Length(User.Recv_Buf) = 0 then
      SetLength(User.Recv_Buf, RECV_BUF_SIZE_DEF);
    Num := 7;
    while True do
    begin
      Num := 8;
      if not Running then Exit;
      if User.Last_Seen = 0 then Exit;
      if User.Socket = INVALID_SOCKET then Exit;
      if (User.Logged = True) and (CanReceive(False) = False) then Exit;
      Num := 9;
      if Counter >= MAX_COMMANDS_PER_CYCLE then Exit;
      if Linking then
        if Counter >= MAX_COMMANDS_PER_CYCLE2 then Exit;
      if TCPSocket_CanRead(User.Socket, 0, Last_Error) then
      begin
        Num := 10;
        Recv_Max := Length(User.Recv_Buf) - User.Recv_Len;
        Num := 11;
        if Recv_Max = 0 then
        begin // Increase buffer
          Num := 12;
          if User.Recv_Len > (RECV_BUF_SIZE_MAX - 4) then
          begin
            Num := 13;
            DisconnectUser(User, '', GetLangT(LNG_DISCONNECT_INVCMD, User.Nick,
              User.Software + ', ' + Decode_Ip(User.Ip)), 'ReceiveData (1)',
              True);
            Exit;
          end;
          Num := 14;
          SetLength(User.Recv_Buf, User.Recv_Len + RECV_BUF_SIZE_MIN);
            // Increase buffer Length if Needed
          Inc(Recv_Max, RECV_BUF_SIZE_MIN);
          Num := 15;
        end;
        Num := 16;
        Len := TCPSocket_RecvBuffer(User.Socket,
          PChar(@User.Recv_Buf[User.Recv_Len + 1]), Recv_Max, Last_Error);
        Num := 17;
        if Last_Error = WSAEWOULDBLOCK then Exit;
        Num := 19;
        if Last_Error <> 0 then
        begin
          Num := 20;
          DisconnectUser(User, '', GetLangT(LNG_DISCONNECT_SOCKETERR, User.Nick,
            User.Software, IntToStr(Last_Error), GetErrorDesc(Last_Error)),
            'ReceiveData (2)', True);
          Exit;
        end;
        Num := 21;
        Inc(User.Recv_Len, Len);
        Inc(Bytes_in, Len);
        Inc(Bandwidth_Down, Len);
      end
      else if Last_Error <> 0 then
        if Last_Error <> WSAEWOULDBLOCK then
        begin
          DisconnectUser(User, '', GetLangT(LNG_DISCONNECT_SOCKETERR, User.Nick,
            User.Software, IntToStr(Last_Error), GetErrorDesc(Last_Error)),
            'ReceiveData (2a)', True);
          Exit;
        end;
      Num := 22;
      if User.Recv_Len < 4 then Exit;
      if locSwapBytes in User.LocalState then
        Len := Ord(User.Recv_Buf[2]) + 256 * Ord(User.Recv_Buf[1])
      else
      begin
        Num := 23;
        Len := Ord(User.Recv_Buf[1]) + 256 * Ord(User.Recv_Buf[2]);
        Rev := Ord(User.Recv_Buf[4]) + 256 * Ord(User.Recv_Buf[3]);
        Num := 24;
        if not User.Logged then
        begin
          if (Rev = 2) or (Rev = 4) or (Rev = 6) or (Rev = 7) or (Rev = 11) or
            (Rev = 920) then
          begin // Checking for Big-endian (Possible senders: Napster 10.3+, Linked server, Some buggy Client)
            Num := 25;
            User.LocalState := User.LocalState + [locSwapBytes];
            Len := Ord(User.Recv_Buf[2]) + 256 * Ord(User.Recv_Buf[1]);
            Num := 26;
          end
          else
          begin // Checking HTTP Client
            if (Copy(User.Recv_Buf, 1, 3) = 'GET') or (Copy(User.Recv_Buf, 1, 4)
              = 'POST') then
            begin // Web server
              SendWebPage(User);
              Exit;
            end;
          end;
        end;
        Num := 27;
      end;
      Num := 28;
      if Len > (RECV_BUF_SIZE_MAX - 4) then
      begin
        Num := 29;
        DisconnectUser(User, '', GetLangT(LNG_DISCONNECT_INVCMD, User.Nick,
          User.Software + ', ' + Decode_Ip(User.Ip)), 'ReceiveData (3)', True);
        Exit;
      end;
      Num := 30;
      if (Len + 4) > Length(User.Recv_Buf) then
      begin // Increase buffer
        Num := 31;
        Tag := ((Len + 4) div RECV_BUF_SIZE_MIN);
        Num := 32;
        SetLength(User.Recv_Buf, Tag * RECV_BUF_SIZE_MIN);
        Num := 33;
        if Recurse >= MAX_RECURSE then Exit;
        Num := 34;
        ReceiveData(User, Counter, Recurse + 1);
        Exit;
      end;
      Num := 35;
      if User.Recv_Len < (Len + 4) then Exit;
      Num := 36;
      while Len < (User.Recv_Len - 3) do // Processing received Buffer
      begin
        Num := 37;
        if User.Recv_Len < 4 then Exit;
        if (User.Recv_Len - 4) < Len then Exit;
        Num := 38;
        if locSwapBytes in User.LocalState then
          Tag := Ord(User.Recv_Buf[4]) + 256 * Ord(User.Recv_Buf[3])
        else
          Tag := Ord(User.Recv_Buf[3]) + 256 * Ord(User.Recv_Buf[4]);
        Num := 39;
        SetLength(GCmd.Cmd, Len);
        Num := 40;
        if Len > 0 then
          Move(User.Recv_Buf[5], GCmd.Cmd[1], Len);
        Num := 41;
        Move(User.Recv_Buf[Len + 5], User.Recv_Buf[1], User.Recv_Len - Len - 4);
        Num := 42;
        Dec(User.Recv_Len, Len + 4);
        Num := 43;
        try
{$IFDEF CHECK_LEAK}
          Old_Mem := AllocMemSize;
{$ENDIF}
          GCmd.Id := Tag;
          if GCmd.Id = 870 then
            Inc(Counter, 3)
          else if GCmd.Id = 200 then
          begin
            if Num_Servers > 0 then
              Inc(Counter, 5)
            else
              Inc(Counter, 1);
          end;
          if not ProcessCommand(User, queryNormal) then
          begin
{$IFDEF CHECK_LEAK}
            New_Mem := AllocMemSize;
            if (New_Mem - Old_Mem) > POSSIBLE_LEAK then
              DebugLog('Possible leak in ProcessCommand(1,' + IntToStr(Tag) + ','
                + GCmd.Cmd + '): ' + IntToStr(New_Mem - Old_Mem) +
                ' bytes allocated');
{$ENDIF}
            Exit;
          end;
{$IFDEF CHECK_LEAK}
          New_Mem := AllocMemSize;
          if (New_Mem - Old_Mem) > POSSIBLE_LEAK then
            DebugLog('Possible leak in ProcessCommand(2,' + IntToStr(Tag) + ','
              + GCmd.Cmd + '): ' + IntToStr(New_Mem - Old_Mem) +
              ' bytes allocated');
{$ENDIF}
        except
          on E: Exception do
          begin
            DebugLog('Exception in TMainThread::ReceiveData (Tag=' +
              IntToStr(Tag) + ') : ' + E.Message);
{$IFDEF CHECK_LEAK}
            New_Mem := AllocMemSize;
            if (New_Mem - Old_Mem) > POSSIBLE_LEAK then
              DebugLog('Possible leak in ProcessCommand(3,' + IntToStr(Tag) + ','
                + GCmd.Cmd + '): ' + IntToStr(New_Mem - Old_Mem) +
                ' bytes allocated');
{$ENDIF}
            Exit;
          end;
        end;
        Num := 44;
{$I CheckSync.pas}
        Num := 45;
        if User.Last_Seen = 0 then Exit;
        Inc(Counter);
        Num := 46;
        if (Counter >= MAX_COMMANDS_PER_CYCLE) or (Linking and (Counter >=
          MAX_COMMANDS_PER_CYCLE2)) then
        begin
          Num := 47;
          Exit;
        end;
        Num := 48;
        if User.Recv_Len > 3 then
        begin
          Num := 49;
          if locSwapBytes in User.LocalState then
            Len := Ord(User.Recv_Buf[2]) + 256 * Ord(User.Recv_Buf[1])
          else
            Len := Ord(User.Recv_Buf[1]) + 256 * Ord(User.Recv_Buf[2]);
          Num := 50;
          if (Len + 4) > Length(User.Recv_Buf) then
          begin
            Num := 51;
            if Len > (RECV_BUF_SIZE_MAX - 4) then
            begin
              Num := 52;
              DisconnectUser(User, '', GetLangT(LNG_DISCONNECT_INVCMD,
                User.Nick, User.Software + ', ' + Decode_Ip(User.Ip)),
                'ReceiveData (4)', True);
              Exit;
            end;
            Num := 53;
            Tag := ((Len + 4) div RECV_BUF_SIZE_MIN);
            SetLength(User.Recv_Buf, Tag * RECV_BUF_SIZE_MIN);
              // Increase buffer Length if Needed
            Num := 54;
            if Recurse >= MAX_RECURSE then Exit;
            ReceiveData(User, Counter, Recurse + 1);
            Num := 55;
            Exit;
          end;
          Num := 56;
        end
        else
          Len := User.Recv_Len + 1;
        Num := 57;
      end; // Loop
      Num := 58;
    end;
    Num := 59;
  except
    DebugLog('Exception in ReceiveData 2  Num=' + IntToStr(Num) + ' I=' +
      IntToStr(I) + ' Len=' + IntToStr(Len) + ' Recv_Max=' + IntToStr(Recv_Max) +
      ' Rev=' + IntToStr(Rev) + ' Tag=' + IntToStr(Tag));
  end;
end;

procedure TMainThread.ResetSearchControl;
var
  I: Integer;
  Loc: TLocalUser;
begin
  for I := DB_Local.Count - 1 downto 0 do
  try
    Loc := DB_Local.Items[I];
    if (I mod 50) = 0 then
    begin
{$I CheckSync.pas}
    end;
    if Loc.Logged then
      if Loc.Searchespm <> 999 then
      begin
        if Loc.Searchespm >= Flood_Max_Searches then
          if Loc.Level < NapUserModerator then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooMuchSearch,
              [Loc.Searchespm]));
        Loc.Searchespm := 0;
      end;
  except
  end;
end;

procedure TMainThread.CloseSockets;
var
  I: Integer;
  Item: PNapCmd2;
begin
  for I := DB_Closed.Count - 1 downto 0 do
  begin
    Item := DB_Closed.Items[I];
    if (Current_Time - Item^.Id1) > 5000 then
    begin
      // DebugLog('Closing Socket');
      SynSock.ShutDown(Item^.Id2, SD_BOTH);
      SynSock.CloseSocket(Item^.Id2);
      Dec(Sockets_Count);
      DB_Closed.Delete(I);
    end;
  end;
end;

procedure TMainThread.SynchronizeConsole;
begin
  Tmp_Pos := 1604;
  if (Current_Time - Last_Sync) < CONSOLE_SYNC then Exit;
  Last_Sync := Current_Time;
  try
    Tmp_Pos := 1605;
    Synchronize(SyncData);
    Tmp_Pos := 1606;
    if Sync_Reply_List.Count > 0 then
      Synchronize(SyncLog);
  except
  end;
  Tmp_Pos := 1607;
end;

procedure TMainThread.ResetWantQueueControl;
var
  I: Integer;
  Loc: TLocalUser;
begin
  for I := DB_Local.Count - 1 downto 0 do
  try
    Loc := DB_Local.Items[I];
    if (I mod 50) = 0 then
    begin
{$I CheckSync.pas}
    end;
    if Loc.Logged then
      if Loc.WantQueuep3m <> 999 then
      begin
        if Loc.Level < NapUserModerator then
          if (WQFloodBlock_Count <> 0) and (Loc.WantQueuep3m >
            WQFloodBlock_Count) then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooMuchQueue,
              [Loc.WantQueuep3m, WQFloodBlock_Count]));
        Loc.WantQueuep3m := 0;
      end;
  except
  end;
end;

procedure TMainThread.ResetDLRequestControl;
var
  I: Integer;
  Loc: TLocalUser;
begin
  for I := DB_Local.Count - 1 downto 0 do
  try
    Loc := DB_Local.Items[I];
    if (I mod 50) = 0 then
    begin
{$I CheckSync.pas}
    end;
    if Loc.Logged then
      if Loc.DLRequestsp3m <> 999 then
      begin
        if Loc.Level < NapUserModerator then
          if (DLFloodBlock_Count <> 0) and (Loc.DLRequestsp3m >
            DLFloodBlock_Count) then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooMuchDL,
              [Loc.DLRequestsp3m, DLFloodBlock_Count]));
        Loc.DLRequestsp3m := 0;
      end;
  except
  end;
end;

procedure TMainThread.CheckBlockedShare;
var
  I: Integer;
  Loc: TLocalUser;
  T: Cardinal;
begin
  Tmp_Pos := 12262;
  if not ShareInform then Exit;
  T := Current_Time - MinShare_Delay;
  Tmp_Pos := 12263;
  for I := 0 to DB_Local.Count - 1 do
  begin
    Loc := DB_Local.Items[I];
    if ((I mod 30) = 0) then
    begin
{$I CheckSync.pas}
    end;
    Tmp_Pos := 12264;
    if Loc.Logged then
      if (Loc.Last_Seen < T) and (Loc.Last_Seen > T - 30000) then
        if not (userHideErrors in Loc.Data^.State) then
        begin
          if Loc.Blocked_Incomplete <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_BlockINCOMPLETE,
              [Loc.Blocked_Incomplete]));
          if Loc.Blocked_Fakeext <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_BlockFakeExt,
              [Loc.Blocked_Fakeext]));
          if Loc.Blocked_Toomany <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooManyFiles,
              [Loc.Blocked_Toomany]));
          if Loc.Blocked_Tooshort <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooShortFileName,
              [Loc.Blocked_Tooshort]));
          if Loc.Blocked_Tooshortmp3 <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooShortDuration,
              [Loc.Blocked_Tooshortmp3]));
          if Loc.Blocked_Toosmall <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooSmallSize,
              [Loc.Blocked_Toosmall]));
          if Loc.Blocked_Toolarge <> 0 then
            Loc.Exec(MSG_SERVER_NOSUCH, Format(RS_Thread_TooLargeSize,
              [Loc.Blocked_Toolarge]));
          Tmp_Pos := 12265;
        end;
  end;
  Tmp_Pos := 12266;
end;

procedure TMainThread.CheckForceEnter;
const
  CHECK_DELAY = 1000; // この関数のチェック間隔(ミリ秒)。
var
  I: Integer;
  Loc: TLocalUser;
  P: PStringHashItem;
begin
  Tmp_Pos := 12267;
  if Last_Force_Enter > Current_Time - CHECK_DELAY then Exit;
  Inc(Last_Force_Enter, CHECK_DELAY);
  if not Force_Enter then Exit;
  Tmp_Pos := 12268;
  I := 0;
  while I < DB_Login.Count do
  begin
    Loc := DB_Login.Items[I];
    if ((I mod 30) = 0) then
    begin
{$I CheckSync.pas}
    end;
    Tmp_Pos := 12269;
    if not Loc.Logged then
      DB_Login.Delete(I)
    else if Loc.Join_Delay < 0 then
    begin
      GCmd.Id := MSG_CLIENT_JOIN;
      if (Pos('WinMX', Loc.Software) <> 0) and
        (Pos('3.', Loc.Software) <> 0) then
      begin
        GCmd.Cmd := RS_Thread_WinMX3Channel; // WinMX V3.x専用部屋
        ProcessCommand(Loc, queryNormal);
      end
      else
      begin
        P := Force_Enter_Channel_List.First;
        while P <> nil do
        begin
          GCmd.Cmd := P^.Data;
          ProcessCommand(Loc, queryNormal);
          P := P^.Next;
        end;
      end;
      DB_Login.Delete(I);
    end
    else
    begin
      Dec(Loc.Join_Delay, CHECK_DELAY);
      Inc(I);
    end;
  end;
  Tmp_Pos := 12270;
end;

procedure TMainThread.KillIdleUser;
var
  I: Integer;
  Loc: TLocalUser;
begin
  if not Kill_Idleuser then Exit;
  for I := DB_Local.Count - 1 downto 0 do
  try
    Loc := DB_Local.Items[I];
    if (I mod 20) = 0 then
    begin
{$I CheckSync.pas}
    end;
    if Loc.Logged then
      if GetTickCount - Loc.Last_Command_Time > Kill_IdleUser_Time then
        if Loc.Level < NapUserModerator then
          if not StrHash_FindString(DB_Friends, Loc.Nick, True) then
          begin
            AddReconnector(Decode_Ip(Loc.Ip));
            DisconnectUser(Loc, '', '', 'KillIdleUser', False);
          end;
  except
  end;
end;

end.
