comparison nnchat.c @ 391:a2b7ac328e62 dev-0_9_12

Code cleanup.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 24 May 2012 00:55:45 +0300
parents 19cb995994c9
children 932829a556c7
comparison
equal deleted inserted replaced
390:acea18a741e3 391:a2b7ac328e62
73 cfgitem_t *cfg = NULL; 73 cfgitem_t *cfg = NULL;
74 74
75 75
76 /* Logging mode flags 76 /* Logging mode flags
77 */ 77 */
78 enum { 78 enum
79 {
79 LOG_FILE = 1, 80 LOG_FILE = 1,
80 LOG_WINDOW = 2, 81 LOG_WINDOW = 2,
81 LOG_STAMP = 4 82 LOG_STAMP = 4
82 }; 83 };
83 84
84 85
85 /* Arguments 86 /* Arguments
86 */ 87 */
87 optarg_t optList[] = { 88 optarg_t optList[] =
89 {
88 { 0, '?', "help", "Show this help", OPT_NONE }, 90 { 0, '?', "help", "Show this help", OPT_NONE },
89 { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, 91 { 1, 'v', "verbose", "Be more verbose", OPT_NONE },
90 { 2, 'p', "port", "Connect to port", OPT_ARGREQ }, 92 { 2, 'p', "port", "Connect to port", OPT_ARGREQ },
91 { 3, 's', "server", "Server to connect to", OPT_ARGREQ }, 93 { 3, 's', "server", "Server to connect to", OPT_ARGREQ },
92 { 4, 'C', "color", "Initial color in RGB hex 000000", OPT_ARGREQ }, 94 { 4, 'C', "color", "Initial color in RGB hex 000000", OPT_ARGREQ },
93 { 5, 'l', "logfile", "Log filename", OPT_ARGREQ }, 95 { 5, 'l', "logfile", "Log filename", OPT_ARGREQ },
94 { 6, 'D', "daemon", "A pseudo-daemon mode for logging", OPT_NONE }, 96 { 6, 'D', "daemon", "A pseudo-daemon mode for logging", OPT_NONE },
95 { 7, 'f', "force-site", "Force site (default: NN)", OPT_ARGREQ }, 97 { 7, 'f', "force-site", "Force site (default: NN)", OPT_ARGREQ },
96 { 8, 'd', "debug", "Enable various debug features", OPT_NONE }, 98 { 8, 'd', "debug", "Enable various debug features", OPT_NONE },
97 99
98 {10, '4', "socks4", "SOCKS4 proxy server", OPT_ARGREQ }, 100 {10, '4', "socks4", "SOCKS4 proxy server", OPT_ARGREQ },
99 {11, 'A', "socks4a", "SOCKS4A proxy server", OPT_ARGREQ }, 101 {11, 'A', "socks4a", "SOCKS4A proxy server", OPT_ARGREQ },
100 {12, 'P', "proxy-port", "Proxy port (default: 1080)", OPT_ARGREQ }, 102 {12, 'P', "proxy-port", "Proxy port (default: 1080)", OPT_ARGREQ },
101 }; 103 };
102 104
104 106
105 107
106 void argShowHelp(void) 108 void argShowHelp(void)
107 { 109 {
108 th_print_banner(stdout, th_prog_name, 110 th_print_banner(stdout, th_prog_name,
109 "[options] <username> <password>"); 111 "[options] <username> <password>");
110 112
111 th_args_help(stdout, optList, optListN); 113 th_args_help(stdout, optList, optListN);
112 } 114 }
113 115
114 116
115 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) 117 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
116 { 118 {
117 switch (optN) { 119 switch (optN)
120 {
118 case 0: 121 case 0:
119 argShowHelp(); 122 argShowHelp();
120 exit(0); 123 exit(0);
121 break; 124 break;
122 125
123 case 1: 126 case 1:
124 th_verbosityLevel++; 127 th_verbosityLevel++;
125 break; 128 break;
126 129
127 case 2: 130 case 2:
128 optPort = atoi(optArg); 131 optPort = atoi(optArg);
129 break; 132 break;
130 133
131 case 3: 134 case 3:
132 optServer = optArg; 135 optServer = optArg;
133 break; 136 break;
134 137
135 case 4: 138 case 4:
136 if ((optUserColor = th_get_hex_triplet(optArg)) < 0) { 139 if ((optUserColor = th_get_hex_triplet(optArg)) < 0)
140 {
137 THERR("Invalid color argument '%s', should be a RGB hex triplet '000000'.\n", 141 THERR("Invalid color argument '%s', should be a RGB hex triplet '000000'.\n",
138 optArg); 142 optArg);
139 return FALSE; 143 return FALSE;
140 } 144 }
141 THMSG(1, "Using color #%06x\n", optUserColor); 145 THMSG(1, "Using color #%06x\n", optUserColor);
178 182
179 default: 183 default:
180 THERR("Unknown option '%s'.\n", currArg); 184 THERR("Unknown option '%s'.\n", currArg);
181 return FALSE; 185 return FALSE;
182 } 186 }
183 187
184 return TRUE; 188 return TRUE;
185 } 189 }
186 190
187 191
188 BOOL argHandleFile(char *currArg) 192 BOOL argHandleFile(char *currArg)
189 { 193 {
190 if (!optUserNameCmd) 194 if (!optUserNameCmd)
191 optUserNameCmd = currArg; 195 optUserNameCmd = currArg;
192 else if (!optPasswordCmd) 196 else if (!optPasswordCmd)
193 optPasswordCmd = currArg; 197 optPasswordCmd = currArg;
194 else { 198 else
199 {
195 THERR("Username '%s' already specified on commandline!\n", optUserNameCmd); 200 THERR("Username '%s' already specified on commandline!\n", optUserNameCmd);
196 return FALSE; 201 return FALSE;
197 } 202 }
198 203
199 return TRUE; 204 return TRUE;
200 } 205 }
201 206
202 BOOL getTimeStamp(char *str, size_t len, const char *fmt) 207 BOOL getTimeStamp(char *str, size_t len, const char *fmt)
203 { 208 {
204 time_t stamp = time(NULL); 209 time_t stamp = time(NULL);
205 struct tm *stamp_tm; 210 struct tm *stamp_tm;
206 if ((stamp_tm = localtime(&stamp)) != NULL) { 211 if ((stamp_tm = localtime(&stamp)) != NULL)
212 {
207 strftime(str, len, fmt, stamp_tm); 213 strftime(str, len, fmt, stamp_tm);
208 return TRUE; 214 return TRUE;
209 } else { 215 }
216 else
217 {
210 str[0] = 0; 218 str[0] = 0;
211 return FALSE; 219 return FALSE;
212 } 220 }
213 } 221 }
214 222
236 244
237 if ((res = nn_window_new(name)) == NULL) 245 if ((res = nn_window_new(name)) == NULL)
238 return FALSE; 246 return FALSE;
239 247
240 for (i = 1; i < SET_MAX_WINDOWS; i++) 248 for (i = 1; i < SET_MAX_WINDOWS; i++)
241 if (chatWindows[i] == NULL) { 249 if (chatWindows[i] == NULL)
242 res->num = i; 250 {
243 chatWindows[i] = res; 251 res->num = i;
244 if (curwin) 252 chatWindows[i] = res;
245 currWin = res; 253 if (curwin)
246 return TRUE; 254 currWin = res;
247 } 255 return TRUE;
248 256 }
257
249 return FALSE; 258 return FALSE;
250 } 259 }
251 260
252 261
253 void closeWindow(nn_window_t *win) 262 void closeWindow(nn_window_t *win)
254 { 263 {
255 int i; 264 int i;
256 if (win == NULL) return; 265 if (win == NULL) return;
257 266
258 for (i = 1; i < SET_MAX_WINDOWS; i++) 267 for (i = 1; i < SET_MAX_WINDOWS; i++)
259 if (chatWindows[i] == win) { 268 if (chatWindows[i] == win)
260 chatWindows[i] = NULL; 269 {
261 nn_window_free(win); 270 chatWindows[i] = NULL;
262 return; 271 nn_window_free(win);
263 } 272 return;
273 }
264 } 274 }
265 275
266 276
267 void updateStatus(void) 277 void updateStatus(void)
268 { 278 {
269 char tmpStr[128]; 279 char tmpStr[128];
270 int i; 280 int i;
271 281
272 if (statusWin == NULL) return; 282 if (statusWin == NULL) return;
273 283
274 getTimeStamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); 284 getTimeStamp(tmpStr, sizeof(tmpStr), "%H:%M:%S");
275 285
276 wbkgdset(statusWin, COLOR_PAIR(10)); 286 wbkgdset(statusWin, COLOR_PAIR(10));
277 werase(statusWin); 287 werase(statusWin);
278 288
279 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); 289 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
280 mvwaddstr(statusWin, 0, 1, tmpStr); 290 mvwaddstr(statusWin, 0, 1, tmpStr);
281 291
282 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 292 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
283 waddstr(statusWin, " | "); 293 waddstr(statusWin, " | ");
284 wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); 294 wattrset(statusWin, A_BOLD | COLOR_PAIR(16));
285 waddstr(statusWin, optUserName); 295 waddstr(statusWin, optUserName);
286 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 296 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
302 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 312 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
303 waddstr(statusWin, " | "); 313 waddstr(statusWin, " | ");
304 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); 314 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
305 315
306 for (i = 0; i < SET_MAX_WINDOWS; i++) 316 for (i = 0; i < SET_MAX_WINDOWS; i++)
307 if (chatWindows[i] != NULL && chatWindows[i]->dirty) { 317 if (chatWindows[i] != NULL && chatWindows[i]->dirty)
308 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1); 318 {
309 waddstr(statusWin, tmpStr); 319 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1);
310 } 320 waddstr(statusWin, tmpStr);
321 }
311 322
312 wrefresh(statusWin); 323 wrefresh(statusWin);
313 } 324 }
314 325
315 326
318 char *tmp; 329 char *tmp;
319 if (editWin == NULL || buf == NULL) return; 330 if (editWin == NULL || buf == NULL) return;
320 331
321 buf->data[buf->len] = 0; 332 buf->data[buf->len] = 0;
322 tmp = nn_username_decode(th_strdup(buf->data)); 333 tmp = nn_username_decode(th_strdup(buf->data));
323 334
324 werase(editWin); 335 werase(editWin);
325 336
326 wattrset(editWin, A_NORMAL); 337 wattrset(editWin, A_NORMAL);
327 338
328 if (buf->pos < buf->len) { 339 if (buf->pos < buf->len)
340 {
329 waddnstr(editWin, tmp, buf->pos); 341 waddnstr(editWin, tmp, buf->pos);
330 wattrset(editWin, A_REVERSE); 342 wattrset(editWin, A_REVERSE);
331 waddch(editWin, tmp[buf->pos]); 343 waddch(editWin, tmp[buf->pos]);
332 wattrset(editWin, A_NORMAL); 344 wattrset(editWin, A_NORMAL);
333 waddnstr(editWin, tmp + buf->pos + 1, buf->len - buf->pos - 1); 345 waddnstr(editWin, tmp + buf->pos + 1, buf->len - buf->pos - 1);
334 } else { 346 }
347 else
348 {
335 waddnstr(editWin, tmp, buf->len); 349 waddnstr(editWin, tmp, buf->len);
336 wattrset(editWin, A_REVERSE); 350 wattrset(editWin, A_REVERSE);
337 waddch(editWin, ' '); 351 waddch(editWin, ' ');
338 wattrset(editWin, A_NORMAL); 352 wattrset(editWin, A_NORMAL);
339 } 353 }
345 int printWin(WINDOW *win, const char *fmt) 359 int printWin(WINDOW *win, const char *fmt)
346 { 360 {
347 const char *s = fmt; 361 const char *s = fmt;
348 int col = 0; 362 int col = 0;
349 363
350 while (*s) { 364 while (*s)
351 if (*s == '½') { 365 {
366 if (*s == '½')
367 {
352 s++; 368 s++;
353 if (*s == '½') { 369 if (*s == '½')
370 {
354 waddch(win, ((unsigned char) *s) | col); 371 waddch(win, ((unsigned char) *s) | col);
355 s++; 372 s++;
356 } else { 373 }
374 else
375 {
357 memcpy(&col, s, sizeof(int)); 376 memcpy(&col, s, sizeof(int));
358 s += sizeof(int); 377 s += sizeof(int);
359 } 378 }
360 } else { 379 }
380 else
381 {
361 waddch(win, ((unsigned char) *s) | col); 382 waddch(win, ((unsigned char) *s) | col);
362 s++; 383 s++;
363 } 384 }
364 } 385 }
365 return 0; 386 return 0;
370 391
371 int nn_window_print(nn_window_t *win, const char *fmt) 392 int nn_window_print(nn_window_t *win, const char *fmt)
372 { 393 {
373 const char *s = fmt; 394 const char *s = fmt;
374 int col = 0; 395 int col = 0;
375 while (*s) { 396 while (*s)
376 if (*s == '½') { 397 {
398 if (*s == '½')
399 {
377 s++; 400 s++;
378 if (*s == '½') { 401 if (*s == '½')
402 {
379 QPUTCH(*s); 403 QPUTCH(*s);
380 QPUTCH(*s); 404 QPUTCH(*s);
381 win->chlen++; 405 win->chlen++;
382 } else { 406 }
407 else
408 {
383 int val = 0; 409 int val = 0;
384 while (*s >= '0' && *s <= '9') { 410 while (*s >= '0' && *s <= '9')
411 {
385 val *= 10; 412 val *= 10;
386 val += (*s - '0'); 413 val += (*s - '0');
387 s++; 414 s++;
388 } 415 }
389 if (*s != '½') return -1; 416 if (*s != '½') return -1;
395 422
396 QPUTCH('½'); 423 QPUTCH('½');
397 424
398 if (!th_growbuf(&(win->buf), &(win->bufsize), &(win->len), sizeof(int))) 425 if (!th_growbuf(&(win->buf), &(win->bufsize), &(win->len), sizeof(int)))
399 return -2; 426 return -2;
400 427
401 memcpy(win->buf + win->len, &col, sizeof(int)); 428 memcpy(win->buf + win->len, &col, sizeof(int));
402 win->len += sizeof(int); 429 win->len += sizeof(int);
403 } 430 }
404 } else 431 }
405 if (*s == '\n') { 432 else if (*s == '\n')
433 {
406 QPUTCH('\n'); 434 QPUTCH('\n');
407 QPUTCH(0); 435 QPUTCH(0);
408 th_ringbuf_add(win->data, win->buf); 436 th_ringbuf_add(win->data, win->buf);
409 win->buf = NULL; 437 win->buf = NULL;
410 win->chlen = 0; 438 win->chlen = 0;
411 win->dirty = TRUE; 439 win->dirty = TRUE;
412 } 440 }
413 else 441 else if (*s != '\r')
414 if (*s != '\r') { 442 {
415 QPUTCH((unsigned char) *s == 255 ? ' ' : *s); 443 QPUTCH((unsigned char) *s == 255 ? ' ' : *s);
416 win->chlen++; 444 win->chlen++;
417 } 445 }
418 446
419 s++; 447 s++;
441 h = getmaxy(mainWin); 469 h = getmaxy(mainWin);
442 470
443 /* Clear and redraw window */ 471 /* Clear and redraw window */
444 werase(mainWin); 472 werase(mainWin);
445 scrollok(mainWin, 1); 473 scrollok(mainWin, 1);
446 for (offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size; offs++) { 474 for (offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size; offs++)
475 {
447 if (buf->data[offs] != NULL) 476 if (buf->data[offs] != NULL)
448 printWin(mainWin, buf->data[offs]); 477 printWin(mainWin, buf->data[offs]);
449 } 478 }
450 479
451 currWin->dirty = FALSE; 480 currWin->dirty = FALSE;
452 wrefresh(mainWin); 481 wrefresh(mainWin);
453 return TRUE; 482 return TRUE;
454 } 483 }
455 484
456 485
457 int printFile(FILE *outFile, const char *fmt) 486 int printFile(FILE *outFile, const char *fmt)
458 { 487 {
459 const char *s = fmt; 488 const char *s = fmt;
460 489
461 while (*s) { 490 while (*s)
462 if (*s == '½') { 491 {
492 if (*s == '½')
493 {
463 s++; 494 s++;
464 if (*s == '½') { 495 if (*s == '½')
496 {
465 fputc((unsigned char) *s, outFile); 497 fputc((unsigned char) *s, outFile);
466 s++; 498 s++;
467 } else { 499 }
500 else
501 {
468 while (*s && isdigit((int) *s)) s++; 502 while (*s && isdigit((int) *s)) s++;
469 if (*s != '½') return -1; 503 if (*s != '½') return -1;
470 s++; 504 s++;
471 } 505 }
472 } else { 506 }
507 else
508 {
473 if ((unsigned char) *s == 255) 509 if ((unsigned char) *s == 255)
474 fputc(' ', outFile); 510 fputc(' ', outFile);
475 else 511 else
476 fputc((unsigned char) *s, outFile); 512 fputc((unsigned char) *s, outFile);
477 s++; 513 s++;
478 } 514 }
479 } 515 }
480 516
481 return 0; 517 return 0;
482 } 518 }
483 519
484 void printMsgV(nn_window_t *win, int flags, const char *fmt, va_list ap) 520 void printMsgV(nn_window_t *win, int flags, const char *fmt, va_list ap)
485 { 521 {
486 char tmpStr[128], *buf; 522 char tmpStr[128], *buf;
487 523
488 getTimeStamp(tmpStr, sizeof(tmpStr), "½17½[½11½%H:%M:%S½17½]½0½ "); 524 getTimeStamp(tmpStr, sizeof(tmpStr), "½17½[½11½%H:%M:%S½17½]½0½ ");
489 525
490 buf = th_strdup_vprintf(fmt, ap); 526 buf = th_strdup_vprintf(fmt, ap);
491 527
492 if (optLogFile && (flags & LOG_FILE)) { 528 if (optLogFile && (flags & LOG_FILE))
529 {
493 if (flags & LOG_STAMP) printFile(optLogFile, tmpStr); 530 if (flags & LOG_STAMP) printFile(optLogFile, tmpStr);
494 printFile(optLogFile, buf); 531 printFile(optLogFile, buf);
495 fflush(optLogFile); 532 fflush(optLogFile);
496 } 533 }
497 534
498 if (!optDaemon && (flags & LOG_WINDOW)) { 535 if (!optDaemon && (flags & LOG_WINDOW))
536 {
499 nn_window_t *tmp = win != NULL ? win : chatWindows[0]; 537 nn_window_t *tmp = win != NULL ? win : chatWindows[0];
500 if (flags & LOG_STAMP) nn_window_print(tmp, tmpStr); 538 if (flags & LOG_STAMP) nn_window_print(tmp, tmpStr);
501 nn_window_print(tmp, buf); 539 nn_window_print(tmp, buf);
502 } 540 }
503 541
504 th_free(buf); 542 th_free(buf);
505 } 543 }
506 544
507 void printMsg(nn_window_t *win, const char *fmt, ...) 545 void printMsg(nn_window_t *win, const char *fmt, ...)
508 { 546 {
509 va_list ap; 547 va_list ap;
510 548
511 va_start(ap, fmt); 549 va_start(ap, fmt);
512 printMsgV(win, LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap); 550 printMsgV(win, LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap);
513 va_end(ap); 551 va_end(ap);
514 } 552 }
515 553
516 void printMsgF(nn_window_t *win, int flags, const char *fmt, ...) 554 void printMsgF(nn_window_t *win, int flags, const char *fmt, ...)
517 { 555 {
518 va_list ap; 556 va_list ap;
519 557
520 va_start(ap, fmt); 558 va_start(ap, fmt);
521 printMsgV(win, flags | LOG_STAMP, fmt, ap); 559 printMsgV(win, flags | LOG_STAMP, fmt, ap);
522 va_end(ap); 560 va_end(ap);
523 } 561 }
524 562
525 void printMsgQ(nn_window_t *win, const char *fmt, ...) 563 void printMsgQ(nn_window_t *win, const char *fmt, ...)
526 { 564 {
527 va_list ap; 565 va_list ap;
528 566
529 va_start(ap, fmt); 567 va_start(ap, fmt);
530 printMsgV(win, LOG_STAMP | LOG_WINDOW, fmt, ap); 568 printMsgV(win, LOG_STAMP | LOG_WINDOW, fmt, ap);
531 va_end(ap); 569 va_end(ap);
532 } 570 }
533 571
537 void errorMsgV(const char *fmt, va_list ap) 575 void errorMsgV(const char *fmt, va_list ap)
538 { 576 {
539 char *tmp = th_strdup_vprintf(fmt, ap); 577 char *tmp = th_strdup_vprintf(fmt, ap);
540 578
541 printMsg(NULL, "%s", tmp); 579 printMsg(NULL, "%s", tmp);
542 580
543 if (errorMessages != NULL) { 581 if (errorMessages != NULL)
582 {
544 char *tmp2 = th_strdup_printf("%s%s", errorMessages, tmp); 583 char *tmp2 = th_strdup_printf("%s%s", errorMessages, tmp);
545 th_free(errorMessages); 584 th_free(errorMessages);
546 th_free(tmp); 585 th_free(tmp);
547 errorMessages = tmp2; 586 errorMessages = tmp2;
548 } else 587 }
588 else
549 errorMessages = tmp; 589 errorMessages = tmp;
550 } 590 }
551 591
552 void errorMsg(const char *fmt, ...) 592 void errorMsg(const char *fmt, ...)
553 { 593 {
572 612
573 613
574 BOOL checkIgnoreList(const char *name) 614 BOOL checkIgnoreList(const char *name)
575 { 615 {
576 qlist_t *node = setIgnoreList; 616 qlist_t *node = setIgnoreList;
577 while (node != NULL) { 617 while (node != NULL)
618 {
578 if (th_strcasecmp(name, (char *) node->data) == 0) 619 if (th_strcasecmp(name, (char *) node->data) == 0)
579 return TRUE; 620 return TRUE;
580 node = node->next; 621 node = node->next;
581 } 622 }
582 return FALSE; 623 return FALSE;
586 int handleUser(nn_conn_t *conn, const char *str) 627 int handleUser(nn_conn_t *conn, const char *str)
587 { 628 {
588 const char *msg = "</USER><MESSAGE>", *p = str; 629 const char *msg = "</USER><MESSAGE>", *p = str;
589 BOOL isMine, isIgnored = FALSE; 630 BOOL isMine, isIgnored = FALSE;
590 char *s, *t, *userName; 631 char *s, *t, *userName;
591 632
592 (void) conn; 633 (void) conn;
593 634
594 /* Find start of the message */ 635 /* Find start of the message */
595 s = strstr(str, msg); 636 s = strstr(str, msg);
596 if (!s) return 1; 637 if (!s) return 1;
597 *s = 0; 638 *s = 0;
598 s += strlen(msg); 639 s += strlen(msg);
599 640
600 /* Find end of the message */ 641 /* Find end of the message */
601 t = strstr(s, "</MESSAGE>"); 642 t = strstr(s, "</MESSAGE>");
602 if (!t) return 3; 643 if (!t) return 3;
603 *t = 0; 644 *t = 0;
604 645
605 /* Decode message string */ 646 /* Decode message string */
606 s = nn_decode_str1(s); 647 s = nn_decode_str1(s);
607 if (!s) return -1; 648 if (!s) return -1;
608 649
609 /* Decode username */ 650 /* Decode username */
610 userName = nn_decode_str1(p); 651 userName = nn_decode_str1(p);
611 if (!userName) { 652 if (!userName)
653 {
612 th_free(s); 654 th_free(s);
613 return -2; 655 return -2;
614 } 656 }
615 657
616 /* Check if the username is on our ignore list and 658 /* Check if the username is on our ignore list and
618 */ 660 */
619 isMine = strcmp(userName, optUserName) == 0; 661 isMine = strcmp(userName, optUserName) == 0;
620 isIgnored = setIgnoreMode && !isMine && checkIgnoreList(userName); 662 isIgnored = setIgnoreMode && !isMine && checkIgnoreList(userName);
621 663
622 /* Is it a special control message? */ 664 /* Is it a special control message? */
623 if (*s == '/') { 665 if (*s == '/')
666 {
624 /* Ignore room join/leave messages */ 667 /* Ignore room join/leave messages */
625 if (!optDebug && (strstr(s, "left the room") || strstr(s, "joined the room from"))) 668 if (!optDebug && (strstr(s, "left the room") || strstr(s, "joined the room from")))
626 goto done; 669 goto done;
627 670
628 t = nn_strip_tags(s + 1); 671 t = nn_strip_tags(s + 1);
629 if (!strncmp(t, "BPRV ", 5)) { 672 if (!strncmp(t, "BPRV ", 5))
673 {
630 char *name, *tmp, *msg, *h; 674 char *name, *tmp, *msg, *h;
631 nn_window_t *win; 675 nn_window_t *win;
632 h = nn_decode_str2(t + 1); 676 h = nn_decode_str2(t + 1);
633 677
634 if (!strncmp(t, "BPRV from ", 10)) { 678 if (!strncmp(t, "BPRV from ", 10))
679 {
635 name = nn_decode_str2(t + 10); 680 name = nn_decode_str2(t + 10);
636 isMine = FALSE; 681 isMine = FALSE;
637 } else { 682 }
683 else
684 {
638 name = nn_decode_str2(t + 8); 685 name = nn_decode_str2(t + 8);
639 isMine = TRUE; 686 isMine = TRUE;
640 } 687 }
641 688
642 for (tmp = name; *tmp && *tmp != ':'; tmp++); 689 for (tmp = name; *tmp && *tmp != ':'; tmp++);
646 msg = ""; 693 msg = "";
647 *tmp = 0; 694 *tmp = 0;
648 695
649 isIgnored = setIgnoreMode && checkIgnoreList(name); 696 isIgnored = setIgnoreMode && checkIgnoreList(name);
650 win = findWindow(name); 697 win = findWindow(name);
651 698
652 if (win != NULL) { 699 if (win != NULL)
700 {
653 printMsgF(win, isIgnored ? 0 : LOG_WINDOW, 701 printMsgF(win, isIgnored ? 0 : LOG_WINDOW,
654 "½5½<½%d½%s½5½>½0½ %s\n", 702 "½5½<½%d½%s½5½>½0½ %s\n",
655 isMine ? 14 : 15, isMine ? optUserName : name, msg); 703 isMine ? 14 : 15, isMine ? optUserName : name, msg);
656 704
657 printMsgF(NULL, LOG_FILE, "½11½%s½0½\n", h); 705 printMsgF(NULL, LOG_FILE, "½11½%s½0½\n", h);
658 } else { 706 }
707 else
708 {
659 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE), 709 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE),
660 "½11½%s½0½\n", h); 710 "½11½%s½0½\n", h);
661 } 711 }
662 th_free(name); 712 th_free(name);
663 th_free(h); 713 th_free(h);
664 } else { 714 }
715 else
716 {
665 /* It's an action (/me) */ 717 /* It's an action (/me) */
666 char *h = nn_decode_str2(t); 718 char *h = nn_decode_str2(t);
667 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE), 719 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE),
668 "½9½* %s½0½\n", h); 720 "½9½* %s½0½\n", h);
669 th_free(h); 721 th_free(h);
670 } 722 }
671 th_free(t); 723 th_free(t);
672 } else { 724 }
725 else
726 {
673 /* It's a normal message */ 727 /* It's a normal message */
674 char *h; 728 char *h;
675 t = nn_strip_tags(s); 729 t = nn_strip_tags(s);
676 h = nn_decode_str2(t); 730 h = nn_decode_str2(t);
677 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE), 731 printMsgF(NULL, isIgnored ? LOG_FILE : (LOG_WINDOW | LOG_FILE),
688 742
689 743
690 int handleLogin(nn_conn_t *conn, const char *str) 744 int handleLogin(nn_conn_t *conn, const char *str)
691 { 745 {
692 char tmpStr[256]; 746 char tmpStr[256];
693 747
694 getTimeStamp(tmpStr, sizeof(tmpStr), "%c"); 748 getTimeStamp(tmpStr, sizeof(tmpStr), "%c");
695 749
696 if (!strncmp(str, "FAILURE", 7)) { 750 if (!strncmp(str, "FAILURE", 7))
751 {
697 printMsg(NULL, "½1½Login failure½0½ - ½3½%s½0½\n", tmpStr); 752 printMsg(NULL, "½1½Login failure½0½ - ½3½%s½0½\n", tmpStr);
698 return -2; 753 return -2;
699 } else if (!strncmp(str, "SUCCESS", 7)) { 754 }
755 else if (!strncmp(str, "SUCCESS", 7))
756 {
700 printMsg(NULL, "½2½Login success½0½ - ½3½%s½0½\n", tmpStr); 757 printMsg(NULL, "½2½Login success½0½ - ½3½%s½0½\n", tmpStr);
701 nn_conn_send_msg(conn, optUserNameEnc, "%%2FRequestUserList"); 758 nn_conn_send_msg(conn, optUserNameEnc, "%%2FRequestUserList");
702 return 0; 759 return 0;
703 } else 760 }
761 else
704 return 1; 762 return 1;
705 } 763 }
706 764
707 765
708 int handleAddUser(nn_conn_t *conn, const char *str) 766 int handleAddUser(nn_conn_t *conn, const char *str)
712 770
713 (void) conn; 771 (void) conn;
714 772
715 if (!s) return 1; 773 if (!s) return 1;
716 *s = 0; 774 *s = 0;
717 775
718 p = nn_dbldecode_str(str); 776 p = nn_dbldecode_str(str);
719 if (!p) return -1; 777 if (!p) return -1;
720 778
721 win = findWindow(p); 779 win = findWindow(p);
722 nn_userhash_insert(nnUsers, nn_username_encode(p)); 780 nn_userhash_insert(nnUsers, nn_username_encode(p));
737 795
738 (void) conn; 796 (void) conn;
739 797
740 if (!s) return 1; 798 if (!s) return 1;
741 *s = 0; 799 *s = 0;
742 800
743 p = nn_dbldecode_str(str); 801 p = nn_dbldecode_str(str);
744 if (!p) return -1; 802 if (!p) return -1;
745 803
746 win = findWindow(p); 804 win = findWindow(p);
747 nn_userhash_delete(nnUsers, nn_username_encode(p)); 805 nn_userhash_delete(nnUsers, nn_username_encode(p));
748 806
749 printMsg(NULL, "! ½3½%s½0½ ½1½DELETED.½0½\n", p); 807 printMsg(NULL, "! ½3½%s½0½ ½1½DELETED.½0½\n", p);
750 if (win != NULL) 808 if (win != NULL)
751 printMsg(win, "! ½3½%s½0½ ½1½left the chat.½0½\n", p); 809 printMsg(win, "! ½3½%s½0½ ½1½left the chat.½0½\n", p);
752 810
753 th_free(p); 811 th_free(p);
754 return 0; 812 return 0;
755 } 813 }
756 814
757 815
758 int handleFoo(nn_conn_t *conn, const char *str) 816 int handleFoo(nn_conn_t *conn, const char *str)
759 { 817 {
760 (void) conn; (void) str; 818 (void) conn;
761 819 (void) str;
820
762 return 0; 821 return 0;
763 } 822 }
764 823
765 824
766 int handleBoot(nn_conn_t *conn, const char *str) 825 int handleBoot(nn_conn_t *conn, const char *str)
767 { 826 {
768 (void) conn; (void) str; 827 (void) conn;
828 (void) str;
769 errorMsg("Booted by server.\n"); 829 errorMsg("Booted by server.\n");
770 return -1; 830 return -1;
771 } 831 }
772 832
773 833
774 typedef struct { 834 typedef struct
835 {
775 char *cmd; 836 char *cmd;
776 ssize_t len; 837 ssize_t len;
777 int (*handler)(nn_conn_t *, const char *); 838 int (*handler)(nn_conn_t *, const char *);
778 } protocmd_t; 839 } protocmd_t;
779 840
780 841
781 static protocmd_t protoCmds[] = { 842 static protocmd_t protoCmds[] =
843 {
782 { "<USER>", -1, handleUser }, 844 { "<USER>", -1, handleUser },
783 { "<LOGIN_", -1, handleLogin }, 845 { "<LOGIN_", -1, handleLogin },
784 { "<DELETE_USER>", -1, handleDeleteUser }, 846 { "<DELETE_USER>", -1, handleDeleteUser },
785 { "<ADD_USER>", -1, handleAddUser }, 847 { "<ADD_USER>", -1, handleAddUser },
786 { "<NUMCLIENTS>", -1, handleFoo }, 848 { "<NUMCLIENTS>", -1, handleFoo },
793 int handleProtocol(nn_conn_t *conn, const char *buf, const ssize_t bufLen) 855 int handleProtocol(nn_conn_t *conn, const char *buf, const ssize_t bufLen)
794 { 856 {
795 static BOOL protoCmdsInit = FALSE; 857 static BOOL protoCmdsInit = FALSE;
796 int i; 858 int i;
797 859
798 if (!protoCmdsInit) { 860 if (!protoCmdsInit)
861 {
799 for (i = 0; i < nprotoCmds; i++) 862 for (i = 0; i < nprotoCmds; i++)
800 protoCmds[i].len = strlen(protoCmds[i].cmd); 863 protoCmds[i].len = strlen(protoCmds[i].cmd);
801 protoCmdsInit = TRUE; 864 protoCmdsInit = TRUE;
802 } 865 }
803 866
804 for (i = 0; i < nprotoCmds; i++) { 867 for (i = 0; i < nprotoCmds; i++)
868 {
805 ssize_t cmdLen = protoCmds[i].len; 869 ssize_t cmdLen = protoCmds[i].len;
806 if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen)) 870 if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen))
807 return protoCmds[i].handler(conn, buf + cmdLen); 871 return protoCmds[i].handler(conn, buf + cmdLen);
808 } 872 }
809 873
810 if (optDebug) { 874 if (optDebug)
875 {
811 printMsg(NULL, "Unknown protocmd: \"%s\"\n", buf); 876 printMsg(NULL, "Unknown protocmd: \"%s\"\n", buf);
812 return 0; 877 return 0;
813 } else 878 }
879 else
814 return 1; 880 return 1;
815 } 881 }
816 882
817 char * trimLeft(char *buf) 883 char * trimLeft(char *buf)
818 { 884 {
827 893
828 int handleUserInput(nn_conn_t *conn, char *buf, size_t bufLen) 894 int handleUserInput(nn_conn_t *conn, char *buf, size_t bufLen)
829 { 895 {
830 char *tmpStr, tmpBuf[4096]; 896 char *tmpStr, tmpBuf[4096];
831 BOOL result; 897 BOOL result;
832 898
833 /* Trim right */ 899 /* Trim right */
834 bufLen--; 900 bufLen--;
835 buf[bufLen--] = 0; 901 buf[bufLen--] = 0;
836 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen]))) 902 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen])))
837 buf[bufLen--] = 0; 903 buf[bufLen--] = 0;
838 904
839 /* Decode completed usernames */ 905 /* Decode completed usernames */
840 nn_username_decode(buf); 906 nn_username_decode(buf);
841 907
842 /* Check for special user commands */ 908 /* Check for special user commands */
843 if (*buf == 0) { 909 if (*buf == 0)
910 {
844 return 1; 911 return 1;
845 } 912 }
846 else if (!th_strncasecmp(buf, "/color ", 7)) { 913 else if (!th_strncasecmp(buf, "/color ", 7))
914 {
847 /* Change color */ 915 /* Change color */
848 int tmpInt; 916 int tmpInt;
849 if ((tmpInt = th_get_hex_triplet(trimLeft(buf + 7))) < 0) { 917 if ((tmpInt = th_get_hex_triplet(trimLeft(buf + 7))) < 0)
918 {
850 printMsgQ(currWin, "Invalid color value '%s'\n", buf+7); 919 printMsgQ(currWin, "Invalid color value '%s'\n", buf+7);
851 return 1; 920 return 1;
852 } 921 }
853 optUserColor = tmpInt; 922 optUserColor = tmpInt;
854 printMsgQ(currWin, "Setting color to #%06x\n", optUserColor); 923 printMsgQ(currWin, "Setting color to #%06x\n", optUserColor);
855 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 924 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
856 return 0; 925 return 0;
857 } 926 }
858 else if (!th_strncasecmp(buf, "/ignore", 7)) { 927 else if (!th_strncasecmp(buf, "/ignore", 7))
928 {
859 char *name = trimLeft(buf + 7); 929 char *name = trimLeft(buf + 7);
860 if (strlen(name) > 0) { 930 if (strlen(name) > 0)
931 {
861 /* Add or remove someone to/from ignore */ 932 /* Add or remove someone to/from ignore */
862 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername); 933 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername);
863 if (user != NULL) { 934 if (user != NULL)
935 {
864 printMsgQ(currWin, "Removed user '%s' from ignore.\n", name); 936 printMsgQ(currWin, "Removed user '%s' from ignore.\n", name);
865 th_llist_delete_node(&setIgnoreList, user); 937 th_llist_delete_node(&setIgnoreList, user);
866 } else { 938 }
939 else
940 {
867 printMsgQ(currWin, "Now ignoring '%s'.\n", name); 941 printMsgQ(currWin, "Now ignoring '%s'.\n", name);
868 th_llist_append(&setIgnoreList, th_strdup(name)); 942 th_llist_append(&setIgnoreList, th_strdup(name));
869 } 943 }
870 } else { 944 }
945 else
946 {
871 /* Just list whomever is in ignore now */ 947 /* Just list whomever is in ignore now */
872 qlist_t *user = setIgnoreList; 948 qlist_t *user = setIgnoreList;
873 ssize_t nuser = th_llist_length(setIgnoreList); 949 ssize_t nuser = th_llist_length(setIgnoreList);
874 char *result = th_strdup_printf("Users ignored (%d): ", nuser); 950 char *result = th_strdup_printf("Users ignored (%d): ", nuser);
875 while (user != NULL) { 951 while (user != NULL)
876 if (user->data != NULL) { 952 {
953 if (user->data != NULL)
954 {
877 th_pstr_printf(&result, "%s'%s'", result, (char *) user->data); 955 th_pstr_printf(&result, "%s'%s'", result, (char *) user->data);
878 if (--nuser > 0) 956 if (--nuser > 0)
879 th_pstr_printf(&result, "%s, ", result); 957 th_pstr_printf(&result, "%s, ", result);
880 } 958 }
881 user = user->next; 959 user = user->next;
883 printMsgQ(currWin, "%s\n", result); 961 printMsgQ(currWin, "%s\n", result);
884 th_free(result); 962 th_free(result);
885 } 963 }
886 return 0; 964 return 0;
887 } 965 }
888 else if (!th_strncasecmp(buf, "/query", 6)) { 966 else if (!th_strncasecmp(buf, "/query", 6))
967 {
889 char *name = trimLeft(buf + 6); 968 char *name = trimLeft(buf + 6);
890 if (strlen(name) > 0) { 969 if (strlen(name) > 0)
970 {
891 nn_user_t *user = nn_user_find(nnUsers, nn_username_encode(name)); 971 nn_user_t *user = nn_user_find(nnUsers, nn_username_encode(name));
892 if (user != NULL) { 972 if (user != NULL)
973 {
893 name = nn_username_decode(th_strdup(user->name)); 974 name = nn_username_decode(th_strdup(user->name));
894 printMsgQ(currWin, "Opening PRV query for '%s'.\n", name); 975 printMsgQ(currWin, "Opening PRV query for '%s'.\n", name);
895 if (openWindow(name, TRUE)) 976 if (openWindow(name, TRUE))
896 printMsgQ(currWin, "In PRV query with '%s'.\n", name); 977 printMsgQ(currWin, "In PRV query with '%s'.\n", name);
897 th_free(name); 978 th_free(name);
898 } 979 }
899 } else { 980 }
981 else
982 {
900 printMsgQ(currWin, "Usage: /query username\n"); 983 printMsgQ(currWin, "Usage: /query username\n");
901 printMsgQ(currWin, "To close a PRV query, use /close [username]\n"); 984 printMsgQ(currWin, "To close a PRV query, use /close [username]\n");
902 printMsgQ(currWin, "/close without username will close the current PRV window.\n"); 985 printMsgQ(currWin, "/close without username will close the current PRV window.\n");
903 } 986 }
904 return 0; 987 return 0;
905 } 988 }
906 else if (!th_strncasecmp(buf, "/win", 4)) { 989 else if (!th_strncasecmp(buf, "/win", 4))
990 {
907 /* Change color */ 991 /* Change color */
908 char *tmp = trimLeft(buf + 4); 992 char *tmp = trimLeft(buf + 4);
909 if (strlen(tmp) > 0) { 993 if (strlen(tmp) > 0)
994 {
910 int val = atoi(tmp); 995 int val = atoi(tmp);
911 if (val >= 1 && val < SET_MAX_WINDOWS) { 996 if (val >= 1 && val < SET_MAX_WINDOWS)
997 {
912 if (chatWindows[val - 1] != NULL) 998 if (chatWindows[val - 1] != NULL)
913 currWin = chatWindows[val - 1]; 999 currWin = chatWindows[val - 1];
914 } else { 1000 }
1001 else
1002 {
915 printMsgQ(currWin, "Invalid window number '%s'\n", tmp); 1003 printMsgQ(currWin, "Invalid window number '%s'\n", tmp);
916 return 1; 1004 return 1;
917 } 1005 }
918 } else { 1006 }
1007 else
1008 {
919 printMsgQ(currWin, "Window : #%d\n", currWin->num); 1009 printMsgQ(currWin, "Window : #%d\n", currWin->num);
920 printMsgQ(currWin, "ID : %s\n", currWin->id); 1010 printMsgQ(currWin, "ID : %s\n", currWin->id);
921 } 1011 }
922 return 0; 1012 return 0;
923 } 1013 }
924 else if (!th_strncasecmp(buf, "/close", 6)) { 1014 else if (!th_strncasecmp(buf, "/close", 6))
1015 {
925 char *name = trimLeft(buf + 6); 1016 char *name = trimLeft(buf + 6);
926 if (strlen(name) > 0) { 1017 if (strlen(name) > 0)
1018 {
927 nn_window_t *win = findWindow(name); 1019 nn_window_t *win = findWindow(name);
928 if (win != NULL) { 1020 if (win != NULL)
1021 {
929 closeWindow(win); 1022 closeWindow(win);
930 printMsgQ(currWin, "Closed PRV query to '%s'.\n", name); 1023 printMsgQ(currWin, "Closed PRV query to '%s'.\n", name);
931 } else { 1024 }
1025 else
1026 {
932 printMsgQ(currWin, "No PRV query by name '%s'.\n", name); 1027 printMsgQ(currWin, "No PRV query by name '%s'.\n", name);
933 } 1028 }
934 } else { 1029 }
935 if (currWin != chatWindows[0]) { 1030 else
1031 {
1032 if (currWin != chatWindows[0])
1033 {
936 closeWindow(currWin); 1034 closeWindow(currWin);
937 currWin = chatWindows[0]; 1035 currWin = chatWindows[0];
938 } 1036 }
939 } 1037 }
940 return 0; 1038 return 0;
941 } 1039 }
942 else if (!th_strncasecmp(buf, "/save", 5)) { 1040 else if (!th_strncasecmp(buf, "/save", 5))
1041 {
943 /* Save configuration */ 1042 /* Save configuration */
944 FILE *cfgfile = fopen(setConfigFile, "w"); 1043 FILE *cfgfile = fopen(setConfigFile, "w");
945 if (cfgfile == NULL) { 1044 if (cfgfile == NULL)
1045 {
946 printMsgQ(currWin, "Could not create configuration to file '%s': %s\n", 1046 printMsgQ(currWin, "Could not create configuration to file '%s': %s\n",
947 setConfigFile, strerror(errno)); 1047 setConfigFile, strerror(errno));
948 return 0; 1048 return 0;
949 } 1049 }
950 printMsgQ(currWin, "Configuration saved in file '%s', res=%d\n", 1050 printMsgQ(currWin, "Configuration saved in file '%s', res=%d\n",
952 th_cfg_write(cfgfile, setConfigFile, cfg)); 1052 th_cfg_write(cfgfile, setConfigFile, cfg));
953 1053
954 fclose(cfgfile); 1054 fclose(cfgfile);
955 return 0; 1055 return 0;
956 } 1056 }
957 else if (!th_strncasecmp(buf, "/w ", 3)) { 1057 else if (!th_strncasecmp(buf, "/w ", 3))
1058 {
958 /* Open given username's profile via firefox in a new tab */ 1059 /* Open given username's profile via firefox in a new tab */
959 char *name = trimLeft(buf + 3); 1060 char *name = trimLeft(buf + 3);
960 1061
961 printMsg(currWin, "Opening profile for: '%s'\n", name); 1062 printMsg(currWin, "Opening profile for: '%s'\n", name);
962 1063
963 tmpStr = nn_encode_str1(name); 1064 tmpStr = nn_encode_str1(name);
964 #ifdef __WIN32 1065 #ifdef __WIN32
965 { 1066 {
966 HINSTANCE status; 1067 HINSTANCE status;
967 snprintf(tmpBuf, sizeof(tmpBuf), "http://www.newbienudes.com/profile/%s/", tmpStr); 1068 snprintf(tmpBuf, sizeof(tmpBuf), "http://www.newbienudes.com/profile/%s/", tmpStr);
968 th_free(tmpStr); 1069 th_free(tmpStr);
969 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA); 1070 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA);
970 if (status <= (HINSTANCE) 32) 1071 if (status <= (HINSTANCE) 32)
971 printMsgQ(currWin, "Could not launch default web browser: %d\n", status); 1072 printMsgQ(currWin, "Could not launch default web browser: %d\n", status);
972 } 1073 }
973 #else 1074 #else
974 { 1075 {
975 int status; 1076 int status;
976 int fds[2]; 1077 int fds[2];
977 pid_t pid; 1078 pid_t pid;
978 snprintf(tmpBuf, sizeof(tmpBuf), "openurl(http://www.newbienudes.com/profile/%s/,new-tab)", tmpStr); 1079 snprintf(tmpBuf, sizeof(tmpBuf), "openurl(http://www.newbienudes.com/profile/%s/,new-tab)", tmpStr);
979 th_free(tmpStr); 1080 th_free(tmpStr);
980 1081
981 if (pipe(fds) == -1) { 1082 if (pipe(fds) == -1)
982 int ret = errno; 1083 {
983 printMsgQ(currWin, "Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret)); 1084 int ret = errno;
984 return 0; 1085 printMsgQ(currWin, "Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret));
985 } 1086 return 0;
986 1087 }
987 if ((pid = fork()) < 0) { 1088
988 printMsgQ(currWin, "Could not create sub-process!\n"); 1089 if ((pid = fork()) < 0)
989 } else if (pid == 0) { 1090 {
990 dup2(fds[1], STDOUT_FILENO); 1091 printMsgQ(currWin, "Could not create sub-process!\n");
991 dup2(fds[0], STDERR_FILENO); 1092 }
992 execlp(setBrowser, setBrowser, "-remote", tmpBuf, (void *)NULL); 1093 else if (pid == 0)
993 _exit(errno); 1094 {
994 } 1095 dup2(fds[1], STDOUT_FILENO);
995 1096 dup2(fds[0], STDERR_FILENO);
996 wait(&status); 1097 execlp(setBrowser, setBrowser, "-remote", tmpBuf, (void *)NULL);
1098 _exit(errno);
1099 }
1100
1101 wait(&status);
997 } 1102 }
998 #endif 1103 #endif
999 return 0; 1104 return 0;
1000 } 1105 }
1001 else if (!th_strncasecmp(buf, "/who", 4)) { 1106 else if (!th_strncasecmp(buf, "/who", 4))
1107 {
1002 /* Alias /who to /listallusers */ 1108 /* Alias /who to /listallusers */
1003 snprintf(tmpBuf, sizeof(tmpBuf), "/listallusers"); 1109 snprintf(tmpBuf, sizeof(tmpBuf), "/listallusers");
1004 buf = tmpBuf; 1110 buf = tmpBuf;
1005 } 1111 }
1006 1112
1007 if (currWin != chatWindows[0]) { 1113 if (currWin != chatWindows[0])
1008 if (currWin->id != NULL) { 1114 {
1115 if (currWin->id != NULL)
1116 {
1009 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", currWin->id, buf); 1117 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", currWin->id, buf);
1010 buf = tmpBuf; 1118 buf = tmpBuf;
1011 } else { 1119 }
1120 else
1121 {
1012 printMsgQ(NULL, "No target set, exiting prv mode.\n"); 1122 printMsgQ(NULL, "No target set, exiting prv mode.\n");
1013 return 1; 1123 return 1;
1014 } 1124 }
1015 } 1125 }
1016 1126
1017 /* Send double-encoded */ 1127 /* Send double-encoded */
1018 tmpStr = nn_dblencode_str(nn_username_decode(buf)); 1128 tmpStr = nn_dblencode_str(nn_username_decode(buf));
1019 if (tmpStr == 0) return -2; 1129 if (tmpStr == 0) return -2;
1020 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr); 1130 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr);
1021 th_free(tmpStr); 1131 th_free(tmpStr);
1022 1132
1023 return result ? 0 : -1; 1133 return result ? 0 : -1;
1024 } 1134 }
1025 1135
1026 void closeWindows(void) 1136 void closeWindows(void)
1027 { 1137 {
1033 BOOL initializeWindows(void) 1143 BOOL initializeWindows(void)
1034 { 1144 {
1035 int w, h; 1145 int w, h;
1036 1146
1037 getmaxyx(stdscr, h, w); 1147 getmaxyx(stdscr, h, w);
1038 1148
1039 closeWindows(); 1149 closeWindows();
1040 1150
1041 mainWin = subwin(stdscr, h - 4, w, 0, 0); 1151 mainWin = subwin(stdscr, h - 4, w, 0, 0);
1042 statusWin = subwin(stdscr, 1, w, h - 4, 0); 1152 statusWin = subwin(stdscr, 1, w, h - 4, 0);
1043 editWin = subwin(stdscr, 3, w, h - 3, 0); 1153 editWin = subwin(stdscr, 3, w, h - 3, 0);
1044 1154
1045 if (mainWin == NULL || statusWin == NULL || editWin == NULL) 1155 if (mainWin == NULL || statusWin == NULL || editWin == NULL)
1046 return FALSE; 1156 return FALSE;
1047 1157
1048 return TRUE; 1158 return TRUE;
1049 } 1159 }
1062 char *str = buf->data; 1172 char *str = buf->data;
1063 int mode = 0; 1173 int mode = 0;
1064 ssize_t endPos, startPos = buf->pos; 1174 ssize_t endPos, startPos = buf->pos;
1065 1175
1066 /* previous word */ 1176 /* previous word */
1067 if (startPos >= 2 && str[startPos - 1] == ' ' && str[startPos - 2] != ' ') { 1177 if (startPos >= 2 && str[startPos - 1] == ' ' && str[startPos - 2] != ' ')
1178 {
1068 startPos -= 2; 1179 startPos -= 2;
1069 endPos = startPos; 1180 endPos = startPos;
1070 while (startPos > 0 && str[startPos - 1] != ' ') startPos--; 1181 while (startPos > 0 && str[startPos - 1] != ' ') startPos--;
1071 mode = 1; 1182 mode = 1;
1072 } else 1183 }
1073 /* middle of a word, new pattern */ 1184 else
1074 if (startPos < buf->len && str[startPos] != ' ') { 1185 /* middle of a word, new pattern */
1075 endPos = startPos; 1186 if (startPos < buf->len && str[startPos] != ' ')
1076 while (startPos > 0 && str[startPos - 1] != ' ') startPos--; 1187 {
1077 while (endPos < buf->len - 1 && str[endPos + 1] != ' ') endPos++; 1188 endPos = startPos;
1078 newPattern = TRUE; 1189 while (startPos > 0 && str[startPos - 1] != ' ') startPos--;
1079 mode = 2; 1190 while (endPos < buf->len - 1 && str[endPos + 1] != ' ') endPos++;
1080 } else 1191 newPattern = TRUE;
1081 /* previous word, new pattern */ 1192 mode = 2;
1082 if (startPos >= 1 && str[startPos - 1] != ' ') { 1193 }
1083 startPos -= 1; 1194 else
1084 endPos = startPos; 1195 /* previous word, new pattern */
1085 while (startPos > 0 && str[startPos - 1] != ' ') startPos--; 1196 if (startPos >= 1 && str[startPos - 1] != ' ')
1086 newPattern = TRUE; 1197 {
1087 mode = 3; 1198 startPos -= 1;
1088 } else { 1199 endPos = startPos;
1089 if (optDebug) 1200 while (startPos > 0 && str[startPos - 1] != ' ') startPos--;
1090 printMsg(currWin, "no mode\n"); 1201 newPattern = TRUE;
1091 return FALSE; 1202 mode = 3;
1092 } 1203 }
1093 1204 else
1094 if (str[endPos] == optNickSep) { 1205 {
1206 if (optDebug)
1207 printMsg(currWin, "no mode\n");
1208 return FALSE;
1209 }
1210
1211 if (str[endPos] == optNickSep)
1212 {
1095 endPos--; 1213 endPos--;
1096 if (startPos > 0) { 1214 if (startPos > 0)
1215 {
1097 if (optDebug) 1216 if (optDebug)
1098 printMsg(currWin, "str[endPos] == optNickSep && startPos > 0 (%d)\n", startPos); 1217 printMsg(currWin, "str[endPos] == optNickSep && startPos > 0 (%d)\n", startPos);
1099 return FALSE; 1218 return FALSE;
1100 } 1219 }
1101 hasSeparator = TRUE; 1220 hasSeparator = TRUE;
1103 1222
1104 if (buf->pos > 0 && str[buf->pos - 1] == ' ') 1223 if (buf->pos > 0 && str[buf->pos - 1] == ' ')
1105 hasSpace = TRUE; 1224 hasSpace = TRUE;
1106 if (buf->pos <= buf->len && str[buf->pos] == ' ') 1225 if (buf->pos <= buf->len && str[buf->pos] == ' ')
1107 hasSpace = TRUE; 1226 hasSpace = TRUE;
1108 1227
1109 if (newPattern) { 1228 if (newPattern)
1229 {
1110 /* Get pattern, check if it matches previous pattern and set 'again' flag */ 1230 /* Get pattern, check if it matches previous pattern and set 'again' flag */
1111 char *npattern = nn_editbuf_get_string(buf, startPos, endPos); 1231 char *npattern = nn_editbuf_get_string(buf, startPos, endPos);
1112 if (pattern && npattern && th_strcasecmp(npattern, pattern) == 0) 1232 if (pattern && npattern && th_strcasecmp(npattern, pattern) == 0)
1113 again = TRUE; 1233 again = TRUE;
1114 1234
1115 th_free(pattern); 1235 th_free(pattern);
1116 pattern = npattern; 1236 pattern = npattern;
1117 1237
1118 if (!again) { 1238 if (!again)
1239 {
1119 th_free(previous); 1240 th_free(previous);
1120 previous = NULL; 1241 previous = NULL;
1121 } 1242 }
1122 } 1243 }
1123 1244
1124 if (optDebug) { 1245 if (optDebug)
1246 {
1125 printMsg(currWin, "sPos=%d, ePos=%d <-> bPos=%d, bufLen=%d : pat='%s' (again=%s, hassep=%s, hasspc=%s, newpat=%s, mode=%d)\n", 1247 printMsg(currWin, "sPos=%d, ePos=%d <-> bPos=%d, bufLen=%d : pat='%s' (again=%s, hassep=%s, hasspc=%s, newpat=%s, mode=%d)\n",
1126 startPos, endPos, buf->pos, buf->len, pattern, 1248 startPos, endPos, buf->pos, buf->len, pattern,
1127 again ? "yes" : "no", 1249 again ? "yes" : "no",
1128 hasSeparator ? "yes" : "no", 1250 hasSeparator ? "yes" : "no",
1129 hasSpace ? "yes" : "no", 1251 hasSpace ? "yes" : "no",
1130 newPattern ? "yes" : "no", mode); 1252 newPattern ? "yes" : "no", mode);
1131 } 1253 }
1132 1254
1133 if (pattern) { 1255 if (pattern)
1256 {
1134 nn_user_t *user = nn_user_match(nnUsers, pattern, previous, again); 1257 nn_user_t *user = nn_user_match(nnUsers, pattern, previous, again);
1135 1258
1136 if (user) { 1259 if (user)
1260 {
1137 int i; 1261 int i;
1138 char *c = user->name; 1262 char *c = user->name;
1139 if (optDebug) 1263 if (optDebug)
1140 printMsg(currWin, "match='%s' / prev='%s'\n", user->name, previous); 1264 printMsg(currWin, "match='%s' / prev='%s'\n", user->name, previous);
1141 1265
1142 for (i = startPos; i <= endPos; i++) 1266 for (i = startPos; i <= endPos; i++)
1143 nn_editbuf_delete(buf, startPos); 1267 nn_editbuf_delete(buf, startPos);
1144 1268
1145 for (i = startPos; *c; i++, c++) 1269 for (i = startPos; *c; i++, c++)
1146 nn_editbuf_insert(buf, i, *c); 1270 nn_editbuf_insert(buf, i, *c);
1147 1271
1148 if (!hasSeparator && startPos == 0) { 1272 if (!hasSeparator && startPos == 0)
1273 {
1149 nn_editbuf_insert(buf, i++, optNickSep); 1274 nn_editbuf_insert(buf, i++, optNickSep);
1150 startPos++; 1275 startPos++;
1151 } 1276 }
1152 if (hasSeparator) 1277 if (hasSeparator)
1153 startPos++; 1278 startPos++;
1156 1281
1157 nn_editbuf_setpos(buf, startPos + 1 + strlen(user->name)); 1282 nn_editbuf_setpos(buf, startPos + 1 + strlen(user->name));
1158 1283
1159 th_free(previous); 1284 th_free(previous);
1160 previous = th_strdup(user->name); 1285 previous = th_strdup(user->name);
1161 1286
1162 return TRUE; 1287 return TRUE;
1163 } 1288 }
1164 } 1289 }
1165 1290
1166 return FALSE; 1291 return FALSE;
1167 } 1292 }
1168 1293
1169 #define VPUTCH(CH) th_vputch(&bufData, &bufSize, &bufLen, CH) 1294 #define VPUTCH(CH) th_vputch(&bufData, &bufSize, &bufLen, CH)
1170 #define VPUTS(STR) th_vputs(&bufData, &bufSize, &bufLen, STR) 1295 #define VPUTS(STR) th_vputs(&bufData, &bufSize, &bufLen, STR)
1173 { 1298 {
1174 size_t bufSize = strlen(fmt) + TH_BUFGROW, bufLen = 0; 1299 size_t bufSize = strlen(fmt) + TH_BUFGROW, bufLen = 0;
1175 char *bufData = th_malloc(bufSize); 1300 char *bufData = th_malloc(bufSize);
1176 char tmpBuf[32]; 1301 char tmpBuf[32];
1177 const char *s = fmt; 1302 const char *s = fmt;
1178 1303
1179 while (*s) { 1304 while (*s)
1180 if (*s == '%') { 1305 {
1306 if (*s == '%')
1307 {
1181 s++; 1308 s++;
1182 switch (*s) { 1309 switch (*s)
1183 case 'i': 1310 {
1184 snprintf(tmpBuf, sizeof(tmpBuf), "%05d", id); 1311 case 'i':
1185 VPUTS(tmpBuf); 1312 snprintf(tmpBuf, sizeof(tmpBuf), "%05d", id);
1186 break; 1313 VPUTS(tmpBuf);
1187 1314 break;
1188 case 'd': 1315
1189 snprintf(tmpBuf, sizeof(tmpBuf), "%d", id); 1316 case 'd':
1190 VPUTS(tmpBuf); 1317 snprintf(tmpBuf, sizeof(tmpBuf), "%d", id);
1191 break; 1318 VPUTS(tmpBuf);
1192 1319 break;
1193 case '%': 1320
1194 VPUTCH('%'); 1321 case '%':
1195 break; 1322 VPUTCH('%');
1323 break;
1196 } 1324 }
1197 s++; 1325 s++;
1198 } else { 1326 }
1327 else
1328 {
1199 VPUTCH(*s); 1329 VPUTCH(*s);
1200 s++; 1330 s++;
1201 } 1331 }
1202 } 1332 }
1203 1333
1204 VPUTCH(0); 1334 VPUTCH(0);
1205 return bufData; 1335 return bufData;
1206 } 1336 }
1207 1337
1208 1338
1209 BOOL logFileOpen(void) 1339 BOOL logFileOpen(void)
1210 { 1340 {
1211 char *filename; 1341 char *filename;
1212 1342
1213 if (optLogFilename == NULL || !optLogEnable) 1343 if (optLogFilename == NULL || !optLogEnable)
1214 return FALSE; 1344 return FALSE;
1215 1345
1216 filename = logParseFilename(optLogFilename, optPort); 1346 filename = logParseFilename(optLogFilename, optPort);
1217 1347
1218 if ((optLogFile = fopen(filename, "a")) == NULL) { 1348 if ((optLogFile = fopen(filename, "a")) == NULL)
1349 {
1219 errorMsg("Could not open logfile '%s' for appending!\n", filename); 1350 errorMsg("Could not open logfile '%s' for appending!\n", filename);
1220 th_free(filename); 1351 th_free(filename);
1221 return FALSE; 1352 return FALSE;
1222 } 1353 }
1223 1354
1224 th_free(filename); 1355 th_free(filename);
1225 1356
1226 return TRUE; 1357 return TRUE;
1227 } 1358 }
1228 1359
1229 void logFileClose(void) 1360 void logFileClose(void)
1230 { 1361 {
1231 if (optLogFile) { 1362 if (optLogFile)
1363 {
1232 fclose(optLogFile); 1364 fclose(optLogFile);
1233 optLogFile = NULL; 1365 optLogFile = NULL;
1234 } 1366 }
1235 } 1367 }
1236 1368
1244 waddstr(win, info); 1376 waddstr(win, info);
1245 wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1); 1377 wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1);
1246 noecho(); 1378 noecho();
1247 if (curVis != ERR) 1379 if (curVis != ERR)
1248 curs_set(curVis); 1380 curs_set(curVis);
1249 1381
1250 for (pos = strlen(tmpBuf) - 1; pos > 0 && (tmpBuf[pos] == '\n' || tmpBuf[pos] == '\r' || th_isspace(tmpBuf[pos])); pos--) 1382 for (pos = strlen(tmpBuf) - 1; pos > 0 && (tmpBuf[pos] == '\n' || tmpBuf[pos] == '\r' || th_isspace(tmpBuf[pos])); pos--)
1251 tmpBuf[pos] = 0; 1383 tmpBuf[pos] = 0;
1252 1384
1253 ptr = trimLeft(tmpBuf); 1385 ptr = trimLeft(tmpBuf);
1254 1386
1259 } 1391 }
1260 1392
1261 void printHelp(void) 1393 void printHelp(void)
1262 { 1394 {
1263 printMsgQ(currWin, "\n" 1395 printMsgQ(currWin, "\n"
1264 "NNChat Help\n" 1396 "NNChat Help\n"
1265 "===========\n" 1397 "===========\n"
1266 "\n" 1398 "\n"
1267 "F1 This help.\n" 1399 "F1 This help.\n"
1268 "F2 \n" 1400 "F2 \n"
1269 ); 1401 );
1270 } 1402 }
1271 1403
1272 int main(int argc, char *argv[]) 1404 int main(int argc, char *argv[])
1273 { 1405 {
1274 nn_conn_t *conn = NULL; 1406 nn_conn_t *conn = NULL;
1288 1420
1289 cfgitem_t *tmpcfg; 1421 cfgitem_t *tmpcfg;
1290 char *homeDir = NULL; 1422 char *homeDir = NULL;
1291 1423
1292 memset(histBuf, 0, sizeof(histBuf)); 1424 memset(histBuf, 0, sizeof(histBuf));
1293 1425
1294 /* Initialize */ 1426 /* Initialize */
1295 th_init("NNChat", "Newbie Nudes chat client", NN_VERSION, 1427 th_init("NNChat", "Newbie Nudes chat client", NN_VERSION,
1296 "Written and designed by Anonymous Finnish Guy (C) 2008-2011", 1428 "Written and designed by Anonymous Finnish Guy (C) 2008-2011",
1297 "This software is freeware, use and distribute as you wish."); 1429 "This software is freeware, use and distribute as you wish.");
1298 th_verbosityLevel = 0; 1430 th_verbosityLevel = 0;
1302 th_cfg_add_comment(&tmpcfg, "General settings"); 1434 th_cfg_add_comment(&tmpcfg, "General settings");
1303 th_cfg_add_string(&tmpcfg, "username", &optUserName, NULL); 1435 th_cfg_add_string(&tmpcfg, "username", &optUserName, NULL);
1304 th_cfg_add_string(&tmpcfg, "password", &optPassword, NULL); 1436 th_cfg_add_string(&tmpcfg, "password", &optPassword, NULL);
1305 th_cfg_add_comment(&tmpcfg, "Default color as a hex-triplet"); 1437 th_cfg_add_comment(&tmpcfg, "Default color as a hex-triplet");
1306 th_cfg_add_hexvalue(&tmpcfg, "color", &optUserColor, optUserColor); 1438 th_cfg_add_hexvalue(&tmpcfg, "color", &optUserColor, optUserColor);
1307 1439
1308 th_cfg_add_comment(&tmpcfg, "Default setting of ignore mode"); 1440 th_cfg_add_comment(&tmpcfg, "Default setting of ignore mode");
1309 th_cfg_add_bool(&tmpcfg, "ignore", &setIgnoreMode, setIgnoreMode); 1441 th_cfg_add_bool(&tmpcfg, "ignore", &setIgnoreMode, setIgnoreMode);
1310 th_cfg_add_comment(&tmpcfg, "People to be ignored when ignore mode is enabled"); 1442 th_cfg_add_comment(&tmpcfg, "People to be ignored when ignore mode is enabled");
1311 th_cfg_add_string_list(&tmpcfg, "ignore_list", &setIgnoreList); 1443 th_cfg_add_string_list(&tmpcfg, "ignore_list", &setIgnoreList);
1312 1444
1339 th_cfg_add_string(&tmpcfg, "filename", &optLogFilename, optLogFilename); 1471 th_cfg_add_string(&tmpcfg, "filename", &optLogFilename, optLogFilename);
1340 th_cfg_add_section(&cfg, "logging", tmpcfg); 1472 th_cfg_add_section(&cfg, "logging", tmpcfg);
1341 1473
1342 #ifdef __WIN32 1474 #ifdef __WIN32
1343 { 1475 {
1344 char tmpPath[MAX_PATH]; 1476 char tmpPath[MAX_PATH];
1345 if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, tmpPath) == S_OK) 1477 if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, tmpPath) == S_OK)
1346 homeDir = th_strdup(tmpPath); 1478 homeDir = th_strdup(tmpPath);
1347 1479
1348 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); 1480 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
1349 } 1481 }
1350 #else 1482 #else
1351 homeDir = th_strdup(getenv("HOME")); 1483 homeDir = th_strdup(getenv("HOME"));
1352 #endif 1484 #endif
1353 1485
1354 if (homeDir != NULL) { 1486 if (homeDir != NULL)
1487 {
1355 FILE *cfgfile; 1488 FILE *cfgfile;
1356 setConfigFile = th_strdup_printf("%s" SET_DIR_SEPARATOR "%s", homeDir, SET_CONFIG_FILE); 1489 setConfigFile = th_strdup_printf("%s" SET_DIR_SEPARATOR "%s", homeDir, SET_CONFIG_FILE);
1357 1490
1358 THMSG(0, "Reading configuration from '%s'.\n", setConfigFile); 1491 THMSG(0, "Reading configuration from '%s'.\n", setConfigFile);
1359 1492
1360 if ((cfgfile = fopen(setConfigFile, "r")) != NULL) { 1493 if ((cfgfile = fopen(setConfigFile, "r")) != NULL)
1494 {
1361 th_cfg_read(cfgfile, setConfigFile, cfg); 1495 th_cfg_read(cfgfile, setConfigFile, cfg);
1362 fclose(cfgfile); 1496 fclose(cfgfile);
1363 } 1497 }
1364 } 1498 }
1365 1499
1366 setBrowser = getenv("BROWSER"); 1500 setBrowser = getenv("BROWSER");
1367 if (setBrowser == NULL) 1501 if (setBrowser == NULL)
1368 setBrowser = "firefox"; 1502 setBrowser = "firefox";
1369 1503
1370 /* Parse command line arguments */ 1504 /* Parse command line arguments */
1371 argsOK = th_args_process(argc, argv, optList, optListN, 1505 argsOK = th_args_process(argc, argv, optList, optListN,
1372 argHandleOpt, argHandleFile, FALSE); 1506 argHandleOpt, argHandleFile, FALSE);
1373 1507
1374 if (optUserNameCmd != NULL) { 1508 if (optUserNameCmd != NULL)
1509 {
1375 optUserName = optUserNameCmd; 1510 optUserName = optUserNameCmd;
1376 optPassword = optPasswordCmd; 1511 optPassword = optPasswordCmd;
1377 } 1512 }
1378 1513
1379 if (!argsOK) 1514 if (!argsOK)
1380 return -2; 1515 return -2;
1381 1516
1382 /* Allocate userhash */ 1517 /* Allocate userhash */
1383 if ((nnUsers = nn_userhash_new()) == NULL) { 1518 if ((nnUsers = nn_userhash_new()) == NULL)
1519 {
1384 THERR("Could not allocate userhash. Fatal error.\n"); 1520 THERR("Could not allocate userhash. Fatal error.\n");
1385 return -105; 1521 return -105;
1386 } 1522 }
1387 1523
1388 /* If no idle messages are set, add default */ 1524 /* If no idle messages are set, add default */
1389 if (setIdleMessages == NULL) { 1525 if (setIdleMessages == NULL)
1526 {
1390 th_llist_append(&setIdleMessages, th_strdup(".")); 1527 th_llist_append(&setIdleMessages, th_strdup("."));
1391 } 1528 }
1392 1529
1393 /* Open logfile */ 1530 /* Open logfile */
1394 logFileOpen(); 1531 logFileOpen();
1395 1532
1396 /* Initialize network */ 1533 /* Initialize network */
1397 if (!nn_network_init()) { 1534 if (!nn_network_init())
1535 {
1398 THERR("Could not initialize network subsystem.\n"); 1536 THERR("Could not initialize network subsystem.\n");
1399 goto err_exit; 1537 goto err_exit;
1400 } else 1538 }
1539 else
1401 networkInit = TRUE; 1540 networkInit = TRUE;
1402 1541
1403 /* Initialize NCurses */ 1542 /* Initialize NCurses */
1404 if (!optDaemon) { 1543 if (!optDaemon)
1544 {
1405 if (LINES < 0 || LINES > 1000) LINES = 24; 1545 if (LINES < 0 || LINES > 1000) LINES = 24;
1406 if (COLS < 0 || COLS > 1000) COLS = 80; 1546 if (COLS < 0 || COLS > 1000) COLS = 80;
1407 initscr(); 1547 initscr();
1408 raw(); 1548 raw();
1409 keypad(stdscr, TRUE); 1549 keypad(stdscr, TRUE);
1410 noecho(); 1550 noecho();
1411 meta(stdscr, TRUE); 1551 meta(stdscr, TRUE);
1412 timeout(SET_DELAY); 1552 timeout(SET_DELAY);
1413 curVis = curs_set(0); 1553 curVis = curs_set(0);
1414 1554
1415 if (has_colors()) { 1555 if (has_colors())
1556 {
1416 start_color(); 1557 start_color();
1417 1558
1418 init_pair( 1, COLOR_RED, COLOR_BLACK); 1559 init_pair( 1, COLOR_RED, COLOR_BLACK);
1419 init_pair( 2, COLOR_GREEN, COLOR_BLACK); 1560 init_pair( 2, COLOR_GREEN, COLOR_BLACK);
1420 init_pair( 3, COLOR_YELLOW, COLOR_BLACK); 1561 init_pair( 3, COLOR_YELLOW, COLOR_BLACK);
1421 init_pair( 4, COLOR_BLUE, COLOR_BLACK); 1562 init_pair( 4, COLOR_BLUE, COLOR_BLACK);
1422 init_pair( 5, COLOR_MAGENTA, COLOR_BLACK); 1563 init_pair( 5, COLOR_MAGENTA, COLOR_BLACK);
1430 init_pair(13, COLOR_YELLOW, COLOR_RED); 1571 init_pair(13, COLOR_YELLOW, COLOR_RED);
1431 init_pair(14, COLOR_BLUE, COLOR_RED); 1572 init_pair(14, COLOR_BLUE, COLOR_RED);
1432 init_pair(15, COLOR_MAGENTA, COLOR_RED); 1573 init_pair(15, COLOR_MAGENTA, COLOR_RED);
1433 init_pair(16, COLOR_CYAN, COLOR_RED); 1574 init_pair(16, COLOR_CYAN, COLOR_RED);
1434 } 1575 }
1435 1576
1436 cursesInit = TRUE; 1577 cursesInit = TRUE;
1437 1578
1438 if (!initializeWindows()) 1579 if (!initializeWindows())
1439 goto err_exit; 1580 goto err_exit;
1440 1581
1441 #ifdef PDCURSES 1582 #ifdef PDCURSES
1442 PDC_set_title("NNChat v" NN_VERSION); 1583 PDC_set_title("NNChat v" NN_VERSION);
1443 #endif 1584 #endif
1444 1585
1445 memset(chatWindows, 0, sizeof(chatWindows)); 1586 memset(chatWindows, 0, sizeof(chatWindows));
1446 chatWindows[0] = nn_window_new(NULL); 1587 chatWindows[0] = nn_window_new(NULL);
1447 currWin = chatWindows[0]; 1588 currWin = chatWindows[0];
1448 updateStatus(); 1589 updateStatus();
1449 } 1590 }
1450 1591
1451 /* Check if we have username and password */ 1592 /* Check if we have username and password */
1452 if (cursesInit && (optUserName == NULL || optPassword == NULL)) { 1593 if (cursesInit && (optUserName == NULL || optPassword == NULL))
1594 {
1453 printWin(editWin, "You can avoid this prompt by issuing '/save' after logging in.\n"); 1595 printWin(editWin, "You can avoid this prompt by issuing '/save' after logging in.\n");
1454 optUserName = promptRequester(editWin, "NN username: ", FALSE); 1596 optUserName = promptRequester(editWin, "NN username: ", FALSE);
1455 optPassword = promptRequester(editWin, "NN password: ", TRUE); 1597 optPassword = promptRequester(editWin, "NN password: ", TRUE);
1456 } 1598 }
1457 1599
1458 if (optUserName == NULL || optPassword == NULL) { 1600 if (optUserName == NULL || optPassword == NULL)
1601 {
1459 errorMsg("Username and/or password not specified.\n"); 1602 errorMsg("Username and/or password not specified.\n");
1460 goto err_exit; 1603 goto err_exit;
1461 } 1604 }
1462 1605
1463 /* Create a connection */ 1606 /* Create a connection */
1464 conn = nn_conn_new(errorFunc, messageFunc); 1607 conn = nn_conn_new(errorFunc, messageFunc);
1465 if (conn == NULL) { 1608 if (conn == NULL)
1609 {
1466 errorMsg("Could not create connection structure.\n"); 1610 errorMsg("Could not create connection structure.\n");
1467 goto err_exit; 1611 goto err_exit;
1468 } 1612 }
1469 1613
1470 /* Are we using a proxy? */ 1614 /* Are we using a proxy? */
1471 if (optProxyType != NN_PROXY_NONE && optProxyServer != NULL) { 1615 if (optProxyType != NN_PROXY_NONE && optProxyServer != NULL)
1472 if (nn_conn_set_proxy(conn, optProxyType, optProxyPort, optProxyServer) != 0) { 1616 {
1617 if (nn_conn_set_proxy(conn, optProxyType, optProxyPort, optProxyServer) != 0)
1618 {
1473 errorMsg("Error setting proxy information.\n"); 1619 errorMsg("Error setting proxy information.\n");
1474 goto err_exit; 1620 goto err_exit;
1475 } 1621 }
1476 } 1622 }
1477 1623
1478 /* Okay ... */ 1624 /* Okay ... */
1479 printMsg(currWin, "Trying to resolve host '%s' ...\n", optServer); 1625 printMsg(currWin, "Trying to resolve host '%s' ...\n", optServer);
1480 conn->host = th_strdup(optServer); 1626 conn->host = th_strdup(optServer);
1481 conn->hst = nn_resolve_host(conn, optServer); 1627 conn->hst = nn_resolve_host(conn, optServer);
1482 if (conn->hst == NULL) { 1628 if (conn->hst == NULL)
1629 {
1483 errorMsg("Could not resolve hostname: %s.\n", strerror(h_errno)); 1630 errorMsg("Could not resolve hostname: %s.\n", strerror(h_errno));
1484 goto err_exit; 1631 goto err_exit;
1485 } 1632 }
1486 1633
1487 #ifdef FINAL_BUILD 1634 #ifdef FINAL_BUILD
1488 /* To emulate the official client, we first make a request for 1635 /* To emulate the official client, we first make a request for
1489 * policy file, even though we don't use it for anything... 1636 * policy file, even though we don't use it for anything...
1490 */ 1637 */
1491 if (nn_conn_open(conn, 843, NULL) != 0) { 1638 if (nn_conn_open(conn, 843, NULL) != 0)
1639 {
1492 errorMsg("Policy file request connection setup failed!\n"); 1640 errorMsg("Policy file request connection setup failed!\n");
1493 goto err_exit; 1641 goto err_exit;
1494 } 1642 }
1495 1643
1496 tmpStr = "<policy-file-request/>"; 1644 tmpStr = "<policy-file-request/>";
1497 if (nn_conn_send_buf(conn, tmpStr, strlen(tmpStr) + 1) == FALSE) { 1645 if (nn_conn_send_buf(conn, tmpStr, strlen(tmpStr) + 1) == FALSE)
1646 {
1498 errorMsg("Failed to send policy file request.\n"); 1647 errorMsg("Failed to send policy file request.\n");
1499 goto err_exit; 1648 goto err_exit;
1500 } else { 1649 }
1650 else
1651 {
1501 int cres = nn_conn_pull(conn); 1652 int cres = nn_conn_pull(conn);
1502 if (cres == 0) { 1653 if (cres == 0)
1654 {
1503 printMsg(currWin, "Probe got: %s\n", conn->buf); 1655 printMsg(currWin, "Probe got: %s\n", conn->buf);
1504 } else { 1656 }
1657 else
1658 {
1505 printMsg(currWin, "Could not get policy probe.\n"); 1659 printMsg(currWin, "Could not get policy probe.\n");
1506 } 1660 }
1507 } 1661 }
1508 nn_conn_close(conn); 1662 nn_conn_close(conn);
1509 #endif 1663 #endif
1510 1664
1511 /* Okay, now do the proper connection ... */ 1665 /* Okay, now do the proper connection ... */
1512 if (nn_conn_open(conn, optPort, NULL) != 0) { 1666 if (nn_conn_open(conn, optPort, NULL) != 0)
1667 {
1513 errorMsg("Main connection setup failed!\n"); 1668 errorMsg("Main connection setup failed!\n");
1514 goto err_exit; 1669 goto err_exit;
1515 } 1670 }
1516 1671
1517 /* Send login command */ 1672 /* Send login command */
1518 optUserNameEnc = nn_dblencode_str(optUserName); 1673 optUserNameEnc = nn_dblencode_str(optUserName);
1519 tmpStr = nn_dblencode_str(optSite); 1674 tmpStr = nn_dblencode_str(optSite);
1520 nn_conn_send_msg(conn, optUserNameEnc, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword); 1675 nn_conn_send_msg(conn, optUserNameEnc, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword);
1521 th_free(tmpStr); 1676 th_free(tmpStr);
1522 1677
1523 /* Initialize random numbers */ 1678 /* Initialize random numbers */
1524 prevTime = time(NULL); 1679 prevTime = time(NULL);
1525 srandom((int) prevTime); 1680 srandom((int) prevTime);
1526 1681
1527 if (cursesInit) { 1682 if (cursesInit)
1683 {
1528 /* Initialize rest of interactive UI code */ 1684 /* Initialize rest of interactive UI code */
1529 nn_editbuf_clear(editBuf); 1685 nn_editbuf_clear(editBuf);
1530 1686
1531 /* First update of screen */ 1687 /* First update of screen */
1532 printEditBuf(editBuf); 1688 printEditBuf(editBuf);
1537 printMsg(NULL, "%s\n", th_prog_license); 1693 printMsg(NULL, "%s\n", th_prog_license);
1538 } 1694 }
1539 1695
1540 /* Enter mainloop */ 1696 /* Enter mainloop */
1541 nn_conn_reset(conn); 1697 nn_conn_reset(conn);
1542 while (!isError && !exitProg) { 1698 while (!isError && !exitProg)
1699 {
1543 int cres = nn_conn_pull(conn); 1700 int cres = nn_conn_pull(conn);
1544 if (cres == 0 && *(conn->ptr - 1) == 0) { 1701 if (cres == 0 && *(conn->ptr - 1) == 0)
1702 {
1545 char *ptr = conn->buf; 1703 char *ptr = conn->buf;
1546 do { 1704 do
1705 {
1547 size_t bufLen = strlen(ptr) + 1; 1706 size_t bufLen = strlen(ptr) + 1;
1548 int result = handleProtocol(conn, ptr, bufLen); 1707 int result = handleProtocol(conn, ptr, bufLen);
1549 1708
1550 if (result > 0) 1709 if (result > 0)
1551 { 1710 {
1559 isError = TRUE; 1718 isError = TRUE;
1560 } 1719 }
1561 1720
1562 conn->total -= bufLen; 1721 conn->total -= bufLen;
1563 ptr += bufLen; 1722 ptr += bufLen;
1564 } while (conn->total > 0 && !isError); 1723 }
1724 while (conn->total > 0 && !isError);
1565 nn_conn_reset(conn); 1725 nn_conn_reset(conn);
1566 } 1726 }
1567 if (!nn_conn_check(conn)) 1727 if (!nn_conn_check(conn))
1568 isError = TRUE; 1728 isError = TRUE;
1569 1729
1570 /* Handle user input */ 1730 /* Handle user input */
1571 if (cursesInit) { 1731 if (cursesInit)
1732 {
1572 int c, cnt = 0; 1733 int c, cnt = 0;
1573 BOOL update = FALSE, updateMain = FALSE; 1734 BOOL update = FALSE, updateMain = FALSE;
1574 1735
1575 /* Handle several buffered keypresses at once */ 1736 /* Handle several buffered keypresses at once */
1576 do { 1737 do
1577 c = wgetch(stdscr); 1738 {
1578 if (c == 0x1b) {
1579 c = wgetch(stdscr); 1739 c = wgetch(stdscr);
1580 if (c == 'O') { 1740 if (c == 0x1b)
1741 {
1581 c = wgetch(stdscr); 1742 c = wgetch(stdscr);
1582 switch (c) { 1743 if (c == 'O')
1583 case 'd': c = 0x204; break; 1744 {
1584 case 'c': c = 0x206; break; 1745 c = wgetch(stdscr);
1746 switch (c)
1747 {
1748 case 'd':
1749 c = 0x204;
1750 break;
1751 case 'c':
1752 c = 0x206;
1753 break;
1585 default: 1754 default:
1586 if (optDebug) 1755 if (optDebug)
1587 printMsg(currWin, "Unhandled ESC-O key sequence 0x%02x\n", c); 1756 printMsg(currWin, "Unhandled ESC-O key sequence 0x%02x\n", c);
1588 break; 1757 break;
1758 }
1589 } 1759 }
1590 } else 1760 else if (c == '[')
1591 if (c == '[') { 1761 {
1592 c = wgetch(stdscr); 1762 c = wgetch(stdscr);
1593 switch (c) { 1763 switch (c)
1764 {
1594 case 0x31: 1765 case 0x31:
1595 c = wgetch(stdscr); 1766 c = wgetch(stdscr);
1596 if (c >= 0x31 && c <= 0x39) 1767 if (c >= 0x31 && c <= 0x39)
1597 c = KEY_F(c - 0x30); 1768 c = KEY_F(c - 0x30);
1598 else 1769 else
1599 c = ERR; 1770 c = ERR;
1600 break; 1771 break;
1601 1772
1602 case 0x32: c = KEY_IC; break; 1773 case 0x32:
1603 case 0x33: c = KEY_DC; break; 1774 c = KEY_IC;
1604 1775 break;
1605 case 0x35: c = KEY_PPAGE; break; 1776 case 0x33:
1606 case 0x36: c = KEY_NPAGE; break; 1777 c = KEY_DC;
1607 1778 break;
1608 case 0x37: c = KEY_HOME; break; 1779
1609 case 0x38: c = KEY_END; break; 1780 case 0x35:
1610 1781 c = KEY_PPAGE;
1782 break;
1783 case 0x36:
1784 c = KEY_NPAGE;
1785 break;
1786
1787 case 0x37:
1788 c = KEY_HOME;
1789 break;
1790 case 0x38:
1791 c = KEY_END;
1792 break;
1793
1611 default: 1794 default:
1612 if (optDebug) 1795 if (optDebug)
1613 printMsg(currWin, "Unhandled ESC-[*~ key sequence 0x%02x\n", c); 1796 printMsg(currWin, "Unhandled ESC-[*~ key sequence 0x%02x\n", c);
1614 c = ERR; 1797 c = ERR;
1615 break; 1798 break;
1799 }
1800 /* Get the trailing ~ */
1801 if (c != ERR)
1802 wgetch(stdscr);
1616 } 1803 }
1617 /* Get the trailing ~ */ 1804 if (c >= 0x31 && c <= 0x39)
1618 if (c != ERR) 1805 {
1619 wgetch(stdscr); 1806 /* Chat window switching via Meta/Esc-[1..9] */
1807 int win = c - 0x31;
1808 if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL)
1809 {
1810 currWin = chatWindows[win];
1811 update = updateMain = TRUE;
1812 }
1813 c = ERR;
1814 }
1815 else
1816 {
1817 if (optDebug)
1818 printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c);
1819 }
1620 } 1820 }
1621 if (c >= 0x31 && c <= 0x39) { 1821 #if defined(__WIN32) && defined(PDCURSES)
1822 else if (c >= 0x198 && c <= 0x1a0)
1823 {
1622 /* Chat window switching via Meta/Esc-[1..9] */ 1824 /* Chat window switching via Meta/Esc-[1..9] */
1623 int win = c - 0x31; 1825 int win = c - 0x198;
1624 if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL) { 1826 if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL)
1827 {
1625 currWin = chatWindows[win]; 1828 currWin = chatWindows[win];
1626 update = updateMain = TRUE; 1829 update = updateMain = TRUE;
1627 } 1830 }
1628 c = ERR; 1831 c = ERR;
1629 } 1832 }
1630 else { 1833 #endif
1631 if (optDebug) 1834
1632 printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c); 1835 switch (c)
1836 {
1837 #ifdef KEY_RESIZE
1838 case KEY_RESIZE:
1839 resize_term(0, 0);
1840 erase();
1841 timeout(SET_DELAY);
1842
1843 if (!initializeWindows())
1844 {
1845 errorMsg("Error resizing curses chatWindows\n");
1846 isError = TRUE;
1847 }
1848 update = updateMain = TRUE;
1849 break;
1850 #endif
1851
1852 case KEY_ENTER:
1853 case '\n':
1854 case '\r':
1855 /* Call the user input handler */
1856 if (editBuf->len > 0)
1857 {
1858 int result;
1859
1860 if (histMax > 0)
1861 {
1862 nn_editbuf_free(histBuf[SET_MAX_HISTORY+1]);
1863 histBuf[SET_MAX_HISTORY+1] = NULL;
1864 memmove(&histBuf[2], &histBuf[1], histMax * sizeof(histBuf[0]));
1865 }
1866
1867 histPos = 0;
1868 histBuf[1] = nn_editbuf_copy(editBuf);
1869 if (histMax < SET_MAX_HISTORY) histMax++;
1870
1871 nn_editbuf_insert(editBuf, editBuf->len, 0);
1872 result = handleUserInput(conn, editBuf->data, editBuf->len);
1873
1874 nn_editbuf_clear(editBuf);
1875
1876 if (result < 0)
1877 {
1878 errorMsg("Fatal error handling user input: %s\n", editBuf->data);
1879 isError = TRUE;
1880 }
1881 else
1882 {
1883 /* Update time value of last sent message for unidle timeouts */
1884 prevTime = time(NULL);
1885 }
1886
1887 updateMain = update = TRUE;
1888 }
1889 break;
1890
1891 case KEY_UP: /* Backwards in input history */
1892 if (histPos == 0)
1893 {
1894 nn_editbuf_free(histBuf[0]);
1895 histBuf[0] = nn_editbuf_copy(editBuf);
1896 }
1897 if (histPos < histMax)
1898 {
1899 histPos++;
1900 nn_editbuf_free(editBuf);
1901 editBuf = nn_editbuf_copy(histBuf[histPos]);
1902 update = TRUE;
1903 }
1904 break;
1905
1906 case KEY_DOWN: /* Forwards in input history */
1907 if (histPos > 0)
1908 {
1909 histPos--;
1910 nn_editbuf_free(editBuf);
1911 editBuf = nn_editbuf_copy(histBuf[histPos]);
1912 update = TRUE;
1913 }
1914 break;
1915
1916 case 0x204: /* ctrl+left arrow = Skip words left */
1917 case 0x20b:
1918 while (editBuf->pos > 0 && isspace((int) editBuf->data[editBuf->pos - 1]))
1919 editBuf->pos--;
1920 while (editBuf->pos > 0 && !isspace((int) editBuf->data[editBuf->pos - 1]))
1921 editBuf->pos--;
1922 update = TRUE;
1923 break;
1924
1925 case 0x206: /* ctrl+right arrow = Skip words right */
1926 case 0x210:
1927 while (editBuf->pos < editBuf->len && isspace((int) editBuf->data[editBuf->pos]))
1928 editBuf->pos++;
1929 while (editBuf->pos < editBuf->len && !isspace((int) editBuf->data[editBuf->pos]))
1930 editBuf->pos++;
1931 update = TRUE;
1932 break;
1933
1934 case KEY_HOME:
1935 nn_editbuf_setpos(editBuf, 0);
1936 update = TRUE;
1937 break;
1938 case KEY_END:
1939 nn_editbuf_setpos(editBuf, editBuf->len);
1940 update = TRUE;
1941 break;
1942 case KEY_LEFT:
1943 nn_editbuf_setpos(editBuf, editBuf->pos - 1);
1944 update = TRUE;
1945 break;
1946 case KEY_RIGHT:
1947 nn_editbuf_setpos(editBuf, editBuf->pos + 1);
1948 update = TRUE;
1949 break;
1950
1951 case KEY_BACKSPACE:
1952 case 0x08:
1953 case 0x7f:
1954 nn_editbuf_delete(editBuf, editBuf->pos - 1);
1955 nn_editbuf_setpos(editBuf, editBuf->pos - 1);
1956 update = TRUE;
1957 break;
1958
1959 case KEY_DC: /* Delete character */
1960 nn_editbuf_delete(editBuf, editBuf->pos);
1961 update = TRUE;
1962 break;
1963
1964
1965 case KEY_IC: /* Ins = Toggle insert / overwrite mode */
1966 insertMode = !insertMode;
1967 update = TRUE;
1968 break;
1969
1970 case KEY_F(1): /* F1 = Print help */
1971 printHelp();
1972 updateMain = TRUE;
1973 break;
1974
1975 case KEY_F(2): /* F2 = Clear editbuffer */
1976 nn_editbuf_clear(editBuf);
1977 update = TRUE;
1978 break;
1979
1980 case KEY_F(5): /* F5 = Ignore mode */
1981 setIgnoreMode = !setIgnoreMode;
1982 printMsgQ(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF");
1983 break;
1984
1985 #if 0
1986 case KEY_F(8): /* F8 = Debug */
1987 optDebug = !optDebug;
1988 update = TRUE;
1989 break;
1990 #endif
1991
1992 case 0x03: /* ^C = quit */
1993 case KEY_F(9): /* F9 = Quit */
1994 printMsg(currWin, "Quitting per user request (%d/0x%x).\n", c, c);
1995 exitProg = TRUE;
1996 break;
1997
1998 case 0x09: /* Tab = complete username */
1999 performTabCompletion(editBuf);
2000 update = TRUE;
2001 break;
2002
2003 case 0x0c: /* Ctrl + L */
2004 updateWindows();
2005 update = updateMain = TRUE;
2006 break;
2007
2008 case KEY_NPAGE:
2009 case KEY_PPAGE:
2010 /* Page Up / Page Down */
2011 if (currWin != NULL)
2012 {
2013 int oldPos = currWin->pos;
2014
2015 currWin->pos += (c == KEY_NPAGE) ? -10 : +10;
2016
2017 if (currWin->pos < 0)
2018 currWin->pos = 0;
2019 else if (currWin->pos >= currWin->data->n - 10)
2020 currWin->pos = currWin->data->n - 10;
2021
2022 if (oldPos != currWin->pos)
2023 updateMain = TRUE;
2024 }
2025 break;
2026
2027 case ERR:
2028 /* Ignore */
2029 break;
2030
2031 default:
2032 if (isprint(c) || c == 0xe4 || c == 0xf6 || c == 0xc4 || c == 0xd6)
2033 {
2034 if (insertMode)
2035 nn_editbuf_insert(editBuf, editBuf->pos, c);
2036 else
2037 nn_editbuf_write(editBuf, editBuf->pos, c);
2038 nn_editbuf_setpos(editBuf, editBuf->pos + 1);
2039 update = TRUE;
2040 }
2041 else
2042 {
2043 if (optDebug)
2044 printMsg(currWin, "Unhandled key: 0x%02x\n", c);
2045 }
2046 break;
1633 } 2047 }
1634 } 2048 }
1635 #if defined(__WIN32) && defined(PDCURSES) 2049 while (c != ERR && !exitProg && ++cnt < 10);
1636 else 2050
1637 if (c >= 0x198 && c <= 0x1a0) {
1638 /* Chat window switching via Meta/Esc-[1..9] */
1639 int win = c - 0x198;
1640 if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL) {
1641 currWin = chatWindows[win];
1642 update = updateMain = TRUE;
1643 }
1644 c = ERR;
1645 }
1646 #endif
1647
1648 switch (c) {
1649 #ifdef KEY_RESIZE
1650 case KEY_RESIZE:
1651 resize_term(0, 0);
1652 erase();
1653 timeout(SET_DELAY);
1654
1655 if (!initializeWindows())
1656 {
1657 errorMsg("Error resizing curses chatWindows\n");
1658 isError = TRUE;
1659 }
1660 update = updateMain = TRUE;
1661 break;
1662 #endif
1663
1664 case KEY_ENTER:
1665 case '\n':
1666 case '\r':
1667 /* Call the user input handler */
1668 if (editBuf->len > 0) {
1669 int result;
1670
1671 if (histMax > 0) {
1672 nn_editbuf_free(histBuf[SET_MAX_HISTORY+1]);
1673 histBuf[SET_MAX_HISTORY+1] = NULL;
1674 memmove(&histBuf[2], &histBuf[1], histMax * sizeof(histBuf[0]));
1675 }
1676
1677 histPos = 0;
1678 histBuf[1] = nn_editbuf_copy(editBuf);
1679 if (histMax < SET_MAX_HISTORY) histMax++;
1680
1681 nn_editbuf_insert(editBuf, editBuf->len, 0);
1682 result = handleUserInput(conn, editBuf->data, editBuf->len);
1683
1684 nn_editbuf_clear(editBuf);
1685
1686 if (result < 0)
1687 {
1688 errorMsg("Fatal error handling user input: %s\n", editBuf->data);
1689 isError = TRUE;
1690 } else {
1691 /* Update time value of last sent message for unidle timeouts */
1692 prevTime = time(NULL);
1693 }
1694
1695 updateMain = update = TRUE;
1696 }
1697 break;
1698
1699 case KEY_UP: /* Backwards in input history */
1700 if (histPos == 0) {
1701 nn_editbuf_free(histBuf[0]);
1702 histBuf[0] = nn_editbuf_copy(editBuf);
1703 }
1704 if (histPos < histMax) {
1705 histPos++;
1706 nn_editbuf_free(editBuf);
1707 editBuf = nn_editbuf_copy(histBuf[histPos]);
1708 update = TRUE;
1709 }
1710 break;
1711
1712 case KEY_DOWN: /* Forwards in input history */
1713 if (histPos > 0) {
1714 histPos--;
1715 nn_editbuf_free(editBuf);
1716 editBuf = nn_editbuf_copy(histBuf[histPos]);
1717 update = TRUE;
1718 }
1719 break;
1720
1721 case 0x204: /* ctrl+left arrow = Skip words left */
1722 case 0x20b:
1723 while (editBuf->pos > 0 && isspace((int) editBuf->data[editBuf->pos - 1]))
1724 editBuf->pos--;
1725 while (editBuf->pos > 0 && !isspace((int) editBuf->data[editBuf->pos - 1]))
1726 editBuf->pos--;
1727 update = TRUE;
1728 break;
1729
1730 case 0x206: /* ctrl+right arrow = Skip words right */
1731 case 0x210:
1732 while (editBuf->pos < editBuf->len && isspace((int) editBuf->data[editBuf->pos]))
1733 editBuf->pos++;
1734 while (editBuf->pos < editBuf->len && !isspace((int) editBuf->data[editBuf->pos]))
1735 editBuf->pos++;
1736 update = TRUE;
1737 break;
1738
1739 case KEY_HOME: nn_editbuf_setpos(editBuf, 0); update = TRUE; break;
1740 case KEY_END: nn_editbuf_setpos(editBuf, editBuf->len); update = TRUE; break;
1741 case KEY_LEFT: nn_editbuf_setpos(editBuf, editBuf->pos - 1); update = TRUE; break;
1742 case KEY_RIGHT: nn_editbuf_setpos(editBuf, editBuf->pos + 1); update = TRUE; break;
1743
1744 case KEY_BACKSPACE:
1745 case 0x08:
1746 case 0x7f:
1747 nn_editbuf_delete(editBuf, editBuf->pos - 1);
1748 nn_editbuf_setpos(editBuf, editBuf->pos - 1);
1749 update = TRUE;
1750 break;
1751
1752 case KEY_DC: /* Delete character */
1753 nn_editbuf_delete(editBuf, editBuf->pos);
1754 update = TRUE;
1755 break;
1756
1757
1758 case KEY_IC: /* Ins = Toggle insert / overwrite mode */
1759 insertMode = !insertMode;
1760 update = TRUE;
1761 break;
1762
1763 case KEY_F(1): /* F1 = Print help */
1764 printHelp();
1765 updateMain = TRUE;
1766 break;
1767
1768 case KEY_F(2): /* F2 = Clear editbuffer */
1769 nn_editbuf_clear(editBuf);
1770 update = TRUE;
1771 break;
1772
1773 case KEY_F(5): /* F5 = Ignore mode */
1774 setIgnoreMode = !setIgnoreMode;
1775 printMsgQ(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF");
1776 break;
1777
1778 #if 0
1779 case KEY_F(8): /* F8 = Debug */
1780 optDebug = !optDebug;
1781 update = TRUE;
1782 break;
1783 #endif
1784
1785 case 0x03: /* ^C = quit */
1786 case KEY_F(9): /* F9 = Quit */
1787 printMsg(currWin, "Quitting per user request (%d/0x%x).\n", c, c);
1788 exitProg = TRUE;
1789 break;
1790
1791 case 0x09: /* Tab = complete username */
1792 performTabCompletion(editBuf);
1793 update = TRUE;
1794 break;
1795
1796 case 0x0c: /* Ctrl + L */
1797 updateWindows();
1798 update = updateMain = TRUE;
1799 break;
1800
1801 case KEY_NPAGE:
1802 case KEY_PPAGE:
1803 /* Page Up / Page Down */
1804 if (currWin != NULL)
1805 {
1806 int oldPos = currWin->pos;
1807
1808 currWin->pos += (c == KEY_NPAGE) ? -10 : +10;
1809
1810 if (currWin->pos < 0)
1811 currWin->pos = 0;
1812 else if (currWin->pos >= currWin->data->n - 10)
1813 currWin->pos = currWin->data->n - 10;
1814
1815 if (oldPos != currWin->pos)
1816 updateMain = TRUE;
1817 }
1818 break;
1819
1820 case ERR:
1821 /* Ignore */
1822 break;
1823
1824 default:
1825 if (isprint(c) || c == 0xe4 || c == 0xf6 || c == 0xc4 || c == 0xd6) {
1826 if (insertMode)
1827 nn_editbuf_insert(editBuf, editBuf->pos, c);
1828 else
1829 nn_editbuf_write(editBuf, editBuf->pos, c);
1830 nn_editbuf_setpos(editBuf, editBuf->pos + 1);
1831 update = TRUE;
1832 } else {
1833 if (optDebug)
1834 printMsg(currWin, "Unhandled key: 0x%02x\n", c);
1835 }
1836 break;
1837 }
1838 } while (c != ERR && !exitProg && ++cnt < 10);
1839
1840 updateMainWin(updateMain); 2051 updateMainWin(updateMain);
1841 2052
1842 if (update || firstUpdate) { 2053 if (update || firstUpdate)
2054 {
1843 /* Update edit line */ 2055 /* Update edit line */
1844 updateStatus(); 2056 updateStatus();
1845 printEditBuf(editBuf); 2057 printEditBuf(editBuf);
1846 firstUpdate = FALSE; /* a nasty hack ... */ 2058 firstUpdate = FALSE; /* a nasty hack ... */
1847 } 2059 }
1848 2060
1849 } /* cursesInit */ 2061 } /* cursesInit */
1850 2062
1851 if (++updateCount > 10) { 2063 if (++updateCount > 10)
2064 {
1852 time_t tmpTime = time(NULL); 2065 time_t tmpTime = time(NULL);
1853 if (tmpTime - prevTime > SET_KEEPALIVE) { 2066 if (tmpTime - prevTime > SET_KEEPALIVE)
2067 {
1854 int n = random() % th_llist_length(setIdleMessages); 2068 int n = random() % th_llist_length(setIdleMessages);
1855 qlist_t *node = th_llist_get_nth(setIdleMessages, n); 2069 qlist_t *node = th_llist_get_nth(setIdleMessages, n);
1856 nn_conn_send_msg(conn, optUserNameEnc, node->data); 2070 nn_conn_send_msg(conn, optUserNameEnc, node->data);
1857 prevTime = tmpTime; 2071 prevTime = tmpTime;
1858 } 2072 }
1859 2073
1860 if (!colorSet) { 2074 if (!colorSet)
2075 {
1861 colorSet = TRUE; 2076 colorSet = TRUE;
1862 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 2077 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
1863 } 2078 }
1864 2079
1865 updateStatus(); 2080 updateStatus();
1866 printEditBuf(editBuf); 2081 printEditBuf(editBuf);
1867 updateCount = 0; 2082 updateCount = 0;
1868 } 2083 }
1869 2084
1870 } 2085 }
1871 2086
1872 /* Shutdown */ 2087 /* Shutdown */
1873 err_exit: 2088 err_exit:
1874 th_cfg_free(cfg); 2089 th_cfg_free(cfg);
1875 th_free(homeDir); 2090 th_free(homeDir);
1876 th_llist_free_func(setIdleMessages, th_free); 2091 th_llist_free_func(setIdleMessages, th_free);
1877 nn_userhash_free(nnUsers); 2092 nn_userhash_free(nnUsers);
1878 nn_editbuf_free(editBuf); 2093 nn_editbuf_free(editBuf);
1879 2094
1880 { 2095 {
1881 int i; 2096 int i;
1882 for (i = 0; i <= SET_MAX_HISTORY; i++) 2097 for (i = 0; i <= SET_MAX_HISTORY; i++)
1883 nn_editbuf_free(histBuf[i]); 2098 nn_editbuf_free(histBuf[i]);
1884 2099
1885 for (i = 0; i < SET_MAX_WINDOWS; i++) 2100 for (i = 0; i < SET_MAX_WINDOWS; i++)
1886 nn_window_free(chatWindows[i]); 2101 nn_window_free(chatWindows[i]);
1887 } 2102 }
1888 2103
1889 #ifdef __WIN32 2104 #ifdef __WIN32
1890 if (errorMessages) { 2105 if (errorMessages)
2106 {
1891 char *tmp; 2107 char *tmp;
1892 wclear(editWin); 2108 wclear(editWin);
1893 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE); 2109 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE);
1894 th_free(tmp); 2110 th_free(tmp);
1895 } 2111 }
1896 #endif 2112 #endif
1897 2113
1898 if (cursesInit) { 2114 if (cursesInit)
2115 {
1899 if (curVis != ERR) 2116 if (curVis != ERR)
1900 curs_set(curVis); 2117 curs_set(curVis);
1901 closeWindows(); 2118 closeWindows();
1902 endwin(); 2119 endwin();
1903 THMSG(1, "NCurses deinitialized.\n"); 2120 THMSG(1, "NCurses deinitialized.\n");
1904 } 2121 }
1905 2122
1906 #ifndef __WIN32 2123 #ifndef __WIN32
1907 if (errorMessages) 2124 if (errorMessages)
1908 THERR("%s", errorMessages); 2125 THERR("%s", errorMessages);
1909 #endif 2126 #endif
1910 2127
1911 th_free(optUserNameEnc); 2128 th_free(optUserNameEnc);
1912 2129
1913 nn_conn_close(conn); 2130 nn_conn_close(conn);
1914 2131
1915 if (networkInit) 2132 if (networkInit)
1916 nn_network_close(); 2133 nn_network_close();
1917 2134
1918 THMSG(1, "Connection terminated.\n"); 2135 THMSG(1, "Connection terminated.\n");
1919 2136
1920 logFileClose(); 2137 logFileClose();
1921 2138
1922 return 0; 2139 return 0;
1923 } 2140 }