diff options
Diffstat (limited to 'bounce.h')
-rw-r--r-- | bounce.h | 123 |
1 files changed, 100 insertions, 23 deletions
diff --git a/bounce.h b/bounce.h index a5dc836..a7bad16 100644 --- a/bounce.h +++ b/bounce.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 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 @@ -12,33 +12,59 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this Program, or any covered work, by linking or + * combining it with OpenSSL (or a modified version of that library), + * containing parts covered by the terms of the OpenSSL License and the + * original SSLeay license, the licensors of this Program grant you + * additional permission to convey the resulting work. Corresponding + * Source for a non-source form of such a combination shall include the + * source code for the parts of OpenSSL used as well as that of the + * covered work. */ +#include <err.h> +#include <limits.h> +#include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> +#include <sysexits.h> #include <tls.h> -#include "compat.h" - -#ifndef CERTBOT_PATH -#define CERTBOT_PATH "/usr/local/etc/letsencrypt" -#endif - #ifndef OPENSSL_BIN #define OPENSSL_BIN "openssl" #endif #define SOURCE_URL "https://git.causal.agency/pounce" -#define ORIGIN "irc.invalid" #define BIT(x) x##Bit, x = 1 << x##Bit, x##Bit_ = x##Bit #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) typedef unsigned char byte; +static inline char *seprintf(char *ptr, char *end, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); +static inline char *seprintf(char *ptr, char *end, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(ptr, end - ptr, fmt, ap); + va_end(ap); + if (n < 0) return NULL; + if (n > end - ptr) return end; + return ptr + n; +} + +static inline void set(char **field, const char *value) { + if (*field) free(*field); + *field = strdup(value); + if (!*field) err(EX_OSERR, "strdup"); +} + enum { MessageCap = 8191 + 512 }; enum { ParamCap = 15 }; @@ -51,9 +77,10 @@ struct Message { static inline struct Message parse(char *line) { struct Message msg = {0}; - if (line[0] == '@') msg.tags = 1 + strsep(&line, " "); - if (line[0] == ':') msg.origin = 1 + strsep(&line, " "); + if (line && line[0] == '@') msg.tags = 1 + strsep(&line, " "); + if (line && line[0] == ':') msg.origin = 1 + strsep(&line, " "); msg.cmd = strsep(&line, " "); + if (msg.cmd && !msg.cmd[0]) msg.cmd = NULL; for (size_t i = 0; line && i < ParamCap; ++i) { if (line[0] == ':') { msg.params[i] = &line[1]; @@ -73,16 +100,21 @@ static inline struct Message parse(char *line) { X("causal.agency/consumer", CapConsumer) \ X("causal.agency/passive", CapPassive) \ X("chghost", CapChghost) \ + X("draft/read-marker", CapReadMarker) \ + X("echo-message", CapEchoMessage) \ X("extended-join", CapExtendedJoin) \ + X("extended-monitor", CapExtendedMonitor) \ X("invite-notify", CapInviteNotify) \ X("labeled-response", CapLabeledResponse) \ X("message-tags", CapMessageTags) \ X("multi-prefix", CapMultiPrefix) \ + X("palaverapp.com", CapPalaverApp) \ X("sasl", CapSASL) \ X("server-time", CapServerTime) \ X("setname", CapSetname) \ X("sts", CapSTS) \ X("userhost-in-names", CapUserhostInNames) \ + X("znc.in/self-message", CapSelfMessage) \ X("", CapUnsupported) enum Cap { @@ -127,13 +159,14 @@ static inline enum Cap capParse(const char *list, const char *values[CapBits]) { static inline const char *capList(enum Cap caps, const char *values[CapBits]) { static char buf[1024]; buf[0] = '\0'; + char *ptr = buf, *end = &buf[sizeof(buf)]; for (size_t i = 0; i < ARRAY_LEN(CapNames); ++i) { if (caps & (1 << i)) { - if (buf[0]) strlcat(buf, " ", sizeof(buf)); - strlcat(buf, CapNames[i], sizeof(buf)); + ptr = seprintf( + ptr, end, "%s%s", (ptr > buf ? " " : ""), CapNames[i] + ); if (values && values[i]) { - strlcat(buf, "=", sizeof(buf)); - strlcat(buf, values[i], sizeof(buf)); + ptr = seprintf(ptr, end, "=%s", values[i]); } } } @@ -141,6 +174,13 @@ static inline const char *capList(enum Cap caps, const char *values[CapBits]) { } extern bool verbose; +static inline void +verboseLog(const char *prefix, const char *line, size_t len) { + if (!verbose) return; + if (len && line[len - 1] == '\n') len--; + if (len && line[len - 1] == '\r') len--; + printf("%s %.*s\n", prefix, (int)len, line); +} void ringAlloc(size_t len); void ringProduce(const char *line); @@ -154,36 +194,68 @@ void ringInfo(void); int ringSave(FILE *file); void ringLoad(FILE *file); -void localConfig(FILE *cert, FILE *priv, FILE *ca, bool require); +int localConfig( + const char *cert, const char *priv, const char *ca, bool require +); size_t localBind(int fds[], size_t cap, const char *host, const char *port); size_t localUnix(int fds[], size_t cap, const char *path); -struct tls *localAccept(int *fd, int bind); +int localAccept(struct tls **tls, int bind); -void serverConfig(bool insecure, const char *cert, const char *priv); +extern struct timeval serverQueueInterval; +void serverConfig( + bool insecure, const char *trust, const char *cert, const char *priv +); int serverConnect(const char *bindHost, const char *host, const char *port); +void serverPrintCert(void); void serverRecv(void); void serverSend(const char *ptr, size_t len); void serverFormat(const char *format, ...) __attribute__((format(printf, 1, 2))); +void serverEnqueue(const char *format, ...) + __attribute__((format(printf, 1, 2))); +void serverDequeue(void); +void serverClose(void); -extern bool clientCA; -extern bool clientSTS; +enum Need { + BIT(NeedHandshake), + BIT(NeedNick), + BIT(NeedUser), + BIT(NeedPass), + BIT(NeedCapEnd), +}; +struct Client { + bool remove; + int sock; + struct tls *tls; + time_t time; + time_t idle; + enum Need need; + enum Cap caps; + size_t consumer; + size_t setPos; + char buf[MessageCap]; + size_t len; +}; +extern enum Cap clientCaps; +extern char *clientOrigin; extern char *clientPass; extern char *clientAway; -struct Client *clientAlloc(struct tls *tls); +extern char *clientQuit; +struct Client *clientAlloc(int sock, struct tls *tls); void clientFree(struct Client *client); -bool clientError(const struct Client *client); void clientRecv(struct Client *client); void clientSend(struct Client *client, const char *ptr, size_t len); void clientFormat(struct Client *client, const char *format, ...) __attribute__((format(printf, 2, 3))); -size_t clientDiff(const struct Client *client); void clientConsume(struct Client *client); +void clientGetMarker(struct Client *client, const char *target); extern bool stateNoNames; extern enum Cap stateCaps; +extern char *stateAccount; +extern bool stateAway; void stateLogin( - const char *pass, bool sasl, const char *plain, + const char *pass, enum Cap blind, const char *plain, const char *nick, const char *user, const char *real ); bool stateReady(void); @@ -192,6 +264,11 @@ void stateSync(struct Client *client); const char *stateNick(void); const char *stateEcho(void); +char *configPath(char *buf, size_t cap, const char *path, int i); +char *dataPath(char *buf, size_t cap, const char *path, int i); +FILE *configOpen(const char *path, const char *mode); +FILE *dataOpen(const char *path, const char *mode); + struct option; int getopt_config( int argc, char *const *argv, |