comparison nnchat.c @ 288:e7ef3db3b954

Implement "windows" in the chat. Only main window used for now, and even that is not working perfectly yet, tho.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 11 Jun 2011 01:10:48 +0300
parents 922d463ebe9b
children c53f880837f5
comparison
equal deleted inserted replaced
287:eb74097b73f5 288:e7ef3db3b954
33 #endif 33 #endif
34 34
35 #define SET_BACKBUF_LEN (512) /* Backbuffer size (in lines) */ 35 #define SET_BACKBUF_LEN (512) /* Backbuffer size (in lines) */
36 #define SET_MAX_HISTORY (16) /* Command history length */ 36 #define SET_MAX_HISTORY (16) /* Command history length */
37 #define SET_KEEPALIVE (15*60) /* Ping/keepalive period in seconds */ 37 #define SET_KEEPALIVE (15*60) /* Ping/keepalive period in seconds */
38 38 #define SET_MAX_WINDOWS (32)
39
40
41 typedef struct {
42 qringbuf_t *data; /* "Backbuffer" data for this window */
43 int pos; /* Current position in the window, 0 = real time */
44 char *id; /* Chatter ID, NULL = main window */
45 BOOL dirty;
46
47 char *buf;
48 size_t len, bufsize;
49 } nn_window_t;
39 50
40 51
41 /* Options 52 /* Options
42 */ 53 */
43 int optPort = 8005; 54 int optPort = 8005;
52 *setTarget = NULL, 63 *setTarget = NULL,
53 *optSite = "NN"; 64 *optSite = "NN";
54 char optNickSep = ':'; 65 char optNickSep = ':';
55 BOOL optDaemon = FALSE; 66 BOOL optDaemon = FALSE;
56 FILE *optLogFile = NULL; 67 FILE *optLogFile = NULL;
57 WINDOW *mainWin = NULL,
58 *statusWin = NULL,
59 *editWin = NULL;
60 BOOL setPrvMode = FALSE; 68 BOOL setPrvMode = FALSE;
61 BOOL setIgnoreMode = FALSE; 69 BOOL setIgnoreMode = FALSE;
62 BOOL optDebug = FALSE; 70 BOOL optDebug = FALSE;
63 BOOL optLogEnable = FALSE; 71 BOOL optLogEnable = FALSE;
72
73 nn_window_t *chatWindows[SET_MAX_WINDOWS],
74 *currWin = NULL;
75 WINDOW *mainWin = NULL,
76 *statusWin = NULL,
77 *editWin = NULL;
64 78
65 qlist_t *setIgnoreList = NULL, 79 qlist_t *setIgnoreList = NULL,
66 *setIdleMessages = NULL; 80 *setIdleMessages = NULL;
67 nn_userhash_t *nnUsers = NULL; 81 nn_userhash_t *nnUsers = NULL;
68 char *setConfigFile = NULL, 82 char *setConfigFile = NULL,
172 } 186 }
173 187
174 return TRUE; 188 return TRUE;
175 } 189 }
176 190
191
177 BOOL getTimeStamp(char *str, size_t len, const char *fmt) 192 BOOL getTimeStamp(char *str, size_t len, const char *fmt)
178 { 193 {
179 time_t stamp = time(NULL); 194 time_t stamp = time(NULL);
180 struct tm *stamp_tm; 195 struct tm *stamp_tm;
181 if ((stamp_tm = localtime(&stamp)) != NULL) { 196 if ((stamp_tm = localtime(&stamp)) != NULL) {
186 return FALSE; 201 return FALSE;
187 } 202 }
188 } 203 }
189 204
190 205
191 char *encodeUsername(char *str) 206 nn_window_t *nn_window_new()
192 { 207 {
193 unsigned char *c = (unsigned char *) str; 208 nn_window_t *res = th_calloc(1, sizeof(nn_window_t));
194 if (str == NULL) return NULL; 209
195 for (; *c ; c++) 210 if (res == NULL) return NULL;
196 if (*c == ' ') *c = 255; 211
197 return str; 212 res->data = th_ringbuf_new(SET_BACKBUF_LEN, th_free);
198 } 213 if (res->data == NULL) {
199 214 th_free(res);
200 215 return NULL;
201 char *decodeUsername(char *str) 216 }
202 { 217
203 unsigned char *c = (unsigned char *) str; 218 return res;
204 if (str == NULL) return NULL; 219 }
205 for (; *c ; c++) 220
206 if (*c == 255) *c = ' '; 221
207 return str; 222 void nn_window_free(nn_window_t *win)
223 {
224 if (win != NULL) {
225 th_ringbuf_free(win->data);
226 th_free(win->id);
227 th_free(win);
228 }
229 }
230
231
232 nn_window_t *nn_find_window(const char *id)
233 {
234 int i;
235
236 for (i = 0; i < SET_MAX_WINDOWS; i++)
237 if (chatWindows[i] != NULL &&
238 chatWindows[i]->id != NULL &&
239 strcasecmp(id, chatWindows[i]->id) == 0)
240 return chatWindows[i];
241
242 return NULL;
208 } 243 }
209 244
210 245
211 void updateStatus(BOOL insertMode) 246 void updateStatus(BOOL insertMode)
212 { 247 {
245 waddstr(statusWin, tmpStr); 280 waddstr(statusWin, tmpStr);
246 281
247 wrefresh(statusWin); 282 wrefresh(statusWin);
248 } 283 }
249 284
285
250 void printEditBuf(const char *str, nn_editbuf_t *buf) 286 void printEditBuf(const char *str, nn_editbuf_t *buf)
251 { 287 {
252 char *tmp; 288 char *tmp;
253 if (statusWin == NULL || buf == NULL) return; 289 if (editWin == NULL || buf == NULL) return;
254 290
255 buf->data[buf->len] = 0; 291 buf->data[buf->len] = 0;
256 tmp = decodeUsername(th_strdup(buf->data)); 292 tmp = nn_username_decode(th_strdup(buf->data));
257 293
258 werase(editWin); 294 werase(editWin);
259 295
260 wattrset(editWin, A_BOLD); 296 wattrset(editWin, A_BOLD);
261 mvwaddstr(editWin, 0, 0, str); 297 mvwaddstr(editWin, 0, 0, str);
305 } else if (val < 30) { 341 } else if (val < 30) {
306 col = A_BOLD | COLOR_PAIR(val - 9); 342 col = A_BOLD | COLOR_PAIR(val - 9);
307 } 343 }
308 } 344 }
309 } else { 345 } else {
310 if ((unsigned char) *s == 255) 346 waddch(win, ((unsigned char) *s) | col);
311 waddch(win, ((unsigned char) ' ') | col);
312 else
313 if (*s != '\r')
314 waddch(win, ((unsigned char) *s) | col);
315 s++; 347 s++;
316 } 348 }
317 } 349 }
318 return 0; 350 return 0;
351 }
352
353
354 void nn_window_print(nn_window_t *win, const char *fmt)
355 {
356 const char *s = fmt;
357 while (*s) {
358 if (*s == '\n') {
359 th_vputch(&(win->buf), &(win->bufsize), &(win->len), '\n');
360 th_vputch(&(win->buf), &(win->bufsize), &(win->len), 0);
361 th_ringbuf_add(win->data, win->buf);
362 win->buf = NULL;
363 win->dirty = TRUE;
364 }
365 else
366 if ((unsigned char) *s == 255)
367 th_vputch(&(win->buf), &(win->bufsize), &(win->len), ' ');
368 else
369 if (*s != '\r')
370 th_vputch(&(win->buf), &(win->bufsize), &(win->len), *s);
371 s++;
372 }
373 }
374
375
376 void updateMainWin(BOOL force)
377 {
378 int y, w, h, offs;
379 qringbuf_t *buf;
380
381 if (mainWin == NULL || currWin == NULL) return;
382 if (!force && !currWin->dirty) return;
383
384 buf = currWin->data;
385 getmaxyx(mainWin, h, w);
386 werase(mainWin);
387
388 offs = buf->size - h - currWin->pos;
389 if (offs < 0)
390 offs = 0;
391
392 for (y = 0; y < h && offs < buf->size; offs++) {
393 if (buf->data[offs] != NULL)
394 printWin(mainWin, (char *) buf->data[offs]);
395 y = getcury(mainWin);
396 }
397
398 currWin->dirty = FALSE;
399 wrefresh(mainWin);
319 } 400 }
320 401
321 402
322 int printFile(FILE *outFile, const char *fmt) 403 int printFile(FILE *outFile, const char *fmt)
323 { 404 {
344 } 425 }
345 426
346 return 0; 427 return 0;
347 } 428 }
348 429
349 void printMsgV(int flags, const char *fmt, va_list ap) 430 void printMsgV(nn_window_t *win, int flags, const char *fmt, va_list ap)
350 { 431 {
351 char tmpStr[128], buf[8192]; 432 char tmpStr[128], *buf;
352 433
353 getTimeStamp(tmpStr, sizeof(tmpStr), "½17½[½11½%H:%M:%S½17½]½0½ "); 434 getTimeStamp(tmpStr, sizeof(tmpStr), "½17½[½11½%H:%M:%S½17½]½0½ ");
354 435
355 vsnprintf(buf, sizeof(buf), fmt, ap); 436 buf = th_strdup_vprintf(fmt, ap);
356 437
357 if (optLogFile && (flags & LOG_FILE)) { 438 if (optLogFile && (flags & LOG_FILE)) {
358 if (flags & LOG_STAMP) printFile(optLogFile, tmpStr); 439 if (flags & LOG_STAMP) printFile(optLogFile, tmpStr);
359 printFile(optLogFile, buf); 440 printFile(optLogFile, buf);
360 fflush(optLogFile); 441 fflush(optLogFile);
361 } 442 }
362 443
363 if (!optDaemon && (flags & LOG_WINDOW)) { 444 if (!optDaemon && (flags & LOG_WINDOW)) {
364 if (flags & LOG_STAMP) printWin(mainWin, tmpStr); 445 nn_window_t *tmp = win != NULL ? win : chatWindows[0];
365 printWin(mainWin, buf); 446 if (flags & LOG_STAMP) nn_window_print(tmp, tmpStr);
366 wrefresh(mainWin); 447 nn_window_print(tmp, buf);
367 } 448 updateMainWin(FALSE);
368 } 449 }
369 450
370 void printMsg(const char *fmt, ...) 451 th_free(buf);
452 }
453
454 void printMsg(nn_window_t *win, const char *fmt, ...)
371 { 455 {
372 va_list ap; 456 va_list ap;
373 457
374 va_start(ap, fmt); 458 va_start(ap, fmt);
375 printMsgV(LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap); 459 printMsgV(win, LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap);
376 va_end(ap); 460 va_end(ap);
377 } 461 }
378 462
379 void printMsgC(const char *fmt, ...) 463 void printMsgC(nn_window_t *win, const char *fmt, ...)
380 { 464 {
381 va_list ap; 465 va_list ap;
382 466
383 va_start(ap, fmt); 467 va_start(ap, fmt);
384 printMsgV(LOG_WINDOW | LOG_FILE, fmt, ap); 468 printMsgV(win, LOG_WINDOW | LOG_FILE, fmt, ap);
385 va_end(ap); 469 va_end(ap);
386 } 470 }
387 471
388 void printMsgQ(BOOL logOnly, const char *fmt, ...) 472 void printMsgQ(nn_window_t *win, BOOL logOnly, const char *fmt, ...)
389 { 473 {
390 va_list ap; 474 va_list ap;
391 475
392 va_start(ap, fmt); 476 va_start(ap, fmt);
393 printMsgV(logOnly ? (LOG_STAMP | LOG_FILE) : (LOG_STAMP | LOG_WINDOW | LOG_FILE), fmt, ap); 477 printMsgV(win, logOnly ? (LOG_STAMP | LOG_FILE) : (LOG_STAMP | LOG_WINDOW | LOG_FILE), fmt, ap);
394 va_end(ap); 478 va_end(ap);
395 } 479 }
396 480
397 481
398 char *errorMessages = NULL; 482 char *errorMessages = NULL;
401 { 485 {
402 char *tmp; 486 char *tmp;
403 va_list ap2; 487 va_list ap2;
404 488
405 va_copy(ap2, ap); 489 va_copy(ap2, ap);
406 printMsgV(LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap); 490 printMsgV(chatWindows[0], LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap);
407 491
408 tmp = th_strdup_vprintf(fmt, ap2); 492 tmp = th_strdup_vprintf(fmt, ap2);
409 493
410 if (errorMessages != NULL) { 494 if (errorMessages != NULL) {
411 char *tmp2 = th_strdup_printf("%s%s", errorMessages, tmp); 495 char *tmp2 = th_strdup_printf("%s%s", errorMessages, tmp);
432 } 516 }
433 517
434 void messageFunc(struct _nn_conn_t *conn, const char *fmt, va_list ap) 518 void messageFunc(struct _nn_conn_t *conn, const char *fmt, va_list ap)
435 { 519 {
436 (void) conn; 520 (void) conn;
437 printMsgV(LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap); 521 printMsgV(chatWindows[0], LOG_STAMP | LOG_WINDOW | LOG_FILE, fmt, ap);
438 } 522 }
439 523
440 524
441 BOOL checkIgnoreList(const char *name) 525 BOOL checkIgnoreList(const char *name)
442 { 526 {
498 if (!isIgnored && setTarget == NULL && !strncmp(h, "PRV from ", 9)) { 582 if (!isIgnored && setTarget == NULL && !strncmp(h, "PRV from ", 9)) {
499 char *q; 583 char *q;
500 setTarget = th_strdup(h + 9); 584 setTarget = th_strdup(h + 9);
501 for (q = setTarget; *q && *q != ':'; q++); 585 for (q = setTarget; *q && *q != ':'; q++);
502 *q = 0; 586 *q = 0;
503 printMsg("PRV target autoset to '%s'\n", setTarget); 587 printMsg(NULL, "PRV target autoset to '%s'\n", setTarget);
504 } 588 }
505 printMsgQ(isIgnored, "½11½%s½0½\n", h); 589 printMsgQ(NULL, isIgnored, "½11½%s½0½\n", h);
506 } else { 590 } else {
507 /* It's an action (/me) */ 591 /* It's an action (/me) */
508 h = nn_decode_str2(t); 592 h = nn_decode_str2(t);
509 printMsgQ(isIgnored, "½9½* %s½0½\n", h); 593 printMsgQ(NULL, isIgnored, "½9½* %s½0½\n", h);
510 } 594 }
511 th_free(h); 595 th_free(h);
512 th_free(t); 596 th_free(t);
513 } else { 597 } else {
514 /* It's a normal message */ 598 /* It's a normal message */
515 t = nn_strip_tags(s); 599 t = nn_strip_tags(s);
516 h = nn_decode_str2(t); 600 h = nn_decode_str2(t);
517 printMsgQ(isIgnored, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, userName, h); 601 printMsgQ(NULL, isIgnored, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, userName, h);
518 th_free(h); 602 th_free(h);
519 th_free(t); 603 th_free(t);
520 } 604 }
521 605
522 done: 606 done:
531 char tmpStr[256]; 615 char tmpStr[256];
532 616
533 getTimeStamp(tmpStr, sizeof(tmpStr), "%c"); 617 getTimeStamp(tmpStr, sizeof(tmpStr), "%c");
534 618
535 if (!strncmp(str, "FAILURE", 7)) { 619 if (!strncmp(str, "FAILURE", 7)) {
536 printMsg("½1½Login failure½0½ - ½3½%s½0½\n", tmpStr); 620 printMsg(NULL, "½1½Login failure½0½ - ½3½%s½0½\n", tmpStr);
537 return -2; 621 return -2;
538 } else if (!strncmp(str, "SUCCESS", 7)) { 622 } else if (!strncmp(str, "SUCCESS", 7)) {
539 printMsg("½2½Login success½0½ - ½3½%s½0½\n", tmpStr); 623 printMsg(NULL, "½2½Login success½0½ - ½3½%s½0½\n", tmpStr);
540 nn_conn_send_msg(conn, optUserNameEnc, "%%2FRequestUserList"); 624 nn_conn_send_msg(conn, optUserNameEnc, "%%2FRequestUserList");
541 return 0; 625 return 0;
542 } else 626 } else
543 return 1; 627 return 1;
544 } 628 }
554 *s = 0; 638 *s = 0;
555 639
556 p = nn_dbldecode_str(str); 640 p = nn_dbldecode_str(str);
557 if (!p) return -1; 641 if (!p) return -1;
558 642
559 nn_userhash_insert(nnUsers, encodeUsername(p)); 643 nn_userhash_insert(nnUsers, nn_username_encode(p));
560 644
561 printMsg("! ½3½%s½0½ ½2½ADDED.½0½\n", p); 645 printMsg(NULL, "! ½3½%s½0½ ½2½ADDED.½0½\n", p);
562 th_free(p); 646 th_free(p);
563 return 0; 647 return 0;
564 } 648 }
565 649
566 650
574 *s = 0; 658 *s = 0;
575 659
576 p = nn_dbldecode_str(str); 660 p = nn_dbldecode_str(str);
577 if (!p) return -1; 661 if (!p) return -1;
578 662
579 nn_userhash_delete(nnUsers, encodeUsername(p)); 663 nn_userhash_delete(nnUsers, nn_username_encode(p));
580 664
581 printMsg("! ½3½%s½0½ ½1½DELETED.½0½\n", p); 665 printMsg(NULL, "! ½3½%s½0½ ½1½DELETED.½0½\n", p);
582 th_free(p); 666 th_free(p);
583 return 0; 667 return 0;
584 } 668 }
585 669
586 670
635 if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen)) 719 if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen))
636 return protoCmds[i].handler(conn, buf + cmdLen); 720 return protoCmds[i].handler(conn, buf + cmdLen);
637 } 721 }
638 722
639 if (optDebug) { 723 if (optDebug) {
640 printMsg("Unknown protocmd: \"%s\"\n", buf); 724 printMsg(NULL, "Unknown protocmd: \"%s\"\n", buf);
641 return 0; 725 return 0;
642 } else 726 } else
643 return 1; 727 return 1;
644 } 728 }
645 729
664 buf[bufLen--] = 0; 748 buf[bufLen--] = 0;
665 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen]))) 749 while (bufLen > 0 && (buf[bufLen] == '\n' || buf[bufLen] == '\r' || th_isspace(buf[bufLen])))
666 buf[bufLen--] = 0; 750 buf[bufLen--] = 0;
667 751
668 /* Decode completed usernames */ 752 /* Decode completed usernames */
669 decodeUsername(buf); 753 nn_username_decode(buf);
670 754
671 /* Check for special user commands */ 755 /* Check for special user commands */
672 if (*buf == 0) { 756 if (*buf == 0) {
673 return 1; 757 return 1;
674 } 758 }
675 else if (!strncasecmp(buf, "/color ", 7)) { 759 else if (!strncasecmp(buf, "/color ", 7)) {
676 /* Change color */ 760 /* Change color */
677 int tmpInt; 761 int tmpInt;
678 if ((tmpInt = th_get_hex_triplet(trimLeft(buf + 7))) < 0) { 762 if ((tmpInt = th_get_hex_triplet(trimLeft(buf + 7))) < 0) {
679 printMsg("Invalid color value '%s'\n", buf+7); 763 printMsg(currWin, "Invalid color value '%s'\n", buf+7);
680 return 1; 764 return 1;
681 } 765 }
682 optUserColor = tmpInt; 766 optUserColor = tmpInt;
683 printMsg("Setting color to #%06x\n", optUserColor); 767 printMsg(currWin, "Setting color to #%06x\n", optUserColor);
684 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 768 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
685 return 0; 769 return 0;
686 } 770 }
687 else if (!strncasecmp(buf, "/ignore", 7)) { 771 else if (!strncasecmp(buf, "/ignore", 7)) {
688 char *name = trimLeft(buf + 7); 772 char *name = trimLeft(buf + 7);
689 if (strlen(name) > 0) { 773 if (strlen(name) > 0) {
690 /* Add or remove someone to/from ignore */ 774 /* Add or remove someone to/from ignore */
691 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername); 775 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername);
692 if (user != NULL) { 776 if (user != NULL) {
693 printMsg("Removed user '%s' from ignore.\n", name); 777 printMsg(currWin, "Removed user '%s' from ignore.\n", name);
694 th_llist_delete_node(&setIgnoreList, user); 778 th_llist_delete_node(&setIgnoreList, user);
695 } else { 779 } else {
696 printMsg("Now ignoring '%s'.\n", name); 780 printMsg(currWin, "Now ignoring '%s'.\n", name);
697 th_llist_append(&setIgnoreList, th_strdup(name)); 781 th_llist_append(&setIgnoreList, th_strdup(name));
698 } 782 }
699 } else { 783 } else {
700 /* Just list whomever is in ignore now */ 784 /* Just list whomever is in ignore now */
701 qlist_t *user = setIgnoreList; 785 qlist_t *user = setIgnoreList;
702 ssize_t nuser = th_llist_length(setIgnoreList); 786 ssize_t nuser = th_llist_length(setIgnoreList);
703 printMsg("Users ignored (%d): ", nuser); 787 char *result = th_strdup_printf("Users ignored (%d): ", nuser);
704 while (user != NULL) { 788 while (user != NULL) {
705 if (user->data != NULL) { 789 if (user->data != NULL) {
706 printMsgC("'%s'", (char *) user->data); 790 th_pstr_printf(&result, "%s'%s'", result, (char *) user->data);
707 if (--nuser > 0) 791 if (--nuser > 0)
708 printMsgC(", "); 792 th_pstr_printf(&result, "%s, ", result);
709 } 793 }
710 user = user->next; 794 user = user->next;
711 } 795 }
712 printMsgC("\n"); 796 printMsg(currWin, "%s\n", result);
797 th_free(result);
798 }
799 return 0;
800 }
801 else if (!strncasecmp(buf, "/query", 6)) {
802 char *name = trimLeft(buf + 6);
803 if (strlen(name) > 0) {
804 // qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername);
805 printMsg(currWin, "Opening query for '%s'.\n", name);
806
807 } else {
808 }
809 return 0;
810 }
811 else if (!strncasecmp(buf, "/win", 4)) {
812 char *name = trimLeft(buf + 4);
813 if (strlen(name) > 0) {
814 } else {
713 } 815 }
714 return 0; 816 return 0;
715 } 817 }
716 else if (!strncasecmp(buf, "/save", 5)) { 818 else if (!strncasecmp(buf, "/save", 5)) {
717 /* Save configuration */ 819 /* Save configuration */
718 FILE *cfgfile = fopen(setConfigFile, "w"); 820 FILE *cfgfile = fopen(setConfigFile, "w");
719 if (cfgfile == NULL) { 821 if (cfgfile == NULL) {
720 printMsg("Could not create configuration to file '%s': %s\n", setConfigFile, 822 printMsg(currWin, "Could not create configuration to file '%s': %s\n",
721 strerror(errno)); 823 setConfigFile, strerror(errno));
722 return 0; 824 return 0;
723 } 825 }
724 printMsg("Configuration saved in file '%s', res=%d\n", 826 printMsg(currWin, "Configuration saved in file '%s', res=%d\n",
725 setConfigFile, 827 setConfigFile,
726 th_cfg_write(cfgfile, setConfigFile, cfg)); 828 th_cfg_write(cfgfile, setConfigFile, cfg));
727 829
728 fclose(cfgfile); 830 fclose(cfgfile);
729 return 0; 831 return 0;
730 } 832 }
731 else if (!strncasecmp(buf, "/w ", 3)) { 833 else if (!strncasecmp(buf, "/w ", 3)) {
732 /* Open given username's profile via firefox in a new tab */ 834 /* Open given username's profile via firefox in a new tab */
733 char *name = trimLeft(buf + 3); 835 char *name = trimLeft(buf + 3);
734 836
735 printMsg("Opening profile for: '%s'\n", name); 837 printMsg(currWin, "Opening profile for: '%s'\n", name);
736 838
737 tmpStr = nn_encode_str1(name); 839 tmpStr = nn_encode_str1(name);
738 #ifdef __WIN32 840 #ifdef __WIN32
739 { 841 {
740 HINSTANCE status; 842 HINSTANCE status;
741 snprintf(tmpBuf, sizeof(tmpBuf), "http://www.newbienudes.com/profile/%s/", tmpStr); 843 snprintf(tmpBuf, sizeof(tmpBuf), "http://www.newbienudes.com/profile/%s/", tmpStr);
742 th_free(tmpStr); 844 th_free(tmpStr);
743 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA); 845 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA);
744 if (status <= 32) 846 if (status <= 32)
745 printMsg("Could not launch default web browser: %d\n", status); 847 printMsg(currWin, "Could not launch default web browser: %d\n", status);
746 } 848 }
747 #else 849 #else
748 { 850 {
749 int status; 851 int status;
750 int fds[2]; 852 int fds[2];
752 snprintf(tmpBuf, sizeof(tmpBuf), "openurl(http://www.newbienudes.com/profile/%s/,new-tab)", tmpStr); 854 snprintf(tmpBuf, sizeof(tmpBuf), "openurl(http://www.newbienudes.com/profile/%s/,new-tab)", tmpStr);
753 th_free(tmpStr); 855 th_free(tmpStr);
754 856
755 if (pipe(fds) == -1) { 857 if (pipe(fds) == -1) {
756 int ret = errno; 858 int ret = errno;
757 printMsg("Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret)); 859 printMsg(currWin, "Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret));
758 return 0; 860 return 0;
759 } 861 }
760 862
761 if ((pid = fork()) < 0) { 863 if ((pid = fork()) < 0) {
762 printMsg("Could not create sub-process!\n"); 864 printMsg(currWin, "Could not create sub-process!\n");
763 } else if (pid == 0) { 865 } else if (pid == 0) {
764 dup2(fds[1], STDOUT_FILENO); 866 dup2(fds[1], STDOUT_FILENO);
765 dup2(fds[0], STDERR_FILENO); 867 dup2(fds[0], STDERR_FILENO);
766 execlp(setBrowser, setBrowser, "-remote", tmpBuf, (void *)NULL); 868 execlp(setBrowser, setBrowser, "-remote", tmpBuf, (void *)NULL);
767 _exit(errno); 869 _exit(errno);
776 char *name = trimLeft(buf + 3); 878 char *name = trimLeft(buf + 3);
777 /* Set private messaging target */ 879 /* Set private messaging target */
778 th_free(setTarget); 880 th_free(setTarget);
779 if (strlen(name) > 0) { 881 if (strlen(name) > 0) {
780 setTarget = th_strdup(trimLeft(buf + 3)); 882 setTarget = th_strdup(trimLeft(buf + 3));
781 printMsg("Set prv target to '%s'\n", setTarget); 883 printMsg(NULL, "Set prv target to '%s'\n", setTarget);
782 } else { 884 } else {
783 setTarget = NULL; 885 setTarget = NULL;
784 printMsg("Cleared prv target.\n"); 886 printMsg(NULL, "Cleared prv target.\n");
785 } 887 }
786 return 0; 888 return 0;
787 } 889 }
788 else if (!strncasecmp(buf, "/who", 4)) { 890 else if (!strncasecmp(buf, "/who", 4)) {
789 /* Alias /who to /listallusers */ 891 /* Alias /who to /listallusers */
794 /* Private chat mode, send as PRV */ 896 /* Private chat mode, send as PRV */
795 if (setTarget != NULL) { 897 if (setTarget != NULL) {
796 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf); 898 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf);
797 buf = tmpBuf; 899 buf = tmpBuf;
798 } else { 900 } else {
799 printMsg("No target set, exiting prv mode.\n"); 901 printMsg(NULL, "No target set, exiting prv mode.\n");
800 setPrvMode = FALSE; 902 setPrvMode = FALSE;
801 return 1; 903 return 1;
802 } 904 }
803 } 905 }
804 906
805 /* Send double-encoded */ 907 /* Send double-encoded */
806 tmpStr = nn_dblencode_str(decodeUsername(buf)); 908 tmpStr = nn_dblencode_str(nn_username_decode(buf));
807 if (tmpStr == 0) return -2; 909 if (tmpStr == 0) return -2;
808 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr); 910 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr);
809 th_free(tmpStr); 911 th_free(tmpStr);
810 912
811 return result ? 0 : -1; 913 return result ? 0 : -1;
829 mainWin = subwin(stdscr, h - 4, w, 0, 0); 931 mainWin = subwin(stdscr, h - 4, w, 0, 0);
830 statusWin = subwin(stdscr, 1, w, h - 4, 0); 932 statusWin = subwin(stdscr, 1, w, h - 4, 0);
831 editWin = subwin(stdscr, 3, w, h - 3, 0); 933 editWin = subwin(stdscr, 3, w, h - 3, 0);
832 934
833 if (mainWin == NULL || statusWin == NULL || editWin == NULL) { 935 if (mainWin == NULL || statusWin == NULL || editWin == NULL) {
834 THERR("Could not create ncurses windows!\n"); 936 THERR("Could not create curses chatWindows!\n");
835 return FALSE; 937 return FALSE;
836 } 938 }
837 scrollok(mainWin, 1); 939 scrollok(mainWin, 1);
838 940
839 return TRUE; 941 return TRUE;
876 while (startPos > 0 && str[startPos - 1] != ' ') startPos--; 978 while (startPos > 0 && str[startPos - 1] != ' ') startPos--;
877 newPattern = TRUE; 979 newPattern = TRUE;
878 mode = 3; 980 mode = 3;
879 } else { 981 } else {
880 if (optDebug) 982 if (optDebug)
881 printMsg("no mode\n"); 983 printMsg(currWin, "no mode\n");
882 return FALSE; 984 return FALSE;
883 } 985 }
884 986
885 if (str[endPos] == optNickSep) { 987 if (str[endPos] == optNickSep) {
886 endPos--; 988 endPos--;
887 if (startPos > 0) { 989 if (startPos > 0) {
888 if (optDebug) 990 if (optDebug)
889 printMsg("str[endPos] == optNickSep && startPos > 0 (%d)\n", startPos); 991 printMsg(currWin, "str[endPos] == optNickSep && startPos > 0 (%d)\n", startPos);
890 return FALSE; 992 return FALSE;
891 } 993 }
892 hasSeparator = TRUE; 994 hasSeparator = TRUE;
893 } 995 }
894 996
911 previous = NULL; 1013 previous = NULL;
912 } 1014 }
913 } 1015 }
914 1016
915 if (optDebug) { 1017 if (optDebug) {
916 printMsg("sPos=%d, ePos=%d <-> bPos=%d, bufLen=%d : pat='%s' (again=%s, hassep=%s, hasspc=%s, newpat=%s, mode=%d)\n", 1018 printMsg(currWin, "sPos=%d, ePos=%d <-> bPos=%d, bufLen=%d : pat='%s' (again=%s, hassep=%s, hasspc=%s, newpat=%s, mode=%d)\n",
917 startPos, endPos, buf->pos, buf->len, pattern, 1019 startPos, endPos, buf->pos, buf->len, pattern,
918 again ? "yes" : "no", 1020 again ? "yes" : "no",
919 hasSeparator ? "yes" : "no", 1021 hasSeparator ? "yes" : "no",
920 hasSpace ? "yes" : "no", 1022 hasSpace ? "yes" : "no",
921 newPattern ? "yes" : "no", mode); 1023 newPattern ? "yes" : "no", mode);
926 1028
927 if (user) { 1029 if (user) {
928 int i; 1030 int i;
929 char *c = user->name; 1031 char *c = user->name;
930 if (optDebug) 1032 if (optDebug)
931 printMsg("match='%s' / prev='%s'\n", user->name, previous); 1033 printMsg(currWin, "match='%s' / prev='%s'\n", user->name, previous);
932 1034
933 for (i = startPos; i <= endPos; i++) 1035 for (i = startPos; i <= endPos; i++)
934 nn_editbuf_delete(buf, startPos); 1036 nn_editbuf_delete(buf, startPos);
935 1037
936 for (i = startPos; *c; i++, c++) 1038 for (i = startPos; *c; i++, c++)
1065 char *tmpStr; 1167 char *tmpStr;
1066 nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE); 1168 nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE);
1067 nn_editbuf_t *histBuf[SET_MAX_HISTORY+2]; 1169 nn_editbuf_t *histBuf[SET_MAX_HISTORY+2];
1068 int histPos = 0, histMax = 0; 1170 int histPos = 0, histMax = 0;
1069 1171
1070 nn_ringbuf_t *backBuf;
1071
1072 cfgitem_t *tmpcfg; 1172 cfgitem_t *tmpcfg;
1073 char *homeDir = NULL; 1173 char *homeDir = NULL;
1074 1174
1075 1175
1076 /* Initialize */ 1176 /* Initialize */
1077 th_init("NNChat", "Newbie Nudes chat client", NN_VERSION, 1177 th_init("NNChat", "Newbie Nudes chat client", NN_VERSION,
1078 "Written and designed by Anonymous Finnish Guy (C) 2008-2011", 1178 "Written and designed by Anonymous Finnish Guy (C) 2008-2011",
1079 "This software is freeware, use and distribute as you wish."); 1179 "This software is freeware, use and distribute as you wish.");
1206 1306
1207 cursesInit = TRUE; 1307 cursesInit = TRUE;
1208 1308
1209 if (!initializeWindows()) 1309 if (!initializeWindows())
1210 goto err_exit; 1310 goto err_exit;
1211 1311
1312 memset(chatWindows, 0, sizeof(chatWindows));
1313 chatWindows[0] = nn_window_new();
1314 currWin = chatWindows[0];
1212 updateStatus(insertMode); 1315 updateStatus(insertMode);
1213 } 1316 }
1214 1317
1215 /* Check if we have username and password */ 1318 /* Check if we have username and password */
1216 if (cursesInit && (optUserName == NULL || optPassword == NULL)) { 1319 if (cursesInit && (optUserName == NULL || optPassword == NULL)) {
1223 errorMsg("Username and/or password not specified.\n"); 1326 errorMsg("Username and/or password not specified.\n");
1224 goto err_exit; 1327 goto err_exit;
1225 } 1328 }
1226 1329
1227 /* Okay ... */ 1330 /* Okay ... */
1228 printMsg("Trying to resolve host '%s' ...\n", optServer); 1331 printMsg(currWin, "Trying to resolve host '%s' ...\n", optServer);
1229 tmpHost = gethostbyname(optServer); 1332 tmpHost = gethostbyname(optServer);
1230 if (tmpHost == NULL) { 1333 if (tmpHost == NULL) {
1231 errorMsg("Could not resolve hostname: %s.\n", strerror(h_errno)); 1334 errorMsg("Could not resolve hostname: %s.\n", strerror(h_errno));
1232 goto err_exit; 1335 goto err_exit;
1233 } 1336 }
1234 printMsg("True hostname: %s\n", tmpHost->h_name); 1337 printMsg(currWin, "True hostname: %s\n", tmpHost->h_name);
1235 1338
1236 /* To emulate the official client, we first make a request for 1339 /* To emulate the official client, we first make a request for
1237 * policy file, even though we don't use it for anything... 1340 * policy file, even though we don't use it for anything...
1238 */ 1341 */
1239 conn = nn_conn_open((struct in_addr *) tmpHost->h_addr, 843); 1342 conn = nn_conn_open((struct in_addr *) tmpHost->h_addr, 843);
1247 errorMsg("Failed to send policy file request.\n"); 1350 errorMsg("Failed to send policy file request.\n");
1248 goto err_exit; 1351 goto err_exit;
1249 } else { 1352 } else {
1250 int cres = nn_conn_pull(conn); 1353 int cres = nn_conn_pull(conn);
1251 if (cres == 0) { 1354 if (cres == 0) {
1252 printMsg("Probe got: %s\n", conn->buf); 1355 printMsg(currWin, "Probe got: %s\n", conn->buf);
1253 } else { 1356 } else {
1254 printMsg("Could not get policy probe.\n"); 1357 printMsg(currWin, "Could not get policy probe.\n");
1255 } 1358 }
1256 } 1359 }
1257 nn_conn_close(conn); 1360 nn_conn_close(conn);
1258 1361
1259 /* Okay, now do the proper connection ... */ 1362 /* Okay, now do the proper connection ... */
1277 srandom((int) prevTime); 1380 srandom((int) prevTime);
1278 1381
1279 if (cursesInit) { 1382 if (cursesInit) {
1280 /* Initialize rest of interactive UI code */ 1383 /* Initialize rest of interactive UI code */
1281 memset(histBuf, 0, sizeof(histBuf)); 1384 memset(histBuf, 0, sizeof(histBuf));
1282 backBuf = nn_ringbuf_new(SET_BACKBUF_LEN); 1385 memset(histBuf, 0, sizeof(histBuf));
1283 nn_editbuf_clear(editBuf); 1386 nn_editbuf_clear(editBuf);
1284 1387
1285 /* First update of screen */ 1388 /* First update of screen */
1286 printEditBuf("", editBuf); 1389 printEditBuf("", editBuf);
1287 updateStatus(insertMode); 1390 updateStatus(insertMode);
1288 } 1391
1392 printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
1393 printMsg(NULL, "%s\n", th_prog_author);
1394 printMsg(NULL, "%s\n", th_prog_license);
1395 }
1396
1289 1397
1290 /* Enter mainloop */ 1398 /* Enter mainloop */
1291 while (!isError && !exitProg) { 1399 while (!isError && !exitProg) {
1292 int cres = nn_conn_pull(conn); 1400 int cres = nn_conn_pull(conn);
1293 if (cres == 0) { 1401 if (cres == 0) {
1295 size_t bufLen = strlen(conn->ptr) + 1; 1403 size_t bufLen = strlen(conn->ptr) + 1;
1296 int result = handleProtocol(conn, conn->ptr, bufLen); 1404 int result = handleProtocol(conn, conn->ptr, bufLen);
1297 1405
1298 if (result > 0) { 1406 if (result > 0) {
1299 /* Couldn't handle the message for some reason */ 1407 /* Couldn't handle the message for some reason */
1300 printMsg("Could not handle: %s\n", conn->ptr); 1408 printMsg(currWin, "Could not handle: %s\n", conn->ptr);
1301 } else if (result < 0) { 1409 } else if (result < 0) {
1302 /* Fatal error, quit */ 1410 /* Fatal error, quit */
1303 errorMsg("Fatal error with message: %s\n", conn->ptr); 1411 errorMsg("Fatal error with message: %s\n", conn->ptr);
1304 isError = TRUE; 1412 isError = TRUE;
1305 } 1413 }
1312 isError = TRUE; 1420 isError = TRUE;
1313 1421
1314 /* Handle user input */ 1422 /* Handle user input */
1315 if (cursesInit) { 1423 if (cursesInit) {
1316 int c, cnt = 0; 1424 int c, cnt = 0;
1317 BOOL update = FALSE; 1425 BOOL update = FALSE, updateMain = TRUE;
1318 1426
1319 /* Handle several buffered keypresses at once */ 1427 /* Handle several buffered keypresses at once */
1320 do { 1428 do {
1321 c = wgetch(stdscr); 1429 c = wgetch(stdscr);
1322 if (c == 0x1b) { 1430 if (c == 0x1b) {
1325 c = wgetch(stdscr); 1433 c = wgetch(stdscr);
1326 switch (c) { 1434 switch (c) {
1327 case 'd': c = 0x204; break; 1435 case 'd': c = 0x204; break;
1328 case 'c': c = 0x206; break; 1436 case 'c': c = 0x206; break;
1329 default: 1437 default:
1330 printMsg("Unhandled ESC-O key sequence 0x%02x\n", c); 1438 printMsg(currWin, "Unhandled ESC-O key sequence 0x%02x\n", c);
1331 break; 1439 break;
1332 } 1440 }
1333 } else 1441 } else
1334 if (c == '[') { 1442 if (c == '[') {
1335 c = wgetch(stdscr); 1443 c = wgetch(stdscr);
1350 1458
1351 case 0x37: c = KEY_HOME; break; 1459 case 0x37: c = KEY_HOME; break;
1352 case 0x38: c = KEY_END; break; 1460 case 0x38: c = KEY_END; break;
1353 1461
1354 default: 1462 default:
1355 printMsg("Unhandled ESC-[*~ key sequence 0x%02x\n", c); 1463 printMsg(currWin, "Unhandled ESC-[*~ key sequence 0x%02x\n", c);
1356 c = ERR; 1464 c = ERR;
1357 break; 1465 break;
1358 } 1466 }
1359 /* Get the trailing ~ */ 1467 /* Get the trailing ~ */
1360 if (c != ERR) 1468 if (c != ERR)
1361 wgetch(stdscr); 1469 wgetch(stdscr);
1362 } else { 1470 } else {
1363 printMsg("Unhandled ESC key sequence 0x%02x\n", c); 1471 printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c);
1364 continue; 1472 continue;
1365 } 1473 }
1366 } 1474 }
1367 1475
1368 1476
1374 #ifdef PDCURSES 1482 #ifdef PDCURSES
1375 timeout(SET_DELAY); 1483 timeout(SET_DELAY);
1376 #endif 1484 #endif
1377 1485
1378 if (!initializeWindows()) { 1486 if (!initializeWindows()) {
1379 errorMsg("Error resizing curses windows\n"); 1487 errorMsg("Error resizing curses chatWindows\n");
1380 isError = TRUE; 1488 isError = TRUE;
1381 } 1489 }
1490
1382 update = TRUE; 1491 update = TRUE;
1492 updateMain = TRUE;
1383 break; 1493 break;
1384 #endif 1494 #endif
1385 1495
1386 case KEY_ENTER: 1496 case KEY_ENTER:
1387 case '\n': 1497 case '\n':
1486 update = TRUE; 1596 update = TRUE;
1487 break; 1597 break;
1488 1598
1489 case KEY_F(5): /* F5 = Ignore mode */ 1599 case KEY_F(5): /* F5 = Ignore mode */
1490 setIgnoreMode = !setIgnoreMode; 1600 setIgnoreMode = !setIgnoreMode;
1491 printMsg("Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF"); 1601 printMsg(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF");
1492 break; 1602 break;
1493 1603
1494 case KEY_F(7): /* F7 = Clear PRV target */ 1604 case KEY_F(7): /* F7 = Clear PRV target */
1495 if (setTarget) { 1605 if (setTarget) {
1496 printMsg("Cleared PRV target.\n"); 1606 printMsg(NULL, "Cleared PRV target.\n");
1497 setPrvMode = FALSE; 1607 setPrvMode = FALSE;
1498 th_free(setTarget); 1608 th_free(setTarget);
1499 setTarget = NULL; 1609 setTarget = NULL;
1500 update = TRUE; 1610 update = TRUE;
1501 } 1611 }
1511 update = TRUE; 1621 update = TRUE;
1512 break; 1622 break;
1513 1623
1514 case 0x03: /* ^C = quit */ 1624 case 0x03: /* ^C = quit */
1515 case KEY_F(9): /* F9 = Quit */ 1625 case KEY_F(9): /* F9 = Quit */
1516 printMsg("Quitting per user request.\n"); 1626 printMsg(currWin, "Quitting per user request.\n");
1517 exitProg = TRUE; 1627 exitProg = TRUE;
1518 break; 1628 break;
1519 1629
1520 case 0x09: /* Tab = complete username */ 1630 case 0x09: /* Tab = complete username */
1521 performTabCompletion(editBuf); 1631 performTabCompletion(editBuf);
1522 update = TRUE; 1632 update = TRUE;
1523 break; 1633 break;
1524 1634
1525 case 0x0c: /* Ctrl + L */ 1635 case 0x0c: /* Ctrl + L */
1526 updateWindows(); 1636 updateWindows();
1637 update = TRUE;
1638 updateMain = TRUE;
1527 break; 1639 break;
1528 1640
1529 case KEY_NPAGE: 1641 case KEY_NPAGE:
1530 case KEY_PPAGE: 1642 case KEY_PPAGE:
1531 #if 0 1643 if (currWin != NULL)
1532 { 1644 {
1533 int nlines, ncol, old; 1645 int numLines, numCols, oldPos = currWin->pos;
1534 getmaxyx(mainWin, nlines, ncol); 1646 getmaxyx(mainWin, numLines, numCols);
1535 nlines /= 2; 1647 numLines = (numLines / 2) + 1;
1536 old = backBufPos; 1648
1537 1649 if (c == KEY_PPAGE)
1538 if (c == KEY_NPAGE) 1650 currWin->pos = (currWin->pos > numLines) ? currWin->pos - numLines : 0;
1539 backBufPos = (backBufPos > nlines) ? backBufPos - nlines : 0;
1540 else 1651 else
1541 backBufPos = (backBufPos < ); 1652 currWin->pos = (currWin->pos < currWin->data->n - numLines) ? currWin->pos + numLines : currWin->data->n - numLines;
1542 1653
1543 if (old != backBufPos) 1654 if (oldPos != currWin->pos)
1544 updateMain(); 1655 updateMain = TRUE;
1545 } 1656 }
1546 #endif
1547 break; 1657 break;
1548 1658
1549 case ERR: 1659 case ERR:
1550 /* Ignore */ 1660 /* Ignore */
1551 break; 1661 break;
1557 else 1667 else
1558 nn_editbuf_write(editBuf, editBuf->pos, c); 1668 nn_editbuf_write(editBuf, editBuf->pos, c);
1559 nn_editbuf_setpos(editBuf, editBuf->pos + 1); 1669 nn_editbuf_setpos(editBuf, editBuf->pos + 1);
1560 update = TRUE; 1670 update = TRUE;
1561 } else { 1671 } else {
1562 printMsg("Unhandled key: 0x%02x\n", c); 1672 printMsg(currWin, "Unhandled key: 0x%02x\n", c);
1563 } 1673 }
1564 break; 1674 break;
1565 } 1675 }
1566 } while (c != ERR && !exitProg && ++cnt < 10); 1676 } while (c != ERR && !exitProg && ++cnt < 10);
1567 1677
1569 /* Update edit line */ 1679 /* Update edit line */
1570 printEditBuf(setPrvMode ? setTarget : "", editBuf); 1680 printEditBuf(setPrvMode ? setTarget : "", editBuf);
1571 updateStatus(insertMode); 1681 updateStatus(insertMode);
1572 firstUpdate = FALSE; /* a nasty hack ... */ 1682 firstUpdate = FALSE; /* a nasty hack ... */
1573 } 1683 }
1684
1685 updateMainWin(updateMain);
1574 } /* cursesInit */ 1686 } /* cursesInit */
1575 1687
1576 if (++updateCount > 10) { 1688 if (++updateCount > 10) {
1577 time_t tmpTime = time(NULL); 1689 time_t tmpTime = time(NULL);
1578 if (tmpTime - prevTime > SET_KEEPALIVE) { 1690 if (tmpTime - prevTime > SET_KEEPALIVE) {
1582 prevTime = tmpTime; 1694 prevTime = tmpTime;
1583 } 1695 }
1584 1696
1585 if (!colorSet) { 1697 if (!colorSet) {
1586 colorSet = TRUE; 1698 colorSet = TRUE;
1587 printMsg("%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
1588 printMsg("%s\n", th_prog_author);
1589 printMsg("%s\n", th_prog_license);
1590 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 1699 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
1591 } 1700 }
1592 1701
1593 updateStatus(insertMode); 1702 updateStatus(insertMode);
1594 updateCount = 0; 1703 updateCount = 0;
1597 } 1706 }
1598 1707
1599 /* Shutdown */ 1708 /* Shutdown */
1600 err_exit: 1709 err_exit:
1601 nn_userhash_free(nnUsers); 1710 nn_userhash_free(nnUsers);
1602 nn_ringbuf_free(backBuf);
1603 nn_editbuf_free(editBuf); 1711 nn_editbuf_free(editBuf);
1604 for (histPos = 0; histPos <= SET_MAX_HISTORY; histPos++) 1712
1605 nn_editbuf_free(histBuf[histPos]); 1713 {
1606 1714 int i;
1607 #ifdef __WIN32 1715 for (i = 0; i <= SET_MAX_HISTORY; i++)
1608 if (errorMessages || isError) { 1716 nn_editbuf_free(histBuf[i]);
1717
1718 for (i = 0; i < SET_MAX_WINDOWS; i++)
1719 nn_window_free(chatWindows[i]);
1720 }
1721
1722 //#ifdef __WIN32
1723 if (errorMessages) {
1609 char *tmp; 1724 char *tmp;
1610 wclear(editWin); 1725 wclear(editWin);
1611 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE); 1726 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE);
1612 th_free(tmp); 1727 th_free(tmp);
1613 } 1728 }
1614 #endif 1729 //#endif
1615 1730
1616 if (cursesInit) { 1731 if (cursesInit) {
1617 if (curVis != ERR) 1732 if (curVis != ERR)
1618 curs_set(curVis); 1733 curs_set(curVis);
1619 closeWindows(); 1734 closeWindows();