view libnnchat.c @ 64:6a3a917303e4

Some random cleanups, bring back WinSock support.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 11 Nov 2008 22:33:35 +0200
parents ff5d74f0d428
children e763ef5cfd53
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);
}