{(
)) . . __ __ ___ __ _ _
(( \`-"'"-'/ ( \/ )( _) / \( \/\/ )
)) ) 6 6 ( - ) ( ) _)( () )\ /
(( =. Y ,= (_/\/\_)(___) \__/ \/\/
)) /^^^\ .
(( / \ ) Mini EO? WOW!
)) ( )-( )/ Created by Sordie out of bordem
(( "" ""
)}
program MEOW;
{$APPTYPE CONSOLE}
{$DEFINE THREAD_SAFE}
{$DEFINE LOG_CONFIG}
{$DEFINE LOG_SQL}
{$DEFINE LOG_UNHANDLED_PACKET_FAMILY}
{$DEFINE LOG_UNHANDLED_PACKET_ACTION}
uses
Windows, WinSock;
type
procedureref = reference to procedure;
CriticalSectionHelper = record helper for TRTLCriticalSection
procedure Create; inline;
procedure Free; inline;
procedure Enter; inline;
procedure Leave; inline;
procedure Section(Code: procedureref); inline;
end;{CriticalSectionHelper}
const
sqlite3 = 'sqlite3.dll';
type
TSQLiteDB = Pointer;
TSQLiteQuery = Pointer;
function sqlite3_open(DBName: PAnsiChar; var DB: TSQLiteDB): Integer; cdecl; external sqlite3;
function sqlite3_close(DB: TSQLiteDB): Integer; cdecl; external sqlite3;
function sqlite3_prepare(DB: TSQLiteDB; QueryStr: PAnsiChar; QuerySize: Integer; var Query: TSQLiteQuery; var NextQuery: PAnsiChar): Integer; cdecl; external sqlite3;
function sqlite3_step(Query: TSQLiteQuery): Integer; cdecl; external sqlite3;
function sqlite3_finalize(Query: TSQLiteQuery): Integer; cdecl; external sqlite3;
function sqlite3_column_count(Query: TSQLiteQuery): Integer; cdecl; external sqlite3;
function sqlite3_column_name(Query: TSQLiteQuery; i: Integer): PAnsiChar; cdecl; external sqlite3;
function sqlite3_column_type(Query: TSQLiteQuery; i: Integer): Integer; cdecl; external sqlite3;
function sqlite3_column_int(Query: TSQLiteQuery; i: Integer): Integer; cdecl; external sqlite3;
function sqlite3_column_text(Query: TSQLiteQuery; i: Integer): PAnsiChar; cdecl; external sqlite3;
const
SQLITE_OK = 0;
SQLITE_ROW = 100;
SQLITE_DONE = 101;
SQLITE_INTEGER = 1;
SQLITE_TEXT = 3;
SQLITE_NULL = 5;
type
TDatabase = class
var CriticalSection: TRTLCriticalSection;
var FileName: AnsiString;
var DB: TSQLiteDB;
var Transaction: Boolean;
type TTable = class
var Database: TDatabase;
type TCell = record
DataType: Integer;
DataStr: AnsiString;
DataInt: Integer;
end;{TCell}
var ColumnNames: array of AnsiString;
var Table: array of array of TCell;
constructor Create(ADatabase: TDatabase; SQL: AnsiString);
destructor Destroy; override;
function Empty: Boolean; inline;
function Column(Name: AnsiString): Integer;
function Value(Name: AnsiString; Row: Integer = 0; Default: AnsiString = ''): AnsiString; overload;
function Value(Name: AnsiString; Row: Integer = 0; Default: Integer = 0): Integer; overload;
end;{TTable}
constructor Create(AFileName: AnsiString);
destructor Destroy; override;
function Prepare(SQL: AnsiString): TSQLiteQuery;
procedure Finalize(var Query: TSQLiteQuery);
function Query (SQL: AnsiString): Boolean;
function QueryTable(SQL: AnsiString): TTable; inline;
function TableExists(Name: AnsiString): Boolean;
function BeginTransaction: Boolean;
function EndTransaction(Rollback: Boolean = False): Boolean;
end;{TDatabase}
TINIFile = class
var CriticalSection: TRTLCriticalSection;
var FileName: AnsiString;
constructor Create(AFileName: AnsiString);
destructor Destroy; override;
function Read(Section, Key: AnsiString; Default: AnsiString = ''): AnsiString; overload;
function Read(Section, Key: AnsiString; Default: Integer = 0): Integer; overload;
function Read(Section, Key: AnsiString; Default: Boolean = False): Boolean; overload;
end;{TINIFile}
TArray<T: class> = class
var Items: array of T;
constructor Create;
destructor Destroy; override;
function Find (Item: T): Integer;
function Add (Item: T): Integer;
function Remove(Item: T): Integer;
procedure Clear;
end;{TArray<T>}
TSHA256Hash = packed record
A, B, C, D, E, F, G, H: Cardinal;
end;{TSHA256Hash}
TSHA256 = record
Hash: TSHA256Hash;
MLen: Int64;
Buffer: array[0..63] of Byte;
Index: Integer;
procedure Init;
procedure Compress;
procedure Update(Data: Pointer; Len: Integer);
function Done: AnsiString;
class function HashStr(S: AnsiString): AnsiString; static;
end;{TSHA256}
Server = class abstract
const RequiredVersion: array[0..2] of Byte = (0, 0, 28);
const ReceiveKey = 8;
const SendKey = 10;
const PacketFamilyRaw = 255;
const PacketFamilyConnection = 1;
const PacketFamilyAccount = 2;
const PacketFamilyLogin = 4;
const PacketActionRaw = 255;
const PacketActionRequest = 1;
const PacketActionAccept = 2;
const PacketActionReply = 3;
const PacketActionCreate = 6;
type TPacket = record
Family: Byte;
Action: Byte;
Data: AnsiString;
Time: Cardinal;
procedure SetID(AFamily, AAction: Byte);
procedure Reset; inline;
procedure Discard(Count: Integer = 1); inline;
procedure AddByte(b: Byte); inline;
procedure AddInt1(i: Byte); inline;
procedure AddInt2(i: Word); inline;
procedure AddInt3(i: Cardinal); inline;
procedure AddInt4(i: Cardinal); inline;
procedure AddBreakString(s: AnsiString); inline;
procedure AddString (s: AnsiString); inline;
function GetByte: Byte;
function GetInt1: Byte;
function GetInt2: Word;
function GetInt3: Cardinal;
function GetInt4: Cardinal;
function GetBreakString: AnsiString;
function GetString(Len: Integer = -1): AnsiString;
end;{TPacket}
type TSession = class
var Socket: TSocket;
var IPStr: AnsiString;
var IPInt: Integer;
var Thread: THandle;
var ID: Cardinal;
var Initialized: Boolean;
var Packet: record
Buffer: AnsiString;
Queue: record
Items: array of TPacket;
Time: Cardinal;
Active: Boolean;
end;{Queue}
Receive: TPacket;
Send: TPacket;
Time: Cardinal;
end;{Packet}
var Name: AnsiString;
var Password: AnsiString;
var HDDSerial: AnsiString;
constructor Create(ASocket: TSocket);
destructor Destroy; override;
function Sync(Discard: Boolean = False): Boolean;
procedure Unload;
procedure Log(Params: array of const);
procedure Send(Packet: TPacket; Raw: Boolean = False); overload;
procedure Send( Raw: Boolean = False); overload; inline;
function Execute: Boolean;
procedure DefaultHandler(var Param); override;
procedure UnhandledAction(Name: AnsiString = '');
procedure HandleRaw (var Param); message Server.PacketFamilyRaw;
procedure HandleConnection(var Param); message Server.PacketFamilyConnection;
procedure HandleAccount (var Param); message Server.PacketFamilyAccount;
procedure HandleLogin (var Param); message Server.PacketFamilyLogin;
end;{Session}
class var CriticalSection: TRTLCriticalSection;
class var Sessions: TArray<TSession>;
class var Socket: TSocket;
class var Database: TDatabase;
class var Configuration: TINIFile;
class var Connection: record
Bind: AnsiString;
Port: Word;
Timeout: Cardinal;
BytesIn: Int64;
BytesOut: Int64;
end;{Connection}
class var PacketQueue: record
Enabled: Boolean;
Size: Integer;
end;{Packet}
class constructor Create;
class destructor Destroy;
class procedure Main;
class var Caption: AnsiString;
class procedure UpdateCaption;
class procedure Log(Params: array of const; Prefix: AnsiString = '');
class function GetSessionByID(ID: Cardinal): TSession;
const NameMax = 12;
const NameChars = 'abcdefghijklmnopqrstuvwxyz0123456789';
class function ValidName(Name: AnsiString): Boolean;
class function GetAccount(Name: AnsiString; Items: AnsiString = '*'): TDatabase.TTable;
class function AccountExists(Name: AnsiString): Boolean;
end;{Server}
const
EOInt1Max = 253;
EOInt2Max = 64009;
EOInt3Max = 16194277;
function PackEOInt(b1: Byte = 0; b2: Byte = 0; b3: Byte = 0; b4: Byte = 0): Cardinal;
begin
if b1 = 254 then b1 := 0 else if b1 > 0 then dec(b1);
if b2 = 254 then b2 := 0 else if b2 > 0 then dec(b2);
if b3 = 254 then b3 := 0 else if b3 > 0 then dec(b3);
if b4 = 254 then b4 := 0 else if b4 > 0 then dec(b4);
Result := (b4 * EOInt3Max) + (b3 * EOInt2Max) + (b2 * EOInt1Max) + b1;
end;{PackEOInt}
function UnpackEOInt(Num: Cardinal): AnsiString;
var
i: Cardinal;
begin
Result := #254#254#254#254;
i := Num;
if i >= EOInt3Max then
begin
Result[4] := AnsiChar(Num div EOInt3Max + 1);
Num := Num mod EOInt3Max;
end;{if i >= EOInt3Max}
if i >= EOInt2Max then
begin
Result[3] := AnsiChar(Num div EOInt2Max + 1);
Num := Num mod EOInt2Max;
end;{if i >= EOInt2Max}
if i >= EOInt1Max then
begin
Result[2] := AnsiChar(Num div EOInt1Max + 1);
Num := Num mod EOInt1Max;
end;{if i >= EOInt3Max}
Result[1] := AnsiChar(Num + 1);
end;{UnpackEOInt}
function FoldData(Str: AnsiString; Key: Byte): AnsiString;
var
i: Integer;
c: AnsiChar;
Buffer: AnsiString;
begin
if Key = 0 then exit(Str);
Result := '';
Buffer := '';
for c in Str do
begin
if (ord(c) mod Key) = 0 then
Buffer := Buffer + c
else
begin
if length(Buffer) > 0 then
begin
for i := length(Buffer) downto 1 do
Result := Result + Buffer[i];
Buffer := '';
end;{if length(Buffer)}
Result := Result + c;
end;{else}
end;{for c}
if length(Buffer) > 0 then
for i := length(Buffer) downto 1 do
Result := Result + Buffer[i];
end;{FoldData}
function bswap(A: integer): Integer;
asm
bswap eax
end;{bswap}
procedure bswap256(s, d: PInteger);
asm
push ebx
mov ecx, eax
mov eax,[ecx]; mov ebx,[ecx+4]; bswap eax; bswap ebx; mov [edx], eax; mov [edx+4], ebx
mov eax,[ecx+8]; mov ebx,[ecx+12]; bswap eax; bswap ebx; mov [edx+8], eax; mov [edx+12], ebx
mov eax,[ecx+16]; mov ebx,[ecx+20]; bswap eax; bswap ebx; mov [edx+16], eax; mov [edx+20], ebx
mov eax,[ecx+24]; mov ebx,[ecx+28]; bswap eax; bswap ebx; mov [edx+24], eax; mov [edx+28], ebx
pop ebx
end;{bswap256}
function InterlockedExchangeAdd64(var Addend: Int64; Value: Int64): Int64; register;
asm
push edi
push esi
push ebp
push ebx
mov esi, dword ptr [Value]
mov edi, dword ptr [Value + 4]
mov ebp, eax
mov eax, [ebp]
mov edx, [ebp + 4]
@@lockmore:
mov ecx, edx
mov ebx, eax
add ebx, esi
adc ecx, edi
lock cmpxchg8b [ebp]
jnz @@lockmore
pop ebx
pop ebp
pop esi
pop edi
end;{InterlockedExchangeAdd64}
function Lower(S: AnsiString): AnsiString;
begin
Result := S;
if length(Result) = 0 then exit;
CharLowerBuffA(Pointer(Result), length(Result));
end;{Lower}
function Int(S: AnsiString; Default: Integer = 0): Integer;
var
Code: Integer;
begin
Val(String(S), Result, Code);
if Code <> 0 then Result := Default;
end;{Int}
function Str(I: Integer): AnsiString; overload;
var
S: ShortString;
begin
System.Str(I, S);
Result := AnsiString(S);
end;{Str(Integer}
function Str(F: Extended): AnsiString; overload;
var
S: ShortString;
begin
System.Str(F:2:2, S);
Result := AnsiString(S);
end;{Str(Extended}
function Tidy(s: AnsiString): AnsiString;
var
i: Integer;
c: AnsiChar;
begin
Result := '';
for c in s do
if pos(String(c), '0123456789.') > 0 then Result := Result + c;
if length(Result) = 0 then exit('0');
if pos('.', String(Result)) > 0 then
begin
while Result[length(Result)] = '0' do
Result := copy(Result, 1, length(Result) - 1);
if Result[length(Result)] = '.' then
Result := copy(Result, 1, length(Result) - 1);
end;{if pos('.'...}
while (length(Result) > 0) and (Result[1] = '0') do
Result := copy(Result, 2, length(Result));
i := pos('.', String(Result)) - 1; if i < 1 then i := length(Result);
repeat
dec(i, 3); if i < 1 then break;
Result := copy(Result, 1, i) + ',' + copy(Result, i + 1, length(Result));
until False;
if (length(Result) = 0) or (Result[1] = '.') then Result := '0' + Result;
end;{Tidy}
function Scale(i: Int64): AnsiString;
const
MinAdjustValue = 900;
ScaleStr: array[0..3] of AnsiString = (' bytes', ' KB', ' MB', ' GB');
var
j: Integer;
k: Extended;
begin
j := 0;
k := i;
while k > MinAdjustValue do
begin
k := k / 1024;
inc(j); if j = high(ScaleStr) then break;
end;{while i}
Result := Tidy(Str(k)) + ScaleStr[j];
end;{Scale}
function Str(B: Boolean): AnsiString; overload;
begin
if B then
Result := 'true'
else
Result := 'false';
end;{Str(Boolean}
function Bool(S: AnsiString; Default: Boolean = False): Boolean;
begin
if length(S) = 0 then exit(Default);
S := Lower(copy(S, 1, 2));
if (S[1] = 't') or (S = 'ok') or (S = 'on') then
Result := True
else
Result := Int(S, Integer(Default)) <> 0;
end;{Bool}
procedure Error(Params: array of const);
begin
Server.Log(Params, '/!\ ERROR');
halt(1);
end;{Error}
procedure CriticalSectionHelper.Create;
begin
{$IFDEF THREAD_SAFE}
InitializeCriticalSection(Self);
{$ENDIF THREAD_SAFE}
end;{CriticalSectionHelper.Create}
procedure CriticalSectionHelper.Free;
begin
{$IFDEF THREAD_SAFE}
DeleteCriticalSection(Self);
{$ENDIF THREAD_SAFE}
end;{CriticalSectionHelper.Free}
procedure CriticalSectionHelper.Enter;
begin
{$IFDEF THREAD_SAFE}
EnterCriticalSection(Self);
{$ENDIF THREAD_SAFE}
end;{CriticalSectionHelper.Enter}
procedure CriticalSectionHelper.Leave;
begin
{$IFDEF THREAD_SAFE}
LeaveCriticalSection(Self);
{$ENDIF THREAD_SAFE}
end;{CriticalSectionHelper.Leave}
procedure CriticalSectionHelper.Section(Code: procedureref);
begin
Enter;
try
Code;
finally
Leave;
end;{try...finally}
end;{CriticalSectionHelper.Secion}
constructor TDatabase.TTable.Create(ADatabase: TDatabase; SQL: AnsiString);
var
i: Integer;
Query: TSQLiteQuery;
begin
inherited Create;
Database := ADatabase;
Database.CriticalSection.Enter;
try
Query := Database.Prepare(SQL);
if Query = nil then exit;
while sqlite3_step(Query) = SQLITE_ROW do
begin
if length(Table) = 0 then
begin
SetLength(ColumnNames, sqlite3_column_count(Query));
for i := 0 to length(ColumnNames) - 1 do
ColumnNames[i] := lower(sqlite3_column_name(Query, i));
end;{if length(Table) = 0}
SetLength(Table, length(Table) + 1);
SetLength(Table[high(Table)], length(ColumnNames));
for i := 0 to length(ColumnNames) - 1 do
with Table[high(Table)][i] do
begin
DataType := sqlite3_column_type(Query, i);
case DataType of
SQLITE_INTEGER:
begin
DataInt := sqlite3_column_int(Query, i);
DataStr := Str(DataInt);
end;{SQLITE_INTEGER:}
SQLITE_TEXT:
begin
DataStr := sqlite3_column_text(Query, i);
DataInt := Int(DataStr);
end;{SQLITE_TEXT}
else
DataStr := '';
DataInt := 0;
end;{case DataType}
end;{with Table}
end;{while sqlite3_step}
finally
Database.Finalize(Query);
end;{try...finally}
end;{TDatabase.TTable.Create}
destructor TDatabase.TTable.Destroy;
begin
Database.CriticalSection.Leave;
inherited;
end;{TDatabase.TTable.Destroy}
function TDatabase.TTable.Empty: Boolean;
begin
Result := length(Table) = 0;
end;{TDatabase.Empty}
function TDatabase.TTable.Column(Name: AnsiString): Integer;
var
i: Integer;
begin
Name := lower(Name);
for i := 0 to length(ColumnNames) - 1 do
if Name = ColumnNames[i] then exit(i);
Result := -1;
end;{TDatabase.TTable.Column}
function TDatabase.TTable.Value(Name: AnsiString; Row: Integer = 0; Default: AnsiString = ''): AnsiString;
var
i: Integer;
begin
i := Column(Name);
if i = -1 then exit(Default);
Result := Table[Row][i].DataStr;
end;{TDatabase.TTable.Value(AnsiString}
function TDatabase.TTable.Value(Name: AnsiString; Row: Integer = 0; Default: Integer = 0): Integer;
var
i: Integer;
begin
i := Column(Name);
if i = -1 then exit(Default);
Result := Table[Row][i].DataInt;
end;{TDatabase.TTable.Value(Integer}
constructor TDatabase.Create(AFileName: AnsiString);
begin
inherited Create;
CriticalSection.Create;
FileName := AFileName;
Transaction := False;
if sqlite3_open(PAnsiChar(FileName), DB) <> SQLITE_OK then
Error(['Failed to open database "', FileName, '"']);
end;{TDatabase.Create}
destructor TDatabase.Destroy;
begin
if DB <> nil then
begin
if Transaction then
EndTransaction(True);
sqlite3_close(DB);
DB := nil;
end;{if DB <> nil}
CriticalSection.Free;
inherited;
end;{TDatabase.Destroy}
function TDatabase.Prepare(SQL: AnsiString): TSQLiteQuery;
var
NextQuery: PAnsiChar;
begin
if DB = nil then exit(nil);
{$IFDEF LOG_SQL}
Server.Log(['Database (', FileName, ') ', SQL]);
{$ENDIF LOG_SQL}
if sqlite3_prepare(DB, PAnsiChar(SQL), -1, Result, NextQuery) <> SQLITE_OK then
if Result <> nil then
Finalize(Result);
end;{TDatabase.Prepare}
procedure TDatabase.Finalize(var Query: TSQLiteQuery);
begin
if Query = nil then exit;
sqlite3_finalize(Query);
Query := nil;
end;{TDatabase.Finalize}
function TDatabase.Query(SQL: AnsiString): Boolean;
var
Query: TSQLiteQuery;
begin
CriticalSection.Enter;
try
Query := Prepare(SQL);
if Query = nil then exit(False);
Result := sqlite3_step(Query) = SQLITE_DONE;
finally
Finalize(Query);
CriticalSection.Leave;
end;{try...finally}
end;{TDatabase.Query}
function TDatabase.QueryTable(SQL: AnsiString): TTable;
begin
Result := TTable.Create(Self, SQL);
end;{TDatabase.QueryTable}
function TDatabase.TableExists(Name: AnsiString): Boolean;
begin
with QueryTable('SELECT `sql` FROM `sqlite_master` WHERE `type` = "table" AND `name` = "' + Name + '";') do try
Result := not Empty;
finally
Free;
end;{with QueryTable..}
end;{TDatabase.TableExists}
function TDatabase.BeginTransaction: Boolean;
begin
CriticalSection.Enter;
try
if Transaction then exit(False);
Result := Query('BEGIN TRANSACTION;');
if Result then Transaction := True;
finally
CriticalSection.Leave;
end;{try...finallly}
end;{TDatabase.BeginTransaction}
function TDatabase.EndTransaction(Rollback: Boolean = False): Boolean;
begin
CriticalSection.Enter;
try
//if not Transaction then exit(False);
if Rollback then
Result := Query('ROLLBACK;')
else
Result := Query('COMMIT;');
if Result then Transaction := False;
finally
CriticalSection.Leave;
end;{try...finally}
end;{TDatabase.EndTransaction}
constructor TINIFile.Create(AFileName: AnsiString);
begin
inherited Create;
FileName := AFileName;
CriticalSection.Create;
end;{TINIFile.Create}
destructor TINIFile.Destroy;
begin
CriticalSection.Free;
inherited;
end;{TINIFile.Destroy}
function TINIFile.Read(Section, Key: AnsiString; Default: AnsiString = ''): AnsiString;
begin
CriticalSection.Enter;
try
SetLength(Result, 256);
SetLength(Result, GetPrivateProfileStringA(PAnsiChar(Section), PAnsiChar(Key), PAnsiChar(Default), PAnsiChar(Result), length(Result), PAnsiChar(FileName)));
finally
CriticalSection.Leave;
end;{try...finally}
{$IFDEF LOG_CONFIG}
Server.Log(['Configuration (', FileName, ') [', Section, '] ', Key ,'=', Result]);
{$ENDIF LOG_CONFIG}
end;{TINIFile.Read(String}
function TINIFile.Read(Section, Key: AnsiString; Default: Integer = 0): Integer;
begin
Result := Int(Read(Section, Key, Str(Default)));
end;{TINIFile.Read(Integer}
function TINIFile.Read(Section, Key: AnsiString; Default: Boolean = False): Boolean;
begin
Result := Bool(Read(Section, Key, Str(Default)));
end;{TINIFile.Read(Boolean}
constructor TArray<T>.Create;
begin
inherited Create;
Clear;
end;{TArray<T>.Create}
destructor TArray<T>.Destroy;
begin
Clear;
inherited;
end;{TArray<T>.Destroy}
function TArray<T>.Find(Item: T): Integer;
var
i: Integer;
begin
for i := 0 to high(Items) do
if Items[i] = Item then exit(i);
Result := -1;
end;{TArray<T>.Add}
function TArray<T>.Add(Item: T): Integer;
begin
Result := Find(Item);
if Result = -1 then
begin
SetLength(Items, length(Items) + 1);
Result := high(Items);
Items[Result] := Item;
end;{if Result = -1}
end;{TArray<T>.Add}
function TArray<T>.Remove(Item: T): Integer;
begin
Result := Find(Item);
if Result = -1 then exit;
if Result < high(Items) then
move(Items[Result + 1], Items[Result], sizeof(T) * (length(Items) - 1));
SetLength(Items, length(Items) - 1);
end;{TArray<T>.Remove}
procedure TArray<T>.Clear;
begin
SetLength(Items, 0);
end;{TArray<T>.Clear}
procedure TSHA256.Init;
begin
Hash.A := $6a09e667;
Hash.B := $bb67ae85;
Hash.C := $3c6ef372;
Hash.D := $a54ff53a;
Hash.E := $510e527f;
Hash.F := $9b05688c;
Hash.G := $1f83d9ab;
Hash.H := $5be0cd19;
FillChar(Buffer, sizeof(Buffer), 0);
Index := 0;
MLen := 0;
end;{TSHA256.Init}
procedure TSHA256.Compress;
var
a, b, c, d, e, f, g, h: Cardinal;
t1, t2: Cardinal;
W: array[0..63] of Cardinal;
i: longword;
begin
Index:= 0;
Move(Buffer,W,Sizeof(Buffer));
a := Hash.A;
b := Hash.B;
c := Hash.C;
d := Hash.D;
e := Hash.E;
f := Hash.F;
g := Hash.G;
h := Hash.H;
for i:= 0 to 15 do
W[i] := bswap(W[i]);
for i:= 16 to 63 do
W[i] := (((W[i - 2] shr 17) or (W[i - 2] shl 15)) xor ((W[i - 2] shr 19) or
(W[i - 2] shl 13)) xor (W[i - 2] shr 10)) + W[i - 7] + (((W[i - 15]
shr 7) or (W[i - 15] shl 25)) xor ((W[i - 15] shr 18) or (W[i - 15]
shl 14)) xor (W[i - 15] shr 3)) + W[i - 16];
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $428a2f98 + W[0]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $71374491 + W[1]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $b5c0fbcf + W[2]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $e9b5dba5 + W[3]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $3956c25b + W[4]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $59f111f1 + W[5]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $923f82a4 + W[6]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $ab1c5ed5 + W[7]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $d807aa98 + W[8]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $12835b01 + W[9]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $243185be + W[10]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $550c7dc3 + W[11]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $72be5d74 + W[12]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $80deb1fe + W[13]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $9bdc06a7 + W[14]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $c19bf174 + W[15]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $e49b69c1 + W[16]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $efbe4786 + W[17]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $0fc19dc6 + W[18]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $240ca1cc + W[19]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $2de92c6f + W[20]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $4a7484aa + W[21]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $5cb0a9dc + W[22]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $76f988da + W[23]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $983e5152 + W[24]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $a831c66d + W[25]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $b00327c8 + W[26]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $bf597fc7 + W[27]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $c6e00bf3 + W[28]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $d5a79147 + W[29]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $06ca6351 + W[30]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $14292967 + W[31]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $27b70a85 + W[32]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $2e1b2138 + W[33]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $4d2c6dfc + W[34]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $53380d13 + W[35]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $650a7354 + W[36]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $766a0abb + W[37]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $81c2c92e + W[38]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $92722c85 + W[39]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $a2bfe8a1 + W[40]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $a81a664b + W[41]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $c24b8b70 + W[42]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $c76c51a3 + W[43]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $d192e819 + W[44]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $d6990624 + W[45]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $f40e3585 + W[46]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $106aa070 + W[47]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $19a4c116 + W[48]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $1e376c08 + W[49]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $2748774c + W[50]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $34b0bcb5 + W[51]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $391c0cb3 + W[52]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $4ed8aa4a + W[53]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $5b9cca4f + W[54]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $682e6ff3 + W[55]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
t1 := h + (((e shr 6) or (e shl 26)) xor ((e shr 11) or (e shl 21)) xor ((e shr 25) or (e shl 7))) + ((e and f) xor (not e and g)) + $748f82ee + W[56]; t2:= (((a shr 2) or (a shl 30)) xor ((a shr 13) or (a shl 19)) xor ((a shr 22) xor (a shl 10))) + ((a and b) xor (a and c) xor (b and c)); h := t1 + t2; d := d + t1;
t1 := g + (((d shr 6) or (d shl 26)) xor ((d shr 11) or (d shl 21)) xor ((d shr 25) or (d shl 7))) + ((d and e) xor (not d and f)) + $78a5636f + W[57]; t2:= (((h shr 2) or (h shl 30)) xor ((h shr 13) or (h shl 19)) xor ((h shr 22) xor (h shl 10))) + ((h and a) xor (h and b) xor (a and b)); g := t1 + t2; c := c + t1;
t1 := f + (((c shr 6) or (c shl 26)) xor ((c shr 11) or (c shl 21)) xor ((c shr 25) or (c shl 7))) + ((c and d) xor (not c and e)) + $84c87814 + W[58]; t2:= (((g shr 2) or (g shl 30)) xor ((g shr 13) or (g shl 19)) xor ((g shr 22) xor (g shl 10))) + ((g and h) xor (g and a) xor (h and a)); f := t1 + t2; b := b + t1;
t1 := e + (((b shr 6) or (b shl 26)) xor ((b shr 11) or (b shl 21)) xor ((b shr 25) or (b shl 7))) + ((b and c) xor (not b and d)) + $8cc70208 + W[59]; t2:= (((f shr 2) or (f shl 30)) xor ((f shr 13) or (f shl 19)) xor ((f shr 22) xor (f shl 10))) + ((f and g) xor (f and h) xor (g and h)); e := t1 + t2; a := a + t1;
t1 := d + (((a shr 6) or (a shl 26)) xor ((a shr 11) or (a shl 21)) xor ((a shr 25) or (a shl 7))) + ((a and b) xor (not a and c)) + $90befffa + W[60]; t2:= (((e shr 2) or (e shl 30)) xor ((e shr 13) or (e shl 19)) xor ((e shr 22) xor (e shl 10))) + ((e and f) xor (e and g) xor (f and g)); d := t1 + t2; h := h + t1;
t1 := c + (((h shr 6) or (h shl 26)) xor ((h shr 11) or (h shl 21)) xor ((h shr 25) or (h shl 7))) + ((h and a) xor (not h and b)) + $a4506ceb + W[61]; t2:= (((d shr 2) or (d shl 30)) xor ((d shr 13) or (d shl 19)) xor ((d shr 22) xor (d shl 10))) + ((d and e) xor (d and f) xor (e and f)); c := t1 + t2; g := g + t1;
t1 := b + (((g shr 6) or (g shl 26)) xor ((g shr 11) or (g shl 21)) xor ((g shr 25) or (g shl 7))) + ((g and h) xor (not g and a)) + $bef9a3f7 + W[62]; t2:= (((c shr 2) or (c shl 30)) xor ((c shr 13) or (c shl 19)) xor ((c shr 22) xor (c shl 10))) + ((c and d) xor (c and e) xor (d and e)); b := t1 + t2; f := f + t1;
t1 := a + (((f shr 6) or (f shl 26)) xor ((f shr 11) or (f shl 21)) xor ((f shr 25) or (f shl 7))) + ((f and g) xor (not f and h)) + $c67178f2 + W[63]; t2:= (((b shr 2) or (b shl 30)) xor ((b shr 13) or (b shl 19)) xor ((b shr 22) xor (b shl 10))) + ((b and c) xor (b and d) xor (c and d)); a := t1 + t2; e := e + t1;
inc(Hash.A, a);
inc(Hash.B, b);
inc(Hash.C, c);
inc(Hash.D, d);
inc(Hash.E, e);
inc(Hash.F, f);
inc(Hash.G, g);
inc(Hash.H, h);
FillChar(W,Sizeof(W),0);
FillChar(Buffer,Sizeof(Buffer),0);
end;{TSHA256.Compress}
procedure TSHA256.Update(Data: Pointer; Len: Integer);
var
i: Integer;
begin
inc(MLen, Int64(Cardinal(Len) shl 3));
while Len > 0 do
begin
i := 64 - Index;
if i <= Len then
begin
move(Data^, Buffer[Index], i);
dec(Len, i);
inc(Integer(Data), i);
Compress;
Index := 0;
end{if i <= Len}
else
begin
move(Data^, Buffer[Index], Len);
inc(Index, Len);
break;
end;{else}
end;{while Len > 0}
end;{TSHA256.Update}
function TSHA256.Done: AnsiString;
const
HexChar: array[0..15] of AnsiChar = '0123456789ABCDEF';
type
TInt64 = packed record
Lo, Hi: Cardinal;
end;{TInt64}
var
i: Integer;
PResult: PAnsiChar;
Digest: array[0..31] of Byte;
begin
Buffer[Index] := $80;
fillchar(Buffer[Index + 1], 63 - Index, 0);
if Index >= 56 then
begin
Compress;
fillchar(Buffer, 56, 0);
end;{if Index >= 56}
PInteger(@Buffer[56])^ := bswap(TInt64(MLen).Hi);
PInteger(@Buffer[60])^ := bswap(TInt64(MLen).Lo);
Compress;
bswap256(@Hash, @Digest);
Setlength(Result, sizeof(Digest) * 2);
PResult := PAnsiChar(Result);
for i := 0 to sizeof(Digest) - 1 do
begin
PResult[0] := HexChar[Digest[I] shr 4];
PResult[1] := HexChar[Digest[I] and 15];
inc(PResult,2);
end;{for i}
end;{TSHA256.Done}
class function TSHA256.HashStr(S: AnsiString): AnsiString;
var
SHA256: TSHA256;
begin
SHA256.Init;
SHA256.Update(PAnsiChar(S), length(S));
Result := SHA256.Done;
end;{class)TSHA256.HashStr}
class constructor Server.Create;
const
Banner = ' . . __ __ ___ __ _ _'#13#10' \`-"''"-''/ '+
'( \/ )( _) / \( \/\/ )'#13#10' } o o { - ) ( ) _)( () )\ '+
'/'#13#10' =. Y ,= (_/\/\_)(___) \__/ \/\/'#13#10' /-O-\ .'#13#10+
' / \ ) Mini EO? WOW!'#13#10' ( )-( )/ Created by Sordie '+
'out of bordem'#13#10' "" ""';
var
WSAData: TWSAData;
AddrIn: TSockAddrIn;
begin
Writeln(Banner);
CriticalSection.Create;
Sessions := TArray<TSession>.Create;
WSAStartup(MakeLong(2, 2), WSAData);
Configuration := TINIFile.Create('.\MEOW.ini');
Database := TDatabase.Create(Configuration.Read('database', 'name', '.\MEOW.db'));
Database.Query('DROP TABLE `accounts`;');
if not Database.TableExists('accounts') then
begin
Log(['Creating accounts database']);
if not Database.Query('CREATE TABLE `accounts` (' +
'`id` INTEGER PRIMARY KEY, ' +
'`name` VARCHAR (' + Str(NameMax) + '), ' +
'`password` VARCHAR (64)' +
');') then
Error(['Failed to create table']);
end;{if not Database.TableExists}
//Database.Query('INSERT INTO `accounts` (`name`) VALUES ("sordie");');
//Writeln(AccountExists('sordie'));
//Writeln(AccountExists('zordie'));
PacketQueue.Enabled := Configuration.Read('packetqueue', 'enabled', True);
if PacketQueue.Enabled then
PacketQueue.Size := Configuration.Read('packetqueue', 'size', 10);
Socket := WinSock.socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if Socket = 0 then
Error(['Failed to create socket']);
Connection.Bind := Configuration.Read('connection', 'bind', '0.0.0.0');
Connection.Port := Configuration.Read('connection', 'port', 8078);
Connection.Timeout := Configuration.Read('connection', 'timeout', 180000);
FillChar(AddrIn, sizeof(AddrIn), 0);
with AddrIn do
begin
sin_family := AF_INET;
sin_addr.S_addr := inet_addr(PAnsiChar(Connection.Bind));
sin_port := htons(Connection.Port);
end;{with AddrIn}
if bind(Socket, AddrIn, sizeof(AddrIn)) <> 0 then
Error(['Failed to bind socket']);
if listen(Socket, 0) <> 0 then
Error(['Cannot listen on socket']);
Connection.BytesIn := 0;
Connection.BytesOut := 0;
UpdateCaption;
try
Main;
except
Log(['Server Exception']);
end;{try...except}
end;{class)Server.Create}
class destructor Server.Destroy;
begin
if Socket <> 0 then
begin
closesocket(Socket);
Socket := 0;
end;{if Socket <> 0}
Sessions.Free;
Configuration.Free;
Database.Free;
CriticalSection.Free;
Readln;
end;{class)Server.Destroy}
class procedure Server.Main;
var
FDSet: TFDSet;
SockSize: Integer;
SockAddr: TSockAddr;
begin
repeat
Sleep(1);
FDSet.fd_count := 1;
FDSet.fd_array[0] := Socket;
if select(0, @FDSet, nil, nil, nil) = 1 then
begin
SockSize := sizeof(SockAddr);
TSession.Create(accept(Socket, @SockAddr, @SockSize));
end;{if select}
until Socket = 0;
end;{class)Server.Main}
class procedure Server.Log(Params: array of const; Prefix: AnsiString = '');
var
i: Integer;
begin
CriticalSection.Enter;
try
if length(Prefix) > 0 then
Write(Prefix + ' ');
for i := 0 to high(Params) do
with TVarRec(Params[i]) do
case VType of
vtInteger: Write(VInteger);
vtBoolean: Write(VBoolean);
vtChar: Write(VChar);
vtWideChar: Write(VWideChar);
vtExtended: Write(VExtended^);
vtString: Write(AnsiString(VString));
vtPointer: Write(Cardinal(VPointer));
vtPChar: Write(AnsiString(VPChar));
vtObject: Write(VObject.ClassName);
vtClass: Write(VClass.ClassName);
vtPWideChar: Write(WideString(VPWideChar));
vtWideString: Write(WideString(VWideString));
vtInt64: Write(VInt64^);
vtUnicodeString: Write(String(VUnicodeString));
vtAnsiString: Write(AnsiString(VAnsiString));
else
Write('?(', VType, ')');
end;{case VType}
finally
Writeln;
CriticalSection.Leave;
end;{try...finally}
end;{class)Server.Log}
class procedure Server.UpdateCaption;
begin
CriticalSection.Section(procedure
var
NewCaption: AnsiString;
begin
NewCaption := 'MEOW - ' +
Str(length(Sessions.Items)) + ' Connection(s) - ' +
Scale(Connection.BytesIn) + ' in / ' +
Scale(Connection.BytesOut) + ' out';
if NewCaption <> Caption then
begin
Caption := NewCaption;
SetConsoleTitleA(PAnsiChar(Caption));
end;{if NewCaption <> Caption}
end);{CriticalSection.Section}
end;{class)Server.Update}
class function Server.GetSessionByID(ID: Cardinal): TSession;
var
Session: TSession;
begin
CriticalSection.Enter;
try
for Session in Sessions.Items do
if Session.ID = ID then exit(Session);
Result := nil;
finally
CriticalSection.Leave;
end;{try...finally}
end;{class)Server.GetSessionByID}
class function Server.ValidName(Name: AnsiString): Boolean;
var
c: AnsiChar;
begin
if (length(Name) < 3) or (length(Name) > NameMax) then exit(False);
for c in Name do
if pos(String(c), NameChars) = 0 then
exit(False);
Result := True;
end;{class)Server.ValidName}
class function Server.GetAccount(Name: AnsiString; Items: AnsiString = '*'): TDatabase.TTable;
begin
Result := Database.QueryTable('SELECT ' + Items + ' FROM `accounts` WHERE `name` = "' + Name + '";');
end;{class)Server.GetAccount}
class function Server.AccountExists(Name: AnsiString): Boolean;
begin
with GetAccount(Name, '`id`') do try
Result := length(Table) > 0
finally
Free;
end;{with GetAccount}
end;{class)Server.AccountExists}
procedure Server.TPacket.SetID(AFamily, AAction: Byte);
begin
Family := AFamily;
Action := AAction;
end;{Server.TPacket.SetID}
procedure Server.TPacket.Reset;
begin
Data := '';
end;{Server.TPacket.Reset}
procedure Server.TPacket.Discard(Count: Integer = 1);
begin
Data := copy(Data, Count + 1, length(Data));
end;{Server.TPacket.Discard}
procedure Server.TPacket.AddByte(b: Byte);
begin
Data := Data + AnsiChar(b);
end;{Server.TPacket.AddByte}
procedure Server.TPacket.AddInt1(i: Byte);
begin
Data := Data + UnpackEOInt(i)[1];
end;{Server.TPacket.AddInt1}
procedure Server.TPacket.AddInt2(i: Word);
begin
Data := Data + copy(UnpackEOInt(i), 1, 2);
end;{Server.TPacket.AddInt2}
procedure Server.TPacket.AddInt3(i: Cardinal);
begin
Data := Data + copy(UnpackEOInt(i), 1, 3);
end;{Server.TPacket.AddInt3}
procedure Server.TPacket.AddInt4(i: Cardinal);
begin
Data := Data + UnpackEOInt(i);
end;{Server.TPacket.AddInt4}
procedure Server.TPacket.AddBreakString(s: AnsiString);
begin
Data := Data + s + #$FF;
end;{Server.TPacket.AddBreakString}
procedure Server.TPacket.AddString(s: AnsiString);
begin
Data := Data + s;
end;{Server.TPacket.AddString}
function Server.TPacket.GetByte: Byte;
begin
if length(Data) = 0 then exit(0);
Result := ord(Data[1]);
Data := copy(Data, 2, length(Data));
end;{Server.TPacket.GetByte}
function Server.TPacket.GetInt1: Byte;
begin
if length(Data) = 0 then exit(0);
Result := PackEOInt(ord(Data[1]));
Data := copy(Data, 2, length(Data));
end;{Server.TPacket.GetInt1}
function Server.TPacket.GetInt2: Word;
begin
if length(Data) = 0 then exit(0);
if length(Data) < 2 then exit(GetInt1);
Result := PackEOInt(ord(Data[1]), ord(Data[2]));
Data := copy(Data, 3, length(Data));
end;{Server.TPacket.GetInt2}
function Server.TPacket.GetInt3: Cardinal;
begin
if length(Data) = 0 then exit(0);
if length(Data) < 2 then exit(GetInt1);
if length(Data) < 3 then exit(GetInt2);
Result := PackEOInt(ord(Data[1]), ord(Data[2]), ord(Data[3]));
Data := copy(Data, 4, length(Data));
end;{Server.TPacket.GetInt3}
function Server.TPacket.GetInt4: Cardinal;
begin
if length(Data) = 0 then exit(0);
if length(Data) < 2 then exit(GetInt1);
if length(Data) < 3 then exit(GetInt2);
if length(Data) < 4 then exit(GetInt3);
Result := PackEOInt(ord(Data[1]), ord(Data[2]), ord(Data[3]), ord(Data[4]));
Data := copy(Data, 5, length(Data));
end;{Server.TPacketGetInt4}
function Server.TPacket.GetBreakString: AnsiString;
var
i: Integer;
begin
for i := 1 to length(Data) do
if Data[i] = #$FF then break;
Result := copy(Data, 1, i - 1);
Data := copy(Data, i + 1, length(Data));
end;{Server.TPacket.GetBreakString}
function Server.TPacket.GetString(Len: Integer = -1): AnsiString;
begin
if Len = -1 then
begin
Result := Data;
Data := '';
end{if Len = -1}
else
begin
Result := copy(Data, 1, Len);
Data := copy(Data, Len + 1, length(Data));
end;{else}
end;{Server.TPacket.GetString}
function SessionThread(Session: Server.TSession): Integer;
begin
Result := 0;
try
try
while Session.Execute do
Sleep(1);
except
Server.Log(['Session exception']);
end;{try...except}
finally
try
Session.Free;
except
{}
end;{try...except}
EndThread(Result);
end;{try...finally}
end;{SessionThread}
constructor Server.TSession.Create(ASocket: TSocket);
var
i: Integer;
Addr: TSockAddr;
begin
inherited Create;
Initialized := False;
Unload;
Socket := ASocket;
if Socket <> 0 then
begin
FillChar(Addr, sizeof(Addr), 0);
i := sizeof(Addr);
getpeername(Socket, Addr, i);
IPStr := AnsiString(inet_ntoa(Addr.sin_addr));
IPInt := Addr.sin_addr.S_addr;
i := 1;
ioctlsocket(Socket, FIONBIO, i);
end;{if Socket}
Server.CriticalSection.Section(procedure
begin
ID := 100;
while Server.GetSessionByID(ID) <> nil do inc(ID);
Server.Sessions.Add(Self);
end);{Server.CriticalSection.Section}
Packet.Time := GetTickCount + Server.Connection.Timeout;
BeginThread(nil, 0, @SessionThread, Pointer(Self), 0, Thread);
Log(['Created']);
Server.UpdateCaption;
end;{Server.TSession.Create}
destructor Server.TSession.Destroy;
begin
if Socket <> 0 then
begin
closesocket(Socket);
Socket := 0;
end;{if Socket <> 0}
Server.CriticalSection.Section(procedure
begin
Server.Sessions.Remove(Self);
end);{Server.CriticalSection.Section}
Unload;
Log(['Destroyed']);
inherited;
Server.UpdateCaption;
end;{Server.TSession.Destroy}
function Server.TSession.Sync(Discard: Boolean = False): Boolean;
var
SQL: AnsiString;
begin
if length(Name) = 0 then exit(False);
if Discard then
with Server.GetAccount(Name) do try
if length(Table) = 0 then exit(False);
Password := Value('password', 0, '');
if length(Password) = 0 then exit(False);
Result := True;
finally
Free;
end{with Server.GetAccount}
else
begin
if Server.AccountExists(Name) then
SQL := 'UPDATE `accounts` SET ' +
'`password` = "' + Password + '" ' +
' WHERE `name` = "' + Name + '";'
else
SQL := 'INSERT INTO `accounts` (' +
'`name`, ' +
'`password` ' +
') values (' +
'"' + Name + '", ' +
'"' + Password + '"' +
');';
Result := Server.Database.Query(SQL);
end{else}
end;{Server.TSession.Sync}
procedure Server.TSession.Unload;
begin
Name := '';
Password := '';
end;{Server.TSession.Unload}
procedure Server.TSession.Log(Params: array of const);
begin
Server.Log(Params, 'Session (' + IPStr + ')');
end;{Server.TSession.Log}
procedure Server.TSession.Send(Packet: TPacket; Raw: Boolean = False);
var
i, j, Size: Integer;
Encoded: AnsiString;
EncodeBuf: AnsiString;
begin
Encoded := copy(UnpackEOInt(length(Packet.Data) + 2), 1, 2) +
AnsiChar(Packet.Action) +
AnsiChar(Packet.Family) +
Packet.Data;
Size := length(Encoded);
if not Raw then
begin
Encoded := FoldData(Encoded, Server.SendKey);
SetLength(EncodeBuf, Size);
EncodeBuf[1] := Encoded[1];
EncodeBuf[2] := Encoded[2];
i := 2; j := 2;
while i < Size do
begin
EncodeBuf[i + 1] := AnsiChar(ord(Encoded[j + 1]) xor $80);
inc(j);
inc(i, 2);
end;{while i < Size}
i := Size - 1;
if Boolean(Size mod 2) then dec(i);
while i >= 2 do
begin
EncodeBuf[i + 1] := AnsiChar(ord(Encoded[j + 1]) xor $80);
inc(j);
dec(i, 2);
end;{while i >= 2}
for i := 3 to Size do
if EncodeBuf[i] = #128 then EncodeBuf[i] := #0
else if EncodeBuf[i] = #0 then EncodeBuf[i] := #128;
Encoded := EncodeBuf;
end;{if not Raw}
WinSock.send(Socket, Encoded[1], Size, 0);
InterlockedExchangeAdd64(Server.Connection.BytesOut, Size);
Server.UpdateCaption;
end;{Server.TSession.Send}
procedure Server.TSession.Send(Raw: Boolean = False);
begin
Send(Packet.Send, Raw);
end;{Server.TSession.Send}
function Server.TSession.Execute: Boolean;
procedure QueuePacket(Time: Cardinal);
begin
if length(Packet.Queue.Items) = Server.PacketQueue.Size then
begin
Log(['Packet queue full']);
Initialized := False;
exit;
end;{if length(Packet.Queue.Items}
SetLength(Packet.Queue.Items, length(Packet.Queue.Items) + 1);
Packet.Queue.Items[high(Packet.Queue.Items)] := Packet.Receive;
Packet.Queue.Items[high(Packet.Queue.Items)].Time := Time;
end;{QueuePacket}
function UnqueuePacket: Boolean;
begin
if (length(Packet.Queue.Items) = 0) or (GetTickCount < Packet.Queue.Time) then exit(False);
Result := True;
Packet.Receive := Packet.Queue.Items[high(Packet.Queue.Items)];
SetLength(Packet.Queue.Items, length(Packet.Queue.Items) - 1);
Packet.Queue.Time := GetTickCount + Packet.Receive.Time;
Packet.Receive.Time := GetTickCount;
end;{UnqueuePacket}
const
BufSize = 1024;
var
i: Integer;
Size: Integer;
ReadLen: Integer;
ReadBuf: AnsiString;
begin
if (Socket = 0) or (recv(Socket, nil^, 0, MSG_OOB) = 0) then
begin
Log(['Connection dropped']);
exit(False);
end;{if (Socket = 0)..}
if GetTickCount > Packet.Time then
begin
Log(['Connection timeout']);
exit(False);
end;{if GetTickCount}
Packet.Queue.Active := UnqueuePacket;
if not Packet.Queue.Active then
begin
if ioctlsocket(Socket, FIONREAD, i) = 0 then
begin
SetLength(ReadBuf, BufSize);
repeat
ReadLen := recv(Socket, ReadBuf[1], BufSize, 0);
if ReadLen < 1 then break;
InterlockedExchangeAdd64(Server.Connection.BytesIn, ReadLen);
Packet.Buffer := Packet.Buffer + copy(ReadBuf, 1, ReadLen);
until False;
Server.UpdateCaption;
Packet.Time := GetTickCount + Server.Connection.Timeout;
end;{if ioctlsocket}
if length(Packet.Buffer) < 2 then exit(True);
Size := PackEOInt(ord(Packet.Buffer[1]), ord(Packet.Buffer[2]));
if length(Packet.Buffer) < (Size + 2) then exit(True);
Packet.Receive.Data := copy(Packet.Buffer, 3, Size);
Packet.Buffer := copy(Packet.Buffer, Size + 3, length(Packet.Buffer));
if Size < 3 then exit(true);
if Initialized then
begin
ReadBuf := '';
i := 1;
while i <= length(Packet.Receive.Data) do
begin
ReadBuf := ReadBuf + AnsiChar(ord(Packet.Receive.Data[i]) xor $80);
inc(i, 2);
end;{while i <= length(Packet.Receive.Data)}
dec(i);
if Boolean(length(Packet.Receive.Data) mod 2) then dec(i, 2);
repeat
ReadBuf := ReadBuf + AnsiChar(ord(Packet.Receive.Data[i]) xor $80);
dec(i, 2);
until i <= 0;
for i := 3 to length(Packet.Receive.Data) do
if ReadBuf[i] = #128 then ReadBuf[i] := #0
else if ReadBuf[i] = #0 then ReadBuf[i] := #128;
Packet.Receive.Data := FoldData(ReadBuf, ReceiveKey);
end;{if Initialized}
Packet.Receive.Family := ord(Packet.Receive.Data[2]);
Packet.Receive.Action := ord(Packet.Receive.Data[1]);
Packet.Receive.Data := copy(Packet.Receive.Data, 3, length(Packet.Receive.Data));
Packet.Receive.Time := GetTickCount;
if Packet.Receive.Family <> Server.PacketFamilyRaw then
begin
// Sequence
Packet.Receive.GetByte;
end;{if Packet.Receive.Family}
end;{if not Packet.Queue.Active}
Packet.Send.Reset;
Packet.Send.SetID(Packet.Receive.Family, Server.PacketActionReply);
i := Packet.Receive.Family;
if (not Server.PacketQueue.Enabled) or Packet.Queue.Active then
Dispatch(i)
else
case Packet.Receive.Family of
0: ;
else
Dispatch(i)
end;{case Packet.Receive.Family}
Result := Initialized;
end;{Server.TSession.Execute}
procedure Server.TSession.DefaultHandler(var Param);
begin
{$IFDEF LOG_UNHANDLED_PACKET_FAMILY}
Log(['Unhandled packet family ', Packet.Receive.Family]);
{$ENDIF LOG_UNHANDLED_PACKET_FAMILY}
end;{Server.TSession.DefaultHandler}
procedure Server.TSession.UnhandledAction(Name: AnsiString = '');
begin
{$IFDEF LOG_UNHANDLED_PACKET_ACTION}
if length(Name) = 0 then Name := 'family (' + Str(Packet.Receive.Family) + ')';
Log(['Unhandled ' + Name + ' action ', Packet.Receive.Action]);
{$ENDIF LOG_UNHANDLED_PACKET_ACTION}
end;{Server.TSession.UnhandledAction}
procedure Server.TSession.HandleRaw(var Param);
function AuthClient(Auth: Integer): Integer;
begin
inc(Auth);
Result := (Auth mod 11 + 1) * 119;
if Result = 0 then exit;
Result := 110905 + (Auth mod 9 + 1) * ((11092004 - Auth) mod Result) * 119 + Auth mod 2004;
end;{AuthClient}
var
Auth: Integer;
s1, s2: Byte;
Ver: array[0..2] of Byte;
Seq: Byte;
begin
Packet.Send.SetID(Server.PacketFamilyRaw, Server.PacketActionRaw);
Auth := Packet.Receive.GetInt3;
Ver[0] := Packet.Receive.GetInt1;
Ver[1] := Packet.Receive.GetInt1;
Ver[2] := Packet.Receive.GetInt1;
if (Ver[0] < Server.RequiredVersion[0])
or (Ver[1] < Server.RequiredVersion[1])
or (Ver[2] < Server.RequiredVersion[2]) then
begin
Packet.Send.AddByte(1);
Packet.Send.AddByte(Server.RequiredVersion[0] + 1);
Packet.Send.AddByte(Server.RequiredVersion[1] + 1);
Packet.Send.AddByte(Server.RequiredVersion[2] + 1);
Log(['Invalid client version ', Ver[0], '.', Ver[1], '.', Ver[2]]);
Send(True);
exit;
end;{if (Ver...}
Packet.Receive.Discard(2);
HDDSerial := Packet.Receive.GetString;
//2 = ok
//3 = ip permabanned
//10 = some weird sound?
Packet.Send.AddByte(2);
Seq := 1 + Random(220);
s1 := (Seq + 12) div 7;
s2 := (Seq + 5) mod 7;
Packet.Send.AddByte(s1);
Packet.Send.AddByte(s2);
Log(['Initialized']);// s1:' + Str(s1) + ' s2:' + Str(s2)]);
Packet.Send.AddByte(Server.SendKey);
Packet.Send.AddByte(Server.ReceiveKey);
Packet.Send.AddInt2(ID);
Packet.Send.AddInt3(AuthClient(Auth));
Send(True);
Initialized := True;
end;{Server.TSession.HandleRaw}
procedure Server.TSession.HandleConnection;
procedure HandleConnectionAccept;
begin
{}
end;{HandleConnectionAccept}
begin
case Packet.Receive.Action of
Server.PacketActionAccept: HandleConnectionAccept;
else
UnhandledAction('connection');
end;{case Packet.Receive.Action}
end;{Server.TSession.HandleConnection}
procedure Server.TSession.HandleAccount;
const
AccountReplyAlreadyExists = 1;
AccountReplyNotApproved = 2;
AccountReplyCreated = 3;
AccountReplyChangeFailed = 5;
AccountReplyChanged = 6;
AccountReplyContinue = 1000;
function CheckAccount(AccountName: AnsiString): Boolean;
begin
Result := True;
if False{AccountsDisabled} then
else if not Server.ValidName(AccountName) then
begin
Packet.Send.AddInt2(AccountReplyNotApproved);
Packet.Send.AddString('NO');
Send;
end{else if not Server.ValidName}
else if Server.AccountExists(AccountName) then
begin
Packet.Send.AddInt2(AccountReplyAlreadyExists);
Packet.Send.AddString('NO');
Send;
end{else if}
else Result := False;
end;{CheckAccount}
procedure HandleAccountRequest;
var
AccountName: AnsiString;
begin
AccountName := Lower(Packet.Receive.GetString);
if CheckAccount(AccountName) then exit;
Packet.Send.AddInt2(AccountReplyContinue);
Packet.Send.AddString('OK');
Send;
end;{HandleAccountRequest}
procedure HandleAccountCreate;
var
AccountName: AnsiString;
begin
Packet.Receive.Discard(3);
AccountName := Lower(Packet.Receive.GetBreakString);
if CheckAccount(AccountName) then exit;
Name := AccountName;
Password := TSHA256.HashStr(Packet.Receive.GetBreakString);
{FullName := }Packet.Receive.GetBreakString;
{Location := }Packet.Receive.GetBreakString;
{EmailAddress := }Packet.Receive.GetBreakString;
{ComputerName := }Packet.Receive.GetBreakString;
if Packet.Receive.GetBreakString <> HDDSerial then
begin
Packet.Send.AddInt2(AccountReplyNotApproved);
Packet.Send.AddString('NO');
Send;
exit;
end;{if Packet.Receive.GetBreakString <> HDDSerial}
Log(['Creating account']);
Sync;
Writeln(Password);
Packet.Send.AddInt2(AccountReplyCreated);
Packet.Send.AddString('OK');
Send;
end;{HandleAccountCreate}
begin
case Packet.Receive.Action of
Server.PacketActionRequest: HandleAccountRequest;
Server.PacketActionCreate: HandleAccountCreate;
else
UnhandledAction('account');
end;{case Packet.Receive.Action}
end;{Server.TSession.HandleAccount}
procedure Server.TSession.HandleLogin(var Param);
const
LoginReplyUnknownUser = 1;
LoginReplyWrongPassword = 2;
LoginReplyOK = 3;
// 4 = clear input
LoginReplyAlreadyLoggedIn = 5;
procedure HandleLoginRequest;
begin
Server.CriticalSection.Section(procedure
var
Pass: AnsiString;
begin
Name := Packet.Receive.GetBreakString;
Pass := TSHA256.HashStr(Packet.Receive.GetBreakString);
// TODO: Check for logged in user
if not Sync(True) then
begin
Unload;
Packet.Send.AddInt2(LoginReplyUnknownUser);
end{if not Sync(True)}
else if Pass <> Password then
begin
Unload;
Packet.Send.AddInt2(LoginReplyWrongPassword);
end{else if Pass <> Password}
else
Packet.Send.AddInt2(LoginReplyOK);
Send;
end);{Server.CriticalSection.Section}
end;{HandleLoginRequest}
begin
case Packet.Receive.Action of
Server.PacketActionRequest: HandleLoginRequest;
else
UnhandledAction('login');
end;{case Packet.Receive.Action}
end;{Server.TSession.HandleLogin}
begin
Server.Create;
end.