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