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
diff --git a/chat.c b/chat.c index 014076b..152bf84 100644 --- a/chat.c +++ b/chat.c @@ -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(); } diff --git a/chat.h b/chat.h index 912bc90..f0d396d 100644 --- a/chat.h +++ b/chat.h @@ -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))); diff --git a/event.c b/event.c index e9864ff..9f8c35e 100644 --- a/event.c +++ b/event.c @@ -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 (;;) { diff --git a/irc.c b/irc.c index 6754e16..f214637 100644 --- a/irc.c +++ b/irc.c @@ -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); |