2005-02-28 07:16:19 +00:00
# include "quakedef.h"
2004-08-23 03:57:39 +00:00
# ifdef IRCCLIENT
//Released under the terms of the gpl as this file uses a bit of quake derived code. All sections of the like are marked as such
//these should be in a header.
void IRC_Frame ( void ) ;
void IRC_Command ( char * imsg ) ;
//porting zone:
# ifdef TERMINALIRC //windows console prog.
# define Q_strncpyz(o, i, l) do {strncpy(o, i, l-1);o[l-1]='\0';}while(0)
# pragma comment (lib, "wsock32.lib")
# include <winsock.h>
# include <stdio.h>
# include <conio.h>
# include <malloc.h>
# include <stdarg.h>
enum { false , true } ;
void main ( void )
{
char buffer [ 1024 ] ;
int len = 0 ;
WSADATA wsadata ;
len = WSAStartup ( MAKEWORD ( 1 , 1 ) , & wsadata ) ;
if ( len )
{
printf ( " Winsock initialization failed. " ) ;
exit ( len ) ;
}
for ( ; ; )
{
if ( kbhit ( ) )
{
buffer [ len ] = getch ( ) ;
printf ( " %c " , buffer [ len ] ) ;
if ( buffer [ len ] = = 8 )
{
if ( len )
{
printf ( " %c " , buffer [ len ] ) ;
len - - ;
}
}
else if ( buffer [ len ] = = ' \r ' ) //return was hit
{
buffer [ len ] = ' \0 ' ;
if ( ! strcmp ( buffer , " /quitprog " ) ) //special case... he he he
{
WSACleanup ( ) ;
exit ( 0 ) ;
}
printf ( " \n " ) ;
IRC_Command ( buffer ) ;
len = 0 ;
}
else
len + + ;
}
IRC_Frame ( ) ;
Sleep ( 100 ) ;
}
}
char * va ( char * format , . . . ) //stolen from quake
{
va_list argptr ;
static char string [ 1024 ] ;
va_start ( argptr , format ) ;
vsprintf ( string , format , argptr ) ;
va_end ( argptr ) ;
return string ;
}
# define dprintf printf
# define wprintf printf
# define twprintf printf
# define COLOURGREEN ""
# define COMMANDPREFIX ""
# define playsound(s)
# define IRC_Malloc malloc
# define IRC_Free free
# define TL_NETGETPACKETERROR "NET_GetPacket Error %s\n"
# define TOKENSIZE 1024
char com_token [ TOKENSIZE ] ;
char * COM_Parse ( char * data ) //this is taken out of quake
{
int c ;
int len ;
len = 0 ;
com_token [ 0 ] = 0 ;
if ( ! data )
return NULL ;
// skip whitespace
skipwhite :
while ( ( c = * data ) < = ' ' )
{
if ( c = = 0 )
return NULL ; // end of file;
data + + ;
}
// skip // comments
if ( c = = ' / ' )
{
if ( data [ 1 ] = = ' / ' )
{
while ( * data & & * data ! = ' \n ' )
data + + ;
goto skipwhite ;
}
}
// handle quoted strings specially
if ( c = = ' \" ' )
{
data + + ;
while ( 1 )
{
if ( len > = TOKENSIZE - 1 )
return data ;
c = * data + + ;
if ( c = = ' \" ' | | ! c )
{
com_token [ len ] = 0 ;
return data ;
}
com_token [ len ] = c ;
len + + ;
}
}
// parse a regular word
do
{
if ( len > = TOKENSIZE - 1 )
return data ;
com_token [ len ] = c ;
data + + ;
len + + ;
c = * data ;
} while ( c > 32 ) ;
com_token [ len ] = 0 ;
return data ;
}
# elif defined(QUAKE2) //client
# include "client.h"
# define printf Com_Printf
# define dprintf Com_DPrintf
# define wprintf Com_Printf
# define COLOURGREEN ""
# define COMMANDPREFIX "irc "
# define playsound(s) S_StartLocalSound(s)
# define IRC_Calloc Z_Malloc
# define IRC_Free Z_Free
# define TL_NETGETPACKETERROR "NET_GetPacket Error %s\n"
# elif 1 //FTE based exe
# include "../http/iweb.h"
# define printf IWebPrintf
# define dprintf IWebDPrintf
# define wprintf IWebWarnPrintf
# define twprintf Con_TPrintf
# define COLOURGREEN "^2"
# define COMMANDPREFIX "irc "
# define playsound(s) S_LocalSound(s)
# define IRC_Malloc IWebMalloc
# define IRC_Free IWebFree
# else
# error "Bad porting target"
# endif
//functions are geared towards windows because windows is fussiest.
//constants towards unix cos they are more proper
# ifdef _WIN32
# include <winsock.h>
# define EWOULDBLOCK WSAEWOULDBLOCK
# define EMSGSIZE WSAEMSGSIZE
# define ECONNRESET WSAECONNRESET
# define ECONNABORTED WSAECONNABORTED
# define ECONNREFUSED WSAECONNREFUSED
# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
# define qerrno WSAGetLastError()
# else
# define qerrno errno
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# include <sys/param.h>
# include <sys/ioctl.h>
# include <sys/uio.h>
# include <arpa/inet.h>
# include <errno.h>
# include <unistd.h>
# ifdef sun
# include <sys/filio.h>
# endif
# ifdef NeXT
# include <libc.h>
# endif
# define closesocket close
# define ioctlsocket ioctl
# endif
int IRC_StringToSockaddr ( char * s , struct sockaddr * sadr ) //From Quake2
{
struct hostent * h ;
char * colon ;
char copy [ 128 ] ;
memset ( sadr , 0 , sizeof ( * sadr ) ) ;
( ( struct sockaddr_in * ) sadr ) - > sin_family = AF_INET ;
( ( struct sockaddr_in * ) sadr ) - > sin_port = 0 ;
strcpy ( copy , s ) ;
// strip off a trailing :port if present
for ( colon = copy ; * colon ; colon + + )
if ( * colon = = ' : ' )
{
* colon = 0 ;
( ( struct sockaddr_in * ) sadr ) - > sin_port = htons ( ( short ) atoi ( colon + 1 ) ) ;
}
if ( copy [ 0 ] > = ' 0 ' & & copy [ 0 ] < = ' 9 ' )
{
* ( int * ) & ( ( struct sockaddr_in * ) sadr ) - > sin_addr = inet_addr ( copy ) ;
}
else
{
if ( ! ( h = gethostbyname ( copy ) ) )
return 0 ;
* ( int * ) & ( ( struct sockaddr_in * ) sadr ) - > sin_addr = * ( int * ) h - > h_addr_list [ 0 ] ;
}
return true ;
}
//\r\n is used to end a line.
//meaning \0s are valid.
//but never used cos it breaks strings
# define IRC_MAXNICKLEN 32 //9 and a null term
# define IRC_MAXMSGLEN 512
char defaultnick [ IRC_MAXNICKLEN + 1 ] ;
typedef struct {
char server [ 64 ] ;
int port ;
int socket ;
char nick [ IRC_MAXNICKLEN ] ;
char pwd [ 64 ] ;
char realname [ 128 ] ;
char hostname [ 128 ] ;
char defaultdest [ IRC_MAXNICKLEN ] ; //channel or nick
char bufferedinmessage [ IRC_MAXMSGLEN + 1 ] ; //there is a max size for protocol. (conveinient eh?) (and it's text format)
int bufferedinammount ;
} ircclient_t ;
ircclient_t * ircclient ;
void IRC_AddClientMessage ( ircclient_t * irc , char * msg )
{
send ( irc - > socket , msg , strlen ( msg ) , 0 ) ; //FIXME: This needs rewriting to cope with errors.
}
ircclient_t * IRC_Connect ( char * server , int port )
{
ircclient_t * irc ;
unsigned long _true = true ;
struct sockaddr_in from ;
irc = IRC_Malloc ( sizeof ( ircclient_t ) ) ;
if ( ! irc )
return NULL ;
memset ( irc , 0 , sizeof ( ircclient_t ) ) ;
if ( ( irc - > socket = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ) = = - 1 )
{
wprintf ( " IRC_TCP_OpenSocket: socket: %s \n " , strerror ( qerrno ) ) ;
return NULL ;
}
IRC_StringToSockaddr ( server , ( struct sockaddr * ) & from ) ;
//not yet blocking. So no frequent attempts please...
//non blocking prevents connect from returning worthwhile sensible value.
if ( connect ( irc - > socket , ( struct sockaddr * ) & from , sizeof ( from ) ) = = - 1 )
{
wprintf ( " IRC_TCP_OpenSocket: connect: %i %s \n " , qerrno , strerror ( qerrno ) ) ;
closesocket ( irc - > socket ) ;
IRC_Free ( irc ) ;
return NULL ;
}
if ( ioctlsocket ( irc - > socket , FIONBIO , & _true ) = = - 1 ) //now make it non blocking.
{
wprintf ( " IRC_TCP_OpenSocket: ioctl FIONBIO: %s \n " , strerror ( qerrno ) ) ;
return NULL ;
}
Q_strncpyz ( irc - > server , server , sizeof ( irc - > server ) ) ;
strcpy ( irc - > nick , " anonymous " ) ;
strcpy ( irc - > realname , " anonymous " ) ;
gethostname ( irc - > hostname , sizeof ( irc - > hostname ) ) ;
irc - > hostname [ sizeof ( irc - > hostname ) - 1 ] = 0 ;
return irc ;
}
void IRC_SetPass ( ircclient_t * irc , char * pass )
{
IRC_AddClientMessage ( irc , va ( " PASS %s \r \n " , pass ) ) ;
}
void IRC_SetNick ( ircclient_t * irc , char * nick )
{
IRC_AddClientMessage ( irc , va ( " NICK %s \r \n " , nick ) ) ;
}
void IRC_SetUser ( ircclient_t * irc , char * user )
{
IRC_AddClientMessage ( irc , va ( " USER %s %s %s :%s \r \n " , user , irc - > hostname , irc - > server , " Something " ) ) ;
}
# define IRC_DONE 0
# define IRC_CONTINUE 1
# define IRC_KILL 2
int IRC_ClientFrame ( ircclient_t * irc )
{
char prefix [ 64 ] ;
int ret ;
char * nextmsg , * msg ;
ret = recv ( irc - > socket , irc - > bufferedinmessage + irc - > bufferedinammount , sizeof ( irc - > bufferedinmessage ) - 1 - irc - > bufferedinammount , 0 ) ;
if ( ret = = 0 )
return IRC_KILL ;
if ( ret = = - 1 )
{
if ( qerrno = = EWOULDBLOCK )
{
if ( ! irc - > bufferedinammount ) //if we are half way through a message, read any possible conjunctions.
return IRC_DONE ; //remove
}
else
{
if ( qerrno = = ECONNABORTED | | qerrno = = ECONNRESET )
return IRC_KILL ;
twprintf ( TL_NETGETPACKETERROR , strerror ( qerrno ) ) ;
return IRC_KILL ;
}
}
if ( ret > 0 )
irc - > bufferedinammount + = ret ;
irc - > bufferedinmessage [ irc - > bufferedinammount ] = ' \0 ' ;
nextmsg = strstr ( irc - > bufferedinmessage , " \r \n " ) ;
if ( ! nextmsg )
return IRC_DONE ;
* nextmsg = ' \0 ' ;
nextmsg + = 2 ;
msg = irc - > bufferedinmessage ;
if ( * msg = = ' : ' ) //we need to strip off the prefix
{
char * sp = strchr ( msg , ' ' ) ;
if ( ! sp )
{
dprintf ( " Ignoring bad message \n %s \n " , msg ) ;
memmove ( irc - > bufferedinmessage , nextmsg , irc - > bufferedinammount - ( msg - irc - > bufferedinmessage ) ) ;
irc - > bufferedinammount - = nextmsg - irc - > bufferedinmessage ;
return IRC_CONTINUE ;
}
if ( sp - msg > = sizeof ( prefix ) )
Q_strncpyz ( prefix , msg + 1 , sizeof ( prefix ) ) ;
else
Q_strncpyz ( prefix , msg + 1 , sp - msg ) ;
msg = sp ;
while ( * msg = = ' ' )
msg + + ;
}
else
strcpy ( prefix , irc - > server ) ;
if ( ! strncmp ( msg , " PING " , 5 ) )
{
dprintf ( " %s \n " , msg ) ;
IRC_AddClientMessage ( irc , va ( " PONG %s \r \n " , msg + 5 ) ) ;
}
else if ( ! strncmp ( msg , " PRIVMSG " , 7 ) | | ! strncmp ( msg , " NOTICE " , 6 ) ) //no autoresponses to notice please, and any autoresponses should be in the form of a notice
{
char * exc = strchr ( prefix , ' ! ' ) ;
char * col = strchr ( msg + 6 , ' : ' ) ;
playsound ( " misc/talk.wav " ) ;
if ( exc & & col )
{
* exc = ' \0 ' ;
printf ( COLOURGREEN " %s: %s \n " , prefix , col + 1 ) ; //from client
}
else dprintf ( COLOURGREEN " :%s%s \n " , prefix , msg ) ; //direct server message
}
else if ( ! strncmp ( msg , " NICK " , 5 ) )
{
char * exc = strchr ( prefix , ' ! ' ) ;
char * col = strchr ( msg + 6 , ' : ' ) ;
if ( exc & & col )
{
* exc = ' \0 ' ;
printf ( COLOURGREEN " %s changes name to %s \n " , prefix , col + 1 ) ;
}
else dprintf ( COLOURGREEN " :%s%s \n " , prefix , msg + 6 ) ;
}
else if ( ! strncmp ( msg , " PART " , 5 ) )
{
char * exc = strchr ( prefix , ' ! ' ) ;
char * col = strchr ( msg + 5 , ' : ' ) ;
if ( ! col )
col = msg + 5 ;
else col + = 1 ;
if ( exc )
{
* exc = ' \0 ' ;
printf ( COLOURGREEN " %s leaves channel %s \n " , prefix , col ) ;
}
else dprintf ( COLOURGREEN " :%sPART %s \n " , prefix , msg + 5 ) ;
}
else if ( ! strncmp ( msg , " JOIN " , 5 ) )
{
char * exc = strchr ( prefix , ' ! ' ) ;
char * col = strchr ( msg + 5 , ' : ' ) ;
if ( exc & & col )
{
* exc = ' \0 ' ;
printf ( COLOURGREEN " %s joins channel %s \n " , prefix , col + 1 ) ;
}
else dprintf ( COLOURGREEN " :%sJOIN %s \n " , prefix , msg + 5 ) ;
}
else if ( ! strncmp ( msg , " 322 " , 4 ) ) //channel listing
{
dprintf ( " %s \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 375 " , 4 ) )
{
dprintf ( " %s \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 431 " , 4 ) )
{
dprintf ( " You need to specify a nickname \n " ) ;
}
else if ( ! strncmp ( msg , " 432 " , 4 ) )
{
dprintf ( " Erroneous/invalid nickname given \n " ) ;
}
else if ( ! strncmp ( msg , " 433 " , 4 ) )
{
dprintf ( " Nickname is already in use by someone \n " ) ;
}
else if ( ! strncmp ( msg , " 436 " , 4 ) )
{
dprintf ( " Nickname collision. You will probably need to reconnect \n " ) ;
}
else if ( ! strncmp ( msg , " 372 " , 4 ) )
{
char * text = strstr ( msg , " :- " ) ;
if ( text )
dprintf ( " %s \n " , text + 2 ) ;
else
dprintf ( " %s \n " , msg ) ;
}
/*
else if ( ! strncmp ( msg , " 401 " , 4 ) )
{
dprintf ( " Nickname/channel does not exist \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 402 " , 4 ) )
{
dprintf ( " No such server \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 403 " , 4 ) )
{
dprintf ( " No such channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 404 " , 4 ) )
{
dprintf ( " Cannot send to that channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 405 " , 4 ) )
{
dprintf ( " You may not join annother channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 406 " , 4 ) )
{
dprintf ( " Nickname does not exist \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 407 " , 4 ) )
{
dprintf ( " Too many targets. Try to specify a specific nickname. \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 409 " , 4 ) )
{
dprintf ( " No origin specified \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 411 " , 4 ) )
{
dprintf ( " No recipient given. \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 412 " , 4 ) )
{
dprintf ( " No text given \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 413 " , 4 ) )
{
dprintf ( " No top level domain specified \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 414 " , 4 ) )
{
dprintf ( " Wildcard in toplevel domain \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 421 " , 4 ) )
{
dprintf ( " Unknown command. \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 422 " , 4 ) )
{
dprintf ( " MOTD file is missing (awww) \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 423 " , 4 ) )
{
dprintf ( " No administrative info is available \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 424 " , 4 ) )
{
dprintf ( " Generic file error \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 441 " , 4 ) )
{
dprintf ( " User isn't in that channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 442 " , 4 ) )
{
dprintf ( " You are not on that channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 443 " , 4 ) )
{
dprintf ( " The user is already on that channel \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 444 " , 4 ) )
{
dprintf ( " User not logged in \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 445 " , 4 ) )
{
dprintf ( " SUMMON has been disabled \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 446 " , 4 ) )
{
dprintf ( " USERS has been disabled \n " , msg ) ;
}
else if ( ! strncmp ( msg , " 451 " , 4 ) )
{
dprintf ( " You have not registered \n " , msg ) ;
}
461 ERR_NEEDMOREPARAMS
" <command> :Not enough parameters "
- Returned by the server by numerous commands to
indicate to the client that it didn ' t supply enough
parameters .
462 ERR_ALREADYREGISTRED
" :You may not reregister "
- Returned by the server to any link which tries to
change part of the registered details ( such as
password or user details from second USER message ) .
463 ERR_NOPERMFORHOST
" :Your host isn't among the privileged "
- Returned to a client which attempts to register with
a server which does not been setup to allow
connections from the host the attempted connection
is tried .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 47
464 ERR_PASSWDMISMATCH
" :Password incorrect "
- Returned to indicate a failed attempt at registering
a connection for which a password was required and
was either not given or incorrect .
465 ERR_YOUREBANNEDCREEP
" :You are banned from this server "
- Returned after an attempt to connect and register
yourself with a server which has been setup to
explicitly deny connections to you .
467 ERR_KEYSET
" <channel> :Channel key already set "
471 ERR_CHANNELISFULL
" <channel> :Cannot join channel (+l) "
472 ERR_UNKNOWNMODE
" <char> :is unknown mode char to me "
473 ERR_INVITEONLYCHAN
" <channel> :Cannot join channel (+i) "
474 ERR_BANNEDFROMCHAN
" <channel> :Cannot join channel (+b) "
475 ERR_BADCHANNELKEY
" <channel> :Cannot join channel (+k) "
481 ERR_NOPRIVILEGES
" :Permission Denied- You're not an IRC operator "
- Any command requiring operator privileges to operate
must return this error to indicate the attempt was
unsuccessful .
482 ERR_CHANOPRIVSNEEDED
" <channel> :You're not channel operator "
- Any command requiring ' chanop ' privileges ( such as
MODE messages ) must return this error if the client
making the attempt is not a chanop on the specified
channel .
483 ERR_CANTKILLSERVER
" :You cant kill a server! "
- Any attempts to use the KILL command on a server
are to be refused and this error returned directly
to the client .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 48
491 ERR_NOOPERHOST
" :No O-lines for your host "
- If a client sends an OPER message and the server has
not been configured to allow connections from the
client ' s host as an operator , this error must be
returned .
501 ERR_UMODEUNKNOWNFLAG
" :Unknown MODE flag "
- Returned by the server to indicate that a MODE
message was sent with a nickname parameter and that
the a mode flag sent was not recognized .
502 ERR_USERSDONTMATCH
" :Cant change mode for other users "
- Error sent to any user trying to view or change the
user mode for a user other than themselves .
6.2 Command responses .
300 RPL_NONE
Dummy reply number . Not used .
302 RPL_USERHOST
" :[<reply>{<space><reply>}] "
- Reply format used by USERHOST to list replies to
the query list . The reply string is composed as
follows :
< reply > : : = < nick > [ ' * ' ] ' = ' < ' + ' | ' - ' > < hostname >
The ' * ' indicates whether the client has registered as an Operator . The ' - ' or ' + ' characters represent whether the client has set an AWAY message or not respectively .
303 RPL_ISON
" :[<nick> {<space><nick>}] "
- Reply format used by ISON to list replies to the
query list .
301 RPL_AWAY
" <nick> :<away message> "
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 49
305 RPL_UNAWAY
" :You are no longer marked as being away "
306 RPL_NOWAWAY
" :You have been marked as being away "
- These replies are used with the AWAY command ( if
allowed ) . RPL_AWAY is sent to any client sending a
PRIVMSG to a client which is away . RPL_AWAY is only
sent by the server to which the client is connected .
Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
client removes and sets an AWAY message .
311 RPL_WHOISUSER
" <nick> <user> <host> * :<real name> "
312 RPL_WHOISSERVER
" <nick> <server> :<server info> "
313 RPL_WHOISOPERATOR
" <nick> :is an IRC operator "
317 RPL_WHOISIDLE
" <nick> <integer> :seconds idle "
318 RPL_ENDOFWHOIS
" <nick> :End of /WHOIS list "
319 RPL_WHOISCHANNELS
" <nick> :{[@|+]<channel><space>} "
- Replies 311 - 313 , 317 - 319 are all replies
generated in response to a WHOIS message . Given that
there are enough parameters present , the answering
server must either formulate a reply out of the above
numerics ( if the query nick is found ) or return an
error reply . The ' * ' in RPL_WHOISUSER is there as
the literal character and not as a wild card . For
each reply set , only RPL_WHOISCHANNELS may appear
more than once ( for long lists of channel names ) .
The ' @ ' and ' + ' characters next to the channel name
indicate whether a client is a channel operator or
has been granted permission to speak on a moderated
channel . The RPL_ENDOFWHOIS reply is used to mark
the end of processing a WHOIS message .
314 RPL_WHOWASUSER
" <nick> <user> <host> * :<real name> "
369 RPL_ENDOFWHOWAS
" <nick> :End of WHOWAS "
- When replying to a WHOWAS message , a server must use
the replies RPL_WHOWASUSER , RPL_WHOISSERVER or
ERR_WASNOSUCHNICK for each nickname in the presented
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 50
list . At the end of all reply batches , there must be RPL_ENDOFWHOWAS ( even if there was only one reply and it was an error ) .
321 RPL_LISTSTART
" Channel :Users Name "
322 RPL_LIST
" <channel> <# visible> :<topic> "
323 RPL_LISTEND
" :End of /LIST "
- Replies RPL_LISTSTART , RPL_LIST , RPL_LISTEND mark
the start , actual replies with data and end of the
server ' s response to a LIST command . If there are
no channels available to return , only the start
and end reply must be sent .
324 RPL_CHANNELMODEIS
" <channel> <mode> <mode params> "
331 RPL_NOTOPIC
" <channel> :No topic is set "
332 RPL_TOPIC
" <channel> :<topic> "
- When sending a TOPIC message to determine the
channel topic , one of two replies is sent . If
the topic is set , RPL_TOPIC is sent back else
RPL_NOTOPIC .
341 RPL_INVITING
" <channel> <nick> "
- Returned by the server to indicate that the
attempted INVITE message was successful and is
being passed onto the end client .
342 RPL_SUMMONING
" <user> :Summoning user to IRC "
- Returned by a server answering a SUMMON message to
indicate that it is summoning that user .
351 RPL_VERSION
" <version>.<debuglevel> <server> :<comments> "
- Reply by the server showing its version details .
The < version > is the version of the software being
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 51
used ( including any patchlevel revisions ) and the
< debuglevel > is used to indicate if the server is
running in " debug mode " .
The " comments " field may contain any comments about the version or further version details .
352 RPL_WHOREPLY
" <channel> <user> <host> <server> <nick> \
< H | G > [ * ] [ @ | + ] : < hopcount > < real name > "
315 RPL_ENDOFWHO
" <name> :End of /WHO list "
- The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
to answer a WHO message . The RPL_WHOREPLY is only
sent if there is an appropriate match to the WHO
query . If there is a list of parameters supplied
with a WHO message , a RPL_ENDOFWHO must be sent
after processing each list item with < name > being
the item .
353 RPL_NAMREPLY
" <channel> :[[@|+]<nick> [[@|+]<nick> [...]]] "
366 RPL_ENDOFNAMES
" <channel> :End of /NAMES list "
- To reply to a NAMES message , a reply pair consisting
of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
server back to the client . If there is no channel
found as in the query , then only RPL_ENDOFNAMES is
returned . The exception to this is when a NAMES
message is sent with no parameters and all visible
channels and contents are sent back in a series of
RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
the end .
364 RPL_LINKS
" <mask> <server> :<hopcount> <server info> "
365 RPL_ENDOFLINKS
" <mask> :End of /LINKS list "
- In replying to the LINKS message , a server must send
replies back using the RPL_LINKS numeric and mark the
end of the list using an RPL_ENDOFLINKS reply .
367 RPL_BANLIST
" <channel> <banid> "
368 RPL_ENDOFBANLIST
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 52
" <channel> :End of channel ban list "
- When listing the active ' bans ' for a given channel ,
a server is required to send the list back using the
RPL_BANLIST and RPL_ENDOFBANLIST messages . A separate
RPL_BANLIST is sent for each active banid . After the
banids have been listed ( or if none present ) a
RPL_ENDOFBANLIST must be sent .
371 RPL_INFO
" :<string> "
374 RPL_ENDOFINFO
" :End of /INFO list "
- A server responding to an INFO message is required to
send all its ' info ' in a series of RPL_INFO messages
with a RPL_ENDOFINFO reply to indicate the end of the
replies .
375 RPL_MOTDSTART
" :- <server> Message of the day - "
376 RPL_ENDOFMOTD
" :End of /MOTD command "
- When responding to the MOTD message and the MOTD file
is found , the file is displayed line by line , with
each line no longer than 80 characters , using
RPL_MOTD format replies . These should be surrounded
by a RPL_MOTDSTART ( before the RPL_MOTDs ) and an
RPL_ENDOFMOTD ( after ) .
381 RPL_YOUREOPER
" :You are now an IRC operator "
- RPL_YOUREOPER is sent back to a client which has
just successfully issued an OPER message and gained
operator status .
382 RPL_REHASHING
" <config file> :Rehashing "
- If the REHASH option is used and an operator sends
a REHASH message , an RPL_REHASHING is sent back to
the operator .
391 RPL_TIME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 53
" <server> :<string showing server's local time> "
- When replying to the TIME message , a server must send
the reply using the RPL_TIME format above . The string
showing the time need only contain the correct day and
time there . There is no further requirement for the
time string .
392 RPL_USERSSTART
" :UserID Terminal Host "
393 RPL_USERS
" :%-8s %-9s %-8s "
394 RPL_ENDOFUSERS
" :End of users "
395 RPL_NOUSERS
" :Nobody logged in "
- If the USERS message is handled by a server , the
replies RPL_USERSTART , RPL_USERS , RPL_ENDOFUSERS and
RPL_NOUSERS are used . RPL_USERSSTART must be sent
first , following by either a sequence of RPL_USERS
or a single RPL_NOUSER . Following this is
RPL_ENDOFUSERS .
200 RPL_TRACELINK
" Link <version & debug level> <destination> \
< next server > "
201 RPL_TRACECONNECTING
" Try. <class> <server> "
202 RPL_TRACEHANDSHAKE
" H.S. <class> <server> "
203 RPL_TRACEUNKNOWN
" ???? <class> [<client IP address in dot form>] "
204 RPL_TRACEOPERATOR
" Oper <class> <nick> "
205 RPL_TRACEUSER
" User <class> <nick> "
206 RPL_TRACESERVER
" Serv <class> <int>S <int>C <server> \
< nick ! user | * ! * > @ < host | server > "
208 RPL_TRACENEWTYPE
" <newtype> 0 <client name> "
261 RPL_TRACELOG
" File <logfile> <debug level> "
- The RPL_TRACE * are all returned by the server in
response to the TRACE message . How many are
returned is dependent on the the TRACE message and
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 54
whether it was sent by an operator or not . There is no predefined order for which occurs first . Replies RPL_TRACEUNKNOWN , RPL_TRACECONNECTING and RPL_TRACEHANDSHAKE are all used for connections which have not been fully established and are either unknown , still attempting to connect or in the process of completing the ' server handshake ' . RPL_TRACELINK is sent by any server which handles a TRACE message and has to pass it on to another server . The list of RPL_TRACELINKs sent in response to a TRACE command traversing the IRC network should reflect the actual connectivity of the servers themselves along that path .
RPL_TRACENEWTYPE is to be used for any connection which does not fit in the other categories but is being displayed anyway .
211 RPL_STATSLINKINFO
" <linkname> <sendq> <sent messages> \
< sent bytes > < received messages > \
< received bytes > < time open > "
212 RPL_STATSCOMMANDS
" <command> <count> "
213 RPL_STATSCLINE
" C <host> * <name> <port> <class> "
214 RPL_STATSNLINE
" N <host> * <name> <port> <class> "
215 RPL_STATSILINE
" I <host> * <host> <port> <class> "
216 RPL_STATSKLINE
" K <host> * <username> <port> <class> "
218 RPL_STATSYLINE
" Y <class> <ping frequency> <connect \
frequency > < max sendq > "
219 RPL_ENDOFSTATS
" <stats letter> :End of /STATS report "
241 RPL_STATSLLINE
" L <hostmask> * <servername> <maxdepth> "
242 RPL_STATSUPTIME
" :Server Up %d days %d:%02d:%02d "
243 RPL_STATSOLINE
" O <hostmask> * <name> "
244 RPL_STATSHLINE
" H <hostmask> * <servername> "
221 RPL_UMODEIS
" <user mode string> "
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 55
- To answer a query about a client ' s own mode ,
RPL_UMODEIS is sent back .
251 RPL_LUSERCLIENT
" :There are <integer> users and <integer> \
invisible on < integer > servers "
252 RPL_LUSEROP
" <integer> :operator(s) online "
253 RPL_LUSERUNKNOWN
" <integer> :unknown connection(s) "
254 RPL_LUSERCHANNELS
" <integer> :channels formed "
255 RPL_LUSERME
" :I have <integer> clients and <integer> \
servers "
- In processing an LUSERS message , the server
sends a set of replies from RPL_LUSERCLIENT ,
RPL_LUSEROP , RPL_USERUNKNOWN ,
RPL_LUSERCHANNELS and RPL_LUSERME . When
replying , a server must send back
RPL_LUSERCLIENT and RPL_LUSERME . The other
replies are only sent back if a non - zero count
is found for them .
256 RPL_ADMINME
" <server> :Administrative info "
257 RPL_ADMINLOC1
" :<admin info> "
258 RPL_ADMINLOC2
" :<admin info> "
259 RPL_ADMINEMAIL
" :<admin info> "
- When replying to an ADMIN message , a server
is expected to use replies RLP_ADMINME
through to RPL_ADMINEMAIL and provide a text
message with each . For RPL_ADMINLOC1 a
description of what city , state and country
the server is in is expected , followed by
details of the university and department
( RPL_ADMINLOC2 ) and finally the administrative
contact for the server ( an email address here
is required ) in RPL_ADMINEMAIL .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Page 56
6.3 Reserved numerics .
These numerics are not described above since they fall into one of the following categories :
1 no longer in use ;
2 reserved for future planned use ;
3 in current use but are part of a non - generic ' feature ' of
the current IRC server .
209 RPL_TRACECLASS 217 RPL_STATSQLINE
231 RPL_SERVICEINFO 232 RPL_ENDOFSERVICES
233 RPL_SERVICE 234 RPL_SERVLIST
235 RPL_SERVLISTEND
316 RPL_WHOISCHANOP 361 RPL_KILLDONE
362 RPL_CLOSING 363 RPL_CLOSEEND
373 RPL_INFOSTART 384 RPL_MYPORTIS
466 ERR_YOUWILLBEBANNED 476 ERR_BADCHANMASK
492 ERR_NOSERVICEHOST
*/
else
dprintf ( " %s \n " , msg ) ;
memmove ( irc - > bufferedinmessage , nextmsg , irc - > bufferedinammount - ( msg - irc - > bufferedinmessage ) ) ;
irc - > bufferedinammount - = nextmsg - irc - > bufferedinmessage ;
return IRC_CONTINUE ;
}
//functions above this line allow connections to multiple servers.
//it is just the control functions that only allow one server.
void IRC_Frame ( void )
{
int stat = IRC_CONTINUE ;
if ( ircclient )
{
while ( stat = = IRC_CONTINUE )
stat = IRC_ClientFrame ( ircclient ) ;
if ( stat = = IRC_KILL )
{
closesocket ( ircclient - > socket ) ;
IRC_Free ( ircclient ) ;
ircclient = NULL ;
Con_Printf ( " Disconnected from irc \n " ) ;
}
}
}
void IRC_Command ( char * imsg )
{
char * msg ;
msg = COM_Parse ( imsg ) ;
if ( * com_token = = ' / ' )
{
if ( ! strcmp ( com_token + 1 , " open " ) | | ! strcmp ( com_token + 1 , " connect " ) )
{
if ( ircclient )
{
printf ( " You are already connected \n Please /quit first " ) ;
return ;
}
msg = COM_Parse ( msg ) ;
ircclient = IRC_Connect ( com_token , 8080 ) ;
if ( ircclient )
{
char username [ 512 ] = " Unknown User " ;
# ifdef _WIN32
DWORD blen = sizeof ( username ) - 1 ;
# endif
printf ( " Trying to connect \n " ) ;
# ifdef _WIN32
GetUserName ( username , & blen ) ;
# endif
IRC_SetPass ( ircclient , " " ) ;
IRC_SetNick ( ircclient , defaultnick ) ;
IRC_SetUser ( ircclient , username ) ;
}
}
else if ( ! strcmp ( com_token + 1 , " nick " ) )
{
msg = COM_Parse ( msg ) ;
Q_strncpyz ( defaultnick , com_token , sizeof ( defaultnick ) ) ;
if ( ircclient )
IRC_SetNick ( ircclient , defaultnick ) ;
}
else if ( ! strcmp ( com_token + 1 , " list " ) )
{
if ( ircclient )
IRC_AddClientMessage ( ircclient , " LIST \r \n " ) ;
else
printf ( " Not connected \n " ) ;
}
else if ( ! strcmp ( com_token + 1 , " join " ) )
{
msg = COM_Parse ( msg ) ;
if ( ircclient )
IRC_AddClientMessage ( ircclient , va ( " JOIN %s \r \n " , com_token ) ) ;
else
printf ( " Not connected \n " ) ;
}
else if ( ! strcmp ( com_token + 1 , " part " ) | | ! strcmp ( com_token + 1 , " leave " ) )
{
msg = COM_Parse ( msg ) ;
if ( ircclient )
IRC_AddClientMessage ( ircclient , va ( " PART %s \r \n " , com_token ) ) ;
else
printf ( " Not connected \n " ) ;
}
else if ( ! strcmp ( com_token + 1 , " msg " ) )
{
msg = COM_Parse ( msg ) ;
if ( ircclient )
IRC_AddClientMessage ( ircclient , va ( " PRIVMSG %s :%s \r \n " , com_token , msg ) ) ;
else
printf ( " Not connected \n " ) ;
}
else if ( ! strcmp ( com_token + 1 , " quote " ) )
{
if ( ircclient )
IRC_AddClientMessage ( ircclient , va ( " %s \r \n " , msg ) ) ;
else
printf ( " Not connected \n " ) ;
}
else if ( ! strcmp ( com_token + 1 , " quit " ) )
{
if ( ircclient )
IRC_AddClientMessage ( ircclient , va ( " QUIT \r \n " ) ) ;
else
printf ( " Not connected \n " ) ;
}
}
else
{
if ( ircclient )
{
IRC_AddClientMessage ( ircclient , va ( " PRIVMSG %s :%s \r \n " , imsg ) ) ;
}
else
printf ( " Not connected \n type \" " COMMANDPREFIX " /open IRCSERVER \" to connect \n " ) ;
}
}
# endif