From 843160236381d0c76bef1eac89e556920d700a9d Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Sat, 1 Feb 2020 01:18:01 -0500 Subject: Blindly implement login flow --- irc.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 irc.c (limited to 'irc.c') diff --git a/irc.c b/irc.c new file mode 100644 index 0000000..c1c0e7a --- /dev/null +++ b/irc.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2020 C. McEnroe + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chat.h" + +struct tls *client; + +void ircConfig(bool insecure, const char *cert, const char *priv) { + struct tls_config *config = tls_config_new(); + if (!config) errx(EX_SOFTWARE, "tls_config_new"); + + int error = tls_config_set_ciphers(config, "compat"); + if (error) { + errx( + EX_SOFTWARE, "tls_config_set_ciphers: %s", + tls_config_error(config) + ); + } + + if (insecure) { + tls_config_insecure_noverifycert(config); + tls_config_insecure_noverifyname(config); + } + + if (cert) { + error = tls_config_set_keypair_file(config, cert, (priv ? priv : cert)); + if (error) { + errx( + EX_SOFTWARE, "tls_config_set_keypair_file: %s", + tls_config_error(config) + ); + } + } + + client = tls_client(); + if (!client) errx(EX_SOFTWARE, "tls_client"); + + error = tls_configure(client, config); + if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); + tls_config_free(config); +} + +int ircConnect(const char *host, const char *port) { + assert(client); + + struct addrinfo *head; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + int error = getaddrinfo(host, port, &hints, &head); + if (error) errx(EX_NOHOST, "%s:%s: %s", host, port, gai_strerror(error)); + + int sock = -1; + for (struct addrinfo *ai = head; ai; ai = ai->ai_next) { + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) err(EX_OSERR, "socket"); + + error = connect(sock, ai->ai_addr, ai->ai_addrlen); + if (!error) break; + + close(sock); + sock = -1; + } + if (sock < 0) err(EX_UNAVAILABLE, "%s:%s", host, port); + freeaddrinfo(head); + + error = tls_connect_socket(client, sock, host); + if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client)); + + error = tls_handshake(client); + if (error) errx(EX_PROTOCOL, "tls_handshake: %s", tls_error(client)); + + return sock; +} + +void ircSend(const char *ptr, size_t len) { + assert(client); + while (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(client)); + ptr += ret; + len -= ret; + } +} + +void ircFormat(const char *format, ...) { + char buf[1024]; + va_list ap; + va_start(ap, format); + int len = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + assert((size_t)len < sizeof(buf)); + ircSend(buf, len); +} + +static const char *TagNames[TagCap] = { +#define X(name, id) [id] = name, + ENUM_TAG +#undef X +}; + +static void unescape(char *tag) { + for (;;) { + tag = strchr(tag, '\\'); + if (!tag) break; + switch (tag[1]) { + break; case ':': tag[1] = ';'; + break; case 's': tag[1] = ' '; + break; case 'r': tag[1] = '\r'; + break; case 'n': tag[1] = '\n'; + } + memmove(tag, &tag[1], strlen(&tag[1]) + 1); + if (tag[0]) tag = &tag[1]; + } +} + +static struct Message parse(char *line) { + struct Message msg = { .cmd = NULL }; + + if (line[0] == '@') { + char *tags = 1 + strsep(&line, " "); + while (tags) { + char *tag = strsep(&tags, ";"); + char *key = strsep(&tag, "="); + for (size_t i = 0; i < TagCap; ++i) { + if (strcmp(key, TagNames[i])) continue; + unescape(tag); + msg.tags[i] = tag; + break; + } + } + } + + if (line[0] == ':') { + char *origin = 1 + strsep(&line, " "); + msg.nick = strsep(&origin, "!"); + msg.user = strsep(&origin, "@"); + msg.host = origin; + } + + msg.cmd = strsep(&line, " "); + for (size_t i = 0; line && i < ParamCap; ++i) { + if (line[0] == ':') { + msg.params[i] = &line[1]; + break; + } + msg.params[i] = strsep(&line, " "); + } + + return msg; +} + +void ircRecv(void) { + static char buf[8191 + 512]; + static size_t len = 0; + + assert(client); + ssize_t ret = tls_read(client, &buf[len], sizeof(buf) - len); + if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) return; + if (ret < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client)); + if (!ret) errx(EX_PROTOCOL, "server closed connection"); + len += ret; + + char *crlf; + char *line = buf; + for (;;) { + crlf = memmem(line, &buf[len] - line, "\r\n", 2); + if (!crlf) break; + *crlf = '\0'; + handle(parse(line)); + line = crlf + 2; + } + + len -= line - buf; + memmove(buf, line, len); +} -- cgit 1.4.1-2-gfad0 From 2b3a8bfb9c022269307feed01419c903ba754508 Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Sat, 1 Feb 2020 02:26:35 -0500 Subject: Add -v flag --- catgirl.1 | 9 ++++++++- chat.c | 7 ++++++- chat.h | 3 ++- irc.c | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) (limited to 'irc.c') diff --git a/catgirl.1 b/catgirl.1 index 158466b..e9bb40e 100644 --- a/catgirl.1 +++ b/catgirl.1 @@ -8,7 +8,7 @@ . .Sh SYNOPSIS .Nm -.Op Fl e +.Op Fl ev .Op Fl a Ar auth .Op Fl c Ar cert .Op Fl h Ar host @@ -88,6 +88,13 @@ Set username to .Ar user . The default username is the same as the nickname. . +.It Fl v +Log raw IRC messages to the +.Sy +window +as well as standard error +if it is not a terminal. +. .It Fl w Ar pass Log in with the server password .Ar pass . diff --git a/chat.c b/chat.c index 89579c0..5796085 100644 --- a/chat.c +++ b/chat.c @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) { const char *real = NULL; int opt; - while (0 < (opt = getopt(argc, argv, "!a:c:eh:j:k:n:p:r:u:w:"))) { + while (0 < (opt = getopt(argc, argv, "!a:c:eh:j:k:n:p:r:u:vw:"))) { switch (opt) { break; case '!': insecure = true; break; case 'a': sasl = true; self.plain = optarg; @@ -52,6 +52,7 @@ int main(int argc, char *argv[]) { break; case 'p': port = optarg; break; case 'r': real = optarg; break; case 'u': user = optarg; + break; case 'v': self.debug = true; break; case 'w': pass = optarg; } } @@ -70,4 +71,8 @@ int main(int argc, char *argv[]) { ircFormat("CAP LS\r\n"); ircFormat("NICK :%s\r\n", nick); ircFormat("USER %s 0 * :%s\r\n", user, real); + + for (;;) { + ircRecv(); + } } diff --git a/chat.h b/chat.h index bb8929b..4dd4732 100644 --- a/chat.h +++ b/chat.h @@ -33,10 +33,11 @@ enum Cap { }; extern struct Self { + bool debug; + const char *join; enum Cap caps; char *plain; char *nick; - const char *join; } self; #define ENUM_TAG \ diff --git a/irc.c b/irc.c index c1c0e7a..cf8aab7 100644 --- a/irc.c +++ b/irc.c @@ -101,6 +101,18 @@ int ircConnect(const char *host, const char *port) { return sock; } +static void debug(char dir, const char *line) { + if (!self.debug) return; + size_t len = strcspn(line, "\r\n"); + /*uiFormat( + Debug, Cold, NULL, "\3%02d%c%c\3 %.*s", + Gray, dir, dir, (int)len, line + );*/ + if (!isatty(STDERR_FILENO)) { + fprintf(stderr, "%c%c %.*s\n", dir, dir, (int)len, line); + } +} + void ircSend(const char *ptr, size_t len) { assert(client); while (len) { @@ -119,6 +131,7 @@ void ircFormat(const char *format, ...) { int len = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); assert((size_t)len < sizeof(buf)); + debug('<', buf); ircSend(buf, len); } @@ -196,6 +209,7 @@ void ircRecv(void) { crlf = memmem(line, &buf[len] - line, "\r\n", 2); if (!crlf) break; *crlf = '\0'; + debug('>', line); handle(parse(line)); line = crlf + 2; } -- cgit 1.4.1-2-gfad0 From e5363bcae0f726455fb4198cd21d46721ad5e39a Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Sat, 1 Feb 2020 19:37:48 -0500 Subject: Implement the beginnings of UI It takes so much code to do anything in curses... --- Makefile | 3 +- chat.c | 8 +++ chat.h | 22 +++++++- handle.c | 21 ++++++++ irc.c | 6 +-- ui.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 ui.c (limited to 'irc.c') diff --git a/Makefile b/Makefile index 999b491..4af59ee 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,13 @@ CFLAGS += -I${LIBRESSL_PREFIX}/include LDFLAGS += -L${LIBRESSL_PREFIX}/lib CFLAGS += -std=c11 -Wall -Wextra -Wpedantic -LDLIBS = -lcrypto -ltls +LDLIBS = -lcurses -lcrypto -ltls OBJS += chat.o OBJS += handle.o OBJS += irc.o OBJS += term.o +OBJS += ui.o catgirl: ${OBJS} ${CC} ${LDFLAGS} ${OBJS} ${LDLIBS} -o $@ diff --git a/chat.c b/chat.c index 462faa0..47227d5 100644 --- a/chat.c +++ b/chat.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -33,6 +34,8 @@ size_t idNext = Network + 1; struct Self self; int main(int argc, char *argv[]) { + setlocale(LC_CTYPE, ""); + bool insecure = false; const char *host = NULL; const char *port = "6697"; @@ -71,6 +74,10 @@ int main(int argc, char *argv[]) { if (!real) real = nick; ircConfig(insecure, cert, priv); + + uiInit(); + uiFormat(Network, Cold, NULL, "Traveling..."); + uiDraw(); int irc = ircConnect(host, port); if (pass) ircFormat("PASS :%s\r\n", pass); @@ -80,6 +87,7 @@ int main(int argc, char *argv[]) { ircFormat("USER %s 0 * :%s\r\n", user, real); for (;;) { + uiDraw(); ircRecv(); } } diff --git a/chat.h b/chat.h index 93014ef..be3952c 100644 --- a/chat.h +++ b/chat.h @@ -82,6 +82,18 @@ struct Message { char *params[ParamCap]; }; +#define B "\2" +#define C "\3" +#define R "\17" +#define V "\26" +#define I "\35" +#define U "\37" +enum Color { + White, Black, Blue, Green, Red, Brown, Magenta, Orange, + Yellow, LightGreen, Cyan, LightCyan, LightBlue, Pink, Gray, LightGray, + Default = 99, +}; + void ircConfig(bool insecure, const char *cert, const char *priv); int ircConnect(const char *host, const char *port); void ircRecv(void); @@ -91,6 +103,14 @@ void ircFormat(const char *format, ...) void handle(struct Message msg); +enum Heat { Cold, Warm, Hot }; +void uiInit(void); +void uiDraw(void); +void uiWrite(size_t id, enum Heat heat, const struct tm *time, const char *str); +void uiFormat( + size_t id, enum Heat heat, const struct tm *time, const char *format, ... +) __attribute__((format(printf, 4, 5))); + enum TermMode { TermFocus, TermPaste, @@ -109,11 +129,9 @@ void termMode(enum TermMode mode, bool set); enum TermEvent termEvent(char ch); #define BASE64_SIZE(len) (1 + ((len) + 2) / 3 * 4) - static const char Base64[64] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" }; - static inline void base64(char *dst, const byte *src, size_t len) { size_t i = 0; while (len > 2) { diff --git a/handle.c b/handle.c index 96bd2a2..b2b2b8d 100644 --- a/handle.c +++ b/handle.c @@ -136,11 +136,32 @@ static void handleReplyWelcome(struct Message *msg) { if (self.join) ircFormat("JOIN :%s\r\n", self.join); } +static void handleReplyISupport(struct Message *msg) { + // TODO: Extract CHANTYPES and PREFIX for future use. + for (size_t i = 1; i < ParamCap; ++i) { + if (!msg->params[i]) break; + char *key = strsep(&msg->params[i], "="); + if (!msg->params[i]) continue; + if (!strcmp(key, "NETWORK")) { + uiFormat(Network, Cold, NULL, "You arrive in %s", msg->params[i]); + } + } +} + +static void handleReplyMOTD(struct Message *msg) { + require(msg, false, 2); + char *line = msg->params[1]; + if (!strncmp(line, "- ", 2)) line += 2; + uiFormat(Network, Cold, NULL, "%s", line); +} + static const struct Handler { const char *cmd; Handler *fn; } Handlers[] = { { "001", handleReplyWelcome }, + { "005", handleReplyISupport }, + { "372", handleReplyMOTD }, { "900", handleReplyLoggedIn }, { "904", handleErrorSASLFail }, { "905", handleErrorSASLFail }, diff --git a/irc.c b/irc.c index cf8aab7..f07fcc8 100644 --- a/irc.c +++ b/irc.c @@ -104,10 +104,10 @@ int ircConnect(const char *host, const char *port) { static void debug(char dir, const char *line) { if (!self.debug) return; size_t len = strcspn(line, "\r\n"); - /*uiFormat( - Debug, Cold, NULL, "\3%02d%c%c\3 %.*s", + uiFormat( + Debug, Cold, NULL, C"%d%c%c"C" %.*s", Gray, dir, dir, (int)len, line - );*/ + ); if (!isatty(STDERR_FILENO)) { fprintf(stderr, "%c%c %.*s\n", dir, dir, (int)len, line); } diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..0295c8d --- /dev/null +++ b/ui.c @@ -0,0 +1,174 @@ +/* Copyright (C) 2020 C. McEnroe + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chat.h" + +#ifndef A_ITALIC +#define A_ITALIC A_UNDERLINE +#endif + +#define BOTTOM (LINES - 1) +#define RIGHT (COLS - 1) +#define WINDOW_LINES (LINES - 2) + +static short colorPairs; + +static void colorInit(void) { + start_color(); + use_default_colors(); + for (short pair = 0; pair < 16; ++pair) { + init_pair(1 + pair, pair % COLORS, -1); + } + colorPairs = 17; +} + +static attr_t colorAttr(short fg) { + return (fg >= COLORS ? A_BOLD : A_NORMAL); +} + +static short colorPair(short fg, short bg) { + if (bg == -1) return 1 + fg; + for (short pair = 17; pair < colorPairs; ++pair) { + short f, b; + pair_content(pair, &f, &b); + if (f == fg && b == bg) return pair; + } + init_pair(colorPairs, fg, bg); + return colorPairs++; +} + +enum { + InputCols = 512, + PadLines = 512, +}; + +static WINDOW *status; +static WINDOW *input; + +struct Window { + size_t id; + WINDOW *pad; + enum Heat heat; + int unread; + int scroll; + bool mark; + struct Window *prev; + struct Window *next; +}; + +static struct { + struct Window *active; + struct Window *other; + struct Window *head; + struct Window *tail; +} windows; + +static void windowAdd(struct Window *window) { + if (windows.tail) windows.tail->next = window; + window->prev = windows.tail; + window->next = NULL; + windows.tail = window; + if (!windows.head) windows.head = window; +} + +static void windowRemove(struct Window *window) { + if (window->prev) window->prev->next = window->next; + if (window->next) window->next->prev = window->prev; + if (windows.head == window) windows.head = window->next; + if (windows.tail == window) windows.tail = window->prev; +} + +static struct Window *windowFor(size_t id) { + struct Window *window; + for (window = windows.head; window; window = window->next) { + if (window->id == id) return window; + } + window = malloc(sizeof(*window)); + if (!window) err(EX_OSERR, "malloc"); + window->id = id; + window->pad = newpad(PadLines, COLS); + wsetscrreg(window->pad, 0, PadLines - 1); + scrollok(window->pad, true); + wmove(window->pad, PadLines - 1, 0); + window->heat = Cold; + window->unread = 0; + window->scroll = PadLines; + window->mark = true; + windowAdd(window); + return window; +} + +void uiInit(void) { + initscr(); + cbreak(); + noecho(); + termInit(); + termNoFlow(); + def_prog_mode(); + colorInit(); + status = newwin(1, COLS, 0, 0); + input = newpad(1, InputCols); + keypad(input, true); + nodelay(input, true); + windows.active = windowFor(Network); +} + +void uiDraw(void) { + wnoutrefresh(status); + pnoutrefresh( + windows.active->pad, + windows.active->scroll - WINDOW_LINES, 0, + 1, 0, + BOTTOM - 1, RIGHT + ); + // TODO: Input scrolling. + pnoutrefresh( + input, + 0, 0, + BOTTOM, 0, + BOTTOM, RIGHT + ); + doupdate(); +} + +void uiWrite(size_t id, enum Heat heat, const struct tm *time, const char *str) { + (void)time; + struct Window *window = windowFor(id); + waddch(window->pad, '\n'); + waddstr(window->pad, str); +} + +void uiFormat( + size_t id, enum Heat heat, const struct tm *time, const char *format, ... +) { + char buf[1024]; + va_list ap; + va_start(ap, format); + int len = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + assert((size_t)len < sizeof(buf)); + uiWrite(id, heat, time, buf); +} -- cgit 1.4.1-2-gfad0 From 052cd2ed2688867f8b980d283ea3aa410d9dd6aa Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Sun, 2 Feb 2020 03:34:05 -0500 Subject: Remove style string macros --- chat.h | 6 ------ handle.c | 2 +- irc.c | 2 +- ui.c | 4 ++-- 4 files changed, 4 insertions(+), 10 deletions(-) (limited to 'irc.c') diff --git a/chat.h b/chat.h index 4ced983..275fef9 100644 --- a/chat.h +++ b/chat.h @@ -26,12 +26,6 @@ typedef unsigned char byte; -#define B "\2" -#define C "\3" -#define R "\17" -#define V "\26" -#define I "\35" -#define U "\37" enum Color { White, Black, Blue, Green, Red, Brown, Magenta, Orange, Yellow, LightGreen, Cyan, LightCyan, LightBlue, Pink, Gray, LightGray, diff --git a/handle.c b/handle.c index f52f6f9..ef61129 100644 --- a/handle.c +++ b/handle.c @@ -188,7 +188,7 @@ static void handleJoin(struct Message *msg) { } uiFormat( id, Cold, tagTime(msg), - C"%02d%s"C" arrives in "C"%02d%s"C, + "\3%02d%s\3 arrives in \3%02d%s\3", hash(msg->user), msg->nick, idColors[id], idNames[id] ); } diff --git a/irc.c b/irc.c index f07fcc8..d8c6a21 100644 --- a/irc.c +++ b/irc.c @@ -105,7 +105,7 @@ static void debug(char dir, const char *line) { if (!self.debug) return; size_t len = strcspn(line, "\r\n"); uiFormat( - Debug, Cold, NULL, C"%d%c%c"C" %.*s", + Debug, Cold, NULL, "\3%d%c%c\3 %.*s", Gray, dir, dir, (int)len, line ); if (!isatty(STDERR_FILENO)) { diff --git a/ui.c b/ui.c index 961e448..3f74e14 100644 --- a/ui.c +++ b/ui.c @@ -271,8 +271,8 @@ static void statusUpdate(void) { int unread; char buf[256]; snprintf( - buf, sizeof(buf), C"%d%s %d %s %n("C"%02d%d"C"%d) ", - idColors[window->id], (window == windows.active ? V : ""), + buf, sizeof(buf), "\3%d%s %d %s %n(\3%02d%d\3%d) ", + idColors[window->id], (window == windows.active ? "\26" : ""), num, idNames[window->id], &unread, (window->heat > Warm ? White : idColors[window->id]), window->unread, -- cgit 1.4.1-2-gfad0 From d57df09511a5e4136559ccdd01ab56e906827f96 Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Tue, 4 Feb 2020 19:50:23 -0500 Subject: Align word wrapping with tab character Also fixes handling whitespace directly after control codes. --- handle.c | 2 +- irc.c | 2 +- ui.c | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'irc.c') diff --git a/handle.c b/handle.c index ef49f7c..29d1500 100644 --- a/handle.c +++ b/handle.c @@ -212,7 +212,7 @@ static void handlePrivmsg(struct Message *msg) { if (query && !network) idColors[id] = hash(msg->user); uiFormat( id, Warm, tagTime(msg), - "\3%d%s%s%s\3 %s", + "\3%d%s%s%s\3\t%s", hash(msg->user), (action ? "* " : notice ? "-" : "<"), msg->nick, diff --git a/irc.c b/irc.c index d8c6a21..2d6f00b 100644 --- a/irc.c +++ b/irc.c @@ -105,7 +105,7 @@ static void debug(char dir, const char *line) { if (!self.debug) return; size_t len = strcspn(line, "\r\n"); uiFormat( - Debug, Cold, NULL, "\3%d%c%c\3 %.*s", + Debug, Cold, NULL, "\3%d%c%c\3\t%.*s", Gray, dir, dir, (int)len, line ); if (!isatty(STDERR_FILENO)) { diff --git a/ui.c b/ui.c index 0c2a64e..e93c08c 100644 --- a/ui.c +++ b/ui.c @@ -287,14 +287,24 @@ static void styleAdd(WINDOW *win, const char *str, bool show) { getmaxyx(win, y, width); size_t len; + int align = 0; struct Style style = Reset; while (*str) { - if (*str == ' ') { + if (*str == '\t') { + waddch(win, ' '); + getyx(win, y, align); + str++; + } else if (*str == ' ') { getyx(win, y, x); const char *word = &str[strspn(str, " ")]; if (width - x - 1 <= wordWidth(word)) { waddch(win, '\n'); + getyx(win, y, x); + wmove(win, y, align); str = word; + } else { + waddch(win, ' '); + str++; } } @@ -313,9 +323,8 @@ static void styleAdd(WINDOW *win, const char *str, bool show) { if (str - code > 1) waddnstr(win, &code[1], str - &code[1]); } - size_t sp = strspn(str, " "); - sp += strcspn(&str[sp], " "); - if (sp < len) len = sp; + size_t ws = strcspn(str, "\t "); + if (ws < len) len = ws; wattr_set( win, -- cgit 1.4.1-2-gfad0 From 8b3bf897c2b7a14ff6a4c096b9969eaeb695a9e0 Mon Sep 17 00:00:00 2001 From: C. McEnroe Date: Thu, 6 Feb 2020 02:21:04 -0500 Subject: Search for cert and priv in config dirs --- chat.c | 14 +++++++++++++- chat.h | 2 +- irc.c | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 5 deletions(-) (limited to 'irc.c') diff --git a/chat.c b/chat.c index 115fe38..c487722 100644 --- a/chat.c +++ b/chat.c @@ -111,7 +111,19 @@ int main(int argc, char *argv[]) { set(&self.chanTypes, "#&"); set(&self.prefixes, "@+"); - ircConfig(insecure, cert, priv); + FILE *certFile = NULL; + FILE *privFile = NULL; + if (cert) { + certFile = configOpen(cert, "r"); + if (!certFile) err(EX_NOINPUT, "%s", cert); + } + if (priv) { + privFile = configOpen(priv, "r"); + if (!privFile) err(EX_NOINPUT, "%s", priv); + } + ircConfig(insecure, certFile, privFile); + if (certFile) fclose(certFile); + if (privFile) fclose(privFile); uiInit(); uiShowID(Network); diff --git a/chat.h b/chat.h index 57d4ba6..112530d 100644 --- a/chat.h +++ b/chat.h @@ -105,7 +105,7 @@ struct Message { char *params[ParamCap]; }; -void ircConfig(bool insecure, const char *cert, const char *priv); +void ircConfig(bool insecure, FILE *cert, FILE *priv); int ircConnect(const char *host, const char *port); void ircRecv(void); void ircSend(const char *ptr, size_t len); diff --git a/irc.c b/irc.c index 2d6f00b..05f8f9d 100644 --- a/irc.c +++ b/irc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,22 @@ struct tls *client; -void ircConfig(bool insecure, const char *cert, const char *priv) { +static byte *readFile(size_t *len, FILE *file) { + struct stat stat; + int error = fstat(fileno(file), &stat); + if (error) err(EX_IOERR, "fstat"); + + byte *buf = malloc(stat.st_size); + if (!buf) err(EX_OSERR, "malloc"); + + rewind(file); + *len = fread(buf, 1, stat.st_size, file); + if (ferror(file)) err(EX_IOERR, "fread"); + + return buf; +} + +void ircConfig(bool insecure, FILE *cert, FILE *priv) { struct tls_config *config = tls_config_new(); if (!config) errx(EX_SOFTWARE, "tls_config_new"); @@ -49,13 +65,28 @@ void ircConfig(bool insecure, const char *cert, const char *priv) { } if (cert) { - error = tls_config_set_keypair_file(config, cert, (priv ? priv : cert)); + size_t len; + byte *buf = readFile(&len, cert); + error = tls_config_set_cert_mem(config, buf, len); + if (error) { + errx( + EX_CONFIG, "tls_config_set_cert_mem: %s", + tls_config_error(config) + ); + } + if (priv) { + free(buf); + buf = readFile(&len, priv); + } + error = tls_config_set_key_mem(config, buf, len); if (error) { errx( - EX_SOFTWARE, "tls_config_set_keypair_file: %s", + EX_CONFIG, "tls_config_set_key_mem: %s", tls_config_error(config) ); } + explicit_bzero(buf, len); + free(buf); } client = tls_client(); -- cgit 1.4.1-2-gfad0