sic-1.1/000755 001750 001750 00000000000 11376772534 012132 5ustar00kriskris000000 000000 sic-1.1/LICENSE000644 001750 001750 00000002330 11376772534 013135 0ustar00kriskris000000 000000 MIT/X Consortium License © 2005-2009 Anselm R Garbe © 2008-2009 Jeroen Schot © 2007-2009 Kris Maglione © 2005 Nico Golde Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sic-1.1/config.mk000644 001750 001750 00000000555 11376772534 013735 0ustar00kriskris000000 000000 # sic version VERSION = 1.1 # Customize below to fit your system # paths PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man # includes and libs INCS = -I. -I/usr/include LIBS = -L/usr/lib -lc # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} # compiler and linker CC = cc sic-1.1/.hgtags000644 001750 001750 00000000757 11376772534 013421 0ustar00kriskris000000 000000 de32c537aaf66554894712563ffba8d9bc4c2714 0.1 56350a01f27753cfbdbb3dbc25f2a53dd4c2ac45 0.2 d77f00af559258679a0fad5d264685d663e6975a 0.3 a3549fb4c72ff0edb816c8c29be7ff289db5b003 0.4 70d49a37b35695f2f771bddaf309f05ea60af8bc 0.5 d7923d9e717c1c6f1ed3b17ec90bfdd7e7bfcca0 0.6 643a6e8b8634b70d2459637fcfff6eca776fc919 0.7 07fb3efaa2e9ed18c6c16f0ddd8576cb66fec9c6 0.8 96eb1bfede5b72fcee3f515d3113d814f7e87108 0.9 b8794f3ed15e34b24ff9fb11c93a4405d0f91433 1.0 d6140e3685b89c609a731471eba6787f7869aa59 1.1 sic-1.1/util.c000644 001750 001750 00000002670 11376772534 013260 0ustar00kriskris000000 000000 /* See LICENSE file for license details. */ #include #include #include 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 char * eat(char *s, int (*p)(int), int r) { while(s != '\0' && p(*s) == r) s++; return s; } static char* skip(char *s, char c) { while(*s != c && *s != '\0') s++; if(*s != '\0') *s++ = '\0'; return s; } static void trim(char *s) { char *e; e = s + strlen(s) - 1; while(isspace(*e) && e > s) e--; *(e + 1) = '\0'; } sic-1.1/.hg_archival.txt000644 001750 001750 00000000222 11376772534 015214 0ustar00kriskris000000 000000 repo: b957ba04faaea81c5f437889897ce708b6885a24 node: 2fa0fcb4cdba1fb57b70b75cf758a2b4c3bc7206 branch: default latesttag: 1.1 latesttagdistance: 1 sic-1.1/Makefile000644 001750 001750 00000002434 11376772534 013575 0ustar00kriskris000000 000000 # sic - simple irc client include config.mk SRC = sic.c OBJ = ${SRC:.c=.o} all: options sic options: @echo sic build options: @echo "CFLAGS = ${CFLAGS}" @echo "LDFLAGS = ${LDFLAGS}" @echo "CC = ${CC}" .c.o: @echo CC $< @${CC} -c ${CFLAGS} $< ${OBJ}: config.mk sic: ${OBJ} @echo CC -o $@ @${CC} -o $@ ${OBJ} ${LDFLAGS} clean: @echo cleaning @rm -f sic ${OBJ} sic-${VERSION}.tar.gz dist: clean @echo creating dist tarball @mkdir -p sic-${VERSION} @cp -R LICENSE Makefile README config.mk sic.1 ${SRC} sic-${VERSION} @tar -cf sic-${VERSION}.tar sic-${VERSION} @gzip sic-${VERSION}.tar @rm -rf sic-${VERSION} install: all @echo installing executable file to ${DESTDIR}${PREFIX}/bin @mkdir -p ${DESTDIR}${PREFIX}/bin @cp -f sic ${DESTDIR}${PREFIX}/bin @chmod 755 ${DESTDIR}${PREFIX}/bin/sic @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1 @sed "s/VERSION/${VERSION}/g" < sic.1 > ${DESTDIR}${MANPREFIX}/man1/sic.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/sic.1 uninstall: @echo removing executable file from ${DESTDIR}${PREFIX}/bin @rm -f ${DESTDIR}${PREFIX}/bin/sic @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 @rm -f ${DESTDIR}${MANPREFIX}/man1/sic.1 .PHONY: all options clean dist install uninstall sic-1.1/sic.1000644 001750 001750 00000002053 11376772534 012772 0ustar00kriskris000000 000000 .TH SIC 1 sic-VERSION .SH NAME sic \- simple irc client .SH SYNOPSIS .B sic .RB [ \-h " "] .RB [ \-p " "] .RB [ \-n " "] .RB [ \-k " "] .RB [ \-v ] .SH DESCRIPTION .B sic is an extremly fast, small and simple irc client. It reads commands from standard input and prints all server output to standard output. It multiplexes also all channel traffic into one output, that you don't have to switch different channel buffers, that's actually a feature. .SH OPTIONS .TP .B \-h Overrides the default host (irc6.oftc.net) .TP .B \-p Overrides the default port (6667) .TP .B \-n Override the default nick ($USER) .TP .B \-k Specifies the keyword to authenticate your nick on the host .TP .BI \-v Prints version information to standard output, then exits. .SH COMMANDS .TP .B :j #channel Join a channel .TP .B :l #channel Leave a channel .TP .B :m #channel/user msg Write a message to #channel/user .TP .B :s #channel/user Set default channel/user .TP Everything which is not a command is simply send the server. sic-1.1/sic.c000644 001750 001750 00000010140 11376772534 013050 0ustar00kriskris000000 000000 /* See LICENSE file for license details. */ #include #include #include #include #include #include #include #include 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_list ap; va_start(ap, fmt); vsnprintf(bufout, sizeof bufout, fmt, ap); va_end(ap); t = time(NULL); strftime(timestr, sizeof timestr, "%D %R", localtime(&t)); fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout); } 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); } 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 *s) { char c, *p; if(s[0] == '\0') return; skip(s, '\n'); if(s[0] != ':') { privmsg(channel, s); return; } c = *++s; if(c != '\0' && isspace(s[1])) { p = s + 2; switch(c) { case 'j': sout("JOIN %s", p); if(channel[0] == '\0') strlcpy(channel, p, sizeof channel); return; case 'l': s = eat(p, isspace, 1); p = eat(s, isspace, 0); if(!*s) s = channel; if(*p) *p++ = '\0'; if(!*p) p = "sic - 250 LOC are too much!"; sout("PART %s :%s", s, p); return; case 'm': s = eat(p, isspace, 1); p = eat(s, isspace, 0); if(*p) *p++ = '\0'; privmsg(s, p); return; case 's': strlcpy(channel, p, sizeof channel); return; } } sout("%s", s); } static void parsesrv(char *cmd) { char *usr, *par, *txt; usr = host; if(!cmd || !*cmd) return; if(cmd[0] == ':') { usr = cmd + 1; cmd = skip(usr, ' '); if(cmd[0] == '\0') return; skip(usr, '!'); } skip(cmd, '\r'); par = skip(cmd, ' '); txt = skip(par, ':'); trim(par); if(!strcmp("PONG", cmd)) return; if(!strcmp("PRIVMSG", cmd)) pout(par, "<%s> %s", usr, txt); else if(!strcmp("PING", cmd)) sout("PONG %s", txt); else { pout(usr, ">< %s (%s): %s", cmd, par, 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; const char *user = getenv("USER"); fd_set rd; strlcpy(nick, user ? user : "unknown", 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, NULL); setbuf(srv, NULL); 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(NULL) - trespond >= 300) eprint("sic shutting down: parse timeout\n"); sout("PING %s", host); continue; } 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)) { if(fgets(bufin, sizeof bufin, stdin) == NULL) eprint("sic: broken pipe\n"); parsein(bufin); } } return 0; } sic-1.1/README000644 001750 001750 00000001211 11376772534 013005 0ustar00kriskris000000 000000 sic - simple irc client ======================= sic is an extremly fast, small and simple irc client. It reads commands from standard input and prints all server output to standard output. It multiplexes also all channel traffic into one output, that you don't have to switch different channel buffers, that's actually a feature. Installation ------------ Edit config.mk to match your local setup. sic is installed into /usr/local by default. Afterwards enter the following command to build and install sic (if necessary as root): $ make clean install Running sic ----------- Simply invoke the 'sic' command with the required arguments.