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

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

 Handling of blocked files

*********************************************************}
unit Blocks;

interface

uses
  Windows, Classes, Classes2, SlavaStrings, Vars, Constants, Memory_Manager,
  STypes, SysUtils, Class_Cmdlist, Keywords, LocalUsers, Share, Users,
  StringResources;

procedure FreeBlocks;
procedure LoadBlocks;
procedure SaveBlocks;
function IsFileBlocked(User: TLocalUser; Item: PShare; FileName: string;
  List: TNapCmdList): Boolean;
function IsSearchBlocked(User: POnlineUser; Query, Included: string;
  List: TNapCmdList): Boolean;
procedure Blocks2List(var Blocks_List: TStringHash);
procedure Handler_Block;

implementation

uses
  Handler, Lang;

procedure FreeBlocks;
var
  I: Integer;
begin
  for I := 0 to DB_Blocks.Count - 1 do
    TNapCmdList(DB_Blocks.Items[I]).Free;
  DB_Blocks.Free;
  DB_Blocks := nil;
end;

procedure LoadBlocks;
var
  I, J, K, Crc: Integer;
  List, Lst: TMyStringList;
  Hash, H2: TNapCmdList;
  Str: string;
  Match: Boolean;
begin
  if DB_Blocks <> nil then
    FreeBlocks;
  DB_Blocks := TMyList.Create;
  List := TMyStringList.Create;
  try
    List.LoadFromFile(ApplicationDir + 'block');
  except
    List.Free;
    Exit;
  end;
  Lst := TMyStringList.Create;
  for I := 0 to List.Count - 1 do
    if Length(List.Strings[I]) > 1 then
      if List.Strings[I][1] <> '#' then
      begin
        Hash := TNapCmdList.Create;
        SplitToKeywords(AnsiLowerCase(List.Strings[I]) + ' ', Hash,
          MAX_FILE_KEYWORDS);
        if Hash.Count > 0 then
        begin
          for K := 0 to DB_Blocks.Count - 1 do
            if Hash <> nil then
            begin
              H2 := DB_Blocks.Items[K];
              if H2.Count = Hash.Count then
              begin
                Match := True;
                  // comparing crc of every keyword (much faster than to compare all keywords)
                for J := 0 to Hash.Count - 1 do
                  if Match then
                    if H2.FindItem(PNapCmd(Hash.Items[J]).Id,
                      PNapCmd(Hash.Items[J]).Cmd) = -1 then
                      Match := False;
                if Match then
                  // all keywords from 'Hash' are present in 'H2' (it doesn't
                  // guarantee that all keywords from 'H2' are present in 'Hash'
                  // because there might be duplicate keywords)
                begin
                  Hash.Free;
                  Hash := nil;
                end
              end;
            end;
          if Hash <> nil then
          begin
            DB_Blocks.Add(Hash);
          end;
        end
        else
          Hash.Free;
      end;
  Lst.Free;
  List.Free;
end;

procedure SaveBlocks;
var
  List: TMyStringList;
  Str: string;
  I, J: Integer;
  Hash: TNapCmdList;
begin
  List := CreateStringList;
  for I := 0 to DB_Blocks.Count - 1 do
  begin
    Hash := DB_Blocks.Items[I];
    Str := '';
    for J := 0 to Hash.Count - 1 do
      Str := Str + PNapCmd(Hash.Items[J])^.Cmd + ' ';
    if Length(Str) > 0 then
      List.Add(Str);
  end;
  List.Sort;
  List.Insert(0, RS_Blocks_FileDescription0);
  List.Insert(1, RS_Blocks_FileDescription1);
  List.Insert(2, RS_Blocks_FileDescription2);
  List.Insert(3, RS_Blocks_FileDescription3);
  List.Insert(4, RS_Blocks_FileDescription4);
  List.Insert(5, RS_Blocks_FileDescription5);
  List.Insert(6, RS_Blocks_FileDescription6);
  List.Insert(7, RS_Blocks_FileDescription7);
  List.Insert(8, RS_Blocks_FileDescription8);
  List.Insert(9, RS_Blocks_FileDescription9);
  try
    List.SaveToFile(ApplicationDir + 'block');
  except
  end;
  FreeStringList(List);
end;

procedure Blocks2List(var Blocks_List: TStringHash);
var
  I, J: Integer;
  List: TNapCmdList;
  Str: string;
begin
  StrHash_Clear(Blocks_List);
  if DB_Blocks <> nil then
    for I := 0 to DB_Blocks.Count - 1 do
    begin
      Tmp_Pos := 1351;
      List := DB_Blocks.Items[I];
      Str := '';
      for J := 0 to List.Count - 1 do
        Str := Str + PNapCmd(List.Items[J])^.Cmd + ' ';
      StrHash_Add(Blocks_List, Str);
    end;
end;

function IsFileBlocked(User: TLocalUser; Item: PShare; FileName: string;
  List: TNapCmdList): Boolean;
var
  Match: Boolean;
  I, J: Integer;
  Hash: TNapCmdList;
begin
  Result := False;
  if (not Block_CheckMods) and (User.Data^.Level > napUserUser) then Exit;
  for I := 0 to DB_Blocks.Count - 1 do
  begin
    Hash := DB_Blocks.Items[I];
    Match := True;
    for J := 0 to Hash.Count - 1 do
      if Match then
        if List.FindById(PNapCmd(Hash.Items[J])^.Id) = -1 then
          Match := False;
    if Match then // all crc matched - checking keywords
      for J := 0 to Hash.Count - 1 do
        if Match then
          if List.FindItem(PNapCmd(Hash.Items[J])^.Id,
            PNapCmd(Hash.Items[J])^.Cmd) = -1 then
            Match := False;
    if Match then
    begin
      Result := True;
      Exit;
    end;
  end;
end;

function IsSearchBlocked(User: POnlineUser; Query, Included: string;
  List: TNapCmdList): Boolean;
begin
  Result := False;
end;

procedure Handler_Block;
var
  I, J, K, Crc: Integer;
  Str: string;
  Hash, H2: TNapCmdList;
begin
  Tmp_Pos := 810;
  if not IsLogged then Exit;
  if not CheckLevel('', napUserAdmin) then Exit;
  case GCmd.Id of
    MSG_CLIENT_BLOCKLIST:
      begin
        Tmp_Pos := 811;
        for I := 0 to DB_Blocks.Count - 1 do
        begin
          Hash := DB_Blocks.Items[I];
          Str := '';
          for J := 0 to Hash.Count - 1 do
            Str := Str + PNapCmd(Hash.Items[J])^.Cmd + ' ';
          case Query of
            queryOperServ, queryNickServ, queryChanServ,
              queryChannel: Error('Block: ' + Str)
          else
            Exec(User, GCmd.Id, Str);
          end;
          if ((I mod 50) = 10) then
          begin
{$I CheckSync.pas}
          end;
        end;
        Tmp_Pos := 812;
        case Query of
          queryOperServ, queryNickServ, queryChanServ,
            queryChannel: Error(GetLangT(LNG_ITEMSLISTED,
              IntToStr(DB_Blocks.Count)));
        else
          Exec(User, GCmd.Id, '');
        end;
      end;
    MSG_CLIENT_BLOCK:
      begin
        if not CheckParams(1) then Exit;
        Tmp_Pos := 813;
        Hash := TNapCmdList.Create;
        if SplitToKeywords(AnsiLowerCase(GCmd.Cmd) + ' ', Hash,
          MAX_FILE_KEYWORDS) = 0 then
        begin
          Hash.Free;
          Exit;
        end;
        Tmp_Pos := 814;
        if Hash.Count > 0 then
        begin
          for I := 0 to DB_Blocks.Count - 1 do
          begin
            H2 := DB_Blocks.Items[I];
            if H2.Count = Hash.Count then
            begin
              K := 0;
                // comparing crc of every keyword (much faster than to compare all keywords)
              for J := 0 to Hash.Count - 1 do
                if K = 0 then
                  if H2.FindItem(PNapCmd(Hash.Items[J]).Id,
                    PNapCmd(Hash.Items[J]).Cmd) = -1 then
                    K := 1;
              if K = 0 then
                // all keywords from 'Hash' are present in 'H2' (it doesn't
                // guarantee that all keywords from 'H2' are present in 'Hash'
                // because there might be duplicate keywords)
              begin
                Hash.Free;
                Exit;
              end;
            end;
          end;
          DB_Blocks.Add(Hash);
        end
        else
          Hash.Free;
        Tmp_Pos := 815;
      end;
    MSG_CLIENT_UNBLOCK:
      begin
        if not CheckParams(1) then Exit;
        Tmp_Pos := 816;
        Hash := TNapCmdList.Create;
        if SplitToKeywords(AnsiLowerCase(GCmd.Cmd) + ' ', Hash,
          MAX_FILE_KEYWORDS) = 0 then
        begin
          Hash.Free;
          Exit;
        end;
        for I := DB_Blocks.Count - 1 downto 0 do
        begin
          H2 := DB_Blocks.Items[I];
          Tmp_Pos := 817;
          if H2.Count = Hash.Count then
          begin
            K := 0;
            for J := 0 to Hash.Count - 1 do
              if K = 0 then
                if H2.FindItem(PNapCmd(Hash.Items[J]).Id,
                  PNapCmd(Hash.Items[J]).Cmd) = -1 then
                  K := 1;
            if K = 0 then // all keywords match
            begin
              H2.Free;
              DB_Blocks.Delete(I);
            end;
          end;
        end;
        Hash.Free;
        Exit;
      end;
  end;
end;

initialization
  begin
    DB_Blocks := nil;
  end;

end.
