www.pudn.com > pino3srv-src.zip > 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önnen nur in einem Methodenaufruf mit SYNCHRONIZE 
           genutzt werden, z.B. 
 
      Synchronize(UpdateCaption); 
 
  und UpdateCaption könnte 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); 
 
                       SendLine(PM_CLOAK,BS[Hidden],EC_NOERROR,''); 
                     end; 
      PM_JOIN       :begin 
                       if st='' then st:=Invited; 
                       if (LoggedIn(PM_JOIN)=false)or(st='') then Exit; 
 
                       i:=RoomList.IndexOf(st); 
                       if i=-1 then 
                         begin 
                           if (maxrooms>-1)and(RoomList.Count-SystemRoomCount>=maxrooms) then 
                             begin 
                               SendLine(PM_JOIN,SC_NORMAL,EC_TOOMANYROOMS,''); 
                               Exit; 
                             end; 
 
                           room:=TRoom.Create(st); 
                         end else room:=TRoom(RoomList.Objects[i]); 
 
                       room.AddUser(self,st=Invited); 
                       if Invited=st then Invited:=''; 
                     end; 
      PM_LEAVE      :begin 
                       i:=Rooms.IndexOf(st); 
                       if (LoggedIn(PM_LEAVE)=false)or(i=-1) then Exit; 
                       TRoom(Rooms.Objects[i]).RemoveUser(self); 
                     end; 
      PM_PRIVMSG    :begin 
                       if LoggedIn(PM_PRIVMSG)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=ActUsers.IndexOf(tokens[0]); 
                       if i>-1 then 
                         begin 
                           au:=TActUser(ActUsers.Objects[i]); 
 
                           au.CheckAway(PM_PRIVMSG,self,''); 
                           SendLine(PM_PRIVMSG,SC_NORMAL,EC_NOERROR,tokens[0]+#1+Color+#1+tokens[1]); 
                           au.UserAction(UA_PRIVMSG,SC_NORMAL,self,tokens[1]); 
                         end else SendLine(PM_PRIVMSG,SC_NORMAL,EC_USERNOTFOUND,tokens[0]); 
                     end; 
      PM_ROOMMSG    :begin 
                       if LoggedIn(PM_ROOMMSG)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=Rooms.IndexOf(tokens[0]); 
                       if i=-1 then Exit; 
                       room:=TRoom(Rooms.Objects[i]); 
 
                       if room.Gagged.IndexOf(self)>-1 then 
                         begin 
                           SendLine(PM_ROOMMSG,SC_NORMAL,EC_GAGGED,tokens[0]); 
                           Exit; 
                         end; 
 
                       if (stat=SC_ALERT)and(UserStatus(room,false)=US_NOOP) then 
                         begin 
                           SendLine(PM_ROOMMSG,SC_ALERT,EC_FORBIDDENCMD,tokens[0]); 
                           Exit; 
                         end; 
 
                       room.RoomAction(RA_MESSAGE,stat,self,tokens[1]); 
                     end; 
      PM_COLOR      :begin 
                       if (LoggedIn(PM_COLOR)=false)or(StrToIntDef('$'+st,-1)=-1)or(Length(st)<>6) then Exit; 
 
                       Color:=st; 
                       if RegUser<>nil then 
                         begin 
                           RegUser^.color:=StrToInt('$'+Color); 
                           WriteUserData(RegUser); 
                         end; 
                       for i:=0 to Rooms.Count-1 do TRoom(Rooms.Objects[i]).RoomAction(RA_COLOR,SC_NORMAL,self,''); 
                       UpdateUserInfo; 
                     end; 
      PM_INVITE     :begin 
                       if LoggedIn(PM_INVITE)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=ActUsers.IndexOf(tokens[1]);                                                                          // Ist eingeladener Benutzer vorhanden? 
                       if i>-1 then 
                         begin                                                                                                  // falls ja... 
                           au:=TActUser(ActUsers.Objects[i]);                                                                      // speicher Benutzerobjekt in "au" 
 
                           i:=Rooms.IndexOf(tokens[0]);                                                                            // Ist Einlader im Zielraum? 
                           if (i=-1)or(au.Rooms.IndexOf(tokens[0])>-1) then Exit;                                                  // falls nein oder Benutzer schon im Raum, abbrechen 
                           if UserStatus(Rooms.Objects[i],false)=US_NOOP then                                                      // falls Einladender kein RoomOP, ChatOP oder RoomOwner ist 
                             begin 
                               SendLine(PM_INVITE,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]);                                            // schicke Fehlermeldung 
                               Exit;                                                                                               // und breche ab 
                             end; 
                           au.Invited:=tokens[0];                                                                                  // speichere Zielraum in "Invited" des Eingeladenen ab 
 
                           au.CheckAway(PM_INVITE,self,tokens[0]); 
                           SendLine(PM_INVITE,SC_NORMAL,EC_NOERROR,tokens[0]+#1+tokens[1]);                                       // informiere Einladenden 
                           au.UserAction(UA_INVITE,SC_NORMAL,self,tokens[0]); 
                         end else SendLine(PM_INVITE,SC_NORMAL,EC_USERNOTFOUND,tokens[0]+#1+tokens[1]);                         // falls nein schicke Fehlermeldung an Einladenden 
                     end; 
      PM_KICK       :begin 
                       if LoggedIn(PM_KICK)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=Rooms.IndexOf(tokens[0]); 
                       if i=-1 then Exit; 
                       room:=TRoom(Rooms.Objects[i]); 
 
                       i:=room.Users.IndexOf(tokens[1]); 
                       if i=-1 then 
                         begin 
                           SendLine(PM_KICK,SC_NORMAL,EC_USERNOTFOUND,tokens[0]+#1+tokens[1]); 
                           Exit; 
                         end; 
                       au:=TActUser(room.Users.Objects[i]); 
 
                       if (UserStatus(room,false)>US_NOOP)and(room.Owner<>au) then 
                         begin 
                           room.RoomAction(RA_KICK,SC_NORMAL,self,tokens[1]); 
                           room.RemoveUser(au); 
                           au.UserAction(UA_KICK,SC_NORMAL,self,tokens[0]); 
                         end else SendLine(PM_KICK,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                     end; 
      PM_AWAY       :begin 
                       if (LoggedIn(PM_AWAY)=false)or(stat=SC_UNSET)and(Away=false) then Exit; 
 
                       Away:=stat<>SC_UNSET; 
                       if Away then AwayReason:=st; 
 
                       for i:=0 to Rooms.Count-1 do 
                         begin 
                           room:=TRoom(Rooms.Objects[i]); 
                           room.RoomAction(RA_AWAY,BS[Away],self,AwayReason+#1+UserStatus(room,true)); 
                         end; 
                       UpdateUserInfo; 
 
                       if Away=false then AwayReason:=''; 
                     end; 
      PM_SETRIGHTS  :begin 
                       if LoggedIn(PM_SETRIGHTS)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=Rooms.IndexOf(tokens[0]); 
                       if i=-1 then Exit; 
                       room:=TRoom(Rooms.Objects[i]); 
 
                       i:=room.Users.IndexOf(tokens[1]); 
                       if i=-1 then 
                         begin 
                           SendLine(PM_SETRIGHTS,SC_NORMAL,EC_USERNOTFOUND,tokens[0]+#1+tokens[1]); 
                           Exit; 
                         end; 
                       au:=TActUser(room.Users.Objects[i]); 
 
                       case stat of 
                         US_NOOP     :begin 
                                        if (UserStatus(room,false)US_ROOMOP) then 
                                          begin 
                                            SendLine(PM_SETRIGHTS,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                                            Exit; 
                                          end; 
 
                                        if room.ROPS.Remove(au)=-1 then Exit; 
 
                                        stat:=SC_LOST_ROP; 
                                      end; 
                         US_ROOMOP   :begin 
                                        if UserStatus(room,false)=US_NOOP then 
                                          begin 
                                            SendLine(PM_SETRIGHTS,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                                            Exit; 
                                          end; 
 
                                        if room.ROPS.IndexOf(au)=-1 then room.ROPS.Add(au); 
 
                                        stat:=SC_GOT_ROP; 
                                      end; 
                         US_ROOMOWNER:begin 
                                        if room.Owner<>self then 
                                          begin 
                                            SendLine(PM_SETRIGHTS,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                                            Exit; 
                                          end; 
 
                                        room.Owner:=au; 
                                        if room.ROPS.IndexOf(au)=-1 then room.ROPS.Add(au); 
 
                                        room.RoomAction(RA_RIGHTS,SC_LOST_ROW,nil,Nick+#1+UserStatus(room,true)); 
                                        stat:=SC_GOT_ROW; 
                                      end; 
                       end; 
 
                       room.RoomAction(RA_RIGHTS,stat,self,au.Nick+#1+au.UserStatus(room,true)); 
                     end; 
      PM_BOOT       :begin 
                       if LoggedIn(PM_BOOT)=false then Exit; 
 
                       if (RegUser=nil)or(RegUser^.chatop=false) then 
                         begin 
                           SendLine(PM_BOOT,SC_NORMAL,EC_FORBIDDENCMD,''); 
                           Exit; 
                         end; 
 
                       DivUp(st,#1,tokens,1,2); 
                       i:=ActUsers.IndexOf(tokens[0]); 
                       if i=-1 then 
                         begin 
                           SendLine(PM_BOOT,SC_NORMAL,EC_USERNOTFOUND,tokens[0]); 
                           Exit; 
                         end; 
                       au:=TActUser(ActUsers.Objects[i]); 
 
                       if tokens.Count=2 then OPKicked.AddObject(FloatToStr(Now+StrToIntDef(tokens[1],0)*0.0006944444),Pointer(au.IP.S_addr)); 
 
                       for i:=0 to au.Rooms.Count-1 do 
                         begin 
                           room:=TRoom(au.Rooms.Objects[i]); 
                           room.RoomAction(RA_BOOT,SC_NORMAL,self,au.Nick); 
                         end; 
                       au.SendLine(PM_DISCONN,SC_NORMAL,EC_BOOTED,Nick); 
                       SendLine(PM_BOOT,SC_NORMAL,EC_NOERROR,au.Nick); 
                       au.Close; 
                     end; 
      PM_BAN        :begin 
                       if LoggedIn(PM_BAN)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=ActUsers.IndexOf(tokens[1]); 
                       if i>-1 then 
                         begin 
                           au:=TActUser(ActUsers.Objects[i]); 
 
                           i:=Rooms.IndexOf(tokens[0]); 
                           if i=-1 then Exit; 
                           room:=TRoom(Rooms.Objects[i]); 
                           if UserStatus(room,false)=US_NOOP then 
                             begin 
                               SendLine(PM_BAN,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                               Exit; 
                             end; 
 
                           case stat of 
                             SC_NORMAL:if room.BannedIPs.Remove(Pointer(au.IP.S_addr))=-1 then room.BannedIPs.Add(Pointer(au.IP.S_addr)); 
                             SC_SET   :if room.BannedIPs.IndexOf(Pointer(au.IP.S_addr))=-1 then room.BannedIPs.Add(Pointer(au.IP.S_addr)) else Exit; 
                             SC_UNSET :if room.BannedIPs.Remove(Pointer(au.IP.S_addr))=-1 then Exit; 
                           end; 
 
                           room.RoomAction(RA_BAN,BS[room.BannedIPs.IndexOf(Pointer(au.IP.S_addr))>-1],self,au.Nick); 
                         end else SendLine(PM_BAN,SC_NORMAL,EC_USERNOTFOUND,tokens[0]+#1+tokens[1]); 
                     end; 
      PM_GAG        :begin 
                       if LoggedIn(PM_GAG)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=Rooms.IndexOf(tokens[0]); 
                       if i=-1 then Exit; 
                       room:=TRoom(Rooms.Objects[i]); 
 
                       i:=room.Users.IndexOf(tokens[1]); 
                       if i=-1 then 
                         begin 
                           SendLine(PM_GAG,SC_NORMAL,EC_USERNOTFOUND,tokens[0]+#1+tokens[1]); 
                           Exit; 
                         end; 
                       au:=TActUser(room.Users.Objects[i]); 
 
                       if (UserStatus(room,false)>US_NOOP)and(room.Owner<>au)and(au<>self)or(room.Owner=self) then 
                         begin 
                           case stat of 
                             SC_NORMAL:if room.Gagged.Remove(au)=-1 then room.Gagged.Add(au); 
                             SC_SET   :if room.Gagged.IndexOf(au)=-1 then room.Gagged.Add(au) else Exit; 
                             SC_UNSET :if room.Gagged.Remove(au)=-1 then Exit; 
                           end; 
 
                           room.RoomAction(RA_GAG,BS[room.Gagged.IndexOf(au)>-1],self,au.Nick); 
                         end else SendLine(PM_GAG,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                     end; 
      PM_PROFILE    :begin 
                       DivUp(st,#1,tokens,6,6); 
 
                       case stat of 
                         SC_REGISTER:begin 
                                       if ValidNickname(tokens[0])=false then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_REGISTER,EC_INVALIDNICK,''); 
                                           Exit; 
                                         end; 
 
                                       i:=RegUsers.IndexOf(tokens[0]); 
                                       if i>-1 then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_REGISTER,EC_NICKREGED,''); 
                                           Exit; 
                                         end; 
 
                                       i:=ActUsers.IndexOf(tokens[0]); 
                                       if (i>-1)and(ActUsers.Objects[i]<>self) then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_REGISTER,EC_NICKINUSE,''); 
                                           Exit; 
                                         end; 
 
                                       if (regpass<>0)and(tokens[1]<>IntToStr(regpass)) then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_REGISTER,EC_WRONGPWD,''); 
                                           Exit; 
                                         end; 
 
                                       New(ru); 
                                       ru^.nick:=tokens[0]; 
                                       ru^.pwd:=StrToIntDef(tokens[1],0); 
                                       ru^.email:=tokens[2]; 
                                       ru^.hp:=tokens[3]; 
                                       ru^.note:=tokens[4]; 
                                       if Nick=ru^.nick then ru^.color:=StrToInt('$'+Color) else ru^.Color:=$000000; 
                                       ru^.cloak:=StrToBool(tokens[5],false); 
                                       ru^.reged:=Now; 
                                       if Nick=ru^.nick then ru^.lastlogin:=Now else ru^.lastlogin:=0; 
                                       ru^.active:=true; 
                                       ru^.chatop:=false; 
 
                                       i:=RegUsers.IndexOf(''); 
                                       if i>-1 then 
                                         begin 
                                           RegUsers[i]:=ru^.nick; 
                                           RegUsers.Objects[i]:=Pointer(ru); 
                                         end else RegUsers.AddObject(ru^.nick,Pointer(ru)); 
 
                                       WriteUserData(ru); 
                                       if Nick=ru^.nick then RegUser:=ru; 
                                       SendLine(PM_PROFILE,SC_REGISTER,EC_NOERROR,''); 
                                     end; 
                         SC_GET     :begin 
                                       if (LoggedIn(PM_PROFILE)=false)or(RegUser=nil) then Exit; 
 
                                       if tokens[0]<>IntToStr(RegUser^.pwd) then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_GET,EC_WRONGPWD,''); 
                                           Exit; 
                                         end; 
 
                                       SendLine(PM_PROFILE,SC_GET,EC_NOERROR,RegUser^.email+#1+RegUser^.hp+#1+RegUser^.note+#1+BS[RegUser^.cloak]); 
                                     end; 
                         SC_EDIT    :begin 
                                       if (LoggedIn(PM_PROFILE)=false)or(RegUser=nil) then Exit; 
 
                                       if tokens[0]<>IntToStr(RegUser^.pwd) then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_EDIT,EC_WRONGPWD,''); 
                                           Exit; 
                                         end; 
 
                                       RegUser^.pwd:=StrToIntDef(tokens[1],0); 
                                       RegUser^.email:=tokens[2]; 
                                       RegUser^.hp:=tokens[3]; 
                                       RegUser^.note:=tokens[4]; 
                                       RegUser^.cloak:=StrToBool(tokens[5],false); 
 
                                       WriteUserData(RegUser); 
                                       SendLine(PM_PROFILE,SC_EDIT,EC_NOERROR,''); 
                                     end; 
                         SC_DELETE  :begin 
                                       if (LoggedIn(PM_PROFILE)=false)or(RegUser=nil) then Exit; 
 
                                       if tokens[0]<>IntToStr(RegUser^.pwd) then 
                                         begin 
                                           SendLine(PM_PROFILE,SC_DELETE,EC_WRONGPWD,''); 
                                           Exit; 
                                         end; 
 
                                       stat:=Char(RegUser^.chatop); 
 
                                       RegUser^.nick:=''; 
                                       WriteUserData(RegUser); 
                                       Dispose(RegUser); 
                                       RegUser:=nil; 
 
                                       i:=RegUsers.IndexOf(Nick); 
                                       RegUsers[i]:=''; 
 
                                       if Boolean(stat) then 
                                         begin 
                                           for i:=0 to Rooms.Count-1 do 
                                             begin 
                                               room:=TRoom(Rooms.Objects[i]); 
                                               room.RoomAction(RA_RIGHTS,SC_LOST_COP,nil,Nick+#1+UserStatus(room,true)); 
                                             end; 
                                           UpdateUserInfo; 
                                         end; 
 
                                       SendLine(PM_PROFILE,SC_DELETE,EC_NOERROR,''); 
                                     end; 
                       end; 
                     end; 
      PM_GETUSERINFO:begin 
                       if LoggedIn(PM_GETUSERINFO)=false then Exit; 
 
                       i:=ActUsers.IndexOf(st); 
                       if i>-1 then au:=TActUser(ActUsers.Objects[i]) else au:=nil; 
 
                       i:=RegUsers.IndexOf(st); 
                       if i>-1 then ru:=PRegUser(RegUsers.Objects[i]) else ru:=nil; 
 
                       if (au=nil)and(ru=nil) then 
                         begin 
                           SendLine(PM_GETUSERINFO,SC_NORMAL,EC_USERNOTFOUND,st); 
                           Exit; 
                         end; 
 
                       tokens.Clear; 
                       for i:=1 to 10 do tokens.Add(''); 
 
                       if au<>nil then 
                         begin 
                           tokens[0]:=au.Nick; 
                           tokens[1]:=au.Color; 
                           tokens[2]:=BS[au.Away]; 
                           tokens[3]:=au.AwayReason; 
 
                           try 
                             tokens[4]:=IntToStr(Round((Now-au.Lastact)/1.15740740740741E-5)); 
                           except 
                             Writeln('Fatal error 915: Please contact alcomp''s support at support@alcomp.net'); 
                             Writeln('Additionally information: '+FloatToStr(au.Lastact)+':'+FloatToStr(Now)); 
                             tokens[4]:='0'; 
                           end; 
 
                           if (RegUser<>nil)and(RegUser^.chatop) then tokens[5]:=inet_ntoa(au.IP); 
                         end; 
 
                       if ru<>nil then 
                         begin 
                           tokens[0]:=ru^.nick; 
                           tokens[1]:=Format('%.6x',[ru^.color]); 
                           tokens[6]:=ru^.email; 
                           tokens[7]:=ru^.hp; 
                           tokens[8]:=ru^.note; 
                           tokens[9]:=BS[ru^.chatop]; 
                         end; 
 
                       SendLine(PM_GETUSERINFO,SC_NORMAL,EC_NOERROR,tokens[0]+#1+tokens[1]+#1+tokens[2]+#1+tokens[3]+#1+tokens[4]+#1+tokens[5]+#1+tokens[6]+#1+tokens[7]+#1+tokens[8]+#1+tokens[9]); 
                     end; 
      PM_GETROOMINFO:begin 
                       i:=Rooms.IndexOf(st); 
                       if (LoggedIn(PM_GETROOMINFO)=false)or(i=-1) then Exit; 
 
                       room:=TRoom(Rooms.Objects[i]); 
                       SendLine(PM_GETROOMINFO,BS[not(room.System or (UserStatus(room,false)=US_NOOP))],EC_NOERROR,room.RoomInfo); 
                     end; 
      PM_SETROOMINFO:begin 
                       if LoggedIn(PM_SETROOMINFO)=false then Exit; 
 
                       DivUp(st,#1,tokens,6,6); 
                       i:=Rooms.IndexOf(tokens[0]); 
                       if i=-1 then Exit; 
 
                       room:=TRoom(Rooms.Objects[i]); 
                       if (room.System)or(UserStatus(room,false)=US_NOOP) then 
                         begin 
                           SendLine(PM_SETROOMINFO,SC_NORMAL,EC_FORBIDDENCMD,tokens[0]); 
                           Exit; 
                         end; 
 
                       if Byte(stat) and RI_TOPIC<>0 then room.Topic:=tokens[1]; 
                       if (Byte(stat) and RI_COLOR<>0)and(StrToIntDef('$'+tokens[2],-1)>-1)and(Length(tokens[2])=6) then room.BgCol:=tokens[2]; 
                       if Byte(stat) and RI_USERS<>0 then room.MaxUsers:=StrToIntDef(tokens[3],0); 
                       if Byte(stat) and RI_LOCKED<>0 then room.Closed:=StrToBool(tokens[4],not room.Closed); 
                       if Byte(stat) and RI_HIDDEN<>0 then 
                         begin 
                           room.Hidden:=StrToBool(tokens[5],not room.Hidden); 
                           if room.Hidden then for i:=0 to ActUsers.Count-1 do TActUser(ActUsers.Objects[i]).SendLine(PM_ROOMLIST,SC_REMOVE,EC_NOERROR,room.Name); 
                         end; 
 
                       room.RoomAction(RA_ROOMINFO,stat,self,room.RoomInfo); 
                       room.UpdateRoomInfo; 
                     end; 
      PM_DIRCON     :begin 
                       if LoggedIn(PM_DIRCON)=false then Exit; 
 
                       DivUp(st,#1,tokens,2,2); 
                       i:=ActUsers.IndexOf(tokens[0]); 
 
                       if i>-1 then 
                         begin 
                           au:=TActUser(ActUsers.Objects[i]); 
                           au.CheckAway(PM_DIRCON,self,''); 
                           au.UserAction(UA_DIRCON,SC_NORMAL,self,inet_ntoa(IP)+#1+tokens[1]); 
                         end else SendLine(PM_DIRCON,SC_NORMAL,EC_USERNOTFOUND,tokens[0]); 
                     end; 
    end; 
  end; 
 
function TActUser.LoggedIn(msg:Char):Boolean; 
  begin 
    Result:=Nick[1]<>' '; 
    if Result=false then SendLine(msg,SC_NORMAL,EC_NOTLOGGEDIN,''); 
  end; 
 
procedure TActUser.SendLine(cmd,stat,err:Char;msg:string); 
  begin 
    Send(cmd+stat+err+msg); 
  end; 
 
procedure TActUser.UpdateUserInfo; 
var i:Integer;st:string; 
  begin 
    if Hidden then Exit; 
 
    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; 
 
procedure TActUser.UserAction(action,status:Char;user:TActUser;msg:string); 
  begin 
    SendLine(PM_USERACTION,action,EC_NOERROR,status+user.Nick+#1+user.Color+#1+msg); 
  end; 
 
function TActUser.UserStatus(room:Pointer;showaway:Boolean):Char; 
  begin 
    Result:=US_NOOP; 
    if room<>nil then 
      begin 
        if TRoom(room).ROPS.IndexOf(self)>-1 then Result:=US_ROOMOP; 
        if TRoom(room).Owner=self then Result:=US_ROOMOWNER; 
      end; 
    if (RegUser<>nil)and(RegUser^.chatop) then Result:=US_CHATOP; 
    if (Away)and(showaway) then Result:=US_AWAY; 
  end; 
 
end.