aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--irc.c19
-rw-r--r--irc.h2
-rw-r--r--nick.c181
-rw-r--r--nick.h2
4 files changed, 123 insertions, 81 deletions
diff --git a/irc.c b/irc.c
index d590e63f..187004c7 100644
--- a/irc.c
+++ b/irc.c
@@ -34,6 +34,7 @@ static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
static char *set_eval_charset( set_t *set, char *value );
static char *set_eval_password( set_t *set, char *value );
static char *set_eval_bw_compat( set_t *set, char *value );
+static char *set_eval_utf8_nicks( set_t *set, char *value );
irc_t *irc_new( int fd )
{
@@ -133,6 +134,7 @@ irc_t *irc_new( int fd )
s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc );
s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
+ s = set_add( &b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc );
irc->root = iu = irc_user_new( irc, ROOT_NICK );
iu->host = g_strdup( myhost );
@@ -961,6 +963,23 @@ static char *set_eval_bw_compat( set_t *set, char *value )
return SET_INVALID;
}
+static char *set_eval_utf8_nicks( set_t *set, char *value )
+{
+ irc_t *irc = set->data;
+ gboolean val = bool2int( value );
+
+ /* Do *NOT* unset this flag in the middle of a session. There will
+ be UTF-8 nicks around already so if we suddenly disable support
+ for them, various functions might behave strangely. */
+ if( val )
+ irc->status |= IRC_UTF8_NICKS;
+ else if( irc->status & IRC_UTF8_NICKS )
+ irc_rootmsg( irc, "You need to reconnect to BitlBee for this "
+ "change to take effect." );
+
+ return set_eval_bool( set, value );
+}
+
void register_irc_plugin( const struct irc_plugin *p )
{
irc_plugins = g_slist_prepend( irc_plugins, (gpointer) p );
diff --git a/irc.h b/irc.h
index 404f5394..866e85c3 100644
--- a/irc.h
+++ b/irc.h
@@ -61,6 +61,8 @@ typedef enum
OPER_HACK_REGISTER = 0x200,
OPER_HACK_ACCOUNT_ADD = 0x400,
OPER_HACK_ANY = 0x3700, /* To check for them all at once. */
+
+ IRC_UTF8_NICKS = 0x10000, /* Disable ASCII restrictions on buddy nicks. */
} irc_status_t;
struct irc_user;
diff --git a/nick.c b/nick.c
index aa9466f9..744a6131 100644
--- a/nick.c
+++ b/nick.c
@@ -111,14 +111,15 @@ char *nick_get( bee_user_t *bu )
char *nick_gen( bee_user_t *bu )
{
gboolean ok = FALSE; /* Set to true once the nick contains something unique. */
- GString *ret = g_string_new( "" );
+ GString *ret = g_string_sized_new( MAX_NICK_LENGTH + 1 );
+ char *rets;
+ irc_t *irc = (irc_t *) bu->bee->ui_data;
char *fmt = set_getstr( &bu->ic->acc->set, "nick_format" ) ? :
set_getstr( &bu->bee->set, "nick_format" );
while( fmt && *fmt && ret->len < MAX_NICK_LENGTH )
{
char *part = NULL, chop = '\0', *asc = NULL;
- int len = MAX_NICK_LENGTH;
if( *fmt != '%' )
{
@@ -141,13 +142,6 @@ char *nick_gen( bee_user_t *bu )
}
fmt += 2;
}
- else if( isdigit( *fmt ) )
- {
- len = 0;
- /* Grab a number. */
- while( isdigit( *fmt ) )
- len = len * 10 + ( *(fmt++) - '0' );
- }
else if( g_strncasecmp( fmt, "nick", 4 ) == 0 )
{
part = bu->nick ? : bu->handle;
@@ -196,31 +190,31 @@ char *nick_gen( bee_user_t *bu )
}
}
+ if( !part )
+ continue;
+
/* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT
should do lossy/approximate conversions, so letters with
accents don't just get stripped. Note that it depends on
LC_CTYPE being set to something other than C/POSIX. */
- if( part )
+ if( !( irc && irc->status & IRC_UTF8_NICKS ) )
part = asc = g_convert_with_fallback( part, -1, "ASCII//TRANSLIT",
"UTF-8", "", NULL, NULL, NULL );
- if( ret->len == 0 && part && isdigit( *part ) )
- g_string_append_c( ret, '_' );
-
- while( part && *part && *part != chop && len > 0 )
- {
- if( strchr( nick_lc_chars, *part ) ||
- strchr( nick_uc_chars, *part ) )
- g_string_append_c( ret, *part );
-
- part ++;
- len --;
- }
+ if( part )
+ g_string_append( ret, part );
g_free( asc );
}
- /* This returns NULL if the nick is empty or otherwise not ok. */
- return g_string_free( ret, ret->len == 0 || !ok );
+ rets = g_string_free( ret, FALSE );
+ if( ok && rets && *rets )
+ {
+ nick_strip( irc, rets );
+ rets[MAX_NICK_LENGTH] = '\0';
+ return rets;
+ }
+ g_free( rets );
+ return NULL;
}
void nick_dedupe( bee_user_t *bu, char nick[MAX_NICK_LENGTH+1] )
@@ -246,24 +240,15 @@ void nick_dedupe( bee_user_t *bu, char nick[MAX_NICK_LENGTH+1] )
if( inf_protection-- == 0 )
{
- int i;
-
- irc_rootmsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
- "This used to be a fatal BitlBee bug, but we tried to fix it. "
- "This message should *never* appear anymore. "
- "If it does, please *do* send us a bug report! "
- "Please send all the following lines in your report:" );
-
- irc_rootmsg( irc, "Trying to get a sane nick for handle %s", bu->handle );
- for( i = 0; i < MAX_NICK_LENGTH; i ++ )
- irc_rootmsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
-
- irc_rootmsg( irc, "FAILED. Returning an insane nick now. Things might break. "
- "Good luck, and please don't forget to paste the lines up here "
- "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
-
g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
+ irc_rootmsg( irc, "Warning: Something went wrong while trying "
+ "to generate a nickname for contact %s on %s.",
+ bu->handle, bu->ic->acc->tag );
+ irc_rootmsg( irc, "This might be a bug in BitlBee, or the result "
+ "of a faulty nick_format setting. Will use %s "
+ "instead.", nick );
+
break;
}
}
@@ -290,43 +275,95 @@ void nick_del( bee_user_t *bu )
void nick_strip( irc_t *irc, char *nick )
{
- int i, j;
+ int len = 0;
- for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
+ if( irc && ( irc->status & IRC_UTF8_NICKS ) )
{
- if( strchr( nick_lc_chars, nick[i] ) ||
- strchr( nick_uc_chars, nick[i] ) )
+ gunichar c;
+ char *p = nick, *n, tmp[strlen(nick)+1];
+
+ while( p && *p )
{
- nick[j] = nick[i];
- j++;
+ c = g_utf8_get_char_validated( p, -1 );
+ n = g_utf8_find_next_char( p, NULL );
+
+ if( ( c < 0x7f && !( strchr( nick_lc_chars, c ) ||
+ strchr( nick_uc_chars, c ) ) ) ||
+ !g_unichar_isgraph( c ) )
+ {
+ strcpy( tmp, n );
+ strcpy( p, tmp );
+ }
+ else
+ p = n;
+ }
+ if( p )
+ len = p - nick;
+ }
+ else
+ {
+ int i;
+
+ for( i = len = 0; nick[i] && len < MAX_NICK_LENGTH; i++ )
+ {
+ if( strchr( nick_lc_chars, nick[i] ) ||
+ strchr( nick_uc_chars, nick[i] ) )
+ {
+ nick[len] = nick[i];
+ len++;
+ }
}
}
if( isdigit( nick[0] ) )
{
char *orig;
+ /* First character of a nick can't be a digit, so insert an
+ underscore if necessary. */
orig = g_strdup( nick );
g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
g_free( orig );
- j ++;
+ len ++;
}
- while( j <= MAX_NICK_LENGTH )
- nick[j++] = '\0';
+ while( len <= MAX_NICK_LENGTH )
+ nick[len++] = '\0';
}
-int nick_ok( irc_t *irc, const char *nick )
+gboolean nick_ok( irc_t *irc, const char *nick )
{
const char *s;
/* Empty/long nicks are not allowed, nor numbers at [0] */
if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
- return( 0 );
+ return 0;
- for( s = nick; *s; s ++ )
- if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
- return( 0 );
+ if( irc && ( irc->status & IRC_UTF8_NICKS ) )
+ {
+ gunichar c;
+ const char *p = nick, *n;
+
+ while( p && *p )
+ {
+ c = g_utf8_get_char_validated( p, -1 );
+ n = g_utf8_find_next_char( p, NULL );
+
+ if( ( c < 0x7f && !( strchr( nick_lc_chars, c ) ||
+ strchr( nick_uc_chars, c ) ) ) ||
+ !g_unichar_isgraph( c ) )
+ {
+ return FALSE;
+ }
+ p = n;
+ }
+ }
+ else
+ {
+ for( s = nick; *s; s ++ )
+ if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
+ return FALSE;
+ }
- return( 1 );
+ return TRUE;
}
int nick_lc( irc_t *irc, char *nick )
@@ -341,38 +378,22 @@ int nick_lc( irc_t *irc, char *nick )
tab[(int)nick_lc_chars[i]] = nick_lc_chars[i];
}
- for( i = 0; nick[i]; i ++ )
+ if( irc && ( irc->status & IRC_UTF8_NICKS ) )
{
- if( !tab[(int)nick[i]] )
- return( 0 );
-
- nick[i] = tab[(int)nick[i]];
- }
-
- return( 1 );
-}
-
-int nick_uc( irc_t *irc, char *nick )
-{
- static char tab[128] = { 0 };
- int i;
-
- if( tab['A'] == 0 )
- for( i = 0; nick_lc_chars[i]; i ++ )
+ gchar *down = g_utf8_strdown( nick, -1 );
+ if( strlen( down ) > strlen( nick ) )
{
- tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
- tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
+ /* Well crap. Corrupt it if we have to. */
+ down[strlen(nick)] = '\0';
}
+ strcpy( nick, down );
+ g_free( down );
+ }
for( i = 0; nick[i]; i ++ )
- {
- if( !tab[(int)nick[i]] )
- return( 0 );
-
nick[i] = tab[(int)nick[i]];
- }
- return( 1 );
+ return nick_ok( irc, nick );
}
int nick_cmp( irc_t *irc, const char *a, const char *b )
diff --git a/nick.h b/nick.h
index 47adbab5..20edb845 100644
--- a/nick.h
+++ b/nick.h
@@ -32,7 +32,7 @@ int nick_saved( bee_user_t *bu );
void nick_del( bee_user_t *bu );
void nick_strip( irc_t *irc, char *nick );
-int nick_ok( irc_t *irc, const char *nick );
+gboolean nick_ok( irc_t *irc, const char *nick );
int nick_lc( irc_t *irc, char *nick );
int nick_uc( irc_t *irc, char *nick );
int nick_cmp( irc_t *irc, const char *a, const char *b );