comparison nnchat.c @ 96:7c9538e71c89

Add connection keepalive by sending /listallusers every 15 minutes, due to NN server booting after about 30 minutes of inactivity; Improve handling of error messages; Add handling for "<BOOT />" protocol token.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 05 Jul 2009 16:55:40 +0300
parents 638f88374e3e
children 218efd2f0641
comparison
equal deleted inserted replaced
95:69f9c46e4a94 96:7c9538e71c89
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-2009 Tecnic Software productions (TNSP)
5 */ 5 */
6 #include "libnnchat.h" 6 #include "libnnchat.h"
7 #include <stdlib.h> 7 #include <stdlib.h>
8 #include "th_args.h" 8 #include "th_args.h"
9 #include <string.h> 9 #include <string.h>
18 18
19 #define SET_MAX_BACKBUF (1024) 19 #define SET_MAX_BACKBUF (1024)
20 #define SET_MAX_HISTORY (16) 20 #define SET_MAX_HISTORY (16)
21 #define SET_DELAY (15) 21 #define SET_DELAY (15)
22 #define SET_DELAY_USEC (SET_DELAY * 1000) 22 #define SET_DELAY_USEC (SET_DELAY * 1000)
23 #define SET_KEEPALIVE (15*60) /* Ping/keepalive period in seconds */
23 24
24 25
25 /* Options 26 /* Options
26 */ 27 */
27 int optPort = 8005; 28 int optPort = 8005;
28 int optUserColor = 0x006080; 29 int optUserColor = 0x006080;
29 char *optServer = "www11.servemedata.com", 30 char *optServer = "chat.newbienudes.com",
30 *optUserName = NULL, 31 *optUserName = NULL,
31 *optUserName2 = NULL, 32 *optUserName2 = NULL,
32 *optPassword = NULL, 33 *optPassword = NULL,
33 *optLogFilename = NULL, 34 *optLogFilename = NULL,
34 *setTarget = NULL, 35 *setTarget = NULL,
309 wrefresh(mainWin); 310 wrefresh(mainWin);
310 } 311 }
311 } 312 }
312 313
313 314
315 void errorMsg(char *fmt, ...)
316 {
317 char buf[8192];
318 va_list ap;
319
320 va_start(ap, fmt);
321 vsnprintf(buf, sizeof(buf), fmt, ap);
322 va_end(ap);
323
324 printMsg(buf);
325 THERR(buf);
326 }
327
328
314 int handleUser(int sock, char *str) 329 int handleUser(int sock, char *str)
315 { 330 {
316 const char *msg = "</USER><MESSAGE>"; 331 const char *msg = "</USER><MESSAGE>";
317 char *p = str, *q, *s, *t, *h; 332 char *p = str, *q, *s, *t, *h;
318 333
428 443
429 return 0; 444 return 0;
430 } 445 }
431 446
432 447
448 int handleBoot(int sock, char *str)
449 {
450 (void) sock; (void) str;
451 errorMsg("Booted by server.\n");
452 return -1;
453 }
454
455
433 typedef struct { 456 typedef struct {
434 char *cmd; 457 char *cmd;
435 int (*handler)(int, char *); 458 int (*handler)(int, char *);
436 } protocmd_t; 459 } protocmd_t;
437 460
440 { "<USER>", handleUser }, 463 { "<USER>", handleUser },
441 { "<LOGIN_", handleLogin }, 464 { "<LOGIN_", handleLogin },
442 { "<DELETE_USER>", handleDeleteUser }, 465 { "<DELETE_USER>", handleDeleteUser },
443 { "<ADD_USER>", handleAddUser }, 466 { "<ADD_USER>", handleAddUser },
444 { "<NUMCLIENTS>", handleFoo }, 467 { "<NUMCLIENTS>", handleFoo },
468 { "<BOOT />", handleBoot },
445 }; 469 };
446 470
447 const int nprotoCmds = (sizeof(protoCmds) / sizeof(protoCmds[0])); 471 const int nprotoCmds = (sizeof(protoCmds) / sizeof(protoCmds[0]));
448 472
449 473
563 exitProg = FALSE, 587 exitProg = FALSE,
564 colorSet = FALSE, 588 colorSet = FALSE,
565 cursesInit = FALSE, 589 cursesInit = FALSE,
566 networkInit = FALSE, 590 networkInit = FALSE,
567 insertMode = TRUE; 591 insertMode = TRUE;
568 struct timeval tv; 592 time_t prevTime;
593 struct timeval socktv;
569 fd_set sockfds; 594 fd_set sockfds;
570 char *tmpStr; 595 char *tmpStr;
571 nn_editbuf_t *editBuf = newBuf(SET_BUFSIZE); 596 nn_editbuf_t *editBuf = newBuf(SET_BUFSIZE);
572 nn_editbuf_t *histBuf[SET_MAX_HISTORY+2]; 597 nn_editbuf_t *histBuf[SET_MAX_HISTORY+2];
573 int histPos = 0, histMax = 0; 598 int histPos = 0, histMax = 0;
574 599
575 memset(histBuf, 0, sizeof(histBuf)); 600 memset(histBuf, 0, sizeof(histBuf));
576 601
577 /* Initialize */ 602 /* Initialize */
578 th_init("NNChat", "Newbie Nudes chat client", "0.7.1", 603 th_init("NNChat", "Newbie Nudes chat client", "0.7.2",
579 "Written and designed by Anonymous Finnish Guy (C) 2008-2009", 604 "Written and designed by Anonymous Finnish Guy (C) 2008-2009",
580 "This software is freeware, use and distribute as you wish."); 605 "This software is freeware, use and distribute as you wish.");
581 th_verbosityLevel = 0; 606 th_verbosityLevel = 0;
582 607
583 /* Parse arguments */ 608 /* Parse arguments */
619 goto err_exit; 644 goto err_exit;
620 } 645 }
621 THMSG(2, "True hostname: %s\n", tmpHost->h_name); 646 THMSG(2, "True hostname: %s\n", tmpHost->h_name);
622 647
623 648
624 #if 0 649 #if 1
625 /* To emulate the official client, we first make a request for 650 /* To emulate the official client, we first make a request for
626 * policy file, even though we don't use it for anything... 651 * policy file, even though we don't use it for anything...
627 */ 652 */
628 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) { 653 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, 843)) < 0) {
629 THERR("Policy file request connection setup failed!\n"); 654 THERR("Policy file request connection setup failed!\n");
630 goto err_exit; 655 goto err_exit;
631 } 656 }
632 657
633 tmpStr = "<policy-file-request/>"; 658 tmpStr = "<policy-file-request/>";
634 if (sendToSocket(tmpSocket, tmpStr, strlen(tmpStr) + 1) == FALSE) { 659 if (sendToSocket(tmpSocket, tmpStr, strlen(tmpStr) + 1) == FALSE) {
635 THERR("Failed to send fakeprobe.\n"); 660 THERR("Failed to send policy file request.\n");
636 goto err_exit; 661 goto err_exit;
637 } else { 662 } else {
638 ssize_t gotBuf; 663 ssize_t gotBuf;
639 char tmpBuf[SET_BUFSIZE]; 664 char tmpBuf[SET_BUFSIZE];
640 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); 665 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0);
699 printEditBuf("", editBuf); 724 printEditBuf("", editBuf);
700 updateStatus(insertMode); 725 updateStatus(insertMode);
701 } 726 }
702 727
703 /* Enter mainloop */ 728 /* Enter mainloop */
729 prevTime = time(NULL);
704 FD_ZERO(&sockfds); 730 FD_ZERO(&sockfds);
705 FD_SET(tmpSocket, &sockfds); 731 FD_SET(tmpSocket, &sockfds);
706 732
707 while (!isError && !exitProg) { 733 while (!isError && !exitProg) {
708 int result; 734 int result;
709 fd_set tmpfds; 735 fd_set tmpfds;
710 736
711 /* Check for incoming data from the server */ 737 /* Check for incoming data from the server */
712 tv.tv_sec = 0; 738 socktv.tv_sec = 0;
713 tv.tv_usec = SET_DELAY_USEC; 739 socktv.tv_usec = SET_DELAY_USEC;
714 tmpfds = sockfds; 740 tmpfds = sockfds;
715 if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &tv)) == -1) { 741 if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &socktv)) == -1) {
716 int res = getSocketErrno(); 742 int res = getSocketErrno();
717 if (res != EINTR) { 743 if (res != EINTR) {
718 printMsg("Error occured in select(sockfds): %d, %s\n", 744 errorMsg("Error occured in select(sockfds): %d, %s\n",
719 res, getSocketErrStr(res)); 745 res, getSocketErrStr(res));
720 isError = TRUE; 746 isError = TRUE;
721 } 747 }
722 } else if (FD_ISSET(tmpSocket, &tmpfds)) { 748 } else if (FD_ISSET(tmpSocket, &tmpfds)) {
723 ssize_t gotBuf; 749 ssize_t gotBuf;
725 char *bufPtr = tmpBuf; 751 char *bufPtr = tmpBuf;
726 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); 752 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0);
727 753
728 if (gotBuf < 0) { 754 if (gotBuf < 0) {
729 int res = getSocketErrno(); 755 int res = getSocketErrno();
730 printMsg("Error in recv: %d, %s\n", res, getSocketErrStr(res)); 756 errorMsg("Error in recv: %d, %s\n", res, getSocketErrStr(res));
731 isError = TRUE; 757 isError = TRUE;
732 } else if (gotBuf == 0) { 758 } else if (gotBuf == 0) {
733 printMsg("Server closed connection.\n"); 759 errorMsg("Server closed connection.\n");
734 isError = TRUE; 760 isError = TRUE;
735 } else { 761 } else {
736 /* Handle protocol data */ 762 /* Handle protocol data */
737 tmpBuf[gotBuf] = 0; 763 tmpBuf[gotBuf] = 0;
738 do { 764 do {
742 if (result > 0) { 768 if (result > 0) {
743 /* Couldn't handle the message for some reason */ 769 /* Couldn't handle the message for some reason */
744 printMsg("Could not handle: %s\n", tmpBuf); 770 printMsg("Could not handle: %s\n", tmpBuf);
745 } else if (result < 0) { 771 } else if (result < 0) {
746 /* Fatal error, quit */ 772 /* Fatal error, quit */
747 printMsg("Fatal error with message: %s\n", tmpBuf); 773 errorMsg("Fatal error with message: %s\n", tmpBuf);
748 isError = TRUE; 774 isError = TRUE;
749 } 775 }
750 776
751 gotBuf -= bufLen; 777 gotBuf -= bufLen;
752 bufPtr += bufLen; 778 bufPtr += bufLen;
783 809
784 switch (c) { 810 switch (c) {
785 #ifdef KEY_RESIZE 811 #ifdef KEY_RESIZE
786 case KEY_RESIZE: 812 case KEY_RESIZE:
787 if (!initializeWindows()) { 813 if (!initializeWindows()) {
788 THERR("Error resizing ncurses windows\n"); 814 errorMsg("Error resizing ncurses windows\n");
789 isError = TRUE; 815 isError = TRUE;
790 } 816 }
791 break; 817 break;
792 #endif 818 #endif
793 819
811 result = handleUserInput(tmpSocket, editBuf->data, editBuf->len); 837 result = handleUserInput(tmpSocket, editBuf->data, editBuf->len);
812 838
813 clearBuf(editBuf); 839 clearBuf(editBuf);
814 840
815 if (result < 0) { 841 if (result < 0) {
816 printMsg("Fatal error handling user input: %s\n", editBuf->data); 842 errorMsg("Fatal error handling user input: %s\n", editBuf->data);
817 isError = TRUE; 843 isError = TRUE;
818 } 844 }
819 845
820 update = TRUE; 846 update = TRUE;
821 } 847 }
936 updateStatus(insertMode); 962 updateStatus(insertMode);
937 } 963 }
938 } /* !optDaemon */ 964 } /* !optDaemon */
939 965
940 if (++updateCount > 10) { 966 if (++updateCount > 10) {
967 time_t tmpTime = time(NULL);
968 if (tmpTime - prevTime > SET_KEEPALIVE) {
969 sendUserMsg(tmpSocket, optUserName2, "/listallusers");
970 prevTime = tmpTime;
971 }
972
973 if (!colorSet) {
974 colorSet = TRUE;
975 printMsg("%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
976 printMsg("%s\n", th_prog_author);
977 printMsg("%s\n", th_prog_license);
978 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
979 }
980
941 updateStatus(insertMode); 981 updateStatus(insertMode);
942 updateCount = 0; 982 updateCount = 0;
943 } 983 }
944 984
945 if (!colorSet) {
946 colorSet = TRUE;
947 printMsg("%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
948 printMsg("%s\n", th_prog_author);
949 printMsg("%s\n", th_prog_license);
950 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
951 }
952 } 985 }
953 986
954 /* Shutdown */ 987 /* Shutdown */
955 err_exit: 988 err_exit:
956 freeBuf(editBuf); 989 freeBuf(editBuf);