2003-01-23 19:45:57 +00:00
/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*
2004-04-04 13:41:01 +00:00
* Inspire is copyright ( C ) 2002 - 2004 ChatSpike - Dev .
2003-01-23 19:45:57 +00:00
* 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 .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/* Now with added unF! ;) */
2004-04-07 13:22:17 +00:00
using namespace std ;
2003-01-23 19:45:57 +00:00
# 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>
2003-09-27 18:58:37 +00:00
# ifdef GCC3
2003-08-17 22:34:59 +00:00
# include <ext/hash_map>
2003-09-27 18:58:37 +00:00
# else
# include <hash_map>
# endif
2003-07-22 21:56:38 +00:00
# include <map>
2003-01-23 19:45:57 +00:00
# include <sstream>
# include <vector>
# include <errno.h>
# include <deque>
2003-01-26 23:53:03 +00:00
# include "connection.h"
2003-01-23 19:45:57 +00:00
# include "users.h"
2003-01-26 20:15:03 +00:00
# include "servers.h"
2003-01-23 19:45:57 +00:00
# include "ctables.h"
# include "globals.h"
# include "modules.h"
# include "dynamic.h"
# include "wildcard.h"
2003-09-27 18:58:37 +00:00
# ifdef GCC3
# define nspace __gnu_cxx
# else
# define nspace std
# endif
2003-02-07 21:15:27 +00:00
int LogLevel = DEFAULT ;
2003-01-23 19:45:57 +00:00
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 ;
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 ) ;
2003-02-07 21:15:27 +00:00
extern vector < Module * > modules ;
2004-04-04 00:58:20 +00:00
vector < string > module_names ;
2003-02-07 21:15:27 +00:00
extern vector < ircd_module * > factory ;
2004-04-02 12:38:41 +00:00
vector < int > fd_reap ;
2003-02-07 21:15:27 +00:00
extern int MODCOUNT ;
2004-04-03 00:33:52 +00:00
bool nofork = false ;
2003-09-27 18:58:37 +00:00
namespace nspace
2003-01-23 19:45:57 +00:00
{
2003-09-27 18:58:37 +00:00
template < > struct nspace : : hash < in_addr >
2003-01-23 19:45:57 +00:00
{
2003-07-22 21:56:38 +00:00
size_t operator ( ) ( const struct in_addr & a ) const
{
size_t q ;
memcpy ( & q , & a , sizeof ( size_t ) ) ;
return q ;
}
} ;
2003-01-23 19:45:57 +00:00
2003-09-27 18:58:37 +00:00
template < > struct nspace : : hash < string >
2003-01-23 19:45:57 +00:00
{
2003-07-22 21:56:38 +00:00
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 ) ;
}
} ;
}
2003-01-23 19:45:57 +00:00
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 ) ;
}
} ;
2003-09-27 18:58:37 +00:00
typedef nspace : : hash_map < std : : string , userrec * , nspace : : hash < string > , StrHashComp > user_hash ;
typedef nspace : : hash_map < std : : string , chanrec * , nspace : : hash < string > , StrHashComp > chan_hash ;
typedef nspace : : hash_map < in_addr , string * , nspace : : hash < in_addr > , InAddr_HashComp > address_cache ;
2003-07-22 21:56:38 +00:00
typedef std : : deque < command_t > command_table ;
2003-01-23 19:45:57 +00:00
2003-02-07 21:15:27 +00:00
serverrec * me [ 32 ] ;
2004-04-01 20:21:06 +00:00
serverrec * servers [ 255 ] ;
2003-02-02 16:43:53 +00:00
2004-04-03 22:34:38 +00:00
FILE * log_file ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
2003-01-23 19:45:57 +00:00
ClassVector Classes ;
struct linger linger = { 0 } ;
char bannerBuffer [ MAXBUF ] ;
int boundPortCount = 0 ;
2003-02-07 21:15:27 +00:00
int portCount = 0 , UDPportCount = 0 , ports [ MAXSOCKS ] ;
int defaultRoute = 0 ;
2003-01-23 19:45:57 +00:00
2004-04-01 20:21:06 +00:00
connection C ;
long MyKey = C . GenKey ( ) ;
2003-01-23 19:45:57 +00:00
/* 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
2004-04-07 13:22:17 +00:00
std : : stringstream config_f ( stringstream : : in | stringstream : : out ) ;
2003-01-23 19:45:57 +00:00
void safedelete ( userrec * p )
{
if ( p )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " deleting %s %s %s %s " , p - > nick , p - > ident , p - > dhost , p - > fullname ) ;
log ( DEBUG , " safedelete(userrec*): pointer is safe to delete " ) ;
2003-01-23 19:45:57 +00:00
delete p ;
}
else
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " safedelete(userrec*): unsafe pointer operation squished " ) ;
2003-01-23 19:45:57 +00:00
}
}
void safedelete ( chanrec * p )
{
if ( p )
{
delete p ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " safedelete(chanrec*): pointer is safe to delete " ) ;
2003-01-23 19:45:57 +00:00
}
else
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " safedelete(chanrec*): unsafe pointer operation squished " ) ;
2003-01-23 19:45:57 +00:00
}
}
2004-04-03 17:24:37 +00:00
void tidystring ( char * str )
{
// strips out double spaces before a : parameter
2004-04-03 20:35:20 +00:00
2004-04-03 17:24:37 +00:00
char temp [ MAXBUF ] ;
bool go_again = true ;
2004-04-03 20:35:20 +00:00
if ( ! str )
{
return ;
}
while ( ( str [ 0 ] = = ' ' ) & & ( strlen ( str ) > 0 ) )
{
str + + ;
}
2004-04-03 17:24:37 +00:00
while ( go_again )
{
bool noparse = false ;
int t = 0 , a = 0 ;
go_again = false ;
while ( a < strlen ( str ) )
{
if ( ( a < strlen ( str ) - 1 ) & & ( noparse = = false ) )
{
if ( ( str [ a ] = = ' ' ) & & ( str [ a + 1 ] = = ' ' ) )
{
log ( DEBUG , " Tidied extra space out of string: %s " , str ) ;
go_again = true ;
a + + ;
}
}
if ( a < strlen ( str ) - 1 )
{
if ( ( str [ a ] = = ' ' ) & & ( str [ a + 1 ] = = ' : ' ) )
{
noparse = true ;
}
}
temp [ t + + ] = str [ a + + ] ;
}
temp [ t ] = ' \0 ' ;
strncpy ( str , temp , MAXBUF ) ;
}
}
2003-01-23 19:45:57 +00:00
/* chop a string down to 512 characters and preserve linefeed (irc max
* line length ) */
void chop ( char * str )
{
2003-03-30 12:33:15 +00:00
string temp = str ;
FOREACH_MOD OnServerRaw ( temp , false ) ;
const char * str2 = temp . c_str ( ) ;
sprintf ( str , " %s " , str2 ) ;
2004-04-03 20:35:20 +00:00
if ( strlen ( str ) > = 512 )
2003-03-30 12:33:15 +00:00
{
2004-04-03 20:35:20 +00:00
str [ 509 ] = ' \r ' ;
str [ 510 ] = ' \n ' ;
str [ 511 ] = ' \0 ' ;
2003-03-30 12:33:15 +00:00
}
2003-01-23 19:45:57 +00:00
}
2003-07-22 21:56:38 +00:00
std : : string getservername ( )
2003-01-23 19:45:57 +00:00
{
return ServerName ;
}
2003-07-22 21:56:38 +00:00
std : : string getserverdesc ( )
2003-02-02 16:43:53 +00:00
{
return ServerDesc ;
}
2003-07-22 21:56:38 +00:00
std : : string getnetworkname ( )
2003-01-23 19:45:57 +00:00
{
return Network ;
}
2003-07-22 21:56:38 +00:00
std : : string getadminname ( )
2003-01-23 19:45:57 +00:00
{
return AdminName ;
}
2003-07-22 21:56:38 +00:00
std : : string getadminemail ( )
2003-01-23 19:45:57 +00:00
{
return AdminEmail ;
}
2003-07-22 21:56:38 +00:00
std : : string getadminnick ( )
2003-01-23 19:45:57 +00:00
{
return AdminNick ;
}
2003-02-07 21:15:27 +00:00
void log ( int level , char * text , . . . )
2003-01-23 19:45:57 +00:00
{
2003-07-22 21:56:38 +00:00
char textbuffer [ MAXBUF ] ;
va_list argsPtr ;
time_t rawtime ;
struct tm * timeinfo ;
if ( level < LogLevel )
return ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
2004-04-03 22:34:38 +00:00
if ( log_file )
2003-07-22 21:56:38 +00:00
{
char b [ MAXBUF ] ;
va_start ( argsPtr , text ) ;
vsnprintf ( textbuffer , MAXBUF , text , argsPtr ) ;
va_end ( argsPtr ) ;
strcpy ( b , asctime ( timeinfo ) ) ;
b [ strlen ( b ) - 1 ] = ' : ' ;
2004-04-03 22:34:38 +00:00
fprintf ( log_file , " %s %s \n " , b , textbuffer ) ;
2004-04-03 00:33:52 +00:00
if ( nofork )
{
// nofork enabled? display it on terminal too
printf ( " %s %s \n " , b , textbuffer ) ;
}
2003-07-22 21:56:38 +00:00
}
2003-01-23 19:45:57 +00:00
}
void readfile ( file_cache & F , const char * fname )
{
FILE * file ;
char linebuf [ MAXBUF ] ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " readfile: loading %s " , fname ) ;
2003-01-23 19:45:57 +00:00
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
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " readfile: failed to load file: %s " , fname ) ;
2003-01-23 19:45:57 +00:00
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " readfile: loaded %s, %d lines " , fname , F . size ( ) ) ;
2003-01-23 19:45:57 +00:00
}
void ReadConfig ( void )
{
2004-04-05 09:57:15 +00:00
char dbg [ MAXBUF ] , pauseval [ MAXBUF ] , Value [ MAXBUF ] , timeout [ MAXBUF ] ;
2003-01-23 19:45:57 +00:00
ConnectClass c ;
2004-04-07 13:22:17 +00:00
LoadConf ( CONFIG_FILE , & config_f ) ;
ConfValue ( " server " , " name " , 0 , ServerName , & config_f ) ;
ConfValue ( " server " , " description " , 0 , ServerDesc , & config_f ) ;
ConfValue ( " server " , " network " , 0 , Network , & config_f ) ;
ConfValue ( " admin " , " name " , 0 , AdminName , & config_f ) ;
ConfValue ( " admin " , " email " , 0 , AdminEmail , & config_f ) ;
ConfValue ( " admin " , " nick " , 0 , AdminNick , & config_f ) ;
ConfValue ( " files " , " motd " , 0 , motd , & config_f ) ;
ConfValue ( " files " , " rules " , 0 , rules , & config_f ) ;
ConfValue ( " power " , " diepass " , 0 , diepass , & config_f ) ;
ConfValue ( " power " , " pause " , 0 , pauseval , & config_f ) ;
ConfValue ( " power " , " restartpass " , 0 , restartpass , & config_f ) ;
ConfValue ( " options " , " prefixquit " , 0 , PrefixQuit , & config_f ) ;
ConfValue ( " die " , " value " , 0 , DieValue , & config_f ) ;
ConfValue ( " options " , " loglevel " , 0 , dbg , & config_f ) ;
2003-02-07 21:15:27 +00:00
if ( ! strcmp ( dbg , " debug " ) )
LogLevel = DEBUG ;
if ( ! strcmp ( dbg , " verbose " ) )
LogLevel = VERBOSE ;
if ( ! strcmp ( dbg , " default " ) )
LogLevel = DEFAULT ;
if ( ! strcmp ( dbg , " sparse " ) )
LogLevel = SPARSE ;
if ( ! strcmp ( dbg , " none " ) )
LogLevel = NONE ;
2004-04-04 23:01:37 +00:00
readfile ( MOTD , motd ) ;
log ( DEBUG , " Reading message of the day " ) ;
2003-01-23 19:45:57 +00:00
readfile ( RULES , rules ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " Reading connect classes " ) ;
2003-01-23 19:45:57 +00:00
Classes . clear ( ) ;
2004-04-07 13:22:17 +00:00
for ( int i = 0 ; i < ConfValueEnum ( " connect " , & config_f ) ; i + + )
2003-01-23 19:45:57 +00:00
{
strcpy ( Value , " " ) ;
2004-04-07 13:22:17 +00:00
ConfValue ( " connect " , " allow " , i , Value , & config_f ) ;
ConfValue ( " connect " , " timeout " , i , timeout , & config_f ) ;
2003-01-23 19:45:57 +00:00
if ( strcmp ( Value , " " ) )
{
strcpy ( c . host , Value ) ;
c . type = CC_ALLOW ;
strcpy ( Value , " " ) ;
2004-04-07 13:22:17 +00:00
ConfValue ( " connect " , " password " , i , Value , & config_f ) ;
2003-01-23 19:45:57 +00:00
strcpy ( c . pass , Value ) ;
2004-04-05 09:57:15 +00:00
c . registration_timeout = 90 ; // default is 2 minutes
if ( atoi ( timeout ) > 0 )
{
c . registration_timeout = atoi ( timeout ) ;
}
2003-01-23 19:45:57 +00:00
Classes . push_back ( c ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " Read connect class type ALLOW, host=%s password=%s " , c . host , c . pass ) ;
2003-01-23 19:45:57 +00:00
}
else
{
2004-04-07 13:22:17 +00:00
ConfValue ( " connect " , " deny " , i , Value , & config_f ) ;
2003-01-23 19:45:57 +00:00
strcpy ( c . host , Value ) ;
c . type = CC_DENY ;
Classes . push_back ( c ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " Read connect class type DENY, host=%s " , c . host ) ;
2003-01-23 19:45:57 +00:00
}
}
}
void Blocking ( int s )
{
int flags ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " Blocking: %d " , s ) ;
2003-01-23 19:45:57 +00:00
flags = fcntl ( s , F_GETFL , 0 ) ;
fcntl ( s , F_SETFL , flags ^ O_NONBLOCK ) ;
}
void NonBlocking ( int s )
{
int flags ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " NonBlocking: %d " , s ) ;
2003-01-23 19:45:57 +00:00
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ! text )
{
log ( DEFAULT , " *** BUG *** Write was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ! text )
{
log ( DEFAULT , " *** BUG *** WriteServ was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! text ) | | ( ! user ) )
{
log ( DEFAULT , " *** BUG *** WriteFrom was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! source ) | | ( ! dest ) | | ( ! data ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** WriteTo was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
2004-04-03 20:35:20 +00:00
char textbuffer [ MAXBUF ] , tb [ MAXBUF ] ;
va_list argsPtr ;
va_start ( argsPtr , data ) ;
2003-01-23 19:45:57 +00:00
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! Ptr ) | | ( ! user ) | | ( ! text ) )
{
log ( DEFAULT , " *** BUG *** WriteChannel was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 ) ;
}
}
}
2004-04-02 13:45:36 +00:00
void WriteChannelWithServ ( char * ServerName , chanrec * Ptr , userrec * user , char * text , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! Ptr ) | | ( ! user ) | | ( ! text ) )
{
log ( DEFAULT , " *** BUG *** WriteChannelWithServ was given an invalid parameter " ) ;
return ;
}
2004-04-02 13:45:36 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2004-04-02 13:45:36 +00:00
{
2004-04-03 20:35:20 +00:00
if ( has_channel ( i - > second , Ptr ) )
{
WriteServ ( i - > second - > fd , " %s " , textbuffer ) ;
}
2004-04-02 13:45:36 +00:00
}
}
}
2003-01-23 19:45:57 +00:00
/* 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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! Ptr ) | | ( ! user ) | | ( ! text ) )
{
log ( DEFAULT , " *** BUG *** ChanExceptSender was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( has_channel ( i - > second , Ptr ) & & ( user ! = i - > second ) )
{
WriteTo ( user , i - > second , " %s " , textbuffer ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
int c_count ( userrec * u )
{
int z = 0 ;
for ( int i = 0 ; i ! = MAXCHANS ; i + + )
2004-04-03 20:35:20 +00:00
if ( u - > chans [ i ] . channel ! = NULL )
2003-01-23 19:45:57 +00:00
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 ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** common_channels was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
return 0 ;
}
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
for ( z = 0 ; z ! = MAXCHANS ; z + + )
{
2004-04-03 20:35:20 +00:00
if ( ( u - > chans [ i ] . channel ! = NULL ) & & ( u2 - > chans [ z ] . channel ! = NULL ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( ( u - > chans [ i ] . channel = = u2 - > chans [ z ] . channel ) & & ( u - > chans [ i ] . channel ) & & ( u2 - > chans [ z ] . channel ) & & ( u - > registered = = 7 ) & & ( u2 - > registered = = 7 ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( ( c_count ( u ) ) & & ( c_count ( u2 ) ) )
{
return 1 ;
}
2003-01-23 19:45:57 +00:00
}
}
}
}
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 , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ! u )
{
log ( DEFAULT , " *** BUG *** WriteCommon was given an invalid parameter " ) ;
return ;
}
if ( u - > registered ! = 7 ) {
log ( DEFAULT , " *** BUG *** WriteCommon on an unregistered user " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( common_channels ( u , i - > second ) & & ( i - > second ! = u ) )
{
WriteFrom ( i - > second - > fd , u , " %s " , textbuffer ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
/* write a formatted string to all users who share at least one common
* channel , NOT including the source user e . g . for use in QUIT */
void WriteCommonExcept ( userrec * u , char * text , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ! u )
{
log ( DEFAULT , " *** BUG *** WriteCommon was given an invalid parameter " ) ;
return ;
}
if ( u - > registered ! = 7 ) {
log ( DEFAULT , " *** BUG *** WriteCommon on an unregistered user " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( ( common_channels ( u , i - > second ) ) & & ( u ! = i - > second ) )
{
WriteFrom ( i - > second - > fd , u , " %s " , textbuffer ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
void WriteOpers ( char * text , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ! text )
{
log ( DEFAULT , " *** BUG *** WriteOpers was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( strchr ( i - > second - > modes , ' o ' ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
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 ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
}
2004-04-05 16:06:32 +00:00
bool hasumode ( userrec * user , char mode )
{
if ( user )
{
return ( strchr ( user - > modes , mode ) > 0 ) ;
}
else return false ;
}
void WriteMode ( const char * modes , int flags , const char * text , . . . )
{
if ( ( ! text ) | | ( ! modes ) | | ( ! flags ) )
{
log ( DEFAULT , " *** BUG *** WriteMode was given an invalid parameter " ) ;
return ;
}
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 ( i - > second )
{
bool send_to_user = false ;
if ( flags = = WM_AND )
{
send_to_user = true ;
for ( int n = 0 ; n < strlen ( modes ) ; n + + )
{
if ( ! hasumode ( i - > second , modes [ n ] ) )
{
send_to_user = false ;
break ;
}
}
}
else if ( flags = = WM_OR )
{
send_to_user = false ;
for ( int n = 0 ; n < strlen ( modes ) ; n + + )
{
if ( hasumode ( i - > second , modes [ n ] ) )
{
send_to_user = true ;
break ;
}
}
}
if ( send_to_user )
{
WriteServ ( i - > second - > fd , " NOTICE %s :%s " , i - > second - > nick , textbuffer ) ;
}
}
}
}
2003-01-23 19:45:57 +00:00
void WriteWallOps ( userrec * source , char * text , . . . )
{
2004-04-03 20:35:20 +00:00
if ( ( ! text ) | | ( ! source ) )
{
log ( DEFAULT , " *** BUG *** WriteOpers was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 + + )
2004-04-03 20:35:20 +00:00
{
if ( i - > second )
{
if ( strchr ( i - > second - > modes , ' w ' ) )
{
WriteTo ( source , i - > second , " WALLOPS %s " , textbuffer ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
/* 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 ] = ' | ' ;
}
}
2003-07-31 01:00:21 +00:00
/* verify that a user's ident and nickname is valid */
int isident ( const char * n )
{
int i = 0 ;
char v [ MAXBUF ] ;
if ( ! n )
{
return 0 ;
}
if ( ! strcmp ( n , " " ) )
{
return 0 ;
}
for ( i = 0 ; i ! = strlen ( n ) ; i + + )
{
if ( ( n [ i ] < 33 ) | | ( n [ i ] > 125 ) )
{
return 0 ;
}
/* can't occur ANYWHERE in an Ident! */
if ( strchr ( " <>,./?:;@'~#=+()*&%$<24> \" ! " , n [ i ] ) )
{
return 0 ;
}
}
return 1 ;
}
2003-01-23 19:45:57 +00:00
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 + + )
{
2004-04-03 20:35:20 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( i - > second - > fd = = fd )
{
i - > second - > bytes_out + = data_out ;
i - > second - > cmds_out + + ;
}
2003-01-23 19:45:57 +00:00
}
}
}
/* find a channel record by channel name and return a pointer to it */
chanrec * FindChan ( const char * chan )
{
2004-04-03 20:35:20 +00:00
if ( ! chan )
{
log ( DEFAULT , " *** BUG *** Findchan was given an invalid parameter " ) ;
return NULL ;
}
2003-01-23 19:45:57 +00:00
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 ( ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: destroyed: %s " , i - > second - > name ) ;
2003-01-23 19:45:57 +00:00
delete i - > second ;
chanlist . erase ( i ) ;
go_again = 1 ;
purge + + ;
break ;
}
}
2004-04-03 20:35:20 +00:00
else
{
log ( DEBUG , " skipped purge for %s " , i - > second - > name ) ;
}
2003-01-23 19:45:57 +00:00
}
}
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " completed channel purge, killed %d " , purge ) ;
2003-01-23 19:45:57 +00:00
}
/* 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 )
{
2004-04-03 20:35:20 +00:00
if ( ( ! user ) | | ( ! chan ) )
{
log ( DEFAULT , " *** BUG *** cmode was given an invalid parameter " ) ;
return " " ;
}
2003-01-23 19:45:57 +00:00
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 " " ;
}
}
}
2004-04-04 21:30:41 +00:00
char scratch [ MAXBUF ] ;
char sparam [ MAXBUF ] ;
2003-01-23 19:45:57 +00:00
char * chanmodes ( chanrec * chan )
{
2004-04-03 20:35:20 +00:00
if ( ! chan )
{
log ( DEFAULT , " *** BUG *** chanmodes was given an invalid parameter " ) ;
strcpy ( scratch , " " ) ;
return scratch ;
}
2003-01-23 19:45:57 +00:00
strcpy ( scratch , " " ) ;
2004-04-03 15:46:53 +00:00
strcpy ( sparam , " " ) ;
2003-01-23 19:45:57 +00:00
if ( chan - > noexternal )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " n " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > topiclock )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " t " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( strcmp ( chan - > key , " " ) )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " k " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > limit )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " l " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > inviteonly )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " i " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > moderated )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " m " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > secret )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " s " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > c_private )
{
2004-04-04 21:30:41 +00:00
strncat ( scratch , " p " , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
if ( strcmp ( chan - > key , " " ) )
{
2004-04-04 21:30:41 +00:00
strncat ( sparam , chan - > key , MAXBUF ) ;
2003-01-23 19:45:57 +00:00
}
if ( chan - > limit )
{
char foo [ 24 ] ;
sprintf ( foo , " %d " , chan - > limit ) ;
2004-04-04 21:30:41 +00:00
strncat ( sparam , foo , MAXBUF ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-03 15:46:53 +00:00
if ( strlen ( chan - > custom_modes ) )
{
strncat ( scratch , chan - > custom_modes , MAXMODES ) ;
2004-04-04 15:18:34 +00:00
for ( int z = 0 ; z < strlen ( chan - > custom_modes ) ; z + + )
{
std : : string extparam = chan - > GetModeParameter ( chan - > custom_modes [ z ] ) ;
if ( extparam ! = " " )
{
2004-04-04 21:30:41 +00:00
strncat ( sparam , " " , MAXBUF ) ;
strncat ( sparam , extparam . c_str ( ) , MAXBUF ) ;
2004-04-04 15:18:34 +00:00
}
}
2004-04-03 15:46:53 +00:00
}
log ( DEBUG , " chanmodes: %s %s%s " , chan - > name , scratch , sparam ) ;
strncat ( scratch , sparam , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
if ( ( ! chan ) | | ( ! user ) )
{
log ( DEFAULT , " *** BUG *** cstatus was given an invalid parameter " ) ;
return 0 ;
}
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
if ( ( ! c ) | | ( ! user ) )
{
log ( DEFAULT , " *** BUG *** userlist was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 ;
2004-04-03 20:35:20 +00:00
if ( ! c )
{
log ( DEFAULT , " *** BUG *** usercount_i was given an invalid parameter " ) ;
return 0 ;
}
2003-01-23 19:45:57 +00:00
strcpy ( list , " " ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
2004-04-02 12:38:41 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-02 12:38:41 +00:00
if ( has_channel ( i - > second , c ) )
2003-01-23 19:45:57 +00:00
{
2004-04-02 12:38:41 +00:00
if ( isnick ( i - > second - > nick ) )
2003-01-23 19:45:57 +00:00
{
2004-04-02 12:38:41 +00:00
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 + + ;
2003-01-23 19:45:57 +00:00
}
}
}
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " usercount_i: %s %d " , c - > name , count ) ;
2003-01-23 19:45:57 +00:00
return count ;
}
int usercount ( chanrec * c )
{
int i = 0 ;
int count = 0 ;
2004-04-03 20:35:20 +00:00
if ( ! c )
{
log ( DEFAULT , " *** BUG *** usercount was given an invalid parameter " ) ;
return 0 ;
}
2003-01-23 19:45:57 +00:00
strcpy ( list , " " ) ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
2004-04-01 20:21:06 +00:00
if ( i - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-01 20:21:06 +00:00
if ( has_channel ( i - > second , c ) )
2003-01-23 19:45:57 +00:00
{
2004-04-01 20:21:06 +00:00
if ( ( isnick ( i - > second - > nick ) ) & & ( i - > second - > registered = = 7 ) )
{
count + + ;
}
2003-01-23 19:45:57 +00:00
}
}
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " usercount: %s %d " , c - > name , count ) ;
2003-01-23 19:45:57 +00:00
return count ;
}
/* add a channel to a user, creating the record for it if needed and linking
* it to the user record */
2004-04-06 10:43:34 +00:00
chanrec * add_channel ( userrec * user , const char * cn , const char * key )
2003-01-23 19:45:57 +00:00
{
2004-04-06 10:43:34 +00:00
if ( ( ! user ) | | ( ! cn ) )
2004-04-03 20:35:20 +00:00
{
log ( DEFAULT , " *** BUG *** add_channel was given an invalid parameter " ) ;
return 0 ;
}
2003-01-23 19:45:57 +00:00
int i = 0 ;
chanrec * Ptr ;
int created = 0 ;
2004-04-06 10:43:34 +00:00
char cname [ MAXBUF ] ;
strncpy ( cname , cn , MAXBUF ) ;
2004-04-03 15:46:53 +00:00
// we MUST declare this wherever we use FOREACH_RESULT
int MOD_RESULT = 0 ;
2003-01-23 19:45:57 +00:00
if ( ( ! cname ) | | ( ! user ) )
{
return NULL ;
}
if ( strlen ( cname ) > CHANMAX - 1 )
{
cname [ CHANMAX - 1 ] = ' \0 ' ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: %s %s " , user - > nick , cname ) ;
2003-01-23 19:45:57 +00:00
2004-04-04 13:41:01 +00:00
if ( ( FindChan ( cname ) ) & & ( has_channel ( user , FindChan ( cname ) ) ) )
2003-01-23 19:45:57 +00:00
{
return NULL ; // already on the channel!
}
2004-04-03 15:46:53 +00:00
2003-01-23 19:45:57 +00:00
if ( ! FindChan ( cname ) )
{
2004-04-03 15:46:53 +00:00
FOREACH_RESULT ( OnUserPreJoin ( user , NULL , cname ) ) ;
if ( MOD_RESULT ) {
return NULL ;
}
2003-01-23 19:45:57 +00:00
/* create a new one */
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: creating: %s " , cname ) ;
2003-01-23 19:45:57 +00:00
{
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 ] ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: created: %s " , cname ) ;
2003-01-23 19:45:57 +00:00
/* 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 )
{
2004-04-03 15:46:53 +00:00
FOREACH_RESULT ( OnUserPreJoin ( user , Ptr , cname ) ) ;
if ( MOD_RESULT ) {
return NULL ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: joining to: %s " , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
if ( strcmp ( Ptr - > key , " " ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: %s has key %s " , Ptr - > name , Ptr - > key ) ;
2003-01-23 19:45:57 +00:00
if ( ! key )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: no key given in JOIN " ) ;
2003-01-23 19:45:57 +00:00
WriteServ ( user - > fd , " 475 %s %s :Cannot join channel (Requires key) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
else
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " key at %p is %s " , key , key ) ;
2003-01-23 19:45:57 +00:00
if ( strcasecmp ( key , Ptr - > key ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: bad key given in JOIN " ) ;
2003-01-23 19:45:57 +00:00
WriteServ ( user - > fd , " 475 %s %s :Cannot join channel (Incorrect key) " , user - > nick , Ptr - > name ) ;
return NULL ;
}
}
}
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: no key " ) ;
2003-01-23 19:45:57 +00:00
if ( Ptr - > inviteonly )
{
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: channel is +i " ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
}
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: channel is not +i " ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
}
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: about to walk banlist " ) ;
2003-01-23 19:45:57 +00:00
/* 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 ;
}
}
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: bans checked " ) ;
2003-01-23 19:45:57 +00:00
user - > RemoveInvite ( Ptr - > name ) ;
2004-04-01 20:21:06 +00:00
log ( DEBUG , " add_channel: invites removed " ) ;
2003-01-23 19:45:57 +00:00
}
created = 1 ;
}
2004-04-01 20:21:06 +00:00
log ( DEBUG , " Passed channel checks " ) ;
2003-01-23 19:45:57 +00:00
for ( i = 0 ; i ! = MAXCHANS ; i + + )
{
if ( user - > chans [ i ] . channel = = NULL )
{
2004-04-01 20:21:06 +00:00
log ( DEBUG , " Adding into their channel list " ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2004-04-01 20:21:06 +00:00
log ( DEBUG , " Sent JOIN to client " ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_channel: user channel max exceeded: %s %s " , user - > nick , cname ) ;
2003-01-23 19:45:57 +00:00
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 */
2004-04-06 10:43:34 +00:00
chanrec * del_channel ( userrec * user , const char * cname , const char * reason )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( ( ! user ) | | ( ! cname ) )
{
log ( DEFAULT , " *** BUG *** del_channel was given an invalid parameter " ) ;
return NULL ;
}
2003-01-23 19:45:57 +00:00
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 ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: removing: %s %s " , user - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: unlinked: %s %s " , user - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
break ;
}
}
/* if there are no users left on the channel */
if ( ! usercount ( Ptr ) )
{
chan_hash : : iterator iter = chanlist . find ( Ptr - > name ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: destroying channel: %s " , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
/* kill the record */
if ( iter ! = chanlist . end ( ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: destroyed: %s " , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
delete iter - > second ;
chanlist . erase ( iter ) ;
}
}
}
void kick_channel ( userrec * src , userrec * user , chanrec * Ptr , char * reason )
{
2004-04-03 20:35:20 +00:00
if ( ( ! src ) | | ( ! user ) | | ( ! Ptr ) | | ( ! reason ) )
{
log ( DEFAULT , " *** BUG *** kick_channel was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
int i = 0 ;
int created = 0 ;
if ( ( ! Ptr ) | | ( ! user ) | | ( ! src ) )
{
return ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " kick_channel: removing: %s %s %s " , user - > nick , Ptr - > name , src - > nick ) ;
2003-01-23 19:45:57 +00:00
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
{
2004-04-05 20:10:43 +00:00
WriteServ ( src - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , src - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
}
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: unlinked: %s %s " , user - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
break ;
}
}
/* if there are no users left on the channel */
if ( ! usercount ( Ptr ) )
{
chan_hash : : iterator iter = chanlist . find ( Ptr - > name ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: destroying channel: %s " , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
/* kill the record */
if ( iter ! = chanlist . end ( ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_channel: destroyed: %s " , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
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 ;
2004-04-03 20:35:20 +00:00
if ( ( ! u ) | | ( ! c ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** has_channel was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** give_ops was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " gave ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
int give_hops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** give_hops was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " gave h-ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
int give_voice ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** give_voice was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
return 0 ;
}
if ( status < STATUS_HOP )
{
2004-04-05 20:10:43 +00:00
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , user - > nick , chan - > name ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " gave voice: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
int take_ops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** take_ops was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " took ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
int take_hops ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** take_hops was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " took h-ops: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
int take_voice ( userrec * user , char * dest , chanrec * chan , int status )
{
userrec * d ;
int i ;
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** take_voice was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
return 0 ;
}
if ( status < STATUS_HOP )
{
2004-04-05 20:10:43 +00:00
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , user - > nick , chan - > name ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " took voice: %s %s " , d - > chans [ i ] . channel - > name , d - > nick ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
return 1 ;
}
void TidyBan ( char * ban )
{
2004-04-03 20:35:20 +00:00
if ( ! ban ) {
log ( DEFAULT , " *** BUG *** TidyBan was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) ) {
log ( DEFAULT , " *** BUG *** add_ban was given an invalid parameter " ) ;
return 0 ;
}
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " add_ban: %s %s " , chan - > name , user - > nick ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
if ( ( ! user ) | | ( ! dest ) | | ( ! chan ) ) {
log ( DEFAULT , " *** BUG *** take_ban was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
return 0 ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " del_ban: %s %s " , chan - > name , user - > nick ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
2004-04-02 13:45:36 +00:00
void process_modes ( char * * parameters , userrec * user , chanrec * chan , int status , int pcnt , bool servermode )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
if ( ( ! parameters ) | | ( ! user ) ) {
log ( DEFAULT , " *** BUG *** process_modes was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_modes: start " ) ;
2003-01-23 19:45:57 +00:00
strcpy ( modelist , parameters [ 1 ] ) ; /* mode list, e.g. +oo-o */
/* parameters[2] onwards are parameters for
* modes that require them : ) */
strcpy ( outlist , " + " ) ;
mdir = 1 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_modes: modelist: %s " , modelist ) ;
2003-01-23 19:45:57 +00:00
for ( ptr = 0 ; ptr < strlen ( modelist ) ; ptr + + )
{
r = 0 ;
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_modes: modechar: %c " , modelist [ ptr ] ) ;
2003-07-22 21:56:38 +00:00
char modechar = modelist [ ptr ] ;
2003-01-23 19:45:57 +00:00
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 ;
2004-04-04 13:41:01 +00:00
2003-01-23 19:45:57 +00:00
case ' k ' :
if ( ( param > = pcnt ) )
break ;
if ( mdir = = 1 )
{
if ( k_set )
break ;
if ( ! strcmp ( chan - > key , " " ) )
{
strcat ( outlist , " k " ) ;
2004-04-04 13:41:01 +00:00
char key [ MAXBUF ] ;
strcpy ( key , parameters [ param + + ] ) ;
if ( strlen ( key ) > 32 ) {
key [ 31 ] = ' \0 ' ;
}
strcpy ( outpars [ pc + + ] , key ) ;
strcpy ( chan - > key , key ) ;
2003-01-23 19:45:57 +00:00
k_set = true ;
}
}
else
{
2004-04-04 13:41:01 +00:00
/* checks on -k are case sensitive and only accurate to the
first 32 characters */
char key [ MAXBUF ] ;
strcpy ( key , parameters [ param + + ] ) ;
if ( strlen ( key ) > 32 ) {
key [ 31 ] = ' \0 ' ;
}
2003-01-23 19:45:57 +00:00
/* only allow -k if correct key given */
2004-04-04 13:41:01 +00:00
if ( ! strcmp ( chan - > key , key ) )
2003-01-23 19:45:57 +00:00
{
strcat ( outlist , " k " ) ;
strcpy ( chan - > key , " " ) ;
2004-04-04 13:41:01 +00:00
strcpy ( outpars [ pc + + ] , key ) ;
2003-01-23 19:45:57 +00:00
}
}
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 ;
2003-04-19 12:41:44 +00:00
default :
2004-04-03 15:46:53 +00:00
log ( DEBUG , " Preprocessing custom mode %c " , modechar ) ;
2003-04-19 12:41:44 +00:00
string_list p ;
p . clear ( ) ;
2004-04-03 15:46:53 +00:00
if ( ( ( ! strchr ( chan - > custom_modes , modechar ) ) & & ( ! mdir ) ) | | ( ( strchr ( chan - > custom_modes , modechar ) ) & & ( mdir ) ) )
{
log ( DEBUG , " Mode %c isnt set on %s but trying to remove! " , modechar , chan - > name ) ;
break ;
}
if ( ModeDefined ( modechar , MT_CHANNEL ) )
2003-04-19 12:41:44 +00:00
{
2004-04-03 15:46:53 +00:00
log ( DEBUG , " A module has claimed this mode " ) ;
2004-04-04 13:41:01 +00:00
if ( param < pcnt )
2003-04-19 12:41:44 +00:00
{
2004-04-04 13:41:01 +00:00
if ( ( ModeDefinedOn ( modechar , MT_CHANNEL ) > 0 ) & & ( mdir ) )
{
p . push_back ( parameters [ param ] ) ;
}
if ( ( ModeDefinedOff ( modechar , MT_CHANNEL ) > 0 ) & & ( ! mdir ) )
{
p . push_back ( parameters [ param ] ) ;
}
2003-04-19 12:41:44 +00:00
}
2004-04-03 15:46:53 +00:00
bool handled = false ;
2004-04-04 13:41:01 +00:00
if ( param > = pcnt )
{
log ( DEBUG , " Not enough parameters for module-mode %c " , modechar ) ;
// we're supposed to have a parameter, but none was given... so dont handle the mode.
if ( ( ( ModeDefinedOn ( modechar , MT_CHANNEL ) > 0 ) & & ( mdir ) ) | | ( ( ModeDefinedOff ( modechar , MT_CHANNEL ) > 0 ) & & ( ! mdir ) ) )
{
handled = true ;
param + + ;
}
}
2004-04-03 15:46:53 +00:00
for ( int i = 0 ; i < = MODCOUNT ; i + + )
2003-07-22 21:56:38 +00:00
{
2004-04-03 15:46:53 +00:00
if ( ! handled )
2003-07-22 21:56:38 +00:00
{
2004-04-03 15:46:53 +00:00
if ( modules [ i ] - > OnExtendedMode ( user , chan , modechar , MT_CHANNEL , mdir , p ) )
2003-07-22 21:56:38 +00:00
{
2004-04-03 15:46:53 +00:00
log ( DEBUG , " OnExtendedMode returned nonzero for a module " ) ;
char app [ ] = { modechar , 0 } ;
if ( ptr > 0 )
{
if ( ( modelist [ ptr - 1 ] = = ' + ' ) | | ( modelist [ ptr - 1 ] = = ' - ' ) )
{
strcat ( outlist , app ) ;
}
else if ( ! strchr ( outlist , modechar ) )
{
strcat ( outlist , app ) ;
}
}
chan - > SetCustomMode ( modechar , mdir ) ;
// include parameters in output if mode has them
2004-04-04 13:41:01 +00:00
if ( ( ModeDefinedOn ( modechar , MT_CHANNEL ) > 0 ) & & ( mdir ) )
2004-04-03 15:46:53 +00:00
{
chan - > SetCustomModeParam ( modelist [ ptr ] , parameters [ param ] , mdir ) ;
strcpy ( outpars [ pc + + ] , parameters [ param + + ] ) ;
}
// break, because only one module can handle the mode.
handled = true ;
}
}
}
2003-04-19 12:41:44 +00:00
}
break ;
2003-01-23 19:45:57 +00:00
}
}
}
/* 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 ] ) ;
}
2004-04-02 13:45:36 +00:00
if ( servermode )
{
WriteChannelWithServ ( ServerName , chan , user , " MODE %s %s " , chan - > name , outstr ) ;
}
else
{
WriteChannel ( chan , user , " MODE %s %s " , chan - > name , outstr ) ;
}
2003-01-23 19:45:57 +00:00
}
}
2004-04-04 21:30:41 +00:00
// based on sourcemodes, return true or false to determine if umode is a valid mode a user may set on themselves or others.
bool allowed_umode ( char umode , char * sourcemodes , bool adding )
{
log ( DEBUG , " Allowed_umode: %c %s " , umode , sourcemodes ) ;
// RFC1459 specified modes
if ( ( umode = = ' w ' ) | | ( umode = = ' s ' ) | | ( umode = = ' i ' ) )
{
log ( DEBUG , " umode %c allowed by RFC1459 scemantics " , umode ) ;
return true ;
}
// user may not +o themselves or others, but an oper may de-oper other opers or themselves
if ( ( strchr ( sourcemodes , ' o ' ) ) & & ( ! adding ) )
{
log ( DEBUG , " umode %c allowed by RFC1459 scemantics " , umode ) ;
return true ;
}
else if ( umode = = ' o ' )
{
log ( DEBUG , " umode %c allowed by RFC1459 scemantics " , umode ) ;
return false ;
}
// process any module-defined modes that need oper
if ( ( ModeDefinedOper ( umode , MT_CLIENT ) ) & & ( strchr ( sourcemodes , ' o ' ) ) )
{
log ( DEBUG , " umode %c allowed by module handler (oper only mode) " , umode ) ;
return true ;
}
else
if ( ModeDefined ( umode , MT_CLIENT ) )
{
// process any module-defined modes that don't need oper
log ( DEBUG , " umode %c allowed by module handler (non-oper mode) " , umode ) ;
if ( ( ModeDefinedOper ( umode , MT_CLIENT ) ) & & ( ! strchr ( sourcemodes , ' o ' ) ) )
{
// no, this mode needs oper, and this user 'aint got what it takes!
return false ;
}
return true ;
}
// anything else - return false.
log ( DEBUG , " umode %c not known by any ruleset " , umode ) ;
return false ;
}
2004-04-05 01:03:26 +00:00
bool process_module_umode ( char umode , userrec * source , void * dest , bool adding )
2004-04-04 21:30:41 +00:00
{
string_list p ;
p . clear ( ) ;
if ( ModeDefined ( umode , MT_CLIENT ) )
{
for ( int i = 0 ; i < = MODCOUNT ; i + + )
{
2004-04-05 01:03:26 +00:00
if ( modules [ i ] - > OnExtendedMode ( source , ( void * ) dest , umode , MT_CLIENT , adding , p ) )
2004-04-04 21:30:41 +00:00
{
log ( DEBUG , " Module claims umode %c " , umode ) ;
return true ;
}
}
log ( DEBUG , " No module claims umode %c " , umode ) ;
return false ;
}
else
{
log ( DEBUG , " *** BUG *** Non-module umode passed to process_module_umode! " ) ;
return false ;
}
}
2003-01-23 19:45:57 +00:00
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 ;
}
2004-04-04 21:30:41 +00:00
2003-01-23 19:45:57 +00:00
if ( ( dest ) & & ( pcnt > 1 ) )
{
2004-04-04 21:30:41 +00:00
char dmodes [ MAXBUF ] ;
strncpy ( dmodes , dest - > modes , MAXBUF ) ;
log ( DEBUG , " pulled up dest user modes: %s " , dmodes ) ;
2003-01-23 19:45:57 +00:00
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
{
2004-04-04 21:30:41 +00:00
if ( ( parameters [ 1 ] [ i ] = = ' i ' ) | | ( parameters [ 1 ] [ i ] = = ' w ' ) | | ( parameters [ 1 ] [ i ] = = ' s ' ) | | ( allowed_umode ( parameters [ 1 ] [ i ] , user - > modes , direction ) ) )
2003-01-23 19:45:57 +00:00
{
can_change = 1 ;
}
}
if ( can_change )
{
if ( direction = = 1 )
{
2004-04-04 21:30:41 +00:00
if ( ( ! strchr ( dmodes , parameters [ 1 ] [ i ] ) ) & & ( allowed_umode ( parameters [ 1 ] [ i ] , user - > modes , true ) ) )
2003-01-23 19:45:57 +00:00
{
2004-04-04 21:30:41 +00:00
char umode = parameters [ 1 ] [ i ] ;
if ( ( process_module_umode ( umode , user , dest , direction ) ) | | ( umode = = ' i ' ) | | ( umode = = ' s ' ) | | ( umode = = ' w ' ) | | ( umode = = ' o ' ) )
{
dmodes [ strlen ( dmodes ) + 1 ] = ' \0 ' ;
dmodes [ strlen ( dmodes ) ] = parameters [ 1 ] [ i ] ;
outpars [ strlen ( outpars ) + 1 ] = ' \0 ' ;
outpars [ strlen ( outpars ) ] = parameters [ 1 ] [ i ] ;
}
2003-01-23 19:45:57 +00:00
}
}
else
{
2004-04-04 21:30:41 +00:00
if ( ( allowed_umode ( parameters [ 1 ] [ i ] , user - > modes , false ) ) & & ( strchr ( dmodes , parameters [ 1 ] [ i ] ) ) )
2003-01-23 19:45:57 +00:00
{
2004-04-04 21:30:41 +00:00
char umode = parameters [ 1 ] [ i ] ;
if ( ( process_module_umode ( umode , user , dest , direction ) ) | | ( umode = = ' i ' ) | | ( umode = = ' s ' ) | | ( umode = = ' w ' ) | | ( umode = = ' o ' ) )
2003-01-23 19:45:57 +00:00
{
2004-04-04 21:30:41 +00:00
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 ( dmodes ) ; q + + )
{
if ( dmodes [ q ] ! = parameters [ 1 ] [ i ] )
{
moo [ 0 ] = dmodes [ q ] ;
moo [ 1 ] = ' \0 ' ;
strcat ( temp , moo ) ;
}
}
strcpy ( dmodes , temp ) ;
2003-01-23 19:45:57 +00:00
}
}
}
}
}
}
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 ) ;
2004-04-04 21:30:41 +00:00
if ( strlen ( dmodes ) > MAXMODES )
{
dmodes [ MAXMODES - 1 ] = ' \0 ' ;
}
log ( DEBUG , " Stripped mode line " ) ;
log ( DEBUG , " Line dest is now %s " , dmodes ) ;
strncpy ( dest - > modes , dmodes , MAXMODES ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-04 21:30:41 +00:00
2003-01-23 19:45:57 +00:00
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 ) )
{
2004-04-05 20:10:43 +00:00
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , user - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
return ;
}
2004-04-02 13:45:36 +00:00
process_modes ( parameters , user , Ptr , cstatus ( user , Ptr ) , pcnt , false ) ;
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
void server_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 ] ) ;
2004-04-04 21:30:41 +00:00
2004-04-04 23:19:13 +00:00
// fix: ChroNiCk found this - we cant use this as debug if its null!
if ( dest )
{
log ( DEBUG , " server_mode on %s " , dest - > nick ) ;
}
2004-04-02 13:45:36 +00:00
if ( ( dest ) & & ( pcnt > 1 ) )
{
2004-04-04 21:30:41 +00:00
log ( DEBUG , " params > 1 " ) ;
char dmodes [ MAXBUF ] ;
strncpy ( dmodes , dest - > modes , MAXBUF ) ;
2004-04-02 13:45:36 +00:00
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
{
2004-04-04 21:30:41 +00:00
log ( DEBUG , " begin mode processing entry " ) ;
can_change = 1 ;
2004-04-02 13:45:36 +00:00
if ( can_change )
{
if ( direction = = 1 )
{
2004-04-04 21:30:41 +00:00
log ( DEBUG , " umode %c being added " , parameters [ 1 ] [ i ] ) ;
if ( ( ! strchr ( dmodes , parameters [ 1 ] [ i ] ) ) & & ( allowed_umode ( parameters [ 1 ] [ i ] , user - > modes , true ) ) )
2004-04-02 13:45:36 +00:00
{
2004-04-04 21:30:41 +00:00
char umode = parameters [ 1 ] [ i ] ;
log ( DEBUG , " umode %c is an allowed umode " , umode ) ;
if ( ( process_module_umode ( umode , user , dest , direction ) ) | | ( umode = = ' i ' ) | | ( umode = = ' s ' ) | | ( umode = = ' w ' ) | | ( umode = = ' o ' ) )
{
dmodes [ strlen ( dmodes ) + 1 ] = ' \0 ' ;
dmodes [ strlen ( dmodes ) ] = parameters [ 1 ] [ i ] ;
outpars [ strlen ( outpars ) + 1 ] = ' \0 ' ;
outpars [ strlen ( outpars ) ] = parameters [ 1 ] [ i ] ;
}
2004-04-02 13:45:36 +00:00
}
}
else
{
2004-04-04 21:30:41 +00:00
// can only remove a mode they already have
log ( DEBUG , " umode %c being removed " , parameters [ 1 ] [ i ] ) ;
if ( ( allowed_umode ( parameters [ 1 ] [ i ] , user - > modes , false ) ) & & ( strchr ( dmodes , parameters [ 1 ] [ i ] ) ) )
2004-04-02 13:45:36 +00:00
{
2004-04-04 21:30:41 +00:00
char umode = parameters [ 1 ] [ i ] ;
log ( DEBUG , " umode %c is an allowed umode " , umode ) ;
if ( ( process_module_umode ( umode , user , dest , direction ) ) | | ( umode = = ' i ' ) | | ( umode = = ' s ' ) | | ( umode = = ' w ' ) | | ( umode = = ' o ' ) )
2004-04-02 13:45:36 +00:00
{
2004-04-04 21:30:41 +00:00
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 ( dmodes ) ; q + + )
{
if ( dmodes [ q ] ! = parameters [ 1 ] [ i ] )
{
moo [ 0 ] = dmodes [ q ] ;
moo [ 1 ] = ' \0 ' ;
strcat ( temp , moo ) ;
}
}
strcpy ( dmodes , temp ) ;
2004-04-02 13:45:36 +00:00
}
}
}
}
}
}
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 ) ;
2004-04-04 21:30:41 +00:00
if ( strlen ( dmodes ) > MAXMODES )
{
dmodes [ MAXMODES - 1 ] = ' \0 ' ;
}
log ( DEBUG , " Stripped mode line " ) ;
log ( DEBUG , " Line dest is now %s " , dmodes ) ;
strncpy ( dest - > modes , dmodes , MAXMODES ) ;
2004-04-02 13:45:36 +00:00
}
2004-04-04 21:30:41 +00:00
2004-04-02 13:45:36 +00:00
return ;
}
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
process_modes ( parameters , user , Ptr , STATUS_OP , pcnt , true ) ;
2003-01-23 19:45:57 +00:00
}
else
{
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
}
}
2004-04-02 13:45:36 +00:00
2003-01-23 19:45:57 +00:00
/* 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 ;
}
2004-04-03 22:34:38 +00:00
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
char reason [ MAXBUF ] ;
strncpy ( reason , parameters [ 2 ] , MAXBUF ) ;
if ( strlen ( reason ) > MAXKICK )
{
reason [ MAXKICK - 1 ] = ' \0 ' ;
}
kick_channel ( user , u , Ptr , reason ) ;
2003-01-23 19:45:57 +00:00
}
else
{
kick_channel ( user , u , Ptr , user - > nick ) ;
}
}
void handle_die ( char * * parameters , int pcnt , userrec * user )
{
2003-07-22 21:56:38 +00:00
log ( DEBUG , " die: %s " , user - > nick ) ;
2003-01-23 19:45:57 +00:00
if ( ! strcmp ( parameters [ 0 ] , diepass ) )
{
WriteOpers ( " *** DIE command from %s!%s@%s, terminating... " , user - > nick , user - > ident , user - > host ) ;
2003-07-22 21:56:38 +00:00
sleep ( DieDelay ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2003-07-22 21:56:38 +00:00
log ( DEBUG , " restart: %s " , user - > nick ) ;
if ( ! strcmp ( parameters [ 0 ] , restartpass ) )
2003-01-23 19:45:57 +00:00
{
2003-07-22 21:56:38 +00:00
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 ) ;
2003-01-23 19:45:57 +00:00
/* Will finish this later when i can be arsed :) */
2003-07-22 21:56:38 +00:00
}
else
2003-01-23 19:45:57 +00:00
{
2003-07-22 21:56:38 +00:00
WriteOpers ( " *** Failed RESTART Command from %s!%s@%s. " , user - > nick , user - > ident , user - > host ) ;
}
2003-01-23 19:45:57 +00:00
}
2004-04-06 10:43:34 +00:00
void kill_link ( userrec * user , const char * r )
2003-01-23 19:45:57 +00:00
{
user_hash : : iterator iter = clientlist . find ( user - > nick ) ;
2004-04-06 10:43:34 +00:00
char reason [ MAXBUF ] ;
strncpy ( reason , r , MAXBUF ) ;
2003-01-23 19:45:57 +00:00
2004-04-03 20:35:20 +00:00
if ( strlen ( reason ) > MAXQUIT )
{
reason [ MAXQUIT - 1 ] = ' \0 ' ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " kill_link: %s '%s' " , user - > nick , reason ) ;
2003-01-23 19:45:57 +00:00
Write ( user - > fd , " ERROR :Closing link (%s@%s) [%s] " , user - > ident , user - > host , reason ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " closing fd %d " , user - > fd ) ;
2004-04-02 12:38:41 +00:00
2003-01-23 19:45:57 +00:00
/* bugfix, cant close() a nonblocking socket (sux!) */
2004-04-02 12:38:41 +00:00
if ( user - > registered = = 7 ) {
FOREACH_MOD OnUserQuit ( user ) ;
WriteCommonExcept ( user , " QUIT :%s " , reason ) ;
}
2004-04-06 09:48:39 +00:00
/* push the socket on a stack of sockets due to be closed at the next opportunity
* ' Client exited ' is an exception to this as it means the client side has already
* closed the socket , we don ' t need to do it .
*/
2004-04-06 18:39:41 +00:00
fd_reap . push_back ( user - > fd ) ;
2004-04-01 20:21:06 +00:00
bool do_purge = false ;
if ( user - > registered = = 7 ) {
2004-04-02 12:38:41 +00:00
WriteOpers ( " *** Client exiting: %s!%s@%s [%s] " , user - > nick , user - > ident , user - > host , reason ) ;
2004-04-01 20:21:06 +00:00
AddWhoWas ( user ) ;
}
2003-01-23 19:45:57 +00:00
if ( iter ! = clientlist . end ( ) )
{
2004-04-01 20:21:06 +00:00
log ( DEBUG , " deleting user hash value %d " , iter - > second ) ;
2004-04-02 12:38:41 +00:00
if ( ( iter - > second ) & & ( user - > registered = = 7 ) ) {
2004-04-01 20:21:06 +00:00
delete iter - > second ;
}
2003-01-23 19:45:57 +00:00
clientlist . erase ( iter ) ;
}
2004-04-02 12:38:41 +00:00
2004-04-03 20:35:20 +00:00
if ( user - > registered = = 7 ) {
purge_empty_chans ( ) ;
}
2003-01-23 19:45:57 +00:00
}
void handle_kill ( char * * parameters , int pcnt , userrec * user )
{
userrec * u = Find ( parameters [ 0 ] ) ;
char killreason [ MAXBUF ] ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " kill: %s %s " , parameters [ 0 ] , parameters [ 1 ] ) ;
2003-01-23 19:45:57 +00:00
if ( u )
{
2004-04-02 12:38:41 +00:00
WriteTo ( user , u , " KILL %s :%s!%s!%s (%s) " , u - > nick , ServerName , user - > dhost , user - > nick , parameters [ 1 ] ) ;
// :Brain!brain@NetAdmin.chatspike.net KILL [Brain] :homer!NetAdmin.chatspike.net!Brain (test kill)
2003-01-23 19:45:57 +00:00
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 )
{
2003-07-22 21:56:38 +00:00
for ( ClassVector : : iterator i = Classes . begin ( ) ; i ! = Classes . end ( ) ; i + + )
{
if ( match ( user - > host , i - > host ) & & ( i - > type = = CC_DENY ) )
{
return true ;
}
}
return false ;
2003-01-23 19:45:57 +00:00
}
2004-04-05 11:00:20 +00:00
2003-01-23 19:45:57 +00:00
void handle_pass ( char * * parameters , int pcnt , userrec * user )
{
2004-04-05 23:27:16 +00:00
// Check to make sure they havnt registered -- Fix by FCS
if ( user - > registered = = 7 )
{
WriteServ ( user - > fd , " 462 %s :You may not reregister " , user - > nick ) ;
return ;
}
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-06 09:48:39 +00:00
WriteServ ( user - > fd , " 401 %s %s :No such nick/channel " , user - > nick , parameters [ 1 ] ) ;
2003-01-23 19:45:57 +00:00
}
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 )
{
2004-04-05 20:10:43 +00:00
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , user - > nick , c - > name ) ;
2003-01-23 19:45:57 +00:00
return ;
}
}
2004-04-06 09:57:13 +00:00
if ( has_channel ( u , c ) )
{
WriteServ ( user - > fd , " 443 %s %s %s :Is already on channel %s " , user - > nick , u - > nick , c - > name , c - > name ) ;
return ;
}
2004-04-05 23:36:13 +00:00
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 ) ;
2003-01-23 19:45:57 +00:00
}
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
{
2004-04-03 21:53:48 +00:00
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
2003-01-23 19:45:57 +00:00
}
}
2004-04-03 21:53:48 +00:00
return ;
2003-01-23 19:45:57 +00:00
}
else if ( pcnt > 1 )
{
if ( strlen ( parameters [ 0 ] ) < = CHANMAX )
{
Ptr = FindChan ( parameters [ 0 ] ) ;
if ( Ptr )
{
if ( ( Ptr - > topiclock ) & & ( cstatus ( user , Ptr ) < STATUS_HOP ) )
{
2004-04-05 20:10:43 +00:00
WriteServ ( user - > fd , " 482 %s %s :You must be at least a half-operator to change modes on this channel " , user - > nick , Ptr - > name ) ;
2003-01-23 19:45:57 +00:00
return ;
}
2004-04-03 20:35:20 +00:00
char topic [ MAXBUF ] ;
2004-04-03 21:53:48 +00:00
strncpy ( topic , parameters [ 1 ] , MAXBUF ) ;
2004-04-03 20:35:20 +00:00
if ( strlen ( topic ) > MAXTOPIC )
{
topic [ MAXTOPIC - 1 ] = ' \0 ' ;
}
strcpy ( Ptr - > topic , topic ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2003-07-22 21:56:38 +00:00
log ( DEBUG , " send_error: %s " , s ) ;
2003-01-23 19:45:57 +00:00
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
{
2004-04-05 11:00:20 +00:00
if ( isnick ( i - > second - > nick ) )
{
WriteServ ( i - > second - > fd , " NOTICE %s :%s " , i - > second - > nick , s ) ;
}
else
{
// fix - unregistered connections receive ERROR, not NOTICE
Write ( i - > second - > fd , " ERROR :%s " , s ) ;
}
2003-01-23 19:45:57 +00:00
}
}
void Error ( int status )
{
2003-07-22 21:56:38 +00:00
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 ) ;
log ( DEBUG , " *** fell down a pothole in the road to perfection *** " ) ;
send_error ( " Error! Segmentation fault! save meeeeeeeeeeeeee *splat!* " ) ;
exit ( status ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-07 17:26:30 +00:00
2003-01-23 19:45:57 +00:00
int main ( int argc , char * argv [ ] )
{
Start ( ) ;
2003-07-22 21:56:38 +00:00
log ( DEBUG , " *** InspIRCd starting up! " ) ;
2003-09-27 20:33:15 +00:00
if ( ! FileExists ( CONFIG_FILE ) )
2003-01-23 19:45:57 +00:00
{
2003-09-27 20:33:15 +00:00
printf ( " ERROR: Cannot open config file: %s \n Exiting... \n " , CONFIG_FILE ) ;
2003-07-22 21:56:38 +00:00
log ( DEBUG , " main: no config " ) ;
2003-01-23 19:45:57 +00:00
printf ( " ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds! \n " ) ;
Exit ( ERROR ) ;
}
2004-04-03 00:33:52 +00:00
if ( argc > 1 ) {
if ( ! strcmp ( argv [ 1 ] , " -nofork " ) ) {
nofork = true ;
}
}
2003-01-23 19:45:57 +00:00
if ( InspIRCd ( ) = = ERROR )
{
2003-07-22 21:56:38 +00:00
log ( DEBUG , " main: daemon function bailed " ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " ReHashNick: %s %s " , Old , New ) ;
2003-01-23 19:45:57 +00:00
if ( ! strcasecmp ( Old , New ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " old nick is new nick, skipping " ) ;
2003-01-23 19:45:57 +00:00
return oldnick - > second ;
}
if ( oldnick = = clientlist . end ( ) ) return NULL ; /* doesnt exist */
2003-02-07 21:15:27 +00:00
log ( DEBUG , " ReHashNick: Found hashed nick %s " , Old ) ;
2003-01-23 19:45:57 +00:00
clientlist [ New ] = new userrec ( ) ;
clientlist [ New ] = oldnick - > second ;
/*delete oldnick->second; */
clientlist . erase ( oldnick ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " ReHashNick: Nick rehashed as %s " , New ) ;
2003-01-23 19:45:57 +00:00
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 ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " added WHOWAS entry, purged an old record " ) ;
2003-01-25 20:00:45 +00:00
return ;
}
}
}
2003-01-25 20:17:53 +00:00
else
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " added fresh WHOWAS entry " ) ;
2003-01-25 20:17:53 +00:00
whowas [ a - > nick ] = a ;
}
2003-01-25 20:00:45 +00:00
}
else
{
2003-02-07 21:15:27 +00:00
log ( 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-07-22 21:56:38 +00:00
int i ;
int blocking = 1 ;
char resolved [ MAXBUF ] ;
string tempnick ;
char tn2 [ MAXBUF ] ;
user_hash : : iterator iter ;
2003-01-25 20:00:45 +00:00
2003-07-22 21:56:38 +00:00
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 ) ;
2003-07-22 21:56:38 +00:00
log ( DEBUG , " AddClient: %d %s %d " , socket , host , port ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2004-04-05 11:00:20 +00:00
strncpy ( clientlist [ tempnick ] - > ident , " unknown " , 9 ) ;
2003-01-23 19:45:57 +00:00
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... " ) ;
}
2004-04-05 11:00:20 +00:00
// set the registration timeout for this user
unsigned long class_regtimeout = 90 ;
for ( ClassVector : : iterator i = Classes . begin ( ) ; i ! = Classes . end ( ) ; i + + )
{
if ( match ( clientlist [ tempnick ] - > host , i - > host ) & & ( i - > type = = CC_ALLOW ) )
{
class_regtimeout = ( unsigned long ) i - > registration_timeout ;
break ;
}
}
log ( DEBUG , " Client has a connection timeout value of %d " , class_regtimeout ) ;
clientlist [ tempnick ] - > timeout = time ( NULL ) + class_regtimeout ;
2003-01-23 19:45:57 +00:00
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 ;
2004-04-04 15:18:34 +00:00
user - > idle_lastmsg = time ( NULL ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
2004-04-06 19:22:11 +00:00
int MOD_RESULT = 0 ;
2004-04-07 16:18:03 +00:00
FOREACH_RESULT ( OnUserPreMessage ( user , chan , TYPE_CHANNEL , std : : string ( parameters [ 1 ] ) ) ) ;
2004-04-06 19:22:11 +00:00
if ( MOD_RESULT ) {
return ;
}
2003-01-23 19:45:57 +00:00
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 ) ;
}
2004-04-06 19:22:11 +00:00
int MOD_RESULT = 0 ;
2004-04-06 19:23:31 +00:00
FOREACH_RESULT ( OnUserPreMessage ( user , dest , TYPE_USER , std : : string ( parameters [ 1 ] ) ) ) ;
2004-04-06 19:22:11 +00:00
if ( MOD_RESULT ) {
return ;
}
2003-01-23 19:45:57 +00:00
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 ;
2004-04-04 15:18:34 +00:00
user - > idle_lastmsg = time ( NULL ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
2004-04-06 19:22:11 +00:00
int MOD_RESULT = 0 ;
2004-04-06 19:23:31 +00:00
FOREACH_RESULT ( OnUserPreNotice ( user , chan , TYPE_CHANNEL , std : : string ( parameters [ 1 ] ) ) ) ;
2004-04-06 19:22:11 +00:00
if ( MOD_RESULT ) {
return ;
}
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-06 19:22:11 +00:00
int MOD_RESULT = 0 ;
2004-04-06 19:23:31 +00:00
FOREACH_RESULT ( OnUserPreNotice ( user , dest , TYPE_USER , std : : string ( parameters [ 1 ] ) ) ) ;
2004-04-06 19:22:11 +00:00
if ( MOD_RESULT ) {
return ;
}
2003-01-23 19:45:57 +00:00
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 ] ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " chlist: %s " , user - > nick ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2004-04-05 16:06:32 +00:00
FOREACH_MOD OnInfo ( user ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-05 09:57:15 +00:00
// bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
if ( dest - > registered = = 7 )
2003-01-23 19:45:57 +00:00
{
2004-04-05 09:57:15 +00:00
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 ) ;
}
2004-04-05 16:06:32 +00:00
FOREACH_MOD OnWhois ( user , dest ) ;
2004-04-05 09:57:15 +00:00
//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 ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-05 09:57:15 +00:00
else
2003-01-23 19:45:57 +00:00
{
2004-04-05 09:57:15 +00:00
WriteServ ( user - > fd , " 401 %s %s :No suck nick/channel " , user - > nick , parameters [ 0 ] ) ;
2003-01-23 19:45:57 +00:00
}
}
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 ) ;
2004-04-03 20:35:20 +00:00
char * reason ;
2003-01-23 19:45:57 +00:00
2004-04-02 20:09:44 +00:00
if ( user - > registered = = 7 )
2003-01-23 19:45:57 +00:00
{
2004-04-02 20:09:44 +00:00
/* theres more to do here, but for now just close the socket */
if ( pcnt = = 1 )
2003-01-23 19:45:57 +00:00
{
2004-04-02 20:09:44 +00:00
if ( parameters [ 0 ] [ 0 ] = = ' : ' )
{
* parameters [ 0 ] + + ;
}
2004-04-03 20:35:20 +00:00
reason = parameters [ 0 ] ;
if ( strlen ( reason ) > MAXQUIT )
{
reason [ MAXQUIT - 1 ] = ' \0 ' ;
}
2004-04-02 20:09:44 +00:00
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 ] ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-02 20:09:44 +00:00
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 ) ;
AddWhoWas ( user ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-02 20:09:44 +00:00
/* push the socket on a stack of sockets due to be closed at the next opportunity */
fd_reap . push_back ( user - > fd ) ;
2003-01-23 19:45:57 +00:00
if ( iter ! = clientlist . end ( ) )
{
2004-04-02 20:09:44 +00:00
log ( DEBUG , " deleting user hash value %d " , iter - > second ) ;
if ( ( iter - > second ) & & ( user - > registered = = 7 ) ) {
delete iter - > second ;
}
2003-01-23 19:45:57 +00:00
clientlist . erase ( iter ) ;
}
2004-04-02 20:09:44 +00:00
if ( user - > registered = = 7 ) {
purge_empty_chans ( ) ;
}
2003-01-23 19:45:57 +00:00
}
void handle_who ( char * * parameters , int pcnt , userrec * user )
{
2003-07-22 21:56:38 +00:00
chanrec * Ptr = NULL ;
2003-01-23 19:45:57 +00:00
/* theres more to do here, but for now just close the socket */
if ( pcnt = = 1 )
{
if ( ( ! strcmp ( parameters [ 0 ] , " 0 " ) ) | | ( ! strcmp ( parameters [ 0 ] , " * " ) ) )
{
2003-04-18 19:03:21 +00:00
if ( user - > chans [ 0 ] . channel )
2003-01-23 19:45:57 +00:00
{
2003-04-18 19:03:21 +00:00
Ptr = user - > chans [ 0 ] . channel ;
for ( user_hash : : const_iterator i = clientlist . begin ( ) ; i ! = clientlist . end ( ) ; i + + )
2003-01-23 19:45:57 +00:00
{
2003-04-18 19:03:21 +00:00
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 ) ;
}
2003-01-23 19:45:57 +00:00
}
}
2003-04-18 19:03:21 +00:00
if ( Ptr )
{
WriteServ ( user - > fd , " 315 %s %s :End of /WHO list. " , user - > nick , Ptr - > name ) ;
}
else
{
WriteServ ( user - > fd , " 315 %s %s :End of /WHO list. " , user - > nick , user - > nick ) ;
}
2003-01-23 19:45:57 +00:00
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 ;
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 ( ) ;
2003-02-07 21:15:27 +00:00
FOREACH_MOD OnRehash ( ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " ConnectUser: %s " , user - > nick ) ;
2003-01-23 19:45:57 +00:00
if ( strcmp ( Passwd ( user ) , " " ) & & ( ! user - > haspassed ) )
{
kill_link ( user , " Invalid password " ) ;
return ;
}
if ( IsDenied ( user ) )
{
kill_link ( user , " Unauthorised connection " ) ;
2004-04-05 09:57:15 +00:00
return ;
2003-01-23 19:45:57 +00:00
}
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 )
{
2004-04-02 12:38:41 +00:00
WriteServ ( user - > fd , " 351 %s :%s %s %s :%s " , user - > nick , VERSION , " $Id$ " , ServerName , SYSTEM ) ;
2003-01-23 19:45:57 +00:00
}
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 )
{
2003-07-31 01:00:21 +00:00
if ( isident ( parameters [ 0 ] ) = = 0 ) {
// This kinda Sucks, According to the RFC thou, its either this,
// or "You have already registered" :p -- Craig
WriteServ ( user - > fd , " 461 %s USER :Not enough parameters " , user - > nick ) ;
}
else {
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 ) ;
}
2003-01-23 19:45:57 +00:00
}
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 ) ;
}
}
}
}
2004-04-04 00:58:20 +00:00
void handle_modules ( char * * parameters , int pcnt , userrec * user )
{
for ( int i = 0 ; i < module_names . size ( ) ; i + + )
{
Version V = modules [ i ] - > GetVersion ( ) ;
2004-04-07 19:34:43 +00:00
WriteServ ( user - > fd , " 900 %s :0x%08lx %d.%d.%d.%d %s " , user - > nick , modules [ i ] , V . Major , V . Minor , V . Revision , V . Build , module_names [ i ] . c_str ( ) ) ;
2004-04-04 00:58:20 +00:00
}
}
2003-01-23 19:45:57 +00:00
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 " ) )
{
2004-04-07 13:22:17 +00:00
for ( int i = 0 ; i < ConfValueEnum ( " oper " , & config_f ) ; i + + )
2003-01-23 19:45:57 +00:00
{
char LoginName [ MAXBUF ] ;
char HostName [ MAXBUF ] ;
char OperType [ MAXBUF ] ;
2004-04-07 13:22:17 +00:00
ConfValue ( " oper " , " name " , i , LoginName , & config_f ) ;
ConfValue ( " oper " , " host " , i , HostName , & config_f ) ;
ConfValue ( " oper " , " type " , i , OperType , & config_f ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
}
2003-01-26 23:53:03 +00:00
void handle_connect ( char * * parameters , int pcnt , userrec * user )
{
2004-04-01 20:21:06 +00:00
char Link_ServerName [ 1024 ] ;
char Link_IPAddr [ 1024 ] ;
char Link_Port [ 1024 ] ;
char Link_Pass [ 1024 ] ;
int LinkPort ;
bool found = false ;
2004-04-07 13:22:17 +00:00
for ( int i = 0 ; i < ConfValueEnum ( " link " , & config_f ) ; i + + )
2004-04-01 20:21:06 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " link " , " name " , i , Link_ServerName , & config_f ) ;
ConfValue ( " link " , " ipaddr " , i , Link_IPAddr , & config_f ) ;
ConfValue ( " link " , " port " , i , Link_Port , & config_f ) ;
ConfValue ( " link " , " sendpass " , i , Link_Pass , & config_f ) ;
2004-04-01 20:21:06 +00:00
log ( DEBUG , " (%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s' " , i , Link_ServerName , Link_IPAddr , Link_Port , Link_Pass ) ;
LinkPort = atoi ( Link_Port ) ;
if ( match ( Link_ServerName , parameters [ 0 ] ) ) {
found = true ;
}
}
if ( ! found ) {
WriteServ ( user - > fd , " NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking. " , user - > nick , parameters [ 0 ] ) ;
return ;
}
// TODO: Perform a check here to stop a server being linked twice!
WriteServ ( user - > fd , " NOTICE %s :*** Connecting to %s (%s) port %s... " , user - > nick , Link_ServerName , Link_IPAddr , Link_Port ) ;
2004-04-01 13:29:11 +00:00
if ( me [ defaultRoute ] )
2003-02-02 16:43:53 +00:00
{
2004-04-01 20:21:06 +00:00
// at this point parameters[0] is an ip in a string.
// TODO: Look this up from the <link> blocks instead!
for ( int j = 0 ; j < 255 ; j + + ) {
if ( servers [ j ] = = NULL ) {
servers [ j ] = new serverrec ;
strcpy ( servers [ j ] - > internal_addr , Link_IPAddr ) ;
strcpy ( servers [ j ] - > name , Link_ServerName ) ;
log ( DEBUG , " Allocated new serverrec " ) ;
if ( ! me [ defaultRoute ] - > BeginLink ( Link_IPAddr , LinkPort , Link_Pass ) )
{
WriteServ ( user - > fd , " NOTICE %s :*** Failed to send auth packet to %s! " , user - > nick , Link_IPAddr ) ;
}
return ;
}
2004-04-01 13:29:11 +00:00
}
2004-04-01 20:21:06 +00:00
WriteServ ( user - > fd , " NOTICE %s :*** Failed to create server record for address %s! " , user - > nick , Link_IPAddr ) ;
2004-04-01 13:29:11 +00:00
}
else
{
2004-04-01 20:21:06 +00:00
WriteServ ( user - > fd , " NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it. " , user - > nick ) ;
2003-02-02 16:43:53 +00:00
}
2003-01-26 23:53:03 +00:00
}
void handle_squit ( char * * parameters , int pcnt , userrec * user )
{
2004-04-01 20:21:06 +00:00
// send out an squit across the mesh and then clear the server list (for local squit)
2003-01-26 23:53:03 +00:00
}
2003-01-23 19:45:57 +00:00
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 ;
2004-04-07 13:22:17 +00:00
for ( i = 0 ; i < ConfValueEnum ( " oper " , & config_f ) ; i + + )
2003-01-23 19:45:57 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " oper " , " name " , i , LoginName , & config_f ) ;
ConfValue ( " oper " , " password " , i , Password , & config_f ) ;
2003-01-23 19:45:57 +00:00
if ( ( ! strcmp ( LoginName , parameters [ 0 ] ) ) & & ( ! strcmp ( Password , parameters [ 1 ] ) ) )
{
/* correct oper credentials */
2004-04-07 13:22:17 +00:00
ConfValue ( " oper " , " type " , i , OperType , & config_f ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2004-04-07 13:22:17 +00:00
for ( j = 0 ; j < ConfValueEnum ( " type " , & config_f ) ; j + + )
2003-01-23 19:45:57 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " type " , " name " , j , TypeName , & config_f ) ;
2003-01-23 19:45:57 +00:00
if ( ! strcmp ( TypeName , OperType ) )
{
/* found this oper's opertype */
2004-04-07 13:22:17 +00:00
ConfValue ( " type " , " host " , j , Hostname , & config_f ) ;
2003-01-23 19:45:57 +00:00
strncpy ( user - > dhost , Hostname , 256 ) ;
}
}
if ( ! strchr ( user - > modes , ' o ' ) )
{
strcat ( user - > modes , " o " ) ;
}
2004-04-05 16:06:32 +00:00
FOREACH_MOD OnOper ( user ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
}
2004-04-06 10:43:34 +00:00
2003-01-23 19:45:57 +00:00
void handle_nick ( char * * parameters , int pcnt , userrec * user )
{
if ( pcnt < 1 )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " not enough params for handle_nick " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
if ( ! parameters [ 0 ] )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " invalid parameter passed to handle_nick " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
if ( ! strlen ( parameters [ 0 ] ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " zero length new nick passed to handle_nick " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
if ( ! user )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " invalid user passed to handle_nick " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
if ( ! user - > nick )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " invalid old nick passed to handle_nick " ) ;
2003-01-23 19:45:57 +00:00
return ;
}
if ( ! strcasecmp ( user - > nick , parameters [ 0 ] ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " old nick is new nick, skipping " ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " new nick set: %s " , user - > nick ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " exit nickchange: %s " , user - > nick ) ;
2003-01-23 19:45:57 +00:00
}
2004-04-06 10:43:34 +00:00
void force_nickchange ( userrec * user , const char * newnick )
{
char nick [ MAXBUF ] ;
strcpy ( nick , " " ) ;
if ( user )
{
if ( newnick )
{
strncpy ( nick , newnick , MAXBUF ) ;
}
if ( user - > registered = = 7 )
{
char * pars [ 1 ] ;
pars [ 0 ] = nick ;
handle_nick ( pars , 1 , user ) ;
}
}
}
2003-01-23 19:45:57 +00:00
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 ;
}
2004-04-06 09:48:39 +00:00
int total_params = 0 ;
for ( int q = 0 ; q < strlen ( cmd ) ; q + + )
{
if ( cmd [ q ] = = ' ' )
total_params + + ;
}
// another phidjit bug...
if ( total_params > 126 )
{
kill_link ( user , " Protocol violation " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
strcpy ( temp , cmd ) ;
2003-03-30 18:38:25 +00:00
2003-04-18 19:03:21 +00:00
string tmp = cmd ;
FOREACH_MOD OnServerRaw ( tmp , true ) ;
const char * cmd2 = tmp . c_str ( ) ;
snprintf ( cmd , 512 , " %s " , cmd2 ) ;
2003-03-30 18:38:25 +00:00
2003-01-23 19:45:57 +00:00
if ( ! strchr ( cmd , ' ' ) )
{
/* no parameters, lets skip the formalities and not chop up
* the string */
2004-04-06 09:48:39 +00:00
log ( DEBUG , " About to preprocess command with no params " ) ;
2003-01-23 19:45:57 +00:00
items = 0 ;
command_p [ 0 ] = NULL ;
parameters = NULL ;
for ( int i = 0 ; i < = strlen ( cmd ) ; i + + )
{
cmd [ i ] = toupper ( cmd [ i ] ) ;
}
2004-04-06 09:48:39 +00:00
log ( DEBUG , " Preprocess done " ) ;
2003-01-23 19:45:57 +00:00
}
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 ;
2004-04-05 20:10:43 +00:00
2004-04-03 20:35:20 +00:00
if ( strlen ( command ) > MAXCOMMAND )
{
2004-04-06 09:48:39 +00:00
kill_link ( user , " Protocol violation " ) ;
return ;
}
for ( int x = 0 ; x < strlen ( command ) ; x + + )
{
2004-04-06 12:29:27 +00:00
if ( ( ( command [ x ] < ' A ' ) | | ( command [ x ] > ' Z ' ) ) & & ( command [ x ] ! = ' . ' ) )
2004-04-06 09:48:39 +00:00
{
2004-04-06 12:29:27 +00:00
if ( ( ( command [ x ] < ' 0 ' ) | | ( command [ x ] > ' 9 ' ) ) & & ( command [ x ] ! = ' - ' ) )
{
kill_link ( user , " Protocol violation " ) ;
return ;
}
2004-04-06 09:48:39 +00:00
}
2004-04-03 20:35:20 +00:00
}
2003-01-23 19:45:57 +00:00
for ( i = 0 ; i ! = cmdlist . size ( ) ; i + + )
{
if ( strcmp ( cmdlist [ i ] . command , " " ) )
{
2004-04-06 09:48:39 +00:00
if ( strlen ( command ) > = ( strlen ( cmdlist [ i ] . command ) ) ) if ( ! strncmp ( command , cmdlist [ i ] . command , MAXCOMMAND ) )
2003-01-23 19:45:57 +00:00
{
2004-04-05 20:10:43 +00:00
log ( DEBUG , " Found matching command " ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-05 20:10:43 +00:00
log ( DEBUG , " Processing command " ) ;
2003-01-23 19:45:57 +00:00
/* activity resets the ping pending timer */
user - > nping = time ( NULL ) + 120 ;
if ( ( items ) < cmdlist [ i ] . min_params )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: not enough parameters: %s %s " , user - > nick , command ) ;
2003-01-23 19:45:57 +00:00
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 ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: permission denied: %s %s " , user - > nick , command ) ;
2003-01-23 19:45:57 +00:00
WriteServ ( user - > fd , " 481 %s :Permission Denied- You do not have the required operator privilages " , user - > nick ) ;
cmd_found = 1 ;
return ;
}
2004-04-06 09:48:39 +00:00
/* if the command isnt USER, PASS, or NICK, and nick is empty,
* deny command ! */
if ( ( strncmp ( command , " USER " , 4 ) ) & & ( strncmp ( command , " NICK " , 4 ) ) & & ( strncmp ( command , " PASS " , 4 ) ) )
2003-01-23 19:45:57 +00:00
{
if ( ( ! isnick ( user - > nick ) ) | | ( user - > registered ! = 7 ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: not registered: %s %s " , user - > nick , command ) ;
2003-01-23 19:45:57 +00:00
WriteServ ( user - > fd , " 451 %s :You have not registered " , command ) ;
return ;
}
}
if ( ( user - > registered = = 7 ) | | ( ! strcmp ( command , " USER " ) ) | | ( ! strcmp ( command , " NICK " ) ) | | ( ! strcmp ( command , " PASS " ) ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: handler: %s %s %d " , user - > nick , command , items ) ;
2003-01-23 19:45:57 +00:00
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
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: not registered: %s %s " , user - > nick , command ) ;
2003-01-23 19:45:57 +00:00
WriteServ ( user - > fd , " 451 %s :You have not registered " , command ) ;
return ;
}
}
cmd_found = 1 ;
}
}
}
if ( ( ! cmd_found ) & & ( user ) )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " process_command: not in table: %s %s " , user - > nick , command ) ;
2003-01-23 19:45:57 +00:00
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 ) ;
2004-04-02 16:38:45 +00:00
log ( DEBUG , " Added command %s (%d parameters) " , cmd , minparams ) ;
2003-01-23 19:45:57 +00:00
}
void SetupCommandTable ( void )
{
2004-04-06 22:52:28 +00:00
createcommand ( " USER " , handle_user , 0 , 4 ) ;
createcommand ( " NICK " , handle_nick , 0 , 1 ) ;
createcommand ( " QUIT " , handle_quit , 0 , 0 ) ;
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_rules , 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 ) ;
createcommand ( " WHOWAS " , handle_whowas , 0 , 1 ) ;
createcommand ( " CONNECT " , handle_connect , ' o ' , 1 ) ;
createcommand ( " SQUIT " , handle_squit , ' o ' , 1 ) ;
createcommand ( " MODULES " , handle_modules , ' o ' , 0 ) ;
2003-01-23 19:45:57 +00:00
}
void process_buffer ( userrec * user )
{
2004-04-03 20:35:20 +00:00
if ( ! user )
{
log ( DEFAULT , " *** BUG *** process_buffer was given an invalid parameter " ) ;
return ;
}
2003-01-23 19:45:57 +00:00
char cmd [ MAXBUF ] ;
int i ;
if ( ! user - > inbuf )
{
2004-04-03 20:35:20 +00:00
log ( DEFAULT , " *** BUG *** process_buffer was given an invalid parameter " ) ;
2003-01-23 19:45:57 +00:00
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 ;
}
2003-02-07 21:15:27 +00:00
log ( DEBUG , " InspIRCd: processing: %s %s " , user - > nick , cmd ) ;
2004-04-03 17:24:37 +00:00
tidystring ( cmd ) ;
2004-04-05 20:10:43 +00:00
if ( ( user ) & & ( cmd ) )
2004-04-03 20:35:20 +00:00
{
process_command ( user , cmd ) ;
}
2003-01-23 19:45:57 +00:00
}
2004-04-01 20:21:06 +00:00
void process_restricted_commands ( char token , char * params , serverrec * source , serverrec * reply , char * udp_host , int udp_port )
2003-02-07 21:15:27 +00:00
{
2004-04-01 20:21:06 +00:00
WriteOpers ( " Secure-UDP-Channel: Token='%c', Params='%s' " , token , params ) ;
}
void handle_link_packet ( long theirkey , char * udp_msg , char * udp_host , int udp_port , serverrec * serv )
{
char response [ 10240 ] ;
char token = udp_msg [ 0 ] ;
char * params = udp_msg + 2 ;
char finalparam [ 1024 ] ;
strcpy ( finalparam , " :xxxx " ) ;
if ( strstr ( params , " : " ) ) {
strncpy ( finalparam , strstr ( params , " : " ) , 1024 ) ;
}
if ( token = = ' S ' ) {
// S test.chatspike.net password :ChatSpike InspIRCd test server
char * servername = strtok ( params , " " ) ;
char * password = strtok ( NULL , " " ) ;
char * serverdesc = finalparam + 2 ;
WriteOpers ( " CONNECT from %s (%s) " , servername , udp_host , password , serverdesc ) ;
char Link_ServerName [ 1024 ] ;
char Link_IPAddr [ 1024 ] ;
char Link_Port [ 1024 ] ;
char Link_Pass [ 1024 ] ;
char Link_SendPass [ 1024 ] ;
int LinkPort = 0 ;
// search for a corresponding <link> block in the config files
2004-04-07 13:22:17 +00:00
for ( int i = 0 ; i < ConfValueEnum ( " link " , & config_f ) ; i + + )
2004-04-01 20:21:06 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " link " , " name " , i , Link_ServerName , & config_f ) ;
ConfValue ( " link " , " ipaddr " , i , Link_IPAddr , & config_f ) ;
ConfValue ( " link " , " port " , i , Link_Port , & config_f ) ;
ConfValue ( " link " , " recvpass " , i , Link_Pass , & config_f ) ;
ConfValue ( " link " , " sendpass " , i , Link_SendPass , & config_f ) ;
2004-04-01 20:21:06 +00:00
log ( DEBUG , " (%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s' " , i , Link_ServerName , Link_IPAddr , Link_Port , Link_Pass ) ;
LinkPort = atoi ( Link_Port ) ;
if ( ! strcasecmp ( Link_ServerName , servername ) ) {
if ( ! strcasecmp ( Link_IPAddr , udp_host ) ) {
if ( LinkPort = = udp_port ) {
// we have a matching link line -
// send a 'diminutive' server message back...
snprintf ( response , 10240 , " s %s %s :%s " , ServerName , Link_SendPass , ServerDesc ) ;
serv - > SendPacket ( response , udp_host , udp_port , 0 ) ;
WriteOpers ( " CONNECT from %s accepted, authenticating " , servername ) ;
for ( int j = 0 ; j < 255 ; j + + ) {
if ( servers [ j ] = = NULL ) {
servers [ j ] = new serverrec ;
strcpy ( servers [ j ] - > internal_addr , udp_host ) ;
strcpy ( servers [ j ] - > name , servername ) ;
// create a server record for this server
snprintf ( response , 10240 , " O %d " , MyKey ) ;
serv - > SendPacket ( response , udp_host , udp_port , 0 ) ;
return ;
}
}
WriteOpers ( " Internal error connecting to %s, failed to create server record! " , servername ) ;
return ;
}
else {
log ( DEBUG , " Port numbers '%d' and '%d' don't match " , LinkPort , udp_port ) ;
}
}
else {
log ( DEBUG , " IP Addresses '%s' and '%s' don't match " , Link_IPAddr , udp_host ) ;
}
}
else {
log ( DEBUG , " Server names '%s' and '%s' don't match " , Link_ServerName , servername ) ;
}
}
serv - > SendPacket ( " E :Access is denied (no matching link block) " , udp_host , udp_port , 0 ) ;
WriteOpers ( " CONNECT from %s denied, no matching link block " , servername ) ;
return ;
}
else
if ( token = = ' O ' ) {
// if this is received, this means the server-ip that sent it said "OK" to credentials.
// only when a server says this do we exchange keys. The server MUST have an entry in the servers
// array, which is only added by an 'S' packet or BeginLink().
for ( int i = 0 ; i < 255 ; i + + ) {
if ( servers [ i ] ! = NULL ) {
if ( ! strcasecmp ( servers [ i ] - > internal_addr , udp_host ) ) {
servers [ i ] - > key = atoi ( params ) ;
log ( DEBUG , " Key for this server is now %d " , servers [ i ] - > key ) ;
serv - > SendPacket ( " Z blah blah " , udp_host , udp_port , MyKey ) ;
return ;
}
}
}
WriteOpers ( " \2 WARNING! \2 Server ip %s attempted a key exchange, but is not in the authentication state! Possible intrusion attempt! " , udp_host ) ;
}
else
if ( token = = ' s ' ) {
// S test.chatspike.net password :ChatSpike InspIRCd test server
char * servername = strtok ( params , " " ) ;
char * password = strtok ( NULL , " " ) ;
char * serverdesc = finalparam + 2 ;
// TODO: we should do a check here to ensure that this server is one we recently initiated a
// link with, and didnt hear an 's' or 'E' back from yet (these are the only two valid responses
// to an 'S' command. If we didn't recently send an 'S' to this server, theyre trying to spoof
// a connect, so put out an oper alert!
// for now, just accept all, we'll fix that later.
WriteOpers ( " %s accepted our link credentials " , servername ) ;
char Link_ServerName [ 1024 ] ;
char Link_IPAddr [ 1024 ] ;
char Link_Port [ 1024 ] ;
char Link_Pass [ 1024 ] ;
char Link_SendPass [ 1024 ] ;
int LinkPort = 0 ;
// search for a corresponding <link> block in the config files
2004-04-07 13:22:17 +00:00
for ( int i = 0 ; i < ConfValueEnum ( " link " , & config_f ) ; i + + )
2004-04-01 20:21:06 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " link " , " name " , i , Link_ServerName , & config_f ) ;
ConfValue ( " link " , " ipaddr " , i , Link_IPAddr , & config_f ) ;
ConfValue ( " link " , " port " , i , Link_Port , & config_f ) ;
ConfValue ( " link " , " recvpass " , i , Link_Pass , & config_f ) ;
ConfValue ( " link " , " sendpass " , i , Link_SendPass , & config_f ) ;
2004-04-01 20:21:06 +00:00
log ( DEBUG , " (%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s' " , i , Link_ServerName , Link_IPAddr , Link_Port , Link_Pass ) ;
LinkPort = atoi ( Link_Port ) ;
if ( ! strcasecmp ( Link_ServerName , servername ) ) {
if ( ! strcasecmp ( Link_IPAddr , udp_host ) ) {
if ( LinkPort = = udp_port ) {
// matching link at this end too, we're all done!
// at this point we must begin key exchange and insert this
// server into our 'active' table.
for ( int j = 0 ; j < 255 ; j + + ) {
if ( servers [ j ] ! = NULL ) {
if ( ! strcasecmp ( servers [ j ] - > internal_addr , udp_host ) ) {
WriteOpers ( " Server %s authenticated, exchanging server keys... " , servername ) ;
snprintf ( response , 10240 , " O %d " , MyKey ) ;
serv - > SendPacket ( response , udp_host , udp_port , 0 ) ;
return ;
}
}
}
WriteOpers ( " \2 WARNING! \2 %s sent us an authentication packet but we are not authenticating with this server right noe! Possible intrusion attempt! " , udp_host ) ;
return ;
}
else {
log ( DEBUG , " Port numbers '%d' and '%d' don't match " , LinkPort , udp_port ) ;
}
}
else {
log ( DEBUG , " IP Addresses '%s' and '%s' don't match " , Link_IPAddr , udp_host ) ;
}
}
else {
log ( DEBUG , " Server names '%s' and '%s' don't match " , Link_ServerName , servername ) ;
}
}
serv - > SendPacket ( " E :Access is denied (no matching link block) " , udp_host , udp_port , 0 ) ;
WriteOpers ( " CONNECT from %s denied, no matching link block " , servername ) ;
return ;
}
else
if ( token = = ' E ' ) {
char * error_message = finalparam + 2 ;
WriteOpers ( " ERROR from %s: %s " , udp_host , error_message ) ;
// remove this server from any lists
for ( int j = 0 ; j < 255 ; j + + ) {
if ( servers [ j ] ! = NULL ) {
if ( ! strcasecmp ( servers [ j ] - > internal_addr , udp_host ) ) {
delete servers [ j ] ;
return ;
}
}
}
return ;
}
else {
serverrec * source_server = NULL ;
for ( int j = 0 ; j < 255 ; j + + ) {
if ( servers [ j ] ! = NULL ) {
if ( ! strcasecmp ( servers [ j ] - > internal_addr , udp_host ) ) {
if ( servers [ j ] - > key = = theirkey ) {
// found a valid key for this server, can process restricted stuff here
process_restricted_commands ( token , params , servers [ j ] , serv , udp_host , udp_port ) ;
return ;
}
}
}
}
log ( DEBUG , " Unrecognised token or unauthenticated host in datagram from %s:%d: %c " , udp_host , udp_port , token ) ;
}
2003-02-07 21:15:27 +00:00
}
2004-04-02 12:38:41 +00:00
int reap_counter = 0 ;
2003-01-23 19:45:57 +00:00
int InspIRCd ( void )
{
2004-04-06 22:52:28 +00:00
struct sockaddr_in client , server ;
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 ] , Type [ MAXBUF ] ;
char resolvedHost [ MAXBUF ] ;
fd_set selectFds ;
struct timeval tv ;
log_file = fopen ( " ircd.log " , " a+ " ) ;
if ( ! log_file )
{
printf ( " ERROR: Could not write to logfile ircd.log, bailing! \n \n " ) ;
Exit ( ERROR ) ;
2003-02-07 21:15:27 +00:00
}
2004-04-06 22:52:28 +00:00
log ( DEBUG , " InspIRCd: startup: begin " ) ;
log ( DEBUG , " $Id$ " ) ;
if ( geteuid ( ) = = 0 )
2003-02-07 21:15:27 +00:00
{
2004-04-06 22:52:28 +00:00
printf ( " WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!! \n \n " ) ;
Exit ( ERROR ) ;
log ( DEBUG , " InspIRCd: startup: not starting with UID 0! " ) ;
2003-02-07 21:15:27 +00:00
}
2004-04-06 22:52:28 +00:00
SetupCommandTable ( ) ;
log ( DEBUG , " InspIRCd: startup: default command table set up " ) ;
ReadConfig ( ) ;
if ( strcmp ( DieValue , " " ) )
{
printf ( " WARNING: %s \n \n " , DieValue ) ;
exit ( 0 ) ;
}
log ( DEBUG , " InspIRCd: startup: read config " ) ;
int count2 = 0 , count3 = 0 ;
2004-04-07 13:22:17 +00:00
for ( count = 0 ; count < ConfValueEnum ( " bind " , & config_f ) ; count + + )
2004-04-06 22:52:28 +00:00
{
2004-04-07 13:22:17 +00:00
ConfValue ( " bind " , " port " , count , configToken , & config_f ) ;
ConfValue ( " bind " , " address " , count , Addr , & config_f ) ;
ConfValue ( " bind " , " type " , count , Type , & config_f ) ;
2004-04-06 22:52:28 +00:00
if ( ! strcmp ( Type , " servers " ) )
{
char Default [ MAXBUF ] ;
strcpy ( Default , " no " ) ;
2004-04-07 13:22:17 +00:00
ConfValue ( " bind " , " default " , count , Default , & config_f ) ;
2004-04-06 22:52:28 +00:00
if ( strchr ( Default , ' y ' ) )
{
defaultRoute = count3 ;
log ( DEBUG , " InspIRCd: startup: binding '%s:%s' is default server route " , Addr , configToken ) ;
}
me [ count3 ] = new serverrec ( ServerName , 100L , false ) ;
me [ count3 ] - > CreateListener ( Addr , atoi ( configToken ) ) ;
count3 + + ;
2003-09-27 04:02:46 +00:00
}
2004-04-06 22:52:28 +00:00
else
2003-09-27 04:02:46 +00:00
{
2004-04-06 22:52:28 +00:00
ports [ count2 ] = atoi ( configToken ) ;
strcpy ( addrs [ count2 ] , Addr ) ;
count2 + + ;
}
log ( DEBUG , " InspIRCd: startup: read binding %s:%s [%s] from config " , Addr , configToken , Type ) ;
}
portCount = count2 ;
UDPportCount = count3 ;
log ( DEBUG , " InspIRCd: startup: read %d total client ports and %d total server ports " , portCount , UDPportCount ) ;
log ( DEBUG , " InspIRCd: startup: InspIRCd is now running! " ) ;
printf ( " \n " ) ;
/* BugFix By Craig! :p */
count2 = 0 ;
2004-04-07 13:22:17 +00:00
for ( count = 0 ; count2 < ConfValueEnum ( " module " , & config_f ) ; count2 + + )
2004-04-06 22:52:28 +00:00
{
char modfile [ MAXBUF ] ;
2004-04-07 13:22:17 +00:00
ConfValue ( " module " , " name " , count , configToken , & config_f ) ;
sprintf ( modfile , " %s/%s " , MOD_PATH , configToken , & config_f ) ;
2004-04-06 22:52:28 +00:00
printf ( " Loading module... \033 [1;37m%s \033 [0;37m \n " , modfile ) ;
log ( DEBUG , " InspIRCd: startup: Loading module: %s " , modfile ) ;
/* If The File Doesnt exist, Trying to load it
* Will Segfault the IRCd . . So , check to see if
* it Exists , Before Proceeding . */
if ( FileExists ( modfile ) )
{
factory [ count ] = new ircd_module ( modfile ) ;
if ( factory [ count ] - > LastError ( ) )
{
log ( 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 : / */
module_names . push_back ( modfile ) ;
}
else
{
log ( DEBUG , " Unable to load %s " , modfile ) ;
sprintf ( " Unable to load %s \n Exiting... \n " , modfile ) ;
Exit ( ERROR ) ;
}
/* Increase the Count */
count + + ;
2003-09-27 04:02:46 +00:00
}
else
{
2004-04-06 22:52:28 +00:00
log ( DEBUG , " InspIRCd: startup: Module Not Found %s " , modfile ) ;
printf ( " Module Not Found: \033 [1;37m%s \033 [0;37m, Skipping \n " , modfile ) ;
2003-09-27 04:02:46 +00:00
}
2004-04-06 22:52:28 +00:00
}
MODCOUNT = count - 1 ;
log ( DEBUG , " Total loaded modules: %d " , MODCOUNT + 1 ) ;
printf ( " \n InspIRCd is now running! \n " ) ;
startup_time = time ( NULL ) ;
if ( nofork )
{
log ( VERBOSE , " Not forking as -nofork was specified " ) ;
2003-01-23 19:45:57 +00:00
}
else
{
2004-04-06 22:52:28 +00:00
if ( DaemonSeed ( ) = = ERROR )
{
log ( 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 ) ;
log ( DEBUG , " InspIRCd: startup: zero selects " ) ;
log ( VERBOSE , " InspIRCd: startup: portCount = %d " , portCount ) ;
for ( count = 0 ; count < portCount ; count + + )
{
if ( ( openSockfd [ boundPortCount ] = OpenTCPSocket ( ) ) = = ERROR )
{
log ( DEBUG , " InspIRCd: startup: bad fd %d " , openSockfd [ boundPortCount ] ) ;
return ( ERROR ) ;
}
if ( BindSocket ( openSockfd [ boundPortCount ] , client , server , ports [ count ] , addrs [ count ] ) = = ERROR )
{
log ( DEBUG , " InspIRCd: startup: failed to bind port %d " , ports [ count ] ) ;
}
else /* well we at least bound to one socket so we'll continue */
{
boundPortCount + + ;
}
2003-01-23 19:45:57 +00:00
}
2004-04-06 22:52:28 +00:00
log ( DEBUG , " InspIRCd: startup: total bound ports %d " , boundPortCount ) ;
/* if we didn't bind to anything then abort */
if ( boundPortCount = = 0 )
2004-04-03 00:33:52 +00:00
{
2004-04-06 22:52:28 +00:00
log ( DEBUG , " InspIRCd: startup: no ports bound, bailing! " ) ;
return ( ERROR ) ;
}
2003-01-23 19:45:57 +00:00
2004-04-06 22:52:28 +00:00
length = sizeof ( client ) ;
int flip_flop = 0 , udp_port = 0 ;
char udp_msg [ MAXBUF ] , udp_host [ MAXBUF ] ;
/* 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 + + ;
reap_counter + + ;
if ( flip_flop > 20 )
{
tv . tv_usec = 1 ;
flip_flop = 0 ;
}
2003-01-23 19:45:57 +00:00
2004-04-06 22:52:28 +00:00
vector < int > : : iterator niterator ;
2004-04-02 12:38:41 +00:00
2004-04-06 22:52:28 +00:00
// *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue
// them in a list, then reap the list every second or so.
if ( reap_counter > 5000 ) {
if ( fd_reap . size ( ) > 0 ) {
for ( int n = 0 ; n < fd_reap . size ( ) ; n + + )
{
Blocking ( fd_reap [ n ] ) ;
close ( fd_reap [ n ] ) ;
NonBlocking ( fd_reap [ n ] ) ;
}
2004-04-02 12:38:41 +00:00
}
2004-04-06 22:52:28 +00:00
fd_reap . clear ( ) ;
reap_counter = 0 ;
2004-04-02 12:38:41 +00:00
}
2004-04-06 22:52:28 +00:00
tv . tv_sec = 0 ;
selectResult = select ( MAXSOCKS , & selectFds , NULL , NULL , & tv ) ;
for ( int x = 0 ; x ! = UDPportCount ; x + + )
{
long theirkey = 0 ;
if ( me [ x ] - > RecvPacket ( udp_msg , udp_host , udp_port , theirkey ) )
{
if ( strlen ( udp_msg ) < 1 ) {
log ( DEBUG , " Invalid datagram from %s:%d:%d [route%d] " , udp_host , udp_port , me [ x ] - > port , x ) ;
}
else
{
2004-04-01 20:21:06 +00:00
FOREACH_MOD OnPacketReceive ( udp_msg ) ;
// Packets must go back via the route they arrived on :)
handle_link_packet ( theirkey , udp_msg , udp_host , udp_port , me [ x ] ) ;
2004-04-06 22:52:28 +00:00
}
}
}
2003-02-02 16:43:53 +00:00
2004-04-06 22:52:28 +00:00
for ( user_hash : : iterator count2 = clientlist . begin ( ) ; count2 ! = clientlist . end ( ) ; count2 + + )
2003-01-23 19:45:57 +00:00
{
char data [ MAXBUF ] ;
if ( ! count2 - > second ) break ;
if ( count2 - > second )
if ( count2 - > second - > fd )
{
2004-04-05 11:00:20 +00:00
// registration timeout -- didnt send USER/NICK/HOST in the time specified in
// their connection class.
if ( ( time ( NULL ) > count2 - > second - > timeout ) & & ( count2 - > second - > registered ! = 7 ) )
{
log ( DEBUG , " InspIRCd: registration timeout: %s " , count2 - > second - > nick ) ;
kill_link ( count2 - > second , " Registration timeout " ) ;
break ;
}
2003-01-23 19:45:57 +00:00
if ( ( ( time ( NULL ) ) > count2 - > second - > nping ) & & ( isnick ( count2 - > second - > nick ) ) & & ( count2 - > second - > registered = = 7 ) )
{
if ( ! count2 - > second - > lastping )
{
2003-02-07 21:15:27 +00:00
log ( DEBUG , " InspIRCd: ping timeout: %s " , count2 - > second - > nick ) ;
2003-01-23 19:45:57 +00:00
kill_link ( count2 - > second , " Ping timeout " ) ;
break ;
}
Write ( count2 - > second - > fd , " PING :%s " , ServerName ) ;
2003-02-07 21:15:27 +00:00
log ( DEBUG , " InspIRCd: pinging: %s " , count2 - > second - > nick ) ;
2003-01-23 19:45:57 +00:00
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 )
{
2004-04-03 20:35:20 +00:00
if ( count2 - > second )
{
log ( DEBUG , " InspIRCd: Exited: %s " , count2 - > second - > nick ) ;
kill_link ( count2 - > second , " Client exited " ) ;
// must bail here? kill_link removes the hash, corrupting the iterator
log ( DEBUG , " Bailing from client exit " ) ;
break ;
}
2003-01-23 19:45:57 +00:00
}
else if ( result > 0 )
{
2004-04-03 20:35:20 +00:00
if ( count2 - > second )
2003-01-23 19:45:57 +00:00
{
2004-04-05 09:57:15 +00:00
// until the buffer is at 509 chars anything can be inserted into it.
2004-04-06 09:48:39 +00:00
if ( ( strlen ( count2 - > second - > inbuf ) < 509 ) & & ( data [ 0 ] ! = ' \0 ' ) ) {
2004-04-05 09:57:15 +00:00
strncat ( count2 - > second - > inbuf , data , result ) ;
}
2004-04-03 20:35:20 +00:00
2004-04-05 09:57:15 +00:00
// once you reach 509 chars, only a \r or \n can be inserted,
// completing the line.
if ( ( strlen ( count2 - > second - > inbuf ) > = 509 ) & & ( ( data [ 0 ] = = ' \r ' ) | | ( data [ 0 ] = = ' \n ' ) ) ) {
2004-04-03 20:35:20 +00:00
count2 - > second - > inbuf [ 509 ] = ' \r ' ;
count2 - > second - > inbuf [ 510 ] = ' \n ' ;
count2 - > second - > inbuf [ 511 ] = ' \0 ' ;
2004-04-06 09:48:39 +00:00
process_buffer ( count2 - > second ) ;
break ;
2004-04-03 20:35:20 +00:00
}
if ( strchr ( count2 - > second - > inbuf , ' \n ' ) | | strchr ( count2 - > second - > inbuf , ' \r ' ) | | ( strlen ( count2 - > second - > inbuf ) > 509 ) )
2003-01-23 19:45:57 +00:00
{
2004-04-03 20:35:20 +00:00
/* at least one complete line is waiting to be processed */
if ( ! count2 - > second - > fd )
break ;
else
{
2004-04-06 09:48:39 +00:00
if ( strlen ( count2 - > second - > inbuf ) < 512 )
2004-04-05 09:57:15 +00:00
{
// double check the length before processing!
process_buffer ( count2 - > second ) ;
}
2004-04-06 09:48:39 +00:00
else
{
strcpy ( count2 - > second - > inbuf , " " ) ;
}
2004-04-03 20:35:20 +00:00
break ;
}
2003-01-23 19:45:57 +00:00
}
}
}
}
}
2004-04-06 22:52:28 +00:00
/* 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 ) ;
log ( DEBUG , " InspIRCd: accept failed: %d " , ports [ count ] ) ;
break ;
}
AddClient ( incomingSockfd , resolved , ports [ count ] , iscached ) ;
log ( DEBUG , " InspIRCd: adding client on port %d fd=%d " , ports [ count ] , incomingSockfd ) ;
break ;
}
}
}
}
/* not reached */
close ( incomingSockfd ) ;
2003-01-23 19:45:57 +00:00
}