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
diff --git a/chat.c b/chat.c index f3d7cc2..fa9cfe7 100644 --- a/chat.c +++ b/chat.c @@ -76,6 +76,5 @@ int main(int argc, char *argv[]) { inputTab(); uiInit(); - ircInit(); eventLoop(); } diff --git a/chat.h b/chat.h index 7e320eb..01dcd72 100644 --- a/chat.h +++ b/chat.h @@ -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); diff --git a/event.c b/event.c index fe48345..444e7df 100644 --- a/event.c +++ b/event.c @@ -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(); } } diff --git a/handle.c b/handle.c index 973845f..137f859 100644 --- a/handle.c +++ b/handle.c @@ -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 }, diff --git a/input.c b/input.c index d31172c..cc52928 100644 --- a/input.c +++ b/input.c @@ -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) { diff --git a/irc.c b/irc.c index 81c3f9a..5253b48 100644 --- a/irc.c +++ b/irc.c @@ -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; } diff --git a/ui.c b/ui.c index 5a26aa2..a7bec55 100644 --- a/ui.c +++ b/ui.c @@ -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) { |