/* $Id$ */
#include "bbs.h"
#include "fnv_hash.h"

/* ----------------------------------------------------- */
/* set file path for boards/user home                    */
/* ----------------------------------------------------- */
static const char * const str_home_file = "home/%c/%s/%s";
static const char * const str_board_file = "boards/%c/%s/%s";
static const char * const str_board_n_file = "boards/%c/%s/%s.%d";

static char cdate_buffer[32];

#define STR_DOTDIR  ".DIR"
static const char * const str_dotdir = STR_DOTDIR;

void
sethomepath(char *buf, const char *userid)
{
    sprintf(buf, "home/%c/%s", userid[0], userid);
}

void
sethomedir(char *buf, const char *userid)
{
    sprintf(buf, str_home_file, userid[0], userid, str_dotdir);
}

void
sethomeman(char *buf, const char *userid)
{
    sprintf(buf, str_home_file, userid[0], userid, "man");
}


void
sethomefile(char *buf, const char *userid, const char *fname)
{
    sprintf(buf, str_home_file, userid[0], userid, fname);
}

void
setuserfile(char *buf, const char *fname)
{
    sprintf(buf, str_home_file, cuser.userid[0], cuser.userid, fname);
}

void
setapath(char *buf, const char *boardname)
{
    sprintf(buf, "man/boards/%c/%s", boardname[0], boardname);
}

void
setadir(char *buf, const char *path)
{
    sprintf(buf, "%s/%s", path, str_dotdir);
}

void
setbpath(char *buf, const char *boardname)
{
    sprintf(buf, "boards/%c/%s", boardname[0], boardname);
}

void
setbdir(char *buf, const char *boardname)
{
    sprintf(buf, str_board_file, boardname[0], boardname,
	    (currmode & MODE_DIGEST ? fn_mandex : str_dotdir));
}

void
setbfile(char *buf, const char *boardname, const char *fname)
{
    sprintf(buf, str_board_file, boardname[0], boardname, fname);
}

void
setbnfile(char *buf, const char *boardname, const char *fname, int n)
{
    sprintf(buf, str_board_n_file, boardname[0], boardname, fname, n);
}

/*
 * input	direct
 * output	buf: copy direct
 * 		fname: direct ���ɦW����
 */
void
setdirpath(char *buf, const char *direct, const char *fname)
{
    char *p;
    strcpy(buf, direct);
    p = strrchr(buf, '/');
    assert(p);
    strcpy(p + 1, fname);
}

/**
 * ���w�峹���D title�A�Ǧ^����D�D�����������СC
 * @param title
 */
char           *
subject(char *title)
{
    if (!strncasecmp(title, str_reply, 3)) {
	title += 3;
	if (*title == ' ')
	    title++;
    }
    return title;
}

/* ----------------------------------------------------- */
/* �r���ഫ�ˬd���                                      */
/* ----------------------------------------------------- */
int
str_checksum(const char *str)
{
    int             n = 1;
    if (strlen(str) < 6)
	return 0;
    while (*str)
	n += *(str++) * (n);
    return n;
}

/**
 * �N�r�� s �ର�p�g�s�^ t
 * @param t allocated char array
 * @param s
 */
void
str_lower(char *t, const char *s)
{
    register unsigned char ch;

    do {
	ch = *s++;
	*t++ = char_lower(ch);
    } while (ch);
}

/**
 * �����r�� buf ��ݦh�l���ťաC
 * @param buf
 */
void
trim(char *buf)
{				/* remove trailing space */
    char           *p = buf;

    while (*p)
	p++;
    while (--p >= buf) {
	if (*p == ' ')
	    *p = '\0';
	else
	    break;
    }
}

/**
 * ���� src �� '\n' �ç令 '\0'
 * @param src
 */
void chomp(char *src)
{
    while(*src){
	if (*src == '\n')
	    *src = 0;
	else
	    src++;
    }
}

/* ----------------------------------------------------- */
/* �r���ˬd��ơG�^��B�Ʀr�B�ɦW�BE-mail address        */
/* ----------------------------------------------------- */

int
invalid_pname(const char *str)
{
    const char           *p1, *p2, *p3;

    p1 = str;
    while (*p1) {
	if (!(p2 = strchr(p1, '/')))
	    p2 = str + strlen(str);
	if (p1 + 1 > p2 || p1 + strspn(p1, ".") == p2)
	    return 1;
	for (p3 = p1; p3 < p2; p3++)
	    if (not_alnum(*p3) && !strchr("@[]-._", *p3))
		return 1;
	p1 = p2 + (*p2 ? 1 : 0);
    }
    return 0;
}

int
valid_ident(const char *ident)
{
    char    *invalid[] = {"unknown@", "root@", "gopher@", "bbs@",
    "@bbs", "guest@", "@ppp", "@slip", NULL};
    int             i;

    for (i = 0; invalid[i]; i++)
	if (strcasestr(ident, invalid[i]))
	    return 0;
    return 1;
}

int
is_uBM(const char *list, const char *id)
{
    register int    len;

    if (list[0] == '[')
	list++;
    if (list[0] > ' ') {
	len = strlen(id);
	do {
	    if (!strncasecmp(list, id, len)) {
		list += len;
		if ((*list == 0) || (*list == '/') ||
		    (*list == ']') || (*list == ' '))
		    return 1;
	    }
	    if ((list = strchr(list, '/')) != NULL)
		list++;
	    else
		break;
	} while (1);
    }
    return 0;
}

int
is_BM(const char *list)
{
    if (is_uBM(list, cuser.userid)) {
	cuser.userlevel |= PERM_BM;	/* Ptt �۰ʥ[�WBM���v�Q */
	return 1;
    }
    return 0;
}

int
userid_is_BM(const char *userid, const char *list)
{
    register int    ch, len;

    // TODO merge with is_uBM
    ch = list[0];
    if ((ch > ' ') && (ch < 128)) {
	len = strlen(userid);
	do {
	    if (!strncasecmp(list, userid, len)) {
		ch = list[len];
		if ((ch == 0) || (ch == '/') || (ch == ']'))
		    return 1;
	    }
	    while ((ch = *list++)) {
		if (ch == '/')
		    break;
	    }
	} while (ch);
    }
    return 0;
}

/* ----------------------------------------------------- */
/* �ɮ��ˬd��ơG�ɮסB�ؿ��B�ݩ�                        */
/* ----------------------------------------------------- */

/**
 * �Ǧ^ fname ���ɮפj�p
 * @param fname
 */
off_t
dashs(const char *fname)
{
    struct stat     st;

    if (!stat(fname, &st))
	return st.st_size;
    else
	return -1;
}

/**
 * �Ǧ^ fname �� mtime
 * @param fname
 */
time4_t
dasht(const char *fname)
{
    struct stat     st;

    if (!stat(fname, &st))
	return st.st_mtime;
    else
	return -1;
}

/**
 * �Ǧ^ fname �O�_�� symbolic link
 * @param fname
 */
int
dashl(const char *fname)
{
    struct stat     st;

    return (lstat(fname, &st) == 0 && S_ISLNK(st.st_mode));
}

/**
 * �Ǧ^ fname �O�_���@�몺�ɮ�
 * @param fname
 */
int
dashf(const char *fname)
{
    struct stat     st;

    return (stat(fname, &st) == 0 && S_ISREG(st.st_mode));
}

/**
 * �Ǧ^ fname �O�_���ؿ�
 * @param fname
 */
int
dashd(const char *fname)
{
    struct stat     st;

    return (stat(fname, &st) == 0 && S_ISDIR(st.st_mode));
}

#define BUFFER_SIZE	8192
static int copy_file_to_file(const char *src, const char *dst)
{
    char buf[BUFFER_SIZE];
    int fdr, fdw, len;

    if ((fdr = open(src, O_RDONLY)) < 0)
	return -1;

    if ((fdw = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
	close(fdr);
	return -1;
    }

    while (1) {
	len = read(fdr, buf, sizeof(buf));
	if (len <= 0)
	    break;
	write(fdw, buf, len);
	if (len < BUFFER_SIZE)
	    break;
    }

    close(fdr);
    close(fdw);
    return 0;
}
#undef BUFFER_SIZE

static int copy_file_to_dir(const char *src, const char *dst)
{
    char buf[256];
    char *slash;
    if ((slash = rindex(src, '/')) == NULL)
	sprintf(buf, "%s/%s", dst, src);
    else
	sprintf(buf, "%s/%s", dst, slash);
    return copy_file_to_file(src, buf);
}

static int copy_dir_to_dir(const char *src, const char *dst)
{
    DIR *dir;
    struct dirent *entry;
    struct stat st;
    char buf[256], buf2[256];

    if (stat(dst, &st) < 0)
	if (mkdir(dst, 0700) < 0)
	    return -1;

    if ((dir = opendir(src)) == NULL)
	return -1;

    while ((entry = readdir(dir)) != NULL) {
	if (strcmp(entry->d_name, ".") == 0 ||
	    strcmp(entry->d_name, "..") == 0)
	    continue;
	sprintf(buf, "%s/%s", src, entry->d_name);
	sprintf(buf2, "%s/%s", dst, entry->d_name);
	if (stat(buf, &st) < 0)
	    continue;
	if (S_ISDIR(st.st_mode))
	    mkdir(buf2, 0700);
	copy_file(buf, buf2);
    }

    closedir(dir);
    return 0;
}

/**
 * copy src to dst (recursively)
 * @param src and dst are file or dir
 * @return -1 if failed
 */
int copy_file(const char *src, const char *dst)
{
    struct stat st;

    if (stat(dst, &st) == 0 && S_ISDIR(st.st_mode)) {
	if (stat(src, &st) < 0)
	    return -1;
	
    	if (S_ISDIR(st.st_mode))
	    return copy_dir_to_dir(src, dst);
	else if (S_ISREG(st.st_mode))
	    return copy_file_to_dir(src, dst);
	return -1;
    }
    else if (stat(src, &st) == 0 && S_ISDIR(st.st_mode))
	return copy_dir_to_dir(src, dst);
    return copy_file_to_file(src, dst);
}

int
belong(const char *filelist, const char *key)
{
    return file_exist_record(filelist, key);
}

unsigned int
ipstr2int(const char *ip)
{
    unsigned int i, val = 0;
    char buf[32];
    char *nil, *p;

    strlcpy(buf, ip, sizeof(buf));
    p = buf;
    for (i = 0; i < 4; i++) {
	nil = strchr(p, '.');
	if (nil != NULL)
	    *nil = 0;
	val *= 256;
	val += atoi(p);
	if (nil != NULL)
	    p = nil + 1;
    }
    return val;
}

#ifndef _BBS_UTIL_C_ /* getdata_buf */
time4_t
gettime(int line, time4_t dt, const char*head)
{
    char            yn[7];
    int i;
    struct tm      *ptime = localtime4(&dt), endtime;

    memcpy(&endtime, ptime, sizeof(struct tm));
    snprintf(yn, sizeof(yn), "%4d", ptime->tm_year + 1900);
    move(line, 0); outs(head);
    i=strlen(head);
    do {
	getdata_buf(line, i, " �褸�~:", yn, 5, LCECHO);
    } while ((endtime.tm_year = atoi(yn) - 1900) < 0 || endtime.tm_year > 200);
    snprintf(yn, sizeof(yn), "%d", ptime->tm_mon + 1);
    do {
	getdata_buf(line, i+15, "��:", yn, 3, LCECHO);
    } while ((endtime.tm_mon = atoi(yn) - 1) < 0 || endtime.tm_mon > 11);
    snprintf(yn, sizeof(yn), "%d", ptime->tm_mday);
    do {
	getdata_buf(line, i+24, "��:", yn, 3, LCECHO);
    } while ((endtime.tm_mday = atoi(yn)) < 1 || endtime.tm_mday > 31);
    snprintf(yn, sizeof(yn), "%d", ptime->tm_hour);
    do {
	getdata_buf(line, i+33, "��(0-23):", yn, 3, LCECHO);
    } while ((endtime.tm_hour = atoi(yn)) < 0 || endtime.tm_hour > 23);
    return mktime(&endtime);
}
#endif

char           *
Cdate(const time4_t *clock)
{
    time_t          temp = (time_t)*clock;
    struct tm      *mytm = localtime(&temp);

    strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y %T %a", mytm);
    return cdate_buffer;
}

char           *
Cdatelite(const time4_t *clock)
{
    time_t          temp = (time_t)*clock;
    struct tm      *mytm = localtime(&temp);

    strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y %T", mytm);
    return cdate_buffer;
}

char           *
Cdatedate(const time4_t * clock)
{
    time_t          temp = (time_t)*clock;
    struct tm      *mytm = localtime(&temp);

    strftime(cdate_buffer, sizeof(cdate_buffer), "%m/%d/%Y", mytm);
    return cdate_buffer;
}

#ifndef _BBS_UTIL_C_
/* �o�@�ϳ��O������e���B�z��, �G _BBS_UTIL_C_ �����n */
static void
capture_screen(void)
{
    char            fname[200];
    FILE           *fp;
    int             i;

    getdata(b_lines - 2, 0, "��o�ӵe�����J��Ȧs�ɡH[y/N] ",
	    fname, 4, LCECHO);
    if (fname[0] != 'y')
	return;

    setuserfile(fname, ask_tmpbuf(b_lines - 1));
    if ((fp = fopen(fname, "w"))) {
	for (i = 0; i < scr_lns; i++)
	    fprintf(fp, "%.*s\n", big_picture[i].len, big_picture[i].data);
	fclose(fp);
    }
}

int
vmsg_lines(const int lines, const char msg[])
{
    int             ch;

    move(lines, 0);
    clrtoeol();

    if (msg)
        outs((char *)msg);
    else
        outs("\033[1;34;44m �e�e�e�e�e�e�e�e�e�e�e�e�e�e�e\033[1;37;44m �Ы� "
"\033[36m���N�� \033[37m�~�� \033[1;34m�e�e�e�e�e\033[36m^T �����Ȧs��\033[34m�e�e�e \033[m");

    do {
	if( (ch = igetch()) == Ctrl('T') )
	    capture_screen();
    } while( ch == 0 );

    move(lines, 0);
    clrtoeol();
    return ch;
}

#ifdef PLAY_ANGEL
void
pressanykey_or_callangel(){
    int             ch;

    outmsg(
"\033[1;34;44m �e�e�e�e \033[32mH \033[36m�I�s�p�Ѩ�\033[34m �e�e�e�e\033[1;37;44m �Ы� "
"\033[36m���N�� \033[37m�~�� \033[1;34m�e�e�e�e�e\033[36m^T �����Ȧs��\033[34m�e�e�e \033[m");
    do {
	ch = igetch();

	if (ch == Ctrl('T')) {
	    capture_screen();
	    break;
	}else if (ch == 'h' || ch == 'H'){
	    CallAngel();
	    break;
	}
    } while ((ch != ' ') && (ch != KEY_LEFT) && (ch != '\r') && (ch != '\n'));
    move(b_lines, 0);
    clrtoeol();
    refresh();
}
#endif

/**
 * �� printf format ���ѼơA�L��̩��U�@��C
 * �Ǧ^�ϥΪ̪����(char)�C
 */
char
getans(const char *fmt,...)
{
    char   msg[256];
    char   ans[5];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(msg , 128, fmt, ap);
    va_end(ap);

    getdata(b_lines, 0, msg, ans, sizeof(ans), LCECHO);
    return ans[0];
}

int
getkey(const char *fmt,...)
{
    char   msg[256], i;
    va_list ap;
    va_start(ap, fmt);
    i = vsnprintf(msg , 128, fmt, ap);
    va_end(ap);
    return vmsg_lines(b_lines, msg);
}

/* TODO ���� caller �Ψ� format, �Ҽ{��}�� vmsgf �`�� cpu */
int
vmsg(const char *fmt,...)
{
    char   msg[256] = "\033[1;36;44m �� ";
    int i=14; // 14=strlen(msg)
    va_list ap;
    va_start(ap, fmt);
    i += vsnprintf(msg + i, 128, fmt, ap);
    va_end(ap);
    for(; i < 71; i++)
	msg[i] = ' ';
    strcat(msg + 71,
	   "\033[33;46m \033[200m\033[1431m\033[506m[�����N���~��]\033[201m \033[m");
    return vmsg_lines(b_lines, msg);
}

/**
 * �q�� y �C�}�l show �X filename �ɮפ����e lines ��C
 * mode �� output ���Ҧ��A�ѼƦP strip_ansi�C
 * @param filename
 * @param x
 * @param lines
 * @param mode
 * @return ���ѶǦ^ 0�A�_�h�� 1�C
 */
int
show_file(const char *filename, int y, int lines, int mode)
{
    FILE           *fp;
    char            buf[256];

    if (y >= 0)
	move(y, 0);
    clrtoline(lines + y);
    if ((fp = fopen(filename, "r"))) {
	while (fgets(buf, sizeof(buf), fp) && lines--)
	    outs(Ptt_prints(buf, mode));
	fclose(fp);
    } else
	return 0;
    return 1;
}

void
bell(void)
{
    char            c;

    c = Ctrl('G');
    write(1, &c, 1);
}

int
search_num(int ch, int max)
{
    int             clen = 1;
    int             x, y;
    char            genbuf[10];

    outmsg("\033[7m ���ܲĴX���G\033[m");
    outc(ch);
    genbuf[0] = ch;
    getyx(&y, &x);
    x--;
    while ((ch = igetch()) != '\r') {
	if (ch == 'q' || ch == 'e')
	    return -1;
	if (ch == '\n')
	    break;
	if (ch == '\177' || ch == Ctrl('H')) {
	    if (clen == 0) {
		bell();
		continue;
	    }
	    clen--;
	    move(y, x + clen);
	    outc(' ');
	    move(y, x + clen);
	    continue;
	}
	if (!isdigit(ch)) {
	    bell();
	    continue;
	}
	if (x + clen >= scr_cols || clen >= 6) {
	    bell();
	    continue;
	}
	genbuf[clen++] = ch;
	outc(ch);
    }
    genbuf[clen] = '\0';
    move(b_lines, 0);
    clrtoeol();
    if (genbuf[0] == '\0')
	return -1;
    clen = atoi(genbuf);
    if (clen == 0)
	return 0;
    if (clen > max)
	return max;
    return clen - 1;
}

/**
 * �b�������W�� show �X "�ititle�j"
 * @param title
 */
void
stand_title(const char *title)
{
    clear();
    prints("\033[1;37;46m�i %s �j\033[m\n", title);
}

void
cursor_show(int row, int column)
{
    move(row, column);
    outs(STR_CURSOR);
    move(row, column + 1);
}

void
cursor_clear(int row, int column)
{
    move(row, column);
    outs(STR_UNCUR);
}

int
cursor_key(int row, int column)
{
    int             ch;

    cursor_show(row, column);
    ch = igetch();
    move(row, column);
    outs(STR_UNCUR);
    return ch;
}

void
printdash(const char *mesg)
{
    int             head = 0, tail;

    if (mesg)
	head = (strlen(mesg) + 1) >> 1;

    tail = head;

    while (head++ < 38)
	outc('-');

    if (tail) {
	outc(' ');
	outs(mesg);
	outc(' ');
    }
    while (tail++ < 38)
	outc('-');
    outc('\n');
}

int
log_user(const char *fmt, ...)
{
    char msg[256], filename[256];
    va_list ap;

    va_start(ap, fmt);
    vsnprintf(msg , 128, fmt, ap);
    va_end(ap);

    sethomefile(filename, cuser.userid, "USERLOG");
    return log_file(filename, LOG_CREAT | LOG_VF,
		    "%s: %s %s", cuser.userid, msg,  Cdate(&now));
}

int
log_file(const char *fn, int flag, const char *fmt,...)
{
    int        fd;
    char       msg[256];
    const char *realmsg;
    if( !(flag & LOG_VF) ){
	realmsg = fmt;
    }
    else{
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(msg , 128, fmt, ap);
	va_end(ap);
	realmsg = msg;
    }

    if( (fd = open(fn, O_APPEND | O_WRONLY | ((flag & LOG_CREAT)? O_CREAT : 0),
		   ((flag & LOG_CREAT) ? 0664 : 0))) < 0 )
	return -1;
    if( write(fd, realmsg, strlen(realmsg)) < 0 ){
	close(fd);
	return -1;
    }
    close(fd);
    return 0;
}

void
show_help(const char * const helptext[])
{
    const char     *str;
    int             i;

    clear();
    for (i = 0; (str = helptext[i]); i++) {
	if (*str == '\0')
	    prints("\033[1m�i %s �j\033[0m\n", str + 1);
	else if (*str == '\01')
	    prints("\n\033[36m�i %s �j\033[m\n", str + 1);
	else
	    prints("        %s\n", str);
    }
#ifdef PLAY_ANGEL
    if (HAS_PERM(PERM_LOGINOK))
	pressanykey_or_callangel();
    else
#endif
	pressanykey();
}

void
show_helpfile(const char *helpfile)
{
    clear();
    show_file((char *)helpfile, 0, b_lines, NO_RELOAD);
#ifdef PLAY_ANGEL
    if (HAS_PERM(PERM_LOGINOK))
	pressanykey_or_callangel();
    else
#endif
    pressanykey();
}

#endif // _BBS_UTIL_C_

/* ----------------------------------------------------- */
/* use mmap() to malloc large memory in CRITICAL_MEMORY  */
/* ----------------------------------------------------- */
#ifdef CRITICAL_MEMORY
void *MALLOC(int size)
{
    int     *p;
    p = (int *)mmap(NULL, (size + 4), PROT_READ | PROT_WRITE,
	    MAP_ANON | MAP_PRIVATE, -1, 0);
    p[0] = size;
#if defined(DEBUG) && !defined(_BBS_UTIL_C_)
    vmsg("critical malloc %d bytes", size);
#endif
    return (void *)&p[1];
}

void FREE(void *ptr)
{
    int     size = ((int *)ptr)[-1];
    munmap((void *)(&(((int *)ptr)[-1])), size);
#if defined(DEBUG) && !defined(_BBS_UTIL_C_)
    vmsg("critical free %d bytes", size);
#endif
}
#endif

unsigned
StringHash(const unsigned char *s)
{
    return fnv1a_32_strcase(s, FNV1_32_INIT);
}

inline int *intbsearch(int key, const int *base0, int nmemb)
{
    /* ��� /usr/src/lib/libc/stdlib/bsearch.c ,
       �M���j int array �Ϊ�, ���z�L compar function �G���֨� */
    const   char *base = (const char *)base0;
    size_t  lim;
    int     *p;

    for (lim = nmemb; lim != 0; lim >>= 1) {
	p = (int *)(base + (lim >> 1) * 4);
	if( key == *p )
	    return p;
	if( key > *p ){/* key > p: move right */
	    base = (char *)p + 4;
	    lim--;
	}               /* else move left */
    }
    return (NULL);
}

int qsort_intcompar(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

#ifdef TIMET64
char           *
ctime4(const time4_t *clock)
{
    time_t temp = (time_t)*clock;
    
    return ctime(&temp);
}

struct tm *localtime4(const time4_t *t)
{
    if( t == NULL )
	return localtime(NULL);
    else {
	time_t  temp = (time_t)*t;
	return localtime(&temp);
    }
}

time4_t time4(time4_t *ptr)
{
    if( ptr == NULL )
	return time(NULL);
    else
	return *ptr = (time4_t)time(NULL);
}
#endif

#ifdef OUTTACACHE
int tobind(const char * host, int port)
{
    int     sockfd, val;
    struct  sockaddr_in     servaddr;

    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
	perror("socket()");
	exit(1);
    }
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
	       (char *)&val, sizeof(val));
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    if (!host || host[0] == NULL)
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    else if (inet_aton(host, &servaddr.sin_addr) == 0) {
	perror("inet_aton()");
	exit(1);
    }
    servaddr.sin_port = htons(port);
    if( bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) {
	perror("bind()");
	exit(1);
    }
    if( listen(sockfd, 5) < 0 ) {
	perror("listen()");
	exit(1);
    }

    return sockfd;
}

int toconnect(const char *host, int port)
{
    int    sock;
    struct sockaddr_in serv_name;
    if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
        perror("socket");
        return -1;
    }

    serv_name.sin_family = AF_INET;
    serv_name.sin_addr.s_addr = inet_addr(host);
    serv_name.sin_port = htons(port);
    if( connect(sock, (struct sockaddr*)&serv_name, sizeof(serv_name)) < 0 ){
        close(sock);
        return -1;
    }
    return sock;
}

/**
 * same as read(2), but read until exactly size len 
 */
int toread(int fd, void *buf, int len)
{
    int     l;
    for( l = 0 ; len > 0 ; )
	if( (l = read(fd, buf, len)) <= 0 )
	    return -1;
	else{
	    buf += l;
	    len -= l;
	}
    return l;
}

/**
 * same as write(2), but write until exactly size len 
 */
int towrite(int fd, const void *buf, int len)
{
    int     l;
    for( l = 0 ; len > 0 ; )
	if( (l = write(fd, buf, len)) <= 0 )
	    return -1;
	else{
	    buf += l;
	    len -= l;
	}
    return l;
}
#endif