diff options
| -rw-r--r-- | chat.c | 22 | ||||
| -rw-r--r-- | chat.h | 8 | ||||
| -rw-r--r-- | event.c | 6 | ||||
| -rw-r--r-- | irc.c | 116 | 
4 files changed, 89 insertions, 63 deletions
| @@ -60,39 +60,35 @@ static char *prompt(const char *prompt) {  int main(int argc, char *argv[]) {  	char *host = NULL; -	const char *port = "6697"; -	const char *pass = NULL; -	const char *webirc = NULL; +	char *port = "6697"; +	char *pass = NULL; +	char *webirc = NULL;  	int opt;  	while (0 < (opt = getopt(argc, argv, "NW:h:j:l:n:p:u:vw:"))) {  		switch (opt) {  			break; case 'N': self.notify = true; -			break; case 'W': webirc = optarg; +			break; case 'W': webirc = strdup(optarg);  			break; case 'h': host = strdup(optarg);  			break; case 'j': selfJoin(optarg);  			break; case 'l': logOpen(optarg);  			break; case 'n': selfNick(optarg); -			break; case 'p': port = optarg; +			break; case 'p': port = strdup(optarg);  			break; case 'u': selfUser(optarg);  			break; case 'v': self.verbose = true; -			break; case 'w': pass = optarg; +			break; case 'w': pass = strdup(optarg);  			break; default:  return EX_USAGE;  		}  	} +	if (!port) err(EX_OSERR, "strdup");  	if (!host) host = prompt("Host: ");  	if (!self.nick) self.nick = prompt("Name: ");  	if (!self.user) selfUser(self.nick);  	inputTab(); -  	uiInit(); -	uiLog(TagStatus, UIWarm, L"Traveling...");  	uiDraw(); - -	int irc = ircConnect(host, port, pass, webirc); -	free(host); - -	eventLoop(STDIN_FILENO, irc); +	ircInit(host, port, pass, webirc); +	eventLoop();  } @@ -43,7 +43,7 @@ void selfJoin(const char *join);  void eventWait(const char *argv[static 2]);  void eventPipe(const char *argv[static 2]); -void eventLoop(int ui, int irc); +void eventLoop(void);  struct Tag {  	size_t id; @@ -100,9 +100,9 @@ void handle(char *line);  void input(struct Tag tag, char *line);  void inputTab(void); -int ircConnect( -	const char *host, const char *port, const char *pass, const char *webPass -); +void ircInit(char *host, char *port, char *pass, char *webPass); +int ircConnect(void); +void ircDisconnect(const char *quit);  void ircRead(void);  void ircWrite(const char *ptr, size_t len);  void ircFmt(const char *format, ...) __attribute__((format(printf, 1, 2))); @@ -106,13 +106,15 @@ static void sigint(int sig) {  	exit(EX_OK);  } -void eventLoop(int ui, int irc) { +void eventLoop(void) {  	signal(SIGINT, sigint);  	signal(SIGCHLD, sigchld); +	int irc = ircConnect(); +  	struct pollfd fds[3] = {  		{ irc, POLLIN, 0 }, -		{ ui, POLLIN, 0 }, +		{ STDIN_FILENO, POLLIN, 0 },  		{ -1, POLLIN, 0 },  	};  	for (;;) { @@ -29,35 +29,40 @@  #include "chat.h" -static struct tls *client; - -static void webirc(const char *pass) { -	const char *ssh = getenv("SSH_CLIENT"); -	if (!ssh) return; -	int len = strlen(ssh); -	const char *sp = strchr(ssh, ' '); -	if (sp) len = sp - ssh; -	ircFmt( -		"WEBIRC %s %s %.*s %.*s\r\n", -		pass, self.user, len, ssh, len, ssh -	); +static struct { +	char *host; +	char *port; +	char *pass; +	char *webirc; +	int sock; +	struct tls_config *config; +	struct tls *client; +} irc = { +	.sock = -1, +}; + +void ircInit(char *host, char *port, char *pass, char *webirc) { +	irc.host = host; +	irc.port = port; +	irc.pass = pass; +	irc.webirc = webirc; + +	irc.config = tls_config_new(); +	int error = tls_config_set_ciphers(irc.config, "compat"); +	if (error) errx(EX_SOFTWARE, "tls_config"); + +	irc.client = tls_client(); +	if (!irc.client) errx(EX_SOFTWARE, "tls_client");  } -int ircConnect( -	const char *host, const char *port, const char *pass, const char *webPass -) { +int ircConnect(void) {  	int error; -	struct tls_config *config = tls_config_new(); -	error = tls_config_set_ciphers(config, "compat"); -	if (error) errx(EX_SOFTWARE, "tls_config: %s", tls_config_error(config)); +	tls_reset(irc.client); +	error = tls_configure(irc.client, irc.config); +	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(irc.client)); -	client = tls_client(); -	if (!client) errx(EX_SOFTWARE, "tls_client"); - -	error = tls_configure(client, config); -	if (error) errx(EX_SOFTWARE, "tls_configure"); -	tls_config_free(config); +	uiFmt(TagStatus, UIWarm, "Traveling to %s", irc.host);  	struct addrinfo *head;  	struct addrinfo hints = { @@ -65,42 +70,65 @@ int ircConnect(  		.ai_socktype = SOCK_STREAM,  		.ai_protocol = IPPROTO_TCP,  	}; -	error = getaddrinfo(host, port, &hints, &head); +	error = getaddrinfo(irc.host, irc.port, &hints, &head);  	if (error) errx(EX_NOHOST, "getaddrinfo: %s", 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"); +		irc.sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); +		if (irc.sock < 0) err(EX_OSERR, "socket"); -		error = connect(sock, ai->ai_addr, ai->ai_addrlen); +		error = connect(irc.sock, ai->ai_addr, ai->ai_addrlen);  		if (!error) break; -		close(sock); -		sock = -1; +		close(irc.sock); +		irc.sock = -1;  	} -	if (sock < 0) err(EX_UNAVAILABLE, "connect"); +	if (irc.sock < 0) err(EX_UNAVAILABLE, "connect");  	freeaddrinfo(head); -	error = fcntl(sock, F_SETFD, FD_CLOEXEC); +	error = fcntl(irc.sock, F_SETFD, FD_CLOEXEC);  	if (error) err(EX_IOERR, "fcntl"); -	error = tls_connect_socket(client, sock, host); -	if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client)); +	error = tls_connect_socket(irc.client, irc.sock, irc.host); +	if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(irc.client)); + +	const char *ssh = getenv("SSH_CLIENT"); +	if (irc.webirc && ssh) { +		int len = strlen(ssh); +		const char *sp = strchr(ssh, ' '); +		if (sp) len = sp - ssh; +		ircFmt( +			"WEBIRC %s %s %.*s %.*s\r\n", +			irc.webirc, self.user, len, ssh, len, ssh +		); +	} + +	if (irc.pass) ircFmt("PASS :%s\r\n", irc.pass); +	ircFmt( +		"NICK %s\r\n" +		"USER %s 0 * :%s\r\n", +		self.nick, self.user, self.nick +	); + +	return irc.sock; +} + +void ircDisconnect(const char *quit) { +	// TODO: Wait for response, send quit to UI. +	ircFmt("QUIT :%s\r\n", quit); -	if (webPass) webirc(webPass); -	if (pass) ircFmt("PASS :%s\r\n", pass); -	ircFmt("NICK %s\r\n", self.nick); -	ircFmt("USER %s 0 * :%s\r\n", self.user, self.nick); +	int error = tls_close(irc.client); +	if (error) errx(EX_IOERR, "tls_close: %s", tls_error(irc.client)); -	return sock; +	error = close(irc.sock); +	if (error) err(EX_IOERR, "close");  }  void ircWrite(const char *ptr, size_t len) {  	while (len) { -		ssize_t ret = tls_write(client, ptr, len); +		ssize_t ret = tls_write(irc.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)); +		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(irc.client));  		ptr += ret;  		len -= ret;  	} @@ -127,8 +155,8 @@ void ircRead(void) {  	static char buf[4096];  	static size_t len; -	ssize_t read = tls_read(client, &buf[len], sizeof(buf) - len); -	if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client)); +	ssize_t read = tls_read(irc.client, &buf[len], sizeof(buf) - len); +	if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(irc.client));  	if (!read) {  		uiExit();  		exit(EX_OK); | 
