Changes in irc.c [92a9c68:e21c0f8]
Legend:
- Unmodified
- Added
- Removed
-
irc.c
r92a9c68 re21c0f8 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 28 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 } 29 GSList *irc_connection_list; 30 31 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond ); 32 static char *set_eval_charset( set_t *set, char *value ); 114 33 115 34 irc_t *irc_new( int fd ) … … 118 37 struct sockaddr_storage sock; 119 38 socklen_t socklen = sizeof( sock ); 39 char *host = NULL, *myhost = NULL; 40 irc_user_t *iu; 120 41 set_t *s; 42 bee_t *b; 121 43 122 44 irc = g_new0( irc_t, 1 ); … … 130 52 irc->last_pong = gettime(); 131 53 132 irc-> userhash = g_hash_table_new( g_str_hash, g_str_equal );54 irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal ); 133 55 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 56 139 57 irc->iconv = (GIConv) -1; … … 142 60 if( global.conf->hostname ) 143 61 { 144 irc->myhost = g_strdup( global.conf->hostname );62 myhost = g_strdup( global.conf->hostname ); 145 63 } 146 64 else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) … … 151 69 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 152 70 { 153 irc->myhost = g_strdup( ipv6_unwrap( buf ) );71 myhost = g_strdup( ipv6_unwrap( buf ) ); 154 72 } 155 73 } … … 162 80 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 163 81 { 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" );82 host = g_strdup( ipv6_unwrap( buf ) ); 83 } 84 } 85 86 if( host == NULL ) 87 host = g_strdup( "localhost.localdomain" ); 88 if( myhost == NULL ) 89 myhost = g_strdup( "localhost.localdomain" ); 172 90 173 91 if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 ) 174 92 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 93 178 94 irc_connection_list = g_slist_append( irc_connection_list, irc ); 179 95 180 s = set_add( &irc->set, "away", NULL, set_eval_away_status, irc ); 181 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, "simulate_netsplit", "true", set_eval_bool, irc ); 204 s = set_add( &irc->set, "status", NULL, set_eval_away_status, irc ); 205 s->flags |= SET_NULL_OK; 206 s = set_add( &irc->set, "strip_html", "true", NULL, irc ); 207 s = set_add( &irc->set, "timezone", "local", set_eval_timezone, irc ); 208 s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc ); 209 s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc ); 96 b = irc->b = bee_new(); 97 b->ui_data = irc; 98 b->ui = &irc_ui_funcs; 99 100 s = set_add( &b->set, "away_devoice", "true", NULL/*set_eval_away_devoice*/, irc ); 101 s = set_add( &b->set, "buddy_sendbuffer", "false", set_eval_bool, irc ); 102 s = set_add( &b->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc ); 103 s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc ); 104 //s = set_add( &b->set, "control_channel", irc->channel, NULL/*set_eval_control_channel*/, irc ); 105 s = set_add( &b->set, "default_target", "root", NULL, irc ); 106 s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc ); 107 s = set_add( &b->set, "handle_unknown", "root", NULL, irc ); 108 s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc ); 109 s = set_add( &b->set, "ops", "both", NULL/*set_eval_ops*/, irc ); 110 s = set_add( &b->set, "private", "true", set_eval_bool, irc ); 111 s = set_add( &b->set, "query_order", "lifo", NULL, irc ); 112 s = set_add( &b->set, "root_nick", ROOT_NICK, NULL/*set_eval_root_nick*/, irc ); 113 s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc ); 114 s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc ); 115 s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc ); 116 117 irc->root = iu = irc_user_new( irc, ROOT_NICK ); 118 iu->host = g_strdup( myhost ); 119 iu->fullname = g_strdup( ROOT_FN ); 120 iu->f = &irc_user_root_funcs; 121 122 iu = irc_user_new( irc, NS_NICK ); 123 iu->host = g_strdup( myhost ); 124 iu->fullname = g_strdup( ROOT_FN ); 125 iu->f = &irc_user_root_funcs; 126 127 irc->user = g_new0( irc_user_t, 1 ); 128 irc->user->host = g_strdup( host ); 210 129 211 130 conf_loaddefaults( irc ); 212 131 213 132 /* Evaluator sets the iconv/oconv structures. */ 214 set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) ); 215 216 return( irc ); 133 set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) ); 134 135 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" ); 136 137 g_free( myhost ); 138 g_free( host ); 139 140 return irc; 217 141 } 218 142 … … 235 159 236 160 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 237 irc-> nick ? irc->nick : "(NONE)", irc->host, reason );161 irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason ); 238 162 239 163 g_free( reason ); … … 245 169 246 170 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 247 irc-> nick ? irc->nick : "(NONE)", irc->host, "No reason given" );171 irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" ); 248 172 } 249 173 … … 266 190 } 267 191 268 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) 269 { 270 g_free( key ); 271 272 return( TRUE ); 273 } 274 275 /* Because we have no garbage collection, this is quite annoying */ 192 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ); 193 276 194 void irc_free( irc_t * irc ) 277 195 { 278 user_t *user, *usertmp;279 280 196 log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); 281 197 282 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) ) 198 /* 199 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 283 200 if( storage_save( irc, NULL, TRUE ) != STORAGE_OK ) 284 201 irc_usermsg( irc, "Error while saving settings!" ); 202 */ 285 203 286 204 irc_connection_list = g_slist_remove( irc_connection_list, irc ); 287 205 288 while( irc->accounts ) 289 { 290 if( irc->accounts->ic ) 291 imc_logout( irc->accounts->ic, FALSE ); 292 else if( irc->accounts->reconnect ) 293 cancel_auto_reconnect( irc->accounts ); 294 295 if( irc->accounts->ic == NULL ) 296 account_del( irc, irc->accounts ); 297 else 298 /* Nasty hack, but account_del() doesn't work in this 299 case and we don't want infinite loops, do we? ;-) */ 300 irc->accounts = irc->accounts->next; 301 } 302 206 /* 303 207 while( irc->queries != NULL ) 304 208 query_del( irc, irc->queries ); 305 306 while( irc->set ) 307 set_del( &irc->set, irc->set->key ); 308 309 if (irc->users != NULL) 310 { 311 user = irc->users; 312 while( user != NULL ) 313 { 314 g_free( user->nick ); 315 g_free( user->away ); 316 g_free( user->handle ); 317 if( user->user != user->nick ) g_free( user->user ); 318 if( user->host != user->nick ) g_free( user->host ); 319 if( user->realname != user->nick ) g_free( user->realname ); 320 b_event_remove( user->sendbuf_timer ); 321 322 usertmp = user; 323 user = user->next; 324 g_free( usertmp ); 325 } 326 } 209 */ 210 211 while( irc->users ) 212 irc_user_free( irc, (irc_user_t *) irc->users->data ); 213 214 while( irc->channels ) 215 irc_channel_free( irc->channels->data ); 327 216 328 217 if( irc->ping_source_id > 0 ) … … 336 225 irc->fd = -1; 337 226 338 g_hash_table_foreach_remove( irc-> userhash, irc_free_hashkey, NULL );339 g_hash_table_destroy( irc-> userhash );227 g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL ); 228 g_hash_table_destroy( irc->nick_user_hash ); 340 229 341 230 g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); … … 350 239 g_free( irc->readbuffer ); 351 240 352 g_free( irc->nick );353 g_free( irc->user );354 g_free( irc->host );355 g_free( irc->realname );356 241 g_free( irc->password ); 357 358 g_free( irc->myhost );359 g_free( irc->mynick );360 361 g_free( irc->channel );362 363 g_free( irc->last_target );364 242 365 243 g_free( irc ); … … 373 251 } 374 252 253 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) 254 { 255 g_free( key ); 256 257 return( TRUE ); 258 } 259 375 260 /* USE WITH CAUTION! 376 261 Sets pass without checking */ 377 void irc_setpass (irc_t *irc, const char *pass) 262 void irc_setpass (irc_t *irc, const char *pass) 378 263 { 379 264 g_free (irc->password); … … 386 271 } 387 272 273 static char **irc_splitlines( char *buffer ); 274 388 275 void irc_process( irc_t *irc ) 389 276 { … … 393 280 if( irc->readbuffer != NULL ) 394 281 { 395 lines = irc_ tokenize( irc->readbuffer );282 lines = irc_splitlines( irc->readbuffer ); 396 283 397 284 for( i = 0; *lines[i] != '\0'; i ++ ) … … 430 317 "`help set charset' for more information. Your " 431 318 "message was ignored.", 432 set_getstr( &irc-> set, "charset" ) );319 set_getstr( &irc->b->set, "charset" ) ); 433 320 434 321 g_free( conv ); … … 437 324 else 438 325 { 439 irc_write( irc, ":%s NOTICE AUTH :%s", irc-> myhost,326 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, 440 327 "Warning: invalid characters received at login time." ); 441 328 … … 475 362 } 476 363 477 /* Splits a long string into separate lines. The array is NULL-terminated and, unless the string 478 contains an incomplete line at the end, ends with an empty string. */ 479 char **irc_tokenize( char *buffer ) 364 /* Splits a long string into separate lines. The array is NULL-terminated 365 and, unless the string contains an incomplete line at the end, ends with 366 an empty string. Could use g_strsplit() but this one does it in-place. 367 (So yes, it's destructive.) */ 368 static char **irc_splitlines( char *buffer ) 480 369 { 481 370 int i, j, n = 3; … … 608 497 } 609 498 610 void irc_reply( irc_t *irc, int code, char *format, ... )611 {612 char text[IRC_MAX_LINE];613 va_list params;614 615 va_start( params, format );616 g_vsnprintf( text, IRC_MAX_LINE, format, params );617 va_end( params );618 irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );619 620 return;621 }622 623 int irc_usermsg( irc_t *irc, char *format, ... )624 {625 char text[1024];626 va_list params;627 char is_private = 0;628 user_t *u;629 630 u = user_find( irc, irc->mynick );631 is_private = u->is_private;632 633 va_start( params, format );634 g_vsnprintf( text, sizeof( text ), format, params );635 va_end( params );636 637 return( irc_msgfrom( irc, u->nick, text ) );638 }639 640 499 void irc_write( irc_t *irc, char *format, ... ) 641 500 { … … 648 507 return; 649 508 } 509 510 void irc_write_all( int now, char *format, ... ) 511 { 512 va_list params; 513 GSList *temp; 514 515 va_start( params, format ); 516 517 temp = irc_connection_list; 518 while( temp != NULL ) 519 { 520 irc_t *irc = temp->data; 521 522 if( now ) 523 { 524 g_free( irc->sendbuffer ); 525 irc->sendbuffer = g_strdup( "\r\n" ); 526 } 527 irc_vawrite( temp->data, format, params ); 528 if( now ) 529 { 530 bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ); 531 } 532 temp = temp->next; 533 } 534 535 va_end( params ); 536 return; 537 } 650 538 651 539 void irc_vawrite( irc_t *irc, char *format, va_list params ) … … 704 592 } 705 593 706 void irc_write_all( int now, char *format, ... ) 707 { 708 va_list params; 709 GSList *temp; 710 711 va_start( params, format ); 712 713 temp = irc_connection_list; 714 while( temp != NULL ) 715 { 716 irc_t *irc = temp->data; 717 718 if( now ) 719 { 720 g_free( irc->sendbuffer ); 721 irc->sendbuffer = g_strdup( "\r\n" ); 722 } 723 irc_vawrite( temp->data, format, params ); 724 if( now ) 725 { 726 bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ); 727 } 728 temp = temp->next; 729 } 730 731 va_end( params ); 732 return; 733 } 734 735 void irc_names( irc_t *irc, char *channel ) 736 { 737 user_t *u; 738 char namelist[385] = ""; 739 struct groupchat *c = NULL; 740 char *ops = set_getstr( &irc->set, "ops" ); 741 742 /* RFCs say there is no error reply allowed on NAMES, so when the 743 channel is invalid, just give an empty reply. */ 744 745 if( g_strcasecmp( channel, irc->channel ) == 0 ) 746 { 747 for( u = irc->users; u; u = u->next ) if( u->online ) 748 { 749 if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 ) 594 int irc_check_login( irc_t *irc ) 595 { 596 if( irc->user->user && irc->user->nick ) 597 { 598 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) ) 599 { 600 irc_send_num( irc, 464, ":This server is password-protected." ); 601 return 0; 602 } 603 else 604 { 605 irc_channel_t *ic; 606 irc_user_t *iu = irc->user; 607 608 irc->user = irc_user_new( irc, iu->nick ); 609 irc->user->user = iu->user; 610 irc->user->host = iu->host; 611 irc->user->fullname = iu->fullname; 612 irc->user->f = &irc_user_self_funcs; 613 g_free( iu->nick ); 614 g_free( iu ); 615 616 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 617 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname ); 618 619 irc->status |= USTATUS_LOGGED_IN; 620 621 /* This is for bug #209 (use PASS to identify to NickServ). */ 622 if( irc->password != NULL ) 750 623 { 751 irc_reply( irc, 353, "= %s :%s", channel, namelist ); 752 *namelist = 0; 624 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; 625 626 /*irc_setpass( irc, NULL );*/ 627 /*root_command( irc, send_cmd );*/ 628 g_free( send_cmd[1] ); 753 629 } 754 630 755 if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) ) 756 strcat( namelist, "+" ); 757 else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) || 758 ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ) 759 strcat( namelist, "@" ); 760 761 strcat( namelist, u->nick ); 762 strcat( namelist, " " ); 763 } 764 } 765 else if( ( c = irc_chat_by_channel( irc, channel ) ) ) 766 { 767 GList *l; 768 769 /* root and the user aren't in the channel userlist but should 770 show up in /NAMES, so list them first: */ 771 sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick, 772 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick ); 773 774 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) ) 775 { 776 if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 ) 777 { 778 irc_reply( irc, 353, "= %s :%s", channel, namelist ); 779 *namelist = 0; 780 } 781 782 strcat( namelist, u->nick ); 783 strcat( namelist, " " ); 784 } 785 } 786 787 if( *namelist ) 788 irc_reply( irc, 353, "= %s :%s", channel, namelist ); 789 790 irc_reply( irc, 366, "%s :End of /NAMES list", channel ); 791 } 792 793 int irc_check_login( irc_t *irc ) 794 { 795 if( irc->user && irc->nick ) 796 { 797 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) ) 798 { 799 irc_reply( irc, 464, ":This server is password-protected." ); 800 return 0; 801 } 802 else 803 { 804 irc_login( irc ); 631 irc_send_login( irc ); 632 633 irc->umode[0] = '\0'; 634 irc_umode_set( irc, "+" UMODE, TRUE ); 635 636 ic = irc_channel_new( irc, ROOT_CHAN ); 637 irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root ); 638 irc_channel_add_user( ic, irc->user ); 639 640 irc->last_root_cmd = g_strdup( ROOT_CHAN ); 641 642 irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN, 643 "Welcome to the BitlBee gateway!\n\n" 644 "If you've never used BitlBee before, please do read the help " 645 "information using the \x02help\x02 command. Lots of FAQs are " 646 "answered there.\n" 647 "If you already have an account on this server, just use the " 648 "\x02identify\x02 command to identify yourself.", NULL ); 649 805 650 return 1; 806 651 } … … 813 658 } 814 659 815 void irc_login( irc_t *irc ) 816 { 817 user_t *u; 818 819 irc_reply( irc, 1, ":Welcome to the BitlBee gateway, %s", irc->nick ); 820 irc_reply( irc, 2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost ); 821 irc_reply( irc, 3, ":%s", IRCD_INFO ); 822 irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES ); 823 irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee " 824 "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", 825 CTYPES, CMODES, MAX_NICK_LENGTH - 1 ); 826 irc_motd( irc ); 827 irc->umode[0] = '\0'; 828 irc_umode_set( irc, "+" UMODE, 1 ); 829 830 u = user_add( irc, irc->mynick ); 831 u->host = g_strdup( irc->myhost ); 832 u->realname = g_strdup( ROOT_FN ); 833 u->online = 1; 834 u->send_handler = root_command_string; 835 u->is_private = 0; /* [SH] The channel is root's personal playground. */ 836 irc_spawn( irc, u ); 837 838 u = user_add( irc, NS_NICK ); 839 u->host = g_strdup( irc->myhost ); 840 u->realname = g_strdup( ROOT_FN ); 841 u->online = 0; 842 u->send_handler = root_command_string; 843 u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */ 844 845 u = user_add( irc, irc->nick ); 846 u->user = g_strdup( irc->user ); 847 u->host = g_strdup( irc->host ); 848 u->realname = g_strdup( irc->realname ); 849 u->online = 1; 850 irc_spawn( irc, u ); 851 852 irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n" 853 "If you've never used BitlBee before, please do read the help " 854 "information using the \x02help\x02 command. Lots of FAQs are " 855 "answered there.\n" 856 "If you already have an account on this server, just use the " 857 "\x02identify\x02 command to identify yourself." ); 858 859 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 860 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); 861 862 irc->status |= USTATUS_LOGGED_IN; 863 864 /* This is for bug #209 (use PASS to identify to NickServ). */ 865 if( irc->password != NULL ) 866 { 867 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; 868 869 irc_setpass( irc, NULL ); 870 root_command( irc, send_cmd ); 871 g_free( send_cmd[1] ); 872 } 873 } 874 875 void irc_motd( irc_t *irc ) 876 { 877 int fd; 878 879 fd = open( global.conf->motdfile, O_RDONLY ); 880 if( fd == -1 ) 881 { 882 irc_reply( irc, 422, ":We don't need MOTDs." ); 883 } 884 else 885 { 886 char linebuf[80]; /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */ 887 char *add, max; 888 int len; 889 890 linebuf[79] = len = 0; 891 max = sizeof( linebuf ) - 1; 892 893 irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost ); 894 while( read( fd, linebuf + len, 1 ) == 1 ) 895 { 896 if( linebuf[len] == '\n' || len == max ) 897 { 898 linebuf[len] = 0; 899 irc_reply( irc, 372, ":- %s", linebuf ); 900 len = 0; 901 } 902 else if( linebuf[len] == '%' ) 903 { 904 read( fd, linebuf + len, 1 ); 905 if( linebuf[len] == 'h' ) 906 add = irc->myhost; 907 else if( linebuf[len] == 'v' ) 908 add = BITLBEE_VERSION; 909 else if( linebuf[len] == 'n' ) 910 add = irc->nick; 911 else 912 add = "%"; 913 914 strncpy( linebuf + len, add, max - len ); 915 while( linebuf[++len] ); 916 } 917 else if( len < max ) 918 { 919 len ++; 920 } 921 } 922 irc_reply( irc, 376, ":End of MOTD" ); 923 close( fd ); 924 } 925 } 926 927 void irc_topic( irc_t *irc, char *channel ) 928 { 929 struct groupchat *c = irc_chat_by_channel( irc, channel ); 930 931 if( c && c->topic ) 932 irc_reply( irc, 332, "%s :%s", channel, c->topic ); 933 else if( g_strcasecmp( channel, irc->channel ) == 0 ) 934 irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC ); 935 else 936 irc_reply( irc, 331, "%s :No topic for this channel", channel ); 937 } 938 939 void irc_umode_set( irc_t *irc, char *s, int allow_priv ) 660 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ) 940 661 { 941 662 /* allow_priv: Set to 0 if s contains user input, 1 if you want 942 663 to set a "privileged" mode (+o, +R, etc). */ 943 char m[256], st = 1, *t; 664 char m[128], st = 1; 665 const char *t; 944 666 int i; 945 667 char changes[512], *p, st2 = 2; … … 949 671 950 672 for( t = irc->umode; *t; t ++ ) 951 m[(int)*t] = 1; 952 673 if( *t < sizeof( m ) ) 674 m[(int)*t] = 1; 675 953 676 p = changes; 954 677 for( t = s; *t; t ++ ) … … 956 679 if( *t == '+' || *t == '-' ) 957 680 st = *t == '+'; 958 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) ) 681 else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) || 682 ( st == 1 && strchr( UMODES, *t ) ) || 683 ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) ) 959 684 { 960 685 if( m[(int)*t] != st) … … 973 698 memset( irc->umode, 0, sizeof( irc->umode ) ); 974 699 975 for( i = 0; i < 256&& strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )700 for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ ) 976 701 if( m[i] ) 977 702 irc->umode[strlen(irc->umode)] = i; 978 703 979 704 if( badflag ) 980 irc_reply( irc, 501, ":Unknown MODE flag" ); 981 /* Deliberately no !user@host on the prefix here */ 705 irc_send_num( irc, 501, ":Unknown MODE flag" ); 982 706 if( *changes ) 983 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes ); 984 } 985 986 void irc_spawn( irc_t *irc, user_t *u ) 987 { 988 irc_join( irc, u, irc->channel ); 989 } 990 991 void irc_join( irc_t *irc, user_t *u, char *channel ) 992 { 993 char *nick; 994 995 if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) ) 996 irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel ); 997 998 if( nick_cmp( u->nick, irc->nick ) == 0 ) 999 { 1000 irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE ); 1001 irc_names( irc, channel ); 1002 irc_topic( irc, channel ); 1003 } 1004 1005 nick = g_strdup( u->nick ); 1006 nick_lc( nick ); 1007 if( g_hash_table_lookup( irc->watches, nick ) ) 1008 { 1009 irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" ); 1010 } 1011 g_free( nick ); 1012 } 1013 1014 void irc_part( irc_t *irc, user_t *u, char *channel ) 1015 { 1016 irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" ); 1017 } 1018 1019 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker ) 1020 { 1021 irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" ); 1022 } 1023 1024 void irc_kill( irc_t *irc, user_t *u ) 1025 { 1026 char *nick, *s; 1027 char reason[128]; 1028 1029 if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) ) 1030 { 1031 if( u->ic->acc->server ) 1032 g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, 1033 u->ic->acc->server ); 1034 else if( ( s = strchr( u->ic->acc->user, '@' ) ) ) 1035 g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, 1036 s + 1 ); 1037 else 1038 g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost, 1039 u->ic->acc->prpl->name, irc->myhost ); 1040 1041 /* proto_opt might contain garbage after the : */ 1042 if( ( s = strchr( reason, ':' ) ) ) 1043 *s = 0; 1044 } 1045 else 1046 { 1047 strcpy( reason, "Leaving..." ); 1048 } 1049 1050 irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason ); 1051 1052 nick = g_strdup( u->nick ); 1053 nick_lc( nick ); 1054 if( g_hash_table_lookup( irc->watches, nick ) ) 1055 { 1056 irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" ); 1057 } 1058 g_free( nick ); 1059 } 1060 1061 int irc_send( irc_t *irc, char *nick, char *s, int flags ) 1062 { 1063 struct groupchat *c = NULL; 1064 user_t *u = NULL; 1065 1066 if( strchr( CTYPES, *nick ) ) 1067 { 1068 if( !( c = irc_chat_by_channel( irc, nick ) ) ) 1069 { 1070 irc_reply( irc, 403, "%s :Channel does not exist", nick ); 1071 return( 0 ); 1072 } 1073 } 1074 else 1075 { 1076 u = user_find( irc, nick ); 1077 1078 if( !u ) 1079 { 1080 if( irc->is_private ) 1081 irc_reply( irc, 401, "%s :Nick does not exist", nick ); 1082 else 1083 irc_usermsg( irc, "Nick `%s' does not exist!", nick ); 1084 return( 0 ); 1085 } 1086 } 1087 1088 if( *s == 1 && s[strlen(s)-1] == 1 ) 1089 { 1090 if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 ) 1091 { 1092 if( s[7] == ' ' ) s ++; 1093 s += 3; 1094 *(s++) = '/'; 1095 *(s++) = 'm'; 1096 *(s++) = 'e'; 1097 *(s++) = ' '; 1098 s -= 4; 1099 s[strlen(s)-1] = 0; 1100 } 1101 else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 ) 1102 { 1103 u = user_find( irc, irc->mynick ); 1104 irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" ); 1105 return( 1 ); 1106 } 1107 else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 ) 1108 { 1109 u = user_find( irc, irc->mynick ); 1110 irc_privmsg( irc, u, "NOTICE", irc->nick, "", s ); 1111 return( 1 ); 1112 } 1113 else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 ) 1114 { 1115 if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 ) 1116 { 1117 time_t current_typing_notice = time( NULL ); 1118 1119 if( current_typing_notice - u->last_typing_notice >= 5 ) 1120 { 1121 u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 ); 1122 u->last_typing_notice = current_typing_notice; 1123 } 1124 } 1125 return( 1 ); 1126 } 1127 else 1128 { 1129 irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" ); 1130 return( 0 ); 1131 } 1132 } 1133 1134 if( u ) 1135 { 1136 /* For the next message, we probably do have to send new notices... */ 1137 u->last_typing_notice = 0; 1138 u->is_private = irc->is_private; 1139 1140 if( u->is_private ) 1141 { 1142 if( !u->online ) 1143 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" ); 1144 else if( u->away ) 1145 irc_reply( irc, 301, "%s :%s", u->nick, u->away ); 1146 } 1147 1148 if( u->send_handler ) 1149 { 1150 u->send_handler( irc, u, s, flags ); 1151 return 1; 1152 } 1153 } 1154 else if( c && c->ic && c->ic->acc && c->ic->acc->prpl ) 1155 { 1156 return( imc_chat_msg( c, s, 0 ) ); 1157 } 1158 1159 return( 0 ); 1160 } 1161 1162 static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond ) 1163 { 1164 user_t *u = data; 1165 1166 /* Shouldn't happen, but just to be sure. */ 1167 if( u->sendbuf_len < 2 ) 1168 return FALSE; 1169 1170 u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */ 1171 imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags ); 1172 1173 g_free( u->sendbuf ); 1174 u->sendbuf = NULL; 1175 u->sendbuf_len = 0; 1176 u->sendbuf_timer = 0; 1177 u->sendbuf_flags = 0; 1178 1179 return FALSE; 1180 } 1181 1182 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) 1183 { 1184 if( !u || !u->ic ) return; 1185 1186 if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) 1187 { 1188 int delay; 1189 1190 if( u->sendbuf_len > 0 && u->sendbuf_flags != flags) 1191 { 1192 /* Flush the buffer */ 1193 b_event_remove( u->sendbuf_timer ); 1194 buddy_send_handler_delayed( u, -1, 0 ); 1195 } 1196 1197 if( u->sendbuf_len == 0 ) 1198 { 1199 u->sendbuf_len = strlen( msg ) + 2; 1200 u->sendbuf = g_new( char, u->sendbuf_len ); 1201 u->sendbuf[0] = 0; 1202 u->sendbuf_flags = flags; 1203 } 1204 else 1205 { 1206 u->sendbuf_len += strlen( msg ) + 1; 1207 u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len ); 1208 } 1209 1210 strcat( u->sendbuf, msg ); 1211 strcat( u->sendbuf, "\n" ); 1212 1213 delay = set_getint( &irc->set, "buddy_sendbuffer_delay" ); 1214 if( delay <= 5 ) 1215 delay *= 1000; 1216 1217 if( u->sendbuf_timer > 0 ) 1218 b_event_remove( u->sendbuf_timer ); 1219 u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u ); 1220 } 1221 else 1222 { 1223 imc_buddy_msg( u->ic, u->handle, msg, flags ); 1224 } 1225 } 1226 1227 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg ) 1228 { 1229 char last = 0; 1230 char *s = msg, *line = msg; 1231 1232 /* The almighty linesplitter .. woohoo!! */ 1233 while( !last ) 1234 { 1235 if( *s == '\r' && *(s+1) == '\n' ) 1236 *(s++) = 0; 1237 if( *s == '\n' ) 1238 { 1239 last = s[1] == 0; 1240 *s = 0; 1241 } 1242 else 1243 { 1244 last = s[0] == 0; 1245 } 1246 if( *s == 0 ) 1247 { 1248 if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 ) 1249 { 1250 irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host, 1251 type, to, line + 4 ); 1252 } 1253 else 1254 { 1255 irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host, 1256 type, to, prefix ? prefix : "", line ); 1257 } 1258 line = s + 1; 1259 } 1260 s ++; 1261 } 1262 1263 return( 1 ); 1264 } 1265 1266 int irc_msgfrom( irc_t *irc, char *nick, char *msg ) 1267 { 1268 user_t *u = user_find( irc, nick ); 1269 static char *prefix = NULL; 1270 1271 if( !u ) return( 0 ); 1272 if( prefix && *prefix ) g_free( prefix ); 1273 1274 if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 ) 1275 { 1276 int len = strlen( irc->nick) + 3; 1277 prefix = g_new (char, len ); 1278 g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) ); 1279 prefix[len-1] = 0; 1280 } 1281 else 1282 { 1283 prefix = ""; 1284 } 1285 1286 return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) ); 1287 } 1288 1289 int irc_noticefrom( irc_t *irc, char *nick, char *msg ) 1290 { 1291 user_t *u = user_find( irc, nick ); 1292 1293 if( u ) 1294 return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) ); 1295 else 1296 return( 0 ); 1297 } 707 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick, 708 irc->user->user, irc->user->host, irc->user->nick, 709 changes ); 710 } 711 1298 712 1299 713 /* Returns 0 if everything seems to be okay, a number >0 when there was a … … 1333 747 } 1334 748 1335 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel ) 1336 { 1337 struct groupchat *c; 1338 account_t *a; 1339 1340 /* This finds the connection which has a conversation which belongs to this channel */ 1341 for( a = irc->accounts; a; a = a->next ) 1342 { 1343 if( a->ic == NULL ) 1344 continue; 1345 1346 c = a->ic->groupchats; 1347 while( c ) 1348 { 1349 if( c->channel && g_strcasecmp( c->channel, channel ) == 0 ) 1350 return c; 1351 1352 c = c->next; 1353 } 1354 } 1355 1356 return NULL; 1357 } 749 750 static char *set_eval_charset( set_t *set, char *value ) 751 { 752 irc_t *irc = set->data; 753 GIConv ic, oc; 754 755 if( g_strcasecmp( value, "none" ) == 0 ) 756 value = g_strdup( "utf-8" ); 757 758 if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) 759 { 760 return NULL; 761 } 762 if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) 763 { 764 g_iconv_close( ic ); 765 return NULL; 766 } 767 768 if( irc->iconv != (GIConv) -1 ) 769 g_iconv_close( irc->iconv ); 770 if( irc->oconv != (GIConv) -1 ) 771 g_iconv_close( irc->oconv ); 772 773 irc->iconv = ic; 774 irc->oconv = oc; 775 776 return value; 777 }
Note: See TracChangeset
for help on using the changeset viewer.