- Timestamp:
- 2006-02-12T07:26:20Z (18 years ago)
- Branches:
- master
- Children:
- f665dab
- Parents:
- a323a22 (diff), 58bc4e6 (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
ra323a22 r5ebe625 27 27 #include "bitlbee.h" 28 28 #include "crypting.h" 29 #include "ipc.h" 29 30 30 31 static gboolean irc_userping( gpointer _irc ); … … 40 41 irc_t *irc_new( int fd ) 41 42 { 42 irc_t *irc = g_new0( irc_t, 1 ); 43 43 irc_t *irc; 44 struct hostent *peer; 45 unsigned int i; 46 char buf[128]; 47 #ifdef IPV6 48 struct sockaddr_in6 sock[1]; 49 #else 44 50 struct sockaddr_in sock[1]; 45 #ifdef IPV646 struct sockaddr_in6 sock6[1];47 51 #endif 48 struct hostent *peer;49 unsigned int i, j;52 53 irc = g_new0( irc_t, 1 ); 50 54 51 55 irc->fd = fd; … … 71 75 72 76 i = sizeof( *sock ); 73 #ifdef IPV6 74 j = sizeof( *sock6 ); 75 #endif 77 76 78 if( global.conf->hostname ) 77 79 irc->myhost = g_strdup( global.conf->hostname ); 78 else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET ) 79 { 80 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) ) 80 #ifdef IPV6 81 else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx ) 82 { 83 if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) ) 81 84 irc->myhost = g_strdup( peer->h_name ); 82 } 83 #ifdef IPV6 84 else if( getsockname( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 ) 85 { 86 if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) ) 85 else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) 86 irc->myhost = g_strdup( ipv6_unwrap( buf ) ); 87 } 88 #else 89 else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx ) 90 { 91 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) ) 87 92 irc->myhost = g_strdup( peer->h_name ); 93 else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) 94 irc->myhost = g_strdup( buf ); 88 95 } 89 96 #endif … … 91 98 i = sizeof( *sock ); 92 99 #ifdef IPV6 93 j = sizeof( *sock6 ); 100 if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx ) 101 { 102 if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) ) 103 irc->host = g_strdup( peer->h_name ); 104 else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) 105 irc->host = g_strdup( ipv6_unwrap( buf ) ); 106 } 107 #else 108 if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx ) 109 { 110 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) ) 111 irc->host = g_strdup( peer->h_name ); 112 else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) 113 irc->host = g_strdup( buf ); 114 } 94 115 #endif 95 if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET ) 96 { 97 if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) ) 98 irc->host = g_strdup( peer->h_name ); 99 } 100 #ifdef IPV6 101 else if( getpeername( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 ) 102 { 103 if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) ) 104 irc->host = g_strdup( peer->h_name ); 105 } 106 #endif 107 116 117 /* Rare, but possible. */ 108 118 if( !irc->host ) irc->host = g_strdup( "localhost." ); 109 119 if( !irc->myhost ) irc->myhost = g_strdup( "localhost." ); … … 142 152 } 143 153 154 /* immed=1 makes this function pretty much equal to irc_free(), except that 155 this one will "log". In case the connection is already broken and we 156 shouldn't try to write to it. */ 157 void irc_abort( irc_t *irc, int immed, char *format, ... ) 158 { 159 if( format != NULL ) 160 { 161 va_list params; 162 char *reason; 163 164 va_start( params, format ); 165 reason = g_strdup_vprintf( format, params ); 166 va_end( params ); 167 168 if( !immed ) 169 irc_write( irc, "ERROR :Closing link: %s", reason ); 170 171 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 172 irc->nick ? irc->nick : "(NONE)", irc->host, reason ); 173 174 g_free( reason ); 175 } 176 else 177 { 178 if( !immed ) 179 irc_write( irc, "ERROR :Closing link" ); 180 181 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 182 irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" ); 183 } 184 185 irc->status = USTATUS_SHUTDOWN; 186 if( irc->sendbuffer && !immed ) 187 { 188 /* We won't read from this socket anymore. Instead, we'll connect a timer 189 to it that should shut down the connection in a second, just in case 190 bitlbee_.._write doesn't do it first. */ 191 192 g_source_remove( irc->r_watch_source_id ); 193 irc->r_watch_source_id = g_timeout_add_full( G_PRIORITY_HIGH, 1000, (GSourceFunc) irc_free, irc, NULL ); 194 } 195 else 196 { 197 irc_free( irc ); 198 } 199 } 200 144 201 static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data ) 145 202 { … … 163 220 if( storage_save( irc, TRUE ) != STORAGE_OK ) 164 221 irc_usermsg( irc, "Error while saving settings!" ); 222 223 closesocket( irc->fd ); 165 224 166 225 if( irc->ping_source_id > 0 ) … … 264 323 g_free(irc); 265 324 266 if( global.conf->runmode == RUNMODE_INETD )325 if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) 267 326 g_main_quit( global.loop ); 268 327 } … … 282 341 } 283 342 284 intirc_process( irc_t *irc )285 { 286 char **lines, *temp ;343 void irc_process( irc_t *irc ) 344 { 345 char **lines, *temp, **cmd; 287 346 int i; 288 347 289 if( irc->readbuffer != NULL ) { 290 lines = irc_tokenize(irc->readbuffer ); 291 for( i = 0; *lines[i] != '\0'; i++ ) { 292 if( lines[i+1] == NULL ) { 348 if( irc->readbuffer != NULL ) 349 { 350 lines = irc_tokenize( irc->readbuffer ); 351 352 for( i = 0; *lines[i] != '\0'; i ++ ) 353 { 354 if( lines[i+1] == NULL ) 355 { 293 356 temp = g_strdup( lines[i] ); 294 357 g_free( irc->readbuffer ); 295 358 irc->readbuffer = temp; 296 i ++;359 i ++; 297 360 break; 298 361 } 299 if (!irc_process_line(irc, lines[i])) { 362 363 if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) 364 continue; 365 irc_exec( irc, cmd ); 366 367 g_free( cmd ); 368 369 /* Shouldn't really happen, but just in case... */ 370 if( !g_slist_find( irc_connection_list, irc ) ) 371 { 300 372 g_free( lines ); 301 return 0;373 return; 302 374 } 303 375 } 304 if(lines[i]!=NULL) { 305 g_free(irc->readbuffer); 306 irc->readbuffer=NULL; 307 } 376 377 if( lines[i] != NULL ) 378 { 379 g_free( irc->readbuffer ); 380 irc->readbuffer = NULL; 381 } 382 308 383 g_free( lines ); 309 384 } 310 return 1;311 385 } 312 386 … … 317 391 318 392 /* Count the number of elements we're gonna need. */ 319 for(i=0, j=1; buffer[i]!='\0'; i++ ) { 320 if(buffer[i]=='\n' ) 321 if(buffer[i+1]!='\r' && buffer[i+1]!='\n') 322 j++; 393 for( i = 0, j = 1; buffer[i] != '\0'; i ++ ) 394 { 395 if( buffer[i] == '\n' ) 396 if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) 397 j ++; 323 398 } 324 399 325 400 /* Allocate j+1 elements. */ 326 lines =g_new (char *, j+1);401 lines = g_new( char *, j + 1 ); 327 402 328 403 /* NULL terminate our list. */ 329 lines[j] =NULL;330 331 lines[0] =buffer;404 lines[j] = NULL; 405 406 lines[0] = buffer; 332 407 333 408 /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional. 334 409 * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. 335 410 */ 336 for( i=0, j=0; buffer[i]!='\0'; i++) { 337 if(buffer[i]=='\n') { 338 buffer[i]='\0'; 339 340 /* We dont want to read 1 byte before our buffer 341 * and (in rare cases) generate a SIGSEGV. 342 */ 343 if(i!=0) 344 if(buffer[i-1]=='\r') 345 buffer[i-1]='\0'; 346 if(buffer[i+1]!='\r'&&buffer[i+1]!='\n') 347 lines[++j]=buffer+i+1; 348 } 349 } 350 351 return(lines); 352 } 353 354 int irc_process_line( irc_t *irc, char *line ) 411 for( i = 0, j = 0; buffer[i] != '\0'; i ++) 412 { 413 if( buffer[i] == '\n' ) 414 { 415 buffer[i] = '\0'; 416 417 if( i > 0 && buffer[i-1] == '\r' ) 418 buffer[i-1] = '\0'; 419 if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) 420 lines[++j] = buffer + i + 1; 421 } 422 } 423 424 return( lines ); 425 } 426 427 char **irc_parse_line( char *line ) 355 428 { 356 429 int i, j; … … 358 431 359 432 /* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */ 360 if(line[0]==':') { 361 for(i=0; line[i]!=32; i++); 362 line=line+i; 363 } 364 for(i=0; line[i]==32; i++); 365 line=line+i; 366 433 if( line[0] == ':' ) 434 { 435 for( i = 0; line[i] != ' '; i ++ ); 436 line = line + i; 437 } 438 for( i = 0; line[i] == ' '; i ++ ); 439 line = line + i; 440 367 441 /* If we're already at the end of the line, return. If not, we're going to need at least one element. */ 368 if(line[0]=='\0') 369 return 1; 370 else 371 j=1; 372 373 /* Count the number of char **cmd elements we're going to need. */ 374 for(i=0; line[i]!='\0'; i++) { 375 if((line[i]==32) && (line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':')) 376 j++; 377 else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]==32)) { 378 j++; 379 break; 380 } 442 if( line[0] == '\0') 443 return NULL; 444 445 /* Count the number of char **cmd elements we're going to need. */ 446 j = 1; 447 for( i = 0; line[i] != '\0'; i ++ ) 448 { 449 if( line[i] == ' ' ) 450 { 451 j ++; 381 452 453 if( line[i+1] == ':' ) 454 break; 455 } 382 456 } 383 457 384 458 /* Allocate the space we need. */ 385 cmd =g_new(char *, j+1);386 cmd[j] =NULL;459 cmd = g_new( char *, j + 1 ); 460 cmd[j] = NULL; 387 461 388 462 /* Do the actual line splitting, format is: … … 391 465 */ 392 466 393 cmd[0]=line; 394 for(i=0, j=0; line[i]!='\0'; i++) { 395 if((line[i]==32)) { 396 line[i]='\0'; 397 if((line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':')) 398 cmd[++j]=line+i+1; 399 } 400 else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]=='\0')) { 401 cmd[++j]=line+i+1; 402 break; 403 } 404 } 405 406 i=irc_exec(irc, cmd); 407 g_free(cmd); 408 409 return(i); 410 } 411 412 int irc_exec( irc_t *irc, char **cmd ) 413 { 414 int i; 415 416 if( (global.conf)->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED ) 417 { 418 if( g_strcasecmp( cmd[0], "PASS" ) == 0 ) 419 { 420 if( !cmd[1] ) 467 cmd[0] = line; 468 for( i = 0, j = 0; line[i] != '\0'; i ++ ) 469 { 470 if( line[i] == ' ' ) 471 { 472 line[i] = '\0'; 473 cmd[++j] = line + i + 1; 474 475 if( line[i+1] == ':' ) 421 476 { 422 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 477 cmd[j] ++; 478 break; 423 479 } 424 else if( strcmp( cmd[1], (global.conf)->password ) == 0 ) 425 { 426 irc->status = USTATUS_AUTHORIZED; 427 } 428 else 429 { 430 irc_reply( irc, 464, ":Nope, maybe you should try it again..." ); 431 } 432 } 433 else 434 { 435 irc_reply( irc, 464, ":Uhh, fine, but I want the password first." ); 436 } 437 438 return( 1 ); 439 } 440 441 if( g_strcasecmp( cmd[0], "USER" ) == 0 ) 442 { 443 if( !( cmd[1] && cmd[2] && cmd[3] && cmd[4] ) ) 444 { 445 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 446 } 447 else if( irc->user ) 448 { 449 irc_reply( irc, 462, ":You can't change your nick/userinfo" ); 450 } 451 else 452 { 453 irc->user = g_strdup( cmd[1] ); 454 irc->realname = g_strdup( cmd[4] ); 455 if( irc->nick ) irc_login( irc ); 456 } 457 return( 1 ); 458 } 459 else if( g_strcasecmp( cmd[0], "NICK" ) == 0 ) 460 { 461 if( !cmd[1] ) 462 { 463 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 464 } 465 else if( irc->nick ) 466 { 467 irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" ); 468 } 469 /* This is not clean, but for now it'll have to be like this... */ 470 else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) ) 471 { 472 irc_reply( irc, 433, ":This nick is already in use" ); 473 } 474 else if( !nick_ok( cmd[1] ) ) 475 { 476 /* [SH] Invalid characters. */ 477 irc_reply( irc, 432, ":This nick contains invalid characters" ); 478 } 479 else 480 { 481 irc->nick = g_strdup( cmd[1] ); 482 if( irc->user ) irc_login( irc ); 483 } 484 return( 1 ); 485 } 486 else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 ) 487 { 488 irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" ); 489 g_io_channel_close( irc->io_channel ); 490 return( 0 ); 491 } 492 493 if( !irc->user || !irc->nick ) 494 { 495 irc_reply( irc, 451, ":Register first" ); 496 return( 1 ); 497 } 498 499 if( g_strcasecmp( cmd[0], "PING" ) == 0 ) 500 { 501 irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); 502 } 503 else if( g_strcasecmp( cmd[0], "MODE" ) == 0 ) 504 { 505 if( !cmd[1] ) 506 { 507 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 508 } 509 else if( *cmd[1] == '#' || *cmd[1] == '&' ) 510 { 511 if( cmd[2] ) 512 { 513 if( *cmd[2] == '+' || *cmd[2] == '-' ) 514 irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] ); 515 else if( *cmd[2] == 'b' ) 516 irc_reply( irc, 368, "%s :No bans possible", cmd[1] ); 517 } 518 else 519 irc_reply( irc, 324, "%s +%s", cmd[1], CMODE ); 520 } 521 else 522 { 523 if( nick_cmp( cmd[1], irc->nick ) == 0 ) 524 { 525 if( cmd[2] ) 526 irc_umode_set( irc, irc->nick, cmd[2] ); 527 } 528 else 529 irc_reply( irc, 502, ":Don't touch their modes" ); 530 } 531 } 532 else if( g_strcasecmp( cmd[0], "NAMES" ) == 0 ) 533 { 534 irc_names( irc, cmd[1]?cmd[1]:irc->channel ); 535 } 536 else if( g_strcasecmp( cmd[0], "PART" ) == 0 ) 537 { 538 struct conversation *c; 539 540 if( !cmd[1] ) 541 { 542 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 543 } 544 else if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) 545 { 546 user_t *u = user_find( irc, irc->nick ); 547 548 /* Not allowed to leave control channel */ 549 irc_part( irc, u, irc->channel ); 550 irc_join( irc, u, irc->channel ); 551 } 552 else if( ( c = conv_findchannel( cmd[1] ) ) ) 553 { 554 user_t *u = user_find( irc, irc->nick ); 555 556 irc_part( irc, u, c->channel ); 557 558 if( c->gc && c->gc->prpl ) 559 { 560 c->joined = 0; 561 c->gc->prpl->chat_leave( c->gc, c->id ); 562 } 563 } 564 else 565 { 566 irc_reply( irc, 403, "%s :No such channel", cmd[1] ); 567 } 568 } 569 else if( g_strcasecmp( cmd[0], "JOIN" ) == 0 ) 570 { 571 if( !cmd[1] ) 572 { 573 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 574 } 575 else if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) 576 ; /* Dude, you're already there... 577 RFC doesn't have any reply for that though? */ 578 else if( cmd[1] ) 579 { 580 if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] ) 581 { 582 user_t *u = user_find( irc, cmd[1] + 1 ); 583 584 if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open ) 585 { 586 irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); 587 588 if( !u->gc->prpl->chat_open( u->gc, u->handle ) ) 589 { 590 irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick ); 591 } 592 } 593 else 594 { 595 irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 ); 596 } 597 } 598 else 599 { 600 irc_reply( irc, 403, "%s :No such channel", cmd[1] ); 601 } 602 } 603 } 604 else if( g_strcasecmp( cmd[0], "INVITE" ) == 0 ) 605 { 606 if( cmd[1] && cmd[2] ) 607 irc_invite( irc, cmd[1], cmd[2] ); 608 else 609 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 610 } 611 else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) 612 { 613 if( !cmd[1] ) 614 { 615 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 616 } 617 else if ( !cmd[2] ) 618 { 619 irc_reply( irc, 412, ":No text to send" ); 620 } 621 else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 622 { 623 irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); 624 } 625 else 626 { 627 if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) 628 { 629 unsigned int i; 630 char *t = set_getstr( irc, "default_target" ); 631 632 if( g_strcasecmp( t, "last" ) == 0 && irc->last_target ) 633 cmd[1] = irc->last_target; 634 else if( g_strcasecmp( t, "root" ) == 0 ) 635 cmd[1] = irc->mynick; 636 637 for( i = 0; i < strlen( cmd[2] ); i ++ ) 638 { 639 if( cmd[2][i] == ' ' ) break; 640 if( cmd[2][i] == ':' || cmd[2][i] == ',' ) 641 { 642 cmd[1] = cmd[2]; 643 cmd[2] += i; 644 *cmd[2] = 0; 645 while( *(++cmd[2]) == ' ' ); 646 break; 647 } 648 } 649 650 irc->is_private = 0; 651 652 if( cmd[1] != irc->last_target ) 653 { 654 if( irc->last_target ) 655 g_free( irc->last_target ); 656 irc->last_target = g_strdup( cmd[1] ); 657 } 658 } 659 else 660 { 661 irc->is_private = 1; 662 } 663 irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 ); 664 } 665 } 666 else if( g_strcasecmp( cmd[0], "WHO" ) == 0 ) 667 { 668 irc_who( irc, cmd[1] ); 669 } 670 else if( g_strcasecmp( cmd[0], "USERHOST" ) == 0 ) 671 { 672 user_t *u; 673 674 if( !cmd[1] ) 675 { 676 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 677 } 678 /* [TV] Usable USERHOST-implementation according to 679 RFC1459. Without this, mIRC shows an error 680 while connecting, and the used way of rejecting 681 breaks standards. 682 */ 683 684 for( i = 1; cmd[i]; i ++ ) 685 if( ( u = user_find( irc, cmd[i] ) ) ) 686 { 687 if( u->online && u->away ) 688 irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host ); 689 else 690 irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host ); 691 } 692 } 693 else if( g_strcasecmp( cmd[0], "ISON" ) == 0 ) 694 { 695 user_t *u; 696 char buff[IRC_MAX_LINE]; 697 int lenleft; 698 699 buff[0] = '\0'; 700 701 /* [SH] Leave room for : and \0 */ 702 lenleft = IRC_MAX_LINE - 2; 703 704 for( i = 1; cmd[i]; i ++ ) 705 { 706 if( ( u = user_find( irc, cmd[i] ) ) && u->online ) 707 { 708 /* [SH] Make sure we don't use too much buffer space. */ 709 lenleft -= strlen( u->nick ) + 1; 710 711 if( lenleft < 0 ) 712 { 713 break; 714 } 715 716 /* [SH] Add the nick to the buffer. Note 717 * that an extra space is always added. Even 718 * if it's the last nick in the list. Who 719 * cares? 720 */ 721 722 strcat( buff, u->nick ); 723 strcat( buff, " " ); 724 } 725 } 726 727 /* [WvG] Well, maybe someone cares, so why not remove it? */ 728 if( strlen( buff ) > 0 ) 729 buff[strlen(buff)-1] = '\0'; 730 731 /* [SH] By the way, that really *was* WvG talking. */ 732 /* [WvG] Really? */ 733 /* [SH] Yeah... But *this* is WvG talking too. ;-P */ 734 /* [WvG] *sigh* */ 735 736 irc_reply( irc, 303, ":%s", buff ); 737 } 738 else if( g_strcasecmp( cmd[0], "WATCH" ) == 0 ) 739 { 740 /* Obviously we could also mark a user structure as being 741 watched, but what if the WATCH command is sent right 742 after connecting? The user won't exist yet then... */ 743 for( i = 1; cmd[i]; i ++ ) 744 { 745 char *nick; 746 user_t *u; 747 748 if( !cmd[i][0] || !cmd[i][1] ) 749 break; 750 751 nick = g_strdup( cmd[i] + 1 ); 752 nick_lc( nick ); 753 754 u = user_find( irc, nick ); 755 756 if( cmd[i][0] == '+' ) 757 { 758 if( !g_hash_table_lookup( irc->watches, nick ) ) 759 g_hash_table_insert( irc->watches, nick, nick ); 760 761 if( u && u->online ) 762 irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" ); 763 else 764 irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" ); 765 } 766 else if( cmd[i][0] == '-' ) 767 { 768 gpointer okey, ovalue; 769 770 if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) ) 771 { 772 g_free( okey ); 773 g_hash_table_remove( irc->watches, okey ); 774 775 irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); 776 } 777 } 778 } 779 } 780 else if( g_strcasecmp( cmd[0], "TOPIC" ) == 0 ) 781 { 782 if( cmd[1] && cmd[2] ) 783 irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] ); 784 else if( cmd[1] ) 785 irc_topic( irc, cmd[1] ); 786 else 787 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 788 } 789 else if( g_strcasecmp( cmd[0], "AWAY" ) == 0 ) 790 { 791 irc_away( irc, cmd[1] ); 792 } 793 else if( g_strcasecmp( cmd[0], "WHOIS" ) == 0 ) 794 { 795 if( cmd[1] ) 796 { 797 irc_whois( irc, cmd[1] ); 798 } 799 else 800 { 801 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 802 } 803 } 804 else if( g_strcasecmp( cmd[0], "WHOWAS" ) == 0 ) 805 { 806 /* For some reason irssi tries a whowas when whois fails. We can 807 ignore this, but then the user never gets a "user not found" 808 message from irssi which is a bit annoying. So just respond 809 with not-found and irssi users will get better error messages */ 810 811 if( cmd[1] ) 812 { 813 irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] ); 814 irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] ); 815 } 816 else 817 { 818 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); 819 } 820 } 821 else if( ( g_strcasecmp( cmd[0], "NICKSERV" ) == 0 ) || ( g_strcasecmp( cmd[0], "NS" ) == 0 ) ) 822 { 823 /* [SH] This aliases the NickServ command to PRIVMSG root */ 824 /* [TV] This aliases the NS command to PRIVMSG root as well */ 825 root_command( irc, cmd + 1 ); 826 } 827 else if( g_strcasecmp( cmd[0], "MOTD" ) == 0 ) 828 { 829 irc_motd( irc ); 830 } 831 else if( g_strcasecmp( cmd[0], "PONG" ) == 0 ) 832 { 833 /* We could check the value we get back from the user, but in 834 fact we don't care, we're just happy he's still alive. */ 835 irc->last_pong = gettime(); 836 irc->pinging = 0; 837 } 838 else if( g_strcasecmp( cmd[0], "COMPLETIONS" ) == 0 ) 839 { 840 user_t *u = user_find( irc, irc->mynick ); 841 help_t *h; 842 set_t *s; 843 int i; 844 845 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" ); 846 847 for( i = 0; commands[i].command; i ++ ) 848 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command ); 849 850 for( h = global.help; h; h = h->next ) 851 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string ); 852 853 for( s = irc->set; s; s = s->next ) 854 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key ); 855 856 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" ); 857 } 858 else if( set_getint( irc, "debug" ) ) 859 { 860 irc_usermsg( irc, "\002--- Unknown command:" ); 861 for( i = 0; cmd[i]; i ++ ) irc_usermsg( irc, "%s", cmd[i] ); 862 irc_usermsg( irc, "\002--------------------" ); 863 } 864 865 return( 1 ); 480 } 481 } 482 483 return cmd; 484 } 485 486 char *irc_build_line( char **cmd ) 487 { 488 int i, len; 489 char *s; 490 491 if( cmd[0] == NULL ) 492 return NULL; 493 494 len = 1; 495 for( i = 0; cmd[i]; i ++ ) 496 len += strlen( cmd[i] ) + 1; 497 498 if( strchr( cmd[i-1], ' ' ) != NULL ) 499 len ++; 500 501 s = g_new0( char, len + 1 ); 502 for( i = 0; cmd[i]; i ++ ) 503 { 504 if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL ) 505 strcat( s, ":" ); 506 507 strcat( s, cmd[i] ); 508 509 if( cmd[i+1] ) 510 strcat( s, " " ); 511 } 512 strcat( s, "\r\n" ); 513 514 return s; 866 515 } 867 516 … … 923 572 if( irc->sendbuffer != NULL ) { 924 573 size = strlen( irc->sendbuffer ) + strlen( line ); 925 #ifdef FLOOD_SEND926 if( size > FLOOD_SEND_MAXBUFFER ) {927 /* Die flooder, die! >:) */928 929 g_free(irc->sendbuffer);930 931 /* We need the \r\n at the start because else we might append our string to a half932 * sent line. A bit hackish, but it works.933 */934 irc->sendbuffer = g_strdup( "\r\nERROR :Sendq Exceeded\r\n" );935 irc->quit = 1;936 937 return;938 }939 #endif940 574 irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 ); 941 575 strcpy( ( irc->sendbuffer + strlen( irc->sendbuffer ) ), line ); … … 1037 671 } 1038 672 1039 void irc_who( irc_t *irc, char *channel ) 1040 { 1041 user_t *u = irc->users; 1042 struct conversation *c; 1043 GList *l; 1044 1045 if( !channel || *channel == '0' || *channel == '*' || !*channel ) 1046 while( u ) 1047 { 1048 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); 1049 u = u->next; 1050 } 1051 else if( g_strcasecmp( channel, irc->channel ) == 0 ) 1052 while( u ) 1053 { 1054 if( u->online ) 1055 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); 1056 u = u->next; 1057 } 1058 else if( ( c = conv_findchannel( channel ) ) ) 1059 for( l = c->in_room; l; l = l->next ) 1060 { 1061 if( ( u = user_findhandle( c->gc, l->data ) ) ) 1062 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname ); 1063 } 1064 else if( ( u = user_find( irc, channel ) ) ) 1065 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname ); 1066 1067 irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" ); 673 int irc_check_login( irc_t *irc ) 674 { 675 if( irc->user && irc->nick ) 676 { 677 if( global.conf->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED ) 678 { 679 irc_reply( irc, 464, ":This server is password-protected." ); 680 return 0; 681 } 682 else 683 { 684 irc_login( irc ); 685 return 1; 686 } 687 } 688 else 689 { 690 /* More information needed. */ 691 return 0; 692 } 1068 693 } 1069 694 … … 1075 700 irc_reply( irc, 2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost ); 1076 701 irc_reply( irc, 3, ":%s", IRCD_INFO ); 1077 irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES , CMODES );702 irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES ); 1078 703 irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 ); 1079 704 irc_motd( irc ); 1080 irc_umode_set( irc, irc->myhost, "+" UMODE);705 irc_umode_set( irc, "+" UMODE, 1 ); 1081 706 1082 707 u = user_add( irc, irc->mynick ); … … 1100 725 u->realname = g_strdup( irc->realname ); 1101 726 u->online = 1; 1102 // u->send_handler = msg_echo;1103 727 irc_spawn( irc, u ); 1104 728 1105 729 irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQ's are answered there." ); 730 731 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 732 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); 1106 733 1107 734 irc->status = USTATUS_LOGGED_IN; … … 1156 783 } 1157 784 irc_reply( irc, 376, ":End of MOTD" ); 1158 close socket( fd );785 close( fd ); 1159 786 } 1160 787 } … … 1177 804 } 1178 805 1179 void irc_whois( irc_t *irc, char *nick ) 1180 { 1181 user_t *u = user_find( irc, nick ); 1182 1183 if( u ) 1184 { 1185 irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname ); 1186 1187 if( u->gc ) 1188 irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username, 1189 *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name ); 1190 else 1191 irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); 1192 1193 if( !u->online ) 1194 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" ); 1195 else if( u->away ) 1196 irc_reply( irc, 301, "%s :%s", u->nick, u->away ); 1197 1198 irc_reply( irc, 318, "%s :End of /WHOIS list", nick ); 1199 } 1200 else 1201 { 1202 irc_reply( irc, 401, "%s :Nick does not exist", nick ); 1203 } 1204 } 1205 1206 1207 void irc_umode_set( irc_t *irc, char *who, char *s ) 1208 { 806 void irc_umode_set( irc_t *irc, char *s, int allow_priv ) 807 { 808 /* allow_priv: Set to 0 if s contains user input, 1 if you want 809 to set a "privileged" mode (+o, +R, etc). */ 1209 810 char m[256], st = 1, *t; 1210 811 int i; … … 1219 820 if( *t == '+' || *t == '-' ) 1220 821 st = *t == '+'; 1221 else 822 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) ) 1222 823 m[(int)*t] = st; 1223 824 } … … 1226 827 1227 828 for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ ) 1228 if( m[i] && strchr( UMODES, i ))829 if( m[i] ) 1229 830 irc->umode[strlen(irc->umode)] = i; 1230 831 1231 832 irc_reply( irc, 221, "+%s", irc->umode ); 1232 }1233 1234 int irc_away( irc_t *irc, char *away )1235 {1236 user_t *u = user_find( irc, irc->nick );1237 GSList *c = get_connections();1238 1239 if( !u ) return( 0 );1240 1241 if( away && *away )1242 {1243 int i, j;1244 1245 /* Copy away string, but skip control chars. Mainly because1246 Jabber really doesn't like them. */1247 u->away = g_malloc( strlen( away ) + 1 );1248 for( i = j = 0; away[i]; i ++ )1249 if( ( u->away[j] = away[i] ) >= ' ' )1250 j ++;1251 u->away[j] = 0;1252 1253 irc_reply( irc, 306, ":You're now away: %s", u->away );1254 /* irc_umode_set( irc, irc->myhost, "+a" ); */1255 }1256 else1257 {1258 if( u->away ) g_free( u->away );1259 u->away = NULL;1260 /* irc_umode_set( irc, irc->myhost, "-a" ); */1261 irc_reply( irc, 305, ":Welcome back" );1262 }1263 1264 while( c )1265 {1266 if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN )1267 proto_away( c->data, u->away );1268 1269 c = c->next;1270 }1271 1272 return( 1 );1273 833 } 1274 834 … … 1324 884 } 1325 885 g_free( nick ); 1326 }1327 1328 void irc_invite( irc_t *irc, char *nick, char *channel )1329 {1330 struct conversation *c = conv_findchannel( channel );1331 user_t *u = user_find( irc, nick );1332 1333 if( u && c && ( u->gc == c->gc ) )1334 if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite )1335 {1336 c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle );1337 irc_reply( irc, 341, "%s %s", nick, channel );1338 return;1339 }1340 1341 irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );1342 886 } 1343 887 … … 1430 974 1431 975 if( u->send_handler ) 1432 return( u->send_handler( irc, u, s, flags ) ); 976 { 977 u->send_handler( irc, u, s, flags ); 978 return 1; 979 } 1433 980 } 1434 981 else if( c && c->gc && c->gc->prpl ) … … 1456 1003 } 1457 1004 1458 intbuddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )1459 { 1460 if( !u || !u->gc ) return ( 0 );1005 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) 1006 { 1007 if( !u || !u->gc ) return; 1461 1008 1462 1009 if( set_getint( irc, "buddy_sendbuffer" ) && set_getint( irc, "buddy_sendbuffer_delay" ) > 0 ) … … 1494 1041 g_source_remove( u->sendbuf_timer ); 1495 1042 u->sendbuf_timer = g_timeout_add( delay, buddy_send_handler_delayed, u ); 1496 1497 return( 1 );1498 1043 } 1499 1044 else 1500 1045 { 1501 return( serv_send_im( irc, u, msg, flags ));1046 serv_send_im( irc, u, msg, flags ); 1502 1047 } 1503 1048 } … … 1604 1149 if( rv > 0 ) 1605 1150 { 1606 irc_write( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv ); 1607 irc_free( irc ); 1151 irc_abort( irc, 0, "Ping Timeout: %d seconds", rv ); 1608 1152 return FALSE; 1609 1153 }
Note: See TracChangeset
for help on using the changeset viewer.