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