- Timestamp:
- 2010-07-24T21:16:18Z (14 years ago)
- Branches:
- master
- Children:
- f1f7b5e
- Parents:
- ef14a83 (diff), 593971d (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
irc.c
ref14a83 r2945c6f 5 5 \********************************************************************/ 6 6 7 /* The big hairy IRCd part of the project*/7 /* The IRC-based UI (for now the only one) */ 8 8 9 9 /* … … 24 24 */ 25 25 26 #define BITLBEE_CORE27 26 #include "bitlbee.h" 28 #include "sock.h"29 #include "crypting.h"30 27 #include "ipc.h" 31 32 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); 33 34 GSList *irc_connection_list = NULL; 35 36 static char *set_eval_password( set_t *set, char *value ) 37 { 38 irc_t *irc = set->data; 39 40 if( irc->status & USTATUS_IDENTIFIED && value ) 41 { 42 irc_setpass( irc, value ); 43 return NULL; 44 } 45 else 46 { 47 return SET_INVALID; 48 } 49 } 50 51 static char *set_eval_charset( set_t *set, char *value ) 52 { 53 irc_t *irc = set->data; 54 char *test; 55 gsize test_bytes = 0; 56 GIConv ic, oc; 57 58 if( g_strcasecmp( value, "none" ) == 0 ) 59 value = g_strdup( "utf-8" ); 60 61 if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) 62 { 63 return NULL; 64 } 65 66 /* Do a test iconv to see if the user picked an IRC-compatible 67 charset (for example utf-16 goes *horribly* wrong). */ 68 if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL || 69 test_bytes > 1 ) 70 { 71 g_free( test ); 72 g_iconv_close( oc ); 73 irc_usermsg( irc, "Unsupported character set: The IRC protocol " 74 "only supports 8-bit character sets." ); 75 return NULL; 76 } 77 g_free( test ); 78 79 if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) 80 { 81 g_iconv_close( oc ); 82 return NULL; 83 } 84 85 if( irc->iconv != (GIConv) -1 ) 86 g_iconv_close( irc->iconv ); 87 if( irc->oconv != (GIConv) -1 ) 88 g_iconv_close( irc->oconv ); 89 90 irc->iconv = ic; 91 irc->oconv = oc; 92 93 return value; 94 } 95 96 static char *set_eval_away_status( set_t *set, char *value ) 97 { 98 irc_t *irc = set->data; 99 account_t *a; 100 101 g_free( set->value ); 102 set->value = g_strdup( value ); 103 104 for( a = irc->accounts; a; a = a->next ) 105 { 106 struct im_connection *ic = a->ic; 107 108 if( ic && ic->flags & OPT_LOGGED_IN ) 109 imc_away_send_update( ic ); 110 } 111 112 return value; 113 } 28 #include "dcc.h" 29 30 GSList *irc_connection_list; 31 32 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond ); 33 static char *set_eval_charset( set_t *set, char *value ); 34 static char *set_eval_password( set_t *set, char *value ); 35 static char *set_eval_bw_compat( set_t *set, char *value ); 114 36 115 37 irc_t *irc_new( int fd ) … … 118 40 struct sockaddr_storage sock; 119 41 socklen_t socklen = sizeof( sock ); 42 char *host = NULL, *myhost = NULL; 43 irc_user_t *iu; 120 44 set_t *s; 45 bee_t *b; 121 46 122 47 irc = g_new0( irc_t, 1 ); … … 125 50 sock_make_nonblocking( irc->fd ); 126 51 127 irc->r_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_READ, bitlbee_io_current_client_read, irc );52 irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc ); 128 53 129 54 irc->status = USTATUS_OFFLINE; 130 55 irc->last_pong = gettime(); 131 56 132 irc-> userhash = g_hash_table_new( g_str_hash, g_str_equal );57 irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal ); 133 58 irc->watches = g_hash_table_new( g_str_hash, g_str_equal ); 134 135 strcpy( irc->umode, UMODE );136 irc->mynick = g_strdup( ROOT_NICK );137 irc->channel = g_strdup( ROOT_CHAN );138 59 139 60 irc->iconv = (GIConv) -1; … … 142 63 if( global.conf->hostname ) 143 64 { 144 irc->myhost = g_strdup( global.conf->hostname );65 myhost = g_strdup( global.conf->hostname ); 145 66 } 146 67 else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) … … 151 72 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 152 73 { 153 irc->myhost = g_strdup( ipv6_unwrap( buf ) );74 myhost = g_strdup( ipv6_unwrap( buf ) ); 154 75 } 155 76 } … … 162 83 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 163 84 { 164 irc->host = g_strdup( ipv6_unwrap( buf ) );165 } 166 } 167 168 if( irc->host == NULL )169 irc->host = g_strdup( "localhost.localdomain" );170 if( irc->myhost == NULL )171 irc->myhost = g_strdup( "localhost.localdomain" );85 host = g_strdup( ipv6_unwrap( buf ) ); 86 } 87 } 88 89 if( host == NULL ) 90 host = g_strdup( "localhost.localdomain" ); 91 if( myhost == NULL ) 92 myhost = g_strdup( "localhost.localdomain" ); 172 93 173 94 if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 ) 174 95 irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc ); 175 176 irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );177 96 178 97 irc_connection_list = g_slist_append( irc_connection_list, irc ); 179 98 180 s = set_add( &irc->set, "away", NULL, set_eval_away_status, irc ); 99 b = irc->b = bee_new(); 100 b->ui_data = irc; 101 b->ui = &irc_ui_funcs; 102 103 s = set_add( &b->set, "allow_takeover", "true", set_eval_bool, irc ); 104 s = set_add( &b->set, "away_devoice", "true", set_eval_bw_compat, irc ); 105 s = set_add( &b->set, "away_reply_timeout", "3600", set_eval_int, irc ); 106 s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc ); 107 s = set_add( &b->set, "default_target", "root", NULL, irc ); 108 s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc ); 109 s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc ); 110 s = set_add( &b->set, "handle_unknown", "add_channel", NULL, irc ); 111 s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc ); 112 s = set_add( &b->set, "nick_format", "%-@nick", NULL, irc ); 113 s = set_add( &b->set, "offline_user_quits", "true", set_eval_bool, irc ); 114 s = set_add( &b->set, "ops", "both", set_eval_irc_channel_ops, irc ); 115 s = set_add( &b->set, "paste_buffer", "false", set_eval_bool, irc ); 116 s->old_key = g_strdup( "buddy_sendbuffer" ); 117 s = set_add( &b->set, "paste_buffer_delay", "200", set_eval_int, irc ); 118 s->old_key = g_strdup( "buddy_sendbuffer_delay" ); 119 s = set_add( &b->set, "password", NULL, set_eval_password, irc ); 181 120 s->flags |= SET_NULL_OK; 182 s = set_add( &irc->set, "away_devoice", "true", set_eval_away_devoice, irc ); 183 s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc ); 184 s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc ); 185 s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc ); 186 s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc ); 187 s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc ); 188 s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc ); 189 s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc ); 190 s = set_add( &irc->set, "debug", "false", set_eval_bool, irc ); 191 s = set_add( &irc->set, "default_target", "root", NULL, irc ); 192 s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc ); 193 s = set_add( &irc->set, "display_timestamps", "true", set_eval_bool, irc ); 194 s = set_add( &irc->set, "handle_unknown", "root", NULL, irc ); 195 s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc ); 196 s = set_add( &irc->set, "ops", "both", set_eval_ops, irc ); 197 s = set_add( &irc->set, "password", NULL, set_eval_password, irc ); 198 s->flags |= SET_NULL_OK; 199 s = set_add( &irc->set, "private", "true", set_eval_bool, irc ); 200 s = set_add( &irc->set, "query_order", "lifo", NULL, irc ); 201 s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc ); 202 s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc ); 203 s = set_add( &irc->set, "show_offline", "false", set_eval_bool, irc ); 204 s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc ); 205 s = set_add( &irc->set, "status", NULL, set_eval_away_status, irc ); 206 s->flags |= SET_NULL_OK; 207 s = set_add( &irc->set, "strip_html", "true", NULL, irc ); 208 s = set_add( &irc->set, "timezone", "local", set_eval_timezone, irc ); 209 s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc ); 210 s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc ); 121 s = set_add( &b->set, "private", "true", set_eval_bool, irc ); 122 s = set_add( &b->set, "query_order", "lifo", NULL, irc ); 123 s = set_add( &b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc ); 124 s = set_add( &b->set, "show_offline", "false", set_eval_bw_compat, irc ); 125 s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc ); 126 s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc ); 127 s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc ); 128 s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc ); 129 130 irc->root = iu = irc_user_new( irc, ROOT_NICK ); 131 iu->host = g_strdup( myhost ); 132 iu->fullname = g_strdup( ROOT_FN ); 133 iu->f = &irc_user_root_funcs; 134 135 iu = irc_user_new( irc, NS_NICK ); 136 iu->host = g_strdup( myhost ); 137 iu->fullname = g_strdup( ROOT_FN ); 138 iu->f = &irc_user_root_funcs; 139 140 irc->user = g_new0( irc_user_t, 1 ); 141 irc->user->host = g_strdup( host ); 211 142 212 143 conf_loaddefaults( irc ); 213 144 214 145 /* Evaluator sets the iconv/oconv structures. */ 215 set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) ); 216 217 return( irc ); 146 set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) ); 147 148 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" ); 149 150 g_free( myhost ); 151 g_free( host ); 152 153 nogaim_init(); 154 155 return irc; 218 156 } 219 157 … … 236 174 237 175 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 238 irc-> nick ? irc->nick : "(NONE)", irc->host, reason );176 irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, reason ); 239 177 240 178 g_free( reason ); … … 246 184 247 185 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 248 irc-> nick ? irc->nick : "(NONE)", irc->host, "No reason given" );186 irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, "No reason given" ); 249 187 } 250 188 … … 267 205 } 268 206 269 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) 270 { 271 g_free( key ); 272 273 return( TRUE ); 274 } 275 276 /* Because we have no garbage collection, this is quite annoying */ 207 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ); 208 277 209 void irc_free( irc_t * irc ) 278 210 { 279 user_t *user, *usertmp;280 281 211 log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); 282 212 283 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc-> set, "save_on_quit" ) )213 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 284 214 if( storage_save( irc, NULL, TRUE ) != STORAGE_OK ) 285 irc_usermsg( irc, "Error while saving settings!");215 log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick ); 286 216 287 217 irc_connection_list = g_slist_remove( irc_connection_list, irc ); 288 289 while( irc->accounts )290 {291 if( irc->accounts->ic )292 imc_logout( irc->accounts->ic, FALSE );293 else if( irc->accounts->reconnect )294 cancel_auto_reconnect( irc->accounts );295 296 if( irc->accounts->ic == NULL )297 account_del( irc, irc->accounts );298 else299 /* Nasty hack, but account_del() doesn't work in this300 case and we don't want infinite loops, do we? ;-) */301 irc->accounts = irc->accounts->next;302 }303 218 304 219 while( irc->queries != NULL ) 305 220 query_del( irc, irc->queries ); 306 221 307 while( irc->set ) 308 set_del( &irc->set, irc->set->key ); 309 310 if (irc->users != NULL) 311 { 312 user = irc->users; 313 while( user != NULL ) 314 { 315 g_free( user->nick ); 316 g_free( user->away ); 317 g_free( user->handle ); 318 if( user->user != user->nick ) g_free( user->user ); 319 if( user->host != user->nick ) g_free( user->host ); 320 if( user->realname != user->nick ) g_free( user->realname ); 321 b_event_remove( user->sendbuf_timer ); 322 323 usertmp = user; 324 user = user->next; 325 g_free( usertmp ); 326 } 327 } 222 /* This is a little bit messy: bee_free() frees all b->users which 223 calls us back to free the corresponding irc->users. So do this 224 before we clear the remaining ones ourselves. */ 225 bee_free( irc->b ); 226 227 while( irc->users ) 228 irc_user_free( irc, (irc_user_t *) irc->users->data ); 229 230 while( irc->channels ) 231 irc_channel_free( irc->channels->data ); 328 232 329 233 if( irc->ping_source_id > 0 ) … … 337 241 irc->fd = -1; 338 242 339 g_hash_table_foreach_remove( irc-> userhash, irc_free_hashkey, NULL );340 g_hash_table_destroy( irc-> userhash );243 g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL ); 244 g_hash_table_destroy( irc->nick_user_hash ); 341 245 342 246 g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); … … 350 254 g_free( irc->sendbuffer ); 351 255 g_free( irc->readbuffer ); 352 353 g_free( irc->nick );354 g_free( irc->user );355 g_free( irc->host );356 g_free( irc->realname );357 256 g_free( irc->password ); 358 359 g_free( irc->myhost ); 360 g_free( irc->mynick ); 361 362 g_free( irc->channel ); 363 364 g_free( irc->last_target ); 257 g_free( irc->last_root_cmd ); 365 258 366 259 g_free( irc ); … … 374 267 } 375 268 269 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) 270 { 271 g_free( key ); 272 273 return( TRUE ); 274 } 275 376 276 /* USE WITH CAUTION! 377 277 Sets pass without checking */ 378 void irc_setpass (irc_t *irc, const char *pass) 278 void irc_setpass (irc_t *irc, const char *pass) 379 279 { 380 280 g_free (irc->password); … … 387 287 } 388 288 289 static char *set_eval_password( set_t *set, char *value ) 290 { 291 irc_t *irc = set->data; 292 293 if( irc->status & USTATUS_IDENTIFIED && value ) 294 { 295 irc_setpass( irc, value ); 296 return NULL; 297 } 298 else 299 { 300 return SET_INVALID; 301 } 302 } 303 304 static char **irc_splitlines( char *buffer ); 305 389 306 void irc_process( irc_t *irc ) 390 307 { … … 394 311 if( irc->readbuffer != NULL ) 395 312 { 396 lines = irc_ tokenize( irc->readbuffer );313 lines = irc_splitlines( irc->readbuffer ); 397 314 398 315 for( i = 0; *lines[i] != '\0'; i ++ ) … … 431 348 "`help set charset' for more information. Your " 432 349 "message was ignored.", 433 set_getstr( &irc-> set, "charset" ) );350 set_getstr( &irc->b->set, "charset" ) ); 434 351 435 352 g_free( conv ); … … 438 355 else 439 356 { 440 irc_write( irc, ":%s NOTICE AUTH :%s", irc-> myhost,357 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, 441 358 "Warning: invalid characters received at login time." ); 442 359 … … 476 393 } 477 394 478 /* Splits a long string into separate lines. The array is NULL-terminated and, unless the string 479 contains an incomplete line at the end, ends with an empty string. */ 480 char **irc_tokenize( char *buffer ) 395 /* Splits a long string into separate lines. The array is NULL-terminated 396 and, unless the string contains an incomplete line at the end, ends with 397 an empty string. Could use g_strsplit() but this one does it in-place. 398 (So yes, it's destructive.) */ 399 static char **irc_splitlines( char *buffer ) 481 400 { 482 401 int i, j, n = 3; … … 609 528 } 610 529 611 void irc_reply( irc_t *irc, int code, char *format, ... )612 {613 char text[IRC_MAX_LINE];614 va_list params;615 616 va_start( params, format );617 g_vsnprintf( text, IRC_MAX_LINE, format, params );618 va_end( params );619 irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );620 621 return;622 }623 624 int irc_usermsg( irc_t *irc, char *format, ... )625 {626 char text[1024];627 va_list params;628 char is_private = 0;629 user_t *u;630 631 u = user_find( irc, irc->mynick );632 is_private = u->is_private;633 634 va_start( params, format );635 g_vsnprintf( text, sizeof( text ), format, params );636 va_end( params );637 638 return( irc_msgfrom( irc, u->nick, text ) );639 }640 641 530 void irc_write( irc_t *irc, char *format, ... ) 642 531 { … … 649 538 return; 650 539 } 540 541 void irc_write_all( int now, char *format, ... ) 542 { 543 va_list params; 544 GSList *temp; 545 546 va_start( params, format ); 547 548 temp = irc_connection_list; 549 while( temp != NULL ) 550 { 551 irc_t *irc = temp->data; 552 553 if( now ) 554 { 555 g_free( irc->sendbuffer ); 556 irc->sendbuffer = g_strdup( "\r\n" ); 557 } 558 irc_vawrite( temp->data, format, params ); 559 if( now ) 560 { 561 bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE ); 562 } 563 temp = temp->next; 564 } 565 566 va_end( params ); 567 return; 568 } 651 569 652 570 void irc_vawrite( irc_t *irc, char *format, va_list params ) … … 696 614 in the event queue. */ 697 615 /* Really can't be done as long as the code doesn't do error checking very well: 698 if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) */616 if( bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE ) ) */ 699 617 700 618 /* So just always do it via the event handler. */ 701 irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc );619 irc->w_watch_source_id = b_input_add( irc->fd, B_EV_IO_WRITE, bitlbee_io_current_client_write, irc ); 702 620 } 703 621 … … 705 623 } 706 624 707 void irc_write_all( int now, char *format, ... ) 708 { 709 va_list params; 710 GSList *temp; 711 712 va_start( params, format ); 713 714 temp = irc_connection_list; 715 while( temp != NULL ) 716 { 717 irc_t *irc = temp->data; 718 719 if( now ) 720 { 721 g_free( irc->sendbuffer ); 722 irc->sendbuffer = g_strdup( "\r\n" ); 723 } 724 irc_vawrite( temp->data, format, params ); 725 if( now ) 726 { 727 bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ); 728 } 729 temp = temp->next; 730 } 731 732 va_end( params ); 733 return; 734 } 735 736 void irc_names( irc_t *irc, char *channel ) 737 { 738 user_t *u; 739 char namelist[385] = ""; 740 struct groupchat *c = NULL; 741 char *ops = set_getstr( &irc->set, "ops" ); 742 743 /* RFCs say there is no error reply allowed on NAMES, so when the 744 channel is invalid, just give an empty reply. */ 745 746 if( g_strcasecmp( channel, irc->channel ) == 0 ) 747 { 748 for( u = irc->users; u; u = u->next ) if( u->online ) 749 { 750 if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 ) 625 /* Flush sendbuffer if you can. If it fails, fail silently and let some 626 I/O event handler clean up. */ 627 void irc_flush( irc_t *irc ) 628 { 629 ssize_t n; 630 size_t len; 631 632 if( irc->sendbuffer == NULL ) 633 return; 634 635 len = strlen( irc->sendbuffer ); 636 if( ( n = send( irc->fd, irc->sendbuffer, len, 0 ) ) == len ) 637 { 638 g_free( irc->sendbuffer ); 639 irc->sendbuffer = NULL; 640 641 b_event_remove( irc->w_watch_source_id ); 642 irc->w_watch_source_id = 0; 643 } 644 else if( n > 0 ) 645 { 646 char *s = g_strdup( irc->sendbuffer + n ); 647 g_free( irc->sendbuffer ); 648 irc->sendbuffer = s; 649 } 650 /* Otherwise something went wrong and we don't currently care 651 what the error was. We may or may not succeed later, we 652 were just trying to flush the buffer immediately. */ 653 } 654 655 /* Meant for takeover functionality. Transfer an IRC connection to a different 656 socket. */ 657 void irc_switch_fd( irc_t *irc, int fd ) 658 { 659 irc_write( irc, "ERROR :Transferring session to a new connection" ); 660 irc_flush( irc ); /* Write it now or forget about it forever. */ 661 662 if( irc->sendbuffer ) 663 { 664 b_event_remove( irc->w_watch_source_id ); 665 irc->w_watch_source_id = 0; 666 g_free( irc->sendbuffer ); 667 irc->sendbuffer = NULL; 668 } 669 670 b_event_remove( irc->r_watch_source_id ); 671 closesocket( irc->fd ); 672 irc->fd = fd; 673 irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc ); 674 } 675 676 void irc_sync( irc_t *irc ) 677 { 678 GSList *l; 679 680 irc_write( irc, ":%s!%s@%s MODE %s :+%s", irc->user->nick, 681 irc->user->user, irc->user->host, irc->user->nick, 682 irc->umode ); 683 684 for( l = irc->channels; l; l = l->next ) 685 { 686 irc_channel_t *ic = l->data; 687 if( ic->flags & IRC_CHANNEL_JOINED ) 688 irc_send_join( ic, irc->user ); 689 } 690 } 691 692 void irc_desync( irc_t *irc ) 693 { 694 GSList *l; 695 696 for( l = irc->channels; l; l = l->next ) 697 irc_channel_del_user( l->data, irc->user, IRC_CDU_KICK, 698 "Switching to old session" ); 699 700 irc_write( irc, ":%s!%s@%s MODE %s :-%s", irc->user->nick, 701 irc->user->user, irc->user->host, irc->user->nick, 702 irc->umode ); 703 } 704 705 int irc_check_login( irc_t *irc ) 706 { 707 if( irc->user->user && irc->user->nick ) 708 { 709 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) ) 710 { 711 irc_send_num( irc, 464, ":This server is password-protected." ); 712 return 0; 713 } 714 else 715 { 716 irc_channel_t *ic; 717 irc_user_t *iu = irc->user; 718 719 irc->user = irc_user_new( irc, iu->nick ); 720 irc->user->user = iu->user; 721 irc->user->host = iu->host; 722 irc->user->fullname = iu->fullname; 723 irc->user->f = &irc_user_self_funcs; 724 g_free( iu->nick ); 725 g_free( iu ); 726 727 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 728 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname ); 729 730 irc->status |= USTATUS_LOGGED_IN; 731 732 irc_send_login( irc ); 733 734 irc->umode[0] = '\0'; 735 irc_umode_set( irc, "+" UMODE, TRUE ); 736 737 ic = irc->default_channel = irc_channel_new( irc, ROOT_CHAN ); 738 irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root ); 739 set_setstr( &ic->set, "auto_join", "true" ); 740 irc_channel_auto_joins( irc, NULL ); 741 742 irc->last_root_cmd = g_strdup( ROOT_CHAN ); 743 744 irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN, 745 "Welcome to the BitlBee gateway!\n\n" 746 "If you've never used BitlBee before, please do read the help " 747 "information using the \x02help\x02 command. Lots of FAQs are " 748 "answered there.\n" 749 "If you already have an account on this server, just use the " 750 "\x02identify\x02 command to identify yourself.", NULL ); 751 752 /* This is for bug #209 (use PASS to identify to NickServ). */ 753 if( irc->password != NULL ) 751 754 { 752 irc_reply( irc, 353, "= %s :%s", channel, namelist ); 753 *namelist = 0; 755 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; 756 757 irc_setpass( irc, NULL ); 758 root_command( irc, send_cmd ); 759 g_free( send_cmd[1] ); 754 760 } 755 761 756 if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )757 strcat( namelist, "+" );758 else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||759 ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )760 strcat( namelist, "@" );761 762 strcat( namelist, u->nick );763 strcat( namelist, " " );764 }765 }766 else if( ( c = irc_chat_by_channel( irc, channel ) ) )767 {768 GList *l;769 770 /* root and the user aren't in the channel userlist but should771 show up in /NAMES, so list them first: */772 sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,773 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );774 775 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )776 {777 if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )778 {779 irc_reply( irc, 353, "= %s :%s", channel, namelist );780 *namelist = 0;781 }782 783 strcat( namelist, u->nick );784 strcat( namelist, " " );785 }786 }787 788 if( *namelist )789 irc_reply( irc, 353, "= %s :%s", channel, namelist );790 791 irc_reply( irc, 366, "%s :End of /NAMES list", channel );792 }793 794 int irc_check_login( irc_t *irc )795 {796 if( irc->user && irc->nick )797 {798 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )799 {800 irc_reply( irc, 464, ":This server is password-protected." );801 return 0;802 }803 else804 {805 irc_login( irc );806 762 return 1; 807 763 } … … 814 770 } 815 771 816 void irc_login( irc_t *irc ) 817 { 818 user_t *u; 819 820 irc_reply( irc, 1, ":Welcome to the BitlBee gateway, %s", irc->nick ); 821 irc_reply( irc, 2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost ); 822 irc_reply( irc, 3, ":%s", IRCD_INFO ); 823 irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES ); 824 irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee " 825 "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", 826 CTYPES, CMODES, MAX_NICK_LENGTH - 1 ); 827 irc_motd( irc ); 828 irc->umode[0] = '\0'; 829 irc_umode_set( irc, "+" UMODE, 1 ); 830 831 u = user_add( irc, irc->mynick ); 832 u->host = g_strdup( irc->myhost ); 833 u->realname = g_strdup( ROOT_FN ); 834 u->online = 1; 835 u->send_handler = root_command_string; 836 u->is_private = 0; /* [SH] The channel is root's personal playground. */ 837 irc_spawn( irc, u ); 838 839 u = user_add( irc, NS_NICK ); 840 u->host = g_strdup( irc->myhost ); 841 u->realname = g_strdup( ROOT_FN ); 842 u->online = 0; 843 u->send_handler = root_command_string; 844 u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */ 845 846 u = user_add( irc, irc->nick ); 847 u->user = g_strdup( irc->user ); 848 u->host = g_strdup( irc->host ); 849 u->realname = g_strdup( irc->realname ); 850 u->online = 1; 851 irc_spawn( irc, u ); 852 853 irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n" 854 "If you've never used BitlBee before, please do read the help " 855 "information using the \x02help\x02 command. Lots of FAQs are " 856 "answered there.\n" 857 "If you already have an account on this server, just use the " 858 "\x02identify\x02 command to identify yourself." ); 859 860 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 861 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); 862 863 irc->status |= USTATUS_LOGGED_IN; 864 865 /* This is for bug #209 (use PASS to identify to NickServ). */ 866 if( irc->password != NULL ) 867 { 868 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; 869 870 irc_setpass( irc, NULL ); 871 root_command( irc, send_cmd ); 872 g_free( send_cmd[1] ); 873 } 874 } 875 876 void irc_motd( irc_t *irc ) 877 { 878 int fd; 879 880 fd = open( global.conf->motdfile, O_RDONLY ); 881 if( fd == -1 ) 882 { 883 irc_reply( irc, 422, ":We don't need MOTDs." ); 884 } 885 else 886 { 887 char linebuf[80]; /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */ 888 char *add, max; 889 int len; 890 891 linebuf[79] = len = 0; 892 max = sizeof( linebuf ) - 1; 893 894 irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost ); 895 while( read( fd, linebuf + len, 1 ) == 1 ) 896 { 897 if( linebuf[len] == '\n' || len == max ) 898 { 899 linebuf[len] = 0; 900 irc_reply( irc, 372, ":- %s", linebuf ); 901 len = 0; 902 } 903 else if( linebuf[len] == '%' ) 904 { 905 read( fd, linebuf + len, 1 ); 906 if( linebuf[len] == 'h' ) 907 add = irc->myhost; 908 else if( linebuf[len] == 'v' ) 909 add = BITLBEE_VERSION; 910 else if( linebuf[len] == 'n' ) 911 add = irc->nick; 912 else 913 add = "%"; 914 915 strncpy( linebuf + len, add, max - len ); 916 while( linebuf[++len] ); 917 } 918 else if( len < max ) 919 { 920 len ++; 921 } 922 } 923 irc_reply( irc, 376, ":End of MOTD" ); 924 close( fd ); 925 } 926 } 927 928 void irc_topic( irc_t *irc, char *channel ) 929 { 930 struct groupchat *c = irc_chat_by_channel( irc, channel ); 931 932 if( c && c->topic ) 933 irc_reply( irc, 332, "%s :%s", channel, c->topic ); 934 else if( g_strcasecmp( channel, irc->channel ) == 0 ) 935 irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC ); 936 else 937 irc_reply( irc, 331, "%s :No topic for this channel", channel ); 938 } 939 940 void irc_umode_set( irc_t *irc, char *s, int allow_priv ) 772 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ) 941 773 { 942 774 /* allow_priv: Set to 0 if s contains user input, 1 if you want 943 775 to set a "privileged" mode (+o, +R, etc). */ 944 char m[256], st = 1, *t; 776 char m[128], st = 1; 777 const char *t; 945 778 int i; 946 779 char changes[512], *p, st2 = 2; … … 950 783 951 784 for( t = irc->umode; *t; t ++ ) 952 m[(int)*t] = 1; 953 785 if( *t < sizeof( m ) ) 786 m[(int)*t] = 1; 787 954 788 p = changes; 955 789 for( t = s; *t; t ++ ) … … 957 791 if( *t == '+' || *t == '-' ) 958 792 st = *t == '+'; 959 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) ) 793 else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) || 794 ( st == 1 && strchr( UMODES, *t ) ) || 795 ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) ) 960 796 { 961 797 if( m[(int)*t] != st) … … 974 810 memset( irc->umode, 0, sizeof( irc->umode ) ); 975 811 976 for( i = 0; i < 256&& strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )812 for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ ) 977 813 if( m[i] ) 978 814 irc->umode[strlen(irc->umode)] = i; 979 815 980 816 if( badflag ) 981 irc_reply( irc, 501, ":Unknown MODE flag" ); 982 /* Deliberately no !user@host on the prefix here */ 817 irc_send_num( irc, 501, ":Unknown MODE flag" ); 983 818 if( *changes ) 984 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes ); 985 } 986 987 void irc_spawn( irc_t *irc, user_t *u ) 988 { 989 irc_join( irc, u, irc->channel ); 990 } 991 992 void irc_join( irc_t *irc, user_t *u, char *channel ) 993 { 994 char *nick; 995 996 if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) ) 997 irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel ); 998 999 if( nick_cmp( u->nick, irc->nick ) == 0 ) 1000 { 1001 irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE ); 1002 irc_names( irc, channel ); 1003 irc_topic( irc, channel ); 1004 } 1005 1006 nick = g_strdup( u->nick ); 1007 nick_lc( nick ); 1008 if( g_hash_table_lookup( irc->watches, nick ) ) 1009 { 1010 irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" ); 1011 } 1012 g_free( nick ); 1013 } 1014 1015 void irc_part( irc_t *irc, user_t *u, char *channel ) 1016 { 1017 irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" ); 1018 } 1019 1020 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker ) 1021 { 1022 irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" ); 1023 } 1024 1025 void irc_kill( irc_t *irc, user_t *u ) 1026 { 1027 char *nick, *s; 1028 char reason[128]; 1029 1030 if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) ) 1031 { 1032 if( u->ic->acc->server ) 1033 g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, 1034 u->ic->acc->server ); 1035 else if( ( s = strchr( u->ic->acc->user, '@' ) ) ) 1036 g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, 1037 s + 1 ); 1038 else 1039 g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost, 1040 u->ic->acc->prpl->name, irc->myhost ); 1041 1042 /* proto_opt might contain garbage after the : */ 1043 if( ( s = strchr( reason, ':' ) ) ) 1044 *s = 0; 1045 } 1046 else 1047 { 1048 strcpy( reason, "Leaving..." ); 1049 } 1050 1051 irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason ); 1052 1053 nick = g_strdup( u->nick ); 1054 nick_lc( nick ); 1055 if( g_hash_table_lookup( irc->watches, nick ) ) 1056 { 1057 irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" ); 1058 } 1059 g_free( nick ); 1060 } 1061 1062 int irc_send( irc_t *irc, char *nick, char *s, int flags ) 1063 { 1064 struct groupchat *c = NULL; 1065 user_t *u = NULL; 1066 1067 if( strchr( CTYPES, *nick ) ) 1068 { 1069 if( !( c = irc_chat_by_channel( irc, nick ) ) ) 1070 { 1071 irc_reply( irc, 403, "%s :Channel does not exist", nick ); 1072 return( 0 ); 1073 } 1074 } 1075 else 1076 { 1077 u = user_find( irc, nick ); 1078 1079 if( !u ) 1080 { 1081 if( irc->is_private ) 1082 irc_reply( irc, 401, "%s :Nick does not exist", nick ); 1083 else 1084 irc_usermsg( irc, "Nick `%s' does not exist!", nick ); 1085 return( 0 ); 1086 } 1087 } 1088 1089 if( *s == 1 && s[strlen(s)-1] == 1 ) 1090 { 1091 if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 ) 1092 { 1093 if( s[7] == ' ' ) s ++; 1094 s += 3; 1095 *(s++) = '/'; 1096 *(s++) = 'm'; 1097 *(s++) = 'e'; 1098 *(s++) = ' '; 1099 s -= 4; 1100 s[strlen(s)-1] = 0; 1101 } 1102 else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 ) 1103 { 1104 u = user_find( irc, irc->mynick ); 1105 irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" ); 1106 return( 1 ); 1107 } 1108 else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 ) 1109 { 1110 u = user_find( irc, irc->mynick ); 1111 irc_privmsg( irc, u, "NOTICE", irc->nick, "", s ); 1112 return( 1 ); 1113 } 1114 else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 ) 1115 { 1116 if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 ) 1117 { 1118 time_t current_typing_notice = time( NULL ); 1119 1120 if( current_typing_notice - u->last_typing_notice >= 5 ) 1121 { 1122 u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 ); 1123 u->last_typing_notice = current_typing_notice; 1124 } 1125 } 1126 return( 1 ); 1127 } 1128 else 1129 { 1130 irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" ); 1131 return( 0 ); 1132 } 1133 } 1134 1135 if( u ) 1136 { 1137 /* For the next message, we probably do have to send new notices... */ 1138 u->last_typing_notice = 0; 1139 u->is_private = irc->is_private; 1140 1141 if( u->is_private ) 1142 { 1143 if( !u->online ) 1144 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" ); 1145 else if( u->away ) 1146 irc_reply( irc, 301, "%s :%s", u->nick, u->away ); 1147 } 1148 1149 if( u->send_handler ) 1150 { 1151 u->send_handler( irc, u, s, flags ); 1152 return 1; 1153 } 1154 } 1155 else if( c && c->ic && c->ic->acc && c->ic->acc->prpl ) 1156 { 1157 return( imc_chat_msg( c, s, 0 ) ); 1158 } 1159 1160 return( 0 ); 1161 } 1162 1163 static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond ) 1164 { 1165 user_t *u = data; 1166 1167 /* Shouldn't happen, but just to be sure. */ 1168 if( u->sendbuf_len < 2 ) 1169 return FALSE; 1170 1171 u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */ 1172 imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags ); 1173 1174 g_free( u->sendbuf ); 1175 u->sendbuf = NULL; 1176 u->sendbuf_len = 0; 1177 u->sendbuf_timer = 0; 1178 u->sendbuf_flags = 0; 1179 1180 return FALSE; 1181 } 1182 1183 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) 1184 { 1185 if( !u || !u->ic ) return; 1186 1187 if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) 1188 { 1189 int delay; 1190 1191 if( u->sendbuf_len > 0 && u->sendbuf_flags != flags) 1192 { 1193 /* Flush the buffer */ 1194 b_event_remove( u->sendbuf_timer ); 1195 buddy_send_handler_delayed( u, -1, 0 ); 1196 } 1197 1198 if( u->sendbuf_len == 0 ) 1199 { 1200 u->sendbuf_len = strlen( msg ) + 2; 1201 u->sendbuf = g_new( char, u->sendbuf_len ); 1202 u->sendbuf[0] = 0; 1203 u->sendbuf_flags = flags; 1204 } 1205 else 1206 { 1207 u->sendbuf_len += strlen( msg ) + 1; 1208 u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len ); 1209 } 1210 1211 strcat( u->sendbuf, msg ); 1212 strcat( u->sendbuf, "\n" ); 1213 1214 delay = set_getint( &irc->set, "buddy_sendbuffer_delay" ); 1215 if( delay <= 5 ) 1216 delay *= 1000; 1217 1218 if( u->sendbuf_timer > 0 ) 1219 b_event_remove( u->sendbuf_timer ); 1220 u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u ); 1221 } 1222 else 1223 { 1224 imc_buddy_msg( u->ic, u->handle, msg, flags ); 1225 } 1226 } 1227 1228 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg ) 1229 { 1230 char last = 0; 1231 char *s = msg, *line = msg; 1232 1233 /* The almighty linesplitter .. woohoo!! */ 1234 while( !last ) 1235 { 1236 if( *s == '\r' && *(s+1) == '\n' ) 1237 *(s++) = 0; 1238 if( *s == '\n' ) 1239 { 1240 last = s[1] == 0; 1241 *s = 0; 1242 } 1243 else 1244 { 1245 last = s[0] == 0; 1246 } 1247 if( *s == 0 ) 1248 { 1249 if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 ) 1250 { 1251 irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host, 1252 type, to, line + 4 ); 1253 } 1254 else 1255 { 1256 irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host, 1257 type, to, prefix ? prefix : "", line ); 1258 } 1259 line = s + 1; 1260 } 1261 s ++; 1262 } 1263 1264 return( 1 ); 1265 } 1266 1267 int irc_msgfrom( irc_t *irc, char *nick, char *msg ) 1268 { 1269 user_t *u = user_find( irc, nick ); 1270 static char *prefix = NULL; 1271 1272 if( !u ) return( 0 ); 1273 if( prefix && *prefix ) g_free( prefix ); 1274 1275 if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 ) 1276 { 1277 int len = strlen( irc->nick) + 3; 1278 prefix = g_new (char, len ); 1279 g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) ); 1280 prefix[len-1] = 0; 1281 } 1282 else 1283 { 1284 prefix = ""; 1285 } 1286 1287 return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) ); 1288 } 1289 1290 int irc_noticefrom( irc_t *irc, char *nick, char *msg ) 1291 { 1292 user_t *u = user_find( irc, nick ); 1293 1294 if( u ) 1295 return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) ); 1296 else 1297 return( 0 ); 819 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick, 820 irc->user->user, irc->user->host, irc->user->nick, 821 changes ); 1298 822 } 1299 823 … … 1334 858 } 1335 859 1336 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel ) 1337 { 1338 struct groupchat *c; 1339 account_t *a; 1340 1341 /* This finds the connection which has a conversation which belongs to this channel */ 1342 for( a = irc->accounts; a; a = a->next ) 1343 { 1344 if( a->ic == NULL ) 1345 continue; 1346 1347 c = a->ic->groupchats; 1348 while( c ) 1349 { 1350 if( c->channel && g_strcasecmp( c->channel, channel ) == 0 ) 1351 return c; 1352 1353 c = c->next; 1354 } 1355 } 1356 1357 return NULL; 1358 } 860 static char *set_eval_charset( set_t *set, char *value ) 861 { 862 irc_t *irc = (irc_t*) set->data; 863 char *test; 864 gsize test_bytes = 0; 865 GIConv ic, oc; 866 867 if( g_strcasecmp( value, "none" ) == 0 ) 868 value = g_strdup( "utf-8" ); 869 870 if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) 871 { 872 return NULL; 873 } 874 875 /* Do a test iconv to see if the user picked an IRC-compatible 876 charset (for example utf-16 goes *horribly* wrong). */ 877 if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL || 878 test_bytes > 1 ) 879 { 880 g_free( test ); 881 g_iconv_close( oc ); 882 irc_usermsg( irc, "Unsupported character set: The IRC protocol " 883 "only supports 8-bit character sets." ); 884 return NULL; 885 } 886 g_free( test ); 887 888 if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) 889 { 890 g_iconv_close( oc ); 891 return NULL; 892 } 893 894 if( irc->iconv != (GIConv) -1 ) 895 g_iconv_close( irc->iconv ); 896 if( irc->oconv != (GIConv) -1 ) 897 g_iconv_close( irc->oconv ); 898 899 irc->iconv = ic; 900 irc->oconv = oc; 901 902 return value; 903 } 904 905 /* Mostly meant for upgrades. If one of these is set to the non-default, 906 set show_users of all channels to something with the same effect. */ 907 static char *set_eval_bw_compat( set_t *set, char *value ) 908 { 909 irc_t *irc = set->data; 910 char *val; 911 GSList *l; 912 913 irc_usermsg( irc, "Setting `%s' is obsolete, use the `show_users' " 914 "channel setting instead.", set->key ); 915 916 if( strcmp( set->key, "away_devoice" ) == 0 && !bool2int( value ) ) 917 val = "online,away"; 918 else if( strcmp( set->key, "show_offline" ) == 0 && bool2int( value ) ) 919 val = "online@,away+,offline"; 920 else 921 return SET_INVALID; 922 923 for( l = irc->channels; l; l = l->next ) 924 { 925 irc_channel_t *ic = l->data; 926 /* No need to check channel type, if the setting doesn't exist it 927 will just be ignored. */ 928 set_setstr( &ic->set, "show_users", val ); 929 } 930 931 return SET_INVALID; 932 }
Note: See TracChangeset
for help on using the changeset viewer.