diff options
| -rw-r--r-- | chat.c | 1 | ||||
| -rw-r--r-- | chat.h | 6 | ||||
| -rw-r--r-- | event.c | 79 | ||||
| -rw-r--r-- | handle.c | 9 | ||||
| -rw-r--r-- | input.c | 7 | ||||
| -rw-r--r-- | irc.c | 97 | ||||
| -rw-r--r-- | ui.c | 4 | 
7 files changed, 75 insertions, 128 deletions
| @@ -76,6 +76,5 @@ int main(int argc, char *argv[]) {  	inputTab();  	uiInit(); -	ircInit();  	eventLoop();  } @@ -48,7 +48,6 @@ struct {  void eventWait(const char *argv[static 2]);  void eventPipe(const char *argv[static 2]); -void eventQuit(void);  noreturn void eventLoop(void);  struct Tag { @@ -106,16 +105,15 @@ void handle(char *line);  void input(struct Tag tag, char *line);  void inputTab(void); -void ircInit(void);  int ircConnect(void); -bool ircRead(void); +void ircRead(void);  void ircWrite(const char *ptr, size_t len);  void ircFmt(const char *format, ...) __attribute__((format(printf, 1, 2)));  void uiInit(void);  void uiShow(void);  void uiHide(void); -noreturn void uiExit(void); +void uiExit(void);  void uiDraw(void);  void uiRead(void);  void uiPrompt(void); @@ -31,20 +31,12 @@  #include "chat.h"  static struct { -	bool quit;  	bool wait; -	bool susp; -	int irc;  	int pipe; -} event = { -	.irc = -1, +} child = {  	.pipe = -1,  }; -void eventQuit(void) { -	event.quit = true; -} -  void eventWait(const char *argv[static 2]) {  	uiHide();  	pid_t pid = fork(); @@ -53,7 +45,7 @@ void eventWait(const char *argv[static 2]) {  		execvp(argv[0], (char *const *)argv);  		err(EX_CONFIG, "%s", argv[0]);  	} -	event.wait = true; +	child.wait = true;  }  static void childWait(void) { @@ -69,11 +61,11 @@ static void childWait(void) {  			"event: signal %s", strsignal(WTERMSIG(status))  		);  	} -	event.wait = false; +	child.wait = false;  }  void eventPipe(const char *argv[static 2]) { -	if (event.pipe > 0) { +	if (child.pipe > 0) {  		uiLog(TagStatus, UIHot, L"event: existing pipe");  		return;  	} @@ -96,20 +88,20 @@ void eventPipe(const char *argv[static 2]) {  	}  	close(rw[1]); -	event.pipe = rw[0]; +	child.pipe = rw[0];  } -static void pipeRead(void) { +static void childRead(void) {  	char buf[256]; -	ssize_t len = read(event.pipe, buf, sizeof(buf) - 1); +	ssize_t len = read(child.pipe, buf, sizeof(buf) - 1);  	if (len < 0) err(EX_IOERR, "read");  	if (len) {  		buf[len] = '\0';  		buf[strcspn(buf, "\n")] = '\0';  		uiFmt(TagStatus, UIHot, "event: %s", buf);  	} else { -		close(event.pipe); -		event.pipe = -1; +		close(child.pipe); +		child.pipe = -1;  	}  } @@ -128,66 +120,45 @@ noreturn void eventLoop(void) {  	};  	sigaction(SIGCHLD, &action, NULL);  	sigaction(SIGINT, &action, NULL); -	sigaction(SIGTSTP, &action, NULL);  	struct sigaction curses;  	sigaction(SIGWINCH, &action, &curses);  	assert(!(curses.sa_flags & SA_SIGINFO)); -	event.irc = ircConnect(); +	uiFmt(TagStatus, UICold, "Traveling to %s...", self.host); +	int irc = ircConnect(); +  	for (;;) {  		if (sig[SIGCHLD]) childWait();  		if (sig[SIGINT]) {  			signal(SIGINT, SIG_DFL);  			ircFmt("QUIT :Goodbye\r\n"); -			event.quit = true; -		} -		if (sig[SIGTSTP]) { -			signal(SIGTSTP, SIG_DFL); -			ircFmt("QUIT :zzz\r\n"); -			event.susp = true;  		}  		if (sig[SIGWINCH]) {  			curses.sa_handler(SIGWINCH);  			uiRead(); +			uiDraw();  		} -		sig[SIGCHLD] = sig[SIGINT] = sig[SIGTSTP] = sig[SIGWINCH] = 0; +		sig[SIGCHLD] = sig[SIGINT] = sig[SIGWINCH] = 0; -		nfds_t nfds = 0;  		struct pollfd fds[3] = { -			{ .events = POLLIN }, -			{ .events = POLLIN }, -			{ .events = POLLIN }, +			{ .events = POLLIN, .fd = irc }, +			{ .events = POLLIN, .fd = STDIN_FILENO }, +			{ .events = POLLIN, .fd = child.pipe },  		}; -		if (!event.wait) fds[nfds++].fd = STDIN_FILENO; -		if (event.irc > 0) fds[nfds++].fd = event.irc; -		if (event.pipe > 0) fds[nfds++].fd = event.pipe; +		if (child.wait) fds[1].events = 0; +		if (child.pipe < 0) fds[2].events = 0; -		int ready = poll(fds, nfds, -1); -		if (ready < 0) { +		int nfds = poll(fds, 3, -1); +		if (nfds < 0) {  			if (errno == EINTR) continue;  			err(EX_IOERR, "poll");  		} -		for (nfds_t i = 0; i < nfds; ++i) { -			if (!fds[i].revents) continue; -			if (fds[i].fd == STDIN_FILENO) uiRead(); -			if (fds[i].fd == event.pipe) pipeRead(); -			if (fds[i].fd == event.irc) { -				if (ircRead()) continue; -				event.irc = -1; -				// TODO: Handle unintended disconnects. -				if (event.quit) uiExit(); -				if (event.susp) { -					uiHide(); -					raise(SIGTSTP); -					sigaction(SIGTSTP, &action, NULL); -					uiShow(); -					event.irc = ircConnect(); -					event.susp = false; -				} -			} -		} +		if (fds[0].revents) ircRead(); +		if (fds[1].revents) uiRead(); +		if (fds[2].revents) childRead(); +  		uiDraw();  	}  } @@ -94,6 +94,14 @@ static void handlePing(char *prefix, char *params) {  	ircFmt("PONG %s\r\n", params);  } +static void handleError(char *prefix, char *params) { +	(void)prefix; +	(void)params; +	// TODO: Show error if unintended disconnect. +	uiExit(); +	exit(EX_OK); +} +  static void handleErrorErroneousNickname(char *prefix, char *params) {  	char *mesg;  	parse(prefix, NULL, NULL, NULL, params, 3, 0, NULL, NULL, &mesg); @@ -470,6 +478,7 @@ static const struct {  	{ "401", handleErrorNoSuchNick },  	{ "432", handleErrorErroneousNickname },  	{ "433", handleErrorErroneousNickname }, +	{ "ERROR", handleError },  	{ "JOIN", handleJoin },  	{ "KICK", handleKick },  	{ "NICK", handleNick }, @@ -105,12 +105,7 @@ static void inputTopic(struct Tag tag, char *params) {  static void inputQuit(struct Tag tag, char *params) {  	(void)tag; -	if (params) { -		ircFmt("QUIT :%s\r\n", params); -	} else { -		ircFmt("QUIT :Goodbye\r\n"); -	} -	eventQuit(); +	ircFmt("QUIT :%s\r\n", params ? params : "Goodbye");  }  static void inputURL(struct Tag tag, char *params) { @@ -19,7 +19,6 @@  #include <netdb.h>  #include <netinet/in.h>  #include <stdarg.h> -#include <stdbool.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> @@ -30,31 +29,21 @@  #include "chat.h" -static struct { -	struct tls_config *config; -	struct tls *client; -	int sock; -} irc = { -	.sock = -1, -}; - -void ircInit(void) { -	irc.config = tls_config_new(); -	int error = tls_config_set_ciphers(irc.config, "compat"); -	if (error) errx(EX_SOFTWARE, "tls_config"); - -	irc.client = tls_client(); -	if (!irc.client) errx(EX_SOFTWARE, "tls_client"); -} +static struct tls *client;  int ircConnect(void) {  	int error; -	tls_reset(irc.client); -	error = tls_configure(irc.client, irc.config); -	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(irc.client)); +	struct tls_config *config = tls_config_new(); +	error = tls_config_set_ciphers(config, "compat"); +	if (error) errx(EX_SOFTWARE, "tls_config"); + +	client = tls_client(); +	if (!client) errx(EX_SOFTWARE, "tls_client"); -	uiFmt(TagStatus, UICold, "Traveling to %s", self.host); +	error = tls_configure(client, config); +	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); +	tls_config_free(config);  	struct addrinfo *head;  	struct addrinfo hints = { @@ -65,24 +54,25 @@ int ircConnect(void) {  	error = getaddrinfo(self.host, self.port, &hints, &head);  	if (error) errx(EX_NOHOST, "getaddrinfo: %s", gai_strerror(error)); +	int sock = -1;  	for (struct addrinfo *ai = head; ai; ai = ai->ai_next) { -		irc.sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); -		if (irc.sock < 0) err(EX_OSERR, "socket"); +		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); +		if (sock < 0) err(EX_OSERR, "socket"); -		error = connect(irc.sock, ai->ai_addr, ai->ai_addrlen); +		error = connect(sock, ai->ai_addr, ai->ai_addrlen);  		if (!error) break; -		close(irc.sock); -		irc.sock = -1; +		close(sock); +		sock = -1;  	} -	if (irc.sock < 0) err(EX_UNAVAILABLE, "connect"); +	if (sock < 0) err(EX_UNAVAILABLE, "connect");  	freeaddrinfo(head); -	error = fcntl(irc.sock, F_SETFD, FD_CLOEXEC); +	error = fcntl(sock, F_SETFD, FD_CLOEXEC);  	if (error) err(EX_IOERR, "fcntl"); -	error = tls_connect_socket(irc.client, irc.sock, self.host); -	if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(irc.client)); +	error = tls_connect_socket(client, sock, self.host); +	if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client));  	const char *ssh = getenv("SSH_CLIENT");  	if (self.webp && ssh) { @@ -95,18 +85,19 @@ int ircConnect(void) {  		);  	} +	if (self.auth) ircFmt("CAP REQ :sasl\r\n");  	if (self.pass) ircFmt("PASS :%s\r\n", self.pass);  	ircFmt("NICK %s\r\n", self.nick);  	ircFmt("USER %s 0 * :%s\r\n", self.user, self.real); -	return irc.sock; +	return sock;  }  void ircWrite(const char *ptr, size_t len) {  	while (len) { -		ssize_t ret = tls_write(irc.client, ptr, len); +		ssize_t ret = tls_write(client, ptr, len);  		if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; -		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(irc.client)); +		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client));  		ptr += ret;  		len -= ret;  	} @@ -116,47 +107,34 @@ void ircFmt(const char *format, ...) {  	char *buf;  	va_list ap;  	va_start(ap, format); -	int len = vasprintf(&buf, format, ap); +	int len =  vasprintf(&buf, format, ap);  	va_end(ap);  	if (!buf) err(EX_OSERR, "vasprintf");  	if (self.verbose) { -		uiFmt( -			TagVerbose, UICold, -			"\3%d<<<\3 %.*s", IRCWhite, len - 2, buf -		); +		uiFmt(TagVerbose, UICold, "\3%d<<<\3 %.*s", IRCWhite, len - 2, buf);  	}  	ircWrite(buf, len);  	free(buf);  } -static void disconnect(void) { -	int error = tls_close(irc.client); -	if (error) errx(EX_IOERR, "tls_close: %s", tls_error(irc.client)); -	error = close(irc.sock); -	if (error) err(EX_IOERR, "close"); -} - -bool ircRead(void) { +void ircRead(void) {  	static char buf[4096];  	static size_t len; -	ssize_t read = tls_read(irc.client, &buf[len], sizeof(buf) - len); -	if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(irc.client)); -	if (!read) { -		disconnect(); -		len = 0; -		return false; -	} +	ssize_t read; +retry: +	read = tls_read(client, &buf[len], sizeof(buf) - len); +	if (read == TLS_WANT_POLLIN || read == TLS_WANT_POLLOUT) goto retry; +	if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client)); +	if (!read) errx(EX_PROTOCOL, "unexpected eof");  	len += read; -	char *crlf, *line = buf; -	while ((crlf = strnstr(line, "\r\n", &buf[len] - line))) { +	char *crlf; +	char *line = buf; +	while (NULL != (crlf = strnstr(line, "\r\n", &buf[len] - line))) {  		crlf[0] = '\0';  		if (self.verbose) { -			uiFmt( -				TagVerbose, UICold, -				"\3%d>>>\3 %s", IRCGray, line -			); +			uiFmt(TagVerbose, UICold, "\3%d>>>\3 %s", IRCGray, line);  		}  		handle(line);  		line = &crlf[2]; @@ -164,5 +142,4 @@ bool ircRead(void) {  	len -= line - buf;  	memmove(buf, line, len); -	return true;  } @@ -22,7 +22,6 @@  #include <stdarg.h>  #include <stdbool.h>  #include <stdlib.h> -#include <stdnoreturn.h>  #include <string.h>  #include <sysexits.h>  #include <wchar.h> @@ -112,13 +111,12 @@ void uiInit(void) {  	uiShow();  } -noreturn void uiExit(void) { +void uiExit(void) {  	uiHide();  	printf(  		"This program is AGPLv3 Free Software!\n"  		"The source is available at <" SOURCE_URL ">.\n"  	); -	exit(EX_OK);  }  static int lastLine(void) { | 
