source: nick.c @ 0e8b3e8

Last change on this file since 0e8b3e8 was 81e04e1, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-01T02:32:25Z

nogaim.c is close to doing something useful again without speaking any IRC
itself.

  • Property mode set to 100644
File size: 6.7 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        store_nick[MAX_NICK_LENGTH] = 0;
50        strncpy( store_nick, nick, MAX_NICK_LENGTH );
51        nick_strip( store_nick );
52       
53        g_hash_table_replace( acc->nicks, store_handle, store_nick );
54}
55
56char *nick_get( account_t *acc, const char *handle )
57{
58        static char nick[MAX_NICK_LENGTH+1];
59        char *store_handle, *found_nick;
60       
61        memset( nick, 0, MAX_NICK_LENGTH + 1 );
62       
63        store_handle = clean_handle( handle );
64        /* Find out if we stored a nick for this person already. If not, try
65           to generate a sane nick automatically. */
66        if( ( found_nick = g_hash_table_lookup( acc->nicks, store_handle ) ) )
67        {
68                strncpy( nick, found_nick, MAX_NICK_LENGTH );
69        }
70        else
71        {
72                char *s;
73               
74                g_snprintf( nick, MAX_NICK_LENGTH, "%s", handle );
75                if( ( s = strchr( nick, '@' ) ) )
76                        while( *s )
77                                *(s++) = 0;
78               
79                nick_strip( nick );
80                if( set_getbool( &acc->bee->set, "lcnicks" ) )
81                        nick_lc( nick );
82        }
83        g_free( store_handle );
84       
85        /* Make sure the nick doesn't collide with an existing one by adding
86           underscores and that kind of stuff, if necessary. */
87        nick_dedupe( acc, handle, nick );
88       
89        return nick;
90}
91
92void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+1] )
93{
94        irc_t *irc = (irc_t*) acc->bee->ui_data;
95        int inf_protection = 256;
96       
97        /* Now, find out if the nick is already in use at the moment, and make
98           subtle changes to make it unique. */
99        while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
100        {
101                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
102                {
103                        nick[strlen(nick)+1] = 0;
104                        nick[strlen(nick)] = '_';
105                }
106                else
107                {
108                        nick[0] ++;
109                }
110               
111                if( inf_protection-- == 0 )
112                {
113                        int i;
114                       
115                        irc_usermsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
116                                          "This used to be a fatal BitlBee bug, but we tried to fix it. "
117                                          "This message should *never* appear anymore. "
118                                          "If it does, please *do* send us a bug report! "
119                                          "Please send all the following lines in your report:" );
120                       
121                        irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
122                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
123                                irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
124                       
125                        irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
126                                          "Good luck, and please don't forget to paste the lines up here "
127                                          "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
128                       
129                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
130                       
131                        break;
132                }
133        }
134}
135
136/* Just check if there is a nickname set for this buddy or if we'd have to
137   generate one. */
138int nick_saved( account_t *acc, const char *handle )
139{
140        char *store_handle, *found;
141       
142        store_handle = clean_handle( handle );
143        found = g_hash_table_lookup( acc->nicks, store_handle );
144        g_free( store_handle );
145       
146        return found != NULL;
147}
148
149void nick_del( account_t *acc, const char *handle )
150{
151        g_hash_table_remove( acc->nicks, handle );
152}
153
154
155/* Character maps, _lc_[x] == _uc_[x] (but uppercase), according to the RFC's.
156   With one difference, we allow dashes. */
157
158static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^`-_|";
159static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~`-_\\";
160
161void nick_strip( char *nick )
162{
163        int i, j;
164       
165        for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
166        {
167                if( strchr( nick_lc_chars, nick[i] ) || 
168                    strchr( nick_uc_chars, nick[i] ) )
169                {
170                        nick[j] = nick[i];
171                        j++;
172                }
173        }
174        if( isdigit( nick[0] ) )
175        {
176                char *orig;
177               
178                orig = g_strdup( nick );
179                g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
180                g_free( orig );
181                j ++;
182        }
183        while( j <= MAX_NICK_LENGTH )
184                nick[j++] = '\0';
185}
186
187int nick_ok( const char *nick )
188{
189        const char *s;
190       
191        /* Empty/long nicks are not allowed, nor numbers at [0] */
192        if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
193                return( 0 );
194       
195        for( s = nick; *s; s ++ )
196                if( !strchr( nick_lc_chars, *s ) && !strchr( nick_uc_chars, *s ) )
197                        return( 0 );
198       
199        return( 1 );
200}
201
202int nick_lc( char *nick )
203{
204        static char tab[128] = { 0 };
205        int i;
206       
207        if( tab['A'] == 0 )
208                for( i = 0; nick_lc_chars[i]; i ++ )
209                {
210                        tab[(int)nick_uc_chars[i]] = nick_lc_chars[i];
211                        tab[(int)nick_lc_chars[i]] = nick_lc_chars[i];
212                }
213       
214        for( i = 0; nick[i]; i ++ )
215        {
216                if( !tab[(int)nick[i]] )
217                        return( 0 );
218               
219                nick[i] = tab[(int)nick[i]];
220        }
221       
222        return( 1 );
223}
224
225int nick_uc( char *nick )
226{
227        static char tab[128] = { 0 };
228        int i;
229       
230        if( tab['A'] == 0 )
231                for( i = 0; nick_lc_chars[i]; i ++ )
232                {
233                        tab[(int)nick_uc_chars[i]] = nick_uc_chars[i];
234                        tab[(int)nick_lc_chars[i]] = nick_uc_chars[i];
235                }
236       
237        for( i = 0; nick[i]; i ++ )
238        {
239                if( !tab[(int)nick[i]] )
240                        return( 0 );
241               
242                nick[i] = tab[(int)nick[i]];
243        }
244       
245        return( 1 );
246}
247
248int nick_cmp( const char *a, const char *b )
249{
250        char aa[1024] = "", bb[1024] = "";
251       
252        strncpy( aa, a, sizeof( aa ) - 1 );
253        strncpy( bb, b, sizeof( bb ) - 1 );
254        if( nick_lc( aa ) && nick_lc( bb ) )
255        {
256                return( strcmp( aa, bb ) );
257        }
258        else
259        {
260                return( -1 );   /* Hmm... Not a clear answer.. :-/ */
261        }
262}
263
264char *nick_dup( const char *nick )
265{
266        return g_strndup( nick, MAX_NICK_LENGTH );
267}
Note: See TracBrowser for help on using the repository browser.