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"
2020-07-04 10:29:08 +00:00
const char * const uirc_ircmd [ ] = {
2020-06-22 16:58:10 +00:00
[ PASS ] = " PASS " ,
[ NICK ] = " NICK " ,
[ USER ] = " USER " ,
[ SERVER ] = " SERVER " ,
[ OPER ] = " OPER " ,
2020-07-03 20:41:52 +00:00
[ SERVICE ] = " SERVICE " ,
2020-06-22 16:58:10 +00:00
[ 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 " ,
2020-07-04 10:29:08 +00:00
[ SERVLIST ] = " SERVLIST " ,
[ SQUERY ] = " SQUERY " ,
2020-06-22 16:58:10 +00:00
[ PRIVMSG ] = " PRIVMSG " ,
[ NOTICE ] = " NOTICE " ,
2020-07-04 10:29:08 +00:00
[ MOTD ] = " MOTD " ,
[ LUSERS ] = " LUSERS " ,
2020-06-22 16:58:10 +00:00
[ WHO ] = " WHO " ,
[ WHOIS ] = " WHOIS " ,
[ WHOWAS ] = " WHOWAS " ,
[ KILL ] = " KILL " ,
[ PING ] = " PING " ,
[ PONG ] = " PONG " ,
[ ERROR ] = " ERROR " ,
[ AWAY ] = " AWAY " ,
[ REHASH ] = " REHASH " ,
2020-07-04 10:29:08 +00:00
[ DIE ] = " DIE " ,
2020-06-22 16:58:10 +00:00
[ 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 {
2020-07-02 16:32:25 +00:00
const char * name ;
2020-06-27 12:30:15 +00:00
IRC_Tag * assg ;
} ;
2020-07-07 21:17:28 +00:00
signed int Ircmd_stoi ( char * str )
2020-06-22 16:58:10 +00:00
{
2020-07-07 21:17:28 +00:00
if ( str = = NULL )
return ERR_UIRC_NULL_ARGS ;
for ( unsigned short i = PASS ; i < = ISON ; i + + ) {
if ( ( uirc_ircmd [ i ] ! = NULL ) & & ( strcmp ( uirc_ircmd [ i ] , str ) = = 0 ) )
return i ;
}
return ERR_UIRC_UNKNOWN_TOKEN ;
}
signed int Tok_mesg ( char * str , IRC_Message * out )
{
if ( str = = NULL | | out = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_NULL_ARGS ;
int ret ;
2020-07-07 21:17:28 +00:00
char * progr = str , * command ;
2020-06-22 16:59:23 +00:00
if ( * progr = = ' @ ' ) {
char * tags ;
2020-06-30 21:39:56 +00:00
if ( ( tags = strtok_r ( progr , " " , & progr ) ) ! = NULL ) {
2020-07-07 21:17:28 +00:00
if ( ( ret = Tok_tags ( tags , & out - > tags ) ) < 0 )
2020-07-02 16:32:25 +00:00
return ret ;
2020-06-22 16:59:23 +00:00
} else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_INVALID_FORMAT ;
2020-06-22 16:59:23 +00:00
}
2020-06-22 16:58:10 +00:00
if ( * progr = = ' : ' ) {
char * prefix ;
2020-06-30 21:39:56 +00:00
if ( ( prefix = strtok_r ( progr , " " , & progr ) ) ! = NULL ) {
2020-07-07 21:17:28 +00:00
if ( ( ret = Tok_user ( prefix , & out - > name , false ) ) < 0 )
2020-07-02 16:32:25 +00:00
return ret ;
2020-06-22 16:59:23 +00:00
} else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_INVALID_FORMAT ;
2020-06-22 16:58:10 +00:00
}
2020-06-30 21:39:56 +00:00
if ( ( command = strtok_r ( NULL , " " , & progr ) ) ! = NULL ) {
2020-07-07 21:17:28 +00:00
if ( ! ( out - > cmd = ( isalpha ( * command ) ) ? Ircmd_stoi ( command ) : atoi ( command ) ) )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_UNKNOWN_TOKEN ;
2020-06-22 16:58:10 +00:00
} else {
2020-07-02 16:32:25 +00:00
return ERR_UIRC_INVALID_FORMAT ;
2020-06-22 16:58:10 +00:00
}
int i ;
2020-07-09 20:37:29 +00:00
for ( i = 0 ; * progr ! = ' : ' & & i < 14 & & * progr ! = ' \0 ' ; i + + ) {
2020-07-07 21:17:28 +00:00
if ( ( out - > args [ i ] = strtok_r ( NULL , " " , & progr ) ) = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_INVALID_FORMAT ;
2020-06-22 16:58:10 +00:00
}
2020-07-07 21:17:28 +00:00
out - > args [ i ] = NULL ;
2020-06-22 16:58:10 +00:00
if ( * progr = = ' : ' )
2020-07-10 11:44:58 +00:00
+ + progr ;
if ( * progr ! = ' \0 ' )
out - > trailing = progr ;
2020-06-22 16:58:10 +00:00
return 1 ;
}
2020-07-07 21:17:28 +00:00
signed int Assm_mesg ( char * buf , IRC_Message * in )
2020-06-22 16:58:10 +00:00
{
2020-07-07 21:17:28 +00:00
if ( buf = = NULL | | in = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-25 19:06:53 +00:00
char * pos = buf ;
2020-07-02 16:32:25 +00:00
int cnt , ret ;
2020-06-27 13:30:04 +00:00
2020-07-07 21:17:28 +00:00
if ( ( ret = Assm_tags ( pos , & in - > tags ) ) < 0 )
2020-07-02 16:32:25 +00:00
return ret ;
2020-07-07 21:17:28 +00:00
else
pos + = ret ;
if ( in - > name . nick ! = NULL | | in - > name . host ! = NULL ) {
* ( pos + + ) = ' : ' ;
if ( ( ret = Assm_user ( pos , & in - > name , false ) ) < = 0 )
2020-07-02 16:32:25 +00:00
return ret ;
2020-07-07 21:17:28 +00:00
else
pos + = ret ;
* ( pos + + ) = ' ' ;
2020-06-27 19:07:59 +00:00
}
2020-07-07 21:17:28 +00:00
if ( ( uirc_ircmd [ in - > cmd ] ! = NULL ) & & ( ( cnt = sprintf ( pos , " %s " , uirc_ircmd [ in - > cmd ] ) ) > 0 ) )
2020-06-25 19:06:53 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_GENERIC ;
2020-07-07 21:17:28 +00:00
for ( unsigned int i = 0 ; i < 14 & & in - > args [ i ] ! = NULL ; i + + ) {
if ( ( cnt = sprintf ( pos , " %s " , in - > args [ i ] ) ) > 0 )
2020-06-25 19:06:53 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-25 19:06:53 +00:00
}
2020-07-07 21:17:28 +00:00
if ( in - > trailing ! = NULL ) {
if ( ( cnt = sprintf ( pos , " :%s " , in - > trailing ) ) > 0 )
2020-07-06 20:57:21 +00:00
pos + = cnt ;
else
return ERR_UIRC_GENERIC ;
}
2020-07-07 21:17:28 +00:00
if ( ( cnt = sprintf ( pos , " \r \n " ) ) = = 2 )
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-07-07 21:17:28 +00:00
return pos - buf ;
2020-06-22 16:58:10 +00:00
}
2020-07-07 21:17:28 +00:00
signed int Assm_tags ( char * buf , IRC_Tags * in )
2020-06-27 13:30:04 +00:00
{
2020-07-07 21:17:28 +00:00
if ( buf = = NULL | | in = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_NULL_ARGS ;
2020-07-07 21:17:28 +00:00
char * pos = buf ;
2020-06-27 13:30:04 +00:00
int cnt ;
2020-07-07 21:17:28 +00:00
struct tagmapping tagmps [ ] = {
{ . name = " time " , . assg = & in - > time } ,
{ . name = " account " , . assg = & in - > account } ,
{ . name = " batch " , . assg = & in - > batch } ,
{ . name = " label " , . assg = & in - > label } ,
{ . name = " msgid " , . assg = & in - > msgid } ,
{ . name = " multiline-concat " , . assg = & in - > multiline_concat } ,
{ . name = " typing " , . assg = & in - > typing } ,
{ . name = " react " , . assg = & in - > react } ,
{ . name = " reply " , . assg = & in - > reply } } ;
for ( unsigned int i = 0 ; i < sizeof ( tagmps ) / sizeof ( struct tagmapping ) ; i + + ) {
if ( ( * tagmps [ i ] . assg ) . present ) {
if ( pos = = buf ) {
if ( sprintf ( pos + + , " @ " ) ! = 1 )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-07-01 19:52:45 +00:00
} else {
2020-07-07 21:17:28 +00:00
if ( sprintf ( pos + + , " ; " ) ! = 1 )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-27 13:30:04 +00:00
}
2020-07-07 21:17:28 +00:00
if ( ( * tagmps [ i ] . assg ) . clientbound ) {
if ( sprintf ( pos + + , " + " ) ! = 1 )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-30 21:39:56 +00:00
}
2020-07-07 21:17:28 +00:00
if ( ( * tagmps [ i ] . assg ) . value ! = NULL )
cnt = sprintf ( pos , " %s=%s " , tagmps [ i ] . name , ( * tagmps [ i ] . assg ) . value ) ;
2020-07-01 19:52:45 +00:00
else
2020-07-07 21:17:28 +00:00
cnt = sprintf ( pos , " %s " , tagmps [ i ] . name ) ;
2020-07-01 19:52:45 +00:00
if ( cnt > 0 )
2020-07-07 21:17:28 +00:00
pos + = cnt ;
2020-07-01 19:52:45 +00:00
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-30 21:39:56 +00:00
}
2020-07-01 19:52:45 +00:00
}
2020-07-07 21:17:28 +00:00
return pos - buf ;
2020-07-01 19:52:45 +00:00
}
2020-07-07 21:17:28 +00:00
signed int Tok_tags ( char * str , IRC_Tags * out )
2020-07-01 19:52:45 +00:00
{
2020-07-07 21:17:28 +00:00
if ( str = = NULL | | out = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_NULL_ARGS ;
2020-07-07 21:17:28 +00:00
char * cval , * cpos = str , * ctag = NULL ;
2020-07-01 19:52:45 +00:00
bool clientbound ;
2020-07-07 21:17:28 +00:00
const struct tagmapping tagmps [ ] = {
{ . name = " time " , . assg = & out - > time } ,
{ . name = " account " , . assg = & out - > account } ,
{ . name = " batch " , . assg = & out - > batch } ,
{ . name = " label " , . assg = & out - > label } ,
{ . name = " msgid " , . assg = & out - > msgid } ,
{ . name = " multiline-concat " , . assg = & out - > multiline_concat } ,
{ . name = " typing " , . assg = & out - > typing } ,
{ . name = " react " , . assg = & out - > react } ,
{ . name = " reply " , . assg = & out - > reply } } ;
2020-07-01 19:52:45 +00:00
if ( * cpos = = ' @ ' )
cpos + + ;
while ( ( ctag = strtok_r ( NULL , " ; " , & cpos ) ) ! = NULL ) {
clientbound = false ;
if ( * ctag = = ' + ' ) {
ctag + + ;
clientbound = true ;
}
2020-07-02 16:32:25 +00:00
if ( ( cval = strchr ( ctag , ' = ' ) ) ! = NULL )
2020-07-01 19:52:45 +00:00
* ( cval + + ) = ' \0 ' ;
2020-07-07 21:17:28 +00:00
for ( unsigned int i = 0 ; i < sizeof ( tagmps ) / sizeof ( struct tagmapping ) ; i + + ) {
if ( ! strcmp ( ctag , tagmps [ i ] . name ) ) {
2020-07-01 19:52:45 +00:00
if ( cval ! = NULL )
2020-07-07 21:17:28 +00:00
( * tagmps [ i ] . assg ) . value = cval ;
( * tagmps [ i ] . assg ) . clientbound = clientbound ;
( * tagmps [ i ] . assg ) . present = true ;
2020-06-27 13:30:04 +00:00
}
}
}
2020-07-02 16:32:25 +00:00
return 1 ;
2020-06-27 13:30:04 +00:00
}
2020-07-07 21:17:28 +00:00
signed int Assm_user ( char * buf , IRC_User * in , bool useorig )
2020-06-28 15:19:38 +00:00
{
2020-07-07 21:17:28 +00:00
if ( buf = = NULL | | in = = NULL )
2020-07-02 16:32:25 +00:00
return ERR_UIRC_NULL_ARGS ;
2020-06-28 15:19:38 +00:00
int cnt ;
2020-07-07 21:17:28 +00:00
char * pos = buf ;
if ( in - > nick = = NULL & & in - > host ! = NULL ) {
if ( ( cnt = sprintf ( pos , " %s " , in - > host ) ) > 0 )
2020-06-28 15:19:38 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-07-07 21:17:28 +00:00
} else if ( in - > nick ! = NULL ) {
if ( ( cnt = sprintf ( pos , " %s " , in - > nick ) ) > 0 )
2020-06-28 15:19:38 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-07-07 21:17:28 +00:00
if ( in - > user ! = NULL ) {
if ( ( cnt = sprintf ( pos , " !%s " , in - > user ) ) > 0 )
pos + = cnt ;
else
return ERR_UIRC_BUFFER_ERR ;
}
2020-07-09 20:37:29 +00:00
if ( useorig & & in - > orig ! = NULL ) {
2020-07-07 21:17:28 +00:00
if ( ( cnt = sprintf ( pos , " %%%s " , in - > orig ) ) > 0 )
2020-06-28 15:19:38 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-28 15:19:38 +00:00
}
2020-07-07 21:17:28 +00:00
if ( in - > host ! = NULL ) {
if ( ( cnt = sprintf ( pos , " @%s " , in - > host ) ) > 0 )
2020-06-28 15:19:38 +00:00
pos + = cnt ;
else
2020-07-02 16:32:25 +00:00
return ERR_UIRC_BUFFER_ERR ;
2020-06-28 15:19:38 +00:00
}
2020-07-02 16:32:25 +00:00
} else
return ERR_UIRC_NULL_ARGS ;
2020-07-07 21:17:28 +00:00
return pos - buf ;
2020-06-28 15:19:38 +00:00
}
2020-07-07 21:17:28 +00:00
signed int Tok_user ( char * str , IRC_User * out , bool useorig )
2020-06-28 15:19:38 +00:00
{
2020-07-07 21:17:28 +00:00
char * pos = ( * str = = ' : ' ) ? str + 1 : str ;
if ( ( out - > host = strchr ( pos , ' @ ' ) ) ! = NULL )
* ( ( char * ) out - > host + + ) = ' \0 ' ;
2020-07-09 20:37:29 +00:00
if ( useorig & & ( out - > orig = strchr ( pos , ' % ' ) ) ! = NULL )
2020-07-07 21:17:28 +00:00
* ( ( char * ) out - > orig + + ) = ' \0 ' ;
if ( ( out - > user = strchr ( pos , ' ! ' ) ) ! = NULL ) /* RFC2812 says this cannot be here without the host but RFC1459 says it can, we accept both options */
* ( ( char * ) out - > user + + ) = ' \0 ' ;
if ( * ( out - > nick = pos ) = = ' \0 ' ) /* NOTE: This may be the server instead of a nick according to RFC2812, it is left to the library out to decide how to interpret this based on the context. */
2020-07-02 16:32:25 +00:00
return ERR_UIRC_INVALID_FORMAT ;
return 1 ;
2020-06-28 15:19:38 +00:00
}