comparison nnchat.c @ 291:cc2a1d837e7b

Window / buffer functionality works now. Queries work (with few minor glitches).
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 11 Jun 2011 03:18:22 +0300
parents c53f880837f5
children ff39ebf05b40
comparison
equal deleted inserted replaced
290:f1049f487987 291:cc2a1d837e7b
39 39
40 40
41 typedef struct { 41 typedef struct {
42 qringbuf_t *data; /* "Backbuffer" data for this window */ 42 qringbuf_t *data; /* "Backbuffer" data for this window */
43 int pos; /* Current position in the window, 0 = real time */ 43 int pos; /* Current position in the window, 0 = real time */
44 BOOL dirty;
45
44 char *id; /* Chatter ID, NULL = main window */ 46 char *id; /* Chatter ID, NULL = main window */
45 BOOL dirty; 47 int num; /* Window number */
46 48
47 char *buf; 49 char *buf;
48 size_t len, bufsize; 50 size_t len, bufsize;
49 } nn_window_t; 51 } nn_window_t;
50 52
58 *optUserNameCmd = NULL, 60 *optUserNameCmd = NULL,
59 *optUserNameEnc = NULL, 61 *optUserNameEnc = NULL,
60 *optPassword = NULL, 62 *optPassword = NULL,
61 *optPasswordCmd = NULL, 63 *optPasswordCmd = NULL,
62 *optLogFilename = NULL, 64 *optLogFilename = NULL,
63 *setTarget = NULL,
64 *optSite = "NN"; 65 *optSite = "NN";
65 char optNickSep = ':'; 66 char optNickSep = ':';
66 BOOL optDaemon = FALSE; 67 BOOL optDaemon = FALSE;
67 FILE *optLogFile = NULL; 68 FILE *optLogFile = NULL;
68 BOOL setPrvMode = FALSE;
69 BOOL setIgnoreMode = FALSE; 69 BOOL setIgnoreMode = FALSE;
70 BOOL optDebug = FALSE; 70 BOOL optDebug = FALSE;
71 BOOL optLogEnable = FALSE; 71 BOOL optLogEnable = FALSE;
72 72
73 nn_window_t *chatWindows[SET_MAX_WINDOWS], 73 nn_window_t *chatWindows[SET_MAX_WINDOWS],
201 return FALSE; 201 return FALSE;
202 } 202 }
203 } 203 }
204 204
205 205
206 nn_window_t *nn_window_new() 206 nn_window_t *nn_window_new(const char *id)
207 { 207 {
208 nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); 208 nn_window_t *res = th_calloc(1, sizeof(nn_window_t));
209 209
210 if (res == NULL) return NULL; 210 if (res == NULL) return NULL;
211 211
212 res->data = th_ringbuf_new(SET_BACKBUF_LEN, th_free); 212 res->data = th_ringbuf_new(SET_BACKBUF_LEN, th_free);
213 if (res->data == NULL) { 213 if (res->data == NULL) {
214 th_free(res); 214 th_free(res);
215 return NULL; 215 return NULL;
216 } 216 }
217 res->id = th_strdup(id);
218 res->num = 0;
217 219
218 return res; 220 return res;
219 } 221 }
220 222
221 223
241 243
242 return NULL; 244 return NULL;
243 } 245 }
244 246
245 247
246 void updateStatus(BOOL insertMode) 248 BOOL openWindow(const char *name, BOOL curwin)
249 {
250 int i;
251 nn_window_t *res;
252 if (name == NULL)
253 return FALSE;
254
255 if ((res = nn_window_new(name)) == NULL)
256 return FALSE;
257
258 for (i = 1; i < SET_MAX_WINDOWS; i++)
259 if (chatWindows[i] == NULL) {
260 res->num = i;
261 chatWindows[i] = res;
262 if (curwin)
263 currWin = res;
264 return TRUE;
265 }
266
267 return FALSE;
268 }
269
270
271 void closeWindow(nn_window_t *win)
272 {
273 int i;
274 if (win == NULL) return;
275
276 for (i = 1; i < SET_MAX_WINDOWS; i++)
277 if (chatWindows[i] == win) {
278 chatWindows[i] = NULL;
279 nn_window_free(win);
280 return;
281 }
282 }
283
284
285 void updateStatus(void)
247 { 286 {
248 char tmpStr[128]; 287 char tmpStr[128];
288 int i;
249 289
250 if (statusWin == NULL) return; 290 if (statusWin == NULL) return;
251 291
252 getTimeStamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); 292 getTimeStamp(tmpStr, sizeof(tmpStr), "%H:%M:%S");
253 293
261 waddstr(statusWin, " | "); 301 waddstr(statusWin, " | ");
262 wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); 302 wattrset(statusWin, A_BOLD | COLOR_PAIR(16));
263 waddstr(statusWin, optUserName); 303 waddstr(statusWin, optUserName);
264 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 304 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
265 305
306 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
266 waddstr(statusWin, " | "); 307 waddstr(statusWin, " | ");
267 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); 308 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
268 waddstr(statusWin, insertMode ? "INS" : "DEL"); 309 snprintf(tmpStr, sizeof(tmpStr), "#%06x", optUserColor);
269 310 waddstr(statusWin, tmpStr);
311
270 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 312 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
271 waddstr(statusWin, " | Prv: "); 313 waddstr(statusWin, " | WIN: ");
272 314 snprintf(tmpStr, sizeof(tmpStr), "%d: %s", currWin->num + 1, currWin->id ? currWin->id : "MAIN");
315 waddstr(statusWin, tmpStr);
316
317 wattrset(statusWin, A_BOLD | COLOR_PAIR(13));
318 waddstr(statusWin, " | ");
273 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); 319 wattrset(statusWin, A_BOLD | COLOR_PAIR(11));
274 waddstr(statusWin, setTarget != NULL ? setTarget : "-"); 320
275 321 for (i = 0; i < SET_MAX_WINDOWS; i++)
276 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); 322 if (chatWindows[i] != NULL && chatWindows[i]->dirty) {
277 waddstr(statusWin, " | P/C: "); 323 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1);
278 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); 324 waddstr(statusWin, tmpStr);
279 snprintf(tmpStr, sizeof(tmpStr), "%d / #%06x", optPort, optUserColor); 325 }
280 waddstr(statusWin, tmpStr);
281 326
282 wrefresh(statusWin); 327 wrefresh(statusWin);
283 } 328 }
284 329
285 330
286 void printEditBuf(const char *str, nn_editbuf_t *buf) 331 void printEditBuf(nn_editbuf_t *buf)
287 { 332 {
288 char *tmp; 333 char *tmp;
289 if (editWin == NULL || buf == NULL) return; 334 if (editWin == NULL || buf == NULL) return;
290 335
291 buf->data[buf->len] = 0; 336 buf->data[buf->len] = 0;
292 tmp = nn_username_decode(th_strdup(buf->data)); 337 tmp = nn_username_decode(th_strdup(buf->data));
293 338
294 werase(editWin); 339 werase(editWin);
295 340
296 wattrset(editWin, A_BOLD);
297 mvwaddstr(editWin, 0, 0, str);
298 waddstr(editWin, "> ");
299 wattrset(editWin, A_NORMAL); 341 wattrset(editWin, A_NORMAL);
300 342
301 if (buf->pos < buf->len) { 343 if (buf->pos < buf->len) {
302 waddnstr(editWin, tmp, buf->pos); 344 waddnstr(editWin, tmp, buf->pos);
303 wattrset(editWin, A_REVERSE); 345 wattrset(editWin, A_REVERSE);
536 578
537 int handleUser(nn_conn_t *conn, const char *str) 579 int handleUser(nn_conn_t *conn, const char *str)
538 { 580 {
539 const char *msg = "</USER><MESSAGE>", *p = str; 581 const char *msg = "</USER><MESSAGE>", *p = str;
540 BOOL isMine, isIgnored = FALSE; 582 BOOL isMine, isIgnored = FALSE;
541 char *s, *t, *h, *userName; 583 char *s, *t, *userName;
542 584
543 (void) conn; 585 (void) conn;
544 586
545 /* Find start of the message */ 587 /* Find start of the message */
546 s = strstr(str, msg); 588 s = strstr(str, msg);
575 /* Ignore room join/leave messages */ 617 /* Ignore room join/leave messages */
576 if (!optDebug && (strstr(s, "left the room") || strstr(s, "joined the room from"))) 618 if (!optDebug && (strstr(s, "left the room") || strstr(s, "joined the room from")))
577 goto done; 619 goto done;
578 620
579 t = nn_strip_tags(s + 1); 621 t = nn_strip_tags(s + 1);
580 if (!strncmp(t, "BPRV", 4)) { 622 if (!strncmp(t, "BPRV ", 5)) {
581 h = nn_decode_str2(t + 1); 623 char *name, *tmp, *msg;
582 if (!isIgnored && setTarget == NULL && !strncmp(h, "PRV from ", 9)) { 624
583 char *q; 625 if (!strncmp(t, "BPRV from ", 10)) {
584 setTarget = th_strdup(h + 9); 626 name = nn_decode_str2(t + 10);
585 for (q = setTarget; *q && *q != ':'; q++); 627 isMine = FALSE;
586 *q = 0; 628 } else {
587 printMsg(NULL, "PRV target autoset to '%s'\n", setTarget); 629 name = nn_decode_str2(t + 8);
630 isMine = TRUE;
588 } 631 }
589 printMsgQ(NULL, isIgnored, "½11½%s½0½\n", h); 632
633 for (tmp = name; *tmp && *tmp != ':'; tmp++);
634 if (tmp[0] != 0 && tmp[1] == ' ')
635 msg = tmp + 2;
636 else
637 msg = "";
638 *tmp = 0;
639
640 isIgnored = setIgnoreMode && checkIgnoreList(name);
641
642 printMsgQ(nn_find_window(name), isIgnored, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, isMine ? optUserName : name, msg);
590 } else { 643 } else {
591 /* It's an action (/me) */ 644 /* It's an action (/me) */
592 h = nn_decode_str2(t); 645 char *h = nn_decode_str2(t);
593 printMsgQ(NULL, isIgnored, "½9½* %s½0½\n", h); 646 printMsgQ(NULL, isIgnored, "½9½* %s½0½\n", h);
594 } 647 th_free(h);
595 th_free(h); 648 }
596 th_free(t); 649 th_free(t);
597 } else { 650 } else {
598 /* It's a normal message */ 651 /* It's a normal message */
652 char *h;
599 t = nn_strip_tags(s); 653 t = nn_strip_tags(s);
600 h = nn_decode_str2(t); 654 h = nn_decode_str2(t);
601 printMsgQ(NULL, isIgnored, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, userName, h); 655 printMsgQ(NULL, isIgnored, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, userName, h);
602 th_free(h); 656 th_free(h);
603 th_free(t); 657 th_free(t);
799 return 0; 853 return 0;
800 } 854 }
801 else if (!strncasecmp(buf, "/query", 6)) { 855 else if (!strncasecmp(buf, "/query", 6)) {
802 char *name = trimLeft(buf + 6); 856 char *name = trimLeft(buf + 6);
803 if (strlen(name) > 0) { 857 if (strlen(name) > 0) {
804 // qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername); 858 nn_user_t *user = nn_user_find(nnUsers, name);
805 printMsg(currWin, "Opening query for '%s'.\n", name); 859 if (user != NULL) {
806 860 printMsg(currWin, "Opening PRV query for '%s'.\n", user->name);
861 if (openWindow(user->name, TRUE))
862 printMsg(currWin, "In PRV query with '%s'.\n", user->name);
863 }
807 } else { 864 } else {
865 printMsg(currWin, "Usage: /query username\n");
866 printMsg(currWin, "To close a PRV query, use /close [username]\n");
867 printMsg(currWin, "/close without username will close the current PRV window (if any).\n");
808 } 868 }
809 return 0; 869 return 0;
810 } 870 }
811 else if (!strncasecmp(buf, "/win", 4)) { 871 else if (!strncasecmp(buf, "/close", 6)) {
812 char *name = trimLeft(buf + 4); 872 char *name = trimLeft(buf + 6);
813 if (strlen(name) > 0) { 873 if (strlen(name) > 0) {
874 nn_user_t *user = nn_user_find(nnUsers, name);
875 if (user != NULL) {
876 nn_window_t *win = nn_find_window(user->name);
877 closeWindow(win);
878 } else {
879 printMsg(currWin, "No PRV query by name '%s'.\n", name);
880 }
814 } else { 881 } else {
882 if (currWin != chatWindows[0]) {
883 closeWindow(currWin);
884 currWin = chatWindows[0];
885 }
815 } 886 }
816 return 0; 887 return 0;
817 } 888 }
818 else if (!strncasecmp(buf, "/save", 5)) { 889 else if (!strncasecmp(buf, "/save", 5)) {
819 /* Save configuration */ 890 /* Save configuration */
872 wait(&status); 943 wait(&status);
873 } 944 }
874 #endif 945 #endif
875 return 0; 946 return 0;
876 } 947 }
877 else if (!strncasecmp(buf, "/to", 3)) {
878 char *name = trimLeft(buf + 3);
879 /* Set private messaging target */
880 th_free(setTarget);
881 if (strlen(name) > 0) {
882 setTarget = th_strdup(trimLeft(buf + 3));
883 printMsg(NULL, "Set prv target to '%s'\n", setTarget);
884 } else {
885 setTarget = NULL;
886 printMsg(NULL, "Cleared prv target.\n");
887 }
888 return 0;
889 }
890 else if (!strncasecmp(buf, "/who", 4)) { 948 else if (!strncasecmp(buf, "/who", 4)) {
891 /* Alias /who to /listallusers */ 949 /* Alias /who to /listallusers */
892 snprintf(tmpBuf, sizeof(tmpBuf), "/listallusers"); 950 snprintf(tmpBuf, sizeof(tmpBuf), "/listallusers");
893 buf = tmpBuf; 951 buf = tmpBuf;
894 } 952 }
895 else if (setPrvMode) { 953 else if (currWin != chatWindows[0]) {
896 /* Private chat mode, send as PRV */ 954 if (currWin->id != NULL) {
897 if (setTarget != NULL) { 955 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", currWin->id, buf);
898 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf);
899 buf = tmpBuf; 956 buf = tmpBuf;
900 } else { 957 } else {
901 printMsg(NULL, "No target set, exiting prv mode.\n"); 958 printMsg(NULL, "No target set, exiting prv mode.\n");
902 setPrvMode = FALSE;
903 return 1; 959 return 1;
904 } 960 }
905 } 961 }
906 962
907 /* Send double-encoded */ 963 /* Send double-encoded */
908 tmpStr = nn_dblencode_str(nn_username_decode(buf)); 964 tmpStr = nn_dblencode_str(nn_username_decode(buf));
909 if (tmpStr == 0) return -2; 965 if (tmpStr == 0) return -2;
910 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr); 966 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr);
911 th_free(tmpStr); 967 th_free(tmpStr);
1308 1364
1309 if (!initializeWindows()) 1365 if (!initializeWindows())
1310 goto err_exit; 1366 goto err_exit;
1311 1367
1312 memset(chatWindows, 0, sizeof(chatWindows)); 1368 memset(chatWindows, 0, sizeof(chatWindows));
1313 chatWindows[0] = nn_window_new(); 1369 chatWindows[0] = nn_window_new(NULL);
1314 currWin = chatWindows[0]; 1370 currWin = chatWindows[0];
1315 updateStatus(insertMode); 1371 updateStatus();
1316 } 1372 }
1317 1373
1318 /* Check if we have username and password */ 1374 /* Check if we have username and password */
1319 if (cursesInit && (optUserName == NULL || optPassword == NULL)) { 1375 if (cursesInit && (optUserName == NULL || optPassword == NULL)) {
1320 printWin(editWin, "You can avoid this prompt by issuing '/save' after logging in.\n"); 1376 printWin(editWin, "You can avoid this prompt by issuing '/save' after logging in.\n");
1383 /* Initialize rest of interactive UI code */ 1439 /* Initialize rest of interactive UI code */
1384 memset(histBuf, 0, sizeof(histBuf)); 1440 memset(histBuf, 0, sizeof(histBuf));
1385 nn_editbuf_clear(editBuf); 1441 nn_editbuf_clear(editBuf);
1386 1442
1387 /* First update of screen */ 1443 /* First update of screen */
1388 printEditBuf("", editBuf); 1444 printEditBuf(editBuf);
1389 updateStatus(insertMode); 1445 updateStatus();
1390 1446
1391 printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname); 1447 printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
1392 printMsg(NULL, "%s\n", th_prog_author); 1448 printMsg(NULL, "%s\n", th_prog_author);
1393 printMsg(NULL, "%s\n", th_prog_license); 1449 printMsg(NULL, "%s\n", th_prog_license);
1394 } 1450 }
1463 break; 1519 break;
1464 } 1520 }
1465 /* Get the trailing ~ */ 1521 /* Get the trailing ~ */
1466 if (c != ERR) 1522 if (c != ERR)
1467 wgetch(stdscr); 1523 wgetch(stdscr);
1468 } else { 1524 }
1525 if (c >= 0x31 && c <= 0x39) {
1526 /* Chat window switching via Meta/Esc-[1..9] */
1527 int win = c - 0x31;
1528 if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL) {
1529 currWin = chatWindows[win];
1530 update = updateMain = TRUE;
1531 }
1532 c = ERR;
1533 }
1534 else {
1469 printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c); 1535 printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c);
1470 continue; 1536 continue;
1471 } 1537 }
1472 } 1538 }
1473 1539
1597 case KEY_F(5): /* F5 = Ignore mode */ 1663 case KEY_F(5): /* F5 = Ignore mode */
1598 setIgnoreMode = !setIgnoreMode; 1664 setIgnoreMode = !setIgnoreMode;
1599 printMsg(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF"); 1665 printMsg(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF");
1600 break; 1666 break;
1601 1667
1602 case KEY_F(7): /* F7 = Clear PRV target */
1603 if (setTarget) {
1604 printMsg(NULL, "Cleared PRV target.\n");
1605 setPrvMode = FALSE;
1606 th_free(setTarget);
1607 setTarget = NULL;
1608 update = TRUE;
1609 }
1610 break;
1611
1612 case KEY_F(8): /* F8 = switch between PRV */
1613 if (setPrvMode)
1614 setPrvMode = FALSE;
1615 else {
1616 if (setTarget != NULL)
1617 setPrvMode = TRUE;
1618 }
1619 update = TRUE;
1620 break;
1621
1622 case 0x03: /* ^C = quit */ 1668 case 0x03: /* ^C = quit */
1623 case KEY_F(9): /* F9 = Quit */ 1669 case KEY_F(9): /* F9 = Quit */
1624 printMsg(currWin, "Quitting per user request.\n"); 1670 printMsg(currWin, "Quitting per user request.\n");
1625 exitProg = TRUE; 1671 exitProg = TRUE;
1626 break; 1672 break;
1673 } 1719 }
1674 } while (c != ERR && !exitProg && ++cnt < 10); 1720 } while (c != ERR && !exitProg && ++cnt < 10);
1675 1721
1676 if (update || firstUpdate) { 1722 if (update || firstUpdate) {
1677 /* Update edit line */ 1723 /* Update edit line */
1678 printEditBuf(setPrvMode ? setTarget : "", editBuf); 1724 printEditBuf(editBuf);
1679 updateStatus(insertMode); 1725 updateStatus();
1680 firstUpdate = FALSE; /* a nasty hack ... */ 1726 firstUpdate = FALSE; /* a nasty hack ... */
1681 } 1727 }
1682 1728
1683 updateMainWin(updateMain); 1729 updateMainWin(updateMain);
1684 } /* cursesInit */ 1730 } /* cursesInit */
1695 if (!colorSet) { 1741 if (!colorSet) {
1696 colorSet = TRUE; 1742 colorSet = TRUE;
1697 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 1743 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
1698 } 1744 }
1699 1745
1700 updateStatus(insertMode); 1746 updateStatus();
1701 updateCount = 0; 1747 updateCount = 0;
1702 } 1748 }
1703 1749
1704 } 1750 }
1705 1751
1715 1761
1716 for (i = 0; i < SET_MAX_WINDOWS; i++) 1762 for (i = 0; i < SET_MAX_WINDOWS; i++)
1717 nn_window_free(chatWindows[i]); 1763 nn_window_free(chatWindows[i]);
1718 } 1764 }
1719 1765
1720 //#ifdef __WIN32 1766 #ifdef __WIN32
1721 if (errorMessages) { 1767 if (errorMessages) {
1722 char *tmp; 1768 char *tmp;
1723 wclear(editWin); 1769 wclear(editWin);
1724 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE); 1770 tmp = promptRequester(editWin, "Press enter to quit.\n", FALSE);
1725 th_free(tmp); 1771 th_free(tmp);
1726 } 1772 }
1727 //#endif 1773 #endif
1728 1774
1729 if (cursesInit) { 1775 if (cursesInit) {
1730 if (curVis != ERR) 1776 if (curVis != ERR)
1731 curs_set(curVis); 1777 curs_set(curVis);
1732 closeWindows(); 1778 closeWindows();