Changeset 1a2c1c0


Ignore:
Timestamp:
2013-06-16T12:42:39Z (7 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
2f9027c
Parents:
ab19567 (diff), 5cb9461 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merging utf8-nicks branch. This adds a utf8_nicks setting which removes the
ASCII restriction on contact nicknames. Use at your own risk!

Files:
11 edited

Legend:

Unmodified
Added
Removed
  • doc/user-guide/commands.xml

    rab19567 r1a2c1c0  
    16201620        </bitlbee-setting>
    16211621
     1622        <bitlbee-setting name="utf8_nicks" type="boolean" scope="global">
     1623                <default>false</default>
     1624
     1625                <description>
     1626                        <para>
     1627                                Officially, IRC nicknames are restricted to ASCII. Recently some clients and servers started supporting Unicode nicknames though. To enable UTF-8 nickname support (contacts only) in BitlBee, enable this setting.
     1628                        </para>
     1629                       
     1630                        <para>
     1631                                To avoid confusing old clients, this setting is disabled by default. Be careful when you try it, and be prepared to be locked out of your BitlBee in case your client interacts poorly with UTF-8 nicknames.
     1632                        </para>
     1633                </description>
     1634        </bitlbee-setting>
     1635
    16221636        <bitlbee-setting name="web_aware" type="string" scope="account">
    16231637                <default>false</default>
  • ipc.c

    rab19567 r1a2c1c0  
    152152                old = l->data;
    153153                if( child != old &&
    154                     old->nick && nick_cmp( old->nick, child->nick ) == 0 &&
     154                    old->nick && nick_cmp( NULL, old->nick, child->nick ) == 0 &&
    155155                    old->password && strcmp( old->password, child->password ) == 0 )
    156156                        break;
     
    298298                return;
    299299       
    300         if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
     300        if( nick_cmp( NULL, cmd[1], irc->user->nick ) != 0 )
    301301                return;         /* It's not for us. */
    302302       
  • irc.c

    rab19567 r1a2c1c0  
    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

    rab19567 r1a2c1c0  
    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
  • irc_commands.c

    rab19567 r1a2c1c0  
    8080                irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] );
    8181        }
    82         else if( !nick_ok( cmd[1] ) )
     82        else if( !nick_ok( NULL, cmd[1] ) )
    8383        {
    8484                /* [SH] Invalid characters. */
     
    291291        else
    292292        {
    293                 if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
     293                if( nick_cmp( NULL, cmd[1], irc->user->nick ) == 0 )
    294294                {
    295295                        if( cmd[2] )
     
    392392        /* At least for now just echo. IIRC some IRC clients use self-notices
    393393           for lag checks, so try to support that. */
    394         if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
     394        if( nick_cmp( NULL, cmd[1], irc->user->nick ) == 0 )
    395395                irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL );
    396396        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
     
    593593               
    594594                nick = g_strdup( cmd[i] + 1 );
    595                 nick_lc( nick );
     595                nick_lc( irc, nick );
    596596               
    597597                iu = irc_user_by_name( irc, nick );
  • irc_im.c

    rab19567 r1a2c1c0  
    697697        irc_channel_name_strip( stripped );
    698698        if( set_getbool( &bee->set, "lcnicks" ) )
    699                 nick_lc( stripped );
     699                nick_lc( irc, stripped );
    700700       
    701701        if( stripped[0] == '\0' )
  • irc_user.c

    rab19567 r1a2c1c0  
    3636       
    3737        iu->key = g_strdup( nick );
    38         nick_lc( iu->key );
     38        nick_lc( irc, iu->key );
    3939        /* Using the hash table for speed and irc->users for easy iteration
    4040           through the list (since the GLib API doesn't have anything sane
     
    107107       
    108108        strcpy( key, nick );
    109         if( nick_lc( key ) )
     109        if( nick_lc( irc, key ) )
    110110                return g_hash_table_lookup( irc->nick_user_hash, key );
    111111        else
     
    121121       
    122122        strcpy( key, new );
    123         if( iu == NULL || !nick_lc( key ) ||
     123        if( iu == NULL || !nick_lc( irc, key ) ||
    124124            ( ( new_iu = irc_user_by_name( irc, new ) ) && new_iu != iu ) )
    125125                return 0;
  • nick.c

    rab19567 r1a2c1c0  
    5151{
    5252        char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 );
     53        irc_t *irc = (irc_t *) acc->bee->ui_data;
    5354       
    5455        store_handle = clean_handle( handle );
    5556        store_nick[MAX_NICK_LENGTH] = '\0';
    5657        strncpy( store_nick, nick, MAX_NICK_LENGTH );
    57         nick_strip( store_nick );
     58        nick_strip( irc, store_nick );
    5859       
    5960        g_hash_table_replace( acc->nicks, store_handle, store_nick );
     
    6970        static char nick[MAX_NICK_LENGTH+1];
    7071        char *store_handle, *found_nick;
     72        irc_t *irc = (irc_t *) bu->bee->ui_data;
    7173       
    7274        memset( nick, 0, MAX_NICK_LENGTH + 1 );
     
    9496                                *(s++) = 0;
    9597               
    96                 nick_strip( nick );
     98                nick_strip( irc, nick );
    9799                if( set_getbool( &bu->bee->set, "lcnicks" ) )
    98                         nick_lc( nick );
     100                        nick_lc( irc, nick );
    99101        }
    100102        g_free( store_handle );
     
    110112{
    111113        gboolean ok = FALSE; /* Set to true once the nick contains something unique. */
    112         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;
    113117        char *fmt = set_getstr( &bu->ic->acc->set, "nick_format" ) ? :
    114118                    set_getstr( &bu->bee->set, "nick_format" );
     
    117121        {
    118122                char *part = NULL, chop = '\0', *asc = NULL;
    119                 int len = MAX_NICK_LENGTH;
    120123               
    121124                if( *fmt != '%' )
     
    140143                                fmt += 2;
    141144                        }
    142                         else if( isdigit( *fmt ) )
    143                         {
    144                                 len = 0;
    145                                 /* Grab a number. */
    146                                 while( isdigit( *fmt ) )
    147                                         len = len * 10 + ( *(fmt++) - '0' );
    148                         }
    149145                        else if( g_strncasecmp( fmt, "nick", 4 ) == 0 )
    150146                        {
     
    195191                }
    196192               
     193                if( !part )
     194                        continue;
     195               
    197196                /* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT
    198197                   should do lossy/approximate conversions, so letters with
    199198                   accents don't just get stripped. Note that it depends on
    200199                   LC_CTYPE being set to something other than C/POSIX. */
    201                 if( part )
     200                if( !( irc && irc->status & IRC_UTF8_NICKS ) )
    202201                        part = asc = g_convert_with_fallback( part, -1, "ASCII//TRANSLIT",
    203202                                                              "UTF-8", "", NULL, NULL, NULL );
    204203               
    205                 if( ret->len == 0 && part && isdigit( *part ) )
    206                         g_string_append_c( ret, '_' );
    207                
    208                 while( part && *part && *part != chop && len > 0 )
    209                 {
    210                         if( strchr( nick_lc_chars, *part ) ||
    211                             strchr( nick_uc_chars, *part ) )
    212                                 g_string_append_c( ret, *part );
    213                        
    214                         part ++;
    215                         len --;
    216                 }
     204                if( part )
     205                        g_string_append( ret, part );
    217206                g_free( asc );
    218207        }
    219208       
    220         /* This returns NULL if the nick is empty or otherwise not ok. */
    221         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;
    222218}
    223219
     
    230226        /* Now, find out if the nick is already in use at the moment, and make
    231227           subtle changes to make it unique. */
    232         while( !nick_ok( nick ) ||
     228        while( !nick_ok( irc, nick ) ||
    233229               ( ( iu = irc_user_by_name( irc, nick ) ) && iu->bu != bu ) )
    234230        {
     
    245241                if( inf_protection-- == 0 )
    246242                {
    247                         int i;
     243                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
    248244                       
    249                         irc_rootmsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
    250                                           "This used to be a fatal BitlBee bug, but we tried to fix it. "
    251                                           "This message should *never* appear anymore. "
    252                                           "If it does, please *do* send us a bug report! "
    253                                           "Please send all the following lines in your report:" );
    254                        
    255                         irc_rootmsg( irc, "Trying to get a sane nick for handle %s", bu->handle );
    256                         for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    257                                 irc_rootmsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
    258                        
    259                         irc_rootmsg( irc, "FAILED. Returning an insane nick now. Things might break. "
    260                                           "Good luck, and please don't forget to paste the lines up here "
    261                                           "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
    262                        
    263                         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 );
    264251                       
    265252                        break;
     
    287274
    288275
    289 void nick_strip( char *nick )
    290 {
    291         int i, j;
    292        
    293         for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
    294         {
    295                 if( strchr( nick_lc_chars, nick[i] ) ||
    296                     strchr( nick_uc_chars, nick[i] ) )
    297                 {
    298                         nick[j] = nick[i];
    299                         j++;
     276void nick_strip( irc_t *irc, char *nick )
     277{
     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                        }
    300315                }
    301316        }
     
    304319                char *orig;
    305320               
     321                /* First character of a nick can't be a digit, so insert an
     322                   underscore if necessary. */
    306323                orig = g_strdup( nick );
    307324                g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
    308325                g_free( orig );
    309                 j ++;
    310         }
    311         while( j <= MAX_NICK_LENGTH )
    312                 nick[j++] = '\0';
    313 }
    314 
    315 int nick_ok( 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 )
    316333{
    317334        const char *s;
     
    319336        /* Empty/long nicks are not allowed, nor numbers at [0] */
    320337        if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
    321                 return( 0 );
    322        
    323         for( s = nick; *s; s ++ )
    324                 if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
    325                         return( 0 );
    326        
    327         return( 1 );
    328 }
    329 
    330 int nick_lc( char *nick )
     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;
     367}
     368
     369int nick_lc( irc_t *irc, char *nick )
    331370{
    332371        static char tab[128] = { 0 };
     
    340379                }
    341380       
     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       
    342393        for( i = 0; nick[i]; i ++ )
    343         {
    344                 if( !tab[(int)nick[i]] )
    345                         return( 0 );
    346                
    347                 nick[i] = tab[(int)nick[i]];
    348         }
    349        
    350         return( 1 );
    351 }
    352 
    353 int nick_uc( char *nick )
    354 {
    355         static char tab[128] = { 0 };
    356         int i;
    357        
    358         if( tab['A'] == 0 )
    359                 for( i = 0; nick_lc_chars[i]; i ++ )
    360                 {
    361                         tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
    362                         tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
    363                 }
    364        
    365         for( i = 0; nick[i]; i ++ )
    366         {
    367                 if( !tab[(int)nick[i]] )
    368                         return( 0 );
    369                
    370                 nick[i] = tab[(int)nick[i]];
    371         }
    372        
    373         return( 1 );
    374 }
    375 
    376 int nick_cmp( const char *a, const char *b )
     394                if( nick[i] < 0x7f )
     395                        nick[i] = tab[(int)nick[i]];
     396       
     397        return nick_ok( irc, nick );
     398}
     399
     400int nick_cmp( irc_t *irc, const char *a, const char *b )
    377401{
    378402        char aa[1024] = "", bb[1024] = "";
     
    380404        strncpy( aa, a, sizeof( aa ) - 1 );
    381405        strncpy( bb, b, sizeof( bb ) - 1 );
    382         if( nick_lc( aa ) && nick_lc( bb ) )
     406        if( nick_lc( irc, aa ) && nick_lc( irc, bb ) )
    383407        {
    384408                return( strcmp( aa, bb ) );
     
    389413        }
    390414}
    391 
    392 char *nick_dup( const char *nick )
    393 {
    394         return g_strndup( nick, MAX_NICK_LENGTH );
    395 }
  • nick.h

    rab19567 r1a2c1c0  
    3131int nick_saved( bee_user_t *bu );
    3232void nick_del( bee_user_t *bu );
    33 void nick_strip( char *nick );
    3433
    35 int nick_ok( const char *nick );
    36 int nick_lc( char *nick );
    37 int nick_uc( char *nick );
    38 int nick_cmp( const char *a, const char *b );
     34void nick_strip( irc_t *irc, char *nick );
     35gboolean nick_ok( irc_t *irc, const char *nick );
     36int nick_lc( irc_t *irc, char *nick );
     37int nick_uc( irc_t *irc, char *nick );
     38int nick_cmp( irc_t *irc, const char *a, const char *b );
    3939char *nick_dup( const char *nick );
  • root_commands.c

    rab19567 r1a2c1c0  
    702702        if( cmd[3] )
    703703        {
    704                 if( !nick_ok( cmd[3] ) )
     704                if( !nick_ok( irc, cmd[3] ) )
    705705                {
    706706                        irc_rootmsg( irc, "The requested nick `%s' is invalid", cmd[3] );
     
    844844                irc_rootmsg( irc, "Use /nick to change your own nickname" );
    845845        }
    846         else if( !nick_ok( cmd[2] ) )
     846        else if( !nick_ok( irc, cmd[2] ) )
    847847        {
    848848                irc_rootmsg( irc, "Nick `%s' is invalid", cmd[2] );
  • storage_xml.c

    rab19567 r1a2c1c0  
    181181        strncpy( xd->given_nick, my_nick, MAX_NICK_LENGTH );
    182182        xd->given_nick[MAX_NICK_LENGTH] = '\0';
    183         nick_lc( xd->given_nick );
     183        nick_lc( NULL, xd->given_nick );
    184184        xd->given_pass = (char*) password;
    185185       
     
    368368       
    369369        path2 = g_strdup( irc->user->nick );
    370         nick_lc( path2 );
     370        nick_lc( NULL, path2 );
    371371        g_snprintf( path, sizeof( path ) - 20, "%s%s%s", global.conf->configdir, path2, ".xml" );
    372372        g_free( path2 );
     
    424424
    425425        lc = g_strdup( nick );
    426         nick_lc( lc );
     426        nick_lc( NULL, lc );
    427427        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, lc, ".xml" );
    428428        g_free( lc );
Note: See TracChangeset for help on using the changeset viewer.