source: nick.c @ 990d5fd

Last change on this file since 990d5fd was 43462708, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-01-06T12:37:55Z

More consistency in error/warning errors. Until now "WARNING:" was usually
in upper case while "Error:" wasn't .... that doesn't really make sense.

  • Property mode set to 100644
File size: 6.6 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        if( isdigit( nick[0] ) )
173        {
174                char *orig;
175               
176                orig = g_strdup( nick );
177                g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
178                g_free( orig );
179                j ++;
180        }
181        while( j <= MAX_NICK_LENGTH )
182                nick[j++] = '\0';
183}
184
185int nick_ok( const char *nick )
186{
187        const char *s;
188       
189        /* Empty/long nicks are not allowed, nor numbers at [0] */
190        if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
191                return( 0 );
192       
193        for( s = nick; *s; s ++ )
194                if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
195                        return( 0 );
196       
197        return( 1 );
198}
199
200int nick_lc( char *nick )
201{
202        static char tab[128] = { 0 };
203        int i;
204       
205        if( tab['A'] == 0 )
206                for( i = 0; nick_lc_chars[i]; i ++ )
207                {
208                        tab[(int)nick_uc_chars[i]] = nick_lc_chars[i];
209                        tab[(int)nick_lc_chars[i]] = nick_lc_chars[i];
210                }
211       
212        for( i = 0; nick[i]; i ++ )
213        {
214                if( !tab[(int)nick[i]] )
215                        return( 0 );
216               
217                nick[i] = tab[(int)nick[i]];
218        }
219       
220        return( 1 );
221}
222
223int nick_uc( char *nick )
224{
225        static char tab[128] = { 0 };
226        int i;
227       
228        if( tab['A'] == 0 )
229                for( i = 0; nick_lc_chars[i]; i ++ )
230                {
231                        tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
232                        tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
233                }
234       
235        for( i = 0; nick[i]; i ++ )
236        {
237                if( !tab[(int)nick[i]] )
238                        return( 0 );
239               
240                nick[i] = tab[(int)nick[i]];
241        }
242       
243        return( 1 );
244}
245
246int nick_cmp( const char *a, const char *b )
247{
248        char aa[1024] = "", bb[1024] = "";
249       
250        strncpy( aa, a, sizeof( aa ) - 1 );
251        strncpy( bb, b, sizeof( bb ) - 1 );
252        if( nick_lc( aa ) && nick_lc( bb ) )
253        {
254                return( strcmp( aa, bb ) );
255        }
256        else
257        {
258                return( -1 );   /* Hmm... Not a clear answer.. :-/ */
259        }
260}
261
262char *nick_dup( const char *nick )
263{
264        return g_strndup( nick, MAX_NICK_LENGTH );
265}
Note: See TracBrowser for help on using the repository browser.