📄 actuser.pas
字号:
unit actuser;
interface
uses Classes, abstuser, misc;
type TActUser = class(TUser)
private
{ Private-Deklarationen }
tokens:TStringList;
Away:Boolean;
AwayReason,Invited:string;
RegUser:PRegUser;
protected
procedure CheckAway(cmd:Char;user:TActUser;room:string);
procedure Execute; override;
procedure IncommingData(st:string); override;
function LoggedIn(msg:Char):Boolean;
public
Color:string[6];
Hidden:Boolean;
Lastact:TDateTime;
Nick:string[20];
Rooms:TStringList;
procedure SendLine(cmd,stat,err:Char;msg:string);
procedure UpdateUserInfo;
procedure UserAction(action,status:Char;user:TActUser;msg:string);
function UserStatus(room:Pointer;showaway:Boolean):Char;
end;
implementation
{ Wichtig: Methoden und Eigenschaften eines Objekts in der VCL
k鰊nen nur in einem Methodenaufruf mit SYNCHRONIZE
genutzt werden, z.B.
Synchronize(UpdateCaption);
und UpdateCaption k鰊nte sein,
procedure TActUser.UpdateCaption;
begin
Form1.Caption := 'Updated in einem Thread';
end; }
{ TActUser }
uses room, SysUtils, tools, Windows, WinSock;
{$I ..\..\defines.inc}
function StrToBool(st:string;default:Boolean):Boolean;
begin
Result:=default;
if (Length(st)>0)and(st[1] in ['0'..'1']) then Result:=Boolean(Byte(st[1])-48);
end;
function ValidNickname(st:string):Boolean;
var i,l:Integer;
begin
Result:=false;
l:=Length(st);
if l in [1..20]=false then Exit;
Result:=true;
for i:=1 to l do Result:=(Result)and(st[i] in [#33..#255])and(st[i]<>#160);
end;
procedure WriteUserData(ru:PRegUser);
var i:Integer;
begin
SetFilePointer(userdb,RegUsers.IndexOfObject(TObject(ru))*soru,nil,FILE_BEGIN);
WriteFile(userdb,ru^,soru,i,nil);
FlushFileBuffers(userdb);
end;
procedure TActUser.CheckAway(cmd:Char;user:TActUser;room:string);
begin
if Away then user.SendLine(cmd,SC_USERISAWAY,EC_NOERROR,Nick+#1+AwayReason+#1+room);
end;
procedure TActUser.Execute;
var i:Integer;acc_conn:Boolean;
begin
// ActUsers.AddObject(' '+IntToStr(Socket),self);
// Writeln('User connected: Connected users ',ActUsers.Count);
tokens:=TStringList.Create;
Rooms:=TStringList.Create;
Away:=false;
AwayReason:='';
Color:='000000';
Hidden:=true;
Invited:='';
Lastact:=Now;
Nick:=' '+IntToStr(Socket);
RegUser:=nil;
EnterCriticalSection(synchronizer);
ActUsers.AddObject(Nick,self);
Log('Incoming user connection from '+inet_ntoa(IP)+' - User connections: '+IntToStr(ActUsers.Count));
acc_conn:=true;
if (maxusers>0)and(ActUsers.Count>maxusers) then
begin
SendLine(PM_DISCONN,SC_NORMAL,EC_TOOMANYUSERS,'');
acc_conn:=false;
end;
if AllowedIP(inet_ntoa(IP),UserIPs,true)=false then
begin
SendLine(PM_DISCONN,SC_NORMAL,EC_BANNED,'');
acc_conn:=false;
end;
i:=OPKicked.IndexOfObject(Pointer(IP.S_addr));
if i>-1 then
begin
if StrToFloat(OPKicked[i])>Now then
begin
SendLine(PM_DISCONN,SC_NORMAL,EC_TEMPBANNED,'');
acc_conn:=false;
end else OPKicked.Delete(i);
end;
if acc_conn then
begin
SendLine(PM_HELLO,SC_NORMAL,EC_NOERROR,'3.'+IntToStr(Build));
LeaveCriticalSection(synchronizer);
inherited Execute;
EnterCriticalSection(synchronizer);
end else Close;
ActUsers.Delete(ActUsers.IndexOf(Nick));
for i:=Rooms.Count-1 downto 0 do TRoom(Rooms.Objects[i]).RemoveUser(self);
if Hidden=false then for i:=0 to ActUsers.Count-1 do TActUser(Actusers.Objects[i]).SendLine(PM_USERLIST,SC_REMOVE,EC_NOERROR,Nick);
LeaveCriticalSection(synchronizer);
Rooms.Free;
tokens.Free;
Log('Closed user connection for '+inet_ntoa(IP)+' ('+Nick+') - User connections: '+IntToStr(ActUsers.Count));
end;
procedure TActUser.IncommingData(st:string);
var cmd,stat:Char;i{,i2}:Integer;room:TRoom;au:TActUser;ru:PRegUser;
begin
if Length(st)<2 then Exit;
cmd:=st[1];
stat:=st[2];
Delete(st,1,2);
Lastact:=Now;
case cmd of
PM_HELLO :begin
SendLine(PM_INIT,SC_INFO,EC_NOERROR,chatname+#1+welcome.Text);
if bannerupdate>0 then SendLine(PM_INIT,SC_BANNER,EC_NOERROR,IntToStr(bannerupdate)+':'+banners.Text);
st:='';
for i:=0 to RoomList.Count-1 do
begin
room:=TRoom(RoomList.Objects[i]);
if room.Hidden=false then st:=st+room.RoomInfo+#2;
end;
SendLine(PM_INIT,SC_ROOMLIST,EC_NOERROR,st);
st:='';
for i:=0 to ActUsers.Count-1 do
begin
au:=TActUser(ActUsers.Objects[i]);
if au.Hidden=false then st:=st+au.Nick+#1+au.Color+#1+au.UserStatus(nil,true)+#2;
end;
SendLine(PM_INIT,SC_USERLIST,EC_NOERROR,st);
end;
PM_NICK :begin
DivUp(st,#1,tokens,2,2);
Log(inet_ntoa(IP)+' wants to log in as '+tokens[0]);
if ValidNickname(tokens[0])=false then
begin
Log('Nickname is invalid ('+tokens[0]+')');
SendLine(PM_NICK,SC_NORMAL,EC_INVALIDNICK,'');
Exit;
end;
if ActUsers.IndexOf(tokens[0])>-1 then
begin
Log('Nickname is already in use ('+tokens[0]+')');
SendLine(PM_NICK,SC_NORMAL,EC_NICKINUSE,'');
Exit;
end;
i:=RegUsers.IndexOf(tokens[0]);
if (i=-1)and(noanos) then
begin
SendLine(PM_NICK,SC_NORMAL,EC_NOANONYMOUS,'');
Exit;
end;
if i>-1 then
begin
if tokens[1]<>IntToStr(PRegUser(RegUsers.Objects[i])^.pwd) then
begin
SendLine(PM_NICK,SC_NORMAL,EC_WRONGPWD,'');
Exit;
end;
if PRegUser(RegUsers.Objects[i])^.active=false then
begin
SendLine(PM_NICK,SC_NORMAL,EC_ACCTDISABLED,'');
Exit;
end;
RegUser:=Pointer(RegUsers.Objects[i]);
RegUser^.lastlogin:=Now;
WriteUserData(RegUser);
end else RegUser:=nil;
st:=Nick;
ActUsers[ActUsers.IndexOf(Nick)]:=tokens[0];
Nick:=tokens[0];
if RegUser<>nil then Color:=Format('%.6x',[RegUser^.color]);
for i:=0 to Rooms.Count-1 do
begin
with TRoom(Rooms.Objects[i]) do
begin
Users[Users.IndexOf(st)]:=Nick;
RoomAction(RA_NICK,SC_NORMAL,self,st+#1+UserStatus(Rooms.Objects[i],true));
end;
end;
cmd:=UserStatus(nil,true);
for i:=0 to ActUsers.Count-1 do
begin
au:=TActUser(ActUsers.Objects[i]);
if (st[1]<>' ')and(Hidden=false) then au.SendLine(PM_USERLIST,SC_REMOVE,EC_NOERROR,st);
if ((st[1]<>' ')xor(Hidden))and not((RegUser<>nil)and(RegUser^.cloak)) then au.SendLine(PM_USERLIST,SC_ADD,EC_NOERROR,Nick+#1+Color+#1+cmd);
end;
Hidden:=not (((st[1]<>' ')xor(Hidden))and not((RegUser<>nil)and(RegUser^.cloak)));
Log(inet_ntoa(IP)+' successfully logged in as '+tokens[0]);
if RegUser=nil then SendLine(PM_NICK,SC_NORMAL,EC_NOERROR,'') else SendLine(PM_NICK,SC_NORMAL,EC_NOERROR,Color);
end;
PM_CLOAK :begin
if LoggedIn(PM_CLOAK)=false then Exit;
case stat of
SC_NORMAL:Hidden:=not Hidden;
SC_SET :if Hidden=false then Hidden:=true else Exit;
SC_UNSET :if Hidden=true then Hidden:=false else Exit;
end;
if Hidden=false then
begin
st:=Nick+#1+Color+#1+UserStatus(nil,true);
for i:=0 to ActUsers.Count-1 do TActUser(ActUsers.Objects[i]).SendLine(PM_USERLIST,SC_ADD,EC_NOERROR,st);
end else for i:=0 to ActUsers.Count-1 do TActUser(ActUsers.Objects[i]).SendLine(PM_USERLIST,SC_REMOVE,EC_NOERROR,Nick);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -