commit 061faac6ec27a2c7ab6afc630e85ec7ceef047ec
parent 57a6df937c80ae960d6c5da712a86c7674d5ed40
Author: garbeam@mmv.wmii.de <unknown>
Date: Thu, 29 Dec 2005 18:59:54 +0200
some other changes
Diffstat:
M | ii.c | | | 384 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 204 insertions(+), 180 deletions(-)
diff --git a/ii.c b/ii.c
@@ -26,43 +26,140 @@
enum { TOK_NICKSRV = 0, TOK_USER, TOK_CMD, TOK_CHAN, TOK_ARG, TOK_TEXT, TOK_LAST };
+typedef struct Channel Channel;
+struct Channel {
+ int fd;
+ char *name;
+ Channel *next;
+};
+
static int irc;
-static char *fifo[_POSIX_PATH_MAX];
-static char *server = "irc.freenode.net";
+static Channel *channels = nil;
+static char *host = "irc.freenode.net";
static char nick[32]; /* might change while running */
static char path[_POSIX_PATH_MAX];
-static char buf[PIPE_BUF]; /* buffers used for communication */
-static char _buf[PIPE_BUF]; /* help buffer */
-
-static int add_channel(char *channel);
+static char message[PIPE_BUF]; /* message buf used for communication */
static void usage()
{
fprintf(stderr, "%s",
"ii - irc it - " VERSION "\n"
" (C)opyright MMV Anselm R. Garbe, Nico Golde\n"
- "usage: ii [-i <irc dir>] [-s <server>] [-p <port>]\n"
+ "usage: ii [-i <irc dir>] [-s <host>] [-p <port>]\n"
" [-n <nick>] [-k <password>] [-f <fullname>]\n");
exit(EXIT_SUCCESS);
}
+/* creates directories top-down, if necessary */
+static void create_dirtree(const char *dir)
+{
+ char tmp[256];
+ char *p;
+ size_t len;
+
+ snprintf(tmp, sizeof(tmp),"%s",dir);
+ len = strlen(tmp);
+ if(tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for(p = tmp + 1; *p; p++)
+ if(*p == '/') {
+ *p = 0;
+ mkdir(tmp, S_IRWXU);
+ *p = '/';
+ }
+ mkdir(tmp, S_IRWXU);
+}
+
+static int get_filepath(char *filepath, size_t len, char *channel,
+ char *file)
+{
+ if(channel) {
+ if(!snprintf(filepath, len, "%s/%s", path, channel))
+ return 0;
+ create_dirtree(filepath);
+ return snprintf(filepath, len, "%s/%s/%s", path, channel, file);
+ }
+ return snprintf(filepath, len, "%s/%s", path, file);
+}
+
+static void create_filepath(char *filepath, size_t len, char *channel,
+ char *suffix)
+{
+ if(!get_filepath(filepath, len, channel, suffix)) {
+ fprintf(stderr, "%s", "ii: path to irc directory too long\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static Channel *get_channel(int fd)
+{
+ Channel *c;
+ for (c = channels; c && c->fd != fd; c = c->next);
+ return c;
+}
+
+static int open_channel(char *name)
+{
+ static char infile[256];
+ create_filepath(infile, sizeof(infile), name, "in");
+ return open(infile, O_RDONLY | O_NONBLOCK, 0);
+}
+
+static void add_channel(char *name)
+{
+ Channel *c;
+ int fd = open_channel(name);
+
+ if(fd < 0) {
+ perror("ii: cannot create in channels");
+ return;
+ }
+ if(!channels)
+ channels = c = calloc(1, sizeof(Channel));
+ else {
+ for(c = channels; c && c->next; c = c->next);
+ c->next = calloc(1, sizeof(Channel));
+ c = c->next;
+ }
+ if(!c) {
+ perror("ii: cannot allocate memory");
+ exit(EXIT_FAILURE);
+ }
+ c->fd = fd;
+ c->name = strdup(name);
+}
+
+static void rm_channel(Channel *c)
+{
+ Channel *p;
+ if(channels == c)
+ channels = channels->next;
+ else {
+ for(p = channels; p && p->next != c; p = p->next);
+ if(p->next == c)
+ p->next = c->next;
+ }
+ free(c->name);
+ free(c);
+}
+
static void login(char *key, char *fullname)
{
if(key)
- snprintf(buf, PIPE_BUF,
+ snprintf(message, PIPE_BUF,
"PASS %s\r\nNICK %s\r\nUSER %s localhost %s :%s\r\n", key,
- nick, nick, server, fullname ? fullname : nick);
+ nick, nick, host, fullname ? fullname : nick);
else
- snprintf(buf, PIPE_BUF, "NICK %s\r\nUSER %s localhost %s :%s\r\n",
- nick, nick, server, fullname ? fullname : nick);
- write(irc, buf, strlen(buf)); /* login */
+ snprintf(message, PIPE_BUF, "NICK %s\r\nUSER %s localhost %s :%s\r\n",
+ nick, nick, host, fullname ? fullname : nick);
+ write(irc, message, strlen(message)); /* login */
}
static int tcpopen(unsigned short port)
{
int fd;
struct sockaddr_in sin;
- struct hostent *hp = gethostbyname(server);
+ struct hostent *hp = gethostbyname(host);
memset(&sin, 0, sizeof(struct sockaddr_in));
if(hp == nil) {
@@ -77,7 +174,7 @@ static int tcpopen(unsigned short port)
exit(EXIT_FAILURE);
}
if(connect(fd, (const struct sockaddr *) &sin, sizeof(sin)) < 0) {
- perror("ii: cannot connect to server");
+ perror("ii: cannot connect to host");
exit(EXIT_FAILURE);
}
return fd;
@@ -106,48 +203,7 @@ static size_t tokenize(char **result, size_t reslen, char *str, char delim)
return i + 2; /* number of tokens */
}
-/* creates directories top-down, if necessary */
-static void create_lastdir(const char *dir)
-{
- char tmp[256];
- char *p;
- size_t len;
-
- snprintf(tmp, sizeof(tmp),"%s",dir);
- len = strlen(tmp);
- if(tmp[len - 1] == '/')
- tmp[len - 1] = 0;
- for(p = tmp + 1; *p; p++)
- if(*p == '/') {
- *p = 0;
- mkdir(tmp, S_IRWXU);
- *p = '/';
- }
- mkdir(tmp, S_IRWXU);
-}
-
-static int get_filepath(char *filepath, size_t len, char *channel,
- char *file)
-{
- if(channel) {
- if(!snprintf(filepath, len, "%s/%s", path, channel))
- return 0;
- create_lastdir(filepath);
- return snprintf(filepath, len, "%s/%s/%s", path, channel, file);
- }
- return snprintf(filepath, len, "%s/%s", path, file);
-}
-
-static void create_filepath(char *filepath, size_t len, char *channel,
- char *suffix)
-{
- if(!get_filepath(filepath, len, channel, suffix)) {
- fprintf(stderr, "%s", "ii: path to irc directory too long\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void print_out(char *channel, char *buffer)
+static void print_out(char *channel, char *buf)
{
static char outfile[256];
FILE *out;
@@ -157,89 +213,88 @@ static void print_out(char *channel, char *buffer)
create_filepath(outfile, sizeof(outfile), channel, "out");
out = fopen(outfile, "a");
strftime(buft, sizeof(buft), "%R", localtime(&t));
- fprintf(out, "%s %s\n", buft, buffer);
+ fprintf(out, "%s %s\n", buft, buf);
fclose(out);
}
-static void proc_fifo_privmsg(char *channel, char *buffer)
+static void proc_channels_privmsg(char *channel, char *buf)
{
- snprintf(buf, PIPE_BUF, "<%s> %s", nick, buffer);
- print_out(channel, buf);
- snprintf(buf, PIPE_BUF, "PRIVMSG %s :%s\r\n", channel, buffer);
- write(irc, buf, strlen(buf));
+ snprintf(message, PIPE_BUF, "<%s> %s", nick, buf);
+ print_out(channel, message);
+ snprintf(message, PIPE_BUF, "PRIVMSG %s :%s\r\n", channel, buf);
+ write(irc, message, strlen(message));
}
-static void proc_fifo_input(int fd, char *buffer)
+static void proc_channels_input(int fd, char *buf)
{
static char infile[256];
char *p;
+ Channel *c = get_channel(fd);
+
/*int ret = 1; */
- if(buffer[0] != '/') {
- if(fifo[fd][0] != 0)
- proc_fifo_privmsg(fifo[fd], buffer);
+ if(c->name[0] != '/' && c->name[0] != 0) {
+ proc_channels_privmsg(c->name, buf);
return;
}
- switch (buffer[1]) {
+ switch (buf[1]) {
case 'j':
- p = strchr(&buffer[3], ' ');
+ p = strchr(&buf[3], ' ');
if(p)
*p = 0;
- snprintf(buf, PIPE_BUF, "JOIN %s\r\n", &buffer[3]);
- add_channel(&buffer[3]);
+ snprintf(message, PIPE_BUF, "JOIN %s\r\n", &buf[3]);
+ add_channel(&buf[3]);
break;
case 't':
- snprintf(buf, PIPE_BUF, "TOPIC %s :%s\r\n", fifo[fd], &buffer[3]);
+ snprintf(message, PIPE_BUF, "TOPIC %s :%s\r\n", c->name, &buf[3]);
break;
case 'a':
- snprintf(buf, PIPE_BUF, "-!- %s is away \"%s\"", nick, &buffer[3]);
- print_out(fifo[fd], buf);
- if(buffer[2] == 0)
- snprintf(buf, PIPE_BUF, "AWAY\r\n");
+ snprintf(message, PIPE_BUF, "-!- %s is away \"%s\"", nick, &buf[3]);
+ print_out(c->name, message);
+ if(buf[2] == 0)
+ snprintf(message, PIPE_BUF, "AWAY\r\n");
else
- snprintf(buf, PIPE_BUF, "AWAY :%s\r\n", &buffer[3]);
+ snprintf(message, PIPE_BUF, "AWAY :%s\r\n", &buf[3]);
break;
case 'm':
- p = strchr(&buffer[3], ' ');
+ p = strchr(&buf[3], ' ');
if(p) {
*p = 0;
- add_channel(&buffer[3]);
- proc_fifo_privmsg(&buffer[3], p + 1);
+ add_channel(&buf[3]);
+ proc_channels_privmsg(&buf[3], p + 1);
}
return;
break;
case 'n':
- snprintf(nick, sizeof(nick),"%s", buffer);
- snprintf(buf, PIPE_BUF, "NICK %s\r\n", &buffer[3]);
+ snprintf(nick, sizeof(nick),"%s", buf);
+ snprintf(message, PIPE_BUF, "NICK %s\r\n", &buf[3]);
break;
case 'l':
- if(fifo[fd][0] == 0)
+ if(c->name[0] == 0)
return;
- if(buffer[2] == ' ')
- snprintf(buf, PIPE_BUF, "PART %s :%s\r\n", fifo[fd],
- &buffer[3]);
+ if(buf[2] == ' ')
+ snprintf(message, PIPE_BUF, "PART %s :%s\r\n", c->name, &buf[3]);
else
- snprintf(buf, PIPE_BUF,
- "PART %s :ii - 500SLOC are too much\r\n", fifo[fd]);
- write(irc, buf, strlen(buf));
+ snprintf(message, PIPE_BUF,
+ "PART %s :ii - 500SLOC are too much\r\n", c->name);
+ write(irc, message, strlen(message));
close(fd);
- create_filepath(infile, sizeof(infile), fifo[fd], "in");
+ create_filepath(infile, sizeof(infile), c->name, "in");
unlink(infile);
- free(fifo[fd]);
- fifo[fd] = 0;
+ rm_channel(c);
return;
break;
default:
- snprintf(buf, PIPE_BUF, "%s\r\n", &buffer[1]);
+ snprintf(message, PIPE_BUF, "%s\r\n", &buf[1]);
break;
}
- write(irc, buf, strlen(buf));
+ write(irc, message, strlen(message));
}
-static void proc_server_cmd(char *buffer)
+static void proc_server_cmd(char *buf)
{
char *argv[TOK_LAST], *cmd, *p;
int i;
- if(!buffer)
+ if(!buf)
return;
for(i = 0; i < TOK_LAST; i++)
@@ -256,18 +311,18 @@ static void proc_server_cmd(char *buffer)
<trailing> ::= <Any, possibly *empty*, sequence of octets not including NUL or CR or LF>
<crlf> ::= CR LF
*/
- if(buffer[0] == ':') { /* check prefix */
- p = strchr(buffer, ' ');
+ if(buf[0] == ':') { /* check prefix */
+ p = strchr(buf, ' ');
*p = 0;
for(++p; *p == ' '; p++);
cmd = p;
- argv[TOK_NICKSRV] = &buffer[1];
- if((p = strchr(buffer, '!'))) {
+ argv[TOK_NICKSRV] = &buf[1];
+ if((p = strchr(buf, '!'))) {
*p = 0;
argv[TOK_USER] = ++p;
}
} else
- cmd = buffer;
+ cmd = buf;
/* remove CRLFs */
for(p = cmd; p && *p != 0; p++)
@@ -281,15 +336,15 @@ static void proc_server_cmd(char *buffer)
tokenize(&argv[TOK_CMD], TOK_LAST - TOK_CMD + 1, cmd, ' ');
if(!strncmp("PING", argv[TOK_CMD], 5)) {
- snprintf(buf, PIPE_BUF, "PONG %s\r\n", argv[TOK_TEXT]);
- write(irc, buf, strlen(buf));
+ snprintf(message, PIPE_BUF, "PONG %s\r\n", argv[TOK_TEXT]);
+ write(irc, message, strlen(message));
return;
} else if(!argv[TOK_NICKSRV] || !argv[TOK_USER]) { /* server command */
- snprintf(buf, PIPE_BUF, "%s", argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- print_out(0, buf);
+ snprintf(message, PIPE_BUF, "%s", argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ print_out(0, message);
return;
} else if(!strncmp("ERROR", argv[TOK_CMD], 6))
- snprintf(buf, PIPE_BUF, "-!- error %s", argv[TOK_TEXT] ? argv[TOK_TEXT] : "unknown");
+ snprintf(message, PIPE_BUF, "-!- error %s", argv[TOK_TEXT] ? argv[TOK_TEXT] : "unknown");
else if(!strncmp("JOIN", argv[TOK_CMD], 5)) {
if(argv[TOK_TEXT]!=nil){
p = strchr(argv[TOK_TEXT], ' ');
@@ -297,97 +352,71 @@ static void proc_server_cmd(char *buffer)
*p = 0;
}
argv[TOK_CHAN] = argv[TOK_TEXT];
- snprintf(buf, PIPE_BUF, "-!- %s(%s) has joined %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_TEXT]);
+ snprintf(message, PIPE_BUF, "-!- %s(%s) has joined %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_TEXT]);
} else if(!strncmp("PART", argv[TOK_CMD], 5)) {
- snprintf(buf, PIPE_BUF, "-!- %s(%s) has left %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_CHAN]);
+ snprintf(message, PIPE_BUF, "-!- %s(%s) has left %s", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_CHAN]);
} else if(!strncmp("MODE", argv[TOK_CMD], 5))
- snprintf(buf, PIPE_BUF, "-!- %s changed mode/%s -> %s %s", argv[TOK_NICKSRV], argv[TOK_CMD + 1], argv[TOK_CMD + 2], argv[TOK_CMD + 3]);
+ snprintf(message, PIPE_BUF, "-!- %s changed mode/%s -> %s %s", argv[TOK_NICKSRV], argv[TOK_CMD + 1], argv[TOK_CMD + 2], argv[TOK_CMD + 3]);
else if(!strncmp("QUIT", argv[TOK_CMD], 5))
- snprintf(buf, PIPE_BUF, "-!- %s(%s) has quit %s \"%s\"", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_CHAN], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ snprintf(message, PIPE_BUF, "-!- %s(%s) has quit %s \"%s\"", argv[TOK_NICKSRV], argv[TOK_USER], argv[TOK_CHAN], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
else if(!strncmp("NICK", argv[TOK_CMD], 5))
- snprintf(buf, PIPE_BUF, "-!- %s changed nick to %s", argv[TOK_NICKSRV], argv[TOK_TEXT]);
+ snprintf(message, PIPE_BUF, "-!- %s changed nick to %s", argv[TOK_NICKSRV], argv[TOK_TEXT]);
else if(!strncmp("TOPIC", argv[TOK_CMD], 6))
- snprintf(buf, PIPE_BUF, "-!- %s changed topic to \"%s\"", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ snprintf(message, PIPE_BUF, "-!- %s changed topic to \"%s\"", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
else if(!strncmp("KICK", argv[TOK_CMD], 5))
- snprintf(buf, PIPE_BUF, "-!- %s kicked %s (\"%s\")", argv[TOK_NICKSRV], argv[TOK_ARG], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ snprintf(message, PIPE_BUF, "-!- %s kicked %s (\"%s\")", argv[TOK_NICKSRV], argv[TOK_ARG], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
else if(!strncmp("NOTICE", argv[TOK_CMD], 7))
- snprintf(buf, PIPE_BUF, "-!- \"%s\")", argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ snprintf(message, PIPE_BUF, "-!- \"%s\")", argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
else if(!strncmp("PRIVMSG", argv[TOK_CMD], 8))
- snprintf(buf, PIPE_BUF, "<%s> %s", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ snprintf(message, PIPE_BUF, "<%s> %s", argv[TOK_NICKSRV], argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
if(!argv[TOK_CHAN] || !strncmp(argv[TOK_CHAN], nick, strlen(nick)))
- print_out(argv[TOK_NICKSRV], buf);
+ print_out(argv[TOK_NICKSRV], message);
else
- print_out(argv[TOK_CHAN], buf);
-}
-
-static int open_fifo(char *channel)
-{
- static char infile[256];
- create_filepath(infile, sizeof(infile), channel, "in");
- if(access(infile, F_OK) == -1)
- mkfifo(infile, S_IRWXU);
- return open(infile, O_RDONLY | O_NONBLOCK, 0);
+ print_out(argv[TOK_CHAN], message);
}
-static int add_channel(char *channel)
+static int read_line(int fd, size_t res_len, char *buf)
{
- int i;
- char *new;
-
- if(channel && channel[0] != 0) {
- for(i = 0; i < 256; i++)
- if(fifo[i] && !strncmp(channel, fifo[i], strlen(channel)))
- return 1;
- }
- new = strdup(channel);
- if((i = open_fifo(new)) >= 0)
- fifo[i] = new;
- else {
- perror("ii: cannot create in fifo");
- return 0;
- }
- return 1;
-}
-
-static int readl_fd(int fd)
-{
- int i = 0;
+ size_t i = 0;
char c;
do {
if(read(fd, &c, sizeof(char)) != sizeof(char))
- return 0;
- _buf[i++] = c;
+ return -1;
+ buf[i++] = c;
}
- while(c != '\n' && i<PIPE_BUF);
- _buf[i - 1] = 0; /* eliminates '\n' */
- return 1;
+ while(c != '\n' && i < res_len);
+ buf[i - 1] = 0; /* eliminates '\n' */
+ return 0;
}
-static void handle_fifo_input(int fd)
+static void handle_channels_input(Channel *c)
{
- if(!readl_fd(fd)) {
- int i;
- if((i = open_fifo(fifo[fd]))) {
- fifo[i] = fifo[fd];
- fifo[fd] = 0;
- }
+ static char buf[PIPE_BUF];
+ if(read_line(c->fd, PIPE_BUF, buf) == -1) {
+ int fd = open_channel(c->name);
+ if(fd != -1)
+ c->fd = fd;
+ else
+ rm_channel(c);
return;
}
- proc_fifo_input(fd, _buf);
+ proc_channels_input(c->fd, buf);
}
static void handle_server_output()
{
- if(!readl_fd(irc)) {
+ static char buf[PIPE_BUF];
+ if(read_line(irc, PIPE_BUF, buf) == -1) {
perror("ii: remote host closed connection");
exit(EXIT_FAILURE);
}
- proc_server_cmd(_buf);
+ proc_server_cmd(buf);
}
static void run()
{
- int i, r, maxfd;
+ Channel *c;
+ int r, maxfd;
fd_set rd;
for(;;) {
@@ -395,11 +424,10 @@ static void run()
FD_ZERO(&rd);
maxfd = irc;
FD_SET(irc, &rd);
- for(i = 0; i < 256; i++) {
- if(fifo[i]) {
- if(maxfd < i)
- maxfd = i;
- FD_SET(i, &rd);
+ for(c = channels; c; c = c->next) {
+ if(maxfd < c->fd) {
+ maxfd = c->fd;
+ FD_SET(c->fd, &rd);
}
}
@@ -410,12 +438,12 @@ static void run()
perror("ii: error on select()");
exit(EXIT_FAILURE);
} else if(r > 0) {
- for(i = 0; i < 256; i++) {
- if(FD_ISSET(i, &rd)) {
- if(i == irc)
+ for(c = channels; c; c = c->next) {
+ if(FD_ISSET(c->fd, &rd)) {
+ if(c->fd == irc)
handle_server_output();
else
- handle_fifo_input(i);
+ handle_channels_input(c);
}
}
}
@@ -447,7 +475,7 @@ int main(int argc, char *argv[])
snprintf(prefix,sizeof(prefix),"%s", argv[++i]);
break;
case 's':
- server = argv[++i];
+ host = argv[++i];
break;
case 'p':
port = atoi(argv[++i]);
@@ -467,17 +495,13 @@ int main(int argc, char *argv[])
}
}
irc = tcpopen(port);
- if(!snprintf(path, sizeof(path), "%s/irc/%s", prefix, server)) {
+ if(!snprintf(path, sizeof(path), "%s/irc/%s", prefix, host)) {
fprintf(stderr, "%s", "ii: path to irc directory too long\n");
exit(EXIT_FAILURE);
}
- create_lastdir(path);
-
- for(i = 0; i < 256; i++)
- fifo[i] = 0;
+ create_dirtree(path);
- if(!add_channel(""))
- exit(EXIT_FAILURE);
+ add_channel(""); /* master channel */
login(key, fullname);
run();