Various small cleanups

Haven't really gone through ui.c yet.
master
C. McEnroe 2020-02-16 23:05:43 -05:00
parent ba524ed804
commit b20be7cbad
7 changed files with 125 additions and 123 deletions

38
chat.c
View File

@ -17,6 +17,7 @@
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <locale.h> #include <locale.h>
#include <poll.h> #include <poll.h>
#include <signal.h> #include <signal.h>
@ -39,7 +40,7 @@
static void genCert(const char *path) { static void genCert(const char *path) {
const char *name = strrchr(path, '/'); const char *name = strrchr(path, '/');
name = (name ? &name[1] : path); name = (name ? &name[1] : path);
char subj[256]; char subj[4 + NAME_MAX];
snprintf(subj, sizeof(subj), "/CN=%.*s", (int)strcspn(name, "."), name); snprintf(subj, sizeof(subj), "/CN=%.*s", (int)strcspn(name, "."), name);
umask(0066); umask(0066);
execlp( execlp(
@ -56,13 +57,11 @@ char *idNames[IDCap] = {
[Debug] = "<debug>", [Debug] = "<debug>",
[Network] = "<network>", [Network] = "<network>",
}; };
enum Color idColors[IDCap] = { enum Color idColors[IDCap] = {
[None] = Black, [None] = Black,
[Debug] = Green, [Debug] = Green,
[Network] = Gray, [Network] = Gray,
}; };
uint idNext = Network + 1; uint idNext = Network + 1;
struct Network network; struct Network network;
@ -79,21 +78,9 @@ static void exitSave(void) {
uint32_t hashInit; uint32_t hashInit;
int utilPipe[2] = { -1, -1 }; uint execID;
int execPipe[2] = { -1, -1 }; int execPipe[2] = { -1, -1 };
int utilPipe[2] = { -1, -1 };
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) return;
buf[len] = '\0';
char *ptr = buf;
while (ptr) {
char *line = strsep(&ptr, "\n");
if (line[0]) uiFormat(Network, Warm, NULL, "%s", line);
}
}
static void execRead(void) { static void execRead(void) {
char buf[1024]; char buf[1024];
@ -108,6 +95,19 @@ 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) return;
buf[len] = '\0';
char *ptr = buf;
while (ptr) {
char *line = strsep(&ptr, "\n");
if (line[0]) uiFormat(Network, Warm, NULL, "%s", line);
}
}
static volatile sig_atomic_t signals[NSIG]; static volatile sig_atomic_t signals[NSIG];
static void signalHandler(int signal) { static void signalHandler(int signal) {
signals[signal] = 1; signals[signal] = 1;
@ -188,7 +188,7 @@ int main(int argc, char *argv[]) {
if (!user) user = nick; if (!user) user = nick;
if (!real) real = nick; if (!real) real = nick;
set(&network.name, host); // Modes defined in RFC 1459:
set(&network.chanTypes, "#&"); set(&network.chanTypes, "#&");
set(&network.prefixes, "@+"); set(&network.prefixes, "@+");
set(&network.prefixModes, "ov"); set(&network.prefixModes, "ov");
@ -196,6 +196,8 @@ int main(int argc, char *argv[]) {
set(&network.paramModes, "k"); set(&network.paramModes, "k");
set(&network.setParamModes, "l"); set(&network.setParamModes, "l");
set(&network.channelModes, "imnpst"); set(&network.channelModes, "imnpst");
set(&network.name, host);
set(&self.nick, "*"); set(&self.nick, "*");
commandComplete(); commandComplete();

67
chat.h
View File

@ -65,8 +65,8 @@ static inline uint idFor(const char *name) {
if (id) return id; if (id) return id;
if (idNext == IDCap) return Network; if (idNext == IDCap) return Network;
idNames[idNext] = strdup(name); idNames[idNext] = strdup(name);
if (!idNames[idNext]) err(EX_OSERR, "strdup");
idColors[idNext] = Default; idColors[idNext] = Default;
if (!idNames[idNext]) err(EX_OSERR, "strdup");
return idNext++; return idNext++;
} }
@ -79,9 +79,22 @@ static inline enum Color hash(const char *str) {
hash ^= *str; hash ^= *str;
hash *= 0x27220A95; hash *= 0x27220A95;
} }
return 2 + hash % 74; return Blue + hash % 74;
} }
extern struct Network {
char *name;
char *chanTypes;
char *prefixes;
char *prefixModes;
char *listModes;
char *paramModes;
char *setParamModes;
char *channelModes;
char excepts;
char invex;
} network;
#define ENUM_CAP \ #define ENUM_CAP \
X("extended-join", CapExtendedJoin) \ X("extended-join", CapExtendedJoin) \
X("invite-notify", CapInviteNotify) \ X("invite-notify", CapInviteNotify) \
@ -96,25 +109,12 @@ enum Cap {
#undef X #undef X
}; };
extern struct Network {
char *name;
char *chanTypes;
char *prefixes;
char *prefixModes;
char *listModes;
char *paramModes;
char *setParamModes;
char *channelModes;
char excepts;
char invex;
} network;
extern struct Self { extern struct Self {
bool debug; bool debug;
bool restricted; bool restricted;
char *plain;
const char *join;
enum Cap caps; enum Cap caps;
char *plain;
char *join;
char *nick; char *nick;
char *user; char *user;
enum Color color; enum Color color;
@ -155,25 +155,8 @@ void ircFormat(const char *format, ...)
__attribute__((format(printf, 1, 2))); __attribute__((format(printf, 1, 2)));
void ircClose(void); void ircClose(void);
extern struct Replies {
uint away;
uint join;
uint list;
uint names;
uint topic;
uint whois;
} replies;
uint execID; uint execID;
int execPipe[2]; int execPipe[2];
void handle(struct Message msg);
void command(uint id, char *input);
const char *commandIsPrivmsg(uint id, const char *input);
const char *commandIsNotice(uint id, const char *input);
const char *commandIsAction(uint id, const char *input);
void commandComplete(void);
int utilPipe[2]; int utilPipe[2];
enum { UtilCap = 16 }; enum { UtilCap = 16 };
@ -190,6 +173,22 @@ static inline void utilPush(struct Util *util, const char *arg) {
} }
} }
extern struct Replies {
uint away;
uint join;
uint list;
uint names;
uint topic;
uint whois;
} replies;
void handle(struct Message msg);
void command(uint id, char *input);
const char *commandIsPrivmsg(uint id, const char *input);
const char *commandIsNotice(uint id, const char *input);
const char *commandIsAction(uint id, const char *input);
void commandComplete(void);
enum Heat { Cold, Warm, Hot }; enum Heat { Cold, Warm, Hot };
extern struct Util uiNotifyUtil; extern struct Util uiNotifyUtil;
void uiInit(void); void uiInit(void);

View File

@ -39,53 +39,45 @@ static void commandQuote(uint id, char *params) {
if (params) ircFormat("%s\r\n", params); if (params) ircFormat("%s\r\n", params);
} }
static void commandPrivmsg(uint id, char *params) { static void echoMessage(char *cmd, uint id, char *params) {
if (!params || !params[0]) return; if (!params || !params[0]) return;
ircFormat("PRIVMSG %s :%s\r\n", idNames[id], params); ircFormat("%s %s :%s\r\n", cmd, idNames[id], params);
struct Message msg = { struct Message msg = {
.nick = self.nick, .nick = self.nick,
.user = self.user, .user = self.user,
.cmd = "PRIVMSG", .cmd = cmd,
.params[0] = idNames[id], .params[0] = idNames[id],
.params[1] = params, .params[1] = params,
}; };
handle(msg); handle(msg);
} }
static void commandPrivmsg(uint id, char *params) {
echoMessage("PRIVMSG", id, params);
}
static void commandNotice(uint id, char *params) { static void commandNotice(uint id, char *params) {
if (!params || !params[0]) return; echoMessage("NOTICE", id, params);
ircFormat("NOTICE %s :%s\r\n", idNames[id], params);
struct Message msg = {
.nick = self.nick,
.user = self.user,
.cmd = "NOTICE",
.params[0] = idNames[id],
.params[1] = params,
};
handle(msg);
} }
static void commandMe(uint id, char *params) { static void commandMe(uint id, char *params) {
char buf[512]; char buf[512];
snprintf(buf, sizeof(buf), "\1ACTION %s\1", (params ? params : "")); snprintf(buf, sizeof(buf), "\1ACTION %s\1", (params ? params : ""));
commandPrivmsg(id, buf); echoMessage("PRIVMSG", id, buf);
} }
static void commandMsg(uint id, char *params) { static void commandMsg(uint id, char *params) {
(void)id; id = idFor(strsep(&params, " "));
char *nick = strsep(&params, " "); echoMessage("PRIVMSG", id, params);
if (!params) return;
commandPrivmsg(idFor(nick), params);
} }
static void commandJoin(uint id, char *params) { static void commandJoin(uint id, char *params) {
if (!params) params = idNames[id];
uint count = 1; uint count = 1;
if (params) {
for (char *ch = params; *ch && *ch != ' '; ++ch) { for (char *ch = params; *ch && *ch != ' '; ++ch) {
if (*ch == ',') count++; if (*ch == ',') count++;
} }
} ircFormat("JOIN %s\r\n", params);
ircFormat("JOIN %s\r\n", (params ? params : idNames[id]));
replies.join += count; replies.join += count;
replies.topic += count; replies.topic += count;
replies.names += count; replies.names += count;
@ -101,7 +93,7 @@ static void commandPart(uint id, char *params) {
static void commandQuit(uint id, char *params) { static void commandQuit(uint id, char *params) {
(void)id; (void)id;
set(&self.quit, (params ? params : "Goodbye")); set(&self.quit, (params ? params : "nyaa~"));
} }
static void commandNick(uint id, char *params) { static void commandNick(uint id, char *params) {
@ -131,7 +123,7 @@ static void commandTopic(uint id, char *params) {
static void commandNames(uint id, char *params) { static void commandNames(uint id, char *params) {
(void)params; (void)params;
ircFormat("NAMES :%s\r\n", idNames[id]); ircFormat("NAMES %s\r\n", idNames[id]);
replies.names++; replies.names++;
} }
@ -170,14 +162,12 @@ static void commandWhois(uint id, char *params) {
static void commandNS(uint id, char *params) { static void commandNS(uint id, char *params) {
(void)id; (void)id;
if (!params) return; if (params) ircFormat("PRIVMSG NickServ :%s\r\n", params);
ircFormat("PRIVMSG NickServ :%s\r\n", params);
} }
static void commandCS(uint id, char *params) { static void commandCS(uint id, char *params) {
(void)id; (void)id;
if (!params) return; if (params) ircFormat("PRIVMSG ChanServ :%s\r\n", params);
ircFormat("PRIVMSG ChanServ :%s\r\n", params);
} }
static void commandQuery(uint id, char *params) { static void commandQuery(uint id, char *params) {
@ -330,36 +320,41 @@ const char *commandIsAction(uint id, const char *input) {
void command(uint id, char *input) { void command(uint id, char *input) {
if (id == Debug && input[0] != '/') { if (id == Debug && input[0] != '/') {
commandQuote(id, input); commandQuote(id, input);
return;
} else if (commandIsPrivmsg(id, input)) { } else if (commandIsPrivmsg(id, input)) {
commandPrivmsg(id, input); commandPrivmsg(id, input);
return;
} else if (input[0] == '/' && isdigit(input[1])) { } else if (input[0] == '/' && isdigit(input[1])) {
commandWindow(id, &input[1]); commandWindow(id, &input[1]);
} else { return;
}
const char *cmd = strsep(&input, " "); const char *cmd = strsep(&input, " ");
const char *unique = complete(None, cmd); const char *unique = complete(None, cmd);
if (unique && !complete(None, cmd)) { if (unique && !complete(None, cmd)) {
cmd = unique; cmd = unique;
completeReject(); completeReject();
} }
const struct Handler *handler = bsearch( const struct Handler *handler = bsearch(
cmd, Commands, ARRAY_LEN(Commands), sizeof(*handler), compar cmd, Commands, ARRAY_LEN(Commands), sizeof(*handler), compar
); );
if (self.restricted && handler && handler->restricted) { if (!handler) {
handler = NULL; uiFormat(id, Warm, NULL, "No such command %s", cmd);
return;
} }
if (handler) { if (self.restricted && handler->restricted) {
uiFormat(id, Warm, NULL, "Command %s is restricted", cmd);
return;
}
if (input) { if (input) {
input += strspn(input, " "); input += strspn(input, " ");
size_t len = strlen(input); size_t len = strlen(input);
while (input[len - 1] == ' ') input[--len] = '\0'; while (input[len - 1] == ' ') input[--len] = '\0';
if (!input[0]) input = NULL; if (!input[0]) input = NULL;
} }
if (input && !input[0]) input = NULL;
handler->fn(id, input); handler->fn(id, input);
} else {
uiFormat(id, Hot, NULL, "No such command %s", cmd);
}
}
} }
void commandComplete(void) { void commandComplete(void) {

View File

@ -35,10 +35,10 @@ static struct Node *alloc(uint id, const char *str, enum Color color) {
if (!node) err(EX_OSERR, "malloc"); if (!node) err(EX_OSERR, "malloc");
node->id = id; node->id = id;
node->str = strdup(str); node->str = strdup(str);
if (!node->str) err(EX_OSERR, "strdup");
node->color = color; node->color = color;
node->prev = NULL; node->prev = NULL;
node->next = NULL; node->next = NULL;
if (!node->str) err(EX_OSERR, "strdup");
return node; return node;
} }
@ -75,7 +75,9 @@ static struct Node *append(struct Node *node) {
static struct Node *find(uint id, const char *str) { static struct Node *find(uint id, const char *str) {
for (struct Node *node = head; node; node = node->next) { for (struct Node *node = head; node; node = node->next) {
if (node->id == id && !strcmp(node->str, str)) return node; if (node->id != id) continue;
if (strcmp(node->str, str)) continue;
return node;
} }
return NULL; return NULL;
} }
@ -86,7 +88,7 @@ void completeAdd(uint id, const char *str, enum Color color) {
void completeTouch(uint id, const char *str, enum Color color) { void completeTouch(uint id, const char *str, enum Color color) {
struct Node *node = find(id, str); struct Node *node = find(id, str);
if (node && node->color != color) node->color = color; if (node) node->color = color;
prepend(node ? detach(node) : alloc(id, str, color)); prepend(node ? detach(node) : alloc(id, str, color));
} }
@ -128,11 +130,10 @@ void completeReplace(uint id, const char *old, const char *new) {
next = node->next; next = node->next;
if (id && node->id != id) continue; if (id && node->id != id) continue;
if (strcmp(node->str, old)) continue; if (strcmp(node->str, old)) continue;
if (match == node) match = NULL;
free(node->str); free(node->str);
node->str = strdup(new); node->str = strdup(new);
if (!node->str) err(EX_OSERR, "strdup");
prepend(detach(node)); prepend(detach(node));
if (!node->str) err(EX_OSERR, "strdup");
} }
} }

18
irc.c
View File

@ -157,15 +157,17 @@ int ircConnect(const char *bindHost, const char *host, const char *port) {
return sock; return sock;
} }
static void debug(char dir, const char *line) { enum { MessageCap = 8191 + 512 };
static void debug(const char *pre, const char *line) {
if (!self.debug) return; if (!self.debug) return;
size_t len = strcspn(line, "\r\n"); size_t len = strcspn(line, "\r\n");
uiFormat( uiFormat(
Debug, Cold, NULL, "\3%d%c%c\3\t%.*s", Debug, Cold, NULL, "\3%02d%s\3\t%.*s",
Gray, dir, dir, (int)len, line Gray, pre, (int)len, line
); );
if (!isatty(STDERR_FILENO)) { if (!isatty(STDERR_FILENO)) {
fprintf(stderr, "%c%c %.*s\n", dir, dir, (int)len, line); fprintf(stderr, "%s %.*s\n", pre, (int)len, line);
} }
} }
@ -181,13 +183,13 @@ void ircSend(const char *ptr, size_t len) {
} }
void ircFormat(const char *format, ...) { void ircFormat(const char *format, ...) {
char buf[1024]; char buf[MessageCap];
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
int len = vsnprintf(buf, sizeof(buf), format, ap); int len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap); va_end(ap);
assert((size_t)len < sizeof(buf)); assert((size_t)len < sizeof(buf));
debug('<', buf); debug("<<", buf);
ircSend(buf, len); ircSend(buf, len);
} }
@ -249,7 +251,7 @@ static struct Message parse(char *line) {
} }
void ircRecv(void) { void ircRecv(void) {
static char buf[8191 + 512]; static char buf[MessageCap];
static size_t len = 0; static size_t len = 0;
assert(client); assert(client);
@ -265,7 +267,7 @@ void ircRecv(void) {
crlf = memmem(line, &buf[len] - line, "\r\n", 2); crlf = memmem(line, &buf[len] - line, "\r\n", 2);
if (!crlf) break; if (!crlf) break;
*crlf = '\0'; *crlf = '\0';
debug('>', line); debug(">>", line);
handle(parse(line)); handle(parse(line));
line = crlf + 2; line = crlf + 2;
} }

4
ui.c
View File

@ -90,10 +90,10 @@ struct Window {
}; };
static struct { static struct {
uint show;
uint swap;
struct Window *ptrs[IDCap]; struct Window *ptrs[IDCap];
uint len; uint len;
uint show;
uint swap;
} windows; } windows;
static uint windowPush(struct Window *window) { static uint windowPush(struct Window *window) {

7
url.c
View File

@ -17,6 +17,7 @@
#include <assert.h> #include <assert.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <regex.h> #include <regex.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -142,8 +143,10 @@ static void urlCopy(const char *url) {
int error = pipe(rw); int error = pipe(rw);
if (error) err(EX_OSERR, "pipe"); if (error) err(EX_OSERR, "pipe");
ssize_t len = write(rw[1], url, strlen(url)); size_t len = strlen(url);
if (len < 0) err(EX_IOERR, "write"); if (len > PIPE_BUF) len = PIPE_BUF;
ssize_t n = write(rw[1], url, len);
if (n < 0) err(EX_IOERR, "write");
error = close(rw[1]); error = close(rw[1]);
if (error) err(EX_IOERR, "close"); if (error) err(EX_IOERR, "close");