diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2013-06-16 13:42:39 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2013-06-16 13:42:39 +0100 |
commit | 1a2c1c0c413ea1124544cdc9a24a0d2faa5dbb8f (patch) | |
tree | d3ae6d42d29b7b226abb017ab5dfb07536d2493b /nick.c | |
parent | ab19567e25a35beb23f922303d1f60ed13228356 (diff) | |
parent | 5cb946132871ef97fe9eabacafa62f1064d80423 (diff) |
Merging utf8-nicks branch. This adds a utf8_nicks setting which removes the
ASCII restriction on contact nicknames. Use at your own risk!
Diffstat (limited to 'nick.c')
-rw-r--r-- | nick.c | 207 |
1 files changed, 113 insertions, 94 deletions
@@ -50,11 +50,12 @@ static char *clean_handle( const char *orig ) void nick_set_raw( account_t *acc, const char *handle, const char *nick ) { char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 ); + irc_t *irc = (irc_t *) acc->bee->ui_data; store_handle = clean_handle( handle ); store_nick[MAX_NICK_LENGTH] = '\0'; strncpy( store_nick, nick, MAX_NICK_LENGTH ); - nick_strip( store_nick ); + nick_strip( irc, store_nick ); g_hash_table_replace( acc->nicks, store_handle, store_nick ); } @@ -68,6 +69,7 @@ char *nick_get( bee_user_t *bu ) { static char nick[MAX_NICK_LENGTH+1]; char *store_handle, *found_nick; + irc_t *irc = (irc_t *) bu->bee->ui_data; memset( nick, 0, MAX_NICK_LENGTH + 1 ); @@ -93,9 +95,9 @@ char *nick_get( bee_user_t *bu ) while( *s ) *(s++) = 0; - nick_strip( nick ); + nick_strip( irc, nick ); if( set_getbool( &bu->bee->set, "lcnicks" ) ) - nick_lc( nick ); + nick_lc( irc, nick ); } g_free( store_handle ); @@ -109,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 != '%' ) { @@ -139,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; @@ -194,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] ) @@ -229,7 +225,7 @@ void nick_dedupe( bee_user_t *bu, char nick[MAX_NICK_LENGTH+1] ) /* Now, find out if the nick is already in use at the moment, and make subtle changes to make it unique. */ - while( !nick_ok( nick ) || + while( !nick_ok( irc, nick ) || ( ( iu = irc_user_by_name( irc, nick ) ) && iu->bu != bu ) ) { if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) ) @@ -244,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; } } @@ -286,48 +273,100 @@ void nick_del( bee_user_t *bu ) } -void nick_strip( char *nick ) +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( 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( char *nick ) +int nick_lc( irc_t *irc, char *nick ) { static char tab[128] = { 0 }; int i; @@ -339,47 +378,32 @@ int nick_lc( 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( 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]]; - } + if( nick[i] < 0x7f ) + nick[i] = tab[(int)nick[i]]; - return( 1 ); + return nick_ok( irc, nick ); } -int nick_cmp( const char *a, const char *b ) +int nick_cmp( irc_t *irc, const char *a, const char *b ) { char aa[1024] = "", bb[1024] = ""; strncpy( aa, a, sizeof( aa ) - 1 ); strncpy( bb, b, sizeof( bb ) - 1 ); - if( nick_lc( aa ) && nick_lc( bb ) ) + if( nick_lc( irc, aa ) && nick_lc( irc, bb ) ) { return( strcmp( aa, bb ) ); } @@ -388,8 +412,3 @@ int nick_cmp( const char *a, const char *b ) return( -1 ); /* Hmm... Not a clear answer.. :-/ */ } } - -char *nick_dup( const char *nick ) -{ - return g_strndup( nick, MAX_NICK_LENGTH ); -} |