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

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

 class for registered users

*********************************************************}
unit Registered;

interface

{$I Defines.pas}

uses
  Windows, Classes2, SysUtils, Constants, STypes, BlckSock, SynSock, WinSock,
  Share, Servers, Users, StringResources;

type
  TRegisteredUser = record
    Nick: string;
    Password: string;
    Level: TNapUserLevel;
    Downloads: Integer;
    Uploads: Integer;
    Last_Ip: Integer;
    Last_Seen: Time_T;
    State: TUserState;
    Created: Time_T;
    Createdby: string;
    Lastsetby: string;
  end;
  PRegisteredUser = ^TRegisteredUser;
  TRegUserList = class(TMyList)
    function Add(Value: TRegisteredUser): Integer;
    procedure Insert(Index: Integer; Value: TRegisteredUser);
    procedure Clear; override;
    procedure Delete(Index: Integer);
    function FindUser(Nick: string): Integer;
    function FindUserRec(Nick: string): PRegisteredUser;
    function IsConsole(Index: Integer): Boolean;
    function User(Index: Integer): TRegisteredUser;
    function PasswordOk(Nick, Password: string): Boolean;
    constructor Create;
    destructor Destroy; override;
  end;
  TRegUserDataBase = class(TObject)
    List: array[0..USERS_NAME_ARRAY - 1] of TRegUserList;
    constructor Create;
    destructor Destroy; override;
    procedure SaveToFile(FileName: string);
    procedure LoadFromFile(FileName: string);
    function FindUser(Nick: string): PRegisteredUser;
    function PasswordOk(Nick, Password: string): Boolean;
    procedure Add(Reg: TRegisteredUser);
    procedure Delete(Nick: string);
    function CountUsers: Integer;
  end;

procedure ResetRegistered(var Reg: TRegisteredUser);

implementation

uses
  Vars, Thread, Lang, Handler, Memory_Manager;

procedure ResetRegistered(var Reg: TRegisteredUser);
begin
  Reg.Nick := '';
  Reg.Password := Null_Pass;
  Reg.Level := napUserUser;
  Reg.Downloads := 0;
  Reg.Uploads := 0;
  Reg.Last_Ip := 0;
  Reg.Last_Seen := 0;
  Reg.State := [];
  Reg.Created := 0;
  Reg.CreatedBy := '';
  Reg.LastSetBy := '';
end;

function TRegUserList.Add(Value: TRegisteredUser): Integer;
var
  Data: PRegisteredUser;
begin
  Data := AllocMem(SizeOf(TRegisteredUser));
  with Data^ do
  begin
    Pointer(Nick) := nil;
    Nick := Value.Nick;
    Pointer(Password) := nil;
    Password := Value.Password;
    Level := Value.Level;
    Downloads := Value.Downloads;
    Uploads := Value.Uploads;
    Last_Ip := Value.Last_Ip;
    Last_Seen := Value.Last_Seen;
    State := Value.State;
    Created := Value.Created;
    Createdby := Value.CreatedBy;
    Pointer(lastsetby) := nil;
    Lastsetby := Value.LastSetBy;
  end;
  Result := inherited Add(Data);
end;

procedure TRegUserList.Insert(Index: Integer; Value: TRegisteredUser);
var
  Data: PRegisteredUser;
begin
  Data := AllocMem(SizeOf(TRegisteredUser));
  with Data^ do
  begin
    Pointer(Nick) := nil;
    Nick := Value.Nick;
    Pointer(Password) := nil;
    Password := Value.Password;
    Level := Value.Level;
    Downloads := Value.Downloads;
    Uploads := Value.Uploads;
    Last_Ip := Value.Last_Ip;
    Last_Seen := Value.Last_Seen;
    State := Value.State;
    Created := Value.Created;
    Createdby := Value.CreatedBy;
    Pointer(Lastsetby) := nil;
    Lastsetby := Value.LastSetBy;
  end;
  inherited Insert(Index, Data);
end;

procedure TRegUserList.Clear;
begin
  while Count > 0 do
    Delete(Count - 1);
  inherited Clear;
end;

procedure TRegUserList.Delete(Index: Integer);
begin
  if (Index < 0) or (Index >= Count) then Exit;
  if Items[Index] <> nil then
  begin
    Finalize(PRegisteredUser(Items[Index])^);
    FreeMem(PRegisteredUser(Items[Index]), SizeOf(TRegisteredUser));
  end;
  inherited Delete(Index);
end;

function TRegUserList.FindUser(Nick: string): Integer;
var
  I: Integer;
beGin
  Result := -1;
  Nick := AnsiLowerCase(Nick);
  for I := 0 to Count - 1 do
    if AnsiLowerCase(PRegisteredUser(Items[I])^.Nick) = Nick then
    begin
      Result := I;
      Exit;
    end;
end;

function TRegUserList.FindUserRec(Nick: string): PRegisteredUser;
var
  I: Integer;
begin
  Result := nil;
  Nick := AnsiLowerCase(Nick);
  for I := 0 to Count - 1 do
    if AnsiLowerCase(PRegisteredUser(Items[I])^.Nick) = Nick then
    begin
      Result := Items[I];
      Exit;
    end;
end;

function TRegUserList.IsConsole(Index: Integer): Boolean;
var
  Str: string;
begin
  Str := PRegisteredUser(Items[Index])^.Password;
  Result := (Str = CONSOLE_PASS) or (Str = CONSOLE_PASS_OFFLINE);
end;

function TRegUserList.User(Index: Integer): TRegisteredUser;
var
  User: TRegisteredUser;
  P: PRegisteredUser;
begin
  P := Items[Index];
  User.Nick := P.Nick;
  User.Password := P.Password;
  User.Level := P.Level;
  User.Downloads := P.Downloads;
  User.Uploads := P.Uploads;
  User.Last_Ip := P.Last_Ip;
  User.Last_Seen := P.Last_Seen;
  User.State := P.State;
  User.Created := P.Created;
  User.CreatedBy := P.CreatedBy;
  User.LastSetBy := P.LastSetBy;
  Result := User;
end;

function TRegUserList.PasswordOk(Nick, Password: string): Boolean;
var
  I: Integer;
  Str: string;
begin
  Result := True;
  Nick := AnsiLowerCase(Nick);
  for I := 0 to Count - 1 do
    if AnsiLowerCase(PRegisteredUser(Items[I])^.Nick) = Nick then
    begin
      Str := PRegisteredUser(Items[I])^.Password;
      Result := (Str = Null_Password) or (Str = Password);
      Exit;
    end;
end;

constructor TRegUserList.Create;
begin
  inherited Create;
end;

destructor TRegUserList.Destroy;
begin
  Clear;
  inherited Destroy;
end;

constructor TRegUserDataBase.Create;
var
  I: Integer;
begin
  inherited Create;
  for I := 0 to USERS_NAME_ARRAY - 1 do
    List[I] := TRegUserList.Create;
end;

destructor TRegUserDataBase.Destroy;
var
  I: Integer;
begin
  for I := 0 to USERS_NAME_ARRAY - 1 do
    List[I].Free;
  inherited Destroy;
end;

procedure TRegUserDataBase.SaveToFile(FileName: string);
var
  Lst: TMyStringList;
  I, J: Integer;
  User: PRegisteredUser;
  Str: string;
begin
  Lst := CreateStringList;
  for J := 0 to USERS_NAME_ARRAY - 1 do
    for I := 0 to List[J].Count - 1 do
    begin
      User := List[J].Items[I];
      Str := User.Nick;
      while Length(Str) < 22 do
        Str := Str + ' ';
      Str := Str + User.Password + ' ' +
        IntToStr(Ord(User.Level)) + ' ' +
        IntToStr(User.Downloads) + ' ' +
        IntToStr(User.Uploads) + ' ' +
        Decode_Ip(User.Last_Ip) + ' ' +
        IntToStr(User.Last_Seen) + ' ' +
        IntToStr(UserState2Int(User.State)) + ' ' +
        IntToStr(User.Created) + ' ' +
        AddStr(User.CreatedBy) + ' ' +
        AddStr(User.LastSetBy);
      Lst.Add(Str);
      if (I mod 30) = 0 then
      begin
{$I CheckSync.pas}
      end;
    end;
  if Lst.Count < 1000 then
    Lst.Sort;
  Lst.Insert(0, RS_Registered_FileDescription0);
  Lst.Insert(1, RS_Registered_FileDescription1);
  Lst.Insert(2, RS_Registered_FileDescription2);
  Lst.Insert(3, RS_Registered_FileDescription3);
  Lst.Insert(4, RS_Registered_FileDescription4);
  Lst.Insert(5, RS_Registered_FileDescription5);
  Lst.Insert(6, RS_Registered_FileDescription6);
  try
    Lst.SaveToFile(FileName);
  except
  end;
  FreeStringList(Lst);
end;

procedure TRegUserDataBase.LoadFromFile(FileName: string);
var
  Version: Integer;
  I: Integer;
  Lst, Entry: TMyStringList;
  Str: string;
  User: TRegisteredUser;
begin
  for I := 0 to USERS_NAME_ARRAY - 1 do
    List[I].Clear;
  Lst := CreateStringList;
  try
    Lst.LoadFromFile(FileName);
  except
    FreeStringList(Lst);
    Exit;
  end;
  Version := 0;
  Entry := CreateStringList;
  for I := 0 to Lst.Count - 1 do
    if Length(Lst.Strings[I]) > 1 then
    begin
      if Lst.Strings[I][1] = '#' then
      begin
        Str := LowerCase(Lst.Strings[I]);
        if Str = '# Version 2' then
          Version := 2;
        if Str = '# Version 3' then
          Version := 3;
      end
      else
      begin
        SplitStringOld(Lst.Strings[I], Entry);
        if Entry.Count > 6 then
          if FindUser(Entry.Strings[0]) = nil then
          begin
            if (I mod 30) = 0 then
            begin
{$I CheckSync.pas}
            end;
            if Version = 2 then
            begin
              ResetRegistered(User);
              User.Nick := Entry.Strings[0];
              User.Password := Entry.Strings[1];
              User.Level := Str2Level(Entry.Strings[3]);
              User.Downloads := StrToIntDef(Entry.Strings[4], 0);
              User.Uploads := StrToIntDef(Entry.Strings[5], 0);
              if Entry.Count > 7 then
                User.Last_Ip := StrToInt64Def(Encode_Ip_Str(Entry.Strings[7]), 0)
              else
                User.Last_Ip := 0;
              if Entry.Count > 8 then
                User.Last_Seen := StrToIntDef(Entry.Strings[8], 0)
              else
                User.Last_Seen := 0;
              if Entry.Count > 9 then
                User.State := Int2UserState(StrToIntDef(Entry.Strings[9], 0),
                  False)
              else
                User.State := [];
              if Entry.Count > 10 then
                User.Created := StrToIntDef(Entry.Strings[10], 0)
              else
                User.Created := GetTickCountT;
              if Entry.Count > 11 then
                User.CreatedBy := Entry.Strings[11]
              else
                User.CreatedBy := '';
              if Entry.Count > 12 then
                User.LastSetBy := Entry.Strings[12]
              else
                User.LastSetBy := '';
              if User.Level <> napUserConsole then
                Add(User);
            end;
            if Version = 3 then
            begin
              ResetRegistered(User);
              User.Nick := Entry.Strings[0];
              User.Password := Entry.Strings[1];
              User.Level := Str2Level(Entry.Strings[2]);
              User.Downloads := StrToIntDef(Entry.Strings[3], 0);
              User.Uploads := StrToIntDef(Entry.Strings[4], 0);
              User.Last_Ip := StrToInt64Def(Encode_Ip_Str(Entry.Strings[5]), 0);
              User.Last_Seen := StrToIntDef(Entry.Strings[6], 0);
              if Entry.Count > 7 then
                User.State := Int2UserState(StrToIntDef(Entry.Strings[7], 0),
                  False)
              else
                User.State := [];
              if Entry.Count > 8 then
                User.Created := StrToIntDef(Entry.Strings[8], 0)
              else
                User.Created := 946702800; // Shows created Date as 1/1/00
              if Entry.Count > 9 then
                User.CreatedBy := Entry.Strings[9]
              else
                User.CreatedBy := '';
              if Entry.Count > 10 then
                User.LastSetBy := Entry.Strings[10]
              else
                User.LastSetBy := '';
              if User.Level <> napUserConsole then
                Add(User);
            end;
          end;
      end;
    end;
  FreeStringList(Entry);
  FreeStringList(Lst);
end;

function TRegUserDataBase.FindUser(Nick: string): PRegisteredUser;
var
  I: Integer;
begin
  Result := nil;
  I := GetCharIndex(Nick);
  if I = -1 then Exit;
  Result := List[I].FindUserRec(Nick);
end;

function TRegUserDataBase.PasswordOk(Nick, Password: string): Boolean;
var
  I: Integer;
begin
  Result := False;
  I := GetCharIndex(Nick);
  if I = -1 then Exit;
  Result := List[I].PasswordOk(Nick, Password);
end;

procedure TRegUserDataBase.Delete(Nick: string);
var
  I, J: Integer;
begin
  I := GetCharIndex(Nick);
  if I = -1 then Exit;
  J := List[I].FindUser(Nick);
  if J <> -1 then
    List[I].Delete(J);
end;

procedure TRegUserDataBase.Add(Reg: TRegisteredUser);
var
  I: Integer;
begin
  if Reg.Level = napUserConsole then Exit;
  I := GetCharIndex(Reg.Nick);
  if I = -1 then Exit;
  List[I].Add(Reg);
end;

function TRegUserDataBase.CountUsers: Integer;
var
  I, J: Integer;
begin
  J := 0;
  for I := 0 to USERS_NAME_ARRAY - 1 do
    Inc(J, List[I].Count);
  Result := J;
end;

end.
