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