63 Commits
0.3 ... 1.1

Author SHA1 Message Date
Anselm R Garbe
6af1b812ae cleanup 2010-05-14 18:01:20 +01:00
Anselm R Garbe
75d42255f2 applied anonymous cleanup patch, thanks anonymous! 2010-04-17 11:12:54 +01:00
Anselm R Garbe
dad75aa6ba removed debug line 2010-03-23 18:00:37 +00:00
anselm@garbe.us
d78d10d1a1 bugfix 2010-03-22 13:29:33 +00:00
Anselm R Garbe
1a4256ef71 merged kris' changes into mainstream sic 2009-11-28 12:16:35 +00:00
Anselm R Garbe
9c7027fcbf applied clamiax' patch for null messages 2009-10-30 09:34:59 +00:00
Kris Maglione
7f1961d4c6 Update sic/util.c to match sic.c tip. 2009-09-23 12:52:13 -04:00
Kris Maglione
2b85380411 Update kris/util.c strlcpy 2009-09-23 11:26:48 -04:00
Anselm R Garbe
14e430ac5b added kris' sic.c and util.c temporarily, will need some time to see what will and won't be integrated into mainstream sic.c 2009-09-23 14:32:20 +01:00
Anselm R Garbe
261dc71e58 applied portions of Mark Edgars patch 2009-09-23 14:21:03 +01:00
Anselm R Garbe
4a4f924fee applied Martin Kopta's splint patch 2009-08-07 08:37:09 +01:00
Anselm R Garbe
b3ed5f414f thanks to Matthias-Christian Ott for this hint 2009-02-21 19:14:13 +00:00
a@null
ca6ba9a64a applied Jeroen Schot's patch 2009-02-14 11:53:47 +00:00
a@null
f3827eec2a applied Matthias-Christian Ott's remark about trailing newlines 2009-02-14 11:42:45 +00:00
Anselm R Garbe
8b2eeee541 Added tag 1.0 for changeset b8794f3ed15e 2008-07-29 19:22:08 +01:00
Anselm R Garbe
2a372e2df1 made Makefile consistent 2008-07-29 19:18:03 +01:00
Anselm R Garbe
888ab22725 updated LICENSE 2008-07-29 19:11:07 +01:00
anselm@aab
8a58b25cb7 updated sic 2008-07-06 13:29:19 +01:00
Anselm R Garbe
589cce35c5 minor update 2008-07-02 21:29:57 +01:00
Anselm R. Garbe
5463bed7ed updating copyright notice in sic as well 2007-04-13 11:50:51 +02:00
Anselm R. Garbe
aa40ba1f3d applied a fix inspired by recent wmii commit 2007-02-21 11:00:12 +01:00
Anselm R. Garbe
ef99e720ff removed LD as well, this is misleading 2007-02-14 10:05:41 +01:00
Anselm R. Garbe
f9f6f8a19c Added tag 0.9 for changeset 96eb1bfede5b 2007-02-13 17:02:42 +01:00
Anselm R. Garbe
82946e102d setting the topic must not be supported, its a trivial IRC command (*and rarely used btw*) 2007-02-13 16:14:52 +01:00
arg@suckless.org
7ef7529687 I believe I have fixed the issue, why sic didn't handled PINGs correctly 2007-02-13 16:06:28 +01:00
Anselm R. Garbe
bcda402396 fixed sic man page 2007-02-09 17:07:29 +01:00
Anselm R. Garbe
1160be7ffa removed fullname, added support for tracking NICK changes 2007-02-09 16:16:06 +01:00
Anselm R. Garbe
75f0af7c42 added eprint() 2007-02-09 16:04:49 +01:00
Anselm R. Garbe
81238e16fe consistency patch 2007-02-09 15:40:58 +01:00
Anselm R. Garbe
60fc462aa9 changing the special command operator 2007-02-09 15:18:08 +01:00
Anselm R. Garbe
9b093ac5c6 removed debug output 2007-02-09 15:04:57 +01:00
Anselm R. Garbe
264f8e9422 changed output 2007-02-09 15:02:56 +01:00
Anselm R. Garbe
fe1e3560be small fix 2007-02-09 14:42:40 +01:00
Anselm R. Garbe
1edd94af86 some changes 2007-02-09 14:40:11 +01:00
Anselm R. Garbe
a3abf3b3ef Don't use sic's hg tip, it is broken atm... 2007-02-08 20:42:29 +01:00
Anselm R. Garbe
e3cbbe71c2 adding debug support 2007-02-08 15:32:51 +01:00
Anselm R. Garbe
93842a5fe0 fixed part message 2007-02-08 15:10:47 +01:00
Anselm R. Garbe
1f1228547c small fix 2007-02-08 15:10:10 +01:00
Anselm R. Garbe
ea71b6e88e small fix, don't write message to server if channel is not given 2007-02-08 15:03:42 +01:00
Anselm R. Garbe
cb68ce9e2c some more simplifications 2007-02-08 14:51:04 +01:00
Anselm R. Garbe
5569a14e8e testing some simplifications 2007-02-08 14:27:39 +01:00
Anselm R. Garbe
2e945e48fb small changes, bigger simplifications are on its way 2007-02-06 16:42:17 +01:00
Anselm R. Garbe
a63ccb4600 Added tag 0.8 for changeset 07fb3efaa2e9 2007-02-01 08:22:31 +01:00
Anselm R. Garbe
0a903a0c79 using Tcmd successors more carefully 2007-01-31 11:01:34 +01:00
Anselm R. Garbe
8edb0e23f4 Added tag 0.7 for changeset 643a6e8b8634 2007-01-11 11:44:41 +01:00
Anselm R. Garbe
44e0417e14 applied some segfault patches of Adrien Krunch Kunysz (thanks to Adrien!) 2007-01-11 11:35:02 +01:00
arg@mig29
148029905b V7 2006-12-14 16:52:12 +01:00
arg@mig29
f8d2e7f236 fixed sizeof stuff 2006-11-26 15:53:33 +01:00
arg@mig29
dc15c0d639 Added tag 0.6 for changeset d7923d9e717c1c6f1ed3b17ec90bfdd7e7bfcca0 2006-11-09 17:38:01 +01:00
arg@mig29
73e181ce5b fixed a small grammar typo 2006-11-09 17:37:57 +01:00
arg@mig29
9197fee8a9 new time info 2006-11-03 14:32:05 +01:00
arg@mig29
45ff5ccf31 Added tag 0.5 for changeset 70d49a37b35695f2f771bddaf309f05ea60af8bc 2006-10-26 12:16:42 +02:00
Anselm R. Garbe
fe306465d0 same problem in sic as in dmenu 2006-10-23 10:56:06 +02:00
Anselm R. Garbe
1f3f048ab7 Added tag 0.4 for changeset a3549fb4c72ff0edb816c8c29be7ff289db5b003 2006-10-13 11:10:41 +02:00
Anselm R. Garbe
3160fd2bed hotfix 2006-10-12 08:03:37 +02:00
Anselm R. Garbe
560111d4ba hotfix 2006-10-11 18:23:03 +02:00
Anselm R. Garbe
48fc6f1b10 removed useless crap 2006-10-09 18:01:26 +02:00
Anselm R. Garbe
4120182a49 changed version 2006-10-09 07:28:43 +02:00
Anselm R. Garbe
516c1cafaf fixed arg processing 2006-10-09 07:26:24 +02:00
Anselm R. Garbe
3a24553892 code polishing, removed useless crap 2006-10-09 07:20:07 +02:00
arg@zarathustra
83e05870ce small change to man page 2006-09-26 17:52:37 +02:00
arg@mmvi
089bad0eb0 updated README 2006-09-26 14:32:24 +02:00
arg@mmvi
1ad6394622 Added tag 0.3 for changeset d77f00af559258679a0fad5d264685d663e6975a 2006-09-26 14:27:34 +02:00
8 changed files with 247 additions and 312 deletions

View File

@@ -1,2 +1,10 @@
de32c537aaf66554894712563ffba8d9bc4c2714 0.1 de32c537aaf66554894712563ffba8d9bc4c2714 0.1
56350a01f27753cfbdbb3dbc25f2a53dd4c2ac45 0.2 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

View File

@@ -1,7 +1,9 @@
MIT/X Consortium License MIT/X Consortium License
(C)opyright MMV-MMVI Anselm R. Garbe <garbeam@gmail.com> © 2005-2009 Anselm R Garbe <anselm@garbe.us>
(C)opyright MMV Nico Golde <nico at ngolde dot de> © 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@@ -1,5 +1,4 @@
# sic - simple irc client # sic - simple irc client
# (C)opyright MMVI Anselm R. Garbe
include config.mk include config.mk
@@ -13,7 +12,6 @@ options:
@echo "CFLAGS = ${CFLAGS}" @echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}" @echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}" @echo "CC = ${CC}"
@echo "LD = ${LD}"
.c.o: .c.o:
@echo CC $< @echo CC $<
@@ -22,9 +20,8 @@ options:
${OBJ}: config.mk ${OBJ}: config.mk
sic: ${OBJ} sic: ${OBJ}
@echo LD $@ @echo CC -o $@
@${LD} -o $@ ${OBJ} ${LDFLAGS} @${CC} -o $@ ${OBJ} ${LDFLAGS}
@strip $@
clean: clean:
@echo cleaning @echo cleaning
@@ -45,7 +42,7 @@ install: all
@chmod 755 ${DESTDIR}${PREFIX}/bin/sic @chmod 755 ${DESTDIR}${PREFIX}/bin/sic
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed 's/VERSION/${VERSION}/g' < sic.1 > ${DESTDIR}${MANPREFIX}/man1/sic.1 @sed "s/VERSION/${VERSION}/g" < sic.1 > ${DESTDIR}${MANPREFIX}/man1/sic.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/sic.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/sic.1
uninstall: uninstall:

10
README
View File

@@ -1,11 +1,11 @@
sic - simple irc client sic - simple irc client
----------------------- =======================
sic is an extremly fast, small and simple irc client. It reads commands from 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 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 also all channel traffic into one output, that you don't have to switch
different channel buffers, that's actually a feature. different channel buffers, that's actually a feature.
Installation Installation
------------ ------------
Edit config.mk to match your local setup. sic is installed into Edit config.mk to match your local setup. sic is installed into
@@ -16,11 +16,7 @@ Afterwards enter the following command to build and install sic
$ make clean install $ make clean install
Running sic Running sic
----------- -----------
Simply invoke the 'sic' command with the required arguments. Simply invoke the 'sic' command with the required arguments.
Configuration
-------------
No configuration is needed.

View File

@@ -1,5 +1,5 @@
# sic version # sic version
VERSION = 0.3 VERSION = 1.1
# Customize below to fit your system # Customize below to fit your system
@@ -12,11 +12,9 @@ INCS = -I. -I/usr/include
LIBS = -L/usr/lib -lc LIBS = -L/usr/lib -lc
# flags # flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE
LDFLAGS = ${LIBS} CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" LDFLAGS = -s ${LIBS}
#LDFLAGS = -g ${LIBS}
# compiler and linker # compiler and linker
CC = cc CC = cc
LD = ${CC}

32
sic.1
View File

@@ -3,11 +3,10 @@
sic \- simple irc client sic \- simple irc client
.SH SYNOPSIS .SH SYNOPSIS
.B sic .B sic
.RB [ \-s <server> ] .RB [ \-h " <host>"]
.RB [ \-p <port> ] .RB [ \-p " <port>"]
.RB [ \-n <nick> ] .RB [ \-n " <nick>"]
.RB [ \-k <keyword> ] .RB [ \-k " <keyword>"]
.RB [ \-f <fullname> ]
.RB [ \-v ] .RB [ \-v ]
.SH DESCRIPTION .SH DESCRIPTION
.B sic .B sic
@@ -17,8 +16,8 @@ also all channel traffic into one output, that you don't have to switch
different channel buffers, that's actually a feature. different channel buffers, that's actually a feature.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-s <server> .B \-h <host>
Overrides the default server (irc.oftc.net) Overrides the default host (irc6.oftc.net)
.TP .TP
.B \-p <port> .B \-p <port>
Overrides the default port (6667) Overrides the default port (6667)
@@ -27,29 +26,22 @@ Overrides the default port (6667)
Override the default nick ($USER) Override the default nick ($USER)
.TP .TP
.B \-k <keyword> .B \-k <keyword>
Specifies the keyword to authenticate your nick on the server Specifies the keyword to authenticate your nick on the host
.TP
.B \-f <fullname>
Specify the real name (default is $USER)
.TP .TP
.BI \-v .BI \-v
Prints version information to standard output, then exits. Prints version information to standard output, then exits.
.SH COMMANDS .SH COMMANDS
.TP .TP
.B /j #channel .B :j #channel
Join a channel Join a channel
.TP .TP
.B /l #channel .B :l #channel
Leave a channel Leave a channel
.TP .TP
.B /m #channel/user msg .B :m #channel/user msg
Write a message to #channel/user Write a message to #channel/user
.TP .TP
.B /s #channel/user .B :s #channel/user
Set default channel/user Set default channel/user
.TP .TP
.B /t topic Everything which is not a command is simply send the server.
Set the channel topic
.TP
Everything which is not a command will simply be posted into the channel or to
the server.

412
sic.c
View File

@@ -1,339 +1,207 @@
/* /* See LICENSE file for license details. */
* (C)opyright MMV-MMVI Anselm R. Garbe <garbeam at gmail dot com> #include <ctype.h>
* (C)opyright MMV-MMVI Nico Golde <nico at ngolde dot de>
* See LICENSE file for license details.
*/
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <stdarg.h>
#include <netinet/in.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#define PINGTIMEOUT 300 static char *host = "irc.oftc.net";
#define MAXMSG 4096 static char *port = "ircd";
static char *password;
enum { Tnick, Tuser, Tcmd, Tchan, Targ, Ttext, Tlast }; static char nick[32];
static char bufin[4096];
static char *server = "irc.oftc.net"; static char bufout[4096];
static unsigned short port = 6667;
static char *nick = NULL;
static char *fullname = NULL;
static char *password = NULL;
static char bufin[MAXMSG], bufout[MAXMSG];
static char channel[256]; static char channel[256];
static int srv;
static time_t trespond; static time_t trespond;
static FILE *srv;
static int #include "util.c"
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 static void
pout(char *channel, char *msg) pout(char *channel, char *fmt, ...) {
{
static char timestr[18]; static char timestr[18];
time_t t = time(0); time_t t;
va_list ap;
strftime(timestr, sizeof(timestr), "%a %R", localtime(&t)); va_start(ap, fmt);
fprintf(stdout, "%-8.8s: %s %s\n", channel, timestr, msg); 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 static void
privmsg(char *channel, char *msg) sout(char *fmt, ...) {
{ va_list ap;
snprintf(bufout, sizeof(bufout), "<%s> %s", nick, msg);
pout(channel, bufout); va_start(ap, fmt);
snprintf(bufout, sizeof(bufout), "PRIVMSG %s :%s\r\n", channel, msg); vsnprintf(bufout, sizeof bufout, fmt, ap);
write(srv, bufout, strlen(bufout)); va_end(ap);
fprintf(srv, "%s\r\n", bufout);
} }
static void static void
parsein(char *msg) privmsg(char *channel, char *msg) {
{ if(channel[0] == '\0') {
char *p; pout("", "No channel to send to");
if(msg[0] == 0)
return;
if(msg[0] != '/') {
privmsg(channel, msg);
return; return;
} }
if(!strncmp(msg + 1, "j ", 2) && (msg[3] == '#')) pout(channel, "<%s> %s", nick, msg);
snprintf(bufout, sizeof(bufout), "JOIN %s\r\n", &msg[3]); sout("PRIVMSG %s :%s", channel, msg);
else if(!strncmp(msg + 1, "l ", 2))
snprintf(bufout, sizeof(bufout), "PART %s :sic\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 if(!strncmp(msg + 1, "t ", 2)) {
if(p = strchr(&msg[3], ' '))
*(p++) = 0;
snprintf(bufout, sizeof(bufout), "TOPIC %s :%s\r\n", &msg[3], p);
}
else
snprintf(bufout, sizeof(bufout), "%s\r\n", &msg[1]);
write(srv, bufout, strlen(bufout));
}
static unsigned int
tokenize(char **result, unsigned int reslen, char *str, char delim)
{
char *p, *n;
unsigned int i = 0;
if(!str)
return 0;
for(n = str; *n == delim; n++);
p = n;
for(i = 0; *n != 0;) {
if(i == reslen)
return i;
if(*n == delim) {
*n = 0;
if(strlen(p))
result[i++] = p;
p = ++n;
} else
n++;
}
if((i < reslen) && (p < n) && strlen(p))
result[i++] = p;
return i; /* number of tokens */
} }
static void static void
parsesrv(char *msg) parsein(char *s) {
{ char c, *p;
char *argv[Tlast], *cmd, *p;
int i; if(s[0] == '\0')
if(!msg || !(*msg)) return;
skip(s, '\n');
if(s[0] != ':') {
privmsg(channel, s);
return; return;
for(i = 0; i < Tlast; i++)
argv[i] = NULL;
/*
<bufout> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
<prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <server> ]
<command> ::= <letter> { <letter> } | <number> <number> <number>
<SPACE> ::= ' ' { ' ' }
<params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
<middle> ::= <Any *non-empty* sequence of octets not including SPACE
or NUL or CR or LF, the first of which may not be ':'>
<trailing> ::= <Any, possibly *empty*, sequence of octets not including NUL or CR or LF>
<crlf> ::= CR LF
*/
if(msg[0] == ':') { /* check prefix */
p = strchr(msg, ' ');
*p = 0;
for(++p; *p == ' '; p++);
cmd = p;
argv[Tnick] = &msg[1];
if((p = strchr(msg, '!'))) {
*p = 0;
argv[Tuser] = ++p;
} }
} else c = *++s;
cmd = msg; if(c != '\0' && isspace(s[1])) {
p = s + 2;
/* remove CRLFs */ switch(c) {
for(p = cmd; p && *p != 0; p++) case 'j':
if(*p == '\r' || *p == '\n') sout("JOIN %s", p);
*p = 0; if(channel[0] == '\0')
strlcpy(channel, p, sizeof channel);
if((p = strchr(cmd, ':'))) { return;
*p = 0; case 'l':
argv[Ttext] = ++p; 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;
} }
tokenize(&argv[Tcmd], Tlast - Tcmd, cmd, ' ');
if(!strncmp("PONG", argv[Tcmd], 5)) {
return;
} else if(!strncmp("PING", argv[Tcmd], 5)) {
snprintf(bufout, sizeof(bufout), "PONG %s\r\n", argv[Ttext]);
write(srv, bufout, strlen(bufout));
return;
} else if(!argv[Tnick] || !argv[Tuser]) { /* server command */
snprintf(bufout, sizeof(bufout), "%s", argv[Ttext] ? argv[Ttext] : "");
pout(server, bufout);
return;
} else if(!strncmp("ERROR", argv[Tcmd], 6))
snprintf(bufout, sizeof(bufout), "-!- error %s",
argv[Ttext] ? argv[Ttext] : "unknown");
else if(!strncmp("JOIN", argv[Tcmd], 5)) {
if(argv[Ttext]!=NULL){
p = strchr(argv[Ttext], ' ');
if(p)
*p = 0;
} }
argv[Tchan] = argv[Ttext]; sout("%s", s);
snprintf(bufout, sizeof(bufout), "-!- %s(%s) has joined %s", }
argv[Tnick], argv[Tuser], argv[Ttext]);
} else if(!strncmp("PART", argv[Tcmd], 5)) { static void
snprintf(bufout, sizeof(bufout), "-!- %s(%s) has left %s", parsesrv(char *cmd) {
argv[Tnick], argv[Tuser], argv[Tchan]); char *usr, *par, *txt;
} else if(!strncmp("MODE", argv[Tcmd], 5))
snprintf(bufout, sizeof(bufout), "-!- %s changed mode/%s -> %s %s", usr = host;
argv[Tnick], argv[Tcmd + 1], if(!cmd || !*cmd)
argv[Tcmd + 2], argv[Tcmd + 3]); return;
else if(!strncmp("QUIT", argv[Tcmd], 5)) if(cmd[0] == ':') {
snprintf(bufout, sizeof(bufout), "-!- %s(%s) has quit \"%s\"", usr = cmd + 1;
argv[Tnick], argv[Tuser], cmd = skip(usr, ' ');
argv[Ttext] ? argv[Ttext] : ""); if(cmd[0] == '\0')
else if(!strncmp("NICK", argv[Tcmd], 5)) return;
snprintf(bufout, sizeof(bufout), "-!- %s changed nick to %s", skip(usr, '!');
argv[Tnick], argv[Ttext]); }
else if(!strncmp("TOPIC", argv[Tcmd], 6)) skip(cmd, '\r');
snprintf(bufout, sizeof(bufout), "-!- %s changed topic to \"%s\"", par = skip(cmd, ' ');
argv[Tnick], argv[Ttext] ? argv[Ttext] : ""); txt = skip(par, ':');
else if(!strncmp("KICK", argv[Tcmd], 5)) trim(par);
snprintf(bufout, sizeof(bufout), "-!- %s kicked %s (\"%s\")", if(!strcmp("PONG", cmd))
argv[Tnick], argv[Targ], return;
argv[Ttext] ? argv[Ttext] : ""); if(!strcmp("PRIVMSG", cmd))
else if(!strncmp("NOTICE", argv[Tcmd], 7)) pout(par, "<%s> %s", usr, txt);
snprintf(bufout, sizeof(bufout), "-!- \"%s\")", else if(!strcmp("PING", cmd))
argv[Ttext] ? argv[Ttext] : ""); sout("PONG %s", txt);
else if(!strncmp("PRIVMSG", argv[Tcmd], 8)) else {
snprintf(bufout, sizeof(bufout), "<%s> %s", pout(usr, ">< %s (%s): %s", cmd, par, txt);
argv[Tnick], argv[Ttext] ? argv[Ttext] : ""); if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
if(!argv[Tchan] || !strncmp(argv[Tchan], nick, strlen(nick))) strlcpy(nick, txt, sizeof nick);
pout(argv[Tnick], bufout); }
else
pout(argv[Tchan], bufout);
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[]) {
{ int i, c;
int i;
struct timeval tv; struct timeval tv;
struct hostent *hp; const char *user = getenv("USER");
static struct sockaddr_in addr; /* initially filled with 0's */
char ping[256];
fd_set rd; fd_set rd;
nick = fullname = getenv("USER"); strlcpy(nick, user ? user : "unknown", sizeof nick);
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { for(i = 1; i < argc; i++) {
switch (argv[i][1]) { c = argv[i][1];
default: if(argv[i][0] != '-' || argv[i][2])
fputs("usage: sic [-s server] [-p port] [-n nick]" c = -1;
" [-k keyword] [-f fullname] [-v]\n", stderr); switch(c) {
exit(EXIT_FAILURE); case 'h':
break; if(++i < argc) host = argv[i];
case 's':
server = argv[++i];
break; break;
case 'p': case 'p':
port = (unsigned short)atoi(argv[++i]); if(++i < argc) port = argv[i];
break; break;
case 'n': case 'n':
nick = argv[++i]; if(++i < argc) strlcpy(nick, argv[i], sizeof nick);
break; break;
case 'k': case 'k':
password = argv[++i]; if(++i < argc) password = argv[i];
break;
case 'f':
fullname = argv[++i];
break; break;
case 'v': case 'v':
fputs("sic-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout); eprint("sic-"VERSION", © 2005-2009 Kris Maglione, Anselm R. Garbe, Nico Golde\n");
exit(EXIT_SUCCESS); default:
break; eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-v]\n");
} }
} }
/* init */ /* init */
if((srv = socket(AF_INET, SOCK_STREAM, 0)) < 0) { i = dial(host, port);
fprintf(stderr, "sic: cannot connect server '%s'\n", server); srv = fdopen(i, "r+");
exit(EXIT_FAILURE);
}
if (NULL == (hp = gethostbyname(server))) {
fprintf(stderr, "sic: cannot resolve hostname '%s'\n", server);
exit(EXIT_FAILURE);
}
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);
fprintf(stderr, "sic: cannot connect server '%s'\n", server);
exit(EXIT_FAILURE);
}
/* login */ /* login */
if(password) if(password)
snprintf(bufout, sizeof(bufout), sout("PASS %s", password);
"PASS %s\r\nNICK %s\r\nUSER %s localhost %s :%s\r\n", sout("NICK %s", nick);
password, nick, nick, server, fullname); sout("USER %s localhost %s :%s", nick, host, nick);
else fflush(srv);
snprintf(bufout, sizeof(bufout), "NICK %s\r\nUSER %s localhost %s :%s\r\n", setbuf(stdout, NULL);
nick, nick, server, fullname); setbuf(srv, NULL);
write(srv, bufout, strlen(bufout)); for(;;) { /* main loop */
snprintf(ping, sizeof(ping), "PING %s\r\n", server);
channel[0] = 0;
setbuf(stdout, NULL); /* unbuffered stdout */
for(;;) {
FD_ZERO(&rd); FD_ZERO(&rd);
FD_SET(0, &rd); FD_SET(0, &rd);
FD_SET(srv, &rd); FD_SET(fileno(srv), &rd);
tv.tv_sec = 120; tv.tv_sec = 120;
tv.tv_usec = 0; 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(i < 0) {
if(errno == EINTR) if(errno == EINTR)
continue; continue;
perror("sic: error on select()"); eprint("sic: error on select():");
exit(EXIT_FAILURE);
} else if(i == 0) {
if(time(NULL) - trespond >= PINGTIMEOUT) {
pout(server, "-!- sic shutting down: parseing timeout");
exit(EXIT_FAILURE);
} }
write(srv, ping, strlen(ping)); else if(i == 0) {
if(time(NULL) - trespond >= 300)
eprint("sic shutting down: parse timeout\n");
sout("PING %s", host);
continue; continue;
} }
if(FD_ISSET(srv, &rd)) { if(FD_ISSET(fileno(srv), &rd)) {
if(getline(srv, sizeof(bufin), bufin) == -1) { if(fgets(bufin, sizeof bufin, srv) == NULL)
perror("sic: remote server closed connection"); eprint("sic: remote host closed connection\n");
exit(EXIT_FAILURE);
}
parsesrv(bufin); parsesrv(bufin);
trespond = time(NULL); trespond = time(NULL);
} }
if(FD_ISSET(0, &rd)) { if(FD_ISSET(0, &rd)) {
if(getline(0, sizeof(bufin), bufin) == -1) { if(fgets(bufin, sizeof bufin, stdin) == NULL)
perror("sic: broken pipe"); eprint("sic: broken pipe\n");
exit(EXIT_FAILURE);
}
parsein(bufin); parsein(bufin);
} }
} }
return 0; return 0;
} }

74
util.c Normal file
View File

@@ -0,0 +1,74 @@
/* 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 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';
}