summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chat.c24
-rw-r--r--chat.h67
-rw-r--r--command.c103
-rw-r--r--complete.c11
-rw-r--r--irc.c18
-rw-r--r--ui.c4
-rw-r--r--url.c7
7 files changed, 118 insertions, 116 deletions
diff --git a/chat.c b/chat.c
index 16ecb8a..fa1240a 100644
--- a/chat.c
+++ b/chat.c
@@ -17,6 +17,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <locale.h>
#include <poll.h>
#include <signal.h>
@@ -39,7 +40,7 @@
static void genCert(const char *path) {
const char *name = strrchr(path, '/');
name = (name ? &name[1] : path);
- char subj[256];
+ char subj[4 + NAME_MAX];
snprintf(subj, sizeof(subj), "/CN=%.*s", (int)strcspn(name, "."), name);
umask(0066);
execlp(
@@ -56,13 +57,11 @@ char *idNames[IDCap] = {
[Debug] = "<debug>",
[Network] = "<network>",
};
-
enum Color idColors[IDCap] = {
[None] = Black,
[Debug] = Green,
[Network] = Gray,
};
-
uint idNext = Network + 1;
struct Network network;
@@ -79,32 +78,33 @@ static void exitSave(void) {
uint32_t hashInit;
-int utilPipe[2] = { -1, -1 };
+uint execID;
int execPipe[2] = { -1, -1 };
+int utilPipe[2] = { -1, -1 };
-static void utilRead(void) {
+static void execRead(void) {
char buf[1024];
- ssize_t len = read(utilPipe[0], buf, sizeof(buf) - 1);
+ ssize_t len = read(execPipe[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);
+ if (line[0]) command(execID, line);
}
}
-static void execRead(void) {
+static void utilRead(void) {
char buf[1024];
- ssize_t len = read(execPipe[0], buf, sizeof(buf) - 1);
+ 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]) command(execID, line);
+ if (line[0]) uiFormat(Network, Warm, NULL, "%s", line);
}
}
@@ -188,7 +188,7 @@ int main(int argc, char *argv[]) {
if (!user) user = nick;
if (!real) real = nick;
- set(&network.name, host);
+ // Modes defined in RFC 1459:
set(&network.chanTypes, "#&");
set(&network.prefixes, "@+");
set(&network.prefixModes, "ov");
@@ -196,6 +196,8 @@ int main(int argc, char *argv[]) {
set(&network.paramModes, "k");
set(&network.setParamModes, "l");
set(&network.channelModes, "imnpst");
+
+ set(&network.name, host);
set(&self.nick, "*");
commandComplete();
diff --git a/chat.h b/chat.h
index 1f4274f..d7f7c5c 100644
--- a/chat.h
+++ b/chat.h
@@ -65,8 +65,8 @@ static inline uint idFor(const char *name) {
if (id) return id;
if (idNext == IDCap) return Network;
idNames[idNext] = strdup(name);
- if (!idNames[idNext]) err(EX_OSERR, "strdup");
idColors[idNext] = Default;
+ if (!idNames[idNext]) err(EX_OSERR, "strdup");
return idNext++;
}
@@ -79,9 +79,22 @@ static inline enum Color hash(const char *str) {
hash ^= *str;
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 \
X("extended-join", CapExtendedJoin) \
X("invite-notify", CapInviteNotify) \
@@ -96,25 +109,12 @@ enum Cap {
#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 {
bool debug;
bool restricted;
- char *plain;
- const char *join;
enum Cap caps;
+ char *plain;
+ char *join;
char *nick;
char *user;
enum Color color;
@@ -155,25 +155,8 @@ void ircFormat(const char *format, ...)
__attribute__((format(printf, 1, 2)));
void ircClose(void);
-extern struct Replies {
- uint away;
- uint join;
- uint list;
- uint names;
- uint topic;
- uint whois;
-} replies;
-
uint execID;
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];
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 };
extern struct Util uiNotifyUtil;
void uiInit(void);
diff --git a/command.c b/command.c
index 58d5a66..cc650da 100644
--- a/command.c
+++ b/command.c
@@ -39,53 +39,45 @@ static void commandQuote(uint id, char *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;
- ircFormat("PRIVMSG %s :%s\r\n", idNames[id], params);
+ ircFormat("%s %s :%s\r\n", cmd, idNames[id], params);
struct Message msg = {
.nick = self.nick,
.user = self.user,
- .cmd = "PRIVMSG",
+ .cmd = cmd,
.params[0] = idNames[id],
.params[1] = params,
};
handle(msg);
}
+static void commandPrivmsg(uint id, char *params) {
+ echoMessage("PRIVMSG", id, params);
+}
+
static void commandNotice(uint id, char *params) {
- if (!params || !params[0]) return;
- 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);
+ echoMessage("NOTICE", id, params);
}
static void commandMe(uint id, char *params) {
char buf[512];
snprintf(buf, sizeof(buf), "\1ACTION %s\1", (params ? params : ""));
- commandPrivmsg(id, buf);
+ echoMessage("PRIVMSG", id, buf);
}
static void commandMsg(uint id, char *params) {
- (void)id;
- char *nick = strsep(&params, " ");
- if (!params) return;
- commandPrivmsg(idFor(nick), params);
+ id = idFor(strsep(&params, " "));
+ echoMessage("PRIVMSG", id, params);
}
static void commandJoin(uint id, char *params) {
+ if (!params) params = idNames[id];
uint count = 1;
- if (params) {
- for (char *ch = params; *ch && *ch != ' '; ++ch) {
- if (*ch == ',') count++;
- }
+ for (char *ch = params; *ch && *ch != ' '; ++ch) {
+ if (*ch == ',') count++;
}
- ircFormat("JOIN %s\r\n", (params ? params : idNames[id]));
+ ircFormat("JOIN %s\r\n", params);
replies.join += count;
replies.topic += count;
replies.names += count;
@@ -101,7 +93,7 @@ static void commandPart(uint id, char *params) {
static void commandQuit(uint id, char *params) {
(void)id;
- set(&self.quit, (params ? params : "Goodbye"));
+ set(&self.quit, (params ? params : "nyaa~"));
}
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) {
(void)params;
- ircFormat("NAMES :%s\r\n", idNames[id]);
+ ircFormat("NAMES %s\r\n", idNames[id]);
replies.names++;
}
@@ -170,14 +162,12 @@ static void commandWhois(uint id, char *params) {
static void commandNS(uint id, char *params) {
(void)id;
- if (!params) return;
- ircFormat("PRIVMSG NickServ :%s\r\n", params);
+ if (params) ircFormat("PRIVMSG NickServ :%s\r\n", params);
}
static void commandCS(uint id, char *params) {
(void)id;
- if (!params) return;
- ircFormat("PRIVMSG ChanServ :%s\r\n", params);
+ if (params) ircFormat("PRIVMSG ChanServ :%s\r\n", 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) {
if (id == Debug && input[0] != '/') {
commandQuote(id, input);
+ return;
} else if (commandIsPrivmsg(id, input)) {
commandPrivmsg(id, input);
+ return;
} else if (input[0] == '/' && isdigit(input[1])) {
commandWindow(id, &input[1]);
- } else {
- const char *cmd = strsep(&input, " ");
- const char *unique = complete(None, cmd);
- if (unique && !complete(None, cmd)) {
- cmd = unique;
- completeReject();
- }
- const struct Handler *handler = bsearch(
- cmd, Commands, ARRAY_LEN(Commands), sizeof(*handler), compar
- );
- if (self.restricted && handler && handler->restricted) {
- handler = NULL;
- }
- if (handler) {
- if (input) {
- input += strspn(input, " ");
- size_t len = strlen(input);
- while (input[len - 1] == ' ') input[--len] = '\0';
- if (!input[0]) input = NULL;
- }
- if (input && !input[0]) input = NULL;
- handler->fn(id, input);
- } else {
- uiFormat(id, Hot, NULL, "No such command %s", cmd);
- }
+ return;
+ }
+
+ const char *cmd = strsep(&input, " ");
+ const char *unique = complete(None, cmd);
+ if (unique && !complete(None, cmd)) {
+ cmd = unique;
+ completeReject();
+ }
+
+ const struct Handler *handler = bsearch(
+ cmd, Commands, ARRAY_LEN(Commands), sizeof(*handler), compar
+ );
+ if (!handler) {
+ uiFormat(id, Warm, NULL, "No such command %s", cmd);
+ return;
+ }
+ if (self.restricted && handler->restricted) {
+ uiFormat(id, Warm, NULL, "Command %s is restricted", cmd);
+ return;
+ }
+
+ if (input) {
+ input += strspn(input, " ");
+ size_t len = strlen(input);
+ while (input[len - 1] == ' ') input[--len] = '\0';
+ if (!input[0]) input = NULL;
}
+ handler->fn(id, input);
}
void commandComplete(void) {
diff --git a/complete.c b/complete.c
index b65d870..ad9bfd7 100644
--- a/complete.c
+++ b/complete.c
@@ -35,10 +35,10 @@ static struct Node *alloc(uint id, const char *str, enum Color color) {
if (!node) err(EX_OSERR, "malloc");
node->id = id;
node->str = strdup(str);
- if (!node->str) err(EX_OSERR, "strdup");
node->color = color;
node->prev = NULL;
node->next = NULL;
+ if (!node->str) err(EX_OSERR, "strdup");
return node;
}
@@ -75,7 +75,9 @@ static struct Node *append(struct Node *node) {
static struct Node *find(uint id, const char *str) {
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;
}
@@ -86,7 +88,7 @@ void completeAdd(uint id, const char *str, enum Color color) {
void completeTouch(uint id, const char *str, enum Color color) {
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));
}
@@ -128,11 +130,10 @@ void completeReplace(uint id, const char *old, const char *new) {
next = node->next;
if (id && node->id != id) continue;
if (strcmp(node->str, old)) continue;
- if (match == node) match = NULL;
free(node->str);
node->str = strdup(new);
- if (!node->str) err(EX_OSERR, "strdup");
prepend(detach(node));
+ if (!node->str) err(EX_OSERR, "strdup");
}
}
diff --git a/irc.c b/irc.c
index 704caa6..6a65c79 100644
--- a/irc.c
+++ b/irc.c
@@ -157,15 +157,17 @@ int ircConnect(const char *bindHost, const char *host, const char *port) {
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;
size_t len = strcspn(line, "\r\n");
uiFormat(
- Debug, Cold, NULL, "\3%d%c%c\3\t%.*s",
- Gray, dir, dir, (int)len, line
+ Debug, Cold, NULL, "\3%02d%s\3\t%.*s",
+ Gray, pre, (int)len, line
);
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, ...) {
- char buf[1024];
+ char buf[MessageCap];
va_list ap;
va_start(ap, format);
int len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
assert((size_t)len < sizeof(buf));
- debug('<', buf);
+ debug("<<", buf);
ircSend(buf, len);
}
@@ -249,7 +251,7 @@ static struct Message parse(char *line) {
}
void ircRecv(void) {
- static char buf[8191 + 512];
+ static char buf[MessageCap];
static size_t len = 0;
assert(client);
@@ -265,7 +267,7 @@ void ircRecv(void) {
crlf = memmem(line, &buf[len] - line, "\r\n", 2);
if (!crlf) break;
*crlf = '\0';
- debug('>', line);
+ debug(">>", line);
handle(parse(line));
line = crlf + 2;
}
diff --git a/ui.c b/ui.c
index aaa7b49..bcb1003 100644
--- a/ui.c
+++ b/ui.c
@@ -90,10 +90,10 @@ struct Window {
};
static struct {
- uint show;
- uint swap;
struct Window *ptrs[IDCap];
uint len;
+ uint show;
+ uint swap;
} windows;
static uint windowPush(struct Window *window) {
diff --git a/url.c b/url.c
index 64fdd8b..949f860 100644
--- a/url.c
+++ b/url.c
@@ -17,6 +17,7 @@
#include <assert.h>
#include <err.h>
#include <errno.h>
+#include <limits.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
@@ -142,8 +143,10 @@ static void urlCopy(const char *url) {
int error = pipe(rw);
if (error) err(EX_OSERR, "pipe");
- ssize_t len = write(rw[1], url, strlen(url));
- if (len < 0) err(EX_IOERR, "write");
+ size_t len = strlen(url);
+ 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]);
if (error) err(EX_IOERR, "close");