2007-07-16 17:30:04 +00:00
/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*
2008-01-10 13:27:07 +00:00
* InspIRCd : ( C ) 2002 - 2008 InspIRCd Development Team
2007-07-16 17:30:04 +00:00
* See : http : //www.inspircd.org/wiki/index.php/Credits
*
* This program is free but copyrighted software ; see
* the file COPYING for details .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2007-10-22 19:53:23 +00:00
/* $Core: libIRCDusers */
2007-07-16 17:30:04 +00:00
# include "inspircd.h"
# include <stdarg.h>
# include "socketengine.h"
# include "wildcard.h"
# include "xline.h"
2007-11-04 13:44:26 +00:00
# include "bancache.h"
2007-07-16 17:30:04 +00:00
# include "commands/cmd_whowas.h"
2008-04-21 23:16:07 +00:00
/* XXX: Used for speeding up WriteCommon operations */
unsigned long uniq_id = 1 ;
2008-04-02 17:08:09 +00:00
static unsigned long * already_sent = NULL ;
void InitializeAlreadySent ( SocketEngine * SE )
{
already_sent = new unsigned long [ SE - > GetMaxFds ( ) ] ;
2008-04-21 23:18:51 +00:00
memset ( already_sent , 0 , SE - > GetMaxFds ( ) * sizeof ( unsigned long ) ) ;
2008-04-02 17:08:09 +00:00
}
2007-07-16 17:30:04 +00:00
2007-10-15 20:59:05 +00:00
std : : string User : : ProcessNoticeMasks ( const char * sm )
2007-07-16 17:30:04 +00:00
{
bool adding = true , oldadding = false ;
const char * c = sm ;
std : : string output ;
while ( c & & * c )
{
switch ( * c )
{
case ' + ' :
adding = true ;
break ;
case ' - ' :
adding = false ;
break ;
case ' * ' :
for ( unsigned char d = ' A ' ; d < = ' z ' ; d + + )
{
if ( ServerInstance - > SNO - > IsEnabled ( d ) )
{
if ( ( ! IsNoticeMaskSet ( d ) & & adding ) | | ( IsNoticeMaskSet ( d ) & & ! adding ) )
{
if ( ( oldadding ! = adding ) | | ( ! output . length ( ) ) )
output + = ( adding ? ' + ' : ' - ' ) ;
this - > SetNoticeMask ( d , adding ) ;
output + = d ;
}
}
oldadding = adding ;
}
break ;
default :
if ( ( * c > = ' A ' ) & & ( * c < = ' z ' ) & & ( ServerInstance - > SNO - > IsEnabled ( * c ) ) )
{
if ( ( ! IsNoticeMaskSet ( * c ) & & adding ) | | ( IsNoticeMaskSet ( * c ) & & ! adding ) )
{
if ( ( oldadding ! = adding ) | | ( ! output . length ( ) ) )
output + = ( adding ? ' + ' : ' - ' ) ;
this - > SetNoticeMask ( * c , adding ) ;
output + = * c ;
}
}
2008-02-26 20:31:01 +00:00
else
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 501 , " %s %c :is unknown snomask char to me " , this - > nick . c_str ( ) , * c ) ;
2008-02-26 20:31:01 +00:00
2007-07-16 17:30:04 +00:00
oldadding = adding ;
break ;
}
* c + + ;
}
return output ;
}
2007-10-15 20:59:05 +00:00
void User : : StartDNSLookup ( )
2007-07-16 17:30:04 +00:00
{
try
{
bool cached ;
2008-04-10 23:35:35 +00:00
const char * sip = this - > GetIPString ( false ) ;
2007-07-16 17:30:04 +00:00
/* Special case for 4in6 (Have i mentioned i HATE 4in6?) */
2008-02-11 09:41:58 +00:00
if ( ! strncmp ( sip , " 0::ffff: " , 8 ) )
res_reverse = new UserResolver ( this - > ServerInstance , this , sip + 8 , DNS_QUERY_PTR4 , cached ) ;
2007-07-16 17:30:04 +00:00
else
2008-02-11 09:41:58 +00:00
res_reverse = new UserResolver ( this - > ServerInstance , this , sip , this - > GetProtocolFamily ( ) = = AF_INET ? DNS_QUERY_PTR4 : DNS_QUERY_PTR6 , cached ) ;
2007-07-16 17:30:04 +00:00
this - > ServerInstance - > AddResolver ( res_reverse , cached ) ;
}
catch ( CoreException & e )
{
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Error in resolver: %s " , e . GetReason ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
2007-10-15 20:59:05 +00:00
bool User : : IsNoticeMaskSet ( unsigned char sm )
2007-07-16 17:30:04 +00:00
{
return ( snomasks [ sm - 65 ] ) ;
}
2007-10-15 20:59:05 +00:00
void User : : SetNoticeMask ( unsigned char sm , bool value )
2007-07-16 17:30:04 +00:00
{
snomasks [ sm - 65 ] = value ;
}
2007-10-15 20:59:05 +00:00
const char * User : : FormatNoticeMasks ( )
2007-07-16 17:30:04 +00:00
{
static char data [ MAXBUF ] ;
int offset = 0 ;
for ( int n = 0 ; n < 64 ; n + + )
{
if ( snomasks [ n ] )
data [ offset + + ] = n + 65 ;
}
data [ offset ] = 0 ;
return data ;
}
2007-10-15 20:59:05 +00:00
bool User : : IsModeSet ( unsigned char m )
2007-07-16 17:30:04 +00:00
{
return ( modes [ m - 65 ] ) ;
}
2007-10-15 20:59:05 +00:00
void User : : SetMode ( unsigned char m , bool value )
2007-07-16 17:30:04 +00:00
{
modes [ m - 65 ] = value ;
}
2007-10-15 20:59:05 +00:00
const char * User : : FormatModes ( )
2007-07-16 17:30:04 +00:00
{
static char data [ MAXBUF ] ;
int offset = 0 ;
for ( int n = 0 ; n < 64 ; n + + )
{
if ( modes [ n ] )
data [ offset + + ] = n + 65 ;
}
data [ offset ] = 0 ;
return data ;
}
2007-10-15 20:59:05 +00:00
void User : : DecrementModes ( )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " DecrementModes() " ) ;
2007-09-30 18:14:51 +00:00
for ( unsigned char n = ' A ' ; n < = ' z ' ; n + + )
2007-07-16 17:30:04 +00:00
{
2007-09-30 18:14:51 +00:00
if ( modes [ n - 65 ] )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " DecrementModes() found mode %c " , n ) ;
2007-09-30 18:14:51 +00:00
ModeHandler * mh = ServerInstance - > Modes - > FindMode ( n , MODETYPE_USER ) ;
2007-07-16 17:30:04 +00:00
if ( mh )
2007-09-30 18:14:51 +00:00
{
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Found handler %c and call ChangeCount " , n ) ;
2007-07-16 17:30:04 +00:00
mh - > ChangeCount ( - 1 ) ;
2007-09-30 18:14:51 +00:00
}
2007-07-16 17:30:04 +00:00
}
}
}
2007-10-15 20:59:05 +00:00
User : : User ( InspIRCd * Instance , const std : : string & uid ) : ServerInstance ( Instance )
2007-07-16 17:30:04 +00:00
{
server = ( char * ) Instance - > FindServerNamePtr ( Instance - > Config - > ServerName ) ;
reset_due = ServerInstance - > Time ( ) ;
2008-02-22 16:40:02 +00:00
age = ServerInstance - > Time ( ) ;
2007-10-21 14:08:13 +00:00
Penalty = 0 ;
2008-07-02 14:22:48 +00:00
lines_in = lastping = signon = idle_lastmsg = nping = registered = 0 ;
2007-10-23 23:54:24 +00:00
ChannelCount = timeout = bytes_in = bytes_out = cmds_in = cmds_out = 0 ;
2008-04-11 14:27:26 +00:00
quietquit = OverPenalty = ExemptFromPenalty = quitting = exempt = haspassed = dns_done = false ;
2007-07-16 17:30:04 +00:00
fd = - 1 ;
recvq . clear ( ) ;
2008-07-02 14:22:48 +00:00
sendq . clear ( ) ;
2007-07-16 17:30:04 +00:00
WriteError . clear ( ) ;
res_forward = res_reverse = NULL ;
Visibility = NULL ;
ip = NULL ;
2007-10-23 23:07:24 +00:00
MyClass = NULL ;
2008-03-24 15:13:17 +00:00
io = NULL ;
2008-03-23 21:12:36 +00:00
AllowedUserModes = NULL ;
AllowedChanModes = NULL ;
2007-11-11 15:44:43 +00:00
AllowedOperCommands = NULL ;
2007-07-16 17:30:04 +00:00
chans . clear ( ) ;
invites . clear ( ) ;
memset ( modes , 0 , sizeof ( modes ) ) ;
memset ( snomasks , 0 , sizeof ( snomasks ) ) ;
2007-08-27 13:36:11 +00:00
2007-08-27 13:40:12 +00:00
if ( uid . empty ( ) )
2008-05-23 17:15:48 +00:00
uuid . assign ( Instance - > GetUID ( ) , 0 , UUID_LENGTH - 1 ) ;
2007-08-27 13:36:11 +00:00
else
2008-05-23 17:15:48 +00:00
uuid . assign ( uid , 0 , UUID_LENGTH - 1 ) ;
2007-08-27 11:43:12 +00:00
2008-05-18 23:15:53 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " New UUID for user: %s (%s) " , uuid . c_str ( ) , uid . empty ( ) ? " allocated new " : " used remote " ) ;
2007-08-27 13:54:15 +00:00
2008-02-02 20:55:16 +00:00
user_hash : : iterator finduuid = Instance - > Users - > uuidlist - > find ( uuid ) ;
if ( finduuid = = Instance - > Users - > uuidlist - > end ( ) )
( * Instance - > Users - > uuidlist ) [ uuid ] = this ;
2007-08-27 11:43:12 +00:00
else
2007-10-15 20:59:05 +00:00
throw CoreException ( " Duplicate UUID " + std : : string ( uuid ) + " in User constructor " ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
User : : ~ User ( )
2007-07-16 17:30:04 +00:00
{
2007-10-23 23:07:24 +00:00
/* NULL for remote users :) */
if ( this - > MyClass )
{
this - > MyClass - > RefCount - - ;
2008-03-30 02:48:54 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " User destructor -- connect refcount now: %lu " , this - > MyClass - > RefCount ) ;
2007-10-23 23:07:24 +00:00
}
2007-11-11 15:44:43 +00:00
if ( this - > AllowedOperCommands )
{
delete AllowedOperCommands ;
AllowedOperCommands = NULL ;
}
2007-10-23 23:07:24 +00:00
2008-03-23 21:12:36 +00:00
if ( this - > AllowedUserModes )
{
2008-03-23 21:36:16 +00:00
delete [ ] AllowedUserModes ;
2008-03-23 21:12:36 +00:00
AllowedUserModes = NULL ;
}
if ( this - > AllowedChanModes )
{
2008-03-23 21:36:16 +00:00
delete [ ] AllowedChanModes ;
2008-03-23 21:12:36 +00:00
AllowedChanModes = NULL ;
}
2007-07-16 17:30:04 +00:00
this - > InvalidateCache ( ) ;
this - > DecrementModes ( ) ;
2008-01-16 07:59:09 +00:00
2007-07-16 17:30:04 +00:00
if ( ip )
{
2008-01-13 03:37:25 +00:00
ServerInstance - > Users - > RemoveCloneCounts ( this ) ;
2007-07-16 17:30:04 +00:00
if ( this - > GetProtocolFamily ( ) = = AF_INET )
{
delete ( sockaddr_in * ) ip ;
}
# ifdef SUPPORT_IP6LINKS
else
{
delete ( sockaddr_in6 * ) ip ;
}
# endif
}
2007-08-27 11:43:12 +00:00
2008-02-02 20:55:16 +00:00
ServerInstance - > Users - > uuidlist - > erase ( uuid ) ;
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 ;
char nhost [ MAXBUF ] ;
/* This is much faster than snprintf */
char * t = nhost ;
2008-05-18 23:15:53 +00:00
for ( const char * n = ident . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' @ ' ;
2008-05-19 19:12:43 +00:00
for ( const char * n = host . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t = 0 ;
2008-05-18 23:15:53 +00:00
this - > cached_makehost . assign ( nhost ) ;
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 ;
char ihost [ MAXBUF ] ;
/* This is much faster than snprintf */
char * t = ihost ;
2008-05-18 23:15:53 +00:00
for ( const char * n = ident . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' @ ' ;
for ( const char * n = this - > GetIPString ( ) ; * n ; n + + )
* t + + = * n ;
* t = 0 ;
2008-05-18 23:15:53 +00:00
this - > cached_hostip = ihost ;
2007-07-16 17:30:04 +00:00
return this - > cached_hostip ;
}
2007-10-15 20:59:05 +00:00
void User : : CloseSocket ( )
2007-07-16 17:30:04 +00:00
{
2008-04-02 22:57:52 +00:00
if ( this - > fd > - 1 )
2008-04-02 22:53:33 +00:00
{
ServerInstance - > SE - > Shutdown ( this , 2 ) ;
ServerInstance - > SE - > Close ( this ) ;
}
2007-07-16 17:30:04 +00:00
}
2008-05-18 23:15:53 +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 ;
char result [ MAXBUF ] ;
char * t = result ;
2008-05-18 23:15:53 +00:00
for ( const char * n = nick . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' ! ' ;
2008-05-18 23:15:53 +00:00
for ( const char * n = ident . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' @ ' ;
2008-05-18 23:15:53 +00:00
for ( const char * n = dhost . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t = 0 ;
2008-05-18 23:15:53 +00:00
this - > cached_fullhost = result ;
2007-07-16 17:30:04 +00:00
return this - > cached_fullhost ;
}
2007-10-15 20:59:05 +00:00
char * User : : MakeWildHost ( )
2007-07-16 17:30:04 +00:00
{
static char nresult [ MAXBUF ] ;
char * t = nresult ;
* t + + = ' * ' ; * t + + = ' ! ' ;
* t + + = ' * ' ; * t + + = ' @ ' ;
2008-05-18 23:15:53 +00:00
for ( const char * n = dhost . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t = 0 ;
return nresult ;
}
2007-10-15 20:59:05 +00:00
int User : : ReadData ( void * buffer , size_t size )
2007-07-16 17:30:04 +00:00
{
if ( IS_LOCAL ( this ) )
{
# ifndef WIN32
return read ( this - > fd , buffer , size ) ;
# else
return recv ( this - > fd , ( char * ) buffer , size , 0 ) ;
# endif
}
else
return 0 ;
}
2008-05-18 23:15:53 +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 ;
char fresult [ MAXBUF ] ;
char * t = fresult ;
2008-05-18 23:15:53 +00:00
for ( const char * n = nick . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' ! ' ;
2008-05-18 23:15:53 +00:00
for ( const char * n = ident . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t + + = ' @ ' ;
2008-05-19 19:12:43 +00:00
for ( const char * n = host . c_str ( ) ; * n ; n + + )
2007-07-16 17:30:04 +00:00
* t + + = * n ;
* t = 0 ;
2008-05-18 23:15:53 +00:00
this - > cached_fullrealhost = fresult ;
2007-07-16 17:30:04 +00:00
return this - > cached_fullrealhost ;
}
2007-10-15 20:59:05 +00:00
bool User : : IsInvited ( const irc : : string & channel )
2007-07-16 17:30:04 +00:00
{
2008-02-08 23:35:39 +00:00
time_t now = time ( NULL ) ;
InvitedList : : iterator safei ;
for ( InvitedList : : iterator i = invites . begin ( ) ; i ! = invites . end ( ) ; + + i )
2007-07-16 17:30:04 +00:00
{
2008-02-08 23:35:39 +00:00
if ( channel = = i - > first )
2007-07-16 17:30:04 +00:00
{
2008-02-08 23:35:39 +00:00
if ( i - > second ! = 0 & & now > i - > second )
{
/* Expired invite, remove it. */
safei = i ;
- - i ;
invites . erase ( safei ) ;
continue ;
}
2007-07-16 17:30:04 +00:00
return true ;
}
}
return false ;
}
2007-10-15 20:59:05 +00:00
InvitedList * User : : GetInviteList ( )
2007-07-16 17:30:04 +00:00
{
2008-02-08 23:35:39 +00:00
time_t now = time ( NULL ) ;
/* Weed out expired invites here. */
InvitedList : : iterator safei ;
for ( InvitedList : : iterator i = invites . begin ( ) ; i ! = invites . end ( ) ; + + i )
{
if ( i - > second ! = 0 & & now > i - > second )
{
/* Expired invite, remove it. */
safei = i ;
- - i ;
invites . erase ( safei ) ;
}
}
2007-07-16 17:30:04 +00:00
return & invites ;
}
2008-02-11 09:41:58 +00:00
void User : : InviteTo ( const irc : : string & channel , time_t invtimeout )
2007-07-16 17:30:04 +00:00
{
2008-02-08 23:35:39 +00:00
time_t now = time ( NULL ) ;
2008-02-11 09:41:58 +00:00
if ( invtimeout ! = 0 & & now > invtimeout ) return ; /* Don't add invites that are expired from the get-go. */
2008-02-08 23:35:39 +00:00
for ( InvitedList : : iterator i = invites . begin ( ) ; i ! = invites . end ( ) ; + + i )
{
if ( channel = = i - > first )
{
2008-02-11 09:41:58 +00:00
if ( i - > second ! = 0 & & invtimeout > i - > second )
2008-02-08 23:35:39 +00:00
{
2008-02-11 09:41:58 +00:00
i - > second = invtimeout ;
2008-02-08 23:35:39 +00:00
}
}
}
2008-02-11 09:41:58 +00:00
invites . push_back ( std : : make_pair ( channel , invtimeout ) ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : RemoveInvite ( const irc : : string & channel )
2007-07-16 17:30:04 +00:00
{
for ( InvitedList : : iterator i = invites . begin ( ) ; i ! = invites . end ( ) ; i + + )
{
2008-02-08 23:35:39 +00:00
if ( channel = = i - > first )
2007-07-16 17:30:04 +00:00
{
invites . erase ( i ) ;
return ;
}
}
}
2008-03-23 20:43:35 +00:00
bool User : : HasModePermission ( unsigned char mode , ModeType type )
{
if ( ! IS_LOCAL ( this ) )
return true ;
if ( ! IS_OPER ( this ) )
return false ;
2008-03-23 21:12:36 +00:00
if ( ! AllowedUserModes | | ! AllowedChanModes )
return false ;
2008-03-23 20:43:35 +00:00
return ( ( type = = MODETYPE_USER ? AllowedUserModes : AllowedChanModes ) ) [ ( mode - ' A ' ) ] ;
}
2007-10-15 20:59:05 +00:00
bool User : : HasPermission ( const std : : string & command )
2007-07-16 17:30:04 +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 .
*/
if ( ! IS_LOCAL ( this ) )
return true ;
// are they even an oper at all?
2007-10-15 22:33:18 +00:00
if ( ! IS_OPER ( this ) )
2007-07-16 17:30:04 +00:00
{
2007-10-15 22:33:18 +00:00
return false ;
}
2007-11-11 15:44:43 +00:00
if ( ! AllowedOperCommands )
2007-10-15 22:33:18 +00:00
return false ;
2007-11-11 15:44:43 +00:00
if ( AllowedOperCommands - > find ( command ) ! = AllowedOperCommands - > end ( ) )
return true ;
else if ( AllowedOperCommands - > find ( " * " ) ! = AllowedOperCommands - > end ( ) )
return true ;
2007-10-15 22:33:18 +00:00
2007-07-16 17:30:04 +00:00
return false ;
}
2008-05-07 21:53:30 +00:00
bool User : : AddBuffer ( const std : : string & a )
2007-07-16 17:30:04 +00:00
{
2008-05-07 21:53:30 +00:00
std : : string : : size_type start = 0 ;
std : : string : : size_type i = a . find ( ' \r ' ) ;
/*
* The old implementation here took a copy , and rfind ( ) on \ r , removing as it found them , before
* copying a second time onto the recvq . That ' s ok , but involves three copies minimum ( recv ( ) to buffer ,
* buffer to here , here to recvq ) - The new method now copies twice ( recv ( ) to buffer , buffer to recvq ) .
*
* We use find ( ) instead of rfind ( ) for clarity , however unlike the old code , our scanning of the string is
* contiguous : as we specify a startpoint , we never see characters we have scanned previously , making this
* marginally faster in cases with a number of \ r hidden early on in the buffer .
*
* How it works :
* Start at first pos of string , find first \ r , append everything in the chunk ( excluding \ r ) to recvq . Set
* i ahead of the \ r , search for next \ r , add next chunk to buffer . . . repeat .
* - - w00t ( 7 may , 2008 )
*/
if ( i = = std : : string : : npos )
{
// no \r that we need to dance around, just add to buffer
recvq . append ( a ) ;
}
else
2007-07-16 17:30:04 +00:00
{
2008-05-07 21:53:30 +00:00
// While we can find the end of a chunk to add
2007-07-16 17:30:04 +00:00
while ( i ! = std : : string : : npos )
{
2008-05-07 21:53:30 +00:00
// Append the chunk that we have
recvq . append ( a , start , ( i - start ) ) ;
2007-07-16 17:30:04 +00:00
2008-05-07 21:53:30 +00:00
// Start looking for the next one
start = i + 1 ;
i = a . find ( ' \r ' , start ) ;
}
2007-07-16 17:30:04 +00:00
2008-05-07 21:53:30 +00:00
if ( start ! = a . length ( ) )
2007-07-16 17:30:04 +00:00
{
2008-05-07 21:53:30 +00:00
/*
* This is here to catch a corner case when we get something like :
* NICK w0
* 0 t \ r \ nU
* SER . . .
* in successive calls to us .
*
* Without this conditional , the ' U ' on the second case will be dropped ,
* which is most * certainly * not the behaviour we want !
* - - w00t
*/
recvq . append ( a , start , ( a . length ( ) - start ) ) ;
2007-07-16 17:30:04 +00:00
}
}
2008-05-07 21:53:30 +00:00
if ( this - > MyClass & & ( recvq . length ( ) > this - > MyClass - > GetRecvqMax ( ) ) )
2007-07-16 17:30:04 +00:00
{
2008-05-07 21:53:30 +00:00
this - > SetWriteError ( " RecvQ exceeded " ) ;
2008-05-18 23:15:53 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' A ' , " User %s RecvQ of %lu exceeds connect class maximum of %lu " , this - > nick . c_str ( ) , ( unsigned long int ) recvq . length ( ) , this - > MyClass - > GetRecvqMax ( ) ) ;
2007-07-16 17:30:04 +00:00
return false ;
}
2008-05-07 21:53:30 +00:00
return true ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
bool User : : BufferIsReady ( )
2007-07-16 17:30:04 +00:00
{
return ( recvq . find ( ' \n ' ) ! = std : : string : : npos ) ;
}
2007-10-15 20:59:05 +00:00
void User : : ClearBuffer ( )
2007-07-16 17:30:04 +00:00
{
recvq . clear ( ) ;
}
2007-10-15 20:59:05 +00:00
std : : string User : : GetBuffer ( )
2007-07-16 17:30:04 +00:00
{
try
{
2007-10-21 12:29:48 +00:00
if ( recvq . empty ( ) )
2007-07-16 17:30:04 +00:00
return " " ;
/* Strip any leading \r or \n off the string.
* Usually there are only one or two of these ,
* so its is computationally cheap to do .
*/
std : : string : : iterator t = recvq . begin ( ) ;
while ( t ! = recvq . end ( ) & & ( * t = = ' \r ' | | * t = = ' \n ' ) )
{
recvq . erase ( t ) ;
t = recvq . begin ( ) ;
}
for ( std : : string : : iterator x = recvq . begin ( ) ; x ! = recvq . end ( ) ; x + + )
{
/* Find the first complete line, return it as the
* result , and leave the recvq as whats left
*/
if ( * x = = ' \n ' )
{
std : : string ret = std : : string ( recvq . begin ( ) , x ) ;
recvq . erase ( recvq . begin ( ) , x + 1 ) ;
return ret ;
}
}
return " " ;
}
catch ( . . . )
{
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Exception in User::GetBuffer() " ) ;
2007-07-16 17:30:04 +00:00
return " " ;
}
}
2008-07-02 14:22:48 +00:00
void User : : AddWriteBuf ( const std : : string & data )
2007-07-16 17:30:04 +00:00
{
if ( * this - > GetWriteError ( ) )
return ;
2008-07-02 14:22:48 +00:00
if ( this - > MyClass & & ( sendq . length ( ) + data . length ( ) > this - > MyClass - > GetSendqMax ( ) ) )
2007-07-16 17:30:04 +00:00
{
/*
2008-01-17 13:07:49 +00:00
* Fix by brain - Set the error text BEFORE calling , because
2007-07-16 17:30:04 +00:00
* if we dont it ' ll recursively call here over and over again trying
* to repeatedly add the text to the sendq !
*/
this - > SetWriteError ( " SendQ exceeded " ) ;
2008-07-02 14:22:48 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' A ' , " User %s SendQ of %lu exceeds connect class maximum of %lu " , this - > nick . c_str ( ) , ( unsigned long int ) sendq . length ( ) + data . length ( ) , this - > MyClass - > GetSendqMax ( ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2008-07-02 14:22:48 +00:00
if ( data . length ( ) > MAXBUF - 2 ) /* MAXBUF has a value of 514, to account for line terminators */
sendq . append ( data . substr ( 0 , MAXBUF - 4 ) ) . append ( " \r \n " ) ; /* MAXBUF-4 = 510 */
else
sendq . append ( data ) ;
2007-07-16 17:30:04 +00:00
}
// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
2007-10-15 20:59:05 +00:00
void User : : FlushWriteBuf ( )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
try
2008-07-02 14:20:38 +00:00
{
2008-07-02 14:22:48 +00:00
if ( ( this - > fd = = FD_MAGIC_NUMBER ) | | ( * this - > GetWriteError ( ) ) )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
sendq . clear ( ) ;
2007-07-16 17:30:04 +00:00
}
2008-07-02 14:22:48 +00:00
if ( ( sendq . length ( ) ) & & ( this - > fd ! = FD_MAGIC_NUMBER ) )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
int old_sendq_length = sendq . length ( ) ;
int n_sent = ServerInstance - > SE - > Send ( this , this - > sendq . data ( ) , this - > sendq . length ( ) , 0 ) ;
2007-08-23 22:06:04 +00:00
2008-07-02 14:22:48 +00:00
if ( n_sent = = - 1 )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
if ( errno = = EAGAIN )
{
/* The socket buffer is full. This isnt fatal,
* try again later .
*/
this - > ServerInstance - > SE - > WantWrite ( this ) ;
}
else
{
/* Fatal error, set write error and bail
*/
this - > SetWriteError ( errno ? strerror ( errno ) : " EOF from client " ) ;
return ;
}
2007-07-16 17:30:04 +00:00
}
else
{
2008-07-02 14:22:48 +00:00
/* advance the queue */
if ( n_sent )
this - > sendq = this - > sendq . substr ( n_sent ) ;
/* update the user's stats counters */
this - > bytes_out + = n_sent ;
2007-07-16 17:30:04 +00:00
this - > cmds_out + + ;
2008-07-02 14:22:48 +00:00
if ( n_sent ! = old_sendq_length )
this - > ServerInstance - > SE - > WantWrite ( this ) ;
2007-07-16 17:30:04 +00:00
}
}
}
2008-07-02 14:22:48 +00:00
catch ( . . . )
{
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Exception in User::FlushWriteBuf() " ) ;
}
2007-07-16 17:30:04 +00:00
if ( this - > sendq . empty ( ) )
{
2008-07-02 14:22:48 +00:00
FOREACH_MOD ( I_OnBufferFlushed , OnBufferFlushed ( this ) ) ;
2007-07-16 17:30:04 +00:00
}
}
2007-10-15 20:59:05 +00:00
void User : : SetWriteError ( const std : : string & error )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
// don't try to set the error twice, its already set take the first string.
if ( this - > WriteError . empty ( ) )
this - > WriteError = error ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
const char * User : : GetWriteError ( )
2007-07-16 17:30:04 +00:00
{
return this - > WriteError . c_str ( ) ;
}
2008-01-02 22:58:47 +00:00
void User : : Oper ( const std : : string & opertype , const std : : string & opername )
2007-07-16 17:30:04 +00:00
{
2007-11-11 15:44:43 +00:00
char * mycmd ;
char * savept ;
char * savept2 ;
2007-07-16 17:30:04 +00:00
try
{
this - > modes [ UM_OPERATOR ] = 1 ;
2008-05-18 23:15:53 +00:00
this - > WriteServ ( " MODE %s :+o " , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
FOREACH_MOD ( I_OnOper , OnOper ( this , opertype ) ) ;
2008-05-19 19:12:43 +00:00
ServerInstance - > Logs - > Log ( " OPER " , DEFAULT , " %s!%s@%s opered as type: %s " , this - > nick . c_str ( ) , this - > ident . c_str ( ) , this - > host . c_str ( ) , opertype . c_str ( ) ) ;
2008-06-01 18:22:42 +00:00
this - > oper . assign ( opertype , 0 , 512 ) ;
2008-02-02 20:55:16 +00:00
ServerInstance - > Users - > all_opers . push_back ( this ) ;
2007-11-11 15:44:43 +00:00
2008-05-18 23:15:53 +00:00
opertype_t : : iterator iter_opertype = ServerInstance - > Config - > opertypes . find ( this - > oper . c_str ( ) ) ;
2007-11-11 15:44:43 +00:00
if ( iter_opertype ! = ServerInstance - > Config - > opertypes . end ( ) )
{
if ( AllowedOperCommands )
AllowedOperCommands - > clear ( ) ;
else
AllowedOperCommands = new std : : map < std : : string , bool > ;
2008-03-23 21:12:36 +00:00
if ( ! AllowedChanModes )
AllowedChanModes = new bool [ 64 ] ;
if ( ! AllowedUserModes )
AllowedUserModes = new bool [ 64 ] ;
2008-03-23 21:36:16 +00:00
memset ( AllowedUserModes , 0 , 64 ) ;
memset ( AllowedChanModes , 0 , 64 ) ;
2008-03-23 21:12:36 +00:00
2007-11-11 15:44:43 +00:00
char * Classes = strdup ( iter_opertype - > second ) ;
char * myclass = strtok_r ( Classes , " " , & savept ) ;
while ( myclass )
{
operclass_t : : iterator iter_operclass = ServerInstance - > Config - > operclass . find ( myclass ) ;
if ( iter_operclass ! = ServerInstance - > Config - > operclass . end ( ) )
{
2008-03-23 20:43:35 +00:00
char * CommandList = strdup ( iter_operclass - > second . commandlist ) ;
2007-11-11 15:44:43 +00:00
mycmd = strtok_r ( CommandList , " " , & savept2 ) ;
while ( mycmd )
{
this - > AllowedOperCommands - > insert ( std : : make_pair ( mycmd , true ) ) ;
mycmd = strtok_r ( NULL , " " , & savept2 ) ;
}
free ( CommandList ) ;
2008-03-23 20:43:35 +00:00
this - > AllowedUserModes [ ' o ' - ' A ' ] = true ; // Call me paranoid if you want.
for ( unsigned char * c = ( unsigned char * ) iter_operclass - > second . umodelist ; * c ; + + c )
{
if ( * c = = ' * ' )
{
2008-03-23 21:36:16 +00:00
memset ( this - > AllowedUserModes , ( int ) ( true ) , 64 ) ;
2008-03-23 20:43:35 +00:00
}
else
{
this - > AllowedUserModes [ * c - ' A ' ] = true ;
}
}
for ( unsigned char * c = ( unsigned char * ) iter_operclass - > second . cmodelist ; * c ; + + c )
{
if ( * c = = ' * ' )
{
2008-03-23 21:36:16 +00:00
memset ( this - > AllowedChanModes , ( int ) ( true ) , 64 ) ;
2008-03-23 20:43:35 +00:00
}
else
{
this - > AllowedChanModes [ * c - ' A ' ] = true ;
}
}
2007-11-11 15:44:43 +00:00
}
myclass = strtok_r ( NULL , " " , & savept ) ;
}
free ( Classes ) ;
}
2008-01-02 22:58:47 +00:00
FOREACH_MOD ( I_OnPostOper , OnPostOper ( this , opertype , opername ) ) ;
2007-07-16 17:30:04 +00:00
}
catch ( . . . )
{
2008-02-22 16:47:10 +00:00
ServerInstance - > Logs - > Log ( " OPER " , DEBUG , " Exception in User::Oper() " ) ;
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
{
2008-02-09 13:06:02 +00:00
if ( IS_OPER ( this ) )
2007-07-16 17:30:04 +00:00
{
2008-02-26 20:46:21 +00:00
/* Remove all oper only modes from the user when the deoper - Bug #466*/
std : : string moderemove ( " - " ) ;
for ( unsigned char letter = ' A ' ; letter < = ' z ' ; letter + + )
{
if ( letter ! = ' o ' )
{
ModeHandler * mh = ServerInstance - > Modes - > FindMode ( letter , MODETYPE_USER ) ;
if ( mh & & mh - > NeedsOper ( ) )
moderemove + = letter ;
}
}
2008-05-04 21:37:36 +00:00
std : : vector < std : : string > parameters ;
parameters . push_back ( this - > nick ) ;
parameters . push_back ( moderemove ) ;
ServerInstance - > Parser - > CallHandler ( " MODE " , parameters , this ) ;
2008-02-26 20:46:21 +00:00
/* unset their oper type (what IS_OPER checks), and remove +o */
2008-05-18 23:15:53 +00:00
this - > oper . clear ( ) ;
2008-02-09 13:06:02 +00:00
this - > modes [ UM_OPERATOR ] = 0 ;
2007-09-26 23:49:15 +00:00
2008-02-26 20:46:21 +00:00
/* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
2008-02-09 13:06:02 +00:00
ServerInstance - > Users - > all_opers . remove ( this ) ;
2007-11-11 15:44:43 +00:00
2008-02-09 13:06:02 +00:00
if ( AllowedOperCommands )
{
delete AllowedOperCommands ;
AllowedOperCommands = NULL ;
2007-07-16 17:30:04 +00:00
}
2008-03-23 21:36:16 +00:00
if ( AllowedUserModes )
{
delete [ ] AllowedUserModes ;
AllowedUserModes = NULL ;
}
if ( AllowedChanModes )
{
delete [ ] AllowedChanModes ;
AllowedChanModes = NULL ;
}
2007-07-16 17:30:04 +00:00
}
}
/* adds or updates an entry in the whowas list */
2007-10-15 20:59:05 +00:00
void User : : AddToWhoWas ( )
2007-07-16 17:30:04 +00:00
{
2007-10-15 20:55:55 +00:00
Command * whowas_command = ServerInstance - > Parser - > GetHandler ( " WHOWAS " ) ;
2007-07-16 17:30:04 +00:00
if ( whowas_command )
{
std : : deque < classbase * > params ;
params . push_back ( this ) ;
whowas_command - > HandleInternal ( WHOWAS_ADD , params ) ;
}
}
/*
* Check class restrictions
*/
2007-10-23 23:25:49 +00:00
void User : : CheckClass ( )
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
if ( ( ! a ) | | ( a - > GetType ( ) = = CC_DENY ) )
{
2008-04-09 15:34:54 +00:00
ServerInstance - > Users - > QuitUser ( this , " Unauthorised connection " ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2008-01-13 03:37:25 +00:00
else if ( ( a - > GetMaxLocal ( ) ) & & ( ServerInstance - > Users - > LocalCloneCount ( this ) > a - > GetMaxLocal ( ) ) )
2007-07-16 17:30:04 +00:00
{
2008-04-09 15:34:54 +00:00
ServerInstance - > Users - > QuitUser ( this , " No more connections allowed from your host via this connect class (local) " ) ;
2008-01-17 15:54:33 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' A ' , " WARNING: maximum LOCAL connections (%ld) exceeded for IP %s " , a - > GetMaxLocal ( ) , this - > GetIPString ( ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2008-01-13 03:37:25 +00:00
else if ( ( a - > GetMaxGlobal ( ) ) & & ( ServerInstance - > Users - > GlobalCloneCount ( this ) > a - > GetMaxGlobal ( ) ) )
2007-07-16 17:30:04 +00:00
{
2008-04-09 15:34:54 +00:00
ServerInstance - > Users - > QuitUser ( this , " No more connections allowed from your host via this connect class (global) " ) ;
2008-01-17 15:54:33 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' A ' , " WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s " , a - > GetMaxGlobal ( ) , this - > GetIPString ( ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2007-08-06 19:55:09 +00:00
this - > nping = ServerInstance - > Time ( ) + a - > GetPingTime ( ) + ServerInstance - > Config - > dns_timeout ;
this - > timeout = ServerInstance - > Time ( ) + a - > GetRegTimeout ( ) ;
2007-08-19 20:14:05 +00:00
this - > MaxChans = a - > GetMaxChans ( ) ;
2007-07-16 17:30:04 +00:00
}
2008-04-12 15:48:01 +00:00
void User : : CheckLines ( )
{
2008-04-13 16:45:32 +00:00
const char * check [ ] = { " G " , " K " , NULL } ;
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 ) ;
return ;
}
}
}
}
2007-10-15 20:59:05 +00:00
void User : : FullConnect ( )
2007-07-16 17:30:04 +00:00
{
ServerInstance - > stats - > statsConnects + + ;
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
*/
2007-10-23 23:25:49 +00:00
this - > SetClass ( ) ;
2007-07-16 17:30:04 +00:00
/* Check the password, if one is required by the user's connect class.
* This CANNOT be in CheckClass ( ) , because that is called prior to PASS as well !
*/
2007-10-25 15:25:32 +00:00
if ( this - > MyClass & & ! this - > MyClass - > GetPass ( ) . empty ( ) & & ! this - > haspassed )
2007-07-16 17:30:04 +00:00
{
2008-04-09 15:34:54 +00:00
ServerInstance - > Users - > QuitUser ( this , " Invalid password " ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2007-10-25 15:25:32 +00:00
2008-04-12 15:48:01 +00:00
CheckLines ( ) ;
2007-07-16 17:30:04 +00:00
this - > WriteServ ( " NOTICE Auth :Welcome to \002 %s \002 ! " , ServerInstance - > Config - > Network ) ;
2008-05-19 19:12:43 +00:00
this - > WriteNumeric ( 001 , " %s :Welcome to the %s IRC Network %s!%s@%s " , this - > nick . c_str ( ) , ServerInstance - > Config - > Network , this - > nick . c_str ( ) , this - > ident . c_str ( ) , this - > host . c_str ( ) ) ;
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 002 , " %s :Your host is %s, running version InspIRCd-1.2 " , this - > nick . c_str ( ) , ServerInstance - > Config - > ServerName ) ;
this - > WriteNumeric ( 003 , " %s :This server was created %s %s " , this - > nick . c_str ( ) , __TIME__ , __DATE__ ) ;
this - > WriteNumeric ( 004 , " %s %s InspIRCd-1.2 %s %s %s " , this - > nick . c_str ( ) , ServerInstance - > Config - > ServerName , ServerInstance - > Modes - > UserModeList ( ) . c_str ( ) , ServerInstance - > Modes - > ChannelModeList ( ) . c_str ( ) , ServerInstance - > Modes - > ParaModeList ( ) . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
ServerInstance - > Config - > Send005 ( this ) ;
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 42 , " %s %s :your unique ID " , this - > nick . c_str ( ) , this - > uuid . c_str ( ) ) ;
2007-08-27 00:12:59 +00:00
2007-07-16 17:30:04 +00:00
this - > ShowMOTD ( ) ;
/* 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
/* Trigger LUSERS output, give modules a chance too */
int MOD_RESULT = 0 ;
2008-06-06 15:28:24 +00:00
std : : string command ( " LUSERS " ) ;
std : : vector < std : : string > parameters ;
FOREACH_RESULT ( I_OnPreCommand , OnPreCommand ( command , parameters , this , true , " LUSERS " ) ) ;
2007-07-16 17:30:04 +00:00
if ( ! MOD_RESULT )
2008-06-06 15:28:24 +00:00
ServerInstance - > CallCommandHandler ( command , parameters , this ) ;
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
*/
FOREACH_MOD ( I_OnUserConnect , OnUserConnect ( this ) ) ;
this - > registered = REG_ALL ;
2008-06-01 14:18:07 +00:00
ServerInstance - > PI - > Introduce ( this ) ;
2007-07-16 17:30:04 +00:00
FOREACH_MOD ( I_OnPostConnect , OnPostConnect ( this ) ) ;
2008-05-19 19:12:43 +00:00
ServerInstance - > SNO - > WriteToSnoMask ( ' c ' , " Client connecting on port %d: %s!%s@%s [%s] [%s] " , this - > GetPort ( ) , this - > nick . c_str ( ) , this - > ident . c_str ( ) , this - > host . c_str ( ) , this - > GetIPString ( ) , this - > fullname . c_str ( ) ) ;
2008-02-09 13:06:02 +00:00
ServerInstance - > Logs - > Log ( " BANCACHE " , DEBUG , " BanCache: Adding NEGATIVE hit for %s " , this - > GetIPString ( ) ) ;
2007-11-04 23:15:26 +00:00
ServerInstance - > BanCache - > AddHit ( this - > GetIPString ( ) , " " , " " ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
/** User::UpdateNick()
2007-07-16 17:30:04 +00:00
* re - allocates a nick in the user_hash after they change nicknames ,
* returns a pointer to the new user as it may have moved
*/
2007-10-15 20:59:05 +00:00
User * User : : UpdateNickHash ( const char * New )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
//user_hash::iterator newnick;
user_hash : : iterator oldnick = ServerInstance - > Users - > clientlist - > find ( this - > nick ) ;
2007-07-16 17:30:04 +00:00
2008-05-18 23:15:53 +00:00
if ( ! irc : : string ( this - > nick . c_str ( ) ) . compare ( New ) )
2008-02-09 13:06:02 +00:00
return oldnick - > second ;
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
if ( oldnick = = ServerInstance - > Users - > clientlist - > end ( ) )
return NULL ; /* doesnt exist */
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
User * olduser = oldnick - > second ;
( * ( ServerInstance - > Users - > clientlist ) ) [ New ] = olduser ;
ServerInstance - > Users - > clientlist - > erase ( oldnick ) ;
return olduser ;
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 */
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
}
2007-10-15 20:59:05 +00:00
bool User : : ForceNickChange ( const char * newnick )
2007-07-16 17:30:04 +00:00
{
2008-04-07 22:00:49 +00:00
int MOD_RESULT = 0 ;
2007-07-16 17:30:04 +00:00
2008-04-07 22:00:49 +00:00
this - > InvalidateCache ( ) ;
2007-07-16 17:30:04 +00:00
2008-04-07 22:00:49 +00:00
FOREACH_RESULT ( I_OnUserPreNick , OnUserPreNick ( this , newnick ) ) ;
2007-07-16 17:30:04 +00:00
2008-04-07 22:00:49 +00:00
if ( MOD_RESULT )
{
ServerInstance - > stats - > statsCollisions + + ;
return false ;
}
2008-02-09 13:06:02 +00:00
2008-04-07 22:00:49 +00:00
std : : deque < classbase * > dummy ;
Command * nickhandler = ServerInstance - > Parser - > GetHandler ( " NICK " ) ;
if ( nickhandler ) // wtfbbq, when would this not be here
2007-07-16 17:30:04 +00:00
{
2008-05-04 21:37:36 +00:00
std : : vector < std : : string > parameters ;
2008-04-07 22:00:49 +00:00
nickhandler - > HandleInternal ( 1 , dummy ) ;
2008-05-04 21:37:36 +00:00
parameters . push_back ( newnick ) ;
bool result = ( ServerInstance - > Parser - > CallHandler ( " NICK " , parameters , this ) = = CMD_SUCCESS ) ;
2008-04-07 22:00:49 +00:00
nickhandler - > HandleInternal ( 0 , dummy ) ;
return result ;
2007-07-16 17:30:04 +00:00
}
2008-02-09 13:06:02 +00:00
2008-04-07 22:00:49 +00:00
// Unreachable, we hope
2008-02-09 13:06:02 +00:00
return false ;
2007-07-16 17:30:04 +00:00
}
2008-02-11 09:41:58 +00:00
void User : : SetSockAddr ( int protocol_family , const char * sip , int port )
2007-07-16 17:30:04 +00:00
{
2008-02-02 22:57:28 +00:00
this - > cachedip = " " ;
2007-07-16 17:30:04 +00:00
switch ( protocol_family )
{
# ifdef SUPPORT_IP6LINKS
case AF_INET6 :
{
sockaddr_in6 * sin = new sockaddr_in6 ;
sin - > sin6_family = AF_INET6 ;
sin - > sin6_port = port ;
2008-02-11 09:41:58 +00:00
inet_pton ( AF_INET6 , sip , & sin - > sin6_addr ) ;
2007-07-16 17:30:04 +00:00
this - > ip = ( sockaddr * ) sin ;
}
break ;
# endif
case AF_INET :
{
sockaddr_in * sin = new sockaddr_in ;
sin - > sin_family = AF_INET ;
sin - > sin_port = port ;
2008-02-11 09:41:58 +00:00
inet_pton ( AF_INET , sip , & sin - > sin_addr ) ;
2007-07-16 17:30:04 +00:00
this - > ip = ( sockaddr * ) sin ;
}
break ;
default :
2008-05-18 23:15:53 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Uh oh, I dont know protocol %d to be set on '%s'! " , protocol_family , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
break ;
}
}
2007-10-15 20:59:05 +00:00
int User : : GetPort ( )
2007-07-16 17:30:04 +00:00
{
if ( this - > ip = = NULL )
return 0 ;
switch ( this - > GetProtocolFamily ( ) )
{
# ifdef SUPPORT_IP6LINKS
case AF_INET6 :
{
sockaddr_in6 * sin = ( sockaddr_in6 * ) this - > ip ;
return sin - > sin6_port ;
}
break ;
# endif
case AF_INET :
{
sockaddr_in * sin = ( sockaddr_in * ) this - > ip ;
return sin - > sin_port ;
}
break ;
default :
break ;
}
return 0 ;
}
2007-10-15 20:59:05 +00:00
int User : : GetProtocolFamily ( )
2007-07-16 17:30:04 +00:00
{
if ( this - > ip = = NULL )
return 0 ;
sockaddr_in * sin = ( sockaddr_in * ) this - > ip ;
return sin - > sin_family ;
}
2008-07-12 08:57:44 +00:00
const char * User : : GetCIDRMask ( int range )
{
static char buf [ 40 ] ;
if ( this - > ip = = NULL )
return " " ;
if ( range < 0 )
throw " Negative range, sorry, no. " ;
/*
* Original code written by Oliver Lupton ( Om ) .
* Integrated by me . Thanks . : ) - - w00t
*/
switch ( this - > GetProtocolFamily ( ) )
{
# ifdef SUPPORT_IP6LINKS
case AF_INET6 :
{
struct in6_addr v6 ;
if ( range > 128 )
{
printf ( " Error, range given (%d) larger than address length (128) \n " , range ) ;
return 0 ;
}
if ( inet_pton ( AF_INET6 , this - > GetIPString ( ) , & v6 ) )
{
/* unsigned char s6_addr[16]; */
int i ;
int bytestoblank ;
int extrabits ;
char buffer [ 64 ] ;
if ( range > 0 )
{
/* (128 - range) bits must be blanked, so ((128 - range) / 8) of the bytes, working backwards, must be blanked. */
bytestoblank = ( 128 - range ) / 8 ;
/* ((128 - range) % 8) bits of the next byte must also be blanked. */
extrabits = ( 128 - range ) % 8 ;
v6 . s6_addr [ 15 - bytestoblank ] = ( v6 . s6_addr [ 15 - bytestoblank ] > > extrabits ) < < extrabits ;
for ( i = 0 ; i < bytestoblank ; i + + )
{
v6 . s6_addr [ 15 - i ] = 0 ;
}
}
else
{
for ( i = 0 ; i < 15 ; i + + )
{
v6 . s6_addr [ i ] = 0 ;
}
}
sprintf ( buf , " %s/%d \n " , inet_ntop ( AF_INET6 , & v6 , buffer , 64 ) , range ) ;
return buf ;
}
else
{
throw " CIDR mask for v6 failed " ;
}
}
break ;
# endif
case AF_INET :
{
struct in_addr v4 ;
if ( range > 32 )
throw " more than 32 bits on an ipv4 connection, can't do that.. " ;
if ( inet_pton ( AF_INET , this - > GetIPString ( ) , & v4 ) )
{
char buffer [ 16 ] ;
uint32_t temp ;
/* (32 - range) is the number of bits we are *ignoring*. We shift this left and then right to wipe off these bits. */
if ( range > 0 )
{
temp = ntohl ( v4 . s_addr ) ;
temp = ( temp > > ( 32 - range ) ) < < ( 32 - range ) ;
v4 . s_addr = htonl ( temp ) ;
}
else
{
v4 . s_addr = 0 ;
}
sprintf ( buf , " %s/%d \n " , inet_ntop ( AF_INET , & v4 , buffer , 16 ) , range ) ;
return buf ;
}
else
{
throw " CIDR mask for v4 failed " ;
}
}
break ;
}
return " " ; // unused, but oh well
}
2008-04-10 23:35:35 +00:00
const char * User : : GetIPString ( bool translate4in6 )
2007-07-16 17:30:04 +00:00
{
2008-07-12 08:57:44 +00:00
static char buf [ 40 ] ;
2007-07-16 17:30:04 +00:00
if ( this - > ip = = NULL )
return " " ;
2008-02-02 22:57:28 +00:00
if ( ! this - > cachedip . empty ( ) )
return this - > cachedip . c_str ( ) ;
2007-07-16 17:30:04 +00:00
switch ( this - > GetProtocolFamily ( ) )
{
# ifdef SUPPORT_IP6LINKS
case AF_INET6 :
{
static char temp [ 1024 ] ;
sockaddr_in6 * sin = ( sockaddr_in6 * ) this - > ip ;
inet_ntop ( sin - > sin6_family , & sin - > sin6_addr , buf , sizeof ( buf ) ) ;
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
if ( * buf = = ' : ' )
{
strlcpy ( & temp [ 1 ] , buf , sizeof ( temp ) - 1 ) ;
* temp = ' 0 ' ;
2008-04-11 16:03:39 +00:00
if ( translate4in6 & & ! strncmp ( temp , " 0::ffff: " , 8 ) )
2008-04-10 23:35:35 +00:00
{
this - > cachedip = temp + 8 ;
return temp + 8 ;
}
2008-02-02 22:57:28 +00:00
this - > cachedip = temp ;
2007-07-16 17:30:04 +00:00
return temp ;
}
2008-02-02 22:57:28 +00:00
this - > cachedip = buf ;
2007-07-16 17:30:04 +00:00
return buf ;
}
break ;
# endif
case AF_INET :
{
sockaddr_in * sin = ( sockaddr_in * ) this - > ip ;
inet_ntop ( sin - > sin_family , & sin - > sin_addr , buf , sizeof ( buf ) ) ;
2008-02-02 22:57:28 +00:00
this - > cachedip = buf ;
2007-07-16 17:30:04 +00:00
return buf ;
}
break ;
default :
break ;
}
2008-02-02 22:57:28 +00:00
// Unreachable, probably
2007-07-16 17:30:04 +00:00
return " " ;
}
/** NOTE: We cannot pass a const reference to this method.
* The string is changed by the workings of the method ,
* so that if we pass const ref , we end up copying it to
* something we can change anyway . Makes sense to just let
* the compiler do that copy for us .
*/
2007-10-15 20:59:05 +00:00
void User : : Write ( std : : string text )
2007-07-16 17:30:04 +00:00
{
2007-07-27 17:20:41 +00:00
if ( ! ServerInstance - > SE - > BoundsCheckFd ( this ) )
2007-07-16 17:30:04 +00:00
return ;
try
{
2008-02-17 00:05:02 +00:00
ServerInstance - > Logs - > Log ( " USEROUTPUT " , DEBUG , " C[%d] O %s " , this - > GetFd ( ) , text . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
text . append ( " \r \n " ) ;
}
catch ( . . . )
{
2008-02-22 16:47:10 +00:00
ServerInstance - > Logs - > Log ( " USEROUTPUT " , DEBUG , " Exception in User::Write() std::string::append " ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2008-03-24 15:13:17 +00:00
if ( this - > io )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
/* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
* implement their own buffering mechanisms
*/
2007-07-16 17:30:04 +00:00
try
{
2008-03-24 15:13:17 +00:00
this - > io - > OnRawSocketWrite ( this - > fd , text . data ( ) , text . length ( ) ) ;
2007-07-16 17:30:04 +00:00
}
catch ( CoreException & modexcept )
{
2008-02-22 16:47:10 +00:00
ServerInstance - > Logs - > Log ( " USEROUTPUT " , DEBUG , " %s threw an exception: %s " , modexcept . GetSource ( ) , modexcept . GetReason ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
else
{
2008-07-02 14:22:48 +00:00
this - > AddWriteBuf ( text ) ;
2007-07-16 17:30:04 +00:00
}
2008-07-02 14:22:48 +00:00
ServerInstance - > stats - > statsSent + = text . length ( ) ;
this - > ServerInstance - > SE - > WantWrite ( this ) ;
2007-07-16 17:30:04 +00:00
}
/** Write()
*/
2007-10-15 20:59:05 +00:00
void User : : Write ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
va_list argsPtr ;
char textbuffer [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > Write ( std : : string ( textbuffer ) ) ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteServ ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
char textbuffer [ MAXBUF ] ;
snprintf ( textbuffer , MAXBUF , " :%s %s " , ServerInstance - > Config - > ServerName , text . c_str ( ) ) ;
this - > Write ( std : : string ( textbuffer ) ) ;
}
/** 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
{
va_list argsPtr ;
char textbuffer [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteServ ( std : : string ( textbuffer ) ) ;
}
2008-03-22 11:45:57 +00:00
void User : : WriteNumeric ( unsigned int numeric , const char * text , . . . )
{
va_list argsPtr ;
char textbuffer [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteNumeric ( numeric , std : : string ( textbuffer ) ) ;
}
void User : : WriteNumeric ( unsigned int numeric , const std : : string & text )
{
char textbuffer [ MAXBUF ] ;
int MOD_RESULT = 0 ;
FOREACH_RESULT ( I_OnNumeric , OnNumeric ( this , numeric , text ) ) ;
if ( MOD_RESULT )
return ;
2008-03-22 12:03:43 +00:00
snprintf ( textbuffer , MAXBUF , " :%s %03u %s " , ServerInstance - > Config - > ServerName , numeric , text . c_str ( ) ) ;
2008-03-22 11:45:57 +00:00
this - > Write ( std : : string ( textbuffer ) ) ;
}
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
{
char tb [ MAXBUF ] ;
2008-05-18 23:15:53 +00:00
snprintf ( tb , MAXBUF , " :%s %s " , user - > GetFullHost ( ) . c_str ( ) , text . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
this - > Write ( std : : string ( tb ) ) ;
}
/* 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
{
va_list argsPtr ;
char textbuffer [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteFrom ( user , std : : string ( textbuffer ) ) ;
}
/* write text to an destination user from a source user (e.g. user privmsg) */
2007-10-15 20:59:05 +00:00
void User : : WriteTo ( User * dest , const char * data , . . . )
2007-07-16 17:30:04 +00:00
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , data ) ;
vsnprintf ( textbuffer , MAXBUF , data , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteTo ( dest , std : : string ( textbuffer ) ) ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteTo ( User * dest , const std : : string & data )
2007-07-16 17:30:04 +00:00
{
dest - > WriteFrom ( this , data ) ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteCommon ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
if ( this - > registered ! = REG_ALL )
return ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteCommon ( std : : string ( textbuffer ) ) ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteCommon ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
bool sent_to_at_least_one = false ;
char tb [ MAXBUF ] ;
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
if ( this - > registered ! = REG_ALL )
return ;
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
uniq_id + + ;
2007-07-16 17:30:04 +00:00
2008-04-02 17:08:09 +00:00
if ( ! already_sent )
InitializeAlreadySent ( ServerInstance - > SE ) ;
2008-02-09 13:06:02 +00:00
/* We dont want to be doing this n times, just once */
2008-07-02 14:22:48 +00:00
snprintf ( tb , MAXBUF , " :%s %s " , this - > GetFullHost ( ) . c_str ( ) , text . c_str ( ) ) ;
std : : string out = tb ;
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
for ( UCListIter v = this - > chans . begin ( ) ; v ! = this - > chans . end ( ) ; v + + )
{
CUList * ulist = v - > first - > GetUsers ( ) ;
for ( CUList : : iterator i = ulist - > begin ( ) ; i ! = ulist - > end ( ) ; i + + )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
if ( ( IS_LOCAL ( i - > first ) ) & & ( already_sent [ i - > first - > fd ] ! = uniq_id ) )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
already_sent [ i - > first - > fd ] = uniq_id ;
2008-07-02 14:22:48 +00:00
i - > first - > Write ( out ) ;
2008-02-09 13:06:02 +00:00
sent_to_at_least_one = true ;
2007-07-16 17:30:04 +00:00
}
}
}
2008-02-09 13:06:02 +00:00
/*
* if the user was not in any channels , no users will receive the text . Make sure the user
* receives their OWN message for WriteCommon
*/
if ( ! sent_to_at_least_one )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
this - > Write ( std : : string ( tb ) ) ;
2007-07-16 17:30:04 +00:00
}
}
/* write a formatted string to all users who share at least one common
* channel , NOT including the source user e . g . for use in QUIT
*/
2007-10-15 20:59:05 +00:00
void User : : WriteCommonExcept ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteCommonExcept ( std : : string ( textbuffer ) ) ;
}
2007-10-15 20:59:05 +00:00
void User : : WriteCommonQuit ( const std : : string & normal_text , const std : : string & oper_text )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
char tb1 [ MAXBUF ] ;
char tb2 [ MAXBUF ] ;
2007-07-16 17:30:04 +00:00
if ( this - > registered ! = REG_ALL )
return ;
uniq_id + + ;
2008-04-02 17:08:09 +00:00
if ( ! already_sent )
InitializeAlreadySent ( ServerInstance - > SE ) ;
2008-07-02 14:22:48 +00:00
snprintf ( tb1 , MAXBUF , " :%s QUIT :%s " , this - > GetFullHost ( ) . c_str ( ) , normal_text . c_str ( ) ) ;
snprintf ( tb2 , MAXBUF , " :%s QUIT :%s " , this - > GetFullHost ( ) . c_str ( ) , oper_text . c_str ( ) ) ;
std : : string out1 = tb1 ;
std : : string out2 = tb2 ;
2007-07-16 17:30:04 +00:00
for ( UCListIter v = this - > chans . begin ( ) ; v ! = this - > chans . end ( ) ; v + + )
{
CUList * ulist = v - > first - > GetUsers ( ) ;
for ( CUList : : iterator i = ulist - > begin ( ) ; i ! = ulist - > end ( ) ; i + + )
{
if ( this ! = i - > first )
{
if ( ( IS_LOCAL ( i - > first ) ) & & ( already_sent [ i - > first - > fd ] ! = uniq_id ) )
{
already_sent [ i - > first - > fd ] = uniq_id ;
2008-07-02 14:22:48 +00:00
i - > first - > Write ( IS_OPER ( i - > first ) ? out2 : out1 ) ;
2007-07-16 17:30:04 +00:00
}
}
}
}
}
2007-10-15 20:59:05 +00:00
void User : : WriteCommonExcept ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
char tb1 [ MAXBUF ] ;
std : : string out1 ;
2007-07-16 17:30:04 +00:00
if ( this - > registered ! = REG_ALL )
return ;
uniq_id + + ;
2008-04-02 17:08:09 +00:00
if ( ! already_sent )
InitializeAlreadySent ( ServerInstance - > SE ) ;
2008-07-02 14:22:48 +00:00
snprintf ( tb1 , MAXBUF , " :%s %s " , this - > GetFullHost ( ) . c_str ( ) , text . c_str ( ) ) ;
out1 = tb1 ;
2007-07-16 17:30:04 +00:00
for ( UCListIter v = this - > chans . begin ( ) ; v ! = this - > chans . end ( ) ; v + + )
{
CUList * ulist = v - > first - > GetUsers ( ) ;
for ( CUList : : iterator i = ulist - > begin ( ) ; i ! = ulist - > end ( ) ; i + + )
{
if ( this ! = i - > first )
{
if ( ( IS_LOCAL ( i - > first ) ) & & ( already_sent [ i - > first - > fd ] ! = uniq_id ) )
{
already_sent [ i - > first - > fd ] = uniq_id ;
2008-07-02 14:22:48 +00:00
i - > first - > Write ( out1 ) ;
2007-07-16 17:30:04 +00:00
}
}
}
}
}
2007-10-15 20:59:05 +00:00
void User : : WriteWallOps ( const std : : string & text )
2007-07-16 17:30:04 +00:00
{
2008-04-03 15:22:42 +00:00
if ( ! IS_LOCAL ( this ) )
2007-07-16 17:30:04 +00:00
return ;
std : : string wallop ( " WALLOPS : " ) ;
wallop . append ( text ) ;
2008-02-02 20:55:16 +00:00
for ( std : : vector < User * > : : const_iterator i = ServerInstance - > Users - > local_users . begin ( ) ; i ! = ServerInstance - > Users - > local_users . end ( ) ; i + + )
2007-07-16 17:30:04 +00:00
{
2007-10-15 20:59:05 +00:00
User * t = * i ;
2007-07-23 18:06:57 +00:00
if ( t - > IsModeSet ( ' w ' ) )
2007-07-16 17:30:04 +00:00
this - > WriteTo ( t , wallop ) ;
}
}
2007-10-15 20:59:05 +00:00
void User : : WriteWallOps ( const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
2008-04-03 15:22:42 +00:00
if ( ! IS_LOCAL ( this ) )
return ;
2007-07-16 17:30:04 +00:00
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
this - > WriteWallOps ( std : : string ( textbuffer ) ) ;
}
/* 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
{
if ( ( ! other ) | | ( this - > registered ! = REG_ALL ) | | ( other - > registered ! = REG_ALL ) )
return false ;
/* Outer loop */
for ( UCListIter i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; i + + )
{
/* 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
*/
if ( i - > first - > HasUser ( other ) )
return true ;
}
return false ;
}
2007-10-15 20:59:05 +00:00
bool User : : ChangeName ( const char * 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 ) )
{
int MOD_RESULT = 0 ;
FOREACH_RESULT ( I_OnChangeLocalUserGECOS , OnChangeLocalUserGECOS ( this , gecos ) ) ;
if ( MOD_RESULT )
return false ;
FOREACH_MOD ( I_OnChangeName , OnChangeName ( this , gecos ) ) ;
}
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 ;
}
2008-02-11 09:41:58 +00:00
bool User : : ChangeDisplayedHost ( const char * shost )
2007-07-16 17:30:04 +00:00
{
2008-05-23 05:15:49 +00:00
if ( dhost = = shost )
2007-07-16 17:30:04 +00:00
return true ;
if ( IS_LOCAL ( this ) )
{
int MOD_RESULT = 0 ;
2008-02-11 09:41:58 +00:00
FOREACH_RESULT ( I_OnChangeLocalUserHost , OnChangeLocalUserHost ( this , shost ) ) ;
2007-07-16 17:30:04 +00:00
if ( MOD_RESULT )
return false ;
2008-02-11 09:41:58 +00:00
FOREACH_MOD ( I_OnChangeHost , OnChangeHost ( this , shost ) ) ;
2007-07-16 17:30:04 +00:00
}
2008-02-09 13:06:02 +00:00
2007-07-16 17:30:04 +00:00
if ( this - > ServerInstance - > Config - > CycleHosts )
this - > WriteCommonExcept ( " QUIT :Changing hosts " ) ;
2007-10-15 20:59:05 +00:00
/* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
2008-05-18 23:15:53 +00:00
this - > dhost . assign ( shost , 0 , 64 ) ;
2007-07-16 17:30:04 +00:00
this - > InvalidateCache ( ) ;
if ( this - > ServerInstance - > Config - > CycleHosts )
{
for ( UCListIter i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; i + + )
{
2008-05-19 21:16:42 +00:00
i - > first - > WriteAllExceptSender ( this , false , 0 , " JOIN %s " , i - > first - > name . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
std : : string n = this - > ServerInstance - > Modes - > ModeString ( this , i - > first ) ;
if ( n . length ( ) > 0 )
2008-05-19 21:16:42 +00:00
i - > first - > WriteAllExceptSender ( this , true , 0 , " MODE %s +%s " , i - > first - > name . c_str ( ) , n . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
if ( IS_LOCAL ( this ) )
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 396 , " %s %s :is now your displayed host " , this - > nick . c_str ( ) , this - > dhost . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
return true ;
}
2007-10-15 20:59:05 +00:00
bool User : : ChangeIdent ( const char * newident )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
if ( ! this - > ident . compare ( newident ) )
2007-07-16 17:30:04 +00:00
return true ;
if ( this - > ServerInstance - > Config - > CycleHosts )
this - > WriteCommonExcept ( " %s " , " QUIT :Changing ident " ) ;
2008-05-25 17:30:43 +00:00
this - > ident . assign ( newident , 0 , ServerInstance - > Config - > Limits . IdentMax + 1 ) ;
2007-07-16 17:30:04 +00:00
this - > InvalidateCache ( ) ;
if ( this - > ServerInstance - > Config - > CycleHosts )
{
for ( UCListIter i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; i + + )
{
2008-05-19 21:16:42 +00:00
i - > first - > WriteAllExceptSender ( this , false , 0 , " JOIN %s " , i - > first - > name . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
std : : string n = this - > ServerInstance - > Modes - > ModeString ( this , i - > first ) ;
if ( n . length ( ) > 0 )
2008-05-19 21:16:42 +00:00
i - > first - > WriteAllExceptSender ( this , true , 0 , " MODE %s +%s " , i - > first - > name . c_str ( ) , n . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
return true ;
}
2008-02-13 18:22:19 +00:00
void User : : SendAll ( const char * command , const char * text , . . . )
2007-07-16 17:30:04 +00:00
{
char textbuffer [ MAXBUF ] ;
2008-07-02 14:22:48 +00:00
char formatbuffer [ MAXBUF ] ;
2007-07-16 17:30:04 +00:00
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
2008-07-02 14:22:48 +00:00
snprintf ( formatbuffer , MAXBUF , " :%s %s $* :%s " , this - > GetFullHost ( ) . c_str ( ) , command , textbuffer ) ;
std : : string fmt = formatbuffer ;
2007-07-16 17:30:04 +00:00
2008-02-02 20:55:16 +00:00
for ( std : : vector < User * > : : const_iterator i = ServerInstance - > Users - > local_users . begin ( ) ; i ! = ServerInstance - > Users - > local_users . end ( ) ; i + + )
2007-07-16 17:30:04 +00:00
{
2008-07-02 14:22:48 +00:00
( * i ) - > Write ( fmt ) ;
2007-07-16 17:30:04 +00:00
}
}
2007-10-15 20:59:05 +00:00
std : : string User : : ChannelList ( User * source )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
std : : string list ;
for ( UCListIter i = this - > chans . begin ( ) ; i ! = this - > chans . end ( ) ; i + + )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
/* If the target is the same as the sender, let them see all their channels.
* If the channel is NOT private / secret OR the user shares a common channel
* If the user is an oper , and the < options : operspywhois > option is set .
*/
if ( ( source = = this ) | | ( IS_OPER ( source ) & & ServerInstance - > Config - > OperSpyWhois ) | | ( ( ( ! i - > first - > IsModeSet ( ' p ' ) ) & & ( ! i - > first - > IsModeSet ( ' s ' ) ) ) | | ( i - > first - > HasUser ( source ) ) ) )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
list . append ( i - > first - > GetPrefixChar ( this ) ) . append ( i - > first - > name ) . append ( " " ) ;
2007-07-16 17:30:04 +00:00
}
}
2008-02-09 13:06:02 +00:00
return list ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : SplitChanList ( User * dest , const std : : string & cl )
2007-07-16 17:30:04 +00:00
{
std : : string line ;
std : : ostringstream prefix ;
std : : string : : size_type start , pos , length ;
2008-02-09 13:06:02 +00:00
prefix < < this - > nick < < " " < < dest - > nick < < " : " ;
line = prefix . str ( ) ;
int namelen = strlen ( ServerInstance - > Config - > ServerName ) + 6 ;
for ( start = 0 ; ( pos = cl . find ( ' ' , start ) ) ! = std : : string : : npos ; start = pos + 1 )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
length = ( pos = = std : : string : : npos ) ? cl . length ( ) : pos ;
2007-07-16 17:30:04 +00:00
2008-02-09 13:06:02 +00:00
if ( line . length ( ) + namelen + length - start > 510 )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
ServerInstance - > SendWhoisLine ( this , dest , 319 , " %s " , line . c_str ( ) ) ;
line = prefix . str ( ) ;
2007-07-16 17:30:04 +00:00
}
2008-02-09 13:06:02 +00:00
if ( pos = = std : : string : : npos )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
line . append ( cl . substr ( start , length - start ) ) ;
break ;
}
else
{
line . append ( cl . substr ( start , length - start + 1 ) ) ;
2007-07-16 17:30:04 +00:00
}
}
2008-02-09 13:06:02 +00:00
if ( line . length ( ) )
2007-07-16 17:30:04 +00:00
{
2008-02-09 13:06:02 +00:00
ServerInstance - > SendWhoisLine ( this , dest , 319 , " %s " , line . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
2007-10-15 20:59:05 +00:00
unsigned int User : : GetMaxChans ( )
2007-08-19 20:14:05 +00:00
{
return this - > MaxChans ;
}
2007-07-16 17:30:04 +00:00
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
*/
2007-10-23 23:25:49 +00:00
ConnectClass * User : : 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 ;
if ( ! IS_LOCAL ( this ) )
return NULL ;
2007-10-23 23:25:49 +00:00
2008-05-18 23:15:53 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , 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
{
2007-08-19 19:23:53 +00:00
for ( ClassVector : : 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 ;
2008-05-18 17:16:55 +00:00
if ( c - > GetDisabled ( ) )
continue ; // can't possibly match, removed from conf
if ( explicit_name = = c - > GetName ( ) )
2007-10-23 23:07:24 +00:00
{
2008-05-18 17:25:29 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , 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
{
for ( ClassVector : : iterator i = ServerInstance - > Config - > Classes . begin ( ) ; i ! = ServerInstance - > Config - > Classes . end ( ) ; i + + )
{
2007-10-24 15:48:00 +00:00
ConnectClass * c = * i ;
2008-05-18 17:41:04 +00:00
if ( c - > GetType ( ) = = CC_ALLOW )
{
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " ALLOW %s %d %s " , c - > GetHost ( ) . c_str ( ) , c - > GetPort ( ) , c - > GetName ( ) . c_str ( ) ) ;
}
else
{
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " DENY %s %d %s " , c - > GetHost ( ) . c_str ( ) , c - > GetPort ( ) , c - > GetName ( ) . c_str ( ) ) ;
}
2008-05-18 18:36:42 +00:00
/* if it's disabled, we can't match this one. */
if ( c - > GetDisabled ( ) )
{
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " Class disabled " ) ;
continue ;
}
2008-05-18 17:16:55 +00:00
/* check if host matches.. */
2008-05-18 17:27:51 +00:00
if ( ( ( ! match ( this - > GetIPString ( ) , c - > GetHost ( ) , true ) ) & & ( ! match ( this - > host , c - > GetHost ( ) ) ) ) )
2007-07-16 17:30:04 +00:00
{
2008-05-18 17:25:29 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , 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
*/
if ( c - > limit & & ( c - > RefCount + 1 > = c - > limit ) )
{
2008-05-18 17:25:29 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " OOPS: Connect class limit (%lu) hit, denying " , c - > limit ) ;
2008-05-18 17:16:55 +00:00
continue ;
}
/* if it requires a port ... */
if ( c - > GetPort ( ) )
{
2008-05-18 17:41:04 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " Requires port (%d) " , c - > GetPort ( ) ) ;
2008-05-18 17:25:29 +00:00
2008-05-18 17:16:55 +00:00
/* and our port doesn't match, fail. */
if ( this - > GetPort ( ) ! = c - > GetPort ( ) )
2007-10-23 23:07:24 +00:00
{
2008-05-18 17:41:04 +00:00
ServerInstance - > Logs - > Log ( " CONNECTCLASS " , DEBUG , " Port match failed (%d) " , this - > GetPort ( ) ) ;
2008-05-18 17:16:55 +00:00
continue ;
2007-10-23 23:07:24 +00:00
}
2007-07-16 17:30:04 +00:00
}
2008-05-18 17:16:55 +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 )
{
2008-05-18 17:16:55 +00:00
/* only fiddle with refcounts if they are already in a class .. */
2007-10-23 23:31:40 +00:00
if ( this - > MyClass )
{
2007-10-24 19:12:45 +00:00
if ( found = = this - > MyClass ) // no point changing this shit :P
return this - > MyClass ;
2007-10-23 23:31:40 +00:00
this - > MyClass - > RefCount - - ;
2008-03-30 02:48:54 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Untying user from connect class -- refcount: %lu " , this - > MyClass - > RefCount ) ;
2007-10-23 23:31:40 +00:00
}
this - > MyClass = found ;
this - > MyClass - > RefCount + + ;
2008-03-30 02:48:54 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " User tied to new class -- connect refcount now: %lu " , this - > MyClass - > RefCount ) ;
2007-10-23 23:31:40 +00:00
}
2007-10-23 23:25:49 +00:00
return this - > MyClass ;
}
/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
* 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
*/
ConnectClass * User : : GetClass ( )
{
return this - > MyClass ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : PurgeEmptyChannels ( )
2007-07-16 17:30:04 +00:00
{
2007-10-15 20:59:05 +00:00
std : : vector < Channel * > to_delete ;
2007-07-16 17:30:04 +00:00
// firstly decrement the count on each channel
for ( UCListIter f = this - > chans . begin ( ) ; f ! = this - > chans . end ( ) ; f + + )
{
f - > first - > RemoveAllPrefixes ( this ) ;
if ( f - > first - > DelUser ( this ) = = 0 )
{
/* No users left in here, mark it for deletion */
try
{
to_delete . push_back ( f - > first ) ;
}
catch ( . . . )
{
2008-02-22 16:47:10 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Exception in User::PurgeEmptyChannels to_delete.push_back() " ) ;
2007-07-16 17:30:04 +00:00
}
}
}
2007-10-15 20:59:05 +00:00
for ( std : : vector < Channel * > : : iterator n = to_delete . begin ( ) ; n ! = to_delete . end ( ) ; n + + )
2007-07-16 17:30:04 +00:00
{
2007-10-15 20:59:05 +00:00
Channel * thischan = * n ;
2007-07-16 17:30:04 +00:00
chan_hash : : iterator i2 = ServerInstance - > chanlist - > find ( thischan - > name ) ;
if ( i2 ! = ServerInstance - > chanlist - > end ( ) )
{
FOREACH_MOD ( I_OnChannelDelete , OnChannelDelete ( i2 - > second ) ) ;
2007-11-04 21:24:40 +00:00
delete i2 - > second ;
2007-07-16 17:30:04 +00:00
ServerInstance - > chanlist - > erase ( i2 ) ;
this - > chans . erase ( * n ) ;
}
}
this - > UnOper ( ) ;
}
2007-10-15 20:59:05 +00:00
void User : : ShowMOTD ( )
2007-07-16 17:30:04 +00:00
{
if ( ! ServerInstance - > Config - > MOTD . size ( ) )
{
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 422 , " %s :Message of the day file is missing. " , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 375 , " %s :%s message of the day " , this - > nick . c_str ( ) , ServerInstance - > Config - > ServerName ) ;
2007-07-16 17:30:04 +00:00
for ( file_cache : : iterator i = ServerInstance - > Config - > MOTD . begin ( ) ; i ! = ServerInstance - > Config - > MOTD . end ( ) ; i + + )
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 372 , " %s :- %s " , this - > nick . c_str ( ) , i - > c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 376 , " %s :End of message of the day. " , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : ShowRULES ( )
2007-07-16 17:30:04 +00:00
{
if ( ! ServerInstance - > Config - > RULES . size ( ) )
{
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 434 , " %s :RULES File is missing " , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
return ;
}
2007-07-24 14:08:16 +00:00
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 308 , " %s :- %s Server Rules - " , this - > nick . c_str ( ) , ServerInstance - > Config - > ServerName ) ;
2007-07-16 17:30:04 +00:00
for ( file_cache : : iterator i = ServerInstance - > Config - > RULES . begin ( ) ; i ! = ServerInstance - > Config - > RULES . end ( ) ; i + + )
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 232 , " %s :- %s " , this - > nick . c_str ( ) , i - > c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
2008-05-18 23:15:53 +00:00
this - > WriteNumeric ( 309 , " %s :End of RULES command. " , this - > nick . c_str ( ) ) ;
2007-07-16 17:30:04 +00:00
}
2007-10-15 20:59:05 +00:00
void User : : HandleEvent ( EventType et , int errornum )
2007-07-16 17:30:04 +00:00
{
2008-01-16 16:19:57 +00:00
if ( this - > quitting ) // drop everything, user is due to be quit
2008-01-16 09:14:23 +00:00
return ;
2007-07-16 17:30:04 +00:00
/* WARNING: May delete this user! */
int thisfd = this - > GetFd ( ) ;
try
{
switch ( et )
{
case EVENT_READ :
ServerInstance - > ProcessUser ( this ) ;
break ;
case EVENT_WRITE :
this - > FlushWriteBuf ( ) ;
break ;
case EVENT_ERROR :
/** This should be safe, but dont DARE do anything after it -- Brain */
this - > SetWriteError ( errornum ? strerror ( errornum ) : " EOF from client " ) ;
break ;
}
}
catch ( . . . )
{
2008-02-22 16:47:10 +00:00
ServerInstance - > Logs - > Log ( " USERS " , DEBUG , " Exception in User::HandleEvent intercepted " ) ;
2007-07-16 17:30:04 +00:00
}
/* If the user has raised an error whilst being processed, quit them now we're safe to */
if ( ( ServerInstance - > SE - > GetRef ( thisfd ) = = this ) )
{
if ( ! WriteError . empty ( ) )
{
2008-04-09 15:34:54 +00:00
ServerInstance - > Users - > QuitUser ( this , GetWriteError ( ) ) ;
2007-07-16 17:30:04 +00:00
}
}
}
2007-10-15 20:59:05 +00:00
void User : : SetOperQuit ( const std : : string & oquit )
2007-07-16 17:30:04 +00:00
{
2008-01-16 07:59:09 +00:00
operquitmsg = oquit ;
2007-07-16 17:30:04 +00:00
}
2008-05-18 23:15:53 +00:00
const std : : string & User : : GetOperQuit ( )
2007-07-16 17:30:04 +00:00
{
2008-05-18 23:15:53 +00:00
return operquitmsg ;
2007-07-16 17:30:04 +00:00
}
2007-10-21 18:01:24 +00:00
void User : : IncreasePenalty ( int increase )
{
this - > Penalty + = increase ;
}
void User : : DecreasePenalty ( int decrease )
{
this - > Penalty - = decrease ;
}
2007-07-16 17:30:04 +00:00
VisData : : VisData ( )
{
}
VisData : : ~ VisData ( )
{
}
2007-10-15 20:59:05 +00:00
bool VisData : : VisibleTo ( User * user )
2007-07-16 17:30:04 +00:00
{
return true ;
}