# HG changeset patch # User Matti Hamalainen # Date 1287092065 -10800 # Node ID eaa524e153f9b31e894c1163f665c3ab4f79b034 # Parent b096ae97fc7d4766372d5ee332caf3b0998f6516 Initial implementation of functions for implementing tab-completion for user names. diff -r b096ae97fc7d -r eaa524e153f9 Makefile.gen --- a/Makefile.gen Mon Oct 11 15:48:05 2010 +0300 +++ b/Makefile.gen Fri Oct 15 00:34:25 2010 +0300 @@ -17,7 +17,7 @@ $(OBJPATH)%.o: %.c %.h $(COMP) -c -o $@ $< -$(NNCHAT_BIN): nnchat.c $(OBJPATH)libnnchat.o $(OBJPATH)th_util.o $(OBJPATH)th_string.o $(OBJPATH)th_args.o +$(NNCHAT_BIN): nnchat.c $(OBJPATH)libnnchat.o $(OBJPATH)th_util.o $(OBJPATH)th_string.o $(OBJPATH)th_args.o $(OBJPATH)th_config.o $(COMP) -o $@ $+ $(LDFLAGS) # diff -r b096ae97fc7d -r eaa524e153f9 libnnchat.c --- a/libnnchat.c Mon Oct 11 15:48:05 2010 +0300 +++ b/libnnchat.c Fri Oct 15 00:34:25 2010 +0300 @@ -550,9 +550,35 @@ } +char * nn_editbuf_get_string(nn_editbuf_t *buf, ssize_t start, ssize_t end) +{ + char *str; + ssize_t siz; + + if (buf == NULL) + return NULL; + + if (start < 0 || end > buf->len || start >= buf->len) + return NULL; + + if (end < 0) { + siz = buf->len - start + 1; + } else if (start <= end) { + siz = end - start + 1; + } else + return NULL; + + str = th_malloc(siz + 1); + memcpy(str, buf->data + start, siz); + str[siz] = 0; + return str; +} + + void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos) { - /* Check arguments */ + assert(buf != NULL); + if (pos < 0) buf->pos = 0; else if (pos >= buf->len) @@ -564,6 +590,7 @@ static uint8_t nn_hash_user(const char *name) { +/* int n = 0; const uint8_t *c = (uint8_t *)name; uint8_t hash = 0xff; @@ -574,6 +601,8 @@ } return (hash & 0xff); +*/ + return tolower(name[0]); } @@ -584,6 +613,26 @@ } +nn_user_t *nn_userhash_foreach(const nn_userhash_t *list, int (*func)(const nn_user_t *)) +{ + int i; + + if (list == NULL) return NULL; + + for (i = 0; i < NN_NUM_BUCKETS; i++) + if (list->buckets[i] != NULL) { + nn_user_t *curr = list->buckets[i]; + while (curr != NULL) { + if (func(curr) != 0) + return curr; + curr = curr->next; + } + } + + return NULL; +} + + nn_user_t *nn_user_find_enc(const nn_userhash_t *list, const char *encname) { uint8_t hash; @@ -604,7 +653,50 @@ } -int nn_user_add_to_hash(nn_userhash_t **list, const char *encname) +nn_user_t *nn_user_match(const nn_userhash_t *list, const char *str, const char *current) +{ + uint8_t hash; + + if (list == NULL) return NULL; + + hash = nn_hash_user(str); + if (list->buckets[hash] != NULL) { + nn_user_t *curr = list->buckets[hash]; + int len = strlen(str); + + if (current != NULL) { + nn_user_t *found = NULL; + while (curr != NULL) { + if (strcasecmp(curr->name, current) == 0) { + found = curr->next; + break; + } + curr = curr->next; + } + if (found != NULL) + curr = found; + else + curr = list->buckets[hash]; + } + + while (curr != NULL) { + if (strncasecmp(curr->name, str, len) == 0) + return curr; + curr = curr->next; + } + } + + return NULL; +} + + +nn_userhash_t *nn_userhash_new(void) +{ + return th_calloc(1, sizeof(nn_userhash_t)); +} + + +int nn_userhash_insert(nn_userhash_t *list, const char *encname) { uint8_t hash; nn_user_t *user; @@ -613,15 +705,8 @@ if (list == NULL || encname == NULL) return -1; - /* Check if list data exists */ - if (*list == NULL) { - *list = th_calloc(1, sizeof(nn_userhash_t)); - if (*list == NULL) - return -2; - } - /* Check if username is already there */ - if (nn_user_find_enc(*list, encname) != NULL) + if (nn_user_find_enc(list, encname) != NULL) return 1; /* No, we'll add it */ @@ -634,11 +719,47 @@ return -4; hash = nn_hash_user(encname); - nn_user_insert(&((*list)->buckets[hash]), user); + nn_user_insert(&(list->buckets[hash]), user); + return 0; } +int nn_userhash_delete(nn_userhash_t *list, const char *encname) +{ + uint8_t hash; + + /* Check arguments */ + if (list == NULL || encname == NULL) + return -1; + + /* Check if username is already there */ + hash = nn_hash_user(encname); + if (list->buckets[hash] != NULL) { + nn_user_t *curr, *prev; + curr = list->buckets[hash]; + prev = NULL; + while (curr != NULL) { + if (strcasecmp(curr->encname, encname) == 0) { + if (prev) + prev->next = curr->next; + else + list->buckets[hash] = curr->next; + + nn_user_free(curr); + + return 0; + } else { + prev = curr; + curr = curr->next; + } + } + } + + return 1; +} + + nn_user_t *nn_user_copy(const nn_user_t *src) { nn_user_t *user; @@ -658,7 +779,7 @@ } -static void nn_user_free(nn_user_t *user) +void nn_user_free(nn_user_t *user) { th_free(user->encname); th_free(user->name); @@ -676,7 +797,7 @@ } } -void nn_user_free_hash(nn_userhash_t *hash) +void nn_userhash_free(nn_userhash_t *hash) { int i; if (hash == NULL) diff -r b096ae97fc7d -r eaa524e153f9 libnnchat.h --- a/libnnchat.h Mon Oct 11 15:48:05 2010 +0300 +++ b/libnnchat.h Fri Oct 15 00:34:25 2010 +0300 @@ -64,8 +64,13 @@ BOOL nn_send_to_socket(const int sock, char *buf, const size_t bufLen); BOOL nn_send_msg(const int sock, const char *user, const char *fmt, ...); -int nn_user_add_to_hash(nn_userhash_t **, const char *encname); -void nn_user_free_hash(nn_userhash_t *); +nn_userhash_t *nn_userhash_new(void); +nn_user_t * nn_userhash_foreach(const nn_userhash_t *, int (*func)(const nn_user_t *)); +nn_user_t * nn_user_match(const nn_userhash_t *list, const char *str, const char *current); +int nn_userhash_insert(nn_userhash_t *, const char *encname); +int nn_userhash_delete(nn_userhash_t *, const char *encname); +void nn_userhash_free(nn_userhash_t *); +void nn_user_free(nn_user_t *); void nn_user_free_list(nn_user_t *); nn_user_t * nn_user_copy(const nn_user_t *src); nn_user_t * nn_user_find_enc(const nn_userhash_t *list, const char *encname); @@ -92,6 +97,7 @@ void nn_editbuf_free(nn_editbuf_t *buf); nn_editbuf_t * nn_editbuf_copy(nn_editbuf_t *src); void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos); +char * nn_editbuf_get_string(nn_editbuf_t *buf, ssize_t start, ssize_t end); #endif diff -r b096ae97fc7d -r eaa524e153f9 nnchat.c --- a/nnchat.c Mon Oct 11 15:48:05 2010 +0300 +++ b/nnchat.c Fri Oct 15 00:34:25 2010 +0300 @@ -1,7 +1,7 @@ /* * NNChat - Custom chat client for NewbieNudes.com chatrooms * Written by Matti 'ccr' Hämäläinen - * (C) Copyright 2008-2009 Tecnic Software productions (TNSP) + * (C) Copyright 2008-2010 Tecnic Software productions (TNSP) */ #include "libnnchat.h" #include @@ -22,6 +22,17 @@ #define SET_DELAY_USEC (SET_DELAY * 1000) #define SET_KEEPALIVE (15*60) /* Ping/keepalive period in seconds */ +char *ignoreList[] = { + "purr_rr", + "moisha", + "leth", + "shaz:)", + "rayen", + "iam2qute4you_92", + NULL +}; + +nn_userhash_t *nnUsers = NULL; /* Options */ @@ -40,6 +51,7 @@ *statusWin = NULL, *editWin = NULL; BOOL setPrvMode = FALSE; +BOOL ignoreMode = FALSE; /* Arguments @@ -282,7 +294,7 @@ } -void printMsgV(const char *fmt, va_list ap) +void printMsgV(BOOL addStamp, BOOL logOnly, const char *fmt, va_list ap) { char tmpStr[128] = "", buf[8192]; time_t timeStamp; @@ -296,13 +308,13 @@ vsnprintf(buf, sizeof(buf), fmt, ap); if (optLogFile) { - printFile(optLogFile, tmpStr); + if (addStamp) printFile(optLogFile, tmpStr); printFile(optLogFile, buf); fflush(optLogFile); } - if (!optDaemon) { - printWin(mainWin, tmpStr); + if (!optDaemon && !logOnly) { + if (addStamp) printWin(mainWin, tmpStr); printWin(mainWin, buf); wrefresh(mainWin); } @@ -313,7 +325,25 @@ va_list ap; va_start(ap, fmt); - printMsgV(fmt, ap); + printMsgV(TRUE, FALSE, fmt, ap); + va_end(ap); +} + +void printMsgC(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printMsgV(FALSE, FALSE, fmt, ap); + va_end(ap); +} + +void printMsgQ(BOOL logOnly, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printMsgV(TRUE, logOnly, fmt, ap); va_end(ap); } @@ -324,7 +354,7 @@ va_start(ap1, fmt); va_copy(ap2, ap1); - printMsgV(fmt, ap1); + printMsgV(TRUE, FALSE, fmt, ap1); va_end(ap1); THERR_V(fmt, ap2); @@ -371,9 +401,20 @@ th_free(t); } else { BOOL isMine = strcmp(p, optUserName) == 0; + BOOL logOnly = FALSE; t = nn_strip_tags(s); h = nn_decode_str2(t); - printMsg("½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, p, h); + if (ignoreMode) { + char **user = ignoreList; + while (*user != NULL) { + if (strcasecmp(p, *user) == 0) { + logOnly = TRUE; + break; + } + user++; + } + } + printMsgQ(logOnly, "½5½<½%d½%s½5½>½0½ %s\n", isMine ? 14 : 15, p, h); th_free(h); th_free(t); } @@ -418,7 +459,9 @@ p = nn_dbldecode_str(str); if (!p) return -1; - + + nn_userhash_insert(nnUsers, str); + printMsg("! ½3½%s½0½ ½2½ADDED.½0½\n", p); th_free(p); return 0; @@ -436,7 +479,8 @@ p = nn_dbldecode_str(str); if (!p) return -1; - + + nn_userhash_delete(nnUsers, str); printMsg("! ½3½%s½0½ ½1½DELETED.½0½\n", p); th_free(p); return 0; @@ -554,14 +598,11 @@ /* Send double-encoded */ tmpStr = nn_dblencode_str(buf); - if (!tmpStr) return -2; - + if (tmpStr == 0) return -2; result = nn_send_msg(sock, optUserName2, "%s", tmpStr); th_free(tmpStr); - if (result) - return 0; - else - return -1; + + return result ? 0 : -1; } @@ -585,6 +626,13 @@ } +int printUserFunc(const nn_user_t *user) +{ + if (user) + printMsgC("%s, ", user->name); + return 0; +} + int main(int argc, char *argv[]) { int tmpSocket = -1, curVis = ERR, updateCount = 0; @@ -606,8 +654,8 @@ memset(histBuf, 0, sizeof(histBuf)); /* Initialize */ - th_init("NNChat", "Newbie Nudes chat client", "0.7.3", - "Written and designed by Anonymous Finnish Guy (C) 2008-2009", + th_init("NNChat", "Newbie Nudes chat client", "0.7.9", + "Written and designed by Anonymous Finnish Guy (C) 2008-2010", "This software is freeware, use and distribute as you wish."); th_verbosityLevel = 0; @@ -624,6 +672,11 @@ if (!argsOK) return -2; + /* Allocate userhash */ + if ((nnUsers = nn_userhash_new()) == NULL) { + THERR("Could not allocate userhash. Fatal error.\n"); + return -105; + } /* Open logfile */ if (optLogFilename) { @@ -852,16 +905,6 @@ } break; - case 0x09: /* Tab = switch between PRV */ - if (setPrvMode) - setPrvMode = FALSE; - else { - if (setTarget != NULL) - setPrvMode = TRUE; - } - update = TRUE; - break; - case KEY_UP: /* Backwards in input history */ if (histPos == 0) { nn_editbuf_free(histBuf[0]); @@ -884,7 +927,7 @@ } break; - case 0x204: /* ctrl+left = Skip words left */ + case 0x204: /* ctrl+left arrow = Skip words left */ while (editBuf->pos > 0 && isspace((int) editBuf->data[editBuf->pos - 1])) editBuf->pos--; while (editBuf->pos > 0 && !isspace((int) editBuf->data[editBuf->pos - 1])) @@ -892,7 +935,7 @@ update = TRUE; break; - case 0x206: /* ctrl+right = Skip words right */ + case 0x206: /* ctrl+right arrow = Skip words right */ while (editBuf->pos < editBuf->len && isspace((int) editBuf->data[editBuf->pos])) editBuf->pos++; while (editBuf->pos < editBuf->len && !isspace((int) editBuf->data[editBuf->pos])) @@ -901,22 +944,7 @@ editBuf->pos = editBuf->len; update = TRUE; break; - - case 0x111: /* F9 = Quit */ - printMsg("Quitting per user request.\n"); - exitProg = TRUE; - break; - - case 0x109: /* F1 = Toggle insert / overwrite mode */ - insertMode = !insertMode; - update = TRUE; - break; - - case 0x10a: /* F2 = Clear editbuffer */ - nn_editbuf_clear(editBuf); - update = TRUE; - break; - + case KEY_HOME: nn_editbuf_setpos(editBuf, 0); update = TRUE; break; case KEY_END: nn_editbuf_setpos(editBuf, editBuf->len); update = TRUE; break; case KEY_LEFT: nn_editbuf_setpos(editBuf, editBuf->pos - 1); update = TRUE; break; @@ -929,14 +957,67 @@ update = TRUE; break; - case 0x14a: - /* Delete */ + case 0x14a: /* Delete */ nn_editbuf_delete(editBuf, editBuf->pos); update = TRUE; break; + + + case 0x109: /* F1 = Toggle insert / overwrite mode */ + insertMode = !insertMode; + update = TRUE; + break; - case 0x0c: - /* ctrl+l */ + case 0x10a: /* F2 = Clear editbuffer */ + nn_editbuf_clear(editBuf); + update = TRUE; + break; + + case 0x10c: /* F3 = Ignore mode */ + ignoreMode = !ignoreMode; + printMsg("Ignore mode = %s\n", ignoreMode ? "ON" : "OFF"); + break; + + case 0x111: /* F9 = Quit */ + printMsg("Quitting per user request.\n"); + exitProg = TRUE; + break; + + case 0x110: /* F8 = switch between PRV */ + if (setPrvMode) + setPrvMode = FALSE; + else { + if (setTarget != NULL) + setPrvMode = TRUE; + } + update = TRUE; + break; + + case 0x09: /* Tab = complete username */ + { + ssize_t pos = editBuf->pos; + while (pos > 0 && !isspace((int) editBuf->data[pos - 1])) + pos--; + + if (!isspace(editBuf->data[pos])) { + char *str = nn_editbuf_get_string(editBuf, pos, editBuf->pos); + if (str) { + static char *c_prev = NULL; + nn_user_t *c_curr = nn_user_match(nnUsers, str, c_prev); + th_free(c_prev); + c_prev = NULL; + + if (c_curr) { + c_prev = th_strdup(c_curr->name); + printMsg("Lol: %s\n", c_curr->name); + } + + } + } + } + break; + + case 0x0c: /* Ctrl + L */ redrawwin(mainWin); redrawwin(statusWin); redrawwin(editWin); @@ -991,6 +1072,8 @@ /* Shutdown */ err_exit: + nn_userhash_free(nnUsers); + nn_editbuf_free(editBuf); for (histPos = 0; histPos <= SET_MAX_HISTORY; histPos++) nn_editbuf_free(histBuf[histPos]);