changeset 103:eaa524e153f9

Initial implementation of functions for implementing tab-completion for user names.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 15 Oct 2010 00:34:25 +0300
parents b096ae97fc7d
children 06e6ac51e3f2
files Makefile.gen libnnchat.c libnnchat.h nnchat.c
diffstat 4 files changed, 276 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- 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)
 
 #
--- 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)
--- 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
--- 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 <stdlib.h>
@@ -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]);