2012-04-19 20:58:29 +02:00
/*
* InspIRCd - - Internet Relay Chat Daemon
2007-07-16 17:30:04 +00:00
*
2012-04-19 20:58:29 +02:00
* Copyright ( C ) 2009 - 2010 Daniel De Graaf < danieldg @ inspircd . org >
* Copyright ( C ) 2006 - 2009 Robin Burchell < robin + git @ viroteck . net >
* Copyright ( C ) 2006 - 2007 , 2009 Dennis Friis < peavey @ inspircd . org >
* Copyright ( C ) 2008 John Brooks < john . brooks @ dereferenced . net >
* Copyright ( C ) 2008 Thomas Stagner < aquanight @ inspircd . org >
* Copyright ( C ) 2008 Oliver Lupton < oliverlupton @ gmail . com >
* Copyright ( C ) 2003 - 2008 Craig Edwards < craigedwards @ brainbox . cc >
2007-07-16 17:30:04 +00:00
*
2012-04-19 20:58:29 +02:00
* This file is part of InspIRCd . InspIRCd is free software : you can
* redistribute it and / or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation , version 2.
2007-07-16 17:30:04 +00:00
*
2012-04-19 20:58:29 +02:00
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-07-16 17:30:04 +00:00
*/
2012-04-19 20:58:29 +02:00
2007-07-16 17:30:04 +00:00
# include "inspircd.h"
# include "xline.h"
2007-10-15 20:59:05 +00:00
bool User : : IsNoticeMaskSet ( unsigned char sm )
2007-07-16 17:30:04 +00:00
{
2008-08-25 15:49:39 +00:00
if ( ! isalpha ( sm ) )
return false ;
2007-07-16 17:30:04 +00:00
return ( snomasks [ sm - 65 ] ) ;
}
2016-12-30 18:51:56 +01:00
bool User : : IsModeSet ( unsigned char m ) const
2007-07-16 17:30:04 +00:00
{
2014-02-21 15:11:24 +01:00
ModeHandler * mh = ServerInstance - > Modes - > FindMode ( m , MODETYPE_USER ) ;
return ( mh & & modes [ mh - > GetId ( ) ] ) ;
2007-07-16 17:30:04 +00:00
}
2016-12-30 18:58:31 +01:00
std : : string User : : GetModeLetters ( bool includeparams ) const
2007-07-16 17:30:04 +00:00
{
2016-12-30 18:58:31 +01:00
std : : string ret ( 1 , ' + ' ) ;
2008-08-31 13:00:12 +00:00
std : : string params ;
2016-12-30 18:58:31 +01:00
for ( unsigned char i = ' A ' ; i < ' z ' ; i + + )
2007-07-16 17:30:04 +00:00
{
2016-12-30 18:58:31 +01:00
const ModeHandler * const mh = ServerInstance - > Modes . FindMode ( i , MODETYPE_USER ) ;
if ( ( ! mh ) | | ( ! IsModeSet ( mh ) ) )
continue ;
ret . push_back ( mh - > GetModeChar ( ) ) ;
if ( ( includeparams ) & & ( mh - > NeedsParam ( true ) ) )
2008-08-31 13:00:12 +00:00
{
2016-12-30 18:58:31 +01:00
const std : : string val = mh - > GetUserParameter ( this ) ;
if ( ! val . empty ( ) )
params . append ( 1 , ' ' ) . append ( val ) ;
2008-08-31 13:00:12 +00:00
}
2007-07-16 17:30:04 +00:00
}
2016-12-30 18:58:31 +01:00
ret + = params ;
return ret ;
2007-07-16 17:30:04 +00:00
}
2017-11-17 00:02:03 +00:00
User : : User ( const std : : string & uid , Server * srv , UserType type )
2016-08-10 17:30:02 +02:00
: age ( ServerInstance - > Time ( ) )
, signon ( 0 )
, uuid ( uid )
2016-08-10 17:26:49 +02:00
, server ( srv )
2016-08-10 17:30:02 +02:00
, registered ( REG_NONE )
, quitting ( false )
2016-08-10 17:26:49 +02:00
, usertype ( type )
2007-07-16 17:30:04 +00:00
{
2009-10-21 23:45:08 +00:00
client_sa . sa . sa_family = AF_UNSPEC ;
2007-08-27 13:36:11 +00:00
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " USERS " , LOG_DEBUG , " New UUID for user: %s " , uuid . c_str ( ) ) ;
2007-08-27 13:54:15 +00:00
2015-12-07 10:11:09 +01:00
// Do not insert FakeUsers into the uuidlist so FindUUID() won't return them which is the desired behavior
if ( type ! = USERTYPE_SERVER )
{
if ( ! ServerInstance - > Users . uuidlist . insert ( std : : make_pair ( uuid , this ) ) . second )
throw CoreException ( " Duplicate UUID in User constructor: " + uuid ) ;
}
2007-07-16 17:30:04 +00:00
}
2009-11-01 21:53:47 +00:00
LocalUser : : LocalUser ( int myfd , irc : : sockets : : sockaddrs * client , irc : : sockets : : sockaddrs * servaddr )
2016-08-10 17:26:49 +02:00
: User ( ServerInstance - > UIDGen . GetUID ( ) , ServerInstance - > FakeClient - > server , USERTYPE_LOCAL )
, eh ( this )
, bytes_in ( 0 )
, bytes_out ( 0 )
, cmds_in ( 0 )
, cmds_out ( 0 )
2016-08-10 17:30:02 +02:00
, quitting_sendq ( false )
, lastping ( true )
, exempt ( false )
2016-08-10 17:26:49 +02:00
, nping ( 0 )
2016-08-10 17:30:02 +02:00
, idle_lastmsg ( 0 )
2016-08-10 17:26:49 +02:00
, CommandFloodPenalty ( 0 )
, already_sent ( 0 )
2009-10-21 23:44:48 +00:00
{
2016-08-10 17:30:02 +02:00
signon = ServerInstance - > Time ( ) ;
// The user's default nick is their UUID
nick = uuid ;
2012-07-09 15:35:12 +02:00
ident = " unknown " ;
2009-11-06 22:37:36 +00:00
eh . SetFd ( myfd ) ;
2012-11-21 02:20:23 +01:00
memcpy ( & client_sa , client , sizeof ( irc : : sockets : : sockaddrs ) ) ;
2009-11-01 21:53:47 +00:00
memcpy ( & server_sa , servaddr , sizeof ( irc : : sockets : : sockaddrs ) ) ;
2017-10-22 21:53:24 +01:00
ChangeRealHost ( GetIPString ( ) , true ) ;
2009-10-21 23:44:48 +00:00
}
2007-10-15 20:59:05 +00:00
User : : ~ User ( )
2007-07-16 17:30:04 +00:00
{
}
2008-05-18 23:15:53 +00:00
const std : : string & User : : MakeHost ( )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > cached_makehost . empty ( ) )
2007-07-16 17:30:04 +00:00
return this - > cached_makehost ;
2013-05-18 18:40:55 +01:00
// XXX: Is there really a need to cache this?
2017-10-22 21:53:24 +01:00
this - > cached_makehost = ident + " @ " + GetRealHost ( ) ;
2007-07-16 17:30:04 +00:00
return this - > cached_makehost ;
}
2008-05-18 23:15:53 +00:00
const std : : string & User : : MakeHostIP ( )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > cached_hostip . empty ( ) )
2007-07-16 17:30:04 +00:00
return this - > cached_hostip ;
2013-05-18 18:40:55 +01:00
// XXX: Is there really a need to cache this?
this - > cached_hostip = ident + " @ " + this - > GetIPString ( ) ;
2007-07-16 17:30:04 +00:00
return this - > cached_hostip ;
}
2009-10-23 22:47:39 +00:00
const std : : string & User : : GetFullHost ( )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > cached_fullhost . empty ( ) )
2007-07-16 17:30:04 +00:00
return this - > cached_fullhost ;
2013-05-18 18:40:55 +01:00
// XXX: Is there really a need to cache this?
2017-10-22 21:53:24 +01:00
this - > cached_fullhost = nick + " ! " + ident + " @ " + GetDisplayedHost ( ) ;
2007-07-16 17:30:04 +00:00
return this - > cached_fullhost ;
}
2009-10-23 22:47:39 +00:00
const std : : string & User : : GetFullRealHost ( )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > cached_fullrealhost . empty ( ) )
2007-07-16 17:30:04 +00:00
return this - > cached_fullrealhost ;
2013-05-18 18:40:55 +01:00
// XXX: Is there really a need to cache this?
2017-10-22 21:53:24 +01:00
this - > cached_fullrealhost = nick + " ! " + ident + " @ " + GetRealHost ( ) ;
2007-07-16 17:30:04 +00:00
return this - > cached_fullrealhost ;
}
2016-08-30 16:05:01 +02:00
bool User : : HasModePermission ( const ModeHandler * mh ) const
2008-03-23 20:43:35 +00:00
{
2009-10-21 23:45:32 +00:00
return true ;
}
2008-03-23 20:43:35 +00:00
2016-08-30 16:05:01 +02:00
bool LocalUser : : HasModePermission ( const ModeHandler * mh ) const
2009-10-21 23:45:32 +00:00
{
2013-04-09 19:12:09 +02:00
if ( ! this - > IsOper ( ) )
2008-03-23 20:43:35 +00:00
return false ;
2016-08-30 16:05:01 +02:00
const unsigned char mode = mh - > GetModeChar ( ) ;
2008-09-13 15:47:01 +00:00
if ( mode < ' A ' | | mode > ( ' A ' + 64 ) ) return false ;
2008-03-23 21:12:36 +00:00
2016-08-30 16:05:01 +02:00
return ( ( mh - > GetModeType ( ) = = MODETYPE_USER ? oper - > AllowedUserModes : oper - > AllowedChanModes ) ) [ ( mode - ' A ' ) ] ;
2009-02-14 21:14:36 +00:00
2008-03-23 20:43:35 +00:00
}
2009-10-21 23:45:32 +00:00
/*
* users on remote servers can completely bypass all permissions based checks .
* This prevents desyncs when one server has different type / class tags to another .
* That having been said , this does open things up to the possibility of source changes
* allowing remote kills , etc - but if they have access to the src , they most likely have
* access to the conf - so it ' s an end to a means either way .
*/
bool User : : HasPermission ( const std : : string & )
2007-07-16 17:30:04 +00:00
{
2009-10-21 23:45:32 +00:00
return true ;
}
2007-07-16 17:30:04 +00:00
2009-10-21 23:45:32 +00:00
bool LocalUser : : HasPermission ( const std : : string & command )
{
2007-07-16 17:30:04 +00:00
// are they even an oper at all?
2013-04-09 19:12:09 +02:00
if ( ! this - > IsOper ( ) )
2007-07-16 17:30:04 +00:00
{
2007-10-15 22:33:18 +00:00
return false ;
}
2017-08-17 18:32:19 +01:00
return oper - > AllowedOperCommands . Contains ( command ) ;
2007-07-16 17:30:04 +00:00
}
2008-10-18 16:52:48 +00:00
bool User : : HasPrivPermission ( const std : : string & privstr , bool noisy )
2008-10-18 16:52:44 +00:00
{
2009-10-21 23:45:32 +00:00
return true ;
}
2008-10-18 16:52:48 +00:00
2009-10-21 23:45:32 +00:00
bool LocalUser : : HasPrivPermission ( const std : : string & privstr , bool noisy )
{
2013-04-09 19:12:09 +02:00
if ( ! this - > IsOper ( ) )
2008-10-18 16:52:48 +00:00
{
if ( noisy )
2013-04-28 12:17:53 +01:00
this - > WriteNotice ( " You are not an oper " ) ;
2008-10-18 16:52:48 +00:00
return false ;
}
2017-08-17 18:32:19 +01:00
if ( oper - > AllowedPrivs . Contains ( privstr ) )
2008-10-18 16:52:48 +00:00
return true ;
if ( noisy )
2013-05-16 01:56:06 +02:00
this - > WriteNotice ( " Oper type " + oper - > name + " does not have access to priv " + privstr ) ;
2013-04-28 12:17:53 +01:00
2008-10-18 16:52:48 +00:00
return false ;
2008-10-18 16:52:44 +00:00
}
2009-11-06 22:37:36 +00:00
void UserIOHandler : : OnDataReady ( )
2009-10-21 23:45:08 +00:00
{
2009-11-06 22:37:36 +00:00
if ( user - > quitting )
2009-09-21 13:26:31 +00:00
return ;
2007-07-16 17:30:04 +00:00
2009-11-06 22:37:36 +00:00
if ( recvq . length ( ) > user - > MyClass - > GetRecvqMax ( ) & & ! user - > HasPrivPermission ( " users/flood/increased-buffers " ) )
2007-07-16 17:30:04 +00:00
{
2009-11-06 22:37:36 +00:00
ServerInstance - > Users - > QuitUser ( user , " RecvQ exceeded " ) ;
2009-09-21 13:26:31 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' a ' , " User %s RecvQ of %lu exceeds connect class maximum of %lu " ,
2009-11-06 22:37:36 +00:00
user - > nick . c_str ( ) , ( unsigned long ) recvq . length ( ) , user - > MyClass - > GetRecvqMax ( ) ) ;
2013-04-19 17:07:10 +02:00
return ;
2007-07-16 17:30:04 +00:00
}
2009-09-26 16:41:07 +00:00
unsigned long sendqmax = ULONG_MAX ;
2009-11-06 22:37:36 +00:00
if ( ! user - > HasPrivPermission ( " users/flood/increased-buffers " ) )
sendqmax = user - > MyClass - > GetSendqSoftMax ( ) ;
2009-11-11 19:52:03 +00:00
unsigned long penaltymax = ULONG_MAX ;
if ( ! user - > HasPrivPermission ( " users/flood/no-fakelag " ) )
penaltymax = user - > MyClass - > GetPenaltyThreshold ( ) * 1000 ;
2008-05-07 21:53:30 +00:00
2009-11-11 19:52:03 +00:00
while ( user - > CommandFloodPenalty < penaltymax & & getSendQSize ( ) < sendqmax )
2007-07-16 17:30:04 +00:00
{
2009-09-21 13:26:31 +00:00
std : : string line ;
2013-05-17 01:34:25 +01:00
line . reserve ( ServerInstance - > Config - > Limits . MaxLine ) ;
2009-09-21 13:26:31 +00:00
std : : string : : size_type qpos = 0 ;
while ( qpos < recvq . length ( ) )
2007-07-16 17:30:04 +00:00
{
2009-09-21 13:26:31 +00:00
char c = recvq [ qpos + + ] ;
switch ( c )
2007-07-16 17:30:04 +00:00
{
2009-09-21 13:26:31 +00:00
case ' \0 ' :
c = ' ' ;
break ;
case ' \r ' :
continue ;
case ' \n ' :
goto eol_found ;
2007-07-16 17:30:04 +00:00
}
2013-05-17 01:35:04 +01:00
if ( line . length ( ) < ServerInstance - > Config - > Limits . MaxLine - 2 )
2009-09-21 13:26:31 +00:00
line . push_back ( c ) ;
2007-07-16 17:30:04 +00:00
}
2009-09-21 13:26:31 +00:00
// if we got here, the recvq ran out before we found a newline
return ;
eol_found :
// just found a newline. Terminate the string, and pull it out of recvq
2015-01-10 15:16:03 +01:00
recvq . erase ( 0 , qpos ) ;
2007-07-16 17:30:04 +00:00
2009-09-21 13:26:31 +00:00
// TODO should this be moved to when it was inserted in recvq?
2014-06-13 15:03:56 +02:00
ServerInstance - > stats . Recv + = qpos ;
2009-11-06 22:37:36 +00:00
user - > bytes_in + = qpos ;
user - > cmds_in + + ;
2009-09-21 13:26:31 +00:00
2014-06-13 15:45:55 +02:00
ServerInstance - > Parser . ProcessBuffer ( line , user ) ;
2009-11-06 22:37:36 +00:00
if ( user - > quitting )
2009-10-19 21:10:10 +00:00
return ;
2007-07-16 17:30:04 +00:00
}
2009-11-11 19:52:03 +00:00
if ( user - > CommandFloodPenalty > = penaltymax & & ! user - > MyClass - > fakelag )
ServerInstance - > Users - > QuitUser ( user , " Excess Flood " ) ;
2007-07-16 17:30:04 +00:00
}
2009-11-06 22:37:36 +00:00
void UserIOHandler : : AddWriteBuf ( const std : : string & data )
2007-07-16 17:30:04 +00:00
{
2011-05-23 21:51:08 -04:00
if ( user - > quitting_sendq )
return ;
2009-11-06 22:37:36 +00:00
if ( ! user - > quitting & & getSendQSize ( ) + data . length ( ) > user - > MyClass - > GetSendqHardMax ( ) & &
! user - > HasPrivPermission ( " users/flood/increased-buffers " ) )
2007-07-16 17:30:04 +00:00
{
2011-05-23 21:51:08 -04:00
user - > quitting_sendq = true ;
ServerInstance - > GlobalCulls . AddSQItem ( user ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2009-03-18 10:28:10 +00:00
// We still want to append data to the sendq of a quitting user,
// e.g. their ERROR message that says 'closing link'
2009-09-21 13:26:31 +00:00
WriteData ( data ) ;
2007-07-16 17:30:04 +00:00
}
2009-11-06 22:37:36 +00:00
void UserIOHandler : : OnError ( BufferedSocketError )
2007-07-16 17:30:04 +00:00
{
2009-11-06 22:37:36 +00:00
ServerInstance - > Users - > QuitUser ( user , getError ( ) ) ;
2009-09-21 13:26:31 +00:00
}
2007-08-23 22:06:04 +00:00
2009-10-17 18:52:39 +00:00
CullResult User : : cull ( )
2009-09-21 13:26:31 +00:00
{
if ( ! quitting )
ServerInstance - > Users - > QuitUser ( this , " Culled without QuitUser " ) ;
2009-09-30 17:12:08 +00:00
2009-11-01 21:53:47 +00:00
if ( client_sa . sa . sa_family ! = AF_UNSPEC )
ServerInstance - > Users - > RemoveCloneCounts ( this ) ;
2009-10-17 18:52:39 +00:00
return Extensible : : cull ( ) ;
2007-07-16 17:30:04 +00:00
}
2009-10-21 23:45:08 +00:00
CullResult LocalUser : : cull ( )
{
2009-11-06 22:37:36 +00:00
eh . cull ( ) ;
2009-10-21 23:45:08 +00:00
return User : : cull ( ) ;
}
2009-10-23 22:47:39 +00:00
CullResult FakeUser : : cull ( )
{
// Fake users don't quit, they just get culled.
quitting = true ;
2015-12-07 10:11:09 +01:00
// Fake users are not inserted into UserManager::clientlist or uuidlist, so we don't need to modify those here
2009-10-23 22:47:39 +00:00
return User : : cull ( ) ;
}
2009-10-21 23:45:44 +00:00
void User : : Oper ( OperInfo * info )
2007-07-16 17:30:04 +00:00
{
2013-06-18 19:17:39 +02:00
ModeHandler * opermh = ServerInstance - > Modes - > FindMode ( ' o ' , MODETYPE_USER ) ;
if ( this - > IsModeSet ( opermh ) )
2008-08-27 19:47:33 +00:00
this - > UnOper ( ) ;
2008-08-27 19:23:17 +00:00
2013-06-18 19:17:39 +02:00
this - > SetMode ( opermh , true ) ;
2009-10-21 23:45:44 +00:00
this - > oper = info ;
2014-02-05 13:49:16 +00:00
this - > WriteCommand ( " MODE " , " +o " ) ;
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnOper , ( this , info - > name ) ) ;
2008-08-27 19:23:17 +00:00
2009-10-21 23:45:44 +00:00
std : : string opername ;
if ( info - > oper_block )
opername = info - > oper_block - > getString ( " name " ) ;
2008-08-27 19:23:17 +00:00
2009-10-23 19:07:40 +00:00
if ( IS_LOCAL ( this ) )
{
LocalUser * l = IS_LOCAL ( this ) ;
std : : string vhost = oper - > getConfig ( " vhost " ) ;
if ( ! vhost . empty ( ) )
2016-02-25 19:23:46 +01:00
l - > ChangeDisplayedHost ( vhost ) ;
2009-10-23 19:07:40 +00:00
std : : string opClass = oper - > getConfig ( " class " ) ;
if ( ! opClass . empty ( ) )
l - > SetClass ( opClass ) ;
}
2009-10-21 23:45:44 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' o ' , " %s (%s@%s) is now an IRC operator of type %s (using oper '%s') " ,
2017-10-22 21:53:24 +01:00
nick . c_str ( ) , ident . c_str ( ) , GetRealHost ( ) . c_str ( ) , oper - > name . c_str ( ) , opername . c_str ( ) ) ;
2016-02-25 16:12:09 +01:00
this - > WriteNumeric ( RPL_YOUAREOPER , InspIRCd : : Format ( " You are now %s %s " , strchr ( " aeiouAEIOU " , oper - > name [ 0 ] ) ? " an " : " a " , oper - > name . c_str ( ) ) ) ;
2009-10-21 23:45:44 +00:00
2013-05-16 01:56:06 +02:00
ServerInstance - > Logs - > Log ( " OPER " , LOG_DEFAULT , " %s opered as type: %s " , GetFullRealHost ( ) . c_str ( ) , oper - > name . c_str ( ) ) ;
2008-08-27 19:23:17 +00:00
ServerInstance - > Users - > all_opers . push_back ( this ) ;
2009-10-21 23:46:05 +00:00
// Expand permissions from config for faster lookup
2009-10-21 23:45:32 +00:00
if ( IS_LOCAL ( this ) )
2009-10-21 23:46:05 +00:00
oper - > init ( ) ;
2009-10-21 23:45:32 +00:00
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnPostOper , ( this , oper - > name , opername ) ) ;
2009-10-21 23:45:32 +00:00
}
2009-10-21 23:46:05 +00:00
void OperInfo : : init ( )
2009-10-21 23:45:32 +00:00
{
2017-08-17 18:32:19 +01:00
AllowedOperCommands . Clear ( ) ;
AllowedPrivs . Clear ( ) ;
2009-10-21 23:45:44 +00:00
AllowedUserModes . reset ( ) ;
AllowedChanModes . reset ( ) ;
2009-10-21 23:46:05 +00:00
AllowedUserModes [ ' o ' - ' A ' ] = true ; // Call me paranoid if you want.
2009-10-21 23:45:44 +00:00
2009-10-21 23:46:05 +00:00
for ( std : : vector < reference < ConfigTag > > : : iterator iter = class_blocks . begin ( ) ; iter ! = class_blocks . end ( ) ; + + iter )
2009-08-03 21:44:10 +00:00
{
2009-10-21 23:45:44 +00:00
ConfigTag * tag = * iter ;
2009-08-03 21:44:10 +00:00
2017-08-17 18:32:19 +01:00
AllowedOperCommands . AddList ( tag - > getString ( " commands " ) ) ;
AllowedPrivs . AddList ( tag - > getString ( " privs " ) ) ;
2008-10-18 16:52:48 +00:00
2012-09-23 02:51:16 +02:00
std : : string modes = tag - > getString ( " usermodes " ) ;
for ( std : : string : : const_iterator c = modes . begin ( ) ; c ! = modes . end ( ) ; + + c )
2009-10-21 23:45:44 +00:00
{
if ( * c = = ' * ' )
{
this - > AllowedUserModes . set ( ) ;
}
2014-06-01 17:53:31 +02:00
else if ( * c > = ' A ' & & * c < = ' z ' )
2009-10-21 23:45:44 +00:00
{
this - > AllowedUserModes [ * c - ' A ' ] = true ;
}
}
2009-08-03 21:44:10 +00:00
2012-09-23 02:51:16 +02:00
modes = tag - > getString ( " chanmodes " ) ;
for ( std : : string : : const_iterator c = modes . begin ( ) ; c ! = modes . end ( ) ; + + c )
2009-10-21 23:45:44 +00:00
{
if ( * c = = ' * ' )
{
this - > AllowedChanModes . set ( ) ;
}
2014-06-01 17:53:31 +02:00
else if ( * c > = ' A ' & & * c < = ' z ' )
2009-10-21 23:45:44 +00:00
{
this - > AllowedChanModes [ * c - ' A ' ] = true ;
2007-11-11 15:44:43 +00:00
}
}
2007-07-16 17:30:04 +00:00
}
}
2007-10-15 20:59:05 +00:00
void User : : UnOper ( )
2007-07-16 17:30:04 +00:00
{
2013-04-09 19:12:09 +02:00
if ( ! this - > IsOper ( ) )
2009-10-21 23:45:32 +00:00
return ;
2008-08-27 21:37:28 +00:00
2009-10-21 23:45:32 +00:00
/*
* unset their oper type ( what IS_OPER checks ) .
* note , order is important - this must come before modes as - o attempts
* to call UnOper . - - w00t
*/
2009-10-21 23:45:44 +00:00
oper = NULL ;
2009-01-03 17:25:10 +00:00
2008-02-26 20:46:21 +00:00
2009-10-21 23:45:32 +00:00
/* Remove all oper only modes from the user when the deoper - Bug #466*/
2014-09-03 15:32:02 +02:00
Modes : : ChangeList changelist ;
2014-09-05 15:06:21 +02:00
const ModeParser : : ModeHandlerMap & usermodes = ServerInstance - > Modes - > GetModes ( MODETYPE_USER ) ;
for ( ModeParser : : ModeHandlerMap : : const_iterator i = usermodes . begin ( ) ; i ! = usermodes . end ( ) ; + + i )
2009-10-21 23:45:32 +00:00
{
2014-09-05 15:06:21 +02:00
ModeHandler * mh = i - > second ;
if ( mh - > NeedsOper ( ) )
2014-09-03 15:32:02 +02:00
changelist . push_remove ( mh ) ;
2009-10-21 23:45:32 +00:00
}
2009-01-03 17:25:10 +00:00
2014-09-03 15:32:02 +02:00
ServerInstance - > Modes - > Process ( this , NULL , this , changelist ) ;
2007-11-11 15:44:43 +00:00
2014-03-25 11:03:29 +01:00
// Remove the user from the oper list
stdalgo : : vector : : swaperase ( ServerInstance - > Users - > all_opers , this ) ;
2008-03-23 21:36:16 +00:00
2013-06-18 19:17:39 +02:00
ModeHandler * opermh = ServerInstance - > Modes - > FindMode ( ' o ' , MODETYPE_USER ) ;
this - > SetMode ( opermh , false ) ;
2009-10-21 23:45:32 +00:00
}
2008-10-18 16:52:48 +00:00
2007-07-16 17:30:04 +00:00
/*
* Check class restrictions
*/
2013-07-01 12:31:36 -07:00
void LocalUser : : CheckClass ( bool clone_count )
2007-07-16 17:30:04 +00:00
{
2007-10-23 23:25:49 +00:00
ConnectClass * a = this - > MyClass ;
2007-07-16 17:30:04 +00:00
2009-10-21 23:45:32 +00:00
if ( ! a )
{
ServerInstance - > Users - > QuitUser ( this , " Access denied by configuration " ) ;
2010-03-06 19:27:57 +00:00
return ;
2009-10-21 23:45:32 +00:00
}
else if ( a - > type = = CC_DENY )
2007-07-16 17:30:04 +00:00
{
2010-02-15 18:29:19 +00:00
ServerInstance - > Users - > QuitUser ( this , a - > config - > getString ( " reason " , " Unauthorised connection " ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2013-07-01 12:31:36 -07:00
else if ( clone_count )
2007-07-16 17:30:04 +00:00
{
2014-03-17 11:05:09 +01:00
const UserManager : : CloneCounts & clonecounts = ServerInstance - > Users - > GetCloneCounts ( this ) ;
if ( ( a - > GetMaxLocal ( ) ) & & ( clonecounts . local > a - > GetMaxLocal ( ) ) )
2013-07-01 12:31:36 -07:00
{
ServerInstance - > Users - > QuitUser ( this , " No more connections allowed from your host via this connect class (local) " ) ;
if ( a - > maxconnwarn )
ServerInstance - > SNO - > WriteToSnoMask ( ' a ' , " WARNING: maximum LOCAL connections (%ld) exceeded for IP %s " , a - > GetMaxLocal ( ) , this - > GetIPString ( ) . c_str ( ) ) ;
return ;
}
2014-03-17 11:05:09 +01:00
else if ( ( a - > GetMaxGlobal ( ) ) & & ( clonecounts . global > a - > GetMaxGlobal ( ) ) )
2013-07-01 12:31:36 -07:00
{
ServerInstance - > Users - > QuitUser ( this , " No more connections allowed from your host via this connect class (global) " ) ;
if ( a - > maxconnwarn )
ServerInstance - > SNO - > WriteToSnoMask ( ' a ' , " WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s " , a - > GetMaxGlobal ( ) , this - > GetIPString ( ) . c_str ( ) ) ;
return ;
}
2007-07-16 17:30:04 +00:00
}
2007-08-06 19:55:09 +00:00
2017-09-03 19:08:52 +01:00
this - > nping = ServerInstance - > Time ( ) + a - > GetPingTime ( ) ;
2007-07-16 17:30:04 +00:00
}
2013-04-01 17:05:12 +02:00
bool LocalUser : : CheckLines ( bool doZline )
2008-04-12 15:48:01 +00:00
{
2008-09-29 08:13:49 +00:00
const char * check [ ] = { " G " , " K " , ( doZline ) ? " Z " : NULL , NULL } ;
2009-02-14 21:14:36 +00:00
2008-04-12 15:48:01 +00:00
if ( ! this - > exempt )
{
for ( int n = 0 ; check [ n ] ; + + n )
{
XLine * r = ServerInstance - > XLines - > MatchesLine ( check [ n ] , this ) ;
if ( r )
{
r - > Apply ( this ) ;
2008-07-12 09:43:58 +00:00
return true ;
2008-04-12 15:48:01 +00:00
}
}
}
2008-07-12 09:43:58 +00:00
return false ;
2008-04-12 15:48:01 +00:00
}
2009-10-21 23:44:58 +00:00
void LocalUser : : FullConnect ( )
2007-07-16 17:30:04 +00:00
{
2014-06-13 15:03:56 +02:00
ServerInstance - > stats . Connects + + ;
2007-07-16 17:30:04 +00:00
this - > idle_lastmsg = ServerInstance - > Time ( ) ;
/*
2007-10-15 20:59:05 +00:00
* You may be thinking " wtf, we checked this in User::AddClient! " - and yes , we did , BUT .
2007-07-16 17:30:04 +00:00
* At the time AddClient is called , we don ' t have a resolved host , by here we probably do - which
* may put the user into a totally seperate class with different restrictions ! so we * must * check again .
* Don ' t remove this ! - - w00t
*/
2010-03-31 18:18:07 -05:00
MyClass = NULL ;
2010-02-09 05:54:43 +00:00
SetClass ( ) ;
2010-01-31 03:42:20 +00:00
CheckClass ( ) ;
CheckLines ( ) ;
2007-10-25 15:25:32 +00:00
2010-01-31 03:42:20 +00:00
if ( quitting )
2008-07-12 09:43:58 +00:00
return ;
2007-07-16 17:30:04 +00:00
2016-02-25 16:12:09 +01:00
this - > WriteNumeric ( RPL_WELCOME , InspIRCd : : Format ( " Welcome to the %s IRC Network %s " , ServerInstance - > Config - > Network . c_str ( ) , GetFullRealHost ( ) . c_str ( ) ) ) ;
this - > WriteNumeric ( RPL_YOURHOSTIS , InspIRCd : : Format ( " Your host is %s, running version %s " , ServerInstance - > Config - > ServerName . c_str ( ) , INSPIRCD_BRANCH ) ) ;
2017-08-16 16:59:56 +01:00
this - > WriteNumeric ( RPL_SERVERCREATED , InspIRCd : : TimeString ( ServerInstance - > startup_time , " This server was created %H:%M:%S %b %d %Y " ) ) ;
2012-09-30 01:10:57 +02:00
2017-10-04 14:10:19 +01:00
const TR1NS : : array < std : : string , 3 > & modelist = ServerInstance - > Modes - > GetModeListFor004Numeric ( ) ;
this - > WriteNumeric ( RPL_SERVERVERSION , ServerInstance - > Config - > ServerName , INSPIRCD_BRANCH , modelist [ 0 ] , modelist [ 1 ] , modelist [ 2 ] ) ;
2007-07-16 17:30:04 +00:00
2013-04-07 22:23:25 +01:00
ServerInstance - > ISupport . SendTo ( this ) ;
2007-08-27 00:12:59 +00:00
2007-07-16 17:30:04 +00:00
/* Now registered */
2008-02-02 20:55:16 +00:00
if ( ServerInstance - > Users - > unregistered_count )
ServerInstance - > Users - > unregistered_count - - ;
2007-07-16 17:30:04 +00:00
2010-01-19 04:43:19 +00:00
/* Trigger MOTD and LUSERS output, give modules a chance too */
2009-09-02 00:49:36 +00:00
ModResult MOD_RESULT ;
2013-04-01 01:01:12 +02:00
std : : string command ( " LUSERS " ) ;
2008-06-06 15:28:24 +00:00
std : : vector < std : : string > parameters ;
2010-01-19 04:43:19 +00:00
FIRST_MOD_RESULT ( OnPreCommand , MOD_RESULT , ( command , parameters , this , true , command ) ) ;
if ( ! MOD_RESULT )
2014-06-13 15:45:55 +02:00
ServerInstance - > Parser . CallHandler ( command , parameters , this ) ;
2010-01-19 04:43:19 +00:00
MOD_RESULT = MOD_RES_PASSTHRU ;
2013-04-01 01:01:12 +02:00
command = " MOTD " ;
2010-01-19 04:43:19 +00:00
FIRST_MOD_RESULT ( OnPreCommand , MOD_RESULT , ( command , parameters , this , true , command ) ) ;
2007-07-16 17:30:04 +00:00
if ( ! MOD_RESULT )
2014-06-13 15:45:55 +02:00
ServerInstance - > Parser . CallHandler ( command , parameters , this ) ;
2007-07-16 17:30:04 +00:00
2010-03-19 18:06:39 +00:00
if ( ServerInstance - > Config - > RawLog )
WriteServ ( " PRIVMSG %s :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded. " , nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
/*
2007-10-16 10:21:11 +00:00
* We don ' t set REG_ALL until triggering OnUserConnect , so some module events don ' t spew out stuff
* for a user that doesn ' t exist yet .
2007-07-16 17:30:04 +00:00
*/
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnUserConnect , ( this ) ) ;
2007-07-16 17:30:04 +00:00
this - > registered = REG_ALL ;
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnPostConnect , ( this ) ) ;
2007-07-16 17:30:04 +00:00
2012-10-21 15:10:44 +02:00
ServerInstance - > SNO - > WriteToSnoMask ( ' c ' , " Client connecting on port %d (class %s): %s (%s) [%s] " ,
2013-04-01 01:27:02 +02:00
this - > GetServerPort ( ) , this - > MyClass - > name . c_str ( ) , GetFullRealHost ( ) . c_str ( ) , this - > GetIPString ( ) . c_str ( ) , this - > fullname . c_str ( ) ) ;
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " BANCACHE " , LOG_DEBUG , " BanCache: Adding NEGATIVE hit for " + this - > GetIPString ( ) ) ;
2014-06-13 15:27:40 +02:00
ServerInstance - > BanCache . AddHit ( this - > GetIPString ( ) , " " , " " ) ;
2010-03-23 14:51:43 +00:00
// reset the flood penalty (which could have been raised due to things like auto +x)
CommandFloodPenalty = 0 ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : InvalidateCache ( )
2007-07-16 17:30:04 +00:00
{
/* Invalidate cache */
2016-09-25 21:41:05 +01:00
cachedip . clear ( ) ;
2008-05-18 23:15:53 +00:00
cached_fullhost . clear ( ) ;
cached_hostip . clear ( ) ;
cached_makehost . clear ( ) ;
cached_fullrealhost . clear ( ) ;
2007-07-16 17:30:04 +00:00
}
2014-07-03 12:27:24 +02:00
bool User : : ChangeNick ( const std : : string & newnick , time_t newts )
2007-07-16 17:30:04 +00:00
{
2013-04-21 17:20:28 +02:00
if ( quitting )
{
2013-04-28 00:32:14 +02:00
ServerInstance - > Logs - > Log ( " USERS " , LOG_DEFAULT , " ERROR: Attempted to change nick of a quitting user: " + this - > nick ) ;
2013-04-21 17:20:28 +02:00
return false ;
}
2014-07-03 12:32:21 +02:00
User * const InUse = ServerInstance - > FindNickOnly ( newnick ) ;
if ( InUse = = this )
2007-07-16 17:30:04 +00:00
{
2014-06-20 16:34:03 +02:00
// case change, don't need to check campers
2010-01-30 18:40:51 +00:00
// and, if it's identical including case, we can leave right now
2014-03-03 15:07:17 +01:00
// We also don't update the nick TS if it's a case change, either
2010-01-30 18:40:51 +00:00
if ( newnick = = nick )
return true ;
2007-07-16 17:30:04 +00:00
}
2010-01-30 18:40:51 +00:00
else
{
/*
* Uh oh . . if the nickname is in use , and it ' s not in use by the person using it ( doh ) - -
* then we have a potential collide . Check whether someone else is camping on the nick
* ( i . e . connect - > send NICK , don ' t send USER . ) If they are camping , force - change the
* camper to their UID , and allow the incoming nick change .
*
* If the guy using the nick is already using it , tell the incoming nick change to gtfo ,
* because the nick is already ( rightfully ) in use . - - w00t
*/
2014-07-03 12:32:21 +02:00
if ( InUse )
2010-01-30 18:40:51 +00:00
{
if ( InUse - > registered ! = REG_ALL )
{
/* force the camper to their UUID, and ask them to re-send a NICK. */
2016-12-30 18:44:39 +01:00
LocalUser * const localuser = static_cast < LocalUser * > ( InUse ) ;
localuser - > OverruleNick ( ) ;
2010-01-30 18:40:51 +00:00
}
else
{
/* No camping, tell the incoming user to stop trying to change nick ;p */
2016-02-25 16:12:09 +01:00
this - > WriteNumeric ( ERR_NICKNAMEINUSE , newnick , " Nickname is already in use. " ) ;
2010-01-30 18:56:39 +00:00
return false ;
2010-01-30 18:40:51 +00:00
}
}
2014-03-03 15:07:17 +01:00
age = newts ? newts : ServerInstance - > Time ( ) ;
2010-01-30 18:40:51 +00:00
}
if ( this - > registered = = REG_ALL )
this - > WriteCommon ( " NICK %s " , newnick . c_str ( ) ) ;
std : : string oldnick = nick ;
nick = newnick ;
2010-01-30 18:56:39 +00:00
2010-01-30 18:40:51 +00:00
InvalidateCache ( ) ;
2014-03-15 15:29:25 +01:00
ServerInstance - > Users - > clientlist . erase ( oldnick ) ;
ServerInstance - > Users - > clientlist [ newnick ] = this ;
2010-01-30 18:56:39 +00:00
2010-02-01 01:18:34 +00:00
if ( registered = = REG_ALL )
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnUserPostNick , ( this , oldnick ) ) ;
2010-02-01 01:18:34 +00:00
2010-01-30 18:40:51 +00:00
return true ;
2007-07-16 17:30:04 +00:00
}
2016-12-30 18:44:39 +01:00
void LocalUser : : OverruleNick ( )
{
this - > WriteFrom ( this , " NICK %s " , this - > uuid . c_str ( ) ) ;
this - > WriteNumeric ( ERR_NICKNAMEINUSE , this - > nick , " Nickname overruled. " ) ;
// Clear the bit before calling ChangeNick() to make it NOT run the OnUserPostNick() hook
this - > registered & = ~ REG_NICK ;
this - > ChangeNick ( this - > uuid ) ;
}
2009-10-21 23:45:08 +00:00
int LocalUser : : GetServerPort ( )
2007-07-16 17:30:04 +00:00
{
2009-09-01 15:07:36 +00:00
switch ( this - > server_sa . sa . sa_family )
2007-07-16 17:30:04 +00:00
{
case AF_INET6 :
2009-09-01 15:07:52 +00:00
return htons ( this - > server_sa . in6 . sin6_port ) ;
2007-07-16 17:30:04 +00:00
case AF_INET :
2009-09-01 15:07:52 +00:00
return htons ( this - > server_sa . in4 . sin_port ) ;
2007-07-16 17:30:04 +00:00
}
return 0 ;
}
2013-04-01 01:27:02 +02:00
const std : : string & User : : GetIPString ( )
2009-09-01 15:07:52 +00:00
{
if ( cachedip . empty ( ) )
2007-07-16 17:30:04 +00:00
{
2017-08-28 15:13:25 +01:00
cachedip = client_sa . addr ( ) ;
2009-09-01 15:07:52 +00:00
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
2013-04-01 01:27:02 +02:00
if ( cachedip [ 0 ] = = ' : ' )
2013-08-31 01:17:07 +02:00
cachedip . insert ( cachedip . begin ( ) , 1 , ' 0 ' ) ;
2007-07-16 17:30:04 +00:00
}
2009-02-14 21:14:36 +00:00
2013-04-01 01:27:02 +02:00
return cachedip ;
2007-07-16 17:30:04 +00:00
}
2017-10-22 21:53:24 +01:00
const std : : string & User : : GetHost ( bool uncloak ) const
{
return uncloak ? GetRealHost ( ) : GetDisplayedHost ( ) ;
}
const std : : string & User : : GetDisplayedHost ( ) const
{
return displayhost . empty ( ) ? realhost : displayhost ;
}
const std : : string & User : : GetRealHost ( ) const
{
return realhost ;
}
2009-10-24 20:04:05 +00:00
irc : : sockets : : cidr_mask User : : GetCIDRMask ( )
2009-10-22 21:49:39 +00:00
{
2017-11-17 00:02:03 +00:00
unsigned char range = 0 ;
2009-10-22 21:49:39 +00:00
switch ( client_sa . sa . sa_family )
{
case AF_INET6 :
range = ServerInstance - > Config - > c_ipv6_range ;
break ;
case AF_INET :
range = ServerInstance - > Config - > c_ipv4_range ;
break ;
}
2009-10-24 20:04:05 +00:00
return irc : : sockets : : cidr_mask ( client_sa , range ) ;
2009-10-22 21:49:39 +00:00
}
2017-10-27 19:15:23 +01:00
bool User : : SetClientIP ( const std : : string & address , bool recheck_eline )
2009-09-01 15:07:36 +00:00
{
2016-09-25 21:41:05 +01:00
this - > InvalidateCache ( ) ;
2017-10-27 19:15:23 +01:00
return irc : : sockets : : aptosa ( address , 0 , client_sa ) ;
2009-09-01 15:07:36 +00:00
}
2013-03-03 23:13:54 +01:00
void User : : SetClientIP ( const irc : : sockets : : sockaddrs & sa , bool recheck_eline )
2012-07-09 15:35:12 +02:00
{
2017-10-22 23:51:15 +01:00
this - > InvalidateCache ( ) ;
2012-07-09 15:35:12 +02:00
memcpy ( & client_sa , & sa , sizeof ( irc : : sockets : : sockaddrs ) ) ;
}
2017-10-27 19:15:23 +01:00
bool LocalUser : : SetClientIP ( const std : : string & address , bool recheck_eline )
2012-07-09 15:35:12 +02:00
{
irc : : sockets : : sockaddrs sa ;
2017-10-27 19:15:23 +01:00
if ( ! irc : : sockets : : aptosa ( address , 0 , sa ) )
2012-07-09 15:35:12 +02:00
// Invalid
return false ;
2013-03-03 23:13:54 +01:00
LocalUser : : SetClientIP ( sa , recheck_eline ) ;
2012-07-09 15:35:12 +02:00
return true ;
}
2013-03-03 23:13:54 +01:00
void LocalUser : : SetClientIP ( const irc : : sockets : : sockaddrs & sa , bool recheck_eline )
2012-07-09 15:35:12 +02:00
{
if ( sa ! = client_sa )
{
User : : SetClientIP ( sa ) ;
2013-03-03 23:13:54 +01:00
if ( recheck_eline )
this - > exempt = ( ServerInstance - > XLines - > MatchesLine ( " E " , this ) ! = NULL ) ;
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnSetUserIP , ( this ) ) ;
2012-07-09 15:35:12 +02:00
}
}
2009-09-21 13:26:31 +00:00
static std : : string wide_newline ( " \r \n " ) ;
2009-09-02 00:45:29 +00:00
void User : : Write ( const std : : string & text )
2009-10-21 23:45:08 +00:00
{
}
void User : : Write ( const char * text , . . . )
{
}
void LocalUser : : Write ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2014-02-08 23:01:44 +01:00
if ( ! SocketEngine : : BoundsCheckFd ( & eh ) )
2007-07-16 17:30:04 +00:00
return ;
2013-05-17 01:35:04 +01:00
if ( text . length ( ) > ServerInstance - > Config - > Limits . MaxLine - 2 )
2007-07-16 17:30:04 +00:00
{
2009-09-21 13:26:31 +00:00
// this should happen rarely or never. Crop the string at 512 and try again.
2015-02-27 01:25:12 +01:00
std : : string try_again ( text , 0 , ServerInstance - > Config - > Limits . MaxLine - 2 ) ;
2009-09-21 13:26:31 +00:00
Write ( try_again ) ;
return ;
2007-07-16 17:30:04 +00:00
}
2009-09-21 13:26:31 +00:00
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " USEROUTPUT " , LOG_RAWIO , " C[%s] O %s " , uuid . c_str ( ) , text . c_str ( ) ) ;
2009-09-21 13:26:31 +00:00
2009-11-06 22:37:36 +00:00
eh . AddWriteBuf ( text ) ;
eh . AddWriteBuf ( wide_newline ) ;
2009-09-21 13:26:31 +00:00
2014-06-13 15:03:56 +02:00
ServerInstance - > stats . Sent + = text . length ( ) + 2 ;
2009-09-21 13:26:31 +00:00
this - > bytes_out + = text . length ( ) + 2 ;
this - > cmds_out + + ;
2007-07-16 17:30:04 +00:00
}
/** Write()
*/
2009-10-21 23:45:08 +00:00
void LocalUser : : Write ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
2013-05-18 11:35:10 -07:00
std : : string textbuffer ;
VAFORMAT ( textbuffer , text , text ) ;
this - > Write ( textbuffer ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : WriteServ ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2009-10-03 01:52:59 +00:00
this - > Write ( " :%s %s " , ServerInstance - > Config - > ServerName . c_str ( ) , text . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
/** WriteServ()
* Same as Write ( ) , except ` text ' is prefixed with ` : server . name ' .
*/
2007-10-15 20:59:05 +00:00
void User : : WriteServ ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
2013-05-18 11:35:10 -07:00
std : : string textbuffer ;
VAFORMAT ( textbuffer , text , text ) ;
this - > WriteServ ( textbuffer ) ;
2007-07-16 17:30:04 +00:00
}
2014-02-05 13:49:16 +00:00
void User : : WriteCommand ( const char * command , const std : : string & text )
2013-04-28 12:17:53 +01:00
{
2014-02-05 13:49:16 +00:00
this - > WriteServ ( command + ( this - > registered & REG_NICK ? " " + this - > nick : " * " ) + " " + text ) ;
2013-04-28 12:17:53 +01:00
}
2007-07-16 17:30:04 +00:00
2016-02-25 15:25:02 +01:00
namespace
{
std : : string BuildNumeric ( const std : : string & source , User * targetuser , unsigned int num , const std : : vector < std : : string > & params )
{
const char * const target = ( targetuser - > registered & REG_NICK ? targetuser - > nick . c_str ( ) : " * " ) ;
std : : string raw = InspIRCd : : Format ( " :%s %03u %s " , source . c_str ( ) , num , target ) ;
if ( ! params . empty ( ) )
{
for ( std : : vector < std : : string > : : const_iterator i = params . begin ( ) ; i ! = params . end ( ) - 1 ; + + i )
raw . append ( 1 , ' ' ) . append ( * i ) ;
raw . append ( " : " ) . append ( params . back ( ) ) ;
}
return raw ;
}
}
2016-02-25 16:12:09 +01:00
void User : : WriteNumeric ( const Numeric : : Numeric & numeric )
2008-03-22 11:45:57 +00:00
{
2009-09-02 00:49:36 +00:00
ModResult MOD_RESULT ;
2008-03-22 11:45:57 +00:00
2016-02-25 16:12:09 +01:00
FIRST_MOD_RESULT ( OnNumeric , MOD_RESULT , ( this , numeric ) ) ;
2008-03-22 11:45:57 +00:00
2009-09-02 00:49:36 +00:00
if ( MOD_RESULT = = MOD_RES_DENY )
2008-03-22 11:45:57 +00:00
return ;
2014-01-23 14:37:09 +01:00
2016-03-29 16:22:07 +02:00
const std : : string & servername = ( numeric . GetServer ( ) ? numeric . GetServer ( ) - > GetName ( ) : ServerInstance - > Config - > ServerName ) ;
this - > Write ( BuildNumeric ( servername , this , numeric . GetNumeric ( ) , numeric . GetParams ( ) ) ) ;
2008-03-22 11:45:57 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : WriteFrom ( User * user , const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2013-05-06 11:49:50 +01:00
const std : : string message = " : " + user - > GetFullHost ( ) + " " + text ;
this - > Write ( message ) ;
2007-07-16 17:30:04 +00:00
}
/* write text from an originating user to originating user */
2007-10-15 20:59:05 +00:00
void User : : WriteFrom ( User * user , const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
2013-05-18 11:35:10 -07:00
std : : string textbuffer ;
VAFORMAT ( textbuffer , text , text ) ;
this - > WriteFrom ( user , textbuffer ) ;
2007-07-16 17:30:04 +00:00
}
2016-03-01 16:15:59 +01:00
void User : : WriteRemoteNotice ( const std : : string & text )
{
ServerInstance - > PI - > SendUserNotice ( this , text ) ;
}
void LocalUser : : WriteRemoteNotice ( const std : : string & text )
{
WriteNotice ( text ) ;
}
2015-01-24 14:55:10 +01:00
namespace
{
class WriteCommonRawHandler : public User : : ForEachNeighborHandler
{
const std : : string & msg ;
void Execute ( LocalUser * user ) CXX11_OVERRIDE
{
user - > Write ( msg ) ;
}
public :
WriteCommonRawHandler ( const std : : string & message )
: msg ( message )
{
}
} ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteCommon ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
2013-05-18 11:35:10 -07:00
std : : string textbuffer ;
VAFORMAT ( textbuffer , text , text ) ;
textbuffer = " : " + this - > GetFullHost ( ) + " " + textbuffer ;
this - > WriteCommonRaw ( textbuffer , true ) ;
2007-07-16 17:30:04 +00:00
}
2009-10-05 23:27:46 +00:00
void User : : WriteCommonRaw ( const std : : string & line , bool include_self )
{
2015-01-24 14:55:10 +01:00
WriteCommonRawHandler handler ( line ) ;
ForEachNeighbor ( handler , include_self ) ;
2007-07-16 17:30:04 +00:00
}
2015-01-24 14:49:10 +01:00
void User : : ForEachNeighbor ( ForEachNeighborHandler & handler , bool include_self )
{
// The basic logic for visiting the neighbors of a user is to iterate the channel list of the user
// and visit all users on those channels. Because two users may share more than one common channel,
// we must skip users that we have already visited.
// To do this, we make use of a global counter and an integral 'already_sent' field in LocalUser.
// The global counter is incremented every time we do something for each neighbor of a user. Then,
// before visiting a member we examine user->already_sent. If it's equal to the current counter, we
// skip the member. Otherwise, we set it to the current counter and visit the member.
// Ask modules to build a list of exceptions.
// Mods may also exclude entire channels by erasing them from include_chans.
IncludeChanList include_chans ( chans . begin ( ) , chans . end ( ) ) ;
std : : map < User * , bool > exceptions ;
exceptions [ this ] = include_self ;
FOREACH_MOD ( OnBuildNeighborList , ( this , include_chans , exceptions ) ) ;
// Get next id, guaranteed to differ from the already_sent field of all users
2015-11-03 13:08:21 +01:00
const already_sent_t newid = ServerInstance - > Users . NextAlreadySentId ( ) ;
2015-01-24 14:49:10 +01:00
// Handle exceptions first
for ( std : : map < User * , bool > : : const_iterator i = exceptions . begin ( ) ; i ! = exceptions . end ( ) ; + + i )
{
LocalUser * curr = IS_LOCAL ( i - > first ) ;
if ( curr )
{
// Mark as visited to ensure we won't visit again if there is a common channel
curr - > already_sent = newid ;
// Always treat quitting users as excluded
if ( ( i - > second ) & & ( ! curr - > quitting ) )
handler . Execute ( curr ) ;
}
}
// Now consider the real neighbors
for ( IncludeChanList : : const_iterator i = include_chans . begin ( ) ; i ! = include_chans . end ( ) ; + + i )
{
Channel * chan = ( * i ) - > chan ;
const Channel : : MemberMap & userlist = chan - > GetUsers ( ) ;
for ( Channel : : MemberMap : : const_iterator j = userlist . begin ( ) ; j ! = userlist . end ( ) ; + + j )
{
LocalUser * curr = IS_LOCAL ( j - > first ) ;
// User not yet visited?
if ( ( curr ) & & ( curr - > already_sent ! = newid ) )
{
// Mark as visited and execute function
curr - > already_sent = newid ;
handler . Execute ( curr ) ;
}
}
}
}
2016-02-25 16:40:50 +01:00
void User : : WriteRemoteNumeric ( const Numeric : : Numeric & numeric )
{
2016-03-29 16:43:30 +02:00
WriteNumeric ( numeric ) ;
2016-02-25 16:40:50 +01:00
}
2007-07-16 17:30:04 +00:00
/* return 0 or 1 depending if users u and u2 share one or more common channels
* ( used by QUIT , NICK etc which arent channel specific notices )
*
* The old algorithm in 1.0 for this was relatively inefficient , iterating over
* the first users channels then the second users channels within the outer loop ,
* therefore it was a maximum of x * y iterations ( upon returning 0 and checking
* all possible iterations ) . However this new function instead checks against the
2007-10-15 20:59:05 +00:00
* channel ' s userlist in the inner loop which is a std : : map < User * , User * >
2007-07-16 17:30:04 +00:00
* and saves us time as we already know what pointer value we are after .
* Don ' t quote me on the maths as i am not a mathematician or computer scientist ,
* but i believe this algorithm is now x + ( log y ) maximum iterations instead .
*/
2007-10-15 20:59:05 +00:00
bool User : : SharesChannelWith ( User * other )
2007-07-16 17:30:04 +00:00
{
/* Outer loop */
2014-07-14 16:24:59 +02:00
for ( User : : ChanList : : iterator i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; + + i )
2007-07-16 17:30:04 +00:00
{
/* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
* by replacing it with a map : : find which * should * be more efficient
*/
2014-01-24 12:58:01 +01:00
if ( ( * i ) - > chan - > HasUser ( other ) )
2007-07-16 17:30:04 +00:00
return true ;
}
return false ;
}
2013-08-09 18:20:12 +02:00
bool User : : ChangeName ( const std : : string & gecos )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > fullname . compare ( gecos ) )
2007-07-16 17:30:04 +00:00
return true ;
if ( IS_LOCAL ( this ) )
{
2009-09-02 00:49:36 +00:00
ModResult MOD_RESULT ;
2009-10-21 23:45:19 +00:00
FIRST_MOD_RESULT ( OnChangeLocalUserGECOS , MOD_RESULT , ( IS_LOCAL ( this ) , gecos ) ) ;
2009-09-02 00:49:36 +00:00
if ( MOD_RESULT = = MOD_RES_DENY )
2007-07-16 17:30:04 +00:00
return false ;
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnChangeName , ( this , gecos ) ) ;
2007-07-16 17:30:04 +00:00
}
2008-05-25 17:30:43 +00:00
this - > fullname . assign ( gecos , 0 , ServerInstance - > Config - > Limits . MaxGecos ) ;
2007-07-16 17:30:04 +00:00
return true ;
}
2013-08-09 18:20:12 +02:00
bool User : : ChangeDisplayedHost ( const std : : string & shost )
2007-07-16 17:30:04 +00:00
{
2017-10-22 21:53:24 +01:00
if ( GetDisplayedHost ( ) = = shost )
2007-07-16 17:30:04 +00:00
return true ;
if ( IS_LOCAL ( this ) )
{
2009-09-02 00:49:36 +00:00
ModResult MOD_RESULT ;
2009-10-21 23:45:19 +00:00
FIRST_MOD_RESULT ( OnChangeLocalUserHost , MOD_RESULT , ( IS_LOCAL ( this ) , shost ) ) ;
2009-09-02 00:49:36 +00:00
if ( MOD_RESULT = = MOD_RES_DENY )
2007-07-16 17:30:04 +00:00
return false ;
}
2008-02-09 13:06:02 +00:00
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnChangeHost , ( this , shost ) ) ;
2008-10-25 12:21:14 +00:00
2017-10-22 21:53:24 +01:00
if ( realhost = = shost )
this - > displayhost . clear ( ) ;
else
this - > displayhost . assign ( shost , 0 , ServerInstance - > Config - > Limits . MaxHost ) ;
2007-07-16 17:30:04 +00:00
this - > InvalidateCache ( ) ;
if ( IS_LOCAL ( this ) )
2017-10-22 21:53:24 +01:00
this - > WriteNumeric ( RPL_YOURDISPLAYEDHOST , this - > GetDisplayedHost ( ) , " is now your displayed host " ) ;
2007-07-16 17:30:04 +00:00
return true ;
}
2017-10-22 21:53:24 +01:00
void User : : ChangeRealHost ( const std : : string & host , bool resetdisplay )
{
if ( displayhost = = host )
return ;
if ( displayhost . empty ( ) & & ! resetdisplay )
displayhost = realhost ;
else if ( displayhost = = host | | resetdisplay )
displayhost . clear ( ) ;
realhost = host ;
this - > InvalidateCache ( ) ;
}
2013-08-09 18:20:12 +02:00
bool User : : ChangeIdent ( const std : : string & newident )
2007-07-16 17:30:04 +00:00
{
2008-10-02 22:27:03 +00:00
if ( this - > ident = = newident )
2007-07-16 17:30:04 +00:00
return true ;
2013-06-26 17:01:33 -04:00
FOREACH_MOD ( OnChangeIdent , ( this , newident ) ) ;
2009-09-02 00:52:12 +00:00
2012-12-09 18:06:21 +01:00
this - > ident . assign ( newident , 0 , ServerInstance - > Config - > Limits . IdentMax ) ;
2007-07-16 17:30:04 +00:00
this - > InvalidateCache ( ) ;
return true ;
}
2007-10-23 23:25:49 +00:00
/*
* Sets a user ' s connection class .
* If the class name is provided , it will be used . Otherwise , the class will be guessed using host / ip / ident / etc .
2007-07-16 17:30:04 +00:00
* NOTE : If the < ALLOW > or < DENY > tag specifies an ip , and this user resolves ,
* then their ip will be taken as ' priority ' anyway , so for example ,
* < connect allow = " 127.0.0.1 " > will match joe ! bloggs @ localhost
*/
2009-10-21 23:45:32 +00:00
void LocalUser : : SetClass ( const std : : string & explicit_name )
2007-07-16 17:30:04 +00:00
{
2007-10-23 23:31:40 +00:00
ConnectClass * found = NULL ;
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Setting connect class for UID %s " , this - > uuid . c_str ( ) ) ;
2008-05-18 17:25:29 +00:00
2007-08-19 19:23:53 +00:00
if ( ! explicit_name . empty ( ) )
2007-07-16 17:30:04 +00:00
{
2014-07-16 12:30:05 +02:00
for ( ServerConfig : : ClassVector : : const_iterator i = ServerInstance - > Config - > Classes . begin ( ) ; i ! = ServerInstance - > Config - > Classes . end ( ) ; + + i )
2007-07-16 17:30:04 +00:00
{
2007-10-24 15:48:00 +00:00
ConnectClass * c = * i ;
2009-08-12 18:03:52 +00:00
if ( explicit_name = = c - > name )
2007-10-23 23:07:24 +00:00
{
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Explicitly set to %s " , explicit_name . c_str ( ) ) ;
2007-10-24 15:48:00 +00:00
found = c ;
2007-10-23 23:07:24 +00:00
}
2007-08-19 19:23:53 +00:00
}
}
else
{
2014-07-16 12:30:05 +02:00
for ( ServerConfig : : ClassVector : : const_iterator i = ServerInstance - > Config - > Classes . begin ( ) ; i ! = ServerInstance - > Config - > Classes . end ( ) ; + + i )
2007-08-19 19:23:53 +00:00
{
2007-10-24 15:48:00 +00:00
ConnectClass * c = * i ;
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Checking %s " , c - > GetName ( ) . c_str ( ) ) ;
2007-10-24 15:48:00 +00:00
2010-02-02 15:02:33 +00:00
ModResult MOD_RESULT ;
FIRST_MOD_RESULT ( OnSetConnectClass , MOD_RESULT , ( this , c ) ) ;
if ( MOD_RESULT = = MOD_RES_DENY )
continue ;
if ( MOD_RESULT = = MOD_RES_ALLOW )
2008-05-18 17:41:04 +00:00
{
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Class forced by module to %s " , c - > GetName ( ) . c_str ( ) ) ;
2010-02-02 15:02:33 +00:00
found = c ;
break ;
2008-05-18 17:41:04 +00:00
}
2010-02-02 15:02:33 +00:00
if ( c - > type = = CC_NAMED )
2010-01-31 03:42:20 +00:00
continue ;
2008-05-18 17:41:04 +00:00
2010-02-09 05:54:43 +00:00
bool regdone = ( registered ! = REG_NONE ) ;
if ( c - > config - > getBool ( " registered " , regdone ) ! = regdone )
continue ;
2008-05-18 17:16:55 +00:00
/* check if host matches.. */
2011-07-17 19:49:03 -04:00
if ( ! InspIRCd : : MatchCIDR ( this - > GetIPString ( ) , c - > GetHost ( ) , NULL ) & &
2017-10-22 21:53:24 +01:00
! InspIRCd : : MatchCIDR ( this - > GetRealHost ( ) , c - > GetHost ( ) , NULL ) )
2007-07-16 17:30:04 +00:00
{
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " No host match (for %s) " , c - > GetHost ( ) . c_str ( ) ) ;
2008-05-18 17:16:55 +00:00
continue ;
}
/*
* deny change if change will take class over the limit check it HERE , not after we found a matching class ,
* because we should attempt to find another class if this one doesn ' t match us . - - w00t
*/
2009-09-30 21:55:21 +00:00
if ( c - > limit & & ( c - > GetReferenceCount ( ) > = c - > limit ) )
2008-05-18 17:16:55 +00:00
{
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " OOPS: Connect class limit (%lu) hit, denying " , c - > limit ) ;
2008-05-18 17:16:55 +00:00
continue ;
}
/* if it requires a port ... */
2016-10-23 15:23:14 +01:00
if ( ! c - > ports . empty ( ) )
2008-05-18 17:16:55 +00:00
{
/* and our port doesn't match, fail. */
2016-10-23 15:23:14 +01:00
if ( ! c - > ports . count ( this - > GetServerPort ( ) ) )
{
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Requires a different port, skipping " ) ;
2008-05-18 17:16:55 +00:00
continue ;
2016-10-23 15:23:14 +01:00
}
2007-07-16 17:30:04 +00:00
}
2008-05-18 17:16:55 +00:00
2010-03-31 09:32:05 -05:00
if ( regdone & & ! c - > config - > getString ( " password " ) . empty ( ) )
2010-02-09 05:54:43 +00:00
{
2014-01-18 04:53:52 +00:00
if ( ! ServerInstance - > PassCompare ( this , c - > config - > getString ( " password " ) , password , c - > config - > getString ( " hash " ) ) )
2010-02-09 05:54:43 +00:00
{
2013-04-12 02:10:06 +01:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , LOG_DEBUG , " Bad password, skipping " ) ;
2010-02-09 05:54:43 +00:00
continue ;
}
}
2010-02-09 05:35:19 +00:00
2008-05-18 18:23:30 +00:00
/* we stop at the first class that meets ALL critera. */
2008-05-18 17:16:55 +00:00
found = c ;
2008-05-18 18:23:30 +00:00
break ;
2007-07-16 17:30:04 +00:00
}
}
2007-10-23 23:07:24 +00:00
2008-05-18 17:16:55 +00:00
/*
* Okay , assuming we found a class that matches . . switch us into that class , keeping refcounts up to date .
*/
2007-10-23 23:31:40 +00:00
if ( found )
{
2009-09-30 21:55:21 +00:00
MyClass = found ;
2007-10-23 23:31:40 +00:00
}
2007-10-23 23:25:49 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : PurgeEmptyChannels ( )
2007-07-16 17:30:04 +00:00
{
// firstly decrement the count on each channel
2014-07-14 16:24:59 +02:00
for ( User : : ChanList : : iterator i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; )
2007-07-16 17:30:04 +00:00
{
2014-01-24 12:58:01 +01:00
Channel * c = ( * i ) - > chan ;
+ + i ;
2009-10-18 02:57:46 +00:00
c - > DelUser ( this ) ;
2007-07-16 17:30:04 +00:00
}
this - > UnOper ( ) ;
}
2009-10-23 22:47:39 +00:00
const std : : string & FakeUser : : GetFullHost ( )
2009-05-13 17:43:35 +00:00
{
2017-12-15 23:26:15 +00:00
if ( ! ServerInstance - > Config - > HideServer . empty ( ) )
return ServerInstance - > Config - > HideServer ;
2014-01-05 15:04:01 +01:00
return server - > GetName ( ) ;
2009-05-13 17:43:35 +00:00
}
2009-10-23 22:47:39 +00:00
const std : : string & FakeUser : : GetFullRealHost ( )
2009-05-13 17:43:35 +00:00
{
2017-12-15 23:26:15 +00:00
if ( ! ServerInstance - > Config - > HideServer . empty ( ) )
return ServerInstance - > Config - > HideServer ;
2014-01-05 15:04:01 +01:00
return server - > GetName ( ) ;
2009-05-13 17:43:35 +00:00
}
2009-10-17 02:40:16 +00:00
ConnectClass : : ConnectClass ( ConfigTag * tag , char t , const std : : string & mask )
2009-11-11 19:52:03 +00:00
: config ( tag ) , type ( t ) , fakelag ( true ) , name ( " unnamed " ) , registration_timeout ( 0 ) , host ( mask ) ,
2010-02-02 15:02:33 +00:00
pingtime ( 0 ) , softsendqmax ( 0 ) , hardsendqmax ( 0 ) , recvqmax ( 0 ) ,
2014-03-19 20:52:56 +00:00
penaltythreshold ( 0 ) , commandrate ( 0 ) , maxlocal ( 0 ) , maxglobal ( 0 ) , maxconnwarn ( true ) , maxchans ( ServerInstance - > Config - > MaxChans ) ,
2013-07-10 12:46:01 +01:00
limit ( 0 ) , resolvehostnames ( true )
2009-08-12 18:03:52 +00:00
{
}
2009-10-17 02:40:16 +00:00
ConnectClass : : ConnectClass ( ConfigTag * tag , char t , const std : : string & mask , const ConnectClass & parent )
2009-08-12 18:03:52 +00:00
{
2013-06-18 21:26:54 +02:00
Update ( & parent ) ;
name = " unnamed " ;
type = t ;
2017-10-21 22:48:29 +01:00
host = mask ;
// Connect classes can inherit from each other but this is problematic for modules which can't use
// ConnectClass::Update so we build a hybrid tag containing all of the values set on this class as
// well as the parent class.
ConfigItems * items = NULL ;
config = ConfigTag : : create ( tag - > tag , tag - > src_name , tag - > src_line , items ) ;
const ConfigItems & parentkeys = parent . config - > getItems ( ) ;
for ( ConfigItems : : const_iterator piter = parentkeys . begin ( ) ; piter ! = parentkeys . end ( ) ; + + piter )
{
// The class name and parent name are not inherited
if ( piter - > first = = " name " | | piter - > first = = " parent " )
continue ;
// Store the item in the config tag. If this item also
// exists in the child it will be overwritten.
( * items ) [ piter - > first ] = piter - > second ;
}
const ConfigItems & childkeys = tag - > getItems ( ) ;
for ( ConfigItems : : const_iterator citer = childkeys . begin ( ) ; citer ! = childkeys . end ( ) ; + + citer )
{
// This will overwrite the parent value if present.
( * items ) [ citer - > first ] = citer - > second ;
}
2009-08-12 18:03:52 +00:00
}
void ConnectClass : : Update ( const ConnectClass * src )
{
2010-05-12 19:47:24 -05:00
config = src - > config ;
type = src - > type ;
fakelag = src - > fakelag ;
2009-08-12 18:03:52 +00:00
name = src - > name ;
registration_timeout = src - > registration_timeout ;
host = src - > host ;
pingtime = src - > pingtime ;
2009-09-26 16:41:07 +00:00
softsendqmax = src - > softsendqmax ;
hardsendqmax = src - > hardsendqmax ;
2009-08-12 18:03:52 +00:00
recvqmax = src - > recvqmax ;
2009-10-19 18:32:11 +00:00
penaltythreshold = src - > penaltythreshold ;
2010-05-12 19:47:24 -05:00
commandrate = src - > commandrate ;
2009-08-12 18:03:52 +00:00
maxlocal = src - > maxlocal ;
maxglobal = src - > maxglobal ;
2012-04-01 21:11:25 +02:00
maxconnwarn = src - > maxconnwarn ;
2010-05-12 19:47:24 -05:00
maxchans = src - > maxchans ;
2009-08-12 18:03:52 +00:00
limit = src - > limit ;
2013-07-10 12:46:01 +01:00
resolvehostnames = src - > resolvehostnames ;
2016-10-23 15:23:14 +01:00
ports = src - > ports ;
2009-08-12 18:03:52 +00:00
}