source: nick.c @ 3f2bc2d

Last change on this file since 3f2bc2d was d06eabf, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-06-04T13:22:05Z

Added imcb_buddy_nick_hint so the Jabber conference module can suggest sane
nicknames for chatroom participants. There'll probably be a lot of
underscores now, but this is by far the cleanest way to implement this, I
think. At least now whispers will work properly. Also using this function
call to set names for ICQ contacts in a slightly saner way.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2007 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Some stuff to fetch, save and handle nicknames for your buddies      */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28
29/* Store handles in lower case and strip spaces, because AIM is braindead. */
30static char *clean_handle( const char *orig )
31{
32        char *new = g_malloc( strlen( orig ) + 1 );
33        int i = 0;
34       
35        do {
36                if (*orig != ' ')
37                        new[i++] = tolower( *orig );
38        }
39        while (*(orig++));
40       
41        return new;
42}
43
44void nick_set( account_t *acc, const char *handle, const char *nick )
45{
46        char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 );
47       
48        store_handle = clean_handle( handle );
49        strncpy( store_nick, nick, MAX_NICK_LENGTH );
50        nick_strip( store_nick );
51       
52        g_hash_table_replace( acc->nicks, store_handle, store_nick );
53}
54
55char *nick_get( account_t *acc, const char *handle )
56{
57        static char nick[MAX_NICK_LENGTH+1];
58        char *store_handle, *found_nick;
59       
60        memset( nick, 0, MAX_NICK_LENGTH + 1 );
61       
62        store_handle = clean_handle( handle );
63        /* Find out if we stored a nick for this person already. If not, try
64           to generate a sane nick automatically. */
65        if( ( found_nick = g_hash_table_lookup( acc->nicks, store_handle ) ) )
66        {
67                strncpy( nick, found_nick, MAX_NICK_LENGTH );
68        }
69        else
70        {
71                char *s;
72               
73                g_snprintf( nick, MAX_NICK_LENGTH, "%s", handle );
74                if( ( s = strchr( nick, '@' ) ) )
75                        while( *s )
76                                *(s++) = 0;
77               
78                nick_strip( nick );
79                if( set_getbool( &acc->irc->set, "lcnicks" ) )
80                        nick_lc( nick );
81        }
82        g_free( store_handle );
83       
84        /* Make sure the nick doesn't collide with an existing one by adding
85           underscores and that kind of stuff, if necessary. */
86        nick_dedupe( acc, handle, nick );
87       
88        return nick;
89}
90
91void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+1] )
92{
93        int inf_protection = 256;
94       
95        /* Now, find out if the nick is already in use at the moment, and make
96           subtle changes to make it unique. */
97        while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
98        {
99                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
100                {
101                        nick[strlen(nick)+1] = 0;
102                        nick[strlen(nick)] = '_';
103                }
104                else
105                {
106                        nick[0] ++;
107                }
108               
109                if( inf_protection-- == 0 )
110                {
111                        int i;
112                       
113                        irc_usermsg( acc->irc, "WARNING: Almost had an infinite loop in nick_get()! "
114                                               "This used to be a fatal BitlBee bug, but we tried to fix it. "
115                                               "This message should *never* appear anymore. "
116                                               "If it does, please *do* send us a bug report! "
117                                               "Please send all the following lines in your report:" );
118                       
119                        irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
120                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
121                                irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
122                       
123                        irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
124                                               "Good luck, and please don't forget to paste the lines up here "
125                                               "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
126                       
127                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
128                       
129                        break;
130                }
131        }
132}
133
134/* Just check if there is a nickname set for this buddy or if we'd have to
135   generate one. */
136int nick_saved( account_t *acc, const char *handle )
137{
138        char *store_handle, *found;
139       
140        store_handle = clean_handle( handle );
141        found = g_hash_table_lookup( acc->nicks, store_handle );
142        g_free( store_handle );
143       
144        return found != NULL;
145}
146
147void nick_del( account_t *acc, const char *handle )
148{
149        g_hash_table_remove( acc->nicks, handle );
150}
151
152
153/* Character maps, _lc_[x] == _uc_[x] (but uppercase), according to the RFC's.
154   With one difference, we allow dashes. */
155
156static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^-_|";
157static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~-_\\";
158
159void nick_strip( char * nick )
160{
161        int i, j;
162       
163        for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
164        {
165                if( strchr( nick_lc_chars, nick[i] ) || 
166                    strchr( nick_uc_chars, nick[i] ) )
167                {
168                        nick[j] = nick[i];
169                        j++;
170                }
171        }
172        while( j <= MAX_NICK_LENGTH )
173                nick[j++] = '\0';
174}
175
176int nick_ok( const char *nick )
177{
178        const char *s;
179       
180        /* Empty/long nicks are not allowed */
181        if( !*nick || strlen( nick ) > MAX_NICK_LENGTH )
182                return( 0 );
183       
184        for( s = nick; *s; s ++ )
185                if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
186                        return( 0 );
187       
188        return( 1 );
189}
190
191int nick_lc( char *nick )
192{
193        static char tab[128] = { 0 };
194        int i;
195       
196        if( tab['A'] == 0 )
197                for( i = 0; nick_lc_chars[i]; i ++ )
198                {
199                        tab[(int)nick_uc_chars[i]] = nick_lc_chars[i];
200                        tab[(int)nick_lc_chars[i]] = nick_lc_chars[i];
201                }
202       
203        for( i = 0; nick[i]; i ++ )
204        {
205                if( !tab[(int)nick[i]] )
206                        return( 0 );
207               
208                nick[i] = tab[(int)nick[i]];
209        }
210       
211        return( 1 );
212}
213
214int nick_uc( char *nick )
215{
216        static char tab[128] = { 0 };
217        int i;
218       
219        if( tab['A'] == 0 )
220                for( i = 0; nick_lc_chars[i]; i ++ )
221                {
222                        tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
223                        tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
224                }
225       
226        for( i = 0; nick[i]; i ++ )
227        {
228                if( !tab[(int)nick[i]] )
229                        return( 0 );
230               
231                nick[i] = tab[(int)nick[i]];
232        }
233       
234        return( 1 );
235}
236
237int nick_cmp( const char *a, const char *b )
238{
239        char aa[1024] = "", bb[1024] = "";
240       
241        strncpy( aa, a, sizeof( aa ) - 1 );
242        strncpy( bb, b, sizeof( bb ) - 1 );
243        if( nick_lc( aa ) && nick_lc( bb ) )
244        {
245                return( strcmp( aa, bb ) );
246        }
247        else
248        {
249                return( -1 );   /* Hmm... Not a clear answer.. :-/ */
250        }
251}
252
253char *nick_dup( const char *nick )
254{
255        return g_strndup( nick, MAX_NICK_LENGTH );
256}
Note: See TracBrowser for help on using the repository browser.