diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2010-06-16 10:31:40 +0200 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2010-06-16 10:31:40 +0200 | 
| commit | 6b90431eba3820aaa5535523622ba45ca65055f4 (patch) | |
| tree | 434c10fe6c17b47ad16acc8ce1d97c25d66cb5cb | |
| parent | e5b521d07dbe197c2dd7552f0036bdcac2116cde (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.h | 1 | ||||
| -rw-r--r-- | irc_channel.c | 59 | ||||
| -rw-r--r-- | irc_commands.c | 46 | 
3 files changed, 50 insertions, 56 deletions
| @@ -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 ) | 
