view libnnchat.c @ 71:3a23c2adfb78

Remove tabs from indentation.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Nov 2008 08:49:40 +0200
parents e763ef5cfd53
children fe5fc76c0806
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;


html_entity_t HTMLEntities[] = {
    { '<', "&lt;" },
    { '>', "&gt;" },
};

const int numHTMLEntities = (sizeof(HTMLEntities) / sizeof(HTMLEntities[0]));


int openConnection(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 closeConnection(const int sock)
{
    if (sock >= 0) {
#ifdef __WIN32
        closesocket(sock);
#else
        close(sock);
#endif
    }
}


BOOL sendToSocket(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) 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 *encodeStr1(const char *str)
{
    const char *s = str;
    char *result;
    size_t resSize, resPos = 0;
    
    if (!str) 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 *decodeStr1(const char *str)
{
    const char *s = str;
    char *result;
    size_t resSize, resPos = 0;
    int c;
    
    if (!str) 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 *stripXMLTags(const char *str)
{
    const char *s = str;
    char *result;
    size_t resSize, resPos = 0;
    
    if (!str) 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 *encodeStr2(const char *str)
{
    const char *s = str;
    char *result;
    size_t resSize, resPos = 0;
    
    if (!str) 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 *decodeStr2(const char *str)
{
    const char *s = str;
    char *result;
    size_t resSize, resPos = 0;
    
    if (!str) 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++) {
                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;
}


BOOL sendUserMsg(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 sendToSocket(sock, tmpBuf2, strlen(tmpBuf2) + 1);
}


ringbuf_t * newRingBuf(const size_t size)
{
    ringbuf_t *res = th_calloc(1, sizeof(ringbuf_t));
    
    res->data = (char **) th_malloc(size * sizeof(char *));
    res->size = size;
    res->n = 0;
    
    return res;
}


void freeRingBuf(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 addRingBuf(ringbuf_t *buf, const char *str)
{
    if (buf->n < buf->size) {
        buf->data[buf->n] = 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] = strdup(str);
    }
}


int writeBuf(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 insertBuf(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 deleteBuf(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 clearBuf(editbuf_t *buf)
{
    buf->len = 0;
    buf->pos = 0;
}


editbuf_t * newBuf(ssize_t n)
{
    editbuf_t *res = th_calloc(1, sizeof(editbuf_t));
    
    res->data = (char *) th_malloc(n);
    res->size = n;
    
    return res;
}


void freeBuf(editbuf_t *buf)
{
    if (buf) {
        th_free(buf->data);
        th_free(buf);
    }
}


editbuf_t * copyBuf(editbuf_t *src)
{
    editbuf_t *res;
    
    assert(src != NULL);
    
    if (src == NULL) return NULL;
    
    if ((res = newBuf(src->size)) == NULL)
        return NULL;
    
    memcpy(res->data, src->data, src->size);
    res->pos = res->len = src->len;
    
    return res;
}


void setBufPos(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;
}