git clone https://orangeshoelaces.net/git/ii.git
Author: Vasilii Kolobkov on 01/07/2019
Committer: Vasilii Kolobkov on 01/08/2019
Act as a pure protocol handler
Leave connection handling to other tools (e.g. socat, nc or
tcpclient). Expect server messages on standard input and provide and
send our messages via standard output.
ii.1 | 21 +-
ii.c | 170 ++------
2 files changed, 49 insertions(+), 142 deletions(-)
diff --git a/ii.1 b/ii.1
index 8e06af7..2ea973e 100644
--- a/ii.1
+++ b/ii.1
@@ -15,12 +15,12 @@ The basic idea of this is to be able to communicate with an IRC
server with basic command line tools.
For example if you will join a channel just do echo "/j #channel" > in
and ii creates a new channel directory with in and out file.
+Connection to server is expected on standard input for server messages
+and standard output for ii messages.
.SH SYNOPSIS
.B ii
.RB < \-s
.IR servername >
-.RB [ \-p
-.IR port ]
.RB [ \-k
.IR "environment variable" ]
.RB [ \-i
@@ -29,18 +29,10 @@ and ii creates a new channel directory with in and out file.
.IR nickname ]
.RB [ \-f
.IR realname ]
-.RB < \-u
-.IR sockname >
.SH OPTIONS
.TP
.BI \-s " servername"
-server to connect to, for example: irc.freenode.net
-.TP
-.BI \-u " sockname"
-connect to a UNIX domain socket instead of directly to a server.
-.TP
-.BI \-p " port"
-lets you override the default port (6667)
+server name, for example: irc.freenode.net
.TP
.BI \-k " environment variable"
lets you specify an environment variable that contains your IRC password, e.g. IIPASS="foobar" ii -k IIPASS.
@@ -85,9 +77,6 @@ set the topic of a channel
.LP
Everything which is not a command will be posted into the channel or to the server.
So if you need /who just write /WHO as described in RFC#1459 to the server in FIFO.
-.SH SSL PROTOCOL SUPPORT
-.LP
-For TLS/SSL protocol support you can connect to a local tunnel, for example with stunnel or socat.
.SH CONTACT
.LP
Subscribe to the mailinglist and write to dev (at) suckless (dot) org for suggestions, fixes, etc.
@@ -95,6 +84,8 @@ Subscribe to the mailinglist and write to dev (at) suckless (dot) org for sugges
ii engineers, see LICENSE file
.SH SEE ALSO
.BR echo (1),
-.BR tail (1)
+.BR tail (1),
+.BR socat (1),
+.BR nc(1)
.SH BUGS
Please report them!
diff --git a/ii.c b/ii.c
index 6c87314..2345214 100644
--- a/ii.c
+++ b/ii.c
@@ -1,16 +1,12 @@
/* See LICENSE file for license details. */
#include <sys/select.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <netdb.h>
-#include <netinet/in.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
@@ -56,22 +52,20 @@ static int channel_reopen(Channel *);
static void channel_rm(Channel *);
static void create_dirtree(const char *);
static void create_filepath(char *, size_t, const char *, const char *, const char *);
-static void ewritestr(int, const char *);
-static void handle_channels_input(int, Channel *);
-static void handle_server_output(int);
+static void ewritestr(const char *);
+static void handle_channels_input(Channel *);
+static void handle_server_output(void);
static int isnumeric(const char *);
-static void loginkey(int, const char *);
-static void loginuser(int, const char *, const char *);
-static void proc_channels_input(int, Channel *, char *);
-static void proc_channels_privmsg(int, Channel *, char *);
-static void proc_server_cmd(int, char *);
+static void loginkey(const char *);
+static void loginuser(const char *, const char *);
+static void proc_channels_input(Channel *, char *);
+static void proc_channels_privmsg(Channel *, char *);
+static void proc_server_cmd(char *);
static int read_line(int, char *, size_t);
-static void run(int, const char *);
+static void run(const char *);
static void setup(void);
static void sighandler(int);
-static int tcpopen(const char *, const char *);
static size_t tokenize(char **, size_t, char *, int);
-static int udsopen(const char *);
static void usage(void);
static int isrunning = 1;
@@ -86,21 +80,20 @@ static char msg[IRC_MSG_MAX]; /* message buf used for communication */
static void
usage(void)
{
- fprintf(stderr, "usage: %s <-s host> [-i <irc dir>] [-p <port>] "
- "[-u <sockname>] [-n <nick>] [-k <password>] "
- "[-f <fullname>]\n", argv0);
+ fprintf(stderr, "usage: %s <-s host> [-i <irc dir>] "
+ "[-n <nick>] [-k <password>] [-f <fullname>]\n", argv0);
exit(1);
}
static void
-ewritestr(int fd, const char *s)
+ewritestr(const char *s)
{
size_t len, off = 0;
int w = -1;
len = strlen(s);
for (off = 0; off < len; off += w) {
- if ((w = write(fd, s + off, len - off)) == -1)
+ if ((w = write(STDOUT_FILENO, s + off, len - off)) == -1)
break;
off += w;
}
@@ -320,81 +313,18 @@ channel_leave(Channel *c)
}
static void
-loginkey(int ircfd, const char *key)
+loginkey(const char *key)
{
snprintf(msg, sizeof(msg), "PASS %s\r\n", key);
- ewritestr(ircfd, msg);
+ ewritestr(msg);
}
static void
-loginuser(int ircfd, const char *host, const char *fullname)
+loginuser(const char *host, const char *fullname)
{
snprintf(msg, sizeof(msg), "NICK %s\r\nUSER %s localhost %s :%s\r\n",
nick, nick, host, fullname);
- puts(msg);
- ewritestr(ircfd, msg);
-}
-
-static int
-udsopen(const char *uds)
-{
- struct sockaddr_un sun;
- size_t len;
- int fd;
-
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- fprintf(stderr, "%s: socket: %s\n", argv0, strerror(errno));
- exit(1);
- }
-
- sun.sun_family = AF_UNIX;
- if (strlcpy(sun.sun_path, uds, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
- fprintf(stderr, "%s: UNIX domain socket path truncation\n", argv0);
- exit(1);
- }
- len = strlen(sun.sun_path) + 1 + sizeof(sun.sun_family);
- if (connect(fd, (struct sockaddr *)&sun, len) == -1) {
- fprintf(stderr, "%s: connect: %s\n", argv0, strerror(errno));
- exit(1);
- }
- return fd;
-}
-
-static int
-tcpopen(const char *host, const char *service)
-{
- struct addrinfo hints, *res = NULL, *rp;
- int fd = -1, e;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC; /* allow IPv4 or IPv6 */
- hints.ai_flags = AI_NUMERICSERV; /* avoid name lookup for port */
- hints.ai_socktype = SOCK_STREAM;
-
- if ((e = getaddrinfo(host, service, &hints, &res))) {
- fprintf(stderr, "%s: getaddrinfo: %s\n", argv0, gai_strerror(e));
- exit(1);
- }
-
- for (rp = res; rp; rp = rp->ai_next) {
- fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd == -1)
- continue;
- if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) {
- close(fd);
- fd = -1;
- continue;
- }
- break; /* success */
- }
- if (fd == -1) {
- fprintf(stderr, "%s: could not connect to %s:%s: %s\n",
- argv0, host, service, strerror(errno));
- exit(1);
- }
-
- freeaddrinfo(res);
- return fd;
+ ewritestr(msg);
}
static int
@@ -446,16 +376,16 @@ channel_print(Channel *c, const char *buf)
}
static void
-proc_channels_privmsg(int ircfd, Channel *c, char *buf)
+proc_channels_privmsg(Channel *c, char *buf)
{
snprintf(msg, sizeof(msg), "<%s> %s", nick, buf);
channel_print(c, msg);
snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", c->name, buf);
- ewritestr(ircfd, msg);
+ ewritestr(msg);
}
static void
-proc_channels_input(int ircfd, Channel *c, char *buf)
+proc_channels_input(Channel *c, char *buf)
{
char *p = NULL;
size_t buflen;
@@ -463,7 +393,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
if (buf[0] == '\0')
return;
if (buf[0] != '/') {
- proc_channels_privmsg(ircfd, c, buf);
+ proc_channels_privmsg(c, buf);
return;
}
@@ -488,7 +418,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
channel_join(&buf[3]);
} else if (p) {
if ((c = channel_join(&buf[3])))
- proc_channels_privmsg(ircfd, c, p + 1);
+ proc_channels_privmsg(c, p + 1);
return;
}
break;
@@ -520,7 +450,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
else
snprintf(msg, sizeof(msg),
"PART %s :leaving\r\n", c->name);
- ewritestr(ircfd, msg);
+ ewritestr(msg);
channel_leave(c);
return;
break;
@@ -530,7 +460,7 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
else
snprintf(msg, sizeof(msg),
"QUIT %s\r\n", "bye");
- ewritestr(ircfd, msg);
+ ewritestr(msg);
isrunning = 0;
return;
break;
@@ -543,11 +473,11 @@ proc_channels_input(int ircfd, Channel *c, char *buf)
snprintf(msg, sizeof(msg), "%s\r\n", &buf[1]);
}
if (msg[0] != '\0')
- ewritestr(ircfd, msg);
+ ewritestr(msg);
}
static void
-proc_server_cmd(int fd, char *buf)
+proc_server_cmd(char *buf)
{
Channel *c;
const char *channel;
@@ -595,7 +525,7 @@ proc_server_cmd(int fd, char *buf)
return;
} else if (!strcmp("PING", argv[TOK_CMD])) {
snprintf(msg, sizeof(msg), "PONG %s\r\n", argv[TOK_TEXT]);
- ewritestr(fd, msg);
+ ewritestr(msg);
return;
} else if (!argv[TOK_NICKSRV] || !argv[TOK_USER]) {
/* server command */
@@ -682,7 +612,7 @@ read_line(int fd, char *buf, size_t bufsiz)
}
static void
-handle_channels_input(int ircfd, Channel *c)
+handle_channels_input(Channel *c)
{
char buf[IRC_MSG_MAX];
@@ -691,22 +621,20 @@ handle_channels_input(int ircfd, Channel *c)
channel_rm(c);
return;
}
- proc_channels_input(ircfd, c, buf);
+ proc_channels_input(c, buf);
}
static void
-handle_server_output(int ircfd)
+handle_server_output()
{
char buf[IRC_MSG_MAX];
- if (read_line(ircfd, buf, sizeof(buf)) == -1) {
+ if (read_line(STDIN_FILENO, buf, sizeof(buf)) == -1) {
fprintf(stderr, "%s: remote host closed connection: %s\n",
argv0, strerror(errno));
exit(1);
}
- fprintf(stdout, "%lu %s\n", (unsigned long)time(NULL), buf);
- fflush(stdout);
- proc_server_cmd(ircfd, buf);
+ proc_server_cmd(buf);
}
static void
@@ -728,7 +656,7 @@ setup(void)
}
static void
-run(int ircfd, const char *host)
+run(const char *host)
{
Channel *c, *tmp;
fd_set rdset;
@@ -738,9 +666,9 @@ run(int ircfd, const char *host)
snprintf(ping_msg, sizeof(ping_msg), "PING %s\r\n", host);
while (isrunning) {
- maxfd = ircfd;
+ maxfd = STDIN_FILENO;
FD_ZERO(&rdset);
- FD_SET(ircfd, &rdset);
+ FD_SET(STDIN_FILENO, &rdset);
for (c = channels; c; c = c->next) {
if (c->fdin > maxfd)
maxfd = c->fdin;
@@ -759,17 +687,17 @@ run(int ircfd, const char *host)
channel_print(channelmaster, "-!- ii shutting down: ping timeout");
exit(2); /* status code 2 for timeout */
}
- ewritestr(ircfd, ping_msg);
+ ewritestr(ping_msg);
continue;
}
- if (FD_ISSET(ircfd, &rdset)) {
- handle_server_output(ircfd);
+ if (FD_ISSET(STDIN_FILENO, &rdset)) {
+ handle_server_output();
last_response = time(NULL);
}
for (c = channels; c; c = tmp) {
tmp = c->next;
if (FD_ISSET(c->fdin, &rdset))
- handle_channels_input(ircfd, c);
+ handle_channels_input(c);
}
}
}
@@ -780,9 +708,8 @@ main(int argc, char *argv[])
Channel *c, *tmp;
struct passwd *spw;
const char *key = NULL, *fullname = NULL, *host = "";
- const char *uds = NULL, *service = "6667";
char prefix[PATH_MAX];
- int ircfd, r;
+ int r;
/* use nickname and home dir of user by default */
if (!(spw = getpwuid(getuid()))) {
@@ -805,15 +732,9 @@ main(int argc, char *argv[])
case 'n':
strlcpy(nick, EARGF(usage()), sizeof(nick));
break;
- case 'p':
- service = EARGF(usage());
- break;
case 's':
host = EARGF(usage());
break;
- case 'u':
- uds = EARGF(usage());
- break;
default:
usage();
break;
@@ -822,11 +743,6 @@ main(int argc, char *argv[])
if (!*host)
usage();
- if (uds)
- ircfd = udsopen(uds);
- else
- ircfd = tcpopen(host, service);
-
#ifdef __OpenBSD__
/* OpenBSD pledge(2) support */
if (pledge("stdio rpath wpath cpath dpath", NULL) == -1) {
@@ -844,10 +760,10 @@ main(int argc, char *argv[])
channelmaster = channel_add(""); /* master channel */
if (key)
- loginkey(ircfd, key);
- loginuser(ircfd, host, fullname && *fullname ? fullname : nick);
+ loginkey(key);
+ loginuser(host, fullname && *fullname ? fullname : nick);
setup();
- run(ircfd, host);
+ run(host);
if (channelmaster)
channel_leave(channelmaster);