[PATCH 41/65] overhaul v2

From: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
Date: Sat, 23 Aug 2014 22:35:26 +0000

Signed-off-by: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
---
 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