about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--channel.c32
-rw-r--r--handle.c52
-rw-r--r--ircd.h2
-rw-r--r--loop.c2
-rw-r--r--peer.c9
-rw-r--r--reply.c2
-rw-r--r--writef.c28
7 files changed, 83 insertions, 44 deletions
diff --git a/channel.c b/channel.c
index 0cf0b30..94b0d6c 100644
--- a/channel.c
+++ b/channel.c
@@ -73,8 +73,38 @@ channel_exit(struct Channel *channel, struct Peer *peer)
 		ensure(i != channels_c, warnx(
 			"channel_exit(): couldn't find empty channel"
 		), 1);
-		channels[i] = channels[--channels_c];
+		channel_remove(i);
 	}
 
 	return 0;
 }
+
+void
+channel_remove(size_t cid)
+{
+	struct Channel *tofix;
+	size_t i, j;
+
+	tofix = &channels[channels_c-1];
+	for (i = 0; i < tofix->users_c; ++i)
+	{
+		for (j = 0; j < tofix->users[i]->channels_c; ++j)
+			if (!strcmp(tofix->users[i]->channels[j]->name, tofix->name))
+				break;
+		if (j == tofix->users[i]->channels_c)
+		{
+			warnx(
+				"channel_remove(): %s doesn't belong to %s@%s, "
+				"though they believe in the opposite",
+				tofix->name,
+				getnick(tofix->users[i]),
+				tofix->users[i]->host
+			);
+			continue;
+		}
+
+		tofix->users[i]->channels[j] = &channels[cid];
+	}
+
+	channels[cid] = channels[--channels_c];
+}
diff --git a/handle.c b/handle.c
index 2a6fe1c..74e354c 100644
--- a/handle.c
+++ b/handle.c
@@ -26,7 +26,7 @@
 static int
 join(struct Message *msg, struct Peer *peer)
 {
-	size_t i, j;
+	size_t i;
 
 	/* TODO: support comma separated list of channels, keys */
 	ensure(peer->type, reply(peer, 451), 0);
@@ -34,19 +34,16 @@ join(struct Message *msg, struct Peer *peer)
 	ensure(peer->channels_c != lengthof(peer->channels), reply(peer, 405, msg->params[0]), 0)
 	ensure(*msg->params[0] == '#', reply(peer, 403, msg->params[0]), 0);
 
+	for (i = 0; i < peer->channels_c; ++i)
+		ensure(strcmp(channels[i].name, msg->params[0]), (void)0, 0);
+
 	for (i = 0; i < channels_c; ++i)
 	{
 		if (strcmp(channels[i].name, msg->params[0]))
 			continue;
 
-		for (j = 0; j < channels[i].users_c; ++j)
-			ensure(
-				strcmp(channels[i].users[j]->nick, peer->nick),
-				(void)0,
-				0
-			);
-
-		ensure(!channel_join(&channels[i], peer), reply(peer, 471), 0);
+		if (channel_join(&channels[i], peer))
+			reply(peer, 471);
 		return 0;
 	}
 
@@ -107,11 +104,21 @@ nick(struct Message *msg, struct Peer *peer)
 	for (i = 0; i < peers_c; ++i)
 		if (peers[i].fd != peer->fd)
 			ensure(
-				!strcmp(peers[i].nick, peer->nick),
+				strcmp(peers[i].nick, msg->params[0]),
 				reply(peer, 433, msg->params[0]),
 				0
 			);
 
+	if (peer->type)
+		announce(
+			peer,
+			":%s!%s@%s NICK %s",
+			getnick(peer),
+			peer->user,
+			peer->host,
+			msg->params[0]
+		);
+
 	user_reg(peer, msg->params[0], NULL, NULL, NULL);
 
 	return 0;
@@ -210,39 +217,20 @@ privmsg(struct Message *msg, struct Peer *peer)
 static int
 quit(struct Message *msg, struct Peer *peer)
 {
-	size_t i, j;
+	size_t i;
 
 	ensure(peer->type, (void)0, 1)
 
-	writef(
-		peer->fd,
+	announce(
+		peer,
 		":%s!%s@%s QUIT :%s",
 		getnick(peer),
 		peer->user,
 		peer->host,
 		msg->params[0] ? msg->params[0] : "Client Quit"
 	);
-
 	for (i = 0; i < peer->channels_c; ++i)
-	{
 		channel_exit(peer->channels[i], peer);
-		for (j = 0; j < peer->channels[i]->users_c; ++j)
-			peer->channels[i]->users[j]->flags |= ANNOUNCE;
-	}
-
-	for (i = 0; i < peers_c; ++i)
-		if (peers[i].flags & ANNOUNCE)
-		{
-			writef(
-				peers[i].fd,
-				":%s!%s@%s QUIT :%s",
-				getnick(peer),
-				peer->user,
-				peer->host,
-				msg->params[0] ? msg->params[0] : "Client Quit"
-			);
-			peers[i].flags &= ~ANNOUNCE;
-		}
 
 	return 1;
 }
diff --git a/ircd.h b/ircd.h
index 2c4b144..0cb20dc 100644
--- a/ircd.h
+++ b/ircd.h
@@ -92,11 +92,13 @@ void user_remove(size_t pid);
 
 int channel_join(struct Channel *channel, struct Peer *peer);
 int channel_exit(struct Channel *channel, struct Peer *peer);
+void channel_remove(size_t cid);
 
 int parse_message(char *buf, struct Message *msg);
 int handle(struct Peer *peer);
 int reply(const struct Peer *peer, int number, ...);
 Handler *find(const char *command);
+void announce(struct Peer *peer, const char *fmt, ...);
 int writef(int fd, const char *fmt, ...);
 int writechanf(const struct Peer *except, const struct Channel *channel, const char *fmt, ...);
 void ircd(void);
diff --git a/loop.c b/loop.c
index cfba4b6..fdb2e66 100644
--- a/loop.c
+++ b/loop.c
@@ -126,7 +126,7 @@ loop:
 		writef(peers[i].fd, "ERROR :Closing Link: %s", peers[i].host);
 		close(peers[i].fd);
 		user_remove(i);
-		i = 0;
+		--i;
 	}
 	goto loop;
 }
diff --git a/peer.c b/peer.c
index 21dba70..3634834 100644
--- a/peer.c
+++ b/peer.c
@@ -60,14 +60,5 @@ handle(struct Peer *peer)
 next:
 		move(peer, p - peer->buf + 2);
 	}
-	if (peer->recvd == sizeof(peer->buf))
-	{
-		/*
-	 	* TODO: maybe somehow be more careful with peer data?
-	 	* or drop them?
-	 	*/
-		memset(peer->buf, 0, sizeof(peer->buf));
-		peer->recvd = 0;
-	}
 	return 0;
 }
diff --git a/reply.c b/reply.c
index 5409908..f89a8c9 100644
--- a/reply.c
+++ b/reply.c
@@ -126,7 +126,7 @@ vreply(const struct Peer *peer, int number, va_list ap)
 		getnick(peer)
 	), _);
 	REPLY(433, WRITE(
-		":%s 431 %s %s :Nickname is already in use",
+		":%s 433 %s %s :Nickname is already in use",
 		hostname,
 		getnick(peer),
 		nick
diff --git a/writef.c b/writef.c
index e010ca4..c5e6b95 100644
--- a/writef.c
+++ b/writef.c
@@ -65,3 +65,31 @@ writechanf(const struct Peer *except, const struct Channel *channel, const char
 
 	return count;
 }
+
+void
+announce(struct Peer *peer, const char *fmt, ...)
+{
+	va_list args;
+	size_t i, j;
+
+	va_start(args, fmt);
+	vstoref(fmt, args);
+	va_end(args);
+
+	if (!peer->channels_c)
+	{
+		write(peer->fd, buf, written);
+		return;
+	}
+
+	for (i = 0; i < peer->channels_c; ++i)
+		for (j = 0; j < peer->channels[i]->users_c; ++j)
+			peer->channels[i]->users[j]->flags |= ANNOUNCE;
+
+	for (i = 0; i < peers_c; ++i)
+		if (peers[i].flags & ANNOUNCE)
+		{
+			write(peers[i].fd, buf, written);
+			peers[i].flags &= ~ANNOUNCE;
+		}
+}