muhstik- irc flooding solution |
git clone git://git.acid.vegas/muhstik.git |
Log | Files | Refs | Archive | README |
clone.c (35649B)
1 /* Muhstik, Copyright (C) 2001-2002, Louis Bavoil <mulder@gmx.fr> */ 2 /* 2003, roadr (bigmac@home.sirklabs.hu) */ 3 /* 2009-2011, Leon Kaiser <literalka@gnaa.eu> */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or */ 6 /* modify it under the terms of the GNU Library General Public License */ 7 /* as published by the Free Software Foundation; either version 2 */ 8 /* of the License, or (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 13 /* GNU Library General Public License for more details. */ 14 15 /* {{{ Header includes */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stdarg.h> 19 #include <unistd.h> 20 #include <time.h> 21 22 #include "../include/globals.h" 23 #include "../include/load.h" 24 #include "../include/control.h" 25 #include "../include/print.h" 26 #include "../include/proxy.h" 27 #include "../include/string.h" 28 #include "../include/lists.h" 29 #include "../include/net.h" 30 #include "../include/mass.h" 31 #include "../include/muhstik.h" 32 /* }}} */ 33 /* {{{ Variables */ 34 /* {{{ External variables */ 35 extern config_t conf; 36 extern char *hostname; 37 extern char *channel[]; 38 extern char *chankey[]; 39 extern int mass_ch; 40 extern char *mass_reas; 41 extern char *target; 42 extern int echo_mode; 43 extern const char *strtype[]; 44 /* }}} */ 45 /*{{{ Global variables */ 46 char *op_nick; 47 clone_t *cl[MAX_CLONES]; 48 char *broth[MAX_BROTHERS]; 49 queue public_queue; 50 queue names_op[MAX_CHANS]; 51 queue names[MAX_CHANS]; 52 time_t lastlock; 53 /* }}} */ 54 /* }}} */ 55 /*{{{ Function prototypes */ 56 /* {{{ void do_jupe(clone_t *clone, char *nick); */ 57 /** 58 * do_jupe() 59 * Function prototype for `do_jupe()'. 60 */ 61 void do_jupe(clone_t *clone, char *nick); 62 /* }}} */ 63 /* }}} */ 64 /* {{{ free()ing and closing functions */ 65 /* {{{ void close_sock(clone_t *clone) */ 66 void close_sock(clone_t *clone) 67 { 68 if (clone->sock != -1) 69 { 70 close(clone->sock); /* XXX: free()? -- Leon */ 71 } 72 } 73 /* }}} */ 74 /* {{{ void free_clone(clone_t *clone) */ 75 void free_clone(clone_t *clone) 76 { 77 int id = clone->id; 78 79 close_sock(clone); 80 81 /* Free the clone memory */ 82 free(clone->jupes); 83 free(clone->nick); 84 free(clone->ident); 85 free(clone->real); 86 free(clone->proxy); 87 free(clone->server); 88 free(clone->server_pass); 89 free(clone->server_ident); 90 free(clone->save); 91 clear_queue(&clone->queue); 92 free(clone); 93 94 /* Free its slot */ 95 cl[id] = NULL; 96 } 97 /* }}} */ 98 /* }}} */ 99 /* {{{ faux boolean functions */ 100 /* {{{ int not_a_clone(char *s) */ 101 /** 102 * not_a_clone() 103 * @return boolean value representing whether or not the nick is a clone 104 * controlled by this muhstik iteration. 105 */ 106 int not_a_clone(char *s) 107 { 108 register int i; 109 clone_t **pcl; 110 char **pt; 111 112 for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl) 113 { 114 if (*pcl && !StrCompare((*pcl)->nick, s)) 115 { 116 return 0; 117 } 118 } 119 120 for (i = 0, pt = broth; i < MAX_BROTHERS; ++i, ++pt) 121 { 122 if (*pt && !StrCompare(*pt, s)) 123 { 124 return 0; 125 } 126 } 127 128 return 1; 129 } 130 /* }}} */ 131 /* {{{ int not_a_mast(char *s) */ 132 int not_a_mast(char *s) 133 { 134 register int i; 135 char **pm; 136 137 for (i = 0, pm = conf.prot; i < MAX_PROTS; ++i, ++pm) 138 { 139 if (*pm && !StrCompare(*pm, s)) 140 { 141 return 0; 142 } 143 } 144 145 return 1; 146 } 147 /* }}} */ 148 /* {{{ int is_enemy(char *s) */ 149 /** 150 * is_enemy() 151 * @return boolean value representing whether or not the nickname `s' is neither 152 * a clone nor a master. 153 */ 154 int is_enemy(char *s) 155 { 156 return (not_a_clone(s) && not_a_mast(s)); 157 } 158 /* }}} */ 159 /* {{{ int is_op(clone_t *clone, int chid) */ 160 /** 161 * is_op() 162 * @return boolean value representing whether or not `clone' is an op in channel 163 * `chid'. 164 */ 165 int is_op(clone_t *clone, int chid) 166 { 167 return (clone && clone->online && clone->op[chid]); 168 } 169 /* }}} */ 170 /* }}} */ 171 /* {{{ Functions for opped clones */ 172 /* {{{ void op(clone_t *clone, int chid, char *s) */ 173 /** 174 * op() 175 * Op the nick `s' in the channel with channelid `chid' assigned to it. 176 */ 177 void op(clone_t *clone, int chid, char *s) 178 { 179 send2server(clone, "MODE %s +o %s\n", channel[chid], s); 180 } 181 /* }}} */ 182 /* {{{ void deop(clone_t *clone, int chid, char *nick) */ 183 /** 184 * deop() 185 * Deop the nick `s' in the channel with channelid `chid' assigned to it. 186 */ 187 void deop(clone_t *clone, int chid, char *nick) 188 { 189 send2server(clone, "MODE %s -o %s\n", channel[chid], nick); 190 } 191 /* }}} */ 192 /* {{{ int deop_enemy(clone_t *clone, int chid, char *nick) */ 193 /** 194 * deop_enemy() 195 * Deop enemy nick `nick' in channel with channelid `chid' assigned to it. 196 * @return boolean indicating success of the deopping. 197 */ 198 int deop_enemy(clone_t *clone, int chid, char *nick) 199 { 200 /* Don't try to deop a server */ 201 if (!nick[0]) 202 { 203 return 1; 204 } 205 206 if (is_enemy(nick)) 207 { 208 deop(clone, chid, nick); 209 return 1; 210 } 211 212 return 0; 213 } 214 /* }}} */ 215 /* {{{ void kick(clone_t *clone, int chid, char *s, char *reas, int mode) */ 216 /** 217 * kick() 218 * Kick the nick `s' from the channel with channelid `chid' with reason `reas'. 219 */ 220 void kick(clone_t *clone, int chid, char *s, char *reas, int mode) 221 { 222 char tmp[BIGBUF]; 223 224 snprintf(tmp, sizeof(tmp), "KICK %s %s :%s\n", channel[chid], s, reas ? reas : KICK_REAS); 225 if (!mode) 226 { 227 send_sock(clone->sock, "%s", tmp); 228 } 229 else 230 { 231 send2server(clone, "%s", tmp); 232 } 233 } 234 /* }}} */ 235 /* {{{ void ban(clone_t *clone, int chid, char *s, int mode) */ 236 /** 237 * ban() 238 * Ban host `s' from channel with channelid `chid' assigned to it. 239 */ 240 void ban(clone_t *clone, int chid, char *s, int mode) 241 { 242 char tmp[BIGBUF]; 243 244 sscanf(s, "%*[^@]@%s", s); 245 snprintf(tmp, sizeof(tmp), "MODE %s +b *!*@%s\n", channel[chid], s); 246 247 if (!mode) 248 { 249 send_sock(clone->sock, "%s", tmp); 250 } 251 else 252 { 253 send2server(clone, "%s", tmp); 254 } 255 } 256 /* }}} */ 257 /* {{{ void kickban(clone_t *clone, char *s) */ 258 void kickban(clone_t *clone, char *s) 259 { 260 send_sock(clone->sock, "WHOIS %s\n", s); 261 clone->wait_whois = 1; 262 } 263 /* }}} */ 264 /* {{{ void unban(clone_t *clone, int chid, char *s) */ 265 /** 266 * unban() 267 * Unban host `s' from the channel with channelid `chid' assigned to it. 268 */ 269 void unban(clone_t *clone, int chid, char *s) 270 { 271 send_sock(clone->sock, "MODE %s -b %s\n", channel[chid], s); 272 } 273 /* }}} */ 274 /* }}} */ 275 /* {{{ Misc clone->IRC communication functions */ 276 /* {{{ void join(clone_t *clone, char *dest) */ 277 /** 278 * join() 279 * Join channel `dest'. 280 */ 281 void join(clone_t *clone, char *dest) 282 { 283 int chid; 284 285 if ((chid = getchid(dest)) == -1) 286 { 287 return; 288 } 289 290 clone->op[chid] = 0; 291 clone->needop[chid] = 0; 292 293 if (chankey[chid] == NULL) 294 { 295 send_sock(clone->sock, "JOIN %s\n", dest); 296 } 297 else 298 { 299 send_sock(clone->sock, "JOIN %s :%s\n", dest, chankey[chid]); 300 } 301 } 302 /* }}} */ 303 /* {{{ void echo(clone_t *clone, char *chan, char *buf) */ 304 void echo(clone_t *clone, char *chan, char *buf) 305 { 306 register int i; 307 char **pchan; 308 309 if (echo_mode == 0) 310 { 311 /* Echo the to the current channel */ 312 send_sock(clone->sock, "PRIVMSG %s %s", chan, buf); 313 } 314 else 315 { 316 /* Echo to all the active channels */ 317 for (i = 0, pchan = channel; i < MAX_CHANS; ++i, ++pchan) 318 { 319 if (*pchan) 320 { 321 send_sock(clone->sock, "PRIVMSG %s %s", *pchan, buf); 322 } 323 } 324 } 325 } 326 /* }}} */ 327 /* {{{ void send_irc_nick(clone_t *clone, char *nick) */ 328 /** 329 * send_irc_nick() 330 * Change `clone's nick to `nick'. 331 */ 332 void send_irc_nick(clone_t *clone, char *nick) 333 { 334 send_sock(clone->sock, "NICK %s\n", nick); 335 } 336 /* }}} */ 337 /* }}} */ 338 /* {{{ Functions for initializing clones */ 339 /* {{{ void register_clone(clone_t *clone) */ 340 void register_clone(clone_t *clone) 341 { 342 char *ident; 343 344 if (clone->server_ident) 345 { 346 ident = clone->server_ident; 347 } 348 else 349 { 350 ident = clone->ident; 351 } 352 353 send_sock(clone->sock, "USER %s 0 0 :%s\n", ident, clone->real); 354 355 if (clone->server_pass) 356 { 357 send_sock(clone->sock, "PASS %s\n", clone->server_pass); 358 } 359 360 send_sock(clone->sock, "MODE %s +i\n", clone->nick); 361 } 362 /* }}} */ 363 /* {{{ int main_clone(void *arg) */ 364 int main_clone(void *arg) 365 { 366 clone_t *clone; 367 clone = (clone_t *) arg; 368 369 if (conf.debug) 370 { 371 if (clone->type != NOSPOOF) 372 { 373 print(1, 0, 0, "%s launched: host=%s server=%s", strtype[clone->type], clone->proxy, clone->server); 374 } 375 else 376 { 377 print(1, 0, 0, "direct connection launched: server=%s", clone->server); 378 } 379 } 380 381 if (clone->type == NOSPOOF || clone->type == VHOST) 382 { 383 if (connect_clone(clone, clone->server, clone->server_port)) 384 { 385 return 1; 386 } 387 } 388 else 389 { 390 if (connect_clone(clone, clone->proxy, clone->proxy_port)) 391 { 392 return 1; 393 } 394 } 395 396 clone->status = WAIT_CONNECT; 397 return 0; 398 } 399 /* }}} */ 400 /* }}} */ 401 /* {{{ Functions for parsing and acting on that parsing */ 402 /* {{{ int parse_deco(clone_t *clone, char *buf) */ 403 int parse_deco(clone_t *clone, char *buf) 404 { 405 if (!clone->online) 406 { 407 if (!StrCmpPrefix(buf, "ERROR")) 408 { 409 if (strstr(buf, "Too many user connections") || strstr(buf, "Too many host connections") || 410 strstr(buf, "Too many connections") || strstr(buf, "This server is full") || strstr(buf, "Invalid username")) /* 468 = invalidusername */ 411 { 412 if (clone->save) 413 { 414 save_host(clone); 415 } 416 } 417 } 418 if (conf.debug) 419 { 420 print_prefix(clone, 4, 0); 421 print(0, 4, 0, "%s", buf); 422 } 423 return 1; 424 } 425 426 clone->online = 0; 427 428 if (conf.verbose) 429 { 430 print_prefix(clone, 4, 0); 431 print(0, 4, 0, "%s", buf); 432 } 433 434 if (conf.max_reco < 0 || clone->reco < conf.max_reco) 435 { 436 if (conf.verbose) 437 { 438 print_prefix(clone, 0, 0); 439 print(1, 0, 0, "is trying to reconnect"); 440 } 441 clone->alarm = time(NULL) + conf.wait_reco; 442 if (conf.max_reco > 0) 443 { 444 ++clone->reco; 445 } 446 close_sock(clone); 447 main_clone(clone); 448 return 0; 449 } 450 451 return 1; 452 } 453 /* }}} */ 454 /* {{{ void save_host(clone_t *clone) */ 455 void save_host(clone_t *clone) 456 { 457 FILE *f; 458 char ip[MEDBUF]; 459 char line[MEDBUF]; 460 461 if (clone->type == NOSPOOF) 462 { 463 return; 464 } 465 466 host2ip(ip, clone->proxy, sizeof(ip)); 467 468 if (clone->type == PROXY || clone->type == SOCKS4 || clone->type == SOCKS5) 469 { 470 snprintf(line, sizeof(line), "%s:%d\n", ip, clone->proxy_port); 471 } 472 else 473 { 474 snprintf(line, sizeof(line), "%s\n", ip); 475 } 476 477 if (!occur_file(line, clone->save) && (f = fopen(clone->save, "a+"))) 478 { 479 fputs(line, f); 480 fclose(f); 481 } 482 } 483 /* }}} */ 484 /* {{{ void parse_irc_connect(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 485 void parse_irc_connect(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 486 { 487 int chid; 488 489 if (clone->save) 490 { 491 save_host(clone); 492 } 493 494 if (clone->type != NOSPOOF) 495 { 496 print(1, 3, 0, "clone available: nick=%s; %s=%s; server=%s", clone->nick, strtype[clone->type], clone->proxy, clone->server); 497 } 498 else 499 { 500 print(1, 3, 0, "clone available: nick=%s; server=%s", clone->nick, clone->server); 501 } 502 503 if (conf.scan || clone->mode == M_QUIT) 504 { 505 free_clone(clone); 506 return; 507 } 508 509 clone->online = 1; 510 511 if (clone->mode == M_NORMAL) 512 { 513 for (chid = 0; chid < MAX_CHANS; ++chid) 514 { 515 if (channel[chid]) 516 { 517 join(clone, channel[chid]); 518 } 519 } 520 } 521 } 522 /* }}} */ 523 /* {{{ Jupe functions */ 524 /* {{{ void parse_irc_isupport(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 525 void parse_irc_isupport(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 526 { 527 char *mspec_str = NULL; 528 529 if (NULL != (mspec_str = strstr(buf, "MONITOR="))) 530 { 531 sscanf(mspec_str, "MONITOR=%u", &(clone->monitor_tmax)); 532 if (0 == clone->monitor_tmax) 533 { 534 return; 535 } 536 537 clone->jupes = xmalloc((conf.nick_length + 1) * clone->monitor_tmax); 538 bzero(clone->jupes, (conf.nick_length + 1) * clone->monitor_tmax); 539 } 540 } 541 /* }}} */ 542 /* {{{ void parse_irc_moffline(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 543 void parse_irc_moffline(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 544 { 545 char *pnick0 = buf; 546 char *pnick = pnick0; 547 548 if(!((NULL != (pnick0 = strchr(pnick0, ':'))) && *(++pnick0))) 549 { 550 return; 551 } 552 553 pnick = pnick0; 554 strsep(&(pnick0), "\r\n"); 555 pnick0 = pnick; 556 557 while(NULL != (pnick = strsep(&(pnick0), ","))) 558 { 559 do_jupe(clone, pnick); 560 } 561 } 562 /* }}} */ 563 /* {{{ void do_jupe(clone_t *clone, char *nick) */ 564 void do_jupe(clone_t *clone, char *nick) 565 { 566 int i; 567 clone_t **pcl; 568 569 if (occur_table(nick, conf.juping, MAX_JUPES)) 570 { 571 return; 572 } 573 574 print_prefix(clone, 0, 0); 575 print(1, 0, 0, "nickname `%s' is available, trying to grab", nick); 576 577 for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl) 578 { 579 if ((*pcl) && (*pcl)->online && (*pcl)->grabbing == 0) 580 { 581 send_irc_nick((*pcl), nick); 582 print_prefix((*pcl), 0, 0); 583 print(1, 0, 0, "Nice nick, I think I'll take it."); 584 (*pcl)->grabbing = 1; 585 add_table(nick, conf.juping, MAX_JUPES); 586 return; 587 } 588 } 589 590 print_prefix(clone, 0, 0); 591 print(1, 0, 0, "no clones left that aren't juping", nick); 592 } 593 /* }}} */ 594 /* }}} */ 595 /* {{{ void parse_irc_kickban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 596 void parse_irc_kickban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 597 { 598 char *toban; 599 char *tokick; 600 601 if (!clone->wait_whois) 602 { 603 return; 604 } 605 606 clone->lastsend = time(NULL); 607 clone->wait_whois = 0; 608 609 strsep(&buf, DELIM); 610 if (!(tokick = strsep(&buf, DELIM))) 611 { 612 return; 613 } 614 615 strsep(&buf, DELIM); 616 if (!(toban = strsep(&buf, DELIM))) 617 { 618 return; 619 } 620 621 ban(clone, mass_ch, toban, 0); 622 kick(clone, mass_ch, tokick, mass_reas ? mass_reas : NULL, 0); 623 } 624 /* }}} */ 625 /* {{{ void parse_irc_nick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 626 void parse_irc_nick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 627 { 628 char *dest; 629 int chid; 630 631 strsep(&buf, ":"); 632 if (!(dest = strsep(&buf, DELIM))) 633 { 634 return; 635 } 636 637 if (!StrCompare(nick, clone->nick)) 638 { 639 StrCopy(clone->nick, dest, conf.nick_length+1); 640 } 641 642 if (target && !StrCompare(nick, target)) 643 { 644 free(target); 645 target = StrDuplicate(dest); 646 } 647 648 update_table(nick, dest, broth, MAX_BROTHERS); 649 update_table(nick, dest, conf.prot, MAX_PROTS); 650 651 update_pattern_table(nick, dest, conf.aop, MAX_AOPS); 652 653 for (chid = 0; chid < MAX_CHANS; ++chid) 654 { 655 update_queue(nick, dest, &names[chid]); 656 update_queue(nick, dest, &names_op[chid]); 657 } 658 } 659 /* }}} */ 660 /* {{{ void parse_irc_control(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 661 void parse_irc_control(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 662 { 663 char buffer[BIGBUF]; 664 char is_aop; 665 666 snprintf(buffer, sizeof(buffer), "%s %s %s %s", from, cmd, clone->nick, buf); 667 is_aop = (match_table(from, conf.aop, MAX_AOPS) != -1); 668 669 if (is_aop && conf.notice) 670 { 671 if (conf.verbose) 672 { 673 print(0, 5, 0, "%s", buffer); 674 } 675 buf = strstr(buffer, " :") + 2; /* don't interfere with IPv6 IP */ 676 op_nick = StrDuplicate(nick); 677 interpret(buf, -clone->id - 2); 678 } 679 } 680 /* }}} */ 681 /* {{{ void parse_irc_notice(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 682 void parse_irc_notice(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 683 { 684 char parm[MINIBUF]; 685 strsep(&buf, DELIM); 686 687 /* Skip mIRC DCC info */ 688 if (!StrParam(parm, sizeof(parm), buf, 0)) 689 { 690 if (!StrCompare(parm, ":dcc")) 691 { 692 return; 693 } 694 } 695 696 parse_irc_control (clone, cmd, nick, from, buf); 697 } 698 /* }}} */ 699 /* {{{ void parse_irc_privmsg(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 700 void parse_irc_privmsg(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 701 { 702 int chid; 703 char *dest; 704 char *parm; 705 706 dest = strsep(&buf, DELIM); 707 if (!StrCompare(dest, clone->nick)) 708 { 709 parse_irc_control(clone, cmd, nick, from, buf); 710 return; 711 } 712 713 if (target && !StrCompare(nick,target)) 714 { 715 echo(clone, dest, buf); 716 return; 717 } 718 719 if ((chid = getchid(dest)) == -1) 720 { 721 return; 722 } 723 724 if (conf.aggressive && is_enemy(nick)) 725 { 726 kick(clone, chid, nick, NULL, 1); 727 return; 728 } 729 730 if (!(parm = strsep(&buf, DELIM))) 731 { 732 return; 733 } 734 735 if (!StrCompare(parm,":!op")) 736 { 737 if (match_table(from, conf.aop, MAX_AOPS) != -1) 738 { 739 if (clone->op[chid]) 740 { 741 op(clone, chid, nick); 742 } 743 } 744 } 745 } 746 /* }}} */ 747 /* {{{ void join_scan(scan_t *scan, char *from) */ 748 void join_scan(scan_t *scan, char *from) 749 { 750 char *host; 751 char ip[MINIBUF]; 752 char line[MEDBUF]; 753 754 if (!(host = strchr(from, '@'))) 755 { 756 return; 757 } 758 759 host2ip(ip, ++host, sizeof(ip)); 760 761 if (scan->type == PROXY) 762 { 763 snprintf(line, sizeof(line), "%s:%d\n", ip, scan->proxy_port); 764 } 765 else 766 { 767 snprintf(line, sizeof(line), "%s\n", ip); 768 } 769 770 if (!occur_file(line, scan->save)) 771 { 772 load_host(scan->type, host, scan->proxy_port, scan->server, scan->server_port, NULL, NULL, scan->save, scan->mode); 773 } 774 } 775 /* }}} */ 776 /* {{{ void parse_irc_join(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 777 void parse_irc_join(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 778 { 779 int i; 780 int is_aop; 781 int chid; 782 char *chan; 783 char *reas; 784 785 strsep(&buf, ":"); 786 chan = strsep(&buf, DELIM); 787 788 if ((chid = getchid(chan)) == -1) 789 { 790 return; 791 } 792 793 if (!StrCompare(nick, clone->nick)) 794 { 795 if (!clone->restricted) 796 { 797 clone->needop[chid] = 1; 798 } 799 return; 800 } 801 802 is_aop = (match_table(from, conf.aop, MAX_AOPS) != -1); 803 if (is_aop && !occur_table(nick, conf.prot, MAX_PROTS)) 804 { 805 if (add_table(nick, conf.prot, MAX_PROTS) != -1) 806 { 807 if (conf.verbose) 808 { 809 print(1, 0, 0, "%s added to the protected nicks (aop)", nick); 810 } 811 } 812 } 813 814 uniq_add_queue(nick, &names[chid]); 815 816 if (clone->op[chid]) 817 { 818 if (is_aop || !not_a_clone(nick)) 819 { 820 op(clone, chid, nick); 821 return; 822 } 823 if ((i = match_table(from, conf.shit, MAX_SHITS)) != -1) 824 { 825 ban(clone, chid, from, 1); 826 if ((reas = strchr(conf.shit[i], ':'))) 827 { 828 kick(clone, chid, nick, reas+1, 1); 829 } 830 else 831 { 832 kick(clone, chid, nick, SHIT_REAS, 1); 833 } 834 return; 835 } 836 } 837 838 if (clone->scan) 839 { 840 join_scan(clone->scan, from); 841 } 842 } 843 /* }}} */ 844 /* {{{ void parse_irc_error_invite(clone_t *clone, int chid) */ 845 void parse_irc_error_invite(clone_t *clone, int chid) 846 { 847 clone_t *one; 848 849 if ((one = getop(chid))) 850 { 851 send_sock(one->sock, "INVITE %s %s\n", clone->nick, channel[chid]); 852 } 853 } 854 /* }}} */ 855 /* {{{ void parse_irc_error(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 856 void parse_irc_error(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 857 { 858 int chid; 859 char *chan; 860 char buffer[BIGBUF]; 861 862 snprintf(buffer, sizeof(buffer), "%s %s %s", from, cmd, buf); 863 864 if (conf.verbose) 865 { 866 print(0, 5, 0, "%s", buffer); 867 } 868 869 if (!StrCompare(cmd,"484")) /* ischanservice */ 870 { 871 clone->restricted = 1; 872 return; 873 } 874 875 strsep(&buf, DELIM); 876 chan = strsep(&buf, DELIM); 877 878 if ((chid = getchid(chan)) == -1) 879 { 880 return; 881 } 882 883 if (!StrCompare(cmd,"471") || !StrCompare(cmd,"473")) /* +l or +i */ 884 { 885 parse_irc_error_invite(clone, chid); 886 } 887 888 if (!StrCompare(cmd,"372") || !StrCompare(cmd,"375") || !StrCompare(cmd,"376")) /* MOTD numerics. */ 889 { 890 return; /* These errors would otherwise kill good clones. */ 891 } 892 893 clone->alarm = time(NULL) + conf.rejoin; 894 895 if (occur_table(channel[chid], channel, MAX_CHANS)) 896 { 897 join(clone, channel[chid]); 898 } 899 } 900 /* }}} */ 901 /* {{{ void parse_irc_kick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 902 void parse_irc_kick(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 903 { 904 int chid; 905 char *chan; 906 char *kicked; 907 908 chan = strsep(&buf, DELIM); 909 kicked = strsep(&buf, DELIM); 910 911 if ((chid = getchid(chan)) == -1) 912 { 913 return; 914 } 915 916 remove_queue(kicked, &names_op[chid]); 917 remove_queue(kicked, &names[chid]); 918 919 if (!StrCompare(kicked, clone->nick)) 920 { 921 clone->op[chid] = 0; 922 clone->needop[chid] = 0; 923 join(clone, channel[chid]); 924 } 925 else if (!conf.peace && clone->op[chid]) 926 { 927 if (!conf.aggressive) 928 { 929 deop_enemy(clone, chid, nick); 930 } 931 else 932 { 933 massdeop(clone, chid); 934 } 935 } 936 } 937 /* }}} */ 938 /* {{{ void parse_irc_part(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 939 void parse_irc_part(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 940 { 941 char *chan; 942 int chid; 943 944 chan = strsep(&buf, DELIM); 945 if ((chid = getchid(chan)) == -1) 946 { 947 return; 948 } 949 950 remove_queue(nick, &names_op[chid]); 951 remove_queue(nick, &names[chid]); 952 } 953 /* }}} */ 954 /* {{{ void parse_irc_mode(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 955 void parse_irc_mode(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 956 { 957 int chid; 958 char *chan; 959 char *mode; 960 char *parm; 961 int i; 962 int x = 1; /* by default it's + */ 963 964 if (clone->restricted) 965 { 966 return; 967 } 968 969 chan = strsep(&buf, DELIM); 970 mode = strsep(&buf, DELIM); 971 972 if (!StrCompare(chan, clone->nick)) 973 { 974 return; 975 } 976 977 if ((chid = getchid(chan)) == -1) 978 { 979 return; 980 } 981 982 if (conf.aggressive && !clone->op[chid]) 983 { 984 clone->needop[chid] = 1; 985 } 986 987 for (i = 0; mode[i]; ++i) 988 { 989 switch (mode[i]) 990 { 991 case '+': 992 x = 1; 993 break; 994 case '-': 995 x = -1; 996 break; 997 case 'b': 998 case 'e': 999 case 'I': 1000 case 'k': 1001 case 'l': 1002 case 'h': /* do we really need this? */ 1003 case 'v': 1004 parm = strsep(&buf, DELIM); 1005 break; 1006 case 'o': 1007 parm = strsep(&buf, DELIM); 1008 if (x == 1) /* +o */ 1009 { 1010 uniq_add_queue(parm, &names_op[chid]); 1011 remove_queue(parm, &names[chid]); 1012 if (!clone->op[chid] && !StrCompare(clone->nick, parm)) 1013 { 1014 clone->op[chid] = 1; 1015 clone->needop[chid] = 0; 1016 massop(clone, chid); 1017 } 1018 if (!conf.aggressive && !conf.peace) 1019 { 1020 if (clone->op[chid] && deop_enemy(clone, chid, nick)) 1021 { 1022 if (is_enemy(parm)) 1023 { 1024 deop(clone, chid, parm); 1025 } 1026 } 1027 } 1028 } 1029 else /* -o */ 1030 { 1031 uniq_add_queue(parm, &names[chid]); 1032 remove_queue(parm, &names_op[chid]); 1033 if (clone->op[chid] && !StrCompare(clone->nick, parm)) 1034 { 1035 clone->op[chid] = 0; 1036 clone->needop[chid] = 1; 1037 } 1038 else if (clone->op[chid]) 1039 { 1040 if (!conf.aggressive && !conf.peace) 1041 { 1042 deop_enemy(clone, chid, nick); 1043 } 1044 if (StrCompare(nick, parm) && !is_enemy(parm)) 1045 { 1046 op(clone, chid, parm); 1047 } 1048 } 1049 } 1050 break; 1051 } 1052 } 1053 1054 if (conf.aggressive && !conf.peace && clone->op[chid]) 1055 { 1056 massdeop(clone, chid); 1057 } 1058 } 1059 /* }}} */ 1060 /* {{{ void parse_irc_names(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 1061 void parse_irc_names(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 1062 { 1063 int chid; 1064 char *chan; 1065 char parm[MINIBUF]; 1066 register int i; 1067 1068 strsep(&buf, DELIM); 1069 strsep(&buf, DELIM); 1070 chan = strsep(&buf, DELIM); 1071 strsep(&buf, ":"); 1072 1073 if ((chid = getchid(chan)) == -1) 1074 { 1075 return; 1076 } 1077 1078 for (i = 0; !StrParam(parm, sizeof(parm), buf, i); ++i) 1079 { 1080 if (parm[0] == '@') 1081 { 1082 uniq_add_queue(parm+1, &names_op[chid]); 1083 } 1084 else if (parm[0] == '+') 1085 { 1086 uniq_add_queue(parm+1, &names[chid]); 1087 } 1088 else 1089 { 1090 uniq_add_queue(parm, &names[chid]); 1091 } 1092 } 1093 1094 if (clone->restricted) 1095 { 1096 return; 1097 } 1098 1099 snprintf(parm, sizeof(parm), "@%s", clone->nick); 1100 if (is_in(parm, buf)) 1101 { 1102 clone->op[chid] = 1; 1103 clone->needop[chid] = 0; 1104 } 1105 } 1106 /* }}} */ 1107 /* {{{ void parse_irc_topic(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 1108 void parse_irc_topic(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 1109 { 1110 int chid; 1111 char *chan; 1112 1113 if (conf.peace) 1114 { 1115 return; 1116 } 1117 1118 chan = strsep(&buf, DELIM); 1119 if ((chid = getchid(chan)) == -1) 1120 { 1121 return; 1122 } 1123 1124 if (clone->op[chid]) 1125 { 1126 deop_enemy(clone, chid, nick); 1127 } 1128 } 1129 /* }}} */ 1130 /* {{{ void parse_irc_unban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 1131 void parse_irc_unban(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 1132 { 1133 char *chan; 1134 char *toban; 1135 int chid; 1136 1137 strsep(&buf, DELIM); 1138 chan = strsep(&buf, DELIM); 1139 1140 if ((chid = getchid(chan)) == -1) 1141 { 1142 return; 1143 } 1144 1145 if (!(toban = strsep(&buf, DELIM))) 1146 { 1147 return; 1148 } 1149 1150 unban(clone, chid, toban); 1151 } 1152 /* }}} */ 1153 /* {{{ void parse_irc_quit(clone_t *clone, char *cmd, char *nick, char *from, char *buf) */ 1154 void parse_irc_quit(clone_t *clone, char *cmd, char *nick, char *from, char *buf) 1155 { 1156 int chid; 1157 1158 if (!remove_table(nick, conf.prot, MAX_PROTS)) 1159 { 1160 if (conf.verbose) 1161 { 1162 print(1, 0, 0, "%s not protected anymore (quit)", nick); 1163 } 1164 } 1165 1166 for (chid = 0; chid < MAX_CHANS; ++chid) 1167 { 1168 remove_queue(nick, &names_op[chid]); 1169 remove_queue(nick, &names[chid]); 1170 } 1171 } 1172 /* }}} */ 1173 /* {{{ Constants */ 1174 #define IDENT1 "IDENTIFY" 1175 #define IDENT2 "choose another one" 1176 #define IDENT3 "Please choose a different nickname" 1177 /* }}} */ 1178 /* {{{ int nick_error(char *cmd, char *nick, char *buf) */ 1179 int nick_error(char *cmd, char *nick, char *buf) 1180 { 1181 if (conf.dalnet && !StrCompare(nick, "nickserv")) 1182 { 1183 if (strstr(buf, IDENT1) || strstr(buf, IDENT2) || strstr(buf, IDENT3)) 1184 { 1185 return 1; 1186 } 1187 } 1188 /* XXX: There *has* to be a better way to compact this. -- Leon */ 1189 if (!StrCompare(cmd, "431") || !StrCompare(cmd, "432") || !StrCompare(cmd, "433") || !StrCompare(cmd, "436") || !StrCompare(cmd, "437") || !StrCompare(cmd, "438")) 1190 { 1191 return 1; 1192 } 1193 1194 return 0; 1195 } 1196 /* }}} */ 1197 /* {{{ void parse_irc(clone_t *clone, char *buf) */ 1198 void parse_irc(clone_t *clone, char *buf) 1199 { 1200 char *from; 1201 char *parm; 1202 char nick[MINIBUF+1]; 1203 /* NOTE: 431, 432, 433, 436, 437, & 438 are covered by ``nick_error()'' */ 1204 static msg_t msg[] = 1205 { { "JOIN", parse_irc_join }, 1206 { "PART", parse_irc_part }, 1207 { "QUIT", parse_irc_quit }, 1208 { "NICK", parse_irc_nick }, 1209 { "PRIVMSG", parse_irc_privmsg }, 1210 { "NOTICE", parse_irc_notice }, 1211 { "KICK", parse_irc_kick }, 1212 { "MODE", parse_irc_mode }, 1213 { "TOPIC", parse_irc_topic }, 1214 { "001", parse_irc_connect }, 1215 { "005", parse_irc_isupport }, 1216 { "311", parse_irc_kickban }, 1217 { "353", parse_irc_names }, 1218 { "367", parse_irc_unban }, 1219 { "372", parse_irc_error }, 1220 { "471", parse_irc_error }, 1221 { "472", parse_irc_error }, 1222 { "473", parse_irc_error }, 1223 { "474", parse_irc_error }, 1224 { "475", parse_irc_error }, 1225 { "484", parse_irc_error }, 1226 { "731", parse_irc_moffline }, 1227 { NULL, NULL, } 1228 }; 1229 msg_t *pmsg; 1230 /* TODO: 1231 367 => "banlist", 1232 368 => "endofbanlist", 1233 404 => "cannotsendtochan", 1234 "INVITE"/"KILL" 1235 */ 1236 1237 if (!StrCmpPrefix(buf, "PING")) 1238 { 1239 buf[1] = 'O'; 1240 send(clone->sock, buf, strlen(buf), 0); 1241 return; 1242 } 1243 1244 if (!strsep(&buf, ":")) 1245 { 1246 return; 1247 } 1248 1249 if (!(from = strsep(&buf, DELIM))) 1250 { 1251 return; 1252 } 1253 1254 if (!(parm = strsep(&buf, DELIM))) 1255 { 1256 return; 1257 } 1258 1259 if (strchr(from, '!')) 1260 { 1261 sscanf(from, "%"MINIBUF_TXT"[^!]", nick); 1262 } 1263 else 1264 { 1265 nick[0] = 0; 1266 } 1267 1268 if (nick_error(parm, nick, buf)) 1269 { 1270 randget(clone, &clone->nick2, conf.nick_length, conf.use_wordlist, conf.nicks, MAX_NICKS); 1271 if (conf.verbose) 1272 { 1273 print(1, 0, 0, "nickname error for %s, changing to %s.", clone->nick, clone->nick2); 1274 } 1275 if (!clone->online) 1276 { 1277 StrCopy(clone->nick, clone->nick2, conf.nick_length+1); 1278 } 1279 send_irc_nick(clone, clone->nick2); 1280 free(clone->nick2); 1281 return; 1282 } 1283 1284 for (pmsg = msg; pmsg->parm; ++pmsg) 1285 { 1286 if (!StrCompare(parm, pmsg->parm)) 1287 { 1288 pmsg->function(clone, parm, nick, from, buf); 1289 return; 1290 } 1291 } 1292 } 1293 /* }}} */ 1294 /* }}} */ 1295 /* {{{ send_*() functions */ 1296 /* {{{ void send_join(char *buffer) */ 1297 void send_join(char *buffer) 1298 { 1299 register int id; 1300 clone_t **pcl; 1301 char *chan; 1302 1303 if (!strsep(&buffer, DELIM)) 1304 { 1305 return; 1306 } 1307 1308 if (!(chan=strsep(&buffer, DELIM))) 1309 { 1310 return; 1311 } 1312 1313 for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl) 1314 { 1315 if (*pcl && (*pcl)->online) 1316 { 1317 join(*pcl, chan); 1318 } 1319 } 1320 } 1321 /* }}} */ 1322 /* {{{ void send_nick() */ 1323 void send_nick() 1324 { 1325 register int id; 1326 clone_t **pcl; 1327 1328 for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl) 1329 { 1330 if (*pcl && (*pcl)->online && (*pcl)->grabbing == 0) 1331 { 1332 randget(*pcl, &(*pcl)->nick2, conf.nick_length, conf.use_wordlist, conf.nicks, MAX_NICKS); 1333 send_irc_nick(*pcl, (*pcl)->nick2); 1334 free((*pcl)->nick2); 1335 } 1336 } 1337 } 1338 /* }}} */ 1339 /* {{{ void send2clones(char *buffer) */ 1340 void send2clones(char *buffer) 1341 { 1342 register int id; 1343 clone_t **pcl; 1344 1345 if (!StrCmpPrefix(buffer, "join")) 1346 { 1347 send_join(buffer); 1348 } 1349 else if (!StrCmpPrefix(buffer, NICKS)) 1350 { 1351 send_nick(); 1352 } 1353 else 1354 { 1355 for (id = 0, pcl = cl; id < MAX_CLONES; ++id, ++pcl) 1356 { 1357 if (*pcl && (*pcl)->online) 1358 { 1359 send((*pcl)->sock, buffer, strlen(buffer), 0); 1360 } 1361 } 1362 } 1363 } 1364 /* }}} */ 1365 /* {{{ void send2server(clone_t *clone, const char *fmt, ...) */ 1366 void send2server(clone_t *clone, const char *fmt, ...) 1367 { 1368 static int lastlock = 0; 1369 clone_t **pcl; 1370 time_t now; 1371 int i; 1372 int j; 1373 int n; 1374 char tosend[BIGBUF]; 1375 va_list ap; 1376 1377 now = time(NULL); 1378 1379 /* Synchronization of the queues */ 1380 if (lastlock != now) 1381 { 1382 lastlock = now; 1383 clear_queue(&public_queue); 1384 1385 for (i = 0, pcl = cl; i < MAX_CLONES; ++i, ++pcl) 1386 { 1387 if (*pcl) 1388 { 1389 clear_queue(&(*pcl)->queue); 1390 } 1391 } 1392 } 1393 1394 va_start(ap, fmt); 1395 n = vsnprintf(tosend, sizeof(tosend), fmt, ap); 1396 va_end(ap); 1397 1398 /* Each clone has its own send queue. */ 1399 /* Before trying to send anything, it puts it in. */ 1400 add_queue(tosend, &clone->queue); 1401 1402 /* If the public queue has more occurences of the message, it has */ 1403 /* already been sent to IRC. */ 1404 i = occur_queue(tosend, &clone->queue) + conf.repeat; 1405 j = occur_queue(tosend, &public_queue); 1406 1407 if (i <= j) 1408 { 1409 return; 1410 } 1411 1412 add_queue(tosend, &public_queue); 1413 1414 send(clone->sock, tosend, strlen(tosend), 0); 1415 clone->lastsend = now; 1416 } 1417 /* }}} */ 1418 /* }}} */