diff options
| -rw-r--r-- | chat.c | 24 | ||||
| -rw-r--r-- | chat.h | 67 | ||||
| -rw-r--r-- | command.c | 103 | ||||
| -rw-r--r-- | complete.c | 11 | ||||
| -rw-r--r-- | irc.c | 18 | ||||
| -rw-r--r-- | ui.c | 4 | ||||
| -rw-r--r-- | url.c | 7 | 
7 files changed, 118 insertions, 116 deletions
@@ -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(); @@ -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); @@ -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(¶ms, " "); -	if (!params) return; -	commandPrivmsg(idFor(nick), params); +	id = idFor(strsep(¶ms, " ")); +	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) { @@ -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");  	}  } @@ -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;  	} @@ -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) { @@ -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");  | 
