ircc.c (18168B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #include <stdlib.h> 7 #include <string.h> 8 #include <stdio.h> 9 #include <stdarg.h> 10 #include <unistd.h> 11 #include <fcntl.h> 12 #include <time.h> 13 #include <pthread.h> 14 #include <netdb.h> 15 #include <sys/types.h> 16 #include <sys/socket.h> 17 #include <netinet/in.h> 18 #include <arpa/inet.h> 19 #include <openssl/bio.h> 20 #include <openssl/ssl.h> 21 #include <openssl/err.h> 22 #include "arg.h" 23 24 #define VERSION "ircc 3rd ed. Linux 1st ed." 25 #define nil NULL 26 27 int tls, debug, ignoreflood, anickused, havenickserv, doautojoin; 28 char *argv0, *lastchan, *clientinfo, *nick, *anick, *passwd; 29 30 typedef struct command command; 31 struct command { 32 char **params; 33 int len; 34 int isalloc; 35 }; 36 37 command *ignorel, *joinl; 38 39 void * 40 realloci(void *p, int i, int d) 41 { 42 43 p = realloc(p, i); 44 if(p == nil) { 45 perror("realloc"); 46 exit(1); 47 } 48 49 if(d != 0) 50 memset(p, 0, i); 51 52 return (void *)p; 53 } 54 55 int 56 swrite(void *sock, char *buf, int l) 57 { 58 int ret; 59 60 if(!tls) 61 ret = write(*(int *)sock, buf, l); 62 else { 63 ret = BIO_write((BIO *)sock, buf, l); 64 (void)BIO_flush((BIO *)sock); 65 } 66 67 return ret; 68 } 69 70 int 71 sread(void *sock, char *buf, int l) 72 { 73 int ret; 74 75 if(!tls) 76 ret = read(*(int *)sock, buf, l); 77 else { 78 ret = BIO_read((BIO *)sock, buf, l); 79 (void)BIO_flush((BIO *)sock); 80 } 81 82 return ret; 83 } 84 85 void 86 tprintf(void *sock, char *fmt, ...) 87 { 88 va_list fmtargs; 89 char buf[8192]; 90 91 va_start(fmtargs, fmt); 92 vsnprintf(buf, sizeof(buf) - 1, fmt, fmtargs); 93 va_end(fmtargs); 94 95 if(swrite(sock, buf, strlen(buf)) < 0) 96 perror("write"); 97 98 return; 99 } 100 101 int 102 connecttcp(char *host, char *service) 103 { 104 int sock; 105 struct addrinfo *ai, *a; 106 107 sock = -1; 108 109 if(getaddrinfo(host, service, nil, &ai) < 0) { 110 perror("getaddrinfo"); 111 return -1; 112 } 113 114 for(a = ai; a; a = a->ai_next) { 115 sock = socket(a->ai_family, a->ai_socktype, a->ai_protocol); 116 if(sock < 0) { 117 perror("socket"); 118 sock = -1; 119 break; 120 } 121 122 if(connect(sock, a->ai_addr, a->ai_addrlen) < 0) { 123 perror("connect"); 124 sock = -1; 125 break; 126 } else 127 break; 128 } 129 130 freeaddrinfo(ai); 131 132 return sock; 133 } 134 135 void 136 freecmd(command *cmd) 137 { 138 int i; 139 140 i = -1; 141 if(cmd != nil) { 142 if(cmd->isalloc) 143 while(++i < cmd->len) 144 if(cmd->params[i] != nil) 145 free(cmd->params[i]); 146 if(cmd->params != nil) 147 free(cmd->params); 148 free(cmd); 149 } 150 151 return; 152 } 153 154 int 155 addlist(command *c, char *p) 156 { 157 int i; 158 159 i = -1; 160 if(c != nil) { 161 if(c->isalloc) { 162 p = strdup(p); 163 while(++i < c->len) { 164 if(c->params[i] == nil) { 165 c->params[i] = p; 166 167 return 2; 168 } 169 } 170 } 171 172 c->len++; 173 c->params = realloc(c->params, sizeof(char *) * c->len); 174 c->params[c->len - 1] = p; 175 176 return 1; 177 } 178 179 return 0; 180 } 181 182 int 183 searchlist(command *c, char *p) 184 { 185 int i; 186 187 i = -1; 188 if(c != nil) 189 while(++i < c->len) 190 if(c->params[i] != nil) 191 if(!strcasecmp(c->params[i], p)) 192 return i; 193 194 return -1; 195 } 196 197 int 198 dellist(command *c, char *p) 199 { 200 int i; 201 202 if(c != nil) { 203 i = searchlist(c, p); 204 if(i != -1) { 205 free(c->params[i]); 206 c->params[i] = nil; 207 c->len--; 208 return 1; 209 } 210 } 211 212 return 0; 213 } 214 215 command * 216 parsecmd(command *cmd, char *data, int cmds) 217 { 218 command *ret; 219 char *next, *last, *temp; 220 221 temp = nil; 222 223 if(cmd == nil) { 224 ret = realloci(nil, sizeof(command), 2); 225 last = data; 226 } else { 227 ret = cmd; 228 if(ret->isalloc) { 229 temp = strdup(ret->params[ret->len - 1]); 230 dellist(ret, ret->params[ret->len - 1]); 231 } else { 232 ret->len--; 233 temp = ret->params[ret->len]; 234 } 235 last = temp; 236 } 237 while((next = strchr(last, ' ')) != nil && ret->len < cmds) { 238 *next = '\0'; 239 next++; 240 if(last[0] == ':') 241 last++; 242 addlist(ret, last); 243 last = next; 244 } 245 if(last[0] == ':') 246 last++; 247 if(last != nil) 248 addlist(ret, last); 249 250 if(temp != nil && cmd->isalloc) 251 free(temp); 252 253 return ret; 254 } 255 256 char * 257 mktimestamp(char bord, char bord_e) 258 { 259 time_t tim; 260 struct tm tm; 261 char *ret; 262 263 time(&tim); 264 localtime_r(&tim, &tm); 265 266 ret = malloc(31); 267 snprintf(ret, 30, "%c%.2d:%.2d%c", bord, tm.tm_hour, tm.tm_min, bord_e); 268 269 return ret; 270 } 271 272 void 273 setchan(char *new) 274 { 275 276 if(lastchan != nil) 277 free(lastchan); 278 279 lastchan = realloci(nil, strlen(new) + 1, 2); 280 strcpy(lastchan, new); 281 } 282 283 void 284 autojoin(void *sock) 285 { 286 int i; 287 288 for(i = 0; i < joinl->len; i++) 289 tprintf(sock, "JOIN %s\r\n", joinl->params[i]); 290 setchan(joinl->params[joinl->len - 1]); 291 } 292 293 int 294 gotcommand(void *sock, char *data, int len) 295 { 296 command *cmd; 297 char *last, *next, *send, *cpy, *test, *tmstmp; 298 int clen; 299 time_t tim; 300 301 clen = len; 302 last = data; 303 send = realloci(nil, 513, 2); 304 305 while((next = strchr(last, '\n')) != nil) { 306 *next++ = '\0'; 307 clen -= (next - last); 308 if(*(next - 2) == '\r') 309 *(next - 2) = '\0'; 310 311 cpy = strdup(last); 312 cmd = parsecmd(nil, last, 3); 313 tmstmp = mktimestamp('(', ')'); 314 315 if(cmd->len > 1) { 316 if(!strncasecmp(cmd->params[0], "PING", 4)) { 317 tprintf(sock, "PONG %s\r\n", cmd->params[1]); 318 goto c_end; 319 } 320 if(!strncasecmp(cmd->params[0], "ERROR", 5)) { 321 printf("%sERROR%% %s %s %s\n", tmstmp, cmd->params[1], cmd->params[2], cmd->params[3]); 322 goto c_end; 323 } 324 } 325 if(cmd->len > 2) { 326 if(!strncasecmp(cmd->params[1], "JOIN", 4)) { 327 printf("%s(%s) has joined %s\n", tmstmp, cmd->params[0], cmd->params[2]); 328 goto c_end; 329 } 330 if(!strncasecmp(cmd->params[1], "PART", 4)) { 331 printf("%s(%s) has parted %s\n", tmstmp, cmd->params[0], cmd->params[2]); 332 goto c_end; 333 } 334 if(!strncasecmp(cmd->params[1], "MODE", 4)) { 335 printf("%s(%s)-m-(%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]); 336 goto c_end; 337 } 338 if(!strncasecmp(cmd->params[1], "QUIT", 4)) { 339 printf("%s(%s) has quit (%s %s)\n", tmstmp, cmd->params[0], cmd->params[2], (cmd->len > 3) ? cmd->params[3] : ""); 340 goto c_end; 341 } 342 if((test = strchr(cmd->params[0], '!')) != nil) 343 *test = '\0'; 344 if(!strncasecmp(cmd->params[1], "NICK", 4)) { 345 printf("%s(%s) changed nick to %s\n", tmstmp, cmd->params[0], cmd->params[2]); 346 if(searchlist(ignorel, cmd->params[0]) != -1) { 347 dellist(ignorel, cmd->params[0]); 348 addlist(ignorel, cmd->params[2]); 349 } 350 goto c_end; 351 } 352 } 353 if(cmd->len > 3) { 354 if(strlen(cmd->params[1]) == 3) { 355 if(ignoreflood) { 356 if(!strncasecmp(cmd->params[1], "001", 3) || 357 !strncasecmp(cmd->params[1], "002", 3) || 358 !strncasecmp(cmd->params[1], "003", 3) || 359 !strncasecmp(cmd->params[1], "004", 3) || 360 !strncasecmp(cmd->params[1], "005", 3) || 361 !strncasecmp(cmd->params[1], "250", 3) || 362 !strncasecmp(cmd->params[1], "251", 3) || 363 !strncasecmp(cmd->params[1], "252", 3) || 364 !strncasecmp(cmd->params[1], "253", 3) || 365 !strncasecmp(cmd->params[1], "254", 3) || 366 !strncasecmp(cmd->params[1], "255", 3) || 367 !strncasecmp(cmd->params[1], "265", 3) || 368 !strncasecmp(cmd->params[1], "266", 3) || 369 !strncasecmp(cmd->params[1], "317", 3) || 370 !strncasecmp(cmd->params[1], "318", 3) || 371 !strncasecmp(cmd->params[1], "366", 3) || 372 !strncasecmp(cmd->params[1], "375", 3) || 373 !strncasecmp(cmd->params[1], "372", 3)) 374 goto c_end; 375 } 376 if(!strncasecmp(cmd->params[1], "376", 3)) { 377 if(doautojoin && (!havenickserv || anickused)) 378 autojoin(sock); 379 goto c_end; 380 } 381 382 printf("%s(%s)(%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[1], cmd->params[3]); 383 if(!strncasecmp(cmd->params[1], "433", 3) && anick != nil) { 384 if(anickused) { 385 printf("%s(IRCC)%% Sorry, but nick and anick are used. Try something different.\n", tmstmp); 386 goto c_end; 387 } 388 tprintf(sock, "NICK %s\r\n", anick); 389 anickused = 1; 390 } 391 goto c_end; 392 } 393 if(!strncasecmp(cmd->params[1], "INVITE", 6)) { 394 printf("%s(%s) invited you to %s\n", tmstmp, cmd->params[0], cmd->params[3]); 395 goto c_end; 396 } 397 if(!strncasecmp(cmd->params[1], "TOPIC", 5)) { 398 printf("%s(%s) topicchange in %s to \"%s\"\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]); 399 goto c_end; 400 } 401 if(!strncasecmp(cmd->params[1], "KICK", 4)) { 402 if(parsecmd(cmd, nil, 4) != nil) 403 printf("%s(%s) kicked %s out of %s \"%s\"\n", tmstmp, cmd->params[0], cmd->params[3], cmd->params[2], cmd->params[4]); 404 else 405 printf("%s(%s) kicked %s out of %s\n", tmstmp, cmd->params[0], cmd->params[3], cmd->params[2]); 406 goto c_end; 407 } 408 if(searchlist(ignorel, cmd->params[0]) == -1 && 409 searchlist(ignorel, cmd->params[2]) == -1) { 410 if(!strncasecmp(cmd->params[1], "NOTICE", 6)) { 411 printf("%s(%s|%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]); 412 if(!strncasecmp(cmd->params[0], "NickServ", 8) && havenickserv) { 413 printf("in case NickServ\n"); 414 tprintf(sock, "PRIVMSG NickServ :IDENTIFY %s\r\n", passwd); 415 memset(passwd, 0, strlen(passwd)); 416 havenickserv = 0; 417 if(doautojoin) 418 autojoin(sock); 419 } 420 goto c_end; 421 } 422 if(!strncasecmp(cmd->params[1], "PRIVMSG", 7)) { 423 if(*(cmd->params[3]) == '\x01') { 424 if(!strncasecmp(cmd->params[3]+1, "VERSION", 7)) 425 tprintf(sock, "NOTICE %s :\x01VERSION " VERSION "\x01\r\n", cmd->params[0]); 426 if(!strncasecmp(cmd->params[3]+1, "TIME", 4)) { 427 tim = time(0); 428 test = ctime(&tim); 429 test[strlen(test) - 1] = '\0'; 430 tprintf(sock, "NOTICE %s :\x01TIME %s\x01\r\n", cmd->params[0], test); 431 } 432 if(!strncasecmp(cmd->params[3]+1, "PING", 4)) 433 tprintf(sock, "NOTICE %s :\x01PONG %s\r\n", cmd->params[0], cmd->params[3]+6); 434 if(!strncasecmp(cmd->params[3]+1, "ACTION", 6)) { 435 *(cmd->params[3] + strlen(cmd->params[3])-1) = '\0'; 436 printf("%s(%s+%s) %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]+8); 437 goto c_end; 438 } 439 if(!strncasecmp(cmd->params[3]+1, "CLIENTINFO", 10)) 440 tprintf(sock, "NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01\r\n", cmd->params[0]); 441 if(!strncasecmp(cmd->params[3]+1, "USERINFO", 8)) 442 tprintf(sock, "NOTICE %s :\x01USERINFO %s\x01\r\n", cmd->params[0], (clientinfo != nil) ? clientinfo : "<nil>"); 443 } 444 printf("%s(%s-%s)%% %s\n", tmstmp, cmd->params[0], cmd->params[2], cmd->params[3]); 445 goto c_end; 446 } 447 if(!strncasecmp(cmd->params[0], "NOTICE", 6)) { 448 printf("%sNOTICE%% %s\n", tmstmp, cmd->params[3]); 449 goto c_end; 450 } 451 } else 452 goto c_end; 453 } 454 printf("%s\n",cpy); 455 c_end: 456 free(tmstmp); 457 free(cpy); 458 freecmd(cmd); 459 last = next; 460 } 461 462 if(clen > 0) 463 strcpy(data, data + len - clen); 464 if(send != nil) 465 free(send); 466 467 return clen; 468 } 469 470 void * 471 recvproc(void *sock) 472 { 473 char *recv; 474 int len, overl; 475 476 recv = realloci(nil, 1025, 2); 477 len = 1; 478 overl = 0; 479 480 while(len > 0 && sock != nil) { 481 len = sread(sock, recv + overl, 1024 - overl); 482 483 if(debug) 484 printf("%s\n", recv); 485 486 if(len > 1) 487 overl = gotcommand(sock, recv, len + overl); 488 } 489 490 free(recv); 491 492 return nil; 493 } 494 495 void 496 usage(void) 497 { 498 499 fprintf(stdout, "usage: %s [-dit] [-a anick] [-c clientinfo]" 500 " [-j #channel ...]" 501 " [-k passwd]" 502 " [-n nick] [-o port] [-p pass] [-u user]" 503 " server\n", 504 argv0); 505 506 exit(1); 507 } 508 509 int 510 main(int argc, char *argv[]) 511 { 512 void *sock; 513 int i, so; 514 char *send, *rad, *tmstmp, *user, *pass, *port; 515 command *cmd; 516 pthread_t th; 517 BIO *bio; 518 SSL_CTX *ctx; 519 SSL *ssl; 520 521 ctx = nil; 522 user = "root"; 523 pass = nil; 524 nick = "root"; 525 anick = nil; 526 port = nil; 527 tls = 0; 528 clientinfo = "The user has not specified his details."; 529 joinl = realloci(nil, sizeof(command), 2); 530 joinl->isalloc = 1; 531 532 ARGBEGIN { 533 case 'u': 534 user = EARGF(usage()); 535 break; 536 case 'p': 537 pass = EARGF(usage()); 538 break; 539 case 't': 540 tls = 1; 541 break; 542 case 'd': 543 debug = 1; 544 break; 545 case 'c': 546 clientinfo = EARGF(usage()); 547 break; 548 case 'i': 549 ignoreflood = 1; 550 break; 551 case 'n': 552 nick = EARGF(usage()); 553 break; 554 case 'o': 555 port = EARGF(usage()); 556 break; 557 case 'a': 558 anick = EARGF(usage()); 559 break; 560 case 'k': 561 havenickserv = 1; 562 passwd = EARGF(usage()); 563 break; 564 case 'j': 565 addlist(joinl, EARGF(usage())); 566 doautojoin = 1; 567 break; 568 default: 569 usage(); 570 } ARGEND; 571 572 573 if(argc < 1) 574 usage(); 575 576 if(!tls) { 577 so = connecttcp(argv[0], (port == nil)? "6667" : port); 578 if(so < 0) { 579 perror("connecttcp"); 580 exit(1); 581 } 582 583 sock = &so; 584 } else { 585 ERR_load_crypto_strings(); 586 SSL_library_init(); 587 588 ctx = SSL_CTX_new(SSLv23_client_method()); 589 if(ctx == nil) { 590 perror("SSL_CTX_new"); 591 ERR_print_errors_fp(stderr); 592 exit(1); 593 } 594 bio = BIO_new_ssl_connect(ctx); 595 if(bio == nil) { 596 perror("BIO_new_ssl_connect"); 597 ERR_print_errors_fp(stderr); 598 exit(1); 599 } 600 601 BIO_get_ssl(bio, &ssl); 602 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 603 604 BIO_set_conn_port(bio, (port == nil)? "994" : port); 605 BIO_set_conn_hostname(bio, argv[0]); 606 if(BIO_do_connect(bio) <= 0) { 607 perror("BIO_do_connect"); 608 ERR_print_errors_fp(stderr); 609 exit(1); 610 } 611 612 sock = bio; 613 } 614 615 if(user == nil) 616 user = nick; 617 618 if(pass != nil) 619 tprintf(sock, "PASS %s\r\n", pass); 620 tprintf(sock, "NICK %s\r\n", nick); 621 tprintf(sock, "USER %s localhost %s :%s\r\n", user, nick, user); 622 623 if(pthread_create(&th, nil, recvproc, sock) < 0) { 624 perror("pthread_create"); 625 exit(1); 626 } 627 628 ignorel = realloci(nil, sizeof(command), 2); 629 ignorel->isalloc = 1; 630 send = realloci(nil, 513, 2); 631 rad = realloci(nil, 513, 2); 632 633 while(sock > 0) { 634 i = -1; 635 cmd = nil; 636 memset(send, 0, 513); 637 memset(rad, 0, 513); 638 639 while(read(0, &rad[++i], 1) && i < 400 && sock != nil) { 640 if(rad[i] == '\n') { 641 rad[i] = '\0'; 642 break; 643 } 644 } 645 rad[i + 1] = '\0'; 646 647 tmstmp = mktimestamp('(', ')'); 648 if(rad[0] == '/') 649 cmd = parsecmd(nil, rad, 2); 650 651 if(cmd != nil) { 652 if(cmd->len > 0) { 653 switch(cmd->params[0][1]) { 654 case 'H': 655 case 'h': 656 printf("%s Help for ircc:\n", tmstmp); 657 printf("%s /a chan text - send /me text to chan\n", tmstmp); 658 printf("%s /c chan what - send CTCP what to chan\n", tmstmp); 659 printf("%s /d - turn debugging on or off\n", tmstmp); 660 printf("%s /h - show this help\n", tmstmp); 661 printf("%s /i chan - ignore/unignore chan\n", tmstmp); 662 printf("%s /j chan - join chan\n", tmstmp); 663 printf("%s /k user [readon] - kick a user\n", tmstmp); 664 printf("%s /l [chan] - list channels on server\n", tmstmp); 665 printf("%s /m chan text - send text to chan\n", tmstmp); 666 printf("%s /n nick - change nickname to nick\n", tmstmp); 667 printf("%s /o chan mode [user] - set mode on chan\n", tmstmp); 668 printf("%s /p chan - part chan\n", tmstmp); 669 printf("%s /q [msg] - quit ircc\n", tmstmp); 670 printf("%s /s chan - set active chan\n", tmstmp); 671 printf("%s /t chan [topic] - set/show topic of chan\n", tmstmp); 672 printf("%s /u chan - WHO of chan\n", tmstmp); 673 printf("%s /w chan - WHOIS of chan\n", tmstmp); 674 goto end_e; 675 case 'D': 676 case 'd': 677 if(debug) 678 debug = 0; 679 else 680 debug = 1; 681 printf("%s debug %d\n", tmstmp, debug); 682 goto end_e; 683 case 'Q': 684 case 'q': 685 sprintf(send, "QUIT :\r\n"); 686 if(cmd->len == 2) 687 sprintf(send + 6, "%s\r\n", cmd->params[1]); 688 if(cmd->len > 2) 689 sprintf(send + 6, "%s %s\r\n", cmd->params[1], cmd->params[2]); 690 swrite(sock, send, strlen(send)); 691 if(tls) 692 BIO_free_all(sock); 693 else 694 close(*(int *)sock); 695 sock = nil; 696 goto end_e; 697 case 'L': 698 case 'l': 699 sprintf(send, "LIST\r\n"); 700 if(cmd->len == 2) 701 sprintf(send + 4, " %s\r\n", cmd->params[1]); 702 if(cmd->len > 2) 703 sprintf(send + 4, " %s %s\r\n", cmd->params[1], cmd->params[2]); 704 swrite(sock, send, strlen(send)); 705 goto end_e; 706 case 'S': 707 case 's': 708 if(cmd->len > 1) 709 setchan(cmd->params[1]); 710 else 711 printf("%s\n", (lastchan == nil) ? "<nil>": lastchan); 712 goto end_e; 713 default: 714 break; 715 } 716 } 717 if(cmd->len > 1) { 718 switch(cmd->params[0][1]) { 719 case 'J': 720 case 'j': 721 tprintf(sock, "JOIN %s\r\n", cmd->params[1]); 722 setchan(cmd->params[1]); 723 goto end_e; 724 case 'P': 725 case 'p': 726 tprintf(sock, "PART %s\r\n", cmd->params[1]); 727 goto end_e; 728 case 'N': 729 case 'n': 730 tprintf(sock, "NICK %s\r\n", cmd->params[1]); 731 goto end_e; 732 case 'W': 733 case 'w': 734 tprintf(sock, "WHOIS %s\r\n", cmd->params[1]); 735 goto end_e; 736 case 'U': 737 case 'u': 738 tprintf(sock, "WHO %s\r\n", cmd->params[1]); 739 goto end_e; 740 case 'T': 741 case 't': 742 sprintf(send, "TOPIC %s\r\n", cmd->params[1]); 743 if(cmd->len > 2) 744 sprintf(send + strlen(send) - 2, " :%s\r\n", cmd->params[2]); 745 tprintf(sock, send); 746 goto end_e; 747 case 'I': 748 case 'i': 749 if(searchlist(ignorel, cmd->params[1]) != -1) { 750 dellist(ignorel, cmd->params[1]); 751 printf("%s no more ignored. %d\n", cmd->params[1], searchlist(ignorel, cmd->params[1])); 752 } else { 753 addlist(ignorel, cmd->params[1]); 754 printf("%s will be ignored.\n", cmd->params[1]); 755 } 756 goto end_e; 757 default: 758 break; 759 } 760 } 761 if(cmd->len > 2) { 762 switch(cmd->params[0][1]) { 763 case 'M': 764 case 'm': 765 tprintf(sock, "PRIVMSG %s :%s\r\n", cmd->params[1], cmd->params[2]); 766 goto end_e; 767 case 'A': 768 case 'a': 769 tprintf(sock, "PRIVMSG %s :%sACTION %s\x01\r\n", "\x01", cmd->params[1], cmd->params[2]); 770 goto end_e; 771 case 'O': 772 case 'o': 773 if(cmd->len > 3) 774 tprintf(sock, "MODE %s %s %s\r\n", cmd->params[1], cmd->params[2], cmd->params[3]); 775 else 776 tprintf(sock, "MODE %s %s\r\n", cmd->params[1], cmd->params[2]); 777 goto end_e; 778 case 'C': 779 case 'c': 780 printf("%s(%s) ctcp %s\n", tmstmp, cmd->params[1], cmd->params[2]); 781 tprintf(sock, "PRIVMSG %s :\x01%s\x01\r\n", cmd->params[1], cmd->params[2]); 782 goto end_e; 783 case 'K': 784 case 'k': 785 sprintf(send, "KICK %s %s\r\n", cmd->params[1], cmd->params[2]); 786 if(cmd->len > 3) 787 sprintf(send + strlen(send) - 2, " :%s\r\n", cmd->params[3]); 788 tprintf(sock, send); 789 goto end_e; 790 default: 791 break; 792 } 793 } 794 } 795 if(lastchan != nil) 796 tprintf(sock, "PRIVMSG %s :%s\r\n", lastchan, rad); 797 else 798 printf("."); 799 end_e: 800 printf("%s\n", tmstmp); 801 free(tmstmp); 802 freecmd(cmd); 803 } 804 805 if(lastchan != nil) 806 free(lastchan); 807 free(send); 808 free(rad); 809 freecmd(ignorel); 810 freecmd(joinl); 811 if(tls) 812 SSL_CTX_free(ctx); 813 814 return 0; 815 } 816