Mercurial > hg > nnchat
comparison nnchat.c @ 62:ff5d74f0d428
Moved some functions to "libnnchat".
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 11 Nov 2008 21:57:51 +0200 |
parents | b802a799c31a |
children | afd90bbb3af6 |
comparison
equal
deleted
inserted
replaced
61:b802a799c31a | 62:ff5d74f0d428 |
---|---|
1 /* | 1 /* |
2 * NNChat - Custom chat client for NewbieNudes.com chatrooms | 2 * NNChat - Custom chat client for NewbieNudes.com chatrooms |
3 * Written by Matti 'ccr' Hämäläinen | 3 * Written by Matti 'ccr' Hämäläinen |
4 * (C) Copyright 2008 Tecnic Software productions (TNSP) | 4 * (C) Copyright 2008 Tecnic Software productions (TNSP) |
5 */ | 5 */ |
6 #include <sys/socket.h> | 6 #include "libnnchat.h" |
7 #include <sys/types.h> | |
8 #include <arpa/inet.h> | |
9 #include <sys/time.h> | |
10 #include <netdb.h> | |
11 | |
12 #include <unistd.h> | |
13 #include <stdlib.h> | 7 #include <stdlib.h> |
14 #include <stdio.h> | |
15 #include "th_args.h" | 8 #include "th_args.h" |
16 #include "th_string.h" | |
17 #include <string.h> | 9 #include <string.h> |
18 #include <errno.h> | 10 #include <errno.h> |
19 #include <time.h> | 11 #include <time.h> |
20 #include <ncurses.h> | 12 #include <ncurses.h> |
21 | 13 |
22 | 14 |
23 #define SET_MAX_BACKBUF (1024) | 15 #define SET_MAX_BACKBUF (1024) |
24 #define SET_MAX_HISTORY (16) | 16 #define SET_MAX_HISTORY (16) |
25 #define SET_BUFSIZE (4096) | |
26 #define SET_ALLOC_SIZE (128) | |
27 #define SET_DELAY (15) | 17 #define SET_DELAY (15) |
28 #define SET_DELAY_USEC (SET_DELAY * 1000) | 18 #define SET_DELAY_USEC (SET_DELAY * 1000) |
29 | |
30 | |
31 typedef struct { | |
32 char c; | |
33 char *ent; | |
34 } html_entity_t; | |
35 | |
36 | |
37 html_entity_t HTMLEntities[] = { | |
38 { '<', "<" }, | |
39 { '>', ">" }, | |
40 }; | |
41 | |
42 const int numHTMLEntities = (sizeof(HTMLEntities) / sizeof(HTMLEntities[0])); | |
43 | 19 |
44 | 20 |
45 /* Options | 21 /* Options |
46 */ | 22 */ |
47 int optPort = 8005; | 23 int optPort = 8005; |
382 wattrset(editWin, A_NORMAL); | 358 wattrset(editWin, A_NORMAL); |
383 } | 359 } |
384 wrefresh(editWin); | 360 wrefresh(editWin); |
385 } | 361 } |
386 | 362 |
387 int openConnection(struct in_addr *addr, const int port) | |
388 { | |
389 struct sockaddr_in tmpAddr; | |
390 int sock = -1; | |
391 | |
392 tmpAddr.sin_family = AF_INET; | |
393 tmpAddr.sin_port = htons(port); | |
394 tmpAddr.sin_addr = *addr; | |
395 | |
396 THMSG(1, "Connecting to %s:%d ...\n", | |
397 inet_ntoa(tmpAddr.sin_addr), port); | |
398 | |
399 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { | |
400 THERR("Could not open socket: %s\n", strerror(errno)); | |
401 return -2; | |
402 } | |
403 | |
404 THMSG(2, "Using socket %d.\n", sock); | |
405 | |
406 if (connect(sock, (struct sockaddr *) &tmpAddr, sizeof(tmpAddr)) == -1) { | |
407 THERR("Could not connect: %s\n", strerror(errno)); | |
408 return -5; | |
409 } | |
410 | |
411 return sock; | |
412 } | |
413 | |
414 | |
415 void closeConnection(const int sock) | |
416 { | |
417 if (sock >= 0) { | |
418 close(sock); | |
419 } | |
420 } | |
421 | |
422 | |
423 BOOL sendToSocket(const int sock, char *buf, const size_t bufLen) | |
424 { | |
425 size_t bufLeft = bufLen; | |
426 char *bufPtr = buf; | |
427 | |
428 while (bufLeft > 0) { | |
429 ssize_t bufSent; | |
430 bufSent = send(sock, bufPtr, bufLeft, 0); | |
431 if (bufSent < 0) return FALSE; | |
432 bufLeft -= bufSent; | |
433 bufPtr += bufSent; | |
434 } | |
435 return TRUE; | |
436 } | |
437 | |
438 int printWin(WINDOW *win, const char *fmt) | 363 int printWin(WINDOW *win, const char *fmt) |
439 { | 364 { |
440 const char *s = fmt; | 365 const char *s = fmt; |
441 int col = 0; | 366 int col = 0; |
442 | 367 |
468 } | 393 } |
469 } | 394 } |
470 return 0; | 395 return 0; |
471 } | 396 } |
472 | 397 |
398 | |
473 int printFile(FILE *outFile, const char *fmt) | 399 int printFile(FILE *outFile, const char *fmt) |
474 { | 400 { |
475 const char *s = fmt; | 401 const char *s = fmt; |
476 | 402 |
477 while (*s) { | 403 while (*s) { |
492 } | 418 } |
493 | 419 |
494 return 0; | 420 return 0; |
495 } | 421 } |
496 | 422 |
423 | |
497 void printMsg(char *fmt, ...) | 424 void printMsg(char *fmt, ...) |
498 { | 425 { |
499 char tmpStr[128] = "", buf[8192]; | 426 char tmpStr[128] = "", buf[8192]; |
500 va_list ap; | 427 va_list ap; |
501 time_t timeStamp; | 428 time_t timeStamp; |
522 wrefresh(mainWin); | 449 wrefresh(mainWin); |
523 } | 450 } |
524 } | 451 } |
525 | 452 |
526 | 453 |
527 BOOL bufRealloc(char **buf, size_t *size, size_t add) | |
528 { | |
529 return ((*buf = th_realloc(*buf, *size + add)) != NULL); | |
530 } | |
531 | |
532 #define PUSHCHAR(x) bufPushChar(&result, &resSize, &resPos, x) | |
533 BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch) | |
534 { | |
535 if (*pos >= *size && !bufRealloc(buf, size, SET_ALLOC_SIZE)) | |
536 return FALSE; | |
537 | |
538 (*buf)[*pos] = ch; | |
539 (*pos)++; | |
540 return TRUE; | |
541 } | |
542 | |
543 #define PUSHSTR(x) bufPushStr(&result, &resSize, &resPos, x) | |
544 BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str) | |
545 { | |
546 size_t tmpLen; | |
547 | |
548 if (!str) return FALSE; | |
549 tmpLen = strlen(str); | |
550 | |
551 if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + SET_ALLOC_SIZE)) | |
552 return FALSE; | |
553 | |
554 strcpy(*buf + *pos, str); | |
555 (*pos) += tmpLen; | |
556 return TRUE; | |
557 } | |
558 | |
559 | |
560 char *encodeStr1(char *str) | |
561 { | |
562 char *result, *s = str; | |
563 size_t resSize, resPos = 0; | |
564 | |
565 if (!str) return NULL; | |
566 | |
567 resSize = strlen(str) + SET_ALLOC_SIZE; | |
568 if ((result = th_malloc(resSize)) == NULL) | |
569 return NULL; | |
570 | |
571 while (*s) { | |
572 switch (*s) { | |
573 case 32: | |
574 PUSHCHAR('+'); | |
575 break; | |
576 | |
577 default: | |
578 if (th_isalnum(*s)) | |
579 PUSHCHAR(*s); | |
580 else { | |
581 char tmpStr[4]; | |
582 sprintf(tmpStr, "%2X", (unsigned char) *s); | |
583 PUSHCHAR('%'); | |
584 PUSHSTR(tmpStr); | |
585 } | |
586 break; | |
587 } | |
588 s++; | |
589 } | |
590 PUSHCHAR(0); | |
591 | |
592 return result; | |
593 } | |
594 | |
595 | |
596 int getxdigit(int c, int shift) | |
597 { | |
598 int i; | |
599 | |
600 if (c >= 'A' && c <= 'F') | |
601 i = c - 'A' + 10; | |
602 else if (c >= 'a' && c <= 'f') | |
603 i = c - 'a' + 10; | |
604 else if (c >= '0' && c <= '9') | |
605 i = c - '0'; | |
606 else | |
607 return -1; | |
608 | |
609 return i << shift; | |
610 } | |
611 | |
612 | |
613 char *decodeStr1(char *str) | |
614 { | |
615 char *result, *s = str; | |
616 size_t resSize, resPos = 0; | |
617 int c; | |
618 | |
619 if (!str) return NULL; | |
620 | |
621 resSize = strlen(str) + SET_ALLOC_SIZE; | |
622 if ((result = th_malloc(resSize)) == NULL) | |
623 return NULL; | |
624 | |
625 while (*s) { | |
626 switch (*s) { | |
627 case '+': | |
628 PUSHCHAR(' '); | |
629 s++; | |
630 break; | |
631 | |
632 case '½': | |
633 /* Escape these .. */ | |
634 PUSHCHAR('½'); | |
635 PUSHCHAR('½'); | |
636 s++; | |
637 break; | |
638 | |
639 case '\r': | |
640 PUSHCHAR(' '); | |
641 s++; | |
642 break; | |
643 | |
644 case '%': | |
645 s++; | |
646 if (*s == '%') | |
647 PUSHCHAR('%'); | |
648 else if ((c = getxdigit(*s, 4)) >= 0) { | |
649 int i = getxdigit(*(++s), 0); | |
650 if (i >= 0) { | |
651 PUSHCHAR(c | i); | |
652 } else { | |
653 PUSHCHAR('§'); | |
654 PUSHCHAR(*s); | |
655 } | |
656 } else { | |
657 PUSHCHAR('§'); | |
658 PUSHCHAR(*s); | |
659 } | |
660 s++; | |
661 break; | |
662 | |
663 default: | |
664 PUSHCHAR(*s); | |
665 s++; | |
666 } | |
667 } | |
668 PUSHCHAR(0); | |
669 | |
670 return result; | |
671 } | |
672 | |
673 | |
674 char *stripTags(char *str) | |
675 { | |
676 char *result, *s = str; | |
677 size_t resSize, resPos = 0; | |
678 | |
679 if (!str) return NULL; | |
680 | |
681 resSize = strlen(str) + SET_ALLOC_SIZE; | |
682 if ((result = th_malloc(resSize)) == NULL) | |
683 return NULL; | |
684 | |
685 while (*s) { | |
686 if (*s == '<') { | |
687 while (*s && *s != '>') s++; | |
688 if (*s == '>') s++; | |
689 } else | |
690 PUSHCHAR(*s++); | |
691 } | |
692 PUSHCHAR(0); | |
693 | |
694 return result; | |
695 } | |
696 | |
697 | |
698 char *encodeStr2(char *str) | |
699 { | |
700 char *result, *s = str; | |
701 size_t resSize, resPos = 0; | |
702 | |
703 if (!str) return NULL; | |
704 | |
705 resSize = strlen(str) + SET_ALLOC_SIZE; | |
706 if ((result = th_malloc(resSize)) == NULL) | |
707 return NULL; | |
708 | |
709 while (*s) { | |
710 int i; | |
711 BOOL found = FALSE; | |
712 for (i = 0; i < numHTMLEntities; i++) | |
713 if (HTMLEntities[i].c == *s) { | |
714 PUSHSTR(HTMLEntities[i].ent); | |
715 found = TRUE; | |
716 break; | |
717 } | |
718 if (!found) PUSHCHAR(*s); | |
719 | |
720 s++; | |
721 } | |
722 PUSHCHAR(0); | |
723 | |
724 return result; | |
725 } | |
726 | |
727 | |
728 char *decodeStr2(char *str) | |
729 { | |
730 char *result, *s = str; | |
731 size_t resSize, resPos = 0; | |
732 | |
733 if (!str) return NULL; | |
734 | |
735 resSize = strlen(str); | |
736 if ((result = th_malloc(resSize)) == NULL) | |
737 return NULL; | |
738 | |
739 while (*s) { | |
740 if (*s == '&') { | |
741 int i; | |
742 BOOL found = FALSE; | |
743 for (i = 0; i < numHTMLEntities; i++) { | |
744 html_entity_t *ent = &HTMLEntities[i]; | |
745 int len = strlen(ent->ent); | |
746 if (!strncmp(s, ent->ent, len)) { | |
747 PUSHCHAR(ent->c); | |
748 s += len; | |
749 found = TRUE; | |
750 break; | |
751 } | |
752 } | |
753 if (!found) PUSHCHAR(*s++); | |
754 } else | |
755 PUSHCHAR(*s++); | |
756 } | |
757 PUSHCHAR(0); | |
758 | |
759 return result; | |
760 } | |
761 | |
762 | |
763 BOOL sendUserMsg(int sock, char *user, char *fmt, ...) | |
764 { | |
765 char tmpBuf[4096], tmpBuf2[4096+256]; | |
766 int n; | |
767 va_list ap; | |
768 | |
769 va_start(ap, fmt); | |
770 n = vsnprintf(tmpBuf, sizeof(tmpBuf), fmt, ap); | |
771 va_end(ap); | |
772 | |
773 if (n < 0) return FALSE; | |
774 | |
775 snprintf(tmpBuf2, sizeof(tmpBuf2), | |
776 "<USER>%s</USER><MESSAGE>%s</MESSAGE>", | |
777 user, tmpBuf); | |
778 | |
779 return sendToSocket(sock, tmpBuf2, strlen(tmpBuf2) + 1); | |
780 } | |
781 | |
782 | |
783 int handleUser(int sock, char *str) | 454 int handleUser(int sock, char *str) |
784 { | 455 { |
785 const char *msg = "</USER><MESSAGE>"; | 456 const char *msg = "</USER><MESSAGE>"; |
786 char *p = str, *q, *s, *t, *h; | 457 char *p = str, *q, *s, *t, *h; |
787 | 458 |
805 return -2; | 476 return -2; |
806 } | 477 } |
807 | 478 |
808 | 479 |
809 if (*s == '/') { | 480 if (*s == '/') { |
810 t = stripTags(s + 1); | 481 t = stripXMLTags(s + 1); |
811 if (!strncmp(t, "BPRV", 4)) { | 482 if (!strncmp(t, "BPRV", 4)) { |
812 h = decodeStr2(t + 1); | 483 h = decodeStr2(t + 1); |
813 printMsg("½11½%s½0½\n", h); | 484 printMsg("½11½%s½0½\n", h); |
814 } else { | 485 } else { |
815 h = decodeStr2(t); | 486 h = decodeStr2(t); |
816 printMsg("½9½* %s½0½\n", h); | 487 printMsg("½9½* %s½0½\n", h); |
817 } | 488 } |
818 th_free(h); | 489 th_free(h); |
819 th_free(t); | 490 th_free(t); |
820 } else { | 491 } else { |
821 t = stripTags(s); | 492 t = stripXMLTags(s); |
822 h = decodeStr2(t); | 493 h = decodeStr2(t); |
823 printMsg("½5½<½%d½%s½5½>½0½ %s\n", strcmp(p, optUserName) ? 15 : 14, p, h); | 494 printMsg("½5½<½%d½%s½5½>½0½ %s\n", strcmp(p, optUserName) ? 15 : 14, p, h); |
824 th_free(h); | 495 th_free(h); |
825 th_free(t); | 496 th_free(t); |
826 } | 497 } |
1088 return -3; | 759 return -3; |
1089 } | 760 } |
1090 THMSG(2, "True hostname: %s\n", tmpHost->h_name); | 761 THMSG(2, "True hostname: %s\n", tmpHost->h_name); |
1091 | 762 |
1092 #if 0 | 763 #if 0 |
1093 /* To emulate the official client, we first make a fake connection ... */ | 764 /* To emulate the official client, we first make a request for |
765 * policy file, even though we don't use it for anything... | |
766 */ | |
1094 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) { | 767 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) { |
1095 THERR("Fakeprobe connection setup failed!\n"); | 768 THERR("Policy file request connection setup failed!\n"); |
1096 goto err_exit; | 769 goto err_exit; |
1097 } | 770 } |
1098 | 771 |
1099 tmpStr = "<policy-file-request/>"; | 772 tmpStr = "<policy-file-request/>"; |
1100 if (sendToSocket(tmpSocket, tmpStr, strlen(tmpStr) + 1) == FALSE) { | 773 if (sendToSocket(tmpSocket, tmpStr, strlen(tmpStr) + 1) == FALSE) { |