diff options
Diffstat (limited to 'chat.c')
-rw-r--r-- | chat.c | 110 |
1 files changed, 62 insertions, 48 deletions
diff --git a/chat.c b/chat.c index ba6c9a1..bc23c3f 100644 --- a/chat.c +++ b/chat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,6 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> -#include <sysexits.h> #include <time.h> #include <tls.h> #include <unistd.h> @@ -50,6 +49,8 @@ #include <capsicum_helpers.h> #endif +char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags); + #include "chat.h" #ifndef OPENSSL_BIN @@ -68,7 +69,7 @@ static void genCert(const char *path) { "-nodes", "-subj", subj, "-out", path, "-keyout", path, NULL ); - err(EX_UNAVAILABLE, "openssl"); + err(127, "openssl"); } char *idNames[IDCap] = { @@ -91,7 +92,7 @@ static void exitSave(void) { int error = uiSave(); if (error) { warn("%s", save); - _exit(EX_IOERR); + _exit(1); } } @@ -102,7 +103,7 @@ int utilPipe[2] = { -1, -1 }; static void execRead(void) { char buf[1024]; ssize_t len = read(execPipe[0], buf, sizeof(buf) - 1); - if (len < 0) err(EX_IOERR, "read"); + if (len < 0) err(1, "read"); if (!len) return; buf[len] = '\0'; for (char *ptr = buf; ptr;) { @@ -114,7 +115,7 @@ static void execRead(void) { static void utilRead(void) { char buf[1024]; ssize_t len = read(utilPipe[0], buf, sizeof(buf) - 1); - if (len < 0) err(EX_IOERR, "read"); + if (len < 0) err(1, "read"); if (!len) return; buf[len] = '\0'; for (char *ptr = buf; ptr;) { @@ -131,6 +132,12 @@ static void parseHash(char *str) { if (*str) hashBound = strtoul(&str[1], NULL, 0); } +static void parsePlain(char *str) { + self.plainUser = strsep(&str, ":"); + if (!str) errx(1, "SASL PLAIN missing colon"); + self.plainPass = str; +} + static volatile sig_atomic_t signals[NSIG]; static void signalHandler(int signal) { signals[signal] = 1; @@ -151,27 +158,27 @@ static void sandboxEarly(bool log) { if (log) { char buf[PATH_MAX]; int error = unveil(dataPath(buf, sizeof(buf), "log", 0), "wc"); - if (error) err(EX_OSERR, "unveil"); + if (error) err(1, "unveil"); ptr = seprintf(ptr, end, " wpath cpath"); } if (!self.restricted) { int error = unveil("/", "x"); - if (error) err(EX_OSERR, "unveil"); + if (error) err(1, "unveil"); ptr = seprintf(ptr, end, " proc exec"); } promisesInitial = ptr; ptr = seprintf(ptr, end, " inet dns"); int error = pledge(promises, NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); } static void sandboxLate(int irc) { (void)irc; *promisesInitial = '\0'; int error = pledge(promises, NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); } #elif defined __FreeBSD__ @@ -194,7 +201,7 @@ static void sandboxLate(int irc) { || caph_rights_limit( irc, cap_rights_init(&rights, CAP_SEND, CAP_RECV, CAP_EVENT) ); - if (error) err(EX_OSERR, "cap_rights_limit"); + if (error) err(1, "cap_rights_limit"); // caph_cache_tzdata(3) doesn't load UTC info, which we need for // certificate verification. gmtime(3) does. @@ -202,7 +209,7 @@ static void sandboxLate(int irc) { gmtime(&(time_t) { time(NULL) }); error = cap_enter(); - if (error) err(EX_OSERR, "cap_enter"); + if (error) err(1, "cap_enter"); } #else @@ -229,7 +236,6 @@ int main(int argc, char *argv[]) { bool log = false; bool sasl = false; char *pass = NULL; - const char *nick = NULL; const char *user = NULL; const char *real = NULL; @@ -238,7 +244,6 @@ int main(int argc, char *argv[]) { { .val = 'C', .name = "copy", required_argument }, { .val = 'H', .name = "hash", required_argument }, { .val = 'I', .name = "highlight", required_argument }, - { .val = 'K', .name = "kiosk", no_argument }, { .val = 'N', .name = "notify", required_argument }, { .val = 'O', .name = "open", required_argument }, { .val = 'R', .name = "restrict", no_argument }, @@ -279,16 +284,15 @@ int main(int argc, char *argv[]) { break; case 'C': utilPush(&urlCopyUtil, optarg); break; case 'H': parseHash(optarg); break; case 'I': filterAdd(Hot, optarg); - break; case 'K': self.kiosk = true; break; case 'N': utilPush(&uiNotifyUtil, optarg); break; case 'O': utilPush(&urlOpenUtil, optarg); break; case 'R': self.restricted = true; break; case 'S': bind = optarg; break; case 'T': { - uiTime.enable = true; - if (optarg) uiTime.format = optarg; + windowTime.enable = true; + if (optarg) windowTime.format = optarg; } - break; case 'a': sasl = true; self.plain = optarg; + break; case 'a': sasl = true; parsePlain(optarg); break; case 'c': cert = optarg; break; case 'e': sasl = true; break; case 'g': genCert(optarg); @@ -298,43 +302,54 @@ int main(int argc, char *argv[]) { break; case 'k': priv = optarg; break; case 'l': log = true; logOpen(); break; case 'm': self.mode = optarg; - break; case 'n': nick = optarg; + break; case 'n': { + for (uint i = 0; i < ARRAY_LEN(self.nicks); ++i) { + self.nicks[i] = strsep(&optarg, " "); + } + } break; case 'o': printCert = true; break; case 'p': port = optarg; - break; case 'q': uiThreshold = Warm; + break; case 'q': windowThreshold = Warm; break; case 'r': real = optarg; break; case 's': save = optarg; break; case 't': trust = optarg; break; case 'u': user = optarg; break; case 'v': self.debug = true; break; case 'w': pass = optarg; - break; default: return EX_USAGE; + break; default: return 1; } } - if (!host) errx(EX_USAGE, "host required"); + if (!host) errx(1, "host required"); if (printCert) { #ifdef __OpenBSD__ int error = pledge("stdio inet dns", NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif ircConfig(true, NULL, NULL, NULL); ircConnect(bind, host, port); ircPrintCert(); ircClose(); - return EX_OK; + return 0; } - if (!nick) nick = getenv("USER"); - if (!nick) errx(EX_CONFIG, "USER unset"); - if (!user) user = nick; - if (!real) real = nick; + if (!self.nicks[0]) self.nicks[0] = getenv("USER"); + if (!self.nicks[0]) errx(1, "USER unset"); + if (!user) user = self.nicks[0]; + if (!real) real = self.nicks[0]; + + if (pass && !pass[0]) { + char *buf = malloc(512); + if (!buf) err(1, "malloc"); + pass = readpassphrase("Server password: ", buf, 512, 0); + if (!pass) errx(1, "unable to read passphrase"); + } - if (self.kiosk) { - char *hash; - int n = asprintf(&hash, "%08" PRIx32, _hash(user)); - if (n < 0) err(EX_OSERR, "asprintf"); - user = hash; + if (self.plainPass && !self.plainPass[0]) { + char *buf = malloc(512); + if (!buf) err(1, "malloc"); + self.plainPass = readpassphrase("Account password: ", buf, 512, 0); + if (!self.plainPass) errx(1, "unable to read passphrase"); } // Modes defined in RFC 1459: @@ -349,18 +364,17 @@ int main(int argc, char *argv[]) { set(&network.name, host); set(&self.nick, "*"); - editCompleteAdd(); - commandCompleteAdd(); + inputCompletion(); ircConfig(insecure, trust, cert, priv); - uiInitEarly(); + uiInit(); sig_t cursesWinch = signal(SIGWINCH, signalHandler); if (save) { uiLoad(save); atexit(exitSave); } - uiShowID(Network); + windowShow(windowFor(Network)); uiFormat( Network, Cold, NULL, "\3%dcatgirl\3\tis GPLv3 fwee softwawe ^w^ " @@ -383,20 +397,20 @@ int main(int argc, char *argv[]) { } if (sasl) ircFormat("CAP REQ :sasl\r\n"); ircFormat("CAP LS\r\n"); - ircFormat("NICK :%s\r\n", nick); + ircFormat("NICK %s\r\n", self.nicks[0]); ircFormat("USER %s 0 * :%s\r\n", user, real); - uiInitLate(); + // Avoid disabling VINTR until main loop. + inputInit(); signal(SIGHUP, signalHandler); signal(SIGINT, signalHandler); signal(SIGALRM, signalHandler); signal(SIGTERM, signalHandler); signal(SIGCHLD, signalHandler); - bool pipes = !self.kiosk && !self.restricted; - if (pipes) { + if (!self.restricted) { int error = pipe(utilPipe) || pipe(execPipe); - if (error) err(EX_OSERR, "pipe"); + if (error) err(1, "pipe"); fcntl(utilPipe[0], F_SETFD, FD_CLOEXEC); fcntl(utilPipe[1], F_SETFD, FD_CLOEXEC); @@ -412,10 +426,10 @@ int main(int argc, char *argv[]) { { .events = POLLIN, .fd = execPipe[0] }, }; while (!self.quit) { - int nfds = poll(fds, (pipes ? ARRAY_LEN(fds) : 2), -1); - if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll"); + int nfds = poll(fds, (self.restricted ? 2 : ARRAY_LEN(fds)), -1); + if (nfds < 0 && errno != EINTR) err(1, "poll"); if (nfds > 0) { - if (fds[0].revents) uiRead(); + if (fds[0].revents) inputRead(); if (fds[1].revents) ircRecv(); if (fds[2].revents) utilRead(); if (fds[3].revents) execRead(); @@ -431,12 +445,12 @@ int main(int argc, char *argv[]) { .it_interval.tv_sec = 30, }; int error = setitimer(ITIMER_REAL, &timer, NULL); - if (error) err(EX_OSERR, "setitimer"); + if (error) err(1, "setitimer"); } if (signals[SIGALRM]) { signals[SIGALRM] = 0; if (ping) { - errx(EX_UNAVAILABLE, "ping timeout"); + errx(69, "ping timeout"); } else { ircFormat("PING nyaa\r\n"); ping = true; @@ -467,7 +481,7 @@ int main(int argc, char *argv[]) { cursesWinch(SIGWINCH); // doupdate(3) needs to be called for KEY_RESIZE to be picked up. uiDraw(); - uiRead(); + inputRead(); } uiDraw(); |