aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-06-16 10:31:40 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2010-06-16 10:31:40 +0200
commit6b90431eba3820aaa5535523622ba45ca65055f4 (patch)
tree434c10fe6c17b47ad16acc8ce1d97c25d66cb5cb
parente5b521d07dbe197c2dd7552f0036bdcac2116cde (diff)
More correct handling of channel names (according to RFC 1459). Pretty
much any 8-bit character is allowed in there - while nicknames are very restricted.
-rw-r--r--irc.h1
-rw-r--r--irc_channel.c59
-rw-r--r--irc_commands.c46
3 files changed, 50 insertions, 56 deletions
diff --git a/irc.h b/irc.h
index 1bbb564a..82652013 100644
--- a/irc.h
+++ b/irc.h
@@ -230,6 +230,7 @@ int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_
void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
void irc_channel_printf( irc_channel_t *ic, char *format, ... );
gboolean irc_channel_name_ok( const char *name );
+int irc_channel_name_cmp( const char *a_, const char *b_ );
void irc_channel_update_ops( irc_channel_t *ic, char *value );
char *set_eval_irc_channel_ops( struct set *set, char *value );
diff --git a/irc_channel.c b/irc_channel.c
index 54e68577..133a6de9 100644
--- a/irc_channel.c
+++ b/irc_channel.c
@@ -65,7 +65,7 @@ irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name )
{
irc_channel_t *ic = l->data;
- if( g_strcasecmp( name, ic->name ) == 0 )
+ if( irc_channel_name_cmp( name, ic->name ) == 0 )
return ic;
}
@@ -266,20 +266,59 @@ void irc_channel_printf( irc_channel_t *ic, char *format, ... )
g_free( text );
}
-gboolean irc_channel_name_ok( const char *name )
+gboolean irc_channel_name_ok( const char *name_ )
{
- char name_[strlen(name)+1];
+ const unsigned char *name = (unsigned char*) name_;
+ int i;
/* Check if the first character is in CTYPES (#&) */
- if( strchr( CTYPES, name[0] ) == NULL )
+ if( strchr( CTYPES, name_[0] ) == NULL )
return FALSE;
- /* Check the rest of the name. Just checking name + 1 doesn't work
- since it will fail if the first character is a number, or if
- it's a one-char channel name - both of which are legal. */
- name_[0] = '_';
- strcpy( name_ + 1, name + 1 );
- return nick_ok( name_ );
+ /* RFC 1459 keeps amazing me: While only a "few" chars are allowed
+ in nicknames, channel names can be pretty much anything as long
+ as they start with # or &. I'll be a little bit more strict and
+ disallow all non-printable characters. */
+ for( i = 1; name[i]; i ++ )
+ if( name[i] <= ' ' || name[i] == ',' )
+ return FALSE;
+
+ return TRUE;
+}
+
+int irc_channel_name_cmp( const char *a_, const char *b_ )
+{
+ static unsigned char case_map[256];
+ const unsigned char *a = (unsigned char*) a_, *b = (unsigned char*) b_;
+ int i;
+
+ if( case_map['A'] == '\0' )
+ {
+ for( i = 33; i < 256; i ++ )
+ if( i != ',' )
+ case_map[i] = i;
+
+ for( i = 0; i < 26; i ++ )
+ case_map['A'+i] = 'a' + i;
+
+ case_map['['] = '{';
+ case_map[']'] = '}';
+ case_map['~'] = '`';
+ case_map['\\'] = '|';
+ }
+
+ if( !irc_channel_name_ok( a_ ) || !irc_channel_name_ok( b_ ) )
+ return -1;
+
+ for( i = 0; a[i] && b[i] && case_map[a[i]] && case_map[b[i]]; i ++ )
+ {
+ if( case_map[a[i]] == case_map[b[i]] )
+ continue;
+ else
+ return case_map[a[i]] - case_map[b[i]];
+ }
+
+ return case_map[a[i]] - case_map[b[i]];
}
static gint irc_channel_user_cmp( gconstpointer a_, gconstpointer b_ )
diff --git a/irc_commands.c b/irc_commands.c
index ac851adf..b1fc74bf 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -313,52 +313,6 @@ static void irc_cmd_privmsg( irc_t *irc, char **cmd )
{
irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
}
-
-
-#if 0
- else if( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
- {
- }
- else
- {
- if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
- {
- unsigned int i;
- char *t = set_getstr( &irc->set, "default_target" );
-
- if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
- cmd[1] = irc->last_target;
- else if( g_strcasecmp( t, "root" ) == 0 )
- cmd[1] = irc->mynick;
-
- for( i = 0; i < strlen( cmd[2] ); i ++ )
- {
- if( cmd[2][i] == ' ' ) break;
- if( cmd[2][i] == ':' || cmd[2][i] == ',' )
- {
- cmd[1] = cmd[2];
- cmd[2] += i;
- *cmd[2] = 0;
- while( *(++cmd[2]) == ' ' );
- break;
- }
- }
-
- irc->is_private = 0;
-
- if( cmd[1] != irc->last_target )
- {
- g_free( irc->last_target );
- irc->last_target = g_strdup( cmd[1] );
- }
- }
- else
- {
- irc->is_private = 1;
- }
- irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
- }
-#endif
}
static void irc_cmd_nickserv( irc_t *irc, char **cmd )