---
ii.c | 351 ++++++++++++++++++++++++++++++++++++++++++---------------------=
----
1 file changed, 222 insertions(+), 129 deletions(-)
diff --git a/ii.c b/ii.c
index 760cc99..d178b4c 100644
--- a/ii.c
+++ b/ii.c
_AT_@ -28,45 +28,50 @@ enum { TOK_NICKSRV =3D 0, TOK_USER, TOK_CMD, TOK_CHAN, =
TOK_ARG, TOK_TEXT, TOK_LAST
typedef struct Channel Channel;
struct Channel {
int fd;
- char *name;
+ char name[IRC_CHANNEL_MAX]; /* channel name (normalized) */
+ char inpath[PATH_MAX]; /* input path (normalized) */
+ char outpath[PATH_MAX]; /* output path */
Channel *next;
};
=20
static time_t last_response =3D 0;
static Channel *channels =3D NULL;
+static Channel *channelmaster =3D NULL;
static char nick[32]; /* might change while running */
-static char path[PATH_MAX]; /* irc dir (-i) */
+static char ircpath[PATH_MAX]; /* irc dir (-i) */
static char msg[IRC_MSG_MAX]; /* message buf used for communication */
=20
static void
usage(void) {
- eprintf("ii-" VERSION ", =C2=A9 2005-2014 ii engineers, see LICENSE for d=
etails\n"
- "usage: %s <-s host> [-i <irc dir>] [-p <port>]\n"
- " [-n <nick>] [-k <password>] [-f <fullname>]\n", argv0);
+ eprintf("ii-" VERSION ", (c) 2005-2014 ii engineers, see LICENSE for deta=
ils\n"
+ "usage: %s <-s host> [-i <irc dir>] [-p <port>] "
+ "[-n <nick>] [-k <password>] [-f <fullname>]\n", argv0);
}
=20
-static char *
-normalizechannel(char *s) {
- char *p =3D NULL;
+static void
+writestr(int fd, const char *s) {
+ size_t len, off =3D 0;
+ int w =3D -1;
=20
- for(p =3D s; p && *p; p++) {
- if(*p =3D=3D '/')
- *p =3D ',';
- *p =3D tolower(*p);
+ len =3D strlen(s);
+ for(off =3D 0; off < len; off +=3D w) {
+ if((w =3D write(fd, s + off, len - off)) =3D=3D -1)
+ break;
+ off +=3D w;
}
- return s;
+ if(w =3D=3D -1)
+ eprintf("write error:");
}
=20
/* creates directories bottom-up, if necessary */
static void
create_dirtree(const char *dir) {
- char tmp[PATH_MAX];
- char *p =3D NULL;
+ char tmp[PATH_MAX], *p =3D NULL;
struct stat st =3D { 0 };
size_t len;
=20
strlcpy(tmp, dir, sizeof(tmp));
- len =3D strnlen(tmp, sizeof(tmp));
+ len =3D strlen(tmp);
if(len > 0 && tmp[len - 1] =3D=3D '/')
tmp[len - 1] =3D '\0';
=20
_AT_@ -84,58 +89,135 @@ create_dirtree(const char *dir) {
}
=20
static void
-create_filepath(char *filepath, size_t len, char *channel, char *suffix) {
+channel_normalize_path(char *s) {
+ for(; *s; s++) {
+ if(isalpha(*s))
+ *s =3D tolower(*s);
+ else if(!(isdigit(*s) || *s =3D=3D '.' || *s =3D=3D '#' || *s =3D=3D '&'=
))
+ *s =3D '_';
+ }
+}
+
+static void
+channel_normalize_name(char *s) {
+ char *p;
+
+ if(*s =3D=3D '&' || *s =3D=3D '#')
+ s++;
+ for(p =3D s; *s; s++) {
+ if(*s !=3D ' ' && *s !=3D ',' && *s !=3D '&' && *s !=3D '#' && *s !=3D 7=
) {
+ *p =3D *s;
+ p++;
+ }
+ }
+ *p =3D '\0';
+}
+
+static void
+create_filepath(char *filepath, size_t len, const char *path,
+ const char *channel, const char *suffix)
+{
const char *e =3D "ii: path to irc directory too long\n";
+ int r;
=20
- if(channel && channel[0]) {
- normalizechannel(channel);
- if(snprintf(filepath, len, "%s/%s", path, channel) <=3D 0)
+ if(channel[0]) {
+ r =3D snprintf(filepath, len, "%s/%s", path, channel);
+ if(r < 0 || r >=3D len)
eprintf(e);
create_dirtree(filepath);
- if(snprintf(filepath, len, "%s/%s/%s", path, channel, suffix) <=3D 0)
+ r =3D snprintf(filepath, len, "%s/%s/%s", path, channel, suffix);
+ if(r < 0 || r >=3D len)
+ eprintf(e);
+ } else {
+ r =3D snprintf(filepath, len, "%s/%s", path, suffix);
+ if(r < 0 || r >=3D len)
eprintf(e);
- } else if(snprintf(filepath, len, "%s/%s", path, suffix) <=3D 0)
- eprintf(e);
+ }
}
=20
static int
-open_channel(char *name) {
- char infile[PATH_MAX];
+channel_open(Channel *c) {
+ int fd;
=20
- create_filepath(infile, sizeof(infile), name, "in");
- if(access(infile, F_OK) =3D=3D -1)
- mkfifo(infile, S_IRWXU);
- return open(infile, O_RDONLY | O_NONBLOCK, 0);
+ if(access(c->inpath, F_OK) =3D=3D -1)
+ mkfifo(c->inpath, S_IRWXU);
+ fd =3D open(c->inpath, O_RDONLY | O_NONBLOCK, 0);
+ c->fd =3D fd;
+ return fd !=3D -1;
}
=20
-static void
-add_channel(char *cname) {
- Channel *c;
- int fd;
- char *name;
+static int
+channel_reopen(Channel *c) {
+ close(c->fd);
+ return channel_open(c);
+}
=20
- name =3D normalizechannel(cname);
- for(c =3D channels; c; c =3D c->next)
- if(!strcmp(name, c->name))
- return; /* already handled */
+static Channel *
+channel_new(int fd, const char *name) {
+ Channel *c;
+ char channelpath[PATH_MAX];
=20
- if((fd =3D open_channel(name)) =3D=3D -1) {
- weprintf("ii: cannot create in channel: %s:", name);
- return;
- }
+ strlcpy(channelpath, name, sizeof(channelpath));
+ channel_normalize_path(channelpath);
=20
if(!(c =3D calloc(1, sizeof(Channel))))
eprintf("ii: cannot allocate memory:");
+ c->next =3D NULL;
+ c->fd =3D fd;
+ strlcpy(c->name, name, sizeof(c->name));
+ channel_normalize_name(c->name);
+
+ create_filepath(c->inpath, sizeof(c->inpath), ircpath,
+ channelpath, "in");
+ create_filepath(c->outpath, sizeof(c->outpath), ircpath,
+ channelpath, "out");
+ return c;
+}
=20
- if(channels)
+static Channel *
+channel_find(const char *name) {
+ Channel *c;
+ char chan[IRC_CHANNEL_MAX];
+
+ strlcpy(chan, name, sizeof(chan));
+ channel_normalize_name(chan);
+ for(c =3D channels; c; c =3D c->next) {
+ if(!strcmp(chan, c->name))
+ return c; /* already handled */
+ }
+ return NULL;
+}
+
+static Channel *
+channel_add(const char *name) {
+ Channel *c;
+
+ c =3D channel_new(-1, name);
+ if(!channel_open(c)) {
+ weprintf("ii: cannot create in channel: %s:", name);
+ free(c);
+ return NULL;
+ }
+ if(!channels) {
+ channels =3D c;
+ } else {
c->next =3D channels;
- channels =3D c;
- c->fd =3D fd;
- c->name =3D strdup(name);
+ channels =3D c;
+ }
+ return c;
+}
+
+static Channel *
+channel_join(const char *name) {
+ Channel *c;
+
+ if(!(c =3D channel_find(name)))
+ c =3D channel_add(name);
+ return c;
}
=20
static void
-rm_channel(Channel *c) {
+channel_rm(Channel *c) {
Channel *p;
=20
if(channels =3D=3D c) {
_AT_@ -145,21 +227,28 @@ rm_channel(Channel *c) {
if(p->next =3D=3D c)
p->next =3D c->next;
}
- free(c->name);
- c->name =3D NULL;
free(c);
}
=20
static void
-login(int ircfd, char *host, char *key, char *fullname) {
- if(key)
- snprintf(msg, sizeof(msg),
- "PASS %s\r\nNICK %s\r\nUSER %s localhost %s :%s\r\n", key,
- nick, nick, host, fullname);
- else
- snprintf(msg, sizeof(msg), "NICK %s\r\nUSER %s localhost %s :%s\r\n",
- nick, nick, host, fullname);
- write(ircfd, msg, strnlen(msg, sizeof(msg)));
+channel_leave(Channel *c) {
+ close(c->fd);
+ /* remove "in" file on leaving the channel */
+ unlink(c->inpath);
+ channel_rm(c);
+}
+
+static void
+loginkey(int ircfd, const char *key) {
+ snprintf(msg, sizeof(msg), "PASS %s\r\n", key);
+ writestr(ircfd, msg);
+}
+
+static void
+loginuser(int ircfd, const char *host, const char *fullname) {
+ snprintf(msg, sizeof(msg), "NICK %s\r\nUSER %s localhost %s :%s\r\n",
+ nick, nick, host, fullname);
+ writestr(ircfd, msg);
}
=20
static int
_AT_@ -199,7 +288,7 @@ isnumeric(const char *s) {
}
=20
static size_t
-tokenize(char **result, size_t reslen, char *str, char delim) {
+tokenize(char **result, size_t reslen, char *str, int delim) {
char *p =3D NULL, *n =3D NULL;
size_t i =3D 0;
=20
_AT_@ -220,49 +309,50 @@ tokenize(char **result, size_t reslen, char *str, cha=
r delim) {
n++;
}
}
+ /* add last entry */
if(i < reslen && p < n && p && *p)
result[i++] =3D p;
return i; /* number of tokens */
}
=20
static void
-print_out(char *channel, char *buf) {
- char outfile[PATH_MAX], buft[18] =3D "";
- FILE *out =3D NULL;
+print_outfile(const char *path, const char *buf) {
time_t t =3D time(NULL);
+ FILE *fp =3D NULL;
+ char buft[18] =3D "";
=20
- /* starts with "-!- " #channel */
- if(channel && !strncmp(buf, "-!- ", 4) &&
- !strncmp(&buf[4], channel, strlen(channel))) {
- channel =3D "";
- }
- create_filepath(outfile, sizeof(outfile), channel, "out");
- if(!(out =3D fopen(outfile, "a")))
+ if(!(fp =3D fopen(path, "a")))
return;
- if(channel && channel[0])
- add_channel(channel);
-
strftime(buft, sizeof(buft), "%Y-%m-%d %H:%M", localtime(&t));
- fprintf(out, "%s %s\n", buft, buf);
- fclose(out);
+ fprintf(fp, "%s %s\n", buft, buf);
+ fclose(fp);
+}
+
+static void
+channel_print(Channel *c, const char *buf) {
+ /* starts with "-!- " #channel */
+ if(!strncmp(buf, "-!- ", 4) &&
+ !strncmp(&buf[4], c->name, strlen(c->name))) {
+ c =3D channelmaster;
+ }
+ print_outfile(c->outpath, buf);
}
=20
static void
-proc_channels_privmsg(int fd, char *channel, char *buf) {
+proc_channels_privmsg(int fd, Channel *c, char *buf) {
snprintf(msg, sizeof(msg), "<%s> %s", nick, buf);
- print_out(channel, msg);
- snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", channel, buf);
- write(fd, msg, strnlen(msg, sizeof(msg)));
+ channel_print(c, msg);
+ snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", c->name, buf);
+ writestr(fd, msg);
}
=20
static void
proc_channels_input(int fd, Channel *c, char *buf) {
- char infile[PATH_MAX];
char *p =3D NULL;
size_t buflen;
=20
if(buf[0] !=3D '/' && buf[0] !=3D '\0') {
- proc_channels_privmsg(fd, c->name, buf);
+ proc_channels_privmsg(fd, c, buf);
return;
}
msg[0] =3D '\0';
_AT_@ -280,11 +370,10 @@ proc_channels_input(int fd, Channel *c, char *buf) {
snprintf(msg, sizeof(msg), "JOIN %s %s\r\n", &buf[3], p + 1);
else
snprintf(msg, sizeof(msg), "JOIN %s\r\n", &buf[3]);
- add_channel(&buf[3]);
- }
- else if(p) {
- add_channel(&buf[3]);
- proc_channels_privmsg(fd, &buf[3], p + 1);
+ c =3D channel_join(&buf[3]);
+ } else if(p) {
+ if((c =3D channel_join(&buf[3])))
+ proc_channels_privmsg(fd, c, p + 1);
return;
}
break;
_AT_@ -295,7 +384,7 @@ proc_channels_input(int fd, Channel *c, char *buf) {
case 'a': /* away */
if(buflen >=3D 3) {
snprintf(msg, sizeof(msg), "-!- %s is away \"%s\"", nick, &buf[3]);
- print_out(c->name, msg);
+ channel_print(c, msg);
}
if(buflen >=3D 3)
snprintf(msg, sizeof(msg), "AWAY :%s\r\n", &buf[3]);
_AT_@ -316,36 +405,33 @@ proc_channels_input(int fd, Channel *c, char *buf) {
else
snprintf(msg, sizeof(msg),
"PART %s :leaving\r\n", c->name);
- write(fd, msg, strnlen(msg, sizeof(msg)));
- close(c->fd);
- /* remove "in" file on leaving the channel */
- if(snprintf(infile, sizeof(infile), "%s/%s/in",
- path, c->name) > 0) {
- unlink(infile);
- }
- rm_channel(c);
+ writestr(fd, msg);
+ channel_leave(c);
return;
break;
default: /* raw IRC command */
snprintf(msg, sizeof(msg), "%s\r\n", &buf[1]);
break;
}
- }
- else /* raw IRC command */
+ } else {
+ /* raw IRC command */
snprintf(msg, sizeof(msg), "%s\r\n", &buf[1]);
-
+ }
if(msg[0] !=3D '\0')
- write(fd, msg, strnlen(msg, sizeof(msg)));
+ writestr(fd, msg);
}
=20
static void
proc_server_cmd(int fd, char *buf) {
+ Channel *c;
+ const char *channel;
char *argv[TOK_LAST], *cmd =3D NULL, *p =3D NULL;
unsigned int i;
=20
- if(!buf || *buf =3D=3D '\0')
+ if(!buf || buf[0] =3D=3D '\0')
return;
=20
+ /* clear tokens */
for(i =3D 0; i < TOK_LAST; i++)
argv[i] =3D NULL;
=20
_AT_@ -382,14 +468,14 @@ proc_server_cmd(int fd, char *buf) {
return;
} else if(!strncmp("PING", argv[TOK_CMD], 5)) {
snprintf(msg, sizeof(msg), "PONG %s\r\n", argv[TOK_TEXT]);
- write(fd, msg, strnlen(msg, sizeof(msg)));
+ writestr(fd, msg);
return;
} else if(!argv[TOK_NICKSRV] || !argv[TOK_USER]) {
/* server command */
snprintf(msg, sizeof(msg), "%s%s",
argv[TOK_ARG] ? argv[TOK_ARG] : "",
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- print_out(NULL, msg);
+ channel_print(channelmaster, msg);
return;
} else if(!strncmp("ERROR", argv[TOK_CMD], 6))
snprintf(msg, sizeof(msg), "-!- error %s",
_AT_@ -405,38 +491,45 @@ proc_server_cmd(int fd, char *buf) {
/* if user itself leaves, don't write to out (don't reopen channel). */
if(!strcmp(argv[TOK_NICKSRV], nick))
return;
- } else if(!strncmp("MODE", argv[TOK_CMD], 5))
+ } else if(!strncmp("MODE", argv[TOK_CMD], 5)) {
snprintf(msg, sizeof(msg), "-!- %s changed mode/%s -> %s %s",
argv[TOK_NICKSRV],
- argv[TOK_CMD + 1] ? argv[TOK_CMD + 1] : "",
- argv[TOK_CMD + 2] ? argv[TOK_CMD + 2] : "",
- argv[TOK_CMD + 3] ? argv[TOK_CMD + 3] : "");
- else if(!strncmp("QUIT", argv[TOK_CMD], 5))
+ argv[TOK_CHAN] ? argv[TOK_CHAN] : "",
+ argv[TOK_ARG] ? argv[TOK_ARG] : "",
+ argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
+ } else if(!strncmp("QUIT", argv[TOK_CMD], 5)) {
snprintf(msg, sizeof(msg), "-!- %s(%s) has quit \"%s\"",
argv[TOK_NICKSRV], argv[TOK_USER],
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- else if(!strncmp("NICK", argv[TOK_CMD], 5))
+ } else if(!strncmp("NICK", argv[TOK_CMD], 5)) {
snprintf(msg, sizeof(msg), "-!- %s changed nick to %s",
argv[TOK_NICKSRV], argv[TOK_TEXT]);
- else if(!strncmp("TOPIC", argv[TOK_CMD], 6))
+ } else if(!strncmp("TOPIC", argv[TOK_CMD], 6)) {
snprintf(msg, sizeof(msg), "-!- %s changed topic to \"%s\"",
argv[TOK_NICKSRV],
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- else if(!strncmp("KICK", argv[TOK_CMD], 5))
+ } else if(!strncmp("KICK", argv[TOK_CMD], 5)) {
snprintf(msg, sizeof(msg), "-!- %s kicked %s (\"%s\")",
argv[TOK_NICKSRV], argv[TOK_ARG],
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- else if(!strncmp("NOTICE", argv[TOK_CMD], 7))
+ } else if(!strncmp("NOTICE", argv[TOK_CMD], 7)) {
snprintf(msg, sizeof(msg), "-!- \"%s\")",
argv[TOK_TEXT] ? argv[TOK_TEXT] : "");
- else if(!strncmp("PRIVMSG", argv[TOK_CMD], 8))
+ } else if(!strncmp("PRIVMSG", argv[TOK_CMD], 8)) {
snprintf(msg, sizeof(msg), "<%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], msg);
+ channel =3D argv[TOK_NICKSRV];
else
- print_out(argv[TOK_CHAN], msg);
+ channel =3D argv[TOK_CHAN];
+
+ if(!channel || channel[0] =3D=3D '\0')
+ c =3D channelmaster;
+ else
+ c =3D channel_join(channel);
+ if(c)
+ channel_print(c, msg);
}
=20
static int
_AT_@ -456,14 +549,12 @@ read_line(int fd, char *buf, size_t bufsiz) {
static void
handle_channels_input(int ircfd, Channel *c) {
char buf[BUFSIZ];
- int fd;
=20
+ if(c->fd =3D=3D -1)
+ return;
if(read_line(c->fd, buf, sizeof(buf)) =3D=3D -1) {
- close(c->fd);
- if((fd =3D open_channel(c->name)) !=3D -1)
- c->fd =3D fd;
- else
- rm_channel(c);
+ if(channel_reopen(c))
+ channel_rm(c);
return;
}
proc_channels_input(ircfd, c, buf);
_AT_@ -479,7 +570,7 @@ handle_server_output(int ircfd) {
}
=20
static void
-run(int ircfd, char *host) {
+run(int ircfd, const char *host) {
Channel *c;
int r, maxfd;
fd_set rd;
_AT_@ -505,10 +596,10 @@ run(int ircfd, char *host) {
eprintf("ii: error on select():");
} else if(r =3D=3D 0) {
if(time(NULL) - last_response >=3D PING_TIMEOUT) {
- print_out(NULL, "-!- ii shutting down: ping timeout");
+ channel_print(channelmaster, "-!- ii shutting down: ping timeout");
exit(EXIT_FAILURE);
}
- write(ircfd, ping_msg, strnlen(ping_msg, sizeof(ping_msg)));
+ writestr(ircfd, ping_msg);
continue;
}
if(FD_ISSET(ircfd, &rd)) {
_AT_@ -525,8 +616,8 @@ run(int ircfd, char *host) {
int
main(int argc, char *argv[]) {
struct passwd *spw;
- char *key =3D NULL, *fullname =3D NULL, *host =3D "";
- char prefix[PATH_MAX], *service =3D "6667";
+ const char *key =3D NULL, *fullname =3D NULL, *host =3D "", *service =3D =
"6667";
+ char prefix[PATH_MAX];
int ircfd;
=20
/* use nickname and home dir of user for ii by default */
_AT_@ -564,12 +655,14 @@ main(int argc, char *argv[]) {
usage();
=20
ircfd =3D tcpopen(host, service);
- if(snprintf(path, sizeof(path), "%s/%s", prefix, host) <=3D 0)
+ if(snprintf(ircpath, sizeof(ircpath), "%s/%s", prefix, host) <=3D 0)
eprintf("ii: path to irc directory too long\n");
- create_dirtree(path);
+ create_dirtree(ircpath);
=20
- add_channel(""); /* master channel */
- login(ircfd, host, key, fullname && *fullname ? fullname : nick);
+ channelmaster =3D channel_add(""); /* master channel */
+ if(key)
+ loginkey(ircfd, key);
+ loginuser(ircfd, host, fullname && *fullname ? fullname : nick);
run(ircfd, host);
=20
return EXIT_SUCCESS;
--=20
2.4.10
--Multipart=_Mon__9_May_2016_17_21_10_+0200_I.6cpFVydhq75aaE
Content-Type: text/x-diff;
name="0042-fix-channel-reopen.patch"
Content-Disposition: attachment;
filename="0042-fix-channel-reopen.patch"
Content-Transfer-Encoding: 7bit
Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Mon May 09 2016 - 17:24:22 CEST