Changeset c608891


Ignore:
Timestamp:
2013-04-23T16:20:06Z (12 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
5cb9461
Parents:
e277e80
Message:

Simple (and possibly still fragile) support for UTF-8 nicknames.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    re277e80 rc608891  
    3535static char *set_eval_password( set_t *set, char *value );
    3636static char *set_eval_bw_compat( set_t *set, char *value );
     37static char *set_eval_utf8_nicks( set_t *set, char *value );
    3738
    3839irc_t *irc_new( int fd )
     
    134135        s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
    135136        s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
     137        s = set_add( &b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc );
    136138
    137139        irc->root = iu = irc_user_new( irc, ROOT_NICK );
     
    962964}
    963965
     966static char *set_eval_utf8_nicks( set_t *set, char *value )
     967{
     968        irc_t *irc = set->data;
     969        gboolean val = bool2int( value );
     970       
     971        /* Do *NOT* unset this flag in the middle of a session. There will
     972           be UTF-8 nicks around already so if we suddenly disable support
     973           for them, various functions might behave strangely. */
     974        if( val )
     975                irc->status |= IRC_UTF8_NICKS;
     976        else if( irc->status & IRC_UTF8_NICKS )
     977                irc_rootmsg( irc, "You need to reconnect to BitlBee for this "
     978                                  "change to take effect." );
     979       
     980        return set_eval_bool( set, value );
     981}
     982
    964983void register_irc_plugin( const struct irc_plugin *p )
    965984{
  • irc.h

    re277e80 rc608891  
    6262        OPER_HACK_ACCOUNT_ADD = 0x400,
    6363        OPER_HACK_ANY = 0x3700, /* To check for them all at once. */
     64       
     65        IRC_UTF8_NICKS = 0x10000, /* Disable ASCII restrictions on buddy nicks. */
    6466} irc_status_t;
    6567
  • nick.c

    re277e80 rc608891  
    112112{
    113113        gboolean ok = FALSE; /* Set to true once the nick contains something unique. */
    114         GString *ret = g_string_new( "" );
     114        GString *ret = g_string_sized_new( MAX_NICK_LENGTH + 1 );
     115        char *rets;
     116        irc_t *irc = (irc_t *) bu->bee->ui_data;
    115117        char *fmt = set_getstr( &bu->ic->acc->set, "nick_format" ) ? :
    116118                    set_getstr( &bu->bee->set, "nick_format" );
     
    119121        {
    120122                char *part = NULL, chop = '\0', *asc = NULL;
    121                 int len = MAX_NICK_LENGTH;
    122123               
    123124                if( *fmt != '%' )
     
    142143                                fmt += 2;
    143144                        }
    144                         else if( isdigit( *fmt ) )
    145                         {
    146                                 len = 0;
    147                                 /* Grab a number. */
    148                                 while( isdigit( *fmt ) )
    149                                         len = len * 10 + ( *(fmt++) - '0' );
    150                         }
    151145                        else if( g_strncasecmp( fmt, "nick", 4 ) == 0 )
    152146                        {
     
    197191                }
    198192               
     193                if( !part )
     194                        continue;
     195               
    199196                /* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT
    200197                   should do lossy/approximate conversions, so letters with
    201198                   accents don't just get stripped. Note that it depends on
    202199                   LC_CTYPE being set to something other than C/POSIX. */
    203                 if( part )
     200                if( !( irc && irc->status & IRC_UTF8_NICKS ) )
    204201                        part = asc = g_convert_with_fallback( part, -1, "ASCII//TRANSLIT",
    205202                                                              "UTF-8", "", NULL, NULL, NULL );
    206203               
    207                 if( ret->len == 0 && part && isdigit( *part ) )
    208                         g_string_append_c( ret, '_' );
    209                
    210                 while( part && *part && *part != chop && len > 0 )
    211                 {
    212                         if( strchr( nick_lc_chars, *part ) ||
    213                             strchr( nick_uc_chars, *part ) )
    214                                 g_string_append_c( ret, *part );
    215                        
    216                         part ++;
    217                         len --;
    218                 }
     204                if( part )
     205                        g_string_append( ret, part );
    219206                g_free( asc );
    220207        }
    221208       
    222         /* This returns NULL if the nick is empty or otherwise not ok. */
    223         return g_string_free( ret, ret->len == 0 || !ok );
     209        rets = g_string_free( ret, FALSE );
     210        if( ok && rets && *rets )
     211        {
     212                nick_strip( irc, rets );
     213                rets[MAX_NICK_LENGTH] = '\0';
     214                return rets;
     215        }
     216        g_free( rets );
     217        return NULL;
    224218}
    225219
     
    247241                if( inf_protection-- == 0 )
    248242                {
    249                         int i;
     243                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
    250244                       
    251                         irc_rootmsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
    252                                           "This used to be a fatal BitlBee bug, but we tried to fix it. "
    253                                           "This message should *never* appear anymore. "
    254                                           "If it does, please *do* send us a bug report! "
    255                                           "Please send all the following lines in your report:" );
    256                        
    257                         irc_rootmsg( irc, "Trying to get a sane nick for handle %s", bu->handle );
    258                         for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    259                                 irc_rootmsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
    260                        
    261                         irc_rootmsg( irc, "FAILED. Returning an insane nick now. Things might break. "
    262                                           "Good luck, and please don't forget to paste the lines up here "
    263                                           "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
    264                        
    265                         g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
     245                        irc_rootmsg( irc, "Warning: Something went wrong while trying "
     246                                          "to generate a nickname for contact %s on %s.",
     247                                          bu->handle, bu->ic->acc->tag );
     248                        irc_rootmsg( irc, "This might be a bug in BitlBee, or the result "
     249                                          "of a faulty nick_format setting. Will use %s "
     250                                          "instead.", nick );
    266251                       
    267252                        break;
     
    291276void nick_strip( irc_t *irc, char *nick )
    292277{
    293         int i, j;
    294        
    295         for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
    296         {
    297                 if( strchr( nick_lc_chars, nick[i] ) ||
    298                     strchr( nick_uc_chars, nick[i] ) )
    299                 {
    300                         nick[j] = nick[i];
    301                         j++;
     278        int len = 0;
     279       
     280        if( irc && ( irc->status & IRC_UTF8_NICKS ) )
     281        {
     282                gunichar c;
     283                char *p = nick, *n, tmp[strlen(nick)+1];
     284               
     285                while( p && *p )
     286                {
     287                        c = g_utf8_get_char_validated( p, -1 );
     288                        n = g_utf8_find_next_char( p, NULL );
     289                       
     290                        if( ( c < 0x7f && !( strchr( nick_lc_chars, c ) ||
     291                                             strchr( nick_uc_chars, c ) ) ) ||
     292                            !g_unichar_isgraph( c ) )
     293                        {
     294                                strcpy( tmp, n );
     295                                strcpy( p, tmp );
     296                        }
     297                        else
     298                                p = n;
     299                }
     300                if( p )
     301                        len = p - nick;
     302        }
     303        else
     304        {
     305                int i;
     306               
     307                for( i = len = 0; nick[i] && len < MAX_NICK_LENGTH; i++ )
     308                {
     309                        if( strchr( nick_lc_chars, nick[i] ) ||
     310                            strchr( nick_uc_chars, nick[i] ) )
     311                        {
     312                                nick[len] = nick[i];
     313                                len++;
     314                        }
    302315                }
    303316        }
     
    306319                char *orig;
    307320               
     321                /* First character of a nick can't be a digit, so insert an
     322                   underscore if necessary. */
    308323                orig = g_strdup( nick );
    309324                g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
    310325                g_free( orig );
    311                 j ++;
    312         }
    313         while( j <= MAX_NICK_LENGTH )
    314                 nick[j++] = '\0';
    315 }
    316 
    317 int nick_ok( irc_t *irc, const char *nick )
     326                len ++;
     327        }
     328        while( len <= MAX_NICK_LENGTH )
     329                nick[len++] = '\0';
     330}
     331
     332gboolean nick_ok( irc_t *irc, const char *nick )
    318333{
    319334        const char *s;
     
    321336        /* Empty/long nicks are not allowed, nor numbers at [0] */
    322337        if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
    323                 return( 0 );
    324        
    325         for( s = nick; *s; s ++ )
    326                 if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
    327                         return( 0 );
    328        
    329         return( 1 );
     338                return 0;
     339       
     340        if( irc && ( irc->status & IRC_UTF8_NICKS ) )
     341        {
     342                gunichar c;
     343                const char *p = nick, *n;
     344               
     345                while( p && *p )
     346                {
     347                        c = g_utf8_get_char_validated( p, -1 );
     348                        n = g_utf8_find_next_char( p, NULL );
     349                       
     350                        if( ( c < 0x7f && !( strchr( nick_lc_chars, c ) ||
     351                                             strchr( nick_uc_chars, c ) ) ) ||
     352                            !g_unichar_isgraph( c ) )
     353                        {
     354                                return FALSE;
     355                        }
     356                        p = n;
     357                }
     358        }
     359        else
     360        {
     361                for( s = nick; *s; s ++ )
     362                        if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
     363                                return FALSE;
     364        }
     365       
     366        return TRUE;
    330367}
    331368
     
    342379                }
    343380       
     381        if( irc && ( irc->status & IRC_UTF8_NICKS ) )
     382        {
     383                gchar *down = g_utf8_strdown( nick, -1 );
     384                if( strlen( down ) > strlen( nick ) )
     385                {
     386                        /* Well crap. Corrupt it if we have to. */
     387                        down[strlen(nick)] = '\0';
     388                }
     389                strcpy( nick, down );
     390                g_free( down );
     391        }
     392       
    344393        for( i = 0; nick[i]; i ++ )
    345         {
    346                 if( !tab[(int)nick[i]] )
    347                         return( 0 );
    348                
    349394                nick[i] = tab[(int)nick[i]];
    350         }
    351        
    352         return( 1 );
    353 }
    354 
    355 int nick_uc( irc_t *irc, char *nick )
    356 {
    357         static char tab[128] = { 0 };
    358         int i;
    359        
    360         if( tab['A'] == 0 )
    361                 for( i = 0; nick_lc_chars[i]; i ++ )
    362                 {
    363                         tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
    364                         tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
    365                 }
    366        
    367         for( i = 0; nick[i]; i ++ )
    368         {
    369                 if( !tab[(int)nick[i]] )
    370                         return( 0 );
    371                
    372                 nick[i] = tab[(int)nick[i]];
    373         }
    374        
    375         return( 1 );
     395       
     396        return nick_ok( irc, nick );
    376397}
    377398
  • nick.h

    re277e80 rc608891  
    3333
    3434void nick_strip( irc_t *irc, char *nick );
    35 int nick_ok( irc_t *irc, const char *nick );
     35gboolean nick_ok( irc_t *irc, const char *nick );
    3636int nick_lc( irc_t *irc, char *nick );
    3737int nick_uc( irc_t *irc, char *nick );
Note: See TracChangeset for help on using the changeset viewer.