1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* Some stuff to fetch, save and handle nicknames for your buddies */
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.
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.
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
29 /* Character maps, _lc_[x] == _uc_[x] (but uppercase), according to the RFC's.
30 With one difference, we allow dashes. These are used to do uc/lc conversions
31 and strip invalid chars. */
32 static char *nick_lc_chars
= "0123456789abcdefghijklmnopqrstuvwxyz{}^`-_|";
33 static char *nick_uc_chars
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~`-_\\";
35 /* Store handles in lower case and strip spaces, because AIM is braindead. */
36 static char *clean_handle( const char *orig
)
38 char *new = g_malloc( strlen( orig
) + 1 );
43 new[i
++] = tolower( *orig
);
50 void nick_set_raw( account_t
*acc
, const char *handle
, const char *nick
)
52 char *store_handle
, *store_nick
= g_malloc( MAX_NICK_LENGTH
+ 1 );
54 store_handle
= clean_handle( handle
);
55 store_nick
[MAX_NICK_LENGTH
] = '\0';
56 strncpy( store_nick
, nick
, MAX_NICK_LENGTH
);
57 nick_strip( store_nick
);
59 g_hash_table_replace( acc
->nicks
, store_handle
, store_nick
);
62 void nick_set( bee_user_t
*bu
, const char *nick
)
64 nick_set_raw( bu
->ic
->acc
, bu
->handle
, nick
);
67 char *nick_get( bee_user_t
*bu
)
69 static char nick
[MAX_NICK_LENGTH
+1];
70 char *store_handle
, *found_nick
;
72 memset( nick
, 0, MAX_NICK_LENGTH
+ 1 );
74 store_handle
= clean_handle( bu
->handle
);
75 /* Find out if we stored a nick for this person already. If not, try
76 to generate a sane nick automatically. */
77 if( ( found_nick
= g_hash_table_lookup( bu
->ic
->acc
->nicks
, store_handle
) ) )
79 strncpy( nick
, found_nick
, MAX_NICK_LENGTH
);
81 else if( ( found_nick
= nick_gen( bu
) ) )
83 strncpy( nick
, found_nick
, MAX_NICK_LENGTH
);
88 /* Keep this fallback since nick_gen() can return NULL in some cases. */
91 g_snprintf( nick
, MAX_NICK_LENGTH
, "%s", bu
->handle
);
92 if( ( s
= strchr( nick
, '@' ) ) )
97 if( set_getbool( &bu
->bee
->set
, "lcnicks" ) )
100 g_free( store_handle
);
102 /* Make sure the nick doesn't collide with an existing one by adding
103 underscores and that kind of stuff, if necessary. */
104 nick_dedupe( bu
, nick
);
109 char *nick_gen( bee_user_t
*bu
)
111 gboolean ok
= FALSE
; /* Set to true once the nick contains something unique. */
112 GString
*ret
= g_string_new( "" );
113 char *fmt
= set_getstr( &bu
->ic
->acc
->set
, "nick_format" ) ? :
114 set_getstr( &bu
->bee
->set
, "nick_format" );
116 while( fmt
&& *fmt
&& ret
->len
< MAX_NICK_LENGTH
)
118 char *part
= NULL
, chop
= '\0', *asc
= NULL
;
119 int len
= MAX_NICK_LENGTH
;
123 g_string_append_c( ret
, *fmt
);
131 /* -char means chop off everything from char */
139 else if( isdigit( *fmt
) )
143 while( isdigit( *fmt
) )
144 len
= len
* 10 + ( *(fmt
++) - '0' );
146 else if( g_strncasecmp( fmt
, "nick", 4 ) == 0 )
148 part
= bu
->nick
? : bu
->handle
;
153 else if( g_strncasecmp( fmt
, "handle", 6 ) == 0 )
160 else if( g_strncasecmp( fmt
, "full_name", 9 ) == 0 )
167 else if( g_strncasecmp( fmt
, "first_name", 10 ) == 0 )
175 else if( g_strncasecmp( fmt
, "group", 5 ) == 0 )
177 part
= bu
->group
? bu
->group
->name
: NULL
;
181 else if( g_strncasecmp( fmt
, "account", 7 ) == 0 )
183 part
= bu
->ic
->acc
->tag
;
193 /* Credits to Josay_ in #bitlbee for this idea. //TRANSLIT
194 should do lossy/approximate conversions, so letters with
195 accents don't just get stripped. Note that it depends on
196 LC_CTYPE being set to something other than C/POSIX. */
198 part
= asc
= g_convert_with_fallback( part
, -1, "ASCII//TRANSLIT",
199 "UTF-8", "", NULL
, NULL
, NULL
);
201 if( ret
->len
== 0 && part
&& isdigit( *part
) )
202 g_string_append_c( ret
, '_' );
204 while( part
&& *part
&& *part
!= chop
&& len
> 0 )
206 if( strchr( nick_lc_chars
, *part
) ||
207 strchr( nick_uc_chars
, *part
) )
208 g_string_append_c( ret
, *part
);
216 /* This returns NULL if the nick is empty or otherwise not ok. */
217 return g_string_free( ret
, ret
->len
== 0 || !ok
);
220 void nick_dedupe( bee_user_t
*bu
, char nick
[MAX_NICK_LENGTH
+1] )
222 irc_t
*irc
= (irc_t
*) bu
->bee
->ui_data
;
223 int inf_protection
= 256;
226 /* Now, find out if the nick is already in use at the moment, and make
227 subtle changes to make it unique. */
228 while( !nick_ok( nick
) ||
229 ( ( iu
= irc_user_by_name( irc
, nick
) ) && iu
->bu
!= bu
) )
231 if( strlen( nick
) < ( MAX_NICK_LENGTH
- 1 ) )
233 nick
[strlen(nick
)+1] = 0;
234 nick
[strlen(nick
)] = '_';
241 if( inf_protection
-- == 0 )
245 irc_rootmsg( irc
, "Warning: Almost had an infinite loop in nick_get()! "
246 "This used to be a fatal BitlBee bug, but we tried to fix it. "
247 "This message should *never* appear anymore. "
248 "If it does, please *do* send us a bug report! "
249 "Please send all the following lines in your report:" );
251 irc_rootmsg( irc
, "Trying to get a sane nick for handle %s", bu
->handle
);
252 for( i
= 0; i
< MAX_NICK_LENGTH
; i
++ )
253 irc_rootmsg( irc
, "Char %d: %c/%d", i
, nick
[i
], nick
[i
] );
255 irc_rootmsg( irc
, "FAILED. Returning an insane nick now. Things might break. "
256 "Good luck, and please don't forget to paste the lines up here "
257 "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
259 g_snprintf( nick
, MAX_NICK_LENGTH
+ 1, "xx%x", rand() );
266 /* Just check if there is a nickname set for this buddy or if we'd have to
268 int nick_saved( bee_user_t
*bu
)
270 char *store_handle
, *found
;
272 store_handle
= clean_handle( bu
->handle
);
273 found
= g_hash_table_lookup( bu
->ic
->acc
->nicks
, store_handle
);
274 g_free( store_handle
);
276 return found
!= NULL
;
279 void nick_del( bee_user_t
*bu
)
281 g_hash_table_remove( bu
->ic
->acc
->nicks
, bu
->handle
);
285 void nick_strip( char *nick
)
289 for( i
= j
= 0; nick
[i
] && j
< MAX_NICK_LENGTH
; i
++ )
291 if( strchr( nick_lc_chars
, nick
[i
] ) ||
292 strchr( nick_uc_chars
, nick
[i
] ) )
298 if( isdigit( nick
[0] ) )
302 orig
= g_strdup( nick
);
303 g_snprintf( nick
, MAX_NICK_LENGTH
, "_%s", orig
);
307 while( j
<= MAX_NICK_LENGTH
)
311 int nick_ok( const char *nick
)
315 /* Empty/long nicks are not allowed, nor numbers at [0] */
316 if( !*nick
|| isdigit( nick
[0] ) || strlen( nick
) > MAX_NICK_LENGTH
)
319 for( s
= nick
; *s
; s
++ )
320 if( !strchr( nick_lc_chars
, *s
) && !strchr( nick_uc_chars
, *s
) )
326 int nick_lc( char *nick
)
328 static char tab
[128] = { 0 };
332 for( i
= 0; nick_lc_chars
[i
]; i
++ )
334 tab
[(int)nick_uc_chars
[i
]] = nick_lc_chars
[i
];
335 tab
[(int)nick_lc_chars
[i
]] = nick_lc_chars
[i
];
338 for( i
= 0; nick
[i
]; i
++ )
340 if( !tab
[(int)nick
[i
]] )
343 nick
[i
] = tab
[(int)nick
[i
]];
349 int nick_uc( char *nick
)
351 static char tab
[128] = { 0 };
355 for( i
= 0; nick_lc_chars
[i
]; i
++ )
357 tab
[(int)nick_uc_chars
[i
]] = nick_uc_chars
[i
];
358 tab
[(int)nick_lc_chars
[i
]] = nick_uc_chars
[i
];
361 for( i
= 0; nick
[i
]; i
++ )
363 if( !tab
[(int)nick
[i
]] )
366 nick
[i
] = tab
[(int)nick
[i
]];
372 int nick_cmp( const char *a
, const char *b
)
374 char aa
[1024] = "", bb
[1024] = "";
376 strncpy( aa
, a
, sizeof( aa
) - 1 );
377 strncpy( bb
, b
, sizeof( bb
) - 1 );
378 if( nick_lc( aa
) && nick_lc( bb
) )
380 return( strcmp( aa
, bb
) );
384 return( -1 ); /* Hmm... Not a clear answer.. :-/ */
388 char *nick_dup( const char *nick
)
390 return g_strndup( nick
, MAX_NICK_LENGTH
);