2003-01-23 19:45:57 +00:00
/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*
* Inspire is copyright ( C ) 2002 - 2003 ChatSpike - Dev .
* E - mail :
* < brain @ chatspike . net >
* < Craig @ chatspike . net >
*
* Written by Craig Edwards , Craig McLure , and others .
* This program is free but copyrighted software ; see
* the file COPYING for details .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$ Log $
2003-01-25 20:17:53 +00:00
Revision 1.3 2003 / 01 / 25 20 : 17 : 53 brain
Fixed WHOWAS memory leak
2003-01-25 20:00:45 +00:00
Revision 1.2 2003 / 01 / 25 20 : 00 : 45 brain
Added / WHOWAS
Revision 1.1 .1 .1 2003 / 01 / 23 19 : 45 : 58 brain
InspIRCd second source tree
2003-01-23 19:45:57 +00:00
Revision 1.56 2003 / 01 / 22 20 : 49 : 16 brain
Added FileReader file - caching class
Changed m_randquote to use FileReader class
Revision 1.55 2003 / 01 / 21 16 : 56 : 19 brain
Fixed a few minor bugs
Revision 1.54 2003 / 01 / 21 02 : 07 : 10 brain
optimisations galore !
Revision 1.53 2003 / 01 / 21 00 : 18 : 40 brain
fixed random crash on kill_link ( AGAIN ) - was / stats
improved speed 10 x ( because i can . . . )
Revision 1.52 2003 / 01 / 19 20 : 12 : 24 brain
Fixed ident max length to 10
Revision 1.51 2003 / 01 / 18 22 : 02 : 11 brain
fixed multiple / MODE + l bugs ( thanks to akky and BOFH bugging meh ! )
Revision 1.50 2003 / 01 / 18 01 : 19 : 14 brain
Added code to tidy up bans ( e . g . max nick length ) - i blame mIRC !
Revision 1.49 2003 / 01 / 17 22 : 03 : 57 brain
Fixed dodgy mode glitches ( the ones Craig loves to play with , awww )
Revision 1.48 2003 / 01 / 17 21 : 20 : 43 brain
Implemented usermode + s
Revision 1.47 2003 / 01 / 17 21 : 13 : 40 brain
Added channel modes , + k , + l , + i , + m etc
Added user and channel modes + i , + p , + s
Revision 1.46 2003 / 01 / 17 18 : 44 : 27 brain
Implemented channel mode + m
Revision 1.45 2003 / 01 / 17 18 : 26 : 42 brain
added / TRACE command
Revision 1.44 2003 / 01 / 17 15 : 21 : 03 brain
Fixed : / LUSERS cant count : P
Revision 1.43 2003 / 01 / 17 13 : 21 : 38 brain
Added CONNECT ALLOW and CONNECT DENY config tags
Added PASS command
Revision 1.42 2003 / 01 / 17 10 : 37 : 55 brain
Added / INVITE command and relevent structures
Revision 1.41 2003 / 01 / 16 20 : 11 : 55 brain
fixed some ugly pointer bugs ( thanks dblack and a | KK | y ! )
Revision 1.40 2003 / 01 / 16 08 : 31 : 44 brain
Fixed parameter error in QUIT code ( was showing junk chars on BSD )
Revision 1.39 2003 / 01 / 15 22 : 47 : 44 brain
Changed user and channel structs to classes ( finally )
Revision 1.38 2003 / 01 / 15 20 : 56 : 58 brain
Added wildcard support
Added channel bans
Revision 1.37 2003 / 01 / 15 16 : 08 : 42 brain
Attempted to fix closed client sessions not being detected
Revision 1.36 2003 / 01 / 15 09 : 36 : 13 brain
added pause = value to / die and / restart in config
Revision 1.35 2003 / 01 / 14 22 : 08 : 31 brain
attemted to fix weird crash on / kill
Revision 1.34 2003 / 01 / 14 21 : 44 : 25 brain
Added / USERS stub
Added / SUMMON stub
Changed optimisation to - O3 ( much faster ! )
Revision 1.33 2003 / 01 / 14 21 : 14 : 30 brain
added / ISON command ( for mIRC etc basic notify )
Revision 1.32 2003 / 01 / 14 20 : 55 : 02 brain
Fixed more param crunching bugs
Added / AWAY
Revision 1.31 2003 / 01 / 14 00 : 46 : 02 brain
Added m_cloaking . so module , provides host masking
Revision 1.30 2003 / 01 / 13 22 : 30 : 50 brain
Added Admin class ( holds / admin info for modules )
Added methods to Server class
Revision 1.29 2003 / 01 / 13 00 : 43 : 29 brain
Added Server class
Added more code to example module demonstrating use of Server class
Revision 1.28 2003 / 01 / 12 17 : 40 : 44 brain
. / configure improved by Craig ( better prompts , dir creation )
' / stats z ' added detail
Revision 1.27 2003 / 01 / 12 16 : 49 : 53 brain
Added ' / stats z '
Revision 1.26 2003 / 01 / 12 15 : 01 : 18 brain
Added hostname / ip caching to speed up connects
Revision 1.25 2003 / 01 / 11 21 : 39 : 57 brain
Made ircd cache message of the day in a vector ( faster ! )
Added support for multiple lines of / NAMES on large channels
Revision 1.24 2003 / 01 / 11 19 : 00 : 10 brain
Added / USERHOST command
Revision 1.23 2003 / 01 / 11 17 : 57 : 28 brain
Added ' / STATS O '
Added more module error checking
Revision 1.22 2003 / 01 / 11 00 : 48 : 44 brain
removed random debug output
Revision 1.21 2003 / 01 / 11 00 : 06 : 46 brain
Fixed random crash on nickchange
Fine tuned ability to handle > 300 users
Revision 1.20 2003 / 01 / 09 22 : 24 : 59 brain
added ' / stats L ' ( connect - info )
Revision 1.19 2003 / 01 / 09 21 : 38 : 51 brain
' / stats u ' support added ( server uptime )
Revision 1.18 2003 / 01 / 09 21 : 09 : 50 brain
added ' / stats M ' command
Revision 1.17 2003 / 01 / 08 22 : 11 : 38 brain
Added extra dynamic module support , new methods to Module class
Revision 1.16 2003 / 01 / 08 17 : 48 : 48 brain
fixed " user lingering " problem in kill_link
Revision 1.15 2003 / 01 / 07 23 : 17 : 51 brain
Fixed wallops and command parameter counting bugs
Revision 1.14 2003 / 01 / 07 20 : 47 : 34 brain
Fixes random crash on nickchange ( must keep classfactory pointers ! )
Revision 1.13 2003 / 01 / 07 19 : 57 : 56 brain
Dynamix module support , preliminary release
Revision 1.12 2003 / 01 / 07 01 : 01 : 30 brain
Changed command table to a vector of command_t types
Revision 1.11 2003 / 01 / 06 23 : 43 : 30 brain
extra debug output
Revision 1.10 2003 / 01 / 06 23 : 38 : 29 brain
just playing with header tags
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/* Now with added unF! ;) */
# include "inspircd.h"
# include "inspircd_io.h"
# include "inspircd_util.h"
# include "inspircd_config.h"
# include <unistd.h>
# include <fcntl.h>
# include <sys/errno.h>
# include <sys/ioctl.h>
# include <sys/utsname.h>
# include <cstdio>
# include <time.h>
# include <string>
# include <hash_map.h>
# include <sstream>
# include <vector>
# include <errno.h>
# include <deque>
# include "users.h"
# include "ctables.h"
# include "globals.h"
# include "modules.h"
# include "dynamic.h"
# include "wildcard.h"
using namespace std ;
char ServerName [ MAXBUF ] ;
char Network [ MAXBUF ] ;
char ServerDesc [ MAXBUF ] ;
char AdminName [ MAXBUF ] ;
char AdminEmail [ MAXBUF ] ;
char AdminNick [ MAXBUF ] ;
char diepass [ MAXBUF ] ;
char restartpass [ MAXBUF ] ;
char motd [ MAXBUF ] ;
char rules [ MAXBUF ] ;
char list [ MAXBUF ] ;
char PrefixQuit [ MAXBUF ] ;
char DieValue [ MAXBUF ] ;
int debugging = 0 ;
int MODCOUNT = - 1 ;
2003-01-25 20:00:45 +00:00
int WHOWAS_STALE = 48 ; // default WHOWAS Entries last 2 days before they go 'stale'
int WHOWAS_MAX = 100 ; // default 100 people maximum in the WHOWAS list
2003-01-23 19:45:57 +00:00
int DieDelay = 5 ;
time_t startup_time = time ( NULL ) ;
template < > struct hash < in_addr >
{
size_t operator ( ) ( const struct in_addr & a ) const
{
size_t q ;
memcpy ( & q , & a , sizeof ( size_t ) ) ;
return q ;
}
} ;
template < > struct hash < string >
{
size_t operator ( ) ( const string & s ) const
{
char a [ MAXBUF ] ;
static struct hash < const char * > strhash ;
strcpy ( a , s . c_str ( ) ) ;
strlower ( a ) ;
return strhash ( a ) ;
}
} ;
struct StrHashComp
{
bool operator ( ) ( const string & s1 , const string & s2 ) const
{
char a [ MAXBUF ] , b [ MAXBUF ] ;
strcpy ( a , s1 . c_str ( ) ) ;
strcpy ( b , s2 . c_str ( ) ) ;
return ( strcasecmp ( a , b ) = = 0 ) ;
}
} ;
struct InAddr_HashComp
{
bool operator ( ) ( const in_addr & s1 , const in_addr & s2 ) const
{
size_t q ;
size_t p ;
memcpy ( & q , & s1 , sizeof ( size_t ) ) ;
memcpy ( & p , & s2 , sizeof ( size_t ) ) ;
return ( q = = p ) ;
}
} ;
typedef hash_map < string , userrec * , hash < string > , StrHashComp > user_hash ;
typedef hash_map < string , chanrec * , hash < string > , StrHashComp > chan_hash ;
typedef hash_map < in_addr , string * , hash < in_addr > , InAddr_HashComp > address_cache ;
typedef deque < command_t > command_table ;
typedef DLLFactory < ModuleFactory > ircd_module ;
user_hash clientlist ;
chan_hash chanlist ;
2003-01-25 20:00:45 +00:00
user_hash whowas ;
2003-01-23 19:45:57 +00:00
command_table cmdlist ;
file_cache MOTD ;
file_cache RULES ;
address_cache IP ;
vector < Module * > modules ( 255 ) ;
vector < ircd_module * > factory ( 255 ) ;
ClassVector Classes ;
struct linger linger = { 0 } ;
char bannerBuffer [ MAXBUF ] ;
int boundPortCount = 0 ;
/* prototypes */
int has_channel ( userrec * u , chanrec * c ) ;
int usercount ( chanrec * c ) ;
int usercount_i ( chanrec * c ) ;
void update_stats_l ( int fd , int data_out ) ;
char * Passwd ( userrec * user ) ;
bool IsDenied ( userrec * user ) ;
2003-01-25 20:00:45 +00:00
void AddWhoWas ( userrec * u ) ;
2003-01-23 19:45:57 +00:00
void safedelete ( userrec * p )
{
if ( p )
{
debug ( " deleting %s %s %s %s " , p - > nick , p - > ident , p - > dhost , p - > fullname ) ;
debug ( " safedelete(userrec*): pointer is safe to delete " ) ;
delete p ;
}
else
{
debug ( " safedelete(userrec*): unsafe pointer operation squished " ) ;
}
}
void safedelete ( chanrec * p )
{
if ( p )
{
delete p ;
debug ( " safedelete(chanrec*): pointer is safe to delete " ) ;
}
else
{
debug ( " safedelete(chanrec*): unsafe pointer operation squished " ) ;
}
}
/* chop a string down to 512 characters and preserve linefeed (irc max
* line length ) */
void chop ( char * str )
{
if ( strlen ( str ) > 512 )
{
str [ 510 ] = ' \r ' ;
str [ 511 ] = ' \n ' ;
str [ 512 ] = ' \0 ' ;
}
}
string getservername ( )
{
return ServerName ;
}
string getnetworkname ( )
{
return Network ;
}
string getadminname ( )
{
return AdminName ;
}
string getadminemail ( )
{
return AdminEmail ;
}
string getadminnick ( )
{
return AdminNick ;
}
void debug ( char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
FILE * f ;
time_t rawtime ;
struct tm * timeinfo ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
if ( debugging )
{
f = fopen ( " ircd.log " , " a+ " ) ;
if ( f )
{
char b [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
strcpy ( b , asctime ( timeinfo ) ) ;
b [ strlen ( b ) - 1 ] = ' : ' ;
fprintf ( f , " %s %s \n " , b , textbuffer ) ;
fclose ( f ) ;
}
else
{
printf ( " Can't write log file, bailing!!! " ) ;
Exit ( ERROR ) ;
}
}
}
void readfile ( file_cache & F , const char * fname )
{
FILE * file ;
char linebuf [ MAXBUF ] ;
debug ( " readfile: loading %s " , fname ) ;
F . clear ( ) ;
file = fopen ( fname , " r " ) ;
if ( file )
{
while ( ! feof ( file ) )
{
fgets ( linebuf , sizeof ( linebuf ) , file ) ;
linebuf [ strlen ( linebuf ) - 1 ] = ' \0 ' ;
if ( ! strcmp ( linebuf , " " ) )
{
strcpy ( linebuf , " " ) ;
}
if ( ! feof ( file ) )
{
F . push_back ( linebuf ) ;
}
}
fclose ( file ) ;
}
else
{
debug ( " readfile: failed to load file: %s " , fname ) ;
}
debug ( " readfile: loaded %s, %d lines " , fname , F . size ( ) ) ;
}
void ReadConfig ( void )
{
char dbg [ MAXBUF ] , pauseval [ MAXBUF ] , Value [ MAXBUF ] ;
ConnectClass c ;
ConfValue ( " server " , " name " , 0 , ServerName ) ;
ConfValue ( " server " , " description " , 0 , ServerDesc ) ;
ConfValue ( " server " , " network " , 0 , Network ) ;
ConfValue ( " admin " , " name " , 0 , AdminName ) ;
ConfValue ( " admin " , " email " , 0 , AdminEmail ) ;
ConfValue ( " admin " , " nick " , 0 , AdminNick ) ;
ConfValue ( " files " , " motd " , 0 , motd ) ;
ConfValue ( " files " , " rules " , 0 , rules ) ;
ConfValue ( " power " , " diepass " , 0 , diepass ) ;
ConfValue ( " power " , " pause " , 0 , pauseval ) ;
ConfValue ( " power " , " restartpass " , 0 , restartpass ) ;
ConfValue ( " options " , " prefixquit " , 0 , PrefixQuit ) ;
ConfValue ( " die " , " value " , 0 , DieValue ) ;
ConfValue ( " options " , " debug " , 0 , dbg ) ;
debugging = 0 ;
if ( ! strcmp ( dbg , " on " ) )
{
debugging = 1 ;
}
DieDelay = atoi ( pauseval ) ;
readfile ( MOTD , motd ) ;
readfile ( RULES , rules ) ;
debug ( " Reading connect classes " ) ;
Classes . clear ( ) ;
for ( int i = 0 ; i < ConfValueEnum ( " connect " ) ; i + + )
{
strcpy ( Value , " " ) ;
ConfValue ( " connect " , " allow " , i , Value ) ;
if ( strcmp ( Value , " " ) )
{
strcpy ( c . host , Value ) ;
c . type = CC_ALLOW ;
strcpy ( Value , " " ) ;
ConfValue ( " connect " , " password " , i , Value ) ;
strcpy ( c . pass , Value ) ;
Classes . push_back ( c ) ;
debug ( " Read connect class type ALLOW, host=%s password=%s " , c . host , c . pass ) ;
}
else
{
ConfValue ( " connect " , " deny " , i , Value ) ;
strcpy ( c . host , Value ) ;
c . type = CC_DENY ;
Classes . push_back ( c ) ;
debug ( " Read connect class type DENY, host=%s " , c . host ) ;
}
}
}
void Blocking ( int s )
{
int flags ;
debug ( " Blocking: %d " , s ) ;
flags = fcntl ( s , F_GETFL , 0 ) ;
fcntl ( s , F_SETFL , flags ^ O_NONBLOCK ) ;
}
void NonBlocking ( int s )
{
int flags ;
debug ( " NonBlocking: %d " , s ) ;
flags = fcntl ( s , F_GETFL , 0 ) ;
fcntl ( s , F_SETFL , flags | O_NONBLOCK ) ;
}
int CleanAndResolve ( char * resolvedHost , const char * unresolvedHost )
{
struct hostent * hostPtr = NULL ;
struct in_addr addr ;
memset ( resolvedHost , ' \0 ' , MAXBUF ) ;
if ( unresolvedHost = = NULL )
return ( ERROR ) ;
if ( ( inet_aton ( unresolvedHost , & addr ) ) = = 0 )
return ( ERROR ) ;
hostPtr = gethostbyaddr ( ( char * ) & addr . s_addr , sizeof ( addr . s_addr ) , AF_INET ) ;
if ( hostPtr ! = NULL )
snprintf ( resolvedHost , MAXBUF , " %s " , hostPtr - > h_name ) ;
else
snprintf ( resolvedHost , MAXBUF , " %s " , unresolvedHost ) ;
return ( TRUE ) ;
}
/* write formatted text to a socket, in same format as printf */
void Write ( int sock , char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
char tb [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
sprintf ( tb , " %s \r \n " , textbuffer ) ;
chop ( tb ) ;
write ( sock , tb , strlen ( tb ) ) ;
update_stats_l ( sock , strlen ( tb ) ) ; /* add one line-out to stats L for this fd */
}
/* write a server formatted numeric response to a single socket */
void WriteServ ( int sock , char * text , . . . )
{
char textbuffer [ MAXBUF ] , tb [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
sprintf ( tb , " :%s %s \r \n " , ServerName , textbuffer ) ;
chop ( tb ) ;
write ( sock , tb , strlen ( tb ) ) ;
update_stats_l ( sock , strlen ( tb ) ) ; /* add one line-out to stats L for this fd */
}
/* write text from an originating user to originating user */
void WriteFrom ( int sock , userrec * user , char * text , . . . )
{
char textbuffer [ MAXBUF ] , tb [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
sprintf ( tb , " :%s!%s@%s %s \r \n " , user - > nick , user - > ident , user - > dhost , textbuffer ) ;
chop ( tb ) ;
write ( sock , tb , strlen ( tb ) ) ;
update_stats_l ( sock , strlen ( tb ) ) ; /* add one line-out to stats L for this fd */
}
/* write text to an destination user from a source user (e.g. user privmsg) */
void WriteTo ( userrec * source , userrec * dest , char * data , . . . )
{
char textbuffer [ MAXBUF ] , tb [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , data ) ;
if ( ( ! dest ) | | ( ! source ) )
{
return ;
}
vsnprintf ( textbuffer , MAXBUF , data , argsPtr ) ;
va_end ( argsPtr ) ;
chop ( tb ) ;
WriteFrom ( dest - > fd , source , " %s " , textbuffer ) ;
}
/* write formatted text from a source user to all users on a channel
* including the sender ( NOT for privmsg , notice etc ! ) */
void WriteChannel ( chanrec * Ptr , userrec * user , char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( has_channel ( i - > second , Ptr ) )
{
WriteTo ( user , i - > second , " %s " , textbuffer ) ;
}
}
}
/* write formatted text from a source user to all users on a channel except
* for the sender ( for privmsg etc ) */
void ChanExceptSender ( chanrec * Ptr , userrec * user , char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( has_channel ( i - > second , Ptr ) & & ( user ! = i - > second ) )
{
WriteTo ( user , i - > second , " %s " , textbuffer ) ;
}
}
}
int c_count ( userrec * u )
{
int z = 0 ;
for ( int i = 0 ; i ! = MAXCHANS ; i + + )
if ( u - > chans [ i ] . channel )
z + + ;
return z ;
}
/* 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 ) */
int common_channels ( userrec * u , userrec * u2 )
{
int i = 0 ;
int z = 0 ;
if ( ( ! u ) | | ( ! u2 ) )
{
return 0 ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
for ( z = 0 ; z ! = MAXCHANS ; z + + )
{
if ( ( u - > chans [ i ] . channel = = u2 - > chans [ z ] . channel ) & & ( u - > chans [ i ] . channel ) & & ( u2 - > chans [ z ] . channel ) & & ( u - > registered = = 7 ) & & ( u2 - > registered = = 7 ) )
{
if ( ( c_count ( u ) ) & & ( c_count ( u2 ) ) )
{
return 1 ;
}
}
}
}
return 0 ;
}
/* write a formatted string to all users who share at least one common
* channel , including the source user e . g . for use in NICK */
void WriteCommon ( userrec * u , char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
WriteFrom ( u - > fd , u , " %s " , textbuffer ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( common_channels ( u , i - > second ) & & ( i - > second ! = u ) )
{
WriteFrom ( i - > second - > fd , u , " %s " , textbuffer ) ;
}
}
}
/* 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 */
void WriteCommonExcept ( userrec * u , char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( common_channels ( u , i - > second ) ) & & ( u ! = i - > second ) )
{
WriteFrom ( i - > second - > fd , u , " %s " , textbuffer ) ;
}
}
}
void WriteOpers ( char * text , . . . )
{
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( strchr ( i - > second - > modes , ' o ' ) )
{
if ( strchr ( i - > second - > modes , ' s ' ) )
{
// send server notices to all with +s
// (TODO: needs SNOMASKs)
WriteServ ( i - > second - > fd , " NOTICE %s :%s " , i - > second - > nick , textbuffer ) ;
}
}
}
}
void WriteWallOps ( userrec * source , char * text , . . . )
{
int i = 0 ;
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( strchr ( i - > second - > modes , ' w ' ) )
{
WriteTo ( source , i - > second , " WALLOPS %s " , textbuffer ) ;
}
}
}
/* convert a string to lowercase. Note following special circumstances
* taken from RFC 1459. Many " official " server branches still hold to this
* rule so i will too ;
*
* Because of IRC ' s scandanavian origin , the characters { } | are
* considered to be the lower case equivalents of the characters [ ] \ ,
* respectively . This is a critical issue when determining the
* equivalence of two nicknames .
*/
void strlower ( char * n )
{
if ( ! n )
{
return ;
}
for ( int i = 0 ; i ! = strlen ( n ) ; i + + )
{
n [ i ] = tolower ( n [ i ] ) ;
if ( n [ i ] = = ' [ ' )
n [ i ] = ' { ' ;
if ( n [ i ] = = ' ] ' )
n [ i ] = ' } ' ;
if ( n [ i ] = = ' \\ ' )
n [ i ] = ' | ' ;
}
}
/* verify that a user's nickname is valid */
int isnick ( const char * n )
{
int i = 0 ;
char v [ MAXBUF ] ;
if ( ! n )
{
return 0 ;
}
if ( ! strcmp ( n , " " ) )
{
return 0 ;
}
if ( strlen ( n ) > NICKMAX - 1 )
{
return 0 ;
}
for ( i = 0 ; i ! = strlen ( n ) ; i + + )
{
if ( ( n [ i ] < 33 ) | | ( n [ i ] > 125 ) )
{
return 0 ;
}
/* can't occur ANYWHERE in a nickname! */
if ( strchr ( " <>,./?:;@'~#=+()*&%$<24> \" ! " , n [ i ] ) )
{
return 0 ;
}
/* can't occur as the first char of a nickname... */
if ( ( strchr ( " 0123456789 " , n [ i ] ) ) & & ( ! i ) )
{
return 0 ;
}
}
return 1 ;
}
/* Find a user record by nickname and return a pointer to it */
userrec * Find ( string nick )
{
user_hash : : iterator iter = clientlist . find ( nick ) ;
if ( iter = = clientlist . end ( ) )
/* Couldn't find it */
return NULL ;
return iter - > second ;
}
void update_stats_l ( int fd , int data_out ) /* add one line-out to stats L for this fd */
{
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( i - > second - > fd = = fd )
{
i - > second - > bytes_out + = data_out ;
i - > second - > cmds_out + + ;
}
}
}
/* find a channel record by channel name and return a pointer to it */
chanrec * FindChan ( const char * chan )
{
chan_hash : : iterator iter = chanlist . find ( chan ) ;
if ( iter = = chanlist . end ( ) )
/* Couldn't find it */
return NULL ;
return iter - > second ;
}
void purge_empty_chans ( void )
{
int go_again = 1 , purge = 0 ;
while ( go_again )
{
go_again = 0 ;
for ( chan_hash : : iterator i = chanlist . begin ( ) ; i ! = chanlist . end ( ) ; i + + )
{
if ( i - > second ) {
if ( ! usercount ( i - > second ) )
{
/* kill the record */
if ( i ! = chanlist . end ( ) )
{
debug ( " del_channel: destroyed: %s " , i - > second - > name ) ;
delete i - > second ;
chanlist . erase ( i ) ;
go_again = 1 ;
purge + + ;
break ;
}
}
}
}
}
debug ( " completed channel purge, killed %d " , purge ) ;
}
/* returns the status character for a given user on a channel, e.g. @ for op,
* % for halfop etc . If the user has several modes set , the highest mode
* the user has must be returned . */
char * cmode ( userrec * user , chanrec * chan )
{
int i ;
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( user - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( ( user - > chans [ i ] . uc_modes & UCMODE_OP ) > 0 )
{
return " @ " ;
}
if ( ( user - > chans [ i ] . uc_modes & UCMODE_HOP ) > 0 )
{
return " % " ;
}
if ( ( user - > chans [ i ] . uc_modes & UCMODE_VOICE ) > 0 )
{
return " + " ;
}
return " " ;
}
}
}
char scratch [ MAXMODES ] ;
char * chanmodes ( chanrec * chan )
{
strcpy ( scratch , " " ) ;
if ( chan - > noexternal )
{
strcat ( scratch , " n " ) ;
}
if ( chan - > topiclock )
{
strcat ( scratch , " t " ) ;
}
if ( strcmp ( chan - > key , " " ) )
{
strcat ( scratch , " k " ) ;
}
if ( chan - > limit )
{
strcat ( scratch , " l " ) ;
}
if ( chan - > inviteonly )
{
strcat ( scratch , " i " ) ;
}
if ( chan - > moderated )
{
strcat ( scratch , " m " ) ;
}
if ( chan - > secret )
{
strcat ( scratch , " s " ) ;
}
if ( chan - > c_private )
{
strcat ( scratch , " p " ) ;
}
if ( strcmp ( chan - > key , " " ) )
{
strcat ( scratch , " " ) ;
strcat ( scratch , chan - > key ) ;
}
if ( chan - > limit )
{
char foo [ 24 ] ;
sprintf ( foo , " %d " , chan - > limit ) ;
strcat ( scratch , foo ) ;
}
debug ( " chanmodes: %s %s " , chan - > name , scratch ) ;
return scratch ;
}
/* returns the status value for a given user on a channel, e.g. STATUS_OP for
* op , STATUS_VOICE for voice etc . If the user has several modes set , the
* highest mode the user has must be returned . */
int cstatus ( userrec * user , chanrec * chan )
{
int i ;
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( user - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( ( user - > chans [ i ] . uc_modes & UCMODE_OP ) > 0 )
{
return STATUS_OP ;
}
if ( ( user - > chans [ i ] . uc_modes & UCMODE_HOP ) > 0 )
{
return STATUS_HOP ;
}
if ( ( user - > chans [ i ] . uc_modes & UCMODE_VOICE ) > 0 )
{
return STATUS_VOICE ;
}
return STATUS_NORMAL ;
}
}
}
/* compile a userlist of a channel into a string, each nick seperated by
* spaces and op , voice etc status shown as @ and + */
void userlist ( userrec * user , chanrec * c )
{
sprintf ( list , " 353 %s = %s : " , user - > nick , c - > name ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( has_channel ( i - > second , c ) )
{
if ( isnick ( i - > second - > nick ) )
{
if ( ( ! has_channel ( i - > second , c ) ) & & ( strchr ( i - > second - > modes , ' i ' ) ) )
{
/* user is +i, and source not on the channel, does not show
* nick in NAMES list */
continue ;
}
strcat ( list , cmode ( i - > second , c ) ) ;
strcat ( list , i - > second - > nick ) ;
strcat ( list , " " ) ;
if ( strlen ( list ) > ( 480 - NICKMAX ) )
{
/* list overflowed into
* multiple numerics */
WriteServ ( user - > fd , list ) ;
sprintf ( list , " 353 %s = %s : " , user - > nick , c - > name ) ;
}
}
}
}
/* if whats left in the list isnt empty, send it */
if ( list [ strlen ( list ) - 1 ] ! = ' : ' )
{
WriteServ ( user - > fd , list ) ;
}
}
/* return a count of the users on a specific channel accounting for
* invisible users who won ' t increase the count . e . g . for / LIST */
int usercount_i ( chanrec * c )
{
int i = 0 ;
int count = 0 ;
strcpy ( list , " " ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( has_channel ( i - > second , c ) )
{
if ( isnick ( i - > second - > nick ) )
{
if ( ( ! has_channel ( i - > second , c ) ) & & ( strchr ( i - > second - > modes , ' i ' ) ) )
{
/* user is +i, and source not on the channel, does not show
* nick in NAMES list */
continue ;
}
count + + ;
}
}
}
debug ( " usercount_i: %s %d " , c - > name , count ) ;
return count ;
}
int usercount ( chanrec * c )
{
int i = 0 ;
int count = 0 ;
strcpy ( list , " " ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( has_channel ( i - > second , c ) )
{
if ( isnick ( i - > second - > nick ) )
{
count + + ;
}
}
}
debug ( " usercount: %s %d " , c - > name , count ) ;
return count ;
}
/* add a channel to a user, creating the record for it if needed and linking
* it to the user record */
chanrec * add_channel ( userrec * user , char * cname , char * key )
{
int i = 0 ;
chanrec * Ptr ;
int created = 0 ;
if ( ( ! cname ) | | ( ! user ) )
{
return NULL ;
}
if ( strlen ( cname ) > CHANMAX - 1 )
{
cname [ CHANMAX - 1 ] = ' \0 ' ;
}
debug ( " add_channel: %s %s " , user - > nick , cname ) ;
if ( ( has_channel ( user , FindChan ( cname ) ) ) & & ( FindChan ( cname ) ) )
{
return NULL ; // already on the channel!
}
if ( ! FindChan ( cname ) )
{
/* create a new one */
debug ( " add_channel: creating: %s " , cname ) ;
{
chanlist [ cname ] = new chanrec ( ) ;
strcpy ( chanlist [ cname ] - > name , cname ) ;
chanlist [ cname ] - > topiclock = 1 ;
chanlist [ cname ] - > noexternal = 1 ;
chanlist [ cname ] - > created = time ( NULL ) ;
strcpy ( chanlist [ cname ] - > topic , " " ) ;
strncpy ( chanlist [ cname ] - > setby , user - > nick , NICKMAX ) ;
chanlist [ cname ] - > topicset = 0 ;
Ptr = chanlist [ cname ] ;
debug ( " add_channel: created: %s " , cname ) ;
/* set created to 2 to indicate user
* is the first in the channel
* and should be given ops */
created = 2 ;
}
}
else
{
/* channel exists, just fish out a pointer to its struct */
Ptr = FindChan ( cname ) ;
if ( Ptr )
{
debug ( " add_channel: joining to: %s " , Ptr - > name ) ;
if ( strcmp ( Ptr - > key , " " ) )
{
debug ( " add_channel: %s has key %s " , Ptr - > name , Ptr - > key ) ;
if ( ! key )
{
debug ( " add_channel: no key given in JOIN " ) ;
WriteServ ( user - > fd , " 475 %s %s :Cannot join channel (Requires key) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
else
{
debug ( " key at %p is %s " , key , key ) ;
if ( strcasecmp ( key , Ptr - > key ) )
{
debug ( " add_channel: bad key given in JOIN " ) ;
WriteServ ( user - > fd , " 475 %s %s :Cannot join channel (Incorrect key) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
}
}
if ( Ptr - > inviteonly )
{
if ( user - > IsInvited ( Ptr - > name ) )
{
/* user was invited to channel */
/* there may be an optional channel NOTICE here */
}
else
{
WriteServ ( user - > fd , " 473 %s %s :Cannot join channel (Invite only) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
}
if ( Ptr - > limit )
{
if ( usercount ( Ptr ) = = Ptr - > limit )
{
WriteServ ( user - > fd , " 471 %s %s :Cannot join channel (Channel is full) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
}
/* check user against the channel banlist */
for ( BanList : : iterator i = Ptr - > bans . begin ( ) ; i ! = Ptr - > bans . end ( ) ; i + + )
{
if ( match ( user - > GetFullHost ( ) , i - > data ) )
{
WriteServ ( user - > fd , " 474 %s %s :Cannot join channel (You're banned) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
}
user - > RemoveInvite ( Ptr - > name ) ;
}
created = 1 ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( user - > chans [ i ] . channel = = NULL )
{
if ( created = = 2 )
{
/* first user in is given ops */
user - > chans [ i ] . uc_modes = UCMODE_OP ;
}
else
{
user - > chans [ i ] . uc_modes = 0 ;
}
user - > chans [ i ] . channel = Ptr ;
WriteChannel ( Ptr , user , " JOIN :%s " , Ptr - > name ) ;
if ( Ptr - > topicset )
{
WriteServ ( user - > fd , " 332 %s %s :%s " , user - > nick , Ptr - > name , Ptr - > topic ) ;
WriteServ ( user - > fd , " 333 %s %s %s %d " , user - > nick , Ptr - > name , Ptr - > setby , Ptr - > topicset ) ;
}
userlist ( user , Ptr ) ;
WriteServ ( user - > fd , " 366 %s %s :End of /NAMES list. " , user - > nick , Ptr - > name ) ;
WriteServ ( user - > fd , " 324 %s %s +%s " , user - > nick , Ptr - > name , chanmodes ( Ptr ) ) ;
WriteServ ( user - > fd , " 329 %s %s %d " , user - > nick , Ptr - > name , Ptr - > created ) ;
FOREACH_MOD OnUserJoin ( user , Ptr ) ;
return Ptr ;
}
}
debug ( " add_channel: user channel max exceeded: %s %s " , user - > nick , cname ) ;
WriteServ ( user - > fd , " 405 %s %s :You are on too many channels " , user - > nick , cname ) ;
return NULL ;
}
/* remove a channel from a users record, and remove the record from memory
* if the channel has become empty */
chanrec * del_channel ( userrec * user , char * cname , char * reason )
{
int i = 0 ;
chanrec * Ptr ;
int created = 0 ;
if ( ( ! cname ) | | ( ! user ) )
{
return NULL ;
}
Ptr = FindChan ( cname ) ;
if ( ! Ptr )
{
return NULL ;
}
FOREACH_MOD OnUserPart ( user , Ptr ) ;
debug ( " del_channel: removing: %s %s " , user - > nick , Ptr - > name ) ;
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
/* zap it from the channel list of the user */
if ( user - > chans [ i ] . channel = = Ptr )
{
if ( reason )
{
WriteChannel ( Ptr , user , " PART %s :%s " , Ptr - > name , reason ) ;
}
else
{
WriteChannel ( Ptr , user , " PART :%s " , Ptr - > name ) ;
}
user - > chans [ i ] . uc_modes = 0 ;
user - > chans [ i ] . channel = NULL ;
debug ( " del_channel: unlinked: %s %s " , user - > nick , Ptr - > name ) ;
break ;
}
}
/* if there are no users left on the channel */
if ( ! usercount ( Ptr ) )
{
chan_hash : : iterator iter = chanlist . find ( Ptr - > name ) ;
debug ( " del_channel: destroying channel: %s " , Ptr - > name ) ;
/* kill the record */
if ( iter ! = chanlist . end ( ) )
{
debug ( " del_channel: destroyed: %s " , Ptr - > name ) ;
delete iter - > second ;
chanlist . erase ( iter ) ;
}
}
}
void kick_channel ( userrec * src , userrec * user , chanrec * Ptr , char * reason )
{
int i = 0 ;
int created = 0 ;
if ( ( ! Ptr ) | | ( ! user ) | | ( ! src ) )
{
return ;
}
debug ( " kick_channel: removing: %s %s %s " , user - > nick , Ptr - > name , src - > nick ) ;
if ( ! has_channel ( user , Ptr ) )
{
WriteServ ( src - > fd , " 441 %s %s %s :They are not on that channel " , src - > nick , user - > nick , Ptr - > name ) ;
return ;
}
if ( ( cstatus ( src , Ptr ) < STATUS_HOP ) | | ( cstatus ( src , Ptr ) < cstatus ( user , Ptr ) ) )
{
if ( cstatus ( src , Ptr ) = = STATUS_HOP )
{
WriteServ ( src - > fd , " 482 %s %s :You must be a channel operator " , src - > nick , Ptr - > name ) ;
}
else
{
WriteServ ( src - > fd , " 482 %s %s :You must be at least a half-operator " , src - > nick , Ptr - > name ) ;
}
return ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
/* zap it from the channel list of the user */
if ( user - > chans [ i ] . channel = = Ptr )
{
WriteChannel ( Ptr , src , " KICK %s %s :%s " , Ptr - > name , user - > nick , reason ) ;
user - > chans [ i ] . uc_modes = 0 ;
user - > chans [ i ] . channel = NULL ;
debug ( " del_channel: unlinked: %s %s " , user - > nick , Ptr - > name ) ;
break ;
}
}
/* if there are no users left on the channel */
if ( ! usercount ( Ptr ) )
{
chan_hash : : iterator iter = chanlist . find ( Ptr - > name ) ;
debug ( " del_channel: destroying channel: %s " , Ptr - > name ) ;
/* kill the record */
if ( iter ! = chanlist . end ( ) )
{
debug ( " del_channel: destroyed: %s " , Ptr - > name ) ;
delete iter - > second ;
chanlist . erase ( iter ) ;
}
}
}
/* returns 1 if user u has channel c in their record, 0 if not */
int has_channel ( userrec * u , chanrec * c )
{
int i = 0 ;
if ( ! u )
{
return 0 ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( u - > chans [ i ] . channel = = c )
{
return 1 ;
}
}
return 0 ;
}
int give_ops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status ! = STATUS_OP )
{
WriteServ ( user - > fd , " 482 %s %s :You're not a channel operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
d = Find ( dest ) ;
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( d - > chans [ i ] . uc_modes & UCMODE_OP )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes = d - > chans [ i ] . uc_modes | UCMODE_OP ;
debug ( " gave ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
int give_hops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status ! = STATUS_OP )
{
WriteServ ( user - > fd , " 482 %s %s :You're not a channel operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
d = Find ( dest ) ;
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( d - > chans [ i ] . uc_modes & UCMODE_HOP )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes = d - > chans [ i ] . uc_modes | UCMODE_HOP ;
debug ( " gave h-ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
int give_voice ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status < STATUS_HOP )
{
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
d = Find ( dest ) ;
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( d - > chans [ i ] . uc_modes & UCMODE_VOICE )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes = d - > chans [ i ] . uc_modes | UCMODE_VOICE ;
debug ( " gave voice: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
int take_ops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status ! = STATUS_OP )
{
WriteServ ( user - > fd , " 482 %s %s :You're not a channel operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
d = Find ( dest ) ;
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( ( d - > chans [ i ] . uc_modes & UCMODE_OP ) = = 0 )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes ^ = UCMODE_OP ;
debug ( " took ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
int take_hops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status ! = STATUS_OP )
{
WriteServ ( user - > fd , " 482 %s %s :You're not a channel operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
d = Find ( dest ) ;
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( ( d - > chans [ i ] . uc_modes & UCMODE_HOP ) = = 0 )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes ^ = UCMODE_HOP ;
debug ( " took h-ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
int take_voice ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
if ( status < STATUS_HOP )
{
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator " , user - > nick , chan - > name ) ;
return 0 ;
}
else
{
d = Find ( dest ) ;
if ( ! isnick ( dest ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
if ( ! d )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , dest ) ;
return 0 ;
}
else
{
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( ( d - > chans [ i ] . channel = = chan ) & & ( chan ! = NULL ) )
{
if ( ( d - > chans [ i ] . uc_modes & UCMODE_VOICE ) = = 0 )
{
/* mode already set on user, dont allow multiple */
return 0 ;
}
d - > chans [ i ] . uc_modes ^ = UCMODE_VOICE ;
debug ( " took voice: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
}
}
}
}
return 1 ;
}
void TidyBan ( char * ban )
{
char temp [ MAXBUF ] , NICK [ MAXBUF ] , IDENT [ MAXBUF ] , HOST [ MAXBUF ] ;
strcpy ( temp , ban ) ;
char * pos_of_pling = strchr ( temp , ' ! ' ) ;
char * pos_of_at = strchr ( temp , ' @ ' ) ;
pos_of_pling [ 0 ] = ' \0 ' ;
pos_of_at [ 0 ] = ' \0 ' ;
pos_of_pling + + ;
pos_of_at + + ;
strncpy ( NICK , temp , NICKMAX ) ;
strncpy ( IDENT , pos_of_pling , IDENTMAX + 1 ) ;
strncpy ( HOST , pos_of_at , 160 ) ;
sprintf ( ban , " %s!%s@%s " , NICK , IDENT , HOST ) ;
}
int add_ban ( userrec * user , char * dest , chanrec * chan , int status )
{
BanItem b ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
return 0 ;
if ( strchr ( dest , ' ! ' ) = = 0 )
return 0 ;
if ( strchr ( dest , ' @ ' ) = = 0 )
return 0 ;
for ( int i = 0 ; i < strlen ( dest ) ; i + + )
if ( dest [ i ] < 32 )
return 0 ;
for ( int i = 0 ; i < strlen ( dest ) ; i + + )
if ( dest [ i ] > 126 )
return 0 ;
int c = 0 ;
for ( int i = 0 ; i < strlen ( dest ) ; i + + )
if ( dest [ i ] = = ' ! ' )
c + + ;
if ( c > 1 )
return 0 ;
c = 0 ;
for ( int i = 0 ; i < strlen ( dest ) ; i + + )
if ( dest [ i ] = = ' @ ' )
c + + ;
if ( c > 1 )
return 0 ;
debug ( " add_ban: %s %s " , chan - > name , user - > nick ) ;
TidyBan ( dest ) ;
for ( BanList : : iterator i = chan - > bans . begin ( ) ; i ! = chan - > bans . end ( ) ; i + + )
{
if ( ! strcasecmp ( i - > data , dest ) )
{
// dont allow a user to set the same ban twice
return 0 ;
}
}
b . set_time = time ( NULL ) ;
strncpy ( b . data , dest , MAXBUF ) ;
strncpy ( b . set_by , user - > nick , NICKMAX ) ;
chan - > bans . push_back ( b ) ;
return 1 ;
}
int take_ban ( userrec * user , char * dest , chanrec * chan , int status )
{
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
return 0 ;
}
debug ( " del_ban: %s %s " , chan - > name , user - > nick ) ;
for ( BanList : : iterator i = chan - > bans . begin ( ) ; i ! = chan - > bans . end ( ) ; i + + )
{
if ( ! strcasecmp ( i - > data , dest ) )
{
chan - > bans . erase ( i ) ;
return 1 ;
}
}
return 0 ;
}
void process_modes ( char * * parameters , userrec * user , chanrec * chan , int status , int pcnt )
{
char modelist [ MAXBUF ] ;
char outlist [ MAXBUF ] ;
char outstr [ MAXBUF ] ;
char outpars [ 32 ] [ MAXBUF ] ;
int param = 2 ;
int pc = 0 ;
int ptr = 0 ;
int mdir = 1 ;
int r = 0 ;
bool k_set = false , l_set = false ;
if ( pcnt < 2 )
{
return ;
}
debug ( " process_modes: start " ) ;
strcpy ( modelist , parameters [ 1 ] ) ; /* mode list, e.g. +oo-o */
/* parameters[2] onwards are parameters for
* modes that require them : ) */
strcpy ( outlist , " + " ) ;
mdir = 1 ;
debug ( " process_modes: modelist: %s " , modelist ) ;
for ( ptr = 0 ; ptr < strlen ( modelist ) ; ptr + + )
{
r = 0 ;
{
debug ( " process_modes: modechar: %c " , modelist [ ptr ] ) ;
switch ( modelist [ ptr ] )
{
case ' - ' :
if ( mdir ! = 0 )
{
if ( ( outlist [ strlen ( outlist ) - 1 ] = = ' + ' ) | | ( outlist [ strlen ( outlist ) - 1 ] = = ' - ' ) )
{
outlist [ strlen ( outlist ) - 1 ] = ' - ' ;
}
else
{
strcat ( outlist , " - " ) ;
}
}
mdir = 0 ;
break ;
case ' + ' :
if ( mdir ! = 1 )
{
if ( ( outlist [ strlen ( outlist ) - 1 ] = = ' + ' ) | | ( outlist [ strlen ( outlist ) - 1 ] = = ' - ' ) )
{
outlist [ strlen ( outlist ) - 1 ] = ' + ' ;
}
else
{
strcat ( outlist , " + " ) ;
}
}
mdir = 1 ;
break ;
case ' o ' :
if ( ( param > = pcnt ) ) break ;
if ( mdir = = 1 )
{
r = give_ops ( user , parameters [ param + + ] , chan , status ) ;
}
else
{
r = take_ops ( user , parameters [ param + + ] , chan , status ) ;
}
if ( r )
{
strcat ( outlist , " o " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param - 1 ] ) ;
}
break ;
case ' h ' :
if ( ( param > = pcnt ) ) break ;
if ( mdir = = 1 )
{
r = give_hops ( user , parameters [ param + + ] , chan , status ) ;
}
else
{
r = take_hops ( user , parameters [ param + + ] , chan , status ) ;
}
if ( r )
{
strcat ( outlist , " h " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param - 1 ] ) ;
}
break ;
case ' v ' :
if ( ( param > = pcnt ) ) break ;
if ( mdir = = 1 )
{
r = give_voice ( user , parameters [ param + + ] , chan , status ) ;
}
else
{
r = take_voice ( user , parameters [ param + + ] , chan , status ) ;
}
if ( r )
{
strcat ( outlist , " v " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param - 1 ] ) ;
}
break ;
case ' b ' :
if ( ( param > = pcnt ) ) break ;
if ( mdir = = 1 )
{
r = add_ban ( user , parameters [ param + + ] , chan , status ) ;
}
else
{
r = take_ban ( user , parameters [ param + + ] , chan , status ) ;
}
if ( r )
{
strcat ( outlist , " b " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param - 1 ] ) ;
}
break ;
case ' k ' :
if ( ( param > = pcnt ) )
break ;
if ( mdir = = 1 )
{
if ( k_set )
break ;
if ( ! strcmp ( chan - > key , " " ) )
{
strcat ( outlist , " k " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param + + ] ) ;
strcpy ( chan - > key , parameters [ param - 1 ] ) ;
k_set = true ;
}
}
else
{
/* only allow -k if correct key given */
if ( strcmp ( chan - > key , " " ) )
{
strcat ( outlist , " k " ) ;
strcpy ( chan - > key , " " ) ;
}
}
break ;
case ' l ' :
if ( mdir = = 0 )
{
if ( chan - > limit )
{
strcat ( outlist , " l " ) ;
chan - > limit = 0 ;
}
}
if ( ( param > = pcnt ) ) break ;
if ( mdir = = 1 )
{
if ( l_set )
break ;
bool invalid = false ;
for ( int i = 0 ; i < strlen ( parameters [ param ] ) ; i + + )
{
if ( ( parameters [ param ] [ i ] < ' 0 ' ) | | ( parameters [ param ] [ i ] > ' 9 ' ) )
{
invalid = true ;
}
}
if ( atoi ( parameters [ param ] ) < 1 )
{
invalid = true ;
}
if ( invalid )
break ;
chan - > limit = atoi ( parameters [ param ] ) ;
if ( chan - > limit )
{
strcat ( outlist , " l " ) ;
strcpy ( outpars [ pc + + ] , parameters [ param + + ] ) ;
l_set = true ;
}
}
break ;
case ' i ' :
if ( chan - > inviteonly ! = mdir )
{
strcat ( outlist , " i " ) ;
}
chan - > inviteonly = mdir ;
break ;
case ' t ' :
if ( chan - > topiclock ! = mdir )
{
strcat ( outlist , " t " ) ;
}
chan - > topiclock = mdir ;
break ;
case ' n ' :
if ( chan - > noexternal ! = mdir )
{
strcat ( outlist , " n " ) ;
}
chan - > noexternal = mdir ;
break ;
case ' m ' :
if ( chan - > moderated ! = mdir )
{
strcat ( outlist , " m " ) ;
}
chan - > moderated = mdir ;
break ;
case ' s ' :
if ( chan - > secret ! = mdir )
{
strcat ( outlist , " s " ) ;
if ( chan - > c_private )
{
chan - > c_private = 0 ;
if ( mdir )
{
strcat ( outlist , " -p+ " ) ;
}
else
{
strcat ( outlist , " +p- " ) ;
}
}
}
chan - > secret = mdir ;
break ;
case ' p ' :
if ( chan - > c_private ! = mdir )
{
strcat ( outlist , " p " ) ;
if ( chan - > secret )
{
chan - > secret = 0 ;
if ( mdir )
{
strcat ( outlist , " -s+ " ) ;
}
else
{
strcat ( outlist , " +s- " ) ;
}
}
}
chan - > c_private = mdir ;
break ;
}
}
}
/* this ensures only the *valid* modes are sent out onto the network */
while ( ( outlist [ strlen ( outlist ) - 1 ] = = ' - ' ) | | ( outlist [ strlen ( outlist ) - 1 ] = = ' + ' ) )
{
outlist [ strlen ( outlist ) - 1 ] = ' \0 ' ;
}
if ( strcmp ( outlist , " " ) )
{
strcpy ( outstr , outlist ) ;
for ( ptr = 0 ; ptr < pc ; ptr + + )
{
strcat ( outstr , " " ) ;
strcat ( outstr , outpars [ ptr ] ) ;
}
WriteChannel ( chan , user , " MODE %s %s " , chan - > name , outstr ) ;
}
}
void handle_mode ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
userrec * dest ;
int can_change , i ;
int direction = 1 ;
char outpars [ MAXBUF ] ;
dest = Find ( parameters [ 0 ] ) ;
if ( ( dest ) & & ( pcnt = = 1 ) )
{
WriteServ ( user - > fd , " 221 %s :+%s " , user - > nick , user - > modes ) ;
return ;
}
if ( ( dest ) & & ( pcnt > 1 ) )
{
can_change = 0 ;
if ( user ! = dest )
{
if ( strchr ( user - > modes , ' o ' ) )
{
can_change = 1 ;
}
}
else
{
can_change = 1 ;
}
if ( ! can_change )
{
WriteServ ( user - > fd , " 482 %s :Can't change mode for other users " , user - > nick ) ;
return ;
}
strcpy ( outpars , " + " ) ;
direction = 1 ;
if ( ( parameters [ 1 ] [ 0 ] ! = ' + ' ) & & ( parameters [ 1 ] [ 0 ] ! = ' - ' ) )
return ;
for ( i = 0 ; i < strlen ( parameters [ 1 ] ) ; i + + )
{
if ( parameters [ 1 ] [ i ] = = ' + ' )
{
if ( direction ! = 1 )
{
if ( ( outpars [ strlen ( outpars ) - 1 ] = = ' + ' ) | | ( outpars [ strlen ( outpars ) - 1 ] = = ' - ' ) )
{
outpars [ strlen ( outpars ) - 1 ] = ' + ' ;
}
else
{
strcat ( outpars , " + " ) ;
}
}
direction = 1 ;
}
else
if ( parameters [ 1 ] [ i ] = = ' - ' )
{
if ( direction ! = 0 )
{
if ( ( outpars [ strlen ( outpars ) - 1 ] = = ' + ' ) | | ( outpars [ strlen ( outpars ) - 1 ] = = ' - ' ) )
{
outpars [ strlen ( outpars ) - 1 ] = ' - ' ;
}
else
{
strcat ( outpars , " - " ) ;
}
}
direction = 0 ;
}
else
{
can_change = 0 ;
if ( strchr ( user - > modes , ' o ' ) )
{
can_change = 1 ;
}
else
{
if ( ( parameters [ 1 ] [ i ] = = ' i ' ) | | ( parameters [ 1 ] [ i ] = = ' w ' ) | | ( parameters [ 1 ] [ i ] = = ' s ' ) )
{
can_change = 1 ;
}
}
if ( can_change )
{
if ( direction = = 1 )
{
if ( ! strchr ( dest - > modes , parameters [ 1 ] [ i ] ) )
{
dest - > modes [ strlen ( dest - > modes ) + 1 ] = ' \0 ' ;
dest - > modes [ strlen ( dest - > modes ) ] = parameters [ 1 ] [ i ] ;
outpars [ strlen ( outpars ) + 1 ] = ' \0 ' ;
outpars [ strlen ( outpars ) ] = parameters [ 1 ] [ i ] ;
}
}
else
{
int q = 0 ;
char temp [ MAXBUF ] ;
char moo [ MAXBUF ] ;
outpars [ strlen ( outpars ) + 1 ] = ' \0 ' ;
outpars [ strlen ( outpars ) ] = parameters [ 1 ] [ i ] ;
strcpy ( temp , " " ) ;
for ( q = 0 ; q < strlen ( user - > modes ) ; q + + )
{
if ( user - > modes [ q ] ! = parameters [ 1 ] [ i ] )
{
moo [ 0 ] = user - > modes [ q ] ;
moo [ 1 ] = ' \0 ' ;
strcat ( temp , moo ) ;
}
}
strcpy ( user - > modes , temp ) ;
}
}
}
}
if ( strlen ( outpars ) )
{
char b [ MAXBUF ] ;
strcpy ( b , " " ) ;
int z = 0 ;
int i = 0 ;
while ( i < strlen ( outpars ) )
{
b [ z + + ] = outpars [ i + + ] ;
b [ z ] = ' \0 ' ;
if ( i < strlen ( outpars ) - 1 )
{
if ( ( ( outpars [ i ] = = ' - ' ) | | ( outpars [ i ] = = ' + ' ) ) & & ( ( outpars [ i + 1 ] = = ' - ' ) | | ( outpars [ i + 1 ] = = ' + ' ) ) )
{
// someones playing silly buggers and trying
// to put a +- or -+ into the line...
i + + ;
}
}
if ( i = = strlen ( outpars ) - 1 )
{
if ( ( outpars [ i ] = = ' - ' ) | | ( outpars [ i ] = = ' + ' ) )
{
i + + ;
}
}
}
z = strlen ( b ) - 1 ;
if ( ( b [ z ] = = ' - ' ) | | ( b [ z ] = = ' + ' ) )
b [ z ] = = ' \0 ' ;
if ( ( ! strcmp ( b , " + " ) ) | | ( ! strcmp ( b , " - " ) ) )
return ;
WriteTo ( user , dest , " MODE %s :%s " , dest - > nick , b ) ;
}
return ;
}
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
if ( pcnt = = 1 )
{
/* just /modes #channel */
WriteServ ( user - > fd , " 324 %s %s +%s " , user - > nick , Ptr - > name , chanmodes ( Ptr ) ) ;
WriteServ ( user - > fd , " 329 %s %s %d " , user - > nick , Ptr - > name , Ptr - > created ) ;
return ;
}
else
if ( pcnt = = 2 )
{
if ( ( ! strcmp ( parameters [ 1 ] , " +b " ) ) | | ( ! strcmp ( parameters [ 1 ] , " b " ) ) )
{
for ( BanList : : iterator i = Ptr - > bans . begin ( ) ; i ! = Ptr - > bans . end ( ) ; i + + )
{
WriteServ ( user - > fd , " 367 %s %s %s %s %d " , user - > nick , Ptr - > name , i - > data , i - > set_by , i - > set_time ) ;
}
WriteServ ( user - > fd , " 368 %s %s :End of channel ban list " , user - > nick , Ptr - > name ) ;
}
}
if ( ( cstatus ( user , Ptr ) < STATUS_HOP ) & & ( Ptr ) )
{
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator " , user - > nick , Ptr - > name ) ;
return ;
}
process_modes ( parameters , user , Ptr , cstatus ( user , Ptr ) , pcnt ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
/* This function pokes and hacks at a parameter list like the following:
*
* PART # winbot , # darkgalaxy : m00 !
*
* to turn it into a series of individual calls like this :
*
* PART # winbot : m00 !
* PART # darkgalaxy : m00 !
*
* The seperate calls are sent to a callback function provided by the caller
* ( the caller will usually call itself recursively ) . The callback function
* must be a command handler . Calling this function on a line with no list causes
* no action to be taken . You must provide a starting and ending parameter number
* where the range of the list can be found , useful if you have a terminating
* parameter as above which is actually not part of the list , or parameters
* before the actual list as well . This code is used by many functions which
* can function as " one to list " ( see the RFC ) */
int loop_call ( handlerfunc fn , char * * parameters , int pcnt , userrec * u , int start , int end , int joins )
{
char plist [ MAXBUF ] ;
char * param ;
char * pars [ 32 ] ;
char blog [ 32 ] [ MAXBUF ] ;
char blog2 [ 32 ] [ MAXBUF ] ;
int i = 0 , j = 0 , q = 0 , total = 0 , t = 0 , t2 = 0 , total2 = 0 ;
char keystr [ MAXBUF ] ;
char moo [ MAXBUF ] ;
for ( i = 0 ; i < 32 ; i + + )
strcpy ( blog [ i ] , " " ) ;
for ( i = 0 ; i < 32 ; i + + )
strcpy ( blog2 [ i ] , " " ) ;
strcpy ( moo , " " ) ;
for ( i = 0 ; i < 10 ; i + + )
{
if ( ! parameters [ i ] )
{
parameters [ i ] = moo ;
}
}
if ( joins )
{
if ( pcnt > 1 ) /* we have a key to copy */
{
strcpy ( keystr , parameters [ 1 ] ) ;
}
}
if ( ! parameters [ start ] )
{
return 0 ;
}
if ( ! strchr ( parameters [ start ] , ' , ' ) )
{
return 0 ;
}
strcpy ( plist , " " ) ;
for ( i = start ; i < = end ; i + + )
{
if ( parameters [ i ] )
{
strcat ( plist , parameters [ i ] ) ;
}
}
j = 0 ;
param = plist ;
t = strlen ( plist ) ;
for ( i = 0 ; i < t ; i + + )
{
if ( plist [ i ] = = ' , ' )
{
plist [ i ] = ' \0 ' ;
strcpy ( blog [ j + + ] , param ) ;
param = plist + i + 1 ;
}
}
strcpy ( blog [ j + + ] , param ) ;
total = j ;
if ( ( joins ) & & ( keystr ) & & ( total > 0 ) ) // more than one channel and is joining
{
strcat ( keystr , " , " ) ;
}
if ( ( joins ) & & ( keystr ) )
{
if ( strchr ( keystr , ' , ' ) )
{
j = 0 ;
param = keystr ;
t2 = strlen ( keystr ) ;
for ( i = 0 ; i < t2 ; i + + )
{
if ( keystr [ i ] = = ' , ' )
{
keystr [ i ] = ' \0 ' ;
strcpy ( blog2 [ j + + ] , param ) ;
param = keystr + i + 1 ;
}
}
strcpy ( blog2 [ j + + ] , param ) ;
total2 = j ;
}
}
for ( j = 0 ; j < total ; j + + )
{
if ( blog [ j ] )
{
pars [ 0 ] = blog [ j ] ;
}
for ( q = end ; q < pcnt - 1 ; q + + )
{
if ( parameters [ q + 1 ] )
{
pars [ q - end + 1 ] = parameters [ q + 1 ] ;
}
}
if ( ( joins ) & & ( parameters [ 1 ] ) )
{
if ( pcnt > 1 )
{
pars [ 1 ] = blog2 [ j ] ;
}
else
{
pars [ 1 ] = NULL ;
}
}
/* repeatedly call the function with the hacked parameter list */
if ( ( joins ) & & ( pcnt > 1 ) )
{
if ( pars [ 1 ] )
{
// pars[1] already set up and containing key from blog2[j]
fn ( pars , 2 , u ) ;
}
else
{
pars [ 1 ] = parameters [ 1 ] ;
fn ( pars , 2 , u ) ;
}
}
else
{
fn ( pars , pcnt - ( end - start ) , u ) ;
}
}
return 1 ;
}
void handle_join ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
int i = 0 ;
if ( loop_call ( handle_join , parameters , pcnt , user , 0 , 0 , 1 ) )
return ;
if ( parameters [ 0 ] [ 0 ] = = ' # ' )
{
Ptr = add_channel ( user , parameters [ 0 ] , parameters [ 1 ] ) ;
}
}
void handle_part ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
if ( pcnt > 1 )
{
if ( loop_call ( handle_part , parameters , pcnt , user , 0 , pcnt - 2 , 0 ) )
return ;
del_channel ( user , parameters [ 0 ] , parameters [ 1 ] ) ;
}
else
{
if ( loop_call ( handle_part , parameters , pcnt , user , 0 , pcnt - 1 , 0 ) )
return ;
del_channel ( user , parameters [ 0 ] , NULL ) ;
}
}
void handle_kick ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr = FindChan ( parameters [ 0 ] ) ;
userrec * u = Find ( parameters [ 1 ] ) ;
if ( ( ! u ) | | ( ! Ptr ) )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
return ;
}
if ( ! has_channel ( u , Ptr ) )
{
WriteServ ( user - > fd , " 442 %s %s :You're not on that channel! " , user - > nick , parameters [ 0 ] ) ;
return ;
}
if ( pcnt > 2 )
{
kick_channel ( user , u , Ptr , parameters [ 2 ] ) ;
}
else
{
kick_channel ( user , u , Ptr , user - > nick ) ;
}
}
void handle_die ( char * * parameters , int pcnt , userrec * user )
{
debug ( " die: %s " , user - > nick ) ;
if ( ! strcmp ( parameters [ 0 ] , diepass ) )
{
WriteOpers ( " *** DIE command from %s!%s@%s, terminating... " , user - > nick , user - > ident , user - > host ) ;
sleep ( DieDelay ) ;
Exit ( ERROR ) ;
}
else
{
WriteOpers ( " *** Failed DIE Command from %s!%s@%s. " , user - > nick , user - > ident , user - > host ) ;
}
}
void handle_restart ( char * * parameters , int pcnt , userrec * user )
{
debug ( " restart: %s " , user - > nick ) ;
if ( ! strcmp ( parameters [ 0 ] , restartpass ) )
{
WriteOpers ( " *** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D " , user - > nick , user - > ident , user - > host ) ;
sleep ( DieDelay ) ;
Exit ( ERROR ) ;
/* Will finish this later when i can be arsed :) */
}
else
{
WriteOpers ( " *** Failed RESTART Command from %s!%s@%s. " , user - > nick , user - > ident , user - > host ) ;
}
}
void kill_link ( userrec * user , char * reason )
{
user_hash : : iterator iter = clientlist . find ( user - > nick ) ;
debug ( " kill_link: %s '%s' " , user - > nick , reason ) ;
Write ( user - > fd , " ERROR :Closing link (%s@%s) [%s] " , user - > ident , user - > host , reason ) ;
fdatasync ( user - > fd ) ;
WriteOpers ( " *** Client exiting: %s!%s@%s [%s] " , user - > nick , user - > ident , user - > host , reason ) ;
FOREACH_MOD OnUserQuit ( user ) ;
debug ( " closing fd %d " , user - > fd ) ;
/* bugfix, cant close() a nonblocking socket (sux!) */
WriteCommonExcept ( user , " QUIT :%s " , reason ) ;
Blocking ( user - > fd ) ;
close ( user - > fd ) ;
NonBlocking ( user - > fd ) ;
2003-01-25 20:00:45 +00:00
AddWhoWas ( user ) ;
2003-01-23 19:45:57 +00:00
if ( iter ! = clientlist . end ( ) )
{
debug ( " deleting user hash value %p " , iter - > second ) ;
delete iter - > second ;
clientlist . erase ( iter ) ;
}
purge_empty_chans ( ) ;
}
void handle_kill ( char * * parameters , int pcnt , userrec * user )
{
userrec * u = Find ( parameters [ 0 ] ) ;
char killreason [ MAXBUF ] ;
debug ( " kill: %s %s " , parameters [ 0 ] , parameters [ 1 ] ) ;
if ( u )
{
WriteOpers ( " *** Local Kill by %s: %s!%s@%s (%s) " , user - > nick , u - > nick , u - > ident , u - > host , parameters [ 1 ] ) ;
sprintf ( killreason , " Killed (%s (%s)) " , user - > nick , parameters [ 1 ] ) ;
kill_link ( u , killreason ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
void handle_summon ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 445 %s :SUMMON has been disabled (depreciated command) " , user - > nick ) ;
}
void handle_users ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 445 %s :USERS has been disabled (depreciated command) " , user - > nick ) ;
}
// looks up a users password for their connection class (<ALLOW>/<DENY> tags)
char * Passwd ( userrec * user )
{
for ( ClassVector : : iterator i = Classes . begin ( ) ; i ! = Classes . end ( ) ; i + + )
{
if ( match ( user - > host , i - > host ) & & ( i - > type = = CC_ALLOW ) )
{
return i - > pass ;
}
}
return " " ;
}
bool IsDenied ( userrec * user )
{
for ( ClassVector : : iterator i = Classes . begin ( ) ; i ! = Classes . end ( ) ; i + + )
{
if ( match ( user - > host , i - > host ) & & ( i - > type = = CC_DENY ) )
{
return true ;
}
}
return false ;
}
void handle_pass ( char * * parameters , int pcnt , userrec * user )
{
if ( ! strcasecmp ( parameters [ 0 ] , Passwd ( user ) ) )
{
user - > haspassed = true ;
}
}
void handle_invite ( char * * parameters , int pcnt , userrec * user )
{
userrec * u = Find ( parameters [ 0 ] ) ;
chanrec * c = FindChan ( parameters [ 1 ] ) ;
if ( ( ! c ) | | ( ! u ) )
{
if ( ! c )
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 1 ] ) ;
}
else
{
if ( c - > inviteonly )
{
WriteServ ( user - > fd , " 401 %s %s :No such nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
return ;
}
if ( c - > inviteonly )
{
if ( cstatus ( user , c ) < STATUS_HOP )
{
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator " , user - > nick , c - > name ) ;
return ;
}
u - > InviteTo ( c - > name ) ;
WriteFrom ( u - > fd , user , " INVITE %s :%s " , u - > nick , c - > name ) ;
WriteServ ( user - > fd , " 341 %s %s %s " , user - > nick , u - > nick , c - > name ) ;
}
}
void handle_topic ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
if ( pcnt = = 1 )
{
if ( strlen ( parameters [ 0 ] ) < = CHANMAX )
{
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
if ( Ptr - > topicset )
{
WriteServ ( user - > fd , " 332 %s %s :%s " , user - > nick , Ptr - > name , Ptr - > topic ) ;
WriteServ ( user - > fd , " 333 %s %s %s %d " , user - > nick , Ptr - > name , Ptr - > setby , Ptr - > topicset ) ;
}
else
{
WriteServ ( user - > fd , " 331 %s %s :No topic is set. " , user - > nick , Ptr - > name ) ;
}
}
else
{
WriteServ ( user - > fd , " 331 %s %s :No topic is set. " , user - > nick , Ptr - > name ) ;
}
}
}
else if ( pcnt > 1 )
{
if ( loop_call ( handle_topic , parameters , pcnt , user , 0 , pcnt - 2 , 0 ) )
return ;
if ( strlen ( parameters [ 0 ] ) < = CHANMAX )
{
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
if ( ( Ptr - > topiclock ) & & ( cstatus ( user , Ptr ) < STATUS_HOP ) )
{
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator " , user - > nick , Ptr - > name ) ;
return ;
}
strcpy ( Ptr - > topic , parameters [ 1 ] ) ;
strcpy ( Ptr - > setby , user - > nick ) ;
Ptr - > topicset = time ( NULL ) ;
WriteChannel ( Ptr , user , " TOPIC %s :%s " , Ptr - > name , Ptr - > topic ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
}
}
/* sends out an error notice to all connected clients (not to be used
* lightly ! ) */
void send_error ( char * s )
{
debug ( " send_error: %s " , s ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
WriteServ ( i - > second - > fd , " NOTICE %s :%s " , i - > second - > nick , s ) ;
}
}
void Error ( int status )
{
signal ( SIGALRM , SIG_IGN ) ;
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGTERM , SIG_IGN ) ;
signal ( SIGABRT , SIG_IGN ) ;
signal ( SIGSEGV , SIG_IGN ) ;
signal ( SIGURG , SIG_IGN ) ;
signal ( SIGKILL , SIG_IGN ) ;
debug ( " *** fell down a pothole in the road to perfection *** " ) ;
send_error ( " Error! Segmentation fault! save meeeeeeeeeeeeee *splat!* " ) ;
exit ( status ) ;
}
int main ( int argc , char * argv [ ] )
{
Start ( ) ;
debug ( " *** InspIRCd starting up! " ) ;
if ( ! CheckConfig ( ) )
{
debug ( " main: no config " ) ;
printf ( " ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds! \n " ) ;
Exit ( ERROR ) ;
}
if ( InspIRCd ( ) = = ERROR )
{
debug ( " main: daemon function bailed " ) ;
printf ( " ERROR: could not initialise. Shutting down. \n " ) ;
Exit ( ERROR ) ;
}
Exit ( TRUE ) ;
return 0 ;
}
template < typename T > inline string ConvToStr ( const T & in )
{
stringstream tmp ;
if ( ! ( tmp < < in ) ) return string ( ) ;
return tmp . str ( ) ;
}
/* re-allocates a nick in the user_hash after they change nicknames,
* returns a pointer to the new user as it may have moved */
userrec * ReHashNick ( char * Old , char * New )
{
user_hash : : iterator newnick ;
user_hash : : iterator oldnick = clientlist . find ( Old ) ;
debug ( " ReHashNick: %s %s " , Old , New ) ;
if ( ! strcasecmp ( Old , New ) )
{
debug ( " old nick is new nick, skipping " ) ;
return oldnick - > second ;
}
if ( oldnick = = clientlist . end ( ) ) return NULL ; /* doesnt exist */
debug ( " ReHashNick: Found hashed nick %s " , Old ) ;
clientlist [ New ] = new userrec ( ) ;
clientlist [ New ] = oldnick - > second ;
/*delete oldnick->second; */
clientlist . erase ( oldnick ) ;
debug ( " ReHashNick: Nick rehashed as %s " , New ) ;
return clientlist [ New ] ;
}
2003-01-25 20:00:45 +00:00
/* adds or updates an entry in the whowas list */
void AddWhoWas ( userrec * u )
{
user_hash : : iterator iter = whowas . find ( u - > nick ) ;
userrec * a = new userrec ( ) ;
strcpy ( a - > nick , u - > nick ) ;
strcpy ( a - > ident , u - > ident ) ;
strcpy ( a - > dhost , u - > dhost ) ;
strcpy ( a - > host , u - > host ) ;
strcpy ( a - > fullname , u - > fullname ) ;
strcpy ( a - > server , u - > server ) ;
a - > signon = u - > signon ;
/* MAX_WHOWAS: max number of /WHOWAS items
* WHOWAS_STALE : number of hours before a WHOWAS item is marked as stale and
* can be replaced by a newer one
*/
if ( iter = = whowas . end ( ) )
{
if ( whowas . size ( ) = = WHOWAS_MAX )
{
for ( user_hash : : iterator i = whowas . begin ( ) ; i ! = whowas . end ( ) ; i + + )
{
// 3600 seconds in an hour ;)
if ( ( i - > second - > signon ) < ( time ( NULL ) - ( WHOWAS_STALE * 3600 ) ) )
{
2003-01-25 20:17:53 +00:00
delete i - > second ;
2003-01-25 20:00:45 +00:00
i - > second = a ;
debug ( " added WHOWAS entry, purged an old record " ) ;
return ;
}
}
}
2003-01-25 20:17:53 +00:00
else
{
debug ( " added fresh WHOWAS entry " ) ;
whowas [ a - > nick ] = a ;
}
2003-01-25 20:00:45 +00:00
}
else
{
debug ( " updated WHOWAS entry " ) ;
2003-01-25 20:17:53 +00:00
delete iter - > second ;
2003-01-25 20:00:45 +00:00
iter - > second = a ;
}
}
2003-01-23 19:45:57 +00:00
/* add a client connection to the sockets list */
void AddClient ( int socket , char * host , int port , bool iscached )
{
2003-01-25 20:00:45 +00:00
int i ;
int blocking = 1 ;
char resolved [ MAXBUF ] ;
string tempnick ;
char tn2 [ MAXBUF ] ;
user_hash : : iterator iter ;
tempnick = ConvToStr ( socket ) + " -unknown " ;
sprintf ( tn2 , " %d-unknown " , socket ) ;
2003-01-23 19:45:57 +00:00
iter = clientlist . find ( tempnick ) ;
if ( iter ! = clientlist . end ( ) ) return ;
/*
* It is OK to access the value here this way since we know
* it exists , we just created it above .
*
* At NO other time should you access a value in a map or a
* hash_map this way .
*/
clientlist [ tempnick ] = new userrec ( ) ;
NonBlocking ( socket ) ;
debug ( " AddClient: %d %s %d " , socket , host , port ) ;
clientlist [ tempnick ] - > fd = socket ;
strncpy ( clientlist [ tempnick ] - > nick , tn2 , NICKMAX ) ;
strncpy ( clientlist [ tempnick ] - > host , host , 160 ) ;
strncpy ( clientlist [ tempnick ] - > dhost , host , 160 ) ;
strncpy ( clientlist [ tempnick ] - > server , ServerName , 256 ) ;
clientlist [ tempnick ] - > registered = 0 ;
clientlist [ tempnick ] - > signon = time ( NULL ) ;
clientlist [ tempnick ] - > nping = time ( NULL ) + 240 ;
clientlist [ tempnick ] - > lastping = 1 ;
clientlist [ tempnick ] - > port = port ;
if ( iscached )
{
WriteServ ( socket , " NOTICE Auth :Found your hostname (cached)... " ) ;
}
else
{
WriteServ ( socket , " NOTICE Auth :Looking up your hostname... " ) ;
}
if ( clientlist . size ( ) = = MAXCLIENTS )
kill_link ( clientlist [ tempnick ] , " No more connections allowed in this class " ) ;
}
void handle_names ( char * * parameters , int pcnt , userrec * user )
{
chanrec * c ;
if ( loop_call ( handle_names , parameters , pcnt , user , 0 , pcnt - 1 , 0 ) )
return ;
c = FindChan ( parameters [ 0 ] ) ;
if ( c )
{
/*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
userlist ( user , c ) ;
WriteServ ( user - > fd , " 366 %s %s :End of /NAMES list. " , user - > nick , c - > name ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
void handle_privmsg ( char * * parameters , int pcnt , userrec * user )
{
userrec * dest ;
chanrec * chan ;
if ( loop_call ( handle_privmsg , parameters , pcnt , user , 0 , pcnt - 2 , 0 ) )
return ;
if ( parameters [ 0 ] [ 0 ] = = ' # ' )
{
chan = FindChan ( parameters [ 0 ] ) ;
if ( chan )
{
if ( ( chan - > noexternal ) & & ( ! has_channel ( user , chan ) ) )
{
WriteServ ( user - > fd , " 404 %s %s :Cannot send to channel (no external messages) " , user - > nick , chan - > name ) ;
return ;
}
if ( ( chan - > moderated ) & & ( cstatus ( user , chan ) < STATUS_VOICE ) )
{
WriteServ ( user - > fd , " 404 %s %s :Cannot send to channel (+m) " , user - > nick , chan - > name ) ;
return ;
}
ChanExceptSender ( chan , user , " PRIVMSG %s :%s " , chan - > name , parameters [ 1 ] ) ;
}
else
{
/* no such nick/channel */
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
return ;
}
dest = Find ( parameters [ 0 ] ) ;
if ( dest )
{
if ( strcmp ( dest - > awaymsg , " " ) )
{
/* auto respond with aweh msg */
WriteServ ( user - > fd , " 301 %s %s :%s " , user - > nick , dest - > nick , dest - > awaymsg ) ;
}
WriteTo ( user , dest , " PRIVMSG %s :%s " , dest - > nick , parameters [ 1 ] ) ;
}
else
{
/* no such nick/channel */
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
void handle_notice ( char * * parameters , int pcnt , userrec * user )
{
userrec * dest ;
chanrec * chan ;
if ( loop_call ( handle_notice , parameters , pcnt , user , 0 , pcnt - 2 , 0 ) )
return ;
if ( parameters [ 0 ] [ 0 ] = = ' # ' )
{
chan = FindChan ( parameters [ 0 ] ) ;
if ( chan )
{
if ( ( chan - > noexternal ) & & ( ! has_channel ( user , chan ) ) )
{
WriteServ ( user - > fd , " 404 %s %s :Cannot send to channel (no external messages) " , user - > nick , chan - > name ) ;
return ;
}
if ( ( chan - > moderated ) & & ( cstatus ( user , chan ) < STATUS_VOICE ) )
{
WriteServ ( user - > fd , " 404 %s %s :Cannot send to channel (+m) " , user - > nick , chan - > name ) ;
return ;
}
WriteChannel ( chan , user , " NOTICE %s :%s " , chan - > name , parameters [ 1 ] ) ;
}
else
{
/* no such nick/channel */
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
return ;
}
dest = Find ( parameters [ 0 ] ) ;
if ( dest )
{
WriteTo ( user , dest , " NOTICE %s :%s " , dest - > nick , parameters [ 1 ] ) ;
}
else
{
/* no such nick/channel */
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
char lst [ MAXBUF ] ;
char * chlist ( userrec * user )
{
int i = 0 ;
char cmp [ MAXBUF ] ;
debug ( " chlist: %s " , user - > nick ) ;
strcpy ( lst , " " ) ;
if ( ! user )
{
return lst ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( user - > chans [ i ] . channel ! = NULL )
{
if ( user - > chans [ i ] . channel - > name )
{
strcpy ( cmp , user - > chans [ i ] . channel - > name ) ;
strcat ( cmp , " " ) ;
if ( ! strstr ( lst , cmp ) )
{
if ( ( ! user - > chans [ i ] . channel - > c_private ) & & ( ! user - > chans [ i ] . channel - > secret ) )
{
strcat ( lst , cmode ( user , user - > chans [ i ] . channel ) ) ;
strcat ( lst , user - > chans [ i ] . channel - > name ) ;
strcat ( lst , " " ) ;
}
}
}
}
}
return lst ;
}
void handle_info ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 371 %s :The Inspire IRCd Project Has been brought to you by the following people.. " , user - > nick ) ;
WriteServ ( user - > fd , " 371 %s :Craig Edwards, Craig McLure, and Others.. " , user - > nick ) ;
WriteServ ( user - > fd , " 371 %s :Will finish this later when i can be arsed :p " , user - > nick ) ;
WriteServ ( user - > fd , " 374 %s :End of /INFO list " , user - > nick ) ;
}
void handle_time ( char * * parameters , int pcnt , userrec * user )
{
time_t rawtime ;
struct tm * timeinfo ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
WriteServ ( user - > fd , " 391 %s %s :%s " , user - > nick , ServerName , asctime ( timeinfo ) ) ;
}
void handle_whois ( char * * parameters , int pcnt , userrec * user )
{
userrec * dest ;
char * t ;
if ( loop_call ( handle_whois , parameters , pcnt , user , 0 , pcnt - 1 , 0 ) )
return ;
dest = Find ( parameters [ 0 ] ) ;
if ( dest )
{
WriteServ ( user - > fd , " 311 %s %s %s %s * :%s " , user - > nick , dest - > nick , dest - > ident , dest - > dhost , dest - > fullname ) ;
if ( ( user = = dest ) | | ( strchr ( user - > modes , ' o ' ) ) )
{
WriteServ ( user - > fd , " 378 %s %s :is connecting from *@%s " , user - > nick , dest - > nick , dest - > host ) ;
}
if ( strcmp ( chlist ( dest ) , " " ) )
{
WriteServ ( user - > fd , " 319 %s %s :%s " , user - > nick , dest - > nick , chlist ( dest ) ) ;
}
WriteServ ( user - > fd , " 312 %s %s %s :%s " , user - > nick , dest - > nick , dest - > server , ServerDesc ) ;
if ( strcmp ( dest - > awaymsg , " " ) )
{
WriteServ ( user - > fd , " 301 %s %s :%s " , user - > nick , dest - > nick , dest - > awaymsg ) ;
}
if ( strchr ( dest - > modes , ' o ' ) )
{
WriteServ ( user - > fd , " 313 %s %s :is an IRC operator " , user - > nick , dest - > nick ) ;
}
//WriteServ(user->fd,"310 %s %s :is available for help.",user->nick, dest->nick);
WriteServ ( user - > fd , " 317 %s %s %d %d :seconds idle, signon time " , user - > nick , dest - > nick , abs ( ( dest - > idle_lastmsg ) - time ( NULL ) ) , dest - > signon ) ;
WriteServ ( user - > fd , " 318 %s %s :End of /WHOIS list. " , user - > nick , dest - > nick ) ;
}
else
{
/* no such nick/channel */
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
void handle_quit ( char * * parameters , int pcnt , userrec * user )
{
user_hash : : iterator iter = clientlist . find ( user - > nick ) ;
/* theres more to do here, but for now just close the socket */
if ( pcnt = = 1 )
{
if ( parameters [ 0 ] [ 0 ] = = ' : ' )
{
* parameters [ 0 ] + + ;
}
Write ( user - > fd , " ERROR :Closing link (%s@%s) [%s] " , user - > ident , user - > host , parameters [ 0 ] ) ;
WriteOpers ( " *** Client exiting: %s!%s@%s [%s] " , user - > nick , user - > ident , user - > host , parameters [ 0 ] ) ;
WriteCommonExcept ( user , " QUIT :%s%s " , PrefixQuit , parameters [ 0 ] ) ;
}
else
{
Write ( user - > fd , " ERROR :Closing link (%s@%s) [QUIT] " , user - > ident , user - > host ) ;
WriteOpers ( " *** Client exiting: %s!%s@%s [Client exited] " , user - > nick , user - > ident , user - > host ) ;
WriteCommonExcept ( user , " QUIT :Client exited " ) ;
}
FOREACH_MOD OnUserQuit ( user ) ;
/* confucious say, he who close nonblocking socket, get nothing! */
Blocking ( user - > fd ) ;
close ( user - > fd ) ;
NonBlocking ( user - > fd ) ;
2003-01-25 20:00:45 +00:00
AddWhoWas ( user ) ;
2003-01-23 19:45:57 +00:00
if ( iter ! = clientlist . end ( ) )
{
debug ( " deleting user hash value " ) ;
delete iter - > second ;
clientlist . erase ( iter ) ;
}
purge_empty_chans ( ) ;
}
void handle_who ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
/* theres more to do here, but for now just close the socket */
if ( pcnt = = 1 )
{
if ( ( ! strcmp ( parameters [ 0 ] , " 0 " ) ) | | ( ! strcmp ( parameters [ 0 ] , " * " ) ) )
{
Ptr = user - > chans [ 0 ] . channel ;
printf ( user - > chans [ 0 ] . channel - > name ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( common_channels ( user , i - > second ) ) & & ( isnick ( i - > second - > nick ) ) )
{
WriteServ ( user - > fd , " 352 %s %s %s %s %s %s Hr@ :0 %s " , user - > nick , Ptr - > name , i - > second - > ident , i - > second - > dhost , ServerName , i - > second - > nick , i - > second - > fullname ) ;
}
}
WriteServ ( user - > fd , " 315 %s %s :End of /WHO list. " , user - > nick , Ptr - > name ) ;
return ;
}
if ( parameters [ 0 ] [ 0 ] = ' # ' )
{
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( has_channel ( i - > second , Ptr ) ) & & ( isnick ( i - > second - > nick ) ) )
{
WriteServ ( user - > fd , " 352 %s %s %s %s %s %s Hr@ :0 %s " , user - > nick , Ptr - > name , i - > second - > ident , i - > second - > dhost , ServerName , i - > second - > nick , i - > second - > fullname ) ;
}
}
WriteServ ( user - > fd , " 315 %s %s :End of /WHO list. " , user - > nick , Ptr - > name ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
}
if ( pcnt = = 2 )
{
if ( ( ! strcmp ( parameters [ 0 ] , " 0 " ) ) | | ( ! strcmp ( parameters [ 0 ] , " * " ) ) & & ( ! strcmp ( parameters [ 1 ] , " o " ) ) )
{
Ptr = user - > chans [ 0 ] . channel ;
printf ( user - > chans [ 0 ] . channel - > name ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( common_channels ( user , i - > second ) ) & & ( isnick ( i - > second - > nick ) ) )
{
if ( strchr ( i - > second - > modes , ' o ' ) )
{
WriteServ ( user - > fd , " 352 %s %s %s %s %s %s Hr@ :0 %s " , user - > nick , Ptr - > name , i - > second - > ident , i - > second - > dhost , ServerName , i - > second - > nick , i - > second - > fullname ) ;
}
}
}
WriteServ ( user - > fd , " 315 %s %s :End of /WHO list. " , user - > nick , Ptr - > name ) ;
return ;
}
}
}
void handle_wallops ( char * * parameters , int pcnt , userrec * user )
{
WriteWallOps ( user , " %s " , parameters [ 0 ] ) ;
}
void handle_list ( char * * parameters , int pcnt , userrec * user )
{
chanrec * Ptr ;
WriteServ ( user - > fd , " 321 %s Channel :Users Name " , user - > nick ) ;
for ( chan_hash : : const_iterator i = chanlist . begin ( ) ; i ! = chanlist . end ( ) ; i + + )
{
if ( ( ! i - > second - > c_private ) & & ( ! i - > second - > secret ) )
{
WriteServ ( user - > fd , " 322 %s %s %d :[+%s] %s " , user - > nick , i - > second - > name , usercount_i ( i - > second ) , chanmodes ( i - > second ) , i - > second - > topic ) ;
}
}
WriteServ ( user - > fd , " 323 %s :End of channel list. " , user - > nick ) ;
}
void handle_rehash ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 382 %s %s :Rehashing " , user - > nick , CONFIG_FILE ) ;
ReadConfig ( ) ;
WriteOpers ( " %s is rehashing config file %s " , user - > nick , CONFIG_FILE ) ;
}
int usercnt ( void )
{
return clientlist . size ( ) ;
}
int usercount_invisible ( void )
{
int c = 0 ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( i - > second - > fd ) & & ( isnick ( i - > second - > nick ) ) & & ( strchr ( i - > second - > modes , ' i ' ) ) ) c + + ;
}
return c ;
}
int usercount_opers ( void )
{
int c = 0 ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( i - > second - > fd ) & & ( isnick ( i - > second - > nick ) ) & & ( strchr ( i - > second - > modes , ' o ' ) ) ) c + + ;
}
return c ;
}
int usercount_unknown ( void )
{
int c = 0 ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( ( i - > second - > fd ) & & ( i - > second - > registered ! = 7 ) )
c + + ;
}
return c ;
}
int chancount ( void )
{
return chanlist . size ( ) ;
}
int servercount ( void )
{
return 1 ;
}
void handle_lusers ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 251 %s :There are %d users and %d invisible on %d servers " , user - > nick , usercnt ( ) - usercount_invisible ( ) , usercount_invisible ( ) , servercount ( ) ) ;
WriteServ ( user - > fd , " 252 %s %d :operator(s) online " , user - > nick , usercount_opers ( ) ) ;
WriteServ ( user - > fd , " 253 %s %d :unknown connections " , user - > nick , usercount_unknown ( ) ) ;
WriteServ ( user - > fd , " 254 %s %d :channels formed " , user - > nick , chancount ( ) ) ;
WriteServ ( user - > fd , " 254 %s :I have %d clients and 0 servers " , user - > nick , usercnt ( ) ) ;
}
void handle_admin ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 256 %s :Administrative info for %s " , user - > nick , ServerName ) ;
WriteServ ( user - > fd , " 257 %s :Name - %s " , user - > nick , AdminName ) ;
WriteServ ( user - > fd , " 258 %s :Nickname - %s " , user - > nick , AdminNick ) ;
WriteServ ( user - > fd , " 258 %s :E-Mail - %s " , user - > nick , AdminEmail ) ;
}
void ShowMOTD ( userrec * user )
{
if ( ! MOTD . size ( ) )
{
WriteServ ( user - > fd , " 422 %s :Message of the day file is missing. " , user - > nick ) ;
return ;
}
WriteServ ( user - > fd , " 375 %s :- %s message of the day " , user - > nick , ServerName ) ;
for ( int i = 0 ; i ! = MOTD . size ( ) ; i + + )
{
WriteServ ( user - > fd , " 372 %s :- %s " , user - > nick , MOTD [ i ] . c_str ( ) ) ;
}
WriteServ ( user - > fd , " 376 %s :End of %s message of the day. " , user - > nick , ServerName ) ;
}
void ShowRULES ( userrec * user )
{
if ( ! RULES . size ( ) )
{
WriteServ ( user - > fd , " NOTICE %s :Rules file is missing. " , user - > nick ) ;
return ;
}
WriteServ ( user - > fd , " NOTICE %s :%s rules " , user - > nick , ServerName ) ;
for ( int i = 0 ; i ! = RULES . size ( ) ; i + + )
{
WriteServ ( user - > fd , " NOTICE %s :%s " , user - > nick , RULES [ i ] . c_str ( ) ) ;
}
WriteServ ( user - > fd , " NOTICE %s :End of %s rules. " , user - > nick , ServerName ) ;
}
/* shows the message of the day, and any other on-logon stuff */
void ConnectUser ( userrec * user )
{
user - > registered = 7 ;
user - > idle_lastmsg = time ( NULL ) ;
debug ( " ConnectUser: %s " , user - > nick ) ;
if ( strcmp ( Passwd ( user ) , " " ) & & ( ! user - > haspassed ) )
{
Write ( user - > fd , " ERROR :Closing link: Invalid password " ) ;
fdatasync ( user - > fd ) ;
kill_link ( user , " Invalid password " ) ;
return ;
}
if ( IsDenied ( user ) )
{
Write ( user - > fd , " ERROR :Closing link: Unauthorized connection " ) ;
fdatasync ( user - > fd ) ;
kill_link ( user , " Unauthorised connection " ) ;
}
WriteServ ( user - > fd , " NOTICE Auth :Welcome to \002 %s \002 ! " , Network ) ;
WriteServ ( user - > fd , " 001 %s :Welcome to the %s IRC Network %s!%s@%s " , user - > nick , Network , user - > nick , user - > ident , user - > host ) ;
WriteServ ( user - > fd , " 002 %s :Your host is %s, running version %s " , user - > nick , ServerName , VERSION ) ;
WriteServ ( user - > fd , " 003 %s :This server was created %s %s " , user - > nick , __TIME__ , __DATE__ ) ;
WriteServ ( user - > fd , " 004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN " , user - > nick , ServerName , VERSION ) ;
WriteServ ( user - > fd , " 005 %s :MAP KNOCK SAFELIST HCN MAXCHANNELS=20 MAXBANS=60 NICKLEN=30 TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 :are supported by this server " , user - > nick ) ;
WriteServ ( user - > fd , " 005 %s :WALLCHOPS WATCH=128 SILENCE=5 MODES=13 CHANTYPES=# PREFIX=(ohv)@%c+ CHANMODES=ohvbeqa,kfL,l,psmntirRcOAQKVHGCuzN NETWORK=%s :are supported by this server " , user - > nick , ' % ' , Network ) ;
ShowMOTD ( user ) ;
FOREACH_MOD OnUserConnect ( user ) ;
WriteOpers ( " *** Client connecting on port %d: %s!%s@%s " , user - > port , user - > nick , user - > ident , user - > host ) ;
}
void handle_version ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " 351 %s :%s %s :%s " , user - > nick , VERSION , ServerName , SYSTEM ) ;
}
void handle_ping ( char * * parameters , int pcnt , userrec * user )
{
WriteServ ( user - > fd , " PONG %s :%s " , ServerName , parameters [ 0 ] ) ;
}
void handle_pong ( char * * parameters , int pcnt , userrec * user )
{
// set the user as alive so they survive to next ping
user - > lastping = 1 ;
}
void handle_motd ( char * * parameters , int pcnt , userrec * user )
{
ShowMOTD ( user ) ;
}
void handle_rules ( char * * parameters , int pcnt , userrec * user )
{
ShowRULES ( user ) ;
}
void handle_user ( char * * parameters , int pcnt , userrec * user )
{
if ( user - > registered < 3 )
{
WriteServ ( user - > fd , " NOTICE Auth :No ident response, ident prefixed with ~ " ) ;
strcpy ( user - > ident , " ~ " ) ; /* we arent checking ident... but these days why bother anyway? */
strncat ( user - > ident , parameters [ 0 ] , IDENTMAX ) ;
strncpy ( user - > fullname , parameters [ 3 ] , 128 ) ;
user - > registered = ( user - > registered | 1 ) ;
}
else
{
WriteServ ( user - > fd , " 462 %s :You may not reregister " , user - > nick ) ;
return ;
}
/* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
if ( user - > registered = = 3 )
{
/* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
ConnectUser ( user ) ;
}
}
void handle_userhost ( char * * parameters , int pcnt , userrec * user )
{
char Return [ MAXBUF ] , junk [ MAXBUF ] ;
sprintf ( Return , " 302 %s : " , user - > nick ) ;
for ( int i = 0 ; i < pcnt ; i + + )
{
userrec * u = Find ( parameters [ i ] ) ;
if ( u )
{
if ( strchr ( u - > modes , ' o ' ) )
{
sprintf ( junk , " %s*=+%s@%s " , u - > nick , u - > ident , u - > host ) ;
strcat ( Return , junk ) ;
}
else
{
sprintf ( junk , " %s=+%s@%s " , u - > nick , u - > ident , u - > host ) ;
strcat ( Return , junk ) ;
}
}
}
WriteServ ( user - > fd , Return ) ;
}
void handle_ison ( char * * parameters , int pcnt , userrec * user )
{
char Return [ MAXBUF ] ;
sprintf ( Return , " 303 %s : " , user - > nick ) ;
for ( int i = 0 ; i < pcnt ; i + + )
{
userrec * u = Find ( parameters [ i ] ) ;
if ( u )
{
strcat ( Return , u - > nick ) ;
strcat ( Return , " " ) ;
}
}
WriteServ ( user - > fd , Return ) ;
}
void handle_away ( char * * parameters , int pcnt , userrec * user )
{
if ( pcnt )
{
strcpy ( user - > awaymsg , parameters [ 0 ] ) ;
WriteServ ( user - > fd , " 306 %s :You have been marked as being away " , user - > nick ) ;
}
else
{
strcpy ( user - > awaymsg , " " ) ;
WriteServ ( user - > fd , " 305 %s :You are no longer marked as being away " , user - > nick ) ;
}
}
2003-01-25 20:00:45 +00:00
void handle_whowas ( char * * parameters , int pcnt , userrec * user )
{
user_hash : : iterator i = whowas . find ( parameters [ 0 ] ) ;
if ( i = = whowas . end ( ) )
{
WriteServ ( user - > fd , " 406 %s %s :There was no such nickname " , user - > nick , parameters [ 0 ] ) ;
WriteServ ( user - > fd , " 369 %s %s :End of WHOWAS " , user - > nick , parameters [ 0 ] ) ;
}
else
{
time_t rawtime = i - > second - > signon ;
tm * timeinfo ;
char b [ MAXBUF ] ;
timeinfo = localtime ( & rawtime ) ;
strcpy ( b , asctime ( timeinfo ) ) ;
b [ strlen ( b ) - 1 ] = ' \0 ' ;
WriteServ ( user - > fd , " 314 %s %s %s %s * :%s " , user - > nick , i - > second - > nick , i - > second - > ident , i - > second - > dhost , i - > second - > fullname ) ;
WriteServ ( user - > fd , " 312 %s %s %s :%s " , user - > nick , i - > second - > nick , i - > second - > server , b ) ;
WriteServ ( user - > fd , " 369 %s %s :End of WHOWAS " , user - > nick , parameters [ 0 ] ) ;
}
}
2003-01-23 19:45:57 +00:00
void handle_trace ( char * * parameters , int pcnt , userrec * user )
{
for ( user_hash : : iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( i - > second )
{
if ( isnick ( i - > second - > nick ) )
{
if ( strchr ( i - > second - > modes , ' o ' ) )
{
WriteServ ( user - > fd , " 205 %s :Oper 0 %s " , user - > nick , i - > second - > nick ) ;
}
else
{
WriteServ ( user - > fd , " 204 %s :User 0 %s " , user - > nick , i - > second - > nick ) ;
}
}
else
{
WriteServ ( user - > fd , " 203 %s :???? 0 [%s] " , user - > nick , i - > second - > host ) ;
}
}
}
}
void handle_stats ( char * * parameters , int pcnt , userrec * user )
{
if ( pcnt ! = 1 )
{
return ;
}
if ( strlen ( parameters [ 0 ] ) > 1 )
{
/* make the stats query 1 character long */
parameters [ 0 ] [ 1 ] = ' \0 ' ;
}
/* stats m (list number of times each command has been used, plus bytecount) */
if ( ! strcasecmp ( parameters [ 0 ] , " m " ) )
{
for ( int i = 0 ; i < cmdlist . size ( ) ; i + + )
{
if ( cmdlist [ i ] . handler_function )
{
if ( cmdlist [ i ] . use_count )
{
/* RPL_STATSCOMMANDS */
WriteServ ( user - > fd , " 212 %s %s %d %d " , user - > nick , cmdlist [ i ] . command , cmdlist [ i ] . use_count , cmdlist [ i ] . total_bytes ) ;
}
}
}
}
/* stats z (debug and memory info) */
if ( ! strcasecmp ( parameters [ 0 ] , " z " ) )
{
WriteServ ( user - > fd , " 249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets) " , user - > nick , clientlist . size ( ) , clientlist . size ( ) * sizeof ( userrec ) , clientlist . bucket_count ( ) ) ;
WriteServ ( user - > fd , " 249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets) " , user - > nick , chanlist . size ( ) , chanlist . size ( ) * sizeof ( chanrec ) , chanlist . bucket_count ( ) ) ;
WriteServ ( user - > fd , " 249 %s :Commands(VECTOR) %d (%d bytes) " , user - > nick , cmdlist . size ( ) , cmdlist . size ( ) * sizeof ( command_t ) ) ;
WriteServ ( user - > fd , " 249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d " , user - > nick , MOTD . size ( ) , RULES . size ( ) ) ;
WriteServ ( user - > fd , " 249 %s :address_cache(HASH_MAP) %d (%d buckets) " , user - > nick , IP . size ( ) , IP . bucket_count ( ) ) ;
WriteServ ( user - > fd , " 249 %s :Modules(VECTOR) %d (%d) " , user - > nick , modules . size ( ) , modules . size ( ) * sizeof ( Module ) ) ;
WriteServ ( user - > fd , " 249 %s :ClassFactories(VECTOR) %d (%d) " , user - > nick , factory . size ( ) , factory . size ( ) * sizeof ( ircd_module ) ) ;
WriteServ ( user - > fd , " 249 %s :Ports(STATIC_ARRAY) %d " , user - > nick , boundPortCount ) ;
}
/* stats o */
if ( ! strcasecmp ( parameters [ 0 ] , " o " ) )
{
for ( int i = 0 ; i < ConfValueEnum ( " oper " ) ; i + + )
{
char LoginName [ MAXBUF ] ;
char HostName [ MAXBUF ] ;
char OperType [ MAXBUF ] ;
ConfValue ( " oper " , " name " , i , LoginName ) ;
ConfValue ( " oper " , " host " , i , HostName ) ;
ConfValue ( " oper " , " type " , i , OperType ) ;
WriteServ ( user - > fd , " 243 %s O %s * %s %s 0 " , user - > nick , HostName , LoginName , OperType ) ;
}
}
/* stats l (show user I/O stats) */
if ( ! strcasecmp ( parameters [ 0 ] , " l " ) )
{
WriteServ ( user - > fd , " 211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out " , user - > nick ) ;
for ( user_hash : : iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
if ( isnick ( i - > second - > nick ) )
{
WriteServ ( user - > fd , " 211 %s :%s:%d %s %d %d %d %d " , user - > nick , ServerName , i - > second - > port , i - > second - > nick , i - > second - > bytes_in , i - > second - > cmds_in , i - > second - > bytes_out , i - > second - > cmds_out ) ;
}
else
{
WriteServ ( user - > fd , " 211 %s :%s:%d (unknown@%d) %d %d %d %d " , user - > nick , ServerName , i - > second - > port , i - > second - > fd , i - > second - > bytes_in , i - > second - > cmds_in , i - > second - > bytes_out , i - > second - > cmds_out ) ;
}
}
}
/* stats u (show server uptime) */
if ( ! strcasecmp ( parameters [ 0 ] , " u " ) )
{
time_t current_time = 0 ;
current_time = time ( NULL ) ;
time_t server_uptime = current_time - startup_time ;
struct tm * stime ;
stime = gmtime ( & server_uptime ) ;
/* i dont know who the hell would have an ircd running for over a year nonstop, but
* Craig suggested this , and it seemed a good idea so in it went */
if ( stime - > tm_year > 70 )
{
WriteServ ( user - > fd , " 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d " , user - > nick , ( stime - > tm_year - 70 ) , stime - > tm_yday , stime - > tm_hour , stime - > tm_min , stime - > tm_sec ) ;
}
else
{
WriteServ ( user - > fd , " 242 %s :Server up %d days, %.2d:%.2d:%.2d " , user - > nick , stime - > tm_yday , stime - > tm_hour , stime - > tm_min , stime - > tm_sec ) ;
}
}
WriteServ ( user - > fd , " 219 %s %s :End of /STATS report " , user - > nick , parameters [ 0 ] ) ;
WriteOpers ( " *** Notice: Stats '%s' requested by %s (%s@%s) " , parameters [ 0 ] , user - > nick , user - > ident , user - > host ) ;
}
void handle_oper ( char * * parameters , int pcnt , userrec * user )
{
char LoginName [ MAXBUF ] ;
char Password [ MAXBUF ] ;
char OperType [ MAXBUF ] ;
char TypeName [ MAXBUF ] ;
char Hostname [ MAXBUF ] ;
int i , j ;
for ( i = 0 ; i < ConfValueEnum ( " oper " ) ; i + + )
{
ConfValue ( " oper " , " name " , i , LoginName ) ;
ConfValue ( " oper " , " password " , i , Password ) ;
if ( ( ! strcmp ( LoginName , parameters [ 0 ] ) ) & & ( ! strcmp ( Password , parameters [ 1 ] ) ) )
{
/* correct oper credentials */
ConfValue ( " oper " , " type " , i , OperType ) ;
WriteOpers ( " *** %s (%s@%s) is now an IRC operator of type %s " , user - > nick , user - > ident , user - > host , OperType ) ;
WriteServ ( user - > fd , " 381 %s :You are now an IRC operator of type %s " , user - > nick , OperType ) ;
WriteServ ( user - > fd , " MODE %s :+o " , user - > nick ) ;
for ( j = 0 ; j < ConfValueEnum ( " type " ) ; j + + )
{
ConfValue ( " type " , " name " , j , TypeName ) ;
if ( ! strcmp ( TypeName , OperType ) )
{
/* found this oper's opertype */
ConfValue ( " type " , " host " , j , Hostname ) ;
strncpy ( user - > dhost , Hostname , 256 ) ;
}
}
if ( ! strchr ( user - > modes , ' o ' ) )
{
strcat ( user - > modes , " o " ) ;
}
return ;
}
}
/* no such oper */
WriteServ ( user - > fd , " 491 %s :Invalid oper credentials " , user - > nick ) ;
WriteOpers ( " *** WARNING! Failed oper attempt by %s!%s@%s! " , user - > nick , user - > ident , user - > host ) ;
}
void handle_nick ( char * * parameters , int pcnt , userrec * user )
{
if ( pcnt < 1 )
{
debug ( " not enough params for handle_nick " ) ;
return ;
}
if ( ! parameters [ 0 ] )
{
debug ( " invalid parameter passed to handle_nick " ) ;
return ;
}
if ( ! strlen ( parameters [ 0 ] ) )
{
debug ( " zero length new nick passed to handle_nick " ) ;
return ;
}
if ( ! user )
{
debug ( " invalid user passed to handle_nick " ) ;
return ;
}
if ( ! user - > nick )
{
debug ( " invalid old nick passed to handle_nick " ) ;
return ;
}
if ( ! strcasecmp ( user - > nick , parameters [ 0 ] ) )
{
debug ( " old nick is new nick, skipping " ) ;
return ;
}
else
{
if ( strlen ( parameters [ 0 ] ) > 1 )
{
if ( parameters [ 0 ] [ 0 ] = = ' : ' )
{
* parameters [ 0 ] + + ;
}
}
if ( ( Find ( parameters [ 0 ] ) ) & & ( Find ( parameters [ 0 ] ) ! = user ) )
{
WriteServ ( user - > fd , " 433 %s %s :Nickname is already in use. " , user - > nick , parameters [ 0 ] ) ;
return ;
}
}
if ( isnick ( parameters [ 0 ] ) = = 0 )
{
WriteServ ( user - > fd , " 432 %s %s :Erroneous Nickname " , user - > nick , parameters [ 0 ] ) ;
return ;
}
if ( user - > registered = = 7 )
{
WriteCommon ( user , " NICK %s " , parameters [ 0 ] ) ;
}
/* change the nick of the user in the users_hash */
user = ReHashNick ( user - > nick , parameters [ 0 ] ) ;
/* actually change the nick within the record */
if ( ! user ) return ;
if ( ! user - > nick ) return ;
strncpy ( user - > nick , parameters [ 0 ] , NICKMAX ) ;
debug ( " new nick set: %s " , user - > nick ) ;
if ( user - > registered < 3 )
user - > registered = ( user - > registered | 2 ) ;
if ( user - > registered = = 3 )
{
/* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
ConnectUser ( user ) ;
}
debug ( " exit nickchange: %s " , user - > nick ) ;
}
int process_parameters ( char * * command_p , char * parameters )
{
int i = 0 ;
int j = 0 ;
int q = 0 ;
q = strlen ( parameters ) ;
if ( ! q )
{
/* no parameters, command_p invalid! */
return 0 ;
}
if ( parameters [ 0 ] = = ' : ' )
{
command_p [ 0 ] = parameters + 1 ;
return 1 ;
}
if ( q )
{
if ( ( strchr ( parameters , ' ' ) = = NULL ) | | ( parameters [ 0 ] = = ' : ' ) )
{
/* only one parameter */
command_p [ 0 ] = parameters ;
if ( parameters [ 0 ] = = ' : ' )
{
if ( strchr ( parameters , ' ' ) ! = NULL )
{
command_p [ 0 ] + + ;
}
}
return 1 ;
}
}
command_p [ j + + ] = parameters ;
for ( i = 0 ; i < = q ; i + + )
{
if ( parameters [ i ] = = ' ' )
{
command_p [ j + + ] = parameters + i + 1 ;
parameters [ i ] = ' \0 ' ;
if ( command_p [ j - 1 ] [ 0 ] = = ' : ' )
{
* command_p [ j - 1 ] + + ; /* remove dodgy ":" */
break ;
/* parameter like this marks end of the sequence */
}
}
}
return j ; /* returns total number of items in the list */
}
void process_command ( userrec * user , char * cmd )
{
char * parameters ;
char * command ;
char * command_p [ 127 ] ;
char p [ MAXBUF ] , temp [ MAXBUF ] ;
int i , j , items , cmd_found ;
for ( int i = 0 ; i < 127 ; i + + )
command_p [ i ] = NULL ;
if ( ! user )
{
return ;
}
if ( ! cmd )
{
return ;
}
if ( ! strcmp ( cmd , " " ) )
{
return ;
}
strcpy ( temp , cmd ) ;
if ( ! strchr ( cmd , ' ' ) )
{
/* no parameters, lets skip the formalities and not chop up
* the string */
items = 0 ;
command_p [ 0 ] = NULL ;
parameters = NULL ;
for ( int i = 0 ; i < = strlen ( cmd ) ; i + + )
{
cmd [ i ] = toupper ( cmd [ i ] ) ;
}
}
else
{
strcpy ( cmd , " " ) ;
j = 0 ;
/* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
for ( i = 0 ; i < strlen ( temp ) ; i + + )
{
if ( ( temp [ i ] ! = 10 ) & & ( temp [ i ] ! = 13 ) & & ( temp [ i ] ! = 0 ) & & ( temp [ i ] ! = 7 ) )
{
cmd [ j + + ] = temp [ i ] ;
cmd [ j ] = 0 ;
}
}
/* split the full string into a command plus parameters */
parameters = p ;
strcpy ( p , " " ) ;
command = cmd ;
if ( strchr ( cmd , ' ' ) )
{
for ( i = 0 ; i < = strlen ( cmd ) ; i + + )
{
/* capitalise the command ONLY, leave params intact */
cmd [ i ] = toupper ( cmd [ i ] ) ;
/* are we nearly there yet?! :P */
if ( cmd [ i ] = = ' ' )
{
command = cmd ;
parameters = cmd + i + 1 ;
cmd [ i ] = ' \0 ' ;
break ;
}
}
}
else
{
for ( i = 0 ; i < = strlen ( cmd ) ; i + + )
{
cmd [ i ] = toupper ( cmd [ i ] ) ;
}
}
}
cmd_found = 0 ;
for ( i = 0 ; i ! = cmdlist . size ( ) ; i + + )
{
if ( strcmp ( cmdlist [ i ] . command , " " ) )
{
if ( ! strcmp ( command , cmdlist [ i ] . command ) )
{
if ( parameters )
{
if ( strcmp ( parameters , " " ) )
{
items = process_parameters ( command_p , parameters ) ;
}
else
{
items = 0 ;
command_p [ 0 ] = NULL ;
}
}
else
{
items = 0 ;
command_p [ 0 ] = NULL ;
}
if ( user )
{
user - > idle_lastmsg = time ( NULL ) ;
/* activity resets the ping pending timer */
user - > nping = time ( NULL ) + 120 ;
if ( ( items ) < cmdlist [ i ] . min_params )
{
debug ( " process_command: not enough parameters: %s %s " , user - > nick , command ) ;
WriteServ ( user - > fd , " 461 %s %s :Not enough parameters " , user - > nick , command ) ;
return ;
}
if ( ( ! strchr ( user - > modes , cmdlist [ i ] . flags_needed ) ) & & ( cmdlist [ i ] . flags_needed ) )
{
debug ( " process_command: permission denied: %s %s " , user - > nick , command ) ;
WriteServ ( user - > fd , " 481 %s :Permission Denied- You do not have the required operator privilages " , user - > nick ) ;
cmd_found = 1 ;
return ;
}
/* if the command isnt USER, PASS, or NICK, and nick is empty,
* deny command ! */
if ( ( strcmp ( command , " USER " ) ) & & ( strcmp ( command , " NICK " ) ) & & ( strcmp ( command , " PASS " ) ) )
{
if ( ( ! isnick ( user - > nick ) ) | | ( user - > registered ! = 7 ) )
{
debug ( " process_command: not registered: %s %s " , user - > nick , command ) ;
WriteServ ( user - > fd , " 451 %s :You have not registered " , command ) ;
return ;
}
}
if ( ( user - > registered = = 7 ) | | ( ! strcmp ( command , " USER " ) ) | | ( ! strcmp ( command , " NICK " ) ) | | ( ! strcmp ( command , " PASS " ) ) )
{
debug ( " process_command: handler: %s %s %d " , user - > nick , command , items ) ;
if ( cmdlist [ i ] . handler_function )
{
/* ikky /stats counters */
if ( temp )
{
if ( user )
{
user - > bytes_in + = strlen ( temp ) ;
user - > cmds_in + + ;
}
cmdlist [ i ] . use_count + + ;
cmdlist [ i ] . total_bytes + = strlen ( temp ) ;
}
/* WARNING: nothing may come after the
* command handler call , as the handler
* may free the user structure ! */
cmdlist [ i ] . handler_function ( command_p , items , user ) ;
}
return ;
}
else
{
debug ( " process_command: not registered: %s %s " , user - > nick , command ) ;
WriteServ ( user - > fd , " 451 %s :You have not registered " , command ) ;
return ;
}
}
cmd_found = 1 ;
}
}
}
if ( ( ! cmd_found ) & & ( user ) )
{
debug ( " process_command: not in table: %s %s " , user - > nick , command ) ;
WriteServ ( user - > fd , " 421 %s %s :Unknown command " , user - > nick , command ) ;
}
}
void createcommand ( char * cmd , handlerfunc f , char flags , int minparams )
{
command_t comm ;
/* create the command and push it onto the table */
strcpy ( comm . command , cmd ) ;
comm . handler_function = f ;
comm . flags_needed = flags ;
comm . min_params = minparams ;
comm . use_count = 0 ;
comm . total_bytes = 0 ;
cmdlist . push_back ( comm ) ;
}
void SetupCommandTable ( void )
{
createcommand ( " USER " , handle_user , 0 , 4 ) ;
createcommand ( " NICK " , handle_nick , 0 , 1 ) ;
createcommand ( " QUIT " , handle_quit , 0 , 1 ) ;
createcommand ( " VERSION " , handle_version , 0 , 0 ) ;
createcommand ( " PING " , handle_ping , 0 , 1 ) ;
createcommand ( " PONG " , handle_pong , 0 , 1 ) ;
createcommand ( " ADMIN " , handle_admin , 0 , 0 ) ;
createcommand ( " PRIVMSG " , handle_privmsg , 0 , 2 ) ;
createcommand ( " INFO " , handle_info , 0 , 0 ) ;
createcommand ( " TIME " , handle_time , 0 , 0 ) ;
createcommand ( " WHOIS " , handle_whois , 0 , 1 ) ;
createcommand ( " WALLOPS " , handle_wallops , ' o ' , 1 ) ;
createcommand ( " NOTICE " , handle_notice , 0 , 2 ) ;
createcommand ( " JOIN " , handle_join , 0 , 1 ) ;
createcommand ( " NAMES " , handle_names , 0 , 1 ) ;
createcommand ( " PART " , handle_part , 0 , 1 ) ;
createcommand ( " KICK " , handle_kick , 0 , 2 ) ;
createcommand ( " MODE " , handle_mode , 0 , 1 ) ;
createcommand ( " TOPIC " , handle_topic , 0 , 1 ) ;
createcommand ( " WHO " , handle_who , 0 , 1 ) ;
createcommand ( " MOTD " , handle_motd , 0 , 0 ) ;
createcommand ( " RULES " , handle_join , 0 , 0 ) ;
createcommand ( " OPER " , handle_oper , 0 , 2 ) ;
createcommand ( " LIST " , handle_list , 0 , 0 ) ;
createcommand ( " DIE " , handle_die , ' o ' , 1 ) ;
createcommand ( " RESTART " , handle_restart , ' o ' , 1 ) ;
createcommand ( " KILL " , handle_kill , ' o ' , 2 ) ;
createcommand ( " REHASH " , handle_rehash , ' o ' , 0 ) ;
createcommand ( " LUSERS " , handle_lusers , 0 , 0 ) ;
createcommand ( " STATS " , handle_stats , 0 , 1 ) ;
createcommand ( " USERHOST " , handle_userhost , 0 , 1 ) ;
createcommand ( " AWAY " , handle_away , 0 , 0 ) ;
createcommand ( " ISON " , handle_ison , 0 , 0 ) ;
createcommand ( " SUMMON " , handle_summon , 0 , 0 ) ;
createcommand ( " USERS " , handle_users , 0 , 0 ) ;
createcommand ( " INVITE " , handle_invite , 0 , 2 ) ;
createcommand ( " PASS " , handle_pass , 0 , 1 ) ;
createcommand ( " TRACE " , handle_trace , ' o ' , 0 ) ;
2003-01-25 20:00:45 +00:00
createcommand ( " WHOWAS " , handle_whowas , 0 , 1 ) ;
2003-01-23 19:45:57 +00:00
}
void process_buffer ( userrec * user )
{
char cmd [ MAXBUF ] ;
int i ;
if ( ! user - > inbuf )
{
return ;
}
if ( ! strcmp ( user - > inbuf , " " ) )
{
return ;
}
strncpy ( cmd , user - > inbuf , MAXBUF ) ;
if ( ! strcmp ( cmd , " " ) )
{
return ;
}
if ( ( cmd [ strlen ( cmd ) - 1 ] = = 13 ) | | ( cmd [ strlen ( cmd ) - 1 ] = = 10 ) )
{
cmd [ strlen ( cmd ) - 1 ] = ' \0 ' ;
}
if ( ( cmd [ strlen ( cmd ) - 1 ] = = 13 ) | | ( cmd [ strlen ( cmd ) - 1 ] = = 10 ) )
{
cmd [ strlen ( cmd ) - 1 ] = ' \0 ' ;
}
strcpy ( user - > inbuf , " " ) ;
if ( ! strcmp ( cmd , " " ) )
{
return ;
}
debug ( " InspIRCd: processing: %s %s " , user - > nick , cmd ) ;
process_command ( user , cmd ) ;
}
int InspIRCd ( void )
{
struct sockaddr_in client , server ;
int portCount = 0 , ports [ MAXSOCKS ] ;
char addrs [ MAXBUF ] [ 255 ] ;
int openSockfd [ MAXSOCKS ] , incomingSockfd , result = TRUE ;
socklen_t length ;
int count = 0 , scanDetectTrigger = TRUE , showBanner = FALSE ;
int selectResult = 0 ;
char * temp , configToken [ MAXBUF ] , stuff [ MAXBUF ] , Addr [ MAXBUF ] ;
char resolvedHost [ MAXBUF ] ;
fd_set selectFds ;
struct timeval tv ;
int count2 ;
debug ( " InspIRCd: startup: begin " ) ;
debug ( " $Id$ " ) ;
if ( ( geteuid ( ) ) & & ( getuid ( ) ) = = 0 )
{
printf ( " WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!! \n \n " ) ;
Exit ( ERROR ) ;
debug ( " InspIRCd: startup: not starting with UID 0! " ) ;
}
SetupCommandTable ( ) ;
debug ( " InspIRCd: startup: default command table set up " ) ;
ReadConfig ( ) ;
if ( strcmp ( DieValue , " " ) )
{
printf ( " WARNING: %s \n \n " , DieValue ) ;
exit ( 0 ) ;
}
debug ( " InspIRCd: startup: read config " ) ;
for ( count = 0 ; count < ConfValueEnum ( " bind " ) ; count + + )
{
ConfValue ( " bind " , " port " , count , configToken ) ;
ConfValue ( " bind " , " address " , count , Addr ) ;
ports [ count ] = atoi ( configToken ) ;
strcpy ( addrs [ count ] , Addr ) ;
debug ( " InspIRCd: startup: read binding %s:%d from config " , addrs [ count ] , ports [ count ] ) ;
}
portCount = ConfValueEnum ( " bind " ) ;
debug ( " InspIRCd: startup: read %d total ports " , portCount ) ;
debug ( " InspIRCd: startup: InspIRCd is now running! " ) ;
printf ( " \n " ) ;
for ( count = 0 ; count < ConfValueEnum ( " module " ) ; count + + )
{
char modfile [ MAXBUF ] ;
ConfValue ( " module " , " name " , count , configToken ) ;
sprintf ( modfile , " %s/%s " , MOD_PATH , configToken ) ;
printf ( " Loading module... \033 [1;37m%s \033 [0;37m \n " , modfile ) ;
debug ( " InspIRCd: startup: Loading module: %s " , modfile ) ;
factory [ count ] = new ircd_module ( modfile ) ;
if ( factory [ count ] - > LastError ( ) )
{
debug ( " Unable to load %s: %s " , modfile , factory [ count ] - > LastError ( ) ) ;
sprintf ( " Unable to load %s: %s \n Exiting... \n " , modfile , factory [ count ] - > LastError ( ) ) ;
Exit ( ERROR ) ;
}
if ( factory [ count ] - > factory )
{
modules [ count ] = factory [ count ] - > factory - > CreateModule ( ) ;
/* save the module and the module's classfactory, if
* this isnt done , random crashes can occur : / */
}
else
{
debug ( " Unable to load %s " , modfile ) ;
sprintf ( " Unable to load %s \n Exiting... \n " , modfile ) ;
Exit ( ERROR ) ;
}
}
MODCOUNT = count - 1 ;
debug ( " Total loaded modules: %d " , MODCOUNT + 1 ) ;
printf ( " \n InspIRCd is now running! \n " ) ;
startup_time = time ( NULL ) ;
if ( DaemonSeed ( ) = = ERROR )
{
debug ( " InspIRCd: startup: can't daemonise " ) ;
printf ( " ERROR: could not go into daemon mode. Shutting down. \n " ) ;
Exit ( ERROR ) ;
}
/* setup select call */
FD_ZERO ( & selectFds ) ;
debug ( " InspIRCd: startup: zero selects " ) ;
for ( count = 0 ; count < portCount ; count + + )
{
if ( ( openSockfd [ boundPortCount ] = OpenTCPSocket ( ) ) = = ERROR )
{
debug ( " InspIRCd: startup: bad fd %d " , openSockfd [ boundPortCount ] ) ;
return ( ERROR ) ;
}
if ( BindSocket ( openSockfd [ boundPortCount ] , client , server , ports [ count ] , addrs [ count ] ) = = ERROR )
{
debug ( " InspIRCd: startup: failed to bind port %d " , ports [ count ] ) ;
}
else /* well we at least bound to one socket so we'll continue */
{
boundPortCount + + ;
}
}
debug ( " InspIRCd: startup: total bound ports %d " , boundPortCount ) ;
/* if we didn't bind to anything then abort */
if ( boundPortCount = = 0 )
{
debug ( " InspIRCd: startup: no ports bound, bailing! " ) ;
return ( ERROR ) ;
}
length = sizeof ( client ) ;
int flip_flop = 0 ;
/* main loop for multiplexing/resetting */
for ( ; ; )
{
/* set up select call */
for ( count = 0 ; count < boundPortCount ; count + + )
{
FD_SET ( openSockfd [ count ] , & selectFds ) ;
}
/* added timeout! select was waiting forever... wank... :/ */
tv . tv_usec = 0 ;
flip_flop + + ;
if ( flip_flop > 20 )
{
tv . tv_usec = 1 ;
flip_flop = 0 ;
}
tv . tv_sec = 0 ;
selectResult = select ( MAXSOCKS , & selectFds , NULL , NULL , & tv ) ;
for ( user_hash : : iterator count2 = clientlist . begin ( ) ; count2 ! = clientlist . end ( ) ; count2 + + )
{
char data [ MAXBUF ] ;
if ( ! count2 - > second ) break ;
if ( count2 - > second )
if ( count2 - > second - > fd )
{
if ( ( ( time ( NULL ) ) > count2 - > second - > nping ) & & ( isnick ( count2 - > second - > nick ) ) & & ( count2 - > second - > registered = = 7 ) )
{
if ( ! count2 - > second - > lastping )
{
debug ( " InspIRCd: ping timeout: %s " , count2 - > second - > nick ) ;
kill_link ( count2 - > second , " Ping timeout " ) ;
break ;
}
Write ( count2 - > second - > fd , " PING :%s " , ServerName ) ;
debug ( " InspIRCd: pinging: %s " , count2 - > second - > nick ) ;
count2 - > second - > lastping = 0 ;
count2 - > second - > nping = time ( NULL ) + 120 ;
}
result = read ( count2 - > second - > fd , data , 1 ) ;
// result EAGAIN means nothing read
if ( result = = EAGAIN )
{
}
else
if ( result = = 0 )
{
debug ( " InspIRCd: Exited: %s " , count2 - > second - > nick ) ;
kill_link ( count2 - > second , " Client exited " ) ;
}
else if ( result > 0 )
{
strncat ( count2 - > second - > inbuf , data , result ) ;
if ( strchr ( count2 - > second - > inbuf , ' \n ' ) | | strchr ( count2 - > second - > inbuf , ' \r ' ) )
{
/* at least one complete line is waiting to be processed */
if ( ! count2 - > second - > fd )
break ;
else
{
process_buffer ( count2 - > second ) ;
break ;
}
}
}
}
}
/* select is reporting a waiting socket. Poll them all to find out which */
if ( selectResult > 0 )
{
char target [ MAXBUF ] , resolved [ MAXBUF ] ;
for ( count = 0 ; count < boundPortCount ; count + + )
{
if ( FD_ISSET ( openSockfd [ count ] , & selectFds ) )
{
incomingSockfd = accept ( openSockfd [ count ] , ( struct sockaddr * ) & client , & length ) ;
address_cache : : iterator iter = IP . find ( client . sin_addr ) ;
bool iscached = false ;
if ( iter = = IP . end ( ) )
{
/* ip isn't in cache, add it */
strncpy ( target , ( char * ) inet_ntoa ( client . sin_addr ) , MAXBUF ) ;
if ( CleanAndResolve ( resolved , target ) ! = TRUE )
{
strncpy ( resolved , target , MAXBUF ) ;
}
/* hostname now in 'target' */
IP [ client . sin_addr ] = new string ( resolved ) ;
/* hostname in cache */
}
else
{
/* found ip (cached) */
strncpy ( resolved , iter - > second - > c_str ( ) , MAXBUF ) ;
iscached = true ;
}
if ( incomingSockfd < 0 )
{
WriteOpers ( " *** WARNING: Accept failed on port %d (%s) " , ports [ count ] , target ) ;
debug ( " InspIRCd: accept failed: %d " , ports [ count ] ) ;
break ;
}
AddClient ( incomingSockfd , resolved , ports [ count ] , iscached ) ;
debug ( " InspIRCd: adding client on port %d fd=%d " , ports [ count ] , incomingSockfd ) ;
break ;
}
}
}
}
/* not reached */
close ( incomingSockfd ) ;
}