aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-03-27 10:31:03 -0400
committerWilmer van der Gaast <wilmer@gaast.net>2010-03-27 10:31:03 -0400
commitb91936398b8ada486e246f769f1f8b8836fa3f43 (patch)
treeb6e0067faa86490295f74083d15bc886ad56d83d
parent9b69eb789bdcb3667c4cc4ac74f3404ae3f60869 (diff)
Mode stuff. Also disallow unsetting +R umode which was possible so far
(and shouldn't be).
-rw-r--r--irc.c60
-rw-r--r--irc.h17
-rw-r--r--irc_channel.c5
-rw-r--r--irc_commands.c50
4 files changed, 98 insertions, 34 deletions
diff --git a/irc.c b/irc.c
index bf84f66d..6dc88825 100644
--- a/irc.c
+++ b/irc.c
@@ -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 )
diff --git a/irc.h b/irc.h
index 48cba879..db629a19 100644
--- a/irc.h
+++ b/irc.h
@@ -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 },