/* $Id: sys.c,v 1.5 2007/02/03 14:13:01 mbalmer Exp $ */

/*
 * Copyright (c) 2006 Marcus Glocker <marcus@nazgul.ch>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>

/*
 * sys_connect()
 *	connect a host
 * Return:
 *	>0 = success, -1 = error
 */
int
sys_connect(const char *hostname, int port)
{
	int			 sfd;
	struct hostent		*he;
	struct sockaddr_in	 address;

	if ((he = gethostbyname(hostname)) == NULL)
		return (-1);

	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		return (-1);

	address.sin_family = AF_INET;
	address.sin_port = htons(port);
	address.sin_addr = *((struct in_addr *)he->h_addr);

	memset(&(address.sin_zero), 0, sizeof(address.sin_zero));

	if (connect(sfd, (struct sockaddr *)&address,
	    (socklen_t)sizeof(struct sockaddr)) == -1)
		return (-1);

	return (sfd);
}

/*
 * sys_getlocalip()
 *	get ip address of local host
 * Return:
 *	0 = success, -1 = error
 */
int
sys_getlocalip(char *ip, size_t len)
{
	char		 hostname[MAXHOSTNAMELEN + 1];
	struct hostent	*host;

	if (gethostname(hostname, sizeof(hostname)) == -1)
		return (-1);

	if ((host = gethostbyname2(hostname, AF_INET)) == NULL)
		host = gethostbyname2("localhost", AF_INET);
	if (host == NULL)
		errx(1, "kiss my ass, sugababe");

	if (inet_ntop(AF_INET, host->h_addr, ip, len) == NULL)
		errx(1, "inet_ntop failed for host %s", hostname);

	return (0);
}

/*
 * sys_read()
 *	synchronous read
 *	used for blocking descriptors
 * Return:
 *	>0 = bytes read, 0 = descriptor closed, -1 = error
 */
ssize_t
sys_read(int sfd, void *buf, size_t len)
{
	ssize_t	r;

	for (;;) {
		r = read(sfd, buf, len);

		/* handle errors */
		if (r == -1) {
			if (errno == EINTR) {
				usleep(1);
				continue;
			}
			break;
		}

		/* descriptor closed by remote */
		if (r == 0)
			break;

		/* got data */
		if (r > 0)
			break;
	}

	return (r);
}

/*
 * sys_write()
 *	synchronous write
 *	used for non-blocking and blocking sockets
 * Return:
 *	>0 = bytes written, -1 = error
 */
ssize_t
sys_write(int sfd, const void *buf, size_t len)
{
	ssize_t		 r, sent = 0;
	const char	*p = (const char *)buf;

	for (;;) {
		r = write(sfd, p + sent, len - sent);

		/* handle errors */
		if (r == -1) {
			if (errno == EINTR) {
				usleep(1);
				continue;
			}
			if (errno == EAGAIN) {
				usleep(1);
				continue;
			}
			return (r);
		}

		/* sent data */
		if (r > 0)
			sent += r;

		/* sent all */
		if (sent == len)
			break;
	}
	return (sent);
}

/*
 * sys_strcutl()
 *	cuts a specific line in a string separated by LF's
 * Return:
 *	<total number of lines> = success, -1 = failed
 */
int
sys_strcutl(char *dst, const char *src, int line, size_t dsize)
{
	int	i = 0, j = 0, cl = 0;

	/* first count all lines */
	while (1) {
		if (src[i] == '\n' && src[i + 1] == '\0') {
			cl++;
			break;
		}
		if (src[i] == '\0') {
			cl++;
			break;
		}
		if (src[i] == '\n')
			cl++;

		i++;
	}

	/* do we have the requested line ? */
	if (line > cl || line == 0)
		return (-1);

	/* go to line start */
	for (i = 0, j = 0; j != line - 1; i++)
		if (src[i] == '\n')
			j++;

	/* read requested line */
	for (j = 0; src[i] != '\n' && src[i] != '\0' && j != dsize - 1; i++) {
		if (src[i] != '\r') {
			dst[j] = src[i];
			j++;
		}
	}

	/* terminate string */
	dst[j] = '\0';

	return (cl);
}

/*
 * sys_strcutw()
 *	cuts a specific word in a string separated by spaces
 * Return:
 *	0 = success, -1 = failed
 */
int
sys_strcutw(char *dst, const char *src, int word, size_t dsize)
{
	int	i, j;

	for (i = 0, j = 1; j != word; i++) {
		if (src[i] == ' ')
			j++;
		/* word not found */
		if (src[i] == '\0')
			return (-1);
	}
		
	for (j = 0; src[i] != ' ' && src[i] != '\0' && j != dsize - 1; i++, j++)
		dst[j] = src[i];

	/* terminate string */
	dst[j] = '\0';

	return (0);
}

/*
 * sys_strcuts()
 *	cuts a string from a string starting at start char until end char
 * Return:
 *	0 = success, -1 = failed
 */
int
sys_strcuts(char *dst, const char *src, char start, char end, 
    size_t dsize)
{
	int     i, j, len;

	len = strlen(src);

        for (i = 0, j = 0; src[i] != start && start != '\0'; i++) {
		/* start not found */
		if (i > len)
			return (-1);
	}

	if (start == '\0') {
		dst[0] = src[0];
		j++;
		i++;
	} else
		i++;

        for (; src[i] != end && i < len && j != dsize - 1; i++, j++)
                dst[j] = src[i];

	/* terminate string */
	dst[j] = '\0';

	/* end not found */
	if (src[i] != end)
		return (-1);

        return (0);	
}
