--- 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: 7bitReceived 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