From 93d007481e25c9db88e8b16117b0378d51951bb6 Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Thu, 07 Mar 2013 15:20:22 +0000
Subject: fix segfault when IRC server does disconnect

and fix lots of whitespace damage
---
diff --git a/irc.c b/irc.c
index 92a925e..5832421 100644
--- a/irc.c
+++ b/irc.c
@@ -14,11 +14,11 @@ static int tcp_connect(const char *host, int port)
 	struct sockaddr_in addr;
 	struct hostent *h;
 	int sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0) 
+	if (sock < 0)
 		return sock;
 
 	h = gethostbyname(host);
-	if (h == NULL) 
+	if (h == NULL)
 		return -1;
 
 	memset(&addr, 0, sizeof(addr));
@@ -38,17 +38,17 @@ struct irc_session *irc_connect(const char* server, int port, const char *nick,
 {
 	char buf[256];
 	struct irc_session *sess;
-	
+
 	sess = malloc(sizeof(struct irc_session));
 	if (sess == NULL)
 		return NULL;
-		
+
 	sess->nick = nick;
 	sess->server = server;
 	sess->fd = tcp_connect(server, port);
-	if (sess->fd < 0) 
+	if (sess->fd < 0)
 		return NULL;
-		
+
 	/* login */
 	if (pass)
 		irc_send(sess, "PASS", pass);
@@ -79,7 +79,9 @@ int irc_send_ping(struct irc_session *s)
 
 int irc_close(struct irc_session *s, const char *msg)
 {
-	irc_send(s, "QUIT", msg ? msg : "");
-	close(s->fd);
+	if (s->fd > 0) {
+		irc_send(s, "QUIT", msg ? msg : "");
+		close(s->fd);
+	}
 	free(s);
 }
diff --git a/sircbot.c b/sircbot.c
index b85d7d0..7d9c1a3 100644
--- a/sircbot.c
+++ b/sircbot.c
@@ -56,8 +56,8 @@ struct sircbot_socket_callback {
 	int (*callback)(struct sircbot_session *sb, struct pollfd *fds,
 			void *ctx);
 };
-	
-	
+
+
 static int foreground = 0;
 static int sigterm = 0;
 static int flush_rate = 2;
@@ -90,7 +90,7 @@ int daemonize(const char *pidfile, const char *logfile)
 	/* exit parent */
 	if (pid > 0)
 		exit(0);
-	
+
 	/* detatch to controling terminal */
 	setsid();
 
@@ -220,10 +220,10 @@ int run_hooks(char *user, char *rcpt, char* data)
 		/* exit parent */
 		if (pid > 0)
 			exit(0);
-		
+
 		snprintf(dir, sizeof(dir), "/etc/" PROGNAME ".d/%s", rcpt);
 		printf("DEBUG: running scripts in %s\n", dir);
-		execlp("/bin/run-parts", "/bin/run-parts", "-a", user, 
+		execlp("/bin/run-parts", "/bin/run-parts", "-a", user,
 			   "-a", data, "-a", rcpt, dir, NULL);
 		log_err("run-parts");
 		exit(1);
@@ -302,17 +302,21 @@ int parse_irc_data(struct sircbot_session *sb, char *buf)
 }
 
 /* callback functions */
-static int irc_server_cb(struct sircbot_session *sb, struct pollfd *fds, 
+static int irc_server_cb(struct sircbot_session *sb, struct pollfd *fds,
 	void *ctx)
 {
 	char buf[4096];
 	int r;
 	struct irc_session *sess = (struct irc_session *) ctx;
 
-	if (fds->revents & POLLHUP) 
+	if (fds->revents & POLLHUP) {
 		/* server hang up on us */
+		printf("DEBUG: %s: connection closed\n", sess ? sess->server : "null");
+		close(sess->fd);
+		sess->fd = -1;
 		return 0;
-	
+	}
+
 	if (fds->revents & POLLERR) {
 		log_err(sess->server);
 		return -1;
@@ -340,7 +344,7 @@ int channel_extend_fd_array(struct sircbot_channel *chan)
 		chan->fd_array[i] = -1;
 	return 0;
 }
-	
+
 
 void channel_add_connection(struct sircbot_channel *chan, int fd)
 {
@@ -428,7 +432,7 @@ static int irc_reset_pollfds(struct sircbot_session *sb, struct pollfd *fds,
 	fds[n].fd = sb->sess->fd;
 	fds[n].events = POLLIN;
 	fds[n].revents = 0;
-	cb[n].context = NULL;
+	cb[n].context = sb->sess;
 	cb[n].callback = &irc_server_cb;
 	n++;
 
@@ -474,18 +478,24 @@ static int send_fifo_queue(struct irc_session *sess,
 	return r;
 }
 
-static void join_channels(struct sircbot_session *sb)
+static int join_channels(struct sircbot_session *sb)
 {
 	time_t now = time(NULL);
 	int i;
 	/* wait atleast 5 secs before we join a channel */
 	for (i = 0; i < sb->numchan; i++)
-		if ((now - sb->chan[i].last_closetime) > 5 
-		     && sb->chan[i].listen_fd < 0) {
+		if ((now - sb->chan[i].last_closetime) > 5
+		     && sb->chan[i].listen_fd < 0 && sb->sess != NULL) {
+			int r = 0;
 			printf("DEBUG: joining %s\n", sb->chan[i].name);
 			sb->chan[i].last_closetime = now;
-			irc_send(sb->sess, "JOIN", sb->chan[i].name);
+			r = irc_send(sb->sess, "JOIN", sb->chan[i].name);
+			if (r < 0) {
+				printf("DEBUG: error %s: %s\n", sb->sess->server, strerror(r));
+				return r;
+			}
 		}
+	return 0;
 }
 
 static int irc_loop(struct sircbot_session *sb)
@@ -504,7 +514,8 @@ static int irc_loop(struct sircbot_session *sb)
 	tv.tv_sec = 1;
 	tv.tv_nsec = 0;
 	while (!sigterm) {
-		join_channels(sb);
+		if (join_channels(sb) < 0)
+			goto ret_err;
 		n = irc_reset_pollfds(sb, fds, cbs, maxfds);
 		r = ppoll(fds, n, &tv, &sigmask);
 		if (r < 0) {
@@ -633,11 +644,11 @@ int main(int argc, char *argv[])
 			sleep(10);
 			continue;
 		}
-		
+
 		irc_loop(&sb);
 		irc_close(sb.sess, "bye");
 		/* reset channel sockets */
-		for (i = 0; i < argc; i++) 
+		for (i = 0; i < argc; i++)
 			close_channel_socket(&sb.chan[i], 0);
 		if (sigterm)
 			break;
--
cgit v0.9.0.3