Mercurial > hg > nnchat
view libnnchat.c @ 100:ed4067c10a8a
Remove useless buffer usage from error reporting function.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 17 Nov 2009 23:09:10 +0200 |
parents | 218efd2f0641 |
children | b096ae97fc7d |
line wrap: on
line source
/* * NNChat - Custom chat client for NewbieNudes.com chatrooms * Written by Matti 'ccr' Hämäläinen * (C) Copyright 2008 Tecnic Software productions (TNSP) */ #include "libnnchat.h" typedef struct { char c; char *ent; } html_entity_t; static const html_entity_t HTMLEntities[] = { { '<', "<" }, { '>', ">" }, }; static const int numHTMLEntities = (sizeof(HTMLEntities) / sizeof(HTMLEntities[0])); #ifdef __WIN32 const char *hstrerror(int err) { static char buf[64]; snprintf(buf, sizeof(buf), "Error #%d", err); return buf; } int nn_get_socket_errno(void) { return WSAGetLastError(); } const char *nn_get_socket_errstr(int err) { static char buf[64]; snprintf(buf, sizeof(buf), "Error #%d", err); return buf; } #else int nn_get_socket_errno(void) { return errno; } const char *nn_get_socket_errstr(int err) { return strerror(err); } #endif int nn_open_connection(struct in_addr *addr, const int port) { struct sockaddr_in tmpAddr; int sock = -1; tmpAddr.sin_family = AF_INET; tmpAddr.sin_port = htons(port); tmpAddr.sin_addr = *addr; THMSG(1, "Connecting to %s:%d ...\n", inet_ntoa(tmpAddr.sin_addr), port); if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { THERR("Could not open socket: %s\n", strerror(errno)); return -2; } THMSG(2, "Using socket %d.\n", sock); if (connect(sock, (struct sockaddr *) &tmpAddr, sizeof(tmpAddr)) == -1) { THERR("Could not connect: %s\n", strerror(errno)); return -5; } return sock; } void nn_close_connection(const int sock) { if (sock >= 0) { #ifdef __WIN32 closesocket(sock); #else close(sock); #endif } } BOOL nn_network_init(void) { #ifdef __WIN32 /* Initialize WinSock, if needed */ WSADATA wsaData; int err = WSAStartup(0x0101, &wsaData); if (err != 0) { THERR("Could not initialize WinSock library (err=%d).\n", err); return FALSE; } #endif return TRUE; } void nn_network_close(void) { #ifdef __WIN32 WSACleanup(); #endif } BOOL nn_send_to_socket(const int sock, char *buf, const size_t bufLen) { size_t bufLeft = bufLen; char *bufPtr = buf; while (bufLeft > 0) { ssize_t bufSent; bufSent = send(sock, bufPtr, bufLeft, 0); if (bufSent < 0) return FALSE; bufLeft -= bufSent; bufPtr += bufSent; } return TRUE; } BOOL bufRealloc(char **buf, size_t *size, size_t add) { return ((*buf = th_realloc(*buf, *size + add)) != NULL); } #define PUSHCHAR(x) bufPushChar(&result, &resSize, &resPos, x) BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch) { if (*pos >= *size && !bufRealloc(buf, size, SET_ALLOC_SIZE)) return FALSE; (*buf)[*pos] = ch; (*pos)++; return TRUE; } #define PUSHSTR(x) bufPushStr(&result, &resSize, &resPos, x) BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str) { size_t tmpLen; if (str == NULL) return FALSE; tmpLen = strlen(str); if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + SET_ALLOC_SIZE)) return FALSE; strcpy(*buf + *pos, str); (*pos) += tmpLen; return TRUE; } char *nn_encode_str1(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + SET_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { switch (*s) { case 32: PUSHCHAR('+'); break; default: if (th_isalnum(*s)) PUSHCHAR(*s); else { char tmpStr[4]; sprintf(tmpStr, "%2X", (unsigned char) *s); PUSHCHAR('%'); PUSHSTR(tmpStr); } break; } s++; } PUSHCHAR(0); return result; } static int getHexDigit(const int c, const int shift) { int i; if (c >= 'A' && c <= 'F') i = c - 'A' + 10; else if (c >= 'a' && c <= 'f') i = c - 'a' + 10; else if (c >= '0' && c <= '9') i = c - '0'; else return -1; return i << shift; } char *nn_decode_str1(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; int c; if (str == NULL) return NULL; resSize = strlen(str) + SET_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { switch (*s) { case '+': PUSHCHAR(' '); s++; break; case '½': /* Escape these .. */ PUSHCHAR('½'); PUSHCHAR('½'); s++; break; case '\r': PUSHCHAR(' '); s++; break; case '%': s++; if (*s == '%') PUSHCHAR('%'); else if ((c = getHexDigit(*s, 4)) >= 0) { int i = getHexDigit(*(++s), 0); if (i >= 0) { PUSHCHAR(c | i); } else { PUSHCHAR('§'); PUSHCHAR(*s); } } else { PUSHCHAR('§'); PUSHCHAR(*s); } s++; break; default: PUSHCHAR(*s); s++; } } PUSHCHAR(0); return result; } char *nn_strip_tags(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + SET_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { if (*s == '<') { while (*s && *s != '>') s++; if (*s == '>') s++; } else PUSHCHAR(*s++); } PUSHCHAR(0); return result; } char *nn_encode_str2(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str) + SET_ALLOC_SIZE; if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { int i; BOOL found = FALSE; for (i = 0; i < numHTMLEntities; i++) if (HTMLEntities[i].c == *s) { PUSHSTR(HTMLEntities[i].ent); found = TRUE; break; } if (!found) PUSHCHAR(*s); s++; } PUSHCHAR(0); return result; } char *nn_decode_str2(const char *str) { const char *s = str; char *result; size_t resSize, resPos = 0; if (str == NULL) return NULL; resSize = strlen(str); if ((result = th_malloc(resSize)) == NULL) return NULL; while (*s) { if (*s == '&') { int i; BOOL found = FALSE; for (i = 0; i < numHTMLEntities; i++) { const html_entity_t *ent = &HTMLEntities[i]; int len = strlen(ent->ent); if (!strncmp(s, ent->ent, len)) { PUSHCHAR(ent->c); s += len; found = TRUE; break; } } if (!found) PUSHCHAR(*s++); } else PUSHCHAR(*s++); } PUSHCHAR(0); return result; } char *nn_dbldecode_str(const char *str) { char *res, *tmp; if ((tmp = nn_decode_str1(str)) == NULL) return NULL; res = nn_decode_str2(tmp); th_free(tmp); return res; } char *nn_dblencode_str(const char *str) { char *res, *tmp; if ((tmp = nn_encode_str2(str)) == NULL) return NULL; res = nn_encode_str1(tmp); th_free(tmp); return res; } BOOL nn_send_msg(const int sock, const char *user, const char *fmt, ...) { char tmpBuf[SET_BUFSIZE], tmpBuf2[SET_BUFSIZE + 256]; int n; va_list ap; va_start(ap, fmt); n = vsnprintf(tmpBuf, sizeof(tmpBuf), fmt, ap); va_end(ap); if (n < 0) return FALSE; snprintf(tmpBuf2, sizeof(tmpBuf2), "<USER>%s</USER><MESSAGE>%s</MESSAGE>", user, tmpBuf); return nn_send_to_socket(sock, tmpBuf2, strlen(tmpBuf2) + 1); } nn_ringbuf_t * nn_ringbuf_new(const size_t size) { nn_ringbuf_t *res = th_calloc(1, sizeof(nn_ringbuf_t)); res->data = (char **) th_malloc(size * sizeof(char *)); res->size = size; res->n = 0; return res; } void nn_ringbuf_free(nn_ringbuf_t *buf) { size_t i; for (i = 0; i < buf->n; i++) th_free(buf->data[i]); th_free(buf->data); th_free(buf); } void nn_ringbuf_add(nn_ringbuf_t *buf, const char *str) { if (buf->n < buf->size) { buf->data[buf->n] = th_strdup(str); buf->n++; } else { th_free(buf->data[0]); memmove(&(buf->data[0]), &(buf->data[1]), buf->size - 1); buf->data[buf->size - 1] = th_strdup(str); } } int nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch) { /* Check arguments */ if (buf->len+1 >= buf->size) return -3; if (pos < 0) return -1; else if (pos >= buf->len) { buf->data[buf->len++] = ch; } else { buf->data[pos] = ch; } return 0; } int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch) { /* Check arguments */ if (buf->len+1 >= buf->size) return -3; if (pos < 0) return -1; else if (pos >= buf->len) { buf->data[buf->len] = ch; } else { memmove(&(buf->data[pos+1]), &(buf->data[pos]), buf->len - pos + 1); buf->data[pos] = ch; } buf->len++; return 0; } int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos) { /* Check arguments */ if (pos < 0) return -1; else if (pos < buf->len) { memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); buf->len--; return 0; } else return -2; } void nn_editbuf_clear(nn_editbuf_t *buf) { buf->len = 0; buf->pos = 0; } nn_editbuf_t * nn_editbuf_new(ssize_t n) { nn_editbuf_t *res = th_calloc(1, sizeof(nn_editbuf_t)); res->data = (char *) th_malloc(n); res->size = n; return res; } void nn_editbuf_free(nn_editbuf_t *buf) { if (buf) { th_free(buf->data); th_free(buf); } } nn_editbuf_t * nn_editbuf_copy(nn_editbuf_t *src) { nn_editbuf_t *res; assert(src != NULL); if (src == NULL) return NULL; if ((res = nn_editbuf_new(src->size)) == NULL) return NULL; memcpy(res->data, src->data, src->size); res->pos = res->len = src->len; return res; } void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos) { /* Check arguments */ if (pos < 0) buf->pos = 0; else if (pos >= buf->len) buf->pos = buf->len; else buf->pos = pos; } static uint8_t hashUserName(char *name) { int n = 0; uint8_t *c = (uint8_t *)name; uint8_t hash = 0xff; while (*c && n < 4) { hash = (hash << 1) ^ tolower(*c); c++; n++; } return (hash & 0xff); } static void insertUser(nn_user_t **list, nn_user_t *node) { node->next = *list; *list = node; } nn_user_t *findUserEnc(nn_userhash_t *list, char *encname) { uint8_t hash; if (list == NULL) return NULL; hash = hashUserName(encname); if (list->buckets[hash] != NULL) { nn_user_t *curr = list->buckets[hash]; while (curr != NULL) { if (strcasecmp(curr->encname, encname) == 0) return curr; curr = curr->next; } } return NULL; } int addUserToHash(nn_userhash_t **list, char *encname) { uint8_t hash; nn_user_t *user; /* Check arguments */ 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 (findUserEnc(*list, encname) != NULL) return 1; /* No, we'll add it */ if ((user = th_calloc(1, sizeof(nn_user_t))) == NULL) return -3; user->encname = th_strdup(encname); user->name = nn_dbldecode_str(encname); if (user->encname == NULL || user->name == NULL) return -4; hash = hashUserName(encname); insertUser(&((*list)->buckets[hash]), user); return 0; } nn_user_t *copyUser(nn_user_t *src) { nn_user_t *user; if (src == NULL) return NULL; if ((user = th_calloc(1, sizeof(nn_user_t))) == NULL) return NULL; /* Copy relevant data */ user->encname = th_strdup(src->encname); user->name = th_strdup(src->name); user->lastspoke = src->lastspoke; user->joined = src->joined; return user; } static void freeUser(nn_user_t *user) { th_free(user->encname); th_free(user->name); th_free(user); } void freeUserList(nn_user_t *list) { nn_user_t *next, *curr = list; while (curr != NULL) { next = curr->next; freeUser(curr); curr = next; } } void freeUserHash(nn_userhash_t *hash) { int i; if (hash == NULL) return; for (i = 0; i < NN_NUM_BUCKETS; i++) { freeUserList(hash->buckets[i]); hash->buckets[i] = NULL; } th_free(hash); }