2020-06-22 16:58:10 +00:00
/*
* This file is part of uIRC . ( https : //git.redxen.eu/caskd/uIRC)
* Copyright ( c ) 2019 , 2020 Alex - David Denes
*
* uIRC is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* any later version .
*
* uIRC is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with uIRC . If not , see < https : //www.gnu.org/licenses/>.
*/
# include "uirc.h"
const char * uirc_ircmd [ ] = {
[ PASS ] = " PASS " ,
[ NICK ] = " NICK " ,
[ USER ] = " USER " ,
[ SERVER ] = " SERVER " ,
[ OPER ] = " OPER " ,
[ QUIT ] = " QUIT " ,
[ SQUIT ] = " SQUIT " ,
[ JOIN ] = " JOIN " ,
[ PART ] = " PART " ,
[ MODE ] = " MODE " ,
[ TOPIC ] = " TOPIC " ,
[ NAMES ] = " NAMES " ,
[ LIST ] = " LIST " ,
[ INVITE ] = " INVITE " ,
[ KICK ] = " KICK " ,
[ VERSION ] = " VERSION " ,
[ STATS ] = " STATS " ,
[ LINKS ] = " LINKS " ,
[ TIME ] = " TIME " ,
[ CONNECT ] = " CONNECT " ,
[ TRACE ] = " TRACE " ,
[ ADMIN ] = " ADMIN " ,
[ INFO ] = " INFO " ,
[ PRIVMSG ] = " PRIVMSG " ,
[ NOTICE ] = " NOTICE " ,
[ WHO ] = " WHO " ,
[ WHOIS ] = " WHOIS " ,
[ WHOWAS ] = " WHOWAS " ,
[ KILL ] = " KILL " ,
[ PING ] = " PING " ,
[ PONG ] = " PONG " ,
[ ERROR ] = " ERROR " ,
[ AWAY ] = " AWAY " ,
[ REHASH ] = " REHASH " ,
[ RESTART ] = " RESTART " ,
[ SUMMON ] = " SUMMON " ,
[ USERS ] = " USERS " ,
[ WALLOPS ] = " WALLOPS " ,
[ USERHOST ] = " USERHOST " ,
[ ISON ] = " ISON " } ;
2020-06-25 19:06:53 +00:00
2020-06-27 12:30:15 +00:00
struct tagmapping {
char * name ;
IRC_Tag * assg ;
} ;
2020-06-27 19:07:59 +00:00
int uirc_tokenize_message ( IRC_Message * irc_msg , char * * line )
2020-06-22 16:58:10 +00:00
{
2020-06-27 19:07:59 +00:00
char * progr = * line , * command ;
2020-06-22 16:58:10 +00:00
2020-06-22 16:59:23 +00:00
if ( * progr = = ' @ ' ) {
char * tags ;
2020-06-27 13:30:04 +00:00
if ( ( tags = tokspace ( progr , & progr ) ) ! = NULL ) {
if ( ! tagmgr ( & tags , irc_msg , true ) )
return - 1 ;
2020-06-22 16:59:23 +00:00
} else
return 0 ;
}
2020-06-22 16:58:10 +00:00
if ( * progr = = ' : ' ) {
char * prefix ;
2020-06-28 15:19:38 +00:00
if ( ( prefix = tokspace ( progr , & progr ) ) ! = NULL ) {
if ( ! tok_prefix ( prefix , & irc_msg - > name ) )
return 0 ;
2020-06-22 16:59:23 +00:00
} else
return 0 ;
2020-06-22 16:58:10 +00:00
}
2020-06-27 11:33:35 +00:00
command = tokspace ( progr , & progr ) ;
2020-06-22 16:58:10 +00:00
if ( isalpha ( * command ) ) {
if ( ! ( irc_msg - > cmd = uirc_ircmd_stoi ( command ) ) )
return 0 ;
} else if ( isdigit ( * command ) ) {
if ( ( irc_msg - > cmd = atoi ( command ) ) = = 0 )
return 0 ;
} else {
return 0 ;
}
2020-06-28 15:19:38 +00:00
if ( progr = = NULL )
return 1 ;
2020-06-22 16:58:10 +00:00
int i ;
for ( i = 0 ; * progr ! = ' : ' & & i < 14 ; i + + ) {
2020-06-27 19:07:59 +00:00
if ( ( irc_msg - > args [ i ] = strtok_r ( NULL , " : " , & progr ) ) = = NULL )
2020-06-22 16:58:10 +00:00
return 0 ;
}
2020-06-25 19:06:53 +00:00
irc_msg - > args [ i ] = NULL ;
2020-06-22 16:58:10 +00:00
if ( * progr = = ' : ' )
+ + progr ;
2020-06-27 11:33:35 +00:00
irc_msg - > trailing = progr ;
2020-06-22 16:58:10 +00:00
return 1 ;
}
unsigned int uirc_ircmd_stoi ( char * str )
{
for ( unsigned short i = PASS ; i < = ISON ; i + + ) {
if ( strcmp ( uirc_ircmd [ i ] , str ) = = 0 )
return i ;
}
return 0 ;
}
2020-06-25 19:06:53 +00:00
int uirc_assm_mesg ( char * buf , IRC_Message * mesg )
2020-06-22 16:58:10 +00:00
{
if ( buf = = NULL )
return - 2 ;
2020-06-25 19:06:53 +00:00
char * pos = buf ;
int cnt ;
2020-06-27 13:30:04 +00:00
if ( ! tagmgr ( & pos , mesg , false ) )
return - 1 ;
2020-06-27 19:07:59 +00:00
if ( mesg - > name . nick | | mesg - > name . host ) {
2020-06-28 15:19:38 +00:00
if ( ! assm_prefix ( & pos , & mesg - > name ) )
return 0 ;
2020-06-27 19:07:59 +00:00
}
2020-06-25 19:06:53 +00:00
if ( ( uirc_ircmd [ mesg - > cmd ] ! = NULL ) & & ( ( cnt = sprintf ( pos , " %s " , uirc_ircmd [ mesg - > cmd ] ) ) > 0 ) )
pos + = cnt ;
else
return - 1 ;
for ( unsigned int i = 0 ; i < 14 & & mesg - > args [ i ] ! = NULL ; i + + ) {
if ( ( cnt = sprintf ( pos , " %s " , mesg - > args [ i ] ) ) > 0 )
pos + = cnt ;
else
return - 1 ;
}
2020-06-27 11:33:35 +00:00
if ( mesg - > trailing ! = NULL ) {
2020-06-27 12:30:15 +00:00
if ( ( cnt = sprintf ( pos , " :%s " , mesg - > trailing ) ) > 0 )
2020-06-25 19:06:53 +00:00
pos + = cnt ;
else
return - 1 ;
}
if ( ( cnt = sprintf ( pos , " \r \n " ) ) ! = 2 )
return - 1 ;
return 1 ;
2020-06-22 16:58:10 +00:00
}
2020-06-28 15:19:38 +00:00
bool tagmgr ( char * * pos , IRC_Message * mesg , bool tagged )
2020-06-27 13:30:04 +00:00
{
2020-06-28 15:19:38 +00:00
const char * origpos = * pos ;
char * cval , * cpos = * pos ;
2020-06-27 13:30:04 +00:00
int cnt ;
bool clientbound ;
2020-06-28 15:19:38 +00:00
const struct tagmapping tags [ ] = {
2020-06-27 13:30:04 +00:00
{ . name = " time " , . assg = & mesg - > tags . time } ,
{ . name = " account " , . assg = & mesg - > tags . account } ,
{ . name = " batch " , . assg = & mesg - > tags . batch } ,
{ . name = " label " , . assg = & mesg - > tags . label } ,
{ . name = " msgid " , . assg = & mesg - > tags . msgid } ,
{ . name = " multiline-concat " , . assg = & mesg - > tags . multiline_concat } ,
{ . name = " typing " , . assg = & mesg - > tags . typing } ,
{ . name = " react " , . assg = & mesg - > tags . react } ,
{ . name = " reply " , . assg = & mesg - > tags . reply } } ;
if ( tagged ) {
2020-06-28 15:19:38 +00:00
if ( * cpos = = ' @ ' )
cpos + + ;
2020-06-27 13:30:04 +00:00
do {
clientbound = false ;
if ( * cpos = = ' + ' ) {
cpos + + ;
clientbound = true ;
}
if ( ( cval = strchr ( cpos , ' = ' ) ) ! = NULL ) {
* ( cval + + ) = ' \0 ' ;
for ( unsigned int i = 0 ; i < sizeof ( tags ) / sizeof ( struct tagmapping ) ; i + + ) {
if ( ! strcmp ( cpos , tags [ i ] . name ) ) {
( * tags [ i ] . assg ) . value = cval ;
( * tags [ i ] . assg ) . clientbound = clientbound ;
}
}
if ( ( cpos = strchr ( cval , ' ; ' ) ) ! = NULL )
* ( cpos + + ) = ' \0 ' ;
} else
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
} while ( cpos ! = NULL ) ;
} else {
for ( unsigned int i = 0 ; i < sizeof ( tags ) / sizeof ( struct tagmapping ) ; i + + ) {
if ( ( * tags [ i ] . assg ) . value ! = NULL ) {
if ( cpos = = origpos ) {
if ( sprintf ( cpos + + , " @ " ) ! = 1 )
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
} else {
if ( sprintf ( cpos + + , " ; " ) ! = 1 )
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
}
if ( ( * tags [ i ] . assg ) . clientbound ) {
if ( sprintf ( cpos + + , " + " ) ! = 1 )
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
}
if ( ( cnt = sprintf ( cpos , " %s=%s " , tags [ i ] . name , ( * tags [ i ] . assg ) . value ) ) > 0 )
cpos + = cnt ;
else
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
}
}
if ( * origpos = = ' @ ' ) {
if ( sprintf ( cpos + + , " " ) ! = 1 )
2020-06-28 15:19:38 +00:00
return false ;
2020-06-27 13:30:04 +00:00
}
* pos = cpos ;
}
2020-06-28 15:19:38 +00:00
return true ;
2020-06-27 13:30:04 +00:00
}
2020-06-27 11:33:35 +00:00
char * tokspace ( char * pos , char * * save )
{
char * delimpos = NULL ;
if ( pos = = NULL | | ( delimpos = strchr ( pos , ' ' ) ) = = NULL )
return NULL ;
while ( * delimpos = = ' ' ) {
* ( delimpos + + ) = ' \0 ' ;
}
* save = delimpos ;
return pos ;
}
2020-06-28 15:19:38 +00:00
bool assm_prefix ( char * * str , IRC_User * usr )
{
int cnt ;
char * pos = * str ;
* ( pos + + ) = ' : ' ;
if ( ! usr - > nick & & ! usr - > user ) {
if ( ( cnt = sprintf ( pos , " %s " , usr - > host ) ) > 0 )
pos + = cnt ;
else
return false ;
} else {
if ( ( cnt = sprintf ( pos , " %s " , usr - > nick ) ) > 0 )
pos + = cnt ;
else
return false ;
if ( usr - > user ) {
if ( ( cnt = sprintf ( pos , " !%s " , usr - > user ) ) > 0 )
pos + = cnt ;
else
return false ;
}
if ( usr - > host ) {
if ( ( cnt = sprintf ( pos , " @%s " , usr - > host ) ) > 0 )
pos + = cnt ;
else
return false ;
}
}
* ( pos + + ) = ' ' ;
* str = pos ;
return true ;
}
bool tok_prefix ( char * prefix , IRC_User * user )
{
char * pos = ( * prefix = = ' : ' ) ? prefix + 1 : prefix ;
if ( ( user - > host = strchr ( prefix , ' @ ' ) ) ! = NULL )
* ( user - > host + + ) = ' \0 ' ;
if ( ( user - > user = strchr ( prefix , ' ! ' ) ) ! = NULL ) /* RFC2812 says this cannot be here without the host but RFC1459 says it can, we accept both options */
* ( user - > user + + ) = ' \0 ' ;
if ( * ( user - > nick = prefix ) = = ' \0 ' ) /* NOTE: This may be the server instead of a nick according to RFC2812, it is left to the library user to decide how to interpret this based on the context. */
return false ;
return true ;
}