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