merged kris' changes into mainstream sic - sic - simple irc client
 (HTM) git clone git://git.suckless.org/sic
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 1a4256ef71ddba6c3cbb28861e0321184860653f
 (DIR) parent 9c7027fcbf86f3082bf0609a7784cc6f6cfa87c7
 (HTM) Author: Anselm R Garbe <anselm@garbe.us>
       Date:   Sat, 28 Nov 2009 12:16:35 +0000
       
       merged kris' changes into mainstream sic
       Diffstat:
         M LICENSE                             |       6 +++---
         M config.mk                           |       2 +-
         D kris/Makefile                       |       2 --
         D kris/config.mk                      |       2 --
         D kris/sic.c                          |     215 -------------------------------
         D kris/util.c                         |      86 ------------------------------
         M sic.c                               |     308 +++++++++++++------------------
         A util.c                              |      81 ++++++++++++++++++++++++++++++
       
       8 files changed, 218 insertions(+), 484 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       @@ -1,8 +1,8 @@
        MIT/X Consortium License
        
       -
       -© 2005-2009 Anselm R Garbe <garbeam at gmail dot com>
       -© 2008-2009 Jeroen Schot <schot at a-eskwadraat dot nl>
       +© 2005-2009 Anselm R Garbe <anselm@garbe.us>
       +© 2008-2009 Jeroen Schot <schot@a-eskwadraat.nl>
       +© 2007-2009 Kris Maglione <maglione.k@gmail.com>
        © 2005 Nico Golde <nico at ngolde dot de>
        
        Permission is hereby granted, free of charge, to any person obtaining a
 (DIR) diff --git a/config.mk b/config.mk
       @@ -1,5 +1,5 @@
        # sic version
       -VERSION = 1.0
       +VERSION = 1.1
        
        # Customize below to fit your system
        
 (DIR) diff --git a/kris/Makefile b/kris/Makefile
       @@ -1 +0,0 @@
       -../Makefile
       -\ No newline at end of file
 (DIR) diff --git a/kris/config.mk b/kris/config.mk
       @@ -1 +0,0 @@
       -../config.mk
       -\ No newline at end of file
 (DIR) diff --git a/kris/sic.c b/kris/sic.c
       @@ -1,215 +0,0 @@
       -/* ? 2005-2007 Anselm R. Garbe <garbeam at gmail dot com>
       - * ? 2007 Kris Maglione <fbsdaemon@gmail.com>
       - * ? 2005 Nico Golde <nico at ngolde dot de>
       - * See LICENSE file for license details.
       - */
       -#include <ctype.h>
       -#include <errno.h>
       -#include <stdarg.h>
       -#include <stdio.h>
       -#include <stdlib.h>
       -#include <string.h>
       -#include <time.h>
       -#include <unistd.h>
       -
       -#define nil ((void*)0)
       -typedef unsigned short ushort;
       -
       -#define PINGTIMEOUT 300
       -
       -static char*        host = "irc.oftc.net";
       -static char*        port = "ircd";
       -static char*        password;
       -static char        nick[32];
       -
       -static char bufin[4096];
       -static char bufout[4096];
       -static char channel[256];
       -static time_t trespond;
       -static FILE *srv;
       -
       -#include "util.c"
       -
       -static void
       -pout(char *channel, char *fmt, ...) {
       -        static char timestr[18];
       -        time_t t;
       -
       -        va_buf(bufout, fmt);
       -
       -        t = time(nil);
       -        strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
       -        fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout);
       -}
       -
       -static void
       -sout(char *fmt, ...) {
       -        va_buf(bufout, fmt);
       -        fprintf(srv, "%s\r\n", bufout);
       -}
       -
       -static void
       -privmsg(char *channel, char *msg) {
       -        if(channel[0] == '\0') {
       -                pout("", "No channel to send to");
       -                return;
       -        }
       -        pout(channel, "<%s> %s", nick, msg);
       -        sout("PRIVMSG %s :%s", channel, msg);
       -}
       -
       -static void
       -parsein(char *msg) {
       -        char *p;
       -        char c;
       -
       -        if(msg[0] == '\0')
       -                return;
       -        msg = ctok(&msg, '\n');
       -        if(msg[0] != ':') {
       -                privmsg(channel, msg);
       -                return;
       -        }
       -        c = *++msg;
       -        if(!c || !isspace(msg[1]))
       -                sout("%s", msg);
       -        else {
       -                if(msg[1])
       -                        msg += 2;
       -                switch(c) {
       -                case 'j':
       -                        sout("JOIN %s", msg);
       -                        if(channel[0] == '\0')
       -                                strlcpy(channel, msg, sizeof channel);
       -                        break;
       -                case 'l':
       -                        p = tok(&msg);
       -                        if(!*p)
       -                                p = channel;
       -                        if(!*msg)
       -                                msg = "sic - 250 LOC are too much!";
       -                        sout("PART %s :%s", p, msg);
       -                        break;
       -                case 'm':
       -                        p = tok(&msg);
       -                        privmsg(p, msg);
       -                        break;
       -                case 's':
       -                        strlcpy(channel, msg, sizeof channel);
       -                        break;
       -                default:
       -                        sout("%c %s", c, msg);
       -                        break;
       -                }
       -        }
       -}
       -
       -static void
       -parsesrv(char *msg) {
       -        char *cmd, *p, *usr, *txt;
       -
       -        usr = host;
       -        if(!msg || !*msg)
       -                return;
       -        if(msg[0] == ':') {
       -                msg++;
       -                p = tok(&msg);
       -                if(!*msg)
       -                        return;
       -                usr = ctok(&p, '!');
       -        }
       -        txt = ctok(&msg, '\r');
       -        msg = ctok(&txt, ':');
       -        cmd = tok(&msg);
       -        if(!strcmp("PONG", cmd))
       -                return;
       -        if(!strcmp("PRIVMSG", cmd))
       -                pout(msg, "<%s> %s", usr, txt);
       -        else if(!strcmp("PING", cmd))
       -                sout("PONG %s", txt);
       -        else {
       -                pout(usr, ">< %s: %s", cmd, txt);
       -                if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
       -                        strlcpy(nick, txt, sizeof nick);
       -        }
       -}
       -
       -int
       -main(int argc, char *argv[]) {
       -        int i, c;
       -        struct timeval tv;
       -        fd_set rd;
       -
       -        strlcpy(nick, getenv("USER"), sizeof nick);
       -        for(i = 1; i < argc; i++) {
       -                c = argv[i][1];
       -                if(argv[i][0] != '-' || argv[i][2])
       -                        c = -1;
       -                switch(c) {
       -                case 'h':
       -                        if(++i < argc) host = argv[i];
       -                        break;
       -                case 'p':
       -                        if(++i < argc) port = argv[i];
       -                        break;
       -                case 'n':
       -                        if(++i < argc) strlcpy(nick, argv[i], sizeof nick);
       -                        break;
       -                case 'k':
       -                        if(++i < argc) password = argv[i];
       -                        break;
       -                case 'v':
       -                        eprint("sic-"VERSION", ©2005-2009 Kris Maglione, Anselm R. Garbe, Nico Golde\n");
       -                default:
       -                        eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
       -                }
       -        }
       -
       -        /* init */
       -        i = dial(host, port);
       -        srv = fdopen(i, "r+");
       -
       -        /* login */
       -        if(password)
       -                sout("PASS %s", password);
       -        sout("NICK %s", nick);
       -        sout("USER %s localhost %s :%s", nick, host, nick);
       -        fflush(srv);
       -
       -        setbuf(stdout, nil);
       -        setbuf(srv, nil);
       -
       -        for(;;) { /* main loop */
       -                FD_ZERO(&rd);
       -                FD_SET(0, &rd);
       -                FD_SET(fileno(srv), &rd);
       -                tv.tv_sec = 120;
       -                tv.tv_usec = 0;
       -                i = select(fileno(srv) + 1, &rd, 0, 0, &tv);
       -                if(i < 0) {
       -                        if(errno == EINTR)
       -                                continue;
       -                        eprint("sic: error on select():");
       -                }
       -                else if(i == 0) {
       -                        if(time(nil) - trespond >= PINGTIMEOUT)
       -                                eprint("sic shutting down: parse timeout\n");
       -                        sout("PING %s", host);
       -                        continue;
       -                }
       -                if(FD_ISSET(fileno(srv), &rd)) {
       -                        if(fgets(bufin, sizeof bufin, srv) == nil)
       -                                eprint("sic: remote host closed connection\n");
       -                        parsesrv(bufin);
       -                        trespond = time(nil);
       -                }
       -                if(FD_ISSET(0, &rd)) {
       -                        if(fgets(bufin, sizeof bufin, stdin) == nil)
       -                                eprint("sic: broken pipe\n");
       -                        parsein(bufin);
       -                }
       -        }
       -        return 0;
       -}
       -
       -
 (DIR) diff --git a/kris/util.c b/kris/util.c
       @@ -1,86 +0,0 @@
       -#include <netdb.h>
       -#include <netinet/in.h>
       -#include <sys/socket.h>
       -
       -#define va_buf(buf, fmt) {\
       -        va_list ap; \
       -        va_start(ap, fmt); \
       -        vsnprintf(buf, sizeof buf, fmt, ap); \
       -        va_end(ap); \
       -}
       -
       -static void
       -eprint(const char *fmt, ...) {
       -
       -        va_buf(bufout, fmt);
       -        fprintf(stderr, "%s", bufout);
       -
       -        if(fmt[0] && fmt[strlen(fmt)-1] == ':')
       -                fprintf(stderr, " %s\n", strerror(errno));
       -        exit(1);
       -}
       -
       -static int
       -dial(char *host, char *port) {
       -        static struct addrinfo hints;
       -        struct addrinfo *res, *r;
       -        int srv;
       -
       -        memset(&hints, 0, sizeof hints);
       -        hints.ai_family = AF_UNSPEC;
       -        hints.ai_socktype = SOCK_STREAM;
       -        if(getaddrinfo(host, port, &hints, &res) != 0)
       -                eprint("error: cannot resolve hostname '%s':", host);
       -        for(r = res; r; r = r->ai_next) {
       -                if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
       -                        continue;
       -                if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
       -                        break;
       -                close(srv);
       -        }
       -        freeaddrinfo(res);
       -        if(!r)
       -                eprint("error: cannot connect to host '%s'\n", host);
       -        return srv;
       -}
       -
       -#define strlcpy _strlcpy
       -static void
       -strlcpy(char *to, const char *from, int l) {
       -        memccpy(to, from, '\0', l);
       -        to[l-1] = '\0';
       -}
       -
       -static void
       -eat(char **s, int (*p)(int), int r) {
       -        char *q;
       -
       -        for(q=*s; *q && p(*q) == r; q++)
       -                ;
       -        *s = q;
       -}
       -
       -static char*
       -tok(char **s) {
       -        char *p;
       -
       -        eat(s, isspace, 1);
       -        p = *s;
       -        eat(s, isspace, 0);
       -        if(**s) *(*s)++ = '\0';
       -        return p;
       -}
       -
       -static char*
       -ctok(char **s, int c) {
       -        char *p, *q;
       -
       -        q = *s;
       -        for(p=q; *p && *p != c; p++)
       -                ;
       -        if(*p) *p++ = '\0';
       -        *s = p;
       -        return q;
       -}
       -
       -
 (DIR) diff --git a/sic.c b/sic.c
       @@ -1,246 +1,204 @@
       -/* See LICENSE file for license details. */
       + /* See LICENSE file for license details. */
       +#include <ctype.h>
        #include <errno.h>
       -#include <netdb.h>
       -#include <netinet/in.h>
        #include <stdarg.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <time.h>
        #include <unistd.h>
       -#include <sys/socket.h>
       -#include <sys/time.h>
        
       -#define PINGTIMEOUT 300
       -#define MAXMSG      4096
       -#ifndef VERSION
       -#define VERSION "dev"
       -#endif
       -
       -static void die(const char *errstr, ...);
       -static void printl(char *channel, char *msg);
       -static void privmsg(char *channel, char *msg);
       -static void parsein(char *msg);
       -static void parsesrv(char *msg);
       -static int readl(int fd, unsigned int len, char *buf);
       -
       -static char *host = "irc6.oftc.net";
       -static char *port = "6667";
       +static char *host = "irc.oftc.net";
       +static char *port = "ircd";
       +static char *password;
        static char nick[32];
       -
       -static char bufin[MAXMSG], bufout[MAXMSG];
       +static char bufin[4096];
       +static char bufout[4096];
        static char channel[256];
       -static int srv;
        static time_t trespond;
       +static FILE *srv;
       +
       +#include "util.c"
        
       -void
       -die(const char *errstr, ...) {
       +static void
       +pout(char *channel, char *fmt, ...) {
       +        static char timestr[18];
       +        time_t t;
                va_list ap;
       -        va_start(ap, errstr);
       -        vfprintf(stderr, errstr, ap);
       +
       +        va_start(ap, fmt);
       +        vsnprintf(bufout, sizeof bufout, fmt, ap);
                va_end(ap);
       -        exit(EXIT_FAILURE);
       +        t = time(NULL);
       +        strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
       +        fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout);
        }
        
       -void
       -printl(char *channel, char *msg) {
       -        static char timestr[18];
       -        time_t t = time(0);
       -        strftime(timestr, sizeof timestr, "%D %R", localtime(&t));
       -        fprintf(stdout, "%-12.12s: %s %s\n", channel, timestr, msg);
       +static void
       +sout(char *fmt, ...) {
       +        va_list ap;
       +
       +        va_start(ap, fmt);
       +        vsnprintf(bufout, sizeof bufout, fmt, ap);
       +        va_end(ap);
       +        fprintf(srv, "%s\r\n", bufout);
       +        fprintf(stderr, "debug: %s\n", bufout);
        }
        
       -void
       +static void
        privmsg(char *channel, char *msg) {
       -        if(channel[0] == '\0')
       +        if(channel[0] == '\0') {
       +                pout("", "No channel to send to");
                        return;
       -        snprintf(bufout, sizeof bufout, "<%s> %s", nick, msg);
       -        printl(channel, bufout);
       -        snprintf(bufout, sizeof bufout, "PRIVMSG %s :%s\r\n", channel, msg);
       -        write(srv, bufout, strlen(bufout));
       +        }
       +        pout(channel, "<%s> %s", nick, msg);
       +        sout("PRIVMSG %s :%s", channel, msg);
        }
        
       -void
       +static void
        parsein(char *msg) {
       -        char *p = NULL;
       +        char *p;
       +        char c;
       +
                if(msg[0] == '\0')
                        return;
       +        msg = ctok(&msg, '\n');
                if(msg[0] != ':') {
                        privmsg(channel, msg);
                        return;
                }
       -        if(strncmp(msg + 1, "j ", 2) == 0 && (msg[3] == '#'))
       -                snprintf(bufout, sizeof bufout, "JOIN %s\r\n", msg + 3);
       -        else if(strncmp(msg + 1, "l ", 2) == 0)
       -                snprintf(bufout, sizeof bufout, "PART %s :sic - 250 LOC are too much!\r\n", msg + 3);
       -        else if(strncmp(msg + 1, "m ", 2) == 0 && (p = strchr(msg + 3, ' '))) {
       -                *(p++) = '\0';
       -                privmsg(msg + 3, p);
       -                return;
       -        }
       -        else if(strncmp(msg + 1, "s ", 2) == 0) {
       -                strncpy(channel, msg + 3, sizeof channel - 1);
       -                return;
       +        c = *++msg;
       +        if(!c || !isspace(msg[1]))
       +                sout("%s", msg);
       +        else {
       +                if(msg[1])
       +                        msg += 2;
       +                switch(c) {
       +                case 'j':
       +                        sout("JOIN %s", msg);
       +                        if(channel[0] == '\0')
       +                                strlcpy(channel, msg, sizeof channel);
       +                        break;
       +                case 'l':
       +                        p = tok(&msg);
       +                        if(!*p)
       +                                p = channel;
       +                        if(!*msg)
       +                                msg = "sic - 250 LOC are too much!";
       +                        sout("PART %s :%s", p, msg);
       +                        break;
       +                case 'm':
       +                        p = tok(&msg);
       +                        privmsg(p, msg);
       +                        break;
       +                case 's':
       +                        strlcpy(channel, msg, sizeof channel);
       +                        break;
       +                default:
       +                        sout("%c %s", c, msg);
       +                        break;
       +                }
                }
       -        else
       -                snprintf(bufout, sizeof bufout, "%s\r\n", msg + 1);
       -        write(srv, bufout, strlen(bufout));
        }
        
       -void
       +static void
        parsesrv(char *msg) {
       -        char *chan, *cmd, *p, *txt, *usr; 
       +        char *cmd, *p, *usr, *txt;
        
       -        txt = NULL;
                usr = host;
       -        if(msg == NULL || *msg == '\0' )
       +        if(!msg || !*msg)
                        return;
       -        if(msg[0] != ':')
       -                cmd = msg;
       -        else {
       -                if(!(p = strchr(msg, ' ')))
       +        if(msg[0] == ':') {
       +                msg++;
       +                p = tok(&msg);
       +                if(!*msg)
                                return;
       -                *p = '\0';
       -                usr = msg + 1;
       -                cmd = ++p;
       -                if((p = strchr(usr, '!')))
       -                        *p = '\0';
       +                usr = ctok(&p, '!');
                }
       -        for(p = cmd; *p != '\0'; p++) /* remove CRLFs */
       -                if(*p == '\r' || *p == '\n')
       -                        *p = '\0';
       -        if((p = strchr(cmd, ':'))) {
       -                *p = '\0';
       -                txt = ++p;
       -        }
       -        if(strncmp("PONG", cmd, 4) == 0)
       +        txt = ctok(&msg, '\r');
       +        msg = ctok(&txt, ':');
       +        cmd = tok(&msg);
       +        if(!strcmp("PONG", cmd))
                        return;
       -        if(strncmp("PRIVMSG", cmd, 7) == 0 && txt != NULL) {
       -                if(!(p = strchr(cmd, ' ')))
       -                        return;
       -                *p = '\0';
       -                chan = ++p;
       -                for(; *p != '\0' && *p != ' '; p++);
       -                *p = '\0';
       -                snprintf(bufout, sizeof bufout, "<%s> %s", usr, txt);
       -                printl(chan, bufout);
       -        }
       -        else if(strncmp("PING", cmd, 4) == 0 && txt != NULL) {
       -                snprintf(bufout, sizeof bufout, "PONG %s\r\n", txt);
       -                write(srv, bufout, strlen(bufout));
       -        }
       +        if(!strcmp("PRIVMSG", cmd))
       +                pout(msg, "<%s> %s", usr, txt);
       +        else if(!strcmp("PING", cmd))
       +                sout("PONG %s", txt);
                else {
       -                if (txt != NULL)
       -                        (void) snprintf(bufout, sizeof bufout, ">< %s: %s", cmd, txt);
       -                else
       -                        (void) snprintf(bufout, sizeof bufout, ">< %s: ", cmd);
       -                printl(usr, bufout);
       -                if(strncmp("NICK", cmd, 4) == 0 && strncmp(usr, nick, sizeof nick) == 0 && txt != NULL)
       -                        strncpy(nick, txt, sizeof nick - 1);
       +                pout(usr, ">< %s: %s", cmd, txt);
       +                if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
       +                        strlcpy(nick, txt, sizeof nick);
                }
        }
        
        int
       -readl(int fd, unsigned int len, char *buf) {
       -        unsigned int i = 0;
       -        char c = '\0';
       -
       -        do {
       -                if(read(fd, &c, sizeof(char)) != (ssize_t) sizeof(char))
       -                        return -1;
       -                buf[i++] = c;
       -        }
       -        while(c != '\n' && i < len);
       -        buf[i - 1] = '\0';
       -        return 0;
       -}
       -
       -
       -int
       -main(const int argc, char *const argv[]) {
       -        int i;
       +main(int argc, char *argv[]) {
       +        int i, c;
                struct timeval tv;
       -        static struct addrinfo hints, *res, *r;
       -        char ping[256];
                fd_set rd;
       -        char *password = NULL;
        
       -        strncpy(nick, getenv("USER"), sizeof nick - 1);
       -        for(i = 1; i < argc; i++)
       -                if(strcmp(argv[i], "-h") == 0) {
       +        strlcpy(nick, getenv("USER"), sizeof nick);
       +        for(i = 1; i < argc; i++) {
       +                c = argv[i][1];
       +                if(argv[i][0] != '-' || argv[i][2])
       +                        c = -1;
       +                switch(c) {
       +                case 'h':
                                if(++i < argc) host = argv[i];
       -                }
       -                else if(strcmp(argv[i], "-p") == 0) {
       +                        break;
       +                case 'p':
                                if(++i < argc) port = argv[i];
       -                }
       -                else if(strcmp(argv[i], "-n") == 0) {
       -                        if(++i < argc) strncpy(nick, argv[i], sizeof nick - 1);
       -                }
       -                else if(strcmp(argv[i], "-k") == 0) {
       +                        break;
       +                case 'n':
       +                        if(++i < argc) strlcpy(nick, argv[i], sizeof nick);
       +                        break;
       +                case 'k':
                                if(++i < argc) password = argv[i];
       -                }
       -                else if(strcmp(argv[i], "-v") == 0)
       -                        die("sic-%s, © 2005-2009 sic engineers\n", VERSION);
       -                else
       -                        die("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
       -
       -        /* init */
       -        memset(&hints, 0, sizeof hints);
       -        hints.ai_family = AF_UNSPEC;
       -        hints.ai_socktype = SOCK_STREAM;
       -        if(getaddrinfo(host, port, &hints, &res) != 0)
       -                die("error: cannot resolve hostname '%s'\n", host);
       -        for(r = res; r; r = r->ai_next) {
       -                if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
       -                        continue;
       -                if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
                                break;
       -                close(srv);
       +                case 'v':
       +                        eprint("sic-"VERSION", © 2005-2009 Kris Maglione, Anselm R. Garbe, Nico Golde\n");
       +                default:
       +                        eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
       +                }
                }
       -        freeaddrinfo(res);
       -        if(!r)
       -                die("error: cannot connect to host '%s'\n", host);
       -
       +        /* init */
       +        i = dial(host, port);
       +        srv = fdopen(i, "r+");
                /* login */
       -        if (password)
       -                snprintf(bufout, sizeof bufout,
       -                        "PASS %s\r\nNICK %s\r\nUSER %s localhost %s :%s\r\n",
       -                        password, nick, nick, host, nick);
       -        else
       -                snprintf(bufout, sizeof bufout, "NICK %s\r\nUSER %s localhost %s :%s\r\n",
       -                         nick, nick, host, nick);
       -        write(srv, bufout, strlen(bufout));
       -        snprintf(ping, sizeof ping, "PING %s\r\n", host);
       -        channel[0] = '\0';
       -        setbuf(stdout, NULL); /* unbuffered stdout */
       -
       +        if(password)
       +                sout("PASS %s", password);
       +        sout("NICK %s", nick);
       +        sout("USER %s localhost %s :%s", nick, host, nick);
       +        fflush(srv);
       +        setbuf(stdout, NULL);
       +        setbuf(srv, NULL);
                for(;;) { /* main loop */
                        FD_ZERO(&rd);
                        FD_SET(0, &rd);
       -                FD_SET(srv, &rd);
       +                FD_SET(fileno(srv), &rd);
                        tv.tv_sec = 120;
                        tv.tv_usec = 0;
       -                i = select(srv + 1, &rd, 0, 0, &tv);
       +                i = select(fileno(srv) + 1, &rd, 0, 0, &tv);
                        if(i < 0) {
                                if(errno == EINTR)
                                        continue;
       -                        die("error: error on select()\n");
       +                        eprint("sic: error on select():");
                        }
                        else if(i == 0) {
       -                        if(time(NULL) - trespond >= PINGTIMEOUT)
       -                                die("error: sic shutting down: parse timeout\n");
       -                        write(srv, ping, strlen(ping));
       +                        if(time(NULL) - trespond >= 300)
       +                                eprint("sic shutting down: parse timeout\n");
       +                        sout("PING %s", host);
                                continue;
                        }
       -                if(FD_ISSET(srv, &rd) != 0) {
       -                        if(readl(srv, sizeof bufin, bufin) == -1)
       -                                die("error: remote host closed connection\n");
       +                if(FD_ISSET(fileno(srv), &rd)) {
       +                        if(fgets(bufin, sizeof bufin, srv) == NULL)
       +                                eprint("sic: remote host closed connection\n");
                                parsesrv(bufin);
                                trespond = time(NULL);
                        }
       -                if(FD_ISSET(0, &rd) != 0) {
       -                        if(readl(0, sizeof bufin, bufin) == -1)
       -                                die("error: broken pipe\n");
       +                if(FD_ISSET(0, &rd)) {
       +                        if(fgets(bufin, sizeof bufin, stdin) == NULL)
       +                                eprint("sic: broken pipe\n");
                                parsein(bufin);
                        }
                }
 (DIR) diff --git a/util.c b/util.c
       @@ -0,0 +1,81 @@
       +/* See LICENSE file for license details. */
       +#include <netdb.h>
       +#include <netinet/in.h>
       +#include <sys/socket.h>
       +
       +static void
       +eprint(const char *fmt, ...) {
       +        va_list ap;
       +
       +        va_start(ap, fmt);
       +        vsnprintf(bufout, sizeof bufout, fmt, ap);
       +        va_end(ap);
       +        fprintf(stderr, "%s", bufout);
       +        if(fmt[0] && fmt[strlen(fmt) - 1] == ':')
       +                fprintf(stderr, " %s\n", strerror(errno));
       +        exit(1);
       +}
       +
       +static int
       +dial(char *host, char *port) {
       +        static struct addrinfo hints;
       +        int srv;
       +        struct addrinfo *res, *r;
       +
       +        memset(&hints, 0, sizeof hints);
       +        hints.ai_family = AF_UNSPEC;
       +        hints.ai_socktype = SOCK_STREAM;
       +        if(getaddrinfo(host, port, &hints, &res) != 0)
       +                eprint("error: cannot resolve hostname '%s':", host);
       +        for(r = res; r; r = r->ai_next) {
       +                if((srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1)
       +                        continue;
       +                if(connect(srv, r->ai_addr, r->ai_addrlen) == 0)
       +                        break;
       +                close(srv);
       +        }
       +        freeaddrinfo(res);
       +        if(!r)
       +                eprint("error: cannot connect to host '%s'\n", host);
       +        return srv;
       +}
       +
       +#define strlcpy _strlcpy
       +static void
       +strlcpy(char *to, const char *from, int l) {
       +        memccpy(to, from, '\0', l);
       +        to[l-1] = '\0';
       +}
       +
       +static void
       +eat(char **s, int (*p)(int), int r) {
       +        char *q;
       +
       +        for(q = *s; *q && p(*q) == r; q++)
       +                ;
       +        *s = q;
       +}
       +
       +static char*
       +tok(char **s) {
       +        char *p;
       +
       +        eat(s, isspace, 1);
       +        p = *s;
       +        eat(s, isspace, 0);
       +        if(**s)
       +                *(*s)++ = '\0';
       +        return p;
       +}
       +
       +static char*
       +ctok(char **s, int c) {
       +        char *p, *q;
       +
       +        q = *s;
       +        for(p = q; *p && *p != c; p++)
       +                ;
       +        if(*p) *p++ = '\0';
       +        *s = p;
       +        return q;
       +}