Mercurial > hg > nnchat
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(); |