diff -r a6692d249139 sic.1 --- a/sic.1 Fri Apr 13 11:50:51 2007 +0200 +++ b/sic.1 Fri Aug 10 10:29:01 2007 -0700 @@ -33,7 +33,7 @@ Prints version information to standard o .SH COMMANDS .TP .B :j #channel -Join a channel +Join a channel (sets #channel to default first time used) .TP .B :l #channel Leave a channel @@ -44,4 +44,7 @@ Write a message to #channel/user .B :s #channel/user Set default channel/user .TP -Everything which is not a command is simply send the server. +.B :a alias #channel/user/command +Creates alias to #channel/user/command. If alias is of #channel/user it can be used for all other sic commands. Command is a command that can be sent to the server. +.TP +Everything which starts with a ':' and is not a known sic command or alias is sent to the server. Everything which does not start with a ':' is sent to the default channel. diff -r a6692d249139 sic.c --- a/sic.c Fri Apr 13 11:50:51 2007 +0200 +++ b/sic.c Fri Aug 10 10:29:01 2007 -0700 @@ -1,236 +1,248 @@ -/* © 2005-2007 Anselm R. Garbe - * © 2005 Nico Golde - * See LICENSE file for license details. */ +/* © 2005-2007 Anselm R. Garbe + * © 2007 Kris Maglione + * © 2005 Nico Golde + * See LICENSE file for license details. + */ +#include #include -#include -#include #include #include #include #include #include #include -#include -#include + +#define nil ((void*)0) +typedef unsigned short ushort; #define PINGTIMEOUT 300 -#define MAXMSG 4096 - -static char *host = "irc.oftc.net"; -static unsigned short port = 6667; -static char *password = NULL; -static char nick[32]; - -static char bufin[MAXMSG], bufout[MAXMSG]; + +static char *host = "irc.oftc.net"; +static ushort port = 6667; +static char *password; +static char nick[32]; + +static int num_alias = 0; +static char alias[256][256]; +static char bufin[4096]; +static char bufout[4096]; static char channel[256]; -static int srv; static time_t trespond; - -static void -eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -static int -getline(int fd, unsigned int len, char *buf) { - unsigned int i = 0; - char c; - - do { - if(read(fd, &c, sizeof(char)) != sizeof(char)) - return -1; - buf[i++] = c; - } - while(c != '\n' && i < len); - buf[i - 1] = 0; - return 0; -} - -static void -pout(char *channel, char *msg) { +static FILE *srv; + +#define va_buf(buf, fmt) {\ + va_list ap; \ + \ + va_start(ap, fmt); \ + vsnprintf(buf, sizeof buf, fmt, ap); \ + va_end(ap); \ +} + +#include "util.c" + +static void +pout(char *channel, char *fmt, ...) { static char timestr[18]; - time_t t = time(0); - + time_t t; + + va_buf(bufout, fmt); + + t = time(nil); strftime(timestr, sizeof timestr, "%D %R", localtime(&t)); - fprintf(stdout, "%-12.12s: %s %s\n", channel, timestr, msg); + 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) - return; - snprintf(bufout, sizeof bufout, "<%s> %s", nick, msg); - pout(channel, bufout); - snprintf(bufout, sizeof bufout, "PRIVMSG %s :%s\r\n", channel, msg); - write(srv, bufout, strlen(bufout)); + if(channel[0] == '\0') { + pout("", "No channel to send to"); + return; + } + pout(channel, "<%s> %s", nick, msg); + sout("PRIVMSG %s :%s", channel, msg); +} + +static char * +alias_lookup(char *channel) { + int i; + char *p; + for(i = num_alias; i > -1; i--) { + p = strchr(alias[i], ' '); + if(!strncmp(channel, alias[i], p - alias[i])) + break; + } + return (i > -1) ? p+1 : channel; } static void parsein(char *msg) { char *p; - - if(msg[0] == 0) - return; + char c; + + if(msg[0] == '\0') + return; + msg = ctok(&msg, '\n'); if(msg[0] != ':') { privmsg(channel, msg); return; } - if(!strncmp(msg + 1, "j ", 2) && (msg[3] == '#')) - snprintf(bufout, sizeof bufout, "JOIN %s\r\n", msg + 3); - else if(!strncmp(msg + 1, "l ", 2)) - snprintf(bufout, sizeof bufout, "PART %s :sic - 250 LOC are too much!\r\n", msg + 3); - else if(!strncmp(msg + 1, "m ", 2)) { - if((p = strchr(msg + 3, ' '))) - *(p++) = 0; - privmsg(msg + 3, p); - return; - } - else if(!strncmp(msg + 1, "s ", 2)) { - strncpy(channel, msg + 3, sizeof channel); - return; - } - else - snprintf(bufout, sizeof bufout, "%s\r\n", msg + 1); - write(srv, bufout, strlen(bufout)); + c = *++msg; + if(!c || !isspace(msg[1])) { + p = tok(&msg); + p = alias_lookup(p); + sout("%s %s", p, msg); + } + else { + if(msg[1]) + msg += 2; + switch(c) { + case 'a': + strlcpy(alias[num_alias], msg, sizeof alias[num_alias]); + num_alias++; + break; + case 'j': + msg = alias_lookup(msg); + sout("JOIN %s", msg); + if(channel[0] == '\0') + strlcpy(channel, msg, sizeof channel); + break; + case 'l': + p = tok(&msg); + p = alias_lookup(p); + 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); + p = alias_lookup(p); + privmsg(p, msg); + break; + case 's': + msg = alias_lookup(msg); + strlcpy(channel, msg, sizeof channel); + break; + default: + p = alias_lookup(&c); + sout("%s %s", p, msg); + break; + } + } } static void parsesrv(char *msg) { - char *chan, *cmd, *p, *txt, *usr; - - txt = NULL; + char *cmd, *p, *usr, *txt; + usr = host; - if(!msg || !(*msg)) - return; - if(msg[0] != ':') - cmd = msg; + 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 { - if(!(p = strchr(msg, ' '))) - return; - *p = 0; - usr = msg + 1; - cmd = ++p; - if((p = strchr(usr, '!'))) - *p = 0; - } - for(p = cmd; *p; p++) /* remove CRLFs */ - if(*p == '\r' || *p == '\n') - *p = 0; - if((p = strchr(cmd, ':'))) { - *p = 0; - txt = ++p; - } - if(!strncmp("PONG", cmd, 4)) - return; - if(!strncmp("PRIVMSG", cmd, 7) && txt) { - if(!(p = strchr(cmd, ' '))) - return; - *p = 0; - chan = ++p; - for(; *p && *p != ' '; p++); - *p = 0; - snprintf(bufout, sizeof bufout, "<%s> %s", usr, txt); - pout(chan, bufout); - } - else if(!strncmp("PING", cmd, 4) && txt) { - snprintf(bufout, sizeof bufout, "PONG %s\r\n", txt); - write(srv, bufout, strlen(bufout)); - } - else { - snprintf(bufout, sizeof bufout, ">< %s: %s", cmd, txt ? txt : ""); - pout(usr, bufout); - if(!strncmp("NICK", cmd, 4) && !strncmp(usr, nick, sizeof nick) && txt) - strncpy(nick, txt, sizeof nick); + 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; + int i, c; struct timeval tv; - struct hostent *hp; - static struct sockaddr_in addr; /* initially filled with 0's */ - char ping[256]; fd_set rd; - strncpy(nick, getenv("USER"), sizeof nick); - for(i = 1; i < argc; i++) - if(!strncmp(argv[i], "-h", 3)) { + 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(!strncmp(argv[i], "-p", 3)) { - if(++i < argc) port = (unsigned short)atoi(argv[i]); - } - else if(!strncmp(argv[i], "-n", 3)) { - if(++i < argc) strncpy(nick, argv[i], sizeof nick); - } - else if(!strncmp(argv[i], "-k", 3)) { + break; + case 'p': + if(++i < argc) port = atoi(argv[i]); + break; + case 'n': + if(++i < argc) strlcpy(nick, argv[i], sizeof nick); + break; + case 'k': if(++i < argc) password = argv[i]; - } - else if(!strncmp(argv[i], "-v", 3)) - eprint("sic-"VERSION", © 2005-2007 Anselm R. Garbe, Nico Golde\n"); - else + break; + case 'v': + eprint("sic-"VERSION", © 2005-2007 Anselm R. Garbe, Nico Golde\n"); + default: eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n"); + } + } /* init */ - if((srv = socket(AF_INET, SOCK_STREAM, 0)) < 0) - eprint("sic: cannot connect host '%s'\n", host); - if(NULL == (hp = gethostbyname(host))) - eprint("sic: cannot resolve hostname '%s'\n", host); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - if(connect(srv, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))) { - close(srv); - eprint("sic: cannot connect host '%s'\n", host); - } + 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 */ + 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(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; - eprint("sic: error on select()"); + eprint("sic: error on select():"); } else if(i == 0) { - if(time(NULL) - trespond >= PINGTIMEOUT) - eprint("sic shutting down: parse timeout"); - write(srv, ping, strlen(ping)); + if(time(nil) - trespond >= PINGTIMEOUT) + eprint("sic shutting down: parse timeout\n"); + sout("PING %s", host); continue; } - if(FD_ISSET(srv, &rd)) { - if(getline(srv, sizeof bufin, bufin) == -1) - eprint("sic: remote host closed connection"); + if(FD_ISSET(fileno(srv), &rd)) { + if(fgets(bufin, sizeof bufin, srv) == nil) + eprint("sic: remote host closed connection\n"); parsesrv(bufin); - trespond = time(NULL); + trespond = time(nil); } if(FD_ISSET(0, &rd)) { - if(getline(0, sizeof bufin, bufin) == -1) - eprint("sic: broken pipe"); + if(fgets(bufin, sizeof bufin, stdin) == nil) + eprint("sic: broken pipe\n"); parsein(bufin); } } return 0; } + diff -r a6692d249139 util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util.c Fri Aug 10 10:29:01 2007 -0700 @@ -0,0 +1,72 @@ +#include +#include +#include + +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, int port) { + struct hostent *hp; + static struct sockaddr_in addr; + int i; + + if((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) + eprint("sic: cannot connect host '%s':", host); + if(nil == (hp = gethostbyname(host))) + eprint("sic: cannot resolve hostname '%s': %s\n", host, hstrerror(h_errno)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); + if(connect(i, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) + eprint("sic: cannot connect host '%s':", host); + return i; +} + +#define strlcpy _strlcpy +static void +strlcpy(char *to, const char *from, int l) { + strncpy(to, from, l-1); + 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; +} +