Mercurial > hg > nnchat
comparison nnchat.c @ 0:728243125263
Import.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 20 Mar 2008 00:15:03 +0000 |
parents | |
children | 351e96e01f4c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:728243125263 |
---|---|
1 #ifdef __WIN32 | |
2 #include <winsock2.h> | |
3 #else | |
4 #include <sys/socket.h> | |
5 #include <sys/types.h> | |
6 #include <arpa/inet.h> | |
7 #include <sys/time.h> | |
8 #include <netdb.h> | |
9 #endif | |
10 | |
11 #include <unistd.h> | |
12 #include <stdlib.h> | |
13 #include <stdio.h> | |
14 #include "th_args.h" | |
15 #include "th_string.h" | |
16 #include <string.h> | |
17 #include <errno.h> | |
18 #include <time.h> | |
19 | |
20 | |
21 #define SET_ALLOC_SIZE (128) | |
22 #define SET_SELECT_USEC (100000) | |
23 | |
24 | |
25 /* Options | |
26 */ | |
27 int optPort = 8005; | |
28 int optUserColor = 0x408060; | |
29 char *optServer = "www11.servemedata.com", | |
30 *optUserName = NULL, | |
31 *optUserName2 = NULL, | |
32 *optPassword = NULL, | |
33 *optLogFilename = NULL; | |
34 | |
35 FILE *optLogFile = NULL; | |
36 | |
37 | |
38 /* Arguments | |
39 */ | |
40 optarg_t optList[] = { | |
41 { 0, '?', "help", "Show this help", OPT_NONE }, | |
42 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, | |
43 { 2, 'p', "port", "Connect to port", OPT_ARGREQ }, | |
44 { 3, 's', "server", "Server to connect to", OPT_ARGREQ }, | |
45 { 4, 'C', "color", "Initial color in RGB hex 000000", OPT_ARGREQ }, | |
46 { 5, 'l', "logfile", "Log filename", OPT_ARGREQ }, | |
47 /* | |
48 { 6, 'p', "plaintext", "Use plaintext logging", OPT_NONE }, | |
49 */ | |
50 }; | |
51 | |
52 const int optListN = (sizeof(optList) / sizeof(optarg_t)); | |
53 | |
54 | |
55 void argShowHelp() | |
56 { | |
57 th_args_help(stdout, optList, optListN, th_prog_name, | |
58 "[options] <username> <password>"); | |
59 } | |
60 | |
61 | |
62 #ifdef __WIN32 | |
63 const char *hstrerror(int err) | |
64 { | |
65 return "???"; | |
66 } | |
67 #endif | |
68 | |
69 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
70 { | |
71 switch (optN) { | |
72 case 0: | |
73 argShowHelp(); | |
74 exit(0); | |
75 break; | |
76 | |
77 case 1: | |
78 th_verbosityLevel++; | |
79 break; | |
80 | |
81 case 2: | |
82 optPort = atoi(optArg); | |
83 break; | |
84 | |
85 case 3: | |
86 optServer = optArg; | |
87 break; | |
88 | |
89 case 4: | |
90 if (sscanf(optArg, "%06x", &optUserColor) != 1) { | |
91 THERR("Invalid color argument '%s', should be a RGB hex triplet '000000'.\n", | |
92 optArg); | |
93 return FALSE; | |
94 } | |
95 THMSG(1, "Using color #%06x\n", optUserColor); | |
96 break; | |
97 | |
98 case 5: | |
99 optLogFilename = optArg; | |
100 break; | |
101 | |
102 default: | |
103 THERR("Unknown option '%s'.\n", currArg); | |
104 return FALSE; | |
105 } | |
106 | |
107 return TRUE; | |
108 } | |
109 | |
110 | |
111 BOOL argHandleFile(char *currArg) | |
112 { | |
113 if (!optUserName) | |
114 optUserName = currArg; | |
115 else if (!optPassword) | |
116 optPassword = currArg; | |
117 else { | |
118 THERR("Username '%s' already specified on commandline!\n", optUserName); | |
119 return FALSE; | |
120 } | |
121 | |
122 return TRUE; | |
123 } | |
124 | |
125 | |
126 BOOL sendToSocket(int sock, char *buf, const size_t bufLen) | |
127 { | |
128 size_t bufLeft = bufLen; | |
129 char *bufPtr = buf; | |
130 | |
131 while (bufLeft > 0) { | |
132 ssize_t bufSent; | |
133 bufSent = send(sock, bufPtr, bufLeft, 0); | |
134 if (bufSent < 0) return FALSE; | |
135 bufLeft -= bufSent; | |
136 bufPtr += bufSent; | |
137 } | |
138 return TRUE; | |
139 } | |
140 | |
141 | |
142 void printMsg(char *fmt, ...) | |
143 { | |
144 char tmpStr[64] = ""; | |
145 va_list ap; | |
146 time_t timeStamp; | |
147 struct tm *tmpTime;; | |
148 | |
149 timeStamp = time(NULL); | |
150 if ((tmpTime = localtime(&timeStamp)) != NULL) { | |
151 strftime(tmpStr, sizeof(tmpStr), "[%H:%M:%S] ", tmpTime); | |
152 } | |
153 | |
154 if (optLogFile) { | |
155 fputs(tmpStr, optLogFile); | |
156 va_start(ap, fmt); | |
157 vfprintf(optLogFile, fmt, ap); | |
158 va_end(ap); | |
159 fflush(optLogFile); | |
160 } | |
161 | |
162 fputs(tmpStr, stdout); | |
163 va_start(ap, fmt); | |
164 vfprintf(stdout, fmt, ap); | |
165 va_end(ap); | |
166 fflush(stdout); | |
167 } | |
168 | |
169 | |
170 BOOL bufRealloc(char **buf, size_t *size, size_t add) | |
171 { | |
172 return ((*buf = th_realloc(*buf, *size + add)) != NULL); | |
173 } | |
174 | |
175 #define pushChar(x) bufPushChar(&result, &resSize, &resPos, x) | |
176 BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch) | |
177 { | |
178 if (*pos >= *size && !bufRealloc(buf, size, SET_ALLOC_SIZE)) | |
179 return FALSE; | |
180 | |
181 (*buf)[*pos] = ch; | |
182 (*pos)++; | |
183 return TRUE; | |
184 } | |
185 | |
186 #define pushStr(x) bufPushStr(&result, &resSize, &resPos, x) | |
187 BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str) | |
188 { | |
189 size_t tmpLen; | |
190 | |
191 if (!str) return FALSE; | |
192 tmpLen = strlen(str); | |
193 | |
194 if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + SET_ALLOC_SIZE)) | |
195 return FALSE; | |
196 | |
197 strcpy(*buf + *pos, str); | |
198 (*pos) += tmpLen; | |
199 return TRUE; | |
200 } | |
201 | |
202 | |
203 char *encodeStr1(char *str) | |
204 { | |
205 char *result, *s = str; | |
206 size_t resSize, resPos = 0; | |
207 | |
208 if (!str) return NULL; | |
209 | |
210 resSize = strlen(str) + SET_ALLOC_SIZE; | |
211 if ((result = th_malloc(resSize)) == NULL) | |
212 return NULL; | |
213 | |
214 while (*s) { | |
215 switch (*s) { | |
216 case 32: | |
217 pushChar('+'); | |
218 break; | |
219 | |
220 default: | |
221 if (th_isalnum(*s)) | |
222 pushChar(*s); | |
223 else { | |
224 char tmpStr[4]; | |
225 sprintf(tmpStr, "%2X", (unsigned char) *s); | |
226 pushChar('%'); | |
227 pushStr(tmpStr); | |
228 } | |
229 break; | |
230 } | |
231 s++; | |
232 } | |
233 pushChar(0); | |
234 | |
235 return result; | |
236 } | |
237 | |
238 int getxdigit(int c, int shift) | |
239 { | |
240 int i; | |
241 | |
242 if (c >= 'A' && c <= 'F') | |
243 i = c - 'A' + 10; | |
244 else if (c >= 'a' && c <= 'f') | |
245 i = c - 'a' + 10; | |
246 else if (c >= '0' && c <= '9') | |
247 i = c - '0'; | |
248 else | |
249 return -1; | |
250 | |
251 return i << shift; | |
252 } | |
253 | |
254 char *decodeStr1(char *str) | |
255 { | |
256 char *result, *s = str; | |
257 size_t resSize, resPos = 0; | |
258 int c; | |
259 | |
260 if (!str) return NULL; | |
261 | |
262 resSize = strlen(str) + SET_ALLOC_SIZE; | |
263 if ((result = th_malloc(resSize)) == NULL) | |
264 return NULL; | |
265 | |
266 while (*s) { | |
267 switch (*s) { | |
268 case '+': | |
269 pushChar(' '); | |
270 s++; | |
271 break; | |
272 | |
273 case '%': | |
274 s++; | |
275 if (*s == '%') | |
276 pushChar('%'); | |
277 else if ((c = getxdigit(*s, 4)) >= 0) { | |
278 int i = getxdigit(*(++s), 0); | |
279 if (i >= 0) { | |
280 pushChar(c | i); | |
281 } else { | |
282 pushChar('§'); | |
283 pushChar(*s); | |
284 } | |
285 } else { | |
286 pushChar('§'); | |
287 pushChar(*s); | |
288 } | |
289 s++; | |
290 break; | |
291 | |
292 default: | |
293 pushChar(*s); | |
294 s++; | |
295 } | |
296 } | |
297 pushChar(0); | |
298 | |
299 return result; | |
300 } | |
301 | |
302 | |
303 char *stripTags(char *str) | |
304 { | |
305 char *result, *s = str; | |
306 size_t resSize, resPos = 0; | |
307 | |
308 if (!str) return NULL; | |
309 | |
310 resSize = strlen(str) + SET_ALLOC_SIZE; | |
311 if ((result = th_malloc(resSize)) == NULL) | |
312 return NULL; | |
313 | |
314 while (*s) { | |
315 if (*s == '<') { | |
316 while (*s && *s != '>') s++; | |
317 if (*s == '>') s++; | |
318 } else | |
319 pushChar(*s++); | |
320 } | |
321 pushChar(0); | |
322 | |
323 return result; | |
324 } | |
325 | |
326 | |
327 typedef struct { | |
328 char c; | |
329 char *ent; | |
330 } html_entity_t; | |
331 | |
332 | |
333 html_entity_t HTMLEntities[] = { | |
334 { '<', "<" }, | |
335 { '>', ">" }, | |
336 /* | |
337 { '&', "&" }, | |
338 { 'ä', "ä" }, | |
339 { 'ö', "ö" }, | |
340 { 'Ä', "Ä" }, | |
341 { 'Ö', "Ö" }, | |
342 */ | |
343 }; | |
344 | |
345 const int numHTMLEntities = (sizeof(HTMLEntities) / sizeof(html_entity_t)); | |
346 | |
347 | |
348 char *encodeStr2(char *str) | |
349 { | |
350 char *result, *s = str; | |
351 size_t resSize, resPos = 0; | |
352 | |
353 if (!str) return NULL; | |
354 | |
355 resSize = strlen(str) + SET_ALLOC_SIZE; | |
356 if ((result = th_malloc(resSize)) == NULL) | |
357 return NULL; | |
358 | |
359 while (*s) { | |
360 int i; | |
361 BOOL found = FALSE; | |
362 for (i = 0; i < numHTMLEntities; i++) | |
363 if (HTMLEntities[i].c == *s) { | |
364 pushStr(HTMLEntities[i].ent); | |
365 found = TRUE; | |
366 break; | |
367 } | |
368 if (!found) pushChar(*s); | |
369 | |
370 s++; | |
371 } | |
372 pushChar(0); | |
373 | |
374 return result; | |
375 } | |
376 | |
377 | |
378 char *decodeStr2(char *str) | |
379 { | |
380 char *result, *s = str; | |
381 size_t resSize, resPos = 0; | |
382 | |
383 if (!str) return NULL; | |
384 | |
385 resSize = strlen(str); | |
386 if ((result = th_malloc(resSize)) == NULL) | |
387 return NULL; | |
388 | |
389 while (*s) { | |
390 if (*s == '&') { | |
391 int i; | |
392 BOOL found = FALSE; | |
393 for (i = 0; i < numHTMLEntities; i++) { | |
394 html_entity_t *ent = &HTMLEntities[i]; | |
395 int len = strlen(ent->ent); | |
396 if (!strncmp(s, ent->ent, len)) { | |
397 pushChar(ent->c); | |
398 s += len; | |
399 found = TRUE; | |
400 break; | |
401 } | |
402 } | |
403 if (!found) pushChar(*s++); | |
404 } else | |
405 pushChar(*s++); | |
406 } | |
407 pushChar(0); | |
408 | |
409 return result; | |
410 } | |
411 | |
412 | |
413 BOOL sendUserMsg(int sock, char *user, char *fmt, ...) | |
414 { | |
415 char tmpBuf[4096], tmpBuf2[4096+256]; | |
416 int n; | |
417 va_list ap; | |
418 | |
419 va_start(ap, fmt); | |
420 n = vsnprintf(tmpBuf, sizeof(tmpBuf), fmt, ap); | |
421 va_end(ap); | |
422 | |
423 if (n < 0) return FALSE; | |
424 | |
425 snprintf(tmpBuf2, sizeof(tmpBuf2), | |
426 "<USER>%s</USER><MESSAGE>%s</MESSAGE>", | |
427 user, tmpBuf); | |
428 | |
429 return sendToSocket(sock, tmpBuf2, strlen(tmpBuf2) + 1); | |
430 } | |
431 | |
432 | |
433 int handleUser(int sock, char *str) | |
434 { | |
435 const char *msg = "</USER><MESSAGE>"; | |
436 char *p = str, *q, *s; | |
437 | |
438 (void) sock; | |
439 | |
440 s = strstr(str, msg); | |
441 if (!s) return 1; | |
442 *s = 0; | |
443 s += strlen(msg); | |
444 | |
445 q = strstr(s, "</MESSAGE>"); | |
446 if (!q) return 3; | |
447 *q = 0; | |
448 | |
449 s = decodeStr1(s); | |
450 if (!s) return -1; | |
451 | |
452 p = decodeStr1(p); | |
453 if (!p) { | |
454 th_free(s); | |
455 return -2; | |
456 } | |
457 | |
458 /* FIXME: decodeStr2() */ | |
459 | |
460 if (*s == '/') { | |
461 char *t = stripTags(s+1); | |
462 printMsg("* %s\n", t); | |
463 th_free(t); | |
464 } else { | |
465 char *t = stripTags(s); | |
466 printMsg("<%s> %s\n", p, t); | |
467 th_free(t); | |
468 } | |
469 | |
470 th_free(s); | |
471 th_free(p); | |
472 return 0; | |
473 } | |
474 | |
475 | |
476 int handleLogin(int sock, char *str) | |
477 { | |
478 if (!strncmp(str, "FAILURE", 7)) { | |
479 printMsg("Login failure.\n"); | |
480 return -2; | |
481 } else if (!strncmp(str, "SUCCESS", 7)) { | |
482 printMsg("Login success.\n"); | |
483 sendUserMsg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); | |
484 return 0; | |
485 } else | |
486 return 1; | |
487 } | |
488 | |
489 | |
490 int handleAddUser(int sock, char *str) | |
491 { | |
492 char *s = strstr(str, "</ADD_USER>"); | |
493 | |
494 (void) sock; | |
495 | |
496 if (!s) return 1; | |
497 *s = 0; | |
498 printMsg("! %s ADDED.\n", str); | |
499 return 0; | |
500 } | |
501 | |
502 | |
503 int handleDeleteUser(int sock, char *str) | |
504 { | |
505 char *s = strstr(str, "</DELETE_USER>"); | |
506 | |
507 (void) sock; | |
508 | |
509 if (!s) return 1; | |
510 *s = 0; | |
511 printMsg("! %s DELETED.\n", str); | |
512 return 0; | |
513 } | |
514 | |
515 | |
516 int handleFoo(int sock, char *str) | |
517 { | |
518 (void) sock; (void) str; | |
519 | |
520 return 0; | |
521 } | |
522 | |
523 | |
524 typedef struct { | |
525 char *cmd; | |
526 int (*handler)(int, char *); | |
527 } protocmd_t; | |
528 | |
529 | |
530 protocmd_t protoCmds[] = { | |
531 { "<USER>", handleUser }, | |
532 { "<LOGIN_", handleLogin }, | |
533 { "<DELETE_USER>", handleDeleteUser }, | |
534 { "<ADD_USER>", handleAddUser }, | |
535 { "<NUMCLIENTS>", handleFoo }, | |
536 }; | |
537 | |
538 const int nprotoCmds = (sizeof(protoCmds) / sizeof(protocmd_t)); | |
539 | |
540 | |
541 int handleProtocol(int sock, char *buf, size_t bufLen) | |
542 { | |
543 int i; | |
544 | |
545 for (i = 0; i < nprotoCmds; i++) { | |
546 size_t cmdLen = strlen(protoCmds[i].cmd); | |
547 if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen)) { | |
548 return protoCmds[i].handler(sock, buf + cmdLen); | |
549 } | |
550 } | |
551 | |
552 return 1; | |
553 } | |
554 | |
555 | |
556 int handleInput(int sock, char *buf, size_t bufLen) | |
557 { | |
558 char *tmpStr, *tmpStr2; | |
559 BOOL result; | |
560 | |
561 /* Trim right */ | |
562 buf[--bufLen] = 0; | |
563 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen]))) | |
564 buf[bufLen--] = 0; | |
565 | |
566 //fprintf(stderr, "'%s'\n", buf); fflush(stderr); | |
567 | |
568 /* Check command */ | |
569 if (*buf == 0) { | |
570 return 1; | |
571 } else if (*buf == '@') { | |
572 /* Send 1-pass encoded 'RAW' */ | |
573 buf++; | |
574 printf("RAW>%s\n", buf); | |
575 fflush(stdout); | |
576 | |
577 tmpStr = encodeStr1(buf); | |
578 if (!tmpStr) return -2; | |
579 | |
580 result = sendUserMsg(sock, optUserName2, "%s", tmpStr); | |
581 th_free(tmpStr); | |
582 if (result) | |
583 return 0; | |
584 else | |
585 return -1; | |
586 } else { | |
587 /* Send double-encoded */ | |
588 printf("ENC>%s\n", buf); | |
589 fflush(stdout); | |
590 | |
591 tmpStr = encodeStr2(buf); | |
592 if (!tmpStr) return -2; | |
593 tmpStr2 = encodeStr1(tmpStr); | |
594 if (!tmpStr2) { | |
595 th_free(tmpStr); | |
596 return -3; | |
597 } | |
598 | |
599 result = sendUserMsg(sock, optUserName2, "%s", tmpStr2); | |
600 th_free(tmpStr); | |
601 th_free(tmpStr2); | |
602 if (result) | |
603 return 0; | |
604 else | |
605 return -1; | |
606 } | |
607 } | |
608 | |
609 | |
610 int main(int argc, char *argv[]) | |
611 { | |
612 int tmpSocket; | |
613 struct hostent *tmpHost; | |
614 struct sockaddr_in tmpAddr; | |
615 BOOL exitProg = FALSE; | |
616 | |
617 /* Initialize */ | |
618 th_init("NNChat", "Newbie Nudes chat client", "0.2", NULL, NULL); | |
619 th_verbosityLevel = 0; | |
620 | |
621 /* Parse arguments */ | |
622 th_args_process(argc, argv, optList, optListN, | |
623 argHandleOpt, argHandleFile, FALSE); | |
624 | |
625 /* Check the mode and arguments */ | |
626 if (optUserName == NULL || optPassword == NULL) { | |
627 THERR("User/pass not specified, get some --help\n"); | |
628 return -1; | |
629 } | |
630 | |
631 /* Open logfile */ | |
632 if (optLogFilename) { | |
633 THMSG(1, "Opening logfile '%s'\n", optLogFilename); | |
634 | |
635 if ((optLogFile = fopen(optLogFilename, "a")) == NULL) { | |
636 THERR("Could not open logfile for appending!\n"); | |
637 return -9; | |
638 } | |
639 } | |
640 | |
641 /* Okay ... */ | |
642 THMSG(1, "Trying to resolve host '%s' ...\n", optServer); | |
643 tmpHost = gethostbyname(optServer); | |
644 if (tmpHost == NULL) { | |
645 THERR("Could not resolve hostname: %s.\n", | |
646 hstrerror(h_errno)); | |
647 return -3; | |
648 } | |
649 THMSG(2, "True hostname: %s\n", tmpHost->h_name); | |
650 | |
651 tmpAddr.sin_family = AF_INET; | |
652 tmpAddr.sin_port = htons(optPort); | |
653 tmpAddr.sin_addr = *((struct in_addr *) tmpHost->h_addr); | |
654 | |
655 THMSG(1, "Connecting to %s:%d ...\n", | |
656 inet_ntoa(tmpAddr.sin_addr), optPort); | |
657 | |
658 if ((tmpSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) { | |
659 THERR("Could not open socket: %s\n", strerror(errno)); | |
660 return -2; | |
661 } | |
662 | |
663 THMSG(2, "Using socket %d.\n", tmpSocket); | |
664 | |
665 if (connect(tmpSocket, (struct sockaddr *) &tmpAddr, sizeof(tmpAddr)) == -1) { | |
666 THERR("Could not connect: %s\n", strerror(errno)); | |
667 return -5; | |
668 } | |
669 | |
670 THMSG(1, "Connected, logging in as '%s'.\n", optUserName); | |
671 optUserName2 = encodeStr1(optUserName); | |
672 | |
673 sendUserMsg(tmpSocket, optUserName2, "%%2Flogin%%20%%2Dsite%%20NN%%20%%2Dpassword%%20%s", optPassword); | |
674 | |
675 struct timeval tv; | |
676 fd_set sockfds; | |
677 fd_set inputfds; | |
678 | |
679 | |
680 FD_ZERO(&inputfds); | |
681 FD_SET(0, &inputfds); | |
682 | |
683 FD_ZERO(&sockfds); | |
684 FD_SET(tmpSocket, &sockfds); | |
685 | |
686 while (!exitProg) { | |
687 ssize_t gotBuf; | |
688 int result; | |
689 char tmpBuf[4096]; | |
690 fd_set tmpfds; | |
691 | |
692 /* Check for incoming data from the server */ | |
693 tv.tv_sec = 0; | |
694 tv.tv_usec = SET_SELECT_USEC; | |
695 tmpfds = sockfds; | |
696 if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &tv)) == -1) { | |
697 THERR("Error occured in select(sockfds): %s\n", strerror(errno)); | |
698 exitProg = TRUE; | |
699 } else if (FD_ISSET(tmpSocket, &tmpfds)) { | |
700 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); | |
701 | |
702 if (gotBuf < 0) { | |
703 THERR("Error in recv: %s\n", strerror(errno)); | |
704 exitProg = TRUE; | |
705 } else if (gotBuf == 0) { | |
706 THERR("Server closed connection.\n"); | |
707 exitProg = TRUE; | |
708 } else { | |
709 /* Handle protocol data */ | |
710 tmpBuf[gotBuf] = 0; | |
711 result = handleProtocol(tmpSocket, tmpBuf, gotBuf); | |
712 | |
713 if (result > 0) { | |
714 /* Couldn't handle the message for some reason */ | |
715 THERR("Could not handle: %s\n", tmpBuf); | |
716 } else if (result < 0) { | |
717 /* Fatal error, quit */ | |
718 THERR("Fatal error with message: %s\n", tmpBuf); | |
719 exitProg = TRUE; | |
720 } | |
721 } | |
722 } | |
723 | |
724 /* Check for user input */ | |
725 tv.tv_sec = 0; | |
726 tv.tv_usec = SET_SELECT_USEC; | |
727 tmpfds = inputfds; | |
728 if ((result = select(1, &tmpfds, NULL, NULL, &tv)) == -1) { | |
729 THERR("Error occured in select(inputfds): %s\n", strerror(errno)); | |
730 exitProg = TRUE; | |
731 } else if (FD_ISSET(0, &tmpfds)) { | |
732 gotBuf = read(0, tmpBuf, sizeof(tmpBuf)); | |
733 | |
734 if (gotBuf < 0) { | |
735 THERR("Error in reading stdio.\n"); | |
736 exitProg = TRUE; | |
737 } else { | |
738 /* Call the user input handler */ | |
739 result = handleInput(tmpSocket, tmpBuf, gotBuf); | |
740 if (result < 0) { | |
741 THERR("Fatal error handling user input: %s\n", | |
742 tmpBuf); | |
743 exitProg = TRUE; | |
744 } | |
745 } | |
746 } | |
747 | |
748 fflush(stdout); | |
749 fflush(stderr); | |
750 } | |
751 | |
752 /* .. */ | |
753 th_free(optUserName2); | |
754 close(tmpSocket); | |
755 | |
756 if (optLogFile) { | |
757 THMSG(1, "Closing logfile.\n"); | |
758 fclose(optLogFile); | |
759 } | |
760 | |
761 THMSG(1, "Connection terminated.\n"); | |
762 | |
763 return 0; | |
764 } |