comparison nnchat.c @ 28:512775f6b081

A refactored ncurses-based UI.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 02 Aug 2008 11:57:09 +0300
parents da721f94c60f
children a27ef0e359b9
comparison
equal deleted inserted replaced
27:da721f94c60f 28:512775f6b081
1 #ifdef __WIN32
2 #include <winsock2.h>
3 #else
4 #include <sys/socket.h> 1 #include <sys/socket.h>
5 #include <sys/types.h> 2 #include <sys/types.h>
6 #include <arpa/inet.h> 3 #include <arpa/inet.h>
7 #include <sys/time.h> 4 #include <sys/time.h>
8 #include <netdb.h> 5 #include <netdb.h>
9 #endif
10 6
11 #include <unistd.h> 7 #include <unistd.h>
12 #include <stdlib.h> 8 #include <stdlib.h>
13 #include <stdio.h> 9 #include <stdio.h>
14 #include "th_args.h" 10 #include "th_args.h"
15 #include "th_string.h" 11 #include "th_string.h"
16 #include <string.h> 12 #include <string.h>
17 #include <errno.h> 13 #include <errno.h>
18 #include <time.h> 14 #include <time.h>
19 15 #include <ncurses.h>
20 16
17
18 #define SET_BUFSIZE (4096)
21 #define SET_ALLOC_SIZE (128) 19 #define SET_ALLOC_SIZE (128)
22 #define SET_SELECT_USEC (100000) 20 #define SET_DELAY (15)
23 21 #define SET_DELAY_USEC (SET_DELAY * 1000)
24 #define ANSI_BLACK "\x1b[0;30m"
25 #define ANSI_RED "\x1b[0;31m"
26 #define ANSI_GREEN "\x1b[0;32m"
27 #define ANSI_YELLOW "\x1b[0;33m"
28 #define ANSI_BLUE "\x1b[0;34m"
29 #define ANSI_MAGENTA "\x1b[0;35m"
30 #define ANSI_CYAN "\x1b[0;36m"
31 #define ANSI_WHITE "\x1b[0;37m"
32
33 #define ANSI_L_BLACK "\x1b[0;1;30m"
34 #define ANSI_L_RED "\x1b[0;1;31m"
35 #define ANSI_L_GREEN "\x1b[0;1;32m"
36 #define ANSI_L_YELLOW "\x1b[0;1;33m"
37 #define ANSI_L_BLUE "\x1b[0;1;34m"
38 #define ANSI_L_MAGENTA "\x1b[0;1;35m"
39 #define ANSI_L_CYAN "\x1b[0;1;36m"
40 #define ANSI_L_WHITE "\x1b[0;1;37m"
41
42 #define ANSI_END "\x1b[0m"
43
44 22
45 /* Options 23 /* Options
46 */ 24 */
47 int optPort = 8005; 25 int optPort = 8005;
48 int optUserColor = 0x408060; 26 int optUserColor = 0x408060;
52 *optPassword = NULL, 30 *optPassword = NULL,
53 *optLogFilename = NULL, 31 *optLogFilename = NULL,
54 *setTarget = NULL; 32 *setTarget = NULL;
55 BOOL optDaemon = FALSE; 33 BOOL optDaemon = FALSE;
56 FILE *optLogFile = NULL; 34 FILE *optLogFile = NULL;
57 35 WINDOW *mainWin = NULL,
36 *statusWin = NULL,
37 *editWin = NULL;
38
39 BOOL setInsertMode = TRUE;
58 40
59 /* Arguments 41 /* Arguments
60 */ 42 */
61 optarg_t optList[] = { 43 optarg_t optList[] = {
62 { 0, '?', "help", "Show this help", OPT_NONE }, 44 { 0, '?', "help", "Show this help", OPT_NONE },
76 th_args_help(stdout, optList, optListN, th_prog_name, 58 th_args_help(stdout, optList, optListN, th_prog_name,
77 "[options] <username> <password>"); 59 "[options] <username> <password>");
78 } 60 }
79 61
80 62
81 #ifdef __WIN32
82 /* Just a bogus stub
83 */
84 const char *hstrerror(int err)
85 {
86 (void) err;
87
88 return "???";
89 }
90 #endif
91
92
93 int getColor(char *str) 63 int getColor(char *str)
94 { 64 {
95 char *p = str; 65 char *p = str;
96 int len, val = 0; 66 int len, val = 0;
97 67
169 139
170 return TRUE; 140 return TRUE;
171 } 141 }
172 142
173 143
144 typedef struct {
145 ssize_t pos, len;
146 char data[SET_BUFSIZE];
147 } editbuf_t;
148
149
150 int writeBuf(editbuf_t *buf, ssize_t pos, int ch)
151 {
152 /* Check arguments */
153 if (buf->len+1 >= SET_BUFSIZE) return -3;
154
155 if (pos < 0)
156 return -1;
157 else if (pos >= buf->len) {
158 buf->data[buf->len++] = ch;
159 } else {
160 buf->data[pos] = ch;
161 }
162 return 0;
163 }
164
165 int insertBuf(editbuf_t *buf, ssize_t pos, int ch)
166 {
167 /* Check arguments */
168 if (buf->len+1 >= SET_BUFSIZE) return -3;
169
170 if (pos < 0)
171 return -1;
172 else if (pos >= buf->len) {
173 buf->data[buf->len] = ch;
174 } else {
175 memmove(&(buf->data[pos+1]), &(buf->data[pos]), buf->len - pos + 1);
176 buf->data[pos] = ch;
177 }
178 buf->len++;
179 return 0;
180 }
181
182 int deleteBuf(editbuf_t *buf, ssize_t pos)
183 {
184 /* Check arguments */
185 if (pos < 0)
186 return -1;
187 else if (pos < buf->len) {
188 memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos);
189 buf->len--;
190 return 0;
191 } else
192 return -2;
193 }
194
195 void clearBuf(editbuf_t *buf)
196 {
197 buf->len = 0;
198 buf->pos = 0;
199 }
200
201 void setBufPos(editbuf_t *buf, ssize_t pos)
202 {
203 /* Check arguments */
204 if (pos < 0)
205 buf->pos = 0;
206 else if (pos >= buf->len)
207 buf->pos = buf->len;
208 else
209 buf->pos = pos;
210 }
211
212 void updateStatus(void)
213 {
214 char tmpStr[128] = "";
215 time_t timeStamp;
216 struct tm *tmpTime;;
217
218 timeStamp = time(NULL);
219 if ((tmpTime = localtime(&timeStamp)) != NULL) {
220 strftime(tmpStr, sizeof(tmpStr), "%H:%M:%S", tmpTime);
221 }
222
223 wbkgdset(statusWin, 0x0d00);
224 werase(statusWin);
225
226 wattrset(statusWin, A_BOLD);
227 mvwaddstr(statusWin, 0, 1, tmpStr);
228 waddstr(statusWin, " | ");
229 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
230 waddstr(statusWin, setInsertMode ? "INS" : "DEL");
231
232 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
233 waddstr(statusWin, " | Private target: ");
234
235 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
236 waddstr(statusWin, setTarget != NULL ? setTarget : "--");
237
238 wrefresh(statusWin);
239 }
240
241 void printEditBuf(editbuf_t *buf)
242 {
243 buf->data[buf->len] = 0;
244 werase(editWin);
245 if (buf->pos < buf->len) {
246 mvwaddnstr(editWin, 0, 0, buf->data, buf->pos);
247 wattrset(editWin, A_REVERSE);
248 waddch(editWin, buf->data[buf->pos]);
249 wattrset(editWin, A_NORMAL);
250 waddnstr(editWin, buf->data + buf->pos + 1, buf->len - buf->pos - 1);
251 } else {
252 mvwaddnstr(editWin, 0, 0, buf->data, buf->len);
253 wattrset(editWin, A_REVERSE);
254 waddch(editWin, ' ');
255 wattrset(editWin, A_NORMAL);
256 }
257 wrefresh(editWin);
258 }
259
174 int openConnection(struct in_addr *addr, int port) 260 int openConnection(struct in_addr *addr, int port)
175 { 261 {
176 struct sockaddr_in tmpAddr; 262 struct sockaddr_in tmpAddr;
177 int sock = -1; 263 int sock = -1;
178 264
200 286
201 287
202 void closeConnection(int sock) 288 void closeConnection(int sock)
203 { 289 {
204 if (sock >= 0) { 290 if (sock >= 0) {
205 #ifdef __WIN32
206 closesocket(sock);
207 #else
208 close(sock); 291 close(sock);
209 #endif
210 } 292 }
211 } 293 }
212 294
213 295
214 BOOL sendToSocket(int sock, char *buf, const size_t bufLen) 296 BOOL sendToSocket(int sock, char *buf, const size_t bufLen)
224 bufPtr += bufSent; 306 bufPtr += bufSent;
225 } 307 }
226 return TRUE; 308 return TRUE;
227 } 309 }
228 310
229 311 int printWin(WINDOW *win, const char *fmt)
230 void printMsg(char *fmt, char *fmt2, ...) 312 {
231 { 313 const char *s = fmt;
232 char tmpStr[64] = ""; 314 int col = 0;
315
316 while (*s) {
317 if (*s == '½') {
318 int val = 0;
319 s++;
320 if (*s == '½') {
321 waddch(win, *s | col);
322 s++;
323 } else {
324 while (*s && isdigit(*s)) {
325 val *= 10;
326 val += (*s - '0');
327 s++;
328 }
329 if (*s != '½') return -1;
330 s++;
331
332 if (val < 9) {
333 col = A_DIM | COLOR_PAIR(val);
334 } else if (val < 30) {
335 col = A_BOLD | COLOR_PAIR(val - 9);
336 }
337 }
338 } else {
339 waddch(win, *s | col);
340 s++;
341 }
342 }
343 return 0;
344 }
345
346 int printFile(FILE *outFile, const char *fmt)
347 {
348 const char *s = fmt;
349
350 while (*s) {
351 if (*s == '½') {
352 s++;
353 if (*s == '½') {
354 s++;
355 } else {
356 while (*s && isdigit(*s)) s++;
357 if (*s != '½') return -1;
358 s++;
359 }
360 } else {
361 fputc(*s, outFile);
362 s++;
363 }
364 }
365
366 return 0;
367 }
368
369 void printMsg(char *fmt, ...)
370 {
371 char tmpStr[128] = "", buf[8192];
233 va_list ap; 372 va_list ap;
234 time_t timeStamp; 373 time_t timeStamp;
235 struct tm *tmpTime;; 374 struct tm *tmpTime;;
236 375
237 timeStamp = time(NULL); 376 timeStamp = time(NULL);
238 if ((tmpTime = localtime(&timeStamp)) != NULL) { 377 if ((tmpTime = localtime(&timeStamp)) != NULL) {
239 strftime(tmpStr, sizeof(tmpStr), "%H:%M:%S", tmpTime); 378 strftime(tmpStr, sizeof(tmpStr), "½17½[½11½%H:%M:%S½17½]½0½ ", tmpTime);
240 } 379 }
380
381 va_start(ap, fmt);
382 vsnprintf(buf, sizeof(buf), fmt, ap);
383 va_end(ap);
241 384
242 if (optLogFile) { 385 if (optLogFile) {
243 fprintf(optLogFile, "[%s] ", tmpStr); 386 printFile(optLogFile, tmpStr);
244 va_start(ap, fmt2); 387 printFile(optLogFile, buf);
245 vfprintf(optLogFile, fmt, ap);
246 va_end(ap);
247 fflush(optLogFile); 388 fflush(optLogFile);
248 } 389 }
249 390
250 if (!optDaemon) { 391 if (!optDaemon) {
251 fprintf(stdout, ANSI_L_BLACK "[" ANSI_L_GREEN "%s" ANSI_L_BLACK "]" ANSI_END " ", tmpStr); 392 printWin(mainWin, tmpStr);
252 va_start(ap, fmt2); 393 printWin(mainWin, buf);
253 vfprintf(stdout, fmt2, ap); 394 wrefresh(mainWin);
254 va_end(ap);
255 fflush(stdout);
256 } 395 }
257 } 396 }
258 397
259 398
260 BOOL bufRealloc(char **buf, size_t *size, size_t add) 399 BOOL bufRealloc(char **buf, size_t *size, size_t add)
360 case '+': 499 case '+':
361 PUSHCHAR(' '); 500 PUSHCHAR(' ');
362 s++; 501 s++;
363 break; 502 break;
364 503
504 case '½':
505 /* Escape these .. */
506 PUSHCHAR('½');
507 PUSHCHAR('½');
508 s++;
509 break;
510
365 case '\r': 511 case '\r':
366 PUSHCHAR(' '); 512 PUSHCHAR(' ');
367 s++; 513 s++;
368 break; 514 break;
369 515
548 694
549 if (*s == '/') { 695 if (*s == '/') {
550 if (!strncmp(s, "/BPRV", 5)) { 696 if (!strncmp(s, "/BPRV", 5)) {
551 t = stripTags(s + 2); 697 t = stripTags(s + 2);
552 h = decodeStr2(t); 698 h = decodeStr2(t);
553 printMsg("%s\n", ANSI_YELLOW "%s" ANSI_END "\n", h); 699 printMsg("%s\n", h);
554 } else { 700 } else {
555 t = stripTags(s + 1); 701 t = stripTags(s + 1);
556 h = decodeStr2(t); 702 h = decodeStr2(t);
557 printMsg("* %s\n", ANSI_L_YELLOW "* %s" ANSI_END "\n", h); 703 printMsg("* %s\n", h);
558 } 704 }
559 th_free(h); 705 th_free(h);
560 th_free(t); 706 th_free(t);
561 } else { 707 } else {
562 t = stripTags(s); 708 t = stripTags(s);
563 h = decodeStr2(t); 709 h = decodeStr2(t);
564 printMsg("<%s> %s\n", ANSI_MAGENTA "<" ANSI_L_CYAN "%s" ANSI_MAGENTA ">" ANSI_END " %s\n", p, h); 710 printMsg("½5½<½15½%s½5½>½0½ %s\n", p, h);
565 th_free(h); 711 th_free(h);
566 th_free(t); 712 th_free(t);
567 } 713 }
568 714
569 th_free(s); 715 th_free(s);
582 if ((tmpTime = localtime(&timeStamp)) != NULL) { 728 if ((tmpTime = localtime(&timeStamp)) != NULL) {
583 strftime(tmpStr, sizeof(tmpStr), "%c", tmpTime); 729 strftime(tmpStr, sizeof(tmpStr), "%c", tmpTime);
584 } 730 }
585 731
586 if (!strncmp(str, "FAILURE", 7)) { 732 if (!strncmp(str, "FAILURE", 7)) {
587 printMsg("Login failure - %s\n", "Login failure - %s\n", tmpStr); 733 printMsg("½1½Login failure½0½ - ½3½%s½0½\n", tmpStr);
588 return -2; 734 return -2;
589 } else if (!strncmp(str, "SUCCESS", 7)) { 735 } else if (!strncmp(str, "SUCCESS", 7)) {
590 printMsg("Login success - %s\n", "Login success - %s\n", tmpStr); 736 printMsg("½2½Login success½0½ - ½3½%s½0½\n", tmpStr);
591 sendUserMsg(sock, optUserName2, "%%2FRequestUserList"); 737 sendUserMsg(sock, optUserName2, "%%2FRequestUserList");
592 return 0; 738 return 0;
593 } else 739 } else
594 return 1; 740 return 1;
595 } 741 }
605 *s = 0; 751 *s = 0;
606 752
607 p = decodeStr1(str); 753 p = decodeStr1(str);
608 if (!p) return -1; 754 if (!p) return -1;
609 755
610 printMsg("! %s ADDED.\n", "! " ANSI_GREEN "%s" ANSI_END " ADDED.\n", p); 756 printMsg("! ½3½%s½0½ ½2½ADDED.½0½\n", p);
611 th_free(p); 757 th_free(p);
612 return 0; 758 return 0;
613 } 759 }
614 760
615 761
623 *s = 0; 769 *s = 0;
624 770
625 p = decodeStr1(str); 771 p = decodeStr1(str);
626 if (!p) return -1; 772 if (!p) return -1;
627 773
628 printMsg("! %s DELETED.\n", "! " ANSI_RED "%s" ANSI_END " DELETED.\n", p); 774 printMsg("! ½3½%s½0½ ½1½DELETED.½0½\n", p);
629 th_free(p); 775 th_free(p);
630 return 0; 776 return 0;
631 } 777 }
632 778
633 779
679 /* Trim right */ 825 /* Trim right */
680 buf[--bufLen] = 0; 826 buf[--bufLen] = 0;
681 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen]))) 827 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen])))
682 buf[bufLen--] = 0; 828 buf[bufLen--] = 0;
683 829
684 //fprintf(stderr, "'%s'\n", buf); fflush(stderr);
685
686 /* Check command */ 830 /* Check command */
687 if (*buf == 0) { 831 if (*buf == 0) {
688 return 1; 832 return 1;
689 } else if (!strncmp(buf, "/color ", 7)) { 833 } else if (!strncmp(buf, "/color ", 7)) {
690 if ((optUserColor = getColor(buf+7)) < 0) { 834 if ((optUserColor = getColor(buf+7)) < 0) {
691 printMsg("Invalid color value '%s'\n", "Invalid color value '%s'\n", buf+7); 835 printMsg("Invalid color value '%s'\n", buf+7);
692 return 1; 836 return 1;
693 } 837 }
694 printMsg("Setting color to #%06x\n", "Setting color to #%06x\n", optUserColor); 838 printMsg("Setting color to #%06x\n", optUserColor);
695 sendUserMsg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 839 sendUserMsg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
696 return 0; 840 return 0;
697 } else if (!strncmp(buf, "/fake ", 6)) { 841 } else if (!strncmp(buf, "/flood ", 7)) {
698 printMsg("Sending /%s\n", "Sending /%s\n", buf+6); 842 int i;
843
844 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg . .",
845 buf+7);
846
699 tmpStr = encodeStr2(tmpBuf); 847 tmpStr = encodeStr2(tmpBuf);
700 if (!tmpStr) return -2; 848 if (!tmpStr) return -2;
701 tmpStr2 = encodeStr1(tmpStr); 849 tmpStr2 = encodeStr1(tmpStr);
702 if (!tmpStr2) { 850 if (!tmpStr2) {
703 th_free(tmpStr); 851 th_free(tmpStr);
704 return -3; 852 return -3;
705 } 853 }
706 sendUserMsg(sock ,optUserName2, "%%2F%s", tmpStr2);
707
708 th_free(tmpStr);
709 th_free(tmpStr2);
710 return 0;
711 } else if (!strncmp(buf, "/flood ", 7)) {
712 int i;
713
714 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg . .",
715 buf+7);
716
717 tmpStr = encodeStr2(tmpBuf);
718 if (!tmpStr) return -2;
719 tmpStr2 = encodeStr1(tmpStr);
720 if (!tmpStr2) {
721 th_free(tmpStr);
722 return -3;
723 }
724 854
725 result = TRUE; 855 result = TRUE;
726 for (i = 0; i < 50 && result; i++) { 856 for (i = 0; i < 50 && result; i++) {
727 result = sendUserMsg(sock, optUserName2, "%s", tmpStr2); 857 result = sendUserMsg(sock, optUserName2, "%s", tmpStr2);
728 usleep(250); 858 usleep(250);
730 860
731 th_free(tmpStr); 861 th_free(tmpStr);
732 th_free(tmpStr2); 862 th_free(tmpStr2);
733 return 0; 863 return 0;
734 } else if (!strncmp(buf, "/msg ", 5)) { 864 } else if (!strncmp(buf, "/msg ", 5)) {
735 if (setTarget) { 865 if (setTarget != NULL) {
736 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf+5); 866 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf+5);
737 buf = tmpBuf; 867 buf = tmpBuf;
738 } else { 868 } else {
739 printMsg("No target set!\n", ANSI_L_RED "No target set!" ANSI_END "\n"); 869 printMsg("No target set!\n");
740 return 1; 870 return 1;
741 } 871 }
742 } else if (!strncmp(buf, "/to ", 4)) { 872 } else if (!strncmp(buf, "/to ", 4)) {
743 buf += 4; 873 buf += 4;
744 th_free(setTarget); 874 th_free(setTarget);
745 setTarget = th_strdup(buf); 875 setTarget = th_strdup(buf);
746 printMsg("Set prv target to '%s'\n", 876 printMsg("Set prv target to '%s'\n", setTarget);
747 "Set prv target to '" ANSI_L_GREEN "%s" ANSI_END "'\n", setTarget);
748 return 0; 877 return 0;
749 } 878 }
750 879
751 { 880 {
752 /* Send double-encoded */ 881 /* Send double-encoded */
753 //printf("ENC>%s\n", buf);
754 //fflush(stdout);
755
756 tmpStr = encodeStr2(buf); 882 tmpStr = encodeStr2(buf);
757 if (!tmpStr) return -2; 883 if (!tmpStr) return -2;
758 tmpStr2 = encodeStr1(tmpStr); 884 tmpStr2 = encodeStr1(tmpStr);
759 if (!tmpStr2) { 885 if (!tmpStr2) {
760 th_free(tmpStr); 886 th_free(tmpStr);
772 } 898 }
773 899
774 900
775 int main(int argc, char *argv[]) 901 int main(int argc, char *argv[])
776 { 902 {
777 int tmpSocket; 903 int tmpSocket, curVis, updateCount = 0;
778 struct hostent *tmpHost; 904 struct hostent *tmpHost;
779 BOOL argsOK, exitProg = FALSE, colorSet = FALSE; 905 BOOL argsOK, isError = FALSE,
906 exitProg = FALSE,
907 colorSet = FALSE,
908 cursesInit = FALSE;
780 struct timeval tv; 909 struct timeval tv;
781 fd_set sockfds; 910 fd_set sockfds;
782 fd_set inputfds;
783 char *tmpStr; 911 char *tmpStr;
912 editbuf_t *editBuf = calloc(1, sizeof(editbuf_t));
784 913
785 /* Initialize */ 914 /* Initialize */
786 th_init("NNChat", "Newbie Nudes chat client", "0.4", 915 th_init("NNChat", "Newbie Nudes chat client", "0.4",
787 "Written and designed by Anonymous Finnish Guy (C) 2008", 916 "Written and designed by Anonymous Finnish Guy (C) 2008",
788 "This software is freeware, use and distribute as you wish."); 917 "This software is freeware, use and distribute as you wish.");
809 THERR("Could not open logfile for appending!\n"); 938 THERR("Could not open logfile for appending!\n");
810 return -9; 939 return -9;
811 } 940 }
812 } 941 }
813 942
814 #ifdef __WIN32
815 {
816 WSADATA wsaData;
817 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
818 THERR("WinSock API v2.0 not supported.\n");
819 return -20;
820 }
821 }
822 #endif
823
824 /* Okay ... */ 943 /* Okay ... */
825 THMSG(1, "Trying to resolve host '%s' ...\n", optServer); 944 THMSG(1, "Trying to resolve host '%s' ...\n", optServer);
826 tmpHost = gethostbyname(optServer); 945 tmpHost = gethostbyname(optServer);
827 if (tmpHost == NULL) { 946 if (tmpHost == NULL) {
828 THERR("Could not resolve hostname: %s.\n", 947 THERR("Could not resolve hostname: %s.\n",
853 /* Okay, now do the proper connection ... */ 972 /* Okay, now do the proper connection ... */
854 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) { 973 if ((tmpSocket = openConnection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) {
855 THERR("Main connection setup failed!\n"); 974 THERR("Main connection setup failed!\n");
856 goto err_exit; 975 goto err_exit;
857 } 976 }
858 977
859
860 THMSG(1, "Connected, logging in as '%s'.\n", optUserName); 978 THMSG(1, "Connected, logging in as '%s'.\n", optUserName);
861 optUserName2 = encodeStr1(optUserName); 979 optUserName2 = encodeStr1(optUserName);
862 980
863 sendUserMsg(tmpSocket, optUserName2, "%%2Flogin%%20%%2Dsite%%20NN%%20%%2Dpassword%%20%s", optPassword); 981 sendUserMsg(tmpSocket, optUserName2, "%%2Flogin%%20%%2Dsite%%20NN%%20%%2Dpassword%%20%s", optPassword);
864 982
865 FD_ZERO(&inputfds); 983 /* Initialize curses */
866 FD_SET(0, &inputfds); 984
985 if (!optDaemon) {
986 initscr();
987 raw();
988 keypad(stdscr, TRUE);
989 noecho();
990 timeout(SET_DELAY);
991 curVis = curs_set(0);
992 if (has_colors()) {
993 start_color();
994
995 init_pair(1, COLOR_RED, COLOR_BLACK);
996 init_pair(2, COLOR_GREEN, COLOR_BLACK);
997 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
998 init_pair(4, COLOR_BLUE, COLOR_BLACK);
999 init_pair(5, COLOR_MAGENTA, COLOR_BLACK);
1000 init_pair(6, COLOR_CYAN, COLOR_BLACK);
1001 init_pair(7, COLOR_WHITE, COLOR_BLACK);
1002 init_pair(8, COLOR_BLACK, COLOR_BLACK);
1003
1004 init_pair(10, COLOR_BLACK, COLOR_RED);
1005 init_pair(11, COLOR_WHITE, COLOR_RED);
1006 init_pair(12, COLOR_GREEN, COLOR_RED);
1007 init_pair(13, COLOR_YELLOW, COLOR_RED);
1008 init_pair(14, COLOR_BLUE, COLOR_RED);
1009 init_pair(15, COLOR_MAGENTA, COLOR_RED);
1010 init_pair(16, COLOR_CYAN, COLOR_RED);
1011
1012 }
1013
1014 mainWin = newwin(LINES - 4, COLS, 0, 0);
1015 statusWin = newwin(1, COLS, LINES - 4, 0);
1016 editWin = newwin(2, COLS, LINES - 3, 0);
1017
1018 if (mainWin == NULL || statusWin == NULL || editWin == NULL) {
1019 THERR("Could not create ncurses windows!\n");
1020 goto err_exit;
1021 }
1022 scrollok(mainWin, 1);
1023
1024 clearBuf(editBuf);
1025 printEditBuf(editBuf);
1026 updateStatus();
1027
1028 cursesInit = TRUE;
1029 }
1030
1031
867 FD_ZERO(&sockfds); 1032 FD_ZERO(&sockfds);
868 FD_SET(tmpSocket, &sockfds); 1033 FD_SET(tmpSocket, &sockfds);
869 1034
870 while (!exitProg) { 1035 while (!isError && !exitProg) {
871 ssize_t gotBuf;
872 int result; 1036 int result;
873 char tmpBuf[4096];
874 fd_set tmpfds; 1037 fd_set tmpfds;
875 1038
876 /* Check for incoming data from the server */ 1039 /* Check for incoming data from the server */
877 tv.tv_sec = 0; 1040 tv.tv_sec = 0;
878 tv.tv_usec = SET_SELECT_USEC; 1041 tv.tv_usec = SET_DELAY_USEC;
879 tmpfds = sockfds; 1042 tmpfds = sockfds;
880 if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &tv)) == -1) { 1043 if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &tv)) == -1) {
881 printMsg("Error occured in select(sockfds): %s\n", 1044 printMsg("Error occured in select(sockfds): %s\n",
882 "Error occured in select(sockfds): %s\n",
883 strerror(errno)); 1045 strerror(errno));
884 exitProg = TRUE; 1046 isError = TRUE;
885 } else if (FD_ISSET(tmpSocket, &tmpfds)) { 1047 } else if (FD_ISSET(tmpSocket, &tmpfds)) {
1048 ssize_t gotBuf;
1049 char tmpBuf[4096];
886 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); 1050 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0);
887 1051
888 if (gotBuf < 0) { 1052 if (gotBuf < 0) {
889 printMsg("Error in recv: %s\n", strerror(errno)); 1053 printMsg("Error in recv: %s\n", strerror(errno));
890 exitProg = TRUE; 1054 isError = TRUE;
891 } else if (gotBuf == 0) { 1055 } else if (gotBuf == 0) {
892 printMsg("Server closed connection.\n", "Server closed connection.\n"); 1056 printMsg("Server closed connection.\n");
893 exitProg = TRUE; 1057 isError = TRUE;
894 } else { 1058 } else {
895 /* Handle protocol data */ 1059 /* Handle protocol data */
896 tmpBuf[gotBuf] = 0; 1060 tmpBuf[gotBuf] = 0;
897 result = handleProtocol(tmpSocket, tmpBuf, gotBuf); 1061 result = handleProtocol(tmpSocket, tmpBuf, gotBuf);
898 1062
899 if (result > 0) { 1063 if (result > 0) {
900 /* Couldn't handle the message for some reason */ 1064 /* Couldn't handle the message for some reason */
901 printMsg("Could not handle: %s\n", "Could not handle: %s\n", tmpBuf); 1065 printMsg("Could not handle: %s\n", tmpBuf);
902 } else if (result < 0) { 1066 } else if (result < 0) {
903 /* Fatal error, quit */ 1067 /* Fatal error, quit */
904 printMsg("Fatal error with message: %s\n", tmpBuf); 1068 printMsg("Fatal error with message: %s\n", tmpBuf);
905 exitProg = TRUE; 1069 isError = TRUE;
906 } 1070 }
1071 updateStatus();
907 } 1072 }
908 } 1073 }
909 1074
910 /* Check for user input */ 1075 /* Handle user input */
911 if (!optDaemon) { 1076 if (!optDaemon) {
912 tv.tv_sec = 0; 1077 int c, cnt = 0;
913 tv.tv_usec = SET_SELECT_USEC; 1078 BOOL update = FALSE;
914 tmpfds = inputfds; 1079
915 if ((result = select(1, &tmpfds, NULL, NULL, &tv)) == -1) { 1080 /* Handle several buffered keypresses at once */
916 printMsg("Error occured in select(inputfds): %s\n", strerror(errno)); 1081 do {
917 exitProg = TRUE; 1082 c = getch();
918 } else if (FD_ISSET(0, &tmpfds)) { 1083 switch (c) {
919 gotBuf = read(0, tmpBuf, sizeof(tmpBuf)); 1084 case KEY_ENTER:
920 1085 case '\n':
921 if (gotBuf < 0) { 1086 case '\r':
922 printMsg("Error in reading stdio.\n", "Error in reading stdio.\n"); 1087 /* Call the user input handler */
1088 if (editBuf->len > 0) {
1089 insertBuf(editBuf, editBuf->pos, 0);
1090 result = handleUserInput(tmpSocket, editBuf->data, editBuf->len);
1091 clearBuf(editBuf);
1092
1093 if (result < 0) {
1094 printMsg("Fatal error handling user input: %s\n", editBuf->data);
1095 isError = TRUE;
1096 }
1097
1098 update = TRUE;
1099 }
1100 break;
1101
1102 case 0x109: /* F1 */
1103 if (setInsertMode)
1104 setInsertMode = FALSE;
1105 else
1106 setInsertMode = TRUE;
1107 update = TRUE;
1108 break;
1109
1110 case 0x204: /* ctrl+left */
1111 editBuf->pos--;
1112 while (editBuf->pos > 0 && !isspace(editBuf->data[editBuf->pos]))
1113 editBuf->pos--;
1114 if (editBuf->pos < 0)
1115 editBuf->pos = 0;
1116 update = TRUE;
1117 break;
1118
1119 case 0x206: /* ctrl+right */
1120 editBuf->pos++;
1121 while (editBuf->pos < editBuf->len && !isspace(editBuf->data[editBuf->pos]))
1122 editBuf->pos++;
1123 if (editBuf->pos > editBuf->len)
1124 editBuf->pos = editBuf->len;
1125 update = TRUE;
1126 break;
1127
1128 case 0x111: /* F9 */
1129 printMsg("Quitting per user request.");
923 exitProg = TRUE; 1130 exitProg = TRUE;
924 } else { 1131 break;
925 /* Call the user input handler */ 1132
926 result = handleUserInput(tmpSocket, tmpBuf, gotBuf); 1133 case 0x10a: /* F2 */
927 if (result < 0) { 1134 clearBuf(editBuf);
928 printMsg("Fatal error handling user input: %s\n", 1135 update = TRUE;
929 tmpBuf); 1136 break;
930 exitProg = TRUE; 1137
1138 case KEY_HOME: setBufPos(editBuf, 0); update = TRUE; break;
1139 case KEY_END: setBufPos(editBuf, editBuf->len); update = TRUE; break;
1140 case KEY_LEFT: setBufPos(editBuf, editBuf->pos - 1); update = TRUE; break;
1141 case KEY_RIGHT: setBufPos(editBuf, editBuf->pos + 1); update = TRUE; break;
1142
1143 case KEY_BACKSPACE:
1144 deleteBuf(editBuf, editBuf->pos - 1);
1145 setBufPos(editBuf, editBuf->pos - 1);
1146 update = TRUE;
1147 break;
1148
1149 case 0x14a:
1150 /* Delete */
1151 deleteBuf(editBuf, editBuf->pos);
1152 update = TRUE;
1153 break;
1154
1155 case 0x0c:
1156 /* ctrl+l */
1157 redrawwin(mainWin);
1158 redrawwin(statusWin);
1159 redrawwin(editWin);
1160 break;
1161
1162 case ERR:
1163 /* Ignore */
1164 break;
1165
1166 default:
1167 if (isprint(c)) {
1168 if (setInsertMode)
1169 insertBuf(editBuf, editBuf->pos, c);
1170 else
1171 writeBuf(editBuf, editBuf->pos, c);
1172 setBufPos(editBuf, editBuf->pos + 1);
1173 update = TRUE;
1174 } else {
1175 printMsg("Unhandled key: %02x\n", c);
931 } 1176 }
1177 break;
932 } 1178 }
933 } 1179 } while (c != ERR && !exitProg && ++cnt < 10);
1180
1181 if (update) {
1182 /* Update edit line */
1183 printEditBuf(editBuf);
1184 updateStatus();
1185 }
934 } /* !optDaemon */ 1186 } /* !optDaemon */
1187
1188 if (++updateCount > 10) {
1189 updateStatus();
1190 updateCount = 0;
1191 }
935 1192
936 if (!colorSet) { 1193 if (!colorSet) {
937 colorSet = TRUE; 1194 colorSet = TRUE;
938 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 1195 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
939 } 1196 }
940 1197 }
941 fflush(stdout); 1198
942 fflush(stderr); 1199 /* Shutdown */
943 }
944
945 /* Shotdiwn */
946 err_exit: 1200 err_exit:
947 THMSG(1, "Error exit.\n"); 1201 if (cursesInit) {
1202 if (curVis != ERR)
1203 curs_set(curVis);
1204 endwin();
1205 THMSG(1, "NCurses deinitialized.\n");
1206 }
1207
1208 if (isError) {
1209 THMSG(1, "Error exit.\n");
1210 }
1211
948 th_free(optUserName2); 1212 th_free(optUserName2);
949 1213
950 closeConnection(tmpSocket); 1214 closeConnection(tmpSocket);
951 1215
952 #ifdef __WIN32
953 WSACleanup();
954 #endif
955
956 THMSG(1, "Connection terminated.\n"); 1216 THMSG(1, "Connection terminated.\n");
957 1217
958 if (optLogFile) { 1218 if (optLogFile) {
959 THMSG(1, "Closing logfile.\n"); 1219 THMSG(1, "Closing logfile.\n");
960 fclose(optLogFile); 1220 fclose(optLogFile);
961 } 1221 }
962 1222
963
964 return 0; 1223 return 0;
965 } 1224 }