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

 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;

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,'# ! このファイルは次回サーバーがシャットダウンしたとき上書きされます。');
 list.Insert(1,'# 編集するときは、サーバーが稼動していないか確認してください。');
 list.Insert(2,'#');
 list.Insert(3,'# 共有から除外するファイルのリストです。');
 list.Insert(4,'# 各行は正規表現で記述します。');
 list.Insert(5,'# 大文字/小文字は区別されません。');
 list.Insert(6,'#');
 list.Insert(7,'# 例: alanis morissette');
 list.Insert(8,'# "sample.block"ファイルに標準の除外ファイルリストがあります.');
 list.Insert(9,'#');
 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.
