diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2010-03-27 10:31:03 -0400 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2010-03-27 10:31:03 -0400 |
commit | b91936398b8ada486e246f769f1f8b8836fa3f43 (patch) | |
tree | b6e0067faa86490295f74083d15bc886ad56d83d | |
parent | 9b69eb789bdcb3667c4cc4ac74f3404ae3f60869 (diff) |
Mode stuff. Also disallow unsetting +R umode which was possible so far
(and shouldn't be).
-rw-r--r-- | irc.c | 60 | ||||
-rw-r--r-- | irc.h | 17 | ||||
-rw-r--r-- | irc_channel.c | 5 | ||||
-rw-r--r-- | irc_commands.c | 50 |
4 files changed, 98 insertions, 34 deletions
@@ -52,8 +52,6 @@ irc_t *irc_new( int fd ) irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal ); irc->watches = g_hash_table_new( g_str_hash, g_str_equal ); - strcpy( irc->umode, UMODE ); - irc->iconv = (GIConv) -1; irc->oconv = (GIConv) -1; @@ -598,9 +596,6 @@ int irc_check_login( irc_t *irc ) g_free( iu->nick ); g_free( iu ); - irc->umode[0] = '\0'; - /*irc_umode_set( irc, "+" UMODE, 1 );*/ - if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname ); @@ -618,6 +613,9 @@ int irc_check_login( irc_t *irc ) irc_send_login( irc ); + irc->umode[0] = '\0'; + irc_umode_set( irc, "+" UMODE, TRUE ); + ic = irc_channel_new( irc, ROOT_CHAN ); irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root ); irc_channel_add_user( ic, irc->user ); @@ -632,6 +630,58 @@ int irc_check_login( irc_t *irc ) } } +void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ) +{ + /* allow_priv: Set to 0 if s contains user input, 1 if you want + to set a "privileged" mode (+o, +R, etc). */ + char m[128], st = 1; + const char *t; + int i; + char changes[512], *p, st2 = 2; + char badflag = 0; + + memset( m, 0, sizeof( m ) ); + + for( t = irc->umode; *t; t ++ ) + if( *t < sizeof( m ) ) + m[(int)*t] = 1; + + p = changes; + for( t = s; *t; t ++ ) + { + if( *t == '+' || *t == '-' ) + st = *t == '+'; + else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) || + ( st == 1 && strchr( UMODES, *t ) ) || + ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) ) + { + if( m[(int)*t] != st) + { + if( st != st2 ) + st2 = st, *p++ = st ? '+' : '-'; + *p++ = *t; + } + m[(int)*t] = st; + } + else + badflag = 1; + } + *p = '\0'; + + memset( irc->umode, 0, sizeof( irc->umode ) ); + + for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ ) + if( m[i] ) + irc->umode[strlen(irc->umode)] = i; + + if( badflag ) + irc_send_num( irc, 501, ":Unknown MODE flag" ); + if( *changes ) + irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick, + irc->user->user, irc->user->host, irc->user->nick, + changes ); +} + static char *set_eval_charset( set_t *set, char *value ) @@ -32,12 +32,14 @@ #define IRC_LOGIN_TIMEOUT 60 #define IRC_PING_STRING "PinglBee" -#define UMODES "abisw" -#define UMODES_PRIV "Ro" -#define CMODES "nt" -#define CMODE "t" -#define UMODE "s" -#define CTYPES "&#" +#define UMODES "abisw" /* Allowed umodes (although they mostly do nothing) */ +#define UMODES_PRIV "Ro" /* Allowed, but not by user directly */ +#define UMODES_KEEP "R" /* Don't allow unsetting using /MODE */ +#define CMODES "nt" /* Allowed modes */ +#define CMODE "t" /* Default mode */ +#define UMODE "s" /* Default mode */ + +#define CTYPES "&#" /* Valid channel name prefixes */ typedef enum { @@ -143,6 +145,8 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ); int irc_check_login( irc_t *irc ); +void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ); + /* irc_channel.c */ irc_channel_t *irc_channel_new( irc_t *irc, const char *name ); irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name ); @@ -150,6 +154,7 @@ int irc_channel_free( irc_channel_t *ic ); int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu ); int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu ); int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who ); +gboolean irc_channel_name_ok( const char *name ); /* irc_commands.c */ void irc_exec( irc_t *irc, char **cmd ); diff --git a/irc_channel.c b/irc_channel.c index d15b73eb..c2e2c685 100644 --- a/irc_channel.c +++ b/irc_channel.c @@ -126,3 +126,8 @@ int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_ return 1; } + +gboolean irc_channel_name_ok( const char *name ) +{ + return strchr( CTYPES, name[0] ) != NULL && nick_ok( name + 1 ); +} diff --git a/irc_commands.c b/irc_commands.c index 36807c54..5f9ae39f 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -183,29 +183,15 @@ static void irc_cmd_motd( irc_t *irc, char **cmd ) irc_send_motd( irc ); } -#if 0 -//#if 0 -static void irc_cmd_oper( irc_t *irc, char **cmd ) -{ - if( global.conf->oper_pass && - ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? - md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : - strcmp( cmd[2], global.conf->oper_pass ) == 0 ) ) - { - irc_umode_set( irc, "+o", 1 ); - irc_send_num( irc, 381, ":Password accepted" ); - } - else - { - irc_send_num( irc, 432, ":Incorrect password" ); - } -} - static void irc_cmd_mode( irc_t *irc, char **cmd ) { - if( strchr( CTYPES, *cmd[1] ) ) + if( irc_channel_name_ok( cmd[1] ) ) { - if( cmd[2] ) + irc_channel_t *ic; + + if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL ) + irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); + else if( cmd[2] ) { if( *cmd[2] == '+' || *cmd[2] == '-' ) irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] ); @@ -213,11 +199,11 @@ static void irc_cmd_mode( irc_t *irc, char **cmd ) irc_send_num( irc, 368, "%s :No bans possible", cmd[1] ); } else - irc_send_num( irc, 324, "%s +%s", cmd[1], CMODE ); + irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode ); } else { - if( nick_cmp( cmd[1], irc->nick ) == 0 ) + if( nick_cmp( cmd[1], irc->user->nick ) == 0 ) { if( cmd[2] ) irc_umode_set( irc, cmd[2], 0 ); @@ -229,6 +215,24 @@ static void irc_cmd_mode( irc_t *irc, char **cmd ) } } +#if 0 +//#if 0 +static void irc_cmd_oper( irc_t *irc, char **cmd ) +{ + if( global.conf->oper_pass && + ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? + md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : + strcmp( cmd[2], global.conf->oper_pass ) == 0 ) ) + { + irc_umode_set( irc, "+o", 1 ); + irc_send_num( irc, 381, ":Password accepted" ); + } + else + { + irc_send_num( irc, 432, ":Incorrect password" ); + } +} + static void irc_cmd_invite( irc_t *irc, char **cmd ) { char *nick = cmd[1], *channel = cmd[2]; @@ -565,9 +569,9 @@ static const command_t irc_commands[] = { { "whois", 1, irc_cmd_whois, IRC_CMD_LOGGED_IN }, { "whowas", 1, irc_cmd_whowas, IRC_CMD_LOGGED_IN }, { "motd", 0, irc_cmd_motd, IRC_CMD_LOGGED_IN }, + { "mode", 1, irc_cmd_mode, IRC_CMD_LOGGED_IN }, #if 0 { "oper", 2, irc_cmd_oper, IRC_CMD_LOGGED_IN }, - { "mode", 1, irc_cmd_mode, IRC_CMD_LOGGED_IN }, { "invite", 2, irc_cmd_invite, IRC_CMD_LOGGED_IN }, { "privmsg", 1, irc_cmd_privmsg, IRC_CMD_LOGGED_IN }, { "notice", 1, irc_cmd_privmsg, IRC_CMD_LOGGED_IN }, |