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